From 06331ccdf6a03a7b058fe62ce2468cc5f052a137 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Thu, 26 Sep 2024 04:39:59 -0400 Subject: [PATCH] [Daily] Daily standardization (#3776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Disable Luck in Daily Runs If the Game Mode is Daily Run, the player's Luck is set to 0, and the Luck value is hidden. * Give free map in daily Adds a Map to the player's pool of starting items for Daily Runs. * Disable Eviolite in Daily Runs Disables Eviolite spawning in Daily Run mode. * Write shop test and add new overrides Adds new overrides that allow you to force content to be locked or unlocked These overrides were also added to the OverridesHelper to make them available to tests Adds a new check function for content unlocks, which returns `true` if it is overrode to be unlocked, `false` if it is overrode to be locked, and the unlock data mapped to a Boolean otherwise All existing checks (other than the ones that involve actually unlocking things) for unlockables have been changed to use this Added a pair of new exporting booleans, specifically for my test, that check if Eviolite or Mini Black Hole are in the loot table * Prevent shinies from altering runs Places variant rolls inside of an ExecuteWithSeedOffset block, using the current floor's RNG seed as the seed and the Pokémon's ID as the offset. --------- Co-authored-by: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> --- src/battle-scene.ts | 6 +- src/field/pokemon.ts | 9 ++- src/modifier/modifier-type.ts | 29 +++++++++- src/overrides.ts | 5 +- src/phases/title-phase.ts | 6 +- src/system/game-data.ts | 12 ++++ src/test/daily_mode.test.ts | 68 +++++++++++++++++++++++ src/test/game-mode.test.ts | 2 + src/test/reload.test.ts | 17 +++++- src/test/utils/gameManager.ts | 3 + src/test/utils/helpers/modifiersHelper.ts | 58 +++++++++++++++++++ src/test/utils/helpers/overridesHelper.ts | 32 +++++++++++ src/test/utils/phaseInterceptor.ts | 5 +- src/tutorial.ts | 4 +- 14 files changed, 240 insertions(+), 16 deletions(-) create mode 100644 src/test/utils/helpers/modifiersHelper.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index bbae01bf2f6..6b53ffd6a7f 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1669,7 +1669,11 @@ export default class BattleScene extends SceneBase { this.scoreText.setVisible(this.gameMode.isDaily); } - updateAndShowText(duration: integer): void { + /** + * Displays the current luck value. + * @param duration The time for this label to fade in, if it is not already visible. + */ + updateAndShowText(duration: number): void { const labels = [ this.luckLabelText, this.luckText ]; labels.forEach(t => t.setAlpha(0)); const luckValue = getPartyLuckValue(this.getParty()); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 871c7160cc2..fda4d2226c0 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1914,10 +1914,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!this.shiny || (!variantData.hasOwnProperty(variantDataIndex) && !variantData.hasOwnProperty(this.species.speciesId))) { return 0; } - const rand = Utils.randSeedInt(10); - if (rand >= 4) { + const rand = new Utils.NumberHolder(0); + this.scene.executeWithSeedOffset(() => { + rand.value = Utils.randSeedInt(10); + }, this.id, this.scene.waveSeed); + if (rand.value >= 4) { return 0; // 6/10 - } else if (rand >= 1) { + } else if (rand.value >= 1) { return 1; // 3/10 } else { return 2; // 1/10 diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 8ba3599e72b..9ce555a617e 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1719,7 +1719,8 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.FORM_CHANGE_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 6, 24), new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { - if (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.EVIOLITE]) { + const { gameMode, gameData } = party[0].scene; + if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier) && !p.isMax()) ? 10 : 0; } @@ -1804,7 +1805,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.VOUCHER_PREMIUM, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily && !party[0].scene.gameMode.isEndless && !party[0].scene.gameMode.isSplicedOnly ? Math.max(5 - rerollCount * 2, 0) : 0, 5), new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => !party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, 24), - new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) ? 1 : 0, 1), + new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => (party[0].scene.gameMode.isDaily || (!party[0].scene.gameMode.isFreshStartChallenge() && party[0].scene.gameData.isUnlocked(Unlockables.MINI_BLACK_HOLE))) ? 1 : 0, 1), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }) @@ -1996,9 +1997,16 @@ export function getModifierPoolForType(poolType: ModifierPoolType): ModifierPool } const tierWeights = [ 768 / 1024, 195 / 1024, 48 / 1024, 12 / 1024, 1 / 1024 ]; +/** + * Allows a unit test to check if an item exists in the Modifier Pool. Checks the pool directly, rather than attempting to reroll for the item. + */ +export const itemPoolChecks: Map = new Map(); export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount: integer = 0) { const pool = getModifierPoolForType(poolType); + itemPoolChecks.forEach((v, k) => { + itemPoolChecks.set(k, false); + }); const ignoredIndexes = {}; const modifierTableData = {}; @@ -2035,6 +2043,9 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod ignoredIndexes[t].push(i++); return total; } + if (itemPoolChecks.has(modifierType.modifierType.id as ModifierTypeKeys)) { + itemPoolChecks.set(modifierType.modifierType.id as ModifierTypeKeys, true); + } thresholds.set(total, i++); return total; }, 0); @@ -2437,10 +2448,22 @@ export class ModifierTypeOption { } } +/** + * Calculates the team's luck value. + * @param party The player's party. + * @returns A number between 0 and 14 based on the party's total luck value, or a random number between 0 and 14 if the player is in Daily Run mode. + */ export function getPartyLuckValue(party: Pokemon[]): integer { + if (party[0].scene.gameMode.isDaily) { + const DailyLuck = new Utils.NumberHolder(0); + party[0].scene.executeWithSeedOffset(() => { + DailyLuck.value = Utils.randSeedInt(15); // Random number between 0 and 14 + }, 0, party[0].scene.seed); + return DailyLuck.value; + } const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) .reduce((total: integer, value: integer) => total += value, 0), 0, 14); - return luck || 0; + return luck ?? 0; } export function getLuckString(luckValue: integer): string { diff --git a/src/overrides.ts b/src/overrides.ts index 35ca299721b..852961db8d7 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -12,6 +12,7 @@ import { type PokeballCounts } from "./battle-scene"; import { Gender } from "./data/gender"; import { Variant } from "./data/variant"; import { type ModifierOverride } from "./modifier/modifier-type"; +import { Unlockables } from "./system/unlockables"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -70,8 +71,10 @@ class DefaultOverrides { [PokeballType.MASTER_BALL]: 0, }, }; + /** Forces an item to be UNLOCKED */ + readonly ITEM_UNLOCK_OVERRIDE: Unlockables[] = []; /** Set to `true` to show all tutorials */ - readonly BYPASS_TUTORIAL_SKIP: boolean = false; + readonly BYPASS_TUTORIAL_SKIP_OVERRIDE: boolean = false; // ---------------- // PLAYER OVERRIDES diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index 52503501837..b23a5ec0c89 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -76,7 +76,8 @@ export class TitlePhase extends Phase { this.scene.ui.clearText(); this.end(); }; - if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + const { gameData } = this.scene; + if (gameData.isUnlocked(Unlockables.ENDLESS_MODE)) { const options: OptionSelectItem[] = [ { label: GameMode.getModeName(GameModes.CLASSIC), @@ -100,7 +101,7 @@ export class TitlePhase extends Phase { } } ]; - if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { + if (gameData.isUnlocked(Unlockables.SPLICED_ENDLESS_MODE)) { options.push({ label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), handler: () => { @@ -220,6 +221,7 @@ export class TitlePhase extends Phase { const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier()) .concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier())) + .concat([modifierTypes.MAP().withIdFromFunc(modifierTypes.MAP).newModifier()]) .concat(getDailyRunStarterModifiers(party)) .filter((m) => m !== null); diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 04fef4a81da..22a793e9aca 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -372,6 +372,18 @@ export class GameData { }; } + /** + * Checks if an `Unlockable` has been unlocked. + * @param unlockable The Unlockable to check + * @returns `true` if the player has unlocked this `Unlockable` or an override has enabled it + */ + public isUnlocked(unlockable: Unlockables): boolean { + if (Overrides.ITEM_UNLOCK_OVERRIDE.includes(unlockable)) { + return true; + } + return this.unlocks[unlockable]; + } + public saveSystem(): Promise { return new Promise(resolve => { this.scene.ui.savingIcon.show(); diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 5cc61a62874..58692330272 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,5 +1,12 @@ +import { MapModifier } from "#app/modifier/modifier"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; +import { Moves } from "#app/enums/moves"; +import { Biome } from "#app/enums/biome"; +import { Mode } from "#app/ui/ui"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; + +//const TIMEOUT = 20 * 1000; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -28,5 +35,66 @@ describe("Daily Mode", () => { expect(pkm.level).toBe(20); expect(pkm.moveset.length).toBeGreaterThan(0); }); + expect(game.scene.getModifiers(MapModifier).length).toBeGreaterThan(0); + }); +}); + +describe("Shop modifications", async () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .startingWave(9) + .startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather + .battleType("single") + .startingLevel(100) // Avoid levelling up + .enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents() + .disableTrainerWaves() + .moveset([Moves.KOWTOW_CLEAVE]) + .enemyMoveset(Moves.SPLASH); + game.modifiers + .addCheck("EVIOLITE") + .addCheck("MINI_BLACK_HOLE"); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + game.modifiers.clearChecks(); + }); + + it("should not have Eviolite and Mini Black Hole available in Classic if not unlocked", async () => { + await game.classicMode.startBattle(); + game.move.select(Moves.KOWTOW_CLEAVE); + await game.phaseInterceptor.to("DamagePhase"); + await game.doKillOpponents(); + await game.phaseInterceptor.to("BattleEndPhase"); + game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + game.modifiers + .testCheck("EVIOLITE", false) + .testCheck("MINI_BLACK_HOLE", false); + }); + }); + + it("should have Eviolite and Mini Black Hole available in Daily", async () => { + await game.dailyMode.startBattle(); + game.move.select(Moves.KOWTOW_CLEAVE); + await game.phaseInterceptor.to("DamagePhase"); + await game.doKillOpponents(); + await game.phaseInterceptor.to("BattleEndPhase"); + game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + game.modifiers + .testCheck("EVIOLITE", true) + .testCheck("MINI_BLACK_HOLE", true); + }); }); }); diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index ccec3a3aa16..11994a102af 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -2,6 +2,7 @@ import { GameMode, GameModes, getGameMode } from "#app/game-mode"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as Utils from "../utils"; import GameManager from "./utils/gameManager"; + describe("game-mode", () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -12,6 +13,7 @@ describe("game-mode", () => { }); afterEach(() => { game.phaseInterceptor.restoreOg(); + vi.clearAllMocks(); vi.resetAllMocks(); }); beforeEach(() => { diff --git a/src/test/reload.test.ts b/src/test/reload.test.ts index 7c4523dd9ef..daf8e43a0cd 100644 --- a/src/test/reload.test.ts +++ b/src/test/reload.test.ts @@ -1,9 +1,13 @@ -import { Species } from "#app/enums/species"; import { GameModes } from "#app/game-mode"; +import OptionSelectUiHandler from "#app/ui/settings/option-select-ui-handler"; +import { Mode } from "#app/ui/ui"; +import { Biome } from "#enums/biome"; +import { Button } from "#enums/buttons"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; +import { MockClock } from "#test/utils/mocks/mockClock"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { Moves } from "#app/enums/moves"; -import { Biome } from "#app/enums/biome"; describe("Reload", () => { let phaserGame: Phaser.Game; @@ -50,6 +54,13 @@ describe("Reload", () => { game.move.select(Moves.KOWTOW_CLEAVE); await game.phaseInterceptor.to("DamagePhase"); await game.doKillOpponents(); + game.onNextPrompt("SelectBiomePhase", Mode.OPTION_SELECT, () => { + (game.scene.time as MockClock).overrideDelay = null; + const optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; + game.scene.time.delayedCall(1010, () => optionSelectUiHandler.processInput(Button.ACTION)); + game.endPhase(); + (game.scene.time as MockClock).overrideDelay = 1; + }); await game.toNextWave(); expect(game.phaseInterceptor.log).toContain("NewBiomeEncounterPhase"); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index f48fe3ef228..6fad87df182 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -47,6 +47,7 @@ import { MoveHelper } from "./helpers/moveHelper"; import { OverridesHelper } from "./helpers/overridesHelper"; import { SettingsHelper } from "./helpers/settingsHelper"; import { ReloadHelper } from "./helpers/reloadHelper"; +import { ModifierHelper } from "./helpers/modifiersHelper"; import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import BattleMessageUiHandler from "#app/ui/battle-message-ui-handler"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; @@ -71,6 +72,7 @@ export default class GameManager { public readonly challengeMode: ChallengeModeHelper; public readonly settings: SettingsHelper; public readonly reload: ReloadHelper; + public readonly modifiers: ModifierHelper; /** * Creates an instance of GameManager. @@ -93,6 +95,7 @@ export default class GameManager { this.challengeMode = new ChallengeModeHelper(this); this.settings = new SettingsHelper(this); this.reload = new ReloadHelper(this); + this.modifiers = new ModifierHelper(this); // Disables Mystery Encounters on all tests (can be overridden at test level) this.override.mysteryEncounterChance(0); diff --git a/src/test/utils/helpers/modifiersHelper.ts b/src/test/utils/helpers/modifiersHelper.ts new file mode 100644 index 00000000000..c38bf5770a8 --- /dev/null +++ b/src/test/utils/helpers/modifiersHelper.ts @@ -0,0 +1,58 @@ +import { expect } from "vitest"; +import { GameManagerHelper } from "./gameManagerHelper"; +import { itemPoolChecks, ModifierTypeKeys } from "#app/modifier/modifier-type"; + +export class ModifierHelper extends GameManagerHelper { + /** + * Adds a Modifier to the list of modifiers to check for. + * + * Note that all modifiers are updated during the start of `SelectModifierPhase`. + * @param modifier The Modifier to add. + * @returns `this` + */ + addCheck(modifier: ModifierTypeKeys): this { + itemPoolChecks.set(modifier, undefined); + return this; + } + + /** + * `get`s a value from the `itemPoolChecks` map. + * + * If the item is in the Modifier Pool, and the player can get it, will return `true`. + * + * If the item is *not* in the Modifier Pool, will return `false`. + * + * If a `SelectModifierPhase` has not occurred, and we do not know if the item is in the Modifier Pool or not, will return `undefined`. + * @param modifier + * @returns + */ + getCheck(modifier: ModifierTypeKeys): boolean | undefined { + return itemPoolChecks.get(modifier); + } + + /** + * `expect`s a Modifier `toBeTruthy` (in the Modifier Pool) or `Falsy` (unobtainable on this floor). Use during a test. + * + * Note that if a `SelectModifierPhase` has not been run yet, these values will be `undefined`, and the check will fail. + * @param modifier The modifier to check. + * @param expectToBePreset Whether the Modifier should be in the Modifier Pool. Set to `false` to expect it to be absent instead. + * @returns `this` + */ + testCheck(modifier: ModifierTypeKeys, expectToBePreset: boolean): this { + if (expectToBePreset) { + expect(itemPoolChecks.get(modifier)).toBeTruthy(); + } + expect(itemPoolChecks.get(modifier)).toBeFalsy(); + return this; + } + + /** Removes all modifier checks. @returns `this` */ + clearChecks() { + itemPoolChecks.clear(); + return this; + } + + private log(...params: any[]) { + console.log("Modifiers:", ...params); + } +} diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 686de58e874..84cb1719e0b 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -10,6 +10,8 @@ import { ModifierOverride } from "#app/modifier/modifier-type"; import Overrides from "#app/overrides"; import { vi } from "vitest"; import { GameManagerHelper } from "./gameManagerHelper"; +import { Unlockables } from "#app/system/unlockables"; +import { Variant } from "#app/data/variant"; import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -300,6 +302,17 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Gives the player access to an Unlockable. + * @param unlockable The Unlockable(s) to enable. + * @returns `this` + */ + enableUnlockable(unlockable: Unlockables[]) { + vi.spyOn(Overrides, "ITEM_UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable); + this.log("Temporarily unlocked the following content: ", unlockable); + return this; + } + /** * Override the items rolled at the end of a battle * @param items the items to be rolled @@ -311,6 +324,25 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override player shininess + * @param shininess Whether the player's Pokemon should be shiny. + */ + shinyLevel(shininess: boolean): this { + vi.spyOn(Overrides, "SHINY_OVERRIDE", "get").mockReturnValue(shininess); + this.log(`Set player Pokemon as ${shininess ? "" : "not "}shiny!`); + return this; + } + /** + * Override player shiny variant + * @param variant The player's shiny variant. + */ + variantLevel(variant: Variant): this { + vi.spyOn(Overrides, "VARIANT_OVERRIDE", "get").mockReturnValue(variant); + this.log(`Set player Pokemon's shiny variant to ${variant}!`); + return this; + } + /** * Override the enemy (Pokemon) to have the given amount of health segments * @param healthSegments the number of segments to give diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 46bb757c867..6c4c9a6cf94 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -43,6 +43,7 @@ import { UnavailablePhase } from "#app/phases/unavailable-phase"; import { VictoryPhase } from "#app/phases/victory-phase"; import { PartyHealPhase } from "#app/phases/party-heal-phase"; import UI, { Mode } from "#app/ui/ui"; +import { SelectBiomePhase } from "#app/phases/select-biome-phase"; import { MysteryEncounterBattlePhase, MysteryEncounterOptionSelectedPhase, @@ -122,6 +123,7 @@ export default class PhaseInterceptor { [EndEvolutionPhase, this.startPhase], [LevelCapPhase, this.startPhase], [AttemptRunPhase, this.startPhase], + [SelectBiomePhase, this.startPhase], [MysteryEncounterPhase, this.startPhase], [MysteryEncounterOptionSelectedPhase, this.startPhase], [MysteryEncounterBattlePhase, this.startPhase], @@ -346,7 +348,8 @@ export default class PhaseInterceptor { console.log("setMode", `${Mode[mode]} (=${mode})`, args); const ret = this.originalSetMode.apply(instance, [mode, ...args]); if (!this.phases[currentPhase.constructor.name]) { - throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptor PHASES list`); + throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptor PHASES list --- Add it to PHASES inside of /test/utils/phaseInterceptor.ts`); + } if (this.phases[currentPhase.constructor.name].endBySetMode) { this.inProgress?.callback(); diff --git a/src/tutorial.ts b/src/tutorial.ts index 18d8291d227..3934ffee57f 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -74,11 +74,11 @@ const tutorialHandlers = { * @returns a promise with result `true` if the tutorial was run and finished, `false` otherwise */ export async function handleTutorial(scene: BattleScene, tutorial: Tutorial): Promise { - if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP) { + if (!scene.enableTutorials && !Overrides.BYPASS_TUTORIAL_SKIP_OVERRIDE) { return false; } - if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP) { + if (scene.gameData.getTutorialFlags()[tutorial] && !Overrides.BYPASS_TUTORIAL_SKIP_OVERRIDE) { return false; }