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

Fixes crash damage move against absorbing abilities #6361

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
44 changes: 4 additions & 40 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -3429,51 +3429,15 @@ BattleScript_EffectSuperFang::
damagetohalftargethp
goto BattleScript_HitFromAtkAnimation

BattleScript_EffectRecoilIfMiss::
attackcanceler
accuracycheck BattleScript_MoveMissedDoDamage, ACC_CURR_MOVE
.if B_CRASH_IF_TARGET_IMMUNE >= GEN_4
typecalc
jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveMissedDoDamage
.endif
goto BattleScript_HitFromAtkString
BattleScript_MoveMissedDoDamage::
jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_PrintMoveMissed
attackstring
ppreduce
pause B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
.if B_CRASH_IF_TARGET_IMMUNE < GEN_4
jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd
.endif
moveendcase MOVEEND_PROTECT_LIKE_EFFECT @ Spiky Shield's damage happens before recoil.
jumpifhasnohp BS_ATTACKER, BattleScript_MoveEnd
BattleScript_RecoilIfMiss::
printstring STRINGID_PKMNCRASHED
waitmessage B_WAIT_TIME_LONG
damagecalc
typecalc
adjustdamage
.if B_CRASH_IF_TARGET_IMMUNE == GEN_4
manipulatedamage DMG_RECOIL_FROM_IMMUNE
.else
manipulatedamage DMG_RECOIL_FROM_MISS
.endif
.if B_CRASH_IF_TARGET_IMMUNE >= GEN_4
clearmoveresultflags MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE
.else
clearmoveresultflags MOVE_RESULT_MISSED
.endif
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE
jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_RecoilEnd
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_IGNORE_DISGUISE
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
tryfaintmon BS_ATTACKER
.if B_CRASH_IF_TARGET_IMMUNE >= GEN_4
setmoveresultflags MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE
.else
setmoveresultflags MOVE_RESULT_MISSED
.endif
goto BattleScript_MoveEnd
return

BattleScript_EffectMist::
attackcanceler
Expand Down
2 changes: 1 addition & 1 deletion include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ struct BattleStruct
u8 printedStrongWindsWeakenedAttack:1;
u8 numSpreadTargets:2;
u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY
u8 padding3:1;
u8 noTargetPresent:1;
u8 usedEjectItem;
u8 usedMicleBerry;
struct MessageStatus slideMessageStatus;
Expand Down
2 changes: 1 addition & 1 deletion include/battle_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ extern const u8 BattleScript_EffectOHKO[];
extern const u8 BattleScript_EffectSuperFang[];
extern const u8 BattleScript_EffectFixedDamageArg[];
extern const u8 BattleScript_EffectHealBlock[];
extern const u8 BattleScript_EffectRecoilIfMiss[];
extern const u8 BattleScript_RecoilIfMiss[];
extern const u8 BattleScript_EffectMist[];
extern const u8 BattleScript_EffectFocusEnergy[];
extern const u8 BattleScript_EffectConfuse[];
Expand Down
12 changes: 5 additions & 7 deletions include/constants/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,11 @@ enum CmdVarious

// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 1
#define DMG_RECOIL_FROM_MISS 2
#define DMG_DOUBLED 3
#define DMG_1_8_TARGET_HP 4
#define DMG_FULL_ATTACKER_HP 5
#define DMG_CURR_ATTACKER_HP 6
#define DMG_BIG_ROOT 7
#define DMG_RECOIL_FROM_IMMUNE 8 // Used to calculate recoil for the Gen 4 version of Jump Kick
#define DMG_DOUBLED 2
#define DMG_1_8_TARGET_HP 3
#define DMG_FULL_ATTACKER_HP 4
#define DMG_CURR_ATTACKER_HP 5
#define DMG_BIG_ROOT 6

// Cmd_jumpifcantswitch
#define SWITCH_IGNORE_ESCAPE_PREVENTION (1 << 7)
Expand Down
42 changes: 22 additions & 20 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,8 @@ static void Cmd_attackcanceler(void)
&& (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|| (IsMoveNotAllowedInSkyBattles(gCurrentMove)))
{
gBattleStruct->noTargetPresent = TRUE;

if (effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling.
gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem;
else
Expand Down Expand Up @@ -6360,6 +6362,25 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
}
else if (gMovesInfo[gCurrentMove].effect == EFFECT_RECOIL_IF_MISS
&& !IsBattlerTurnDamaged(gBattlerTarget)
&& !gBattleStruct->noTargetPresent
&& IsBattlerAlive(gBattlerAttacker))
{
if (B_RECOIL_IF_MISS_DMG >= GEN_5 || (B_CRASH_IF_TARGET_IMMUNE == GEN_4 && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_DOESNT_AFFECT_FOE))
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
else if (B_RECOIL_IF_MISS_DMG == GEN_4 && (GetNonDynamaxMaxHP(gBattlerTarget) / 2) < gBattleStruct->moveDamage[gBattlerTarget])
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
else // Fallback if B_RECOIL_IF_MISS_DMG is set to gen3 or lower.
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;

if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
gBattleStruct->moveDamage[gBattlerAttacker] = 1;

BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RecoilIfMiss;
effect = TRUE;
}
else if (moveRecoil > 0
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerAttacker)
Expand Down Expand Up @@ -7296,6 +7317,7 @@ static void Cmd_moveend(void)
gBattleStruct->fickleBeamBoosted = FALSE;
gBattleStruct->redCardActivates = FALSE;
gBattleStruct->battlerState[gBattlerAttacker].usedMicleBerry = FALSE;
gBattleStruct->noTargetPresent = FALSE;
if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
gBattleStruct->pledgeMove = FALSE;
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
Expand Down Expand Up @@ -11927,23 +11949,6 @@ static void Cmd_manipulatedamage(void)
case DMG_CHANGE_SIGN:
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
break;
case DMG_RECOIL_FROM_MISS:
if (B_RECOIL_IF_MISS_DMG >= GEN_5)
{
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
}
else if (B_RECOIL_IF_MISS_DMG == GEN_4)
{
if ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleStruct->moveDamage[gBattlerTarget])
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
}
else
{
gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget] /= 2;
}
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
gBattleStruct->moveDamage[gBattlerAttacker] = 1;
break;
case DMG_DOUBLED:
gBattleStruct->moveDamage[gBattlerTarget] *= 2;
break;
Expand All @@ -11961,9 +11966,6 @@ static void Cmd_manipulatedamage(void)
case DMG_CURR_ATTACKER_HP:
gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerAttacker);
break;
case DMG_RECOIL_FROM_IMMUNE:
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
break;
}

gBattlescriptCurrInstr = cmd->nextInstr;
Expand Down
2 changes: 1 addition & 1 deletion src/data/battle_move_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =

[EFFECT_RECOIL_IF_MISS] =
{
.battleScript = BattleScript_EffectRecoilIfMiss,
.battleScript = BattleScript_EffectHit,
.battleTvScore = 1,
},

Expand Down
41 changes: 37 additions & 4 deletions test/battle/move_effect/recoil_if_miss.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ASSUMPTIONS
ASSUME(GetMoveEffect(MOVE_JUMP_KICK) == EFFECT_RECOIL_IF_MISS);
}

SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick has 50% recoil on miss")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
Expand All @@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
}
}

SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect")
SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick has 50% recoil on protect")
{
GIVEN {
ASSUME(!MoveIgnoresProtect(MOVE_JUMP_KICK));
Expand All @@ -38,7 +38,7 @@ SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect")
}
}

SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick has no recoil if no target")
{
GIVEN {
ASSUME(B_HEALING_WISH_SWITCH >= GEN_5);
Expand All @@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
}
}

SINGLE_BATTLE_TEST("Jump Kick's recoil happens after Spiky Shield damage and Pokemon can faint from either of these")
SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick's recoil happens after Spiky Shield damage and Pokemon can faint from either of these")
{
s16 hp, maxHp = 256;
bool32 faintOnSpiky = FALSE, faintOnJumpKick = FALSE;
Expand Down Expand Up @@ -98,3 +98,36 @@ SINGLE_BATTLE_TEST("Jump Kick's recoil happens after Spiky Shield damage and Pok
}
}
}

SINGLE_BATTLE_TEST("Recoil if miss: Jump Kick recoil happens after Spiky Shield damage")
{
GIVEN {
ASSUME(!gMovesInfo[MOVE_JUMP_KICK].ignoresProtect);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_SPIKY_SHIELD); MOVE(player, MOVE_JUMP_KICK); }
} SCENE {
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKY_SHIELD, opponent);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_JUMP_KICK, player);
MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Spiky Shield!");
MESSAGE("Wobbuffet kept going and crashed!");
HP_BAR(player, damage: maxHP / 2);
}
}

SINGLE_BATTLE_TEST("Recoil if miss: Supercell Slam causes recoil if it is absorbed")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_LIGHTNING_ROD); }
} WHEN {
TURN { MOVE(player, MOVE_SUPERCELL_SLAM); }
} SCENE {
s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP);
ABILITY_POPUP(opponent, ABILITY_LIGHTNING_ROD);
MESSAGE("Wobbuffet kept going and crashed!");
HP_BAR(player, damage: maxHP / 2);
}
}