Pokémon FireRed and LeafGreen
The Generation III remakes of Red and Green for Game Boy Advance, read through the pret/pokefirered decompilation.
On this page
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
| Mechanic | Kind | How |
|---|---|---|
| Critical hit | From stages | Ruby'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 chance | Move accuracy | Emerald's percent accuracy, skipped for every move in Pokédude battles and for the player's in the first battle |
| Type effectiveness | 17 types | Emerald's chart, entry for entry |
| Same-type attack bonus | Half again | damage × 15 / 10, just before the type rows |
| Damage formula | Attack over defense | Emerald's damage and 85–100% random factor, unchanged |
| Multi-hit attack | Per-hit damage | Emerald's 2–5 hits, line for line |
| Random encounter | By area | a step cooldown, then a roll out of 1,600 on its own generator that grows easier with each failed check |
| Fleeing | Speed ratio | Ruby's formula, plus a sure escape from a ghost the Silph Scope hasn't revealed |
| Turn order | Priority, then Speed | Emerald's priority and Speed rule |
| Capture | Four shake checks | Emerald's formula and shake checks, plus a dodge in ghost battles |
Every claim about this game, by concept (11)
References
- ^ abFireRed and LeafGreen's
Cmd_critcalckeeps 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/pokeemeraldrevisedHow 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.
- ^FireRed and LeafGreen's
gTypeEffectivenessis Emerald's, entry for entry: 108 matchup rows, the Foresight marker, two Ghost immunities, and the end marker.Codepret/pokefirered · pret/pokeemeraldrevisedHow 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.
- ^FireRed and LeafGreen keep Ruby's escape formula, 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.
- ^FireRed and LeafGreen's
Cmd_accuracycheckis 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/pokeemeraldrevisedHow 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.
- ^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.
- ^FireRed and LeafGreen roll encounters on their own generator, , 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 1600src/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.
Sources
Code
- pret contributors. 2026. “pokefirered: decompilation of Pokémon FireRed and LeafGreen.” pret. Commit ce6406d. pret/pokefirered @ ce6406d · licence, all uses
- pret contributors. 2026. “pokeemerald: decompilation of Pokémon Emerald.” pret. Commit 731ad5b. pret/pokeemerald @ 731ad5b · licence, all uses