mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-25 16:26:25 +00:00
[Improvement] Refactored Test Phase Management with Error Handling (#1962)
* better phase management in tests * cleanup runFrom/to * first step of async error handling * second step of async error handling, halt await, still an issue with select-starter test * added back whenAboutToRun * added back full run suite for starter-select.test.ts
This commit is contained in:
parent
0af0ad5b49
commit
c301a54039
@ -44,8 +44,8 @@ describe("Abilities - Intrepid Sword", () => {
|
||||
expect(game.scene.getParty()[0].summonData).not.toBeUndefined();
|
||||
let battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
|
||||
expect(battleStatsPokemon[BattleStat.ATK]).toBe(0);
|
||||
await game.phaseInterceptor.mustRun(ShowAbilityPhase).catch((error) => expect(error).toBe(ShowAbilityPhase));
|
||||
await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase));
|
||||
await game.phaseInterceptor.run(ShowAbilityPhase);
|
||||
await game.phaseInterceptor.run(StatChangePhase);
|
||||
battleStatsPokemon = game.scene.getParty()[0].summonData.battleStats;
|
||||
expect(battleStatsPokemon[BattleStat.ATK]).toBe(1);
|
||||
}, 20000);
|
||||
@ -57,8 +57,8 @@ describe("Abilities - Intrepid Sword", () => {
|
||||
let battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
|
||||
expect(battleStatsOpponent[BattleStat.ATK]).toBe(0);
|
||||
await game.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase);
|
||||
await game.phaseInterceptor.mustRun(StatChangePhase).catch((error) => expect(error).toBe(StatChangePhase));
|
||||
await game.phaseInterceptor.whenAboutToRun(MessagePhase);
|
||||
await game.phaseInterceptor.run(StatChangePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats;
|
||||
expect(battleStatsOpponent[BattleStat.ATK]).toBe(1);
|
||||
}, 20000);
|
||||
|
@ -5,7 +5,7 @@ import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {
|
||||
CommandPhase, EnemyCommandPhase,
|
||||
CommandPhase, EnemyCommandPhase, SelectTargetPhase,
|
||||
TurnStartPhase
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
@ -55,7 +55,6 @@ describe("Battle order", () => {
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
|
||||
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
|
||||
const order = phase.getOrder();
|
||||
expect(order[0]).toBe(2);
|
||||
@ -77,7 +76,6 @@ describe("Battle order", () => {
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
|
||||
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
|
||||
const order = phase.getOrder();
|
||||
expect(order[0]).toBe(0);
|
||||
@ -118,9 +116,7 @@ describe("Battle order", () => {
|
||||
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
|
||||
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
|
||||
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
|
||||
const order = phase.getOrder();
|
||||
expect(order.indexOf(0)).toBeGreaterThan(order.indexOf(2));
|
||||
@ -163,9 +159,7 @@ describe("Battle order", () => {
|
||||
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
|
||||
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
|
||||
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
|
||||
const order = phase.getOrder();
|
||||
expect(order.indexOf(3)).toBeLessThan(order.indexOf(0));
|
||||
@ -207,9 +201,7 @@ describe("Battle order", () => {
|
||||
const handler = game.scene.ui.getHandler() as TargetSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(CommandPhase).to(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.whenAboutToRun(TurnStartPhase);
|
||||
await game.phaseInterceptor.runFrom(SelectTargetPhase).to(TurnStartPhase, false);
|
||||
const phase = game.scene.getCurrentPhase() as TurnStartPhase;
|
||||
const order = phase.getOrder();
|
||||
expect(order.indexOf(1)).toBeLessThan(order.indexOf(0));
|
||||
|
@ -1,34 +1,21 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import {generateStarter, getMovePosition, waitUntil,} from "#app/test/utils/gameManagerUtils";
|
||||
import {generateStarter, getMovePosition,} from "#app/test/utils/gameManagerUtils";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {GameModes} from "#app/game-mode";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import * as overrides from "../../overrides";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {
|
||||
BattleEndPhase,
|
||||
BerryPhase,
|
||||
CommandPhase,
|
||||
DamagePhase,
|
||||
EggLapsePhase,
|
||||
EncounterPhase,
|
||||
EnemyCommandPhase,
|
||||
FaintPhase,
|
||||
LoginPhase,
|
||||
MessagePhase,
|
||||
MoveEffectPhase,
|
||||
MoveEndPhase,
|
||||
MovePhase,
|
||||
PostSummonPhase,
|
||||
SelectGenderPhase,
|
||||
SelectModifierPhase,
|
||||
SelectStarterPhase,
|
||||
StatChangePhase,
|
||||
SummonPhase,
|
||||
TitlePhase,
|
||||
TurnEndPhase,
|
||||
TurnInitPhase,
|
||||
TurnStartPhase,
|
||||
VictoryPhase,
|
||||
} from "#app/phases";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
@ -36,6 +23,7 @@ import Phaser from "phaser";
|
||||
import {allSpecies} from "#app/data/pokemon-species";
|
||||
import {PlayerGender} from "#app/data/enums/player-gender";
|
||||
import { getGameMode } from "#app/game-mode.js";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
@ -55,22 +43,6 @@ describe("Test Battle Phase", () => {
|
||||
game = new GameManager(phaserGame);
|
||||
});
|
||||
|
||||
it("test phase interceptor with remove", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
|
||||
await game.phaseInterceptor.run(LoginPhase, () => {
|
||||
return game.phaseInterceptor.log.includes("LoginPhase");
|
||||
});
|
||||
|
||||
game.scene.gameData.gender = PlayerGender.MALE;
|
||||
await game.phaseInterceptor.remove(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase));
|
||||
|
||||
await game.phaseInterceptor.run(TitlePhase);
|
||||
await waitUntil(() => game.scene.ui?.getMode() === Mode.TITLE);
|
||||
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
|
||||
}, 100000);
|
||||
|
||||
it("test phase interceptor with prompt", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
|
||||
@ -87,7 +59,7 @@ describe("Test Battle Phase", () => {
|
||||
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
|
||||
expect(game.scene.gameData.gender).toBe(PlayerGender.MALE);
|
||||
}, 100000);
|
||||
}, 20000);
|
||||
|
||||
it("test phase interceptor with prompt with preparation for a future prompt", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
@ -109,13 +81,13 @@ describe("Test Battle Phase", () => {
|
||||
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.TITLE);
|
||||
expect(game.scene.gameData.gender).toBe(PlayerGender.MALE);
|
||||
}, 100000);
|
||||
}, 20000);
|
||||
|
||||
it("newGame one-liner", async() => {
|
||||
await game.startBattle();
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 100000);
|
||||
}, 20000);
|
||||
|
||||
it("do attack wave 3 - single battle - regular - OHKO", async() => {
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
@ -123,6 +95,8 @@ describe("Test Battle Phase", () => {
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
await game.startBattle();
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
@ -132,28 +106,10 @@ describe("Test Battle Phase", () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(TurnStartPhase);
|
||||
|
||||
await game.phaseInterceptor.run(MovePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
await game.phaseInterceptor.run(MoveEffectPhase);
|
||||
await game.phaseInterceptor.run(DamagePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(FaintPhase));
|
||||
await game.phaseInterceptor.run(FaintPhase);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
|
||||
await game.phaseInterceptor.run(VictoryPhase);
|
||||
await game.phaseInterceptor.run(MoveEndPhase);
|
||||
await game.phaseInterceptor.run(MovePhase);
|
||||
await game.phaseInterceptor.run(BerryPhase);
|
||||
await game.phaseInterceptor.run(TurnEndPhase);
|
||||
await game.phaseInterceptor.run(BattleEndPhase);
|
||||
await game.phaseInterceptor.run(EggLapsePhase);
|
||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.MODIFIER_SELECT);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
}, 100000);
|
||||
}, 20000);
|
||||
|
||||
it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async() => {
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
@ -161,7 +117,8 @@ describe("Test Battle Phase", () => {
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(5);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP]);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP, Moves.TAIL_WHIP]);
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
await game.startBattle();
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
@ -171,35 +128,8 @@ describe("Test Battle Phase", () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, Moves.TACKLE);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(TurnStartPhase);
|
||||
|
||||
await game.phaseInterceptor.run(MovePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
await game.phaseInterceptor.run(MoveEffectPhase);
|
||||
await game.phaseInterceptor.run(DamagePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase));
|
||||
await game.phaseInterceptor.run(MoveEndPhase);
|
||||
|
||||
await game.phaseInterceptor.run(MovePhase);
|
||||
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEffectPhase));
|
||||
await game.phaseInterceptor.run(MoveEffectPhase);
|
||||
game.scene.moveAnimations = null; // Mandatory to avoid the crash
|
||||
await game.phaseInterceptor.run(StatChangePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase) || game.isCurrentPhase(DamagePhase));
|
||||
await game.phaseInterceptor.run(DamagePhase, () => game.isCurrentPhase(MessagePhase) || game.isCurrentPhase(MoveEndPhase));
|
||||
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(MoveEndPhase));
|
||||
await game.phaseInterceptor.run(MoveEndPhase);
|
||||
|
||||
await game.phaseInterceptor.run(BerryPhase);
|
||||
await game.phaseInterceptor.run(MessagePhase, () => game.isCurrentPhase(TurnEndPhase));
|
||||
await game.phaseInterceptor.run(TurnEndPhase);
|
||||
|
||||
await game.phaseInterceptor.run(TurnInitPhase);
|
||||
await game.phaseInterceptor.run(CommandPhase);
|
||||
await waitUntil(() => game.scene.ui?.getMode() === Mode.COMMAND);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 100000);
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase);
|
||||
}, 20000);
|
||||
|
||||
it("load 100% data file", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
@ -208,7 +138,7 @@ describe("Test Battle Phase", () => {
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
}, 50000);
|
||||
}, 20000);
|
||||
|
||||
it("start battle with selected team", async() => {
|
||||
await game.startBattle([
|
||||
@ -219,26 +149,7 @@ describe("Test Battle Phase", () => {
|
||||
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CHARIZARD);
|
||||
expect(game.scene.getParty()[1].species.speciesId).toBe(Species.CHANSEY);
|
||||
expect(game.scene.getParty()[2].species.speciesId).toBe(Species.MEW);
|
||||
}, 50000);
|
||||
|
||||
it("assert next phase", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
|
||||
game.scene.gameData.gender = PlayerGender.MALE;
|
||||
game.endPhase();
|
||||
}, () => game.isCurrentPhase(TitlePhase));
|
||||
await game.phaseInterceptor.mustRun(SelectGenderPhase).catch((error) => expect(error).toBe(SelectGenderPhase));
|
||||
await game.phaseInterceptor.mustRun(TitlePhase).catch((error) => expect(error).toBe(TitlePhase));
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
game.scene.gameMode = getGameMode(GameModes.CLASSIC);
|
||||
const starters = generateStarter(game.scene);
|
||||
const selectStarterPhase = new SelectStarterPhase(game.scene);
|
||||
game.scene.pushPhase(new EncounterPhase(game.scene, false));
|
||||
selectStarterPhase.initBattle(starters);
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(EncounterPhase).catch((error) => expect(error).toBe(EncounterPhase));
|
||||
await game.phaseInterceptor.mustRun(PostSummonPhase).catch((error) => expect(error).toBe(PostSummonPhase));
|
||||
}, 50000);
|
||||
}, 20000);
|
||||
|
||||
it("test remove random battle seed int", async() => {
|
||||
for (let i=0; i<10; i++) {
|
||||
@ -246,5 +157,107 @@ describe("Test Battle Phase", () => {
|
||||
expect(rand).toBe(14);
|
||||
}
|
||||
});
|
||||
|
||||
it("wrong phase", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
await game.phaseInterceptor.run(LoginPhase).catch((e) => {
|
||||
expect(e).toBe("Wrong phase: this is SelectGenderPhase and not LoginPhase");
|
||||
});
|
||||
}, 20000);
|
||||
|
||||
it("wrong phase but skip", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
await game.phaseInterceptor.run(LoginPhase, () => game.isCurrentPhase(SelectGenderPhase));
|
||||
}, 20000);
|
||||
|
||||
it("good run", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
|
||||
game.scene.gameData.gender = PlayerGender.MALE;
|
||||
game.endPhase();
|
||||
}, () => game.isCurrentPhase(TitlePhase));
|
||||
await game.phaseInterceptor.run(SelectGenderPhase, () => game.isCurrentPhase(TitlePhase));
|
||||
await game.phaseInterceptor.run(TitlePhase);
|
||||
}, 20000);
|
||||
|
||||
it("good run from select gender to title", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
|
||||
game.scene.gameData.gender = PlayerGender.MALE;
|
||||
game.endPhase();
|
||||
}, () => game.isCurrentPhase(TitlePhase));
|
||||
await game.phaseInterceptor.runFrom(SelectGenderPhase).to(TitlePhase);
|
||||
}, 20000);
|
||||
|
||||
it("good run to SummonPhase phase", async() => {
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
game.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
|
||||
game.scene.gameData.gender = PlayerGender.MALE;
|
||||
game.endPhase();
|
||||
}, () => game.isCurrentPhase(TitlePhase));
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
game.scene.gameMode = getGameMode(GameModes.CLASSIC);
|
||||
const starters = generateStarter(game.scene);
|
||||
const selectStarterPhase = new SelectStarterPhase(game.scene);
|
||||
game.scene.pushPhase(new EncounterPhase(game.scene, false));
|
||||
selectStarterPhase.initBattle(starters);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(SelectGenderPhase).to(SummonPhase);
|
||||
}, 20000);
|
||||
|
||||
it("2vs1", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
await game.startBattle([
|
||||
Species.BLASTOISE,
|
||||
Species.CHARIZARD,
|
||||
]);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
|
||||
it("1vs1", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
await game.startBattle([
|
||||
Species.BLASTOISE,
|
||||
]);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
|
||||
it("2vs2", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
await game.startBattle([
|
||||
Species.BLASTOISE,
|
||||
Species.CHARIZARD,
|
||||
]);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
|
||||
it("4vs2", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MIGHTYENA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
await game.startBattle([
|
||||
Species.BLASTOISE,
|
||||
Species.CHARIZARD,
|
||||
Species.DARKRAI,
|
||||
Species.GABITE,
|
||||
]);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
});
|
||||
|
||||
|
39
src/test/battle/error-handling.test.ts
Normal file
39
src/test/battle/error-handling.test.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, it, vi} from "vitest";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
|
||||
describe("Test Battle Phase", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
});
|
||||
|
||||
it("should start phase", async() => {
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(3);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
await game.startBattle();
|
||||
}, 100000);
|
||||
});
|
||||
|
@ -28,7 +28,8 @@ describe("Phases", () => {
|
||||
describe("LoginPhase", () => {
|
||||
it("should start the login phase", async () => {
|
||||
const loginPhase = new LoginPhase(scene);
|
||||
loginPhase.start();
|
||||
scene.pushPhase(loginPhase);
|
||||
await game.phaseInterceptor.run(LoginPhase);
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MESSAGE);
|
||||
});
|
||||
});
|
||||
@ -36,16 +37,18 @@ describe("Phases", () => {
|
||||
describe("TitlePhase", () => {
|
||||
it("should start the title phase", async () => {
|
||||
const titlePhase = new TitlePhase(scene);
|
||||
titlePhase.start();
|
||||
expect(scene.ui.getMode()).to.equal(Mode.MESSAGE);
|
||||
scene.pushPhase(titlePhase);
|
||||
await game.phaseInterceptor.run(TitlePhase);
|
||||
expect(scene.ui.getMode()).to.equal(Mode.TITLE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("UnavailablePhase", () => {
|
||||
it("should start the unavailable phase", async () => {
|
||||
const unavailablePhase = new UnavailablePhase(scene);
|
||||
unavailablePhase.start();
|
||||
scene.pushPhase(unavailablePhase);
|
||||
await game.phaseInterceptor.run(UnavailablePhase);
|
||||
expect(scene.ui.getMode()).to.equal(Mode.UNAVAILABLE);
|
||||
});
|
||||
}, 20000);
|
||||
});
|
||||
});
|
||||
|
@ -15,9 +15,9 @@ import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler";
|
||||
import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler";
|
||||
import {OptionSelectItem} from "#app/ui/abstact-option-select-ui-handler";
|
||||
import {Gender} from "#app/data/gender";
|
||||
import {allSpecies} from "#app/data/pokemon-species";
|
||||
import {Nature} from "#app/data/nature";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {allSpecies} from "#app/data/pokemon-species";
|
||||
|
||||
|
||||
describe("UI - Starter select", () => {
|
||||
@ -51,12 +51,13 @@ describe("UI - Starter select", () => {
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -73,6 +74,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -84,10 +86,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -99,19 +99,25 @@ describe("UI - Starter select", () => {
|
||||
|
||||
it("Bulbasaur - shiny - variant 2 female hardy overgrow", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.CYCLE_GENDER);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -128,6 +134,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -139,10 +146,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -153,15 +158,19 @@ describe("UI - Starter select", () => {
|
||||
expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.OVERGROW);
|
||||
}, 20000);
|
||||
|
||||
it("Bulbasaur - shiny - variant 2 female lonely cholorophyl", async() => {
|
||||
it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
@ -169,7 +178,9 @@ describe("UI - Starter select", () => {
|
||||
handler.processInput(Button.CYCLE_NATURE);
|
||||
handler.processInput(Button.CYCLE_ABILITY);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -186,6 +197,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -197,10 +209,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -211,21 +221,27 @@ describe("UI - Starter select", () => {
|
||||
expect(game.scene.getParty()[0].getAbility().id).toBe(Abilities.CHLOROPHYLL);
|
||||
}, 20000);
|
||||
|
||||
it("Bulbasaur - shiny - variant 2 female", async() => {
|
||||
it("Bulbasaur - shiny - variant 2 female lonely chlorophyl", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.CYCLE_GENDER);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -242,6 +258,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -253,10 +270,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -268,19 +283,25 @@ describe("UI - Starter select", () => {
|
||||
|
||||
it("Bulbasaur - not shiny", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.CYCLE_SHINY);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -297,6 +318,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -308,10 +330,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -320,76 +340,28 @@ describe("UI - Starter select", () => {
|
||||
expect(game.scene.getParty()[0].variant).toBe(0);
|
||||
}, 20000);
|
||||
|
||||
it("Bulbasaur - shiny - variant 0", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.V);
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => {
|
||||
optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler;
|
||||
options = optionSelectUiHandler.getOptionsWithScroll();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
expect(options.some(option => option.label === "Add to Party")).toBe(true);
|
||||
expect(options.some(option => option.label === "Toggle IVs")).toBe(true);
|
||||
expect(options.some(option => option.label === "Manage Moves")).toBe(true);
|
||||
expect(options.some(option => option.label === "Use Candies")).toBe(true);
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.BULBASAUR);
|
||||
expect(game.scene.getParty()[0].shiny).toBe(true);
|
||||
expect(game.scene.getParty()[0].variant).toBe(0);
|
||||
}, 20000);
|
||||
|
||||
it("Bulbasaur - shiny - variant 1", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.V);
|
||||
handler.processInput(Button.V);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -406,6 +378,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -417,10 +390,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -429,15 +400,19 @@ describe("UI - Starter select", () => {
|
||||
expect(game.scene.getParty()[0].variant).toBe(1);
|
||||
}, 20000);
|
||||
|
||||
it("Bulbasaur - shiny - variant 1", async() => {
|
||||
it("Bulbasaur - shiny - variant 2", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
@ -445,7 +420,9 @@ describe("UI - Starter select", () => {
|
||||
handler.processInput(Button.V);
|
||||
handler.processInput(Button.V);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -462,6 +439,7 @@ describe("UI - Starter select", () => {
|
||||
expect(options.some(option => option.label === "Cancel")).toBe(true);
|
||||
optionSelectUiHandler.processInput(Button.ACTION);
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.SUBMIT);
|
||||
@ -473,10 +451,8 @@ describe("UI - Starter select", () => {
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.SAVE_SLOT, () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
resolve();
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
|
||||
@ -485,15 +461,19 @@ describe("UI - Starter select", () => {
|
||||
expect(game.scene.getParty()[0].variant).toBe(2);
|
||||
}, 20000);
|
||||
|
||||
it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column ", async() => {
|
||||
it("Check if first pokemon in party is caterpie from gen 1 and 1rd row, 3rd column", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
@ -501,7 +481,9 @@ describe("UI - Starter select", () => {
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -526,6 +508,7 @@ describe("UI - Starter select", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
expect(starterSelectUiHandler.starterGens[0]).toBe(0);
|
||||
expect(starterSelectUiHandler.starterCursors[0]).toBe(3);
|
||||
expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18);
|
||||
@ -539,23 +522,23 @@ describe("UI - Starter select", () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.CATERPIE);
|
||||
}, 20000);
|
||||
|
||||
it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1) ", async() => {
|
||||
it("Check if first pokemon in party is nidoran_m from gen 1 and 2nd row, 4th column (cursor (9+4)-1)", async() => {
|
||||
await game.importData("src/test/utils/saves/everything.prsv");
|
||||
const caughtCount = Object.keys(game.scene.gameData.dexData).filter((key) => {
|
||||
const species = game.scene.gameData.dexData[key];
|
||||
return species.caughtAttr !== 0n;
|
||||
}).length;
|
||||
expect(caughtCount).toBe(Object.keys(allSpecies).length);
|
||||
await game.runToTitle();
|
||||
game.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
const currentPhase = game.scene.getCurrentPhase() as TitlePhase;
|
||||
currentPhase.gameMode = GameModes.CLASSIC;
|
||||
currentPhase.end();
|
||||
});
|
||||
await game.phaseInterceptor.mustRun(SelectStarterPhase).catch((error) => expect(error).toBe(SelectStarterPhase));
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.RIGHT);
|
||||
@ -564,7 +547,9 @@ describe("UI - Starter select", () => {
|
||||
handler.processInput(Button.RIGHT);
|
||||
handler.processInput(Button.DOWN);
|
||||
handler.processInput(Button.ACTION);
|
||||
game.phaseInterceptor.unlock();
|
||||
});
|
||||
await game.phaseInterceptor.run(SelectStarterPhase);
|
||||
let options: OptionSelectItem[];
|
||||
let optionSelectUiHandler: OptionSelectUiHandler;
|
||||
await new Promise<void>((resolve) => {
|
||||
@ -589,6 +574,7 @@ describe("UI - Starter select", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
expect(starterSelectUiHandler.starterGens[0]).toBe(0);
|
||||
expect(starterSelectUiHandler.starterCursors[0]).toBe(12);
|
||||
expect(starterSelectUiHandler.cursorObj.x).toBe(132 + 4 * 18);
|
||||
@ -602,10 +588,6 @@ describe("UI - Starter select", () => {
|
||||
const saveSlotSelectUiHandler = game.scene.ui.getHandler() as SaveSlotSelectUiHandler;
|
||||
saveSlotSelectUiHandler.processInput(Button.ACTION);
|
||||
});
|
||||
game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => {
|
||||
const handler = game.scene.ui.getHandler() as StarterSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
});
|
||||
await game.phaseInterceptor.whenAboutToRun(EncounterPhase);
|
||||
expect(game.scene.getParty()[0].species.speciesId).toBe(Species.NIDORAN_M);
|
||||
}, 20000);
|
||||
|
50
src/test/utils/errorInterceptor.ts
Normal file
50
src/test/utils/errorInterceptor.ts
Normal file
@ -0,0 +1,50 @@
|
||||
export default class ErrorInterceptor {
|
||||
private static instance: ErrorInterceptor;
|
||||
public running;
|
||||
|
||||
constructor() {
|
||||
this.running = [];
|
||||
}
|
||||
|
||||
public static getInstance(): ErrorInterceptor {
|
||||
if (!ErrorInterceptor.instance) {
|
||||
ErrorInterceptor.instance = new ErrorInterceptor();
|
||||
}
|
||||
return ErrorInterceptor.instance;
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.running = [];
|
||||
}
|
||||
|
||||
add(obj) {
|
||||
this.running.push(obj);
|
||||
}
|
||||
|
||||
remove(obj) {
|
||||
const index = this.running.indexOf(obj);
|
||||
if (index !== -1) {
|
||||
this.running.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
process.on("uncaughtException", (error) => {
|
||||
console.log(error);
|
||||
const toStop = ErrorInterceptor.getInstance().running;
|
||||
for (const elm of toStop) {
|
||||
elm.rejectAll(error);
|
||||
}
|
||||
global.testFailed = true;
|
||||
});
|
||||
|
||||
// Global error handler for unhandled promise rejections
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
console.log(reason);
|
||||
const toStop = ErrorInterceptor.getInstance().running;
|
||||
for (const elm of toStop) {
|
||||
elm.rejectAll(reason);
|
||||
}
|
||||
global.testFailed = true;
|
||||
});
|
@ -2,21 +2,17 @@ import GameWrapper from "#app/test/utils/gameWrapper";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {generateStarter, waitUntil} from "#app/test/utils/gameManagerUtils";
|
||||
import {
|
||||
CheckSwitchPhase,
|
||||
CommandPhase,
|
||||
EncounterPhase,
|
||||
LoginPhase,
|
||||
PostSummonPhase,
|
||||
SelectGenderPhase,
|
||||
SelectStarterPhase,
|
||||
SummonPhase,
|
||||
TitlePhase,
|
||||
ToggleDoublePositionPhase,
|
||||
} from "#app/phases";
|
||||
import BattleScene from "#app/battle-scene.js";
|
||||
import PhaseInterceptor from "#app/test/utils/phaseInterceptor";
|
||||
import TextInterceptor from "#app/test/utils/TextInterceptor";
|
||||
import {expect} from "vitest";
|
||||
import {GameModes, getGameMode} from "#app/game-mode";
|
||||
import fs from "fs";
|
||||
import { AES, enc } from "crypto-js";
|
||||
@ -26,6 +22,7 @@ import {PlayerGender} from "#app/data/enums/player-gender";
|
||||
import {GameDataType} from "#app/data/enums/game-data-type";
|
||||
import InputsHandler from "#app/test/utils/inputsHandler";
|
||||
import {ExpNotification} from "#app/enums/exp-notification";
|
||||
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
|
||||
|
||||
/**
|
||||
* Class to manage the game state and transitions between phases.
|
||||
@ -43,6 +40,8 @@ export default class GameManager {
|
||||
* @param bypassLogin - Whether to bypass the login phase.
|
||||
*/
|
||||
constructor(phaserGame: Phaser.Game, bypassLogin: boolean = true) {
|
||||
localStorage.clear();
|
||||
ErrorInterceptor.getInstance().clear();
|
||||
BattleScene.prototype.randBattleSeedInt = (arg) => arg-1;
|
||||
this.gameWrapper = new GameWrapper(phaserGame, bypassLogin);
|
||||
this.scene = new BattleScene();
|
||||
@ -94,14 +93,14 @@ export default class GameManager {
|
||||
* @returns A promise that resolves when the title phase is reached.
|
||||
*/
|
||||
runToTitle(): Promise<void> {
|
||||
return new Promise(async(resolve) => {
|
||||
await this.phaseInterceptor.run(LoginPhase);
|
||||
return new Promise(async(resolve, reject) => {
|
||||
await this.phaseInterceptor.run(LoginPhase).catch((e) => reject(e));
|
||||
this.onNextPrompt("SelectGenderPhase", Mode.OPTION_SELECT, () => {
|
||||
this.scene.gameData.gender = PlayerGender.MALE;
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(TitlePhase));
|
||||
await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase));
|
||||
await this.phaseInterceptor.run(TitlePhase);
|
||||
await this.phaseInterceptor.run(SelectGenderPhase, () => this.isCurrentPhase(TitlePhase)).catch((e) => reject(e));
|
||||
await this.phaseInterceptor.run(TitlePhase).catch((e) => reject(e));
|
||||
this.scene.gameSpeed = 5;
|
||||
this.scene.moveAnimations = false;
|
||||
this.scene.showLevelUpStats = false;
|
||||
@ -118,8 +117,8 @@ export default class GameManager {
|
||||
* @returns A promise that resolves when the summon phase is reached.
|
||||
*/
|
||||
runToSummon(species?: Species[]): Promise<void> {
|
||||
return new Promise(async(resolve) => {
|
||||
await this.runToTitle();
|
||||
return new Promise(async(resolve, reject) => {
|
||||
await this.runToTitle().catch((e) => reject(e));
|
||||
this.onNextPrompt("TitlePhase", Mode.TITLE, () => {
|
||||
this.scene.gameMode = getGameMode(GameModes.CLASSIC);
|
||||
const starters = generateStarter(this.scene, species);
|
||||
@ -127,7 +126,7 @@ export default class GameManager {
|
||||
this.scene.pushPhase(new EncounterPhase(this.scene, false));
|
||||
selectStarterPhase.initBattle(starters);
|
||||
});
|
||||
await this.phaseInterceptor.run(EncounterPhase);
|
||||
await this.phaseInterceptor.run(EncounterPhase).catch((e) => reject(e));
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
@ -138,25 +137,18 @@ export default class GameManager {
|
||||
* @returns A promise that resolves when the battle is started.
|
||||
*/
|
||||
startBattle(species?: Species[]): Promise<void> {
|
||||
return new Promise(async(resolve) => {
|
||||
await this.runToSummon(species);
|
||||
await this.phaseInterceptor.runFrom(PostSummonPhase).to(ToggleDoublePositionPhase);
|
||||
await this.phaseInterceptor.run(SummonPhase, () => this.isCurrentPhase(CheckSwitchPhase) || this.isCurrentPhase(PostSummonPhase));
|
||||
return new Promise(async(resolve, reject) => {
|
||||
await this.runToSummon(species).catch((e) => reject(e));
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(PostSummonPhase));
|
||||
}, () => this.isCurrentPhase(CommandPhase));
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(PostSummonPhase));
|
||||
await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase));
|
||||
await this.phaseInterceptor.run(CheckSwitchPhase, () => this.isCurrentPhase(PostSummonPhase));
|
||||
await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase);
|
||||
await waitUntil(() => this.scene.ui?.getMode() === Mode.COMMAND);
|
||||
}, () => this.isCurrentPhase(CommandPhase));
|
||||
await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase).catch((e) => reject(e));
|
||||
console.log("==================[New Turn]==================");
|
||||
expect(this.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(this.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ export default class GameWrapper {
|
||||
frames: {},
|
||||
});
|
||||
Pokemon.prototype.enableMask = () => null;
|
||||
localStorage.clear();
|
||||
}
|
||||
|
||||
setScene(scene: BattleScene) {
|
||||
|
@ -6,10 +6,12 @@ import {
|
||||
LoginPhase, MessagePhase, MoveEffectPhase, MoveEndPhase, MovePhase, NewBattlePhase, NextEncounterPhase,
|
||||
PostSummonPhase,
|
||||
SelectGenderPhase, SelectModifierPhase,
|
||||
SelectStarterPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase,
|
||||
TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, VictoryPhase
|
||||
SelectStarterPhase, SelectTargetPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase,
|
||||
TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, UnavailablePhase, VictoryPhase
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import UI, {Mode} from "#app/ui/ui";
|
||||
import {Phase} from "#app/phase";
|
||||
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
|
||||
|
||||
export default class PhaseInterceptor {
|
||||
public scene;
|
||||
@ -21,6 +23,9 @@ export default class PhaseInterceptor {
|
||||
private intervalRun;
|
||||
private prompts;
|
||||
private phaseFrom;
|
||||
private inProgress;
|
||||
private originalSetMode;
|
||||
private originalSuperEnd;
|
||||
|
||||
/**
|
||||
* List of phases with their corresponding start methods.
|
||||
@ -56,6 +61,12 @@ export default class PhaseInterceptor {
|
||||
[MoveEndPhase, this.startPhase],
|
||||
[StatChangePhase, this.startPhase],
|
||||
[ShinySparklePhase, this.startPhase],
|
||||
[SelectTargetPhase, this.startPhase],
|
||||
[UnavailablePhase, this.startPhase],
|
||||
];
|
||||
|
||||
private endBySetMode = [
|
||||
TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase
|
||||
];
|
||||
|
||||
/**
|
||||
@ -71,6 +82,15 @@ export default class PhaseInterceptor {
|
||||
this.startPromptHander();
|
||||
}
|
||||
|
||||
rejectAll(error) {
|
||||
if (this.inProgress) {
|
||||
clearInterval(this.promptInterval);
|
||||
clearInterval(this.interval);
|
||||
clearInterval(this.intervalRun);
|
||||
this.inProgress.onError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to set the starting phase.
|
||||
* @param phaseFrom - The phase to start from.
|
||||
@ -86,20 +106,31 @@ export default class PhaseInterceptor {
|
||||
* @param phaseTo - The phase to transition to.
|
||||
* @returns A promise that resolves when the transition is complete.
|
||||
*/
|
||||
async to(phaseTo): Promise<void> {
|
||||
return new Promise(async (resolve) => {
|
||||
await this.run(this.phaseFrom);
|
||||
async to(phaseTo, runTarget: boolean = true): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
ErrorInterceptor.getInstance().add(this);
|
||||
await this.run(this.phaseFrom).catch((e) => reject(e));
|
||||
this.phaseFrom = null;
|
||||
const targetName = typeof phaseTo === "string" ? phaseTo : phaseTo.name;
|
||||
this.intervalRun = setInterval(async () => {
|
||||
this.intervalRun = setInterval(async() => {
|
||||
const currentPhase = this.onHold?.length && this.onHold[0];
|
||||
if (currentPhase && currentPhase.name !== targetName) {
|
||||
await this.run(currentPhase.name);
|
||||
} else if (currentPhase.name === targetName) {
|
||||
await this.run(currentPhase.name);
|
||||
if (currentPhase && currentPhase.name === targetName) {
|
||||
clearInterval(this.intervalRun);
|
||||
if (!runTarget) {
|
||||
return resolve();
|
||||
}
|
||||
await this.run(currentPhase).catch((e) => {
|
||||
clearInterval(this.intervalRun);
|
||||
return reject(e);
|
||||
});
|
||||
return resolve();
|
||||
}
|
||||
if (currentPhase && currentPhase.name !== targetName) {
|
||||
await this.run(currentPhase).catch((e) => {
|
||||
clearInterval(this.intervalRun);
|
||||
return reject(e);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -111,92 +142,53 @@ export default class PhaseInterceptor {
|
||||
* @returns A promise that resolves when the phase is run.
|
||||
*/
|
||||
run(phaseTarget, skipFn?): Promise<void> {
|
||||
this.scene.moveAnimations = null; // Mandatory to avoid crash
|
||||
return new Promise(async (resolve) => {
|
||||
this.waitUntil(phaseTarget, skipFn).then(() => {
|
||||
const currentPhase = this.onHold.shift();
|
||||
currentPhase.call();
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to ensure a phase is run, to throw error on test if not.
|
||||
* @param phaseTarget - The phase to run.
|
||||
* @returns A promise that resolves when the phase is run.
|
||||
*/
|
||||
mustRun(phaseTarget): Promise<void> {
|
||||
const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name;
|
||||
this.scene.moveAnimations = null; // Mandatory to avoid crash
|
||||
return new Promise(async (resolve, reject) => {
|
||||
ErrorInterceptor.getInstance().add(this);
|
||||
const interval = setInterval(async () => {
|
||||
const currentPhase = this.onHold?.length && this.onHold[0];
|
||||
if (currentPhase && currentPhase.name !== targetName) {
|
||||
reject(currentPhase);
|
||||
} else if (currentPhase && currentPhase.name === targetName) {
|
||||
const currentPhase = this.onHold.shift();
|
||||
if (currentPhase) {
|
||||
if (currentPhase.name !== targetName) {
|
||||
clearInterval(interval);
|
||||
await this.run(phaseTarget);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to execute actions when about to run a phase. Does not run the phase, stop right before.
|
||||
* @param phaseTarget - The phase to run.
|
||||
* @param skipFn - Optional skip function.
|
||||
* @returns A promise that resolves when the phase is about to run.
|
||||
*/
|
||||
whenAboutToRun(phaseTarget, skipFn?): Promise<void> {
|
||||
return new Promise(async (resolve) => {
|
||||
this.waitUntil(phaseTarget, skipFn).then(() => {
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to remove a phase from the list.
|
||||
* @param phaseTarget - The phase to remove.
|
||||
* @param skipFn - Optional skip function.
|
||||
* @returns A promise that resolves when the phase is removed.
|
||||
*/
|
||||
remove(phaseTarget, skipFn?): Promise<void> {
|
||||
return new Promise(async (resolve) => {
|
||||
this.waitUntil(phaseTarget, skipFn).then(() => {
|
||||
this.onHold.shift();
|
||||
this.scene.getCurrentPhase().end();
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to wait until a specific phase is reached.
|
||||
* @param phaseTarget - The phase to wait for.
|
||||
* @param skipFn - Optional skip function.
|
||||
* @returns A promise that resolves when the phase is reached.
|
||||
*/
|
||||
waitUntil(phaseTarget, skipFn?): Promise<void> {
|
||||
const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name;
|
||||
return new Promise((resolve, reject) => {
|
||||
this.interval = setInterval(() => {
|
||||
const currentPhase = this.onHold?.length && this.onHold[0] && this.onHold[0].name;
|
||||
// if the currentPhase here is not filled, it means it's a phase we haven't added to the list
|
||||
if (currentPhase === targetName) {
|
||||
clearInterval(this.interval);
|
||||
const skip = skipFn && skipFn(currentPhase.name);
|
||||
if (skip) {
|
||||
this.onHold.unshift(currentPhase);
|
||||
ErrorInterceptor.getInstance().remove(this);
|
||||
return resolve();
|
||||
} else if (skipFn && skipFn()) {
|
||||
clearInterval(this.interval);
|
||||
return reject("Skipped phase");
|
||||
}
|
||||
clearInterval(interval);
|
||||
return reject(`Wrong phase: this is ${currentPhase.name} and not ${targetName}`);
|
||||
}
|
||||
clearInterval(interval);
|
||||
this.inProgress = {
|
||||
name: currentPhase.name,
|
||||
callback: () => {
|
||||
ErrorInterceptor.getInstance().remove(this);
|
||||
resolve();
|
||||
},
|
||||
onError: (error) => reject(error),
|
||||
};
|
||||
currentPhase.call();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
whenAboutToRun(phaseTarget, skipFn?): Promise<void> {
|
||||
const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name;
|
||||
this.scene.moveAnimations = null; // Mandatory to avoid crash
|
||||
return new Promise(async (resolve, reject) => {
|
||||
ErrorInterceptor.getInstance().add(this);
|
||||
const interval = setInterval(async () => {
|
||||
const currentPhase = this.onHold.shift();
|
||||
if (currentPhase) {
|
||||
if (currentPhase.name !== targetName) {
|
||||
this.onHold.unshift(currentPhase);
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -206,10 +198,17 @@ export default class PhaseInterceptor {
|
||||
* Method to initialize phases and their corresponding methods.
|
||||
*/
|
||||
initPhases() {
|
||||
for (const [phase, method] of this.PHASES) {
|
||||
this.originalSetMode = UI.prototype.setMode;
|
||||
this.originalSuperEnd = Phase.prototype.end;
|
||||
UI.prototype.setMode = (mode, ...args) => this.setMode.call(this, mode, ...args);
|
||||
Phase.prototype.end = () => this.superEndPhase.call(this);
|
||||
for (const [phase, methodStart] of this.PHASES) {
|
||||
const originalStart = phase.prototype.start;
|
||||
this.phases[phase.name] = originalStart;
|
||||
phase.prototype.start = () => method.call(this, phase);
|
||||
this.phases[phase.name] = {
|
||||
start: originalStart,
|
||||
endBySetMode: this.endBySetMode.some((elm) => elm.name === phase.name),
|
||||
};
|
||||
phase.prototype.start = () => methodStart.call(this, phase);
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,11 +222,44 @@ export default class PhaseInterceptor {
|
||||
this.onHold.push({
|
||||
name: phase.name,
|
||||
call: () => {
|
||||
this.phases[phase.name].apply(instance);
|
||||
this.phases[phase.name].start.apply(instance);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unlock() {
|
||||
this.inProgress?.callback();
|
||||
this.inProgress = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to end a phase and log it.
|
||||
* @param phase - The phase to start.
|
||||
*/
|
||||
superEndPhase() {
|
||||
const instance = this.scene.getCurrentPhase();
|
||||
console.log(`%c INTERCEPTED Super End Phase ${instance.constructor.name}`, "color:red;");
|
||||
this.originalSuperEnd.apply(instance);
|
||||
this.inProgress?.callback();
|
||||
this.inProgress = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* m2m to set mode.
|
||||
* @param phase - The phase to start.
|
||||
*/
|
||||
setMode(mode: Mode, ...args: any[]): Promise<void> {
|
||||
const currentPhase = this.scene.getCurrentPhase();
|
||||
const instance = this.scene.ui;
|
||||
console.log("setMode", mode, args);
|
||||
const ret = this.originalSetMode.apply(instance, [mode, ...args]);
|
||||
if (this.phases[currentPhase.constructor.name].endBySetMode) {
|
||||
this.inProgress?.callback();
|
||||
this.inProgress = undefined;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to start the prompt handler.
|
||||
*/
|
||||
@ -271,9 +303,12 @@ export default class PhaseInterceptor {
|
||||
*/
|
||||
restoreOg() {
|
||||
for (const [phase] of this.PHASES) {
|
||||
phase.prototype.start = this.phases[phase.name];
|
||||
phase.prototype.start = this.phases[phase.name].start;
|
||||
}
|
||||
UI.prototype.setMode = this.originalSetMode;
|
||||
Phase.prototype.end = this.originalSuperEnd;
|
||||
clearInterval(this.promptInterval);
|
||||
clearInterval(this.interval);
|
||||
clearInterval(this.intervalRun);
|
||||
}
|
||||
}
|
||||
|
@ -21,3 +21,5 @@ initPokemonForms();
|
||||
initSpecies();
|
||||
initMoves();
|
||||
initAbilities();
|
||||
|
||||
global.testFailed = false;
|
||||
|
Loading…
Reference in New Issue
Block a user