Fix damage roll order for AI calcs (#6356)

This commit is contained in:
Alex 2025-03-07 18:40:40 +01:00 committed by GitHub
parent 752181bbcb
commit 46b821c196
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 17 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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;
}