mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-05 07:52:17 +02:00
Revert leaveField tests for other PR
This commit is contained in:
parent
a42b7ed9f7
commit
ebe4878a2b
@ -110,10 +110,14 @@ export function ForceSwitch<TBase extends SubMoveOrAbAttr>(Base: TBase) {
|
||||
this.tryFleeWildPokemon(switchOutTarget);
|
||||
}
|
||||
|
||||
// NB: `prependToPhase` is used here to ensure that the switch happens before the move ends
|
||||
// and `arena.ignoreAbilities` is reset.
|
||||
// This ensures ability ignore effects will persist for the duration of the switch (for hazards).
|
||||
|
||||
private trySwitchPlayerPokemon(switchOutTarget: PlayerPokemon): void {
|
||||
// If not forced to switch, add a SwitchPhase to allow picking the next switched in Pokemon.
|
||||
if (this.switchType !== SwitchType.FORCE_SWITCH) {
|
||||
globalScene.appendToPhase(
|
||||
globalScene.prependToPhase(
|
||||
new SwitchPhase(this.switchType, switchOutTarget.getFieldIndex(), true, true),
|
||||
MoveEndPhase,
|
||||
);
|
||||
@ -124,7 +128,7 @@ export function ForceSwitch<TBase extends SubMoveOrAbAttr>(Base: TBase) {
|
||||
const reservePartyMembers = globalScene.getBackupPartyMemberIndices(true);
|
||||
const switchInIndex = reservePartyMembers[switchOutTarget.randSeedInt(reservePartyMembers.length)];
|
||||
|
||||
globalScene.appendToPhase(
|
||||
globalScene.prependToPhase(
|
||||
new SwitchSummonPhase(this.switchType, switchOutTarget.getFieldIndex(), switchInIndex, false, true),
|
||||
MoveEndPhase,
|
||||
);
|
||||
@ -144,7 +148,7 @@ export function ForceSwitch<TBase extends SubMoveOrAbAttr>(Base: TBase) {
|
||||
this.switchType === SwitchType.FORCE_SWITCH
|
||||
? reservePartyIndices[switchOutTarget.randSeedInt(reservePartyIndices.length)]
|
||||
: (globalScene.currentBattle.trainer.getNextSummonIndex(switchOutTarget.trainerSlot) ?? 0);
|
||||
globalScene.appendToPhase(
|
||||
globalScene.prependToPhase(
|
||||
new SwitchSummonPhase(this.switchType, switchOutTarget.getFieldIndex(), summonIndex, false, false),
|
||||
MoveEndPhase,
|
||||
);
|
||||
|
@ -1336,7 +1336,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
* @see {@linkcode SubstituteTag}
|
||||
* @see {@linkcode getFieldPositionOffset}
|
||||
*/
|
||||
getSubstituteOffset(): [number, number] {
|
||||
getSubstituteOffset(): [x: number, y: number] {
|
||||
return this.isPlayer() ? [-30, 10] : [30, -10];
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,8 @@ export class FaintPhase extends PokemonPhase {
|
||||
faintPokemon.getTag(BattlerTagType.GRUDGE)?.lapse(faintPokemon, BattlerTagLapseType.CUSTOM, this.source);
|
||||
}
|
||||
|
||||
// Check for reviver seed
|
||||
faintPokemon.resetSummonData();
|
||||
|
||||
if (!this.preventInstantRevive) {
|
||||
const instantReviveModifier = globalScene.applyModifier(
|
||||
PokemonInstantReviveModifier,
|
||||
@ -70,7 +71,6 @@ export class FaintPhase extends PokemonPhase {
|
||||
) as PokemonInstantReviveModifier;
|
||||
|
||||
if (instantReviveModifier) {
|
||||
faintPokemon.resetSummonData();
|
||||
faintPokemon.loseHeldItem(instantReviveModifier);
|
||||
globalScene.updateModifiers(this.player);
|
||||
return this.end();
|
||||
@ -179,11 +179,11 @@ export class FaintPhase extends PokemonPhase {
|
||||
} else {
|
||||
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
|
||||
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
|
||||
const reservePartyIndices = globalScene.getBackupPartyMemberIndices(
|
||||
false,
|
||||
(pokemon as EnemyPokemon).trainerSlot,
|
||||
);
|
||||
if (reservePartyIndices.length) {
|
||||
const hasReservePartyMember = !!globalScene
|
||||
.getEnemyParty()
|
||||
.filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
|
||||
.length;
|
||||
if (hasReservePartyMember) {
|
||||
globalScene.pushPhase(new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false));
|
||||
}
|
||||
}
|
||||
@ -217,7 +217,6 @@ export class FaintPhase extends PokemonPhase {
|
||||
globalScene.addFaintedEnemyScore(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();
|
||||
this.end();
|
||||
},
|
||||
|
@ -274,6 +274,8 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
||||
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
|
||||
}
|
||||
|
||||
pokemon.resetTurnData();
|
||||
|
||||
if (
|
||||
!this.loaded ||
|
||||
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType) ||
|
||||
|
@ -165,8 +165,13 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
party[this.slotIndex] = this.lastPokemon;
|
||||
party[this.fieldIndex] = switchedInPokemon;
|
||||
const showTextAndSummon = () => {
|
||||
// TODO: Should this remove the info container?
|
||||
this.lastPokemon.leaveField(![SwitchType.BATON_PASS, SwitchType.SHED_TAIL].includes(this.switchType), false);
|
||||
// We don't reset temp effects here as we need to transfer them to tne new pokemon
|
||||
// TODO: When should this remove the info container?
|
||||
// Force switch moves did it prior
|
||||
this.lastPokemon.leaveField(
|
||||
![SwitchType.BATON_PASS, SwitchType.SHED_TAIL].includes(this.switchType),
|
||||
this.doReturn,
|
||||
);
|
||||
globalScene.ui.showText(
|
||||
this.player
|
||||
? i18next.t("battle:playerGo", {
|
||||
@ -184,13 +189,11 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
* If this switch is passing a Substitute, make the switched Pokemon matches the returned Pokemon's state as it left.
|
||||
* Otherwise, clear any persisting tags on the returned Pokemon.
|
||||
*/
|
||||
if (this.switchType === SwitchType.BATON_PASS || this.switchType === SwitchType.SHED_TAIL) {
|
||||
const substitute = this.lastPokemon.getTag(SubstituteTag);
|
||||
if (substitute) {
|
||||
switchedInPokemon.x += this.lastPokemon.getSubstituteOffset()[0];
|
||||
switchedInPokemon.y += this.lastPokemon.getSubstituteOffset()[1];
|
||||
switchedInPokemon.setAlpha(0.5);
|
||||
}
|
||||
const substitute = this.lastPokemon.getTag(SubstituteTag);
|
||||
if ((this.switchType === SwitchType.BATON_PASS || this.switchType === SwitchType.SHED_TAIL) && substitute) {
|
||||
switchedInPokemon.x += this.lastPokemon.getSubstituteOffset()[0];
|
||||
switchedInPokemon.y += this.lastPokemon.getSubstituteOffset()[1];
|
||||
switchedInPokemon.setAlpha(0.5);
|
||||
}
|
||||
this.summon();
|
||||
};
|
||||
@ -209,35 +212,35 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
onEnd(): void {
|
||||
super.onEnd();
|
||||
|
||||
const pokemon = this.getPokemon();
|
||||
const activePokemon = 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;
|
||||
activePokemon.resetTurnData();
|
||||
activePokemon.resetSummonData();
|
||||
activePokemon.tempSummonData.turnCount--;
|
||||
activePokemon.tempSummonData.waveTurnCount--;
|
||||
activePokemon.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) {
|
||||
pokemon.transferSummon(this.lastPokemon);
|
||||
activePokemon.transferSummon(this.lastPokemon);
|
||||
this.lastPokemon.resetTurnData();
|
||||
this.lastPokemon.resetSummonData();
|
||||
} else if (this.switchType === SwitchType.SHED_TAIL) {
|
||||
const subTag = this.lastPokemon.getTag(SubstituteTag);
|
||||
if (subTag) {
|
||||
pokemon.summonData.tags.push(subTag);
|
||||
activePokemon.summonData.tags.push(subTag);
|
||||
}
|
||||
this.lastPokemon.resetTurnData();
|
||||
this.lastPokemon.resetSummonData();
|
||||
}
|
||||
|
||||
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
globalScene.triggerPokemonFormChange(activePokemon, SpeciesFormChangeActiveTrigger, true);
|
||||
// Reverts to weather-based forms when weather suppressors (Cloud Nine/Air Lock) are switched out
|
||||
globalScene.arena.triggerWeatherBasedFormChanges();
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { ArenaTagSide } from "#app/data/arena-tag";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
@ -24,29 +26,60 @@ describe("Abilities - Mold Breaker", () => {
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.moveset([Moves.SPLASH])
|
||||
.moveset([Moves.ERUPTION, Moves.EARTHQUAKE, Moves.DRAGON_TAIL])
|
||||
.ability(Abilities.MOLD_BREAKER)
|
||||
.battleStyle("single")
|
||||
.disableCrits()
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyPassiveAbility(Abilities.NO_GUARD)
|
||||
.enemyMoveset(Moves.SPLASH);
|
||||
});
|
||||
|
||||
it("should turn off the ignore abilities arena variable after the user's move", async () => {
|
||||
game.override
|
||||
.enemyMoveset(Moves.SPLASH)
|
||||
.ability(Abilities.MOLD_BREAKER)
|
||||
.moveset([Moves.ERUPTION])
|
||||
.startingLevel(100)
|
||||
.enemyLevel(2);
|
||||
it("should ignore ignorable abilities during the move's execution", async () => {
|
||||
game.override.startingLevel(100).enemyLevel(2).enemyAbility(Abilities.STURDY);
|
||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||
const enemy = game.scene.getEnemyPokemon()!;
|
||||
|
||||
expect(enemy.isFainted()).toBe(false);
|
||||
game.move.select(Moves.ERUPTION);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getEnemyPokemon()?.isFainted()).toBe(true);
|
||||
});
|
||||
|
||||
it("should turn off ignore abilities arena variable after the user's move concludes", async () => {
|
||||
game.override.startingLevel(100).enemyLevel(2);
|
||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||
|
||||
expect(globalScene.arena.ignoreAbilities).toBe(false);
|
||||
game.move.select(Moves.SPLASH);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.phaseInterceptor.to("MoveEndPhase", true);
|
||||
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
expect(globalScene.arena.ignoreAbilities).toBe(true);
|
||||
|
||||
await game.phaseInterceptor.to("MoveEndPhase");
|
||||
expect(globalScene.arena.ignoreAbilities).toBe(false);
|
||||
});
|
||||
|
||||
it("should keep Levitate opponents grounded when using force switch moves", async () => {
|
||||
game.override.enemyAbility(Abilities.LEVITATE).enemySpecies(Species.WEEZING).startingWave(8); // first rival battle; guaranteed 2 mon party
|
||||
|
||||
// Setup toxic spikes and stealth rock
|
||||
game.scene.arena.addTag(ArenaTagType.TOXIC_SPIKES, -1, Moves.TOXIC_SPIKES, 1, ArenaTagSide.ENEMY);
|
||||
game.scene.arena.addTag(ArenaTagType.SPIKES, -1, Moves.CEASELESS_EDGE, 1, ArenaTagSide.ENEMY);
|
||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||
|
||||
const [weezing1, weezing2] = game.scene.getEnemyParty();
|
||||
// Weezing's levitate prevented removal of Toxic Spikes, ignored Spikes damage
|
||||
expect(game.scene.arena.getTagOnSide(ArenaTagType.TOXIC_SPIKES, ArenaTagSide.ENEMY)).toBeDefined();
|
||||
expect(weezing1.getHpRatio()).toBe(1);
|
||||
|
||||
game.move.select(Moves.DRAGON_TAIL);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
// Levitate was ignored during the switch, causing Toxic Spikes to be removed and Spikes to deal damage
|
||||
expect(weezing1.isOnField()).toBe(false);
|
||||
expect(weezing2.isOnField()).toBe(true);
|
||||
expect(weezing2.getHpRatio()).toBeCloseTo(0.75);
|
||||
expect(game.scene.arena.getTagOnSide(ArenaTagType.TOXIC_SPIKES, ArenaTagSide.ENEMY)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
@ -349,7 +349,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
confirmNoSwitch();
|
||||
|
||||
// Turn 2: get back enough HP that substitute doesn't put us under
|
||||
wimpod.hp = wimpod.getMaxHp() * 0.8;
|
||||
wimpod.hp = wimpod.getMaxHp() * 0.78;
|
||||
|
||||
game.move.select(Moves.SUBSTITUTE);
|
||||
game.doSelectPartyPokemon(1);
|
||||
@ -373,7 +373,7 @@ describe("Abilities - Wimp Out", () => {
|
||||
it("should disregard Shell Bell recovery while still activating it before switching", async () => {
|
||||
game.override
|
||||
.moveset(Moves.DOUBLE_EDGE)
|
||||
.enemyMoveset([Moves.SPLASH])
|
||||
.enemyMoveset(Moves.SPLASH)
|
||||
.startingHeldItems([{ name: "SHELL_BELL", count: 4 }]); // heals 50% of damage dealt, more than recoil takes away
|
||||
await game.classicMode.startBattle([Species.WIMPOD, Species.TYRUNT]);
|
||||
|
||||
@ -382,10 +382,13 @@ describe("Abilities - Wimp Out", () => {
|
||||
|
||||
game.move.select(Moves.DOUBLE_EDGE);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
|
||||
// Wimp out activated before shell bell healing
|
||||
// Wimp out check activated from recoil before shell bell procced, but did not deny the pokemon its recovery
|
||||
expect(wimpod.turnData.damageTaken).toBeGreaterThan(0);
|
||||
expect(wimpod.getHpRatio()).toBeGreaterThan(0.5);
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
confirmSwitch();
|
||||
expect(game.phaseInterceptor.log).toContain("PokemonHealPhase");
|
||||
});
|
||||
|
@ -106,10 +106,9 @@ describe("Items - Reviver Seed", () => {
|
||||
|
||||
// Self-damage tests
|
||||
it.each([
|
||||
{ moveType: "Relative Recoil", move: Moves.DOUBLE_EDGE },
|
||||
{ moveType: "HP% Recoil", move: Moves.CHLOROBLAST },
|
||||
{ moveType: "Recoil", move: Moves.DOUBLE_EDGE },
|
||||
{ moveType: "Self-KO", move: Moves.EXPLOSION },
|
||||
{ moveType: "Ghost-type Curse", move: Moves.CURSE },
|
||||
{ moveType: "Self-Deduction", move: Moves.CURSE },
|
||||
{ moveType: "Liquid Ooze", move: Moves.GIGA_DRAIN },
|
||||
])("should not activate the holder's reviver seed from $moveType", async ({ move }) => {
|
||||
game.override
|
||||
|
@ -32,34 +32,25 @@ describe("Moves - U-turn", () => {
|
||||
.disableCrits();
|
||||
});
|
||||
|
||||
it("should switch the user out upon use", async () => {
|
||||
await game.classicMode.startBattle([Species.RAICHU, Species.SHUCKLE]);
|
||||
const [raichu, shuckle] = game.scene.getPlayerParty();
|
||||
expect(raichu).toBeDefined();
|
||||
expect(shuckle).toBeDefined();
|
||||
|
||||
expect(game.scene.getPlayerPokemon()!).toBe(raichu);
|
||||
game.move.select(Moves.U_TURN);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
|
||||
expect(game.scene.getPlayerPokemon()!).toBe(shuckle);
|
||||
});
|
||||
|
||||
it("triggers regenerator passive once upon switch", async () => {
|
||||
it("triggers regenerator a single time when a regenerator user switches out with u-turn", async () => {
|
||||
// arrange
|
||||
const playerHp = 1;
|
||||
game.override.ability(Abilities.REGENERATOR);
|
||||
await game.classicMode.startBattle([Species.RAICHU, Species.SHUCKLE]);
|
||||
game.scene.getPlayerPokemon()!.hp = 1;
|
||||
game.scene.getPlayerPokemon()!.hp = playerHp;
|
||||
|
||||
// act
|
||||
game.move.select(Moves.U_TURN);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.getPlayerParty()[1].hp).toBeGreaterThan(1);
|
||||
// assert
|
||||
expect(game.scene.getPlayerParty()[1].hp).toEqual(
|
||||
Math.floor(game.scene.getPlayerParty()[1].getMaxHp() * 0.33 + playerHp),
|
||||
);
|
||||
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
|
||||
expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.SHUCKLE);
|
||||
});
|
||||
}, 20000);
|
||||
|
||||
it("triggers rough skin on the u-turn user before a new pokemon is switched in", async () => {
|
||||
// arrange
|
||||
|
@ -1,240 +0,0 @@
|
||||
import { PokemonSummonData, PokemonTurnData } from "#app/field/pokemon";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { BattleType } from "#enums/battle-type";
|
||||
import { BattlerTagType } from "#enums/battler-tag-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("Manual Switching -", () => {
|
||||
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)
|
||||
.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...
|
||||
])(
|
||||
"Mid-Battle Switch Outs - $name - ",
|
||||
({ playerMove = Moves.SPLASH, playerAbility = Abilities.BALL_FETCH, enemyMove = 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
|
||||
.moveset(playerMove)
|
||||
.ability(playerAbility)
|
||||
.battleStyle("single")
|
||||
.disableCrits()
|
||||
.enemyLevel(100)
|
||||
.battleType(BattleType.TRAINER)
|
||||
.passiveAbility(Abilities.STURDY)
|
||||
.enemySpecies(Species.MAGIKARP)
|
||||
.enemyMoveset(enemyMove)
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyPassiveAbility(Abilities.NO_GUARD);
|
||||
});
|
||||
|
||||
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(playerMove);
|
||||
game.doSelectPartyPokemon(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();
|
||||
piloswine.addTag(BattlerTagType.AQUA_RING, 999); // give piloswine a tag to ensure we know if summonData got reset
|
||||
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(playerMove);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(piloSummonSpy).toHaveBeenCalledTimes(1);
|
||||
expect(piloTurnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(mamoSummonSpy).toHaveBeenCalledTimes(1);
|
||||
expect(mamoTurnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(piloswine.summonData).toEqual(new PokemonSummonData());
|
||||
expect(piloswine.turnData).toEqual(new PokemonTurnData());
|
||||
});
|
||||
|
||||
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(playerMove);
|
||||
game.doSelectPartyPokemon(1);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(piloWaveSpy).toHaveBeenCalledTimes(0);
|
||||
expect(piloBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||
expect(mamoWaveSpy).toHaveBeenCalledTimes(0);
|
||||
expect(mamoBattleWaveSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
},
|
||||
);
|
Loading…
Reference in New Issue
Block a user