Skip to content

Commit

Permalink
Fix SelectModifierPhase tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DayKev committed Nov 14, 2024
1 parent 7c0ed01 commit cc33ac9
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 58 deletions.
108 changes: 62 additions & 46 deletions src/test/phases/select-modifier-phase.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import Phaser from "phaser";
import GameManager from "#app/test/utils/gameManager";
import { initSceneWithoutEncounterPhase } from "#app/test/utils/gameManagerUtils";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import type BattleScene from "#app/battle-scene";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { PlayerPokemon } from "#app/field/pokemon";
import { ModifierTier } from "#app/modifier/modifier-tier";
import * as Utils from "#app/utils";
import { CustomModifierSettings, ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type";
import BattleScene from "#app/battle-scene";
import { Species } from "#enums/species";
import { Mode } from "#app/ui/ui";
import { PlayerPokemon } from "#app/field/pokemon";
import { getPokemonSpecies } from "#app/data/pokemon-species";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import { Mode } from "#app/ui/ui";
import { shiftCharCodes } from "#app/utils";
import { Abilities } from "#enums/abilities";
import { Button } from "#enums/buttons";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import GameManager from "#test/utils/gameManager";
import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";

// TODO: why are the `expect(modifierSelectHandler.options.length).toEqual(#)` checks unreliable/failing?
describe.skip("SelectModifierPhase", () => {
describe("SelectModifierPhase", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
let scene: BattleScene;
Expand All @@ -29,7 +32,11 @@ describe.skip("SelectModifierPhase", () => {
game = new GameManager(phaserGame);
scene = game.scene;

initSceneWithoutEncounterPhase(scene, [ Species.ABRA, Species.VOLCARONA ]);
game.override
.moveset([ Moves.FISSURE, Moves.SPLASH ])
.ability(Abilities.NO_GUARD)
.startingLevel(200)
.enemySpecies(Species.MAGIKARP);
});

afterEach(() => {
Expand All @@ -39,6 +46,7 @@ describe.skip("SelectModifierPhase", () => {
});

it("should start a select modifier phase", async () => {
initSceneWithoutEncounterPhase(scene, [ Species.ABRA, Species.VOLCARONA ]);
const selectModifierPhase = new SelectModifierPhase();
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);
Expand All @@ -47,17 +55,17 @@ describe.skip("SelectModifierPhase", () => {
});

it("should generate random modifiers", async () => {
const selectModifierPhase = new SelectModifierPhase();
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);

await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
game.move.select(Moves.FISSURE);
await game.phaseInterceptor.to("SelectModifierPhase");

expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(3);
});

it("should modify reroll cost", async () => {
initSceneWithoutEncounterPhase(scene, [ Species.ABRA, Species.VOLCARONA ]);
const options = [
new ModifierTypeOption(modifierTypes.POTION(), 0, 100),
new ModifierTypeOption(modifierTypes.ETHER(), 0, 400),
Expand All @@ -72,50 +80,48 @@ describe.skip("SelectModifierPhase", () => {
expect(cost2).toEqual(cost1 * 2);
});

it("should generate random modifiers from reroll", async () => {
let selectModifierPhase = new SelectModifierPhase();
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);
it.todo("should generate random modifiers from reroll", async () => {
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
scene.shopCursorTarget = 0;

game.move.select(Moves.FISSURE);
await game.phaseInterceptor.to("SelectModifierPhase");

// TODO: nagivate the ui to reroll somehow
//const smphase = scene.getCurrentPhase() as SelectModifierPhase;
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(3);

// Simulate selecting reroll
selectModifierPhase = new SelectModifierPhase(1, [ ModifierTier.COMMON, ModifierTier.COMMON, ModifierTier.COMMON ]);
scene.unshiftPhase(selectModifierPhase);
scene.ui.setMode(Mode.MESSAGE).then(() => game.endPhase());
await game.phaseInterceptor.run(SelectModifierPhase);
modifierSelectHandler.processInput(Button.ACTION);

expect(scene.money).toBe(1000000 - 250);
expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
expect(modifierSelectHandler.options.length).toEqual(3);
});

it("should generate random modifiers of same tier for reroll with reroll lock", async () => {
it.todo("should generate random modifiers of same tier for reroll with reroll lock", async () => {
game.override.startingModifier([{ name: "LOCK_CAPSULE" }]);
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
// Just use fully random seed for this test
vi.spyOn(scene, "resetSeed").mockImplementation(() => {
scene.waveSeed = Utils.shiftCharCodes(scene.seed, 5);
scene.waveSeed = shiftCharCodes(scene.seed, 5);
Phaser.Math.RND.sow([ scene.waveSeed ]);
console.log("Wave Seed:", scene.waveSeed, 5);
scene.rngCounter = 0;
});

let selectModifierPhase = new SelectModifierPhase();
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);
game.move.select(Moves.FISSURE);
await game.phaseInterceptor.to("SelectModifierPhase");

expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
expect(modifierSelectHandler.options.length).toEqual(3);
const firstRollTiers: ModifierTier[] = modifierSelectHandler.options.map(o => o.modifierTypeOption.type.tier);

// Simulate selecting reroll with lock
scene.lockModifierTiers = true;
scene.reroll = true;
selectModifierPhase = new SelectModifierPhase(1, firstRollTiers);
scene.unshiftPhase(selectModifierPhase);
scene.ui.setMode(Mode.MESSAGE).then(() => game.endPhase());
await game.phaseInterceptor.run(SelectModifierPhase);
// TODO: nagivate ui to reroll with lock capsule enabled

expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
expect(modifierSelectHandler.options.length).toEqual(3);
Expand All @@ -126,13 +132,15 @@ describe.skip("SelectModifierPhase", () => {
});

it("should generate custom modifiers", async () => {
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
const customModifiers: CustomModifierSettings = {
guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_ULTRA, modifierTypes.LEFTOVERS, modifierTypes.AMULET_COIN, modifierTypes.GOLDEN_PUNCH ]
};
const selectModifierPhase = new SelectModifierPhase(0, undefined, customModifiers);
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);

scene.unshiftPhase(selectModifierPhase);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("SelectModifierPhase");

expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
Expand All @@ -145,6 +153,8 @@ describe.skip("SelectModifierPhase", () => {
});

it("should generate custom modifier tiers that can upgrade from luck", async () => {
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
const customModifiers: CustomModifierSettings = {
guaranteedModifierTiers: [ ModifierTier.COMMON, ModifierTier.GREAT, ModifierTier.ULTRA, ModifierTier.ROGUE, ModifierTier.MASTER ]
};
Expand All @@ -157,9 +167,9 @@ describe.skip("SelectModifierPhase", () => {
scene.getPlayerParty().push(pokemon, pokemon, pokemon, pokemon, pokemon, pokemon);

const selectModifierPhase = new SelectModifierPhase(0, undefined, customModifiers);
scene.pushPhase(selectModifierPhase);
await game.phaseInterceptor.run(SelectModifierPhase);

scene.unshiftPhase(selectModifierPhase);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to("SelectModifierPhase");

expect(scene.ui.getMode()).to.equal(Mode.MODIFIER_SELECT);
const modifierSelectHandler = scene.ui.handlers.find(h => h instanceof ModifierSelectUiHandler) as ModifierSelectUiHandler;
Expand All @@ -172,12 +182,15 @@ describe.skip("SelectModifierPhase", () => {
});

it("should generate custom modifiers and modifier tiers together", async () => {
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
const customModifiers: CustomModifierSettings = {
guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM, modifierTypes.TM_COMMON ],
guaranteedModifierTiers: [ ModifierTier.MASTER, ModifierTier.MASTER ]
};
const selectModifierPhase = new SelectModifierPhase(0, undefined, customModifiers);
scene.pushPhase(selectModifierPhase);
scene.unshiftPhase(selectModifierPhase);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.run(SelectModifierPhase);


Expand All @@ -191,13 +204,16 @@ describe.skip("SelectModifierPhase", () => {
});

it("should fill remaining modifiers if fillRemaining is true with custom modifiers", async () => {
await game.classicMode.startBattle([ Species.ABRA, Species.VOLCARONA ]);
scene.money = 1000000;
const customModifiers: CustomModifierSettings = {
guaranteedModifierTypeFuncs: [ modifierTypes.MEMORY_MUSHROOM ],
guaranteedModifierTiers: [ ModifierTier.MASTER ],
fillRemaining: true
};
const selectModifierPhase = new SelectModifierPhase(0, undefined, customModifiers);
scene.pushPhase(selectModifierPhase);
scene.unshiftPhase(selectModifierPhase);
game.move.select(Moves.SPLASH);
await game.phaseInterceptor.run(SelectModifierPhase);


Expand Down
25 changes: 14 additions & 11 deletions src/test/utils/gameManagerUtils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import BattleScene from "#app/battle-scene";
import Battle, { BattleType } from "#app/battle";
import type BattleScene from "#app/battle-scene";
import { getDailyRunStarters } from "#app/data/daily-run";
import { Gender } from "#app/data/gender";
import { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
import { Moves } from "#app/enums/moves";
import { PlayerPokemon } from "#app/field/pokemon";
import { GameModes, getGameMode } from "#app/game-mode";
import type { StarterMoveset } from "#app/system/game-data";
import { Starter } from "#app/ui/starter-select-ui-handler";
import { Moves } from "#enums/moves";
import { Species } from "#enums/species";
import Battle, { BattleType } from "#app/battle";

/** Function to convert Blob to string */
export function blobToString(blob) {
Expand All @@ -31,7 +32,7 @@ export function holdOn(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}

export function generateStarter(scene, species?: Species[]) {
export function generateStarter(scene: BattleScene, species?: Species[]): Starter[] {
const seed = "test";
const starters = getTestRunStarters(seed, species);
const startingLevel = scene.gameMode.getStartingLevel();
Expand All @@ -42,12 +43,16 @@ export function generateStarter(scene, species?: Species[]) {
? !starterProps.female ? Gender.MALE : Gender.FEMALE
: Gender.GENDERLESS;
const starterPokemon = scene.addPlayerPokemon(starter.species, startingLevel, starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, undefined, starter.nature);
starter.moveset = starterPokemon.moveset;
const moveset: Moves[] = [];
starterPokemon.moveset.forEach((move) => {
moveset.push(move!.getMove().id);
});
starter.moveset = moveset as StarterMoveset;
}
return starters;
}

function getTestRunStarters(seed, species) {
function getTestRunStarters(seed: string, species?: Species[]): Starter[] {
if (!species) {
return getDailyRunStarters(seed);
}
Expand All @@ -71,7 +76,7 @@ function getTestRunStarters(seed, species) {
return starters;
}

export function waitUntil(truth) {
export function waitUntil(truth): Promise<unknown> {
return new Promise(resolve => {
const interval = setInterval(() => {
if (truth()) {
Expand All @@ -83,7 +88,7 @@ export function waitUntil(truth) {
}

/** Get the index of `move` from the moveset of the pokemon on the player's field at location `pokemonIndex` */
export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: Moves) {
export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: Moves): number {
const playerPokemon = scene.getPlayerField()[pokemonIndex];
const moveSet = playerPokemon.getMoveset();
const index = moveSet.findIndex((m) => m?.moveId === move && m?.ppUsed < m?.getMovePp());
Expand All @@ -93,10 +98,8 @@ export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: M

/**
* Useful for populating party, wave index, etc. without having to spin up and run through an entire EncounterPhase
* @param scene
* @param species
*/
export function initSceneWithoutEncounterPhase(scene: BattleScene, species?: Species[]) {
export function initSceneWithoutEncounterPhase(scene: BattleScene, species?: Species[]): void {
const starters = generateStarter(scene, species);
starters.forEach((starter) => {
const starterProps = scene.gameData.getSpeciesDexAttrProps(starter.species, starter.dexAttr);
Expand Down
8 changes: 7 additions & 1 deletion src/test/utils/phaseInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,13 @@ export default class PhaseInterceptor {
const currentHandler = this.scene.ui.getHandler();
if (expireFn) {
this.prompts.shift();
} else if (currentMode === actionForNextPrompt.mode && currentPhase === actionForNextPrompt.phaseTarget && currentHandler.active && (!actionForNextPrompt.awaitingActionInput || (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))) {
} else if (
currentMode === actionForNextPrompt.mode
&& currentPhase === actionForNextPrompt.phaseTarget
&& currentHandler.active
&& (!actionForNextPrompt.awaitingActionInput
|| (actionForNextPrompt.awaitingActionInput && currentHandler.awaitingActionInput))
) {
const prompt = this.prompts.shift();
if (prompt?.callback) {
prompt.callback();
Expand Down

0 comments on commit cc33ac9

Please sign in to comment.