Pokémon Ruby and Sapphire
The first Generation III Pokémon games, for Game Boy Advance, read through the pret/pokeruby decompilation.
On this page
Pokémon Ruby and Sapphire are the first Generation III games, for the Game Boy Advance. The code read here is pret’s pokeruby decompilation, diffed function by function against Emerald.
Emerald keeps nearly all of what the atlas reads here. The staged critical hit1, percent accuracy2, the percent-based random factor3, and the escape formula4 all date from Ruby and Sapphire. The generation’s new rules are here too: 77 abilities5, 25 natures6, and weather that carries from the overworld into battle7.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Critical hit | From stages | stages from 1 in 16 to 1 in 2, and Battle Armor and Shell Armor block it |
| Hit chance | Move accuracy | accuracy in percent times one combined stage ratio, then ability and item modifiers |
| Type effectiveness | 17 types | Crystal's 110 rows in the same order |
| Same-type attack bonus | Half again | damage × 15 / 10, just before the type rows |
| Damage formula | Attack over defense | the random factor is 100 − rand % 16 percent, about the old 217–255 over 255 |
| Multi-hit attack | Per-hit damage | 2–5 hits at Red and Blue's odds, each with its own critical and damage roll |
| Random encounter | By area | 16 times the area's rate out of 2,880 per step, with bike, flute, Cleanse Tag, Stench, and Illuminate modifiers |
| Fleeing | Speed ratio | 128 times Speed over the foe's, plus 30 per try, out of 256; a Smoke Ball or Run Away always escapes |
| Turn order | Priority, then Speed | priority, then adjusted Speed, with a Quick Claw that puts its holder first on 20% of turns at equal priority |
| Ability | 77 abilities, one or two per species, picked by the personality value | |
| Nature | 25 natures from the personality value, ±10% on two stats | |
| Held item | items carry a hold effect and a parameter; the Quick Claw's is 20% | |
| Weather | Field and ability | overworld weather carries into battle, and Drizzle sets rain with no turn limit |
| Capture | Four shake checks | Emerald's four shake checks, but bad poison gives no status bonus |
Every claim about this game, by concept (13)
References
- ^Ruby and Sapphire's
atk04_critcalc, which Emerald keeps apart from a renamed helper, sums Focus Energy (+2), a move whose effect is high-critical, Sky Attack, Blaze Kick, or Poison Tail (+1), a Scope Lens (+1), and Lucky Punch or Stick on their species (+2), caps the stage at 4, and hits critically 1 time in 16, 8, 4, 3, or 2. Battle Armor or Shell Armor on the target, theSTATUS3_CANT_SCORE_A_CRITflag on the attacker, Wally's tutorial, and the first battle rule it out.Codepret/pokeruby · pret/pokeemeraldrevisedHow we know
1387 critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0) 1388 + (gBattleMoves[gCurrentMove].effect == EFFECT_HIGH_CRITICAL) 1389 + (gBattleMoves[gCurrentMove].effect == EFFECT_SKY_ATTACK) 1390 + (gBattleMoves[gCurrentMove].effect == EFFECT_BLAZE_KICK) 1391 + (gBattleMoves[gCurrentMove].effect == EFFECT_POISON_TAIL) 1392 + (holdEffect == HOLD_EFFECT_SCOPE_LENS) ⋮ 1399 if ((gBattleMons[gBattlerTarget].ability != ABILITY_BATTLE_ARMOR && gBattleMons[gBattlerTarget].ability != ABILITY_SHELL_ARMOR) 1400 && !(gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT) 1401 && !(gBattleTypeFlags & (BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FIRST_BATTLE)) 1402 && !(Random() % sCriticalHitChance[critChance]))
src/battle_script_commands.c lines 1387–1402 at 5784633 · upstream ↗ 822static const u16 sCriticalHitChance[] = {16, 8, 4, 3, 2};src/battle_script_commands.c line 822 at 5784633 · upstream ↗ 1253static void Cmd_critcalc(void)src/battle_script_commands.c lines 1253–1289 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.
- ^Ruby and Sapphire's
atk01_accuracycheck, which Emerald keeps with renamed constants, scales a move's percent accuracy by one combined stage ratio, applies Compound Eyes (×1.3), Sand Veil in a sandstorm and Hustle on physical moves (×0.8 each), and a target's evasion item, and misses when a roll from 1 to 100 exceeds the result.Codepret/pokeruby · pret/pokeemeraldHow we know
1272 calc = gAccuracyStageRatios[buff].dividend * moveAcc; 1273 calc /= gAccuracyStageRatios[buff].divisor; ⋮ 1276 calc = (calc * 130) / 100; // 1.3 compound eyes boost ⋮ 1278 calc = (calc * 80) / 100; // 1.2 sand veil loss; ⋮ 1280 calc = (calc * 80) / 100; // 1.2 hustle loss; ⋮ 1296 calc = (calc * (100 - quality)) / 100; ⋮ 1299 if ((Random() % 100 + 1) > calc)
src/battle_script_commands.c lines 1272–1299 at 5784633 · upstream ↗ src/battle_script_commands.c#L1099-L1252 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Ruby and Sapphire already use Emerald's random factor, damage × (100 − rand % 16) / 100, raised to 1 if that gives 0; Gen 1 and 2 reach about the same 85–100% spread as a byte from 217 to 255 over 255.Codepret/pokeruby · pret/pokeemeraldrevised
How we know
1751static inline void ApplyRandomDmgMultiplier(void) ⋮ 1753 u16 rand = Random(); 1754 u16 randPercent = 100 - (rand % 16); ⋮ 1758 gBattleMoveDamage *= randPercent; 1759 gBattleMoveDamage /= 100; 1760 if (gBattleMoveDamage == 0) 1761 gBattleMoveDamage = 1;
src/battle_script_commands.c lines 1751–1763 at 5784633 · upstream ↗ 1639static inline void ApplyRandomDmgMultiplier(void) ⋮ 1641 u16 rand = Random(); 1642 u16 randPercent = 100 - (rand % 16);
src/battle_script_commands.c lines 1639–1651 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.
- ^Ruby and Sapphire's
TryRunFromBattlealways escapes with a Smoke Ball or Run Away; otherwise, in a single battle, a Pokémon at least as fast as the foe escapes, and a slower one when , for earlier tries, beats a random byte. Emerald adds only the Battle Pyramid's and Frontier's rules.Codepret/pokeruby · pret/pokeemeraldHow we know
5465 if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) ⋮ 5471 else if (gBattleMons[bank].ability == ABILITY_RUN_AWAY) ⋮ 5477 else ⋮ 5481 if (gBattleMons[bank].speed < gBattleMons[bank ^ BIT_SIDE].speed) ⋮ 5483 speedVar = (gBattleMons[bank].speed * 128) / (gBattleMons[bank ^ BIT_SIDE].speed) + (gBattleStruct->runTries * 30); 5484 if (speedVar > (Random() & 0xFF))
src/battle_main.c lines 5465–5490 at 5784633 · upstream ↗ src/battle_util.c#L407-L485 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Ruby and Sapphire define 77 abilities, from Stench (1) to Air Lock (77); a species lists one or two, and when it has two, the lowest bit of the Pokémon's personality value picks which.Codepret/pokeruby
How we know
4#define ABILITY_NONE 0 5#define ABILITY_STENCH 1 ⋮ 81#define ABILITY_AIR_LOCK 77 ⋮ 83#define ABILITIES_COUNT 78
include/constants/abilities.h lines 4–83 at 5784633 · upstream ↗ 1465 if (gBaseStats[species].ability2) ⋮ 1467 value = personality & 1; 1468 SetBoxMonData(boxMon, MON_DATA_ALT_ABILITY, &value);
src/pokemon_1.c lines 1465–1468 at 5784633 · upstream ↗ 1056u8 GetAbilityBySpecies(u16 species, bool8 altAbility) ⋮ 1058 if (altAbility) 1059 gLastUsedAbility = gBaseStats[species].ability2; 1060 else 1061 gLastUsedAbility = gBaseStats[species].ability1;
src/pokemon_2.c lines 1056–1063 at 5784633 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A Ruby and Sapphire Pokémon's nature is its personality value mod 25; each of the 25 raises one stat other than HP by 10% and lowers another by 10%, rounded down, except Hardy, Docile, Serious, Bashful, and Quirky, which change nothing.Codepret/pokeruby
How we know
261u8 GetNatureFromPersonality(u32 personality) ⋮ 263 return personality % 25;
src/pokemon_3.c lines 261–264 at 5784633 · upstream ↗ 627u16 nature_stat_mod(u8 nature, u16 n, u8 statIndex) ⋮ 638 switch (gNatureStatTable[nature][statIndex - 1]) ⋮ 640 case 1: 641 return (u16)(n * 110) / 100; 642 case -1: 643 return (u16)(n * 90) / 100;
src/pokemon_3.c lines 627–657 at 5784633 · upstream ↗ 1285const s8 gNatureStatTable[][5] = ⋮ 1287 // Atk Def Spd Sp.Atk Sp.Def 1288 { 0, 0, 0, 0, 0}, // Hardy 1289 { +1, -1, 0, 0, 0}, // Lonely
src/pokemon_1.c lines 1285–1313 at 5784633 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^In Ruby and Sapphire, rain, sandstorm, or drought on the overworld starts a battle in that weather with no turn limit, Drizzle sets lasting rain when its holder enters, and Cloud Nine or Air Lock on the field turns weather's effects off.Codepret/pokeruby
How we know
1794 case 0xFF: //weather from overworld 1795 switch (GetCurrentWeather()) ⋮ 1797 case WEATHER_RAIN_LIGHT: ⋮ 1802 gBattleWeather = (B_WEATHER_RAIN_TEMPORARY | B_WEATHER_RAIN_PERMANENT); ⋮ 1833 case ABILITY_DRIZZLE: 1834 if (!(gBattleWeather & B_WEATHER_RAIN_PERMANENT)) ⋮ 1836 gBattleWeather = (B_WEATHER_RAIN_PERMANENT | B_WEATHER_RAIN_TEMPORARY);
src/battle_util.c lines 1794–1836 at 5784633 · upstream ↗ 50#define WEATHER_HAS_EFFECT ((!AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, ABILITY_CLOUD_NINE, 0, 0) && !AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, ABILITY_AIR_LOCK, 0, 0)))include/battle_util.h line 50 at 5784633 · upstream ↗ 771 case ENDTURN_RAIN: 772 if (gBattleWeather & B_WEATHER_RAIN) ⋮ 774 if (!(gBattleWeather & B_WEATHER_RAIN_PERMANENT)) ⋮ 776 if (--gWishFutureKnock.weatherDuration == 0)
src/battle_util.c lines 771–776 at 5784633 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Sources
Code
- pret contributors. 2026. “pokeruby: decompilation of Pokémon Ruby and Sapphire.” pret. Commit 5784633. pret/pokeruby @ 5784633 · licence, all uses
- pret contributors. 2026. “pokeemerald: decompilation of Pokémon Emerald.” pret. Commit 731ad5b. pret/pokeemerald @ 731ad5b · licence, all uses