fix ai crit calculations

This commit is contained in:
sneed 2024-06-09 22:30:49 +03:00
parent db15190508
commit 1ca4676c4c
3 changed files with 34 additions and 18 deletions

View file

@ -24,7 +24,7 @@ struct PickupItem
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk); 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 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility);
s32 GetCritHitChance(s32 critChanceIndex); s32 GetCritHitOdds(s32 critChanceIndex);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
u8 GetBattlerTurnOrderNum(u8 battlerId); u8 GetBattlerTurnOrderNum(u8 battlerId);
bool32 NoAliveMonsForPlayer(void); bool32 NoAliveMonsForPlayer(void);

View file

@ -515,15 +515,23 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]); 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 if (critChanceIndex > 1) // Consider crit damage only if a move has at least +2 crit chance
{ {
s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower, s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
effectivenessMultiplier, weather, TRUE, effectivenessMultiplier, weather, TRUE,
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
u32 critChance = GetCritHitChance(critChanceIndex); u32 critOdds = GetCritHitOdds(critChanceIndex); // Crit chance is 1/critOdds
// With critChance getting closer to 1, dmg gets closer to critDmg. // With critOdds getting closer to 1, dmg gets closer to critDmg.
dmg = LowestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance)); dmg = LowestRollDmg((critDmg + normalDmg * (critOdds - 1)) / (critOdds));
}
else if (critChanceIndex == -2) // Guaranteed critical
{
s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
effectivenessMultiplier, weather, TRUE,
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
dmg = LowestRollDmg(critDmg);
} }
else else
{ {

View file

@ -1905,11 +1905,11 @@ static void Cmd_ppreduce(void)
// The chance is 1/N for each stage. // The chance is 1/N for each stage.
#if B_CRIT_CHANCE >= GEN_7 #if B_CRIT_CHANCE >= GEN_7
static const u8 sCriticalHitChance[] = {24, 8, 2, 1, 1}; static const u8 sCriticalHitOdds[] = {24, 8, 2, 1, 1};
#elif B_CRIT_CHANCE == GEN_6 #elif B_CRIT_CHANCE == GEN_6
static const u8 sCriticalHitChance[] = {16, 8, 2, 1, 1}; static const u8 sCriticalHitOdds[] = {16, 8, 2, 1, 1};
#else #else
static const u8 sCriticalHitChance[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5 static const u8 sCriticalHitOdds[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5
#endif // B_CRIT_CHANCE #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)) #define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD))
@ -1917,8 +1917,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec
{ {
s32 critChance = 0; s32 critChance = 0;
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT)
|| abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{ {
critChance = -1; critChance = -1;
} }
@ -1940,12 +1939,21 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec
+ (abilityAtk == ABILITY_SUPER_LUCK) + (abilityAtk == ABILITY_SUPER_LUCK)
+ gBattleStruct->bonusCritStages[gBattlerAttacker]; + gBattleStruct->bonusCritStages[gBattlerAttacker];
// Record ability only if move had at least +3 chance to get a crit if (critChance >= ARRAY_COUNT(sCriticalHitOdds))
if (critChance >= 3 && recordAbility && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)) critChance = ARRAY_COUNT(sCriticalHitOdds) - 1;
RecordAbilityBattle(battlerDef, abilityDef); }
if (critChance >= ARRAY_COUNT(sCriticalHitChance)) if (critChance != -1 && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR))
critChance = ARRAY_COUNT(sCriticalHitChance) - 1; {
// Record ability only if move had 100% chance to get a crit
if (recordAbility)
{
if (critChance == -2)
RecordAbilityBattle(battlerDef, abilityDef);
else if (sCriticalHitOdds[critChance] == 1)
RecordAbilityBattle(battlerDef, abilityDef);
}
critChance = -1;
} }
return critChance; return critChance;
@ -1960,12 +1968,12 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
} }
#undef BENEFITS_FROM_LEEK #undef BENEFITS_FROM_LEEK
s32 GetCritHitChance(s32 critChanceIndex) s32 GetCritHitOdds(s32 critChanceIndex)
{ {
if (critChanceIndex < 0) if (critChanceIndex < 0)
return -1; return -1;
else else
return sCriticalHitChance[critChanceIndex]; return sCriticalHitOdds[critChanceIndex];
} }
static void Cmd_critcalc(void) static void Cmd_critcalc(void)
@ -1983,7 +1991,7 @@ static void Cmd_critcalc(void)
else if (critChance == -2) else if (critChance == -2)
gIsCriticalHit = TRUE; gIsCriticalHit = TRUE;
else else
gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1); gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitOdds[critChance] - 1, 1);
// Counter for EVO_CRITICAL_HITS. // Counter for EVO_CRITICAL_HITS.
partySlot = gBattlerPartyIndexes[gBattlerAttacker]; partySlot = gBattlerPartyIndexes[gBattlerAttacker];