From 186a1af7b82a0da8102a2e4eb3e05b29682ef662 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer Date: Fri, 19 Jul 2024 19:21:46 -0400 Subject: [PATCH] nit updates and cleanup --- src/battle-scene.ts | 4 +-- src/battle.ts | 2 +- .../mystery-encounters/mystery-encounter.ts | 16 ++++++---- .../fiery-fallout-encounter.test.ts | 32 ++++++++++++++----- .../encounters/lost-at-sea-encounter.test.ts | 31 +++++++++++++----- .../mystery-encounter.test.ts | 12 ++----- .../phases/mystery-encounter-phase.test.ts | 15 ++------- src/test/utils/gameManager.ts | 8 ++++- src/test/utils/overridesHelper.ts | 20 +++++++++--- 9 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 9c32c58efdb..4c0f31b051e 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2650,8 +2650,8 @@ export default class BattleScene extends SceneBase { return encounter; } - // Common / Great / Ultra / Rogue - const tierWeights = [64, 40, 21, 3]; + // See Enum values for base tier weights + const tierWeights = [MysteryEncounterTier.COMMON, MysteryEncounterTier.GREAT, MysteryEncounterTier.ULTRA, MysteryEncounterTier.ROGUE]; // Adjust tier weights by previously encountered events to lower odds of only common/uncommons in run this.mysteryEncounterData.encounteredEvents.forEach(val => { diff --git a/src/battle.ts b/src/battle.ts index 9076eba7d0a..2c033ce38bf 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -206,7 +206,7 @@ export default class Battle { getBgmOverride(scene: BattleScene): string { const battlers = this.enemyParty.slice(0, this.getBattlerCount()); if (this.battleType === BattleType.TRAINER || this.mysteryEncounter?.encounterVariant === MysteryEncounterVariant.TRAINER_BATTLE) { - if (!this.started && this.trainer?.config?.encounterBgm && this.trainer?.getEncounterMessages()?.length) { + if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages().length) { return `encounter_${this.trainer.getEncounterBgm()}`; } if (scene.musicPreference === 0) { diff --git a/src/data/mystery-encounters/mystery-encounter.ts b/src/data/mystery-encounters/mystery-encounter.ts index 7fc66dfa4e7..6136e338854 100644 --- a/src/data/mystery-encounters/mystery-encounter.ts +++ b/src/data/mystery-encounters/mystery-encounter.ts @@ -27,15 +27,19 @@ export enum MysteryEncounterVariant { WILD_BATTLE, BOSS_BATTLE, NO_BATTLE, + /** For spawning new encounter queries instead of continuing to next wave */ REPEATED_ENCOUNTER } +/** + * Enum values are base spawn weights of each tier + */ export enum MysteryEncounterTier { - COMMON, - GREAT, - ULTRA, - ROGUE, - MASTER // Not currently used + COMMON = 64, + GREAT = 40, + ULTRA = 21, + ROGUE = 3, + MASTER = 0 // Not currently used } export interface StartOfBattleEffect { @@ -438,7 +442,7 @@ export class MysteryEncounterBuilder implements Partial { * @param callback - {@linkcode OptionPhaseCallback} * @returns */ - withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback) { + withSimpleOption(dialogue: OptionTextDisplay, callback: OptionPhaseCallback): this { return this.withOption(new MysteryEncounterOptionBuilder().withOptionMode(EncounterOptionMode.DEFAULT).withDialogue(dialogue).withOptionPhase(callback).build()); } diff --git a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts index 19d909cab64..9bcb3a36d2c 100644 --- a/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/fiery-fallout-encounter.test.ts @@ -18,6 +18,7 @@ import BattleScene from "#app/battle-scene"; import { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { Type } from "#app/data/type"; import { Status, StatusEffect } from "#app/data/status-effect"; +import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter"; const namespace = "mysteryEncounter:fieryFallout"; /** Arcanine and Ninetails for 2 Fire types. Lapras, Gengar, Abra for burnable mon. */ @@ -38,9 +39,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { game = new GameManager(phaserGame); scene = game.scene; game.override.mysteryEncounterChance(100); + game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.trainerWave(false); + game.override.disableTrainerWave(true); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -55,9 +57,11 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); it("should have the correct properties", async () => { - await game.runToMysteryEncounter(defaultParty); + game.override.mysteryEncounter(MysteryEncounterType.FIERY_FALLOUT); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); expect(FieryFalloutEncounter.encounterType).toBe(MysteryEncounterType.FIERY_FALLOUT); + expect(FieryFalloutEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(FieryFalloutEncounter.dialogue).toBeDefined(); expect(FieryFalloutEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}:intro` }]); expect(FieryFalloutEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}:title`); @@ -126,6 +130,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); describe("Option 1 - Fight 2 Volcarona", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.FIERY_FALLOUT); + }); + it("should have the correct properties", () => { const option1 = FieryFalloutEncounter.options[0]; expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT); @@ -144,7 +152,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { it("should start battle against 2 Volcarona", async () => { const phaseSpy = vi.spyOn(scene, "pushPhase"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runSelectMysteryEncounterOption(game, 1, true); const enemyField = scene.getEnemyField(); @@ -161,7 +169,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); it("should give charcoal to lead pokemon", async () => { - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runSelectMysteryEncounterOption(game, 1, true); await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); @@ -176,6 +184,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); describe("Option 2 - Suffer the weather", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.FIERY_FALLOUT); + }); + it("should have the correct properties", () => { const option1 = FieryFalloutEncounter.options[1]; expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT); @@ -192,7 +204,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); it("should damage all non-fire party PKM by 20% and randomly burn 1", async () => { - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); const party = scene.getParty(); const lapras = party.find((pkm) => pkm.species.speciesId === Species.LAPRAS); @@ -215,7 +227,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { it("should leave encounter without battle", async () => { const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runSelectMysteryEncounterOption(game, 2); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); @@ -223,6 +235,10 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); describe("Option 3 - use FIRE types", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.FIERY_FALLOUT); + }); + it("should have the correct properties", () => { const option1 = FieryFalloutEncounter.options[2]; expect(option1.optionMode).toBe(EncounterOptionMode.DISABLED_OR_SPECIAL); @@ -240,7 +256,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { }); it("should give charcoal to lead pokemon", async () => { - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runSelectMysteryEncounterOption(game, 3); // await skipBattleRunMysteryEncounterRewardsPhase(game); await game.phaseInterceptor.to(SelectModifierPhase, false); @@ -256,7 +272,7 @@ describe("Fiery Fallout - Mystery Encounter", () => { it("should leave encounter without battle", async () => { const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.FIERY_FALLOUT, defaultParty); await runSelectMysteryEncounterOption(game, 3); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); diff --git a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts index 99b1c8b4764..04854574a77 100644 --- a/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/lost-at-sea-encounter.test.ts @@ -11,6 +11,7 @@ import { Species } from "#app/enums/species"; import GameManager from "#app/test/utils/gameManager"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { runSelectMysteryEncounterOption } from "../encounterTestUtils"; +import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter"; const namespace = "mysteryEncounter:lostAtSea"; /** Blastoise for surf. Pidgeot for fly. Abra for none. */ @@ -31,7 +32,7 @@ describe("Lost at Sea - Mystery Encounter", () => { game.override.mysteryEncounterChance(100); game.override.startingWave(defaultWave); game.override.startingBiome(defaultBiome); - game.override.trainerWave(false); + game.override.disableTrainerWave(true); vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue( new Map([ @@ -46,9 +47,11 @@ describe("Lost at Sea - Mystery Encounter", () => { }); it("should have the correct properties", async () => { - await game.runToMysteryEncounter(defaultParty); + game.override.mysteryEncounter(MysteryEncounterType.LOST_AT_SEA); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); expect(LostAtSeaEncounter.encounterType).toBe(MysteryEncounterType.LOST_AT_SEA); + expect(LostAtSeaEncounter.encounterTier).toBe(MysteryEncounterTier.COMMON); expect(LostAtSeaEncounter.dialogue).toBeDefined(); expect(LostAtSeaEncounter.dialogue.intro).toStrictEqual([{ text: `${namespace}:intro` }]); expect(LostAtSeaEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}:title`); @@ -96,6 +99,10 @@ describe("Lost at Sea - Mystery Encounter", () => { }); describe("Option 1 - Surf", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.LOST_AT_SEA); + }); + it("should have the correct properties", () => { const option1 = LostAtSeaEncounter.options[0]; expect(option1.optionMode).toBe(EncounterOptionMode.DISABLED_OR_DEFAULT); @@ -116,7 +123,7 @@ describe("Lost at Sea - Mystery Encounter", () => { it("should award exp to surfable PKM (Blastoise)", async () => { const laprasSpecies = getPokemonSpecies(Species.LAPRAS); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); const blastoise = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT); const expBefore = blastoise.exp; @@ -130,7 +137,7 @@ describe("Lost at Sea - Mystery Encounter", () => { game.override.startingWave(33); const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); await runSelectMysteryEncounterOption(game, 1); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); @@ -142,6 +149,10 @@ describe("Lost at Sea - Mystery Encounter", () => { }); describe("Option 2 - Fly", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.LOST_AT_SEA); + }); + it("should have the correct properties", () => { const option2 = LostAtSeaEncounter.options[1]; @@ -165,7 +176,7 @@ describe("Lost at Sea - Mystery Encounter", () => { const wave = 33; game.override.startingWave(wave); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); const pidgeot = party.find((pkm) => pkm.species.speciesId === Species.PIDGEOT); const expBefore = pidgeot.exp; @@ -179,7 +190,7 @@ describe("Lost at Sea - Mystery Encounter", () => { game.override.startingWave(33); const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); await runSelectMysteryEncounterOption(game, 2); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); @@ -191,6 +202,10 @@ describe("Lost at Sea - Mystery Encounter", () => { }); describe("Option 3 - Wander aimlessy", () => { + beforeEach(async () => { + game.override.mysteryEncounter(MysteryEncounterType.LOST_AT_SEA); + }); + it("should have the correct properties", () => { const option3 = LostAtSeaEncounter.options[2]; @@ -210,7 +225,7 @@ describe("Lost at Sea - Mystery Encounter", () => { it("should damage all (allowed in battle) party PKM by 25%", async () => { game.override.startingWave(33); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); const party = game.scene.getParty(); const abra = party.find((pkm) => pkm.species.speciesId === Species.ABRA); @@ -231,7 +246,7 @@ describe("Lost at Sea - Mystery Encounter", () => { game.override.startingWave(33); const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); - await game.runToMysteryEncounter(defaultParty); + await game.runToMysteryEncounter(MysteryEncounterType.LOST_AT_SEA, defaultParty); await runSelectMysteryEncounterOption(game, 3); expect(leaveEncounterWithoutBattleSpy).toBeCalled(); diff --git a/src/test/mystery-encounter/mystery-encounter.test.ts b/src/test/mystery-encounter/mystery-encounter.test.ts index cadca89b5e8..ef0b5b3238a 100644 --- a/src/test/mystery-encounter/mystery-encounter.test.ts +++ b/src/test/mystery-encounter/mystery-encounter.test.ts @@ -24,24 +24,18 @@ describe("Mystery Encounters", () => { game.override.startingWave(11); game.override.mysteryEncounterChance(100); game.override.mysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS); - game.override.trainerWave(false); + game.override.disableTrainerWave(true); }); it("Spawns a mystery encounter", async () => { - await game.runToMysteryEncounter([ - Species.CHARIZARD, - Species.VOLCARONA - ]); + await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); }); it("", async () => { - await game.runToMysteryEncounter([ - Species.CHARIZARD, - Species.VOLCARONA - ]); + await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); diff --git a/src/test/phases/mystery-encounter-phase.test.ts b/src/test/phases/mystery-encounter-phase.test.ts index 9fd989e82b8..2a7d3de3700 100644 --- a/src/test/phases/mystery-encounter-phase.test.ts +++ b/src/test/phases/mystery-encounter-phase.test.ts @@ -35,20 +35,14 @@ describe("Mystery Encounter Phases", () => { describe("MysteryEncounterPhase", () => { it("Runs to MysteryEncounterPhase", async() => { - await game.runToMysteryEncounter([ - Species.CHARIZARD, - Species.VOLCARONA - ]); + await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); await game.phaseInterceptor.to(MysteryEncounterPhase, false); expect(game.scene.getCurrentPhase().constructor.name).toBe(MysteryEncounterPhase.name); }); it("Runs MysteryEncounterPhase", async() => { - await game.runToMysteryEncounter([ - Species.CHARIZARD, - Species.VOLCARONA - ]); + await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); game.onNextPrompt("MysteryEncounterPhase", Mode.MYSTERY_ENCOUNTER, () => { // End phase early for test @@ -65,10 +59,7 @@ describe("Mystery Encounter Phases", () => { it("Selects an option for MysteryEncounterPhase", async() => { const dialogueSpy = vi.spyOn(game.scene.ui, "showDialogue"); const messageSpy = vi.spyOn(game.scene.ui, "showText"); - await game.runToMysteryEncounter([ - Species.CHARIZARD, - Species.VOLCARONA - ]); + await game.runToMysteryEncounter(MysteryEncounterType.MYSTERIOUS_CHALLENGERS, [Species.CHARIZARD, Species.VOLCARONA]); game.onNextPrompt("MysteryEncounterPhase", Mode.MESSAGE, () => { const handler = game.scene.ui.getHandler() as MessageUiHandler; diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 1b8c5c383a0..7ccec8113b3 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -36,6 +36,8 @@ import TargetSelectUiHandler from "#app/ui/target-select-ui-handler.js"; import BattleMessageUiHandler from "#app/ui/battle-message-ui-handler"; import {MysteryEncounterPhase} from "#app/phases/mystery-encounter-phases"; import { OverridesHelper } from "./overridesHelper"; +import { expect } from "vitest"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; /** * Class to manage the game state and transitions between phases. @@ -144,10 +146,11 @@ export default class GameManager { /** * Runs the game to a mystery encounter phase. + * @param encounterType - if specified, will expect encounter to have been spawned * @param species - Optional array of species for party. * @returns A promise that resolves when the EncounterPhase ends. */ - async runToMysteryEncounter(species?: Species[]) { + async runToMysteryEncounter(encounterType?: MysteryEncounterType, species?: Species[]) { await this.runToTitle(); this.onNextPrompt("TitlePhase", Mode.TITLE, () => { @@ -164,6 +167,9 @@ export default class GameManager { }, () => this.isCurrentPhase(MysteryEncounterPhase), true); await this.phaseInterceptor.run(EncounterPhase); + if (encounterType) { + expect(this.scene.currentBattle?.mysteryEncounter?.encounterType).toBe(encounterType); + } } /** diff --git a/src/test/utils/overridesHelper.ts b/src/test/utils/overridesHelper.ts index 97caeafd7a6..ff32f41e849 100644 --- a/src/test/utils/overridesHelper.ts +++ b/src/test/utils/overridesHelper.ts @@ -5,6 +5,7 @@ import { MockInstance, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import * as overrides from "#app/overrides"; +import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter"; /** * Helper to handle overrides in tests @@ -28,6 +29,17 @@ export class OverridesHelper { return spy; } + /** + * Override the encounter chance for a mystery encounter. + * @returns spy instance + * @param tier + */ + mysteryEncounterTier(tier: MysteryEncounterTier): MockInstance { + const spy = vi.spyOn(Overrides, "MYSTERY_ENCOUNTER_TIER_OVERRIDE", "get").mockReturnValue(tier); + this.log(`Mystery encounter tier set to ${tier}!`); + return spy; + } + /** * Override the encounter that spawns for the scene * @param encounterType @@ -63,11 +75,11 @@ export class OverridesHelper { /** * Override each wave to have or not have standard trainer battles * @returns spy instance - * @param isTrainer + * @param disable - true */ - trainerWave(isTrainer: boolean): MockInstance { - const spy = vi.spyOn(this.game.scene.gameMode, "isWaveTrainer").mockReturnValue(isTrainer); - this.log(`${isTrainer? "forcing" : "ignoring"} trainer waves!`); + disableTrainerWave(disable: boolean): MockInstance { + const spy = vi.spyOn(this.game.scene.gameMode, "isWaveTrainer").mockReturnValue(!disable); + this.log(`Standard trainer waves are ${disable? "disabled" : "enabled"}!`); return spy; }