From 71cfab64774b5148be27e0677015257d16022e26 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:01:00 +0200 Subject: [PATCH] Fixes Magician Life Orb interaction (#6676) --- include/battle.h | 4 +--- include/battle_util.h | 1 + src/battle_script_commands.c | 2 -- src/battle_util.c | 32 +++++++++++--------------------- test/battle/ability/magician.c | 8 +++----- 5 files changed, 16 insertions(+), 31 deletions(-) diff --git a/include/battle.h b/include/battle.h index 1189ada4ea..185e565ed2 100644 --- a/include/battle.h +++ b/include/battle.h @@ -228,13 +228,11 @@ struct SpecialStatus // End of byte u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; - u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects. u8 distortedTypeMatchups:1; u8 teraShellAbilityDone:1; u8 criticalHit:1; - // End of byte u8 enduredDamage:1; - u8 padding:7; + // End of byte }; struct SideTimer diff --git a/include/battle_util.h b/include/battle_util.h index 5fef1b4f60..e4a54990c0 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -351,5 +351,6 @@ bool32 HasWeatherEffect(void); bool32 IsMovePowderBlocked(u32 battlerAtk, u32 battlerDef, u32 move); bool32 EmergencyExitCanBeTriggered(u32 battler); u32 RestoreWhiteHerbStats(u32 battler); +bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef); #endif // GUARD_BATTLE_UTIL_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 225646ee29..c812df97c8 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7064,7 +7064,6 @@ static void Cmd_moveend(void) gEffectBattler = gBattlerTarget; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MagicianActivates; - gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; effect = TRUE; } gBattleScripting.moveendState++; @@ -7404,7 +7403,6 @@ static void Cmd_moveend(void) gBattleStruct->ateBoost[gBattlerAttacker] = FALSE; gStatuses3[gBattlerAttacker] &= ~STATUS3_ME_FIRST; gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE; - gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = 0; gSpecialStatuses[gBattlerTarget].berryReduced = FALSE; gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE; gBattleScripting.moveEffect = 0; diff --git a/src/battle_util.c b/src/battle_util.c index d9e64c969c..0093550a47 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2930,8 +2930,6 @@ bool32 HandleWishPerishSongOnTurnEnd(void) if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter && !(gAbsentBattlerFlags & (1u << battler))) { - struct Pokemon *party; - if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter && gWishFutureKnock.futureSightCounter[BATTLE_PARTNER(battler)] <= gBattleTurnCounter) { @@ -2952,8 +2950,7 @@ bool32 HandleWishPerishSongOnTurnEnd(void) gBattlerAttacker = gWishFutureKnock.futureSightBattlerIndex[battler]; gCurrentMove = gWishFutureKnock.futureSightMove[battler]; - party = GetSideParty(GetBattlerSide(gBattlerAttacker)); - if (&party[gWishFutureKnock.futureSightPartyIndex[gBattlerTarget]] == &party[gBattlerPartyIndexes[gBattlerAttacker]]) + if (!IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget)) SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker); BattleScriptExecute(BattleScript_MonTookFutureAttack); @@ -5879,12 +5876,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(gBattlerAttacker)) { // Prevent Innards Out effect if Future Sight user is currently not on field - if (GetMoveEffect(gCurrentMove) == EFFECT_FUTURE_SIGHT) - { - if (gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] != gBattlerPartyIndexes[gBattlerAttacker] - && gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] != BATTLE_PARTNER(gBattlerPartyIndexes[gBattlerAttacker])) - break; - } + if (GetMoveEffect(gCurrentMove) == EFFECT_FUTURE_SIGHT + && IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget)) + break; gBattleScripting.battler = gBattlerTarget; gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget]; @@ -8202,7 +8196,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage) + && !IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget)) { gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 10; if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) @@ -10510,8 +10504,6 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData if (dmg == 0) dmg = 1; - gSpecialStatuses[battlerAtk].preventLifeOrbDamage = TRUE; - return dmg; } @@ -10538,14 +10530,11 @@ static u32 GetWeather(void) return gBattleWeather; } -static inline bool32 IsFutureSightAttackerInParty(struct DamageCalculationData *damageCalcData) +bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef) { - if (GetMoveEffect(damageCalcData->move) != EFFECT_FUTURE_SIGHT) - return FALSE; - - struct Pokemon *party = GetSideParty(GetBattlerSide(damageCalcData->battlerAtk)); - return &party[gWishFutureKnock.futureSightPartyIndex[damageCalcData->battlerDef]] - != &party[gBattlerPartyIndexes[damageCalcData->battlerAtk]]; + struct Pokemon *party = GetSideParty(GetBattlerSide(battlerAtk)); + return &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[gBattlerPartyIndexes[battlerAtk]] + && &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]] != &party[BATTLE_PARTNER(gBattlerPartyIndexes[battlerAtk])]; } s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedBasePower) @@ -10557,7 +10546,8 @@ s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedB GetBattlerAbility(damageCalcData->battlerDef), damageCalcData->updateFlags); - if (IsFutureSightAttackerInParty(damageCalcData)) + if (GetMoveEffect(damageCalcData->move) == EFFECT_FUTURE_SIGHT + && IsFutureSightAttackerInParty(damageCalcData->battlerAtk, damageCalcData->battlerDef)) return DoFutureSightAttackDamageCalc(damageCalcData, typeEffectivenessMultiplier, GetWeather()); return DoMoveDamageCalc(damageCalcData, fixedBasePower, typeEffectivenessMultiplier, GetWeather()); diff --git a/test/battle/ability/magician.c b/test/battle/ability/magician.c index f622ac07df..d12fe920b8 100644 --- a/test/battle/ability/magician.c +++ b/test/battle/ability/magician.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Magician does not get self-damage recoil after stealing Life Orb") +SINGLE_BATTLE_TEST("Magician gets self-damage recoil after stealing Life Orb") { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); @@ -16,10 +16,8 @@ SINGLE_BATTLE_TEST("Magician does not get self-damage recoil after stealing Life MESSAGE("Delphox used Tackle!"); ABILITY_POPUP(player, ABILITY_MAGICIAN); MESSAGE("Delphox stole the opposing Wobbuffet's Life Orb!"); - NONE_OF { - HP_BAR(player); - MESSAGE("Delphox was hurt by the Life Orb!"); - } + HP_BAR(player); + MESSAGE("Delphox was hurt by the Life Orb!"); // 2nd turn - Life Orb recoil happens now MESSAGE("Delphox used Tackle!"); HP_BAR(player);