Skip to content

Commit

Permalink
fix ai crit calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
Sneed69 committed Jun 9, 2024
1 parent db15190 commit 1ca4676
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 18 deletions.
2 changes: 1 addition & 1 deletion include/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
16 changes: 12 additions & 4 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
34 changes: 21 additions & 13 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1905,20 +1905,19 @@ 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))
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
{
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;
}
Expand All @@ -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;
Expand All @@ -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)
Expand All @@ -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];
Expand Down

0 comments on commit 1ca4676

Please sign in to comment.