From 0d3fcd82bbec7373cb6430c0e9053ab9f8a2c37e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Tue, 13 Aug 2024 13:48:56 -0700 Subject: [PATCH] [Bug] Fix daily run generated movesets (#3519) * Fix daily run generated movesets * add unit-tests for `fix-daily-run` (#3) * add `daily` and `classic` helper. split `runToSummon` there is now a `classicMode.runToSummon` which represents the old one used. There is now a `dailyMode.runToSummon` too * add daily_mode.test.ts covers the occured issue --------- Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> --- src/field/pokemon.ts | 7 ++-- src/test/abilities/ability_timing.test.ts | 2 +- src/test/abilities/intimidate.test.ts | 14 ++++---- src/test/abilities/intrepid_sword.test.ts | 2 +- src/test/daily_mode.test.ts | 32 +++++++++++++++++ src/test/evolution.test.ts | 8 ++--- src/test/field/pokemon.test.ts | 2 +- src/test/internals.test.ts | 4 +-- src/test/moves/multi_target.test.ts | 2 +- src/test/moves/spikes.test.ts | 8 ++--- src/test/utils/gameManager.ts | 35 +++++------------- src/test/utils/helpers/classicModeHelper.ts | 35 ++++++++++++++++++ src/test/utils/helpers/dailyModeHelper.ts | 36 +++++++++++++++++++ .../utils/{ => helpers}/gameManagerHelper.ts | 2 +- src/test/utils/{ => helpers}/moveHelper.ts | 0 .../utils/{ => helpers}/overridesHelper.ts | 0 16 files changed, 139 insertions(+), 50 deletions(-) create mode 100644 src/test/daily_mode.test.ts create mode 100644 src/test/utils/helpers/classicModeHelper.ts create mode 100644 src/test/utils/helpers/dailyModeHelper.ts rename src/test/utils/{ => helpers}/gameManagerHelper.ts (82%) rename src/test/utils/{ => helpers}/moveHelper.ts (100%) rename src/test/utils/{ => helpers}/overridesHelper.ts (100%) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 4a46e7b2947..c7d653c54fd 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3255,9 +3255,12 @@ export class PlayerPokemon extends Pokemon { this.variant = Overrides.VARIANT_OVERRIDE; } } - if (!dataSource) { - this.moveset = []; + if (this.scene.gameMode.isDaily) { + this.generateAndPopulateMoveset(); + } else { + this.moveset = []; + } } this.generateCompatibleTms(); } diff --git a/src/test/abilities/ability_timing.test.ts b/src/test/abilities/ability_timing.test.ts index bb025d7fc53..3906233a7bf 100644 --- a/src/test/abilities/ability_timing.test.ts +++ b/src/test/abilities/ability_timing.test.ts @@ -39,7 +39,7 @@ describe("Ability Timing", () => { it("should trigger after switch check", async() => { initI18n(); i18next.changeLanguage("en"); - await game.runToSummon([Species.EEVEE, Species.FEEBAS]); + await game.classicMode.runToSummon([Species.EEVEE, Species.FEEBAS]); game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { game.setMode(Mode.MESSAGE); diff --git a/src/test/abilities/intimidate.test.ts b/src/test/abilities/intimidate.test.ts index 2c2b68bc5df..2b4c1041bfe 100644 --- a/src/test/abilities/intimidate.test.ts +++ b/src/test/abilities/intimidate.test.ts @@ -39,7 +39,7 @@ describe("Abilities - Intimidate", () => { }); it("single - wild with switch", async () => { - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -69,7 +69,7 @@ describe("Abilities - Intimidate", () => { it("single - boss should only trigger once then switch", async () => { game.override.startingWave(10); - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -98,7 +98,7 @@ describe("Abilities - Intimidate", () => { it("single - trainer should only trigger once with switch", async () => { game.override.startingWave(5); - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -128,7 +128,7 @@ describe("Abilities - Intimidate", () => { it("double - trainer should only trigger once per pokemon", async () => { game.override.battleType("double"); game.override.startingWave(5); - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -154,7 +154,7 @@ describe("Abilities - Intimidate", () => { it("double - wild: should only trigger once per pokemon", async () => { game.override.battleType("double"); game.override.startingWave(3); - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -180,7 +180,7 @@ describe("Abilities - Intimidate", () => { it("double - boss: should only trigger once per pokemon", async () => { game.override.battleType("double"); game.override.startingWave(10); - await game.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA, Species.POOCHYENA]); game.onNextPrompt( "CheckSwitchPhase", Mode.CONFIRM, @@ -334,7 +334,7 @@ describe("Abilities - Intimidate", () => { it("double - wild vs only 1 on player side", async () => { game.override.battleType("double"); game.override.startingWave(3); - await game.runToSummon([Species.MIGHTYENA]); + await game.classicMode.runToSummon([Species.MIGHTYENA]); await game.phaseInterceptor.to(CommandPhase, false); const battleStatsOpponent = game.scene.currentBattle.enemyParty[0].summonData.battleStats; expect(battleStatsOpponent[BattleStat.ATK]).toBe(-1); diff --git a/src/test/abilities/intrepid_sword.test.ts b/src/test/abilities/intrepid_sword.test.ts index bc83c9bb44b..dcc91421165 100644 --- a/src/test/abilities/intrepid_sword.test.ts +++ b/src/test/abilities/intrepid_sword.test.ts @@ -30,7 +30,7 @@ describe("Abilities - Intrepid Sword", () => { }); it("INTREPID SWORD on player", async() => { - await game.runToSummon([ + await game.classicMode.runToSummon([ Species.ZACIAN, ]); await game.phaseInterceptor.to(CommandPhase, false); diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts new file mode 100644 index 00000000000..5cc61a62874 --- /dev/null +++ b/src/test/daily_mode.test.ts @@ -0,0 +1,32 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import GameManager from "./utils/gameManager"; + +describe("Daily Mode", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + it("should initialize properly", async () => { + await game.dailyMode.runToSummon(); + + const party = game.scene.getParty(); + expect(party).toHaveLength(3); + party.forEach(pkm => { + expect(pkm.level).toBe(20); + expect(pkm.moveset.length).toBeGreaterThan(0); + }); + }); +}); diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index b1764a67ad7..b54deaa4611 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -32,7 +32,7 @@ describe("Evolution", () => { }); it("should keep hidden ability after evolving", async () => { - await game.runToSummon([Species.EEVEE, Species.TRAPINCH]); + await game.classicMode.runToSummon([Species.EEVEE, Species.TRAPINCH]); const eevee = game.scene.getParty()[0]; const trapinch = game.scene.getParty()[1]; @@ -47,7 +47,7 @@ describe("Evolution", () => { }, TIMEOUT); it("should keep same ability slot after evolving", async () => { - await game.runToSummon([Species.BULBASAUR, Species.CHARMANDER]); + await game.classicMode.runToSummon([Species.BULBASAUR, Species.CHARMANDER]); const bulbasaur = game.scene.getParty()[0]; const charmander = game.scene.getParty()[1]; @@ -62,7 +62,7 @@ describe("Evolution", () => { }, TIMEOUT); it("should handle illegal abilityIndex values", async () => { - await game.runToSummon([Species.SQUIRTLE]); + await game.classicMode.runToSummon([Species.SQUIRTLE]); const squirtle = game.scene.getPlayerPokemon()!; squirtle.abilityIndex = 5; @@ -72,7 +72,7 @@ describe("Evolution", () => { }, TIMEOUT); it("should handle nincada's unique evolution", async () => { - await game.runToSummon([Species.NINCADA]); + await game.classicMode.runToSummon([Species.NINCADA]); const nincada = game.scene.getPlayerPokemon()!; nincada.abilityIndex = 2; diff --git a/src/test/field/pokemon.test.ts b/src/test/field/pokemon.test.ts index 2220a6f613e..ee8e41e8b42 100644 --- a/src/test/field/pokemon.test.ts +++ b/src/test/field/pokemon.test.ts @@ -21,7 +21,7 @@ describe("Spec - Pokemon", () => { }); it("should not crash when trying to set status of undefined", async () => { - await game.runToSummon([Species.ABRA]); + await game.classicMode.runToSummon([Species.ABRA]); const pkm = game.scene.getPlayerPokemon()!; expect(pkm).toBeDefined(); diff --git a/src/test/internals.test.ts b/src/test/internals.test.ts index d186849830d..0ecd156431d 100644 --- a/src/test/internals.test.ts +++ b/src/test/internals.test.ts @@ -23,7 +23,7 @@ describe("Internals", () => { }); it("should provide Eevee with 3 defined abilities", async () => { - await game.runToSummon([Species.EEVEE]); + await game.classicMode.runToSummon([Species.EEVEE]); const eevee = game.scene.getPlayerPokemon()!; expect(eevee.getSpeciesForm().getAbilityCount()).toBe(3); @@ -34,7 +34,7 @@ describe("Internals", () => { }); it("should set Eeeve abilityIndex between 0-2", async () => { - await game.runToSummon([Species.EEVEE]); + await game.classicMode.runToSummon([Species.EEVEE]); const eevee = game.scene.getPlayerPokemon()!; expect(eevee.abilityIndex).toBeGreaterThanOrEqual(0); diff --git a/src/test/moves/multi_target.test.ts b/src/test/moves/multi_target.test.ts index a4ed936c5ee..4cb2dfb764d 100644 --- a/src/test/moves/multi_target.test.ts +++ b/src/test/moves/multi_target.test.ts @@ -88,7 +88,7 @@ async function checkTargetMultiplier(game: GameManager, attackMove: Moves, killA async function checkDamageDecrease(game: GameManager, attackMove: Moves, killAlly: boolean, killSecondEnemy: boolean, shouldDecreased: boolean, ability?: Abilities) { // Tested combination on first turn, 1v1 on second turn - await game.runToSummon([Species.EEVEE, Species.EEVEE]); + await game.classicMode.runToSummon([Species.EEVEE, Species.EEVEE]); if (ability !== undefined) { game.scene.getPlayerField()[1].abilityIndex = ability; diff --git a/src/test/moves/spikes.test.ts b/src/test/moves/spikes.test.ts index 1f5bb757ee4..bbbb3347580 100644 --- a/src/test/moves/spikes.test.ts +++ b/src/test/moves/spikes.test.ts @@ -39,7 +39,7 @@ describe("Moves - Spikes", () => { // player set spikes on the field and do splash for 3 turns // opponent do splash for 4 turns // nobody should take damage - await game.runToSummon([ + await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA, ]); @@ -64,7 +64,7 @@ describe("Moves - Spikes", () => { // player set spikes on the field and switch back to back // opponent do splash for 2 turns // nobody should take damage - await game.runToSummon([ + await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA, ]); @@ -87,7 +87,7 @@ describe("Moves - Spikes", () => { // player set spikes on the field and do splash for 3 turns // opponent do splash for 4 turns // nobody should take damage - await game.runToSummon([ + await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA, ]); @@ -107,7 +107,7 @@ describe("Moves - Spikes", () => { // turn 1: player set spikes, opponent do splash // turn 2: player do splash, opponent switch pokemon // opponent pokemon should trigger spikes and lose HP - await game.runToSummon([ + await game.classicMode.runToSummon([ Species.MIGHTYENA, Species.POOCHYENA, ]); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 935d40324a2..27ba7a215eb 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -23,12 +23,13 @@ import { Species } from "#enums/species"; import { Button } from "#enums/buttons"; import { BattlerIndex } from "#app/battle.js"; import TargetSelectUiHandler from "#app/ui/target-select-ui-handler.js"; -import { OverridesHelper } from "./overridesHelper"; +import { OverridesHelper } from "./helpers/overridesHelper"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; -import overrides from "#app/overrides.js"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js"; -import { MoveHelper } from "./moveHelper"; +import { MoveHelper } from "./helpers/moveHelper"; import { vi } from "vitest"; +import { ClassicModeHelper } from "./helpers/classicModeHelper"; +import { DailyModeHelper } from "./helpers/dailyModeHelper"; /** * Class to manage the game state and transitions between phases. @@ -41,6 +42,8 @@ export default class GameManager { public inputsHandler: InputsHandler; public readonly override: OverridesHelper; public readonly move: MoveHelper; + public readonly classicMode: ClassicModeHelper; + public readonly dailyMode: DailyModeHelper; /** * Creates an instance of GameManager. @@ -58,6 +61,8 @@ export default class GameManager { this.gameWrapper.setScene(this.scene); this.override = new OverridesHelper(this); this.move = new MoveHelper(this); + this.classicMode = new ClassicModeHelper(this); + this.dailyMode = new DailyModeHelper(this); } /** @@ -118,28 +123,6 @@ export default class GameManager { } - /** - * Runs the game to the summon phase. - * @param species - Optional array of species to summon. - * @returns A promise that resolves when the summon phase is reached. - */ - async runToSummon(species?: Species[]) { - await this.runToTitle(); - - this.onNextPrompt("TitlePhase", Mode.TITLE, () => { - this.scene.gameMode = getGameMode(GameModes.CLASSIC); - const starters = generateStarter(this.scene, species); - const selectStarterPhase = new SelectStarterPhase(this.scene); - this.scene.pushPhase(new EncounterPhase(this.scene, false)); - selectStarterPhase.initBattle(starters); - }); - - await this.phaseInterceptor.run(EncounterPhase); - if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { - this.removeEnemyHeldItems(); - } - } - /** * Helper function to run to the final boss encounter as it's a bit tricky due to extra dialogue * Also handles Major/Minor bosses from endless modes @@ -178,7 +161,7 @@ export default class GameManager { * @returns A promise that resolves when the battle is started. */ async startBattle(species?: Species[]) { - await this.runToSummon(species); + await this.classicMode.runToSummon(species); this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { this.setMode(Mode.MESSAGE); diff --git a/src/test/utils/helpers/classicModeHelper.ts b/src/test/utils/helpers/classicModeHelper.ts new file mode 100644 index 00000000000..e6854d5bc79 --- /dev/null +++ b/src/test/utils/helpers/classicModeHelper.ts @@ -0,0 +1,35 @@ +import { Species } from "#app/enums/species.js"; +import { GameModes, getGameMode } from "#app/game-mode.js"; +import overrides from "#app/overrides.js"; +import { EncounterPhase, SelectStarterPhase } from "#app/phases.js"; +import { Mode } from "#app/ui/ui.js"; +import { generateStarter } from "../gameManagerUtils"; +import { GameManagerHelper } from "./gameManagerHelper"; + +/** + * Helper to handle classic mode specifics + */ +export class ClassicModeHelper extends GameManagerHelper { + + /** + * Runs the classic game to the summon phase. + * @param species - Optional array of species to summon. + * @returns A promise that resolves when the summon phase is reached. + */ + async runToSummon(species?: Species[]) { + await this.game.runToTitle(); + + this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + this.game.scene.gameMode = getGameMode(GameModes.CLASSIC); + const starters = generateStarter(this.game.scene, species); + const selectStarterPhase = new SelectStarterPhase(this.game.scene); + this.game.scene.pushPhase(new EncounterPhase(this.game.scene, false)); + selectStarterPhase.initBattle(starters); + }); + + await this.game.phaseInterceptor.run(EncounterPhase); + if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { + this.game.removeEnemyHeldItems(); + } + } +} diff --git a/src/test/utils/helpers/dailyModeHelper.ts b/src/test/utils/helpers/dailyModeHelper.ts new file mode 100644 index 00000000000..c83a2e587d9 --- /dev/null +++ b/src/test/utils/helpers/dailyModeHelper.ts @@ -0,0 +1,36 @@ +import { Button } from "#app/enums/buttons.js"; +import overrides from "#app/overrides.js"; +import { EncounterPhase, TitlePhase } from "#app/phases.js"; +import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler.js"; +import { Mode } from "#app/ui/ui.js"; +import { GameManagerHelper } from "./gameManagerHelper"; + +/** + * Helper to handle daily mode specifics + */ +export class DailyModeHelper extends GameManagerHelper { + + /** + * Runs the daily game to the summon phase. + * @returns A promise that resolves when the summon phase is reached. + */ + async runToSummon() { + await this.game.runToTitle(); + + this.game.onNextPrompt("TitlePhase", Mode.TITLE, () => { + const titlePhase = new TitlePhase(this.game.scene); + titlePhase.initDailyRun(); + }); + + this.game.onNextPrompt("TitlePhase", Mode.SAVE_SLOT, () => { + const uihandler = this.game.scene.ui.getHandler(); + uihandler.processInput(Button.ACTION); // select first slot. that's fine + }); + + await this.game.phaseInterceptor.run(EncounterPhase); + + if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { + this.game.removeEnemyHeldItems(); + } + } +} diff --git a/src/test/utils/gameManagerHelper.ts b/src/test/utils/helpers/gameManagerHelper.ts similarity index 82% rename from src/test/utils/gameManagerHelper.ts rename to src/test/utils/helpers/gameManagerHelper.ts index 2caa94ae5ed..432e6fdf853 100644 --- a/src/test/utils/gameManagerHelper.ts +++ b/src/test/utils/helpers/gameManagerHelper.ts @@ -1,4 +1,4 @@ -import GameManager from "./gameManager"; +import GameManager from "../gameManager"; /** * Base class for defining all game helpers. diff --git a/src/test/utils/moveHelper.ts b/src/test/utils/helpers/moveHelper.ts similarity index 100% rename from src/test/utils/moveHelper.ts rename to src/test/utils/helpers/moveHelper.ts diff --git a/src/test/utils/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts similarity index 100% rename from src/test/utils/overridesHelper.ts rename to src/test/utils/helpers/overridesHelper.ts