From 8b2774e07d5a907fbbd191e138b0427c9d5133eb Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 26 Jul 2024 20:19:58 +0200 Subject: [PATCH 1/4] Fixes cantBeSurpressed ability check for breakable abilities --- src/battle_util.c | 1 - test/battle/ability/disguise.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/battle_util.c b/src/battle_util.c index 9ea7a453cb3f..2cd38c55593b 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6224,7 +6224,6 @@ u32 GetBattlerAbility(u32 battler) && gStatuses3[battler] & STATUS3_GASTRO_ACID && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - return gBattleMons[battler].ability; } if (gStatuses3[battler] & STATUS3_GASTRO_ACID) diff --git a/test/battle/ability/disguise.c b/test/battle/ability/disguise.c index 7d3e36bf7857..c4f79d8fe350 100644 --- a/test/battle/ability/disguise.c +++ b/test/battle/ability/disguise.c @@ -121,3 +121,16 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu takes damage from Rough Skin without break EXPECT_EQ(player->species, SPECIES_MIMIKYU_DISGUISED); } } + +SINGLE_BATTLE_TEST("Disguised Mimikyu is ignored by Mold Breaker") +{ + GIVEN { + PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } + OPPONENT(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } + } WHEN { + TURN { MOVE(opponent, MOVE_AERIAL_ACE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_AERIAL_ACE, opponent); + NOT ABILITY_POPUP(player, ABILITY_DISGUISE); + } +} From 89563cb9b124e4b9a6329091e23ad4463b8690c3 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 26 Jul 2024 21:11:16 +0200 Subject: [PATCH 2/4] check for breakable ability --- include/battle_util.h | 2 +- src/battle_ai_util.c | 6 +++--- src/battle_util.c | 24 ++++++++++++++---------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index 644a112d7dab..118ef8c6b3a9 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -146,7 +146,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility) u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg); bool32 TryPrimalReversion(u32 battler); bool32 IsNeutralizingGasOnField(void); -bool32 IsMoldBreakerTypeAbility(u32 ability); +bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability); u32 GetBattlerAbility(u32 battler); u32 IsAbilityOnSide(u32 battler, u32 ability); u32 IsAbilityOnOpposingSide(u32 battler, u32 ability); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index b9770ba95091..1498d8936ce4 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1188,7 +1188,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move) if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI handicap flag: doesn't understand ability suppression concept - if (IsMoldBreakerTypeAbility(atkAbility) || gMovesInfo[move].ignoresTargetAbility) + if (IsMoldBreakerTypeAbility(sBattler_AI, atkAbility) || gMovesInfo[move].ignoresTargetAbility) return TRUE; return FALSE; @@ -2766,7 +2766,7 @@ bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) { - if (((!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) + if (((!IsMoldBreakerTypeAbility(battlerAtk, AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)) // Opponent goes first @@ -2809,7 +2809,7 @@ bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move) || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || (!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) + || (!IsMoldBreakerTypeAbility(battlerAtk, AI_DATA->abilities[battlerAtk]) && (AI_DATA->abilities[battlerDef] == ABILITY_SHIELD_DUST || AI_DATA->abilities[battlerDef] == ABILITY_INNER_FOCUS))) return FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index 2cd38c55593b..d0ccf4859e01 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6207,8 +6207,11 @@ bool32 IsNeutralizingGasOnField(void) return FALSE; } -bool32 IsMoldBreakerTypeAbility(u32 ability) +bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) { + if (gStatuses3[battler] & STATUS3_GASTRO_ACID) + return FALSE; + return (ability == ABILITY_MOLD_BREAKER || ability == ABILITY_TERAVOLT || ability == ABILITY_TURBOBLAZE || (ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove))); } @@ -6224,6 +6227,9 @@ u32 GetBattlerAbility(u32 battler) && gStatuses3[battler] & STATUS3_GASTRO_ACID && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; + + if (!gAbilitiesInfo[gBattleMons[battler].ability].breakable) + return gBattleMons[battler].ability; } if (gStatuses3[battler] & STATUS3_GASTRO_ACID) @@ -6234,15 +6240,13 @@ u32 GetBattlerAbility(u32 battler) && noAbilityShield) return ABILITY_NONE; - if (((IsMoldBreakerTypeAbility(gBattleMons[gBattlerAttacker].ability) - && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) - || gMovesInfo[gCurrentMove].ignoresTargetAbility) - && battler != gBattlerAttacker - && gAbilitiesInfo[gBattleMons[battler].ability].breakable - && noAbilityShield - && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker - && gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE - && gCurrentTurnActionNumber < gBattlersCount) + if ((IsMoldBreakerTypeAbility(gBattlerAttacker, gBattleMons[gBattlerAttacker].ability) || gMovesInfo[gCurrentMove].ignoresTargetAbility) + && battler != gBattlerAttacker + && gAbilitiesInfo[gBattleMons[battler].ability].breakable + && noAbilityShield + && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker + && gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE + && gCurrentTurnActionNumber < gBattlersCount) return ABILITY_NONE; return gBattleMons[battler].ability; From dfd63fd34f894c4ad46f9a93bb351e09ce70d3a5 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 26 Jul 2024 21:30:41 +0200 Subject: [PATCH 3/4] func CanBreakThroughAbility --- src/battle_util.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index d0ccf4859e01..ea2da5709eb8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6216,11 +6216,22 @@ bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) || (ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove))); } +static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 ability) +{ + return ((IsMoldBreakerTypeAbility(battlerAtk, ability) || gMovesInfo[gCurrentMove].ignoresTargetAbility) + && battlerDef != battlerAtk + && gAbilitiesInfo[gBattleMons[battlerDef].ability].breakable + && gBattlerByTurnOrder[gCurrentTurnActionNumber] == battlerAtk + && gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE + && gCurrentTurnActionNumber < gBattlersCount); +} + u32 GetBattlerAbility(u32 battler) { bool32 noAbilityShield = GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD; + bool32 abilityCantBeSuppressed = gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed; - if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed) + if (abilityCantBeSuppressed) { // Edge case: pokemon under the effect of gastro acid transforms into a pokemon with Comatose (Todo: verify how other unsuppressable abilities behave) if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED @@ -6228,8 +6239,10 @@ u32 GetBattlerAbility(u32 battler) && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - if (!gAbilitiesInfo[gBattleMons[battler].ability].breakable) - return gBattleMons[battler].ability; + if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) + return ABILITY_NONE; + + return gBattleMons[battler].ability; } if (gStatuses3[battler] & STATUS3_GASTRO_ACID) @@ -6240,13 +6253,7 @@ u32 GetBattlerAbility(u32 battler) && noAbilityShield) return ABILITY_NONE; - if ((IsMoldBreakerTypeAbility(gBattlerAttacker, gBattleMons[gBattlerAttacker].ability) || gMovesInfo[gCurrentMove].ignoresTargetAbility) - && battler != gBattlerAttacker - && gAbilitiesInfo[gBattleMons[battler].ability].breakable - && noAbilityShield - && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker - && gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE - && gCurrentTurnActionNumber < gBattlersCount) + if (noAbilityShield && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) return ABILITY_NONE; return gBattleMons[battler].ability; From 5dd10a4af11685b9cba3cd0013fa66fe4fcbfc10 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 26 Jul 2024 21:34:20 +0200 Subject: [PATCH 4/4] forgot abilityShield check --- src/battle_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_util.c b/src/battle_util.c index ea2da5709eb8..e87fa9f368f4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6239,7 +6239,7 @@ u32 GetBattlerAbility(u32 battler) && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) + if (noAbilityShield && CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability)) return ABILITY_NONE; return gBattleMons[battler].ability;