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

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

MechanicKindHow
Critical hitFrom stagesstages from 1 in 16 to 1 in 2, and Battle Armor and Shell Armor block it
Hit chanceMove accuracyaccuracy in percent times one combined stage ratio, then ability and item modifiers
Type effectiveness17 typesCrystal's 110 rows in the same order
Same-type attack bonusHalf againdamage × 15 / 10, just before the type rows
Damage formulaAttack over defensethe random factor is 100 − rand % 16 percent, about the old 217–255 over 255
Multi-hit attackPer-hit damage2–5 hits at Red and Blue's odds, each with its own critical and damage roll
Random encounterBy area16 times the area's rate out of 2,880 per step, with bike, flute, Cleanse Tag, Stench, and Illuminate modifiers
FleeingSpeed ratio128 times Speed over the foe's, plus 30 per try, out of 256; a Smoke Ball or Run Away always escapes
Turn orderPriority, then Speedpriority, then adjusted Speed, with a Quick Claw that puts its holder first on 20% of turns at equal priority
Ability77 abilities, one or two per species, picked by the personality value
Nature25 natures from the personality value, ±10% on two stats
Held itemitems carry a hold effect and a parameter; the Quick Claw's is 20%
WeatherField and abilityoverworld weather carries into battle, and Drizzle sets rain with no turn limit
CaptureFour shake checksEmerald's four shake checks, but bad poison gives no status bonus
Every claim about this game, by concept (13)
AbilityRuby 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.Code
CaptureRuby and Sapphire run the same formula and shake checks as Emerald, except that their status test leaves out bad poison (STATUS1_TOXIC_POISON, a separate status bit from poison), so a badly poisoned Pokémon gets no bonus. Emerald's test includes it.Code
Critical hitRuby 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, the STATUS3_CANT_SCORE_A_CRIT flag on the attacker, Wally's tutorial, and the first battle rule it out.Code
Damage formulaRuby 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.Code
FleeingRuby and Sapphire's TryRunFromBattle always 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 ⌊128P/E⌋+30t, for t earlier tries, beats a random byte. Emerald adds only the Battle Pyramid's and Frontier's rules.Code
Hit chanceRuby 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.Code
Multi-hit attackRuby and Sapphire's atk8D_setmultihitcounter gives 2 or 3 hits with probability 3/8 each and 4 or 5 with 1/8 each, the same code as Emerald's; the multi-hit battle script runs accuracycheck once and then loops critcalc, damagecalc, and adjustnormaldamage for every hit.Code
NatureA 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.Code
Random encounterRuby and Sapphire multiply the area's encounter rate by 16, cut it to 80% on the Mach or Acro Bike, apply the flute and Cleanse Tag modifiers, halve it for a lead with Stench and double it for Illuminate, cap it at 2,880, and start a battle when Random() % 2880 is below it. Emerald keeps the roll and adds more ability modifiers.Code
Same-type attack bonusRuby and Sapphire's atk06_typecalc applies STAB as damage×15/10 before the type rows, as Emerald's Cmd_typecalc does.Code
Turn orderRuby and Sapphire's GetWhoStrikesFirst puts the higher-priority move first; at equal priority the higher adjusted Speed goes first, and a tie is a coin flip. Adjusted Speed applies stat stages, doubles for Swift Swim in rain or Chlorophyll in sun, takes ×1.1 for the player's Pokémon with the third badge outside link battles, halves with a Macho Brace, and quarters under paralysis; a held Quick Claw sets it to the maximum when a per-turn random number is below its parameter, 20, as a percent of 0xFFFF.Code
Type effectivenessRuby and Sapphire's gTypeEffectiveness holds the same 110 rows as Emerald's and Crystal's, in the same order, with literal 0xFE and 0xFF bytes where Emerald names TYPE_FORESIGHT and TYPE_ENDTABLE.Code
WeatherIn 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.Code

References

  1. ^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, the STATUS3_CANT_SCORE_A_CRIT flag on the attacker, Wally's tutorial, and the first battle rule it out.Codepret/pokeruby · pret/pokeemeraldrevised
    How 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.

    In the claim ledger

  2. ^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/pokeemerald
    How 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.

    In the claim ledger

  3. ^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.

    In the claim ledger

  4. ^Ruby and Sapphire's TryRunFromBattle always 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 ⌊128P/E⌋+30t, for t earlier tries, beats a random byte. Emerald adds only the Battle Pyramid's and Frontier's rules.Codepret/pokeruby · pret/pokeemerald
    How 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.

    In the claim ledger

  5. ^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.

    In the claim ledger

  6. ^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 the claim ledger

  7. ^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.

    In the claim ledger

Sources

Code