Fix Explosion + Galvanize + Volt Absorb and Mind Blown (#2688)

* Fix Explosion and Mind Blown
* Use battler ability in jumpifabilitypresent
This commit is contained in:
DizzyEggg 2023-02-21 23:50:29 +01:00 committed by GitHub
parent f3c6b647c0
commit d73ab0246f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 268 additions and 43 deletions

View File

@ -1318,6 +1318,12 @@
.4byte \jumpInstr .4byte \jumpInstr
.endm .endm
.macro jumpifmorethanhalfHP battler:req, jumpInstr:req
callnative BS_JumpIfMoreThanHalfHP
.byte \battler
.4byte \jumpInstr
.endm
@ various command changed to more readable macros @ various command changed to more readable macros
.macro cancelmultiturnmoves battler:req .macro cancelmultiturnmoves battler:req
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES

View File

@ -3418,26 +3418,19 @@ BattleScript_EffectParalyzeHit::
setmoveeffect MOVE_EFFECT_PARALYSIS setmoveeffect MOVE_EFFECT_PARALYSIS
goto BattleScript_EffectHit goto BattleScript_EffectHit
BattleScript_EffectExplosion:: BattleScript_EffectExplosion_AnimDmgRet:
attackcanceler jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionAnimRet
attackstring
ppreduce
@ Below jumps to BattleScript_DampStopsExplosion if it fails (only way it can)
tryexplosion
setatkhptozero
waitstate
jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionDoAnimStartLoop
call BattleScript_PreserveMissedBitDoMoveAnim call BattleScript_PreserveMissedBitDoMoveAnim
goto BattleScript_ExplosionLoop goto BattleScript_ExplosionDmgRet
BattleScript_ExplosionDoAnimStartLoop: BattleScript_ExplosionAnimRet:
attackanimation attackanimation
waitanimation waitanimation
BattleScript_ExplosionLoop: BattleScript_ExplosionDmgRet:
movevaluescleanup movevaluescleanup
critcalc critcalc
damagecalc damagecalc
adjustdamage adjustdamage
accuracycheck BattleScript_ExplosionMissed, ACC_CURR_MOVE accuracycheck BattleScript_ExplosionMissedRet, ACC_CURR_MOVE
effectivenesssound effectivenesssound
hitanimation BS_TARGET hitanimation BS_TARGET
waitstate waitstate
@ -3448,17 +3441,25 @@ BattleScript_ExplosionLoop:
resultmessage resultmessage
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
tryfaintmon BS_TARGET tryfaintmon BS_TARGET
moveendto MOVEEND_NEXT_TARGET BattleScript_ExplosionAnimEndRet_Return:
jumpifnexttargetvalid BattleScript_ExplosionLoop return
tryfaintmon BS_ATTACKER BattleScript_ExplosionMissedRet:
moveendcase MOVEEND_CLEAR_BITS
end
BattleScript_ExplosionMissed:
effectivenesssound effectivenesssound
resultmessage resultmessage
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
moveendto MOVEEND_NEXT_TARGET goto BattleScript_ExplosionAnimEndRet_Return
jumpifnexttargetvalid BattleScript_ExplosionLoop
BattleScript_EffectExplosion::
attackcanceler
attackstring
ppreduce
@ Below jumps to BattleScript_DampStopsExplosion if it fails (only way it can)
tryexplosion
waitstate
BattleScript_EffectExplosion_AnimDmgFaintAttacker:
call BattleScript_EffectExplosion_AnimDmgRet
moveendall
setatkhptozero
tryfaintmon BS_ATTACKER tryfaintmon BS_ATTACKER
end end
@ -3466,14 +3467,28 @@ BattleScript_EffectMindBlown::
attackcanceler attackcanceler
attackstring attackstring
ppreduce ppreduce
tryexplosion jumpifbyte CMP_GREATER_THAN, sB_ANIM_TARGETS_HIT, 0, BattleScript_EffectMindBlown_NoHpLoss
jumpifabilitypresent ABILITY_DAMP, BattleScript_MindBlownDamp
jumpifmorethanhalfHP BS_ATTACKER, BattleScript_EffectMindBlown_HpDown
setbyte sMULTIHIT_EFFECT, 0 @ Note to faint the attacker
instanthpdrop BS_ATTACKER
waitstate
goto BattleScript_EffectExplosion_AnimDmgFaintAttacker
BattleScript_EffectMindBlown_NoHpLoss:
jumpifbyte CMP_EQUAL, sMULTIHIT_EFFECT, 0, BattleScript_EffectExplosion_AnimDmgFaintAttacker
goto BattleScript_EffectMindBlown_AnimDmgNoFaint
BattleScript_MindBlownDamp:
copybyte gBattlerTarget, gBattlerAbility
goto BattleScript_DampStopsExplosion
BattleScript_EffectMindBlown_HpDown:
setbyte sMULTIHIT_EFFECT, 1 @ Note to not faint the attacker
dmg_1_2_attackerhp dmg_1_2_attackerhp
healthbarupdate BS_ATTACKER healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER datahpupdate BS_ATTACKER
waitstate waitstate
jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionDoAnimStartLoop BattleScript_EffectMindBlown_AnimDmgNoFaint:
call BattleScript_PreserveMissedBitDoMoveAnim call BattleScript_EffectExplosion_AnimDmgRet
goto BattleScript_ExplosionLoop goto BattleScript_MoveEnd
BattleScript_PreserveMissedBitDoMoveAnim: BattleScript_PreserveMissedBitDoMoveAnim:
bichalfword gMoveResultFlags, MOVE_RESULT_MISSED bichalfword gMoveResultFlags, MOVE_RESULT_MISSED
@ -8360,9 +8375,9 @@ BattleScript_AbilityRaisesDefenderStat::
BattleScript_AbilityPopUp: BattleScript_AbilityPopUp:
.if B_ABILITY_POP_UP == TRUE .if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ABILITY_BATTLER showabilitypopup BS_ABILITY_BATTLER
recordability BS_ABILITY_BATTLER
pause 40 pause 40
.endif .endif
recordability BS_ABILITY_BATTLER
sethword sABILITY_OVERWRITE, 0 sethword sABILITY_OVERWRITE, 0
return return

View File

@ -5017,10 +5017,17 @@ static void Cmd_jumpifabilitypresent(void)
{ {
CMD_ARGS(u16 ability, const u8 *jumpInstr); CMD_ARGS(u16 ability, const u8 *jumpInstr);
if (IsAbilityOnField(cmd->ability)) u16 ability = cmd->ability;
u32 abilityBattler = IsAbilityOnField(ability);
if (abilityBattler)
{
gBattlerAbility = abilityBattler - 1;
gBattlescriptCurrInstr = cmd->jumpInstr; gBattlescriptCurrInstr = cmd->jumpInstr;
}
else else
{
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
}
} }
static void Cmd_endselectionscript(void) static void Cmd_endselectionscript(void)
@ -11183,14 +11190,15 @@ static void Cmd_tryexplosion(void)
{ {
CMD_ARGS(); CMD_ARGS();
u32 dampBattler;
if (gBattleControllerExecFlags) if (gBattleControllerExecFlags)
return; return;
if ((gBattlerTarget = IsAbilityOnField(ABILITY_DAMP))) if ((dampBattler = IsAbilityOnField(ABILITY_DAMP)))
{ {
// Failed, a battler has Damp // Failed, a battler has Damp
gLastUsedAbility = ABILITY_DAMP; gLastUsedAbility = ABILITY_DAMP;
RecordAbilityBattle(--gBattlerTarget, ABILITY_DAMP); gBattlerTarget = --dampBattler;
gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; gBattlescriptCurrInstr = BattleScript_DampStopsExplosion;
return; return;
} }
@ -11200,14 +11208,6 @@ static void Cmd_tryexplosion(void)
BtlController_EmitHealthBarUpdate(BUFFER_A, INSTANT_HP_BAR_DROP); BtlController_EmitHealthBarUpdate(BUFFER_A, INSTANT_HP_BAR_DROP);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
if (gBattlerTarget == gBattlerAttacker)
continue;
if (IsBattlerAlive(gBattlerTarget))
break;
}
} }
static void Cmd_setatkhptozero(void) static void Cmd_setatkhptozero(void)
@ -16033,6 +16033,17 @@ void BS_CalcMetalBurstDmg(void)
} }
} }
void BS_JumpIfMoreThanHalfHP(void)
{
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
u8 battler = GetBattlerForBattleScript(cmd->battler);
if (gBattleMons[battler].hp > (gBattleMons[battler].maxHP + 1) / 2)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_JumpIfHoldEffect(void) void BS_JumpIfHoldEffect(void)
{ {
u8 battler = gBattlescriptCurrInstr[5]; u8 battler = gBattlescriptCurrInstr[5];

View File

@ -19,6 +19,26 @@ SINGLE_BATTLE_TEST("Damp prevents explosion-like moves from enemies")
} }
} }
DOUBLE_BATTLE_TEST("Damp prevents explosion-like moves from enemies in a double battle")
{
u32 move;
PARAMETRIZE { move = MOVE_EXPLOSION; }
PARAMETRIZE { move = MOVE_SELF_DESTRUCT; }
PARAMETRIZE { move = MOVE_MIND_BLOWN; }
PARAMETRIZE { move = MOVE_MISTY_EXPLOSION; }
GIVEN {
PLAYER(SPECIES_PARAS) { Ability(ABILITY_DAMP); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponentLeft, move); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_DAMP);
NONE_OF { HP_BAR(playerLeft); HP_BAR(opponentLeft); HP_BAR(playerRight); HP_BAR(opponentRight); }
}
}
SINGLE_BATTLE_TEST("Damp prevents explosion-like moves from self") SINGLE_BATTLE_TEST("Damp prevents explosion-like moves from self")
{ {
u32 move; u32 move;

View File

@ -63,6 +63,30 @@ SINGLE_BATTLE_TEST("Volt Absorb is only triggered once on multi strike moves")
} }
} }
DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from damaging other pokemon", s16 damage1, s16 damage2) // Fixed issue #1961
{
GIVEN {
ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
ASSUME(gBattleMoves[MOVE_EXPLOSION].type == TYPE_NORMAL);
PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(TEST_MAX_HP); }
PLAYER(SPECIES_ABRA);
OPPONENT(SPECIES_GRAVELER_ALOLAN) { Ability(ABILITY_GALVANIZE); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(opponentLeft, MOVE_EXPLOSION); }
} SCENE {
ABILITY_POPUP(playerLeft, ABILITY_VOLT_ABSORB);
HP_BAR(playerLeft, hp: TEST_MAX_HP / 4 + 1);
MESSAGE("Jolteon restored HP using its Volt Absorb!");
HP_BAR(playerRight, captureDamage: &results->damage1);
HP_BAR(opponentRight, captureDamage: &results->damage2);
}
FINALLY {
EXPECT_NE(results[0].damage1, 0);
EXPECT_NE(results[0].damage2, 0);
}
}
SINGLE_BATTLE_TEST("Volt Absorb prevents Cell Battery from activating") SINGLE_BATTLE_TEST("Volt Absorb prevents Cell Battery from activating")
{ {
GIVEN { GIVEN {

View File

@ -8,7 +8,6 @@ ASSUMPTIONS
SINGLE_BATTLE_TEST("Explosion causes the user to faint") SINGLE_BATTLE_TEST("Explosion causes the user to faint")
{ {
u16 remainingHP;
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
@ -17,12 +16,29 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint")
} SCENE { } SCENE {
HP_BAR(player, hp: 0); HP_BAR(player, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player);
MESSAGE("Wobbuffet fainted!");
}
}
SINGLE_BATTLE_TEST("Explosion causes the user & the target to faint")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_EXPLOSION); }
} SCENE {
HP_BAR(player, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player);
HP_BAR(opponent, hp: 0);
MESSAGE("Foe Wobbuffet fainted!");
MESSAGE("Wobbuffet fainted!");
} }
} }
SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it misses") SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it misses")
{ {
u16 remainingHP;
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
@ -31,12 +47,12 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it misses")
} SCENE { } SCENE {
HP_BAR(player, hp: 0); HP_BAR(player, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player);
MESSAGE("Wobbuffet fainted!");
} }
} }
SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect") SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect")
{ {
u16 remainingHP;
GIVEN { GIVEN {
ASSUME(gBattleMoves[MOVE_EXPLOSION].type == TYPE_NORMAL); ASSUME(gBattleMoves[MOVE_EXPLOSION].type == TYPE_NORMAL);
ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST); ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST);
@ -49,5 +65,29 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect"
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player);
MESSAGE("It doesn't affect Foe Gastly…"); MESSAGE("It doesn't affect Foe Gastly…");
NOT HP_BAR(opponent); NOT HP_BAR(opponent);
MESSAGE("Wobbuffet fainted!");
}
}
DOUBLE_BATTLE_TEST("Explosion causes everyone to faint in a double battle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_ABRA) { HP(1); }
OPPONENT(SPECIES_KADABRA) { HP(1); }
OPPONENT(SPECIES_KADABRA);
} WHEN {
TURN { MOVE(playerLeft, MOVE_EXPLOSION); }
} SCENE {
HP_BAR(playerLeft, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
HP_BAR(opponentLeft, hp: 0);
MESSAGE("Foe Abra fainted!");
HP_BAR(playerRight, hp: 0);
MESSAGE("Wynaut fainted!");
HP_BAR(opponentRight, hp: 0);
MESSAGE("Foe Kadabra fainted!");
MESSAGE("Wobbuffet fainted!");
} }
} }

View File

@ -0,0 +1,109 @@
#include "global.h"
#include "test_battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_MIND_BLOWN].effect == EFFECT_MIND_BLOWN);
}
#define HP_TEST (400)
SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST); MaxHP(HP_TEST); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_MIND_BLOWN); }
} SCENE {
HP_BAR(player, hp: HP_TEST / 2);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player);
NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint.
}
}
DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP in a double battle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST); MaxHP(HP_TEST); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); }
} SCENE {
HP_BAR(playerLeft, hp: HP_TEST / 2);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft);
NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint.
}
}
SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST / 2); MaxHP(HP_TEST); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_MIND_BLOWN); }
} SCENE {
HP_BAR(player, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player);
MESSAGE("Wobbuffet fainted!");
}
}
DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP in a double battle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST / 2); MaxHP(HP_TEST); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_MIND_BLOWN);}
} SCENE {
HP_BAR(playerLeft, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft);
MESSAGE("Wobbuffet fainted!");
}
}
SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below 1/2 of its HP")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST / 2) ; MaxHP(HP_TEST); }
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_MIND_BLOWN);}
} SCENE {
HP_BAR(player, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player);
HP_BAR(opponent, hp: 0);
MESSAGE("Foe Wobbuffet fainted!");
MESSAGE("Wobbuffet fainted!");
}
}
DOUBLE_BATTLE_TEST("Mind Blown causes everyone to faint in a double battle")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(HP_TEST / 2); MaxHP(HP_TEST); }
PLAYER(SPECIES_WYNAUT) { HP(1); }
OPPONENT(SPECIES_ABRA) { HP(1); }
OPPONENT(SPECIES_KADABRA) { HP(1); }
OPPONENT(SPECIES_KADABRA);
} WHEN {
TURN { MOVE(playerLeft, MOVE_MIND_BLOWN, criticalHit: FALSE); }
} SCENE {
HP_BAR(playerLeft, hp: 0);
ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft);
HP_BAR(opponentLeft, hp: 0);
MESSAGE("Foe Abra fainted!");
HP_BAR(playerRight, hp: 0);
MESSAGE("Wynaut fainted!");
HP_BAR(opponentRight, hp: 0);
MESSAGE("Foe Kadabra fainted!");
MESSAGE("Wobbuffet fainted!");
}
}