From 7df32985342380ea207a32143c4b3f73e5aef10a Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:43:45 +0100 Subject: [PATCH] Minor Recoil Effect refactor (#6409) --- include/constants/battle_move_effects.h | 1 + include/move.h | 26 ++++++------- src/battle_ai_util.c | 9 ++--- src/battle_script_commands.c | 2 +- src/data/battle_move_effects.h | 6 +++ src/data/moves_info.h | 50 ++++++++++++------------- test/battle/move_flags/recoil.c | 12 +++--- 7 files changed, 56 insertions(+), 50 deletions(-) diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 6525cf1544..1e0a6f35fe 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -352,6 +352,7 @@ enum { EFFECT_ORDER_UP, EFFECT_RAPID_SPIN, EFFECT_SPECTRAL_THIEF, + EFFECT_RECOIL, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/move.h b/include/move.h index 5537840703..d00751642a 100644 --- a/include/move.h +++ b/include/move.h @@ -56,7 +56,6 @@ struct MoveInfo } zMove; // end of word s32 priority:4; - u32 recoil:7; u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit. u32 criticalHitStage:2; bool32 alwaysCriticalHit:1; @@ -74,7 +73,6 @@ struct MoveInfo bool32 ballisticMove:1; bool32 powderMove:1; bool32 danceMove:1; - // end of word bool32 windMove:1; bool32 slicingMove:1; bool32 healingMove:1; @@ -82,6 +80,7 @@ struct MoveInfo bool32 ignoresTargetAbility:1; bool32 ignoresTargetDefenseEvasionStages:1; bool32 damagesUnderground:1; + // end of word bool32 damagesUnderwater:1; bool32 damagesAirborne:1; bool32 damagesAirborneDoubleDamage:1; @@ -106,7 +105,7 @@ struct MoveInfo bool32 sketchBanned:1; //Other bool32 validApprenticeMove:1; - u32 padding:3; + u32 padding:10; // end of word union { @@ -119,11 +118,12 @@ struct MoveInfo u16 property; // can be used to remove the hardcoded values } protect; u32 status; - u16 moveProperty; - u16 holdEffect; - u16 type; - u16 fixedDamage; - u16 absorbPercentage; + u32 moveProperty; + u32 holdEffect; + u32 type; + u32 fixedDamage; + u32 absorbPercentage; + u32 recoilPercentage; } argument; // primary/secondary effects @@ -212,11 +212,6 @@ static inline s32 GetMovePriority(u32 moveId) return gMovesInfo[SanitizeMoveId(moveId)].priority; } -static inline u32 GetMoveRecoil(u32 moveId) -{ - return gMovesInfo[SanitizeMoveId(moveId)].recoil; -} - static inline u32 GetMoveStrikeCount(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].strikeCount; @@ -490,6 +485,11 @@ static inline u32 GetMoveAbsorbPercentage(u32 moveId) return gMovesInfo[moveId].argument.absorbPercentage; } +static inline u32 GetMoveRecoil(u32 moveId) +{ + return gMovesInfo[SanitizeMoveId(moveId)].argument.recoilPercentage; +} + static inline const struct AdditionalEffect *GetMoveAdditionalEffectById(u32 moveId, u32 effect) { return &gMovesInfo[SanitizeMoveId(moveId)].additionalEffects[effect]; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 24bb482b4a..8de3f078ca 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -947,10 +947,6 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s u32 abilityDef = AI_DATA->abilities[battlerDef]; u8 i; - // recoil - if (GetMoveRecoil(move) > 0 && AI_IsDamagedByRecoil(battlerAtk)) - return TRUE; - switch (GetMoveEffect(move)) { case EFFECT_MAX_HP_50_RECOIL: @@ -961,6 +957,9 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s case EFFECT_RECOIL_IF_MISS: if (AI_IsDamagedByRecoil(battlerAtk)) return TRUE; + case EFFECT_RECOIL: + if (AI_IsDamagedByRecoil(battlerAtk)) + return TRUE; break; default: { @@ -3923,7 +3922,7 @@ static u32 IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statI { if (GetMonData(&playerParty[AI_DATA->mostSuitableMonId[battlerDef]], MON_DATA_SPEED, NULL) > gBattleMons[battlerAtk].speed) return NO_INCREASE; - } + } } // Otherwise if predicting switch, stat increases are great momentum tempScore += WEAK_EFFECT; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e67323ffa9..495efc98a3 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6361,7 +6361,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; } - else if (moveRecoil > 0 + else if (moveEffect == EFFECT_RECOIL && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index e2970afcaf..cf9814ac02 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2246,4 +2246,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectSpectralThief, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_RECOIL] = + { + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 0a8c157806..b34aad70d4 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -1019,15 +1019,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A reckless charge attack\n" "that also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 90, .type = TYPE_NORMAL, .accuracy = 85, - .recoil = 25, .pp = 20, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 25 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -1071,15 +1071,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A life-risking tackle that\n" "also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_NORMAL, .accuracy = 100, - .recoil = 33, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -1785,16 +1785,16 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A reckless body slam that\n" "also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 80, .type = TYPE_FIGHTING, .accuracy = 80, .pp = B_UPDATED_MOVE_DATA >= GEN_6 ? 20 : 25, - .recoil = 25, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, + .argument = { .recoilPercentage = 25 }, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -4333,9 +4333,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), #else - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .accuracy = 100, - .recoil = 25, + .argument = { .recoilPercentage = 25 }, #endif .power = 50, .type = TYPE_NORMAL, @@ -8989,11 +8989,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .power = 120, .type = TYPE_ELECTRIC, .accuracy = 100, - .recoil = 33, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, #if B_UPDATED_MOVE_DATA >= GEN_4 .additionalEffects = ADDITIONAL_EFFECTS({ @@ -10191,15 +10191,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A charge that may burn the\n" "foe. Also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_FIRE, .accuracy = 100, - .recoil = 33, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .thawsUser = TRUE, .additionalEffects = ADDITIONAL_EFFECTS({ @@ -10655,15 +10655,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A low altitude charge that\n" "also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_FLYING, .accuracy = 100, - .recoil = 33, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_CUTE, @@ -11632,15 +11632,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Slams the body into a foe.\n" "The user gets hurt too."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_GRASS, .accuracy = 100, - .recoil = 33, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -11750,15 +11750,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A life-risking headbutt that\n" "seriously hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 150, .type = TYPE_ROCK, .accuracy = 80, - .recoil = 50, .pp = 5, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 50 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -13445,15 +13445,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "An electrical tackle that\n" "also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 90, .type = TYPE_ELECTRIC, .accuracy = 100, - .recoil = 25, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 25 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_COOL, @@ -13802,15 +13802,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A charge using guard hair.\n" "It hurts the user a little."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 120, .type = TYPE_NORMAL, .accuracy = 100, - .recoil = 25, .pp = 15, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 25 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -15655,15 +15655,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Fires a great beam of light\n" "that also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = 140, .type = TYPE_FAIRY, .accuracy = 90, - .recoil = 50, .pp = 5, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, + .argument = { .recoilPercentage = 50 }, .metronomeBanned = TRUE, .battleAnimScript = gBattleAnimMove_LightOfRuin, }, @@ -19202,15 +19202,15 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A slam shrouded in water.\n" "It also hurts the user."), - .effect = EFFECT_HIT, + .effect = EFFECT_RECOIL, .power = B_UPDATED_MOVE_DATA >= GEN_9 ? 120 : 75, .type = TYPE_WATER, .accuracy = 100, - .recoil = 33, .pp = 10, .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, + .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, .battleAnimScript = gBattleAnimMove_WaveCrash, diff --git a/test/battle/move_flags/recoil.c b/test/battle/move_flags/recoil.c index 5a8f3be576..b775c175d3 100644 --- a/test/battle/move_flags/recoil.c +++ b/test/battle/move_flags/recoil.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Take Down deals 25% of recoil damage to the user") +SINGLE_BATTLE_TEST("Recoil: Take Down deals 25% of recoil damage to the user") { s16 directDamage; s16 recoilDamage; @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Take Down deals 25% of recoil damage to the user") } } -SINGLE_BATTLE_TEST("Double Edge deals 33% of recoil damage to the user") +SINGLE_BATTLE_TEST("Recoil: Double Edge deals 33% of recoil damage to the user") { s16 directDamage; s16 recoilDamage; @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Double Edge deals 33% of recoil damage to the user") } } -SINGLE_BATTLE_TEST("Head Smash deals 50% of recoil damage to the user") +SINGLE_BATTLE_TEST("Recoil: Head Smash deals 50% of recoil damage to the user") { s16 directDamage; s16 recoilDamage; @@ -61,7 +61,7 @@ SINGLE_BATTLE_TEST("Head Smash deals 50% of recoil damage to the user") } } -SINGLE_BATTLE_TEST("Flare Blitz deals 33% of recoil damage to the user and can burn target") +SINGLE_BATTLE_TEST("Recoil: Flare Blitz deals 33% of recoil damage to the user and can burn target") { s16 directDamage; s16 recoilDamage; @@ -84,10 +84,10 @@ SINGLE_BATTLE_TEST("Flare Blitz deals 33% of recoil damage to the user and can b } } -SINGLE_BATTLE_TEST("Flare Blitz is absorbed by Flash Fire and no recoil damage is dealt") +SINGLE_BATTLE_TEST("Recoil: Flare Blitz is absorbed by Flash Fire and no recoil damage is dealt") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLARE_BLITZ].recoil > 0); + ASSUME(GetMoveRecoil(MOVE_FLARE_BLITZ) > 0); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_VULPIX) { Ability(ABILITY_FLASH_FIRE); }; } WHEN {