From 0be82b32dd5eeb29fdfee2ee34c54eef31573dd3 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Sun, 18 Aug 2024 12:52:06 -0400 Subject: [PATCH 01/30] Improve scroll bar Remaking these changes on the beta branch since you're supposed to do it for the PR checklist --- src/ui/scroll-bar.ts | 4 ++-- src/ui/starter-select-ui-handler.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/scroll-bar.ts b/src/ui/scroll-bar.ts index 02282edb4cd..e756393ae1a 100644 --- a/src/ui/scroll-bar.ts +++ b/src/ui/scroll-bar.ts @@ -29,8 +29,8 @@ export class ScrollBar extends Phaser.GameObjects.Container { setPages(pages: number): void { this.pages = pages; - this.handleBody.height = (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) / this.pages; + this.handleBody.height = (this.bg.displayHeight - 1 - this.handleBottom.displayHeight) * 9 / this.pages; - this.setVisible(this.pages > 1); + this.setVisible(this.pages > 9); } } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 5e942f3e75a..fcb21f0710b 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2415,7 +2415,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); - this.starterSelectScrollBar.setPages(Math.ceil((this.filteredStarterContainers.length - 81) / 9) + 1); + this.starterSelectScrollBar.setPages(Math.ceil(this.filteredStarterContainers.length / 9)); this.starterSelectScrollBar.setPage(0); // sort From 103ad807ee3da23778c6726862449f6ee2c0898b Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 21 Aug 2024 06:57:59 -0400 Subject: [PATCH 02/30] Fix potential divide by zero error Thank you to KimJeongSun for bringing this up Co-authored-by: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> --- src/ui/starter-select-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index fcb21f0710b..50763ff219c 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2415,7 +2415,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); - this.starterSelectScrollBar.setPages(Math.ceil(this.filteredStarterContainers.length / 9)); + this.starterSelectScrollBar.setPages(Math.max(Math.ceil(this.filteredStarterContainers.length / 9)), 1); this.starterSelectScrollBar.setPage(0); // sort From d1e14850efc6f44dc6184d1f1f94a85ce603488f Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:36:43 -0400 Subject: [PATCH 03/30] Fix parenthases order oops Co-authored-by: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> --- src/ui/starter-select-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 50763ff219c..975cac0b318 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -2415,7 +2415,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); - this.starterSelectScrollBar.setPages(Math.max(Math.ceil(this.filteredStarterContainers.length / 9)), 1); + this.starterSelectScrollBar.setPages(Math.max(Math.ceil(this.filteredStarterContainers.length / 9), 1)); this.starterSelectScrollBar.setPage(0); // sort From 02e9273f974e9f1a110458ec75f7e4dee072713a Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:47:07 -0400 Subject: [PATCH 04/30] 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. --- src/battle-scene.ts | 4 ++-- src/modifier/modifier-type.ts | 4 ++++ src/ui/modifier-select-ui-handler.ts | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 922a145780b..cd85808a509 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1549,7 +1549,7 @@ export default class BattleScene extends SceneBase { this.scoreText.setVisible(this.gameMode.isDaily); } - updateAndShowText(duration: integer): void { + updateAndShowText(duration: integer, isDaily?: boolean): void { const labels = [ this.luckLabelText, this.luckText ]; labels.forEach(t => t.setAlpha(0)); const luckValue = getPartyLuckValue(this.getParty()); @@ -1565,7 +1565,7 @@ export default class BattleScene extends SceneBase { duration: duration, alpha: 1, onComplete: () => { - labels.forEach(t => t.setVisible(true)); + labels.forEach(t => t.setVisible(!isDaily)); } }); } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 365fc433d2f..a481e336c5f 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -28,6 +28,7 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; +import { GameModes } from "#app/game-mode.js"; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -2221,6 +2222,9 @@ export class ModifierTypeOption { } export function getPartyLuckValue(party: Pokemon[]): integer { + if (party[0].scene.gameMode.modeId == GameModes.DAILY) { + return 0 + } const luck = Phaser.Math.Clamp(party.map(p => p.isFainted() ? 0 : p.getLuck()) .reduce((total: integer, value: integer) => total += value, 0), 0, 14); return luck || 0; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 4a567c926d7..f0cd4233a37 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -13,6 +13,7 @@ import * as Utils from "./../utils"; import Overrides from "#app/overrides"; import i18next from "i18next"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; +import { GameModes } from "#app/game-mode.js"; export const SHOP_OPTIONS_ROW_LIMIT = 6; @@ -200,7 +201,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { /* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */ this.scene.showShopOverlay(750 * this.scene.gameSpeed); - this.scene.updateAndShowText(750); + this.scene.updateAndShowText(750, this.scene.gameMode.modeId == GameModes.DAILY); this.scene.updateBiomeWaveText(); this.scene.updateMoneyText(); From 590f1a68339ef6d21fac48c98cede320d6651edf Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:50:20 -0400 Subject: [PATCH 05/30] Give free map in daily Adds a Map to the player's pool of starting items for Daily Runs. --- src/phases/title-phase.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index c74dca97f5c..c755f0c0feb 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -220,6 +220,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); From e4c62e55cfa0c96c703ca479f0ab263416102816 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:52:19 -0400 Subject: [PATCH 06/30] Disable Eviolite in Daily Runs Disables Eviolite spawning in Daily Run mode. --- src/modifier/modifier-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index a481e336c5f..fe3838f1c1c 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1597,7 +1597,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32), 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]) { + if (!party[0].scene.gameMode.isFreshStartChallenge() && !party[0].scene.gameMode.isDaily && party[0].scene.gameData.unlocks[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)) ? 10 : 0; } return 0; From ae33a46945681db8115da7af218e656f44010a0a Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:48:53 -0400 Subject: [PATCH 07/30] Fix formatting == my bebanished --- src/modifier/modifier-type.ts | 4 ++-- src/ui/modifier-select-ui-handler.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index fe3838f1c1c..857dd32261a 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2222,8 +2222,8 @@ export class ModifierTypeOption { } export function getPartyLuckValue(party: Pokemon[]): integer { - if (party[0].scene.gameMode.modeId == GameModes.DAILY) { - return 0 + if (party[0].scene.gameMode.modeId === GameModes.DAILY) { + return 0; } const luck = Phaser.Math.Clamp(party.map(p => p.isFainted() ? 0 : p.getLuck()) .reduce((total: integer, value: integer) => total += value, 0), 0, 14); diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index f0cd4233a37..ec2bca11bdd 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -201,7 +201,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { /* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */ this.scene.showShopOverlay(750 * this.scene.gameSpeed); - this.scene.updateAndShowText(750, this.scene.gameMode.modeId == GameModes.DAILY); + this.scene.updateAndShowText(750, this.scene.gameMode.modeId === GameModes.DAILY); this.scene.updateBiomeWaveText(); this.scene.updateMoneyText(); From 1b558cd94592abae9274a2c6ec6d535ad0c36013 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:04:53 -0400 Subject: [PATCH 08/30] Review Suggestions: Reformatting Small edits to formatting as requested by flx Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> --- src/battle-scene.ts | 2 +- src/modifier/modifier-type.ts | 2 +- src/ui/modifier-select-ui-handler.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index cd85808a509..6f70dbdc66e 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1549,7 +1549,7 @@ export default class BattleScene extends SceneBase { this.scoreText.setVisible(this.gameMode.isDaily); } - updateAndShowText(duration: integer, isDaily?: boolean): void { + updateAndShowText(duration: number, isDaily?: boolean): void { const labels = [ this.luckLabelText, this.luckText ]; labels.forEach(t => t.setAlpha(0)); const luckValue = getPartyLuckValue(this.getParty()); diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 857dd32261a..6350f19ee0f 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -28,7 +28,7 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; -import { GameModes } from "#app/game-mode.js"; +import { GameModes } from "#app/game-mode"; const outputModifierData = false; const useMaxWeightForOutput = false; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index ec2bca11bdd..997f8245577 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -13,7 +13,7 @@ import * as Utils from "./../utils"; import Overrides from "#app/overrides"; import i18next from "i18next"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; -import { GameModes } from "#app/game-mode.js"; +import { GameModes } from "#app/game-mode"; export const SHOP_OPTIONS_ROW_LIMIT = 6; From 9baeac8d40121983d334c135960f8bafb275bebe Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:05:44 -0400 Subject: [PATCH 09/30] Update src/modifier/modifier-type.ts Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com> --- src/modifier/modifier-type.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 6350f19ee0f..406e3e7a651 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1597,7 +1597,8 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32), new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { - if (!party[0].scene.gameMode.isFreshStartChallenge() && !party[0].scene.gameMode.isDaily && party[0].scene.gameData.unlocks[Unlockables.EVIOLITE]) { + const { gameMode, gameData } = party[0].scene; + if (!gameMode.isFreshStartChallenge() && !gameMode.isDaily && gameData.unlocks[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)) ? 10 : 0; } return 0; From 48fbc571cd54a30e681d9f4034597ba7ea06b686 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:09:57 -0400 Subject: [PATCH 10/30] Update modifier-type.ts --- src/modifier/modifier-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 406e3e7a651..36f991fcd7d 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2223,7 +2223,7 @@ export class ModifierTypeOption { } export function getPartyLuckValue(party: Pokemon[]): integer { - if (party[0].scene.gameMode.modeId === GameModes.DAILY) { + if (party[0].scene.gameMode.isDaily) { return 0; } const luck = Phaser.Math.Clamp(party.map(p => p.isFainted() ? 0 : p.getLuck()) From 6225a020e07f1c57190be628e73750d37d027a14 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:13:29 -0400 Subject: [PATCH 11/30] Remove unused import --- src/modifier/modifier-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 36f991fcd7d..0cf3ea66def 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -28,7 +28,6 @@ import { BerryType } from "#enums/berry-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages.js"; -import { GameModes } from "#app/game-mode"; const outputModifierData = false; const useMaxWeightForOutput = false; From e9b06bdf1b4750f4dba727b920796863c72a697a Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:40:53 -0400 Subject: [PATCH 12/30] Try (and fail) to write tests Wrote a check (that might not even work) to make sure the player starts with a Map in the Daily Run Attempted to write a check to see if Eviolite spawns in Daily Run, but can't figure out how to look for the right thing in the loot table Attempted to write a check for shiny luck, but don't know how to manually set luck --- src/modifier/modifier-type.ts | 28 ++++++++++++++++++++++++++-- src/test/daily_mode.test.ts | 12 ++++++++++++ src/test/game-mode.test.ts | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 0cf3ea66def..20835e745f7 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1597,7 +1597,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { const { gameMode, gameData } = party[0].scene; - if (!gameMode.isFreshStartChallenge() && !gameMode.isDaily && gameData.unlocks[Unlockables.EVIOLITE]) { + if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.unlocks[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)) ? 10 : 0; } return 0; @@ -1675,7 +1675,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.MULTI_LENS, 18), 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.unlocks[Unlockables.MINI_BLACK_HOLE])) ? 1 : 0, 1), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }) @@ -2090,6 +2090,30 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P return ret; } +/* +export function getModifierThresholdPool(poolType: ModifierPoolType) { + let thresholds: {} + switch (poolType) { + case ModifierPoolType.PLAYER: + thresholds = modifierPoolThresholds; + break; + case ModifierPoolType.WILD: + thresholds = enemyModifierPoolThresholds; + break; + case ModifierPoolType.TRAINER: + thresholds = enemyModifierPoolThresholds; + break; + case ModifierPoolType.ENEMY_BUFF: + thresholds = enemyBuffModifierPoolThresholds; + break; + case ModifierPoolType.DAILY_STARTER: + thresholds = dailyStarterModifierPoolThresholds; + break; + } + return thresholds; +} +*/ + function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0): ModifierTypeOption | null { const player = !poolType; const pool = getModifierPoolForType(poolType); diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 5cc61a62874..ebc19c0b6de 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,5 +1,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; +import { MapModifier } from "#app/modifier/modifier.js"; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -28,5 +29,16 @@ describe("Daily Mode", () => { expect(pkm.level).toBe(20); expect(pkm.moveset.length).toBeGreaterThan(0); }); + expect(game.scene.getModifiers(MapModifier).length).toBeGreaterThan(0); }); + + /* + Can't figure out how to check the shop's item pool :( + describe("Shop modifications", async () => { + const modifierPhase = new SelectModifierPhase(game.scene); + game.scene.unshiftPhase(modifierPhase); + await game.phaseInterceptor.run(SelectModifierPhase); + expect(getModifierThresholdPool(ModifierPoolType.PLAYER)); + }); + */ }); diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index ccec3a3aa16..b3f014d0154 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -41,4 +41,22 @@ describe("game-mode", () => { expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy(); }); }); + /* + Need to figure out how to override my party members' luck to calculate this + describe("Luck Check", async () => { + let classicGameMode: GameMode; + let dailyGameMode: GameMode; + beforeEach(() => { + classicGameMode = getGameMode(GameModes.CLASSIC); + dailyGameMode = getGameMode(GameModes.DAILY); + }); + const party = game.scene.getParty(); + const oldmode = game.scene.gameMode; + game.scene.gameMode = classicGameMode!; + expect(getPartyLuckValue(party)).toBe(3); + game.scene.gameMode = dailyGameMode!; + expect(getPartyLuckValue(party)).toBe(0); + game.scene.gameMode = oldmode; + }) + */ }); From f5b49d812d9858b3541c5ff5a3996598b3675344 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:56:26 -0400 Subject: [PATCH 13/30] 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 please forgive my jank --- src/modifier/modifier-type.ts | 16 +++++++-- src/overrides.ts | 5 +++ src/phases/title-phase.ts | 6 ++-- src/system/unlockables.ts | 12 +++++++ src/test/daily_mode.test.ts | 44 +++++++++++++++++++---- src/test/utils/helpers/overridesHelper.ts | 13 +++++++ 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 20835e745f7..e2c1420565c 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -10,7 +10,7 @@ import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from ".. import * as Utils from "../utils"; import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from "../data/temp-battle-stat"; import { getBerryEffectDescription, getBerryName } from "../data/berry"; -import { Unlockables } from "../system/unlockables"; +import { isUnlocked, Unlockables } from "../system/unlockables"; import { StatusEffect, getStatusEffectDescriptor } from "../data/status-effect"; import { SpeciesFormKey } from "../data/pokemon-species"; import BattleScene from "../battle-scene"; @@ -1597,7 +1597,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { const { gameMode, gameData } = party[0].scene; - if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.unlocks[Unlockables.EVIOLITE])) { + if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && isUnlocked(Unlockables.EVIOLITE, gameData))) { 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)) ? 10 : 0; } return 0; @@ -1675,7 +1675,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.MULTI_LENS, 18), 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.isDaily || (!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() && isUnlocked(Unlockables.MINI_BLACK_HOLE, party[0].scene.gameData))) ? 1 : 0, 1), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }) @@ -1867,9 +1867,13 @@ export function getModifierPoolForType(poolType: ModifierPoolType): ModifierPool } const tierWeights = [ 768 / 1024, 195 / 1024, 48 / 1024, 12 / 1024, 1 / 1024 ]; +export let poolHasEviolite: boolean = false; +export let poolHasBlackHole: boolean = false; export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount: integer = 0) { const pool = getModifierPoolForType(poolType); + poolHasEviolite = false; + poolHasBlackHole = false; const ignoredIndexes = {}; const modifierTableData = {}; @@ -1906,6 +1910,12 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod ignoredIndexes[t].push(i++); return total; } + if (modifierType.modifierType.id === "EVIOLITE") { + poolHasEviolite = true; + } + if (modifierType.modifierType.id === "MINI_BLACK_HOLE") { + poolHasBlackHole = true; + } thresholds.set(total, i++); return total; }, 0); diff --git a/src/overrides.ts b/src/overrides.ts index 8b3d628e05e..811461a3c60 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -13,6 +13,7 @@ import { Gender } from "./data/gender"; import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars import { Variant } from "./data/variant"; import { type ModifierOverride } from "./modifier/modifier-type"; +import { Unlockables } from "./system/unlockables"; /** * Overrides that are using when testing different in game situations @@ -69,6 +70,10 @@ class DefaultOverrides { [PokeballType.MASTER_BALL]: 0, }, }; + /** Forces an item to be UNLOCKED */ + readonly UNLOCK_OVERRIDE: Unlockables[] = []; + /** Forces an item to be NOT UNLOCKED */ + readonly DISABLE_UNLOCK_OVERRIDE: Unlockables[] = []; // ---------------- // PLAYER OVERRIDES diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index c755f0c0feb..023fd382558 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -8,7 +8,7 @@ import { GameModes, GameMode, getGameMode } from "#app/game-mode.js"; import { regenerateModifierPoolThresholds, ModifierPoolType, modifierTypes, getDailyRunStarterModifiers } from "#app/modifier/modifier-type.js"; import { Phase } from "#app/phase.js"; import { SessionSaveData } from "#app/system/game-data.js"; -import { Unlockables } from "#app/system/unlockables.js"; +import { isUnlocked, Unlockables } from "#app/system/unlockables.js"; import { vouchers } from "#app/system/voucher.js"; import { OptionSelectItem, OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler.js"; import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler.js"; @@ -76,7 +76,7 @@ export class TitlePhase extends Phase { this.scene.ui.clearText(); this.end(); }; - if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + if (isUnlocked(Unlockables.ENDLESS_MODE, this.scene.gameData)) { const options: OptionSelectItem[] = [ { label: GameMode.getModeName(GameModes.CLASSIC), @@ -100,7 +100,7 @@ export class TitlePhase extends Phase { } } ]; - if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { + if (isUnlocked(Unlockables.SPLICED_ENDLESS_MODE, this.scene.gameData)) { options.push({ label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), handler: () => { diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index 983909373fd..81f390afdb0 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -1,5 +1,7 @@ import i18next from "i18next"; import { GameMode, GameModes } from "../game-mode"; +import Overrides from "#app/overrides"; +import { GameData } from "./game-data"; export enum Unlockables { ENDLESS_MODE, @@ -8,6 +10,16 @@ export enum Unlockables { EVIOLITE } +export function isUnlocked(unlockable: Unlockables, gameData: GameData): boolean { + if (Overrides.UNLOCK_OVERRIDE.includes(unlockable)) { + return true; + } + if (Overrides.DISABLE_UNLOCK_OVERRIDE.includes(unlockable)) { + return false; + } + return !!gameData.unlocks[Unlockables.MINI_BLACK_HOLE]; +} + export function getUnlockableName(unlockable: Unlockables) { switch (unlockable) { case Unlockables.ENDLESS_MODE: diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index ebc19c0b6de..6ddabae3285 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,6 +1,11 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; import { MapModifier } from "#app/modifier/modifier.js"; +import { SelectModifierPhase } from "../phases/select-modifier-phase"; +import { Moves } from "#app/enums/moves.js"; +import { Abilities } from "#app/enums/abilities.js"; +import { Unlockables } from "#app/system/unlockables.js"; +import { poolHasEviolite, poolHasBlackHole } from "#app/modifier/modifier-type.js"; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -32,13 +37,38 @@ describe("Daily Mode", () => { expect(game.scene.getModifiers(MapModifier).length).toBeGreaterThan(0); }); - /* - Can't figure out how to check the shop's item pool :( describe("Shop modifications", async () => { - const modifierPhase = new SelectModifierPhase(game.scene); - game.scene.unshiftPhase(modifierPhase); - await game.phaseInterceptor.run(SelectModifierPhase); - expect(getModifierThresholdPool(ModifierPoolType.PLAYER)); + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .startingLevel(200) + .moveset([Moves.SURF]) + .enemyAbility(Abilities.BALL_FETCH) + .startingModifier([{ name: "LOCK_CAPSULE" }]) + .lockUnlockable([Unlockables.MINI_BLACK_HOLE, Unlockables.EVIOLITE]); + }); + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { + await game.classicMode.runToSummon(); + await game.startBattle(); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to(SelectModifierPhase, false); + expect(poolHasEviolite).toBeFalsy(); + expect(poolHasBlackHole).toBeFalsy(); + }); + it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { + await game.dailyMode.runToSummon(); + await game.startBattle(); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to(SelectModifierPhase, false); + expect(poolHasEviolite).toBeTruthy(); + expect(poolHasBlackHole).toBeTruthy(); + }); }); - */ }); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index d5eaee003db..505641e7e06 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -10,6 +10,7 @@ import { ModifierOverride } from "#app/modifier/modifier-type.js"; import Overrides from "#app/overrides"; import { vi } from "vitest"; import { GameManagerHelper } from "./gameManagerHelper"; +import { Unlockables } from "#app/system/unlockables.js"; /** * Helper to handle overrides in tests @@ -281,6 +282,18 @@ export class OverridesHelper extends GameManagerHelper { return this; } + unlockUnlockable(unlockable: Unlockables[]) { + vi.spyOn(Overrides, "UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable); + this.log("Temporarily unlocked the following content: ", unlockable); + return this; + } + + lockUnlockable(unlockable: Unlockables[]) { + vi.spyOn(Overrides, "DISABLE_UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable); + this.log("Temporarily re-locked the following content: ", unlockable); + return this; + } + private log(...params: any[]) { console.log("Overrides:", ...params); } From 3095ecebf8abc5adf7e524718a4d4e999166c6c8 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:09:26 -0400 Subject: [PATCH 14/30] Update src/system/unlockables.ts Fixing my silly typo Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> --- src/system/unlockables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index 81f390afdb0..80a12e2df11 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -17,7 +17,7 @@ export function isUnlocked(unlockable: Unlockables, gameData: GameData): boolean if (Overrides.DISABLE_UNLOCK_OVERRIDE.includes(unlockable)) { return false; } - return !!gameData.unlocks[Unlockables.MINI_BLACK_HOLE]; + return gameData.unlocks[unlockable]; } export function getUnlockableName(unlockable: Unlockables) { From d7263b66779caebd3d312eccf0759b5467d4f1de Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 14:09:48 -0400 Subject: [PATCH 15/30] Update src/modifier/modifier-type.ts Remove unused code I forgot to delete Co-authored-by: Amani H. <109637146+xsn34kzx@users.noreply.github.com> --- src/modifier/modifier-type.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index e2c1420565c..993ff652321 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -2100,30 +2100,6 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P return ret; } -/* -export function getModifierThresholdPool(poolType: ModifierPoolType) { - let thresholds: {} - switch (poolType) { - case ModifierPoolType.PLAYER: - thresholds = modifierPoolThresholds; - break; - case ModifierPoolType.WILD: - thresholds = enemyModifierPoolThresholds; - break; - case ModifierPoolType.TRAINER: - thresholds = enemyModifierPoolThresholds; - break; - case ModifierPoolType.ENEMY_BUFF: - thresholds = enemyBuffModifierPoolThresholds; - break; - case ModifierPoolType.DAILY_STARTER: - thresholds = dailyStarterModifierPoolThresholds; - break; - } - return thresholds; -} -*/ - function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0): ModifierTypeOption | null { const player = !poolType; const pool = getModifierPoolForType(poolType); From 3e65888ff1e8650232353aa3bb05e2fd24e3ad1f Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:54:09 -0400 Subject: [PATCH 16/30] Update overrides Relocated the "isUnlocked" function to gameData since it requires a reference to it in order to run Removed unnecessary override that disables unlocked items (and its associated overridesHelper statement) --- src/modifier/modifier-type.ts | 6 +++--- src/overrides.ts | 2 -- src/phases/title-phase.ts | 6 +++--- src/system/game-data.ts | 6 ++++++ src/system/unlockables.ts | 12 ------------ src/test/daily_mode.test.ts | 12 ++++++++---- src/test/utils/helpers/overridesHelper.ts | 6 ------ 7 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 993ff652321..ec4814a56a6 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -10,7 +10,7 @@ import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from ".. import * as Utils from "../utils"; import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from "../data/temp-battle-stat"; import { getBerryEffectDescription, getBerryName } from "../data/berry"; -import { isUnlocked, Unlockables } from "../system/unlockables"; +import { Unlockables } from "../system/unlockables"; import { StatusEffect, getStatusEffectDescriptor } from "../data/status-effect"; import { SpeciesFormKey } from "../data/pokemon-species"; import BattleScene from "../battle-scene"; @@ -1597,7 +1597,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { const { gameMode, gameData } = party[0].scene; - if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && isUnlocked(Unlockables.EVIOLITE, gameData))) { + 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)) ? 10 : 0; } return 0; @@ -1675,7 +1675,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.MULTI_LENS, 18), 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.isDaily || (!party[0].scene.gameMode.isFreshStartChallenge() && isUnlocked(Unlockables.MINI_BLACK_HOLE, party[0].scene.gameData))) ? 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; }) diff --git a/src/overrides.ts b/src/overrides.ts index 811461a3c60..ed1af8ab35e 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -72,8 +72,6 @@ class DefaultOverrides { }; /** Forces an item to be UNLOCKED */ readonly UNLOCK_OVERRIDE: Unlockables[] = []; - /** Forces an item to be NOT UNLOCKED */ - readonly DISABLE_UNLOCK_OVERRIDE: Unlockables[] = []; // ---------------- // PLAYER OVERRIDES diff --git a/src/phases/title-phase.ts b/src/phases/title-phase.ts index 023fd382558..55879e52bdb 100644 --- a/src/phases/title-phase.ts +++ b/src/phases/title-phase.ts @@ -8,7 +8,7 @@ import { GameModes, GameMode, getGameMode } from "#app/game-mode.js"; import { regenerateModifierPoolThresholds, ModifierPoolType, modifierTypes, getDailyRunStarterModifiers } from "#app/modifier/modifier-type.js"; import { Phase } from "#app/phase.js"; import { SessionSaveData } from "#app/system/game-data.js"; -import { isUnlocked, Unlockables } from "#app/system/unlockables.js"; +import { Unlockables } from "#app/system/unlockables.js"; import { vouchers } from "#app/system/voucher.js"; import { OptionSelectItem, OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler.js"; import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler.js"; @@ -76,7 +76,7 @@ export class TitlePhase extends Phase { this.scene.ui.clearText(); this.end(); }; - if (isUnlocked(Unlockables.ENDLESS_MODE, this.scene.gameData)) { + if (this.scene.gameData.isUnlocked(Unlockables.ENDLESS_MODE)) { const options: OptionSelectItem[] = [ { label: GameMode.getModeName(GameModes.CLASSIC), @@ -100,7 +100,7 @@ export class TitlePhase extends Phase { } } ]; - if (isUnlocked(Unlockables.SPLICED_ENDLESS_MODE, this.scene.gameData)) { + if (this.scene.gameData.isUnlocked(Unlockables.SPLICED_ENDLESS_MODE)) { options.push({ label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), handler: () => { diff --git a/src/system/game-data.ts b/src/system/game-data.ts index e7bc85d9037..90b80c87415 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -364,6 +364,12 @@ export class GameData { unlockPity: this.unlockPity.slice(0) }; } + public isUnlocked(unlockable: Unlockables): boolean { + if (Overrides.UNLOCK_OVERRIDE.includes(unlockable)) { + return true; + } + return this.unlocks[unlockable]; + } public saveSystem(): Promise { return new Promise(resolve => { diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index 80a12e2df11..983909373fd 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -1,7 +1,5 @@ import i18next from "i18next"; import { GameMode, GameModes } from "../game-mode"; -import Overrides from "#app/overrides"; -import { GameData } from "./game-data"; export enum Unlockables { ENDLESS_MODE, @@ -10,16 +8,6 @@ export enum Unlockables { EVIOLITE } -export function isUnlocked(unlockable: Unlockables, gameData: GameData): boolean { - if (Overrides.UNLOCK_OVERRIDE.includes(unlockable)) { - return true; - } - if (Overrides.DISABLE_UNLOCK_OVERRIDE.includes(unlockable)) { - return false; - } - return gameData.unlocks[unlockable]; -} - export function getUnlockableName(unlockable: Unlockables) { switch (unlockable) { case Unlockables.ENDLESS_MODE: diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 6ddabae3285..e1e9b6ace95 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -4,8 +4,8 @@ import { MapModifier } from "#app/modifier/modifier.js"; import { SelectModifierPhase } from "../phases/select-modifier-phase"; import { Moves } from "#app/enums/moves.js"; import { Abilities } from "#app/enums/abilities.js"; -import { Unlockables } from "#app/system/unlockables.js"; import { poolHasEviolite, poolHasBlackHole } from "#app/modifier/modifier-type.js"; +import { TitlePhase } from "#app/phases/title-phase.js"; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -45,14 +45,15 @@ describe("Daily Mode", () => { .battleType("single") .startingLevel(200) .moveset([Moves.SURF]) - .enemyAbility(Abilities.BALL_FETCH) - .startingModifier([{ name: "LOCK_CAPSULE" }]) - .lockUnlockable([Unlockables.MINI_BLACK_HOLE, Unlockables.EVIOLITE]); + .enemyAbility(Abilities.BALL_FETCH); }); afterEach(() => { game.phaseInterceptor.restoreOg(); }); it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { + const titlePhase = new TitlePhase(game.scene); + game.scene.unshiftPhase(titlePhase); + await game.phaseInterceptor.run(TitlePhase); await game.classicMode.runToSummon(); await game.startBattle(); @@ -62,6 +63,9 @@ describe("Daily Mode", () => { expect(poolHasBlackHole).toBeFalsy(); }); it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { + const titlePhase = new TitlePhase(game.scene); + game.scene.unshiftPhase(titlePhase); + await game.phaseInterceptor.run(TitlePhase); await game.dailyMode.runToSummon(); await game.startBattle(); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 505641e7e06..cbae9d1ead1 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -288,12 +288,6 @@ export class OverridesHelper extends GameManagerHelper { return this; } - lockUnlockable(unlockable: Unlockables[]) { - vi.spyOn(Overrides, "DISABLE_UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable); - this.log("Temporarily re-locked the following content: ", unlockable); - return this; - } - private log(...params: any[]) { console.log("Overrides:", ...params); } From 49036f95223052a720c93a414b1f1597b1954b1f Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:28:27 -0400 Subject: [PATCH 17/30] More testing attempts please help me --- src/test/daily_mode.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index e1e9b6ace95..f0a1dc5cfe0 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -5,7 +5,6 @@ import { SelectModifierPhase } from "../phases/select-modifier-phase"; import { Moves } from "#app/enums/moves.js"; import { Abilities } from "#app/enums/abilities.js"; import { poolHasEviolite, poolHasBlackHole } from "#app/modifier/modifier-type.js"; -import { TitlePhase } from "#app/phases/title-phase.js"; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -51,9 +50,6 @@ describe("Daily Mode", () => { game.phaseInterceptor.restoreOg(); }); it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { - const titlePhase = new TitlePhase(game.scene); - game.scene.unshiftPhase(titlePhase); - await game.phaseInterceptor.run(TitlePhase); await game.classicMode.runToSummon(); await game.startBattle(); @@ -63,9 +59,6 @@ describe("Daily Mode", () => { expect(poolHasBlackHole).toBeFalsy(); }); it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { - const titlePhase = new TitlePhase(game.scene); - game.scene.unshiftPhase(titlePhase); - await game.phaseInterceptor.run(TitlePhase); await game.dailyMode.runToSummon(); await game.startBattle(); From b71ddda1916257b83557cb5c9ec705eab104b30c Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:52:07 -0400 Subject: [PATCH 18/30] (Temporary) Implement startBattle fix --- src/test/daily_mode.test.ts | 6 ++--- src/test/utils/gameManager.ts | 21 +++++++++------ src/test/utils/helpers/classicModeHelper.ts | 27 +++++++++++++++++++ src/test/utils/helpers/dailyModeHelper.ts | 29 ++++++++++++++++++++- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index f0a1dc5cfe0..5947e010cbb 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -50,8 +50,7 @@ describe("Daily Mode", () => { game.phaseInterceptor.restoreOg(); }); it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { - await game.classicMode.runToSummon(); - await game.startBattle(); + await game.classicMode.startBattle(); game.move.select(Moves.SURF); await game.phaseInterceptor.to(SelectModifierPhase, false); @@ -59,8 +58,7 @@ describe("Daily Mode", () => { expect(poolHasBlackHole).toBeFalsy(); }); it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { - await game.dailyMode.runToSummon(); - await game.startBattle(); + await game.dailyMode.startBattle(); game.move.select(Moves.SURF); await game.phaseInterceptor.to(SelectModifierPhase, false); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index cb3c547744b..d3c2652fcbe 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -1,6 +1,7 @@ import { updateUserInfo } from "#app/account"; import { BattlerIndex } from "#app/battle"; import BattleScene from "#app/battle-scene"; +import { BattleStyle } from "#app/enums/battle-style"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import Trainer from "#app/field/trainer"; import { GameModes, getGameMode } from "#app/game-mode"; @@ -170,6 +171,8 @@ export default class GameManager { } /** + * @deprecated Use `game.classicMode.startBattle()` or `game.dailyMode.startBattle()` instead + * * Transitions to the start of a battle. * @param species - Optional array of species to start the battle with. * @returns A promise that resolves when the battle is started. @@ -177,15 +180,17 @@ export default class GameManager { async startBattle(species?: Species[]) { await this.classicMode.runToSummon(species); - this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); - this.endPhase(); - }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); + if (this.scene.battleStyle === BattleStyle.SWITCH) { + this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.setMode(Mode.MESSAGE); + this.endPhase(); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); - this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { - this.setMode(Mode.MESSAGE); - this.endPhase(); - }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); + this.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.setMode(Mode.MESSAGE); + this.endPhase(); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnInitPhase)); + } await this.phaseInterceptor.to(CommandPhase); console.log("==================[New Turn]=================="); diff --git a/src/test/utils/helpers/classicModeHelper.ts b/src/test/utils/helpers/classicModeHelper.ts index f41472303b4..55e995fc9dc 100644 --- a/src/test/utils/helpers/classicModeHelper.ts +++ b/src/test/utils/helpers/classicModeHelper.ts @@ -1,8 +1,11 @@ +import { BattleStyle } from "#app/enums/battle-style"; import { Species } from "#app/enums/species"; import { GameModes, getGameMode } from "#app/game-mode"; import overrides from "#app/overrides"; +import { CommandPhase } from "#app/phases/command-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { SelectStarterPhase } from "#app/phases/select-starter-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import { Mode } from "#app/ui/ui"; import { generateStarter } from "../gameManagerUtils"; import { GameManagerHelper } from "./gameManagerHelper"; @@ -33,4 +36,28 @@ export class ClassicModeHelper extends GameManagerHelper { this.game.removeEnemyHeldItems(); } } + + /** + * Transitions to the start of a battle. + * @param species - Optional array of species to start the battle with. + * @returns A promise that resolves when the battle is started. + */ + async startBattle(species?: Species[]) { + await this.runToSummon(species); + + if (this.game.scene.battleStyle === BattleStyle.SWITCH) { + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + } + + await this.game.phaseInterceptor.to(CommandPhase); + console.log("==================[New Turn]=================="); + } } diff --git a/src/test/utils/helpers/dailyModeHelper.ts b/src/test/utils/helpers/dailyModeHelper.ts index 8f60981f4d8..c535533c9e7 100644 --- a/src/test/utils/helpers/dailyModeHelper.ts +++ b/src/test/utils/helpers/dailyModeHelper.ts @@ -1,7 +1,11 @@ + +import { BattleStyle } from "#app/enums/battle-style"; import { Button } from "#app/enums/buttons"; import overrides from "#app/overrides"; +import { CommandPhase } from "#app/phases/command-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { TitlePhase } from "#app/phases/title-phase"; +import { TurnInitPhase } from "#app/phases/turn-init-phase"; import SaveSlotSelectUiHandler from "#app/ui/save-slot-select-ui-handler"; import { Mode } from "#app/ui/ui"; import { GameManagerHelper } from "./gameManagerHelper"; @@ -28,10 +32,33 @@ export class DailyModeHelper extends GameManagerHelper { uihandler.processInput(Button.ACTION); // select first slot. that's fine }); - await this.game.phaseInterceptor.run(EncounterPhase); + await this.game.phaseInterceptor.to(EncounterPhase); if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { this.game.removeEnemyHeldItems(); } } + + /** + * Transitions to the start of a battle. + * @returns A promise that resolves when the battle is started. + */ + async startBattle() { + await this.runToSummon(); + + if (this.game.scene.battleStyle === BattleStyle.SWITCH) { + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + + this.game.onNextPrompt("CheckSwitchPhase", Mode.CONFIRM, () => { + this.game.setMode(Mode.MESSAGE); + this.game.endPhase(); + }, () => this.game.isCurrentPhase(CommandPhase) || this.game.isCurrentPhase(TurnInitPhase)); + } + + await this.game.phaseInterceptor.to(CommandPhase); + console.log("==================[New Turn]=================="); + } } From 6373a8601133e27b3e6b5221585f871a95835d8d Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 1 Sep 2024 01:13:37 -0700 Subject: [PATCH 19/30] Fix tests --- src/test/daily_mode.test.ts | 76 +++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 5947e010cbb..ecbb756ca0e 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,10 +1,11 @@ +import { Abilities } from "#app/enums/abilities"; +import { Moves } from "#app/enums/moves"; +import { MapModifier } from "#app/modifier/modifier"; +import { poolHasBlackHole, poolHasEviolite } from "#app/modifier/modifier-type"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; -import { MapModifier } from "#app/modifier/modifier.js"; -import { SelectModifierPhase } from "../phases/select-modifier-phase"; -import { Moves } from "#app/enums/moves.js"; -import { Abilities } from "#app/enums/abilities.js"; -import { poolHasEviolite, poolHasBlackHole } from "#app/modifier/modifier-type.js"; + +const TIMEOUT = 20 * 1000; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -35,35 +36,46 @@ describe("Daily Mode", () => { }); expect(game.scene.getModifiers(MapModifier).length).toBeGreaterThan(0); }); +}); - describe("Shop modifications", async () => { - beforeEach(() => { - game = new GameManager(phaserGame); +describe("Shop modifications", async () => { + let phaserGame: Phaser.Game; + let game: GameManager; - game.override - .battleType("single") - .startingLevel(200) - .moveset([Moves.SURF]) - .enemyAbility(Abilities.BALL_FETCH); - }); - afterEach(() => { - game.phaseInterceptor.restoreOg(); - }); - it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { - await game.classicMode.startBattle(); - - game.move.select(Moves.SURF); - await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(poolHasEviolite).toBeFalsy(); - expect(poolHasBlackHole).toBeFalsy(); - }); - it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { - await game.dailyMode.startBattle(); - - game.move.select(Moves.SURF); - await game.phaseInterceptor.to(SelectModifierPhase, false); - expect(poolHasEviolite).toBeTruthy(); - expect(poolHasBlackHole).toBeTruthy(); + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, }); }); + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override + .battleType("single") + .startingLevel(200) + .moveset([Moves.SURF]) + .enemyAbility(Abilities.BALL_FETCH); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { + await game.classicMode.startBattle(); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to("SelectModifierPhase", false); + expect(poolHasEviolite).toBeFalsy(); + expect(poolHasBlackHole).toBeFalsy(); + }, TIMEOUT); + + it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { + await game.dailyMode.startBattle(); + + game.move.select(Moves.SURF); + await game.phaseInterceptor.to("SelectModifierPhase", false); + expect(poolHasEviolite).toBeTruthy(); + expect(poolHasBlackHole).toBeTruthy(); + }, TIMEOUT); }); From 103c87ec3b5014cf89b0692402b3f1fe66bbdbfc Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Thu, 12 Sep 2024 01:09:44 +0100 Subject: [PATCH 20/30] Undo egg skip event --- src/modifier/modifier-type.ts | 5 +---- src/phases/trainer-victory-phase.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index f7041d55be3..20047e5b81b 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1545,7 +1545,6 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.TEMP_STAT_STAGE_BOOSTER, 4), new WeightedModifierType(modifierTypes.BERRY, 2), new WeightedModifierType(modifierTypes.TM_COMMON, 2), - new WeightedModifierType(modifierTypes.VOUCHER, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0, 1), ].map(m => { m.setTier(ModifierTier.COMMON); return m; }), @@ -1616,7 +1615,6 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3), new WeightedModifierType(modifierTypes.TERA_SHARD, 1), new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 4 : 0), - new WeightedModifierType(modifierTypes.VOUCHER, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily ? Math.max(3 - rerollCount * 3, 0) : 0, 3), ].map(m => { m.setTier(ModifierTier.GREAT); return m; }), @@ -1697,7 +1695,6 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.RARE_FORM_CHANGE_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 6, 24), new WeightedModifierType(modifierTypes.MEGA_BRACELET, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 9, 36), new WeightedModifierType(modifierTypes.DYNAMAX_BAND, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 9, 36), - new WeightedModifierType(modifierTypes.VOUCHER_PLUS, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily ? Math.max(9 - rerollCount * 3, 0) : 0, 9), ].map(m => { m.setTier(ModifierTier.ROGUE); return m; }), @@ -1706,7 +1703,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.SHINY_CHARM, 14), new WeightedModifierType(modifierTypes.HEALING_CHARM, 18), new WeightedModifierType(modifierTypes.MULTI_LENS, 18), - 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(15 - rerollCount * 5, 0) : 0, 15), + 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), ].map(m => { diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts index 7815244c35c..a38874c9acd 100644 --- a/src/phases/trainer-victory-phase.ts +++ b/src/phases/trainer-victory-phase.ts @@ -30,7 +30,7 @@ export class TrainerVictoryPhase extends BattlePhase { const trainerType = this.scene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? if (vouchers.hasOwnProperty(TrainerType[trainerType])) { if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer?.config.isBoss) { - this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][vouchers[TrainerType[trainerType]].voucherType])); + this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][vouchers[TrainerType[trainerType]].voucherType])); } } From 801b0a66f715584aa3a61ce3c6684093c58c6f10 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Thu, 12 Sep 2024 01:13:22 +0100 Subject: [PATCH 21/30] Readded vouchers to original weights --- src/modifier/modifier-type.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 20047e5b81b..d6cfd017829 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1615,6 +1615,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3), new WeightedModifierType(modifierTypes.TERA_SHARD, 1), new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 4 : 0), + new WeightedModifierType(modifierTypes.VOUCHER, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily ? Math.max(1 - rerollCount, 0) : 0, 1), ].map(m => { m.setTier(ModifierTier.GREAT); return m; }), @@ -1695,6 +1696,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.RARE_FORM_CHANGE_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 6, 24), new WeightedModifierType(modifierTypes.MEGA_BRACELET, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 9, 36), new WeightedModifierType(modifierTypes.DYNAMAX_BAND, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 50), 4) * 9, 36), + new WeightedModifierType(modifierTypes.VOUCHER_PLUS, (party: Pokemon[], rerollCount: integer) => !party[0].scene.gameMode.isDaily ? Math.max(3 - rerollCount * 1, 0) : 0, 3), ].map(m => { m.setTier(ModifierTier.ROGUE); return m; }), From 0114d795a5f70ffc520dfd71f6a9c5b7f6f41d01 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:35:04 -0400 Subject: [PATCH 22/30] Tests I forgot what desc I wrote this morning but here you go Still working on this, but will submit now to show my work --- src/modifier/modifier-type.ts | 15 ++++----- src/test/daily_mode.test.ts | 20 +++++++++--- src/test/game-mode.test.ts | 40 ++++++++++++++++------- src/test/utils/helpers/overridesHelper.ts | 26 +++++++++++++-- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index f04e17b9068..1ef8bceb486 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1900,13 +1900,13 @@ export function getModifierPoolForType(poolType: ModifierPoolType): ModifierPool } const tierWeights = [ 768 / 1024, 195 / 1024, 48 / 1024, 12 / 1024, 1 / 1024 ]; -export let poolHasEviolite: boolean = false; -export let poolHasBlackHole: boolean = false; +export const itemPoolChecks: Map = new Map(); export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount: integer = 0) { const pool = getModifierPoolForType(poolType); - poolHasEviolite = false; - poolHasBlackHole = false; + itemPoolChecks.forEach((v, k) => { + itemPoolChecks.set(k, false); + }); const ignoredIndexes = {}; const modifierTableData = {}; @@ -1943,11 +1943,8 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod ignoredIndexes[t].push(i++); return total; } - if (modifierType.modifierType.id === "EVIOLITE") { - poolHasEviolite = true; - } - if (modifierType.modifierType.id === "MINI_BLACK_HOLE") { - poolHasBlackHole = true; + if (itemPoolChecks.has(modifierType.modifierType.id as ModifierTypeKeys)) { + itemPoolChecks.set(modifierType.modifierType.id as ModifierTypeKeys, true); } thresholds.set(total, i++); return total; diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index ecbb756ca0e..adda041fb10 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,9 +1,9 @@ import { Abilities } from "#app/enums/abilities"; import { Moves } from "#app/enums/moves"; import { MapModifier } from "#app/modifier/modifier"; -import { poolHasBlackHole, poolHasEviolite } from "#app/modifier/modifier-type"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; +import { itemPoolChecks } from "#app/modifier/modifier-type"; const TIMEOUT = 20 * 1000; @@ -64,18 +64,28 @@ describe("Shop modifications", async () => { it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { await game.classicMode.startBattle(); + itemPoolChecks.set("EVIOLITE", false); + itemPoolChecks.set("MINI_BLACK_HOLE", false); + game.move.select(Moves.SURF); await game.phaseInterceptor.to("SelectModifierPhase", false); - expect(poolHasEviolite).toBeFalsy(); - expect(poolHasBlackHole).toBeFalsy(); + expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy(); + + itemPoolChecks.clear(); }, TIMEOUT); it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { await game.dailyMode.startBattle(); + itemPoolChecks.set("EVIOLITE", false); + itemPoolChecks.set("MINI_BLACK_HOLE", false); + game.move.select(Moves.SURF); await game.phaseInterceptor.to("SelectModifierPhase", false); - expect(poolHasEviolite).toBeTruthy(); - expect(poolHasBlackHole).toBeTruthy(); + expect(itemPoolChecks.get("EVIOLITE")).toBeTruthy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeTruthy(); + + itemPoolChecks.clear(); }, TIMEOUT); }); diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index b3f014d0154..1dee379d484 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"; +import { getPartyLuckValue } from "#app/modifier/modifier-type"; describe("game-mode", () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -41,22 +42,39 @@ describe("game-mode", () => { expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy(); }); }); - /* - Need to figure out how to override my party members' luck to calculate this + //* + //Need to figure out how to override my party members' luck to calculate this describe("Luck Check", async () => { let classicGameMode: GameMode; let dailyGameMode: GameMode; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + beforeEach(() => { + game = new GameManager(phaserGame); classicGameMode = getGameMode(GameModes.CLASSIC); dailyGameMode = getGameMode(GameModes.DAILY); }); - const party = game.scene.getParty(); - const oldmode = game.scene.gameMode; - game.scene.gameMode = classicGameMode!; - expect(getPartyLuckValue(party)).toBe(3); - game.scene.gameMode = dailyGameMode!; - expect(getPartyLuckValue(party)).toBe(0); - game.scene.gameMode = oldmode; - }) - */ + + it("does not apply luck in Daily Runs", () => { + game.override + .shinyLevel(true, 2); + const party = game.scene.getParty(); + const oldmode = game.scene.gameMode; + game.scene.gameMode = classicGameMode!; + expect(getPartyLuckValue(party)).toBe(3); + game.scene.gameMode = dailyGameMode!; + expect(getPartyLuckValue(party)).toBe(0); + game.scene.gameMode = oldmode; + }); + }); + //*/ }); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 12db3b5c1db..61613a1eec6 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -10,7 +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.js"; +import { Unlockables } from "#app/system/unlockables"; +import { Variant } from "#app/data/variant"; /** * Helper to handle overrides in tests @@ -304,7 +305,7 @@ export class OverridesHelper extends GameManagerHelper { 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 @@ -316,6 +317,27 @@ export class OverridesHelper extends GameManagerHelper { return this; } + /** + * Override player shininess + * @param shininess Whether the player's Pokemon should be shiny. + * @param variant The player's shiny variant. + */ + shinyLevel(shininess?: boolean, variant?: Variant): this { + if (shininess !== undefined) { + vi.spyOn(Overrides, "SHINY_OVERRIDE", "get").mockReturnValue(shininess); + } + if (variant !== undefined) { + vi.spyOn(Overrides, "VARIANT_OVERRIDE", "get").mockReturnValue(variant); + } + if (shininess !== undefined) { + this.log(`Set player Pokemon as ${shininess ? "" : "not "}shiny!`); + } + if (variant !== undefined) { + 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 From a9b6359e3454137b7e6f81942737f2aee1954291 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:14:20 -0400 Subject: [PATCH 23/30] Tests still broken what else is new god i hate tests go away eslinter nobody likes you --- src/modifier/modifier-type.ts | 2 +- src/test/daily_mode.test.ts | 43 ++++++++---------------------- src/test/game-mode.test.ts | 20 ++++++++------ src/test/utils/phaseInterceptor.ts | 4 ++- 4 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 1ef8bceb486..cce7241b630 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1630,7 +1630,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { const { gameMode, gameData } = party[0].scene; - if (gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { + if (party[0].scene.gameMode.isDaily || 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)) ? 10 : 0; } return 0; diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index adda041fb10..47142769c23 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,11 +1,11 @@ -import { Abilities } from "#app/enums/abilities"; -import { Moves } from "#app/enums/moves"; import { MapModifier } from "#app/modifier/modifier"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; -import { itemPoolChecks } from "#app/modifier/modifier-type"; +//import { Abilities } from "#app/enums/abilities"; +//import { Moves } from "#app/enums/moves"; +//import { itemPoolChecks } from "#app/modifier/modifier-type"; -const TIMEOUT = 20 * 1000; +//const TIMEOUT = 20 * 1000; describe("Daily Mode", () => { let phaserGame: Phaser.Game; @@ -38,6 +38,9 @@ describe("Daily Mode", () => { }); }); +/* +// Need to figure out how to properly start a battle +// Need to fix eviolite - test keeps insisting it is not in loot table, even though Mini Black Hole (which is using the exact same condition) is describe("Shop modifications", async () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -55,37 +58,13 @@ describe("Shop modifications", async () => { .startingLevel(200) .moveset([Moves.SURF]) .enemyAbility(Abilities.BALL_FETCH); + itemPoolChecks.set("EVIOLITE", false); + itemPoolChecks.set("MINI_BLACK_HOLE", false); }); afterEach(() => { game.phaseInterceptor.restoreOg(); + itemPoolChecks.clear(); }); - - it("should only allow Mini Black Hole and Eviolite outside of Daily if unlocked", async () => { - await game.classicMode.startBattle(); - - itemPoolChecks.set("EVIOLITE", false); - itemPoolChecks.set("MINI_BLACK_HOLE", false); - - game.move.select(Moves.SURF); - await game.phaseInterceptor.to("SelectModifierPhase", false); - expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); - expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy(); - - itemPoolChecks.clear(); - }, TIMEOUT); - - it("should allow Eviolite and Mini Black Hole in shop when in Daily Run", async () => { - await game.dailyMode.startBattle(); - - itemPoolChecks.set("EVIOLITE", false); - itemPoolChecks.set("MINI_BLACK_HOLE", false); - - game.move.select(Moves.SURF); - await game.phaseInterceptor.to("SelectModifierPhase", false); - expect(itemPoolChecks.get("EVIOLITE")).toBeTruthy(); - expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeTruthy(); - - itemPoolChecks.clear(); - }, TIMEOUT); }); +//*/ diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index 1dee379d484..4032fc54911 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -2,7 +2,8 @@ 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"; -import { getPartyLuckValue } from "#app/modifier/modifier-type"; +//import { getPartyLuckValue } from "#app/modifier/modifier-type"; +//import { Species } from "#app/enums/species"; describe("game-mode", () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -42,8 +43,8 @@ describe("game-mode", () => { expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy(); }); }); - //* - //Need to figure out how to override my party members' luck to calculate this + /* + // Need to figure out how to properly start a battle describe("Luck Check", async () => { let classicGameMode: GameMode; let dailyGameMode: GameMode; @@ -64,16 +65,19 @@ describe("game-mode", () => { dailyGameMode = getGameMode(GameModes.DAILY); }); + it("applies luck in Classic", () => { + game.override + .shinyLevel(true, 2); + game.classicMode.startBattle([Species.PICHU]); + const party = game.scene.getParty(); + expect(getPartyLuckValue(party)).toBe(3); + }); it("does not apply luck in Daily Runs", () => { game.override .shinyLevel(true, 2); + game.dailyMode.startBattle(); const party = game.scene.getParty(); - const oldmode = game.scene.gameMode; - game.scene.gameMode = classicGameMode!; - expect(getPartyLuckValue(party)).toBe(3); - game.scene.gameMode = dailyGameMode!; expect(getPartyLuckValue(party)).toBe(0); - game.scene.gameMode = oldmode; }); }); //*/ diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index a89d1788be9..aff14b76750 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"; export default class PhaseInterceptor { public scene; @@ -104,6 +105,7 @@ export default class PhaseInterceptor { [EndEvolutionPhase, this.startPhase], [LevelCapPhase, this.startPhase], [AttemptRunPhase, this.startPhase], + [SelectBiomePhase, this.startPhase], ]; private endBySetMode = [ @@ -320,7 +322,7 @@ 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 phaseInterceptior 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(); From 7ea608fb8aaa0769e6a9799cbb3b1c45d3dc9474 Mon Sep 17 00:00:00 2001 From: MokaStitcher <54149968+MokaStitcher@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:56:55 +0200 Subject: [PATCH 24/30] [Bug] Fix Dire Hit & System Data Conversion Failure (#4282) Co-authored-by: xsn34kzx --- src/system/version-converter.ts | 40 +++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/system/version-converter.ts b/src/system/version-converter.ts index f7996124886..6cb2c24d84d 100644 --- a/src/system/version-converter.ts +++ b/src/system/version-converter.ts @@ -22,15 +22,25 @@ export function applySessionDataPatches(data: SessionSaveData) { } else if (m.className === "PokemonResetNegativeStatStageModifier") { m.className = "ResetNegativeStatStageModifier"; } else if (m.className === "TempBattleStatBoosterModifier") { - m.className = "TempStatStageBoosterModifier"; - m.typeId = "TEMP_STAT_STAGE_BOOSTER"; + // Dire Hit no longer a part of the TempBattleStatBoosterModifierTypeGenerator + if (m.typeId !== "DIRE_HIT") { + m.className = "TempStatStageBoosterModifier"; + m.typeId = "TEMP_STAT_STAGE_BOOSTER"; - // Migration from TempBattleStat to Stat - const newStat = m.typePregenArgs[0] + 1; - m.typePregenArgs[0] = newStat; + // Migration from TempBattleStat to Stat + const newStat = m.typePregenArgs[0] + 1; + m.typePregenArgs[0] = newStat; + + // From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ] + m.args = [ newStat, 5, m.args[1] ]; + } else { + m.className = "TempCritBoosterModifier"; + m.typePregenArgs = []; + + // From [ stat, battlesLeft ] to [ maxBattles, battleCount ] + m.args = [ 5, m.args[1] ]; + } - // From [ stat, battlesLeft ] to [ stat, maxBattles, battleCount ] - m.args = [ newStat, 5, m.args[1] ]; } else if (m.className === "DoubleBattleChanceBoosterModifier" && m.args.length === 1) { let maxBattles: number; switch (m.typeId) { @@ -73,7 +83,7 @@ export function applySystemDataPatches(data: SystemSaveData) { case "1.0.3": case "1.0.4": // --- LEGACY PATCHES --- - if (data.starterData) { + if (data.starterData && data.dexData) { // Migrate ability starter data if empty for caught species Object.keys(data.starterData).forEach(sd => { if (data.dexData[sd]?.caughtAttr && (data.starterData[sd] && !data.starterData[sd].abilityAttr)) { @@ -104,12 +114,14 @@ export function applySystemDataPatches(data: SystemSaveData) { // --- PATCHES --- // Fix Starter Data - for (const starterId of defaultStarterSpecies) { - if (data.starterData[starterId]?.abilityAttr) { - data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; - } - if (data.dexData[starterId]?.caughtAttr) { - data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; + if (data.starterData && data.dexData) { + for (const starterId of defaultStarterSpecies) { + if (data.starterData[starterId]?.abilityAttr) { + data.starterData[starterId].abilityAttr |= AbilityAttr.ABILITY_1; + } + if (data.dexData[starterId]?.caughtAttr) { + data.dexData[starterId].caughtAttr |= DexAttr.FEMALE; + } } } } From 029dfa4b3bc98af094d5a19c092df1b178d106a4 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:24:08 -0400 Subject: [PATCH 25/30] Update reload.test.ts Thanks to DayKev again for these fixes --- src/test/reload.test.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) 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"); From 21315a3664ba3ec3c27066a67b3e5da17e43d28e Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:25:22 -0400 Subject: [PATCH 26/30] Push progress so I can sync to beta --- src/battle-scene.ts | 9 +++++ src/modifier/modifier-type.ts | 9 ++++- src/overrides.ts | 4 +- src/phases/title-phase.ts | 5 ++- src/system/game-data.ts | 8 +++- src/test/daily_mode.test.ts | 40 ++++++++++++++++---- src/test/game-mode.test.ts | 27 ++++++++------ src/test/ui/transfer-item.test.ts | 45 +++++++++++++++++++++++ src/test/utils/helpers/overridesHelper.ts | 9 ++++- src/tutorial.ts | 4 +- src/ui/modifier-select-ui-handler.ts | 3 +- 11 files changed, 131 insertions(+), 32 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 9787185b6ae..8665f1e97e5 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1674,6 +1674,11 @@ export default class BattleScene extends SceneBase { this.scoreText.setVisible(this.gameMode.isDaily); } + /** + * Displays the current luck value. + * @param duration The time for this label to fade in, if it is not already visible. + * @param isDaily If true, hides the label. (This is done because Luck does not apply in Daily Mode anymore) + */ updateAndShowText(duration: number, isDaily?: boolean): void { const labels = [ this.luckLabelText, this.luckText ]; labels.forEach(t => t.setAlpha(0)); @@ -1685,6 +1690,10 @@ export default class BattleScene extends SceneBase { this.luckText.setTint(0xffef5c, 0x47ff69, 0x6b6bff, 0xff6969); } this.luckLabelText.setX((this.game.canvas.width / 6) - 2 - (this.luckText.displayWidth + 2)); + if (isDaily) { + // Hide luck label + labels.forEach(t => t.setVisible(false)); + } this.tweens.add({ targets: labels, duration: duration, diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index c5e7ea8739e..859779977d5 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1700,7 +1700,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { const { gameMode, gameData } = party[0].scene; - if (party[0].scene.gameMode.isDaily || gameMode.isDaily || (!gameMode.isFreshStartChallenge() && gameData.isUnlocked(Unlockables.EVIOLITE))) { + 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)) ? 10 : 0; } return 0; @@ -2418,11 +2418,16 @@ export class ModifierTypeOption { } } +/** + * Calculates the team's luck value. + * @param party The player's party. + * @returns A value between 0 and 14, or 0 if the player is in Daily Run mode. + */ export function getPartyLuckValue(party: Pokemon[]): integer { if (party[0].scene.gameMode.isDaily) { return 0; } - const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) + const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? (p.scene.gameMode.isDaily ? 0 : p.getLuck()) : 0) .reduce((total: integer, value: integer) => total += value, 0), 0, 14); return luck || 0; } diff --git a/src/overrides.ts b/src/overrides.ts index dc9de8990d0..6b5d89d9bdc 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -72,9 +72,9 @@ class DefaultOverrides { }, }; /** Forces an item to be UNLOCKED */ - readonly UNLOCK_OVERRIDE: Unlockables[] = []; + 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 2c7084e808f..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.isUnlocked(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.isUnlocked(Unlockables.SPLICED_ENDLESS_MODE)) { + if (gameData.isUnlocked(Unlockables.SPLICED_ENDLESS_MODE)) { options.push({ label: GameMode.getModeName(GameModes.SPLICED_ENDLESS), handler: () => { diff --git a/src/system/game-data.ts b/src/system/game-data.ts index d8af753f230..22a793e9aca 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -371,8 +371,14 @@ export class GameData { unlockPity: this.unlockPity.slice(0) }; } + + /** + * 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.UNLOCK_OVERRIDE.includes(unlockable)) { + if (Overrides.ITEM_UNLOCK_OVERRIDE.includes(unlockable)) { return true; } return this.unlocks[unlockable]; diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 47142769c23..1b868cab116 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -1,9 +1,12 @@ import { MapModifier } from "#app/modifier/modifier"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "./utils/gameManager"; -//import { Abilities } from "#app/enums/abilities"; -//import { Moves } from "#app/enums/moves"; -//import { itemPoolChecks } from "#app/modifier/modifier-type"; +import { Moves } from "#app/enums/moves"; +import { getPartyLuckValue, itemPoolChecks } from "#app/modifier/modifier-type"; +import { Biome } from "#app/enums/biome"; +import { BattleEndPhase } from "#app/phases/battle-end-phase"; +import { Mode } from "#app/ui/ui"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; //const TIMEOUT = 20 * 1000; @@ -38,7 +41,7 @@ describe("Daily Mode", () => { }); }); -/* +//* // Need to figure out how to properly start a battle // Need to fix eviolite - test keeps insisting it is not in loot table, even though Mini Black Hole (which is using the exact same condition) is describe("Shop modifications", async () => { @@ -54,10 +57,14 @@ describe("Shop modifications", async () => { game = new GameManager(phaserGame); game.override + .startingWave(9) + .startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather .battleType("single") - .startingLevel(200) - .moveset([Moves.SURF]) - .enemyAbility(Abilities.BALL_FETCH); + .startingLevel(100) // Avoid levelling up + .enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents() + .disableTrainerWaves() + .moveset([Moves.KOWTOW_CLEAVE]) + .enemyMoveset(Moves.SPLASH); itemPoolChecks.set("EVIOLITE", false); itemPoolChecks.set("MINI_BLACK_HOLE", false); }); @@ -66,5 +73,24 @@ describe("Shop modifications", async () => { game.phaseInterceptor.restoreOg(); itemPoolChecks.clear(); }); + + it("should do literally anything please god im begging you", async () => { + await game.dailyMode.runToSummon(); + const party = game.scene.getParty(); + expect(party[0]).toBeDefined(); + party[0].shiny = true; + expect(getPartyLuckValue(party)).toBe(0); + expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); + expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy(); + 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); + }); + }); }); //*/ diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index 4032fc54911..75e76ac3b9d 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -2,8 +2,10 @@ 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"; -//import { getPartyLuckValue } from "#app/modifier/modifier-type"; -//import { Species } from "#app/enums/species"; +import { getPartyLuckValue } from "#app/modifier/modifier-type"; +import { Species } from "#app/enums/species"; +import { getPokemonSpecies } from "#app/data/pokemon-species"; + describe("game-mode", () => { let phaserGame: Phaser.Game; let game: GameManager; @@ -14,6 +16,7 @@ describe("game-mode", () => { }); afterEach(() => { game.phaseInterceptor.restoreOg(); + vi.clearAllMocks(); vi.resetAllMocks(); }); beforeEach(() => { @@ -43,12 +46,7 @@ describe("game-mode", () => { expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy(); }); }); - /* - // Need to figure out how to properly start a battle - describe("Luck Check", async () => { - let classicGameMode: GameMode; - let dailyGameMode: GameMode; - + describe.skip("Luck Check", async () => { beforeAll(() => { phaserGame = new Phaser.Game({ type: Phaser.HEADLESS, @@ -61,24 +59,29 @@ describe("game-mode", () => { beforeEach(() => { game = new GameManager(phaserGame); - classicGameMode = getGameMode(GameModes.CLASSIC); - dailyGameMode = getGameMode(GameModes.DAILY); }); it("applies luck in Classic", () => { game.override .shinyLevel(true, 2); game.classicMode.startBattle([Species.PICHU]); + game.scene.addPlayerPokemon(getPokemonSpecies(Species.PICHU), 5, undefined, undefined, undefined, true, 2); const party = game.scene.getParty(); - expect(getPartyLuckValue(party)).toBe(3); + const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) + .reduce((total: integer, value: integer) => total += value, 0), 0, 14); + expect(luck).toBeGreaterThan(0); + expect(getPartyLuckValue(party)).toBeGreaterThan(0); }); it("does not apply luck in Daily Runs", () => { game.override .shinyLevel(true, 2); game.dailyMode.startBattle(); + game.scene.addPlayerPokemon(getPokemonSpecies(Species.PICHU), 5, undefined, undefined, undefined, true, 2); const party = game.scene.getParty(); + const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) + .reduce((total: integer, value: integer) => total += value, 0), 0, 14); + expect(luck).toBeGreaterThan(0); expect(getPartyLuckValue(party)).toBe(0); }); }); - //*/ }); diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index f7dea463574..f952cf4c59c 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -2,6 +2,7 @@ import { BerryType } from "#app/enums/berry-type"; import { Button } from "#app/enums/buttons"; import { Moves } from "#app/enums/moves"; import { Species } from "#app/enums/species"; +import { itemPoolChecks } from "#app/modifier/modifier-type"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; @@ -94,3 +95,47 @@ describe("UI - Transfer Items", () => { await game.phaseInterceptor.to(SelectModifierPhase); }, 20000); }); + +describe("Test", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(async () => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .startingLevel(100) + .startingWave(1) + .startingHeldItems([ + { name: "BERRY", count: 1, type: BerryType.SITRUS }, + { name: "BERRY", count: 2, type: BerryType.APICOT }, + { name: "BERRY", count: 2, type: BerryType.LUM }, + ]) + .moveset([Moves.DRAGON_CLAW]) + .enemySpecies(Species.MAGIKARP) + .enemyMoveset([Moves.SPLASH]); + itemPoolChecks.set("EVIOLITE", false); + itemPoolChecks.set("MINI_BLACK_HOLE", false); + }); + it("should run", async () => { + await game.classicMode.startBattle([Species.RAYQUAZA, Species.RAYQUAZA, Species.RAYQUAZA]); + + game.move.select(Moves.DRAGON_CLAW); + + game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { + expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + }); + + await game.phaseInterceptor.to(BattleEndPhase); + }); +}); diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 0640d6c41ba..52b23d112bf 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -302,8 +302,13 @@ export class OverridesHelper extends GameManagerHelper { return this; } - unlockUnlockable(unlockable: Unlockables[]) { - vi.spyOn(Overrides, "UNLOCK_OVERRIDE", "get").mockReturnValue(unlockable); + /** + * Gives the player access to an Unlockable. + * @param unlockable The Unlockable 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; } 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; } diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index af4f0905b6d..521162b8842 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -13,7 +13,6 @@ import * as Utils from "./../utils"; import Overrides from "#app/overrides"; import i18next from "i18next"; import { ShopCursorTarget } from "#app/enums/shop-cursor-target"; -import { GameModes } from "#app/game-mode"; import { IntegerHolder } from "./../utils"; import Phaser from "phaser"; @@ -231,7 +230,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { /* Multiplies the appearance duration by the speed parameter so that it is always constant, and avoids "flashbangs" at game speed x5 */ this.scene.showShopOverlay(750 * this.scene.gameSpeed); - this.scene.updateAndShowText(750, this.scene.gameMode.modeId === GameModes.DAILY); + this.scene.updateAndShowText(750, this.scene.gameMode.isDaily); this.scene.updateBiomeWaveText(); this.scene.updateMoneyText(); From 752bd4f017480d63c04ff120602622d193deb78b Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:55:03 -0400 Subject: [PATCH 27/30] I might have done it the tests didn't fail --- src/test/daily_mode.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 1b868cab116..d9fce3faa33 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -60,6 +60,7 @@ describe("Shop modifications", async () => { .startingWave(9) .startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather .battleType("single") + .shinyLevel(true, 2) .startingLevel(100) // Avoid levelling up .enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents() .disableTrainerWaves() @@ -78,7 +79,6 @@ describe("Shop modifications", async () => { await game.dailyMode.runToSummon(); const party = game.scene.getParty(); expect(party[0]).toBeDefined(); - party[0].shiny = true; expect(getPartyLuckValue(party)).toBe(0); expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); @@ -90,6 +90,10 @@ describe("Shop modifications", async () => { await game.phaseInterceptor.to(BattleEndPhase); game.onNextPrompt("SelectModifierPhase", Mode.MODIFIER_SELECT, () => { expect(game.scene.ui.getHandler()).toBeInstanceOf(ModifierSelectUiHandler); + expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); + expect(itemPoolChecks.get("EVIOLITE")).toBeTruthy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeTruthy(); }); }); }); From 4a2725223115c0fa9b7317083205dbe3af405f0e Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:58:24 -0400 Subject: [PATCH 28/30] Delete a skipped test, and skip a nonfunctional one The test I added a skip statement to is just there as a second possible method of making these last tests --- src/test/game-mode.test.ts | 41 ------------------------------- src/test/ui/transfer-item.test.ts | 2 +- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/src/test/game-mode.test.ts b/src/test/game-mode.test.ts index 75e76ac3b9d..11994a102af 100644 --- a/src/test/game-mode.test.ts +++ b/src/test/game-mode.test.ts @@ -2,9 +2,6 @@ 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"; -import { getPartyLuckValue } from "#app/modifier/modifier-type"; -import { Species } from "#app/enums/species"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; describe("game-mode", () => { let phaserGame: Phaser.Game; @@ -46,42 +43,4 @@ describe("game-mode", () => { expect(classicGameMode.isWaveTrainer(19, arena)).toBeFalsy(); }); }); - describe.skip("Luck Check", async () => { - beforeAll(() => { - phaserGame = new Phaser.Game({ - type: Phaser.HEADLESS, - }); - }); - - afterEach(() => { - game.phaseInterceptor.restoreOg(); - }); - - beforeEach(() => { - game = new GameManager(phaserGame); - }); - - it("applies luck in Classic", () => { - game.override - .shinyLevel(true, 2); - game.classicMode.startBattle([Species.PICHU]); - game.scene.addPlayerPokemon(getPokemonSpecies(Species.PICHU), 5, undefined, undefined, undefined, true, 2); - const party = game.scene.getParty(); - const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) - .reduce((total: integer, value: integer) => total += value, 0), 0, 14); - expect(luck).toBeGreaterThan(0); - expect(getPartyLuckValue(party)).toBeGreaterThan(0); - }); - it("does not apply luck in Daily Runs", () => { - game.override - .shinyLevel(true, 2); - game.dailyMode.startBattle(); - game.scene.addPlayerPokemon(getPokemonSpecies(Species.PICHU), 5, undefined, undefined, undefined, true, 2); - const party = game.scene.getParty(); - const luck = Phaser.Math.Clamp(party.map(p => p.isAllowedInBattle() ? p.getLuck() : 0) - .reduce((total: integer, value: integer) => total += value, 0), 0, 14); - expect(luck).toBeGreaterThan(0); - expect(getPartyLuckValue(party)).toBe(0); - }); - }); }); diff --git a/src/test/ui/transfer-item.test.ts b/src/test/ui/transfer-item.test.ts index f952cf4c59c..7b5fa7f9171 100644 --- a/src/test/ui/transfer-item.test.ts +++ b/src/test/ui/transfer-item.test.ts @@ -96,7 +96,7 @@ describe("UI - Transfer Items", () => { }, 20000); }); -describe("Test", () => { +describe.skip("Backup Test", () => { let phaserGame: Phaser.Game; let game: GameManager; From 696a52fe15ad2615bc1e47e30b28a9e9f5a0a0e1 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:58:39 -0400 Subject: [PATCH 29/30] Rename test --- src/test/daily_mode.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index d9fce3faa33..24e8edfdd3e 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -75,7 +75,7 @@ describe("Shop modifications", async () => { itemPoolChecks.clear(); }); - it("should do literally anything please god im begging you", async () => { + it("should have Eviolite and Mini Black Hole available in Daily", async () => { await game.dailyMode.runToSummon(); const party = game.scene.getParty(); expect(party[0]).toBeDefined(); From 9062925cf8539d1b703d61749e7850c2c18817c7 Mon Sep 17 00:00:00 2001 From: RedstonewolfX <108761527+RedstonewolfX@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:02:36 -0400 Subject: [PATCH 30/30] Almost there!! --- src/test/daily_mode.test.ts | 42 ++++++++++++++++++++--- src/test/utils/helpers/overridesHelper.ts | 24 ++++++------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/test/daily_mode.test.ts b/src/test/daily_mode.test.ts index 24e8edfdd3e..dea204a2d2c 100644 --- a/src/test/daily_mode.test.ts +++ b/src/test/daily_mode.test.ts @@ -7,6 +7,7 @@ import { Biome } from "#app/enums/biome"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { Mode } from "#app/ui/ui"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; +import Overrides from "#app/overrides"; //const TIMEOUT = 20 * 1000; @@ -60,7 +61,7 @@ describe("Shop modifications", async () => { .startingWave(9) .startingBiome(Biome.ICE_CAVE) // Will lead to Snowy Forest with randomly generated weather .battleType("single") - .shinyLevel(true, 2) + .shinyLevel(true) .startingLevel(100) // Avoid levelling up .enemyLevel(1000) // Avoid opponent dying before game.doKillOpponents() .disableTrainerWaves() @@ -75,11 +76,27 @@ describe("Shop modifications", async () => { itemPoolChecks.clear(); }); + it("should not have Eviolite and Mini Black Hole available in Classic if not unlocked", async () => { + await game.classicMode.runToSummon(); + expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); + expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy(); + 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); + expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); + expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined(); + expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeFalsy(); + }); + }); + it("should have Eviolite and Mini Black Hole available in Daily", async () => { await game.dailyMode.runToSummon(); - const party = game.scene.getParty(); - expect(party[0]).toBeDefined(); - expect(getPartyLuckValue(party)).toBe(0); expect(itemPoolChecks.get("EVIOLITE")).toBeDefined(); expect(itemPoolChecks.get("EVIOLITE")).toBeFalsy(); expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeDefined(); @@ -96,5 +113,22 @@ describe("Shop modifications", async () => { expect(itemPoolChecks.get("MINI_BLACK_HOLE")).toBeTruthy(); }); }); + + it("should apply luck in Classic Mode", async () => { + await game.classicMode.runToSummon(); + const party = game.scene.getParty(); + expect(Overrides.SHINY_OVERRIDE).toBeTruthy(); + expect(party[0]).toBeDefined(); + expect(party[0].getLuck()).toBeGreaterThan(0); + expect(getPartyLuckValue(party)).toBeGreaterThan(0); + }); + + it("should not apply luck in Daily Run", async () => { + await game.dailyMode.runToSummon(); + const party = game.scene.getParty(); + expect(party[0]).toBeDefined(); + expect(party[0].getLuck()).toBeGreaterThan(0); + expect(getPartyLuckValue(party)).toBe(0); + }); }); //*/ diff --git a/src/test/utils/helpers/overridesHelper.ts b/src/test/utils/helpers/overridesHelper.ts index 52b23d112bf..d2a0cbdb2d7 100644 --- a/src/test/utils/helpers/overridesHelper.ts +++ b/src/test/utils/helpers/overridesHelper.ts @@ -327,21 +327,19 @@ export class OverridesHelper extends GameManagerHelper { /** * 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. */ - shinyLevel(shininess?: boolean, variant?: Variant): this { - if (shininess !== undefined) { - vi.spyOn(Overrides, "SHINY_OVERRIDE", "get").mockReturnValue(shininess); - } - if (variant !== undefined) { - vi.spyOn(Overrides, "VARIANT_OVERRIDE", "get").mockReturnValue(variant); - } - if (shininess !== undefined) { - this.log(`Set player Pokemon as ${shininess ? "" : "not "}shiny!`); - } - if (variant !== undefined) { - this.log(`Set player Pokemon's shiny variant to ${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; }