add unit tests for pokemon salesman
This commit is contained in:
parent
792af86f39
commit
0c45194892
|
@ -94,7 +94,7 @@ export const PokemonSalesmanEncounter: IMysteryEncounter =
|
||||||
encounter.setDialogueToken("purchasePokemon", pokemon.name);
|
encounter.setDialogueToken("purchasePokemon", pokemon.name);
|
||||||
encounter.setDialogueToken("price", price.toString());
|
encounter.setDialogueToken("price", price.toString());
|
||||||
encounter.misc = {
|
encounter.misc = {
|
||||||
money: price,
|
price: price,
|
||||||
pokemon: pokemon
|
pokemon: pokemon
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,11 +118,11 @@ export const PokemonSalesmanEncounter: IMysteryEncounter =
|
||||||
})
|
})
|
||||||
.withOptionPhase(async (scene: BattleScene) => {
|
.withOptionPhase(async (scene: BattleScene) => {
|
||||||
const encounter = scene.currentBattle.mysteryEncounter;
|
const encounter = scene.currentBattle.mysteryEncounter;
|
||||||
const cost = encounter.misc.money;
|
const price = encounter.misc.price;
|
||||||
const purchasedPokemon = encounter.misc.pokemon as PlayerPokemon;
|
const purchasedPokemon = encounter.misc.pokemon as PlayerPokemon;
|
||||||
|
|
||||||
// Update money
|
// Update money
|
||||||
updatePlayerMoney(scene, -cost, true, false);
|
updatePlayerMoney(scene, -price, true, false);
|
||||||
|
|
||||||
// Show dialogue
|
// Show dialogue
|
||||||
await showEncounterDialogue(scene, `${namespace}:option:1:selected_dialogue`, `${namespace}:speaker`);
|
await showEncounterDialogue(scene, `${namespace}:option:1:selected_dialogue`, `${namespace}:speaker`);
|
||||||
|
|
|
@ -316,6 +316,7 @@ export function initCustomMovesForEncounter(scene: BattleScene, moves: Moves | M
|
||||||
* @param scene - Battle Scene
|
* @param scene - Battle Scene
|
||||||
* @param changeValue
|
* @param changeValue
|
||||||
* @param playSound
|
* @param playSound
|
||||||
|
* @param showMessage
|
||||||
*/
|
*/
|
||||||
export function updatePlayerMoney(scene: BattleScene, changeValue: number, playSound: boolean = true, showMessage: boolean = true) {
|
export function updatePlayerMoney(scene: BattleScene, changeValue: number, playSound: boolean = true, showMessage: boolean = true) {
|
||||||
scene.money = Math.min(Math.max(scene.money + changeValue, 0), Number.MAX_SAFE_INTEGER);
|
scene.money = Math.min(Math.max(scene.money + changeValue, 0), Number.MAX_SAFE_INTEGER);
|
||||||
|
|
|
@ -173,6 +173,9 @@ export default class MysteryEncounterIntroVisuals extends Phaser.GameObjects.Con
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load dex progress icon
|
||||||
|
this.scene.loadAtlas("encounter_radar", "mystery-encounters");
|
||||||
|
|
||||||
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
||||||
this.spriteConfigs.every((config) => {
|
this.spriteConfigs.every((config) => {
|
||||||
if (config.isItem) {
|
if (config.isItem) {
|
||||||
|
|
|
@ -273,8 +273,6 @@ export class LoadingScene extends SceneBase {
|
||||||
this.loadAtlas("xbox", "inputs");
|
this.loadAtlas("xbox", "inputs");
|
||||||
this.loadAtlas("keyboard", "inputs");
|
this.loadAtlas("keyboard", "inputs");
|
||||||
|
|
||||||
this.loadAtlas("encounter_radar", "mystery-encounters");
|
|
||||||
|
|
||||||
this.loadSe("select");
|
this.loadSe("select");
|
||||||
this.loadSe("menu_open");
|
this.loadSe("menu_open");
|
||||||
this.loadSe("hit");
|
this.loadSe("hit");
|
||||||
|
|
|
@ -117,9 +117,9 @@ export const EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// 1 to 256, set to null to ignore
|
// 1 to 256, set to null to ignore
|
||||||
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = 256;
|
export const MYSTERY_ENCOUNTER_RATE_OVERRIDE: number = null;
|
||||||
export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
|
export const MYSTERY_ENCOUNTER_TIER_OVERRIDE: MysteryEncounterTier = null;
|
||||||
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = MysteryEncounterType.POKEMON_SALESMAN;
|
export const MYSTERY_ENCOUNTER_OVERRIDE: MysteryEncounterType = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MODIFIER / ITEM OVERRIDES
|
* MODIFIER / ITEM OVERRIDES
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
|
import { Biome } from "#app/enums/biome";
|
||||||
|
import { MysteryEncounterType } from "#app/enums/mystery-encounter-type";
|
||||||
|
import { Species } from "#app/enums/species";
|
||||||
|
import GameManager from "#app/test/utils/gameManager";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import Battle from "#app/battle";
|
||||||
|
import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
|
import { EncounterOptionMode } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
|
import { runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounterTestUtils";
|
||||||
|
import BattleScene from "#app/battle-scene";
|
||||||
|
import { MysteryEncounterTier } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
|
import { PlayerPokemon } from "#app/field/pokemon";
|
||||||
|
import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
|
import { PokemonSalesmanEncounter } from "#app/data/mystery-encounters/encounters/pokemon-salesman-encounter";
|
||||||
|
|
||||||
|
const namespace = "mysteryEncounter:pokemonSalesman";
|
||||||
|
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||||
|
const defaultBiome = Biome.CAVE;
|
||||||
|
const defaultWave = 45;
|
||||||
|
|
||||||
|
describe("The Pokemon Salesman - Mystery Encounter", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
let scene: BattleScene;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({ type: Phaser.HEADLESS });
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
scene = game.scene;
|
||||||
|
game.override.mysteryEncounterChance(100);
|
||||||
|
game.override.mysteryEncounterTier(MysteryEncounterTier.COMMON);
|
||||||
|
game.override.startingWave(defaultWave);
|
||||||
|
game.override.startingBiome(defaultBiome);
|
||||||
|
|
||||||
|
const biomeMap = new Map<Biome, MysteryEncounterType[]>([
|
||||||
|
[Biome.VOLCANO, [MysteryEncounterType.MYSTERIOUS_CHALLENGERS]],
|
||||||
|
]);
|
||||||
|
HUMAN_TRANSITABLE_BIOMES.forEach(biome => {
|
||||||
|
biomeMap.set(biome, [MysteryEncounterType.POKEMON_SALESMAN]);
|
||||||
|
});
|
||||||
|
vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
vi.clearAllMocks();
|
||||||
|
vi.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have the correct properties", async () => {
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||||
|
|
||||||
|
expect(PokemonSalesmanEncounter.encounterType).toBe(MysteryEncounterType.POKEMON_SALESMAN);
|
||||||
|
expect(PokemonSalesmanEncounter.encounterTier).toBe(MysteryEncounterTier.ULTRA);
|
||||||
|
expect(PokemonSalesmanEncounter.dialogue).toBeDefined();
|
||||||
|
expect(PokemonSalesmanEncounter.dialogue.intro).toStrictEqual([
|
||||||
|
{ text: `${namespace}:intro` },
|
||||||
|
{ speaker: "mysteryEncounter:pokemonSalesman:speaker", text: "mysteryEncounter:pokemonSalesman:intro_dialogue" }
|
||||||
|
]);
|
||||||
|
expect(PokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.title).toBe(`${namespace}:title`);
|
||||||
|
expect(PokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.description).toBe(`${namespace}:description`);
|
||||||
|
expect(PokemonSalesmanEncounter.dialogue.encounterOptionsDialogue.query).toBe(`${namespace}:query`);
|
||||||
|
expect(PokemonSalesmanEncounter.options.length).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not spawn outside of HUMAN_TRANSITABLE_BIOMES", async () => {
|
||||||
|
game.override.startingBiome(Biome.VOLCANO);
|
||||||
|
await game.runToMysteryEncounter();
|
||||||
|
|
||||||
|
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.POKEMON_SALESMAN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not run below wave 10", async () => {
|
||||||
|
game.override.startingWave(9);
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter();
|
||||||
|
|
||||||
|
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.POKEMON_SALESMAN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not run above wave 179", async () => {
|
||||||
|
game.override.startingWave(181);
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter();
|
||||||
|
|
||||||
|
expect(scene.currentBattle.mysteryEncounter).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should initialize fully ", async () => {
|
||||||
|
vi.spyOn(scene, "currentBattle", "get").mockReturnValue({ mysteryEncounter: PokemonSalesmanEncounter } as Battle);
|
||||||
|
|
||||||
|
const { onInit } = PokemonSalesmanEncounter;
|
||||||
|
|
||||||
|
expect(PokemonSalesmanEncounter.onInit).toBeDefined();
|
||||||
|
|
||||||
|
const onInitResult = onInit(scene);
|
||||||
|
|
||||||
|
expect(PokemonSalesmanEncounter.dialogueTokens?.purchasePokemon).toBeDefined();
|
||||||
|
expect(PokemonSalesmanEncounter.dialogueTokens?.price).toBeDefined();
|
||||||
|
expect(PokemonSalesmanEncounter.misc.pokemon instanceof PlayerPokemon).toBeTruthy();
|
||||||
|
expect(PokemonSalesmanEncounter.misc?.price?.toString()).toBe(PokemonSalesmanEncounter.dialogueTokens?.price);
|
||||||
|
expect(onInitResult).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Option 1 - Purchase the pokemon", () => {
|
||||||
|
it("should have the correct properties", () => {
|
||||||
|
const option1 = PokemonSalesmanEncounter.options[0];
|
||||||
|
expect(option1.optionMode).toBe(EncounterOptionMode.DEFAULT_OR_SPECIAL);
|
||||||
|
expect(option1.dialogue).toBeDefined();
|
||||||
|
expect(option1.dialogue).toStrictEqual({
|
||||||
|
buttonLabel: `${namespace}:option:1:label`,
|
||||||
|
buttonTooltip: `${namespace}:option:1:tooltip`,
|
||||||
|
selected: [
|
||||||
|
{
|
||||||
|
text: `${namespace}:option:1:selected_message`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should update the player's money properly", async () => {
|
||||||
|
const initialMoney = 20000;
|
||||||
|
scene.money = initialMoney;
|
||||||
|
const updateMoneySpy = vi.spyOn(EncounterPhaseUtils, "updatePlayerMoney");
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||||
|
await runSelectMysteryEncounterOption(game, 1);
|
||||||
|
|
||||||
|
const price = scene.currentBattle.mysteryEncounter.misc.price;
|
||||||
|
|
||||||
|
expect(updateMoneySpy).toHaveBeenCalledWith(scene, -price, true, false);
|
||||||
|
expect(scene.money).toBe(initialMoney - price);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should add the Pokemon to the party", async () => {
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||||
|
|
||||||
|
const initialPartySize = scene.getParty().length;
|
||||||
|
const pokemonName = scene.currentBattle.mysteryEncounter.misc.pokemon.name;
|
||||||
|
|
||||||
|
await runSelectMysteryEncounterOption(game, 1);
|
||||||
|
|
||||||
|
expect(scene.getParty().length).toBe(initialPartySize + 1);
|
||||||
|
expect(scene.getParty().find(p => p.name === pokemonName) instanceof PlayerPokemon).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should leave encounter without battle", async () => {
|
||||||
|
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||||
|
await runSelectMysteryEncounterOption(game, 1);
|
||||||
|
|
||||||
|
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Option 2 - Leave", () => {
|
||||||
|
it("should leave encounter without battle", async () => {
|
||||||
|
const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle");
|
||||||
|
|
||||||
|
await game.runToMysteryEncounter(MysteryEncounterType.POKEMON_SALESMAN, defaultParty);
|
||||||
|
await runSelectMysteryEncounterOption(game, 2);
|
||||||
|
|
||||||
|
expect(leaveEncounterWithoutBattleSpy).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -22,6 +22,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
|
||||||
|
import { PokemonBaseStatTotalModifier } from "#app/modifier/modifier";
|
||||||
|
|
||||||
const namespace = "mysteryEncounter:theStrongStuff";
|
const namespace = "mysteryEncounter:theStrongStuff";
|
||||||
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
const defaultParty = [Species.LAPRAS, Species.GENGAR, Species.ABRA];
|
||||||
|
@ -153,7 +154,9 @@ describe("The Strong Stuff - Mystery Encounter", () => {
|
||||||
await runSelectMysteryEncounterOption(game, 1);
|
await runSelectMysteryEncounterOption(game, 1);
|
||||||
|
|
||||||
const bstsAfter = scene.getParty().map(p => {
|
const bstsAfter = scene.getParty().map(p => {
|
||||||
return p.getSpeciesForm().getBaseStatTotal();
|
const baseStats = p.getSpeciesForm().baseStats.slice(0);
|
||||||
|
scene.applyModifiers(PokemonBaseStatTotalModifier, true, p, baseStats);
|
||||||
|
return baseStats.reduce((a, b) => a + b);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(bstsAfter[0]).toEqual(bstsPrior[0] - 20 * 6);
|
expect(bstsAfter[0]).toEqual(bstsPrior[0] - 20 * 6);
|
||||||
|
|
|
@ -298,7 +298,7 @@ describe("Mystery Encounter Utils", () => {
|
||||||
const spy = vi.spyOn(game.scene.ui, "showDialogue");
|
const spy = vi.spyOn(game.scene.ui, "showDialogue");
|
||||||
|
|
||||||
showEncounterDialogue(scene, "mysteryEncounter:unit_test_dialogue", "mysteryEncounter:unit_test_dialogue");
|
showEncounterDialogue(scene, "mysteryEncounter:unit_test_dialogue", "mysteryEncounter:unit_test_dialogue");
|
||||||
expect(spy).toHaveBeenCalledWith("valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", "valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", null, undefined, 0, 0);
|
expect(spy).toHaveBeenCalledWith("valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", "valuevalue {{testvalue}} {{test1}} {{test}} {{test\\}} {{test\\}} {test}}", null, expect.any(Function), 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,14 @@ export default class MockText {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disableInteractive() {
|
||||||
|
// Disables interaction with this Game Object.
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTint() {
|
||||||
|
// Clears tint on this Game Object.
|
||||||
|
}
|
||||||
|
|
||||||
add(obj) {
|
add(obj) {
|
||||||
// Adds a child to this Game Object.
|
// Adds a child to this Game Object.
|
||||||
this.list.push(obj);
|
this.list.push(obj);
|
||||||
|
|
Loading…
Reference in New Issue