Added overloads to modifier functions, cleaned up existing uses theroef

This commit is contained in:
Bertie690 2025-06-05 23:02:55 -04:00
parent 8cf8c854ce
commit e089fd28f2
24 changed files with 126 additions and 139 deletions

View File

@ -0,0 +1,4 @@
import type { Modifier } from "../modifier/modifier";
export type ModifierPredicate = (modifier: Modifier) => boolean;
export type ModifierIdentityPredicate<T extends Modifier> = (modifier: Modifier) => modifier is T;

View File

@ -19,12 +19,8 @@ import {
type Constructor,
} from "#app/utils/common";
import { deepMergeSpriteData } from "#app/utils/data";
import type {
Modifier,
ModifierIdentityPredicate,
ModifierPredicate,
TurnHeldItemTransferModifier,
} from "./modifier/modifier";
import type { Modifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import type { ModifierIdentityPredicate, ModifierPredicate } from "./@types/modifier-predicate";
import {
ConsumableModifier,
ConsumablePokemonModifier,
@ -2125,9 +2121,10 @@ export default class BattleScene extends SceneBase {
enemy.getSpeciesForm().getBaseExp() *
(enemy.level / this.getMaxExpLevel()) *
((enemy.ivs.reduce((iv: number, total: number) => (total += iv), 0) / 93) * 0.2 + 0.8);
this.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id, false).map(
m => (scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier()),
);
this.findModifiers(
(m): m is PokemonHeldItemModifier => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id,
false,
).forEach(m => (scoreIncrease *= m.getScoreMultiplier()));
if (enemy.isBoss()) {
scoreIncrease *= Math.sqrt(enemy.bossSegments);
}
@ -3070,9 +3067,10 @@ export default class BattleScene extends SceneBase {
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
newItemModifier.pokemonId = target.id;
const matchingModifier = this.findModifier(
m => m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
target.isPlayer(),
) as PokemonHeldItemModifier;
);
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount();
@ -3137,9 +3135,10 @@ export default class BattleScene extends SceneBase {
}
const matchingModifier = this.findModifier(
m => m instanceof PokemonHeldItemModifier && m.matchType(mod) && m.pokemonId === target.id,
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.matchType(mod) && m.pokemonId === target.id,
target.isPlayer(),
) as PokemonHeldItemModifier;
);
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount();
@ -3365,28 +3364,29 @@ export default class BattleScene extends SceneBase {
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @returns the list of all modifiers that matched `modifierType`.
* @deprecated - use `findModifiers`
*/
getModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player = true): T[] {
return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType);
}
findModifiers<T extends PersistentModifier>(modifierFilter: ModifierIdentityPredicate<T>, isPlayer?: boolean): T[];
findModifiers(modifierFilter: ModifierPredicate, isPlayer?: boolean): PersistentModifier[];
/**
* Get all of the modifiers that pass the `modifierFilter` function
* @param modifierFilter - The function used to filter a target's modifiers
* @param isPlayer - Whether to search the player (`true`) or the enemy (`false`) party; default `true`.
* @returns - An array containing all modifiers that passed the `modifierFilter` function.
*/
findModifiers(modifierFilter: ModifierPredicate, isPlayer?: boolean): PersistentModifier[];
findModifiers<T extends PersistentModifier>(modifierFilter: ModifierIdentityPredicate<T>, isPlayer?: boolean): T[];
findModifiers(modifierFilter: ModifierPredicate, isPlayer = true): PersistentModifier[] {
return (isPlayer ? this.modifiers : this.enemyModifiers).filter(modifierFilter);
}
findModifier(modifierFilter: ModifierPredicate, player?: boolean): PersistentModifier | undefined;
findModifier<T extends PersistentModifier>(
modifierFilter: ModifierIdentityPredicate<T>,
player?: boolean,
): T | undefined;
findModifier(modifierFilter: ModifierPredicate, player?: boolean): PersistentModifier | undefined;
/**
* Get the first modifier that passes the `modifierFilter` function.
* @param modifierFilter - The function used to filter a target's modifiers.
@ -3503,13 +3503,10 @@ export default class BattleScene extends SceneBase {
let matchingFormChange: SpeciesFormChange | null;
if (pokemon.species.speciesId === SpeciesId.NECROZMA && matchingFormChangeOpts.length > 1) {
// Ultra Necrozma is changing its form back, so we need to figure out into which form it devolves.
const formChangeItemModifiers = (
this.findModifiers(
m => m instanceof PokemonFormChangeItemModifier && m.pokemonId === pokemon.id,
) as PokemonFormChangeItemModifier[]
)
.filter(m => m.active)
.map(m => m.formChangeItem);
const formChangeItemModifiers = this.findModifiers(
(m): m is PokemonFormChangeItemModifier =>
m instanceof PokemonFormChangeItemModifier && m.active && m.pokemonId === pokemon.id,
).map(m => m.formChangeItem);
matchingFormChange = formChangeItemModifiers.includes(FormChangeItem.N_LUNARIZER)
? matchingFormChangeOpts[0]
@ -3691,13 +3688,13 @@ export default class BattleScene extends SceneBase {
): void {
const participantIds = pokemonParticipantIds ?? this.currentBattle.playerParticipantIds;
const party = this.getPlayerParty();
const expShareModifier = this.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
const expBalanceModifier = this.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
const expShareModifier = this.findModifier(m => m instanceof ExpShareModifier);
const expBalanceModifier = this.findModifier(m => m instanceof ExpBalanceModifier);
const multipleParticipantExpBonusModifier = this.findModifier(
m => m instanceof MultipleParticipantExpBonusModifier,
) as MultipleParticipantExpBonusModifier;
const nonFaintedPartyMembers = party.filter(p => p.hp);
const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.getMaxExpLevel());
);
const nonFaintedPartyMembers = party.filter(p => p.hp > 0);
const expPartyMembers = party.filter(p => p.hp > 0 && p.level < this.getMaxExpLevel());
const partyMemberExp: number[] = [];
// EXP value calculation is based off Pokemon.getExpValue
if (useWaveIndexMultiplier) {

View File

@ -178,14 +178,14 @@ export default class Battle {
this.postBattleLoot.push(
...globalScene
.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable,
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable,
false,
)
.map(i => {
const ret = i as PokemonHeldItemModifier;
// @ts-ignore - this is awful to fix/change
ret.pokemonId = null;
return ret;
i.pokemonId = null;
return i;
}),
);
}

View File

@ -1777,8 +1777,10 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
}
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
return globalScene.findModifiers((m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()
);
}
}
@ -1904,8 +1906,10 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
}
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
return globalScene.findModifiers((m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()
);
}
}

View File

@ -815,7 +815,7 @@ export default class Move implements Localizable {
applyPreAttackAbAttrs(MoveTypeChangeAbAttr, source, target, this, true, typeChangeHolder, typeChangeMovePowerMultiplier);
const sourceTeraType = source.getTeraType();
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !globalScene.findModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
if (source.isTerastallized && sourceTeraType === this.type && power.value < 60 && this.priority <= 0 && !this.hasAttr(MultiHitAttr) && !globalScene.hasModifier(m => m instanceof PokemonMultiHitModifier && m.pokemonId === source.id)) {
power.value = 60;
}
@ -2570,8 +2570,10 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
}
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
return globalScene.findModifiers((m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()
);
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
@ -2652,8 +2654,10 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
}
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[];
return globalScene.findModifiers((m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier
&& m.pokemonId === target.id, target.isPlayer()
);
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
@ -2712,8 +2716,10 @@ export class EatBerryAttr extends MoveEffectAttr {
}
getTargetHeldBerries(target: Pokemon): BerryModifier[] {
return globalScene.findModifiers(m => m instanceof BerryModifier
&& (m as BerryModifier).pokemonId === target.id, target.isPlayer()) as BerryModifier[];
return globalScene.findModifiers((m): m is BerryModifier =>
m instanceof BerryModifier
&& m.pokemonId === target.id, target.isPlayer()
);
}
reduceBerryModifier(target: Pokemon) {

View File

@ -191,7 +191,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
globalScene.loadSe("Follow Me", "battle_anims", "Follow Me.mp3");
// Get all player berry items, remove from party, and store reference
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier);
// Sort berries by party member ID to more easily re-add later if necessary
const berryItemsMap = new Map<number, BerryModifier[]>();
@ -256,7 +256,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
// Remove the berries from the party
// Session has been safely saved at this point, so data won't be lost
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier) as BerryModifier[];
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier);
berryItems.forEach(berryMod => {
globalScene.removeModifier(berryMod);
});

View File

@ -314,12 +314,10 @@ function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
// Will try to apply to prioritized pokemon first, then do normal application method if it fails
if (prioritizedPokemon) {
const heldBerriesOfType = globalScene.findModifier(
m =>
m instanceof BerryModifier &&
m.pokemonId === prioritizedPokemon.id &&
(m as BerryModifier).berryType === berryType,
(m): m is BerryModifier =>
m instanceof BerryModifier && m.pokemonId === prioritizedPokemon.id && m.berryType === berryType,
true,
) as BerryModifier;
);
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
applyModifierTypeToPlayerPokemon(prioritizedPokemon, berry);
@ -330,9 +328,10 @@ function tryGiveBerry(prioritizedPokemon?: PlayerPokemon) {
// Iterate over the party until berry was successfully given
for (const pokemon of party) {
const heldBerriesOfType = globalScene.findModifier(
m => m instanceof BerryModifier && m.pokemonId === pokemon.id && (m as BerryModifier).berryType === berryType,
(m): m is BerryModifier =>
m instanceof BerryModifier && m.pokemonId === pokemon.id && (m as BerryModifier).berryType === berryType,
true,
) as BerryModifier;
);
if (!heldBerriesOfType || heldBerriesOfType.getStackCount() < heldBerriesOfType.getMaxStackCount()) {
applyModifierTypeToPlayerPokemon(pokemon, berry);

View File

@ -367,10 +367,10 @@ export const BugTypeSuperfanEncounter: MysteryEncounter = MysteryEncounterBuilde
const modifierOptions: ModifierTypeOption[] = [generateModifierTypeOption(modifierTypes.MASTER_BALL)!];
const specialOptions: ModifierTypeOption[] = [];
if (!globalScene.findModifier(m => m instanceof MegaEvolutionAccessModifier)) {
if (!globalScene.hasModifier(m => m instanceof MegaEvolutionAccessModifier)) {
modifierOptions.push(generateModifierTypeOption(modifierTypes.MEGA_BRACELET)!);
}
if (!globalScene.findModifier(m => m instanceof GigantamaxAccessModifier)) {
if (!globalScene.hasModifier(m => m instanceof GigantamaxAccessModifier)) {
modifierOptions.push(generateModifierTypeOption(modifierTypes.DYNAMAX_BAND)!);
}
const nonRareEvolutionModifier = generateModifierTypeOption(modifierTypes.EVOLUTION_ITEM);

View File

@ -166,7 +166,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
.withOptionPhase(async () => {
// Give the player an Amulet Coin
// Check if the player has max stacks of that item already
const existing = globalScene.findModifier(m => m instanceof MoneyMultiplierModifier) as MoneyMultiplierModifier;
const existing = globalScene.findModifier(m => m instanceof MoneyMultiplierModifier);
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
// At max stacks, give the first party pokemon a Shell Bell instead
@ -247,9 +247,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
// Give the player a Candy Jar if they gave a Berry, and a Berry Pouch for Reviver Seed
if (modifier instanceof BerryModifier) {
// Check if the player has max stacks of that Candy Jar already
const existing = globalScene.findModifier(
m => m instanceof LevelIncrementBoosterModifier,
) as LevelIncrementBoosterModifier;
const existing = globalScene.findModifier(m => m instanceof LevelIncrementBoosterModifier);
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
// At max stacks, give the first party pokemon a Shell Bell instead
@ -271,7 +269,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
}
} else {
// Check if the player has max stacks of that Berry Pouch already
const existing = globalScene.findModifier(m => m instanceof PreserveBerryModifier) as PreserveBerryModifier;
const existing = globalScene.findModifier(m => m instanceof PreserveBerryModifier);
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
// At max stacks, give the first party pokemon a Shell Bell instead
@ -357,7 +355,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
const chosenPokemon: PlayerPokemon = encounter.misc.chosenPokemon;
// Check if the player has max stacks of Healing Charm already
const existing = globalScene.findModifier(m => m instanceof HealingBoosterModifier) as HealingBoosterModifier;
const existing = globalScene.findModifier(m => m instanceof HealingBoosterModifier);
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {
// At max stacks, give the first party pokemon a Shell Bell instead

View File

@ -17,7 +17,8 @@ import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/myst
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { SpeciesId } from "#enums/species-id";
import { HitHealModifier, PokemonHeldItemModifier, TurnHealModifier } from "#app/modifier/modifier";
import { PokemonHeldItemModifier, TurnHealModifier } from "#app/modifier/modifier";
import type { HitHealModifier } from "#app/modifier/modifier";
import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import i18next from "#app/plugins/i18n";
@ -231,12 +232,10 @@ async function tryApplyDigRewardItems() {
// Iterate over the party until an item was successfully given
// First leftovers
for (const pokemon of party) {
const heldItems = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
const existingLeftovers = globalScene.findModifier(
(m): m is TurnHealModifier => m instanceof TurnHealModifier && m.pokemonId === pokemon.id,
true,
) as PokemonHeldItemModifier[];
const existingLeftovers = heldItems.find(m => m instanceof TurnHealModifier) as TurnHealModifier;
);
if (!existingLeftovers || existingLeftovers.getStackCount() < existingLeftovers.getMaxStackCount()) {
await applyModifierTypeToPlayerPokemon(pokemon, leftovers);
break;
@ -245,12 +244,10 @@ async function tryApplyDigRewardItems() {
// Second leftovers
for (const pokemon of party) {
const heldItems = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
const existingLeftovers = globalScene.findModifier(
(m): m is TurnHealModifier => m instanceof TurnHealModifier && m.pokemonId === pokemon.id,
true,
) as PokemonHeldItemModifier[];
const existingLeftovers = heldItems.find(m => m instanceof TurnHealModifier) as TurnHealModifier;
);
if (!existingLeftovers || existingLeftovers.getStackCount() < existingLeftovers.getMaxStackCount()) {
await applyModifierTypeToPlayerPokemon(pokemon, leftovers);
break;
@ -270,12 +267,10 @@ async function tryApplyDigRewardItems() {
// Only Shell bell
for (const pokemon of party) {
const heldItems = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
const existingShellBell = globalScene.findModifier(
(m): m is HitHealModifier => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
true,
) as PokemonHeldItemModifier[];
const existingShellBell = heldItems.find(m => m instanceof HitHealModifier) as HitHealModifier;
);
if (!existingShellBell || existingShellBell.getStackCount() < existingShellBell.getMaxStackCount()) {
await applyModifierTypeToPlayerPokemon(pokemon, shellBell);
break;

View File

@ -204,9 +204,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
// Remove 4 random berries from player's party
// Get all player berry items, remove from party, and store reference
const berryItems: BerryModifier[] = globalScene.findModifiers(
m => m instanceof BerryModifier,
) as BerryModifier[];
const berryItems = globalScene.findModifiers(m => m instanceof BerryModifier);
for (let i = 0; i < 4; i++) {
const index = randSeedInt(berryItems.length);
const randBerry = berryItems[index];

View File

@ -377,12 +377,10 @@ export class PersistentModifierRequirement extends EncounterSceneRequirement {
let modifierCount = 0;
for (const modifier of this.requiredHeldItemModifiers) {
const matchingMods = globalScene.findModifiers(m => m.constructor.name === modifier);
if (matchingMods?.length > 0) {
for (const matchingMod of matchingMods) {
modifierCount += matchingMod.stackCount;
}
}
}
return modifierCount >= this.minNumberOfItems;
}

View File

@ -404,12 +404,12 @@ export async function applyModifierTypeToPlayerPokemon(
// Check if the Pokemon has max stacks of that item already
const modifier = modType.newModifier(pokemon);
const existing = globalScene.findModifier(
m =>
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier &&
m.type.id === modType.id &&
m.pokemonId === pokemon.id &&
m.matchType(modifier),
) as PokemonHeldItemModifier;
);
// At max stacks
if (existing && existing.getStackCount() >= existing.getMaxStackCount()) {

View File

@ -1206,14 +1206,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.setScale(this.getSpriteScale());
}
getHeldItems(): PokemonHeldItemModifier[] {
/**
* Return all of this Pokemon's held modifiers.
* @param transferrableOnly - Whether to only consider transferrable held items; default `false`
* @returns An array of all {@linkcode PokemonHeldItemModifier}s held by this Pokemon.
*/
getHeldItems(transferrableOnly = this.getFusionIconAtlasKey): PokemonHeldItemModifier[] {
if (!globalScene) {
return [];
}
return globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === this.id,
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.pokemonId === this.id && !(transferrableOnly && !m.isTransferable()),
this.isPlayer(),
) as PokemonHeldItemModifier[];
);
}
updateScale(): void {
@ -5872,10 +5878,7 @@ export class PlayerPokemon extends Pokemon {
globalScene.getPlayerParty().push(newPokemon);
newPokemon.evolve(!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution), evoSpecies);
const modifiers = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === this.id,
true,
) as PokemonHeldItemModifier[];
const modifiers = this.getHeldItems();
modifiers.forEach(m => {
const clonedModifier = m.clone() as PokemonHeldItemModifier;
clonedModifier.pokemonId = newPokemon.id;
@ -5993,11 +5996,7 @@ export class PlayerPokemon extends Pokemon {
}
// combine the two mons' held items
const fusedPartyMemberHeldModifiers = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id,
true,
) as PokemonHeldItemModifier[];
for (const modifier of fusedPartyMemberHeldModifiers) {
for (const modifier of pokemon.getHeldItems()) {
globalScene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true, false);
}
globalScene.updateModifiers(true, true);

View File

@ -394,8 +394,9 @@ export class PokemonHeldItemModifierType extends PokemonModifierType {
(pokemon: PlayerPokemon) => {
const dummyModifier = this.newModifier(pokemon);
const matchingModifier = globalScene.findModifier(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(dummyModifier),
) as PokemonHeldItemModifier;
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(dummyModifier),
);
const maxStackCount = dummyModifier.getMaxStackCount();
if (!maxStackCount) {
return i18next.t("modifierType:ModifierType.PokemonHeldItemModifierType.extra.inoperable", {

View File

@ -54,9 +54,6 @@ import {
} from "#app/data/abilities/ability";
import { globalScene } from "#app/global-scene";
export type ModifierPredicate = (modifier: Modifier) => boolean;
export type ModifierIdentityPredicate<T extends Modifier> = (modifier: Modifier) => modifier is T;
const iconOverflowIndex = 24;
export const modifierSortFunc = (a: Modifier, b: Modifier): number => {
@ -3253,10 +3250,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
}
const transferredModifierTypes: ModifierType[] = [];
const itemModifiers = globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === targetPokemon.id && m.isTransferable,
targetPokemon.isPlayer(),
) as PokemonHeldItemModifier[];
const itemModifiers = targetPokemon.getHeldItems();
for (let i = 0; i < transferredItemCount; i++) {
if (!itemModifiers.length) {

View File

@ -82,8 +82,9 @@ export class BattleEndPhase extends BattlePhase {
}
const lapsingModifiers = globalScene.findModifiers(
m => m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier,
) as (LapsingPersistentModifier | LapsingPokemonHeldItemModifier)[];
(m): m is LapsingPersistentModifier | LapsingPokemonHeldItemModifier =>
m instanceof LapsingPersistentModifier || m instanceof LapsingPokemonHeldItemModifier,
);
for (const m of lapsingModifiers) {
const args: any[] = [];
if (m instanceof LapsingPokemonHeldItemModifier) {

View File

@ -40,7 +40,7 @@ export class SelectBiomePhase extends BattlePhase {
.filter(b => !Array.isArray(b) || !randSeedInt(b[1]))
.map(b => (!Array.isArray(b) ? b : b[0]));
if (biomes.length > 1 && globalScene.findModifier(m => m instanceof MapModifier)) {
if (biomes.length > 1 && globalScene.hasModifier(m => m instanceof MapModifier)) {
const biomeSelectItems = biomes.map(b => {
const ret: OptionSelectItem = {
label: getBiomeName(b),

View File

@ -15,12 +15,7 @@ import {
getPlayerModifierTypeOptions,
} from "#app/modifier/modifier-type";
import type { Modifier } from "#app/modifier/modifier";
import {
ExtraModifierModifier,
HealShopCostModifier,
PokemonHeldItemModifier,
TempExtraModifierModifier,
} from "#app/modifier/modifier";
import { ExtraModifierModifier, HealShopCostModifier, TempExtraModifierModifier } from "#app/modifier/modifier";
import type ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler";
import { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler";
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler";
@ -150,12 +145,7 @@ export class SelectModifierPhase extends BattlePhase {
fromSlotIndex !== toSlotIndex &&
itemIndex > -1
) {
const itemModifiers = globalScene.findModifiers(
m =>
m instanceof PokemonHeldItemModifier &&
m.isTransferable &&
m.pokemonId === party[fromSlotIndex].id,
) as PokemonHeldItemModifier[];
const itemModifiers = party[toSlotIndex].getHeldItems(true);
const itemModifier = itemModifiers[itemIndex];
globalScene.tryTransferHeldItemModifier(
itemModifier,

View File

@ -138,7 +138,6 @@ export class SwitchSummonPhase extends SummonPhase {
return;
}
if (this.switchType === SwitchType.BATON_PASS) {
// If switching via baton pass, update opposing tags coming from the prior pokemon
(this.player ? globalScene.getEnemyField() : globalScene.getPlayerField()).forEach((enemyPokemon: Pokemon) =>
@ -147,17 +146,17 @@ export class SwitchSummonPhase extends SummonPhase {
// If the recipient pokemon lacks a baton, give our baton to it during the swap
if (
!globalScene.findModifier(
!globalScene.hasModifier(
m =>
m instanceof SwitchEffectTransferModifier &&
(m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id,
)
) {
const batonPassModifier = globalScene.findModifier(
m =>
(m): m is SwitchEffectTransferModifier =>
m instanceof SwitchEffectTransferModifier &&
(m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id,
) as SwitchEffectTransferModifier;
);
if (batonPassModifier) {
globalScene.tryTransferHeldItemModifier(

View File

@ -225,8 +225,9 @@ export default class PartyUiHandler extends MessageUiHandler {
public static FilterItemMaxStacks = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => {
const matchingModifier = globalScene.findModifier(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(modifier),
) as PokemonHeldItemModifier;
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.pokemonId === pokemon.id && m.matchType(modifier),
);
if (matchingModifier && matchingModifier.stackCount === matchingModifier.getMaxStackCount()) {
return i18next.t("partyUiHandler:tooManyItems", { pokemonName: getPokemonNameWithAffix(pokemon, false) });
}
@ -552,11 +553,11 @@ export default class PartyUiHandler extends MessageUiHandler {
// this next bit checks to see if the the selected item from the original transfer pokemon exists on the new pokemon `p`
// this returns `undefined` if the new pokemon doesn't have the item at all, otherwise it returns the `pokemonHeldItemModifier` for that item
const matchingModifier = globalScene.findModifier(
m =>
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier &&
m.pokemonId === newPokemon.id &&
m.matchType(this.getTransferrableItemsFromPokemon(pokemon)[this.transferOptionCursor]),
) as PokemonHeldItemModifier;
);
const partySlot = this.partySlots.filter(m => m.getPokemon() === newPokemon)[0]; // this gets pokemon [p] for us
if (p !== this.transferCursor) {
// this skips adding the able/not able labels on the pokemon doing the transfer
@ -1161,9 +1162,9 @@ export default class PartyUiHandler extends MessageUiHandler {
}
private allowBatonModifierSwitch(): boolean {
return !!(
return (
this.partyUiMode !== PartyUiMode.FAINT_SWITCH &&
globalScene.findModifier(
globalScene.hasModifier(
m =>
m instanceof SwitchEffectTransferModifier && m.pokemonId === globalScene.getPlayerField()[this.fieldIndex].id,
)

View File

@ -19,7 +19,9 @@ describe("Abilities - Harvest", () => {
let game: GameManager;
const getPlayerBerries = () =>
game.scene.getModifiers(BerryModifier, true).filter(b => b.pokemonId === game.scene.getPlayerPokemon()?.id);
game.scene.findModifiers(
(b): b is BerryModifier => b instanceof BerryModifier && b.pokemonId === game.scene.getPlayerPokemon()!.id,
);
/** Check whether the player's Modifiers contains the specified berries and nothing else. */
function expectBerriesContaining(...berries: ModifierOverride[]): void {

View File

@ -64,8 +64,8 @@ describe("Items - Dire Hit", () => {
await game.phaseInterceptor.to(BattleEndPhase);
const modifier = game.scene.findModifier(m => m instanceof TempCritBoosterModifier) as TempCritBoosterModifier;
expect(modifier.getBattleCount()).toBe(4);
const modifier = game.scene.findModifier(m => m instanceof TempCritBoosterModifier);
expect(modifier?.getBattleCount()).toBe(4);
// Forced DIRE_HIT to spawn in the first slot with override
game.onNextPrompt(

View File

@ -157,9 +157,10 @@ describe("Absolute Avarice - Mystery Encounter", () => {
for (const partyPokemon of scene.getPlayerParty()) {
const pokemonId = partyPokemon.id;
const pokemonItems = scene.findModifiers(
m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === pokemonId,
(m): m is PokemonHeldItemModifier =>
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"),
);