Adds Ability Shield activation message (#7224)

This commit is contained in:
PhallenTree 2025-06-26 13:42:32 +01:00 committed by GitHub
parent 6f7dac6d11
commit a82aa618fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 111 additions and 30 deletions

View File

@ -2461,6 +2461,11 @@
.4byte \jumpInstr
.endm
.macro tryactivateabilityshield battler:req
callnative BS_TryActivateAbilityShield
.byte \battler
.endm
.macro setallytonexttarget jumpInstr:req
jumpifbyte CMP_GREATER_THAN, gBattlerTarget, 0x1, 1f
addbyte gBattlerTarget, 0x2

View File

@ -7176,9 +7176,20 @@ BattleScript_AbilityCantRaiseDefenderStat::
restoreattacker
return
BattleScript_AbilityShieldProtects::
saveattacker
copybyte gBattlerAttacker, gBattlerAbility
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT
waitanimation
printstring STRINGID_ABILITYSHIELDPROTECTS
waitmessage B_WAIT_TIME_LONG
restoreattacker
return
BattleScript_AbilityPopUpTarget::
copybyte gBattlerAbility, gBattlerTarget
BattleScript_AbilityPopUp::
tryactivateabilityshield BS_ABILITY_BATTLER
.if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ABILITY_BATTLER
pause 40
@ -7428,14 +7439,10 @@ BattleScript_TryIntimidateHoldEffectsRet:
BattleScript_IntimidateActivates::
savetarget
.if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ATTACKER
pause B_WAIT_TIME_LONG
call BattleScript_AbilityPopUp
destroyabilitypopup
.endif
setbyte gBattlerTarget, 0
BattleScript_IntimidateLoop:
jumpifbyteequal gBattlerTarget, gBattlerAttacker, BattleScript_IntimidateLoopIncrement
jumpiftargetally BattleScript_IntimidateLoopIncrement
jumpifabsent BS_TARGET, BattleScript_IntimidateLoopIncrement
jumpifvolatile BS_TARGET, VOLATILE_SUBSTITUTE, BattleScript_IntimidateLoopIncrement
@ -7488,16 +7495,12 @@ BattleScript_IntimidateInReverse::
BattleScript_SupersweetSyrupActivates::
savetarget
.if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ATTACKER
pause B_WAIT_TIME_LONG
call BattleScript_AbilityPopUp
destroyabilitypopup
.endif
printstring STRINGID_SUPERSWEETAROMAWAFTS
waitmessage B_WAIT_TIME_LONG
setbyte gBattlerTarget, 0
BattleScript_SupersweetSyrupLoop:
jumpifbyteequal gBattlerTarget, gBattlerAttacker, BattleScript_SupersweetSyrupLoopIncrement
jumpiftargetally BattleScript_SupersweetSyrupLoopIncrement
jumpifabsent BS_TARGET, BattleScript_SupersweetSyrupLoopIncrement
jumpifvolatile BS_TARGET, VOLATILE_SUBSTITUTE, BattleScript_SupersweetSyrupLoopIncrement
@ -7510,8 +7513,12 @@ BattleScript_SupersweetSyrupEffect:
printfromtable gStatDownStringIds
BattleScript_SupersweetSyrupEffect_WaitString:
waitmessage B_WAIT_TIME_LONG
saveattacker
savetarget
copybyte sBATTLER, gBattlerTarget
call BattleScript_TryIntimidateHoldEffects
restoreattacker
restoretarget
BattleScript_SupersweetSyrupLoopIncrement:
addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_SupersweetSyrupLoop
@ -7977,6 +7984,11 @@ BattleScript_ProteanActivates::
waitmessage B_WAIT_TIME_LONG
return
BattleScript_AbilityAvoidsDamage::
call BattleScript_AbilityPopUp
printfromtable gMissStringIds @ waitmessage is executed next so no waitmessage here
return
BattleScript_TeraShellDistortingTypeMatchups::
pause B_WAIT_TIME_SHORTEST
call BattleScript_AbilityPopUpScripting

View File

@ -243,6 +243,8 @@ extern const u8 BattleScript_ConsumableStatRaiseRet[];
extern const u8 BattleScript_BerryFocusEnergyRet[];
extern const u8 BattleScript_BerryFocusEnergyEnd2[];
extern const u8 BattleScript_ActionSelectionItemsCantBeUsed[];
extern const u8 BattleScript_AbilityAvoidsDamage[];
extern const u8 BattleScript_AbilityShieldProtects[];
extern const u8 BattleScript_ArenaTurnBeginning[];
extern const u8 BattleScript_PalacePrintFlavorText[];
extern const u8 BattleScript_ArenaDoJudgment[];

View File

@ -257,7 +257,8 @@ bool32 TryPrimalReversion(u32 battler);
bool32 IsNeutralizingGasOnField(void);
bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability);
u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler);
u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker);
u32 GetBattlerAbilityNoAbilityShield(u32 battler);
u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityShield);
u32 GetBattlerAbility(u32 battler);
u32 IsAbilityOnSide(u32 battler, u32 ability);
u32 IsAbilityOnOpposingSide(u32 battler, u32 ability);

View File

@ -738,6 +738,7 @@ enum StringID
STRINGID_TOXICSPIKESBADLYPOISONED,
STRINGID_POWERCONSTRUCTPRESENCEOFMANY,
STRINGID_POWERCONSTRUCTTRANSFORM,
STRINGID_ABILITYSHIELDPROTECTS,
STRINGID_COUNT
};

View File

@ -897,6 +897,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] =
[STRINGID_QUESTIONFORFEITBATTLE] = COMPOUND_STRING("Would you like to give up on this battle and quit now? Quitting the battle is the same as losing the battle."),
[STRINGID_POWERCONSTRUCTPRESENCEOFMANY] = COMPOUND_STRING("You sense the presence of many!"),
[STRINGID_POWERCONSTRUCTTRANSFORM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into its Complete Forme!"),
[STRINGID_ABILITYSHIELDPROTECTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s Ability is protected by the effects of its {B_LAST_ITEM}!"),
};
const u16 gTrainerUsedItemStringIds[] =

View File

@ -2879,8 +2879,15 @@ static void Cmd_resultmessage(void)
return;
}
if (gBattleStruct->missStringId[gBattlerTarget] > B_MSG_AVOIDED_ATK) // Wonder Guard or Levitate - show the ability pop-up
CreateAbilityPopUp(gBattlerTarget, gBattleMons[gBattlerTarget].ability, IsDoubleBattle());
if (gBattleStruct->missStringId[gBattlerTarget] > B_MSG_AVOIDED_ATK) // Wonder Guard or Levitate
{
gBattlerAbility = gBattlerTarget;
gBattleCommunication[MULTISTRING_CHOOSER] = gBattleStruct->missStringId[gBattlerTarget];
gBattlescriptCurrInstr = cmd->nextInstr;
BattleScriptCall(BattleScript_AbilityAvoidsDamage);
return;
}
gBattleCommunication[MSG_DISPLAY] = 1;
stringId = gMissStringIds[gBattleStruct->missStringId[gBattlerTarget]];
}
@ -18601,3 +18608,18 @@ void BS_JumpIfAbilityCantBeSuppressed(void)
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_TryActivateAbilityShield(void)
{
NATIVE_ARGS(u8 battler);
u32 battler = GetBattlerForBattleScript(cmd->battler);
gBattlescriptCurrInstr = cmd->nextInstr;
if (GetBattlerAbilityNoAbilityShield(battler) != GetBattlerAbility(battler))
{
gLastUsedItem = gBattleMons[battler].item;
RecordItemEffectBattle(battler, GetItemHoldEffect(gLastUsedItem));
BattleScriptCall(BattleScript_AbilityShieldProtects);
}
}

View File

@ -3878,7 +3878,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_INTIMIDATE:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattlerAttacker = battler;
gBattlerAbility = gBattlerAttacker = battler;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
SET_STATCHANGER(STAT_ATK, 1, TRUE);
BattleScriptPushCursorAndCallback(BattleScript_IntimidateActivates);
@ -3889,7 +3889,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (!gSpecialStatuses[battler].switchInAbilityDone
&& !gBattleStruct->partyState[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].supersweetSyrup)
{
gBattlerAttacker = battler;
gBattlerAbility = gBattlerAttacker = battler;
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
gBattleStruct->partyState[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].supersweetSyrup = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_SupersweetSyrupActivates);
@ -5415,19 +5415,24 @@ static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32
&& gCurrentTurnActionNumber < gBattlersCount);
}
u32 GetBattlerAbilityNoAbilityShield(u32 battler)
{
return GetBattlerAbilityInternal(battler, FALSE, TRUE);
}
u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler)
{
return GetBattlerAbilityInternal(battler, TRUE);
return GetBattlerAbilityInternal(battler, TRUE, FALSE);
}
u32 GetBattlerAbility(u32 battler)
{
return GetBattlerAbilityInternal(battler, FALSE);
return GetBattlerAbilityInternal(battler, FALSE, FALSE);
}
u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker)
u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityShield)
{
bool32 hasAbilityShield = GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD;
bool32 hasAbilityShield = !noAbilityShield && GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD;
bool32 abilityCantBeSuppressed = gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed;
if (abilityCantBeSuppressed)

View File

@ -6,7 +6,7 @@ ASSUMPTIONS
ASSUME(gItemsInfo[ITEM_ABILITY_SHIELD].holdEffect == HOLD_EFFECT_ABILITY_SHIELD);
}
SINGLE_BATTLE_TEST("Ability Shield prevents Neutralizing Gas")
SINGLE_BATTLE_TEST("Ability Shield protects against Neutralizing Gas")
{
u32 item;
@ -22,12 +22,14 @@ SINGLE_BATTLE_TEST("Ability Shield prevents Neutralizing Gas")
ABILITY_POPUP(opponent, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing gas filled the area!");
if (item == ITEM_ABILITY_SHIELD) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Torkoal's Ability is protected by the effects of its Ability Shield!");
ABILITY_POPUP(player, ABILITY_DROUGHT);
MESSAGE("Torkoal's Drought intensified the sun's rays!");
} else {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("Torkoal's Ability is protected by the effects of its Ability Shield!");
ABILITY_POPUP(player, ABILITY_DROUGHT);
MESSAGE("Torkoal's Drought intensified the sun's rays!");
}
}
}
@ -41,17 +43,18 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mold Breaker")
PARAMETRIZE { item = ITEM_NONE; }
GIVEN {
PLAYER(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); Item(item); }
OPPONENT(SPECIES_TINKATON) { Ability(ABILITY_MOLD_BREAKER); }
ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND);
PLAYER(SPECIES_FLYGON) { Ability(ABILITY_LEVITATE); Item(item); }
OPPONENT(SPECIES_EXCADRILL) { Ability(ABILITY_MOLD_BREAKER); }
} WHEN {
TURN { MOVE(opponent, MOVE_GIGATON_HAMMER); }
TURN { MOVE(opponent, MOVE_EARTHQUAKE); }
} SCENE {
if (item == ITEM_ABILITY_SHIELD) {
NONE_OF {
MESSAGE("Shedinja fainted!");
}
ABILITY_POPUP(player, ABILITY_LEVITATE);
NOT HP_BAR(player);
} else {
MESSAGE("Shedinja fainted!");
NOT ABILITY_POPUP(player, ABILITY_LEVITATE);
HP_BAR(player);
}
}
}
@ -64,10 +67,12 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might")
PARAMETRIZE { item = ITEM_NONE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_SPORE) == MOVE_EFFECT_SLEEP);
PLAYER(SPECIES_VIGOROTH) { Ability(ABILITY_VITAL_SPIRIT); Item(item); }
OPPONENT(SPECIES_TOEDSCOOL) { Ability(ABILITY_MYCELIUM_MIGHT); }
} WHEN {
TURN { MOVE(opponent, MOVE_SPORE); MOVE(player, MOVE_SPORE); }
TURN { MOVE(opponent, MOVE_SPORE); }
} SCENE {
if (item == ITEM_ABILITY_SHIELD) {
@ -90,6 +95,7 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike")
PARAMETRIZE { item = ITEM_NONE; }
GIVEN {
ASSUME(MoveIgnoresTargetAbility(MOVE_SUNSTEEL_STRIKE));
PLAYER(SPECIES_SHEDINJA) { Ability(ABILITY_WONDER_GUARD); Item(item); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -104,3 +110,29 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Sunsteel Strike")
}
}
}
SINGLE_BATTLE_TEST("Ability Shield protects against Skill Swap")
{
u32 item;
PARAMETRIZE { item = ITEM_ABILITY_SHIELD; }
PARAMETRIZE { item = ITEM_NONE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP);
PLAYER(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); Item(item); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SKILL_SWAP); }
} SCENE {
if (item == ITEM_ABILITY_SHIELD) {
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent);
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
}
} else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent);
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
}
}
}