diff --git a/include/battle.h b/include/battle.h index 176adf7343..de25626c6b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -764,7 +764,7 @@ struct BattleStruct s16 critChance[MAX_BATTLERS_COUNT]; u16 moveResultFlags[MAX_BATTLERS_COUNT]; u8 missStringId[MAX_BATTLERS_COUNT]; - u8 noResultString[MAX_BATTLERS_COUNT]; + enum CalcDamageState noResultString[MAX_BATTLERS_COUNT]; u8 doneDoublesSpreadHit:1; u8 calculatedDamageDone:1; u8 calculatedSpreadMoveAccuracy:1; @@ -865,8 +865,6 @@ static inline bool32 IsBattleMoveStatus(u32 move) #define SET_STATCHANGER(statId, stage, goesDown) (gBattleScripting.statChanger = (statId) + ((stage) << 3) + (goesDown << 7)) #define SET_STATCHANGER2(dst, statId, stage, goesDown)(dst = (statId) + ((stage) << 3) + (goesDown << 7)) -#define DO_ACCURACY_CHECK 2 // Don't skip the accuracy check before the move might be absorbed - // NOTE: The members of this struct have hard-coded offsets // in include/constants/battle_script_commands.h struct BattleScripting diff --git a/include/constants/battle.h b/include/constants/battle.h index 5faa91ad7e..730dbd63c7 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -700,4 +700,11 @@ enum MonState MON_OUTSIDE_BATTLE, }; +enum __attribute__((packed)) CalcDamageState +{ + CAN_DAMAGE, + WILL_FAIL, + CHECK_ACCURACY, +}; + #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9c4da75feb..162e55dba9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1407,7 +1407,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if ((!calcSpreadMove && battlerDef != gBattlerTarget) || IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) - || (gBattleStruct->noResultString[battlerDef] && gBattleStruct->noResultString[battlerDef] != DO_ACCURACY_CHECK)) + || gBattleStruct->noResultString[battlerDef] == WILL_FAIL) continue; numTargets++; @@ -1743,7 +1743,7 @@ static void Cmd_critcalc(void) continue; if (IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) - || gBattleStruct->noResultString[battlerDef] + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE || gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) continue; @@ -1819,7 +1819,7 @@ static void Cmd_damagecalc(void) for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) - || gBattleStruct->noResultString[battlerDef] + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE || gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) continue; @@ -1882,7 +1882,7 @@ static void Cmd_adjustdamage(void) continue; if (IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) - || gBattleStruct->noResultString[battlerDef]) + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE) continue; if (DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) @@ -2029,8 +2029,8 @@ static u32 UpdateEffectivenessResultFlagsForDoubleSpreadMoves(u32 resultFlags) { for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { - if ((gBattleStruct->moveResultFlags[battlerDef] & (MOVE_RESULT_MISSED | MOVE_RESULT_NO_EFFECT) - || gBattleStruct->noResultString[battlerDef])) + if (gBattleStruct->moveResultFlags[battlerDef] & (MOVE_RESULT_MISSED | MOVE_RESULT_NO_EFFECT) + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE) continue; switch (sound) @@ -2115,7 +2115,7 @@ static bool32 ProcessPreAttackAnimationFuncs(void) { if (IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) || (battlerDef == BATTLE_PARTNER(gBattlerAttacker) && !(moveTarget & MOVE_TARGET_FOES_AND_ALLY)) - || (gBattleStruct->noResultString[battlerDef] && gBattleStruct->noResultString[battlerDef] != DO_ACCURACY_CHECK)) + || gBattleStruct->noResultString[battlerDef] == WILL_FAIL) continue; if (TryStrongWindsWeakenAttack(battlerDef, moveType)) @@ -2127,7 +2127,7 @@ static bool32 ProcessPreAttackAnimationFuncs(void) { if (IsBattlerInvalidForSpreadMove(gBattlerAttacker, battlerDef, moveTarget) || (battlerDef == BATTLE_PARTNER(gBattlerAttacker) && !(moveTarget & MOVE_TARGET_FOES_AND_ALLY)) - || (gBattleStruct->noResultString[battlerDef] && gBattleStruct->noResultString[battlerDef] != DO_ACCURACY_CHECK)) + || gBattleStruct->noResultString[battlerDef] == WILL_FAIL) continue; if (TryTeraShellDistortTypeMatchups(battlerDef)) @@ -2255,7 +2255,7 @@ static void DoublesHPBarReduction(void) { if (gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT || gBattleStruct->moveDamage[battlerDef] == 0 - || gBattleStruct->noResultString[battlerDef] + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE || DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove) || DoesDisguiseBlockMove(battlerDef, gCurrentMove)) continue; @@ -2534,7 +2534,7 @@ static inline bool32 ShouldPrintTwoFoesMessage(u32 moveResult) { return gBattlerTarget == BATTLE_OPPOSITE(gBattlerAttacker) && gBattleStruct->moveResultFlags[BATTLE_PARTNER(gBattlerTarget)] & moveResult - && !gBattleStruct->noResultString[BATTLE_PARTNER(gBattlerTarget)]; + && gBattleStruct->noResultString[BATTLE_PARTNER(gBattlerTarget)] == CAN_DAMAGE; } static inline bool32 ShouldRelyOnTwoFoesMessage(u32 moveResult) @@ -2542,7 +2542,7 @@ static inline bool32 ShouldRelyOnTwoFoesMessage(u32 moveResult) return gBattlerTarget == BATTLE_PARTNER(BATTLE_OPPOSITE(gBattlerAttacker)) && gBattleStruct->moveResultFlags[BATTLE_OPPOSITE(gBattlerAttacker)] & moveResult && !(gBattleStruct->moveResultFlags[BATTLE_OPPOSITE(gBattlerAttacker)] & MOVE_RESULT_MISSED && gBattleStruct->missStringId[BATTLE_OPPOSITE(gBattlerAttacker)] > B_MSG_AVOIDED_ATK) - && !gBattleStruct->noResultString[BATTLE_OPPOSITE(gBattlerAttacker)]; + && gBattleStruct->noResultString[BATTLE_OPPOSITE(gBattlerAttacker)] == CAN_DAMAGE; } static void Cmd_resultmessage(void) @@ -8247,7 +8247,7 @@ static void Cmd_hitanimation(void) for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT - || gBattleStruct->noResultString[battlerDef]) + || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE) continue; if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) diff --git a/src/battle_util.c b/src/battle_util.c index ce82a997cc..caa4be0191 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -205,7 +205,7 @@ static const struct BattleWeatherInfo sBattleWeatherInfo[BATTLE_WEATHER_COUNT] = // Helper function for actual dmg calcs during battle. For simulated AI dmg, CalcTypeEffectivenessMultiplier should be used directly // This should stay a static function. Ideally everything else is handled through CalcTypeEffectivenessMultiplier just like AI -static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities) +static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, bool32 recordAbilities) { struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; @@ -213,8 +213,8 @@ static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u3 ctx.move = move; ctx.moveType = moveType; ctx.updateFlags = recordAbilities; - ctx.abilityAtk = GetBattlerAbility(battlerAtk); - ctx.abilityDef = defAbility; + ctx.abilityAtk = abilityAtk; + ctx.abilityDef = abilityDef; ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); @@ -2541,22 +2541,23 @@ static enum MoveCanceller CancellerMultiTargetMoves(void) || IsBattlerProtected(gBattlerAttacker, battlerDef, gCurrentMove)) // Missing Invulnerable check { gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_NO_EFFECT; - gBattleStruct->noResultString[battlerDef] = TRUE; + gBattleStruct->noResultString[battlerDef] = WILL_FAIL; } else if (CanAbilityBlockMove(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, gCurrentMove, CHECK_TRIGGER) || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetBattleMovePriority(gBattlerAttacker, abilityAtk, gCurrentMove) > 0)) { gBattleStruct->moveResultFlags[battlerDef] = 0; - gBattleStruct->noResultString[battlerDef] = TRUE; + gBattleStruct->noResultString[battlerDef] = WILL_FAIL; } else if (CanAbilityAbsorbMove(gBattlerAttacker, battlerDef, abilityDef, gCurrentMove, GetBattleMoveType(gCurrentMove), CHECK_TRIGGER)) { gBattleStruct->moveResultFlags[battlerDef] = 0; - gBattleStruct->noResultString[battlerDef] = DO_ACCURACY_CHECK; + gBattleStruct->noResultString[battlerDef] = CHECK_ACCURACY; } else { - CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); + CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, abilityAtk, abilityDef, TRUE); // Sets moveResultFlags + gBattleStruct->noResultString[battlerDef] = CAN_DAMAGE; } } if (moveTarget == MOVE_TARGET_BOTH) @@ -5669,7 +5670,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u battleScript = BattleScript_NotAffected; } else if (option == RUN_SCRIPT // Check only important during battle execution for moves - && CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, abilityDef, TRUE) + && CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, abilityAtk, abilityDef, TRUE) && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) { battleScript = BattleScript_ButItFailed; @@ -11223,7 +11224,7 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerD bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) { u32 moveType = GetBattleMoveType(gCurrentMove); - return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) + return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) || IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove) || IsSemiInvulnerable(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerAtk, battlerDef, moveType)); @@ -11284,7 +11285,7 @@ void ClearDamageCalcResults(void) { gBattleStruct->moveDamage[battler] = 0; gBattleStruct->critChance[battler] = 0; - gBattleStruct->moveResultFlags[battler] = 0; + gBattleStruct->moveResultFlags[battler] = CAN_DAMAGE; gBattleStruct->noResultString[battler] = 0; gBattleStruct->missStringId[battler] = 0; gSpecialStatuses[battler].criticalHit = FALSE;