Partially fixed absolute avarice, fixed HeldItemRequirement to actually count the items

This commit is contained in:
Wlowscha 2025-07-12 13:14:35 +02:00
parent e312a4b8f2
commit ee2412cafb
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
3 changed files with 37 additions and 66 deletions

View File

@ -30,7 +30,7 @@ import { Stat } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro"; import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
import { MoveUseMode } from "#enums/move-use-mode"; import { MoveUseMode } from "#enums/move-use-mode";
import type { HeldItemConfiguration } from "#app/items/held-item-data-types"; import type { HeldItemConfiguration, PokemonItemMap } from "#app/items/held-item-data-types";
import { allHeldItems } from "#app/data/data-lists"; import { allHeldItems } from "#app/data/data-lists";
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id"; import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import { HeldItemRequirement } from "../mystery-encounter-requirements"; import { HeldItemRequirement } from "../mystery-encounter-requirements";
@ -113,7 +113,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
// Get all berries in party, with references to the pokemon // Get all berries in party, with references to the pokemon
const berryItems = getPartyBerries(); const berryItems = getPartyBerries();
encounter.misc.berryItemsMap = berryItems; encounter.misc = { berryItemsMap: berryItems };
// Adds stolen berries to the Greedent item configuration // Adds stolen berries to the Greedent item configuration
const bossHeldItemConfig: HeldItemConfiguration = []; const bossHeldItemConfig: HeldItemConfiguration = [];
@ -164,7 +164,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
// Session has been safely saved at this point, so data won't be lost // Session has been safely saved at this point, so data won't be lost
const berryItems = getPartyBerries(); const berryItems = getPartyBerries();
berryItems.forEach(map => { berryItems.forEach(map => {
globalScene.getPokemonById(map.pokemonId)?.heldItemManager.remove(map.item.id); globalScene.getPokemonById(map.pokemonId)?.heldItemManager.remove(map.item.id as HeldItemId);
}); });
globalScene.updateItems(true); globalScene.updateItems(true);
@ -225,13 +225,12 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
}) })
.withOptionPhase(async () => { .withOptionPhase(async () => {
const encounter = globalScene.currentBattle.mysteryEncounter!; const encounter = globalScene.currentBattle.mysteryEncounter!;
const berryMap = encounter.misc.berryItemsMap; const berryMap = encounter.misc.berryItemsMap as PokemonItemMap[];
// Returns 2/5 of the berries stolen to each Pokemon // Returns 2/5 of the berries stolen to each Pokemon
const party = globalScene.getPlayerParty(); const party = globalScene.getPlayerParty();
party.forEach(pokemon => { party.forEach(pokemon => {
// TODO: is this check legal? const stolenBerries = berryMap.filter(map => map.pokemonId === pokemon.id);
const stolenBerries = berryMap.filter(map => map.pokemon === pokemon);
const returnedBerryCount = Math.floor(((stolenBerries.length ?? 0) * 2) / 5); const returnedBerryCount = Math.floor(((stolenBerries.length ?? 0) * 2) / 5);
if (returnedBerryCount > 0) { if (returnedBerryCount > 0) {
@ -239,7 +238,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
// Shuffle remaining berry types and pop // Shuffle remaining berry types and pop
Phaser.Math.RND.shuffle(stolenBerries); Phaser.Math.RND.shuffle(stolenBerries);
const randBerryType = stolenBerries.pop(); const randBerryType = stolenBerries.pop();
pokemon.heldItemManager.add(randBerryType); pokemon.heldItemManager.add(randBerryType?.item.id as HeldItemId);
} }
} }
}); });

View File

@ -886,33 +886,24 @@ export class HeldItemRequirement extends EncounterSceneRequirement {
if (isNullOrUndefined(partyPokemon)) { if (isNullOrUndefined(partyPokemon)) {
return false; return false;
} }
console.log("COUNTED:", this.queryPartyForItems(partyPokemon), this.minNumberOfItems);
return this.queryPartyForItems(partyPokemon) >= this.minNumberOfItems; return this.queryPartyForItems(partyPokemon) >= this.minNumberOfItems;
} }
queryPartyForItems(partyPokemon: PlayerPokemon[]): number { queryPartyForItems(partyPokemon: PlayerPokemon[]): number {
if (!this.invertQuery) { let count = 0;
return partyPokemon.reduce((count, pokemon) => { for (const pokemon of partyPokemon) {
const matchingItems = this.requiredHeldItems.filter(heldItem => { for (const item of pokemon.getHeldItems()) {
return this.requireTransferable const itemInList = this.requiredHeldItems.some(
? pokemon.heldItemManager.hasTransferableItem(heldItem)
: pokemon.heldItemManager.hasItem(heldItem);
});
return count + matchingItems.length;
}, 0);
}
// for an inverted query, we only want to get the pokemon that have any held items that are NOT in requiredHeldItemModifiers
// E.g. functions as a blacklist
return partyPokemon.reduce((count, pokemon) => {
const matchingItems = pokemon.getHeldItems().filter(item => {
const notRequired = !this.requiredHeldItems.some(
heldItem => item === heldItem || getHeldItemCategory(item) === heldItem, heldItem => item === heldItem || getHeldItemCategory(item) === heldItem,
); );
const transferableOk = !this.requireTransferable || allHeldItems[item].isTransferable; const requiredItem = this.invertQuery ? !itemInList : itemInList;
return notRequired && transferableOk; if (requiredItem && (!this.requireTransferable || allHeldItems[item].isTransferable)) {
}); count += pokemon.heldItemManager.getStack(item);
}
return count + matchingItems.length; }
}, 0); }
return count;
} }
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {

View File

@ -12,14 +12,12 @@ import type BattleScene from "#app/battle-scene";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters";
import { BerryModifier, PokemonHeldItemModifier } from "#app/modifier/modifier";
import { BerryType } from "#enums/berry-type";
import { AbsoluteAvariceEncounter } from "#app/data/mystery-encounters/encounters/absolute-avarice-encounter"; import { AbsoluteAvariceEncounter } from "#app/data/mystery-encounters/encounters/absolute-avarice-encounter";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { CommandPhase } from "#app/phases/command-phase"; import { CommandPhase } from "#app/phases/command-phase";
import { MovePhase } from "#app/phases/move-phase"; import { MovePhase } from "#app/phases/move-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase"; import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import i18next from "i18next"; import { HeldItemId } from "#enums/held-item-id";
const namespace = "mysteryEncounters/absoluteAvarice"; const namespace = "mysteryEncounters/absoluteAvarice";
const defaultParty = [SpeciesId.LAPRAS, SpeciesId.GENGAR, SpeciesId.ABRA]; const defaultParty = [SpeciesId.LAPRAS, SpeciesId.GENGAR, SpeciesId.ABRA];
@ -77,8 +75,6 @@ describe("Absolute Avarice - Mystery Encounter", () => {
}); });
it("should not spawn if player does not have enough berries", async () => { it("should not spawn if player does not have enough berries", async () => {
scene.modifiers = [];
await game.runToMysteryEncounter(); await game.runToMysteryEncounter();
expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.ABSOLUTE_AVARICE); expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.ABSOLUTE_AVARICE);
@ -86,9 +82,9 @@ describe("Absolute Avarice - Mystery Encounter", () => {
it("should spawn if player has enough berries", async () => { it("should spawn if player has enough berries", async () => {
game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT).startingHeldItems([ game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT).startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS }, { entry: HeldItemId.SITRUS_BERRY, count: 2 },
{ name: "BERRY", count: 3, type: BerryType.GANLON }, { entry: HeldItemId.GANLON_BERRY, count: 3 },
{ name: "BERRY", count: 2, type: BerryType.APICOT }, { entry: HeldItemId.APICOT_BERRY, count: 2 },
]); ]);
await game.runToMysteryEncounter(); await game.runToMysteryEncounter();
@ -98,15 +94,15 @@ describe("Absolute Avarice - Mystery Encounter", () => {
it("should remove all player's berries at the start of the encounter", async () => { it("should remove all player's berries at the start of the encounter", async () => {
game.override.startingHeldItems([ game.override.startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS }, { entry: HeldItemId.SITRUS_BERRY, count: 2 },
{ name: "BERRY", count: 3, type: BerryType.GANLON }, { entry: HeldItemId.GANLON_BERRY, count: 3 },
{ name: "BERRY", count: 2, type: BerryType.APICOT }, { entry: HeldItemId.APICOT_BERRY, count: 2 },
]); ]);
await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty);
expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE); expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE);
expect(scene.modifiers?.length).toBe(0); expect(scene.getPlayerParty()[0].getHeldItems().length).toBe(0);
}); });
describe("Option 1 - Fight the Greedent", () => { describe("Option 1 - Fight the Greedent", () => {
@ -151,16 +147,7 @@ describe("Absolute Avarice - Mystery Encounter", () => {
expect(scene.phaseManager.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name); expect(scene.phaseManager.getCurrentPhase()?.constructor.name).toBe(SelectModifierPhase.name);
for (const partyPokemon of scene.getPlayerParty()) { for (const partyPokemon of scene.getPlayerParty()) {
const pokemonId = partyPokemon.id; expect(partyPokemon.heldItemManager.getStack(HeldItemId.REVIVER_SEED)).toBe(1);
const pokemonItems = scene.findModifiers(
m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === pokemonId,
true,
) as PokemonHeldItemModifier[];
const revSeed = pokemonItems.find(
i => i.type.name === i18next.t("modifierType:ModifierType.REVIVER_SEED.name"),
);
expect(revSeed).toBeDefined;
expect(revSeed?.stackCount).toBe(1);
} }
}); });
}); });
@ -183,42 +170,36 @@ describe("Absolute Avarice - Mystery Encounter", () => {
it("Should return 3 (2/5ths floored) berries if 8 were stolen", { retry: 5 }, async () => { it("Should return 3 (2/5ths floored) berries if 8 were stolen", { retry: 5 }, async () => {
game.override.startingHeldItems([ game.override.startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS }, { entry: HeldItemId.SITRUS_BERRY, count: 2 },
{ name: "BERRY", count: 3, type: BerryType.GANLON }, { entry: HeldItemId.GANLON_BERRY, count: 3 },
{ name: "BERRY", count: 3, type: BerryType.APICOT }, { entry: HeldItemId.APICOT_BERRY, count: 3 },
]); ]);
await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty);
expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE); expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE);
expect(scene.modifiers?.length).toBe(0); expect(scene.getPlayerParty()[0].getHeldItems().length).toBe(0);
await runMysteryEncounterToEnd(game, 2); await runMysteryEncounterToEnd(game, 2);
const berriesAfter = scene.findModifiers(m => m instanceof BerryModifier); expect(scene.getPlayerParty()[0].heldItemManager.getHeldItemCount()).toBe(3);
const berryCountAfter = berriesAfter.reduce((a, b) => a + b.stackCount, 0);
expect(berriesAfter).toBeDefined();
expect(berryCountAfter).toBe(3);
}); });
it("Should return 2 (2/5ths floored) berries if 7 were stolen", { retry: 5 }, async () => { it("Should return 2 (2/5ths floored) berries if 7 were stolen", { retry: 5 }, async () => {
game.override.startingHeldItems([ game.override.startingHeldItems([
{ name: "BERRY", count: 2, type: BerryType.SITRUS }, { entry: HeldItemId.SITRUS_BERRY, count: 2 },
{ name: "BERRY", count: 3, type: BerryType.GANLON }, { entry: HeldItemId.GANLON_BERRY, count: 3 },
{ name: "BERRY", count: 2, type: BerryType.APICOT }, { entry: HeldItemId.APICOT_BERRY, count: 2 },
]); ]);
await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty); await game.runToMysteryEncounter(MysteryEncounterType.ABSOLUTE_AVARICE, defaultParty);
expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE); expect(scene.currentBattle?.mysteryEncounter?.encounterType).toBe(MysteryEncounterType.ABSOLUTE_AVARICE);
expect(scene.modifiers?.length).toBe(0); expect(scene.getPlayerParty()[0].getHeldItems().length).toBe(0);
await runMysteryEncounterToEnd(game, 2); await runMysteryEncounterToEnd(game, 2);
const berriesAfter = scene.findModifiers(m => m instanceof BerryModifier); expect(scene.getPlayerParty()[0].heldItemManager.getHeldItemCount()).toBe(2);
const berryCountAfter = berriesAfter.reduce((a, b) => a + b.stackCount, 0);
expect(berriesAfter).toBeDefined();
expect(berryCountAfter).toBe(2);
}); });
it("should leave encounter without battle", async () => { it("should leave encounter without battle", async () => {