Removed AttackTypeBoosterModifierRequirement for MEs

This commit is contained in:
Wlowscha 2025-06-10 00:12:14 +02:00
parent 4a3a442ebd
commit 3891ef5f85
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
4 changed files with 60 additions and 129 deletions

View File

@ -1,6 +1,5 @@
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { import {
generateModifierType,
generateModifierTypeOption, generateModifierTypeOption,
initBattleWithEnemyConfig, initBattleWithEnemyConfig,
leaveEncounterWithoutBattle, 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 { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { import {
AttackTypeBoosterHeldItemTypeRequirement,
CombinationPokemonRequirement, CombinationPokemonRequirement,
HeldItemRequirement, HeldItemRequirement,
TypeRequirement, TypeRequirement,
} from "#app/data/mystery-encounters/mystery-encounter-requirements"; } from "#app/data/mystery-encounters/mystery-encounter-requirements";
import { PokemonType } from "#enums/pokemon-type"; 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 { modifierTypes } from "#app/modifier/modifier-type";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { GigantamaxAccessModifier, MegaEvolutionAccessModifier } from "#app/modifier/modifier";
import {
ContactHeldItemTransferChanceModifier,
GigantamaxAccessModifier,
MegaEvolutionAccessModifier,
} from "#app/modifier/modifier";
import i18next from "i18next"; import i18next from "i18next";
import MoveInfoOverlay from "#app/ui/move-info-overlay"; import MoveInfoOverlay from "#app/ui/move-info-overlay";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; 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 */ /** the i18n namespace for the encounter */
const namespace = "mysteryEncounters/bugTypeSuperfan"; 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 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 = [ const PHYSICAL_TUTOR_MOVES = [
MoveId.MEGAHORN, MoveId.MEGAHORN,
MoveId.ATTACK_ORDER, MoveId.ATTACK_ORDER,
@ -184,8 +181,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
.withPrimaryPokemonRequirement( .withPrimaryPokemonRequirement(
CombinationPokemonRequirement.Some( CombinationPokemonRequirement.Some(
// Must have at least 1 Bug type on team, OR have a bug item somewhere on the team // Must have at least 1 Bug type on team, OR have a bug item somewhere on the team
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement(REQUIRED_ITEMS, 1),
new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1),
new TypeRequirement(PokemonType.BUG, false, 1), new TypeRequirement(PokemonType.BUG, false, 1),
), ),
) )
@ -257,13 +253,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
}, },
]; ];
const requiredItems = [ const requiredItemString = REQUIRED_ITEMS.map(m => allHeldItems[m].name ?? "unknown").join("/");
generateModifierType(modifierTypes.QUICK_CLAW),
generateModifierType(modifierTypes.GRIP_CLAW),
generateModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, [PokemonType.BUG]),
];
const requiredItemString = requiredItems.map(m => m?.name ?? "unknown").join("/");
encounter.setDialogueToken("requiredBugItems", requiredItemString); encounter.setDialogueToken("requiredBugItems", requiredItemString);
return true; return true;
@ -413,8 +403,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
.withPrimaryPokemonRequirement( .withPrimaryPokemonRequirement(
CombinationPokemonRequirement.Some( CombinationPokemonRequirement.Some(
// Meets one or both of the below reqs // Meets one or both of the below reqs
new HeldItemRequirement(["BypassSpeedChanceModifier", "ContactHeldItemTransferChanceModifier"], 1), new HeldItemRequirement(REQUIRED_ITEMS, 1),
new AttackTypeBoosterHeldItemTypeRequirement(PokemonType.BUG, 1),
), ),
) )
.withDialogue({ .withDialogue({
@ -437,25 +426,19 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
const onPokemonSelected = (pokemon: PlayerPokemon) => { const onPokemonSelected = (pokemon: PlayerPokemon) => {
// Get Pokemon held items and filter for valid ones // Get Pokemon held items and filter for valid ones
const validItems = pokemon.getHeldItems().filter(item => { const validItems = pokemon.heldItemManager.getTransferableHeldItems().filter(item => {
return ( item in REQUIRED_ITEMS;
(item instanceof BypassSpeedChanceModifier ||
item instanceof ContactHeldItemTransferChanceModifier ||
(item instanceof AttackTypeBoosterModifier &&
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)) &&
item.isTransferable
);
}); });
return validItems.map((modifier: PokemonHeldItemModifier) => { return validItems.map((item: HeldItemId) => {
const option: OptionSelectItem = { const option: OptionSelectItem = {
label: modifier.type.name, label: allHeldItems[item].name,
handler: () => { handler: () => {
// Pokemon and item selected // Pokemon and item selected
encounter.setDialogueToken("selectedItem", modifier.type.name); encounter.setDialogueToken("selectedItem", allHeldItems[item].name);
encounter.misc = { encounter.misc = {
chosenPokemon: pokemon, chosenPokemon: pokemon,
chosenModifier: modifier, chosenItem: item,
}; };
return true; return true;
}, },
@ -467,12 +450,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
const selectableFilter = (pokemon: Pokemon) => { const selectableFilter = (pokemon: Pokemon) => {
// If pokemon has valid item, it can be selected // If pokemon has valid item, it can be selected
const hasValidItem = pokemon.getHeldItems().some(item => { const hasValidItem = pokemon.getHeldItems().some(item => {
return ( item in REQUIRED_ITEMS;
item instanceof BypassSpeedChanceModifier ||
item instanceof ContactHeldItemTransferChanceModifier ||
(item instanceof AttackTypeBoosterModifier &&
(item.type as AttackTypeBoosterModifierType).moveType === PokemonType.BUG)
);
}); });
if (!hasValidItem) { if (!hasValidItem) {
return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null; return getEncounterText(`${namespace}:option.3.invalid_selection`) ?? null;
@ -489,7 +467,7 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon; const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
chosenPokemon.loseHeldItem(modifier, false); chosenPokemon.loseHeldItem(modifier, false);
globalScene.updateModifiers(true, true); globalScene.updateModifiers(true);
const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!; const bugNet = generateModifierTypeOption(modifierTypes.MYSTERY_ENCOUNTER_GOLDEN_BUG_NET)!;
bugNet.type.tier = ModifierTier.ROGUE; bugNet.type.tier = ModifierTier.ROGUE;

View File

@ -7,8 +7,6 @@ import { StatusEffect } from "#enums/status-effect";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import type { PlayerPokemon } from "#app/field/pokemon"; 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 { isNullOrUndefined } from "#app/utils/common";
import type { AbilityId } from "#enums/ability-id"; import type { AbilityId } from "#enums/ability-id";
import { MoveId } from "#enums/move-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 { SpeciesId } from "#enums/species-id";
import { SpeciesFormKey } from "#enums/species-form-key"; import { SpeciesFormKey } from "#enums/species-form-key";
import { TimeOfDay } from "#enums/time-of-day"; 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 { export interface EncounterRequirement {
meetsRequirement(): boolean; // Boolean to see if a requirement is met meetsRequirement(): boolean; // Boolean to see if a requirement is met
@ -897,72 +897,13 @@ export class CanEvolveWithItemRequirement extends EncounterPokemonRequirement {
} }
export class HeldItemRequirement extends EncounterPokemonRequirement { export class HeldItemRequirement extends EncounterPokemonRequirement {
requiredHeldItemModifiers: string[]; requiredHeldItems: HeldItemId[];
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[];
minNumberOfPokemon: number; minNumberOfPokemon: number;
invertQuery: boolean; invertQuery: boolean;
requireTransferable: boolean; requireTransferable: boolean;
constructor( constructor(
heldItemTypes: PokemonType | PokemonType[], heldItem: HeldItemId | HeldItemId[],
minNumberOfPokemon = 1, minNumberOfPokemon = 1,
invertQuery = false, invertQuery = false,
requireTransferable = true, requireTransferable = true,
@ -970,7 +911,7 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
super(); super();
this.minNumberOfPokemon = minNumberOfPokemon; this.minNumberOfPokemon = minNumberOfPokemon;
this.invertQuery = invertQuery; this.invertQuery = invertQuery;
this.requiredHeldItemTypes = Array.isArray(heldItemTypes) ? heldItemTypes : [heldItemTypes]; this.requiredHeldItems = Array.isArray(heldItem) ? heldItem : [heldItem];
this.requireTransferable = requireTransferable; this.requireTransferable = requireTransferable;
} }
@ -985,14 +926,9 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] { override queryParty(partyPokemon: PlayerPokemon[]): PlayerPokemon[] {
if (!this.invertQuery) { if (!this.invertQuery) {
return partyPokemon.filter(pokemon => return partyPokemon.filter(pokemon =>
this.requiredHeldItemTypes.some(heldItemType => { this.requiredHeldItems.some(heldItem => {
return pokemon.getHeldItems().some(it => { pokemon.heldItemManager.hasItem(heldItem) &&
return ( (!this.requireTransferable || allHeldItems[heldItem].isTransferable);
it instanceof AttackTypeBoosterModifier &&
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
(!this.requireTransferable || it.isTransferable)
);
});
}), }),
); );
} }
@ -1000,30 +936,24 @@ export class AttackTypeBoosterHeldItemTypeRequirement extends EncounterPokemonRe
// E.g. functions as a blacklist // E.g. functions as a blacklist
return partyPokemon.filter( return partyPokemon.filter(
pokemon => pokemon =>
pokemon.getHeldItems().filter(it => { pokemon.getHeldItems().filter(item => {
return !this.requiredHeldItemTypes.some( return (
heldItemType => !this.requiredHeldItems.some(heldItem => item === heldItem) &&
it instanceof AttackTypeBoosterModifier && (!this.requireTransferable || allHeldItems[item].isTransferable)
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType &&
(!this.requireTransferable || it.isTransferable),
); );
}).length > 0, }).length > 0,
); );
} }
override getDialogueToken(pokemon?: PlayerPokemon): [string, string] { override getDialogueToken(pokemon?: PlayerPokemon): [string, string] {
const requiredItems = pokemon?.getHeldItems().filter(it => { const requiredItems = pokemon?.getHeldItems().filter(item => {
return ( return (
this.requiredHeldItemTypes.some( this.requiredHeldItems.some(heldItem => item === heldItem) &&
heldItemType => (!this.requireTransferable || allHeldItems[item].isTransferable)
it instanceof AttackTypeBoosterModifier &&
(it.type as AttackTypeBoosterModifierType).moveType === heldItemType,
) &&
(!this.requireTransferable || it.isTransferable)
); );
}); });
if (requiredItems && requiredItems.length > 0) { if (requiredItems && requiredItems.length > 0) {
return ["heldItem", requiredItems[0].type.name]; return ["heldItem", allHeldItems[requiredItems[0]].name];
} }
return ["heldItem", ""]; return ["heldItem", ""];
} }

View File

@ -18,8 +18,8 @@ export interface ITEM_STEAL_PARAMS {
/** /**
* Abstract class for held items that steal other Pokemon's items. * Abstract class for held items that steal other Pokemon's items.
* @see {@linkcode TurnHeldItemTransferModifier} * @see {@linkcode TurnEndItemStealHeldItem}
* @see {@linkcode ContactHeldItemTransferChanceModifier} * @see {@linkcode ContactItemStealChanceHeldItem}
*/ */
export abstract class ItemTransferHeldItem extends HeldItem { export abstract class ItemTransferHeldItem extends HeldItem {
/** /**

View File

@ -1,7 +1,7 @@
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions"; import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import type { NumberHolder } from "#app/utils/common"; 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 { SpeciesId } from "#enums/species-id";
import type { Stat } from "#enums/stat"; import type { Stat } from "#enums/stat";
import { HeldItem, ITEM_EFFECT } from "../held-item"; 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 * Modifier used for held items that Applies {@linkcode Stat} boost(s) using a
* multiplier if the holder is of a specific {@linkcode SpeciesId}. * 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 */ /** The species that the held item's stat boost(s) apply to */
private species: SpeciesId[]; 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); super(type, maxStackCount, stats, multiplier);
this.species = species; this.species = species;
} }