From 9463da879762b9e688c07878265e38bca3ca7bf4 Mon Sep 17 00:00:00 2001 From: Adrian T <68144167+torranx@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:56:44 +0800 Subject: [PATCH] [Bug] Fix ice face blocking all hits from multihit moves (#2391) * fix ice face bug * add multihit test --- src/data/ability.ts | 29 +++++++++++++++++------------ src/test/abilities/ice_face.test.ts | 29 +++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index e1d047c7806..9c74b896ac5 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3682,13 +3682,21 @@ export class PostSummonStatChangeOnArenaAbAttr extends PostSummonStatChangeAbAtt } /** - * Applies immunity to physical moves. + * Takes no damage from the first hit of a physical move. * This is used in Ice Face ability. */ -export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr { +export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAttr { + private multiplier: number; + + constructor(condition: PokemonDefendCondition, multiplier: number) { + super(condition, multiplier); + + this.multiplier = multiplier; + } + /** * Applies the Ice Face pre-defense ability to the Pokémon. - * Removes BattlerTagType.ICE_FACE hit by physical attack and is in Ice Face form. + * Removes BattlerTagType.ICE_FACE when hit by physical attack and is in Ice Face form. * * @param {Pokemon} pokemon - The Pokémon with the Ice Face ability. * @param {boolean} passive - Whether the ability is passive. @@ -3699,16 +3707,13 @@ export class IceFaceMoveImmunityAbAttr extends MoveImmunityAbAttr { * @returns {boolean} - Whether the immunity was applied. */ applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean { - const isImmune = super.applyPreDefend(pokemon, passive, attacker, move, cancelled, args); - - if (isImmune) { - const simulated = args.length > 1 && args[1]; - if (!simulated) { - pokemon.removeTag(BattlerTagType.ICE_FACE); - } + if (this.condition(pokemon, attacker, move)) { + (args[0] as Utils.NumberHolder).value = this.multiplier; + pokemon.removeTag(BattlerTagType.ICE_FACE); + return true; } - return isImmune; + return false; } /** @@ -4768,7 +4773,7 @@ export function initAbilities() { .conditionalAttr(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW), PostSummonAddBattlerTagAbAttr, BattlerTagType.ICE_FACE, 0) // When weather changes to HAIL or SNOW while pokemon is fielded, add BattlerTagType.ICE_FACE .attr(PostWeatherChangeAddBattlerTagAttr, BattlerTagType.ICE_FACE, 0, WeatherType.HAIL, WeatherType.SNOW) - .attr(IceFaceMoveImmunityAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE)) + .attr(IceFaceBlockPhysicalAbAttr, (target, user, move) => move.category === MoveCategory.PHYSICAL && !!target.getTag(BattlerTagType.ICE_FACE), 0) .ignorable(), new Ability(Abilities.POWER_SPOT, 8) .attr(AllyMoveCategoryPowerBoostAbAttr, [MoveCategory.SPECIAL, MoveCategory.PHYSICAL], 1.3), diff --git a/src/test/abilities/ice_face.test.ts b/src/test/abilities/ice_face.test.ts index 759b036770a..58937ddf231 100644 --- a/src/test/abilities/ice_face.test.ts +++ b/src/test/abilities/ice_face.test.ts @@ -4,6 +4,7 @@ import GameManager from "#app/test/utils/gameManager"; import * as overrides from "#app/overrides"; import { Species } from "#enums/species"; import { + MoveEffectPhase, MoveEndPhase, TurnEndPhase, TurnInitPhase, @@ -52,6 +53,34 @@ describe("Abilities - Ice Face", () => { expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); }); + it("takes no damage from multihit physical move and transforms to Noice", async () => { + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SURGING_STRIKES]); + vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(5); + await game.startBattle([Species.HITMONLEE]); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES)); + + const eiscue = game.scene.getEnemyPokemon(); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); + + // First hit + await game.phaseInterceptor.to(MoveEffectPhase); + expect(eiscue.hp).equals(eiscue.getMaxHp()); + expect(eiscue.formIndex).toBe(icefaceForm); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); + + // Second hit + await game.phaseInterceptor.to(MoveEffectPhase); + expect(eiscue.hp).lessThan(eiscue.getMaxHp()); + expect(eiscue.formIndex).toBe(noiceForm); + + await game.phaseInterceptor.to(MoveEndPhase); + + expect(eiscue.hp).lessThan(eiscue.getMaxHp()); + expect(eiscue.formIndex).toBe(noiceForm); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); + }); + it("takes damage from special moves", async () => { await game.startBattle([Species.MAGIKARP]);