From 102554cdb7d65307796f3936a08e31b295cfeab0 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Mon, 21 Apr 2025 12:51:28 -0400 Subject: [PATCH] Moved empty moveset verification mapping thing to upgrade script bc i wanted to --- src/data/abilities/ability.ts | 26 ++--- src/data/moves/move.ts | 22 +++-- src/field/pokemon.ts | 12 ++- src/system/pokemon-data.ts | 14 +-- .../version_migration/versions/v1_9_0.ts | 27 +++--- test/abilities/cud_chew.test.ts | 32 +++++++ test/abilities/harvest.test.ts | 2 +- test/field/pokemon.test.ts | 28 ------ test/moves/rage_fist.test.ts | 96 +++++++++---------- test/testUtils/gameManager.ts | 2 +- 10 files changed, 139 insertions(+), 122 deletions(-) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 3f8ccd1be02..bde7a69d789 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -3273,13 +3273,13 @@ export class ConditionalUserFieldStatusEffectImmunityAbAttr extends UserFieldSta /** * Conditionally provides immunity to stat drop effects to the user's field. - * + * * Used by {@linkcode Abilities.FLOWER_VEIL | Flower Veil}. */ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbAttr { /** {@linkcode BattleStat} to protect or `undefined` if **all** {@linkcode BattleStat} are protected */ protected protectedStat?: BattleStat; - + /** If the method evaluates to true, the stat will be protected. */ protected condition: (target: Pokemon) => boolean; @@ -3296,7 +3296,7 @@ export class ConditionalUserFieldProtectStatAbAttr extends PreStatStageChangeAbA * @param stat The stat being affected * @param cancelled Holds whether the stat change was already prevented. * @param args Args[0] is the target pokemon of the stat change. - * @returns + * @returns */ override canApplyPreStatStageChange(pokemon: Pokemon, passive: boolean, simulated: boolean, stat: BattleStat, cancelled: BooleanHolder, args: [Pokemon, ...any]): boolean { const target = args[0]; @@ -3428,7 +3428,7 @@ export class BonusCritAbAttr extends AbAttr { /** * Apply the bonus crit ability by increasing the value in the provided number holder by 1 - * + * * @param pokemon The pokemon with the BonusCrit ability (unused) * @param passive Unused * @param simulated Unused @@ -3581,7 +3581,7 @@ export class PreWeatherEffectAbAttr extends AbAttr { args: any[]): boolean { return true; } - + applyPreWeatherEffect( pokemon: Pokemon, passive: boolean, @@ -4143,25 +4143,24 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr { * Used by {@linkcode Abilities.CUD_CHEW}. */ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr { - constructor() { - super(true); - } + // no need for constructor; all it does is set `showAbility` which we override before triggering anyways /** * @returns `true` if the pokemon ate anything last turn */ override canApply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + this.showAbility = true; // force ability popup if ability triggers return !!pokemon.summonData.berriesEatenLast.length; } /** * Cause this {@linkcode Pokemon} to regurgitate and eat all berries * inside its `berriesEatenLast` array. - * @param pokemon The pokemon having the tummy ache - * @param _passive N/A - * @param _simulated N/A - * @param _cancelled N/A - * @param _args N/A + * @param pokemon - The pokemon having the tummy ache + * @param _passive - N/A + * @param _simulated - N/A + * @param _cancelled - N/A + * @param _args - N/A */ override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void { // play berry animation @@ -4182,6 +4181,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr { * @returns `true` if the pokemon ate anything this turn (we move it into `battleData`) */ override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { + this.showAbility = false; // don't show popup for turn end berry moving (should ideally be hidden) return !!pokemon.turnData.berriesEaten.length; } diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index c091e688904..e28e0c27c39 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2694,7 +2694,9 @@ export class EatBerryAttr extends MoveEffectAttr { if (!preserve.value) { this.reduceBerryModifier(target); } - this.eatBerry(target); + + // Don't update harvest for berries preserved via Berry pouch (no item dupes lol) + this.eatBerry(target, undefined, !preserve.value); return true; } @@ -2711,15 +2713,21 @@ export class EatBerryAttr extends MoveEffectAttr { globalScene.updateModifiers(target.isPlayer()); } - eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer) { - // consumer eats berry, owner triggers unburden and similar effects - // These are the same under normal circumstances + + /** + * Internal function to apply berry effects. + * + * @param consumer - The {@linkcode Pokemon} eating the berry; assumed to also be owner if `berryOwner` is omitted + * @param berryOwner - The {@linkcode Pokemon} whose berry is being eaten; defaults to `consumer` if not specified. + * @param updateHarvest - Whether to prevent harvest from tracking berries; + * defaults to whether `consumer` equals `berryOwner` (i.e. consuming own berry). + */ + eatBerry(consumer: Pokemon, berryOwner: Pokemon = consumer, updateHarvest = consumer === berryOwner) { + // consumer eats berry, owner triggers unburden and similar effects getBerryEffectFunc(this.chosenBerry.berryType)(consumer); applyPostItemLostAbAttrs(PostItemLostAbAttr, berryOwner, false); applyAbAttrs(HealFromBerryUseAbAttr, consumer, new BooleanHolder(false)); - - // Harvest doesn't track berries eaten by other pokemon - consumer.recordEatenBerry(this.chosenBerry.berryType, berryOwner !== consumer); + consumer.recordEatenBerry(this.chosenBerry.berryType, updateHarvest); } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 80c7f2fd764..f60528e8e7c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -279,6 +279,12 @@ export enum FieldPosition { } export default abstract class Pokemon extends Phaser.GameObjects.Container { + /** + * This pokemon's {@link https://bulbapedia.bulbagarden.net/wiki/Personality_value | Personality value/PID}, + * used to determine various parameters of this Pokemon. + * Represented as a random 32-bit unsigned integer. + * TODO: Stop treating this like a unique ID and stop treating 0 as no pokemon + */ public id: number; public name: string; public nickname: string; @@ -324,7 +330,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public fusionCustomPokemonData: CustomPokemonData | null; public fusionTeraType: PokemonType; - public customPokemonData: CustomPokemonData = new CustomPokemonData(); + public customPokemonData: CustomPokemonData = new CustomPokemonData; /** * TODO: Figure out if we can remove this thing @@ -7892,7 +7898,7 @@ export class PokemonSummonData { public gender: Gender; public fusionGender: Gender; public stats: number[] = [0, 0, 0, 0, 0, 0]; - public moveset: PokemonMove[]; + public moveset: PokemonMove[] | null; public illusionBroken: boolean = false; // If not initialized this value will not be populated from save data. @@ -7915,6 +7921,8 @@ export class PokemonSummonData { constructor(source?: PokemonSummonData | Partial) { if (!isNullOrUndefined(source)) { Object.assign(this, source) + this.moveset &&= this.moveset.map(m => PokemonMove.loadMove(m)) + this.tags &&= this.tags.map(t => loadBattlerTag(t)) } } } diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index e32ce707b98..55ee5343870 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -2,14 +2,14 @@ import { BattleType } from "#enums/battle-type"; import { globalScene } from "#app/global-scene"; import type { Gender } from "../data/gender"; import { Nature } from "#enums/nature"; -import type { PokeballType } from "#enums/pokeball"; +import { PokeballType } from "#enums/pokeball"; import { getPokemonSpecies, getPokemonSpeciesForm } from "../data/pokemon-species"; import type { Status } from "../data/status-effect"; import Pokemon, { EnemyPokemon, PokemonBattleData, PokemonMove, PokemonSummonData } from "../field/pokemon"; import { TrainerSlot } from "#enums/trainer-slot"; import type { Variant } from "#app/sprites/variant"; import type { Biome } from "#enums/biome"; -import { Moves } from "#enums/moves"; +import type { Moves } from "#enums/moves"; import type { Species } from "#enums/species"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { PokemonType } from "#enums/pokemon-type"; @@ -59,11 +59,11 @@ export default class PokemonData { public fusionTeraType: PokemonType; public boss: boolean; - public bossSegments?: number; + public bossSegments: number; // Effects that need to be preserved between waves - public summonData: PokemonSummonData = new PokemonSummonData(); - public battleData: PokemonBattleData = new PokemonBattleData(); + public summonData: PokemonSummonData; + public battleData: PokemonBattleData; public summonDataSpeciesFormIndex: number; public customPokemonData: CustomPokemonData; @@ -87,7 +87,7 @@ export default class PokemonData { this.passive = source.passive; this.shiny = sourcePokemon?.isShiny() ?? source.shiny; this.variant = sourcePokemon?.getVariant() ?? source.variant; - this.pokeball = source.pokeball; + this.pokeball = source.pokeball ?? PokeballType.POKEBALL; this.level = source.level; this.exp = source.exp; this.levelExp = source.levelExp; @@ -98,7 +98,7 @@ export default class PokemonData { // TODO: Can't we move some of this verification stuff to an upgrade script? this.nature = source.nature ?? Nature.HARDY; - this.moveset = source.moveset ?? [new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL)]; + this.moveset = source.moveset.map((m: any) => PokemonMove.loadMove(m)); this.status = source.status ?? null; this.friendship = source.friendship ?? getPokemonSpecies(this.species).baseFriendship; this.metLevel = source.metLevel || 5; diff --git a/src/system/version_migration/versions/v1_9_0.ts b/src/system/version_migration/versions/v1_9_0.ts index f0301aec230..1d39676bf7b 100644 --- a/src/system/version_migration/versions/v1_9_0.ts +++ b/src/system/version_migration/versions/v1_9_0.ts @@ -1,11 +1,9 @@ import type { SessionSaveMigrator } from "#app/@types/SessionSaveMigrator"; -import { loadBattlerTag } from "#app/data/battler-tags"; import { Status } from "#app/data/status-effect"; import { PokemonMove } from "#app/field/pokemon"; import type { SessionSaveData } from "#app/system/game-data"; -import PokemonData from "#app/system/pokemon-data"; +import type PokemonData from "#app/system/pokemon-data"; import { Moves } from "#enums/moves"; -import { PokeballType } from "#enums/pokeball"; /** * Migrate all lingering rage fist data inside `CustomPokemonData`, @@ -23,23 +21,26 @@ const migratePartyData: SessionSaveMigrator = { pkmnData.status.sleepTurnsRemaining, ); // remove empty moves from moveset - pkmnData.moveset = pkmnData.moveset.filter(m => !!m) ?? [ - new PokemonMove(Moves.TACKLE), - new PokemonMove(Moves.GROWL), - ]; - pkmnData.pokeball ??= PokeballType.POKEBALL; - pkmnData.summonData.tags = pkmnData.summonData.tags.map((t: any) => loadBattlerTag(t)); + pkmnData.moveset = (pkmnData.moveset ?? [new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL)]).filter( + m => !!m, + ); + // only edit summondata moveset if exists + pkmnData.summonData.moveset &&= pkmnData.summonData.moveset.filter(m => !!m); + if ( + pkmnData.customPokemonData && "hitsRecCount" in pkmnData.customPokemonData && typeof pkmnData.customPokemonData["hitsRecCount"] === "number" ) { - pkmnData.battleData.hitCount = pkmnData.customPokemonData?.["hitsRecCount"]; + // transfer old hit count stat to battleData. + // No need to reset it as new Pokemon + pkmnData.battleData.hitCount = pkmnData.customPokemonData["hitsRecCount"]; } - pkmnData = new PokemonData(pkmnData); + return pkmnData; }; - data.party.forEach(mapParty); - data.enemyParty.forEach(mapParty); + data.party = data.party.map(mapParty); + data.enemyParty = data.enemyParty.map(mapParty); }, }; diff --git a/test/abilities/cud_chew.test.ts b/test/abilities/cud_chew.test.ts index 683238d99ee..532c72f6e66 100644 --- a/test/abilities/cud_chew.test.ts +++ b/test/abilities/cud_chew.test.ts @@ -1,6 +1,7 @@ import { RepeatBerryNextTurnAbAttr } from "#app/data/abilities/ability"; import { getBerryEffectFunc } from "#app/data/berry"; import Pokemon from "#app/field/pokemon"; +import { globalScene } from "#app/global-scene"; import { Abilities } from "#enums/abilities"; import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; @@ -65,6 +66,37 @@ describe("Abilities - Cud Chew", () => { expect(farigiraf.turnData.berriesEaten).toEqual([]); }); + it("shouldn't show ability popup for end-of-turn storage", async () => { + const abDisplaySpy = vi.spyOn(globalScene, "queueAbilityDisplay"); + await game.classicMode.startBattle([Species.FARIGIRAF]); + + const farigiraf = game.scene.getPlayerPokemon()!; + farigiraf.hp = 1; // needed to allow sitrus procs + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + + // doesn't trigger since cud chew hasn't eaten berry yet + expect(abDisplaySpy).not.toHaveBeenCalledWith(farigiraf); + await game.toNextTurn(); + + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("BerryPhase"); + + // globalScene.queueAbilityDisplay should be called twice: once to show cud chew before regurgitating berries, + // once to hide after finishing application + expect(abDisplaySpy).toBeCalledTimes(2); + expect(abDisplaySpy.mock.calls[0][0]).toBe(farigiraf); + expect(abDisplaySpy.mock.calls[0][2]).toBe(true); + expect(abDisplaySpy.mock.calls[1][0]).toBe(farigiraf); + expect(abDisplaySpy.mock.calls[1][2]).toBe(false); + + await game.phaseInterceptor.to("TurnEndPhase"); + + // not called again at turn end + expect(abDisplaySpy).toBeCalledTimes(2); + }); + it("can store multiple berries across 2 turns with teatime", async () => { // always eat first berry for stuff cheeks & company vi.spyOn(Pokemon.prototype, "randSeedInt").mockReturnValue(0); diff --git a/test/abilities/harvest.test.ts b/test/abilities/harvest.test.ts index 472273d3d9c..38a37f43ea6 100644 --- a/test/abilities/harvest.test.ts +++ b/test/abilities/harvest.test.ts @@ -254,7 +254,7 @@ describe("Abilities - Harvest", () => { game.move.select(Moves.SPLASH); await game.phaseInterceptor.to("TurnEndPhase", false); - // won;t trigger harvest since we didn't lose the berry (it just doesn't ever add it to the array) + // won't trigger harvest since we didn't lose the berry (it just doesn't ever add it to the array) expect(game.scene.getPlayerPokemon()?.battleData.berriesEaten).toEqual([]); expectBerriesContaining(...initBerries); }); diff --git a/test/field/pokemon.test.ts b/test/field/pokemon.test.ts index d0701037471..85128a31f7f 100644 --- a/test/field/pokemon.test.ts +++ b/test/field/pokemon.test.ts @@ -6,9 +6,6 @@ import type BattleScene from "#app/battle-scene"; import { Moves } from "#app/enums/moves"; import { PokemonType } from "#enums/pokemon-type"; import { CustomPokemonData } from "#app/data/custom-pokemon-data"; -import PokemonData from "#app/system/pokemon-data"; -import { PlayerPokemon } from "#app/field/pokemon"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; describe("Spec - Pokemon", () => { let phaserGame: Phaser.Game; @@ -212,29 +209,4 @@ describe("Spec - Pokemon", () => { expect(types[1]).toBe(PokemonType.DARK); }); }); - - // TODO: Remove/rework after save data overhaul - it("should preserve common fields when converting to and from PokemonData", async () => { - await game.classicMode.startBattle([Species.ALAKAZAM]); - const alakazam = game.scene.getPlayerPokemon()!; - expect(alakazam).toBeDefined(); - - alakazam.hp = 5; - const alakaData = new PokemonData(alakazam); - const alaka2 = new PlayerPokemon( - getPokemonSpecies(Species.ALAKAZAM), - 5, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - alakaData, - ); - for (const key of Object.keys(alakazam).filter(k => k in alakaData)) { - expect(alakazam[key]).toEqual(alaka2[key]); - } - }); }); diff --git a/test/moves/rage_fist.test.ts b/test/moves/rage_fist.test.ts index 57bc5ef563b..4570ff28df6 100644 --- a/test/moves/rage_fist.test.ts +++ b/test/moves/rage_fist.test.ts @@ -32,6 +32,7 @@ describe("Moves - Rage Fist", () => { .moveset([Moves.RAGE_FIST, Moves.SPLASH, Moves.SUBSTITUTE, Moves.TIDY_UP]) .startingLevel(100) .enemyLevel(1) + .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.BALL_FETCH) .enemyMoveset(Moves.DOUBLE_KICK); @@ -39,9 +40,7 @@ describe("Moves - Rage Fist", () => { }); it("should gain power per hit taken", async () => { - game.override.enemySpecies(Species.MAGIKARP); - - await game.classicMode.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); @@ -51,9 +50,7 @@ describe("Moves - Rage Fist", () => { }); it("caps at 6 hits taken", async () => { - game.override.enemySpecies(Species.MAGIKARP); - - await game.classicMode.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.FEEBAS]); // spam splash against magikarp hitting us 2 times per turn game.move.select(Moves.SPLASH); @@ -72,10 +69,10 @@ describe("Moves - Rage Fist", () => { expect(move.calculateBattlePower).toHaveLastReturnedWith(350); }); - it("should not count subsitute hits or confusion damage", async () => { + it("should not count substitute hits or confusion damage", async () => { game.override.enemySpecies(Species.SHUCKLE).enemyMoveset([Moves.CONFUSE_RAY, Moves.DOUBLE_KICK]); - await game.classicMode.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.REGIROCK]); game.move.select(Moves.SUBSTITUTE); await game.forceEnemyMove(Moves.DOUBLE_KICK); @@ -92,68 +89,52 @@ describe("Moves - Rage Fist", () => { await game.toNextTurn(); game.move.select(Moves.RAGE_FIST); + await game.forceEnemyMove(Moves.CONFUSE_RAY); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.move.forceConfusionActivation(true); - await game.forceEnemyMove(Moves.DOUBLE_KICK); - await game.phaseInterceptor.to("BerryPhase"); + await game.toNextTurn(); - // didn't go up + // didn't go up from hitting ourself expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(0); - - await game.toNextTurn(); - - game.move.select(Moves.RAGE_FIST); - await game.forceEnemyMove(Moves.DOUBLE_KICK); - await game.move.forceConfusionActivation(false); - await game.toNextTurn(); - - expect(move.calculateBattlePower).toHaveLastReturnedWith(150); - expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(2); }); it("should maintain hits recieved between wild waves", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(1); - - await game.classicMode.startBattle([Species.MAGIKARP]); + await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextWave(); - game.move.select(Moves.RAGE_FIST); - await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); - await game.phaseInterceptor.to("BerryPhase", false); + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(2); - expect(move.calculateBattlePower).toHaveLastReturnedWith(250); - expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(4); - }); - - it("should reset hits recieved before trainer battles", async () => { - game.override.enemySpecies(Species.MAGIKARP).moveset(Moves.DOUBLE_IRON_BASH); - await game.classicMode.startBattle([Species.MARSHADOW]); - - const marshadow = game.scene.getPlayerPokemon()!; - expect(marshadow).toBeDefined(); - - // beat up a magikarp game.move.select(Moves.RAGE_FIST); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnEndPhase"); + expect(game.scene.getPlayerPokemon()?.battleData.hitCount).toBe(4); + expect(move.calculateBattlePower).toHaveLastReturnedWith(250); + }); + + it("should reset hits recieved before trainer battles", async () => { + await game.classicMode.startBattle([Species.IRON_HANDS]); + + const ironHands = game.scene.getPlayerPokemon()!; + expect(ironHands).toBeDefined(); + + // beat up a magikarp + game.move.select(Moves.RAGE_FIST); + await game.forceEnemyMove(Moves.DOUBLE_KICK); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(game.isVictory()).toBe(true); - expect(marshadow.battleData.hitCount).toBe(2); + expect(ironHands.battleData.hitCount).toBe(2); expect(move.calculateBattlePower).toHaveLastReturnedWith(150); game.override.battleType(BattleType.TRAINER); await game.toNextWave(); - expect(game.scene.lastEnemyTrainer).not.toBeNull(); - expect(marshadow.battleData.hitCount).toBe(0); - - game.move.select(Moves.RAGE_FIST); - await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); - await game.phaseInterceptor.to("TurnEndPhase"); - - expect(move.calculateBattlePower).toHaveLastReturnedWith(150); + expect(ironHands.battleData.hitCount).toBe(0); }); it("should reset the hitRecCounter if we enter new biome", async () => { @@ -173,24 +154,39 @@ describe("Moves - Rage Fist", () => { }); it("should not reset the hitRecCounter if switched out", async () => { - game.override.enemySpecies(Species.MAGIKARP).startingWave(1).enemyMoveset(Moves.TACKLE); + game.override.enemyMoveset(Moves.TACKLE); + + const getPartyHitCount = () => + game.scene + .getPlayerParty() + .filter(p => !!p) + .map(m => m.battleData.hitCount); await game.classicMode.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + // Charizard hit game.move.select(Moves.SPLASH); await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([1, 0]); + // blastoise switched in & hit game.doSwitchPokemon(1); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([1, 1]); + // charizard switched in & hit game.doSwitchPokemon(1); await game.toNextTurn(); + expect(getPartyHitCount()).toEqual([2, 1]); + // Charizard rage fist game.move.select(Moves.RAGE_FIST); await game.phaseInterceptor.to("MoveEndPhase"); - expect(game.scene.getPlayerParty()[0].species.speciesId).toBe(Species.CHARIZARD); + const charizard = game.scene.getPlayerPokemon()!; + expect(charizard).toBeDefined(); + expect(charizard.species.speciesId).toBe(Species.CHARIZARD); expect(move.calculateBattlePower).toHaveLastReturnedWith(150); }); }); diff --git a/test/testUtils/gameManager.ts b/test/testUtils/gameManager.ts index 874d8f786b8..65aa9b1bb34 100644 --- a/test/testUtils/gameManager.ts +++ b/test/testUtils/gameManager.ts @@ -576,7 +576,7 @@ export default class GameManager { * Intercepts `TurnStartPhase` and mocks {@linkcode TurnStartPhase.getSpeedOrder}'s return value. * Used to manually modify Pokemon turn order. * Note: This *DOES NOT* account for priority, only speed. - * @param {BattlerIndex[]} order The turn order to set + * @param order - The turn order to set as an array of {@linkcode BattlerIndex}es. * @example * ```ts * await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]);