diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a1ee84a529..d9338ad599 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1508,12 +1508,6 @@ .4byte \jumpInstr .endm - .macro jumpifemergencyexited battler:req, jumpInstr:req - callnative BS_JumpIfEmergencyExited - .byte \battler - .4byte \jumpInstr - .endm - .macro jumpifelectricabilityaffected battler:req, ability:req, jumpInstr:req callnative BS_JumpIfElectricAbilityAffected .byte \battler diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d67b32faf2..ae9ff11e01 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -308,13 +308,17 @@ BattleScript_CheckPrimalWeather: jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_STRONG_WINDS, BattleScript_MysteriousAirCurrentBlowsOn return -BattleScript_MoveSwitchPursuit: +BattleScript_MoveSwitchPursuitEnd: + call BattleScript_MoveSwitchPursuitRet + end + +BattleScript_MoveSwitchPursuitRet: jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_MoveSwitchEnd jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_MoveSwitchEnd printstring STRINGID_PKMNWENTBACK waitmessage B_WAIT_TIME_SHORT jumpifnopursuitswitchdmg BattleScript_MoveSwitchOpenPartyScreen - end + return BattleScript_MoveSwitch: jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_MoveSwitchEnd @@ -1344,7 +1348,7 @@ BattleScript_EffectPartingShotTrySpAtk: waitmessage B_WAIT_TIME_LONG BattleScript_EffectPartingShotSwitch: moveendall - goto BattleScript_MoveSwitchPursuit + goto BattleScript_MoveSwitchPursuitEnd BattleScript_EffectPowder:: attackcanceler @@ -2768,21 +2772,12 @@ BattleScript_EffectHealBlock:: goto BattleScript_MoveEnd BattleScript_EffectHitEscape:: - call BattleScript_EffectHit_Ret - jumpifmovehadnoeffect BattleScript_MoveEnd - tryfaintmon BS_TARGET - moveendto MOVEEND_ATTACKER_VISIBLE - moveendfrom MOVEEND_TARGET_VISIBLE - jumpifbattleend BattleScript_HitEscapeEnd - jumpifbyte CMP_NOT_EQUAL, gBattleOutcome, 0, BattleScript_HitEscapeEnd - jumpifemergencyexited BS_TARGET, BattleScript_HitEscapeEnd jumpiffainted BS_TARGET, FALSE, BattleScript_HitEscapeSwitch setbyte sGIVEEXP_STATE, 0 getexp BS_TARGET BattleScript_HitEscapeSwitch: - goto BattleScript_MoveSwitchPursuit -BattleScript_HitEscapeEnd: - end + call BattleScript_MoveSwitchPursuitRet + return BattleScript_EffectPlaceholder:: attackcanceler diff --git a/include/battle.h b/include/battle.h index 2c4e0cfbb2..457cbbc6b0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -192,7 +192,7 @@ struct SpecialStatus u8 lightningRodRedirected:1; u8 restoredBattlerSprite: 1; u8 faintedHasReplacement:1; - u8 emergencyExited:1; + u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects. u8 afterYou:1; u8 enduredDamage:1; u8 stormDrainRedirected:1; @@ -216,8 +216,7 @@ struct SpecialStatus // End of byte u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; - u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects. - u8 unused:3; + u8 unused:4; // End of byte }; diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 23cec12e24..6bd25e8647 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -27,6 +27,7 @@ s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec s32 GetCritHitOdds(s32 critChanceIndex); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); +bool32 NoAliveMonsForBattlerSide(u32 battler); bool32 NoAliveMonsForPlayer(void); bool32 NoAliveMonsForEitherParty(void); void SetMoveEffect(bool32 primary, bool32 certain); diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index c59b0ee170..42a654471d 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -286,6 +286,7 @@ enum MoveEndEffects MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc MOVEEND_EMERGENCY_EXIT, MOVEEND_EJECT_PACK, + MOVEEND_HIT_ESCAPE, MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts MOVEEND_PICKPOCKET, MOVEEND_WHITE_HERB, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 29ae4a5917..558b0d6f1f 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2199,6 +2199,7 @@ static void Cmd_adjustdamage(void) // Damage deals typeless 0 HP. gBattleStruct->moveResultFlags[battlerDef] &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE); gBattleStruct->moveDamage[battlerDef] = 0; + gSpecialStatuses[battlerDef].enduredDamage = TRUE; RecordAbilityBattle(gBattlerTarget, ABILITY_ICE_FACE); gDisableStructs[battlerDef].iceFaceActivationPrevention = TRUE; // Form change will be done after attack animation in Cmd_resultmessage. @@ -5412,6 +5413,21 @@ static void Cmd_getexp(void) } } +bool32 NoAliveMonsForBattlerSide(u32 battler) +{ + struct Pokemon *party = GetBattlerParty(battler); + + for (u32 partyMon = 0; partyMon < PARTY_SIZE; partyMon++) + { + if (GetMonData(&party[partyMon], MON_DATA_SPECIES) + && GetMonData(&gEnemyParty[partyMon], MON_DATA_HP) > 0 + && !GetMonData(&party[partyMon], MON_DATA_IS_EGG)) + return FALSE; + } + + return TRUE; +} + bool32 NoAliveMonsForPlayer(void) { u32 i; @@ -7302,11 +7318,7 @@ static void Cmd_moveend(void) gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; - if (moveEffect == EFFECT_HIT_ESCAPE) - gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection - effect = TRUE; - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; gBattleStruct->battlerState[battler].usedEjectItem = TRUE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; @@ -7314,7 +7326,9 @@ static void Cmd_moveend(void) break; // Only the fastest Eject Button activates } } - if (!effect) + if (effect) + gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + else gBattleScripting.moveendState++; break; case MOVEEND_EJECT_PACK: @@ -7351,10 +7365,6 @@ static void Cmd_moveend(void) gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; - - if (moveEffect == EFFECT_HIT_ESCAPE) - gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection - effect = TRUE; gBattleStruct->battlerState[battler].usedEjectItem = TRUE; BattleScriptPushCursor(); @@ -7364,7 +7374,10 @@ static void Cmd_moveend(void) break; // Only the fastest Eject item activates } } - gBattleScripting.moveendState++; + if (effect) + gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + else + gBattleScripting.moveendState++; break; case MOVEEND_WHITE_HERB: for (i = 0; i < gBattlersCount; i++) @@ -7413,14 +7426,11 @@ static void Cmd_moveend(void) && !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battler))) { effect = TRUE; - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; gLastUsedItem = gBattleMons[battler].item; SaveBattlerTarget(battler); // save battler with red card SaveBattlerAttacker(gBattlerAttacker); gBattleScripting.battler = battler; gEffectBattler = gBattlerAttacker; - if (moveEffect == EFFECT_HIT_ESCAPE) - gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection BattleScriptPushCursor(); if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE || GetBattlerAbility(gBattlerAttacker) == ABILITY_GUARD_DOG @@ -7433,7 +7443,9 @@ static void Cmd_moveend(void) } } } - if (!effect) + if (effect) + gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + else gBattleScripting.moveendState++; break; case MOVEEND_LIFEORB_SHELLBELL: @@ -7514,8 +7526,6 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection effect = TRUE; - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; - gSpecialStatuses[battler].emergencyExited = TRUE; gBattleScripting.battler = battler; BattleScriptPushCursor(); @@ -7527,9 +7537,24 @@ static void Cmd_moveend(void) break; // Only the fastest Emergency Exit / Wimp Out activates } } - if (!effect) + if (effect) + gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + else gBattleScripting.moveendState++; break; + case MOVEEND_HIT_ESCAPE: + if (moveEffect == EFFECT_HIT_ESCAPE + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && IsBattlerTurnDamaged(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !NoAliveMonsForBattlerSide(gBattlerTarget)) + { + effect = TRUE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_EffectHitEscape; + } + gBattleScripting.moveendState++; + break; case MOVEEND_SYMBIOSIS: for (i = 0; i < gBattlersCount; i++) { @@ -17436,16 +17461,6 @@ void BS_JumpIfShellTrap(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfEmergencyExited(void) -{ - NATIVE_ARGS(u8 battler, const u8 *jumpInstr); - u8 battler = GetBattlerForBattleScript(cmd->battler); - if (gSpecialStatuses[battler].emergencyExited) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_JumpIfElectricAbilityAffected(void) { NATIVE_ARGS(u8 battler, u16 ability, const u8 *jumpInstr); diff --git a/src/battle_util.c b/src/battle_util.c index 55304318c0..0206122aec 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -522,10 +522,7 @@ void HandleAction_UseMove(void) BattleArena_AddMindPoints(gBattlerAttacker); for (i = 0; i < MAX_BATTLERS_COUNT; i++) - { gBattleStruct->hpBefore[i] = gBattleMons[i].hp; - gSpecialStatuses[i].emergencyExited = FALSE; - } gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 38928c4f4c..d0481b4a95 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1080,7 +1080,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_HIT_ESCAPE] = { - .battleScript = BattleScript_EffectHitEscape, + .battleScript = BattleScript_EffectHit, .battleTvScore = 4, }, diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index 83280f9f50..57743ceee0 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -179,3 +179,18 @@ SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pok EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); } } + +SINGLE_BATTLE_TEST("Hit Escape: U-turn will fail to switch if the user faints") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ROCKY_HELMET); } + } WHEN { + TURN { MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); + HP_BAR(opponent); + } +} +