diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index e3bd6cd51..b2dbd6d84 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -32,10 +32,10 @@ u32 GetHealthPercentage(u32 battler); bool32 IsBattlerTrapped(u32 battler, bool32 switching); u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered); bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk); -bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); +bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); -u16 AI_GetHoldEffect(u32 battlerId); +u32 AI_GetHoldEffect(u32 battlerId); u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u32 move); bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move); u32 AI_GetWeather(struct AiLogicData *aiData); diff --git a/include/battle_main.h b/include/battle_main.h index 5d1fe6bbf..91e9fd90e 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -57,7 +57,7 @@ void SwitchInClearSetData(u32 battler); void FaintClearSetData(u32 battler); void BattleTurnPassed(void); u8 IsRunningFromBattleImpossible(u32 battler); -void SwitchPartyOrder(u8 battlerId); +void SwitchPartyOrder(u32 battlerId); void SwapTurnOrder(u8 id1, u8 id2); u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect); u32 GetBattlerTotalSpeedStat(u32 battler); @@ -69,7 +69,7 @@ u32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves); void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); void SpecialStatusesClear(void); -void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk); +void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk); bool32 IsWildMonSmart(void); u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags); void ModifyPersonalityForNature(u32 *personality, u32 newNature); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 71c1c2f69..ed08b5eb4 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -16,8 +16,9 @@ struct StatFractions u8 divisor; }; +s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk); s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility); -s32 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move); +s32 GetCritHitChance(s32 critChanceIndex); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); bool32 NoAliveMonsForEitherParty(void); diff --git a/include/battle_util.h b/include/battle_util.h index 7058c9899..8c4dc260b 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -174,7 +174,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); s32 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef); -uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities); +uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities); uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); uq4_12_t GetTypeModifier(u32 atkType, u32 defType); s32 GetStealthHazardDamage(u8 hazardType, u32 battler); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 43bc619d2..8adc12a40 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -698,12 +698,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) u32 weather; u16 predictedMove = aiData->predictedMoves[battlerDef]; - SetTypeBeforeUsingMove(move, battlerAtk); - GET_MOVE_TYPE(move, moveType); - if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; + SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); // check non-user target @@ -3757,10 +3755,9 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) { - /* TODO predicted moves if (gLastMoves[battlerDef] == predictedMove) score += 3; - else */if (CanMoveFaintBattler(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) + else if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) score += 2; //Disable move that can kill attacker } } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index cb7e5c41e..4ac6ddec6 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -723,7 +723,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) { SetTypeBeforeUsingMove(moves[i], attacker); GET_MOVE_TYPE(moves[i], moveType); - if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, FALSE) != 0) + if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0) usable |= gBitTable[i]; } } @@ -731,41 +731,6 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) return (usable == 0); } -static bool32 AI_GetIfCrit(u32 move, u32 battlerAtk, u32 battlerDef) -{ - bool32 isCrit; - - switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE)) - { - case -1: - case 0: - default: - isCrit = FALSE; - break; - case 1: - if (gBattleMoves[move].highCritRatio && (Random() % 5 == 0)) - isCrit = TRUE; - else - isCrit = FALSE; - break; - case 2: - if (gBattleMoves[move].highCritRatio && (Random() % 2 == 0)) - isCrit = TRUE; - else if (!(gBattleMoves[move].highCritRatio) && (Random() % 4) == 0) - isCrit = TRUE; - else - isCrit = FALSE; - break; - case -2: - case 3: - case 4: - isCrit = TRUE; - break; - } - - return isCrit; -} - // To save computation time this function has 2 variants. One saves, sets and restores battlers, while the other doesn't. s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) { @@ -776,8 +741,9 @@ s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *type s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather) { - s32 dmg, moveType, critDmg, normalDmg, fixedBasePower, n; + s32 dmg, moveType; uq4_12_t effectivenessMultiplier; + struct AiLogicData *aiData = AI_DATA; SetBattlerData(battlerAtk); SetBattlerData(battlerDef); @@ -797,14 +763,12 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); - effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); + effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE); if (gBattleMoves[move].power) { - s32 critChance; - struct AiLogicData *aiData = AI_DATA; + s32 critChanceIndex, normalDmg, fixedBasePower, n; ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType); - critChance = GetInverseCritChance(battlerAtk, battlerDef, move); // Certain moves like Rollout calculate damage based on values which change during the move execution, but before calling dmg calc. switch (gBattleMoves[move].effect) { @@ -823,15 +787,22 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes effectivenessMultiplier, weather, FALSE, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); - critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, + + critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]); + if (critChanceIndex > 1) // Consider crit damage only if a move has at least +1 crit chance + { + s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, weather, TRUE, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); - - if (critChance == -1) - dmg = normalDmg; - else + u32 critChance = GetCritHitChance(critChanceIndex); + // With critChance getting closer to 1, dmg gets closer to critDmg. dmg = (critDmg + normalDmg * (critChance - 1)) / (critChance); + } + else + { + dmg = normalDmg; + } if (!gBattleStruct->zmove.active) { @@ -1056,7 +1027,7 @@ uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) gBattleStruct->dynamicMoveType = 0; SetTypeBeforeUsingMove(move, battlerAtk); GET_MOVE_TYPE(move, moveType); - typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); + typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], FALSE); RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); @@ -1191,18 +1162,14 @@ bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits) return FALSE; } -bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) +bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) { - s32 i, dmg; - u8 effectiveness; - u32 unusable = AI_DATA->moveLimitations[battlerDef]; - - if (move != MOVE_NONE - && move != 0xFFFF - && !(unusable & gBitTable[i]) - && AI_CalcDamageSaveBattlers(move, battlerDef, battlerAtk, &effectiveness, FALSE) >= gBattleMons[battlerAtk].hp) - return TRUE; - + u32 indexSlot = GetMoveSlot(GetMovesArray(battlerDef), move); + if (indexSlot < MAX_MON_MOVES) + { + if (GetNoOfHitsToKO(AI_DATA->simulatedDmg[battlerDef][battlerAtk][indexSlot], gBattleMons[battlerAtk].hp) <= nHits) + return TRUE; + } return FALSE; } @@ -1282,7 +1249,7 @@ s32 AI_GetAbility(u32 battlerId) return ABILITY_NONE; // Unknown. } -u16 AI_GetHoldEffect(u32 battlerId) +u32 AI_GetHoldEffect(u32 battlerId) { u32 holdEffect; diff --git a/src/battle_main.c b/src/battle_main.c index b2143513e..9a1abf095 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -751,7 +751,7 @@ static void SetAllPlayersBerryData(void) { s32 numPlayers; struct BattleEnigmaBerry *src; - u8 battler; + u32 battler; if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { @@ -2268,7 +2268,7 @@ static void EndLinkBattleInSteps(void) case 2: if (!gPaletteFade.active) { - u8 battlerCount; + u32 battlerCount; gMain.anyLinkBattlerHasFrontierPass = RecordedBattle_GetFrontierPassFlag(); @@ -4021,11 +4021,10 @@ u8 IsRunningFromBattleImpossible(u32 battler) return BATTLE_RUN_SUCCESS; } -void SwitchPartyOrder(u8 battler) +void SwitchPartyOrder(u32 battler) { s32 i; - u8 partyId1; - u8 partyId2; + u32 partyId1, partyId2; for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++) gBattlePartyCurrentOrder[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)); @@ -5589,7 +5588,7 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk) +void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) { u32 moveType, ateType, attackerAbility; u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE); @@ -5728,8 +5727,8 @@ void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk) // var8001 - var8007: stat changes void SetTotemBoost(void) { - u8 battler = gSpecialVar_0x8000; - u8 i; + u32 battler = gSpecialVar_0x8000; + u32 i; for (i = 0; i < (NUM_BATTLE_STATS - 1); i++) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f98a66ad1..13876639c 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1752,10 +1752,11 @@ static void Cmd_accuracycheck(void) { CMD_ARGS(const u8 *failInstr, u16 move); - u16 type, move = cmd->move; - u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); - u16 gBattlerAttackerAbility = GetBattlerAbility(gBattlerAttacker); - u8 gBattlerAttackerHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + u32 type, move = cmd->move; + u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); + u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + u32 abilityDef = GetBattlerAbility(gBattlerTarget); + u32 holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); if (move == ACC_CURR_MOVE) move = gCurrentMove; @@ -1771,7 +1772,7 @@ static void Cmd_accuracycheck(void) } else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT || (gSpecialStatuses[gBattlerAttacker].multiHitOn - && (gBattlerAttackerAbility == ABILITY_SKILL_LINK || gBattlerAttackerHoldEffect == HOLD_EFFECT_LOADED_DICE + && (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE || !(gBattleMoves[move].effect == EFFECT_TRIPLE_KICK || gBattleMoves[move].effect == EFFECT_POPULATION_BOMB)))) { // No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb @@ -1791,16 +1792,16 @@ static void Cmd_accuracycheck(void) gBattlerAttacker, gBattlerTarget, move, - gBattlerAttackerAbility, - GetBattlerAbility(gBattlerTarget), - gBattlerAttackerHoldEffect, + abilityAtk, + abilityDef, + holdEffectAtk, GetBattlerHoldEffect(gBattlerTarget, TRUE) ); if (!RandomPercentage(RNG_ACCURACY, accuracy)) { gMoveResultFlags |= MOVE_RESULT_MISSED; - if (gBattlerAttackerHoldEffect == HOLD_EFFECT_BLUNDER_POLICY) + if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY) gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && @@ -1810,7 +1811,7 @@ static void Cmd_accuracycheck(void) gBattleCommunication[MISS_TYPE] = B_MSG_MISSED; if (gBattleMoves[move].power) - CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, TRUE); + CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, abilityDef, TRUE); } JumpIfMoveFailed(7, move); } @@ -1907,24 +1908,15 @@ static void Cmd_ppreduce(void) #endif // B_CRIT_CHANCE #define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD)) -s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility) +s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk) { s32 critChance = 0; - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); - u32 abilityDef = GetBattlerAbility(gBattlerTarget); - u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT - || gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) + || gStatuses3[battlerAtk] & STATUS3_CANT_SCORE_A_CRIT) { critChance = -1; } - else if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR) - { - if (recordAbility) - RecordAbilityBattle(battlerDef, abilityDef); - critChance = -1; - } else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS || gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) @@ -1934,27 +1926,41 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA } else { - critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0) + (gBattleMoves[gCurrentMove].highCritRatio) + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) - + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) + + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY) + 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk) #if B_AFFECTION_MECHANICS == TRUE - + 2 * (GetBattlerFriendshipScore(gBattlerAttacker) >= FRIENDSHIP_200_TO_254) + + 2 * (GetBattlerFriendshipScore(battlerAtk) >= FRIENDSHIP_200_TO_254) #endif + (abilityAtk == ABILITY_SUPER_LUCK); + if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR) + { + if (recordAbility && critChance >= 2) // Record ability only if move had at least +1 chance to get a crit. + RecordAbilityBattle(battlerDef, abilityDef); + critChance = -1; + } + if (critChance >= ARRAY_COUNT(sCriticalHitChance)) critChance = ARRAY_COUNT(sCriticalHitChance) - 1; } return critChance; } + +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility) +{ + u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + u32 abilityDef = GetBattlerAbility(gBattlerTarget); + u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); + return CalcCritChanceStageArgs(battlerAtk, battlerDef, move, recordAbility, abilityAtk, abilityDef, holdEffectAtk); +} #undef BENEFITS_FROM_LEEK -s32 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move) +s32 GetCritHitChance(s32 critChanceIndex) { - s32 critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE); if (critChanceIndex < 0) return -1; else @@ -2005,7 +2011,7 @@ static void Cmd_typecalc(void) u8 moveType; GET_MOVE_TYPE(gCurrentMove, moveType); - CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, TRUE); + CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE); gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/src/battle_util.c b/src/battle_util.c index bdee81d72..d0bcb6379 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4368,7 +4368,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { move = gBattleMons[i].moves[j]; GET_MOVE_TYPE(move, moveType); - if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, FALSE) >= UQ_4_12(2.0)) + if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, ABILITY_ANTICIPATION, FALSE) >= UQ_4_12(2.0)) { effect++; break; @@ -9827,7 +9827,8 @@ static u32 GetWeather(void) s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags) { return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, randomFactor, - updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags), GetWeather()); + updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), updateFlags), + GetWeather()); } // for AI so that typeEffectivenessModifier, weather, abilities and holdEffects are calculated only once @@ -9985,13 +9986,12 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov return modifier; } -uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities) +uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities) { uq4_12_t modifier = UQ_4_12(1.0); if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { - u32 defAbility = GetBattlerAbility(defAbility); modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); if (gBattleMoves[move].effect == EFFECT_TWO_TYPED_MOVE) modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier, defAbility);