diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 9e121b81fea..810cadc3a2a 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -959,22 +959,29 @@ class SafeguardTag extends ArenaTag { * Imprison will apply to any opposing Pokemon that switch onto the field as well. */ class ImprisonTag extends ArenaTrapTag { - private source: Pokemon; - constructor(sourceId: number, side: ArenaTagSide) { super(ArenaTagType.IMPRISON, Moves.IMPRISON, sourceId, side, 1); } + /** + * Helper function that retrieves the source Pokemon + * @param {BattleScene} scene medium to retrieve the source Pokemon + * @returns {Pokemon} pokemon or undefined + */ + private retrieveSource(scene: BattleScene): Pokemon | undefined { + if (this.sourceId) { + return scene.getPokemonById(this.sourceId) ?? undefined; + } + return undefined; + } + /** * Helper function that retrieves the Pokemon affected * @param {BattleScene} scene medium to retrieve the involved Pokemon - * @returns list of PlayerPokemon or EnemyPokemon on the field + * @returns list of opposing Pokemon on the field */ private retrieveField(scene: BattleScene): PlayerPokemon[] | EnemyPokemon[] { - if (!this.source.isPlayer()) { - return scene.getPlayerField() ?? []; - } - return scene.getEnemyField() ?? []; + return (this.side === ArenaTagSide.PLAYER) ? scene.getPlayerField() : scene.getEnemyField(); } /** @@ -982,13 +989,13 @@ class ImprisonTag extends ArenaTrapTag { * @param arena */ override onAdd({ scene }: Arena) { - this.source = scene.getPokemonById(this.sourceId!)!; - if (this.source) { + const source = this.retrieveSource(scene); + if (source) { const party = this.retrieveField(scene); party?.forEach((p: PlayerPokemon | EnemyPokemon ) => { p.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId); }); - scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", {pokemonNameWithAffix: getPokemonNameWithAffix(this.source)})); + scene.queueMessage(i18next.t("battlerTags:imprisonOnAdd", {pokemonNameWithAffix: getPokemonNameWithAffix(source)})); } } @@ -997,8 +1004,9 @@ class ImprisonTag extends ArenaTrapTag { * @param _arena * @returns `true` if the source of the tag is still active on the field | `false` if not */ - override lapse(_arena: Arena): boolean { - return this.source.isActive(true); + override lapse({ scene }: Arena): boolean { + const source = this.retrieveSource(scene); + return source ? source.isActive(true) : false; } /** @@ -1007,7 +1015,8 @@ class ImprisonTag extends ArenaTrapTag { * @returns `true` */ override activateTrap(pokemon: Pokemon): boolean { - if (this.source.isActive(true)) { + const source = this.retrieveSource(pokemon.scene); + if (source && source.isActive(true)) { pokemon.addTag(BattlerTagType.IMPRISON, 1, Moves.IMPRISON, this.sourceId); } return true; diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 01d569173c2..8300cc4a632 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -23,6 +23,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; import { StatStageChangePhase, StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import { PokemonAnimType } from "#app/enums/pokemon-anim-type"; +import { BattleScene } from "#app/battle-scene"; export enum BattlerTagLapseType { FAINT, @@ -137,9 +138,10 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag { * Gets whether this tag is restricting a move. * * @param {Moves} move {@linkcode Moves} ID to check restriction for. + * @param {Pokemon} user {@linkcode Pokemon} the Pokemon involved * @returns {boolean} `true` if the move is restricted by this tag, otherwise `false`. */ - abstract isMoveRestricted(move: Moves): boolean; + abstract isMoveRestricted(move: Moves, user?: Pokemon): boolean; /** * Checks if this tag is restricting a move based on a user's decisions during the target selection phase @@ -327,6 +329,11 @@ export class GorillaTacticsTag extends MoveRestrictionBattlerTag { pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.ATK, false) * 1.5, false); } + /** + * Loads the Gorilla Tactics Battler Tag along with its unique class variable moveId + * @override + * @param source {@linkcode BattlerTag} Gorilla Tactic's Battler Tag information + */ override loadTag(source: BattlerTag | any): void { super.loadTag(source); this.moveId = source.moveId; @@ -2487,8 +2494,6 @@ export class MysteryEncounterPostSummonTag extends BattlerTag { * Torment does not interrupt the move if the move is performed consecutively in the same turn and right after Torment is applied */ export class TormentTag extends MoveRestrictionBattlerTag { - private target: Pokemon; - constructor(sourceId: number) { super(BattlerTagType.TORMENT, BattlerTagLapseType.AFTER_MOVE, 1, Moves.TORMENT, sourceId); } @@ -2500,15 +2505,9 @@ export class TormentTag extends MoveRestrictionBattlerTag { */ override onAdd(pokemon: Pokemon) { super.onAdd(pokemon); - this.target = pokemon; pokemon.scene.queueMessage(i18next.t("battlerTags:tormentOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), 1500); } - override loadTag(source: BattlerTag | any): void { - super.loadTag(source); - this.target = source.target.toPokemon(); - } - /** * Torment only ends when the affected Pokemon leaves the battle field * @param {Pokemon} pokemon the Pokemon under the effects of Torment @@ -2524,8 +2523,8 @@ export class TormentTag extends MoveRestrictionBattlerTag { * @param {Moves} move the move under investigation * @returns `true` if there is valid consecutive usage | `false` if the moves are different from each other */ - override isMoveRestricted(move: Moves): boolean { - const lastMove = this.target.getLastXMoves(1)[0]; + override isMoveRestricted(move: Moves, user: Pokemon): boolean { + const lastMove = user.getLastXMoves(1)[0]; if ( !lastMove ) { return false; } @@ -2584,26 +2583,22 @@ export class TauntTag extends MoveRestrictionBattlerTag { * The tag is only removed when the source-user is removed from the field. */ export class ImprisonTag extends MoveRestrictionBattlerTag { - private source: Pokemon | null; - constructor(sourceId: number) { super(BattlerTagType.IMPRISON, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.AFTER_MOVE], 1, Moves.IMPRISON, sourceId); } - override onAdd(pokemon: Pokemon) { - if (this.sourceId) { - this.source = pokemon.scene.getPokemonById(this.sourceId); - } - } - /** * Checks if the source of Imprison is still active * @param _pokemon * @param _lapseType * @returns `true` if the source is still active */ - override lapse(_pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean { - return this.source?.isActive(true) ?? false; + override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean { + const source = this.retrieveSource(pokemon.scene); + if (source) { + return source.isActive(true) ?? false; + } + return false; } /** @@ -2611,19 +2606,14 @@ export class ImprisonTag extends MoveRestrictionBattlerTag { * @param {Moves} move the move under investigation * @returns `false` if either condition is not met */ - override isMoveRestricted(move: Moves): boolean { - if (this.source) { - const sourceMoveset = this.source.getMoveset().map(m => m!.moveId); - return sourceMoveset?.includes(move) && this.source.isActive(true); + override isMoveRestricted(move: Moves, user: Pokemon): boolean { + const source = this.retrieveSource(user.scene); + if (source) { + return source?.isActive(true) ?? false; } return false; } - override loadTag(source: BattlerTag | any): void { - super.loadTag(source); - this.source = source.source.toPokemon(); - } - override selectionDeniedText(_pokemon: Pokemon, move: Moves): string { return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name }); } @@ -2631,6 +2621,15 @@ export class ImprisonTag extends MoveRestrictionBattlerTag { override interruptedText(pokemon: Pokemon, move: Moves): string { return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name }); } + + /** + * Helper function that retrieves the source Pokemon object + * @param scene medium to retrieve the source Pokemon + * @returns source pokemon {@linkcode Pokemon} or undefined + */ + private retrieveSource(scene: BattleScene): Pokemon | undefined { + return scene.getPokemonById(this.sourceId); + } } /** diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c66da0572ad..2252b353dcd 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3059,7 +3059,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { */ getRestrictingTag(moveId: Moves, user?: Pokemon, target?: Pokemon): MoveRestrictionBattlerTag | null { for (const tag of this.findTags(t => t instanceof MoveRestrictionBattlerTag)) { - if ((tag as MoveRestrictionBattlerTag).isMoveRestricted(moveId)) { + if ((tag as MoveRestrictionBattlerTag).isMoveRestricted(moveId, user)) { return tag as MoveRestrictionBattlerTag; } else if (user && target && (tag as MoveRestrictionBattlerTag).isMoveTargetRestricted(moveId, user, target)) { return tag as MoveRestrictionBattlerTag;