From 2b24d5cd09b063fad89c9ed892df4e36cd9051eb Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 18 Mar 2025 11:45:53 -0700 Subject: [PATCH 01/10] Fix applying even when suppressed --- src/data/ability.ts | 35 ++++++++++++++++----------------- src/data/moves/move.ts | 5 +++-- src/phases/move-effect-phase.ts | 3 +-- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index ab78d1dd06c..dac5ae2eaba 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -776,29 +776,28 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr { /** * Class for abilities that make drain moves deal damage to user instead of healing them. * @extends PostDefendAbAttr - * @see {@linkcode applyPostDefend} + * @see {@linkcode applyPreDefend} */ -export class ReverseDrainAbAttr extends PostDefendAbAttr { +export class ReverseDrainAbAttr extends PreDefendAbAttr { + private attacker: Pokemon; - override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { + /** + * Determines if a damage and draining move was used + * Examples include: Absorb, Draining Kiss, Bitter Blade, etc. + * + * If so, this ability should cause the move user should be damaged instead of healed + */ + override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + this.attacker = attacker; return move.hasAttr(HitHealAttr) && !move.hitsSubstitute(attacker, pokemon); } - /** - * Determines if a damage and draining move was used to check if this ability should stop the healing. - * Examples include: Absorb, Draining Kiss, Bitter Blade, etc. - * Also displays a message to show this ability was activated. - * @param pokemon {@linkcode Pokemon} with this ability - * @param _passive N/A - * @param attacker {@linkcode Pokemon} that is attacking this Pokemon - * @param move {@linkcode PokemonMove} that is being used - * @param _hitResult N/A - * @param _args N/A - */ - override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void { - if (!simulated) { - globalScene.queueMessage(i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(attacker) })); - } + override applyPreDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { + cancelled.value = true; + } + + public override getTriggerMessage(pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { + return i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(this.attacker) }); } } diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index f2157ab65b7..f11d8fe2688 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2176,7 +2176,8 @@ export class HitHealAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { let healAmount = 0; let message = ""; - const reverseDrain = target.hasAbilityWithAttr(ReverseDrainAbAttr, false); + const reverseDrain = new Utils.BooleanHolder(false); + applyPreDefendAbAttrs(ReverseDrainAbAttr, target, user, move, reverseDrain); if (this.healStat !== null) { // Strength Sap formula healAmount = target.getEffectiveStat(this.healStat); @@ -2186,7 +2187,7 @@ export class HitHealAttr extends MoveEffectAttr { healAmount = Utils.toDmgValue(user.turnData.singleHitDamageDealt * this.healRatio); message = i18next.t("battle:regainHealth", { pokemonName: getPokemonNameWithAffix(user) }); } - if (reverseDrain) { + if (reverseDrain.value) { if (user.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { healAmount = 0; message = ""; diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 4152fc243f0..29874348bc8 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -608,11 +608,10 @@ export class MoveEffectPhase extends PokemonPhase { /** * Applies reactive effects that occur when a Pokémon is hit. - * (i.e. Effect Spore, Disguise, Liquid Ooze, Beak Blast) + * (i.e. Effect Spore, Disguise, Beak Blast) * @param user - The {@linkcode Pokemon} using this phase's invoked move * @param target - {@linkcode Pokemon} the current target of this phase's invoked move * @param hitResult - The {@linkcode HitResult} of the attempted move - * @returns a `Promise` intended to be passed into a `then()` call. */ protected applyOnGetHitAbEffects(user: Pokemon, target: Pokemon, hitResult: HitResult): void { if (!target.isFainted() || target.canApplyAbility()) { From bcdeb8a36abbb7fdbf5cd3623438d6c905d9acde Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 18 Mar 2025 12:33:46 -0700 Subject: [PATCH 02/10] Rewrite move/ability effects --- src/data/ability.ts | 16 +++++++++++----- src/data/moves/move.ts | 27 ++++++++++----------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index dac5ae2eaba..6acae2b203f 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -776,9 +776,9 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr { /** * Class for abilities that make drain moves deal damage to user instead of healing them. * @extends PostDefendAbAttr - * @see {@linkcode applyPreDefend} + * @see {@linkcode applyPostDefend} */ -export class ReverseDrainAbAttr extends PreDefendAbAttr { +export class ReverseDrainAbAttr extends PostDefendAbAttr { private attacker: Pokemon; /** @@ -787,13 +787,19 @@ export class ReverseDrainAbAttr extends PreDefendAbAttr { * * If so, this ability should cause the move user should be damaged instead of healed */ - override canApplyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { + override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { this.attacker = attacker; return move.hasAttr(HitHealAttr) && !move.hitsSubstitute(attacker, pokemon); } - override applyPreDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): void { - cancelled.value = true; + override applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): void { + const cancelled = new Utils.BooleanHolder(false); + applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + if (!cancelled.value) { + const damageAmount = move.getAttrs(HitHealAttr)[0].getHealAmount(attacker, pokemon); + pokemon.turnData.damageTaken += damageAmount; + globalScene.unshiftPhase(new PokemonHealPhase(attacker.getBattlerIndex(), -damageAmount, null, false, true)); + } } public override getTriggerMessage(pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index f11d8fe2688..b40f35191f5 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2174,29 +2174,18 @@ export class HitHealAttr extends MoveEffectAttr { * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - let healAmount = 0; + if (target.hasAbilityWithAttr(ReverseDrainAbAttr)) { + return false; + } + + const healAmount = this.getHealAmount(user, target); let message = ""; - const reverseDrain = new Utils.BooleanHolder(false); - applyPreDefendAbAttrs(ReverseDrainAbAttr, target, user, move, reverseDrain); if (this.healStat !== null) { - // Strength Sap formula - healAmount = target.getEffectiveStat(this.healStat); message = i18next.t("battle:drainMessage", { pokemonName: getPokemonNameWithAffix(target) }); } else { - // Default healing formula used by draining moves like Absorb, Draining Kiss, Bitter Blade, etc. - healAmount = Utils.toDmgValue(user.turnData.singleHitDamageDealt * this.healRatio); message = i18next.t("battle:regainHealth", { pokemonName: getPokemonNameWithAffix(user) }); } - if (reverseDrain.value) { - if (user.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { - healAmount = 0; - message = ""; - } else { - user.turnData.damageTaken += healAmount; - healAmount = healAmount * -1; - message = ""; - } - } + globalScene.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true)); return true; } @@ -2215,6 +2204,10 @@ export class HitHealAttr extends MoveEffectAttr { } return Math.floor(Math.max((1 - user.getHpRatio()) - 0.33, 0) * (move.power / 4)); } + + public getHealAmount(user: Pokemon, target: Pokemon): number { + return (this.healStat) ? target.getEffectiveStat(this.healStat) : Utils.toDmgValue(user.turnData.singleHitDamageDealt * this.healRatio); + } } /** From e7e7ec97bcd38f526b639be81aaa03415437e287 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 18 Mar 2025 12:41:33 -0700 Subject: [PATCH 03/10] Fix using defender instead of attacker when applying magic guard --- src/data/ability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 6acae2b203f..761df44f6d2 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -794,7 +794,7 @@ export class ReverseDrainAbAttr extends PostDefendAbAttr { override applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): void { const cancelled = new Utils.BooleanHolder(false); - applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled); if (!cancelled.value) { const damageAmount = move.getAttrs(HitHealAttr)[0].getHealAmount(attacker, pokemon); pokemon.turnData.damageTaken += damageAmount; From 3363078bb4c08f8f4116deeeb94350adc1b1a833 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 18 Mar 2025 12:43:10 -0700 Subject: [PATCH 04/10] Add test --- test/abilities/liquid_ooze.test.ts | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 test/abilities/liquid_ooze.test.ts diff --git a/test/abilities/liquid_ooze.test.ts b/test/abilities/liquid_ooze.test.ts new file mode 100644 index 00000000000..b4ef530f433 --- /dev/null +++ b/test/abilities/liquid_ooze.test.ts @@ -0,0 +1,63 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Liquid Ooze", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.LIQUID_OOZE) + .enemyMoveset(Moves.SPLASH); + }); + + it("should drain the attacker's HP after a draining move", async () => { + game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.GIGA_DRAIN); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(false); + }); + + it("should not drain the attacker's HP if it ignores indirect damage", async () => { + game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20).ability(Abilities.MAGIC_GUARD); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.GIGA_DRAIN); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(true); + }); + + it("should not apply if suppressed", async () => { + game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20).ability(Abilities.NEUTRALIZING_GAS); + await game.classicMode.startBattle([Species.FEEBAS]); + + game.move.select(Moves.GIGA_DRAIN); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(true); + }); +}); From 3a37f301c5ae6c0b60c214cfedf0b9cafbdc7aec Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 18 Mar 2025 12:51:42 -0700 Subject: [PATCH 05/10] Unchange move effect phase --- src/phases/move-effect-phase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 29874348bc8..ad1b2dcffff 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -608,7 +608,7 @@ export class MoveEffectPhase extends PokemonPhase { /** * Applies reactive effects that occur when a Pokémon is hit. - * (i.e. Effect Spore, Disguise, Beak Blast) + * (i.e. Effect Spore, Disguise, Liquid Ooze, Beak Blast) * @param user - The {@linkcode Pokemon} using this phase's invoked move * @param target - {@linkcode Pokemon} the current target of this phase's invoked move * @param hitResult - The {@linkcode HitResult} of the attempted move From 0d6f45092ca8a2d0653bea209ad1b39430df8ed3 Mon Sep 17 00:00:00 2001 From: Dean <69436131+emdeann@users.noreply.github.com> Date: Tue, 8 Apr 2025 00:42:57 -0700 Subject: [PATCH 06/10] Kev fixes Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/data/ability.ts | 4 ++-- test/abilities/liquid_ooze.test.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index f82c17716f4..b1a1d76cff1 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -807,10 +807,10 @@ export class ReverseDrainAbAttr extends PostDefendAbAttr { private attacker: Pokemon; /** - * Determines if a damage and draining move was used + * Determines if a damage and draining move was used. * Examples include: Absorb, Draining Kiss, Bitter Blade, etc. * - * If so, this ability should cause the move user should be damaged instead of healed + * If so, this ability should cause the move user to be damaged instead of healed */ override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean { this.attacker = attacker; diff --git a/test/abilities/liquid_ooze.test.ts b/test/abilities/liquid_ooze.test.ts index b4ef530f433..860defbf572 100644 --- a/test/abilities/liquid_ooze.test.ts +++ b/test/abilities/liquid_ooze.test.ts @@ -22,17 +22,17 @@ describe("Abilities - Liquid Ooze", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([Moves.SPLASH]) + .moveset([Moves.SPLASH, Moves.GIGA_DRAIN]) .ability(Abilities.BALL_FETCH) .battleType("single") .disableCrits() + .enemyLevel(20) .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.LIQUID_OOZE) .enemyMoveset(Moves.SPLASH); }); it("should drain the attacker's HP after a draining move", async () => { - game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20); await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.GIGA_DRAIN); @@ -42,7 +42,7 @@ describe("Abilities - Liquid Ooze", () => { }); it("should not drain the attacker's HP if it ignores indirect damage", async () => { - game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20).ability(Abilities.MAGIC_GUARD); + game.override.ability(Abilities.MAGIC_GUARD); await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.GIGA_DRAIN); @@ -52,7 +52,7 @@ describe("Abilities - Liquid Ooze", () => { }); it("should not apply if suppressed", async () => { - game.override.moveset(Moves.GIGA_DRAIN).enemyLevel(20).ability(Abilities.NEUTRALIZING_GAS); + game.override.ability(Abilities.NEUTRALIZING_GAS); await game.classicMode.startBattle([Species.FEEBAS]); game.move.select(Moves.GIGA_DRAIN); From cc4e2244ed8dd07642b248817679b82d5fc6cb66 Mon Sep 17 00:00:00 2001 From: Dean Date: Wed, 23 Apr 2025 14:45:52 -0700 Subject: [PATCH 07/10] Fix liquid ooze test --- test/abilities/liquid_ooze.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/abilities/liquid_ooze.test.ts b/test/abilities/liquid_ooze.test.ts index 860defbf572..538b31a499d 100644 --- a/test/abilities/liquid_ooze.test.ts +++ b/test/abilities/liquid_ooze.test.ts @@ -24,7 +24,7 @@ describe("Abilities - Liquid Ooze", () => { game.override .moveset([Moves.SPLASH, Moves.GIGA_DRAIN]) .ability(Abilities.BALL_FETCH) - .battleType("single") + .battleStyle("single") .disableCrits() .enemyLevel(20) .enemySpecies(Species.MAGIKARP) From 3551f69b0ecffebcabd8dbee9dad91374d8ef148 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 17 Jun 2025 10:50:34 -0700 Subject: [PATCH 08/10] Fix hithealattr apply method --- src/data/moves/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 49e70a4726b..875a93eb315 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -2254,7 +2254,7 @@ export class HitHealAttr extends MoveEffectAttr { * @returns true if the function succeeds */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (target.hasAbilityWithAttr(ReverseDrainAbAttr)) { + if (target.hasAbilityWithAttr("ReverseDrainAbAttr")) { return false; } From 151c308d6361cb4b5401a19bf59ad5bbb69adec9 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 17 Jun 2025 11:18:01 -0700 Subject: [PATCH 09/10] Fix test --- test/abilities/liquid_ooze.test.ts | 33 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/test/abilities/liquid_ooze.test.ts b/test/abilities/liquid_ooze.test.ts index 538b31a499d..da9f861ad2c 100644 --- a/test/abilities/liquid_ooze.test.ts +++ b/test/abilities/liquid_ooze.test.ts @@ -1,6 +1,6 @@ -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; -import { Species } from "#enums/species"; +import { AbilityId } from "#enums/ability-id"; +import { MoveId } from "#enums/move-id"; +import { SpeciesId } from "#enums/species-id"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; @@ -22,40 +22,39 @@ describe("Abilities - Liquid Ooze", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([Moves.SPLASH, Moves.GIGA_DRAIN]) - .ability(Abilities.BALL_FETCH) + .moveset([MoveId.SPLASH, MoveId.GIGA_DRAIN]) + .ability(AbilityId.BALL_FETCH) .battleStyle("single") - .disableCrits() .enemyLevel(20) - .enemySpecies(Species.MAGIKARP) - .enemyAbility(Abilities.LIQUID_OOZE) - .enemyMoveset(Moves.SPLASH); + .enemySpecies(SpeciesId.MAGIKARP) + .enemyAbility(AbilityId.LIQUID_OOZE) + .enemyMoveset(MoveId.SPLASH); }); it("should drain the attacker's HP after a draining move", async () => { - await game.classicMode.startBattle([Species.FEEBAS]); + await game.classicMode.startBattle([SpeciesId.FEEBAS]); - game.move.select(Moves.GIGA_DRAIN); + game.move.select(MoveId.GIGA_DRAIN); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(false); }); it("should not drain the attacker's HP if it ignores indirect damage", async () => { - game.override.ability(Abilities.MAGIC_GUARD); - await game.classicMode.startBattle([Species.FEEBAS]); + game.override.ability(AbilityId.MAGIC_GUARD); + await game.classicMode.startBattle([SpeciesId.FEEBAS]); - game.move.select(Moves.GIGA_DRAIN); + game.move.select(MoveId.GIGA_DRAIN); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(true); }); it("should not apply if suppressed", async () => { - game.override.ability(Abilities.NEUTRALIZING_GAS); - await game.classicMode.startBattle([Species.FEEBAS]); + game.override.ability(AbilityId.NEUTRALIZING_GAS); + await game.classicMode.startBattle([SpeciesId.FEEBAS]); - game.move.select(Moves.GIGA_DRAIN); + game.move.select(MoveId.GIGA_DRAIN); await game.phaseInterceptor.to("BerryPhase"); expect(game.scene.getPlayerPokemon()?.isFullHp()).toBe(true); From 458faf90eb72d96f3e1b59222b04c850af024e9d Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 17 Jun 2025 19:21:46 -0700 Subject: [PATCH 10/10] Move checks to canApply --- src/data/abilities/ability.ts | 36 ++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 8596fb8926d..498bccec7c5 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -1176,23 +1176,37 @@ export class ReverseDrainAbAttr extends PostDefendAbAttr { override canApplyPostDefend( _pokemon: Pokemon, _passive: boolean, - _simulated: boolean, - _attacker: Pokemon, + simulated: boolean, + attacker: Pokemon, move: Move, _hitResult: HitResult | null, _args: any[], ): boolean { - return move.hasAttr("HitHealAttr"); + const cancelled = new BooleanHolder(false); + applyAbAttrs("BlockNonDirectDamageAbAttr", attacker, cancelled, simulated); + this.attacker = attacker; + return !cancelled.value && move.hasAttr("HitHealAttr"); } - override applyPostDefend(pokemon: Pokemon, _passive: boolean, _simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult | null, _args: any[]): void { - const cancelled = new BooleanHolder(false); - applyAbAttrs("BlockNonDirectDamageAbAttr", attacker, cancelled); - if (!cancelled.value) { - const damageAmount = move.getAttrs<"HitHealAttr">("HitHealAttr")[0].getHealAmount(attacker, pokemon); - pokemon.turnData.damageTaken += damageAmount; - globalScene.phaseManager.unshiftNew("PokemonHealPhase", attacker.getBattlerIndex(), -damageAmount, null, false, true); - } + override applyPostDefend( + pokemon: Pokemon, + _passive: boolean, + _simulated: boolean, + attacker: Pokemon, + move: Move, + _hitResult: HitResult | null, + _args: any[], + ): void { + const damageAmount = move.getAttrs<"HitHealAttr">("HitHealAttr")[0].getHealAmount(attacker, pokemon); + pokemon.turnData.damageTaken += damageAmount; + globalScene.phaseManager.unshiftNew( + "PokemonHealPhase", + attacker.getBattlerIndex(), + -damageAmount, + null, + false, + true, + ); } public override getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null {