On this page
  1. Related
  2. Mechanics
  3. References
  4. Sources

Pokémon FireRed and LeafGreen remake Red and Green on the Generation III engine. The code read here is pret’s pokefirered decompilation, diffed function by function against Emerald.

The battle rules are Ruby and Sapphire’s, not Red and Blue’s: staged critical hits1, the 17-type chart2, and the Gen 3 escape formula3. Pokédude battles have no critical hits and no accuracy rolls, and the first battle has no critical hits, and no accuracy roll for the player’s moves, until tutorial flags are set1,4.

Wild encounters differ most. A step cooldown comes first5. The roll uses its own generator, out of 1,600 rather than Emerald’s 2,880, and each failed check makes the next one easier6.

Mechanics

MechanicKindHow
Critical hitFrom stagesRuby's stages, with none in the Old Man's or Pokédude battles, or in the first battle until a tutorial flag is set
Hit chanceMove accuracyEmerald's percent accuracy, skipped for every move in Pokédude battles and for the player's in the first battle
Type effectiveness17 typesEmerald's chart, entry for entry
Same-type attack bonusHalf againdamage × 15 / 10, just before the type rows
Damage formulaAttack over defenseEmerald's damage and 85–100% random factor, unchanged
Multi-hit attackPer-hit damageEmerald's 2–5 hits, line for line
Random encounterBy areaa step cooldown, then a roll out of 1,600 on its own generator that grows easier with each failed check
FleeingSpeed ratioRuby's formula, plus a sure escape from a ghost the Silph Scope hasn't revealed
Turn orderPriority, then SpeedEmerald's priority and Speed rule
CaptureFour shake checksEmerald's formula and shake checks, plus a dodge in ghost battles
Every claim about this game, by concept (11)
CaptureFireRed and LeafGreen run Emerald's formula, status test (bad poison included), and shake checks unchanged; before them, a ball thrown in a battle flagged BATTLE_TYPE_GHOST is dodged.Code
Critical hitFireRed and LeafGreen's Cmd_critcalc keeps Ruby's stages and its 1 in 16, 8, 4, 3, or 2, but rules out critical hits in the Old Man's catching tutorial, in Pokédude battles, and in the first battle until a tutorial flag is set.Code
Damage formulaFireRed and LeafGreen's Cmd_damagecalc and Cmd_adjustnormaldamage diff identical with Emerald's: Cmd_damagecalc multiplies the base damage by the critical multiplier, 2 on a critical hit, and the random factor is damage × (100 − rand % 16) / 100, 85–100%.Code
FleeingFireRed and LeafGreen keep Ruby's escape formula, ⌊128P/E⌋+30t against a random byte, with Smoke Ball and Run Away always escaping, and add that the player always escapes a ghost battle fought without the Silph Scope.Code
Hit chanceFireRed and LeafGreen's Cmd_accuracycheck is Emerald's with one addition: in Pokédude battles every move, on either side, skips the accuracy roll, and in the first battle the player's damaging moves skip it until one tutorial flag is set and the player's status moves until a second.Code
Multi-hit attackFireRed and LeafGreen's Cmd_setmultihitcounter is Emerald's, line for line: 2 or 3 hits at 3/8 each and 4 or 5 at 1/8. The battle script runs accuracycheck once, then loops critcalc, damagecalc, and adjustnormaldamage for every hit.Code
Random encounterFireRed and LeafGreen roll encounters on their own generator, x←1103515245x+12345, seeded at a new game; a check passes when its value mod 1,600 is below 16 times the area's rate, cut to 80% on a bike, plus 16/200 of a buff to which every failed check adds the area's rate, reset by a battle or a Repel.Code
Before that roll, FireRed and LeafGreen require a minimum number of steps since the last battle, 8 − ⌊rate/10⌋ (0 at a rate of 80 or more, 8 below 10), and before then let a check through only on a 5-in-100 roll; the flutes, a Cleanse Tag, and the lead's Stench or Illuminate scale both numbers.Code
Same-type attack bonusFireRed and LeafGreen keep Emerald's STAB, damage×15/10 before the type rows; their Cmd_typecalc differs from Emerald's only in how it names the defender's types.Code
Turn orderFireRed and LeafGreen's GetWhoStrikesFirst is Emerald's rule: the higher-priority move first, then the higher adjusted Speed, with a tie a coin flip, and a Quick Claw that sets Speed to the maximum on its roll. It differs only in withholding the third badge's ×1.1 Speed in link battles alone, where Emerald also withholds it in recorded-link and Frontier battles.Code
Type effectivenessFireRed and LeafGreen's gTypeEffectiveness is Emerald's, entry for entry: 108 matchup rows, the Foresight marker, two Ghost immunities, and the end marker.Code

References

  1. ^ abFireRed and LeafGreen's Cmd_critcalc keeps Ruby's stages and its 1 in 16, 8, 4, 3, or 2, but rules out critical hits in the Old Man's catching tutorial, in Pokédude battles, and in the first battle until a tutorial flag is set.Codepret/pokefirered · pret/pokeemeraldrevised
    How we know
    1196    if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR)
    1197     && !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
    1198     && !(gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL)
    1199     && !(Random() % sCriticalHitChance[critChance])
    1200     && (!(gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) || BtlCtrl_OakOldMan_TestState2Flag(1))
    1201     && !(gBattleTypeFlags & BATTLE_TYPE_POKEDUDE))
    
    src/battle_script_commands.c lines 1196–1201 at ce6406d · upstream ↗
    588static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2};
    
    src/battle_script_commands.c line 588 at ce6406d · upstream ↗
    1253static void Cmd_critcalc(void)
    ⋮
    1281     && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE))
    1282     && !(Random() % sCriticalHitChance[critChance]))
    
    src/battle_script_commands.c lines 1253–1288 at 731ad5b · upstream ↗
    606static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2};
    
    src/battle_script_commands.c line 606 at 731ad5b · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Revised after a check by a second AI model, 2026-10-21.

    In the claim ledger

  2. ^FireRed and LeafGreen's gTypeEffectiveness is Emerald's, entry for entry: 108 matchup rows, the Foresight marker, two Ghost immunities, and the end marker.Codepret/pokefirered · pret/pokeemeraldrevised
    How we know
    312const u8 gTypeEffectiveness[336] =
    
    src/battle_main.c lines 312–426 at ce6406d · upstream ↗
    335const u8 gTypeEffectiveness[336] =
    
    src/battle_main.c lines 335–449 at 731ad5b · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Revised after a check by a second AI model, 2026-10-21.

    In the claim ledger

  3. ^FireRed and LeafGreen keep Ruby's escape formula, ⌊128P/E⌋+30t against a random byte, with Smoke Ball and Run Away always escaping, and add that the player always escapes a ghost battle fought without the Silph Scope.Codepret/pokefirered
    How we know
    4252    else if (IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(gBattleTypeFlags))
    ⋮
    4254        if (GetBattlerSide(battler) == B_SIDE_PLAYER)
    4255            effect++;
    ⋮
    4257    else
    ⋮
    4263                speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30);
    
    src/battle_main.c lines 4252–4263 at ce6406d · upstream ↗
    69#define IS_BATTLE_TYPE_GHOST_WITHOUT_SCOPE(flags) ((flags) & BATTLE_TYPE_GHOST && !((flags) & BATTLE_TYPE_GHOST_UNVEILED))
    
    include/constants/battle.h line 69 at ce6406d · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  4. ^FireRed and LeafGreen's Cmd_accuracycheck is Emerald's with one addition: in Pokédude battles every move, on either side, skips the accuracy roll, and in the first battle the player's damaging moves skip it until one tutorial flag is set and the player's status moves until a second.Codepret/pokefirered · pret/pokeemeraldrevised
    How we know
    1003static void Cmd_accuracycheck(void)
    ⋮
    1007    if ((gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE
    1008        && !BtlCtrl_OakOldMan_TestState2Flag(1)
    1009        && gBattleMoves[move].power != 0
    1010        && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
    1011     || (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE
    1012        && !BtlCtrl_OakOldMan_TestState2Flag(2)
    1013        && gBattleMoves[move].power == 0
    1014        && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
    1015     || (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE))
    ⋮
    1017        JumpIfMoveFailed(7, move);
    1018        return;
    
    src/battle_script_commands.c lines 1003–1019 at ce6406d · upstream ↗
    1099static void Cmd_accuracycheck(void)
    ⋮
    1101    u16 move = T2_READ_16(gBattlescriptCurrInstr + 5);
    ⋮
    1103    if (move == NO_ACC_CALC || move == NO_ACC_CALC_CHECK_LOCK_ON)
    
    src/battle_script_commands.c lines 1099–1103 at 731ad5b · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Revised after a check by a second AI model, 2026-10-21.

    In the claim ledger

  5. ^Before that roll, FireRed and LeafGreen require a minimum number of steps since the last battle, 8 − ⌊rate/10⌋ (0 at a rate of 80 or more, 8 below 10), and before then let a check through only on a 5-in-100 roll; the flutes, a Cleanse Tag, and the lead's Stench or Illuminate scale both numbers.Codepret/pokefirered
    How we know
    682        if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate >= 80)
    683            return 0;
    684        if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate < 10)
    685            return 8;
    686        return 8 - (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate / 10);
    
    src/wild_encounter.c lines 682–686 at ce6406d · upstream ↗
    717    minSteps *= 256;
    718    encRate = 5 * 256;
    ⋮
    749    if (sWildEncounterData.stepsSinceLastEncounter >= minSteps)
    750        return TRUE;
    751    sWildEncounterData.stepsSinceLastEncounter++;
    752    if ((Random() % 100) < encRate)
    753        return TRUE;
    
    src/wild_encounter.c lines 716–755 at ce6406d · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  6. ^FireRed and LeafGreen roll encounters on their own generator, x←1103515245x+12345, seeded at a new game; a check passes when its value mod 1,600 is below 16 times the area's rate, cut to 80% on a bike, plus 16/200 of a buff to which every failed check adds the area's rate, reset by a battle or a Repel.Codepret/pokefireredrevised
    How we know
    20#define MAX_ENCOUNTER_RATE 1600
    
    src/wild_encounter.c line 20 at ce6406d · upstream ↗
    304    if (WildEncounterRandom() % MAX_ENCOUNTER_RATE < encounterRate)
    ⋮
    311    encounterRate *= 16;
    312    if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE))
    313        encounterRate = encounterRate * 80 / 100;
    314    encounterRate += sWildEncounterData.encounterRateBuff * 16 / 200;
    
    src/wild_encounter.c lines 302–314 at ce6406d · upstream ↗
    372            if (DoWildEncounterRateTest(gWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
    ⋮
    374                AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
    
    src/wild_encounter.c lines 372–374 at ce6406d · upstream ↗
    667static u16 WildEncounterRandom(void)
    ⋮
    669    sWildEncounterData.rngState = ISO_RANDOMIZE2(sWildEncounterData.rngState);
    670    return sWildEncounterData.rngState >> 16;
    
    src/wild_encounter.c lines 667–671 at ce6406d · upstream ↗
    18#define RAND_MULT 1103515245
    ⋮
    20#define ISO_RANDOMIZE2(val)(RAND_MULT * (val) + 12345)
    
    include/random.h lines 18–20 at ce6406d · upstream ↗
    778static void AddToWildEncounterRateBuff(u8 encounterRate)
    ⋮
    780    if (VarGet(VAR_REPEL_STEP_COUNT) == 0)
    781        sWildEncounterData.encounterRateBuff += encounterRate;
    782    else
    783        sWildEncounterData.encounterRateBuff = 0;
    
    src/wild_encounter.c lines 778–784 at ce6406d · upstream ↗
    103    SeedWildEncounterRng(Random());
    
    src/new_game.c line 103 at ce6406d · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Revised after a check by a second AI model, 2026-10-21.

    In the claim ledger

Sources

Code