Fixes some Ability Shield interactions (#7532)

This commit is contained in:
PhallenTree 2025-08-12 14:45:02 +01:00 committed by GitHub
parent eab10dc2f0
commit c6ee7feaa3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 125 additions and 22 deletions

View File

@ -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

View File

@ -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
{

View File

@ -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;

View File

@ -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");