diff --git a/src/battle-scene.ts b/src/battle-scene.ts index bf6bd4833dc..276904da191 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -2717,11 +2717,12 @@ export default class BattleScene extends SceneBase { } /** - * Try to transfer a held item to another pokemon. + * Try to transfer a held item from source to target. * If the recepient already has the maximum amount allowed for this item, the transfer is cancelled. * The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item. * A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful. * @param heldItemId {@linkcode HeldItemId} item to transfer + * @param source {@linkcode Pokemon} giver in this transfer * @param target {@linkcode Pokemon} recepient in this transfer * @param playSound `true` to play a sound when transferring the item * @param transferQuantity How many items of the stack to transfer. Optional, defaults to `1` diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 4b461e7e9fa..cbeb66aea56 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -35,7 +35,7 @@ import { } from "#app/data/moves/move"; import { allMoves } from "../data-lists"; import { ArenaTagSide } from "#app/data/arena-tag"; -import { BerryModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; +import { BerryModifier, type PokemonHeldItemModifier } from "#app/modifier/modifier"; import { TerrainType } from "#app/data/terrain"; import { SpeciesFormChangeAbilityTrigger, @@ -91,6 +91,7 @@ import type Move from "#app/data/moves/move"; import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; import { HeldItemId } from "#enums/held-item-id"; +import { allHeldItems } from "#app/items/all-held-items"; export class BlockRecoilDamageAttr extends AbAttr { constructor() { @@ -2540,17 +2541,11 @@ export class AllyStatMultiplierAbAttr extends AbAttr { * @extends AbAttr */ export class ExecutedMoveAbAttr extends AbAttr { - canApplyExecutedMove( - _pokemon: Pokemon, - _simulated: boolean, - ): boolean { + canApplyExecutedMove(_pokemon: Pokemon, _simulated: boolean): boolean { return true; } - applyExecutedMove( - _pokemon: Pokemon, - _simulated: boolean, - ): void {} + applyExecutedMove(_pokemon: Pokemon, _simulated: boolean): void {} } /** @@ -2558,7 +2553,7 @@ export class ExecutedMoveAbAttr extends AbAttr { * @extends ExecutedMoveAbAttr */ export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr { - constructor(showAbility: boolean = false) { + constructor(showAbility = false) { super(showAbility); } @@ -2575,7 +2570,7 @@ export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr { export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { private stealCondition: PokemonAttackCondition | null; - private stolenItem?: PokemonHeldItemModifier; + private stolenItem?: HeldItemId; constructor(stealCondition?: PokemonAttackCondition) { super(); @@ -2598,11 +2593,11 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { hitResult < HitResult.NO_EFFECT && (!this.stealCondition || this.stealCondition(pokemon, defender, move)) ) { - const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable); + const heldItems = defender.heldItemManager.getTransferableHeldItems(); if (heldItems.length) { // Ensure that the stolen item in testing is the same as when the effect is applied this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; - if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) { + if (globalScene.canTransferHeldItem(this.stolenItem, defender, pokemon)) { return true; } } @@ -2620,28 +2615,21 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { _hitResult: HitResult, _args: any[], ): void { - const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable); + const heldItems = defender.heldItemManager.getTransferableHeldItems(); if (!this.stolenItem) { this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; } - if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { + if (globalScene.tryTransferHeldItem(this.stolenItem, defender, pokemon, false)) { globalScene.phaseManager.queueMessage( i18next.t("abilityTriggers:postAttackStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), defenderName: defender.name, - stolenItemType: this.stolenItem.type.name, + stolenItemType: allHeldItems[this.stolenItem].name, }), ); } this.stolenItem = undefined; } - - getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { - return globalScene.findModifiers( - m => m instanceof PokemonHeldItemModifier && m.pokemonId === target.id, - target.isPlayer(), - ) as PokemonHeldItemModifier[]; - } } export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr { @@ -2762,7 +2750,7 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr { export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { private condition?: PokemonDefendCondition; - private stolenItem?: PokemonHeldItemModifier; + private stolenItem?: HeldItemId; constructor(condition?: PokemonDefendCondition) { super(); @@ -2780,10 +2768,10 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { _args: any[], ): boolean { if (!simulated && hitResult < HitResult.NO_EFFECT && (!this.condition || this.condition(pokemon, attacker, move))) { - const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferable); + const heldItems = attacker.heldItemManager.getTransferableHeldItems(); if (heldItems.length) { this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; - if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) { + if (globalScene.canTransferHeldItem(this.stolenItem, attacker, pokemon)) { return true; } } @@ -2800,28 +2788,21 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { _hitResult: HitResult, _args: any[], ): void { - const heldItems = this.getTargetHeldItems(attacker).filter(i => i.isTransferable); + const heldItems = attacker.heldItemManager.getTransferableHeldItems(); if (!this.stolenItem) { this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; } - if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { + if (globalScene.tryTransferHeldItem(this.stolenItem, attacker, pokemon, false)) { globalScene.phaseManager.queueMessage( i18next.t("abilityTriggers:postDefendStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), attackerName: attacker.name, - stolenItemType: this.stolenItem.type.name, + stolenItemType: allHeldItems[this.stolenItem].name, }), ); } this.stolenItem = undefined; } - - getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { - return globalScene.findModifiers( - m => m instanceof PokemonHeldItemModifier && m.pokemonId === target.id, - target.isPlayer(), - ) as PokemonHeldItemModifier[]; - } } /** @@ -7782,7 +7763,7 @@ export function applyPreAttackAbAttrs( export function applyExecutedMoveAbAttrs( attrType: Constructor, pokemon: Pokemon, - simulated: boolean = false, + simulated = false, ...args: any[] ): void { applyAbAttrsInternal( diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index f670da69fd0..84a1ee49df9 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2559,16 +2559,18 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { return false; } - const heldItems = this.getTargetHeldItems(target).filter((i) => i.isTransferable); + const heldItems = target.heldItemManager.getTransferableHeldItems(); if (!heldItems.length) { return false; } - const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; - const highestItemTier = heldItems.map((m) => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct? - const tierHeldItems = heldItems.filter((m) => m.type.getOrInferTier(poolType) === highestItemTier); - const stolenItem = tierHeldItems[user.randBattleSeedInt(tierHeldItems.length)]; - if (!globalScene.tryTransferHeldItemModifier(stolenItem, user, false)) { + const stolenItem = heldItems[user.randBattleSeedInt(heldItems.length)]; + +// const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; +// const highestItemTier = heldItems.map((m) => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct? +// const tierHeldItems = heldItems.filter((m) => m.type.getOrInferTier(poolType) === highestItemTier); +// const stolenItem = tierHeldItems[user.randBattleSeedInt(tierHeldItems.length)]; + if (!globalScene.tryTransferHeldItem(stolenItem, target, user, false)) { return false; } @@ -2576,18 +2578,13 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { return true; } - getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { - return globalScene.findModifiers(m => m instanceof PokemonHeldItemModifier - && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier[]; - } - getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - const heldItems = this.getTargetHeldItems(target); + const heldItems = target.heldItemManager.getTransferableHeldItems(); return heldItems.length ? 5 : 0; } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - const heldItems = this.getTargetHeldItems(target); + const heldItems = target.heldItemManager.getTransferableHeldItems(); return heldItems.length ? -5 : 0; } } diff --git a/src/field/pokemon-held-item-manager.ts b/src/field/pokemon-held-item-manager.ts index 71385cda254..564b01e3a41 100644 --- a/src/field/pokemon-held-item-manager.ts +++ b/src/field/pokemon-held-item-manager.ts @@ -35,6 +35,24 @@ export class PokemonItemManager { return Object.keys(this.heldItems).map(k => Number(k)); } + getTransferableHeldItems(): number[] { + return Object.keys(this.heldItems) + .filter(k => allHeldItems[k].isTransferable) + .map(k => Number(k)); + } + + getStealableHeldItems(): number[] { + return Object.keys(this.heldItems) + .filter(k => allHeldItems[k].isStealable) + .map(k => Number(k)); + } + + getSuppressableHeldItems(): number[] { + return Object.keys(this.heldItems) + .filter(k => allHeldItems[k].isSuppressable) + .map(k => Number(k)); + } + hasItem(itemType: HeldItemId): boolean { return itemType in this.heldItems; } diff --git a/src/items/held-items/item-steal.ts b/src/items/held-items/item-steal.ts index 1e338c98d9a..d5712187b2e 100644 --- a/src/items/held-items/item-steal.ts +++ b/src/items/held-items/item-steal.ts @@ -47,7 +47,7 @@ export abstract class ItemTransferHeldItem extends HeldItem { // TODO: Change this logic to use held items const transferredModifierTypes: HeldItemId[] = []; - const heldItems = targetPokemon.heldItemManager.getHeldItemKeys(); + const heldItems = targetPokemon.heldItemManager.getTransferableHeldItems(); for (let i = 0; i < transferredItemCount; i++) { if (!heldItems.length) { @@ -56,7 +56,7 @@ export abstract class ItemTransferHeldItem extends HeldItem { const randItemIndex = pokemon.randBattleSeedInt(heldItems.length); const randItem = heldItems[randItemIndex]; // TODO: Fix this after updating the various methods in battle-scene.ts - if (globalScene.tryTransferHeldItemModifier(randItem, pokemon, false)) { + if (globalScene.tryTransferHeldItem(randItem, targetPokemon, pokemon, false)) { transferredModifierTypes.push(randItem); heldItems.splice(randItemIndex, 1); }