Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions asm/macros/battle_script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1317,6 +1317,12 @@
.2byte \holdEffect
.4byte \jumpInstr
.endm

.macro jumpifmorethanhalfHP battler:req, jumpInstr:req
callnative BS_JumpIfMoreThanHalfHP
.byte \battler
.4byte \jumpInstr
.endm

@ various command changed to more readable macros
.macro cancelmultiturnmoves battler:req
Expand Down
69 changes: 42 additions & 27 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -3405,27 +3405,20 @@ BattleScript_EffectFreezeHit::
BattleScript_EffectParalyzeHit::
setmoveeffect MOVE_EFFECT_PARALYSIS
goto BattleScript_EffectHit

BattleScript_EffectExplosion::
attackcanceler
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

BattleScript_EffectExplosion_AnimDmgRet:
jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionAnimRet
call BattleScript_PreserveMissedBitDoMoveAnim
goto BattleScript_ExplosionLoop
BattleScript_ExplosionDoAnimStartLoop:
goto BattleScript_ExplosionDmgRet
BattleScript_ExplosionAnimRet:
attackanimation
waitanimation
BattleScript_ExplosionLoop:
BattleScript_ExplosionDmgRet:
movevaluescleanup
critcalc
damagecalc
adjustdamage
accuracycheck BattleScript_ExplosionMissed, ACC_CURR_MOVE
accuracycheck BattleScript_ExplosionMissedRet, ACC_CURR_MOVE
effectivenesssound
hitanimation BS_TARGET
waitstate
Expand All @@ -3436,32 +3429,54 @@ BattleScript_ExplosionLoop:
resultmessage
waitmessage B_WAIT_TIME_LONG
tryfaintmon BS_TARGET
moveendto MOVEEND_NEXT_TARGET
jumpifnexttargetvalid BattleScript_ExplosionLoop
tryfaintmon BS_ATTACKER
moveendcase MOVEEND_CLEAR_BITS
end
BattleScript_ExplosionMissed:
BattleScript_ExplosionAnimEndRet_Return:
return
BattleScript_ExplosionMissedRet:
effectivenesssound
resultmessage
waitmessage B_WAIT_TIME_LONG
moveendto MOVEEND_NEXT_TARGET
jumpifnexttargetvalid BattleScript_ExplosionLoop
goto BattleScript_ExplosionAnimEndRet_Return

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
end

BattleScript_EffectMindBlown::
attackcanceler
attackstring
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
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
waitstate
jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionDoAnimStartLoop
call BattleScript_PreserveMissedBitDoMoveAnim
goto BattleScript_ExplosionLoop
BattleScript_EffectMindBlown_AnimDmgNoFaint:
call BattleScript_EffectExplosion_AnimDmgRet
goto BattleScript_MoveEnd

BattleScript_PreserveMissedBitDoMoveAnim:
bichalfword gMoveResultFlags, MOVE_RESULT_MISSED
Expand Down Expand Up @@ -8349,9 +8364,9 @@ BattleScript_AbilityRaisesDefenderStat::
BattleScript_AbilityPopUp:
.if B_ABILITY_POP_UP == TRUE
showabilitypopup BS_ABILITY_BATTLER
recordability BS_ABILITY_BATTLER
pause 40
.endif
recordability BS_ABILITY_BATTLER
sethword sABILITY_OVERWRITE, 0
return

Expand Down
33 changes: 22 additions & 11 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -5017,10 +5017,17 @@ static void Cmd_jumpifabilitypresent(void)
{
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;
}
else
{
gBattlescriptCurrInstr = cmd->nextInstr;
}
}

static void Cmd_endselectionscript(void)
Expand Down Expand Up @@ -11148,14 +11155,15 @@ static void Cmd_tryexplosion(void)
{
CMD_ARGS();

u32 dampBattler;
if (gBattleControllerExecFlags)
return;

if ((gBattlerTarget = IsAbilityOnField(ABILITY_DAMP)))
if ((dampBattler = IsAbilityOnField(ABILITY_DAMP)))
{
// Failed, a battler has Damp
gLastUsedAbility = ABILITY_DAMP;
RecordAbilityBattle(--gBattlerTarget, ABILITY_DAMP);
gBattlerTarget = --dampBattler;
gBattlescriptCurrInstr = BattleScript_DampStopsExplosion;
return;
}
Expand All @@ -11165,14 +11173,6 @@ static void Cmd_tryexplosion(void)
BtlController_EmitHealthBarUpdate(BUFFER_A, INSTANT_HP_BAR_DROP);
MarkBattlerForControllerExec(gActiveBattler);
gBattlescriptCurrInstr = cmd->nextInstr;

for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
if (gBattlerTarget == gBattlerAttacker)
continue;
if (IsBattlerAlive(gBattlerTarget))
break;
}
}

static void Cmd_setatkhptozero(void)
Expand Down Expand Up @@ -16038,6 +16038,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)
{
u8 battler = gBattlescriptCurrInstr[5];
Expand Down
20 changes: 20 additions & 0 deletions test/ability_damp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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")
{
u32 move;
Expand Down
28 changes: 26 additions & 2 deletions test/ability_volt_absorb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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")
{
GIVEN {
Expand All @@ -75,11 +99,11 @@ SINGLE_BATTLE_TEST("Volt Absorb prevents Cell Battery from activating")
ABILITY_POPUP(player, ABILITY_VOLT_ABSORB);
HP_BAR(player, hp: TEST_MAX_HP / 4 + 1);
MESSAGE("Jolteon restored HP using its Volt Absorb!");
NONE_OF {
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Using Cell Battery, the attack of Jolteon rose!");
}

}
}
46 changes: 43 additions & 3 deletions test/move_effect_explosion.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ ASSUMPTIONS

SINGLE_BATTLE_TEST("Explosion causes the user to faint")
{
u16 remainingHP;
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
Expand All @@ -17,12 +16,29 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint")
} SCENE {
HP_BAR(player, hp: 0);
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")
{
u16 remainingHP;
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
Expand All @@ -31,12 +47,12 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it misses")
} SCENE {
HP_BAR(player, hp: 0);
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")
{
u16 remainingHP;
GIVEN {
ASSUME(gBattleMoves[MOVE_EXPLOSION].type == TYPE_NORMAL);
ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST);
Expand All @@ -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);
MESSAGE("It doesn't affect Foe Gastly…");
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!");
}
}
Loading