diff --git a/include/battle.h b/include/battle.h index 559b4eb88b..57e92bccef 100755 --- a/include/battle.h +++ b/include/battle.h @@ -667,7 +667,7 @@ struct BattleStruct u8 multipleSwitchInState:2; u8 multipleSwitchInCursor:3; u8 sleepClauseNotBlocked:1; - u8 padding1:1; + u8 moldBreakerActive:1; u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT]; void (*savedCallback)(void); u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 16d15e644e..c9c5f6dec6 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7020,6 +7020,7 @@ static void Cmd_moveend(void) gSpecialStatuses[gBattlerTarget].berryReduced = FALSE; gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE; gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + gBattleStruct->moldBreakerActive = FALSE; gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->categoryOverride = FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index 647e21bb66..06023975e9 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -490,6 +490,9 @@ void HandleAction_UseMove(void) gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); } + if (IsMoldBreakerTypeAbility(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) || MoveIgnoresTargetAbility(gCurrentMove)) + gBattleStruct->moldBreakerActive = TRUE; + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); if (!HandleMoveTargetRedirection()) @@ -933,6 +936,7 @@ void HandleAction_ActionFinished(void) gBattleStruct->dynamicMoveType = 0; gBattleStruct->bouncedMoveIsUsed = FALSE; gBattleStruct->snatchedMoveIsUsed = FALSE; + gBattleStruct->moldBreakerActive = FALSE; gBattleScripting.moveendState = 0; gBattleCommunication[3] = 0; gBattleCommunication[4] = 0; @@ -5360,17 +5364,11 @@ bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) return FALSE; } -static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 ability, u32 hasAbilityShield, u32 ignoreMoldBreaker) +static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 hasAbilityShield, u32 ignoreMoldBreaker) { - if (hasAbilityShield || ignoreMoldBreaker) + if (hasAbilityShield || ignoreMoldBreaker || battlerDef == battlerAtk) return FALSE; - - return ((IsMoldBreakerTypeAbility(battlerAtk, ability) || MoveIgnoresTargetAbility(gCurrentMove)) - && battlerDef != battlerAtk - && gAbilitiesInfo[gBattleMons[battlerDef].ability].breakable - && gBattlerByTurnOrder[gCurrentTurnActionNumber] == battlerAtk - && gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE - && gCurrentTurnActionNumber < gBattlersCount); + return gBattleStruct->moldBreakerActive && gAbilitiesInfo[gBattleMons[battlerDef].ability].breakable; } u32 GetBattlerAbilityNoAbilityShield(u32 battler) @@ -5401,7 +5399,7 @@ u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityS && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield, ignoreMoldBreaker)) + if (CanBreakThroughAbility(gBattlerAttacker, battler, hasAbilityShield, ignoreMoldBreaker)) return ABILITY_NONE; return gBattleMons[battler].ability; @@ -5415,7 +5413,7 @@ u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityS && (gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS || gBattleMons[battler].volatiles.gastroAcid)) return ABILITY_NONE; - if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield, ignoreMoldBreaker)) + if (CanBreakThroughAbility(gBattlerAttacker, battler, hasAbilityShield, ignoreMoldBreaker)) return ABILITY_NONE; return gBattleMons[battler].ability; diff --git a/test/battle/ability/neutralizing_gas.c b/test/battle/ability/neutralizing_gas.c index 426f4c969f..9971d53c44 100644 --- a/test/battle/ability/neutralizing_gas.c +++ b/test/battle/ability/neutralizing_gas.c @@ -353,3 +353,45 @@ SINGLE_BATTLE_TEST("Neutralizing Gas only displays exiting message for the last NOT MESSAGE("The effects of the neutralizing gas wore off!"); } } + +DOUBLE_BATTLE_TEST("Neutralizing Gas is active for the duration of a Spread Move even if Neutralizing Gas is no longer on the field") +{ + GIVEN { + ASSUME(GetMoveTarget(MOVE_ORIGIN_PULSE) == MOVE_TARGET_BOTH); + PLAYER(SPECIES_WEEZING) { HP(1); Ability(ABILITY_NEUTRALIZING_GAS); } + PLAYER(SPECIES_GOLEM) { Ability(ABILITY_STURDY); } + OPPONENT(SPECIES_BASCULEGION) { Ability(ABILITY_MOLD_BREAKER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_ORIGIN_PULSE); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ORIGIN_PULSE, opponentLeft); + HP_BAR(playerLeft); + HP_BAR(playerRight); + MESSAGE("Weezing fainted!"); + MESSAGE("Golem fainted!"); + NOT ABILITY_POPUP(playerRight, ABILITY_STURDY); + } +} + +DOUBLE_BATTLE_TEST("Neutralizing Gas is active until the last Dragon Darts hit even if Neutralizing Gas is no longer on the field") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS); + PLAYER(SPECIES_WEEZING) { HP(1); Ability(ABILITY_NEUTRALIZING_GAS); } + PLAYER(SPECIES_GOLEM) { HP(2); MaxHP(2); Ability(ABILITY_STURDY); } + OPPONENT(SPECIES_BASCULEGION) { Ability(ABILITY_MOLD_BREAKER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_DRAGON_DARTS, target: playerLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_NEUTRALIZING_GAS); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, opponentLeft); + HP_BAR(playerLeft); + MESSAGE("Weezing fainted!"); + HP_BAR(playerRight); + NOT MESSAGE("Golem fainted!"); + ABILITY_POPUP(playerRight, ABILITY_STURDY); + } +}