diff --git a/src/@types/trainer-funcs.ts b/src/@types/trainer-funcs.ts index cc4ba91aff3..fafa0a0f250 100644 --- a/src/@types/trainer-funcs.ts +++ b/src/@types/trainer-funcs.ts @@ -11,7 +11,7 @@ export type GenModifiersFunc = (party: readonly EnemyPokemon[]) => PersistentMod export type GenAIFunc = (party: readonly EnemyPokemon[]) => void; export interface TrainerTierPools { - [key: number]: SpeciesId[]; + [key: number]: (SpeciesId | SpeciesId[])[]; } export interface TrainerConfigs { [key: number]: TrainerConfig; diff --git a/src/battle.ts b/src/battle.ts index 27a2498ffdb..5a1856ff91e 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -32,6 +32,7 @@ import { shiftCharCodes, } from "#utils/common"; import { getEnumValues } from "#utils/enums"; +import { randSeedUniqueItem } from "#utils/random"; export interface TurnCommand { command: Command; @@ -523,13 +524,12 @@ export class FixedBattleConfig { return this; } } - /** * Helper function to generate a random trainer for evil team trainers and the elite 4/champion - * @param trainerPool - An array of trainer types to choose from. If an entry is an array, a random trainer type will be chosen from that array - * @param randomGender - Whether or not to randomly (50%) generate a female trainer (for use with evil team grunts) - * @param seedOffset - The seed offset to use for the random generation of the trainer - * @returns A function to get a random trainer + * @param trainerPool - The TrainerType or list of TrainerTypes that can possibly be generated + * @param randomGender - (default `false`); Whether or not to randomly (50%) generate a female trainer (for use with evil team grunts) + * @param seedOffset - (default `0`); A seed offset indicating the invocation count of the function to attempt to choose a random, but unique, trainer from the pool + * @returns A function to generate a random trainer */ export function getRandomTrainerFunc( trainerPool: readonly (TrainerType | readonly TrainerType[])[], @@ -537,16 +537,12 @@ export function getRandomTrainerFunc( seedOffset = 0, ): GetTrainerFunc { return () => { - const rand = randSeedInt(trainerPool.length); - const trainerTypes: TrainerType[] = new Array(trainerPool.length); + /** The chosen entry in the pool */ + let choice = randSeedItem(trainerPool); - globalScene.executeWithSeedOffset(() => { - for (let i = 0; i < trainerPool.length; i++) { - const trainerPoolEntry = trainerPool[i]; - const trainerType = Array.isArray(trainerPoolEntry) ? randSeedItem(trainerPoolEntry) : trainerPoolEntry; - trainerTypes[i] = trainerType; - } - }, seedOffset); + if (typeof choice !== "number") { + choice = seedOffset === 0 ? randSeedItem(choice) : randSeedUniqueItem(choice, seedOffset); + } let trainerGender = TrainerVariant.DEFAULT; if (randomGender) { @@ -566,12 +562,12 @@ export function getRandomTrainerFunc( TrainerType.MACRO_GRUNT, TrainerType.STAR_GRUNT, ]; - const isEvilTeamGrunt = evilTeamGrunts.includes(trainerTypes[rand]); + const isEvilTeamGrunt = evilTeamGrunts.includes(choice); - if (trainerConfigs[trainerTypes[rand]].hasDouble && isEvilTeamGrunt) { - return new Trainer(trainerTypes[rand], randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); + if (trainerConfigs[choice].hasDouble && isEvilTeamGrunt) { + return new Trainer(choice, randInt(3) === 0 ? TrainerVariant.DOUBLE : trainerGender); } - return new Trainer(trainerTypes[rand], trainerGender); + return new Trainer(choice, trainerGender); }; } diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 38c7a1990e4..cafebb0dadf 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -503,6 +503,7 @@ export class SingleGenerationChallenge extends Challenge { ClassicFixedBossWaves.EVIL_GRUNT_4, ClassicFixedBossWaves.EVIL_ADMIN_2, ClassicFixedBossWaves.EVIL_BOSS_1, + ClassicFixedBossWaves.EVIL_ADMIN_3, ClassicFixedBossWaves.EVIL_BOSS_2, ]; const evilTeamGrunts = [ @@ -516,9 +517,37 @@ export class SingleGenerationChallenge extends Challenge { [TrainerType.MACRO_GRUNT], [TrainerType.STAR_GRUNT], ]; - const evilTeamAdmins = [ - [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL], - [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL], + const evilAdminFight1 = [ + [TrainerType.PETREL], + [TrainerType.PETREL], + [ + [TrainerType.TABITHA, TrainerType.COURTNEY], + [TrainerType.MATT, TrainerType.SHELLY], + ], + [TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN], + [TrainerType.ZINZOLIN, TrainerType.COLRESS], + [TrainerType.BRYONY], + [TrainerType.FABA, TrainerType.PLUMERIA], + [TrainerType.OLEANA], + [TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI], + ]; + const evilAdminFight2 = [ + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], + [ + [TrainerType.TABITHA, TrainerType.COURTNEY], + [TrainerType.MATT, TrainerType.SHELLY], + ], + [TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN], + [TrainerType.ZINZOLIN], + [TrainerType.XEROSIC], + [TrainerType.FABA, TrainerType.PLUMERIA], + [TrainerType.OLEANA], + [TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI], + ]; + const evilAdminFight3 = [ + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], [ [TrainerType.TABITHA, TrainerType.COURTNEY], [TrainerType.MATT, TrainerType.SHELLY], @@ -563,8 +592,13 @@ export class SingleGenerationChallenge extends Challenge { trainerTypes = evilTeamGrunts[this.value - 1]; break; case ClassicFixedBossWaves.EVIL_ADMIN_1: + trainerTypes = evilAdminFight1[this.value - 1]; + break; case ClassicFixedBossWaves.EVIL_ADMIN_2: - trainerTypes = evilTeamAdmins[this.value - 1]; + trainerTypes = evilAdminFight2[this.value - 1]; + break; + case ClassicFixedBossWaves.EVIL_ADMIN_3: + trainerTypes = evilAdminFight3[this.value - 1]; break; case ClassicFixedBossWaves.EVIL_BOSS_1: trainerTypes = evilTeamBosses[this.value - 1]; diff --git a/src/data/trainers/evil-admin-trainer-pools.ts b/src/data/trainers/evil-admin-trainer-pools.ts index ad08a17d29f..ae7ff106f8a 100644 --- a/src/data/trainers/evil-admin-trainer-pools.ts +++ b/src/data/trainers/evil-admin-trainer-pools.ts @@ -3,218 +3,256 @@ import { TrainerPoolTier } from "#enums/trainer-pool-tier"; import type { TrainerTierPools } from "#types/trainer-funcs"; /** Team Rocket's admin trainer pool. */ -const ROCKET: TrainerTierPools = { +const ROCKET_PETREL: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.RATTATA, SpeciesId.SPEAROW, - SpeciesId.EKANS, - SpeciesId.VILEPLUME, + SpeciesId.ZUBAT, SpeciesId.DIGLETT, - SpeciesId.GROWLITHE, - SpeciesId.GRIMER, + SpeciesId.GEODUDE, SpeciesId.DROWZEE, SpeciesId.VOLTORB, SpeciesId.EXEGGCUTE, - SpeciesId.CUBONE, - SpeciesId.KOFFING, - SpeciesId.MAGIKARP, + SpeciesId.TANGELA, + SpeciesId.PINECO, + ], + [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.MAGNEMITE, + SpeciesId.SHELLDER, + SpeciesId.OMANYTE, + SpeciesId.QWILFISH, + SpeciesId.ALOLA_GEODUDE, + SpeciesId.HISUI_VOLTORB, + ], + [TrainerPoolTier.RARE]: [SpeciesId.MAGIKARP], +}; + +const ROCKET_ARCHER: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ SpeciesId.ZUBAT, - SpeciesId.ONIX, - SpeciesId.HOUNDOUR, - SpeciesId.MURKROW, + SpeciesId.VENONAT, + SpeciesId.BELLSPROUT, + SpeciesId.GRIMER, + SpeciesId.DROWZEE, + SpeciesId.CUBONE, + SpeciesId.TAUROS, + SpeciesId.MISDREAVUS, + SpeciesId.WYNAUT, ], [TrainerPoolTier.UNCOMMON]: [ SpeciesId.ABRA, - SpeciesId.GASTLY, - SpeciesId.OMANYTE, - SpeciesId.KABUTO, - SpeciesId.PORYGON, - SpeciesId.MANKEY, - SpeciesId.SCYTHER, + SpeciesId.ONIX, + SpeciesId.MAGIKARP, + SpeciesId.SNEASEL, SpeciesId.ELEKID, - SpeciesId.MAGBY, - SpeciesId.ALOLA_SANDSHREW, - SpeciesId.ALOLA_MEOWTH, - SpeciesId.ALOLA_GEODUDE, - SpeciesId.ALOLA_GRIMER, SpeciesId.PALDEA_TAUROS, ], - [TrainerPoolTier.RARE]: [SpeciesId.DRATINI, SpeciesId.LARVITAR], + [TrainerPoolTier.RARE]: [SpeciesId.LARVITAR], +}; + +const ROCKET_ARIANA: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + SpeciesId.WEEDLE, + SpeciesId.ZUBAT, + SpeciesId.GROWLITHE, + SpeciesId.KOFFING, + SpeciesId.LICKITUNG, + SpeciesId.SMOOCHUM, + SpeciesId.SNUBBULL, + SpeciesId.MISDREAVUS, + SpeciesId.SLUGMA, + ], + [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.SCYTHER, + SpeciesId.MAGIKARP, + SpeciesId.PORYGON, + SpeciesId.KABUTO, + SpeciesId.ALOLA_RATTATA, + SpeciesId.ALOLA_MEOWTH, + ], + [TrainerPoolTier.RARE]: [SpeciesId.LAPRAS], +}; + +const ROCKET_PROTON: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + SpeciesId.SANDSHREW, + SpeciesId.PARAS, + SpeciesId.MANKEY, + SpeciesId.POLIWAG, + [SpeciesId.SLOWPOKE, SpeciesId.GALAR_SLOWPOKE], + SpeciesId.KANGASKHAN, + SpeciesId.PINSIR, + SpeciesId.DUNSPARCE, + ], + [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.GASTLY, + SpeciesId.MAGIKARP, + SpeciesId.AERODACTYL, + SpeciesId.MAGBY, + SpeciesId.ALOLA_SANDSHREW, + SpeciesId.ALOLA_GRIMER, + SpeciesId.GALAR_SLOWPOKE, + ], + [TrainerPoolTier.RARE]: [SpeciesId.DRATINI], }; /** Team Magma's admin trainer pool */ const MAGMA: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.DIGLETT, - SpeciesId.GROWLITHE, - SpeciesId.VULPIX, + SpeciesId.GEODUDE, SpeciesId.KOFFING, - SpeciesId.RHYHORN, - SpeciesId.SLUGMA, SpeciesId.HOUNDOUR, + SpeciesId.PHANPY, SpeciesId.POOCHYENA, - SpeciesId.TORKOAL, SpeciesId.ZANGOOSE, - SpeciesId.SOLROCK, - SpeciesId.BALTOY, + SpeciesId.CACNEA, + SpeciesId.SIZZLIPEDE, SpeciesId.ROLYCOLY, ], [TrainerPoolTier.UNCOMMON]: [ SpeciesId.MAGBY, - SpeciesId.TRAPINCH, - SpeciesId.LILEEP, - SpeciesId.ANORITH, - SpeciesId.GOLETT, - SpeciesId.FLETCHLING, + [SpeciesId.LILEEP, SpeciesId.ANORITH], + SpeciesId.DRAPION, + SpeciesId.DRUDDIGON, + SpeciesId.DARUMAKA, SpeciesId.SALANDIT, SpeciesId.TURTONATOR, - SpeciesId.TOEDSCOOL, - SpeciesId.CAPSAKID, - SpeciesId.HISUI_GROWLITHE, ], - [TrainerPoolTier.RARE]: [SpeciesId.CHARCADET, SpeciesId.ARON], + [TrainerPoolTier.RARE]: [SpeciesId.RHYHORN, SpeciesId.ARON, SpeciesId.CHARCADET], }; const AQUA: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.TENTACOOL, + SpeciesId.KRABBY, SpeciesId.GRIMER, - SpeciesId.AZURILL, - SpeciesId.CHINCHOU, - SpeciesId.REMORAID, + SpeciesId.MANTYKE, SpeciesId.POOCHYENA, SpeciesId.LOTAD, SpeciesId.WINGULL, - SpeciesId.WAILMER, SpeciesId.SEVIPER, - SpeciesId.BARBOACH, - SpeciesId.CORPHISH, + SpeciesId.WAILMER, SpeciesId.SPHEAL, - SpeciesId.CLAMPERL, - ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.MANTYKE, - SpeciesId.HORSEA, - SpeciesId.FEEBAS, - SpeciesId.TYMPOLE, - SpeciesId.SKRELP, - SpeciesId.WIMPOD, - SpeciesId.DHELMISE, + SpeciesId.RELICANTH, SpeciesId.ARROKUDA, SpeciesId.CLOBBOPUS, - SpeciesId.HISUI_QWILFISH, - SpeciesId.WIGLETT, - ], - [TrainerPoolTier.RARE]: [SpeciesId.BASCULEGION, SpeciesId.DONDOZO], -}; - -const GALACTIC: TrainerTierPools = { - [TrainerPoolTier.COMMON]: [ - SpeciesId.ZUBAT, - SpeciesId.MAGNEMITE, - SpeciesId.RHYHORN, - SpeciesId.TANGELA, - SpeciesId.LICKITUNG, - SpeciesId.MAGIKARP, - SpeciesId.YANMA, - SpeciesId.MURKROW, - SpeciesId.SWINUB, - SpeciesId.ELEKID, - SpeciesId.MAGBY, - SpeciesId.BRONZOR, - SpeciesId.SKORUPI, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.ABRA, - SpeciesId.GLIGAR, - SpeciesId.SNEASEL, - SpeciesId.DUSKULL, + SpeciesId.SHELLDER, + SpeciesId.HORSEA, + [SpeciesId.OMANYTE, SpeciesId.KABUTO], + SpeciesId.CROAGUNK, + SpeciesId.BINACLE, + SpeciesId.SKRELP, + SpeciesId.WIMPOD, + ], + [TrainerPoolTier.RARE]: [SpeciesId.MAGIKARP, SpeciesId.FEEBAS, SpeciesId.BASCULEGION], +}; + +const GALACTIC_MARS: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + SpeciesId.MAGNEMITE, + SpeciesId.KANGASKHAN, SpeciesId.DRIFLOON, - SpeciesId.CRANIDOS, - SpeciesId.SHIELDON, - SpeciesId.ROTOM, - SpeciesId.HISUI_QWILFISH, + SpeciesId.SHELLOS, + SpeciesId.CHINGLING, ], - [TrainerPoolTier.RARE]: [ - SpeciesId.SPIRITOMB, - SpeciesId.TEDDIURSA, - SpeciesId.HISUI_SNEASEL, - SpeciesId.HISUI_LILLIGANT, + [TrainerPoolTier.UNCOMMON]: [SpeciesId.PORYGON, SpeciesId.TOGEPI, SpeciesId.ELEKID, SpeciesId.MISDREAVUS], + [TrainerPoolTier.RARE]: [SpeciesId.HISUI_LILLIGANT], +}; + +const GALACTIC_JUPITER: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + SpeciesId.SABLEYE, + SpeciesId.BUDEW, + SpeciesId.COMBEE, + SpeciesId.SHELLOS, + SpeciesId.NOSEPASS, ], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.GLIGAR, SpeciesId.SWINUB, SpeciesId.DUSKULL, SpeciesId.SNOVER], + [TrainerPoolTier.RARE]: [SpeciesId.HISUI_SNEASEL], +}; + +const GALACTIC_SATURN: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [SpeciesId.ZUBAT, SpeciesId.AIPOM, SpeciesId.OCTILLERY, SpeciesId.ABSOL, SpeciesId.SKORUPI], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.RHYHORN, SpeciesId.MAGBY, SpeciesId.GALLADE, SpeciesId.SPIRITOMB], + [TrainerPoolTier.RARE]: [SpeciesId.OVERQWIL], }; const PLASMA_ZINZOLIN: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.SNEASEL, SpeciesId.SWINUB, - SpeciesId.SNORUNT, + SpeciesId.GLALIE, SpeciesId.SNOVER, - SpeciesId.TIMBURR, - SpeciesId.TYMPOLE, - SpeciesId.SANDILE, - SpeciesId.DARUMAKA, - SpeciesId.VANILLITE, - SpeciesId.FOONGUS, + SpeciesId.MUNNA, + SpeciesId.VENIPEDE, SpeciesId.FRILLISH, - SpeciesId.JOLTIK, - SpeciesId.FERROSEED, SpeciesId.CUBCHOO, - SpeciesId.GALAR_DARUMAKA, + SpeciesId.MIENFOO, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.SPHEAL, - SpeciesId.DRILBUR, - SpeciesId.SIGILYPH, - SpeciesId.YAMASK, - SpeciesId.ZORUA, - SpeciesId.TYNAMO, - SpeciesId.MIENFOO, - SpeciesId.GOLETT, - SpeciesId.PAWNIARD, - SpeciesId.VULLABY, - SpeciesId.DURANT, SpeciesId.BERGMITE, SpeciesId.EISCUE, SpeciesId.ALOLA_SANDSHREW, + SpeciesId.GALAR_DARUMAKA, SpeciesId.HISUI_ZORUA, + SpeciesId.HISUI_BRAVIARY, ], - [TrainerPoolTier.RARE]: [SpeciesId.DEINO, SpeciesId.FRIGIBAX, SpeciesId.HISUI_BRAVIARY], + [TrainerPoolTier.RARE]: [SpeciesId.FRIGIBAX], }; const PLASMA_COLRESS: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.MAGNEMITE, - SpeciesId.GRIMER, SpeciesId.VOLTORB, SpeciesId.PORYGON, - SpeciesId.BRONZOR, + SpeciesId.NOSEPASS, SpeciesId.ROTOM, - SpeciesId.MUNNA, SpeciesId.DWEBBLE, - SpeciesId.FERROSEED, - SpeciesId.ELGYEM, + SpeciesId.BLIPBUG, ], [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.ELEKID, + SpeciesId.MAGBY, SpeciesId.BELDUM, - SpeciesId.SIGILYPH, - SpeciesId.TIRTOUGA, - SpeciesId.ARCHEN, - SpeciesId.TYNAMO, SpeciesId.GOLETT, - SpeciesId.BLIPBUG, + [SpeciesId.TIRTOUGA, SpeciesId.ARCHEN], + SpeciesId.TYNAMO, SpeciesId.VAROOM, SpeciesId.ALOLA_GRIMER, - SpeciesId.HISUI_VOLTORB, ], - [TrainerPoolTier.RARE]: [SpeciesId.ELEKID, SpeciesId.MAGBY, SpeciesId.PAWNIARD, SpeciesId.DURALUDON], + [TrainerPoolTier.RARE]: [SpeciesId.DURALUDON], }; const FLARE: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.ELECTRIKE, - SpeciesId.SKORUPI, - SpeciesId.PURRLOIN, SpeciesId.FOONGUS, + SpeciesId.SCRAGGY, + SpeciesId.DRUDDIGON, + SpeciesId.BUNNELBY, + SpeciesId.FLETCHLING, + SpeciesId.PANCHAM, + SpeciesId.ESPURR, + SpeciesId.PUMPKABOO, + SpeciesId.PHANTUMP, + SpeciesId.CLAUNCHER, + SpeciesId.HELIOPTILE, + SpeciesId.KLEFKI, + ], + [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.LITWICK, + SpeciesId.HEATMOR, + SpeciesId.BINACLE, + SpeciesId.SKRELP, + SpeciesId.BERGMITE, + SpeciesId.CAPSAKID, + ], + [TrainerPoolTier.RARE]: [SpeciesId.GOODRA, SpeciesId.HONEDGE], +}; + +const FLARE_XEROSIC: TrainerTierPools = { + [TrainerPoolTier.COMMON]: [ + SpeciesId.PANCHAM, + SpeciesId.BINACLE, + SpeciesId.HELIOPTILE, + SpeciesId.CLAUNCHER, SpeciesId.BUNNELBY, SpeciesId.FLETCHLING, SpeciesId.LITLEO, @@ -225,124 +263,92 @@ const FLARE: TrainerTierPools = { SpeciesId.HELIOPTILE, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.HOUNDOUR, + [SpeciesId.AMAURA, SpeciesId.TYRUNT], SpeciesId.SNEASEL, SpeciesId.LITWICK, - SpeciesId.HONEDGE, + SpeciesId.LITLEO, SpeciesId.BINACLE, SpeciesId.SKRELP, SpeciesId.NOIBAT, SpeciesId.PHANTUMP, SpeciesId.PUMPKABOO, ], - [TrainerPoolTier.RARE]: [SpeciesId.GOOMY, SpeciesId.HISUI_AVALUGG], + [TrainerPoolTier.RARE]: [SpeciesId.HISUI_GOODRA, SpeciesId.HONEDGE], }; const AETHER: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ SpeciesId.ABRA, SpeciesId.SLOWPOKE, - SpeciesId.MAGNEMITE, - SpeciesId.EXEGGUTOR, + SpeciesId.MR_MIME, SpeciesId.NATU, + SpeciesId.MEDITITE, SpeciesId.BALTOY, - SpeciesId.MIME_JR, - SpeciesId.ELGYEM, SpeciesId.INKAY, - SpeciesId.BRUXISH, - SpeciesId.BLIPBUG, - SpeciesId.ALOLA_RAICHU, + SpeciesId.EXEGGCUTE, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.RALTS, - SpeciesId.MEDITITE, - SpeciesId.BELDUM, + SpeciesId.PORYGON, + [SpeciesId.STANTLER, SpeciesId.GIRAFARIG], SpeciesId.SOLOSIS, SpeciesId.HATENNA, - SpeciesId.STANTLER, - SpeciesId.GIRAFARIG, SpeciesId.ALOLA_GRIMER, - SpeciesId.GALAR_SLOWPOKE, + SpeciesId.GALAR_SLOWKING, ], - [TrainerPoolTier.RARE]: [SpeciesId.PORYGON, SpeciesId.ARMAROUGE], + [TrainerPoolTier.RARE]: [SpeciesId.BELDUM], }; const SKULL: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.GASTLY, - SpeciesId.KOFFING, - SpeciesId.ZUBAT, SpeciesId.VENONAT, - SpeciesId.STUNKY, + SpeciesId.GASTLY, + SpeciesId.ZUBAT, SpeciesId.CROAGUNK, SpeciesId.VENIPEDE, - SpeciesId.SCRAGGY, - SpeciesId.MAREANIE, SpeciesId.FOMANTIS, - SpeciesId.ALOLA_GRIMER, + SpeciesId.TOXEL, + SpeciesId.PALDEA_WOOPER, ], [TrainerPoolTier.UNCOMMON]: [ SpeciesId.NIDORAN_F, SpeciesId.SKORUPI, - SpeciesId.PAWNIARD, SpeciesId.VULLABY, - SpeciesId.TOXEL, + SpeciesId.SKRELP, SpeciesId.GLIMMET, - SpeciesId.PALDEA_WOOPER, - SpeciesId.GALAR_SLOWPOKE, + SpeciesId.GALAR_SLOWBRO, ], - [TrainerPoolTier.RARE]: [SpeciesId.SKRELP, SpeciesId.HISUI_SNEASEL], + [TrainerPoolTier.RARE]: [SpeciesId.HISUI_SNEASEL], }; const MACRO_COSMOS: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.VULPIX, - SpeciesId.FEEBAS, + SpeciesId.SMOOCHUM, SpeciesId.MAWILE, + SpeciesId.VESPIQUEN, SpeciesId.FROSLASS, SpeciesId.GOTHITA, - SpeciesId.FLABEBE, + SpeciesId.SPRITZEE, SpeciesId.SALANDIT, - SpeciesId.TSAREENA, - SpeciesId.SINISTEA, - SpeciesId.HATENNA, SpeciesId.INDEEDEE, - SpeciesId.GALAR_PONYTA, + SpeciesId.HATENNA, ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.TOGEPI, - SpeciesId.VULLABY, - SpeciesId.MAREANIE, - SpeciesId.CUFANT, - SpeciesId.TINKATINK, - SpeciesId.ALOLA_VULPIX, - SpeciesId.GALAR_CORSOLA, - ], - [TrainerPoolTier.RARE]: [SpeciesId.APPLIN, SpeciesId.HISUI_LILLIGANT], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.VULLABY, SpeciesId.FLABEBE, SpeciesId.TINKATINK, SpeciesId.GALAR_PONYTA], + [TrainerPoolTier.RARE]: [SpeciesId.HYDRAPPLE], }; const STAR_DARK: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ SpeciesId.MURKROW, - SpeciesId.SEEDOT, SpeciesId.SABLEYE, SpeciesId.CACNEA, + SpeciesId.CORPHISH, SpeciesId.STUNKY, SpeciesId.SANDILE, - SpeciesId.INKAY, SpeciesId.NYMBLE, - SpeciesId.MASCHIFF, - ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.UMBREON, - SpeciesId.CORPHISH, - SpeciesId.SNEASEL, - SpeciesId.ZORUA, - SpeciesId.IMPIDIMP, SpeciesId.BOMBIRDIER, - SpeciesId.GALAR_ZIGZAGOON, ], - [TrainerPoolTier.RARE]: [SpeciesId.DEINO, SpeciesId.SPRIGATITO], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.SNEASEL, SpeciesId.SPIRITOMB, SpeciesId.ZORUA, SpeciesId.GALAR_ZIGZAGOON], + [TrainerPoolTier.RARE]: [SpeciesId.SPRIGATITO], }; const STAR_FIRE: TrainerTierPools = { @@ -353,101 +359,77 @@ const STAR_FIRE: TrainerTierPools = { SpeciesId.TORKOAL, SpeciesId.FLETCHLING, SpeciesId.LITLEO, - SpeciesId.SIZZLIPEDE, + SpeciesId.ORICORIO, SpeciesId.ROLYCOLY, - SpeciesId.CAPSAKID, ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.PONYTA, - SpeciesId.FLAREON, - SpeciesId.MAGBY, - SpeciesId.DARUMAKA, - SpeciesId.LITWICK, - SpeciesId.SALANDIT, - SpeciesId.TURTONATOR, - ], - [TrainerPoolTier.RARE]: [SpeciesId.LARVESTA, SpeciesId.FUECOCO], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.DARUMAKA, SpeciesId.TURTONATOR, SpeciesId.SIZZLIPEDE, SpeciesId.CERULEDGE], + [TrainerPoolTier.RARE]: [SpeciesId.FUECOCO], }; const STAR_POISON: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.GRIMER, SpeciesId.VENONAT, + SpeciesId.GRIMER, + SpeciesId.GULPIN, SpeciesId.SEVIPER, SpeciesId.STUNKY, SpeciesId.FOONGUS, SpeciesId.MAREANIE, - SpeciesId.TOXEL, - SpeciesId.GRAFAIAI, - SpeciesId.PALDEA_WOOPER, ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.ZUBAT, - SpeciesId.GASTLY, - SpeciesId.SKRELP, - SpeciesId.OVERQWIL, - SpeciesId.ALOLA_GRIMER, - SpeciesId.GALAR_SLOWPOKE, - ], - [TrainerPoolTier.RARE]: [SpeciesId.GLIMMET, SpeciesId.BULBASAUR], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.GASTLY, SpeciesId.SALAZZLE, SpeciesId.GLIMMET, SpeciesId.PALDEA_WOOPER], + [TrainerPoolTier.RARE]: [SpeciesId.BULBASAUR], }; const STAR_FAIRY: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ + SpeciesId.CLEFFA, SpeciesId.IGGLYBUFF, + SpeciesId.MR_MIME, SpeciesId.AZURILL, - SpeciesId.COTTONEE, - SpeciesId.FLABEBE, + SpeciesId.DEDENNE, SpeciesId.KLEFKI, - SpeciesId.CUTIEFLY, SpeciesId.HATENNA, - SpeciesId.TINKATINK, + SpeciesId.IMPIDIMP, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.CLEFFA, - SpeciesId.TOGEPI, - SpeciesId.GARDEVOIR, - SpeciesId.SYLVEON, + SpeciesId.RALTS, + SpeciesId.FLABEBE, + SpeciesId.MIMIKYU, SpeciesId.MIMIKYU, - SpeciesId.IMPIDIMP, SpeciesId.ALOLA_VULPIX, ], - [TrainerPoolTier.RARE]: [SpeciesId.GALAR_PONYTA, SpeciesId.POPPLIO], + [TrainerPoolTier.RARE]: [SpeciesId.POPPLIO], }; const STAR_FIGHTING: TrainerTierPools = { [TrainerPoolTier.COMMON]: [ - SpeciesId.TYROGUE, SpeciesId.SHROOMISH, SpeciesId.MAKUHITA, + [SpeciesId.MEDITITE, SpeciesId.GALLADE], SpeciesId.RIOLU, SpeciesId.CROAGUNK, - SpeciesId.SCRAGGY, - SpeciesId.MIENFOO, SpeciesId.PASSIMIAN, + SpeciesId.FALINKS, SpeciesId.PAWMI, ], - [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.MEDITITE, - SpeciesId.GALLADE, - SpeciesId.TIMBURR, - SpeciesId.HAWLUCHA, - SpeciesId.STUFFUL, - SpeciesId.FALINKS, - SpeciesId.FLAMIGO, - SpeciesId.PALDEA_TAUROS, - ], - [TrainerPoolTier.RARE]: [SpeciesId.JANGMO_O, SpeciesId.QUAXLY], + [TrainerPoolTier.UNCOMMON]: [SpeciesId.HERACROSS, SpeciesId.HAWLUCHA, SpeciesId.CRABRAWLER, SpeciesId.PALDEA_TAUROS], + [TrainerPoolTier.RARE]: [SpeciesId.QUAXLY], }; export type EvilTeam = - | "rocket" + | "rocket_petrel" + | "rocket_archer" + | "rocket_ariana" + | "rocket_proton" | "magma" | "aqua" - | "galactic" + | "galactic_mars" + | "galactic_jupiter" + | "galactic_saturn" | "plasma_zinzolin" | "plasma_colress" | "flare" + | "flare_xerosic" | "aether" | "skull" | "macro_cosmos" @@ -459,13 +441,19 @@ export type EvilTeam = /** Trainer pools for each evil admin team */ export const evilAdminTrainerPools: Record = { - rocket: ROCKET, + rocket_petrel: ROCKET_PETREL, + rocket_archer: ROCKET_ARCHER, + rocket_ariana: ROCKET_ARIANA, + rocket_proton: ROCKET_PROTON, magma: MAGMA, aqua: AQUA, - galactic: GALACTIC, + galactic_mars: GALACTIC_MARS, + galactic_jupiter: GALACTIC_JUPITER, + galactic_saturn: GALACTIC_SATURN, plasma_zinzolin: PLASMA_ZINZOLIN, plasma_colress: PLASMA_COLRESS, flare: FLARE, + flare_xerosic: FLARE_XEROSIC, aether: AETHER, macro_cosmos: MACRO_COSMOS, skull: SKULL, diff --git a/src/data/trainers/fixed-battle-configs.ts b/src/data/trainers/fixed-battle-configs.ts index bb6d591654b..ea991968dab 100644 --- a/src/data/trainers/fixed-battle-configs.ts +++ b/src/data/trainers/fixed-battle-configs.ts @@ -127,12 +127,12 @@ export const classicFixedBattles: FixedBattleConfigs = { .setGetTrainerFunc( getRandomTrainerFunc( [ - [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL], + TrainerType.PETREL, [TrainerType.TABITHA, TrainerType.COURTNEY], [TrainerType.MATT, TrainerType.SHELLY], [TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN], [TrainerType.ZINZOLIN, TrainerType.COLRESS], - [TrainerType.XEROSIC, TrainerType.BRYONY], + TrainerType.BRYONY, TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, @@ -180,12 +180,12 @@ export const classicFixedBattles: FixedBattleConfigs = { .setGetTrainerFunc( getRandomTrainerFunc( [ - [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL], + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], [TrainerType.TABITHA, TrainerType.COURTNEY], [TrainerType.MATT, TrainerType.SHELLY], [TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN], - [TrainerType.ZINZOLIN, TrainerType.COLRESS], - [TrainerType.XEROSIC, TrainerType.BRYONY], + TrainerType.ZINZOLIN, + TrainerType.XEROSIC, TrainerType.FABA, TrainerType.PLUMERIA, TrainerType.OLEANA, @@ -241,6 +241,27 @@ export const classicFixedBattles: FixedBattleConfigs = { ], allowLuckUpgrades: false, }), + [ClassicFixedBossWaves.EVIL_ADMIN_3]: new FixedBattleConfig() + .setBattleType(BattleType.TRAINER) + .setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1) + .setGetTrainerFunc( + getRandomTrainerFunc( + [ + [TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON], + [TrainerType.TABITHA, TrainerType.COURTNEY], + [TrainerType.MATT, TrainerType.SHELLY], + [TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN], + [TrainerType.ZINZOLIN, TrainerType.COLRESS], + [TrainerType.XEROSIC, TrainerType.BRYONY], + TrainerType.FABA, + TrainerType.PLUMERIA, + TrainerType.OLEANA, + [TrainerType.GIACOMO, TrainerType.MELA, TrainerType.ATTICUS, TrainerType.ORTEGA, TrainerType.ERI], + ], + true, + 2, + ), + ), [ClassicFixedBossWaves.EVIL_BOSS_2]: new FixedBattleConfig() .setBattleType(BattleType.TRAINER) .setSeedOffsetWave(ClassicFixedBossWaves.EVIL_GRUNT_1) diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index fc718ba9db3..906bf2e4aa2 100644 --- a/src/data/trainers/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -7,6 +7,7 @@ import { doubleBattleDialogue } from "#data/double-battle-dialogue"; import { Gender } from "#data/gender"; import type { PokemonSpecies, PokemonSpeciesFilter } from "#data/pokemon-species"; import { AbilityId } from "#enums/ability-id"; +import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves"; import { MoveId } from "#enums/move-id"; import { PartyMemberStrength } from "#enums/party-member-strength"; import { PokeballType } from "#enums/pokeball"; @@ -18,6 +19,7 @@ import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerType } from "#enums/trainer-type"; import { TrainerVariant } from "#enums/trainer-variant"; import type { EnemyPokemon } from "#field/pokemon"; +import type { SpeciesStatBoosterModifier } from "#modifiers/modifier"; import { PokemonMove } from "#moves/pokemon-move"; import { getIsInitialized, initI18n } from "#plugins/i18n"; import type { EvilTeam } from "#trainers/evil-admin-trainer-pools"; @@ -66,14 +68,36 @@ const GYM_LEADER_TERA_WAVE = 100; */ export class TrainerAI { public teraMode: TeraAIMode = TeraAIMode.NO_TERA; - public instantTeras: number[]; + /** + * Logic determining which Pokémon will instantly Tera. + * Each entry is either a number (the slot index) or a tuple of the slot index and a condition function. + */ + private readonly teraLogic: (number | [slot: number, condition: () => boolean])[] = []; + + /** + * Determine the indices of the Pokémon that will instantly Tera + */ + public get instantTeras(): number[] { + if (this.teraMode === TeraAIMode.NO_TERA) { + return []; + } + const instantTeras: number[] = []; + for (const index of this.teraLogic) { + if (typeof index === "number") { + instantTeras.push(index); + } else if (index[1]?.()) { + instantTeras.push(index[0]); + } + } + + return instantTeras; + } /** * @param canTerastallize Whether this trainer is allowed to tera */ constructor(teraMode: TeraAIMode = TeraAIMode.NO_TERA) { this.teraMode = teraMode; - this.instantTeras = []; } /** @@ -86,11 +110,16 @@ export class TrainerAI { /** * Sets a pokemon on this AI to just instantly Tera on first move used - * @param index The index of the pokemon to instantly tera. + * @param index - The index of the pokemon to instantly tera + * @param condition - An optional condition function, evaluated at */ - public setInstantTera(index: number) { + public setInstantTera(index: number, condition?: () => boolean) { this.teraMode = TeraAIMode.INSTANT_TERA; - this.instantTeras.push(index); + if (typeof condition === "function") { + this.teraLogic.push([index, condition]); + } else { + this.teraLogic.push(index); + } } } @@ -527,11 +556,12 @@ export class TrainerConfig { /** * Sets a specific pokemon to instantly Tera - * @param index The index within the team to have instant Tera. - * @returns this + * @param index - The index within the team to have instant Tera. + * @param condition - A condition under which the tera will occur + * @returns `this` */ - setInstantTera(index: number): TrainerConfig { - this.trainerAI.setInstantTera(index); + setInstantTera(index: number, condition?: () => boolean): this { + this.trainerAI.setInstantTera(index, condition); return this; } @@ -558,17 +588,18 @@ export class TrainerConfig { /** * Initializes the trainer configuration for an evil team admin. - * @param title The title of the evil team admin. - * @param poolName The evil team the admin belongs to. - * @param signatureSpecies The signature species for the evil team leader. - * @param specialtyType The specialty Type of the admin, if they have one + * @param title - The title of the evil team admin. + * @param poolName - The evil team the admin belongs to. + * @param signatureSpecies - The signature species for the evil team leader. + * @param specialtyType - The specialty Type of the admin, if they have one + * @param starAdminInstantTeraSlot - (default `4`); If the admin is a Star Admin, the slot that should instantly Tera in {@linkcode ClassicFixedBossWaves.EVIL_ADMIN_3} * @returns The updated TrainerConfig instance. */ initForEvilTeamAdmin( title: string, poolName: EvilTeam, - signatureSpecies: (SpeciesId | SpeciesId[])[], specialtyType?: PokemonType, + starAdminInstantTeraSlot = 4, ): TrainerConfig { if (!getIsInitialized()) { initI18n(); @@ -578,15 +609,18 @@ export class TrainerConfig { this.setSpecialtyType(specialtyType); } + if (title === "star_admin") { + this.setInstantTera( + starAdminInstantTeraSlot, + () => globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3, + ); + } + this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); // Set the species pools for the evil team admin. this.speciesPools = evilAdminTrainerPools[poolName]; - signatureSpecies.forEach((speciesPool, s) => { - this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(coerceArray(speciesPool))); - }); - const nameForCall = toCamelCase(this.name); this.name = i18next.t(`trainerNames:${nameForCall}`); this.setHasVoucher(false); @@ -2014,18 +2048,18 @@ export const trainerConfigs: TrainerConfigs = { SpeciesId.CUBONE, SpeciesId.LICKITUNG, SpeciesId.TAUROS, - SpeciesId.MAGIKARP, SpeciesId.MURKROW, - SpeciesId.ELEKID, - SpeciesId.MAGBY, ], [TrainerPoolTier.RARE]: [ + SpeciesId.MAGIKARP, SpeciesId.ABRA, SpeciesId.GASTLY, SpeciesId.SCYTHER, SpeciesId.PORYGON, SpeciesId.OMANYTE, SpeciesId.KABUTO, + SpeciesId.ELEKID, + SpeciesId.MAGBY, SpeciesId.ALOLA_RATTATA, SpeciesId.ALOLA_SANDSHREW, SpeciesId.ALOLA_MEOWTH, @@ -2037,36 +2071,83 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.ARCHER]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("rocket_admin", "rocket", [SpeciesId.HOUNDOOM]) + .initForEvilTeamAdmin("rocket_admin", "rocket_archer") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_rocket_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.ELECTRODE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.MAGMAR])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.HOUNDOOM], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 1; // Flash Fire + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.ARIANA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("rocket_admin_female", "rocket", [SpeciesId.ARBOK]) + .initForEvilTeamAdmin("rocket_admin_female", "rocket_ariana") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_rocket_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.VILEPLUME])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.HONCHKROW])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.ARBOK], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 0; // Intimidate + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.PROTON]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("rocket_admin", "rocket", [SpeciesId.CROBAT]) + .initForEvilTeamAdmin("rocket_admin", "rocket_proton") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_rocket_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MUK])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.ELECTIVIRE])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.CROBAT], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.PETREL]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("rocket_admin", "rocket", [SpeciesId.WEEZING]) + .initForEvilTeamAdmin("rocket_admin", "rocket_petrel") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_rocket_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.RATICATE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.GALAR_WEEZING])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.WEEZING], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t) .setHasGenders("Magma Grunt Female") .setHasDouble("Magma Grunts") @@ -2079,51 +2160,75 @@ export const trainerConfigs: TrainerConfigs = { .setSpeciesPools({ [TrainerPoolTier.COMMON]: [ SpeciesId.DIGLETT, - SpeciesId.GROWLITHE, + SpeciesId.KOFFING, SpeciesId.SLUGMA, SpeciesId.POOCHYENA, SpeciesId.ZIGZAGOON, - SpeciesId.NUMEL, SpeciesId.TORKOAL, SpeciesId.BALTOY, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.RHYHORN, SpeciesId.PHANPY, SpeciesId.MAGBY, SpeciesId.ZANGOOSE, + SpeciesId.NUMEL, SpeciesId.SOLROCK, SpeciesId.HEATMOR, SpeciesId.ROLYCOLY, - SpeciesId.CAPSAKID, + SpeciesId.SIZZLIPEDE, ], [TrainerPoolTier.RARE]: [ SpeciesId.TRAPINCH, SpeciesId.LILEEP, SpeciesId.ANORITH, - SpeciesId.GOLETT, SpeciesId.TURTONATOR, SpeciesId.TOEDSCOOL, - SpeciesId.HISUI_GROWLITHE, + SpeciesId.CAPSAKID, ], - [TrainerPoolTier.SUPER_RARE]: [SpeciesId.CHARCADET, SpeciesId.ARON], + [TrainerPoolTier.SUPER_RARE]: [SpeciesId.RHYHORN, SpeciesId.ARON], }), [TrainerType.TABITHA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("magma_admin", "magma", [SpeciesId.CAMERUPT]) + .initForEvilTeamAdmin("magma_admin", "magma") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_aqua_magma_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.TORKOAL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.FLYGON])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 1; // Solid Rock + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.COURTNEY]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("magma_admin_female", "magma", [SpeciesId.CAMERUPT]) + .initForEvilTeamAdmin("magma_admin_female", "magma") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_aqua_magma_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.NINETALES])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.CLAYDOL])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 1; // Solid Rock + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.AQUA_GRUNT]: new TrainerConfig(++t) .setHasGenders("Aqua Grunt Female") .setHasDouble("Aqua Grunts") @@ -2135,55 +2240,78 @@ export const trainerConfigs: TrainerConfigs = { .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) .setSpeciesPools({ [TrainerPoolTier.COMMON]: [ + SpeciesId.TENTACOOL, SpeciesId.QWILFISH, SpeciesId.REMORAID, SpeciesId.ZIGZAGOON, + SpeciesId.POOCHYENA, SpeciesId.LOTAD, SpeciesId.WINGULL, - SpeciesId.CARVANHA, - SpeciesId.WAILMER, SpeciesId.BARBOACH, SpeciesId.CORPHISH, - SpeciesId.SPHEAL, ], [TrainerPoolTier.UNCOMMON]: [ - SpeciesId.TENTACOOL, SpeciesId.HORSEA, SpeciesId.CHINCHOU, SpeciesId.WOOPER, SpeciesId.AZURILL, SpeciesId.SEVIPER, + SpeciesId.CARVANHA, + SpeciesId.WAILMER, SpeciesId.CLAMPERL, - SpeciesId.WIMPOD, - SpeciesId.CLOBBOPUS, + SpeciesId.SPHEAL, ], [TrainerPoolTier.RARE]: [ SpeciesId.MANTYKE, SpeciesId.TYMPOLE, SpeciesId.SKRELP, + SpeciesId.WIMPOD, + SpeciesId.CLOBBOPUS, SpeciesId.ARROKUDA, SpeciesId.WIGLETT, - SpeciesId.HISUI_QWILFISH, - SpeciesId.PALDEA_WOOPER, ], - [TrainerPoolTier.SUPER_RARE]: [SpeciesId.BASCULEGION, SpeciesId.DONDOZO], + [TrainerPoolTier.SUPER_RARE]: [SpeciesId.FEEBAS, SpeciesId.DONDOZO], }), [TrainerType.MATT]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("aqua_admin", "aqua", [SpeciesId.SHARPEDO]) + .initForEvilTeamAdmin("aqua_admin", "aqua") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_aqua_magma_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.AZUMARILL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.HUNTAIL])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.SHELLY]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("aqua_admin_female", "aqua", [SpeciesId.SHARPEDO]) + .initForEvilTeamAdmin("aqua_admin_female", "aqua") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_aqua_magma_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.CRAWDAUNT])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.GOREBYSS])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t) .setHasGenders("Galactic Grunt Female") .setHasDouble("Galactic Grunts") @@ -2212,7 +2340,7 @@ export const trainerConfigs: TrainerConfigs = { SpeciesId.TANGELA, SpeciesId.YANMA, SpeciesId.GLIGAR, - SpeciesId.SWINUB, + SpeciesId.SHELLOS, SpeciesId.SKORUPI, ], [TrainerPoolTier.RARE]: [ @@ -2220,36 +2348,73 @@ export const trainerConfigs: TrainerConfigs = { SpeciesId.TEDDIURSA, SpeciesId.ELEKID, SpeciesId.MAGBY, + SpeciesId.SWINUB, SpeciesId.DUSKULL, - SpeciesId.HISUI_GROWLITHE, - SpeciesId.HISUI_QWILFISH, ], - [TrainerPoolTier.SUPER_RARE]: [SpeciesId.SPIRITOMB, SpeciesId.ROTOM, SpeciesId.HISUI_SNEASEL], + [TrainerPoolTier.SUPER_RARE]: [SpeciesId.SPIRITOMB, SpeciesId.ROTOM], }), [TrainerType.JUPITER]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("galactic_commander_female", "galactic", [SpeciesId.SKUNTANK]) + .initForEvilTeamAdmin("galactic_commander_female", "galactic_jupiter") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_galactic_admin") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.TANGROWTH])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BRONZONG])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.SKUNTANK], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.MARS]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("galactic_commander_female", "galactic", [SpeciesId.PURUGLY]) + .initForEvilTeamAdmin("galactic_commander_female", "galactic_mars") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_galactic_admin") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.YANMEGA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BRONZONG])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.PURUGLY], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 0; // Thick Fat + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.SATURN]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("galactic_commander", "galactic", [SpeciesId.TOXICROAK]) + .initForEvilTeamAdmin("galactic_commander", "galactic_saturn") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_galactic_admin") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.ALAKAZAM])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BRONZONG])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.TOXICROAK], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 1; // Dry Skin + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t) .setHasGenders("Plasma Grunt Female") .setHasDouble("Plasma Grunts") @@ -2296,20 +2461,42 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.ZINZOLIN]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("plasma_sage", "plasma_zinzolin", [SpeciesId.CRYOGONAL]) + .initForEvilTeamAdmin("plasma_sage", "plasma_zinzolin") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_plasma_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.CRYOGONAL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.VANILLUXE])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.WEAVILE], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.COLRESS]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("plasma_boss", "plasma_colress", [SpeciesId.KLINKLANG]) + .initForEvilTeamAdmin("plasma_boss", "plasma_colress") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_colress") .setMixedBattleBgm("battle_colress") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MAGNEZONE])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BEHEEYEM])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.KLINKLANG], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 2; // Clear Body + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.FLARE_GRUNT]: new TrainerConfig(++t) .setHasGenders("Flare Grunt Female") .setHasDouble("Flare Grunts") @@ -2321,19 +2508,21 @@ export const trainerConfigs: TrainerConfigs = { .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) .setSpeciesPools({ [TrainerPoolTier.COMMON]: [ - SpeciesId.HOUNDOUR, SpeciesId.GULPIN, SpeciesId.SKORUPI, SpeciesId.CROAGUNK, SpeciesId.PURRLOIN, SpeciesId.SCRAGGY, + SpeciesId.BUNNELBY, SpeciesId.FLETCHLING, SpeciesId.SCATTERBUG, SpeciesId.LITLEO, SpeciesId.ESPURR, + SpeciesId.HELIOPTILE, SpeciesId.INKAY, ], [TrainerPoolTier.UNCOMMON]: [ + SpeciesId.HOUNDOUR, SpeciesId.POOCHYENA, SpeciesId.ELECTRIKE, SpeciesId.FOONGUS, @@ -2341,29 +2530,48 @@ export const trainerConfigs: TrainerConfigs = { SpeciesId.BINACLE, SpeciesId.SKRELP, SpeciesId.CLAUNCHER, - SpeciesId.HELIOPTILE, SpeciesId.PHANTUMP, SpeciesId.PUMPKABOO, ], - [TrainerPoolTier.RARE]: [SpeciesId.SNEASEL, SpeciesId.LITWICK, SpeciesId.PAWNIARD, SpeciesId.NOIBAT], - [TrainerPoolTier.SUPER_RARE]: [SpeciesId.SLIGGOO, SpeciesId.HISUI_SLIGGOO, SpeciesId.HISUI_AVALUGG], + [TrainerPoolTier.RARE]: [SpeciesId.LITWICK, SpeciesId.BERGMITE, SpeciesId.NOIBAT], + [TrainerPoolTier.SUPER_RARE]: [SpeciesId.GOOMY, SpeciesId.HONEDGE], }), [TrainerType.BRYONY]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("flare_admin_female", "flare", [SpeciesId.LIEPARD]) + .initForEvilTeamAdmin("flare_admin_female", "flare") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_flare_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.LIEPARD])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.BISHARP], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.XEROSIC]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("flare_admin", "flare", [SpeciesId.MALAMAR]) + .initForEvilTeamAdmin("flare_admin", "flare_xerosic", PokemonType.FIRE) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_flare_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.CROBAT])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.MALAMAR], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 0; // Contrary + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.AETHER_GRUNT]: new TrainerConfig(++t) .setHasGenders("Aether Grunt Female") .setHasDouble("Aether Grunts") @@ -2417,12 +2625,25 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.FABA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("aether_admin", "aether", [SpeciesId.HYPNO]) + .initForEvilTeamAdmin("aether_admin", "aether") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_aether_grunt") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.BRUXISH])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.ALOLA_RAICHU])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.HYPNO], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 1; // FOREWARN + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.SKULL_GRUNT]: new TrainerConfig(++t) .setHasGenders("Skull Grunt Female") .setHasDouble("Skull Grunts") @@ -2460,23 +2681,35 @@ export const trainerConfigs: TrainerConfigs = { SpeciesId.ALOLA_MAROWAK, ], [TrainerPoolTier.RARE]: [ - SpeciesId.PAWNIARD, + SpeciesId.DEWPIDER, SpeciesId.WISHIWASHI, SpeciesId.SANDYGAST, SpeciesId.MIMIKYU, SpeciesId.DHELMISE, SpeciesId.NYMBLE, ], - [TrainerPoolTier.SUPER_RARE]: [SpeciesId.GRUBBIN, SpeciesId.DEWPIDER], + [TrainerPoolTier.SUPER_RARE]: [SpeciesId.PAWNIARD, SpeciesId.GRUBBIN], }), [TrainerType.PLUMERIA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("skull_admin", "skull", [SpeciesId.SALAZZLE]) + .initForEvilTeamAdmin("skull_admin", "skull") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_skull_admin") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.TOXAPEX])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.ALOLA_MUK])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.SALAZZLE], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.MACRO_GRUNT]: new TrainerConfig(++t) .setHasGenders("Macro Grunt Female") .setHasDouble("Macro Grunts") @@ -2524,12 +2757,25 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.OLEANA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("macro_admin", "macro_cosmos", [SpeciesId.GARBODOR]) + .initForEvilTeamAdmin("macro_admin", "macro_cosmos") .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_oleana") .setVictoryBgm("victory_team_plasma") - .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()), + .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MILOTIC])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.TSAREENA])) + .setPartyMemberFunc( + 5, + getRandomPartyMemberFunc([SpeciesId.GARBODOR], TrainerSlot.TRAINER, true, p => { + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_3) { + p.setBoss(true, 2); + } + p.abilityIndex = 0; // Weak Armor + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; + }), + ), [TrainerType.STAR_GRUNT]: new TrainerConfig(++t) .setHasGenders("Star Grunt Female") .setHasDouble("Star Grunts") @@ -2591,102 +2837,137 @@ export const trainerConfigs: TrainerConfigs = { }), [TrainerType.GIACOMO]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_dark", [SpeciesId.KINGAMBIT], PokemonType.DARK) + .initForEvilTeamAdmin("star_admin", "star_dark", PokemonType.DARK) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") .setVictoryBgm("victory_team_plasma") .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MABOSSTIFF])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.KINGAMBIT])) .setPartyMemberFunc( - 3, + 5, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = 1; // Segin Starmobile - p.moveset = [ - new PokemonMove(MoveId.WICKED_TORQUE), - new PokemonMove(MoveId.SPIN_OUT), - new PokemonMove(MoveId.PARTING_SHOT), - new PokemonMove(MoveId.HIGH_HORSEPOWER), - ]; + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_1) { + p.formIndex = 0; + p.generateAndPopulateMoveset(); + } else { + p.formIndex = 1; // Segin Starmobile + p.moveset = [ + new PokemonMove(MoveId.WICKED_TORQUE), + new PokemonMove(MoveId.SPIN_OUT), + new PokemonMove(MoveId.PARTING_SHOT), + new PokemonMove(MoveId.HIGH_HORSEPOWER), + ]; + } }), ), [TrainerType.MELA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_fire", [SpeciesId.ARMAROUGE], PokemonType.FIRE) + .initForEvilTeamAdmin("star_admin", "star_fire", PokemonType.FIRE) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") .setVictoryBgm("victory_team_plasma") .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.SCOVILLAIN])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.ARMAROUGE])) .setPartyMemberFunc( - 3, + 5, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = 2; // Schedar Starmobile - p.moveset = [ - new PokemonMove(MoveId.BLAZING_TORQUE), - new PokemonMove(MoveId.SPIN_OUT), - new PokemonMove(MoveId.FLAME_CHARGE), - new PokemonMove(MoveId.HIGH_HORSEPOWER), - ]; + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_1) { + p.formIndex = 0; + p.generateAndPopulateMoveset(); + } else { + p.formIndex = 2; // Schedar Starmobile + p.moveset = [ + new PokemonMove(MoveId.BLAZING_TORQUE), + new PokemonMove(MoveId.SPIN_OUT), + new PokemonMove(MoveId.FLAME_CHARGE), + new PokemonMove(MoveId.HIGH_HORSEPOWER), + ]; + } }), ), [TrainerType.ATTICUS]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_poison", [SpeciesId.REVAVROOM], PokemonType.POISON) + .initForEvilTeamAdmin("star_admin", "star_poison", PokemonType.POISON) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") .setVictoryBgm("victory_team_plasma") .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GRAFAIAI])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.REVAVROOM])) .setPartyMemberFunc( - 3, + 5, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = 3; // Navi Starmobile - p.moveset = [ - new PokemonMove(MoveId.NOXIOUS_TORQUE), - new PokemonMove(MoveId.SPIN_OUT), - new PokemonMove(MoveId.TOXIC_SPIKES), - new PokemonMove(MoveId.HIGH_HORSEPOWER), - ]; + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_1) { + p.formIndex = 0; + p.generateAndPopulateMoveset(); + } else { + p.formIndex = 3; // Navi Starmobile + p.moveset = [ + new PokemonMove(MoveId.NOXIOUS_TORQUE), + new PokemonMove(MoveId.SPIN_OUT), + new PokemonMove(MoveId.TOXIC_SPIKES), + new PokemonMove(MoveId.HIGH_HORSEPOWER), + ]; + } }), ), [TrainerType.ORTEGA]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_fairy", [SpeciesId.DACHSBUN], PokemonType.FAIRY) + .initForEvilTeamAdmin("star_admin", "star_fairy", PokemonType.FAIRY) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") .setVictoryBgm("victory_team_plasma") .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.TINKATON])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.DACHSBUN])) .setPartyMemberFunc( - 3, + 5, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = 4; // Ruchbah Starmobile - p.moveset = [ - new PokemonMove(MoveId.MAGICAL_TORQUE), - new PokemonMove(MoveId.SPIN_OUT), - new PokemonMove(MoveId.MISTY_TERRAIN), - new PokemonMove(MoveId.HIGH_HORSEPOWER), - ]; + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_1) { + p.formIndex = 0; + p.generateAndPopulateMoveset(); + } else { + p.formIndex = 4; // Ruchbah Starmobile + p.moveset = [ + new PokemonMove(MoveId.MAGICAL_TORQUE), + new PokemonMove(MoveId.SPIN_OUT), + new PokemonMove(MoveId.MISTY_TERRAIN), + new PokemonMove(MoveId.HIGH_HORSEPOWER), + ]; + } }), ), [TrainerType.ERI]: new TrainerConfig(++t) .setMoneyMultiplier(1.5) - .initForEvilTeamAdmin("star_admin", "star_fighting", [SpeciesId.ANNIHILAPE], PokemonType.FIGHTING) + .initForEvilTeamAdmin("star_admin", "star_fighting", PokemonType.FIGHTING) .setEncounterBgm(TrainerType.PLASMA_GRUNT) .setBattleBgm("battle_plasma_grunt") .setMixedBattleBgm("battle_star_admin") .setVictoryBgm("victory_team_plasma") .setPartyTemplateFunc(() => getEvilGruntPartyTemplate()) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.FLAMIGO])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.ANNIHILAPE])) .setPartyMemberFunc( - 3, + 5, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { - p.formIndex = 5; // Caph Starmobile - p.moveset = [ - new PokemonMove(MoveId.COMBAT_TORQUE), - new PokemonMove(MoveId.SPIN_OUT), - new PokemonMove(MoveId.IRON_DEFENSE), - new PokemonMove(MoveId.HIGH_HORSEPOWER), - ]; + if (globalScene.currentBattle.waveIndex === ClassicFixedBossWaves.EVIL_ADMIN_1) { + p.formIndex = 0; + p.generateAndPopulateMoveset(); + } else { + p.formIndex = 5; // Caph Starmobile + p.moveset = [ + new PokemonMove(MoveId.COMBAT_TORQUE), + new PokemonMove(MoveId.SPIN_OUT), + new PokemonMove(MoveId.IRON_DEFENSE), + new PokemonMove(MoveId.HIGH_HORSEPOWER), + ]; + } }), ), @@ -3161,8 +3442,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.ORICORIO, SpeciesId.ALOLA_MAROWAK], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = p.species.speciesId === SpeciesId.ORICORIO ? 3 : 0; // Oricorio-Sensu + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -3842,10 +4123,17 @@ export const trainerConfigs: TrainerConfigs = { p => { p.generateAndPopulateMoveset(); p.teraType = p.species.type1; + p.abilityIndex = p.species.speciesId === SpeciesId.EXEGGUTOR ? 2 : 0; // Intimidate Gyarados / Arcanine, Harvest Exeggutor }, ), ) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.RHYPERIOR, SpeciesId.ELECTIVIRE])) + .setPartyMemberFunc( + 2, + getRandomPartyMemberFunc([SpeciesId.RHYPERIOR, SpeciesId.ELECTIVIRE], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = p.species.speciesId === SpeciesId.RHYPERIOR ? 1 : 0; // Solid Rock Rhyperior, Motor Drive Electivire + }), + ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MACHAMP])) .setPartyMemberFunc( 4, @@ -3858,11 +4146,11 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.PIDGEOT], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 1; // Mega Pidgeot p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; - p.setBoss(true, 2); }), ) .setInstantTera(1), // Tera Fire Arcanine, Tera Grass Exeggutor, Tera Water Gyarados @@ -3887,7 +4175,13 @@ export const trainerConfigs: TrainerConfigs = { ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.MEGANIUM, SpeciesId.TYPHLOSION, SpeciesId.FERALIGATR])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.ESPEON, SpeciesId.UMBREON, SpeciesId.SYLVEON])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.SNORLAX])) + .setPartyMemberFunc( + 3, + getRandomPartyMemberFunc([SpeciesId.SNORLAX], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); + p.abilityIndex = 1; // Thick Fat + }), + ) .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.LUGIA], TrainerSlot.TRAINER, true, p => { @@ -3903,21 +4197,37 @@ export const trainerConfigs: TrainerConfigs = { TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 1; // Mega Venusaur, Mega Charizard X, or Mega Blastoise p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; - p.setBoss(true, 2); }, ), ) - .setInstantTera(0), // Tera Electric Pikachu + .setInstantTera(0) // Tera Electric Pikachu + .setGenModifiersFunc(party => { + const pikachu = party[0]; + return [ + modifierTypes + .RARE_SPECIES_STAT_BOOSTER() + .generateType([], ["LIGHT_BALL"]) + ?.withIdFromFunc(modifierTypes.RARE_SPECIES_STAT_BOOSTER) + .newModifier(pikachu) as SpeciesStatBoosterModifier, + ]; + }), [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t) .setName("Lance") .initForChampion(true) .setBattleBgm("battle_johto_champion") .setMixedBattleBgm("battle_johto_champion") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.GYARADOS, SpeciesId.KINGDRA])) + .setPartyMemberFunc( + 0, + getRandomPartyMemberFunc([SpeciesId.GYARADOS, SpeciesId.KINGDRA], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Intimidate Gyarados, Sniper Kingdra + p.generateAndPopulateMoveset(); + }), + ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.AERODACTYL])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.CHARIZARD])) .setPartyMemberFunc( @@ -3943,11 +4253,11 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.DRAGONITE], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.abilityIndex = 2; // Multiscale - p.gender = Gender.MALE; p.setBoss(true, 2); p.teraType = PokemonType.DRAGON; + p.abilityIndex = 2; // Multiscale + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; }), ) .setInstantTera(5), // Tera Dragon Dragonite @@ -3965,7 +4275,13 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); }), ) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.SKARMORY, SpeciesId.CLAYDOL])) + .setPartyMemberFunc( + 1, + getRandomPartyMemberFunc([SpeciesId.SKARMORY, SpeciesId.CLAYDOL], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Sturdy Skarmory, Levitate Claydol + p.generateAndPopulateMoveset(); + }), + ) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.AGGRON])) .setPartyMemberFunc( 3, @@ -3989,13 +4305,18 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.METAGROSS], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 1; // Mega Metagross p.generateAndPopulateMoveset(); p.generateName(); - p.setBoss(true, 2); }), ) - .setInstantTera(4), // Tera Rock Regirock / Ice Regice / Steel Registeel + .setInstantTera(4) // Tera Rock Regirock / Ice Regice / Steel Registeel + .setGenModifiersFunc(party => { + // Mystical Rock Gigalith + const weather = party[0]; + return [modifierTypes.MYSTICAL_ROCK().newModifier(weather)]; + }), [TrainerType.WALLACE]: new TrainerConfig(++t) .initForChampion(true) .setBattleBgm("battle_hoenn_champion_g5") @@ -4028,7 +4349,6 @@ export const trainerConfigs: TrainerConfigs = { 3, getRandomPartyMemberFunc([SpeciesId.LATIAS, SpeciesId.LATIOS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); - p.generateName(); p.pokeball = PokeballType.ULTRA_BALL; }), ) @@ -4043,12 +4363,17 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.MILOTIC], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.gender = Gender.FEMALE; - p.setBoss(true, 2); }), ) - .setInstantTera(5), // Tera Water Milotic + .setInstantTera(5) // Tera Water Milotic + .setGenModifiersFunc(party => { + // Mystical Rock Pelipper + const weather = party[0]; + return [modifierTypes.MYSTICAL_ROCK().newModifier(weather)]; + }), [TrainerType.CYNTHIA]: new TrainerConfig(++t) .initForChampion(false) .setBattleBgm("battle_sinnoh_champion") @@ -4058,6 +4383,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.TOGEKISS], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Serene Grace p.generateAndPopulateMoveset(); p.teraType = p.species.type1; }), @@ -4073,11 +4399,11 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.GARCHOMP], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 1; // Mega Garchomp p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.FEMALE; - p.setBoss(true, 2); }), ) .setInstantTera(2), // Tera Fairy Togekiss @@ -4096,6 +4422,7 @@ export const trainerConfigs: TrainerConfigs = { TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Hustle Lilligant, Illusion Zoroark, Adaptability Basculegion p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; }, @@ -4108,13 +4435,13 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.KELDEO], TrainerSlot.TRAINER, true, p => { - p.pokeball = PokeballType.ROGUE_BALL; + p.formIndex = 1; // Resolute Form p.generateAndPopulateMoveset(); if (!p.moveset.some(move => move != null && move.moveId === MoveId.SECRET_SWORD)) { // Check if Secret Sword is in the moveset, if not, replace the third move with Secret Sword. p.moveset[2] = new PokemonMove(MoveId.SECRET_SWORD); } - p.formIndex = 1; // Resolute Form + p.pokeball = PokeballType.ROGUE_BALL; }), ) .setPartyMemberFunc( @@ -4127,10 +4454,10 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.VOLCARONA], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; p.setBoss(true, 2); p.teraType = PokemonType.FIRE; + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; }), ) .setInstantTera(5), // Tera Fire Volcarona @@ -4168,10 +4495,10 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.HAXORUS], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.abilityIndex = 1; // Mold Breaker p.generateAndPopulateMoveset(); p.gender = Gender.FEMALE; - p.setBoss(true, 2); }), ) .setInstantTera(5), // Tera Dragon Haxorus @@ -4189,9 +4516,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.TYRANTRUM, SpeciesId.AURORUS], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Rock Head Tyrantrum, Snow Warning Aurorus p.teraType = p.species.type2!; + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GOODRA])) @@ -4205,11 +4532,11 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.GARDEVOIR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 1; // Mega Gardevoir p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.FEMALE; - p.setBoss(true, 2); }), ) .setInstantTera(2), // Tera Dragon Tyrantrum / Ice Aurorus @@ -4219,15 +4546,15 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 0, getRandomPartyMemberFunc([SpeciesId.LYCANROC], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 2; // Dusk Lycanroc + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.MAGNEZONE, SpeciesId.ALOLA_NINETALES], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = p.species.speciesId === SpeciesId.MAGNEZONE ? 1 : 2; // Sturdy Magnezone, Snow Warning Ninetales + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -4246,25 +4573,25 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.TAPU_LELE, SpeciesId.TAPU_FINI], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 0; // Psychic / Misty Surge p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.abilityIndex = 0; // Psychic / Misty Surge }), ) .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.SNORLAX], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 1; // G-Max Snorlax + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.INCINEROAR, SpeciesId.HISUI_DECIDUEYE], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; p.teraType = p.species.type2!; p.setBoss(true, 2); + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; }), ) .setInstantTera(5), // Tera Dark Incineroar / Fighting Hisuian Decidueye @@ -4289,9 +4616,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.TAPU_KOKO, SpeciesId.TAPU_BULU], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 0; // Electric / Grassy Surge p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.abilityIndex = 0; // Electric / Grassy Surge }), ) .setPartyMemberFunc( @@ -4304,8 +4631,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.DECIDUEYE, SpeciesId.PRIMARINA], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.setBoss(true, 2); + p.generateAndPopulateMoveset(); p.gender = p.species.speciesId === SpeciesId.PRIMARINA ? Gender.FEMALE : Gender.MALE; p.teraType = p.species.speciesId === SpeciesId.PRIMARINA ? PokemonType.WATER : PokemonType.GHOST; }), @@ -4339,11 +4666,11 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.CHARIZARD], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = 3; // G-Max Charizard p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; - p.setBoss(true, 2); }), ) .setInstantTera(3), // Tera Grass Rillaboom, Fire Cinderace, Water Inteleon @@ -4375,6 +4702,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.VENUSAUR, SpeciesId.BLASTOISE], TrainerSlot.TRAINER, true, p => { + p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; }), ) @@ -4383,7 +4711,6 @@ export const trainerConfigs: TrainerConfigs = { getRandomPartyMemberFunc([SpeciesId.KOMMO_O], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -4414,9 +4741,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 0, getRandomPartyMemberFunc([SpeciesId.GLIMMORA], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.gender = Gender.MALE; - p.setBoss(true, 2); }), ) .setPartyMemberFunc( @@ -4438,13 +4765,13 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.KINGAMBIT], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Supreme Overlord + p.teraType = PokemonType.FLYING; p.generateAndPopulateMoveset(); if (!p.moveset.some(move => move != null && move.moveId === MoveId.TERA_BLAST)) { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. p.moveset[2] = new PokemonMove(MoveId.TERA_BLAST); } - p.abilityIndex = 1; // Supreme Overlord - p.teraType = PokemonType.FLYING; }), ) .setInstantTera(5), // Tera Flying Kingambit @@ -4458,7 +4785,13 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); }), ) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.PAWMOT])) + .setPartyMemberFunc( + 1, + getRandomPartyMemberFunc([SpeciesId.PAWMOT], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 2; // Iron Fist + p.generateAndPopulateMoveset(); + }), + ) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.DUDUNSPARCE], TrainerSlot.TRAINER, true, p => { @@ -4481,10 +4814,10 @@ export const trainerConfigs: TrainerConfigs = { TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; p.setBoss(true, 2); p.teraType = p.species.type2!; + p.generateAndPopulateMoveset(); + p.gender = Gender.MALE; }, ), ) @@ -4496,8 +4829,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.INCINEROAR, SpeciesId.GRIMMSNARL], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = p.species.speciesId === SpeciesId.INCINEROAR ? 2 : 0; // Intimidate Incineroar, Prankster Grimmsnarl + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -4528,7 +4861,6 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.HYDRAPPLE], TrainerSlot.TRAINER, true, p => { - p.gender = Gender.MALE; p.setBoss(true, 2); p.teraType = PokemonType.FIGHTING; p.generateAndPopulateMoveset(); @@ -4536,6 +4868,7 @@ export const trainerConfigs: TrainerConfigs = { // Check if Tera Blast is in the moveset, if not, replace the third move with Tera Blast. p.moveset[2] = new PokemonMove(MoveId.TERA_BLAST); } + p.gender = Gender.MALE; }), ) .setInstantTera(5), // Tera Fighting Hydrapple @@ -4661,19 +4994,19 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Kangaskhan p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; }), ) .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.RHYPERIOR], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.abilityIndex = 1; // Solid Rock - p.setBoss(true, 2); }), ), [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t) @@ -4693,8 +5026,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.NIDOKING, SpeciesId.NIDOQUEEN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Sheer Force + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -4710,10 +5043,10 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Kangaskhan p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; }), ) .setPartyMemberFunc( @@ -4723,10 +5056,10 @@ export const trainerConfigs: TrainerConfigs = { TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); + p.abilityIndex = 2; // Snow Cloak Articuno, Static Zapdos, Flame Body Moltres p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.abilityIndex = 2; // Snow Cloak Articuno, Static Zapdos, Flame Body Moltres - p.setBoss(true, 2); }, ), ) @@ -4746,8 +5079,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 0, getRandomPartyMemberFunc([SpeciesId.TORKOAL], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 1; // Drought + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.SOLROCK])) @@ -4755,8 +5088,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.SCOVILLAIN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 0; // Chlorophyll + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.DONPHAN])) @@ -4764,10 +5097,10 @@ export const trainerConfigs: TrainerConfigs = { 5, getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Camerupt p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.MALE; }), ), @@ -4787,19 +5120,19 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.NINETALES, SpeciesId.TORKOAL], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); if (p.species.speciesId === SpeciesId.NINETALES) { p.abilityIndex = 2; // Drought } else if (p.species.speciesId === SpeciesId.TORKOAL) { p.abilityIndex = 1; // Drought } + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.SCOVILLAIN], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 0; // Chlorophyll + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -4813,10 +5146,10 @@ export const trainerConfigs: TrainerConfigs = { 4, getRandomPartyMemberFunc([SpeciesId.CAMERUPT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Camerupt p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.MALE; }), ) @@ -4854,10 +5187,10 @@ export const trainerConfigs: TrainerConfigs = { 5, getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Sharpedo p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.MALE; }), ), @@ -4877,12 +5210,12 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.POLITOED, SpeciesId.PELIPPER], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); if (p.species.speciesId === SpeciesId.POLITOED) { p.abilityIndex = 2; // Drizzle } else if (p.species.speciesId === SpeciesId.PELIPPER) { p.abilityIndex = 1; // Drizzle } + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.DHELMISE])) @@ -4897,10 +5230,10 @@ export const trainerConfigs: TrainerConfigs = { 4, getRandomPartyMemberFunc([SpeciesId.SHARPEDO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Sharpedo p.generateName(); + p.generateAndPopulateMoveset(); + p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.MALE; }), ) @@ -4960,10 +5293,10 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc([SpeciesId.HOUNDOOM], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Houndoom + p.generateAndPopulateMoveset(); p.generateName(); + p.pokeball = PokeballType.ULTRA_BALL; }), ) .setPartyMemberFunc( @@ -5017,9 +5350,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.JELLICENT, SpeciesId.BASCULEGION], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); - p.gender = Gender.MALE; p.formIndex = 0; + p.gender = Gender.MALE; + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.KINGAMBIT])) @@ -5071,11 +5404,11 @@ export const trainerConfigs: TrainerConfigs = { 5, getRandomPartyMemberFunc([SpeciesId.GYARADOS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Gyarados + p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; + p.pokeball = PokeballType.ULTRA_BALL; }), ), [TrainerType.LYSANDRE_2]: new TrainerConfig(++t) @@ -5104,11 +5437,11 @@ export const trainerConfigs: TrainerConfigs = { 4, getRandomPartyMemberFunc([SpeciesId.GYARADOS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); - p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; // Mega Gyarados + p.generateAndPopulateMoveset(); p.generateName(); p.gender = Gender.MALE; + p.pokeball = PokeballType.ULTRA_BALL; }), ) .setPartyMemberFunc( @@ -5202,32 +5535,32 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 0, getRandomPartyMemberFunc([SpeciesId.YANMEGA, SpeciesId.LOKIX], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); if (p.species.speciesId === SpeciesId.YANMEGA) { p.abilityIndex = 1; // Tinted Lens } else if (p.species.speciesId === SpeciesId.LOKIX) { p.abilityIndex = 2; // Tinted Lens } + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.HERACROSS])) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.SCIZOR, SpeciesId.KLEAVOR], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); if (p.species.speciesId === SpeciesId.SCIZOR) { p.abilityIndex = 1; // Technician } else if (p.species.speciesId === SpeciesId.KLEAVOR) { p.abilityIndex = 2; // Sharpness } + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GALVANTULA, SpeciesId.VIKAVOLT])) .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.PINSIR], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 1; // Mega Pinsir + p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.generateName(); }), @@ -5272,8 +5605,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.CRAWDAUNT, SpeciesId.HISUI_SAMUROTT], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Sharpness Hisuian Samurott, Adaptability Crawdaunt + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -5350,8 +5683,8 @@ export const trainerConfigs: TrainerConfigs = { 5, getRandomPartyMemberFunc([SpeciesId.COPPERAJAH], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); p.formIndex = 1; // G-Max Copperajah + p.generateAndPopulateMoveset(); p.generateName(); p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.FEMALE; @@ -5374,9 +5707,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.DRACOZOLT, SpeciesId.DRACOVISH], TrainerSlot.TRAINER, true, p => { + p.abilityIndex = 1; // Strong Jaw Dracovish, Hustle Dracozolt p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; - p.abilityIndex = 1; // Strong Jaw Dracovish, Hustle Dracozolt }), ) .setPartyMemberFunc( @@ -5390,8 +5723,8 @@ export const trainerConfigs: TrainerConfigs = { 4, getRandomPartyMemberFunc([SpeciesId.COPPERAJAH], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); p.formIndex = 1; // G-Max Copperajah + p.generateAndPopulateMoveset(); p.generateName(); p.pokeball = PokeballType.ULTRA_BALL; p.gender = Gender.FEMALE; @@ -5418,7 +5751,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.ESPEON])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.UMBREON])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.LEAFEON, SpeciesId.GLACEON])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.VAPOREON, SpeciesId.FLAREON, SpeciesId.JOLTEON])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.VAPOREON, SpeciesId.FLAREON, SpeciesId.JOLTEON])) // Do not change order .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.SYLVEON], TrainerSlot.TRAINER, true, p => { @@ -5436,8 +5769,8 @@ export const trainerConfigs: TrainerConfigs = { 5, getRandomPartyMemberFunc([SpeciesId.EEVEE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); p.formIndex = 2; // G-Max Eevee + p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.generateName(); }), @@ -5464,8 +5797,8 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.ROTOM], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow + p.generateAndPopulateMoveset(); }), ) .setPartyMemberFunc( @@ -5478,7 +5811,7 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 3, getRandomPartyMemberFunc( - [SpeciesId.WALKING_WAKE, SpeciesId.GOUGING_FIRE, SpeciesId.RAGING_BOLT], + [SpeciesId.WALKING_WAKE, SpeciesId.GOUGING_FIRE, SpeciesId.RAGING_BOLT], // Do not change order TrainerSlot.TRAINER, true, p => { @@ -5490,18 +5823,18 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 4, getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { + p.setBoss(true, 2); p.formIndex = randSeedInt(5, 1); // Random Starmobile form p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ROGUE_BALL; - p.setBoss(true, 2); }), ) .setPartyMemberFunc( 5, getRandomPartyMemberFunc([SpeciesId.EEVEE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); + p.formIndex = 2; // G-Max p.generateAndPopulateMoveset(); - p.formIndex = 2; p.generateName(); p.pokeball = PokeballType.ULTRA_BALL; }), @@ -5522,7 +5855,6 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.VENUSAUR, SpeciesId.COALOSSAL], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.pokeball = PokeballType.GREAT_BALL; if (p.species.speciesId === SpeciesId.VENUSAUR) { p.formIndex = 2; // Gmax @@ -5530,14 +5862,15 @@ export const trainerConfigs: TrainerConfigs = { } else { p.formIndex = 1; // Gmax } + p.generateAndPopulateMoveset(); p.generateName(); }), ) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.AGGRON], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 1; // Mega + p.generateAndPopulateMoveset(); p.generateName(); }), ) @@ -5571,17 +5904,17 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.SNORLAX, SpeciesId.LAPRAS], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; // Gmax p.generateAndPopulateMoveset(); p.pokeball = PokeballType.GREAT_BALL; - p.formIndex = 1; // Gmax p.generateName(); }), ) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.AUDINO], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 1; // Mega + p.generateAndPopulateMoveset(); p.generateName(); }), ) @@ -5613,17 +5946,17 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.CINDERACE, SpeciesId.INTELEON], TrainerSlot.TRAINER, true, p => { + p.formIndex = 1; // Gmax p.generateAndPopulateMoveset(); p.pokeball = PokeballType.GREAT_BALL; - p.formIndex = 1; // Gmax p.generateName(); }), ) .setPartyMemberFunc( 2, getRandomPartyMemberFunc([SpeciesId.AERODACTYL], TrainerSlot.TRAINER, true, p => { - p.generateAndPopulateMoveset(); p.formIndex = 1; // Mega + p.generateAndPopulateMoveset(); p.generateName(); }), ) @@ -5644,8 +5977,8 @@ export const trainerConfigs: TrainerConfigs = { 0, getRandomPartyMemberFunc([SpeciesId.ALAKAZAM], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); p.formIndex = 1; + p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.generateName(); }), @@ -5653,9 +5986,9 @@ export const trainerConfigs: TrainerConfigs = { .setPartyMemberFunc( 1, getRandomPartyMemberFunc([SpeciesId.GENGAR, SpeciesId.HATTERENE], TrainerSlot.TRAINER, true, p => { + p.formIndex = p.species.speciesId === SpeciesId.GENGAR ? 2 : 1; // Gmax p.generateAndPopulateMoveset(); p.pokeball = PokeballType.GREAT_BALL; - p.formIndex = p.species.speciesId === SpeciesId.GENGAR ? 2 : 1; // Gmax p.generateName(); }), ) @@ -5677,8 +6010,8 @@ export const trainerConfigs: TrainerConfigs = { 0, getRandomPartyMemberFunc([SpeciesId.LUCARIO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); - p.generateAndPopulateMoveset(); p.formIndex = 1; + p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.generateName(); }), diff --git a/src/data/trainers/trainer-party-template.ts b/src/data/trainers/trainer-party-template.ts index 450a1260f68..af2dac48dfd 100644 --- a/src/data/trainers/trainer-party-template.ts +++ b/src/data/trainers/trainer-party-template.ts @@ -186,6 +186,7 @@ export const trainerPartyTemplates = { new TrainerPartyTemplate(1, PartyMemberStrength.STRONG, undefined, undefined, EvoLevelThresholdKind.STRONG), new TrainerPartyTemplate(1, PartyMemberStrength.STRONGER, undefined, undefined, EvoLevelThresholdKind.STRONG), ), + /** 3 Average 2 Strong 1 Stronger */ GYM_LEADER_5: new TrainerPartyCompoundTemplate( new TrainerPartyTemplate(3, PartyMemberStrength.AVERAGE, undefined, undefined, EvoLevelThresholdKind.STRONG), new TrainerPartyTemplate(2, PartyMemberStrength.STRONG, undefined, undefined, EvoLevelThresholdKind.STRONG), @@ -254,7 +255,7 @@ export function getEvilGruntPartyTemplate(): TrainerPartyTemplate { return trainerPartyTemplates.TWO_AVG_ONE_STRONG; } if (waveIndex <= ClassicFixedBossWaves.EVIL_ADMIN_1) { - return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger + return trainerPartyTemplates.GYM_LEADER_5; // 3avg 2 strong 1 stronger } return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger } diff --git a/src/enums/fixed-boss-waves.ts b/src/enums/fixed-boss-waves.ts index b1725d14215..9e84f67d570 100644 --- a/src/enums/fixed-boss-waves.ts +++ b/src/enums/fixed-boss-waves.ts @@ -12,6 +12,7 @@ export enum ClassicFixedBossWaves { EVIL_ADMIN_2 = 114, EVIL_BOSS_1 = 115, RIVAL_5 = 145, + EVIL_ADMIN_3 = 164, EVIL_BOSS_2 = 165, ELITE_FOUR_1 = 182, ELITE_FOUR_2 = 184, diff --git a/src/field/trainer.ts b/src/field/trainer.ts index a41795ce718..7386c2d9e17 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -452,20 +452,21 @@ export class Trainer extends Phaser.GameObjects.Container { genNewPartyMemberSpecies(level: number, strength: PartyMemberStrength, attempt?: number): PokemonSpecies { const battle = globalScene.currentBattle; const template = this.getPartyTemplate(); - let baseSpecies: PokemonSpecies; if (this.config.speciesPools) { const tierValue = randSeedInt(512); - let tier = - tierValue >= 156 - ? TrainerPoolTier.COMMON - : tierValue >= 32 - ? TrainerPoolTier.UNCOMMON - : tierValue >= 6 - ? TrainerPoolTier.RARE - : tierValue >= 1 - ? TrainerPoolTier.SUPER_RARE - : TrainerPoolTier.ULTRA_RARE; + let tier: TrainerPoolTier; + if (tierValue >= 156) { + tier = TrainerPoolTier.COMMON; + } else if (tierValue >= 32) { + tier = TrainerPoolTier.UNCOMMON; + } else if (tierValue >= 6) { + tier = TrainerPoolTier.RARE; + } else if (tierValue >= 1) { + tier = TrainerPoolTier.SUPER_RARE; + } else { + tier = TrainerPoolTier.ULTRA_RARE; + } console.log(TrainerPoolTier[tier]); while (!this.config.speciesPools.hasOwnProperty(tier) || this.config.speciesPools[tier].length === 0) { console.log( @@ -474,7 +475,11 @@ export class Trainer extends Phaser.GameObjects.Container { tier--; } const tierPool = this.config.speciesPools[tier]; - baseSpecies = getPokemonSpecies(randSeedItem(tierPool)); + let rolledSpecies = randSeedItem(tierPool); + while (typeof rolledSpecies !== "number") { + rolledSpecies = randSeedItem(tierPool); + } + baseSpecies = getPokemonSpecies(rolledSpecies); } else { baseSpecies = globalScene.randomSpecies(battle.waveIndex, level, false, this.config.speciesFilter); } diff --git a/src/utils/random.ts b/src/utils/random.ts new file mode 100644 index 00000000000..530ee394c70 --- /dev/null +++ b/src/utils/random.ts @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2025 Pagefault Games + * SPDX-FileContributor: SirzBenjie + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +/** + * A collection of utility methods for working with the game's RNG + * @module + */ + +import { globalScene } from "#app/global-scene"; +import type { Mutable } from "#types/type-helpers"; +import { randSeedItem } from "#utils/common"; + +/** + * Select a random element using an offset such that the chosen element is + * guaranteed to be unique from the last `seedOffset` selections. + * + * @remarks + * If the seed offset is greater than the number of choices, this will just choose a random element + * + * @param arr - The array of items to choose from + * @param scene - (default {@linkcode globalScene}); The scene to use for random seeding + * @returns A random item from the array that is guaranteed to be different from the + * @typeParam T - The type of items in the array + * + * @example + * ``` + * const choices = ['a', 'b', 'c', 'd']; + * const choice1 = randSeedUniqueItem(choices, 0); + * const choice2 = randSeedUniqueItem(choices, 1); + * const choice3 = randSeedUniqueItem(choices, 2); + * assert(choice2 !== choice1); + * assert(choice3 !== choice1); + * assert(choice3 !== choice2); + * ``` + */ +export function randSeedUniqueItem(choices: readonly T[], seedOffset: number, scene = globalScene): T { + if (seedOffset === 0 || choices.length <= seedOffset) { + // cast to mutable is safe because randSeedItem does not actually modify the array + return randSeedItem(choices as Mutable); + } + + // TODO: Refactor `excuteWithSeedOffset` and pull it into this module + let choice: T; + + scene.executeWithSeedOffset(() => { + const curChoices = choices.slice(); + for (let i = 0; i < seedOffset; i++) { + const previousChoice = randSeedItem(curChoices); + curChoices.splice(curChoices.indexOf(previousChoice), 1); + } + choice = randSeedItem(curChoices); + }, seedOffset); + + // Bang is safe since there are at least `seedOffset` choices, so the method above is guaranteed to set `choice` + return choice!; +}