[Balance] Evil Team Admin Rework + Misc Trainer Changes (#6608)

* Update trainer-config.ts

* Update trainer-config.ts

* Revert "Update trainer-config.ts"

This reverts commit 6243592913.

* Revert "Update trainer-config.ts"

This reverts commit 6243592913.

* Update Admins, Add Admin 3

* Update Admins, Add Admin 3

* Update trainer-config.ts

* Update trainer-config.ts

* Initial Pool Updates

* Initial Pool Updates

* allow evil team admins to use subpools

* allow evil team admins to use subpools

* Remove trainer pool tier stairs

* freedom motif

* Remove trainer pool tier stairs

* freedom motif

* fix: missing import in trainer-config.ts

* Fix incorrect Starmobile forms

* Pool Updates + Boss additions

* Misc Changes

* Reorder p functions in Trainer Config

This let move gen properly account for Boss Health, Form Changes, and Abilities for future functions

* Ensure evil admins are uniquely selected in different fights

* Ensure evil admins are uniquely selected in different fights

* Implement evil team admin instant tera for slot 4

* Revert Starmobile Changes

* Minor Grunt Pool Changes

* Champion Adjustments

* Update trainer-config.ts

* Update trainer-config.ts

* Update challenge.ts

---------

Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
Co-authored-by: Madmadness65 <blaze.the.fireman@gmail.com>
This commit is contained in:
Blitzy 2025-10-08 00:08:50 -05:00 committed by GitHub
parent 112963637a
commit dacf71151a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 943 additions and 504 deletions

View File

@ -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;

View File

@ -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);
};
}

View File

@ -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];

View File

@ -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<EvilTeam, TrainerTierPools> = {
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,

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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,

View File

@ -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);
}

60
src/utils/random.ts Normal file
View File

@ -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<T>(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<typeof choices>);
}
// 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!;
}