function Teambuilder(id, elem) { var selfR = this; this.id = id; this.elem = elem; if (window.me) { this.meIdent = {name: me.name, named: 'init'}; me.rooms[id] = {}; this.me = me.rooms[id]; } this.activeTeam = null; this.activeTeamIndex = -1; this.activePokemon = null; this.activePokemonIndex = -1; this.activeChart = null; this.exportMode = false; this.exportAllMode = false; this.movelists = {}; elem.html('
'); this.teamListElem = elem.find('.teamlist'); this.saveButtonElem = elem.find('.savebutton'); this.teamBuilderElem = elem.find('.teambuilder'); this.teamEditElem = null; this.teamNameEditElem = null; this.focus = function() { if (!selfR.movelists.bulbasaur) selfR.buildMovelists(); selfR.updateMe(); }; this.init = function(data) { selfR.update(data); selfR.updateMe(); selfR.updateMainElem(); }; this.message = function(message) { rooms.lobby.message(message); }; this.send = function (message) { emit(me.socket, 'chat', {room:'',message:message}); }; this.update = function(data) { if (!data) { selfR.updateMainElem(); return; } if (data.team === 'saved') { //alert('saved'); } selfR.updateMainElem(); }; this.updateMainElem = function() { var text = ''; if (selfR.activeTeam) { if (selfR.activePokemon) { text = ' '; text += '
'; var isAdd = false; if (selfR.activeTeam.team.length && !selfR.activeTeam.team[selfR.activeTeam.team.length-1].name && selfR.activePokemonIndex !== selfR.activeTeam.team.length-1) { selfR.activeTeam.team.splice(selfR.activeTeam.team.length-1, 1); } for (var i=0; i'; if (!set.name) { text += ' '; isAdd = true; } else if (i == selfR.activePokemonIndex) { text += ' '; } else { text += ' '; } } if (selfR.activeTeam.team.length < 6 && !isAdd) { text += ' '; } text += '
'; } else { text = ' '; } if (selfR.exportMode) { text += ''; } else { text += '
'; text += '
    '; var i=0; if (!selfR.activePokemon && selfR.activeTeam.team.length && !selfR.activeTeam.team[selfR.activeTeam.team.length-1].species) { selfR.activeTeam.team.splice(selfR.activeTeam.team.length-1, 1); } if (exports.BattleFormats && !selfR.activePokemon) { text += '
  1. '; } if (!selfR.activeTeam.team.length) { text += '
  2. you have no pokemon lol
  3. '; } for (i=0; i'; if (!set.species) { text += '
    '; text += ''; if (selfR.activePokemon) { break; } continue; } text += '
    '; text += ''; text += '
    '; text += '
    '; // icon var itemicon = ''; if (set.item) { var item = Tools.getItem(set.item); itemicon = ''; } text += '
    '+itemicon+'
    '; // details text += '
    '; text += '
    '; text += '
    '; text += '
    '; text += '
    '; text += '
    '; // moves if (!set.moves) set.moves = []; text += '
    '; text += '
    '; text += '
    '; text += '
    '; text += '
    '; text += '
    '; // stats text += '
    '; text += '
    '; if (selfR.activePokemon) { break; } } if (!selfR.activePokemon && i < 6) { text += '
  4. '; } text += '
'; text += '
'; } if (selfR.activePokemon) { text += '
'; selfR.chartPrevSearch = '[init]'; } selfR.teamBuilderElem.html(text); selfR.teamEditElem = elem.find('.teamedit'); selfR.teamNameEditElem = elem.find('.teamnameedit'); selfR.chartElem = $('#'+selfR.id+'-results'); var curInput = selfR.teamBuilderElem.find('input.chartinput'); curInput.focus(selfR.formChartFocus); curInput.change(selfR.formChartChange); curInput.keyup(selfR.formChartKeyUp); curInput.keydown(selfR.formChartKeyDown); //selfR.teamBuilderElem.html(text); selfR.teamListElem.hide(); selfR.teamBuilderElem.show(); } else if (selfR.exportAllMode) { text = ' '; text += ''; selfR.teamListElem.html(text); selfR.teamListElem.show(); selfR.teamBuilderElem.hide(); selfR.teamEditElem = elem.find('.teamedit'); } else { text = '

lol zarel this is a horrible teambuilder

' text += '

i know stfu im not done with it

' text += ''; text += ''; text += ' '; text += '

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 && cookieTeams) { text += ' WARNING: Additional teams WILL NOT BE SAVED.'; } selfR.teamListElem.html(text); selfR.teamListElem.show(); selfR.teamBuilderElem.hide(); } }; this.chartTimeout = null; this.chartPrevSearch = '[init]'; this.arrangeCallback = { pokemon: function(pokemon) { if (!pokemon) { if (selfR.activeTeam) { if (selfR.activeTeam.format === 'uber') return ['Uber','OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (selfR.activeTeam.format === 'cap') return ['G5CAP','G4CAP','OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (selfR.activeTeam.format === 'ou') return ['OU','BL','UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (selfR.activeTeam.format === 'uu') return ['UU','BL2','RU','BL3','NU','NFE','LC Uber','LC']; if (selfR.activeTeam.format === 'ru') return ['RU','BL3','NU','NFE','LC Uber','LC']; if (selfR.activeTeam.format === 'nu') return ['NU','NFE','LC Uber','LC']; if (selfR.activeTeam.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 (!selfR.activePokemon) return; var template = Tools.getTemplate(selfR.activePokemon.species); if (!ability) return ['Abilities', 'Dream World Ability']; 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 (!selfR.activePokemon) return; if (!move) return ['Viable Moves', 'Usable Moves', 'Moves', 'Usable Sketch Moves', 'Sketch Moves']; var id = toId(selfR.activePokemon.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 (exports.BattleFormatsData && exports.BattleFormatsData[id] && exports.BattleFormatsData[id].viableMoves && exports.BattleFormatsData[id].viableMoves[move.id]) return 'Viable Moves'; if (move.isViable) return 'Usable Moves'; return 'Moves'; } }; this.getStat = function(stat, set, evOverride, natureOverride) { if (!set) set = selfR.activePokemon; 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); }; this.formChangeDetails = function() { var set = selfR.activePokemon; if (!set) return; var level = parseInt($('#'+selfR.id+'-level').val(),10); if (!level || level > 100 || level < 1) level = 100; if (level !== 100 || set.level) set.level = level; var happiness = parseInt($('#'+selfR.id+'-happiness').val(),10); if (happiness > 255) happiness = 255; if (happiness < 0) happiness = 255; if (happiness !== 255 || set.happiness || set.happiness === 0) set.happiness = happiness; var shiny = ($('#'+selfR.id+'-shiny-yes').length && $('#'+selfR.id+'-shiny-yes')[0].checked); if (shiny) set.shiny = true; else delete set.shiny; if ($('#'+selfR.id+'-gender-m').length && $('#'+selfR.id+'-gender-m')[0].checked) { set.gender = 'M'; } else if ($('#'+selfR.id+'-gender-f').length && $('#'+selfR.id+'-gender-f')[0].checked) { set.gender = 'F'; } else if ($('#'+selfR.id+'-gender-n').length && $('#'+selfR.id+'-gender-n')[0].checked) { //set.gender = 'N'; delete set.gender; } selfR.updateDetails(); }; this.formChangePokemon = function(val) { var template = Tools.getTemplate(val); var newPokemon = !selfR.activePokemon.species; if (template.exists) { if (!selfR.activePokemon.species || selfR.activePokemon.name === selfR.activePokemon.species) { selfR.activePokemon.name = ''; } selfR.activePokemon.species = val; if (selfR.activeTeam && selfR.activeTeam.format === 'lc' && !selfR.activePokemon.level) selfR.activePokemon.level = 5; if (template.id === 'garchomp') { selfR.activePokemon.ability = ''; } else { selfR.activePokemon.ability = template.abilities['0']; } if (template.gender) { selfR.activePokemon.gender = template.gender; } else if (selfR.activePokemon.gender === 'N') { delete selfR.activePokemon.gender; } if (!selfR.activePokemon.name) { selfR.activePokemon.name = template.species; } selfR.updateMainElem(); selfR.updateDetails(); $('input[name=ability]').val(selfR.activePokemon.ability); selfR.teamBuilderElem.find('input[name=item]').select(); } }; this.updateDetailsForm = function() { var text = ''; var set = selfR.activePokemon; var template = Tools.getTemplate(set.species); if (!set) return; text += '

Details

'; text += '
'; text += '
'; text += '
'; if (template.gender) { var genderTable = {'M': "Male", 'F': "Female", 'N': "Genderless"}; text += genderTable[template.gender]; } else { text += ' '; text += ' '; text += ''; } text += '
'; text += '
'; text += '
'; text += ' '; text += ''; text += '
'; text += '
'; selfR.chartElem.html(text); /* var curInput = selfR.teamBuilderElem.find('input.numform'); curInput.keyup(selfR.formStatKeyUp); curInput.keydown(selfR.formStatKeyDown); */ }; this.guessRole = function() { var set = selfR.activePokemon; if (!set) return '?'; if (!set.moves) return '?'; var moveCount = { 'Physical': 0, 'Special': 0, 'PhysicalOffense': 0, 'SpecialOffense': 0, 'PhysicalSetup': 0, 'SpecialSetup': 0, 'Support': 0, 'Setup': 0, 'Restoration': 0, 'Offense': 0, 'Stall': 0, 'SpecialStall': 0, 'PhysicalStall': 0, 'Ultrafast': 0 }; var hasMove = {}; var template = Tools.getTemplate(set.species || set.name); var stats = template.baseStats; var itemid = toId(set.item); var abilityid = toId(set.ability); if (set.moves.length < 4 && template.id !== 'unown' && template.id !== 'ditto') return '?'; for (var i=0,len=set.moves.length; i 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'; }; this.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 :( }; this.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 :( }; this.guessEVs = function(role) { var set = selfR.activePokemon; 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 (selfR.activeTeam && (selfR.activeTeam.format === 'hackmons' || selfR.activeTeam.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; }; this.updateStatForm = function(setGuessed) { var text = ''; var set = selfR.activePokemon; text += '

EVs

'; text += '
'; var role = selfR.guessRole(); var guessedEVs = {}; var guessedPlus = ''; var guessedMinus = ''; text += '

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

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

'; } if (setGuessed) { set.evs = guessedEVs; selfR.plus = guessedPlus; selfR.minus = guessedMinus; selfR.updateNature(); } var stats = {hp:'',atk:'',def:'',spa:'',spd:'',spe:''}; if (!set) return; var nature = BattleNatures[set.nature || 'Serious']; if (!nature) nature = {}; // label column text += '
'; text += '
'; text += '
'; text += '
'; for (var i in stats) { stats[i] = selfR.getStat(i); text += '
'+stats[i]+'
'; } text += '
'; text += '
'; 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; text += '
'; } text += '
Remaining:
'; text += '
'; text += '
EVs
'; var totalev = 0; selfR.plus = ''; selfR.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 += '+'; selfR.plus = i; } if (nature.minus === i) { val += '-'; selfR.minus = i; } text += '
'; totalev += (set.evs[i]||0); } if (totalev <= 510) { text += '
'+(totalev>508?0:508-totalev)+'
'; } else { text += '
'+(510-totalev)+'
'; } text += '
'; text += '
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]); text += '
'; } //text += '
'+''+'
'; text += '
'; text += '

Nature:

'; text += '

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

'; text += '
'; selfR.chartElem.html(text); var curInput = selfR.teamBuilderElem.find('input.numform'); curInput.keyup(selfR.formStatKeyUp); curInput.keydown(selfR.formStatKeyDown); }; this.formChangeNature = function(nature) { var set = selfR.activePokemon; if (!set) return; if (nature) { set.nature = nature; selfR.plus = ''; selfR.minus = ''; } nature = BattleNatures[set.nature||'Serious']; for (var i in BattleStatNames) { var val = ''+(set.evs[i]||''); if (nature.plus === i) { selfR.plus = i; } if (selfR.plus === i) { val += '+'; } if (nature.minus === i) { selfR.minus = i; } if (selfR.minus === i) { val += '-'; } selfR.chartElem.find('input[name=stat-'+i+']').val(val); } selfR.updateStatGraph(); }; this.updatePokemonSprite = function() { var set = selfR.activePokemon; if (!set) return; var shiny = (set.shiny?'-shiny':''); var sprite = Tools.getTemplate(set.species).spriteid; if (BattlePokemonSprites && BattlePokemonSprites[sprite] && BattlePokemonSprites[sprite].front && BattlePokemonSprites[sprite].front.anif && set.gender === 'F') { sprite+='-f'; } $('#'+selfR.id+'-pokemonicon').css('background-image', Tools.getTeambuilderSprite(set).substr(17)); $('#pokemonicon-'+selfR.activePokemonIndex).css('background', Tools.getIcon(set).substr(11)); var item = Tools.getItem(set.item); if (item.id) { $('#'+selfR.id+'-itemicon').css('background', Tools.getItemIcon(item).substr(11)); } else { $('#'+selfR.id+'-itemicon').css('background', 'none'); } selfR.updateStatGraph(); }; this.updateStatGraph = function() { var text = '
'; var stats = {hp:'',atk:'',def:'',spa:'',spd:'',spe:''}; var set = selfR.activePokemon; if (!set) return; for (var i in stats) { stats[i] = selfR.getStat(i); text += '
'+stats[i]+'
'; } $('#'+selfR.id+'-statscol').html(text); text = '
'; var totalev = 0; 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 color = Math.floor(stats[i]*180/714); if (color>360) color = 360; text += '
'; totalev += (set.evs[i]||0); } text += '
Remaining:
'; $('#'+selfR.id+'-graphcol').html(text); if (totalev <= 510) { $('#'+selfR.id+'-totalev').html(''+(totalev>508?0:508-totalev)+''); } else { $('#'+selfR.id+'-totalev').html(''+(510-totalev)+''); } $('#'+selfR.id+'-nature').val(set.nature||'Serious'); text = ' EV'; for (var j in BattleStatNames) { var ev = ''+(set.evs[j] || '')+''; if (BattleNatures[set.nature] && BattleNatures[set.nature].plus === j) { ev += '+'; } else if (BattleNatures[set.nature] && BattleNatures[set.nature].minus === j) { ev += ''; } var width = stats[j]*75/504; if (j=='hp') width = stats[j]*75/704; if (width>75) width = 75; var color = Math.floor(stats[j]*180/714); if (color>360) color = 360; text += ' '+ev+''; } $('#'+selfR.id+'-setstats').html(text); }; this.updateDetails = function() { var set = selfR.activePokemon; if (!set) return; var text = ''; var GenderChart = { 'M': 'Male', 'F': 'Female', 'N': '—' }; text += ''+(set.level||100)+''; text += ''+GenderChart[set.gender||'N']+''; text += ''+(typeof set.happiness==='number'?set.happiness:255)+''; text += ''+(set.shiny?'Yes':'No')+''; $('#'+selfR.id+'-setdetails').html(text); selfR.updatePokemonSprite(); }; this.formStatKeyDown = function(e) { var inputName = $(e.target).prop('name'); // like I remember how to do this outside of jQuery modifier = (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey || e.cmdKey); switch (inputName) { case 'stat-hp': if (e.keyCode === 9 && e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && !e.cmdKey) { e.stopPropagation(); e.preventDefault(); var moveElem = selfR.teamBuilderElem.find('input[name=move1]'); if (moveElem.val()) moveElem = selfR.teamBuilderElem.find('input[name=move2]'); if (moveElem.val()) moveElem = selfR.teamBuilderElem.find('input[name=move3]'); if (moveElem.val()) moveElem = selfR.teamBuilderElem.find('input[name=move4]'); moveElem.select(); return; } if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-atk]').select(); return; } break; case 'stat-atk': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-def]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-hp]').select(); return; } break; case 'stat-def': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-spa]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-atk]').select(); return; } break; case 'stat-spa': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-spd]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-def]').select(); return; } break; case 'stat-spd': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-spe]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-spa]').select(); return; } break; case 'stat-spe': if (e.keyCode === 13) { e.stopPropagation(); e.preventDefault(); selfR.formBack(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=stat-spd]').select(); return; } break; case 'iv-hp': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-atk]').select(); return; } break; case 'iv-atk': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-def]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-hp]').select(); return; } break; case 'iv-def': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-spa]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-atk]').select(); return; } break; case 'iv-spa': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-spd]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-def]').select(); return; } break; case 'iv-spd': if (e.keyCode === 13 || (e.keyCode === 40 && !modifier)) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-spe]').select(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-spa]').select(); return; } break; case 'iv-spe': if (e.keyCode === 13) { e.stopPropagation(); e.preventDefault(); return; } if (e.keyCode === 38 && !modifier) { e.stopPropagation(); e.preventDefault(); selfR.chartElem.find('input[name=iv-spd]').select(); return; } break; } }; this.updateNature = function() { var set = selfR.activePokemon; if (!set) return; if (selfR.plus === '' || selfR.minus === '') set.nature = 'Serious'; else { for (var i in BattleNatures) { if (BattleNatures[i].plus === selfR.plus && BattleNatures[i].minus === selfR.minus) { set.nature = i; break; } } } }; this.formStatKeyUp = function(e) { var inputName = ''; inputName = $(e.target).prop('name'); // like I remember how to do this outside of jQuery var val = Math.abs(parseInt(e.target.value, 10)); var set = selfR.activePokemon; var lastchar = e.target.value.substr(e.target.value.length-1); var firstchar = e.target.value.substr(0,1); var stat = inputName.substr(5); var natureChange = true; if ((lastchar === '+' || firstchar === '+') && stat !== 'hp') { selfR.plus = stat; } else if ((lastchar === '-' || lastchar === "\u2212" || firstchar === '-' || firstchar === "\u2212") && stat !== 'hp') { selfR.minus = stat; } else if (selfR.plus === stat) { selfR.plus = ''; } else if (selfR.minus === stat) { selfR.minus = ''; } else { natureChange = false; } if (natureChange) { selfR.updateNature(); } if (!set) return; if (val > 252) val = 252; if (val < 0) val = 0; if (inputName.substr(0,3) === 'iv-') { if (val > 31) val = 31; } modifier = (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey || e.cmdKey); switch (inputName) { case 'stat-hp': if (!set.evs) set.evs = {}; if (set.evs.hp !== val) { set.evs.hp = val; selfR.updateStatGraph(); } break; case 'stat-atk': if (!set.evs) set.evs = {}; if (set.evs.atk !== val) { set.evs.atk = val; selfR.updateStatGraph(); } break; case 'stat-def': if (!set.evs) set.evs = {}; if (set.evs.def !== val) { set.evs.def = val; selfR.updateStatGraph(); } break; case 'stat-spa': if (!set.evs) set.evs = {}; if (set.evs.spa !== val) { set.evs.spa = val; selfR.updateStatGraph(); } break; case 'stat-spd': if (!set.evs) set.evs = {}; if (set.evs.spd !== val) { set.evs.spd = val; selfR.updateStatGraph(); } break; case 'stat-spe': if (!set.evs) set.evs = {}; if (set.evs.spe !== val) { set.evs.spe = val; selfR.updateStatGraph(); } break; case 'iv-hp': if (!set.ivs) set.ivs = {}; if (set.ivs.hp !== val) { set.ivs.hp = val; selfR.updateStatGraph(); } break; case 'iv-atk': if (!set.ivs) set.ivs = {}; if (set.ivs.atk !== val) { set.ivs.atk = val; selfR.updateStatGraph(); } break; case 'iv-def': if (!set.ivs) set.ivs = {}; if (set.ivs.def !== val) { set.ivs.def = val; selfR.updateStatGraph(); } break; case 'iv-spa': if (!set.ivs) set.ivs = {}; if (set.ivs.spa !== val) { set.ivs.spa = val; selfR.updateStatGraph(); } break; case 'iv-spd': if (!set.ivs) set.ivs = {}; if (set.ivs.spd !== val) { set.ivs.spd = val; selfR.updateStatGraph(); } break; case 'iv-spe': if (!set.ivs) set.ivs = {}; if (set.ivs.spe !== val) { set.ivs.spe = val; selfR.updateStatGraph(); } break; } }; this.updateChart = function(target, type, init) { if (selfR.chartTimeout) clearTimeout(selfR.chartTimeout); if (type === 'stats') { selfR.updateStatForm(); return; } if (type === 'details') { selfR.updateDetailsForm(); return; } selfR.chartTimeout = setTimeout(function() { if (!target) return; var search = target.value; if (search === selfR.chartPrevSearch) return; selfR.chartPrevSearch = search; selfR.chartElem.html(Chart.chart(search, type, init, selfR.arrangeCallback[type])); selfR.chartTimeout = null; }, init?0:200); }; this.updateMe = function() { }; this.parseText = function(text, teams) { var text = text.split("\n"); var team = []; var curSet = null; if (teams === true) { window.teams = []; teams = window.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= 0) { teams.splice(deletedTeamLoc,0,deletedTeam); deletedTeam = null; deletedTeamLoc = -1; selfR.formSave(); } }; this.formKeyPress = function() { //selfR.saveButtonElem[0].disabled = false; //selfR.saveButtonElem.html('Save'); }; this.formReset = function() { selfR.teamEditElem.val('Donphan (M) @ Custap Berry :: Trait: Sturdy :: EVs: 252 HP / 252 Atk / 4 Spd :: Adamant Nature (+Atk, -SAtk) :: - Earthquake :: - Ice Shard :: - Rapid Spin :: - Stealth Rock :: :: Venusaur (M) @ Life Orb :: Trait: Chlorophyll :: EVs: 44 HP / 4 Def / 252 SAtk / 208 Spd :: Modest Nature (+SAtk, -Atk) :: - Energy Ball :: - Hidden Power [Fire] :: - Sludge Bomb :: - Growth :: :: Sawsbuck (M) @ Life Orb :: Trait: Chlorophyll :: EVs: 72 HP / 252 Atk / 4 SDef / 180 Spd :: Adamant Nature (+Atk, -SAtk) :: - Horn Leech :: - Return :: - Nature Power :: - Swords Dance :: :: Ninetales (M) @ Air Balloon :: Trait: Drought :: EVs: 240 HP / 24 SAtk / 244 SDef :: Calm Nature (+SDef, -Atk) :: - Overheat :: - Will-O-Wisp :: - Sunny Day :: - Substitute :: :: Kingdra (M) @ Choice Specs :: Trait: Swift Swim :: EVs: 4 HP / 252 SAtk / 252 Spd :: Modest Nature (+SAtk, -Atk) :: - Draco Meteor :: - Hydro Pump :: - Hidden Power [Fighting] :: - Sleep Talk :: :: Darmanitan (M) @ Choice Scarf :: Trait: Sheer Force :: EVs: 4 HP / 252 Atk / 252 Spd :: Adamant Nature (+Atk, -SAtk) :: - Flare Blitz :: - Rock Slide :: - Superpower :: - U-turn'.replace(/ :: /g, "\n")); }; this.buildMovelists = function() { 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]); selfR.movelists[pokemon] = moves; } }; selfR.init(); } Teambuilder.writeTeams = 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); } }; var deletedTeam = null; var deletedTeamLoc = -1; var selectedTeam = -1; function selectTeam(i) { if (typeof i === 'undefined') i = -1; i = parseInt(i); //if (i === selectedTeam) return; if (i < 0) { rooms.lobby.send('/utm null'); } else { rooms.lobby.send('/utm '+$.toJSON(teams[i].team)); } // if (i < 0) { // emit(me.socket, 'saveTeam', {team: null}); // } else { // emit(me.socket, 'saveTeam', {team: teams[i].team}); // } selectedTeam = i; }