[P1][Beta] Fix softlock when losing a run on local build (#4846)

This commit is contained in:
PigeonBar 2024-11-11 18:22:27 -05:00 committed by GitHub
parent cebedd220b
commit 4802f512ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 103 additions and 5 deletions

View File

@ -125,10 +125,9 @@ export class GameOverPhase extends BattlePhase {
} }
const clear = (endCardPhase?: EndCardPhase) => { const clear = (endCardPhase?: EndCardPhase) => {
if (newClear) {
this.handleUnlocks();
}
if (this.isVictory && newClear) { if (this.isVictory && newClear) {
this.handleUnlocks();
for (const species of this.firstRibbons) { for (const species of this.firstRibbons) {
this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species)); this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species));
} }
@ -183,6 +182,8 @@ export class GameOverPhase extends BattlePhase {
this.scene.gameData.offlineNewClear(this.scene).then(result => { this.scene.gameData.offlineNewClear(this.scene).then(result => {
doGameOver(result); doGameOver(result);
}); });
} else {
doGameOver(false);
} }
} }

View File

@ -0,0 +1,77 @@
import { Biome } from "#enums/biome";
import { Abilities } from "#enums/abilities";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { achvs } from "#app/system/achv";
import { Unlockables } from "#app/system/unlockables";
describe("Game Over 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);
game.override
.moveset([ Moves.MEMENTO, Moves.ICE_BEAM, Moves.SPLASH ])
.ability(Abilities.BALL_FETCH)
.battleType("single")
.disableCrits()
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(Moves.SPLASH)
.startingWave(200)
.startingBiome(Biome.END)
.startingLevel(10000);
});
it("winning a run should give rewards", async () => {
await game.classicMode.startBattle([ Species.BULBASAUR ]);
vi.spyOn(game.scene, "validateAchv");
// Note: `game.doKillOpponents()` does not properly handle final boss
// Final boss phase 1
game.move.select(Moves.ICE_BEAM);
await game.toNextTurn();
// Final boss phase 2
game.move.select(Moves.ICE_BEAM);
await game.phaseInterceptor.to("PostGameOverPhase", false);
// The game refused to actually give the vouchers during tests,
// so the best we can do is to check that their reward phases occurred.
expect(game.phaseInterceptor.log.includes("GameOverPhase")).toBe(true);
expect(game.phaseInterceptor.log.includes("UnlockPhase")).toBe(true);
expect(game.phaseInterceptor.log.includes("RibbonModifierRewardPhase")).toBe(true);
expect(game.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]).toBe(true);
expect(game.scene.validateAchv).toHaveBeenCalledWith(achvs.CLASSIC_VICTORY);
expect(game.scene.gameData.achvUnlocks[achvs.CLASSIC_VICTORY.id]).toBeTruthy();
});
it("losing a run should not give rewards", async () => {
await game.classicMode.startBattle([ Species.BULBASAUR ]);
vi.spyOn(game.scene, "validateAchv");
game.move.select(Moves.MEMENTO);
await game.phaseInterceptor.to("PostGameOverPhase", false);
expect(game.phaseInterceptor.log.includes("GameOverPhase")).toBe(true);
expect(game.phaseInterceptor.log.includes("UnlockPhase")).toBe(false);
expect(game.phaseInterceptor.log.includes("RibbonModifierRewardPhase")).toBe(false);
expect(game.phaseInterceptor.log.includes("GameOverModifierRewardPhase")).toBe(false);
expect(game.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]).toBe(false);
expect(game.scene.validateAchv).not.toHaveBeenCalledWith(achvs.CLASSIC_VICTORY);
expect(game.scene.gameData.achvUnlocks[achvs.CLASSIC_VICTORY.id]).toBeFalsy();
});
});

View File

@ -55,6 +55,11 @@ import {
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { PartyExpPhase } from "#app/phases/party-exp-phase"; import { PartyExpPhase } from "#app/phases/party-exp-phase";
import { ExpPhase } from "#app/phases/exp-phase"; import { ExpPhase } from "#app/phases/exp-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
import { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
import { UnlockPhase } from "#app/phases/unlock-phase";
import { PostGameOverPhase } from "#app/phases/post-game-over-phase";
export interface PromptHandler { export interface PromptHandler {
phaseTarget?: string; phaseTarget?: string;
@ -113,10 +118,15 @@ type PhaseClass =
| typeof MysteryEncounterBattlePhase | typeof MysteryEncounterBattlePhase
| typeof MysteryEncounterRewardsPhase | typeof MysteryEncounterRewardsPhase
| typeof PostMysteryEncounterPhase | typeof PostMysteryEncounterPhase
| typeof RibbonModifierRewardPhase
| typeof GameOverModifierRewardPhase
| typeof ModifierRewardPhase | typeof ModifierRewardPhase
| typeof PartyExpPhase | typeof PartyExpPhase
| typeof ExpPhase | typeof ExpPhase
| typeof EncounterPhase; | typeof EncounterPhase
| typeof GameOverPhase
| typeof UnlockPhase
| typeof PostGameOverPhase;
type PhaseString = type PhaseString =
| "LoginPhase" | "LoginPhase"
@ -167,10 +177,15 @@ type PhaseString =
| "MysteryEncounterBattlePhase" | "MysteryEncounterBattlePhase"
| "MysteryEncounterRewardsPhase" | "MysteryEncounterRewardsPhase"
| "PostMysteryEncounterPhase" | "PostMysteryEncounterPhase"
| "RibbonModifierRewardPhase"
| "GameOverModifierRewardPhase"
| "ModifierRewardPhase" | "ModifierRewardPhase"
| "PartyExpPhase" | "PartyExpPhase"
| "ExpPhase" | "ExpPhase"
| "EncounterPhase"; | "EncounterPhase"
| "GameOverPhase"
| "UnlockPhase"
| "PostGameOverPhase";
type PhaseInterceptorPhase = PhaseClass | PhaseString; type PhaseInterceptorPhase = PhaseClass | PhaseString;
@ -245,10 +260,15 @@ export default class PhaseInterceptor {
[ MysteryEncounterBattlePhase, this.startPhase ], [ MysteryEncounterBattlePhase, this.startPhase ],
[ MysteryEncounterRewardsPhase, this.startPhase ], [ MysteryEncounterRewardsPhase, this.startPhase ],
[ PostMysteryEncounterPhase, this.startPhase ], [ PostMysteryEncounterPhase, this.startPhase ],
[ RibbonModifierRewardPhase, this.startPhase ],
[ GameOverModifierRewardPhase, this.startPhase ],
[ ModifierRewardPhase, this.startPhase ], [ ModifierRewardPhase, this.startPhase ],
[ PartyExpPhase, this.startPhase ], [ PartyExpPhase, this.startPhase ],
[ ExpPhase, this.startPhase ], [ ExpPhase, this.startPhase ],
[ EncounterPhase, this.startPhase ], [ EncounterPhase, this.startPhase ],
[ GameOverPhase, this.startPhase ],
[ UnlockPhase, this.startPhase ],
[ PostGameOverPhase, this.startPhase ],
]; ];
private endBySetMode = [ private endBySetMode = [