Added teszt file to confirm switching data resets

This commit is contained in:
Bertie690 2025-05-17 15:45:59 -04:00
parent 02a3a56ef6
commit 5532432085
5 changed files with 175 additions and 8 deletions

View File

@ -7984,6 +7984,7 @@ export class PokemonTurnData {
public statStagesDecreased = false;
public moveEffectiveness: TypeDamageMultiplier | null = null;
public combiningPledge?: Moves;
/** Whether the pokemon was sent into battle during this turn; used for {@linkcode Abilities.STAKEOUT} and {@linkcode Abilities.SPEED_BOOST}. */
public switchedInThisTurn = false;
public failedRunAway = false;
public joinedRound = false;

View File

@ -61,6 +61,8 @@ export class FaintPhase extends PokemonPhase {
faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source);
}
faintPokemon.resetSummonData();
if (!this.preventInstantRevive) {
const instantReviveModifier = globalScene.applyModifier(
PokemonInstantReviveModifier,
@ -69,7 +71,6 @@ export class FaintPhase extends PokemonPhase {
) as PokemonInstantReviveModifier;
if (instantReviveModifier) {
faintPokemon.resetSummonData();
faintPokemon.loseHeldItem(instantReviveModifier);
globalScene.updateModifiers(this.player);
return this.end();

View File

@ -274,9 +274,6 @@ export class SummonPhase extends PartyMemberPokemonPhase {
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
}
// TODO: This might be a duplicate - check to see if can be removed without breaking things
pokemon.resetTurnData();
if (
!this.loaded ||
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType) ||

View File

@ -209,9 +209,9 @@ export class SwitchSummonPhase extends SummonPhase {
const pokemon = this.getPokemon();
if (this.switchType === SwitchType.BATON_PASS && pokemon) {
if (this.switchType === SwitchType.BATON_PASS) {
pokemon.transferSummon(this.lastPokemon);
} else if (this.switchType === SwitchType.SHED_TAIL && pokemon) {
} else if (this.switchType === SwitchType.SHED_TAIL) {
const subTag = this.lastPokemon.getTag(SubstituteTag);
if (subTag) {
pokemon.summonData.tags.push(subTag);
@ -223,10 +223,11 @@ export class SwitchSummonPhase extends SummonPhase {
if (this.switchType !== SwitchType.INITIAL_SWITCH) {
pokemon.tempSummonData.turnCount--;
pokemon.tempSummonData.waveTurnCount--;
// No need to reset turn/summon data for initial switch since both get initialized to an empty object on object creation
pokemon.turnData.switchedInThisTurn = true;
// No need to reset turn/summon data for initial switch
//(since both get initialized to an empty object on object creation)
pokemon.resetTurnData();
pokemon.resetSummonData();
pokemon.turnData.switchedInThisTurn = true;
}
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);

View File

@ -0,0 +1,167 @@
import Trainer from "#app/field/trainer";
import { Abilities } from "#enums/abilities";
import { BattleType } from "#enums/battle-type";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe.each<{ name: string; selfMove?: Moves; selfAbility?: Abilities; oppMove?: Moves }>([
{ name: "Self Switch Attack Moves", selfMove: Moves.U_TURN },
{ name: "Target Switch Attack Moves", oppMove: Moves.DRAGON_TAIL },
{ name: "Self Switch Status Moves", selfMove: Moves.TELEPORT },
{ name: "Target Switch Status Moves", oppMove: Moves.WHIRLWIND },
{ name: "Self Switch Abilities", selfAbility: Abilities.EMERGENCY_EXIT },
])(
"Switch Outs - $name - ",
({ selfMove = Moves.SPLASH, selfAbility = Abilities.BALL_FETCH, oppMove = Moves.SPLASH }) => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.battleStyle("single")
.disableCrits()
.enemySpecies(Species.MAGIKARP)
.enemyPassiveAbility(Abilities.NO_GUARD);
});
describe("Player -", () => {
beforeEach(() => {
game.override.moveset(oppMove).ability(selfAbility).enemyMoveset(selfMove).enemyAbility(Abilities.BALL_FETCH);
});
it("should only call leaveField once on the switched out pokemon", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [piloswine, mamoswine] = game.scene.getPlayerParty();
const piloLeaveSpy = vi.spyOn(piloswine, "leaveField");
const mamoLeaveSpy = vi.spyOn(mamoswine, "leaveField");
game.move.select(selfMove);
game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("BerryPhase", false);
expect(piloLeaveSpy).toHaveBeenCalledTimes(1);
expect(mamoLeaveSpy).toHaveBeenCalledTimes(0);
});
it("should only reset summonData/turnData once per switch", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [piloswine, mamoswine] = game.scene.getPlayerParty();
const piloSummonSpy = vi.spyOn(piloswine, "resetSummonData");
const piloTurnSpy = vi.spyOn(piloswine, "resetTurnData");
const mamoSummonSpy = vi.spyOn(mamoswine, "resetSummonData");
const mamoTurnSpy = vi.spyOn(mamoswine, "resetTurnData");
game.move.select(selfMove);
game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("BerryPhase", false);
expect(piloSummonSpy).toHaveBeenCalledTimes(1);
expect(piloTurnSpy).toHaveBeenCalledTimes(1);
expect(mamoSummonSpy).toHaveBeenCalledTimes(1);
expect(mamoTurnSpy).toHaveBeenCalledTimes(1);
});
it("should not reset battleData/waveData upon switching", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [piloswine, mamoswine] = game.scene.getPlayerParty();
const piloWaveSpy = vi.spyOn(piloswine, "resetWaveData");
const piloBattleWaveSpy = vi.spyOn(piloswine, "resetBattleAndWaveData");
const mamoWaveSpy = vi.spyOn(mamoswine, "resetWaveData");
const mamoBattleWaveSpy = vi.spyOn(mamoswine, "resetBattleAndWaveData");
game.move.select(selfMove);
game.doSelectPartyPokemon(1);
await game.phaseInterceptor.to("TurnEndPhase");
expect(piloWaveSpy).toHaveBeenCalledTimes(0);
expect(piloBattleWaveSpy).toHaveBeenCalledTimes(0);
expect(mamoWaveSpy).toHaveBeenCalledTimes(0);
expect(mamoBattleWaveSpy).toHaveBeenCalledTimes(0);
});
});
describe("Enemy - ", () => {
beforeEach(() => {
game.override
.enemyMoveset(oppMove)
.enemyAbility(selfAbility)
.moveset(selfMove)
.ability(Abilities.BALL_FETCH)
.battleType(BattleType.TRAINER);
// prevent natural trainer switches
vi.spyOn(Trainer.prototype, "getPartyMemberMatchupScores").mockReturnValue([
[100, 1],
[100, 1],
]);
});
it("should only call leaveField once on the switched out pokemon", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [enemy1, enemy2] = game.scene.getEnemyParty();
const enemy1LeaveSpy = vi.spyOn(enemy1, "leaveField");
const enemy2LeaveSpy = vi.spyOn(enemy2, "leaveField");
game.move.select(selfMove);
await game.phaseInterceptor.to("BerryPhase", false);
expect(enemy1LeaveSpy).toHaveBeenCalledTimes(1);
expect(enemy2LeaveSpy).toHaveBeenCalledTimes(0);
});
it("should only reset summonData/turnData once per switch", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [enemy1, enemy2] = game.scene.getEnemyParty();
const enemy1SummonSpy = vi.spyOn(enemy1, "resetSummonData");
const enemy1TurnSpy = vi.spyOn(enemy1, "resetTurnData");
const enemy2SummonSpy = vi.spyOn(enemy2, "resetSummonData");
const enemy2TurnSpy = vi.spyOn(enemy2, "resetTurnData");
game.move.select(selfMove);
await game.phaseInterceptor.to("BerryPhase", false);
expect(enemy1SummonSpy).toHaveBeenCalledTimes(1);
expect(enemy1TurnSpy).toHaveBeenCalledTimes(1);
expect(enemy2SummonSpy).toHaveBeenCalledTimes(1);
expect(enemy2TurnSpy).toHaveBeenCalledTimes(1);
});
it("should not reset battleData/waveData upon switching", async () => {
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
const [enemy1, enemy2] = game.scene.getEnemyParty();
const enemy1WaveSpy = vi.spyOn(enemy1, "resetWaveData");
const enemy1BattleWaveSpy = vi.spyOn(enemy1, "resetBattleAndWaveData");
const enemy2WaveSpy = vi.spyOn(enemy2, "resetWaveData");
const enemy2BattleWaveSpy = vi.spyOn(enemy2, "resetBattleAndWaveData");
game.move.select(selfMove);
await game.phaseInterceptor.to("TurnEndPhase");
expect(enemy1WaveSpy).toHaveBeenCalledTimes(0);
expect(enemy1BattleWaveSpy).toHaveBeenCalledTimes(0);
expect(enemy2WaveSpy).toHaveBeenCalledTimes(0);
expect(enemy2BattleWaveSpy).toHaveBeenCalledTimes(0);
});
});
},
);