From f8fc86275ccb8c259eecf8cb46e2bd2fb16c5ae0 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 1 Jul 2025 17:48:57 +0200 Subject: [PATCH] Fixes protective pads not protecting from secondary protect effects (#7229) --- include/battle_util.h | 3 +- src/battle_script_commands.c | 6 +-- src/battle_util.c | 90 +++++++++++++++---------------- test/battle/ability/fluffy.c | 42 +++++++++++++-- test/battle/move_effect/protect.c | 17 ++++++ 5 files changed, 104 insertions(+), 54 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index 2ce91c3f25..57327176a8 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -263,7 +263,8 @@ enum ItemHoldEffect GetBattlerHoldEffect(u32 battler, bool32 checkNegating); enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating); enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility); u32 GetBattlerHoldEffectParam(u32 battler); -bool32 IsMoveMakingContact(u32 move, u32 battlerAtk); +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); bool32 IsBattlerGrounded(u32 battler); u32 GetMoveSlot(u16 *moves, u32 move); u32 GetBattlerWeight(u32 battler); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a1d29bc696..386d636e77 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1422,7 +1422,7 @@ static void Cmd_attackcanceler(void) && effect != EFFECT_COUNTER && effect != EFFECT_UPPER_HAND) { - if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) + if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; @@ -1438,7 +1438,7 @@ static void Cmd_attackcanceler(void) gBattleCommunication[MISS_TYPE] = B_MSG_PROTECTED; gBattlescriptCurrInstr = cmd->nextInstr; } - else if (gProtectStructs[gBattlerTarget].beakBlastCharge && IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) + else if (gProtectStructs[gBattlerTarget].beakBlastCharge && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; @@ -7262,7 +7262,7 @@ static void Cmd_moveend(void) if (IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item && !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off - && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) // Pickpocket requires contact + && IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) // Pickpocket requires contact && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked { u8 battlers[4] = {0, 1, 2, 3}; diff --git a/src/battle_util.c b/src/battle_util.c index 226b041be0..e4d43d7766 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4465,8 +4465,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && gDisableStructs[gBattlerAttacker].overwrittenAbility != GetBattlerAbility(gBattlerTarget) && gBattleMons[gBattlerAttacker].ability != ABILITY_MUMMY && gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA @@ -4490,8 +4489,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && !(GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSwapped) { @@ -4547,8 +4545,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { SET_STATCHANGER(STAT_SPEED, 1, TRUE); PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); @@ -4564,8 +4561,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (B_ROUGH_SKIN_DMG >= GEN_4 ? 8 : 16); if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) @@ -4580,8 +4576,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !IsBattlerAlive(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { if ((battler = IsAbilityOnField(ABILITY_DAMP))) { @@ -4650,8 +4645,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBeSlept(gBattlerAttacker, gBattlerTarget, ability, NOT_BLOCKED_BY_SLEEP_CLAUSE) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { if (IsSleepClauseEnabled()) gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; @@ -4674,8 +4668,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBePoisoned(gBattlerTarget, gBattlerAttacker, gLastUsedAbility, GetBattlerAbility(gBattlerAttacker)) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); @@ -4695,8 +4688,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBeParalyzed(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) { gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); @@ -4711,8 +4703,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && (IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && IsBattlerTurnDamaged(gBattlerTarget) && CanBeBurned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3))) @@ -4735,8 +4726,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) && AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget) && GetBattlerAbility(gBattlerAttacker) != ABILITY_OBLIVIOUS - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL)) { gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget); @@ -4806,8 +4796,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(battler) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && (IsMoveMakingContact(move, gBattlerAttacker)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && !(gStatuses3[gBattlerAttacker] & STATUS3_PERISH_SONG)) { if (!(gStatuses3[battler] & STATUS3_PERISH_SONG)) @@ -4932,8 +4921,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(gBattlerTarget) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && CanBePoisoned(gBattlerAttacker, gBattlerTarget, gLastUsedAbility, GetBattlerAbility(gBattlerTarget)) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && IsBattlerTurnDamaged(gBattlerTarget) // Need to actually hit the target && RandomPercentage(RNG_POISON_TOUCH, 30)) { @@ -7191,8 +7179,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_ROCKY_HELMET: if (IsBattlerTurnDamaged(gBattlerTarget) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) && IsBattlerAlive(gBattlerAttacker) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) { @@ -7324,8 +7311,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) case HOLD_EFFECT_STICKY_BARB: if (IsBattlerTurnDamaged(gBattlerTarget) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && IsBattlerAlive(gBattlerAttacker) && CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item) @@ -7691,26 +7677,35 @@ u32 GetBattlerHoldEffectParam(u32 battler) return GetItemHoldEffectParam(gBattleMons[battler].item); } -bool32 IsMoveMakingContact(u32 move, u32 battlerAtk) +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) { - enum ItemHoldEffect atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE); - - if (!MoveMakesContact(move)) + if (holdEffectAtk == HOLD_EFFECT_PROTECTIVE_PADS) { - if (GetMoveEffect(move) == EFFECT_SHELL_SIDE_ARM && gBattleStruct->shellSideArmCategory[battlerAtk][gBattlerTarget] == DAMAGE_CATEGORY_PHYSICAL) - return TRUE; - else - return FALSE; + RecordItemEffectBattle(battlerAtk, HOLD_EFFECT_PROTECTIVE_PADS); + return TRUE; } - else if ((atkHoldEffect == HOLD_EFFECT_PUNCHING_GLOVE && IsPunchingMove(move)) - || GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH) + + return !IsMoveMakingContact(battlerAtk, battlerDef, abilityAtk, holdEffectAtk, move); +} + +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) +{ + if (!(MoveMakesContact(move) || (GetMoveEffect(move) == EFFECT_SHELL_SIDE_ARM + && gBattleStruct->shellSideArmCategory[battlerAtk][battlerDef] == DAMAGE_CATEGORY_PHYSICAL))) { return FALSE; } - else + else if (holdEffectAtk == HOLD_EFFECT_PUNCHING_GLOVE && IsPunchingMove(move)) { - return TRUE; + RecordItemEffectBattle(battlerAtk, HOLD_EFFECT_PUNCHING_GLOVE); + return FALSE; } + else if (abilityAtk == ABILITY_LONG_REACH) + { + RecordAbilityBattle(battlerAtk, ABILITY_LONG_REACH); + return FALSE; + } + return TRUE; } static inline bool32 IsSideProtected(u32 battler, enum ProtectMethod method) @@ -7729,7 +7724,8 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) { if (IsZMove(move) || IsMaxMove(move)) return FALSE; // Z-Moves and Max Moves bypass protection (except Max Guard). - if (IsMoveMakingContact(move, battlerAtk) && GetBattlerAbility(battlerAtk) == ABILITY_UNSEEN_FIST) + if (GetBattlerAbility(battlerAtk) == ABILITY_UNSEEN_FIST + && IsMoveMakingContact(battlerAtk, battlerDef, ABILITY_UNSEEN_FIST, GetBattlerHoldEffect(battlerAtk, TRUE), move)) return FALSE; } @@ -8431,7 +8427,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); break; case ABILITY_TOUGH_CLAWS: - if (IsMoveMakingContact(move, battlerAtk)) + if (IsMoveMakingContact(battlerAtk, battlerDef, atkAbility, holdEffectAtk, move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); break; case ABILITY_STRONG_JAW: @@ -9242,7 +9238,7 @@ static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typ return UQ_4_12(1.0); } -static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t typeEffectivenessModifier, u32 abilityDef) +static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t typeEffectivenessModifier, u32 abilityDef, enum ItemHoldEffect holdEffectAtk) { switch (abilityDef) { @@ -9258,9 +9254,9 @@ static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 return UQ_4_12(0.75); break; case ABILITY_FLUFFY: - if (!IsMoveMakingContact(move, battlerAtk) && moveType == TYPE_FIRE) + if (moveType == TYPE_FIRE && !IsMoveMakingContact(battlerAtk, battlerDef, ABILITY_NONE, holdEffectAtk, move)) return UQ_4_12(2.0); - if (IsMoveMakingContact(move, battlerAtk) && moveType != TYPE_FIRE) + if (moveType != TYPE_FIRE && IsMoveMakingContact(battlerAtk, battlerDef, ABILITY_NONE, holdEffectAtk, move)) return UQ_4_12(0.5); break; case ABILITY_PUNK_ROCK: @@ -9375,14 +9371,14 @@ static inline uq4_12_t GetOtherModifiers(struct DamageCalculationData *damageCal if (unmodifiedAttackerSpeed >= unmodifiedDefenderSpeed) { DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk)); - DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef, holdEffectAtk)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner)); DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier, holdEffectAtk)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(damageCalcData, typeEffectivenessModifier, abilityDef, holdEffectDef)); } else { - DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef, holdEffectAtk)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner)); DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(damageCalcData, typeEffectivenessModifier, abilityDef, holdEffectDef)); diff --git a/test/battle/ability/fluffy.c b/test/battle/ability/fluffy.c index 4b8ef60396..6525c73212 100644 --- a/test/battle/ability/fluffy.c +++ b/test/battle/ability/fluffy.c @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct conta } WHEN { TURN { MOVE(player, MOVE_SCRATCH); } } SCENE { - MESSAGE("Wobbuffet used Scratch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage); @@ -39,7 +39,7 @@ SINGLE_BATTLE_TEST("Fluffy doubles damage taken from fire type moves", s16 damag } WHEN { TURN { MOVE(player, MOVE_EMBER); } } SCENE { - MESSAGE("Wobbuffet used Ember!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage); @@ -57,7 +57,43 @@ SINGLE_BATTLE_TEST("Fluffy does not alter damage of fire-type moves that make di } WHEN { TURN { MOVE(player, MOVE_FIRE_PUNCH); } } SCENE { - MESSAGE("Wobbuffet used Fire Punch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PUNCH, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct contact even if protected by Protective Pads", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_KLUTZ; } + PARAMETRIZE { ability = ABILITY_FLUFFY; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PROTECTIVE_PADS); } + OPPONENT(SPECIES_STUFFUL) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Fluffy does not halve damage taken from moves that make direct contact but are ignored by Punching Glove", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_KLUTZ; } + PARAMETRIZE { ability = ABILITY_FLUFFY; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PUNCHING_GLOVE); } + OPPONENT(SPECIES_STUFFUL) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_THUNDER_PUNCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_PUNCH, player); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_EQ(results[0].damage, results[1].damage); diff --git a/test/battle/move_effect/protect.c b/test/battle/move_effect/protect.c index e0c32e5267..09fc4c12bf 100644 --- a/test/battle/move_effect/protect.c +++ b/test/battle/move_effect/protect.c @@ -618,3 +618,20 @@ SINGLE_BATTLE_TEST("Protect: Quick Guard, Wide Guard and Crafty Shield don't red EXPECT_EQ(results[4].damage, results[5].damage); } } + +SINGLE_BATTLE_TEST("Protect: Protective Pads protects from secondary effects") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PROTECTIVE_PADS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_BURNING_BULWARK); MOVE(player, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BURNING_BULWARK, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); + HP_BAR(opponent); + STATUS_ICON(player, STATUS1_BURN); + } + } +}