From 5965c08326c5d92473a5fc576cf7ab993402e0a6 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Fri, 14 Mar 2025 20:11:42 +0100 Subject: [PATCH] Create move end Sheer Force (#6411) --- include/constants/battle_script_commands.h | 4 ++-- src/battle_script_commands.c | 25 ++++++++++++---------- src/battle_util.c | 1 - 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 2aa5799a9e..782e0546c7 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -273,6 +273,7 @@ enum MoveEndEffects MOVEEND_ITEM_EFFECTS_TARGET, MOVEEND_MOVE_EFFECTS2, MOVEEND_ITEM_EFFECTS_ALL, + MOVEEND_SYMBIOSIS, MOVEEND_HIT_SWITCH_TARGET, MOVEEND_KINGSROCK, // These item effects will occur each strike of a multi-hit move MOVEEND_NUM_HITS, @@ -287,6 +288,7 @@ enum MoveEndEffects MOVEEND_RAPID_SPIN, MOVEEND_ITEM_EFFECTS_ATTACKER, MOVEEND_MAGICIAN, // Occurs after final multi-hit strike, and after other items/abilities would activate + MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until opportunist MOVEEND_RED_CARD, // Red Card triggers before Eject Pack MOVEEND_EJECT_ITEMS, MOVEEND_WHITE_HERB, @@ -294,10 +296,8 @@ enum MoveEndEffects MOVEEND_CHANGED_ITEMS, MOVEEND_PICKPOCKET, MOVEEND_EMERGENCY_EXIT, - MOVEEND_SYMBIOSIS, MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts MOVEEND_SAME_MOVE_TURNS, - MOVEEND_SET_EVOLUTION_TRACKER, MOVEEND_CLEAR_BITS, MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 495efc98a3..8e71ba08f5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6951,6 +6951,12 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + case MOVEEND_SHEER_FORCE: + if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) + gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + else + gBattleScripting.moveendState++; + break; case MOVEEND_EJECT_ITEMS: { // Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items. @@ -6975,8 +6981,6 @@ static void Cmd_moveend(void) if (battler != gBattlerAttacker && ejectButtonBattlers & (1u << battler)) { - if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Apparently Sheer Force blocks Eject Button, but not Eject Pack - continue; // Since we check if battler was damaged, we don't need to check move result. // In fact, doing so actually prevents multi-target moves from activating eject button properly if (!IsBattlerTurnDamaged(battler)) @@ -7111,7 +7115,6 @@ static void Cmd_moveend(void) if (IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item && !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off - && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Pickpocket doesn't activate for sheer force && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) // Pickpocket requires contact && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked { @@ -7196,24 +7199,24 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_SAME_MOVE_TURNS: - if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT || gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] + || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT + || gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) gBattleStruct->sameMoveTurns[gBattlerAttacker] = 0; else if (gCurrentMove == gLastResultingMoves[gBattlerAttacker] && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) gBattleStruct->sameMoveTurns[gBattlerAttacker]++; gBattleScripting.moveendState++; break; - case MOVEEND_SET_EVOLUTION_TRACKER: - // If the Pokémon needs to keep track of move usage for its evolutions, do it - if (originallyUsedMove != MOVE_NONE) - TryUpdateEvolutionTracker(EVO_USE_MOVE_TWENTY_TIMES, 1, originallyUsedMove); - gBattleScripting.moveendState++; - break; case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits. if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget) gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3; if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget) gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3; + // If the Pokémon needs to keep track of move usage for its evolutions, do it + if (originallyUsedMove != MOVE_NONE) + TryUpdateEvolutionTracker(EVO_USE_MOVE_TWENTY_TIMES, 1, originallyUsedMove); + if (B_RAMPAGE_CANCELLING >= GEN_5 && MoveHasAdditionalEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT // And it is unusable @@ -7277,7 +7280,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; - case MOVEEND_DANCER: // Special case because it's so annoying + case MOVEEND_DANCER: if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) { u32 battler, nextDancer = 0; diff --git a/src/battle_util.c b/src/battle_util.c index 737d894d0c..0d6a2c929e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8221,7 +8221,6 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) 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)