From 1ca4676c4c6e5546c5e0c514e831cc6614929c85 Mon Sep 17 00:00:00 2001 From: sneed Date: Sun, 9 Jun 2024 22:30:49 +0300 Subject: [PATCH] fix ai crit calculations --- include/battle_script_commands.h | 2 +- src/battle_ai_util.c | 16 +++++++++++---- src/battle_script_commands.c | 34 ++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 540390bb5373..5075d52be735 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -24,7 +24,7 @@ struct PickupItem 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 GetCritHitChance(s32 critChanceIndex); +s32 GetCritHitOdds(s32 critChanceIndex); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); bool32 NoAliveMonsForPlayer(void); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4524e3b25b51..f8275d417a79 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -515,15 +515,23 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); 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, effectivenessMultiplier, weather, TRUE, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef], aiData->abilities[battlerAtk], aiData->abilities[battlerDef]); - u32 critChance = GetCritHitChance(critChanceIndex); - // With critChance getting closer to 1, dmg gets closer to critDmg. - dmg = LowestRollDmg((critDmg + normalDmg * (critChance - 1)) / (critChance)); + u32 critOdds = GetCritHitOdds(critChanceIndex); // Crit chance is 1/critOdds + // With critOdds getting closer to 1, dmg gets closer to critDmg. + 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 { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e9679239317f..d2274562249a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1905,11 +1905,11 @@ static void Cmd_ppreduce(void) // The chance is 1/N for each stage. #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 - static const u8 sCriticalHitChance[] = {16, 8, 2, 1, 1}; + static const u8 sCriticalHitOdds[] = {16, 8, 2, 1, 1}; #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 #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; - if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT - || abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR) + if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT) { critChance = -1; } @@ -1940,12 +1939,21 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec + (abilityAtk == ABILITY_SUPER_LUCK) + gBattleStruct->bonusCritStages[gBattlerAttacker]; - // Record ability only if move had at least +3 chance to get a crit - if (critChance >= 3 && recordAbility && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)) - RecordAbilityBattle(battlerDef, abilityDef); + if (critChance >= ARRAY_COUNT(sCriticalHitOdds)) + critChance = ARRAY_COUNT(sCriticalHitOdds) - 1; + } - if (critChance >= ARRAY_COUNT(sCriticalHitChance)) - critChance = ARRAY_COUNT(sCriticalHitChance) - 1; + if (critChance != -1 && (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)) + { + // 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; @@ -1960,12 +1968,12 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA } #undef BENEFITS_FROM_LEEK -s32 GetCritHitChance(s32 critChanceIndex) +s32 GetCritHitOdds(s32 critChanceIndex) { if (critChanceIndex < 0) return -1; else - return sCriticalHitChance[critChanceIndex]; + return sCriticalHitOdds[critChanceIndex]; } static void Cmd_critcalc(void) @@ -1983,7 +1991,7 @@ static void Cmd_critcalc(void) else if (critChance == -2) gIsCriticalHit = TRUE; else - gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1); + gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitOdds[critChance] - 1, 1); // Counter for EVO_CRITICAL_HITS. partySlot = gBattlerPartyIndexes[gBattlerAttacker];