mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-05 16:02:20 +02:00
Hopefully fixed extraneous reset calls and call timing
This commit is contained in:
parent
5532432085
commit
a42b7ed9f7
@ -86,7 +86,7 @@ export function ForceSwitch<TBase extends SubMoveOrAbAttr>(Base: TBase) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper function to handle the actual "switching out" of Pokemon.
|
* Wrapper function to handle the actual "switching out" of Pokemon.
|
||||||
* @param switchOutTarget - The {@linkcode Pokemon} (player or enemy) attempting to switch out.
|
* @param switchOutTarget - The {@linkcode Pokemon} (player or enemy) to be switched switch out.
|
||||||
*/
|
*/
|
||||||
protected doSwitch(switchOutTarget: Pokemon): void {
|
protected doSwitch(switchOutTarget: Pokemon): void {
|
||||||
if (switchOutTarget instanceof PlayerPokemon) {
|
if (switchOutTarget instanceof PlayerPokemon) {
|
||||||
|
@ -7771,8 +7771,9 @@ const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target
|
|||||||
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseQueue.find(phase => phase instanceof MovePhase) !== undefined;
|
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseQueue.find(phase => phase instanceof MovePhase) !== undefined;
|
||||||
|
|
||||||
const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||||
const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
const player = user.isPlayer();
|
||||||
return party.some(pokemon => pokemon.isActive() && !pokemon.isOnField());
|
const otherPartyIndices = globalScene.getBackupPartyMemberIndices(player, !player ? (user as EnemyPokemon).trainerSlot : undefined)
|
||||||
|
return otherPartyIndices.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => !target.isOfType(PokemonType.GHOST);
|
const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => !target.isOfType(PokemonType.GHOST);
|
||||||
|
@ -5034,6 +5034,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const tag of source.summonData.tags) {
|
for (const tag of source.summonData.tags) {
|
||||||
|
// Skip non-Baton Passable tags (or telekinesis for mega gengar; cf. https://bulbapedia.bulbagarden.net/wiki/Telekinesis_(move))
|
||||||
if (
|
if (
|
||||||
!tag.isBatonPassable ||
|
!tag.isBatonPassable ||
|
||||||
(tag.tagType === BattlerTagType.TELEKINESIS &&
|
(tag.tagType === BattlerTagType.TELEKINESIS &&
|
||||||
@ -6314,20 +6315,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @param destroy - Whether to destroy this Pokemon once it leaves the field; default `false`
|
* @param destroy - Whether to destroy this Pokemon once it leaves the field; default `false`
|
||||||
* @remarks
|
* @remarks
|
||||||
* This **SHOULD NOT** be called when a `SummonPhase` or `SwitchSummonPhase` is already being added,
|
* This **SHOULD NOT** be called when a `SummonPhase` or `SwitchSummonPhase` is already being added,
|
||||||
* which can lead to premature resetting of {@klinkcode turnData} and {@linkcode summonData}.
|
* which can lead to premature resetting of {@linkcode turnData} and {@linkcode summonData}.
|
||||||
*/
|
*/
|
||||||
leaveField(clearEffects = true, hideInfo = true, destroy = false) {
|
leaveField(clearEffects = true, hideInfo = true, destroy = false) {
|
||||||
console.log(`leaveField called on Pokemon ${this.name}`)
|
console.log(`leaveField called on Pokemon ${this.name}`)
|
||||||
this.resetSprite();
|
this.resetSprite();
|
||||||
this.resetTurnData();
|
|
||||||
globalScene
|
globalScene
|
||||||
.getField(true)
|
.getField(true)
|
||||||
.filter(p => p !== this)
|
.filter(p => p !== this)
|
||||||
.forEach(p => p.removeTagsBySourceId(this.id));
|
.forEach(p => p.removeTagsBySourceId(this.id));
|
||||||
|
|
||||||
if (clearEffects) {
|
if (clearEffects) {
|
||||||
this.destroySubstitute();
|
this.destroySubstitute();
|
||||||
this.resetSummonData();
|
this.resetSummonData();
|
||||||
|
this.resetTurnData();
|
||||||
}
|
}
|
||||||
if (hideInfo) {
|
if (hideInfo) {
|
||||||
this.hideInfo();
|
this.hideInfo();
|
||||||
|
@ -61,8 +61,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source);
|
faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source);
|
||||||
}
|
}
|
||||||
|
|
||||||
faintPokemon.resetSummonData();
|
// Check for reviver seed
|
||||||
|
|
||||||
if (!this.preventInstantRevive) {
|
if (!this.preventInstantRevive) {
|
||||||
const instantReviveModifier = globalScene.applyModifier(
|
const instantReviveModifier = globalScene.applyModifier(
|
||||||
PokemonInstantReviveModifier,
|
PokemonInstantReviveModifier,
|
||||||
@ -71,6 +70,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
) as PokemonInstantReviveModifier;
|
) as PokemonInstantReviveModifier;
|
||||||
|
|
||||||
if (instantReviveModifier) {
|
if (instantReviveModifier) {
|
||||||
|
faintPokemon.resetSummonData();
|
||||||
faintPokemon.loseHeldItem(instantReviveModifier);
|
faintPokemon.loseHeldItem(instantReviveModifier);
|
||||||
globalScene.updateModifiers(this.player);
|
globalScene.updateModifiers(this.player);
|
||||||
return this.end();
|
return this.end();
|
||||||
@ -179,11 +179,11 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
} else {
|
} else {
|
||||||
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
|
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
|
||||||
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
||||||
const hasReservePartyMember = !!globalScene
|
const reservePartyIndices = globalScene.getBackupPartyMemberIndices(
|
||||||
.getEnemyParty()
|
false,
|
||||||
.filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
|
(pokemon as EnemyPokemon).trainerSlot,
|
||||||
.length;
|
);
|
||||||
if (hasReservePartyMember) {
|
if (reservePartyIndices.length) {
|
||||||
globalScene.pushPhase(new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false));
|
globalScene.pushPhase(new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,6 +217,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
globalScene.addFaintedEnemyScore(pokemon as EnemyPokemon);
|
globalScene.addFaintedEnemyScore(pokemon as EnemyPokemon);
|
||||||
globalScene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
|
globalScene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
|
||||||
}
|
}
|
||||||
|
// TODO: Do we need to leave the field here & now as opposed to during `switchSummonPhase`?
|
||||||
pokemon.leaveField();
|
pokemon.leaveField();
|
||||||
this.end();
|
this.end();
|
||||||
},
|
},
|
||||||
|
@ -111,7 +111,6 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
globalScene.time.delayedCall(750, () => this.switchAndSummon());
|
globalScene.time.delayedCall(750, () => this.switchAndSummon());
|
||||||
lastPokemon.leaveField(this.switchType === SwitchType.SWITCH, false);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -162,9 +161,12 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swap around the 2 pokemon's party positions and play an animation to send in the new pokemon.
|
||||||
party[this.slotIndex] = this.lastPokemon;
|
party[this.slotIndex] = this.lastPokemon;
|
||||||
party[this.fieldIndex] = switchedInPokemon;
|
party[this.fieldIndex] = switchedInPokemon;
|
||||||
const showTextAndSummon = () => {
|
const showTextAndSummon = () => {
|
||||||
|
// TODO: Should this remove the info container?
|
||||||
|
this.lastPokemon.leaveField(![SwitchType.BATON_PASS, SwitchType.SHED_TAIL].includes(this.switchType), false);
|
||||||
globalScene.ui.showText(
|
globalScene.ui.showText(
|
||||||
this.player
|
this.player
|
||||||
? i18next.t("battle:playerGo", {
|
? i18next.t("battle:playerGo", {
|
||||||
@ -209,25 +211,30 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
|
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
|
|
||||||
|
// If not switching at start of battle, reset turn counts and temp data on the newly sent in Pokemon
|
||||||
|
// Needed as we increment turn counters in `TurnEndPhase`.
|
||||||
|
if (this.switchType !== SwitchType.INITIAL_SWITCH) {
|
||||||
|
// No need to reset turn/summon data for initial switch
|
||||||
|
// (since both get initialized to an empty object on object creation)
|
||||||
|
this.lastPokemon.resetTurnData();
|
||||||
|
this.lastPokemon.resetSummonData();
|
||||||
|
pokemon.tempSummonData.turnCount--;
|
||||||
|
pokemon.tempSummonData.waveTurnCount--;
|
||||||
|
pokemon.turnData.switchedInThisTurn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baton Pass over any eligible effects or substitutes before resetting the last pokemon's temporary data.
|
||||||
if (this.switchType === SwitchType.BATON_PASS) {
|
if (this.switchType === SwitchType.BATON_PASS) {
|
||||||
pokemon.transferSummon(this.lastPokemon);
|
pokemon.transferSummon(this.lastPokemon);
|
||||||
|
this.lastPokemon.resetTurnData();
|
||||||
|
this.lastPokemon.resetSummonData();
|
||||||
} else if (this.switchType === SwitchType.SHED_TAIL) {
|
} else if (this.switchType === SwitchType.SHED_TAIL) {
|
||||||
const subTag = this.lastPokemon.getTag(SubstituteTag);
|
const subTag = this.lastPokemon.getTag(SubstituteTag);
|
||||||
if (subTag) {
|
if (subTag) {
|
||||||
pokemon.summonData.tags.push(subTag);
|
pokemon.summonData.tags.push(subTag);
|
||||||
}
|
}
|
||||||
}
|
this.lastPokemon.resetTurnData();
|
||||||
|
this.lastPokemon.resetSummonData();
|
||||||
// If not switching at start of battle, reset turn counts and temp data.
|
|
||||||
// Needed as we increment turn counters in `TurnEndPhase`.
|
|
||||||
if (this.switchType !== SwitchType.INITIAL_SWITCH) {
|
|
||||||
pokemon.tempSummonData.turnCount--;
|
|
||||||
pokemon.tempSummonData.waveTurnCount--;
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||||
|
@ -1,21 +1,157 @@
|
|||||||
import Trainer from "#app/field/trainer";
|
import { PokemonSummonData, PokemonTurnData } from "#app/field/pokemon";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { BattleType } from "#enums/battle-type";
|
import { BattleType } from "#enums/battle-type";
|
||||||
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
describe.each<{ name: string; selfMove?: Moves; selfAbility?: Abilities; oppMove?: Moves }>([
|
describe("Manual Switching -", () => {
|
||||||
{ name: "Self Switch Attack Moves", selfMove: Moves.U_TURN },
|
let phaserGame: Phaser.Game;
|
||||||
{ name: "Target Switch Attack Moves", oppMove: Moves.DRAGON_TAIL },
|
let game: GameManager;
|
||||||
{ name: "Self Switch Status Moves", selfMove: Moves.TELEPORT },
|
|
||||||
{ name: "Target Switch Status Moves", oppMove: Moves.WHIRLWIND },
|
beforeAll(() => {
|
||||||
{ name: "Self Switch Abilities", selfAbility: Abilities.EMERGENCY_EXIT },
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.battleStyle("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset(Moves.SPLASH)
|
||||||
|
.enemyMoveset(Moves.SPLASH)
|
||||||
|
.battleType(BattleType.TRAINER)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Player", () => {
|
||||||
|
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.doSwitchPokemon(1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
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.doSwitchPokemon(1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(piloSummonSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(piloTurnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mamoSummonSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mamoTurnSpy).toHaveBeenCalledTimes(2); // once from switching, once at turn start
|
||||||
|
});
|
||||||
|
|
||||||
|
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.doSwitchPokemon(1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(piloWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(piloBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(mamoWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(mamoBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Enemy", () => {
|
||||||
|
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(Moves.SPLASH);
|
||||||
|
game.forceEnemyToSwitch();
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
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(Moves.SPLASH);
|
||||||
|
game.forceEnemyToSwitch();
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemy1SummonSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(enemy1TurnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(enemy2SummonSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(enemy2TurnSpy).toHaveBeenCalledTimes(2); // once from switching, once at turn start
|
||||||
|
});
|
||||||
|
|
||||||
|
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(Moves.SPLASH);
|
||||||
|
game.forceEnemyToSwitch();
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemy1WaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(enemy1BattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(enemy2WaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
expect(enemy2BattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.each<{ name: string; playerMove?: Moves; playerAbility?: Abilities; enemyMove?: Moves }>([
|
||||||
|
{ name: "Self Switch Attack Moves", playerMove: Moves.U_TURN },
|
||||||
|
{ name: "Target Switch Attack Moves", enemyMove: Moves.DRAGON_TAIL },
|
||||||
|
{ name: "Self Switch Status Moves", playerMove: Moves.TELEPORT },
|
||||||
|
{ name: "Target Switch Status Moves", enemyMove: Moves.WHIRLWIND },
|
||||||
|
{ name: "Self Switch Abilities", playerAbility: Abilities.EMERGENCY_EXIT, enemyMove: Moves.BRAVE_BIRD },
|
||||||
|
/* { name: "Fainting", playerMove: Moves.EXPLOSION }, */ // TODO: This calls it twice...
|
||||||
])(
|
])(
|
||||||
"Switch Outs - $name - ",
|
"Mid-Battle Switch Outs - $name - ",
|
||||||
({ selfMove = Moves.SPLASH, selfAbility = Abilities.BALL_FETCH, oppMove = Moves.SPLASH }) => {
|
({ playerMove = Moves.SPLASH, playerAbility = Abilities.BALL_FETCH, enemyMove = Moves.SPLASH }) => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
let game: GameManager;
|
let game: GameManager;
|
||||||
|
|
||||||
@ -32,136 +168,73 @@ describe.each<{ name: string; selfMove?: Moves; selfAbility?: Abilities; oppMove
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override
|
game.override
|
||||||
|
.moveset(playerMove)
|
||||||
|
.ability(playerAbility)
|
||||||
.battleStyle("single")
|
.battleStyle("single")
|
||||||
.disableCrits()
|
.disableCrits()
|
||||||
|
.enemyLevel(100)
|
||||||
|
.battleType(BattleType.TRAINER)
|
||||||
|
.passiveAbility(Abilities.STURDY)
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyMoveset(enemyMove)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyPassiveAbility(Abilities.NO_GUARD);
|
.enemyPassiveAbility(Abilities.NO_GUARD);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Player -", () => {
|
it("should only call leaveField once on the switched out pokemon", async () => {
|
||||||
beforeEach(() => {
|
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
||||||
game.override.moveset(oppMove).ability(selfAbility).enemyMoveset(selfMove).enemyAbility(Abilities.BALL_FETCH);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should only call leaveField once on the switched out pokemon", async () => {
|
const [piloswine, mamoswine] = game.scene.getPlayerParty();
|
||||||
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
const piloLeaveSpy = vi.spyOn(piloswine, "leaveField");
|
||||||
|
const mamoLeaveSpy = vi.spyOn(mamoswine, "leaveField");
|
||||||
|
|
||||||
const [piloswine, mamoswine] = game.scene.getPlayerParty();
|
game.move.select(playerMove);
|
||||||
const piloLeaveSpy = vi.spyOn(piloswine, "leaveField");
|
game.doSelectPartyPokemon(1);
|
||||||
const mamoLeaveSpy = vi.spyOn(mamoswine, "leaveField");
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
game.move.select(selfMove);
|
expect(piloLeaveSpy).toHaveBeenCalledTimes(1);
|
||||||
game.doSelectPartyPokemon(1);
|
expect(mamoLeaveSpy).toHaveBeenCalledTimes(0);
|
||||||
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 - ", () => {
|
it("should only reset summonData/turnData once per switch", async () => {
|
||||||
beforeEach(() => {
|
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
||||||
game.override
|
|
||||||
.enemyMoveset(oppMove)
|
|
||||||
.enemyAbility(selfAbility)
|
|
||||||
.moveset(selfMove)
|
|
||||||
.ability(Abilities.BALL_FETCH)
|
|
||||||
.battleType(BattleType.TRAINER);
|
|
||||||
|
|
||||||
// prevent natural trainer switches
|
const [piloswine, mamoswine] = game.scene.getPlayerParty();
|
||||||
vi.spyOn(Trainer.prototype, "getPartyMemberMatchupScores").mockReturnValue([
|
piloswine.addTag(BattlerTagType.AQUA_RING, 999); // give piloswine a tag to ensure we know if summonData got reset
|
||||||
[100, 1],
|
const piloSummonSpy = vi.spyOn(piloswine, "resetSummonData");
|
||||||
[100, 1],
|
const piloTurnSpy = vi.spyOn(piloswine, "resetTurnData");
|
||||||
]);
|
const mamoSummonSpy = vi.spyOn(mamoswine, "resetSummonData");
|
||||||
});
|
const mamoTurnSpy = vi.spyOn(mamoswine, "resetTurnData");
|
||||||
|
|
||||||
it("should only call leaveField once on the switched out pokemon", async () => {
|
game.move.select(playerMove);
|
||||||
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
const [enemy1, enemy2] = game.scene.getEnemyParty();
|
expect(piloSummonSpy).toHaveBeenCalledTimes(1);
|
||||||
const enemy1LeaveSpy = vi.spyOn(enemy1, "leaveField");
|
expect(piloTurnSpy).toHaveBeenCalledTimes(1);
|
||||||
const enemy2LeaveSpy = vi.spyOn(enemy2, "leaveField");
|
expect(mamoSummonSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mamoTurnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(piloswine.summonData).toEqual(new PokemonSummonData());
|
||||||
|
expect(piloswine.turnData).toEqual(new PokemonTurnData());
|
||||||
|
});
|
||||||
|
|
||||||
game.move.select(selfMove);
|
it("should not reset battleData/waveData upon switching", async () => {
|
||||||
await game.phaseInterceptor.to("BerryPhase", false);
|
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
||||||
|
|
||||||
expect(enemy1LeaveSpy).toHaveBeenCalledTimes(1);
|
const [piloswine, mamoswine] = game.scene.getPlayerParty();
|
||||||
expect(enemy2LeaveSpy).toHaveBeenCalledTimes(0);
|
const piloWaveSpy = vi.spyOn(piloswine, "resetWaveData");
|
||||||
});
|
const piloBattleWaveSpy = vi.spyOn(piloswine, "resetBattleAndWaveData");
|
||||||
|
const mamoWaveSpy = vi.spyOn(mamoswine, "resetWaveData");
|
||||||
|
const mamoBattleWaveSpy = vi.spyOn(mamoswine, "resetBattleAndWaveData");
|
||||||
|
|
||||||
it("should only reset summonData/turnData once per switch", async () => {
|
game.move.select(playerMove);
|
||||||
await game.classicMode.startBattle([Species.PILOSWINE, Species.MAMOSWINE]);
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
const [enemy1, enemy2] = game.scene.getEnemyParty();
|
expect(piloWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
const enemy1SummonSpy = vi.spyOn(enemy1, "resetSummonData");
|
expect(piloBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
const enemy1TurnSpy = vi.spyOn(enemy1, "resetTurnData");
|
expect(mamoWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
const enemy2SummonSpy = vi.spyOn(enemy2, "resetSummonData");
|
expect(mamoBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user