From d88d15ad51922264d01082ba2267d8e0c55c3617 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 28 Sep 2024 22:37:42 -0400 Subject: [PATCH 1/6] Gen 1 crit chance --- src/battle_script_commands.c | 95 +++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index bfb7eec56d11..730d6941d2dc 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1948,6 +1948,80 @@ 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) +{ + // Change these scalers if you want to change how much Focus Energy and high crit rate moves affect crit chance + u8 focusEnergyScaler = 4; // vanilla is 4 + u8 highCritRatioScaler = 8; // vanilla is 8 + u8 superLuckScaler = 4; // not in vanilla + u8 scopeLensScaler = 4; // not in vanilla + u8 luckyPunchScaler = 8; // not in vanilla + u8 farfetchedLeekScaler = 8; // not in vanilla + + 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; + + // Threshold is base speed / 2 + critChance = baseSpeed / 2; + + // Scale for high crit chance moves + if (moveCritStage > 0) + critChance = critChance * highCritRatioScaler * moveCritStage; + + // Scale for Focus Energy + if ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + critChance = critChance * focusEnergyScaler; + + // Scale for Scope Lens + if (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) + critChance = critChance * scopeLensScaler; + + // Scale for Lucky Punch + if (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) + critChance = critChance * luckyPunchScaler; + + // Scale for Farfetch'd holding Leek + if (BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)) + critChance = critChance * farfetchedLeekScaler; + + // Scale for Super Luck + if (abilityAtk == ABILITY_SUPER_LUCK) + critChance = critChance * superLuckScaler; + + // Capped at 255 + 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) @@ -1963,7 +2037,13 @@ static void Cmd_critcalc(void) CMD_ARGS(); u16 partySlot; - s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); + + #if B_CRIT_CHANCE == GEN_1 + s32 critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); + #else + s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); + #endif // B_CRIT_CHANCE + gPotentialItemEffectBattler = gBattlerAttacker; if (gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) @@ -1973,7 +2053,18 @@ static void Cmd_critcalc(void) else if (critChance == -2) gIsCriticalHit = TRUE; else - gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, sCriticalHitOdds[critChance]); + { + // Gen 1 crit chance + #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]); + #endif // B_CRIT_CHANCE + } // Counter for EVO_CRITICAL_HITS. partySlot = gBattlerPartyIndexes[gBattlerAttacker]; From cbb580f5a7b8b0b303e87401058e9571758bc7a0 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 28 Sep 2024 22:55:26 -0400 Subject: [PATCH 2/6] Move comment --- src/battle_script_commands.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 730d6941d2dc..a27b27d4a78f 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2011,8 +2011,9 @@ s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recor RecordAbilityBattle(battlerDef, abilityDef); critChance = -1; - // Guaranteed crits } + + // Guaranteed crits else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS || gMovesInfo[move].alwaysCriticalHit == TRUE || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) From c97ced13075cda90796a3bb9c32f136b1c6eb367 Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sat, 28 Sep 2024 22:57:11 -0400 Subject: [PATCH 3/6] Remove comment --- src/battle_script_commands.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a27b27d4a78f..de80078b2f22 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2055,7 +2055,6 @@ static void Cmd_critcalc(void) gIsCriticalHit = TRUE; else { - // Gen 1 crit chance #if B_CRIT_CHANCE == GEN_1 u8 critRoll = RandomUniform(RNG_CRITICAL_HIT, 1, 256); if (critRoll <= critChance) From b349892d392077ce77ddafdf56ebee9c8b3c4ccc Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sun, 29 Sep 2024 07:42:24 -0400 Subject: [PATCH 4/6] Remove preprocs and comments --- src/battle_script_commands.c | 43 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index de80078b2f22..08bd2d8022d1 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1956,13 +1956,15 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA // Focus Energy = 4 * (Base Speed / 2) s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility) { - // Change these scalers if you want to change how much Focus Energy and high crit rate moves affect crit chance - u8 focusEnergyScaler = 4; // vanilla is 4 - u8 highCritRatioScaler = 8; // vanilla is 8 - u8 superLuckScaler = 4; // not in vanilla - u8 scopeLensScaler = 4; // not in vanilla - u8 luckyPunchScaler = 8; // not in vanilla - u8 farfetchedLeekScaler = 8; // not in vanilla + // Vanilla + u8 focusEnergyScaler = 4; + u8 highCritRatioScaler = 8; + + // Not vanilla + u8 superLuckScaler = 4; + u8 scopeLensScaler = 4; + u8 luckyPunchScaler = 8; + u8 farfetchedLeekScaler = 8; s32 critChance = 0; s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage; @@ -1971,34 +1973,27 @@ s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recor u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); u16 baseSpeed = gSpeciesInfo[gBattleMons[battlerAtk].species].baseSpeed; - // Threshold is base speed / 2 critChance = baseSpeed / 2; - // Scale for high crit chance moves + // Crit scaling if (moveCritStage > 0) critChance = critChance * highCritRatioScaler * moveCritStage; - // Scale for Focus Energy if ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) critChance = critChance * focusEnergyScaler; - // Scale for Scope Lens if (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) critChance = critChance * scopeLensScaler; - // Scale for Lucky Punch if (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY) critChance = critChance * luckyPunchScaler; - // Scale for Farfetch'd holding Leek if (BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)) critChance = critChance * farfetchedLeekScaler; - // Scale for Super Luck if (abilityAtk == ABILITY_SUPER_LUCK) critChance = critChance * superLuckScaler; - // Capped at 255 if (critChance > 255) critChance = 255; @@ -2010,7 +2005,6 @@ s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recor if (recordAbility) RecordAbilityBattle(battlerDef, abilityDef); critChance = -1; - } // Guaranteed crits @@ -2038,12 +2032,12 @@ static void Cmd_critcalc(void) CMD_ARGS(); u16 partySlot; + s32 critChance; - #if B_CRIT_CHANCE == GEN_1 - s32 critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); - #else - s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); - #endif // B_CRIT_CHANCE + if (B_CRIT_CHANCE == GEN_1) + critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); + else + critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE); gPotentialItemEffectBattler = gBattlerAttacker; @@ -2055,15 +2049,16 @@ static void Cmd_critcalc(void) gIsCriticalHit = TRUE; else { - #if B_CRIT_CHANCE == GEN_1 + if (B_CRIT_CHANCE == GEN_1) + { u8 critRoll = RandomUniform(RNG_CRITICAL_HIT, 1, 256); if (critRoll <= critChance) gIsCriticalHit = 1; else gIsCriticalHit = 0; - #else + } + else gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, sCriticalHitOdds[critChance]); - #endif // B_CRIT_CHANCE } // Counter for EVO_CRITICAL_HITS. From 5912e838e8334e622702e56deb38569cb0ce0a4b Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sun, 29 Sep 2024 07:58:04 -0400 Subject: [PATCH 5/6] u8s -> u32s --- src/battle_script_commands.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 08bd2d8022d1..b611af0a9a27 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1957,14 +1957,14 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility) { // Vanilla - u8 focusEnergyScaler = 4; - u8 highCritRatioScaler = 8; + u32 focusEnergyScaler = 4; + u32 highCritRatioScaler = 8; // Not vanilla - u8 superLuckScaler = 4; - u8 scopeLensScaler = 4; - u8 luckyPunchScaler = 8; - u8 farfetchedLeekScaler = 8; + u32 superLuckScaler = 4; + u32 scopeLensScaler = 4; + u32 luckyPunchScaler = 8; + u32 farfetchedLeekScaler = 8; s32 critChance = 0; s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage; From b8dfee59c6f97139cd04218a9152b3860d4440ab Mon Sep 17 00:00:00 2001 From: Pawkkie Date: Sun, 29 Sep 2024 11:25:36 -0400 Subject: [PATCH 6/6] Lansat Berry and G-Max Chi Strike --- src/battle_script_commands.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b611af0a9a27..507f4aa8b7df 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1968,6 +1968,7 @@ s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recor s32 critChance = 0; s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage; + s32 bonusCritStage = gBattleStruct->bonusCritStages[gBattlerAttacker]; // G-Max Chi Strike u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); u32 abilityDef = GetBattlerAbility(gBattlerTarget); u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); @@ -1978,8 +1979,11 @@ s32 CalcCritChanceStageGen1(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recor // Crit scaling if (moveCritStage > 0) critChance = critChance * highCritRatioScaler * moveCritStage; + + if (bonusCritStage > 0) + critChance = critChance * bonusCritStage; - if ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) + if ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY_ANY) != 0) critChance = critChance * focusEnergyScaler; if (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)