mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2024-11-25 08:16:04 +00:00
[Test] Add Tests for Zen Mode Ability (#1978)
* added tests for zen mode - change form in battle * added tests to run some battle against trainer/rival & boss * added a test with a method to kill a pokemon * added an override in the clock mocked to reduce the time of fainting pokemon and thus reducing test time from 5s to less than 1s * added some more tests + doAttack, doKillOpponents, toNextWave, toNextTurn helper * added some more tests + doAttack, doKillOpponents, toNextWave, toNextTurn helper + fix some tests
This commit is contained in:
parent
32d222c9cd
commit
e29c08ba1f
@ -1079,6 +1079,10 @@ export class NextEncounterPhase extends EncounterPhase {
|
||||
super(scene);
|
||||
}
|
||||
|
||||
start() {
|
||||
super.start();
|
||||
}
|
||||
|
||||
doEncounter(): void {
|
||||
this.scene.playBgm(undefined, true);
|
||||
|
||||
@ -1497,6 +1501,10 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
this.batonPass = batonPass;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
super.start();
|
||||
}
|
||||
|
||||
preSummon(): void {
|
||||
if (!this.player) {
|
||||
if (this.slotIndex === -1) {
|
||||
|
142
src/test/abilities/zen_mode.test.ts
Normal file
142
src/test/abilities/zen_mode.test.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import Phaser from "phaser";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import * as overrides from "#app/overrides";
|
||||
import {Abilities} from "#app/data/enums/abilities";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {
|
||||
CommandPhase,
|
||||
DamagePhase,
|
||||
EnemyCommandPhase,
|
||||
MessagePhase,
|
||||
PostSummonPhase,
|
||||
SwitchPhase,
|
||||
SwitchSummonPhase,
|
||||
TurnEndPhase, TurnInitPhase,
|
||||
TurnStartPhase,
|
||||
} from "#app/phases";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Stat} from "#app/data/pokemon-stat";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import {getMovePosition} from "#app/test/utils/gameManagerUtils";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {QuietFormChangePhase} from "#app/form-change-phase";
|
||||
|
||||
|
||||
describe("Abilities - Zen mode", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
});
|
||||
|
||||
it("ZEN MODE - not enough damage to change form", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 100;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(40);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(TurnEndPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).toBeLessThan(100);
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
}, 20000);
|
||||
|
||||
it("ZEN MODE - enough damage to change form", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(QuietFormChangePhase);
|
||||
await game.phaseInterceptor.to(TurnInitPhase, false);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
}, 20000);
|
||||
|
||||
it("ZEN MODE - kill pokemon while on zen mode", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
Species.CHARIZARD,
|
||||
]);
|
||||
game.scene.getParty()[0].stats[Stat.SPD] = 1;
|
||||
game.scene.getParty()[0].stats[Stat.HP] = 1000;
|
||||
game.scene.getParty()[0].hp = 100;
|
||||
expect(game.scene.getParty()[0].formIndex).toBe(0);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false);
|
||||
// await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false);
|
||||
const damagePhase = game.scene.getCurrentPhase() as DamagePhase;
|
||||
damagePhase.updateAmount(80);
|
||||
await game.phaseInterceptor.runFrom(DamagePhase).to(QuietFormChangePhase);
|
||||
expect(game.scene.getParty()[0].hp).not.toBe(100);
|
||||
expect(game.scene.getParty()[0].formIndex).not.toBe(0);
|
||||
await game.killPokemon(game.scene.getParty()[0]);
|
||||
expect(game.scene.getParty()[0].isFainted()).toBe(true);
|
||||
await game.phaseInterceptor.run(MessagePhase);
|
||||
await game.phaseInterceptor.run(EnemyCommandPhase);
|
||||
await game.phaseInterceptor.run(TurnStartPhase);
|
||||
game.onNextPrompt("SwitchPhase", Mode.PARTY, () => {
|
||||
game.scene.unshiftPhase(new SwitchSummonPhase(game.scene, 0, 1, false, false));
|
||||
game.scene.ui.setMode(Mode.MESSAGE);
|
||||
});
|
||||
game.onNextPrompt("SwitchPhase", Mode.MESSAGE, () => {
|
||||
game.endPhase();
|
||||
});
|
||||
await game.phaseInterceptor.run(SwitchPhase);
|
||||
await game.phaseInterceptor.to(PostSummonPhase);
|
||||
expect(game.scene.getParty()[1].formIndex).toBe(1);
|
||||
}, 20000);
|
||||
});
|
@ -6,7 +6,7 @@ import {Species} from "#app/data/enums/species";
|
||||
import * as overrides from "../../overrides";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import {
|
||||
CommandPhase,
|
||||
CommandPhase, DamagePhase,
|
||||
EncounterPhase,
|
||||
EnemyCommandPhase,
|
||||
LoginPhase,
|
||||
@ -15,7 +15,7 @@ import {
|
||||
SelectStarterPhase,
|
||||
SummonPhase,
|
||||
TitlePhase,
|
||||
TurnInitPhase,
|
||||
TurnInitPhase, VictoryPhase,
|
||||
} from "#app/phases";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
@ -106,9 +106,7 @@ 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.runFrom(EnemyCommandPhase).to(SelectModifierPhase);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.MODIFIER_SELECT);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(SelectModifierPhase.name);
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(SelectModifierPhase, false);
|
||||
}, 20000);
|
||||
|
||||
it("do attack wave 3 - single battle - regular - NO OHKO with opponent using non damage attack", async() => {
|
||||
@ -128,7 +126,7 @@ 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.runFrom(EnemyCommandPhase).to(TurnInitPhase);
|
||||
await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(TurnInitPhase, false);
|
||||
}, 20000);
|
||||
|
||||
it("load 100% data file", async() => {
|
||||
@ -259,5 +257,71 @@ describe("Test Battle Phase", () => {
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
|
||||
it("kill opponent pokemon", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
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([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
await game.startBattle([
|
||||
Species.DARMANITAN,
|
||||
Species.CHARIZARD,
|
||||
]);
|
||||
|
||||
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
game.scene.ui.setMode(Mode.FIGHT, (game.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
game.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
const movePosition = getMovePosition(game.scene, 0, moveToUse);
|
||||
(game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
|
||||
});
|
||||
await game.phaseInterceptor.to(DamagePhase, false);
|
||||
await game.killPokemon(game.scene.currentBattle.enemyParty[0]);
|
||||
expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true);
|
||||
await game.phaseInterceptor.to(VictoryPhase, false);
|
||||
}, 200000);
|
||||
|
||||
it("to next turn", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
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([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
await game.startBattle();
|
||||
const turn = game.scene.currentBattle.turn;
|
||||
await game.doAttack(0);
|
||||
await game.toNextTurn();
|
||||
expect(game.scene.currentBattle.turn).toBeGreaterThan(turn);
|
||||
}, 20000);
|
||||
|
||||
it("to next wave with pokemon killed, single", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
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([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
await game.startBattle();
|
||||
const waveIndex = game.scene.currentBattle.waveIndex;
|
||||
await game.doAttack(0);
|
||||
await game.doKillOpponents();
|
||||
await game.toNextWave();
|
||||
expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex);
|
||||
}, 20000);
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, it, vi} from "vitest";
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import * as overrides from "#app/overrides";
|
||||
@ -22,18 +22,24 @@ describe("Test Battle Phase", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
});
|
||||
|
||||
it("should start phase", async() => {
|
||||
const moveToUse = Moves.SPLASH;
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTER_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEWTWO);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.ZEN_MODE);
|
||||
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);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([moveToUse]);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE,Moves.TACKLE,Moves.TACKLE,Moves.TACKLE]);
|
||||
});
|
||||
|
||||
it.skip("to next turn", async() => {
|
||||
await game.startBattle();
|
||||
}, 100000);
|
||||
const turn = game.scene.currentBattle.turn;
|
||||
await game.doAttack(0);
|
||||
await game.toNextTurn();
|
||||
expect(game.scene.currentBattle.turn).toBeGreaterThan(turn);
|
||||
}, 20000);
|
||||
});
|
||||
|
||||
|
137
src/test/battle/special_battle.test.ts
Normal file
137
src/test/battle/special_battle.test.ts
Normal file
@ -0,0 +1,137 @@
|
||||
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
||||
import {Mode} from "#app/ui/ui";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import * as overrides from "../../overrides";
|
||||
import {
|
||||
CommandPhase,
|
||||
} from "#app/phases";
|
||||
import {Moves} from "#app/data/enums/moves";
|
||||
import GameManager from "#app/test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
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);
|
||||
vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.RATTATA);
|
||||
vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(2000);
|
||||
vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE]);
|
||||
vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.HYDRATION);
|
||||
vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE]);
|
||||
});
|
||||
|
||||
it("startBattle 2vs1 boss", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10);
|
||||
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("startBattle 2vs2 boss", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(10);
|
||||
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("startBattle 2vs2 trainer", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5);
|
||||
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("startBattle 2vs1 trainer", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5);
|
||||
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("startBattle 2vs1 rival", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(8);
|
||||
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("startBattle 2vs2 rival", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(8);
|
||||
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("startBattle 1vs1 trainer", async() => {
|
||||
vi.spyOn(overrides, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5);
|
||||
await game.startBattle([
|
||||
Species.BLASTOISE,
|
||||
]);
|
||||
expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND);
|
||||
expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name);
|
||||
}, 20000);
|
||||
|
||||
it("startBattle 2vs2 trainer", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5);
|
||||
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("startBattle 4vs2 trainer", async() => {
|
||||
vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true);
|
||||
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(5);
|
||||
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);
|
||||
});
|
||||
|
@ -11,6 +11,6 @@ export default class TextInterceptor {
|
||||
}
|
||||
|
||||
getLatestMessage(): string {
|
||||
return this.logs[this.logs.length - 1];
|
||||
return this.logs.pop();
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,20 @@ import {Mode} from "#app/ui/ui";
|
||||
import {generateStarter, waitUntil} from "#app/test/utils/gameManagerUtils";
|
||||
import {
|
||||
CommandPhase,
|
||||
DamagePhase,
|
||||
EncounterPhase,
|
||||
LoginPhase,
|
||||
PostSummonPhase,
|
||||
FaintPhase,
|
||||
LoginPhase, NewBattlePhase,
|
||||
SelectGenderPhase,
|
||||
SelectStarterPhase,
|
||||
TitlePhase,
|
||||
TitlePhase, TurnInitPhase,
|
||||
} 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 {GameModes, getGameMode} from "#app/game-mode";
|
||||
import fs from "fs";
|
||||
import { AES, enc } from "crypto-js";
|
||||
import {AES, enc} from "crypto-js";
|
||||
import {updateUserInfo} from "#app/account";
|
||||
import {Species} from "#app/data/enums/species";
|
||||
import {PlayerGender} from "#app/data/enums/player-gender";
|
||||
@ -23,6 +24,11 @@ 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";
|
||||
import {EnemyPokemon, PlayerPokemon} from "#app/field/pokemon";
|
||||
import {MockClock} from "#app/test/utils/mocks/mockClock";
|
||||
import {Command} from "#app/ui/command-ui-handler";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||
import {Button} from "#app/enums/buttons";
|
||||
|
||||
/**
|
||||
* Class to manage the game state and transitions between phases.
|
||||
@ -84,8 +90,8 @@ export default class GameManager {
|
||||
* @param callback - The callback to execute.
|
||||
* @param expireFn - Optional function to determine if the prompt has expired.
|
||||
*/
|
||||
onNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn?: () => void) {
|
||||
this.phaseInterceptor.addToNextPrompt(phaseTarget, mode, callback, expireFn);
|
||||
onNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn?: () => void, awaitingActionInput: boolean = false) {
|
||||
this.phaseInterceptor.addToNextPrompt(phaseTarget, mode, callback, expireFn, awaitingActionInput);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,17 +148,68 @@ export default class GameManager {
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(CommandPhase));
|
||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase));
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(CommandPhase));
|
||||
await this.phaseInterceptor.runFrom(PostSummonPhase).to(CommandPhase).catch((e) => reject(e));
|
||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase));
|
||||
await this.phaseInterceptor.to(CommandPhase).catch((e) => reject(e));
|
||||
console.log("==================[New Turn]==================");
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
|
||||
doAttack(moveIndex: integer): Promise<void> {
|
||||
this.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
|
||||
this.scene.ui.setMode(Mode.FIGHT, (this.scene.getCurrentPhase() as CommandPhase).getFieldIndex());
|
||||
});
|
||||
this.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
|
||||
(this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, moveIndex, false);
|
||||
});
|
||||
return this.phaseInterceptor.to(DamagePhase);
|
||||
}
|
||||
|
||||
doKillOpponents() {
|
||||
return new Promise<void>(async(resolve, reject) => {
|
||||
await this.killPokemon(this.scene.currentBattle.enemyParty[0]).catch((e) => reject(e));
|
||||
if (this.scene.currentBattle.double) {
|
||||
await this.killPokemon(this.scene.currentBattle.enemyParty[1]).catch((e) => reject(e));
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
|
||||
toNextTurn(): Promise<void> {
|
||||
return new Promise<void>(async(resolve, reject) => {
|
||||
await this.phaseInterceptor.to(CommandPhase).catch((e) => reject(e));
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
|
||||
toNextWave(): Promise<void> {
|
||||
return new Promise<void>(async(resolve, reject) => {
|
||||
this.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => {
|
||||
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
||||
handler.processInput(Button.CANCEL);
|
||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase), true);
|
||||
this.onNextPrompt("SelectModifierPhase", Mode.CONFIRM, () => {
|
||||
const handler = this.scene.ui.getHandler() as ModifierSelectUiHandler;
|
||||
handler.processInput(Button.ACTION);
|
||||
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(NewBattlePhase));
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(TurnInitPhase));
|
||||
this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => {
|
||||
this.setMode(Mode.MESSAGE);
|
||||
this.endPhase();
|
||||
}, () => this.isCurrentPhase(TurnInitPhase));
|
||||
await this.phaseInterceptor.to(CommandPhase).catch((e) => reject(e));
|
||||
|
||||
return resolve();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player has won the battle.
|
||||
* @returns True if the player has won, otherwise false.
|
||||
@ -213,4 +270,15 @@ export default class GameManager {
|
||||
}
|
||||
return updateUserInfo();
|
||||
}
|
||||
|
||||
async killPokemon(pokemon: PlayerPokemon | EnemyPokemon) {
|
||||
(this.scene.time as MockClock).overrideDelay = 0.01;
|
||||
return new Promise<void>(async(resolve, reject) => {
|
||||
pokemon.hp = 0;
|
||||
this.scene.pushPhase(new FaintPhase(this.scene, pokemon.getBattlerIndex(), true));
|
||||
await this.phaseInterceptor.to(FaintPhase).catch((e) => reject(e));
|
||||
(this.scene.time as MockClock).overrideDelay = undefined;
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ export default class GameWrapper {
|
||||
pause: () => null,
|
||||
setRate: () => null,
|
||||
add: () => this.scene.sound,
|
||||
get: () => this.scene.sound,
|
||||
get: () => ({...this.scene.sound, totalDuration: 0}),
|
||||
getAllPlaying: () => [],
|
||||
manager: {
|
||||
game: this.game,
|
||||
@ -131,6 +131,13 @@ export default class GameWrapper {
|
||||
key: "",
|
||||
};
|
||||
|
||||
this.scene.cameras = {
|
||||
main: {
|
||||
setPostPipeline: () => null,
|
||||
removePostPipeline: () => null,
|
||||
},
|
||||
}
|
||||
|
||||
this.scene.tweens = {
|
||||
add: (data) => {
|
||||
if (data.onComplete) {
|
||||
|
@ -2,8 +2,10 @@ import Clock = Phaser.Time.Clock;
|
||||
|
||||
|
||||
export class MockClock extends Clock {
|
||||
public overrideDelay: number;
|
||||
constructor(scene) {
|
||||
super(scene);
|
||||
this.overrideDelay = undefined;
|
||||
setInterval(() => {
|
||||
/*
|
||||
To simulate frame update
|
||||
@ -14,4 +16,9 @@ export class MockClock extends Clock {
|
||||
this.update(this.systems.game.loop.time, 100);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
addEvent(config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig): Phaser.Time.TimerEvent {
|
||||
const cfg = { ...config, delay: this.overrideDelay || config.delay};
|
||||
return super.addEvent(cfg);
|
||||
}
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ export default class MockSprite {
|
||||
|
||||
play() {
|
||||
// return this.phaserSprite.play();
|
||||
return this;
|
||||
}
|
||||
|
||||
setPipelineData(key, value) {
|
||||
|
@ -1,17 +1,43 @@
|
||||
import {
|
||||
BattleEndPhase,
|
||||
BerryPhase,
|
||||
CheckSwitchPhase, CommandPhase, DamagePhase, EggLapsePhase,
|
||||
EncounterPhase, EnemyCommandPhase, FaintPhase,
|
||||
LoginPhase, MessagePhase, MoveEffectPhase, MoveEndPhase, MovePhase, NewBattlePhase, NextEncounterPhase,
|
||||
CheckSwitchPhase,
|
||||
CommandPhase,
|
||||
DamagePhase,
|
||||
EggLapsePhase,
|
||||
EncounterPhase,
|
||||
EnemyCommandPhase,
|
||||
FaintPhase,
|
||||
LoginPhase,
|
||||
MessagePhase,
|
||||
MoveEffectPhase,
|
||||
MoveEndPhase,
|
||||
MovePhase,
|
||||
NewBattlePhase,
|
||||
NextEncounterPhase,
|
||||
PostSummonPhase,
|
||||
SelectGenderPhase, SelectModifierPhase,
|
||||
SelectStarterPhase, SelectTargetPhase, ShinySparklePhase, ShowAbilityPhase, StatChangePhase, SummonPhase,
|
||||
TitlePhase, ToggleDoublePositionPhase, TurnEndPhase, TurnInitPhase, TurnStartPhase, UnavailablePhase, VictoryPhase
|
||||
SelectGenderPhase,
|
||||
SelectModifierPhase,
|
||||
SelectStarterPhase,
|
||||
SelectTargetPhase,
|
||||
ShinySparklePhase,
|
||||
ShowAbilityPhase,
|
||||
StatChangePhase,
|
||||
SummonPhase,
|
||||
SwitchPhase,
|
||||
SwitchSummonPhase,
|
||||
TitlePhase,
|
||||
ToggleDoublePositionPhase,
|
||||
TurnEndPhase,
|
||||
TurnInitPhase,
|
||||
TurnStartPhase,
|
||||
UnavailablePhase,
|
||||
VictoryPhase
|
||||
} from "#app/phases";
|
||||
import UI, {Mode} from "#app/ui/ui";
|
||||
import {Phase} from "#app/phase";
|
||||
import ErrorInterceptor from "#app/test/utils/errorInterceptor";
|
||||
import {QuietFormChangePhase} from "#app/form-change-phase";
|
||||
|
||||
export default class PhaseInterceptor {
|
||||
public scene;
|
||||
@ -63,10 +89,13 @@ export default class PhaseInterceptor {
|
||||
[ShinySparklePhase, this.startPhase],
|
||||
[SelectTargetPhase, this.startPhase],
|
||||
[UnavailablePhase, this.startPhase],
|
||||
[QuietFormChangePhase, this.startPhase],
|
||||
[SwitchPhase, this.startPhase],
|
||||
[SwitchSummonPhase, this.startPhase],
|
||||
];
|
||||
|
||||
private endBySetMode = [
|
||||
TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase
|
||||
TitlePhase, SelectGenderPhase, CommandPhase
|
||||
];
|
||||
|
||||
/**
|
||||
@ -78,8 +107,8 @@ export default class PhaseInterceptor {
|
||||
this.log = [];
|
||||
this.onHold = [];
|
||||
this.prompts = [];
|
||||
this.startPromptHandler();
|
||||
this.initPhases();
|
||||
this.startPromptHander();
|
||||
}
|
||||
|
||||
rejectAll(error) {
|
||||
@ -109,8 +138,10 @@ export default class PhaseInterceptor {
|
||||
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;
|
||||
if (this.phaseFrom) {
|
||||
await this.run(this.phaseFrom).catch((e) => reject(e));
|
||||
this.phaseFrom = null;
|
||||
}
|
||||
const targetName = typeof phaseTo === "string" ? phaseTo : phaseTo.name;
|
||||
this.intervalRun = setInterval(async() => {
|
||||
const currentPhase = this.onHold?.length && this.onHold[0];
|
||||
@ -238,7 +269,6 @@ export default class PhaseInterceptor {
|
||||
*/
|
||||
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;
|
||||
@ -253,6 +283,9 @@ export default class PhaseInterceptor {
|
||||
const instance = this.scene.ui;
|
||||
console.log("setMode", mode, args);
|
||||
const ret = this.originalSetMode.apply(instance, [mode, ...args]);
|
||||
if (!this.phases[currentPhase.constructor.name]) {
|
||||
throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptior PHASES list`);
|
||||
}
|
||||
if (this.phases[currentPhase.constructor.name].endBySetMode) {
|
||||
this.inProgress?.callback();
|
||||
this.inProgress = undefined;
|
||||
@ -263,16 +296,17 @@ export default class PhaseInterceptor {
|
||||
/**
|
||||
* Method to start the prompt handler.
|
||||
*/
|
||||
startPromptHander() {
|
||||
startPromptHandler() {
|
||||
this.promptInterval = setInterval(() => {
|
||||
if (this.prompts.length) {
|
||||
const actionForNextPrompt = this.prompts[0];
|
||||
const expireFn = actionForNextPrompt.expireFn && actionForNextPrompt.expireFn();
|
||||
const currentMode = this.scene.ui.getMode();
|
||||
const currentPhase = this.scene.getCurrentPhase().constructor.name;
|
||||
const currentHandler = this.scene.ui.getHandler();
|
||||
if (expireFn) {
|
||||
this.prompts.shift();
|
||||
} else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget) {
|
||||
} else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget && currentHandler.active && (!actionForNextPrompt.awaitingActionInput || (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))) {
|
||||
this.prompts.shift().callback();
|
||||
}
|
||||
}
|
||||
@ -286,12 +320,13 @@ export default class PhaseInterceptor {
|
||||
* @param callback - The callback function to execute.
|
||||
* @param expireFn - The function to determine if the prompt has expired.
|
||||
*/
|
||||
addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn: () => void) {
|
||||
addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn: () => void, awaitingActionInput: boolean = false) {
|
||||
this.prompts.push({
|
||||
phaseTarget,
|
||||
mode,
|
||||
callback,
|
||||
expireFn
|
||||
expireFn,
|
||||
awaitingActionInput
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user