Shell Bell Clean up / Simplification and Tests (#5924)
This commit is contained in:
parent
bc409b3028
commit
5391b451ae
@ -68,9 +68,6 @@
|
||||
|
||||
#define BATTLE_BUFFER_LINK_SIZE 0x1000
|
||||
|
||||
// Special indicator value for shellBellDmg in SpecialStatus
|
||||
#define IGNORE_SHELL_BELL 0xFFFF
|
||||
|
||||
struct ResourceFlags
|
||||
{
|
||||
u32 flags[MAX_BATTLERS_COUNT];
|
||||
@ -200,7 +197,6 @@ struct ProtectStruct
|
||||
|
||||
struct SpecialStatus
|
||||
{
|
||||
s32 shellBellDmg;
|
||||
s32 physicalDmg;
|
||||
s32 specialDmg;
|
||||
u8 physicalBattlerId;
|
||||
@ -212,7 +208,8 @@ struct SpecialStatus
|
||||
u8 faintedHasReplacement:1;
|
||||
u8 focusBanded:1;
|
||||
u8 focusSashed:1;
|
||||
u8 unused:2;
|
||||
u8 emergencyExited:1;
|
||||
u8 afterYou:1;
|
||||
// End of byte
|
||||
u8 sturdied:1;
|
||||
u8 stormDrainRedirected:1;
|
||||
@ -231,16 +228,13 @@ struct SpecialStatus
|
||||
u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS
|
||||
u8 affectionEndured:1;
|
||||
// End of byte
|
||||
u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute.
|
||||
u8 dancerUsedMove:1;
|
||||
u8 dancerOriginalTarget:3;
|
||||
// End of byte
|
||||
u8 emergencyExited:1;
|
||||
u8 afterYou:1;
|
||||
u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects.
|
||||
u8 distortedTypeMatchups:1;
|
||||
u8 teraShellAbilityDone:1;
|
||||
u8 criticalHit:1;
|
||||
// End of byte
|
||||
};
|
||||
|
||||
struct SideTimer
|
||||
|
||||
@ -2124,12 +2124,12 @@ static void Cmd_adjustdamage(void)
|
||||
continue;
|
||||
|
||||
if (DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove))
|
||||
goto END;
|
||||
continue;
|
||||
|
||||
if (DoesDisguiseBlockMove(battlerDef, gCurrentMove))
|
||||
{
|
||||
gBattleStruct->enduredDamage |= 1u << battlerDef;
|
||||
goto END;
|
||||
continue;
|
||||
}
|
||||
if (GetBattlerAbility(battlerDef) == ABILITY_ICE_FACE && IsBattleMovePhysical(gCurrentMove) && gBattleMons[battlerDef].species == SPECIES_EISCUE)
|
||||
{
|
||||
@ -2139,10 +2139,10 @@ static void Cmd_adjustdamage(void)
|
||||
RecordAbilityBattle(gBattlerTarget, ABILITY_ICE_FACE);
|
||||
gBattleResources->flags->flags[battlerDef] |= RESOURCE_FLAG_ICE_FACE;
|
||||
// Form change will be done after attack animation in Cmd_resultmessage.
|
||||
goto END;
|
||||
continue;
|
||||
}
|
||||
if (gBattleMons[gBattlerTarget].hp > gBattleStruct->moveDamage[battlerDef])
|
||||
goto END;
|
||||
continue;
|
||||
|
||||
holdEffect = GetBattlerHoldEffect(battlerDef, TRUE);
|
||||
param = GetBattlerHoldEffectParam(battlerDef);
|
||||
@ -2178,7 +2178,7 @@ static void Cmd_adjustdamage(void)
|
||||
&& !gSpecialStatuses[battlerDef].focusSashed
|
||||
&& (B_AFFECTION_MECHANICS == FALSE || !gSpecialStatuses[battlerDef].affectionEndured)
|
||||
&& !gSpecialStatuses[battlerDef].sturdied)
|
||||
goto END;
|
||||
continue;
|
||||
|
||||
// Handle reducing the dmg to 1 hp.
|
||||
gBattleStruct->moveDamage[battlerDef] = gBattleMons[battlerDef].hp - 1;
|
||||
@ -2204,10 +2204,6 @@ static void Cmd_adjustdamage(void)
|
||||
{
|
||||
gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_ENDURED_AFFECTION;
|
||||
}
|
||||
|
||||
END:
|
||||
if (!(gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) && gBattleStruct->moveDamage[battlerDef] >= 1)
|
||||
gSpecialStatuses[gBattlerAttacker].damagedMons |= 1u << battlerDef;
|
||||
}
|
||||
|
||||
if (calcSpreadMoveDamage)
|
||||
@ -2580,14 +2576,10 @@ static void Cmd_datahpupdate(void)
|
||||
{
|
||||
if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler])
|
||||
{
|
||||
if (gSpecialStatuses[battler].shellBellDmg == 0)
|
||||
gSpecialStatuses[battler].shellBellDmg = gBattleStruct->moveDamage[battler];
|
||||
gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gSpecialStatuses[battler].shellBellDmg == 0)
|
||||
gSpecialStatuses[battler].shellBellDmg = gDisableStructs[battler].substituteHP;
|
||||
gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP;
|
||||
gDisableStructs[battler].substituteHP = 0;
|
||||
}
|
||||
@ -2653,10 +2645,6 @@ static void Cmd_datahpupdate(void)
|
||||
gBattleMons[battler].hp = 0;
|
||||
}
|
||||
|
||||
// Record damage for Shell Bell
|
||||
if (gSpecialStatuses[battler].shellBellDmg == 0 && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE))
|
||||
gSpecialStatuses[battler].shellBellDmg = gBattleStruct->moveDamage[battler];
|
||||
|
||||
u32 effect = GetMoveEffect(gCurrentMove);
|
||||
|
||||
// Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are
|
||||
@ -2700,13 +2688,7 @@ static void Cmd_datahpupdate(void)
|
||||
MarkBattlerForControllerExec(battler);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// MOVE_RESULT_NO_EFFECT was set
|
||||
battler = GetBattlerForBattleScript(cmd->battler);
|
||||
if (gSpecialStatuses[battler].shellBellDmg == 0)
|
||||
gSpecialStatuses[battler].shellBellDmg = IGNORE_SHELL_BELL;
|
||||
}
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -6996,7 +6978,6 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->ateBoost[gBattlerAttacker] = FALSE;
|
||||
gStatuses3[gBattlerAttacker] &= ~STATUS3_ME_FIRST;
|
||||
gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE;
|
||||
gSpecialStatuses[gBattlerAttacker].damagedMons = 0;
|
||||
gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = 0;
|
||||
gSpecialStatuses[gBattlerTarget].berryReduced = FALSE;
|
||||
gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE;
|
||||
@ -13247,7 +13228,6 @@ static void Cmd_painsplitdmgcalc(void)
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff;
|
||||
|
||||
gSpecialStatuses[gBattlerTarget].shellBellDmg = IGNORE_SHELL_BELL;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
|
||||
@ -2949,7 +2949,6 @@ bool32 HandleWishPerishSongOnTurnEnd(void)
|
||||
|
||||
gBattlerTarget = battler;
|
||||
gBattlerAttacker = gWishFutureKnock.futureSightBattlerIndex[battler];
|
||||
gSpecialStatuses[gBattlerTarget].shellBellDmg = IGNORE_SHELL_BELL;
|
||||
gCurrentMove = gWishFutureKnock.futureSightMove[battler];
|
||||
|
||||
party = GetSideParty(GetBattlerSide(gBattlerAttacker));
|
||||
@ -5888,7 +5887,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
||||
&& !IsBattlerAlive(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = gSpecialStatuses[gBattlerTarget].shellBellDmg;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget];
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_AftermathDmg;
|
||||
effect++;
|
||||
@ -8180,19 +8179,21 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn)
|
||||
switch (atkHoldEffect)
|
||||
{
|
||||
case HOLD_EFFECT_SHELL_BELL:
|
||||
if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage
|
||||
if (gBattleScripting.savedDmg > 0
|
||||
&& MoveResultHasEffect(battler)
|
||||
&& gBattlerAttacker != gBattlerTarget
|
||||
&& gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP
|
||||
&& !IsBattlerAtMaxHp(gBattlerAttacker)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_FUTURE_SIGHT
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_PAIN_SPLIT
|
||||
&& (B_HEAL_BLOCKING < GEN_5 || !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)))
|
||||
{
|
||||
gLastUsedItem = atkItem;
|
||||
gPotentialItemEffectBattler = gBattlerAttacker;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = (gSpecialStatuses[gBattlerTarget].shellBellDmg / atkHoldEffectParam) * -1;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleScripting.savedDmg / atkHoldEffectParam) * -1;
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = -1;
|
||||
gSpecialStatuses[gBattlerTarget].shellBellDmg = 0;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret;
|
||||
effect = ITEM_HP_CHANGE;
|
||||
@ -8200,11 +8201,11 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn)
|
||||
break;
|
||||
case HOLD_EFFECT_LIFE_ORB:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveDamage[gBattlerTarget]) // Needs the second check in case of Substitute
|
||||
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
&& !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage
|
||||
&& gSpecialStatuses[gBattlerAttacker].damagedMons)
|
||||
&& !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 10;
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
@ -8212,7 +8213,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn)
|
||||
effect = ITEM_HP_CHANGE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_ItemHurtRet;
|
||||
gLastUsedItem = gBattleMons[gBattlerAttacker].item;
|
||||
gLastUsedItem = atkItem;
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_THROAT_SPRAY: // Does NOT need to be a damaging move
|
||||
|
||||
0
test/battle/hold_effect/life_orb.c
Normal file
0
test/battle/hold_effect/life_orb.c
Normal file
141
test/battle/hold_effect/shell_bell.c
Normal file
141
test/battle/hold_effect/shell_bell.c
Normal file
@ -0,0 +1,141 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gItemsInfo[ITEM_SHELL_BELL].holdEffect == HOLD_EFFECT_SHELL_BELL);
|
||||
}
|
||||
|
||||
#define HITS 5
|
||||
SINGLE_BATTLE_TEST("Shell Bell recovers 1/8 of HP from after the last hit from all hits of a multi hit move")
|
||||
{
|
||||
s16 multiHitDamage[HITS];
|
||||
s16 totalDamage = 0;
|
||||
s16 shellBellRecovery = 0;
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_BULLET_SEED); }
|
||||
} SCENE {
|
||||
for (u32 i = 0; i < HITS; i++) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player);
|
||||
HP_BAR(opponent, captureDamage: &multiHitDamage[i]);
|
||||
totalDamage += multiHitDamage[i];
|
||||
}
|
||||
HP_BAR(player, captureDamage: &shellBellRecovery);
|
||||
} THEN {
|
||||
EXPECT_EQ(totalDamage / 8, -1 * shellBellRecovery);
|
||||
}
|
||||
}
|
||||
#undef HITS
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell recovers no HP if the move did no damage")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FALSE_SWIPE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FALSE_SWIPE, player);
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell activates if it hits a Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
// HP_BAR(opponent); // When you hit a sub the hp bar check doesn't work. Not sure if this is a bug
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell activates after Absorb")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ABSORB); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player);
|
||||
HP_BAR(opponent);
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell activates after Rough Skin")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_GIBLE) { Ability(ABILITY_ROUGH_SKIN); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
HP_BAR(opponent);
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is on the field")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN {}
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
MESSAGE("The opposing Wynaut took the Future Sight attack!");
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is not on the field")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
MESSAGE("The opposing Wynaut took the Future Sight attack!");
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
HP_BAR(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Thief or Covet, it will recover HP for the use of that move that stole the Shell Bell")
|
||||
TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Magician, it will recover HP for the use of that move that stole the Shell Bell")
|
||||
Loading…
x
Reference in New Issue
Block a user