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
This commit is contained in:
parent
e9b06bdf1b
commit
f5b49d812d
|
@ -10,7 +10,7 @@ import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from "..
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from "../data/temp-battle-stat";
|
import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from "../data/temp-battle-stat";
|
||||||
import { getBerryEffectDescription, getBerryName } from "../data/berry";
|
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 { StatusEffect, getStatusEffectDescriptor } from "../data/status-effect";
|
||||||
import { SpeciesFormKey } from "../data/pokemon-species";
|
import { SpeciesFormKey } from "../data/pokemon-species";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
|
@ -1597,7 +1597,7 @@ const modifierPool: ModifierPool = {
|
||||||
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
|
new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)),
|
||||||
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
|
new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => {
|
||||||
const { gameMode, gameData } = party[0].scene;
|
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 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;
|
return 0;
|
||||||
|
@ -1675,7 +1675,7 @@ const modifierPool: ModifierPool = {
|
||||||
new WeightedModifierType(modifierTypes.MULTI_LENS, 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(5 - rerollCount * 2, 0) : 0, 5),
|
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.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 => {
|
].map(m => {
|
||||||
m.setTier(ModifierTier.MASTER); return 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 ];
|
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) {
|
export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType, rerollCount: integer = 0) {
|
||||||
const pool = getModifierPoolForType(poolType);
|
const pool = getModifierPoolForType(poolType);
|
||||||
|
poolHasEviolite = false;
|
||||||
|
poolHasBlackHole = false;
|
||||||
|
|
||||||
const ignoredIndexes = {};
|
const ignoredIndexes = {};
|
||||||
const modifierTableData = {};
|
const modifierTableData = {};
|
||||||
|
@ -1906,6 +1910,12 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
|
||||||
ignoredIndexes[t].push(i++);
|
ignoredIndexes[t].push(i++);
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
if (modifierType.modifierType.id === "EVIOLITE") {
|
||||||
|
poolHasEviolite = true;
|
||||||
|
}
|
||||||
|
if (modifierType.modifierType.id === "MINI_BLACK_HOLE") {
|
||||||
|
poolHasBlackHole = true;
|
||||||
|
}
|
||||||
thresholds.set(total, i++);
|
thresholds.set(total, i++);
|
||||||
return total;
|
return total;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { Gender } from "./data/gender";
|
||||||
import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
import { allSpecies } from "./data/pokemon-species"; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
import { Variant } from "./data/variant";
|
import { Variant } from "./data/variant";
|
||||||
import { type ModifierOverride } from "./modifier/modifier-type";
|
import { type ModifierOverride } from "./modifier/modifier-type";
|
||||||
|
import { Unlockables } from "./system/unlockables";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides that are using when testing different in game situations
|
* Overrides that are using when testing different in game situations
|
||||||
|
@ -69,6 +70,10 @@ class DefaultOverrides {
|
||||||
[PokeballType.MASTER_BALL]: 0,
|
[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
|
// PLAYER OVERRIDES
|
||||||
|
|
|
@ -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 { regenerateModifierPoolThresholds, ModifierPoolType, modifierTypes, getDailyRunStarterModifiers } from "#app/modifier/modifier-type.js";
|
||||||
import { Phase } from "#app/phase.js";
|
import { Phase } from "#app/phase.js";
|
||||||
import { SessionSaveData } from "#app/system/game-data.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 { vouchers } from "#app/system/voucher.js";
|
||||||
import { OptionSelectItem, OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler.js";
|
import { OptionSelectItem, OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler.js";
|
||||||
import { SaveSlotUiMode } from "#app/ui/save-slot-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.scene.ui.clearText();
|
||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
|
if (isUnlocked(Unlockables.ENDLESS_MODE, this.scene.gameData)) {
|
||||||
const options: OptionSelectItem[] = [
|
const options: OptionSelectItem[] = [
|
||||||
{
|
{
|
||||||
label: GameMode.getModeName(GameModes.CLASSIC),
|
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({
|
options.push({
|
||||||
label: GameMode.getModeName(GameModes.SPLICED_ENDLESS),
|
label: GameMode.getModeName(GameModes.SPLICED_ENDLESS),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { GameMode, GameModes } from "../game-mode";
|
import { GameMode, GameModes } from "../game-mode";
|
||||||
|
import Overrides from "#app/overrides";
|
||||||
|
import { GameData } from "./game-data";
|
||||||
|
|
||||||
export enum Unlockables {
|
export enum Unlockables {
|
||||||
ENDLESS_MODE,
|
ENDLESS_MODE,
|
||||||
|
@ -8,6 +10,16 @@ export enum Unlockables {
|
||||||
EVIOLITE
|
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) {
|
export function getUnlockableName(unlockable: Unlockables) {
|
||||||
switch (unlockable) {
|
switch (unlockable) {
|
||||||
case Unlockables.ENDLESS_MODE:
|
case Unlockables.ENDLESS_MODE:
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import GameManager from "./utils/gameManager";
|
import GameManager from "./utils/gameManager";
|
||||||
import { MapModifier } from "#app/modifier/modifier.js";
|
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", () => {
|
describe("Daily Mode", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -32,13 +37,38 @@ describe("Daily Mode", () => {
|
||||||
expect(game.scene.getModifiers(MapModifier).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 () => {
|
describe("Shop modifications", async () => {
|
||||||
const modifierPhase = new SelectModifierPhase(game.scene);
|
beforeEach(() => {
|
||||||
game.scene.unshiftPhase(modifierPhase);
|
game = new GameManager(phaserGame);
|
||||||
await game.phaseInterceptor.run(SelectModifierPhase);
|
|
||||||
expect(getModifierThresholdPool(ModifierPoolType.PLAYER));
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { ModifierOverride } from "#app/modifier/modifier-type.js";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
import { GameManagerHelper } from "./gameManagerHelper";
|
import { GameManagerHelper } from "./gameManagerHelper";
|
||||||
|
import { Unlockables } from "#app/system/unlockables.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to handle overrides in tests
|
* Helper to handle overrides in tests
|
||||||
|
@ -281,6 +282,18 @@ export class OverridesHelper extends GameManagerHelper {
|
||||||
return this;
|
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[]) {
|
private log(...params: any[]) {
|
||||||
console.log("Overrides:", ...params);
|
console.log("Overrides:", ...params);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue