From 6a1b675ad7d3408136f1504431c6796817bd116a Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 25 Feb 2025 11:54:45 -0800 Subject: [PATCH] Handle Mold Breaker case in MoveEndPhase --- src/data/ability.ts | 110 +++-------------------------------- src/field/pokemon.ts | 4 +- src/phases/move-end-phase.ts | 18 +++++- src/phases/move-phase.ts | 2 +- 4 files changed, 24 insertions(+), 110 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index e19b9e459d3..33739b324a9 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1932,42 +1932,6 @@ export class SynchronizeStatusAbAttr extends PostSetStatusAbAttr { } } -/** - * Remove the status condition of a pokemon that just gained it, if the pokemon is immune to that status by ability - * - * Occurs when, for example, Mold breaker is used to paralyze a pokemon with Limber - */ -export class PostSetStatusHealStatusAbAttr extends PostSetStatusAbAttr { - private immuneEffects: StatusEffect[]; - private statusHealed: StatusEffect; - - /** - * @param immuneEffects - The {@linkcode StatusEffect}s the Pokémon is immune to. - */ - constructor(...immuneEffects: StatusEffect[]) { - super(); - this.immuneEffects = immuneEffects; - } - - public override applyPostSetStatus(pokemon: Pokemon, sourcePokemon: (Pokemon | null) | undefined, passive: boolean, effect: StatusEffect, simulated: boolean, args: any[]): boolean { - const status = pokemon.status?.effect; - if (status && (this.immuneEffects.length < 1 || this.immuneEffects.includes(status))) { - this.statusHealed = status; - pokemon.resetStatus(false); - pokemon.updateInfo(); - return true; - } - return false; - } - - public override getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { - if (this.statusHealed) { - return getStatusEffectHealText(this.statusHealed, getPokemonNameWithAffix(_pokemon)); - } - return null; - } -} - export class PostVictoryAbAttr extends AbAttr { applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { return false; @@ -2162,6 +2126,11 @@ export class PostSummonAbAttr extends AbAttr { } } +/** + * Base class for ability attributes which remove an effect on summon + */ +export class PostSummonRemoveEffectAbAttr extends PostSummonAbAttr {} + /** * Removes specified arena tags when a Pokemon is summoned. */ @@ -2249,7 +2218,7 @@ export class PostSummonAddBattlerTagAbAttr extends PostSummonAbAttr { * * This should realistically only ever activate on gain rather than on summon */ -export class PostSummonRemoveBattlerTagAbAttr extends PostSummonAbAttr { +export class PostSummonRemoveBattlerTagAbAttr extends PostSummonRemoveEffectAbAttr { private immuneTags: BattlerTagType[]; /** @@ -2469,7 +2438,7 @@ export class PostSummonTerrainChangeAbAttr extends PostSummonAbAttr { /** * Heals a status effect if the Pokemon is afflicted with it upon switch in (or gain) */ -export class PostSummonHealStatusAbAttr extends PostSummonAbAttr { +export class PostSummonHealStatusAbAttr extends PostSummonRemoveEffectAbAttr { private immuneEffects: StatusEffect[]; private statusHealed: StatusEffect; @@ -3288,46 +3257,6 @@ export class MultCritAbAttr extends AbAttr { } } -/** - * Base class for ability attributes which activate when a {@linkcode BattlerTag} is added to the Pokemon - */ -export class PostApplyBattlerTagAbAttr extends AbAttr { - public applyPostApplyBattlerTag( - pokemon: Pokemon, - passive: boolean, - simulated: boolean, - tag: BattlerTag, - args: any[], - ): boolean { - return false; - } -} - -/** - * Removes a tag immediately after it was applied - * - * Occurs when a Pokemon immune to a tag is affected with it anyway (through mold breaker, etc.) - */ -export class PostApplyBattlerTagRemoveTagAbAttr extends PostApplyBattlerTagAbAttr { - private immuneTags: BattlerTagType[]; - - /** - * @param immuneTags - The {@linkcode BattlerTagType | battler tags} the Pokémon is immune to. - */ - constructor(...immuneTags: BattlerTagType[]) { - super(); - this.immuneTags = immuneTags; - } - - public override applyPostApplyBattlerTag(pokemon: Pokemon, passive: boolean, simulated: boolean, tag: BattlerTag, args: any[]): boolean { - if (this.immuneTags.includes(tag.tagType)) { - return pokemon.removeTag(tag.tagType); - } - - return false; - } -} - /** * Guarantees a critical hit according to the given condition, except if target prevents critical hits. ie. Merciless * @extends AbAttr @@ -6027,21 +5956,6 @@ export function applyPostItemLostAbAttrs( ); } -export function applyPostApplyBattlerTagAbAttrs( - attrType: Constructor, - pokemon: Pokemon, - tag: BattlerTag, - simulated: boolean = false, - ...args: any[] -): void { - applyAbAttrsInternal( - attrType, - pokemon, - (attr, passive) => attr.applyPostApplyBattlerTag(pokemon, passive, simulated, tag, args), - args, - ); -} - /** * Applies abilities when they become active mid-turn (ability switch) * @@ -6107,7 +6021,6 @@ export function initAbilities() { new Ability(Abilities.LIMBER, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.PARALYSIS) .attr(PostSummonHealStatusAbAttr, StatusEffect.PARALYSIS) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.PARALYSIS) .ignorable(), new Ability(Abilities.SAND_VEIL, 3) .attr(StatMultiplierAbAttr, Stat.EVA, 1.2) @@ -6126,7 +6039,6 @@ export function initAbilities() { new Ability(Abilities.OBLIVIOUS, 3) .attr(BattlerTagImmunityAbAttr, [ BattlerTagType.INFATUATED, BattlerTagType.TAUNT ]) .attr(PostSummonRemoveBattlerTagAbAttr, BattlerTagType.INFATUATED, BattlerTagType.TAUNT) - .attr(PostApplyBattlerTagRemoveTagAbAttr, BattlerTagType.INFATUATED, BattlerTagType.TAUNT) .attr(IntimidateImmunityAbAttr) .ignorable(), new Ability(Abilities.CLOUD_NINE, 3) @@ -6140,7 +6052,6 @@ export function initAbilities() { new Ability(Abilities.INSOMNIA, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) .attr(PostSummonHealStatusAbAttr, StatusEffect.SLEEP) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.SLEEP) .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable(), new Ability(Abilities.COLOR_CHANGE, 3) @@ -6149,7 +6060,6 @@ export function initAbilities() { new Ability(Abilities.IMMUNITY, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .attr(PostSummonHealStatusAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .ignorable(), new Ability(Abilities.FLASH_FIRE, 3) .attr(TypeImmunityAddBattlerTagAbAttr, Type.FIRE, BattlerTagType.FIRE_BOOST, 1) @@ -6160,7 +6070,6 @@ export function initAbilities() { new Ability(Abilities.OWN_TEMPO, 3) .attr(BattlerTagImmunityAbAttr, BattlerTagType.CONFUSED) .attr(PostSummonRemoveBattlerTagAbAttr, BattlerTagType.CONFUSED) - .attr(PostApplyBattlerTagRemoveTagAbAttr, BattlerTagType.CONFUSED) .attr(IntimidateImmunityAbAttr) .ignorable(), new Ability(Abilities.SUCTION_CUPS, 3) @@ -6228,12 +6137,10 @@ export function initAbilities() { new Ability(Abilities.MAGMA_ARMOR, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.FREEZE) .attr(PostSummonHealStatusAbAttr, StatusEffect.FREEZE) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.FREEZE) .ignorable(), new Ability(Abilities.WATER_VEIL, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.MAGNET_PULL, 3) .attr(ArenaTrapAbAttr, (user, target) => { @@ -6326,7 +6233,6 @@ export function initAbilities() { new Ability(Abilities.VITAL_SPIRIT, 3) .attr(StatusEffectImmunityAbAttr, StatusEffect.SLEEP) .attr(PostSummonHealStatusAbAttr, StatusEffect.SLEEP) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.SLEEP) .attr(BattlerTagImmunityAbAttr, BattlerTagType.DROWSY) .ignorable(), new Ability(Abilities.WHITE_SMOKE, 3) @@ -6738,7 +6644,6 @@ export function initAbilities() { .attr(MoveTypePowerBoostAbAttr, Type.WATER, 2) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.STEELWORKER, 7) .attr(MoveTypePowerBoostAbAttr, Type.STEEL), @@ -7019,7 +6924,6 @@ export function initAbilities() { .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => user.getMoveType(move) === Type.FIRE && move.category !== MoveCategory.STATUS, Stat.ATK, 1) .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) .attr(PostSummonHealStatusAbAttr, StatusEffect.BURN) - .attr(PostSetStatusHealStatusAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.ANGER_SHELL, 9) .attr(PostDefendHpGatedStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ Stat.ATK, Stat.SPATK, Stat.SPD ], 1) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b3b65770129..4c7b05ec4e1 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -64,7 +64,7 @@ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoo import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag"; import type { Ability, AbAttr } from "#app/data/ability"; -import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseClearWeatherAbAttrs, applyPostApplyBattlerTagAbAttrs, PostApplyBattlerTagAbAttr } from "#app/data/ability"; +import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseClearWeatherAbAttrs } from "#app/data/ability"; import type PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; import { Mode } from "#app/ui/ui"; @@ -3232,8 +3232,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!cancelled.value && newTag.canAdd(this)) { this.summonData.tags.push(newTag); newTag.onAdd(this); - globalScene.arena.setIgnoreAbilities(false); - applyPostApplyBattlerTagAbAttrs(PostApplyBattlerTagAbAttr, this, newTag); return true; } diff --git a/src/phases/move-end-phase.ts b/src/phases/move-end-phase.ts index 428dacd639a..3b711940be6 100644 --- a/src/phases/move-end-phase.ts +++ b/src/phases/move-end-phase.ts @@ -2,10 +2,16 @@ import { globalScene } from "#app/global-scene"; import type { BattlerIndex } from "#app/battle"; import { BattlerTagLapseType } from "#app/data/battler-tags"; import { PokemonPhase } from "./pokemon-phase"; +import { applyPostSummonAbAttrs, PostSummonRemoveEffectAbAttr } from "#app/data/ability"; +import type Pokemon from "#app/field/pokemon"; export class MoveEndPhase extends PokemonPhase { - constructor(battlerIndex: BattlerIndex) { + /** Targets from the preceding MovePhase */ + private targets: Pokemon[]; + constructor(battlerIndex: BattlerIndex, targets: Pokemon[]) { super(battlerIndex); + + this.targets = targets; } start() { @@ -13,11 +19,17 @@ export class MoveEndPhase extends PokemonPhase { const pokemon = this.getPokemon(); if (pokemon.isActive(true)) { - pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE); + pokemon. lapseTags(BattlerTagLapseType.AFTER_MOVE); } - globalScene.arena.setIgnoreAbilities(false); + // Remove effects which were set on a Pokemon which removes them on summon (i.e. via Mold Breaker) + for (const target of this.targets) { + if (target) { + applyPostSummonAbAttrs(PostSummonRemoveEffectAbAttr, target); + } + } + this.end(); } } diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index d58c052812f..95bd694d5df 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -427,7 +427,7 @@ export class MovePhase extends BattlePhase { */ public end(): void { if (!this.followUp && this.canMove()) { - globalScene.unshiftPhase(new MoveEndPhase(this.pokemon.getBattlerIndex())); + globalScene.unshiftPhase(new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon())); } super.end();