mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-19 22:09:27 +02:00
Added tests for failing catches
This commit is contained in:
parent
b32bb090d4
commit
6c22ab9483
@ -82,6 +82,14 @@ export class GameMode implements GameModeConfig {
|
|||||||
return this.challenges.some(c => c.id === challenge && c.value !== 0);
|
return this.challenges.some(c => c.id === challenge && c.value !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to see if a GameMode has any challenges, needed in tests
|
||||||
|
* @returns true if the game mode has at least one challenge
|
||||||
|
*/
|
||||||
|
hasAnyChallenges(): boolean {
|
||||||
|
return this.challenges.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to see if the game mode is using fresh start
|
* Helper function to see if the game mode is using fresh start
|
||||||
* @returns true if a fresh start challenge is being applied
|
* @returns true if a fresh start challenge is being applied
|
||||||
|
@ -390,12 +390,12 @@ export class CommandPhase extends FieldPhase {
|
|||||||
const isClassicFinalBoss = globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex);
|
const isClassicFinalBoss = globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex);
|
||||||
const isEndlessMinorBoss = globalScene.gameMode.isEndlessMinorBoss(globalScene.currentBattle.waveIndex);
|
const isEndlessMinorBoss = globalScene.gameMode.isEndlessMinorBoss(globalScene.currentBattle.waveIndex);
|
||||||
const isFullFreshStart = globalScene.gameMode.isFullFreshStartChallenge();
|
const isFullFreshStart = globalScene.gameMode.isFullFreshStartChallenge();
|
||||||
|
|
||||||
const someUncaughtSpeciesOnField = globalScene
|
const someUncaughtSpeciesOnField = globalScene
|
||||||
.getEnemyField()
|
.getEnemyField()
|
||||||
.some(p => p.isActive() && !dexData[p.species.speciesId].caughtAttr);
|
.some(p => p.isActive() && !dexData[p.species.speciesId].caughtAttr);
|
||||||
const missingMultipleStarters =
|
const missingMultipleStarters =
|
||||||
gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarterCosts).length - 1;
|
gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarterCosts).length - 1;
|
||||||
|
|
||||||
if (biomeType === BiomeId.END) {
|
if (biomeType === BiomeId.END) {
|
||||||
if (
|
if (
|
||||||
(isClassic && !isClassicFinalBoss && someUncaughtSpeciesOnField) ||
|
(isClassic && !isClassicFinalBoss && someUncaughtSpeciesOnField) ||
|
||||||
@ -410,7 +410,7 @@ export class CommandPhase extends FieldPhase {
|
|||||||
(isEndless && isEndlessMinorBoss) ||
|
(isEndless && isEndlessMinorBoss) ||
|
||||||
isDaily
|
isDaily
|
||||||
) {
|
) {
|
||||||
// Uncatchable final boss in classic and endless
|
// Uncatchable final boss in classic, endless and daily
|
||||||
this.queueShowText("battle:noPokeballForceFinalBoss");
|
this.queueShowText("battle:noPokeballForceFinalBoss");
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@ -446,10 +446,8 @@ export class CommandPhase extends FieldPhase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restricts use of Master Ball against final boss in challenges
|
const isChallengeActive = globalScene.gameMode.hasAnyChallenges();
|
||||||
const restrictMasterBall =
|
const isFinalBoss = globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex);
|
||||||
globalScene.gameMode.isChallenge &&
|
|
||||||
globalScene.gameMode.isBattleClassicFinalBoss(globalScene.currentBattle.waveIndex);
|
|
||||||
|
|
||||||
const numBallTypes = 5;
|
const numBallTypes = 5;
|
||||||
if (cursor < numBallTypes) {
|
if (cursor < numBallTypes) {
|
||||||
@ -460,10 +458,16 @@ export class CommandPhase extends FieldPhase {
|
|||||||
// TODO: Decouple this hardcoded exception for wonder guard and just check the target...
|
// TODO: Decouple this hardcoded exception for wonder guard and just check the target...
|
||||||
!targetPokemon?.hasAbility(AbilityId.WONDER_GUARD, false, true)
|
!targetPokemon?.hasAbility(AbilityId.WONDER_GUARD, false, true)
|
||||||
) {
|
) {
|
||||||
if (restrictMasterBall) {
|
// When facing the final boss, it must be weakened unless a Master Ball is used AND no challenges are active.
|
||||||
|
// The message is customized for the final boss.
|
||||||
|
if (
|
||||||
|
isFinalBoss &&
|
||||||
|
(cursor < PokeballType.MASTER_BALL || (cursor === PokeballType.MASTER_BALL && isChallengeActive))
|
||||||
|
) {
|
||||||
this.queueShowText("battle:noPokeballForceFinalBossCatchable");
|
this.queueShowText("battle:noPokeballForceFinalBossCatchable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// When facing any other boss, Master Ball can always be used, and we use the standard message.
|
||||||
if (cursor < PokeballType.MASTER_BALL) {
|
if (cursor < PokeballType.MASTER_BALL) {
|
||||||
this.queueShowText("battle:noPokeballStrong");
|
this.queueShowText("battle:noPokeballStrong");
|
||||||
return false;
|
return false;
|
||||||
|
244
test/field/catching.test.ts
Normal file
244
test/field/catching.test.ts
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
import { pokerogueApi } from "#api/pokerogue-api";
|
||||||
|
import { BiomeId } from "#enums/biome-id";
|
||||||
|
import { Challenges } from "#enums/challenges";
|
||||||
|
import { GameModes } from "#enums/game-modes";
|
||||||
|
import { MoveId } from "#enums/move-id";
|
||||||
|
import { PokeballType } from "#enums/pokeball";
|
||||||
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import { GameManager } from "#test/test-utils/game-manager";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to run tests on cactching mons
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* - Starts a run on the desired game mode, then attempts to throw a ball
|
||||||
|
* - If still in the command phase (meaning the ball did not catch) uses a move to proceed
|
||||||
|
* - If expecting success, checks that party length has increased by 1
|
||||||
|
* - Otherwise, checks that {@link i18next} has been called on the requested error key
|
||||||
|
*
|
||||||
|
* @param game {@link GameManager} The game manager from the test
|
||||||
|
* @param ball {@link PokeballType} The type of pokéball to be used for the catch attempt
|
||||||
|
* @param expectedResult {@link string} Either "success", if the enemy should be caught, or the expected locales error key
|
||||||
|
* @param mode One between "classic", "daily", and "challenge", defaults to "classic".
|
||||||
|
*/
|
||||||
|
async function runPokeballTest(
|
||||||
|
game: GameManager,
|
||||||
|
ball: PokeballType,
|
||||||
|
expectedResult: string,
|
||||||
|
mode: "classic" | "daily" | "challenge" = "classic",
|
||||||
|
) {
|
||||||
|
if (mode === "classic") {
|
||||||
|
await game.classicMode.startBattle([SpeciesId.MAGIKARP]);
|
||||||
|
} else if (mode === "daily") {
|
||||||
|
// Have to do it this way because daily run is weird...
|
||||||
|
await game.runToFinalBossEncounter([SpeciesId.MAGIKARP], GameModes.DAILY);
|
||||||
|
} else if (mode === "challenge") {
|
||||||
|
await game.challengeMode.startBattle([SpeciesId.MAGIKARP]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const partyLength = game.scene.getPlayerParty().length;
|
||||||
|
|
||||||
|
game.scene.pokeballCounts[ball] = 1;
|
||||||
|
|
||||||
|
const tSpy = vi.spyOn(i18next, "t").mockImplementation((key: string) => key);
|
||||||
|
|
||||||
|
game.doThrowPokeball(ball);
|
||||||
|
|
||||||
|
// If still in the command phase due to ball failing, use a move to go on
|
||||||
|
if (game.isCurrentPhase("CommandPhase")) {
|
||||||
|
game.move.select(MoveId.SPLASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.toEndOfTurn();
|
||||||
|
if (expectedResult === "success") {
|
||||||
|
// Check that a mon has been caught by noticing that party length has increased
|
||||||
|
expect(game.scene.getPlayerParty()).toHaveLength(partyLength + 1);
|
||||||
|
} else {
|
||||||
|
expect(tSpy).toHaveBeenCalledWith(expectedResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Throwing balls in classic", () => {
|
||||||
|
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
|
||||||
|
.startingWave(199)
|
||||||
|
.startingBiome(BiomeId.END)
|
||||||
|
.battleStyle("single")
|
||||||
|
.moveset([MoveId.SPLASH])
|
||||||
|
.enemyMoveset([MoveId.SPLASH])
|
||||||
|
.startingLevel(9999);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at paradox mon", async () => {
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForce");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at two paradox mons", async () => {
|
||||||
|
game.override.battleStyle("double");
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballMulti");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at previously caught paradox mon", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "success");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at final boss", async () => {
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForceFinalBoss");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing rogue ball at final boss with full dex", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.ROGUE_BALL, "battle:noPokeballForceFinalBossCatchable");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing master ball at final boss with full dex", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "success");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Throwing balls in fresh start challenge", () => {
|
||||||
|
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.challengeMode.addChallenge(Challenges.FRESH_START, 2, 1);
|
||||||
|
game.override
|
||||||
|
.startingWave(199)
|
||||||
|
.startingBiome(BiomeId.END)
|
||||||
|
.battleStyle("single")
|
||||||
|
.moveset([MoveId.SPLASH])
|
||||||
|
.enemyMoveset([MoveId.SPLASH])
|
||||||
|
.startingLevel(9999);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tests should give the same result as a normal classic run, except for the last one
|
||||||
|
it("throwing ball at paradox mon", async () => {
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForce", "challenge");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at previously caught paradox mon", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "success", "challenge");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at final boss", async () => {
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForceFinalBoss", "challenge");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing rogue ball at final boss with full dex", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.ROGUE_BALL, "battle:noPokeballForceFinalBossCatchable", "challenge");
|
||||||
|
});
|
||||||
|
|
||||||
|
// If a challenge is active, even if the dex is complete we still need to weaken the final boss to master ball it
|
||||||
|
it("throwing ball at final boss with full dex", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForceFinalBossCatchable", "challenge");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Throwing balls in full fresh start challenge", () => {
|
||||||
|
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.challengeMode.addChallenge(Challenges.FRESH_START, 1, 1);
|
||||||
|
game.override
|
||||||
|
.startingWave(199)
|
||||||
|
.startingBiome(BiomeId.END)
|
||||||
|
.battleStyle("single")
|
||||||
|
.moveset([MoveId.SPLASH])
|
||||||
|
.enemyMoveset([MoveId.SPLASH])
|
||||||
|
.startingLevel(9999);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Paradox and final boss can NEVER be caught in the full fresh start challenge
|
||||||
|
it("throwing ball at previously caught paradox mon", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForce", "challenge");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at final boss with full dex", async () => {
|
||||||
|
await game.importData("./test/test-utils/saves/everything.prsv");
|
||||||
|
game.override.startingWave(200);
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForceFinalBoss", "challenge");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Throwing balls in daily run", () => {
|
||||||
|
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(pokerogueApi.daily, "getSeed").mockResolvedValue("test-seed");
|
||||||
|
game.override
|
||||||
|
.startingWave(50)
|
||||||
|
.startingBiome(BiomeId.END)
|
||||||
|
.battleStyle("single")
|
||||||
|
.moveset([MoveId.SPLASH])
|
||||||
|
.enemyMoveset([MoveId.SPLASH])
|
||||||
|
.startingLevel(9999);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throwing ball at daily run boss", async () => {
|
||||||
|
await runPokeballTest(game, PokeballType.MASTER_BALL, "battle:noPokeballForceFinalBoss", "daily");
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user