');
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 += '';
}
if (!selfR.activeTeam.team.length)
{
text += '
you have no pokemon lol
';
}
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 += '';
}
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 += '
';
if (!teams.length)
{
if (deletedTeamLoc >= 0)
{
text += '';
}
text += '
you don\'t have any teams lol
';
}
else for (var i=0; i';
}
if (i >= teams.length) break;
if (i==2 && cookieTeams)
{
text += '
== UNSAVED TEAM LINE == All teams below this line will not be saved.
';
}
var team = teams[i];
var formatText = '';
if (team.format)
{
formatText = '['+team.format+'] ';
}
text += '
';
}
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;
}