From 46b821c1967cf095a662454dce9695b65bebaebc Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Fri, 7 Mar 2025 18:40:40 +0100 Subject: [PATCH] Fix damage roll order for AI calcs (#6356) --- include/battle_util.h | 1 + src/battle_ai_util.c | 61 ++++++++++++++++++++++++++++++++++--------- src/battle_util.c | 21 ++++++++++++--- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/include/battle_util.h b/include/battle_util.h index 6b7fdef74a..21ce76de40 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -249,6 +249,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); s32 CalculateMoveDamage(struct DamageCalculationData *damageCalcData, u32 fixedBasePower); s32 CalculateMoveDamageVars(struct DamageCalculationData *damageCalcData, u32 fixedBasePower, uq4_12_t typeEffectivenessModifier, u32 weather, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef); +s32 ApplyModifiersAfterDmgRoll(s32 dmg, struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk, u32 holdEffectDef); 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); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9a522fba09..2bafe83d22 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -686,19 +686,26 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u effectivenessMultiplier, weather, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + nonCritDmg = ApplyModifiersAfterDmgRoll(nonCritDmg, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + damageCalcData.isCrit = TRUE; s32 critDmg = CalculateMoveDamageVars(&damageCalcData, fixedBasePower, effectivenessMultiplier, weather, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); - u32 critOdds = GetCritHitOdds(critChanceIndex); - // With critOdds getting closer to 1, dmg gets closer to critDmg. - simDamage.expected = GetDamageByRollType((critDmg + nonCritDmg * (critOdds - 1)) / critOdds, rollType); - if (critOdds == 1) - simDamage.minimum = LowestRollDmg(critDmg); - else - simDamage.minimum = LowestRollDmg(nonCritDmg); + simDamage.expected = GetDamageByRollType(critDmg, rollType); + simDamage.expected = ApplyModifiersAfterDmgRoll(simDamage.expected, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + simDamage.minimum = (GetCritHitOdds(critChanceIndex) == 1) ? LowestRollDmg(critDmg) : LowestRollDmg(nonCritDmg); + simDamage.minimum = ApplyModifiersAfterDmgRoll(simDamage.minimum, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); } else if (critChanceIndex == -2) // Guaranteed critical { @@ -710,6 +717,14 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u simDamage.expected = GetDamageByRollType(critDmg, rollType); simDamage.minimum = LowestRollDmg(critDmg); + + simDamage.expected = ApplyModifiersAfterDmgRoll(simDamage.expected, &damageCalcData, effectivenessMultiplier, + aiData->abilities[battlerAtk], aiData->abilities[battlerDef], + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]); + + simDamage.minimum = ApplyModifiersAfterDmgRoll(simDamage.minimum, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); } else { @@ -718,10 +733,21 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u { for (gMultiHitCounter = GetMoveStrikeCount(move); gMultiHitCounter > 0; gMultiHitCounter--) // The global is used to simulate actual damage done { - nonCritDmg += CalculateMoveDamageVars(&damageCalcData, fixedBasePower, - effectivenessMultiplier, weather, - aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], - aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + s32 oneTripleKickHit = CalculateMoveDamageVars(&damageCalcData, fixedBasePower, + effectivenessMultiplier, weather, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + simDamage.expected = GetDamageByRollType(oneTripleKickHit, rollType); + simDamage.minimum = LowestRollDmg(oneTripleKickHit); + + nonCritDmg += ApplyModifiersAfterDmgRoll(simDamage.expected, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + nonCritDmg += ApplyModifiersAfterDmgRoll(simDamage.minimum, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); } } else @@ -730,9 +756,18 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u effectivenessMultiplier, weather, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + simDamage.expected = GetDamageByRollType(nonCritDmg, rollType); + simDamage.minimum = LowestRollDmg(nonCritDmg); + + simDamage.expected = ApplyModifiersAfterDmgRoll(simDamage.expected, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); + + simDamage.minimum = ApplyModifiersAfterDmgRoll(simDamage.minimum, &damageCalcData, effectivenessMultiplier, + aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], + aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); } - simDamage.expected = GetDamageByRollType(nonCritDmg, rollType); - simDamage.minimum = LowestRollDmg(nonCritDmg); } if (GetActiveGimmick(battlerAtk) != GIMMICK_Z_MOVE) diff --git a/src/battle_util.c b/src/battle_util.c index 44a0b678b4..737d894d0c 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -10462,9 +10462,24 @@ static inline s32 DoMoveDamageCalcVars(struct DamageCalculationData *damageCalcD dmg *= DMG_ROLL_PERCENT_HI - RandomUniform(RNG_DAMAGE_MODIFIER, 0, DMG_ROLL_PERCENT_HI - DMG_ROLL_PERCENT_LO); dmg /= 100; } + else // Apply rest of modifiers in the ai function + { + if (dmg == 0) + dmg = 1; + return dmg; + } - if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA) - DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(battlerAtk, damageCalcData->moveType)); + dmg = ApplyModifiersAfterDmgRoll(dmg, damageCalcData, typeEffectivenessModifier, abilityAtk, abilityDef, holdEffectAtk, holdEffectDef); + + if (dmg == 0) + dmg = 1; + return dmg; +} + +s32 ApplyModifiersAfterDmgRoll(s32 dmg, struct DamageCalculationData *damageCalcData, uq4_12_t typeEffectivenessModifier, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk, u32 holdEffectDef) +{ + if (GetActiveGimmick(damageCalcData->battlerAtk) == GIMMICK_TERA) + DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(damageCalcData->battlerAtk, damageCalcData->moveType)); else DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(damageCalcData, abilityAtk)); DAMAGE_APPLY_MODIFIER(typeEffectivenessModifier); @@ -10472,8 +10487,6 @@ static inline s32 DoMoveDamageCalcVars(struct DamageCalculationData *damageCalcD DAMAGE_APPLY_MODIFIER(GetZMaxMoveAgainstProtectionModifier(damageCalcData)); DAMAGE_APPLY_MODIFIER(GetOtherModifiers(damageCalcData, typeEffectivenessModifier, abilityAtk, abilityDef, holdEffectAtk, holdEffectDef)); - if (dmg == 0) - dmg = 1; return dmg; }