diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index b7b4ec99cd..8318d7d214 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2459,6 +2459,7 @@ BattleScript_EffectGastroAcid:: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce + jumpifvolatile BS_TARGET, VOLATILE_GASTRO_ACID, BattleScript_ButItFailed setgastroacid BattleScript_ButItFailed attackanimation waitanimation diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 86cb831bb0..c58b85d187 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -335,6 +335,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u static void ResetValuesForCalledMove(void); static void TryRestoreDamageAfterCheekPouch(u32 battler); static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd); +static bool32 CanAbilityShieldActivateForBattler(u32 battler); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); @@ -12901,22 +12902,40 @@ static void Cmd_tryswapitems(void) } } +static bool32 CanAbilityShieldActivateForBattler(u32 battler) +{ + if (GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD) + return FALSE; + + RecordItemEffectBattle(battler, HOLD_EFFECT_ABILITY_SHIELD); + gBattlerAbility = battler; + gLastUsedItem = gBattleMons[battler].item; + return TRUE; +} + // Role Play, Doodle static void Cmd_trycopyability(void) { CMD_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); + u32 partner = BATTLE_PARTNER(battler); u16 defAbility = gBattleMons[gBattlerTarget].ability; + bool32 shouldConsiderPartner = IsBattlerAlive(partner) && GetMoveEffect(gCurrentMove) == EFFECT_DOODLE; if (gBattleMons[battler].ability == defAbility || defAbility == ABILITY_NONE || gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed - || (IsBattlerAlive(BATTLE_PARTNER(battler)) && gAbilitiesInfo[gBattleMons[BATTLE_PARTNER(battler)].ability].cantBeSuppressed && GetMoveEffect(gCurrentMove) == EFFECT_DOODLE) + || (shouldConsiderPartner && gAbilitiesInfo[gBattleMons[partner].ability].cantBeSuppressed) || gAbilitiesInfo[defAbility].cantBeCopied) { gBattlescriptCurrInstr = cmd->failInstr; } + else if (CanAbilityShieldActivateForBattler(battler) || (shouldConsiderPartner && CanAbilityShieldActivateForBattler(partner))) + { + gBattlescriptCurrInstr = BattleScript_MoveEnd; + BattleScriptCall(BattleScript_AbilityShieldProtects); + } else { gBattleScripting.abilityPopupOverwrite = gBattleMons[battler].ability; @@ -12964,7 +12983,6 @@ static void Cmd_settoxicspikes(void) } } -// TODO: possible failing bug for when gastro acid is already active static void Cmd_setgastroacid(void) { CMD_ARGS(const u8 *failInstr); @@ -12973,6 +12991,11 @@ static void Cmd_setgastroacid(void) { gBattlescriptCurrInstr = cmd->failInstr; } + else if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + { + RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); + gBattlescriptCurrInstr = cmd->failInstr; + } else { if (gBattleMons[gBattlerTarget].ability == ABILITY_NEUTRALIZING_GAS) @@ -13074,10 +13097,10 @@ static void Cmd_tryswapabilities(void) RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + else if (CanAbilityShieldActivateForBattler(gBattlerAttacker) || CanAbilityShieldActivateForBattler(gBattlerTarget)) { - RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); - gBattlescriptCurrInstr = cmd->failInstr; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + BattleScriptCall(BattleScript_AbilityShieldProtects); } else { @@ -14535,10 +14558,10 @@ static void Cmd_tryworryseed(void) RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + else if (CanAbilityShieldActivateForBattler(gBattlerTarget)) { - RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); - gBattlescriptCurrInstr = cmd->failInstr; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + BattleScriptCall(BattleScript_AbilityShieldProtects); } else { @@ -16645,10 +16668,15 @@ void BS_TryActivateAbilityShield(void) { NATIVE_ARGS(u8 battler); u32 battler = GetBattlerForBattleScript(cmd->battler); + u32 ability = GetBattlerAbility(battler); gBattlescriptCurrInstr = cmd->nextInstr; - if (GetBattlerAbilityNoAbilityShield(battler) != GetBattlerAbility(battler)) + if (ability != ABILITY_NONE // if ability would be negated by breaking effects Ability Shield doesn't print message + && ability == GetBattlerAbilityInternal(battler, TRUE, TRUE)) + return; + + if (GetBattlerAbilityNoAbilityShield(battler) != ability) { gLastUsedItem = gBattleMons[battler].item; RecordItemEffectBattle(battler, GetItemHoldEffect(gLastUsedItem)); @@ -17344,10 +17372,10 @@ void BS_SetSimpleBeam(void) RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + else if (CanAbilityShieldActivateForBattler(gBattlerTarget)) { - RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); - gBattlescriptCurrInstr = cmd->failInstr; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + BattleScriptCall(BattleScript_AbilityShieldProtects); } else { @@ -17369,10 +17397,10 @@ void BS_TryEntrainment(void) RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + else if (CanAbilityShieldActivateForBattler(gBattlerTarget)) { - RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); - gBattlescriptCurrInstr = cmd->failInstr; + gBattlescriptCurrInstr = BattleScript_MoveEnd; + BattleScriptCall(BattleScript_AbilityShieldProtects); } else { diff --git a/src/battle_util.c b/src/battle_util.c index 8eb6a89bc1..ed00fb4d45 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3533,6 +3533,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (gSpecialStatuses[battler].switchInAbilityDone) break; + if (GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + break; side = (BATTLE_OPPOSITE(GetBattlerPosition(battler))) & BIT_SIDE; target1 = GetBattlerAtPosition(side); @@ -4529,7 +4531,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSuppressed) { - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_ABILITY_SHIELD); break; @@ -4549,11 +4551,16 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSwapped) { - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_ABILITY_SHIELD); break; } + if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + { + RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); + break; + } gLastUsedAbility = gBattleMons[gBattlerAttacker].ability; gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability; diff --git a/test/battle/hold_effect/ability_shield.c b/test/battle/hold_effect/ability_shield.c index ded39ff05b..9f98ea98ef 100644 --- a/test/battle/hold_effect/ability_shield.c +++ b/test/battle/hold_effect/ability_shield.c @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Neutralizing Gas") } } -SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker") +SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker (no message)") { u32 item; @@ -50,16 +50,20 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker") TURN { MOVE(opponent, MOVE_EARTHQUAKE); } } SCENE { if (item == ITEM_ABILITY_SHIELD) { + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Flygon's Ability is protected by the effects of its Ability Shield!"); + HP_BAR(player); + } ABILITY_POPUP(player, ABILITY_LEVITATE); - NOT HP_BAR(player); } else { - NOT ABILITY_POPUP(player, ABILITY_LEVITATE); HP_BAR(player); + NOT ABILITY_POPUP(player, ABILITY_LEVITATE); } } } -SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might") +SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might (no message)") { u32 item; @@ -79,7 +83,10 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might") NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); STATUS_ICON(player, sleep: TRUE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Vigoroth's Ability is protected by the effects of its Ability Shield!"); } + ABILITY_POPUP(player, ABILITY_VITAL_SPIRIT); } else { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); STATUS_ICON(player, sleep: TRUE); @@ -87,7 +94,7 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might") } } -SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike") +SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike (no message)") { u32 item; @@ -103,10 +110,38 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike") } SCENE { if (item == ITEM_ABILITY_SHIELD) { NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Shedinja's Ability is protected by the effects of its Ability Shield!"); MESSAGE("Shedinja fainted!"); } + ABILITY_POPUP(player, ABILITY_WONDER_GUARD); } else { MESSAGE("Shedinja fainted!"); + NOT ABILITY_POPUP(player, ABILITY_WONDER_GUARD); + } + } +} + +SINGLE_BATTLE_TEST("Ability Shield protects the user's ability from being suppressed by Gastro Acid") +{ + u32 item; + + PARAMETRIZE { item = ITEM_ABILITY_SHIELD; } + PARAMETRIZE { item = ITEM_NONE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_BLAZIKEN) { Ability(ABILITY_SPEED_BOOST); Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_GASTRO_ACID); } + } SCENE { + if (item == ITEM_ABILITY_SHIELD) { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponent); + ABILITY_POPUP(player, ABILITY_SPEED_BOOST); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponent); + NOT ABILITY_POPUP(player, ABILITY_SPEED_BOOST); } } } @@ -130,9 +165,41 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Skill Swap") ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); } + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Gyarados's Ability is protected by the effects of its Ability Shield!"); } else { ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); } } } + +SINGLE_BATTLE_TEST("Ability Shield protects against Skill Swap even if user has Klutz") +{ + u32 item; + + PARAMETRIZE { item = ITEM_ABILITY_SHIELD; } + PARAMETRIZE { item = ITEM_NONE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + PLAYER(SPECIES_LOPUNNY) { Ability(ABILITY_KLUTZ); Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SKILL_SWAP); } + } SCENE { + if (item == ITEM_ABILITY_SHIELD) { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Lopunny's Ability is protected by the effects of its Ability Shield!"); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + } + } +} + +// These currently do not activate, but probably should do held item animation + message +TO_DO_BATTLE_TEST("Ability Shield prevents the user's Trace from changing its ability"); +TO_DO_BATTLE_TEST("Ability Shield prevents the user's Receiver from changing its ability"); +TO_DO_BATTLE_TEST("Ability Shield protects against Wandering Spirit"); +TO_DO_BATTLE_TEST("Ability Shield protects against Mummy/Lingering Aroma");