clean up unit tests and utils

This commit is contained in:
ImperialSympathizer 2024-07-18 11:04:52 -04:00
parent c928445f5e
commit 2697a738ba
16 changed files with 166 additions and 145 deletions

View File

@ -145,7 +145,7 @@ export const FieryFalloutEncounter: IMysteryEncounter =
.withOption(
new MysteryEncounterOptionBuilder()
.withOptionMode(EncounterOptionMode.DISABLED_OR_SPECIAL)
.withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, 2)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withPrimaryPokemonRequirement(new TypeRequirement(Type.FIRE, true,2)) // Will set option2PrimaryName and option2PrimaryMove dialogue tokens automatically
.withDialogue({
buttonLabel: `${namespace}_option_3_label`,
buttonTooltip: `${namespace}_option_3_tooltip`,

View File

@ -57,7 +57,7 @@ export const SafariZoneEncounter: IMysteryEncounter =
.withOptionPhase(async (scene: BattleScene) => {
// Start safari encounter
const encounter = scene.currentBattle.mysteryEncounter;
encounter.encounterVariant = MysteryEncounterVariant.SAFARI_BATTLE;
encounter.encounterVariant = MysteryEncounterVariant.REPEATED_ENCOUNTER;
encounter.misc = {
safariPokemonRemaining: 3
};
@ -463,14 +463,15 @@ function tryChangeCatchStage(scene: BattleScene, change: number, chance?: number
return true;
}
async function doEndTurn(scene: BattleScene, cursorIndex: number, message?: string) {
const pokemon = scene.currentBattle.mysteryEncounter.misc.pokemon;
const isFlee = isPokemonFlee(pokemon, scene.currentBattle.mysteryEncounter.misc.fleeStage);
async function doEndTurn(scene: BattleScene, cursorIndex: number) {
const encounter = scene.currentBattle.mysteryEncounter;
const pokemon = encounter.misc.pokemon;
const isFlee = isPokemonFlee(pokemon, encounter.misc.fleeStage);
if (isFlee) {
// Pokemon flees!
await doPokemonFlee(scene, pokemon);
// Check how many safari pokemon left
if (scene.currentBattle.mysteryEncounter.misc.safariPokemonRemaining > 0) {
if (encounter.misc.safariPokemonRemaining > 0) {
await summonSafariPokemon(scene);
initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true });
} else {

View File

@ -27,7 +27,7 @@ export enum MysteryEncounterVariant {
WILD_BATTLE,
BOSS_BATTLE,
NO_BATTLE,
SAFARI_BATTLE
REPEATED_ENCOUNTER
}
export enum MysteryEncounterTier {
@ -38,7 +38,7 @@ export enum MysteryEncounterTier {
MASTER // Not currently used
}
export class StartOfBattleEffect {
export interface StartOfBattleEffect {
sourcePokemon?: Pokemon;
sourceBattlerIndex?: BattlerIndex;
targets: BattlerIndex[];
@ -108,10 +108,6 @@ export default interface IMysteryEncounter {
* You should never need to modify this
*/
seedOffset?: any;
/**
* Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases
*/
startOfBattleEffectsComplete?: boolean;
/**
* Flags
@ -134,6 +130,10 @@ export default interface IMysteryEncounter {
* Will be set to false after a shop is shown (so can't reroll same rarity items for free)
*/
lockEncounterRewardTiers?: boolean;
/**
* Will be set automatically, indicates special moves in startOfBattleEffects are complete (so will not repeat)
*/
startOfBattleEffectsComplete?: boolean;
/**
* Will be set by option select handlers automatically, and can be used to refer to which option was chosen by later phases
*/
@ -473,6 +473,8 @@ export class MysteryEncounterBuilder implements Partial<IMysteryEncounter> {
/**
* Defines any EncounterAnim animations that are intended to be used during the encounter
* EncounterAnims can be played at any point during an encounter or callback
* They just need to be specified here so that resources are loaded on encounter init
* @param encounterAnimations
* @returns
*/

View File

@ -555,8 +555,10 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase:
return;
}
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.SAFARI_BATTLE) {
scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));
// If in repeated encounter variant, do nothing
// Variant must eventually be swapped in order to handle "true" end of the encounter
if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.REPEATED_ENCOUNTER) {
return;
} else if (scene.currentBattle.mysteryEncounter.encounterVariant === MysteryEncounterVariant.NO_BATTLE) {
scene.pushPhase(new EggLapsePhase(scene));
scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase));

View File

@ -117,9 +117,9 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
*/
// 1 to 256, set to null to ignore
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null;
export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.FIERY_FALLOUT;
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null;
/**
* MODIFIER / ITEM OVERRIDES

View File

@ -1,17 +1,19 @@
import { Button } from "#app/enums/buttons";
import { MessagePhase } from "#app/phases";
import { MessagePhase, VictoryPhase } from "#app/phases";
import { MysteryEncounterPhase, MysteryEncounterRewardsPhase } from "#app/phases/mystery-encounter-phase";
import MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler";
import { Mode } from "#app/ui/ui";
import GameManager from "../utils/gameManager";
import MessageUiHandler from "#app/ui/message-ui-handler";
export async function runSelectMysteryEncounterOption(game: GameManager, optionNo: number) {
if (game.isCurrentPhase(MessagePhase)) {
// Handle eventual weather messages (e.g. a downpour started!)
// Handle any eventual queued messages (e.g. weather phase, etc.)
game.onNextPrompt("MessagePhase", Mode.MESSAGE, () => {
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
uiHandler.processInput(Button.ACTION);
});
if (game.isCurrentPhase(MessagePhase)) {
await game.phaseInterceptor.run(MessagePhase);
}
@ -20,8 +22,10 @@ export async function runSelectMysteryEncounterOption(game: GameManager, optionN
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
uiHandler.processInput(Button.ACTION);
});
await game.phaseInterceptor.run(MysteryEncounterPhase);
// select the desired option
game.onNextPrompt("MysteryEncounterPhase", Mode.MYSTERY_ENCOUNTER, () => {
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
uiHandler.unblockInput(); // input are blocked by 1s to prevent accidental input. Tests need to handle that
@ -42,13 +46,32 @@ export async function runSelectMysteryEncounterOption(game: GameManager, optionN
}
uiHandler.processInput(Button.ACTION);
});
await game.phaseInterceptor.run(MysteryEncounterPhase);
// run the selected options phase
game.onNextPrompt("MysteryEncounterOptionSelectedPhase", Mode.MESSAGE, () => {
const uiHandler = game.scene.ui.getHandler<MysteryEncounterUiHandler>();
uiHandler.processInput(Button.ACTION);
});
// If a battle is started, fast forward to end of the battle
game.onNextPrompt("CommandPhase", Mode.COMMAND, () => {
game.scene.clearPhaseQueue();
game.scene.clearPhaseQueueSplice();
game.scene.unshiftPhase(new VictoryPhase(game.scene, 0));
game.endPhase();
});
// Handle end of battle trainer messages
game.onNextPrompt("TrainerVictoryPhase", Mode.MESSAGE, () => {
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
uiHandler.processInput(Button.ACTION);
});
// Handle egg hatch dialogue
game.onNextPrompt("EggLapsePhase", Mode.MESSAGE, () => {
const uiHandler = game.scene.ui.getHandler<MessageUiHandler>();
uiHandler.processInput(Button.ACTION);
});
await game.phaseInterceptor.to(MysteryEncounterRewardsPhase);
}

View File

@ -9,7 +9,6 @@ import { Moves } from "#app/enums/moves";
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
import { Species } from "#app/enums/species";
import GameManager from "#app/test/utils/gameManager";
import { workaround_reInitSceneWithOverrides } from "#app/test/utils/testUtils";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { runSelectMysteryEncounterOption } from "../encounterTestUtils";
@ -30,8 +29,9 @@ describe("Lost at Sea - Mystery Encounter", () => {
beforeEach(async () => {
game = new GameManager(phaserGame);
game.override.mysteryEncounterChance(100);
game.override.startingBiome(defaultBiome);
game.override.startingWave(defaultWave);
game.override.startingBiome(defaultBiome);
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(
new Map<Biome, MysteryEncounterType[]>([
[Biome.SEA, [MysteryEncounterType.LOST_AT_SEA]],
@ -45,7 +45,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
});
it("should have the correct properties", async () => {
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
expect(LostAtSeaEncounter.encounterType).toBe(MysteryEncounterType.LOST_AT_SEA);
@ -59,7 +58,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
it("should not spawn outside of sea biome", async () => {
game.override.startingBiome(Biome.MOUNTAIN);
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter();
expect(game.scene.currentBattle.mysteryEncounter.encounterType).not.toBe(MysteryEncounterType.LOST_AT_SEA);
@ -117,7 +115,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
it("should award exp to surfable PKM (Blastoise)", async () => {
const laprasSpecies = getPokemonSpecies(Species.LAPRAS);
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
const party = game.scene.getParty();
const blastoise = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT);
@ -126,13 +123,12 @@ describe("Lost at Sea - Mystery Encounter", () => {
await runSelectMysteryEncounterOption(game, 2);
expect(blastoise.exp).toBe(expBefore + laprasSpecies.baseExp * defaultWave);
});
}, 10000000);
it("should leave encounter without battle", async () => {
game.override.startingWave(33);
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
await runSelectMysteryEncounterOption(game, 1);
@ -168,7 +164,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
const wave = 33;
game.override.startingWave(wave);
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
const party = game.scene.getParty();
const pidgeot = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT);
@ -183,7 +178,7 @@ describe("Lost at Sea - Mystery Encounter", () => {
game.override.startingWave(33);
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
await workaround_reInitSceneWithOverrides(game);
// await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
await runSelectMysteryEncounterOption(game, 2);
@ -215,7 +210,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
it("should damage all (allowed in battle) party PKM by 25%", async () => {
game.override.startingWave(33);
await workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
const party = game.scene.getParty();
@ -237,7 +231,6 @@ describe("Lost at Sea - Mystery Encounter", () => {
game.override.startingWave(33);
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
workaround_reInitSceneWithOverrides(game);
await game.runToMysteryEncounter(defaultParty);
await runSelectMysteryEncounterOption(game, 3);

View File

@ -36,16 +36,12 @@ describe("Mystery Encounter Utils", () => {
describe("getRandomPlayerPokemon", () => {
it("gets a random pokemon from player party", () => {
// Seeds are calculated to return index 0 first, 1 second (if both pokemon are legal)
scene.waveSeed = "random";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random");
let result = getRandomPlayerPokemon(scene);
expect(result.species.speciesId).toBe(Species.MANAPHY);
scene.waveSeed = "random2";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random2");
result = getRandomPlayerPokemon(scene);
expect(result.species.speciesId).toBe(Species.ARCEUS);
@ -60,16 +56,12 @@ describe("Mystery Encounter Utils", () => {
});
// Seeds are calculated to return index 0 first, 1 second (if both pokemon are legal)
scene.waveSeed = "random";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random");
let result = getRandomPlayerPokemon(scene);
expect(result.species.speciesId).toBe(Species.MANAPHY);
scene.waveSeed = "random2";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random2");
result = getRandomPlayerPokemon(scene);
expect(result.species.speciesId).toBe(Species.ARCEUS);
@ -83,16 +75,12 @@ describe("Mystery Encounter Utils", () => {
party[0].updateInfo();
// Seeds are calculated to return index 0 first, 1 second (if both pokemon are legal)
scene.waveSeed = "random";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random");
let result = getRandomPlayerPokemon(scene, true);
expect(result.species.speciesId).toBe(Species.MANAPHY);
scene.waveSeed = "random2";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random2");
result = getRandomPlayerPokemon(scene, true);
expect(result.species.speciesId).toBe(Species.MANAPHY);
@ -106,16 +94,12 @@ describe("Mystery Encounter Utils", () => {
party[0].updateInfo();
// Seeds are calculated to return index 0 first, 1 second (if both pokemon are legal)
scene.waveSeed = "random";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random");
let result = getRandomPlayerPokemon(scene, true, false);
expect(result.species.speciesId).toBe(Species.MANAPHY);
scene.waveSeed = "random2";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random2");
result = getRandomPlayerPokemon(scene, true, false);
expect(result.species.speciesId).toBe(Species.MANAPHY);
@ -129,16 +113,12 @@ describe("Mystery Encounter Utils", () => {
party[0].updateInfo();
// Seeds are calculated to return index 0 first, 1 second (if both pokemon are legal)
scene.waveSeed = "random";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random");
let result = getRandomPlayerPokemon(scene, true, true);
expect(result.species.speciesId).toBe(Species.ARCEUS);
scene.waveSeed = "random2";
Phaser.Math.RND.sow([scene.waveSeed]);
scene.rngCounter = 0;
game.override.seed("random2");
result = getRandomPlayerPokemon(scene, true, true);
expect(result.species.speciesId).toBe(Species.ARCEUS);

View File

@ -1,5 +1,4 @@
import { afterEach, beforeAll, beforeEach, expect, describe, it, vi } from "vitest";
import * as overrides from "../../overrides";
import { afterEach, beforeAll, beforeEach, expect, describe, it } from "vitest";
import GameManager from "#app/test/utils/gameManager";
import Phaser from "phaser";
import { Species } from "#enums/species";
@ -22,16 +21,9 @@ describe("Mystery Encounters", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(256);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(11);
vi.spyOn(overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
// Seed guarantees wild encounter to be replaced by ME
vi.spyOn(game.scene, "resetSeed").mockImplementation(() => {
game.scene.waveSeed = "test";
Phaser.Math.RND.sow([game.scene.waveSeed]);
game.scene.rngCounter = 0;
});
game.override.startingWave(11);
game.override.mysteryEncounterChance(100);
game.override.mysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
});
it("Spawns a mystery encounter", async () => {

View File

@ -1,14 +1,14 @@
import {afterEach, beforeAll, beforeEach, expect, describe, it, vi} from "vitest";
import * as overrides from "../../overrides";
import {afterEach, beforeAll, beforeEach, expect, describe, it, vi } from "vitest";
import GameManager from "#app/test/utils/gameManager";
import Phaser from "phaser";
import {Species} from "#enums/species";
import {MysteryEncounterOptionSelectedPhase, MysteryEncounterPhase} from "#app/phases/mystery-encounter-phase";
import { MysteryEncounterOptionSelectedPhase, MysteryEncounterPhase } from "#app/phases/mystery-encounter-phase";
import {Mode} from "#app/ui/ui";
import {Button} from "#enums/buttons";
import MysteryEncounterUiHandler from "#app/ui/mystery-encounter-ui-handler";
import {MysteryEncounterType} from "#enums/mystery-encounter-type";
import {MysteryEncounterTier} from "#app/data/mystery-encounters/mystery-encounter";
import MessageUiHandler from "#app/ui/message-ui-handler";
describe("Mystery Encounter Phases", () => {
let phaserGame: Phaser.Game;
@ -26,16 +26,11 @@ describe("Mystery Encounter Phases", () => {
beforeEach(() => {
game = new GameManager(phaserGame);
vi.spyOn(overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(256);
vi.spyOn(overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(11);
vi.spyOn(overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
game.override.startingWave(11);
game.override.mysteryEncounterChance(100);
game.override.mysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS);
// Seed guarantees wild encounter to be replaced by ME
vi.spyOn(game.scene, "resetSeed").mockImplementation(() => {
game.scene.waveSeed = "test";
Phaser.Math.RND.sow([ game.scene.waveSeed ]);
game.scene.rngCounter = 0;
});
game.override.seed("test");
});
describe("MysteryEncounterPhase", () => {
@ -75,21 +70,25 @@ describe("Mystery Encounter Phases", () => {
Species.VOLCARONA
]);
game.onNextPrompt("MysteryEncounterPhase", Mode.MYSTERY_ENCOUNTER, () => {
game.onNextPrompt("MysteryEncounterPhase", Mode.MESSAGE, () => {
const handler = game.scene.ui.getHandler() as MessageUiHandler;
handler.processInput(Button.ACTION);
});
await game.phaseInterceptor.run(MysteryEncounterPhase);
// Select option 1 for encounter
const handler = game.scene.ui.getHandler() as MysteryEncounterUiHandler;
handler.unblockInput();
handler.processInput(Button.ACTION);
}, () => !game.isCurrentPhase(MysteryEncounterPhase));
await game.phaseInterceptor.run(MysteryEncounterPhase);
// After option selected
expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterOptionSelectedPhase.name);
// Waitfor required so that option select messages and preOptionPhase logic are handled
await vi.waitFor(() => expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterOptionSelectedPhase.name));
expect(game.scene.ui.getMode()).toBe(Mode.MESSAGE);
expect(dialogueSpy).toHaveBeenCalledTimes(1);
expect(messageSpy).toHaveBeenCalledTimes(2);
expect(dialogueSpy).toHaveBeenCalledWith("What's this?", "???", null, expect.any(Function));
expect(messageSpy).toHaveBeenCalledWith("Mysterious challengers have appeared!", null, expect.any(Function), 300, true);
expect(messageSpy).toHaveBeenCalledWith("Mysterious challengers have appeared!", null, expect.any(Function), 750, true);
expect(messageSpy).toHaveBeenCalledWith("The trainer steps forward...", null, expect.any(Function), 300, true);
});
});

View File

@ -11,6 +11,11 @@ export default class TextInterceptor {
this.logs.push(text);
}
showDialogue(text: string, name: string, delay?: integer, callback?: Function, callbackDelay?: integer, promptDelay?: integer): void {
console.log(name, text);
this.logs.push(name, text);
}
getLatestMessage(): string {
return this.logs.pop();
}

View File

@ -62,7 +62,7 @@ export default class GameManager {
this.phaseInterceptor = new PhaseInterceptor(this.scene);
this.textInterceptor = new TextInterceptor(this.scene);
this.gameWrapper.setScene(this.scene);
this.override = new OverridesHelper();
this.override = new OverridesHelper(this);
}
/**

View File

@ -17,6 +17,7 @@ export default class MockText {
// Phaser.GameObjects.Text.prototype.updateText = () => null;
// Phaser.Textures.TextureManager.prototype.addCanvas = () => {};
UI.prototype.showText = this.showText;
UI.prototype.showDialogue = this.showDialogue;
// super(scene, x, y);
// this.phaserText = new Phaser.GameObjects.Text(scene, x, y, content, styleOptions);
}
@ -79,6 +80,13 @@ export default class MockText {
}
}
showDialogue(text, name, delay, callback, callbackDelay, promptDelay) {
this.scene.messageWrapper.showDialogue(text, name, delay, callback, callbackDelay, promptDelay);
if (callback) {
callback();
}
}
setScale(scale) {
// return this.phaserText.setScale(scale);
}

View File

@ -1,61 +1,90 @@
import { Weather, WeatherType } from "#app/data/weather";
import { Biome } from "#app/enums/biome";
import * as Overrides from "#app/overrides";
import { vi } from "vitest";
import { MockInstance, vi } from "vitest";
import GameManager from "#test/utils/gameManager";
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import * as overrides from "#app/overrides";
/**
* Helper to handle overrides in tests
*/
export class OverridesHelper {
constructor() {}
game: GameManager;
constructor(game: GameManager) {
this.game = game;
}
/**
* Override the encounter chance for a mystery encounter.
* @param percentage the encounter chance in %
* @returns spy instance
*/
mysteryEncounterChance(percentage: number) {
mysteryEncounterChance(percentage: number): MockInstance {
const maxRate: number = 256; // 100%
const rate = maxRate * (percentage / 100);
vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate);
const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_RATE_OVERRIDE", "get").mockReturnValue(rate);
this.log(`Mystery encounter chance set to ${percentage}% (=${rate})!`);
return spy;
}
/**
* Override the encounter that spawns for the scene
* @param encounterType
* @returns spy instance
*/
mysteryEncounter(encounterType: MysteryEncounterType): MockInstance {
const spy = vi.spyOn(overrides, "MYSTERY_ENCOUNTER_OVERRIDE", "get").mockReturnValue(encounterType);
this.log(`Mystery encounter override set to ${encounterType}!`);
return spy;
}
/**
* Override the starting biome
* @warning The biome will not be overridden unless you call `workaround_reInitSceneWithOverrides()` (testUtils)
* @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line
* @param biome the biome to set
*/
startingBiome(biome: Biome) {
vi.spyOn(Overrides, "STARTING_BIOME_OVERRIDE", "get").mockReturnValue(biome);
this.game.scene.newArena(biome);
this.log(`Starting biome set to ${Biome[biome]} (=${biome})!`);
}
/**
* Override the starting wave (index)
* @param wave the wave (index) to set. Classic: `1`-`200`
* @returns spy instance
*/
startingWave(wave: number) {
vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(wave);
startingWave(wave: number): MockInstance {
const spy = vi.spyOn(Overrides, "STARTING_WAVE_OVERRIDE", "get").mockReturnValue(wave);
this.log(`Starting wave set to ${wave}!`);
return spy;
}
/**
* Override the weather (type)
* @param type weather type to set
* @returns spy instance
*/
weather(type: WeatherType) {
vi.spyOn(Overrides, "WEATHER_OVERRIDE", "get").mockReturnValue(type);
weather(type: WeatherType): MockInstance {
const spy = vi.spyOn(Overrides, "WEATHER_OVERRIDE", "get").mockReturnValue(type);
this.log(`Weather set to ${Weather[type]} (=${type})!`);
return spy;
}
/**
* Override the seed
* @warning The seed will not be overridden unless you call `workaround_reInitSceneWithOverrides()` (testUtils)
* @param seed the seed to set
* @returns spy instance
*/
seed(seed: string) {
vi.spyOn(Overrides, "SEED_OVERRIDE", "get").mockReturnValue(seed);
seed(seed: string): MockInstance {
const spy = vi.spyOn(this.game.scene, "resetSeed").mockImplementation(() => {
this.game.scene.waveSeed = seed;
Phaser.Math.RND.sow([seed]);
this.game.scene.rngCounter = 0;
});
this.game.scene.resetSeed();
this.log(`Seed set to "${seed}"!`);
return spy;
}
private log(...params: any[]) {

View File

@ -108,7 +108,7 @@ export default class PhaseInterceptor {
];
private endBySetMode = [
TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase, PostMysteryEncounterPhase
TitlePhase, SelectGenderPhase, CommandPhase, SelectModifierPhase, MysteryEncounterPhase, PostMysteryEncounterPhase
];
/**

View File

@ -1,6 +1,5 @@
import i18next, { type ParseKeys } from "i18next";
import { vi } from "vitest";
import GameManager from "./gameManager";
/**
* Sets up the i18next mock.
@ -22,15 +21,3 @@ export function mockI18next() {
export function arrayOfRange(start: integer, end: integer) {
return Array.from({ length: end - start }, (_v, k) => k + start);
}
/**
* Woraround to reinitialize the game scene with overrides being set properly.
* By default the scene is initialized without all overrides even having a chance to be applied.
* @warning USE AT YOUR OWN RISK! Might be deleted in the future
* @param game The game manager
* @deprecated
*/
export async function workaround_reInitSceneWithOverrides(game: GameManager) {
await game.runToTitle();
game.gameWrapper.setScene(game.scene);
}