From d7c28e27818cd981920fa03c4d7deb89c3707182 Mon Sep 17 00:00:00 2001 From: AJ Fontaine Date: Tue, 13 May 2025 18:20:55 -0400 Subject: [PATCH] Pokemon constructors accept pregen args --- src/battle-scene.ts | 6 +- src/data/trainers/trainer-config.ts | 61 +++++++++++++++++- src/field/pokemon.ts | 95 +++++++++++++++++++++++++---- src/system/pokemon-data.ts | 37 +++++++++++ 4 files changed, 184 insertions(+), 15 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index cf7f4062c7e..374b1b91729 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -186,6 +186,7 @@ import { hasExpSprite } from "./sprites/sprite-utils"; import { timedEventManager } from "./global-event-manager"; import { starterColors } from "./global-vars/starter-colors"; import { startingWave } from "./starting-wave"; +import { PokemonPregenData } from "#app/system/pokemon-data"; const DEBUG_RNG = false; @@ -977,6 +978,7 @@ export default class BattleScene extends SceneBase { shinyLock = false, dataSource?: PokemonData, postProcess?: (enemyPokemon: EnemyPokemon) => void, + pregenData?: PokemonPregenData, ): EnemyPokemon { if (Overrides.OPP_LEVEL_OVERRIDE > 0) { level = Overrides.OPP_LEVEL_OVERRIDE; @@ -987,12 +989,12 @@ export default class BattleScene extends SceneBase { boss = this.getEncounterBossSegments(this.currentBattle.waveIndex, level, species) > 1; } - const pokemon = new EnemyPokemon(species, level, trainerSlot, boss, shinyLock, dataSource); + const pokemon = new EnemyPokemon(species, level, trainerSlot, boss, shinyLock, dataSource, pregenData); if (Overrides.OPP_FUSION_OVERRIDE) { pokemon.generateFusionSpecies(); } - if (boss && !dataSource) { + if (boss && !dataSource && !pregenData?.ivs) { const secondaryIvs = getIvsFromId(randSeedInt(4294967296)); for (let s = 0; s < pokemon.ivs.length; s++) { diff --git a/src/data/trainers/trainer-config.ts b/src/data/trainers/trainer-config.ts index 8a61eade8ca..41bf8f559b4 100644 --- a/src/data/trainers/trainer-config.ts +++ b/src/data/trainers/trainer-config.ts @@ -38,7 +38,7 @@ import { timedEventManager } from "#app/global-event-manager"; import type { PokemonSpeciesFilter } from "#app/data/pokemon-species"; import type PokemonSpecies from "#app/data/pokemon-species"; import type { ModifierTypeFunc } from "#app/modifier/modifier-type"; -import type { EnemyPokemon } from "#app/field/pokemon"; +import { EnemyPokemon } from "#app/field/pokemon"; import type { EvilTeam } from "./evil-admin-trainer-pools"; import type { PartyMemberFunc, @@ -50,6 +50,9 @@ import type { PartyMemberFuncs, TrainerPartyConfigs, } from "./typedefs"; +import PokemonData, { PokemonPregenData } from "#app/system/pokemon-data"; +import { Variant } from "#app/sprites/variant"; +import { Nature } from "#enums/nature"; export interface TrainerPartyMemberConfig { species: Species, @@ -62,6 +65,10 @@ export interface TrainerPartyMemberConfig { isBoss?: boolean, bossBars?: number, ball?: PokeballType, + shiny?: boolean, + variant?: Variant, + ivs?: number[], + nature?: Nature, } export type TrainerPartySetSlot = [ @@ -724,6 +731,44 @@ export class TrainerConfig { return this; } + initPartyMemberFuncFromConfig(cfgs: TrainerPartyMemberConfig[], postProcess?: (Pokemon) => void) { + return (level: number, strength: PartyMemberStrength) => { + let cfg: TrainerPartyMemberConfig = cfgs[0]; + if (cfgs.length > 1) { + cfg = randSeedItem(cfgs); + } + cfg.teraType = cfg.teraType ?? this.specialtyType; + const moveset = cfg.moves?.map(m => new PokemonMove(m)); + const monPregenData: PokemonPregenData = { + player: false, + species: cfg.species, + formIndex: cfg.formIndex, + abilityIndex: cfg.abilityIndex, + shiny: cfg.shiny, + variant: cfg.variant, + pokeball: cfg.ball, + boss: cfg.isBoss, + bossSegments: cfg.bossBars, + nature: cfg.nature, + ivs: cfg.ivs, + gender: cfg.gender, + teraType: cfg.teraType, + moveset: moveset, + level: level, + } + return globalScene.addEnemyPokemon( + getPokemonSpecies(cfg.species), + level, + TrainerSlot.TRAINER, + cfg.isBoss, + false, + undefined, + postProcess, + monPregenData + ); + } + } + /** * Initializes the trainer configuration for an Elite Four member. * @param signatureSpecies - The signature species for the Elite Four member. @@ -746,6 +791,20 @@ export class TrainerConfig { // Set the party templates for the Elite Four. this.setPartyTemplates(trainerPartyTemplates.ELITE_FOUR); + trainerPartyConfigs[this.trainerType].forEach((slot, s) => { + const cfg = Array.isArray(slot[1]) ? slot[1] : [slot[1]]; + if (s === 5) { + cfg.forEach(c => { + c.isBoss = true; + c.bossBars = 2; + }); + } + if (cfg.some(c => c.teraType || c.instantTera)) { + this.setInstantTera(s); + } + this.setPartyMemberFunc(slot[0], this.initPartyMemberFuncFromConfig(cfg)); + }); + // Set up party members with their corresponding species. signatureSpecies.forEach((speciesPool, s) => { // Ensure speciesPool is an array. diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 91ff9534a28..476d04f78a2 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -260,6 +260,7 @@ import { MoveFlags } from "#enums/MoveFlags"; import { timedEventManager } from "#app/global-event-manager"; import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; import { ResetStatusPhase } from "#app/phases/reset-status-phase"; +import { PokemonPregenData } from "#app/system/pokemon-data"; export enum LearnMoveSituation { MISC, @@ -402,6 +403,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ivs?: number[], nature?: Nature, dataSource?: Pokemon | PokemonData, + pregenData?: PokemonPregenData, ) { super(globalScene, x, y); @@ -409,8 +411,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { throw `Cannot create a player Pokemon for species '${species.getName(formIndex)}'`; } + const partialData = dataSource ?? pregenData; + this.species = species; - this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL; + this.pokeball = partialData?.pokeball || PokeballType.POKEBALL; this.level = level; this.abilityIndex = abilityIndex ?? this.generateAbilityIndex() @@ -428,7 +432,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.variant = variant; } this.exp = - dataSource?.exp || getLevelTotalExp(this.level, species.growthRate); + dataSource?.exp || getLevelTotalExp(this.level, species.growthRate); this.levelExp = dataSource?.levelExp || 0; if (dataSource) { @@ -481,7 +485,67 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.teraType = dataSource.teraType; this.isTerastallized = dataSource.isTerastallized; this.stellarTypesBoosted = dataSource.stellarTypesBoosted ?? []; - } else { + } + else if (pregenData) { + this.id = randSeedInt(4294967296); + this.ivs = pregenData.ivs ?? getIvsFromId(this.id); + + if (this.gender === undefined) { + this.generateGender(); + } + + if (this.formIndex === undefined) { + this.formIndex = globalScene.getSpeciesFormIndex( + species, + this.gender, + this.nature, + this.isPlayer(), + ); + } + + if (this.shiny === undefined) { + this.trySetShiny(); + } + + if (this.variant === undefined) { + this.variant = this.shiny ? this.generateShinyVariant() : 0; + } + + if (nature !== undefined) { + this.setNature(nature); + } else { + this.generateNature(); + } + + if (pregenData.fusionSpecies) { + this.fusionSpecies = getPokemonSpecies(pregenData.fusionSpecies); + this.fusionAbilityIndex = pregenData.fusionAbilityIndex ?? 0; + this.fusionFormIndex = pregenData.fusionFormIndex ?? 0; + this.fusionGender = pregenData.fusionGender ?? 0; + this.fusionShiny = !!pregenData.fusionShiny; + this.fusionVariant = pregenData.fusionVariant ?? 0; + } + + this.friendship = pregenData.friendship ?? species.baseFriendship; + this.metLevel = level; + this.metBiome = globalScene.currentBattle + ? globalScene.arena.biomeType + : -1; + this.metSpecies = species.speciesId; + this.metWave = globalScene.currentBattle + ? globalScene.currentBattle.waveIndex + : -1; + this.pokerus = !!pregenData.pokerus; + this.luck = pregenData.luck ?? + (this.shiny ? this.variant + 1 : 0) + + (this.fusionShiny ? this.fusionVariant + 1 : 0); + this.fusionLuck = pregenData.fusionLuck ?? this.luck; + this.nickname = pregenData.nickname ?? ""; + this.teraType = pregenData.teraType ?? randSeedItem(this.getTypes(false, false, true)); + this.isTerastallized = false; + this.stellarTypesBoosted = []; + } + else { this.id = randSeedInt(4294967296); this.ivs = ivs || getIvsFromId(this.id); @@ -7057,27 +7121,29 @@ export class EnemyPokemon extends Pokemon { boss: boolean, shinyLock = false, dataSource?: PokemonData, + pregenData?: PokemonPregenData, ) { super( 236, 84, species, level, - dataSource?.abilityIndex, - dataSource?.formIndex, - dataSource?.gender, - !shinyLock && dataSource ? dataSource.shiny : false, - !shinyLock && dataSource ? dataSource.variant : undefined, - undefined, + dataSource?.abilityIndex ?? pregenData?.abilityIndex, + dataSource?.formIndex ?? pregenData?.formIndex, + dataSource?.gender ?? pregenData?.gender, + !shinyLock ? dataSource?.shiny ?? pregenData?.shiny : false, + !shinyLock ? dataSource?.variant ?? pregenData?.variant : undefined, + dataSource?.ivs ?? pregenData?.ivs ?? undefined, dataSource ? dataSource.nature : undefined, dataSource, + pregenData, ); this.trainerSlot = trainerSlot; this.initialTeamIndex = globalScene.currentBattle?.enemyParty.length ?? 0; - this.isPopulatedFromDataSource = !!dataSource; // if a dataSource is provided, then it was populated from dataSource + this.isPopulatedFromDataSource = !!dataSource || !!pregenData; // if a dataSource is provided, then it was populated from dataSource if (boss) { - this.setBoss(boss, dataSource?.bossSegments); + this.setBoss(boss, dataSource?.bossSegments ?? pregenData?.bossSegments); } if (Overrides.OPP_STATUS_OVERRIDE) { @@ -7098,9 +7164,14 @@ export class EnemyPokemon extends Pokemon { this.formIndex = Overrides.OPP_FORM_OVERRIDES[speciesId]; } - if (!dataSource) { + if (pregenData && pregenData.presetMoves) { + this.generateAndPopulateMoveset(...pregenData.presetMoves); + } + else if (!dataSource) { this.generateAndPopulateMoveset(); + } + if (!dataSource && !pregenData) { if (shinyLock || Overrides.OPP_SHINY_OVERRIDE === false) { this.shiny = false; } else { diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 00169678ed0..4cc5f5f3582 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -14,6 +14,43 @@ import type { Species } from "#enums/species"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { PokemonType } from "#enums/pokemon-type"; +export interface PokemonPregenData { + player: boolean; + species: Species; + nickname?: string; + formIndex?: number; + abilityIndex?: number; + passive?: boolean; + shiny?: boolean; + variant?: Variant; + pokeball?: PokeballType; + level?: number; + gender?: Gender; + ivs?: number[]; + nature?: Nature; + moveset?: PokemonMove[]; + presetMoves?: Moves[]; + friendship?: number; + luck?: number; + pokerus?: boolean; + teraType?: PokemonType; + + fusionSpecies?: Species; + fusionFormIndex?: number; + fusionAbilityIndex?: number; + fusionShiny?: boolean; + fusionVariant?: Variant; + fusionGender?: Gender; + fusionLuck?: number; + fusionTeraType?: PokemonType; + + boss?: boolean; + bossSegments?: number; + + customPokemonData?: CustomPokemonData; + fusionCustomPokemonData?: CustomPokemonData; +} + export default class PokemonData { public id: number; public player: boolean;