From ec92955748a377540e0d1fe78a8a24eeedc6df17 Mon Sep 17 00:00:00 2001 From: pyuk-bot Date: Wed, 26 Feb 2025 14:40:49 -0600 Subject: [PATCH] Teambuilder: Update popular items for gen 9 & add doubles support (#2321) * Teambuilder: Customize Metronome Battle's popular items * Teambuilder: Update popular items for gen 9 & add doubles support * Fixes * Update play.pokemonshowdown.com/src/battle-dex-search.ts * Apply suggestions from code review * Update play.pokemonshowdown.com/src/battle-dex-search.ts * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review --------- Co-authored-by: Kris Johnson <11083252+KrisXV@users.noreply.github.com> --- build-tools/build-indexes | 52 +++++++++++++++---- .../src/battle-dex-data.ts | 2 + .../src/battle-dex-search.ts | 50 ++++++++++++------ play.pokemonshowdown.com/src/battle-dex.ts | 12 +++++ .../src/battle-tooltips.ts | 9 +--- 5 files changed, 91 insertions(+), 34 deletions(-) diff --git a/build-tools/build-indexes b/build-tools/build-indexes index 87a5b137f..c06d3a7ce 100755 --- a/build-tools/build-indexes +++ b/build-tools/build-indexes @@ -560,6 +560,7 @@ process.stdout.write("Building `data/teambuilder-tables.js`... "); } else if (isDoubles) { BattleTeambuilderTable[gen + 'doubles'] = {}; BattleTeambuilderTable[gen + 'doubles'].tiers = tiers; + BattleTeambuilderTable[gen + 'doubles'].items = items; BattleTeambuilderTable[gen + 'doubles'].overrideTier = overrideTier; BattleTeambuilderTable[gen + 'doubles'].formatSlices = formatSlices; } else if (isGen9BH) { @@ -685,23 +686,55 @@ process.stdout.write("Building `data/teambuilder-tables.js`... "); if (banlist.isBanned('item:' + item.id)) continue; } switch (id) { - case 'leftovers': - case 'lifeorb': + // mainstays case 'choiceband': - case 'choicescarf': case 'choicespecs': case 'eviolite': + greatItems.push(id); + break; + // great everywhere but metronome + case 'leftovers': + case 'lifeorb': + case 'choicescarf': case 'assaultvest': case 'focussash': case 'powerherb': case 'rockyhelmet': + if (!isMetBattle) greatItems.push(id); + else goodItems.push(id); + break; + // just singles + case 'airballoon': + case 'loadeddice': case 'heavydutyboots': case 'expertbelt': case 'salacberry': - greatItems.push(id); + if (isDoubles || isMetBattle) goodItems.push(id); + else greatItems.push(id); break; + // just doubles + case 'safetygoggles': + case 'ejectbutton': + case 'ejectpack': + if (isDoubles) greatItems.push(id); + else goodItems.push(id); + break; + // doubles + metronome + case 'covertcloak': + case 'clearamulet': + case 'weaknesspolicy': + if (isDoubles || isMetBattle) greatItems.push(id); + else goodItems.push(id); + break; + // metronome only + case 'mirrorherb': + if (isMetBattle) greatItems.push(id); + else goodItems.push(id); + break; + // generation specific case 'mentalherb': - if (genNum > 4) greatItems.push(id); + if (isMetBattle) goodItems.push(id); + else if (genNum > 4) greatItems.push(id); else poorItems.push(id); break; case 'lumberry': @@ -709,8 +742,8 @@ process.stdout.write("Building `data/teambuilder-tables.js`... "); else greatItems.push(id); break; case 'sitrusberry': - if (genNum > 6) goodItems.push(id); - else if (genNum > 3 && genNum < 7) greatItems.push(id); + if (genNum > 3 && (genNum < 7 || isDoubles)) greatItems.push(id); + else if (genNum > 6) goodItems.push(id); else poorItems.push(id); break; case 'aguavberry': @@ -718,7 +751,8 @@ process.stdout.write("Building `data/teambuilder-tables.js`... "); case 'iapapaberry': case 'magoberry': case 'wikiberry': - if (genNum >= 7) greatItems.push(id); + if (genNum === 7) greatItems.push(id); + else if (genNum >= 8) goodItems.push(id); else poorItems.push(id); break; case 'berryjuice': @@ -744,8 +778,8 @@ process.stdout.write("Building `data/teambuilder-tables.js`... "); case 'blueorb': case 'redorb': case 'souldew': + // falls through // Other - // fallsthrough case 'stick': case 'thickclub': case 'lightball': diff --git a/play.pokemonshowdown.com/src/battle-dex-data.ts b/play.pokemonshowdown.com/src/battle-dex-data.ts index 9ba4641e2..f725145c1 100644 --- a/play.pokemonshowdown.com/src/battle-dex-data.ts +++ b/play.pokemonshowdown.com/src/battle-dex-data.ts @@ -1496,6 +1496,7 @@ export class Species implements Effect { readonly evoMove: string; readonly evoItem: string; readonly evoCondition: string; + readonly nfe: boolean; readonly requiredItems: readonly string[]; readonly tier: string; readonly isTotem: boolean; @@ -1550,6 +1551,7 @@ export class Species implements Effect { this.evoMove = data.evoMove || ''; this.evoItem = data.evoItem || ''; this.evoCondition = data.evoCondition || ''; + this.nfe = data.nfe || false; this.requiredItems = data.requiredItems || (data.requiredItem ? [data.requiredItem] : []); this.tier = data.tier || ''; diff --git a/play.pokemonshowdown.com/src/battle-dex-search.ts b/play.pokemonshowdown.com/src/battle-dex-search.ts index c7c12e87d..8eabbb5f5 100644 --- a/play.pokemonshowdown.com/src/battle-dex-search.ts +++ b/play.pokemonshowdown.com/src/battle-dex-search.ts @@ -729,6 +729,9 @@ abstract class BattleTypedSearch { results = [...this.baseResults]; illegalResults = null; } + if (this.defaultFilter) { + results = this.defaultFilter(results); + } if (sortCol) { results = results.filter(([rowType]) => rowType === this.searchType); @@ -888,6 +891,7 @@ abstract class BattleTypedSearch { abstract getDefaultResults(): SearchRow[]; abstract getBaseResults(): SearchRow[]; abstract filter(input: SearchRow, filters: string[][]): boolean; + defaultFilter?(input: SearchRow[]): SearchRow[]; abstract sort(input: SearchRow[], sortCol: string, reverseSort?: boolean): SearchRow[]; } @@ -1279,6 +1283,8 @@ class BattleItemSearch extends BattleTypedSearch<'item'> { table = table['gen5bw1']; } else if (this.formatType === 'natdex') { table = table[`gen${this.dex.gen}natdex`]; + } else if (this.formatType?.endsWith('doubles')) { // no natdex/bdsp doubles support + table = table[`gen${this.dex.gen}doubles`]; } else if (this.formatType === 'metronome') { table = table[`gen${this.dex.gen}metronome`]; } else if (this.dex.gen < 9) { @@ -1300,32 +1306,42 @@ class BattleItemSearch extends BattleTypedSearch<'item'> { const speciesName = this.dex.species.get(this.species).name; const results = this.getDefaultResults(); const speciesSpecific: SearchRow[] = []; + const abilitySpecific: SearchRow[] = []; + const abilityItem = { + protosynthesis: 'boosterenergy', + quarkdrive: 'boosterenegy', + // poisonheal: 'toxicorb', + // toxicboost: 'toxicorb', + // flareboost: 'flameorb', + }[toID(this.set?.ability) as string]; for (const row of results) { if (row[0] !== 'item') continue; - if (this.dex.items.get(row[1]).itemUser?.includes(speciesName)) { - speciesSpecific.push(row); - } + const item = this.dex.items.get(row[1]); + if (item.itemUser?.includes(speciesName)) speciesSpecific.push(row); + if (abilityItem === item.id) abilitySpecific.push(row); } if (speciesSpecific.length) { - return [ + results.unshift( ['header', "Specific to " + speciesName], - ...speciesSpecific, - ...results, - ]; + ...speciesSpecific + ); + } + if (abilitySpecific.length) { + results.unshift( + ['header', `Specific to ${this.set!.ability!}`], + ...abilitySpecific + ); + } + return results; + } + override defaultFilter(results: SearchRow[]) { + if (this.species && !this.dex.species.get(this.species).nfe) { + results.splice(results.findIndex(row => row[1] === 'eviolite'), 1); + return results; } return results; } filter(row: SearchRow, filters: string[][]) { - if (!filters) return true; - if (row[0] !== 'ability') return true; - const ability = this.dex.abilities.get(row[1]); - for (const [filterType, value] of filters) { - switch (filterType) { - case 'pokemon': - if (!Dex.hasAbility(this.dex.species.get(value), ability.name)) return false; - break; - } - } return true; } sort(results: SearchRow[], sortCol: string | null, reverseSort?: boolean): SearchRow[] { diff --git a/play.pokemonshowdown.com/src/battle-dex.ts b/play.pokemonshowdown.com/src/battle-dex.ts index b1d27921f..9288fa2f6 100644 --- a/play.pokemonshowdown.com/src/battle-dex.ts +++ b/play.pokemonshowdown.com/src/battle-dex.ts @@ -471,6 +471,12 @@ export const Dex = new class implements ModdedDex { if (!data.tier && data.baseSpecies && toID(data.baseSpecies) !== id) { data.tier = this.species.get(data.baseSpecies).tier; } + data.nfe = data.id === 'dipplin' || !!(data as Species).evos?.some(evo => { + const evoSpecies = this.species.get(evo); + return !evoSpecies.isNonstandard || evoSpecies.isNonstandard === data.isNonstandard || + // Pokemon with Hisui evolutions + evoSpecies.isNonstandard === "Unobtainable"; + }); species = new Species(id, name, data); window.BattlePokedex[id] = species; } @@ -1064,6 +1070,12 @@ export class ModdedDex { data.tier = this.species.get(data.baseSpecies).tier; } if (data.gen > this.gen) data.tier = 'Illegal'; + data.nfe = data.id === 'dipplin' || !!data.evos?.some(evo => { + const evoSpecies = this.species.get(evo); + return !evoSpecies.isNonstandard || evoSpecies.isNonstandard === data.isNonstandard || + // Pokemon with Hisui evolutions + evoSpecies.isNonstandard === "Unobtainable"; + }); const species = new Species(id, name, data); this.cache.Species[id] = species; diff --git a/play.pokemonshowdown.com/src/battle-tooltips.ts b/play.pokemonshowdown.com/src/battle-tooltips.ts index f7acf44ad..770b84fd6 100644 --- a/play.pokemonshowdown.com/src/battle-tooltips.ts +++ b/play.pokemonshowdown.com/src/battle-tooltips.ts @@ -1192,14 +1192,7 @@ export class BattleTooltips { speedModifiers.push(1.5); } } - const isNFE = this.battle.dex.species.get(serverPokemon.speciesForme).evos?.some(evo => { - const evoSpecies = this.battle.dex.species.get(evo); - return !evoSpecies.isNonstandard || - evoSpecies.isNonstandard === this.battle.dex.species.get(serverPokemon.speciesForme)?.isNonstandard || - // Pokemon with Hisui evolutions - evoSpecies.isNonstandard === "Unobtainable"; - }); - if (item === 'eviolite' && (isNFE || this.battle.dex.species.get(serverPokemon.speciesForme).id === 'dipplin')) { + if (item === 'eviolite' && this.battle.dex.species.get(serverPokemon.speciesForme).nfe) { stats.def = Math.floor(stats.def * 1.5); stats.spd = Math.floor(stats.spd * 1.5); }