(function($) { // this is a useful global var teams; var TeambuilderRoom = this.TeambuilderRoom = this.Room.extend({ initialize: function() { teams = app.user.teams; // left menu this.$el.addClass('ps-room-light'); app.on('init:loadteams', this.update, this); this.update(); }, focus: function() { if (!Tools.movelists) { this.buildMovelists(); } }, events: { // teambuilder events 'keydown .chartinput': 'chartKeydown', 'focus .chartinput': 'chartFocus', 'change .chartinput': 'chartChange' }, dispatchClick: function(e) { e.preventDefault(); e.stopPropagation(); if (this[e.currentTarget.value]) this[e.currentTarget.value].call(this, e); }, saveTeams: function() { TeambuilderRoom.saveTeams(); app.user.trigger('saveteams'); this.update(); }, back: function() { if (this.exportMode) { this.exportMode = false; } else if (this.curSet) { this.curSet = null; } else if (this.curTeam) { this.curTeam = null; } else { return; } this.saveTeams(); }, // the teambuilder has three views: // - team list (curTeam falsy) // - team view (curTeam exists, curSet falsy) // - set view (curTeam exists, curSet exists) curTeam: null, curTeamLoc: 0, curSet: null, curSetLoc: 0, exportMode: false, update: function() { teams = app.user.teams; if (this.curTeam) { if (this.curSet) { return this.updateSetView(); } return this.updateTeamView(); } return this.updateTeamList(); }, /********************************************************* * Team list view *********************************************************/ deletedTeam: null, deletedTeamLoc: -1, updateTeamList: function() { var teams = app.user.teams; var buf = ''; if (this.exportMode) { buf = '
'; buf += ''; this.$el.html(buf); return; } buf = '

lol zarel this is a horrible teambuilder

' if (!teams) { buf += '

that\'s because we\'re not done loading it...

'; this.$el.html(buf); return; } buf += '

i know stfu im not done with it

' buf += ''; buf += ''; buf += ' '; buf += '

Clearing your cookies or localStorage will delete your teams.

If you want to clear your cookies or localStorage, you can use the Backup/Restore feature to save your teams as text first.

'; if (teams.length >= 2 && app.user.cookieTeams) { buf += ' WARNING: Additional teams WILL NOT BE SAVED.'; } buf += ''; this.$el.html(buf); }, // button actions edit: function(i) { var i = +i; this.curTeam = teams[i]; this.curTeamIndex = i; this.update(); }, delete: function(i) { var i = +i; this.deletedTeamLoc = i; this.deletedTeam = teams.splice(i, 1)[0]; this.saveTeams(); }, undoDelete: function() { if (this.deletedTeamLoc >= 0) { teams.splice(this.deletedTeamLoc, 0, this.deletedTeam); this.deletedTeam = null; this.deletedTeamLoc = -1; this.saveTeams(); } }, saveBackup: function() { this.parseText(this.$('.teamedit').val(), true); this.back(); }, new: function() { var newTeam = { name: 'Untitled '+(teams.length+1), team: [] }; teams.push(newTeam); this.curTeam = newTeam; this.curTeamLoc = teams.length-1; this.update(); }, import: function() { if (this.exportMode) return this.back(); if (!this.curTeam) { var newTeam = { name: 'Untitled '+(teams.length+1), team: [] }; teams.push(newTeam); this.curTeam = newTeam; this.curTeamLoc = teams.length-1; } this.exportMode = true; this.update(); }, backup: function() { this.curTeam = null; this.exportMode = true; this.update(); }, /********************************************************* * Team view *********************************************************/ updateTeamView: function() { var buf = ''; if (this.exportMode) { buf = '
'; buf += ''; } else { buf = '
'; buf += '
'; buf += '
    '; var i=0; if (this.curTeam.team.length && !this.curTeam.team[this.curTeam.team.length-1].species) { this.curTeam.team.splice(this.curTeam.team.length-1, 1); } if (BattleFormats) { buf += '
  1. '; } if (!this.curTeam.team.length) { buf += '
  2. you have no pokemon lol
  3. '; } for (i=0; i'; if (!set.species) { buf += '
    '; buf += ''; return buf; } buf += '
    '; buf += ''; buf += '
    '; buf += '
    '; // icon var itemicon = ''; if (set.item) { var item = Tools.getItem(set.item); itemicon = ''; } buf += '
    '+itemicon+'
    '; // details buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; // moves if (!set.moves) set.moves = []; buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; // stats buf += '
    '; buf += '
    '; return buf; }, saveImport: function() { this.curTeam.team = this.parseText(this.$('.teamedit').val()); this.back(); }, addPokemon: function() { if (!this.curTeam) return; var newPokemon = { name: '', species: '', item: '', nature: '', evs: {}, ivs: {}, moves: [] }; this.curTeam.team.push(newPokemon); this.curSet = newPokemon; this.curSetLoc = this.curTeam.team.length-1; this.update(); this.$('input[name=pokemon]').select(); }, /********************************************************* * Set view *********************************************************/ updateSetView: function() { // pokemon var buf = '
    '; buf += '
    '; buf += '
    '; var isAdd = false; if (this.curTeam.team.length && !this.curTeam.team[this.curTeam.team.length-1].name && this.curSetLoc !== this.curTeam.team.length-1) { this.curTeam.team.splice(this.curTeam.team.length-1, 1); } for (var i=0; i'; if (!set.name) { buf += ' '; isAdd = true; } else if (i == this.curSetLoc) { buf += ' '; } else { buf += ' '; } } if (this.curTeam.team.length < 6 && !isAdd) { buf += ' '; } buf += '
    '; // pokemon buf += '
    '; buf += '
      '; buf += this.renderSet(this.curSet, this.curSetLoc); buf += '
    '; buf += '
    '; // results this.chartPrevSearch = '[init]'; buf += '
    '; this.$el.html(buf); this.$chart = this.$('.teambuilder-results'); }, curChartType: '', curChartName: '', updateChart: function() { var type = this.curChartType; if (type === 'stats') { this.updateStatForm(); return; } if (type === 'details') { this.updateDetailsForm(); return; } this.$chart.html('Loading '+this.curChartType+'...'); }, setStatFormGuesses: function() { this.updateStatForm(true); }, updateStatForm: function(setGuessed) { var buf = ''; var set = this.curSet; buf += '

    EVs

    '; buf += '
    '; var role = this.guessRole(); var guessedEVs = {}; var guessedPlus = ''; var guessedMinus = ''; buf += '

    Suggested spread:'; if (role === '?') { buf += '
    (Please choose 4 moves to get a suggested spread)

    '; } else { guessedEVs = this.guessEVs(role); guessedPlus = guessedEVs.plusStat; delete guessedEVs.plusStat; guessedMinus = guessedEVs.minusStat; delete guessedEVs.minusStat; buf += '
    '; buf += '
    ('+role+' | bulk: phys '+Math.round(this.moveCount.physicalBulk/1000)+' + spec '+Math.round(this.moveCount.specialBulk/1000)+' = '+Math.round(this.moveCount.bulk/1000)+')

    '; } if (setGuessed) { set.evs = guessedEVs; this.plus = guessedPlus; this.minus = guessedMinus; this.updateNature(); } var stats = {hp:'',atk:'',def:'',spa:'',spd:'',spe:''}; if (!set) return; var nature = BattleNatures[set.nature || 'Serious']; if (!nature) nature = {}; // label column buf += '
    '; buf += '
    '; buf += '
    '; buf += '
    '; for (var i in stats) { stats[i] = this.getStat(i); buf += '
    '+stats[i]+'
    '; } buf += '
    '; buf += '
    '; for (var i in stats) { var width = stats[i]*200/504; if (i=='hp') width = Math.floor(stats[i]*200/704); if (width > 199) width = 199; var color = Math.floor(stats[i]*180/714); if (color>360) color = 360; buf += '
    '; } buf += '
    Remaining:
    '; buf += '
    '; buf += '
    EVs
    '; var totalev = 0; this.plus = ''; this.minus = ''; for (var i in stats) { var width = stats[i]*200/504; if (i=='hp') width = stats[i]*200/704; if (width > 200) width = 200; var val = ''+(set.evs[i]||''); if (nature.plus === i) { val += '+'; this.plus = i; } if (nature.minus === i) { val += '-'; this.minus = i; } buf += '
    '; totalev += (set.evs[i]||0); } if (totalev <= 510) { buf += '
    '+(totalev>508?0:508-totalev)+'
    '; } else { buf += '
    '+(510-totalev)+'
    '; } buf += '
    '; buf += '
    IVs
    '; var totalev = 0; if (!set.ivs) set.ivs = {}; for (var i in stats) { if (typeof set.ivs[i] === 'undefined') set.ivs[i] = 31; var val = ''+(set.ivs[i]); buf += '
    '; } //buf += '
    '+''+'
    '; buf += '
    '; buf += '

    Nature:

    '; buf += '

    Protip: You can also set natures by typing "+" and "-" next to a stat.

    '; buf += '
    '; this.$chart.html(buf); }, updateDetailsForm: function() { var buf = ''; var set = this.curSet; var template = Tools.getTemplate(set.species); if (!set) return; buf += '

    Details

    '; buf += '
    '; buf += '
    '; buf += '
    '; if (template.gender) { var genderTable = {'M': "Male", 'F': "Female", 'N': "Genderless"}; buf += genderTable[template.gender]; } else { buf += ' '; buf += ' '; buf += ''; } buf += '
    '; buf += '
    '; buf += '
    '; buf += ' '; buf += ''; buf += '
    '; buf += '
    '; this.$chart.html(buf); }, arrangeCallback: { pokemon: function(pokemon) { if (!pokemon) { if (this.curTeam) { if (this.curTeam.format === 'uber') return ['Uber','OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'cap') return ['G5CAP','G4CAP','OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'ou') return ['OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'uu') return ['UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'ru') return ['RU','BL3','NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'nu') return ['NU','NFE','LC Uber','LC']; if (this.curTeam.format === 'lc') return ['LC','NU']; } return ['OU','Unreleased','Uber','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC','G5CAP','G4CAP']; } var tierData = exports.BattleFormatsData[toId(pokemon.species)]; if (!tierData) return 'Limbo'; return tierData.tier; }, item: function(item) { if (!item) return ['Items']; return 'Items'; }, ability: function(ability) { if (!this.curSet) return; if (!ability) return ['Abilities', 'Dream World Ability']; var template = Tools.getTemplate(this.curSet.species); if (!template.abilities) return 'Abilities'; if (ability.name === template.abilities['0']) return 'Abilities'; if (ability.name === template.abilities['1']) return 'Abilities'; if (ability.name === template.abilities['DW']) return 'Dream World Ability'; return 'Illegal'; }, move: function(move) { if (!this.curSet) return; if (!move) return ['Viable Moves', 'Usable Moves', 'Moves', 'Usable Sketch Moves', 'Sketch Moves']; var id = toId(this.curSet.species); var movelist = selfR.movelists[id]; if (!movelist) return 'Illegal'; if (!movelist[move.id]) { if (movelist['sketch']) { if (move.isViable) return 'Usable Sketch Moves'; else if (move.id !== 'chatter' && move.id !== 'struggle') return 'Sketch Moves'; } return 'Illegal'; } if (BattleFormatsData && BattleFormatsData[id] && BattleFormatsData[id].viableMoves && BattleFormatsData[id].viableMoves[move.id]) return 'Viable Moves'; if (move.isViable) return 'Usable Moves'; return 'Moves'; } }, selectPokemon: function(i) { i = +i; var set = this.curTeam.team[i]; if (set) { this.curSet = set; this.curSetLoc = i; this.update(); } }, stats: function(i, button) { if (!this.curSet) this.selectPokemon($(button).closest('li').val()); this.curChartType = 'stats'; this.updateStatForm(); }, details: function(i, button) { if (!this.curSet) this.selectPokemon($(button).closest('li').val()); this.curChartType = 'details'; this.updateDetailsForm(); }, chartTypes: { pokemon: 'pokemon', item: 'item', ability: 'ability', move1: 'move', move2: 'move', move3: 'move', move4: 'move', stats: 'stats', details: 'details' }, chartKeydown: function() { // }, chartFocus: function(e) { var $target = $(e.currentTarget); var name = e.currentTarget.name; var type = this.chartTypes[name]; if (!this.curSet) { var i = +$target.closest('li').prop('value'); this.curSet = this.curTeam.team[i]; this.curSetLoc = i; this.update(); if (type === 'stats' || type === 'details') { this.$('button[name='+name+']').click(); } else { this.$('input[name='+name+']').select(); } return; } this.curChartName = name; this.curChartType = type; this.updateChart(); }, chartChange: function(e) { var name = e.currentTarget.name; var type = this.chartTypes[name]; var val = Chart.firstResult; var id = toId(e.currentTarget.value); if (toId(val) !== id) { $(e.currentTarget).addClass('incomplete'); return; } e.currentTarget.value = val; switch (name) { case 'pokemon': // selfR.formChangePokemon(val); break; case 'item': if (val || e.currentTarget.value === '') { this.curSet.item = val; // selfR.updatePokemonSprite(); } break; case 'ability': if (val) { this.curSet.ability = val; } break; case 'move1': if (val || e.currentTarget.value === '') { this.curSet.moves[0] = val; // selfR.formChooseMove(val); } break; case 'move2': if (!this.curSet.moves[0]) this.curSet.moves[0] = ''; if (val || e.currentTarget.value === '') { this.curSet.moves[1] = val; // selfR.formChooseMove(val); } break; case 'move3': if (!this.curSet.moves[0]) this.curSet.moves[0] = ''; if (!this.curSet.moves[1]) this.curSet.moves[1] = ''; if (val || e.currentTarget.value === '') { this.curSet.moves[2] = val; // selfR.formChooseMove(val); } break; case 'move4': if (!this.curSet.moves[0]) this.curSet.moves[0] = ''; if (!this.curSet.moves[1]) this.curSet.moves[1] = ''; if (!this.curSet.moves[2]) this.curSet.moves[2] = ''; if (val || e.currentTarget.value === '') { this.curSet.moves[3] = val; // selfR.formChooseMove(val); } break; } }, /********************************************************* * Utility functions *********************************************************/ // text import/export parseText: function(text, teams) { var text = text.split("\n"); var team = []; var curSet = null; if (teams === true) { app.user.teams = []; teams = app.user.teams; } for (var i=0; i= 0) { format = line.substr(1, bracketIndex-1); line = $.trim(line.substr(bracketIndex+1)); } teams.push({ name: line, format: format, team: team }); } else if (!curSet) { curSet = {name: '', species: '', gender: ''}; team.push(curSet); var atIndex = line.lastIndexOf(' @ '); if (atIndex !== -1) { curSet.item = line.substr(atIndex+3); line = line.substr(0, atIndex); } if (line.substr(line.length-4) === ' (M)') { curSet.gender = 'M'; line = line.substr(0, line.length-4); } if (line.substr(line.length-4) === ' (F)') { curSet.gender = 'F'; line = line.substr(0, line.length-4); } var parenIndex = line.lastIndexOf(' ('); if (line.substr(line.length-1) === ')' && parenIndex !== -1) { line = line.substr(0, line.length-1); curSet.species = line.substr(parenIndex+2); line = line.substr(0, parenIndex); curSet.name = line; } else { curSet.name = line; curSet.species = line; } } else if (line.substr(0, 7) === 'Trait: ') { line = line.substr(7); curSet.ability = line; } else if (line === 'Shiny: Yes') { curSet.shiny = true; } else if (line.substr(0, 7) === 'Level: ') { line = line.substr(7); curSet.level = +line; } else if (line.substr(0, 11) === 'Happiness: ') { line = line.substr(11); curSet.happiness = +line; } else if (line.substr(0, 9) === 'Ability: ') { line = line.substr(9); curSet.ability = line; } else if (line.substr(0, 5) === 'EVs: ') { line = line.substr(5); var evLines = line.split('/'); curSet.evs = {hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0}; for (var j=0; j 95); var physicalBulk = (stats.hp+75)*(stats.def+87); var specialBulk = (stats.hp+75)*(stats.spd+87); if (hasMove['willowisp'] || hasMove['acidarmor'] || hasMove['irondefense'] || hasMove['cottonguard']) { physicalBulk *= 1.6; moveCount['PhysicalStall']++; } else if (hasMove['scald'] || hasMove['bulkup'] || hasMove['coil'] || hasMove['cosmicpower']) { physicalBulk *= 1.3; if (hasMove['scald']) { // partial stall goes in reverse moveCount['SpecialStall']++; } else { moveCount['PhysicalStall']++; } } if (abilityid === 'flamebody') physicalBulk *= 1.1; if (hasMove['calmmind'] || hasMove['quiverdance']) { specialBulk *= 1.3; moveCount['SpecialStall']++; } if (template.id === 'tyranitar') specialBulk *= 1.5; if (hasMove['bellydrum']) { physicalBulk *= 0.6; specialBulk *= 0.6; } if (moveCount['Restoration']) { physicalBulk *= 1.5; specialBulk *= 1.5; } else if (hasMove['painsplit'] && hasMove['substitute']) { // SubSplit isn't generally a stall set moveCount['Stall']--; } else if (hasMove['painsplit'] || hasMove['rest']) { physicalBulk *= 1.4; specialBulk *= 1.4; } if ((hasMove['bodyslam'] || hasMove['thunder']) && abilityid === 'serenegrace' || hasMove['thunderwave']) { physicalBulk *= 1.1; specialBulk *= 1.1; } if ((hasMove['ironhead'] || hasMove['airslash']) && abilityid === 'serenegrace') { physicalBulk *= 1.1; specialBulk *= 1.1; } if (hasMove['gigadrain'] || hasMove['drainpunch'] || hasMove['hornleech']) { physicalBulk *= 1.15; specialBulk *= 1.15; } if (itemid === 'leftovers' || itemid === 'blacksludge') { physicalBulk *= 1 + 0.1*(1+moveCount['Stall']/1.5); specialBulk *= 1 + 0.1*(1+moveCount['Stall']/1.5); } if (hasMove['leechseed']) { physicalBulk *= 1 + 0.1*(1+moveCount['Stall']/1.5); specialBulk *= 1 + 0.1*(1+moveCount['Stall']/1.5); } if ((itemid === 'flameorb' || itemid === 'toxicorb') && abilityid !== 'magicguard') { if (itemid === 'toxicorb' && abilityid === 'poisonheal') { physicalBulk *= 1 + 0.1*(2+moveCount['Stall']); specialBulk *= 1 + 0.1*(2+moveCount['Stall']); } else { physicalBulk *= 0.8; specialBulk *= 0.8; } } if (itemid === 'lifeorb') { physicalBulk *= 0.9; specialBulk *= 0.9; } if (abilityid === 'multiscale' || abilityid === 'magicguard' || abilityid === 'regenerator') { physicalBulk *= 1.4; specialBulk *= 1.4; } if (itemid === 'eviolite') { physicalBulk *= 1.5; specialBulk *= 1.5; } var bulk = physicalBulk + specialBulk; if (bulk < 46000 && stats.spe >= 70) isFast = true; moveCount['bulk'] = bulk; moveCount['physicalBulk'] = physicalBulk; moveCount['specialBulk'] = specialBulk; if (hasMove['agility'] || hasMove['dragondance'] || hasMove['quiverdance'] || hasMove['rockpolish'] || hasMove['shellsmash'] || hasMove['flamecharge']) { isFast = true; } else if (abilityid === 'unburden' || abilityid === 'speedboost' || abilityid === 'motordrive') { isFast = true; moveCount['Ultrafast'] = 1; } else if (abilityid === 'chlorophyll' || abilityid === 'swiftswim' || abilityid === 'sandrush') { isFast = true; moveCount['Ultrafast'] = 2; } if (hasMove['agility'] || hasMove['shellsmash'] || hasMove['autotomize'] || hasMove['shiftgear'] || hasMove['rockpolish']) moveCount['Ultrafast'] = 2; moveCount['Fast'] = isFast?1:0; this.moveCount = moveCount; this.hasMove = hasMove; if (template.id === 'ditto') return abilityid==='imposter'?'Physically Defensive':'Fast Bulky Support'; if (template.id === 'shedinja') return 'Fast Physical Sweeper'; if (itemid === 'choiceband' && moveCount['PhysicalAttack'] >= 2) { if (!isFast) return 'Bulky Band'; return 'Fast Band'; } else if (itemid === 'choicespecs' && moveCount['SpecialAttack'] >= 2) { if (!isFast) return 'Bulky Specs'; return 'Fast Specs'; } else if (itemid === 'choicescarf') { if (moveCount['PhysicalAttack'] === 0) return 'Special Scarf'; if (moveCount['SpecialAttack'] === 0) return 'Physical Scarf'; if (moveCount['PhysicalAttack'] > moveCount['SpecialAttack']) return 'Physical Biased Mixed Scarf'; if (moveCount['PhysicalAttack'] < moveCount['SpecialAttack']) return 'Special Biased Mixed Scarf'; if (stats.atk < stats.spa) return 'Special Biased Mixed Scarf'; return 'Physical Biased Mixed Scarf'; } if (template.id === 'unown') return 'Fast Special Sweeper'; if (moveCount['PhysicalStall'] && moveCount['Restoration']) { return 'Specially Defensive'; } if (moveCount['SpecialStall'] && moveCount['Restoration']) { return 'Physically Defensive'; } var offenseBias = ''; if (stats.spa > stats.atk && moveCount['Special'] > 1) offenseBias = 'Special'; else if (stats.spa > stats.atk && moveCount['Special'] > 1) offenseBias = 'Special'; else if (moveCount['Special'] > moveCount['Physical']) offenseBias = 'Special'; else offenseBias = 'Physical'; var offenseStat = stats[offenseBias === 'Special'?'spa':'atk']; if (moveCount['Stall'] + moveCount['Support'] <= 2 && bulk < 135000 && moveCount[offenseBias] >= 2) { if (isFast) { if (bulk > 80000 && !moveCount['Ultrafast']) return 'Bulky '+offenseBias+' Sweeper'; return 'Fast '+offenseBias+' Sweeper'; } else { if (moveCount[offenseBias] >= 3 || moveCount['Stall'] <= 0) { return 'Bulky '+offenseBias+' Sweeper'; } } } if (isFast) { if (stats.spe > 100 || bulk < 55000 || moveCount['Ultrafast']) { return 'Fast Bulky Support'; } } if (moveCount['SpecialStall']) return 'Physically Defensive'; if (moveCount['PhysicalStall']) return 'Specially Defensive'; if (template.id === 'blissey' || template.id === 'chansey') return 'Physically Defensive'; if (specialBulk >= physicalBulk) return 'Specially Defensive'; return 'Physically Defensive'; }, ensureMinEVs: function(evs, stat, min, evTotal) { if (!evs[stat]) evs[stat] = 0; var diff = min - evs[stat]; if (diff <= 0) return evTotal; if (evTotal <= 504) { var change = Math.min(508 - evTotal, diff); evTotal += change; evs[stat] += change; diff -= change; } if (diff <= 0) return evTotal; var evPriority = {def:1, spd:1, hp:1, atk:1, spa:1, spe:1}; for (var i in evPriority) { if (i === stat) continue; if (evs[i] && evs[i] > 128) { evs[i] -= diff; evs[stat] += diff; return evTotal; } } return evTotal; // can't do it :( }, ensureMaxEVs: function(evs, stat, min, evTotal) { if (!evs[stat]) evs[stat] = 0; var diff = evs[stat] - min; if (diff <= 0) return evTotal; evs[stat] -= diff; evTotal -= diff; return evTotal; // can't do it :( }, guessEVs: function(role) { var set = this.curSet; if (!set) return {}; var template = Tools.getTemplate(set.species || set.name); var stats = template.baseStats; var hasMove = this.hasMove; var moveCount = this.moveCount; var evs = {}; var plusStat = ''; var minusStat = ''; var statChart = { 'Bulky Band': ['atk', 'hp'], 'Fast Band': ['spe', 'atk'], 'Bulky Specs': ['spa', 'hp'], 'Fast Specs': ['spe', 'spa'], 'Physical Scarf': ['atk', 'spe'], 'Special Scarf': ['spa', 'spe'], 'Physical Biased Mixed Scarf': ['atk', 'spe'], 'Special Biased Mixed Scarf': ['spa', 'spe'], 'Fast Physical Sweeper': ['spe', 'atk'], 'Fast Special Sweeper': ['spe', 'spa'], 'Bulky Physical Sweeper': ['atk', 'hp'], 'Bulky Special Sweeper': ['spa', 'hp'], 'Fast Bulky Support': ['spe', 'hp'], 'Physically Defensive': ['def', 'hp'], 'Specially Defensive': ['spd', 'hp'] }; plusStat = statChart[role][0]; if (role === 'Fast Bulky Support') moveCount['Ultrafast'] = 0; if (plusStat === 'spe' && (moveCount['Ultrafast'] || evs['spe'] < 252)) { if (statChart[role][1] === 'atk' || statChart[role][1] == 'spa') { plusStat = statChart[role][1]; } else if (moveCount['Physical'] >= 3) { plusStat = 'atk'; } else if (stats.spd > stats.def) { plusStat = 'spd'; } else { plusStat = 'def'; } } if (this.curTeam && (this.curTeam.format === 'hackmons' || this.curTeam.format === 'balancedhackmons')) { evs = {hp:252, atk:252, def:252, spa:252, spd:252, spe:252}; if (hasMove['gyroball'] || hasMove['trickroom']) delete evs.spe; } else { if (!statChart[role]) return {}; var evTotal = 0; var i = statChart[role][0]; var stat = this.getStat(i, null, 252, plusStat===i?1.1:1.0); var ev = 252; while (stat <= this.getStat(i, null, ev-4, plusStat===i?1.1:1.0)) ev -= 4; evs[i] = ev; evTotal += ev; var i = statChart[role][1]; if (i === 'hp' && set.level && set.level < 20) i = 'spd'; var stat = this.getStat(i, null, 252, plusStat===i?1.1:1.0); var ev = 252; if (i === 'hp' && (hasMove['substitute'] || hasMove['transform']) && stat == Math.floor(stat/4)*4) stat -= 1; while (stat <= this.getStat(i, null, ev-4, plusStat===i?1.1:1.0)) ev -= 4; evs[i] = ev; evTotal += ev; if (template.id === 'tentacruel') evTotal = this.ensureMinEVs(evs, 'spe', 16, evTotal); if (template.id === 'skarmory') evTotal = this.ensureMinEVs(evs, 'spe', 24, evTotal); if (template.id === 'jirachi') evTotal = this.ensureMinEVs(evs, 'spe', 32, evTotal); if (template.id === 'celebi') evTotal = this.ensureMinEVs(evs, 'spe', 36, evTotal); if (template.id === 'volcarona') evTotal = this.ensureMinEVs(evs, 'spe', 52, evTotal); if (template.id === 'gliscor') evTotal = this.ensureMinEVs(evs, 'spe', 72, evTotal); if (stats.spe == 97) evTotal = this.ensureMaxEVs(evs, 'spe', 220, evTotal); if (template.id === 'dragonite' && evs['hp']) evTotal = this.ensureMaxEVs(evs, 'spe', 220, evTotal); if (evTotal < 508) { var remaining = 508 - evTotal; if (!evs['atk'] && moveCount['PhysicalAttack']) { evs['atk'] = remaining; } else if (!evs['spa'] && moveCount['SpecialAttack']) { evs['spa'] = remaining; } else if (stats.hp == 1 && !evs['def']) { evs['def'] = remaining; } else if (stats.def === stats.spd && !evs['spd']) { evs['spd'] = remaining; } else if (!evs['hp'] && !(set.level && set.level < 20)) { evs['hp'] = remaining; } else if (!evs['spd']) { evs['spd'] = remaining; } else if (!evs['def']) { evs['def'] = remaining; } } } if (hasMove['gyroball'] || hasMove['trickroom']) { minusStat = 'spe'; } else if (!moveCount['PhysicalAttack']) { minusStat = 'atk'; } else if (!moveCount['SpecialAttack']) { minusStat = 'spa'; } else if (stats.def > stats.spd) { minusStat = 'spd'; } else { minusStat = 'def'; } evs.plusStat = plusStat; evs.minusStat = minusStat; return evs; }, // Stat calculator getStat: function(stat, set, evOverride, natureOverride) { if (!set) set = this.curSet; if (!set) return 0; var template = Tools.getTemplate(set.species); if (!template.exists) return 0; if (!set.ivs) set.ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 }; if (!set.evs) set.evs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 }; if (!set.level) set.level = 100; if (typeof set.ivs[stat] === 'undefined') set.ivs[stat] = 31; if (stat === 'hp') { if (template.baseStats['hp'] === 1) return 1; return Math.floor(Math.floor(2*template.baseStats['hp']+(set.ivs['hp']||0)+Math.floor((evOverride||set.evs['hp']||0)/4)+100)*set.level / 100 + 10); } var val = Math.floor(Math.floor(2*template.baseStats[stat]+(set.ivs[stat]||0)+Math.floor((evOverride||set.evs[stat]||0)/4))*set.level / 100 + 5); if (natureOverride) { val *= natureOverride; } else if (BattleNatures[set.nature] && BattleNatures[set.nature].plus === stat) { val *= 1.1; } else if (BattleNatures[set.nature] && BattleNatures[set.nature].minus === stat) { val *= 0.9; } return Math.floor(val); }, // initialization buildMovelists: function() { Tools.movelists = {}; for (var pokemon in window.BattlePokedex) { var template = Tools.getTemplate(pokemon); var moves = {}; var alreadyChecked = {}; do { alreadyChecked[template.speciesid] = true; if (template.learnset) { for (var l in template.learnset) { moves[l] = true; } } if (template.speciesid === 'shaymin') { template = Tools.getTemplate('shayminsky'); } else if (toId(template.baseSpecies) !== toId(template.species) && toId(template.baseSpecies) !== 'kyurem') { template = Tools.getTemplate(template.baseSpecies); } else { template = Tools.getTemplate(template.prevo); } } while (template && template.species && !alreadyChecked[template.speciesid]); Tools.movelists[pokemon] = moves; } } }, { // static saveTeams: function() { if (window.localStorage) { $.cookie('showdown_team1', null); $.cookie('showdown_team2', null); $.cookie('showdown_team3', null); localStorage.setItem('showdown_teams', JSON.stringify(teams)); } else { if (teams[0]) { $.cookie('showdown_team1', null); $.cookie('showdown_team1', $.toJSON(teams[0]),{expires:60,domain:'pokemonshowdown.com'}); } else { $.cookie('showdown_team1', null); $.cookie('showdown_team1', null, {domain:'pokemonshowdown.com'}); } if (teams[1]) { $.cookie('showdown_team2', null); $.cookie('showdown_team2', $.toJSON(teams[1]),{expires:60,domain:'pokemonshowdown.com'}); } else { $.cookie('showdown_team2', null); $.cookie('showdown_team2', null, {domain:'pokemonshowdown.com'}); } $.cookie('showdown_team3', null); } } }); }).call(this, jQuery);