Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gen 1 Crit Chance #5439

Merged
merged 6 commits into from
Sep 29, 2024
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 88 additions & 2 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1948,6 +1948,75 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
return CalcCritChanceStageArgs(battlerAtk, battlerDef, move, recordAbility, abilityAtk, abilityDef, holdEffectAtk);
}

// Bulbapedia: https://bulbapedia.bulbagarden.net/wiki/Critical_hit#Generation_I
// Crit chance = Threshold / 256, Threshold maximum of 255
// Threshold = Base Speed / 2
// High crit move = 8 * (Base Speed / 2)
// Focus Energy = 4 * (Base Speed / 2)
s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility)
{
// Vanilla
u8 focusEnergyScaler = 4;
u8 highCritRatioScaler = 8;

// Not vanilla
u8 superLuckScaler = 4;
u8 scopeLensScaler = 4;
u8 luckyPunchScaler = 8;
u8 farfetchedLeekScaler = 8;
Pawkkie marked this conversation as resolved.
Show resolved Hide resolved

s32 critChance = 0;
s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage;
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
u16 baseSpeed = gSpeciesInfo[gBattleMons[battlerAtk].species].baseSpeed;

critChance = baseSpeed / 2;

// Crit scaling
if (moveCritStage > 0)
critChance = critChance * highCritRatioScaler * moveCritStage;

if ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
critChance = critChance * focusEnergyScaler;

if (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
critChance = critChance * scopeLensScaler;

if (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
critChance = critChance * luckyPunchScaler;

if (BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk))
critChance = critChance * farfetchedLeekScaler;

if (abilityAtk == ABILITY_SUPER_LUCK)
critChance = critChance * superLuckScaler;

if (critChance > 255)
critChance = 255;

// Prevented crits
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT)
critChance = -1;
else if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{
if (recordAbility)
RecordAbilityBattle(battlerDef, abilityDef);
critChance = -1;
}

// Guaranteed crits
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gMovesInfo[move].alwaysCriticalHit == TRUE
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY))
{
critChance = -2;
}

return critChance;
}
#undef BENEFITS_FROM_LEEK

s32 GetCritHitOdds(s32 critChanceIndex)
Expand All @@ -1963,7 +2032,13 @@ static void Cmd_critcalc(void)
CMD_ARGS();

u16 partySlot;
s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
s32 critChance;

if (B_CRIT_CHANCE == GEN_1)
critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
else
critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);

gPotentialItemEffectBattler = gBattlerAttacker;

if (gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
Expand All @@ -1973,7 +2048,18 @@ static void Cmd_critcalc(void)
else if (critChance == -2)
gIsCriticalHit = TRUE;
else
gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, sCriticalHitOdds[critChance]);
{
if (B_CRIT_CHANCE == GEN_1)
{
u8 critRoll = RandomUniform(RNG_CRITICAL_HIT, 1, 256);
if (critRoll <= critChance)
gIsCriticalHit = 1;
else
gIsCriticalHit = 0;
}
else
gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, sCriticalHitOdds[critChance]);
}

// Counter for EVO_CRITICAL_HITS.
partySlot = gBattlerPartyIndexes[gBattlerAttacker];
Expand Down
Loading