From 3891ef5f8572ca140df35b842a367a229a76643b Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 10 Jun 2025 00:12:14 +0200 Subject: [PATCH] Removed AttackTypeBoosterModifierRequirement for MEs --- .../encounters/bug-type-superfan-encounter.ts | 56 +++------- .../mystery-encounter-requirements.ts | 102 +++--------------- src/items/held-items/item-steal.ts | 4 +- src/items/held-items/stat-booster.ts | 27 ++++- 4 files changed, 60 insertions(+), 129 deletions(-) diff --git a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts index 4dee937927e..51452422ef9 100644 --- a/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts +++ b/src/data/mystery-encounters/encounters/bug-type-superfan-encounter.ts @@ -1,6 +1,5 @@ import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { - generateModifierType, generateModifierTypeOption, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, @@ -31,26 +30,22 @@ import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler" import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { - AttackTypeBoosterHeldItemTypeRequirement, CombinationPokemonRequirement, HeldItemRequirement, TypeRequirement, } from "#app/data/mystery-encounters/mystery-encounter-requirements"; import { PokemonType } from "#enums/pokemon-type"; -import type { AttackTypeBoosterModifierType, ModifierTypeOption } from "#app/modifier/modifier-type"; +import type { ModifierTypeOption } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type"; -import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; -import { - ContactHeldItemTransferChanceModifier, - GigantamaxAccessModifier, - MegaEvolutionAccessModifier, -} from "#app/modifier/modifier"; +import { GigantamaxAccessModifier, MegaEvolutionAccessModifier } from "#app/modifier/modifier"; import i18next from "i18next"; import MoveInfoOverlay from "#app/ui/move-info-overlay"; import { allMoves } from "#app/data/data-lists"; import { ModifierTier } from "#app/modifier/modifier-tier"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { HeldItemId } from "#enums/held-item-id"; +import { allHeldItems } from "#app/items/all-held-items"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/bugTypeSuperfan"; @@ -141,6 +136,8 @@ const POOL_3_POKEMON: { species: SpeciesId; formIndex?: number }[] = [ const POOL_4_POKEMON = [SpeciesId.GENESECT, SpeciesId.SLITHER_WING, SpeciesId.BUZZWOLE, SpeciesId.PHEROMOSA]; +const REQUIRED_ITEMS = [HeldItemId.QUICK_CLAW, HeldItemId.GRIP_CLAW, HeldItemId.SILVER_POWDER]; + const PHYSICAL_TUTOR_MOVES = [ MoveId.MEGAHORN, MoveId.ATTACK_ORDER, @@ -184,8 +181,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde .withPrimaryPokemonRequirement( CombinationPokemonRequirement.Some( // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team - new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), - new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1), + new HeldItemRequirement(REQUIRED_ITEMS, 1), new TypeRequirement(PokemonType.BUG, false, 1), ), ) @@ -257,13 +253,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde }, ]; - const requiredItems = [ - generateModifierType(modifierTypes.QUICK_CLAW), - generateModifierType(modifierTypes.GRIP_CLAW), - generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [PokemonType.BUG]), - ]; - - const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/"); + const requiredItemString = REQUIRED_ITEMS.map(m => allHeldItems[m].name ?? "unknown").join("/"); encounter.setDialogueToken("requiredBugItems", requiredItemString); return true; @@ -413,8 +403,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde .withPrimaryPokemonRequirement( CombinationPokemonRequirement.Some( // Meets one or both of the below reqs - new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), - new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1), + new HeldItemRequirement(REQUIRED_ITEMS, 1), ), ) .withDialogue({ @@ -437,25 +426,19 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde const onPokemonSelected = (pokemon: PlayerPokemon) => { // Get Pokemon held items and filter for valid ones - const validItems = pokemon.getHeldItems().filter(item => { - return ( - (item instanceof BypassSpeedChanceModifier || - item instanceof ContactHeldItemTransferChanceModifier || - (item instanceof AttackTypeBoosterModifier && - (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)) && - item.isTransferable - ); + const validItems = pokemon.heldItemManager.getTransferableHeldItems().filter(item => { + item in REQUIRED_ITEMS; }); - return validItems.map((modifier: PokemonHeldItemModifier) => { + return validItems.map((item: HeldItemId) => { const option: OptionSelectItem = { - label: modifier.type.name, + label: allHeldItems[item].name, handler: () => { // Pokemon and item selected - encounter.setDialogueToken("selectedItem", modifier.type.name); + encounter.setDialogueToken("selectedItem", allHeldItems[item].name); encounter.misc = { chosenPokemon: pokemon, - chosenModifier: modifier, + chosenItem: item, }; return true; }, @@ -467,12 +450,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde const selectableFilter = (pokemon: Pokemon) => { // If pokemon has valid item, it can be selected const hasValidItem = pokemon.getHeldItems().some(item => { - return ( - item instanceof BypassSpeedChanceModifier || - item instanceof ContactHeldItemTransferChanceModifier || - (item instanceof AttackTypeBoosterModifier && - (item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG) - ); + item in REQUIRED_ITEMS; }); if (!hasValidItem) { return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null; @@ -489,7 +467,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; chosenPokemon.loseHeldItem(modifier, false); - globalScene.updateModifiers(true, true); + globalScene.updateModifiers(true); const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; bugNet.type.tier = ModifierTier.ROGUE; diff --git a/src/data/mystery-encounters/mystery-encounter-requirements.ts b/src/data/mystery-encounters/mystery-encounter-requirements.ts index 88d9ba402a9..f49129e5f87 100644 --- a/src/data/mystery-encounters/mystery-encounter-requirements.ts +++ b/src/data/mystery-encounters/mystery-encounter-requirements.ts @@ -7,8 +7,6 @@ import { StatusEffect } from "#enums/status-effect"; import { PokemonType } from "#enums/pokemon-type"; import { WeatherType } from "#enums/weather-type"; import type { PlayerPokemon } from "#app/field/pokemon"; -import { AttackTypeBoosterModifier } from "#app/modifier/modifier"; -import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type"; import { isNullOrUndefined } from "#app/utils/common"; import type { AbilityId } from "#enums/ability-id"; import { MoveId } from "#enums/move-id"; @@ -16,6 +14,8 @@ import type { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { SpeciesId } from "#enums/species-id"; import { SpeciesFormKey } from "#enums/species-form-key"; import { TimeOfDay } from "#enums/time-of-day"; +import type { HeldItemId } from "#enums/held-item-id"; +import { allHeldItems } from "#app/items/all-held-items"; export interface EncounterRequirement { meetsRequirement(): boolean; // Boolean to see if a requirement is met @@ -897,72 +897,13 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement { } export class HeldItemRequirement extends EncounterPokemonRequirement { - requiredHeldItemModifiers: string[]; - minNumberOfPokemon: number; - invertQuery: boolean; - requireTransferable: boolean; - - constructor(heldItem: string | string[], minNumberOfPokemon = 1, invertQuery = false, requireTransferable = true) { - super(); - this.minNumberOfPokemon = minNumberOfPokemon; - this.invertQuery = invertQuery; - this.requiredHeldItemModifiers = Array.isArray(heldItem) ? heldItem : [heldItem]; - this.requireTransferable = requireTransferable; - } - - override meetsRequirement(): boolean { - const partyPokemon = globalScene.getPlayerParty(); - if (isNullOrUndefined(partyPokemon)) { - return false; - } - return this.queryParty(partyPokemon).length >= this.minNumberOfPokemon; - } - - override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { - if (!this.invertQuery) { - return partyPokemon.filter(pokemon => - this.requiredHeldItemModifiers.some(heldItem => { - return pokemon.getHeldItems().some(it => { - return it.constructor.name === heldItem && (!this.requireTransferable || it.isTransferable); - }); - }), - ); - } - // 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.filter( - pokemon => - pokemon.getHeldItems().filter(it => { - return ( - !this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) && - (!this.requireTransferable || it.isTransferable) - ); - }).length > 0, - ); - } - - override getDialogueToken(pokemon?: PlayerPokemon): [string, string] { - const requiredItems = pokemon?.getHeldItems().filter(it => { - return ( - this.requiredHeldItemModifiers.some(heldItem => it.constructor.name === heldItem) && - (!this.requireTransferable || it.isTransferable) - ); - }); - if (requiredItems && requiredItems.length > 0) { - return ["heldItem", requiredItems[0].type.name]; - } - return ["heldItem", ""]; - } -} - -export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRequirement { - requiredHeldItemTypes: PokemonType[]; + requiredHeldItems: HeldItemId[]; minNumberOfPokemon: number; invertQuery: boolean; requireTransferable: boolean; constructor( - heldItemTypes: PokemonType | PokemonType[], + heldItem: HeldItemId | HeldItemId[], minNumberOfPokemon = 1, invertQuery = false, requireTransferable = true, @@ -970,7 +911,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe super(); this.minNumberOfPokemon = minNumberOfPokemon; this.invertQuery = invertQuery; - this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes]; + this.requiredHeldItems = Array.isArray(heldItem) ? heldItem : [heldItem]; this.requireTransferable = requireTransferable; } @@ -985,14 +926,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { if (!this.invertQuery) { return partyPokemon.filter(pokemon => - this.requiredHeldItemTypes.some(heldItemType => { - return pokemon.getHeldItems().some(it => { - return ( - it instanceof AttackTypeBoosterModifier && - (it.type as AttackTypeBoosterModifierType).moveType === heldItemType && - (!this.requireTransferable || it.isTransferable) - ); - }); + this.requiredHeldItems.some(heldItem => { + pokemon.heldItemManager.hasItem(heldItem) && + (!this.requireTransferable || allHeldItems[heldItem].isTransferable); }), ); } @@ -1000,30 +936,24 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe // E.g. functions as a blacklist return partyPokemon.filter( pokemon => - pokemon.getHeldItems().filter(it => { - return !this.requiredHeldItemTypes.some( - heldItemType => - it instanceof AttackTypeBoosterModifier && - (it.type as AttackTypeBoosterModifierType).moveType === heldItemType && - (!this.requireTransferable || it.isTransferable), + pokemon.getHeldItems().filter(item => { + return ( + !this.requiredHeldItems.some(heldItem => item === heldItem) && + (!this.requireTransferable || allHeldItems[item].isTransferable) ); }).length > 0, ); } override getDialogueToken(pokemon?: PlayerPokemon): [string, string] { - const requiredItems = pokemon?.getHeldItems().filter(it => { + const requiredItems = pokemon?.getHeldItems().filter(item => { return ( - this.requiredHeldItemTypes.some( - heldItemType => - it instanceof AttackTypeBoosterModifier && - (it.type as AttackTypeBoosterModifierType).moveType === heldItemType, - ) && - (!this.requireTransferable || it.isTransferable) + this.requiredHeldItems.some(heldItem => item === heldItem) && + (!this.requireTransferable || allHeldItems[item].isTransferable) ); }); if (requiredItems && requiredItems.length > 0) { - return ["heldItem", requiredItems[0].type.name]; + return ["heldItem", allHeldItems[requiredItems[0]].name]; } return ["heldItem", ""]; } diff --git a/src/items/held-items/item-steal.ts b/src/items/held-items/item-steal.ts index 9f2d292a713..57bf222ff82 100644 --- a/src/items/held-items/item-steal.ts +++ b/src/items/held-items/item-steal.ts @@ -18,8 +18,8 @@ export interface ITEM_STEAL_PARAMS { /** * Abstract class for held items that steal other Pokemon's items. - * @see {@linkcode TurnHeldItemTransferModifier} - * @see {@linkcode ContactHeldItemTransferChanceModifier} + * @see {@linkcode TurnEndItemStealHeldItem} + * @see {@linkcode ContactItemStealChanceHeldItem} */ export abstract class ItemTransferHeldItem extends HeldItem { /** diff --git a/src/items/held-items/stat-booster.ts b/src/items/held-items/stat-booster.ts index 831d645e807..0674cf83bc2 100644 --- a/src/items/held-items/stat-booster.ts +++ b/src/items/held-items/stat-booster.ts @@ -1,7 +1,7 @@ import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import type Pokemon from "#app/field/pokemon"; import type { NumberHolder } from "#app/utils/common"; -import type { HeldItemId } from "#enums/held-item-id"; +import { HeldItemId } from "#enums/held-item-id"; import type { SpeciesId } from "#enums/species-id"; import type { Stat } from "#enums/stat"; import { HeldItem, ITEM_EFFECT } from "../held-item"; @@ -112,6 +112,23 @@ export class EvolutionStatBoostHeldItem extends StatBoostHeldItem { } } +export type SpeciesStatBoosterItemId = + | typeof HeldItemId.LIGHT_BALL + | typeof HeldItemId.THICK_CLUB + | typeof HeldItemId.METAL_POWDER + | typeof HeldItemId.QUICK_POWDER + | typeof HeldItemId.DEEP_SEA_SCALE + | typeof HeldItemId.DEEP_SEA_TOOTH; + +export const SPECIES_STAT_BOOSTER_ITEMS: SpeciesStatBoosterItemId[] = [ + HeldItemId.LIGHT_BALL, + HeldItemId.THICK_CLUB, + HeldItemId.METAL_POWDER, + HeldItemId.QUICK_POWDER, + HeldItemId.DEEP_SEA_SCALE, + HeldItemId.DEEP_SEA_TOOTH, +]; + /** * Modifier used for held items that Applies {@linkcode Stat} boost(s) using a * multiplier if the holder is of a specific {@linkcode SpeciesId}. @@ -122,7 +139,13 @@ export class SpeciesStatBoostHeldItem extends StatBoostHeldItem { /** The species that the held item's stat boost(s) apply to */ private species: SpeciesId[]; - constructor(type: HeldItemId, maxStackCount = 1, stats: Stat[], multiplier: number, species: SpeciesId[]) { + constructor( + type: SpeciesStatBoosterItemId, + maxStackCount = 1, + stats: Stat[], + multiplier: number, + species: SpeciesId[], + ) { super(type, maxStackCount, stats, multiplier); this.species = species; }