On this page
  1. Two rolls
  2. One catch roll
  3. Four shake checks
  4. Other differences
  5. Related
  6. Games
  7. References
  8. Sources

Pokémon capture turns a thrown ball into a chance determined by the target’s catch rate, its HP and status, and the ball. The generations use different random-roll sequences, although a Bulbasaur in a Poké Ball has similar computed chances at full HP across Red and Blue, Crystal, and Emerald1.

  • Two rollsPokémon Red and Blue (1996). A ball-limited byte less 25 or 12 for status against the catch rate, then a second byte against an HP term; the shakes on a miss are worked out with no roll.2,3,4,5,6Pokémon Yellow (1998). Red and Blue's capture code line for line, plus a Pikachu battle that catches outright.7
  • Single catch rollPokémon Gold and Silver (1999). Crystal's code: one byte against the catch rate scaled by (3M − 2H)/3M, plus 10 for sleep or freeze and nothing for burn, poison or paralysis.8,9Pokémon Crystal (2000). One byte against the ball-modified rate scaled by (3M − 2H)/3M plus a sleep or freeze bonus; the wobbles are rolled after the result.10,11,9,12,13,14
  • Four shake checksPokémon Ruby and Sapphire (2002). Emerald's four shake checks, but bad poison gives no status bonus.15Pokémon Emerald (2004). The ball, HP and status set a rate, and four 16-bit rolls under a threshold near 65535 (a/255)^(1/4) catch; a miss shows the shakes it passed.16,17,18,19Pokémon FireRed and LeafGreen (2004). Emerald's formula and shake checks, plus a dodge in ghost battles.20Pokémon Platinum (2008). Emerald's formula and four shake checks, with the Dusk and Quick Balls added.21,22Pokémon HeartGold and SoulSilver (2009). Platinum's formula and four shake checks; the Apricorn balls change the catch rate itself.23,24,25
Pokémon Red and Blue, YellowGold and Silver, CrystalRuby and Sapphire onward
Catch decisionA ball-limited byte is checked against status and catch rate, then another byte against an HP term2,3,4.The ball, HP, and status modify one rate, then one byte decides the catch10,11,9,12.The rate becomes a threshold for up to four 16-bit rolls; each passing roll adds a shake, and four pass to catch18.
Failed throwThe shake count is calculated from the catch rate and HP term without another roll5.The throw result comes first; each of up to three wobble animations then gets its own roll13.The passed checks are the displayed shakes18.

#Two rolls

In Pokémon Red and Blue, the first random byte is redrawn until it falls within a ball-specific range. Sleep or freeze subtracts 25 from it, another status subtracts 12, and no status subtracts nothing; a value below that subtraction catches outright, while a value above the remaining catch rate fails2,3. If the first check passes, a second byte is compared with an HP term that grows as the target loses HP4. On a miss, the game derives the displayed shakes from the same values, without another random roll5.

Pokémon Yellow keeps Red and Blue’s capture routine line for line, with a Pikachu battle added to the outright-catch branch7.

#One catch roll

Pokémon Gold and Silver use Crystal’s capture routine and wobble table8. The routine first modifies the catch rate by the ball, then scales it by the target’s HP and adds a status bonus before one random byte decides the catch10,11,9,12. Sleep or freeze adds 10; burn, poison, and paralysis add nothing because the status test clears the value before the next test9.

The wobble rolls follow the catch decision, so they animate a failed throw without changing its result13,12. The table’s comment describes a fourth-root probability; the atlas reads this as the chance for each animation step, not four checks that decide capture13.

Crystal’s Level Ball skips the HP and status calculations, making its final rate depend on the catch rate and the two Pokémon’s levels14. Its HP calculation also breaks above max HP 341 because the routine quarters values that must fit in a byte11.

#Four shake checks

Pokémon Ruby and Sapphire, Emerald, FireRed and LeafGreen, Platinum, and HeartGold and SoulSilver use four shake checks. Their formula converts catch rate, ball, HP, and status into a rate, then into a threshold; each of up to four 16-bit random values below that threshold adds a shake, and four shakes catch17,18,15,20,21,23.

Ruby and Sapphire omit bad poison from the status bonus, while Emerald and the later implementations include it15,20,21,23. FireRed and LeafGreen also dodge balls in battles flagged as ghost battles20. Platinum adds Dusk and Quick Ball multipliers and changes the Dive Ball’s condition; HeartGold and SoulSilver add Apricorn ball modifiers22,24.

#Other differences

Red and Blue can give a Great Ball a higher catch chance than an Ultra Ball because the Great Ball’s HP divisor is smaller6. Crystal’s Level Ball and HP overflow are specific exceptions to its usual one-roll path14,11. In Emerald, the Master Ball draws its shake checks before the code sets the displayed count to four18.

Games

GameYearHowNote
Pokémon Red and Blue1996Two rollsa ball-limited byte less 25 or 12 for status against the catch rate, then a second byte against an HP term; the shakes on a miss are worked out with no roll
Pokémon Yellow1998Two rollsRed and Blue's capture code line for line, plus a Pikachu battle that catches outright
Pokémon Gold and Silver1999Single catch rollCrystal's code: one byte against the catch rate scaled by (3M − 2H)/3M, plus 10 for sleep or freeze and nothing for burn, poison or paralysis
Pokémon Crystal2000Single catch rollone byte against the ball-modified rate scaled by (3M − 2H)/3M plus a sleep or freeze bonus; the wobbles are rolled after the result
Pokémon Ruby and Sapphire2002Four shake checksEmerald's four shake checks, but bad poison gives no status bonus
Pokémon Emerald2004Four shake checksthe ball, HP and status set a rate, and four 16-bit rolls under a threshold near 65535 (a/255)^(1/4) catch; a miss shows the shakes it passed
Pokémon FireRed and LeafGreen2004Four shake checksEmerald's formula and shake checks, plus a dodge in ghost battles
Pokémon Platinum2008Four shake checksEmerald's formula and four shake checks, with the Dusk and Quick Balls added
Pokémon HeartGold and SoulSilver2009Four shake checksPlatinum's formula and four shake checks; the Apricorn balls change the catch rate itself
Every claim about this mechanic, by game (31)
Pokémon Red and Blue 1996A wild Pokémon's catch rate is its species' catch-rate byte, copied into wEnemyMonActualCatchRate when the battle loads it (45 for Bulbasaur). In the Safari Zone, bait halves that copy and a rock doubles it, capped at 255.Code
ItemUseBall first draws a random byte R1: any value for a Poké Ball, redrawn until it is at most 200 for a Great Ball and at most 150 for an Ultra or Safari Ball. A Master Ball catches before the range test.Code
A status subtracts from R1: 25 for sleep or freeze, 12 for any other (burn, paralysis, poison), 0 for none. If R1 is below that value the Pokémon is caught at once; otherwise the ball fails when R1 less the value is greater than the catch rate, and passes on to the HP check when it is not.Code
For the HP check, ItemUseBall computes W=⌊⌊255M/F⌋/max⁡(⌊H/4⌋,1)⌋ from max HP M and current HP H, where the ball factor F is 8 for a Great Ball and 12 for every other ball. A W over 255 catches; otherwise a second random byte R2 catches when it is at most W. The check runs only after the status and catch-rate test has passed.Code
Computed, counting every value of each roll as equally likely: with no status, Red and Blue catch with chance min⁡(C+1,N)N⋅min⁡(W+1,256)256, where N is 256, 201, or 151 values of R1 for a Poké, Great, or Ultra Ball. For a Bulbasaur (catch rate 45) with max HP 100 in a Poké Ball, that is about 6.0% at full HP and 46 in 256 (18.0%) at 1 HP.Code
Computed: because the Great Ball's ball factor is 8 and the Ultra Ball's is 12, a Great Ball can beat an Ultra Ball. With a catch rate of 200 or more, both first rolls always pass, so the Great Ball never catches less often. For a Bulbasaur (catch rate 45) with max HP 100 at full HP and no status, the Great Ball catches about 11.4% of the time and the Ultra Ball about 10.2%.Code
When the ball fails, Red and Blue choose its shakes without a roll: Y=⌊100C/B⌋, with B 255 for a Poké Ball, 200 for a Great Ball, and 150 otherwise; then Z=⌊min⁡(W,255)⋅Y/255⌋, plus 10 for sleep or freeze or 5 for another status. A Z under 10 is a miss ("You missed the Pokémon!"), under 30 one shake, under 70 two, and 70 or more three ("Shoot! It was so close too!").Code
Before any roll, ItemUseBall makes the ball dodge an unidentified ghost and the Restless Soul Marowak on Pokémon Tower 6F, and catches the old man's demonstration Pokémon outright.Code
Pokémon Yellow 1998Yellow runs the same capture code as Red and Blue from the first roll to the shake count: the ranges, the status values, the ball factors, and the shake thresholds match line for line. Before the rolls it adds a Pikachu battle (BATTLE_TYPE_PIKACHU), which takes the old man's branch and catches outright.Code
Pokémon Gold and Silver 1999Gold and Silver run the same capture code as Crystal: from the catch-rate load to the final roll, PokeBallEffect differs only in comments, and the wobble table is identical.Code
Pokémon Crystal 2000A wild Pokémon's catch rate is its species' catch-rate byte, copied into wEnemyMonCatchRate when the battle loads it (45 for Bulbasaur).Code
PokeBallEffect catches outright with a Master Ball or in the catching tutorial. Otherwise a ball's routine changes the catch rate: the Ultra Ball doubles it, and the Great, Safari, and Park Balls add half of it, each capped at 255. The Poké Ball has no routine and leaves it as it is.Code
Except with a Level Ball, PokeBallEffect scales the ball-modified rate C′ by HP: X=max⁡(⌊C′(3M−2H)/3M⌋,1) for max HP M and current HP H. When 3M is 256 or more, both 3M and 2H are first divided by 4 (a quartered 2H of 0 becomes 1) and only each low byte is kept, so the formula breaks for max HP over 341.Code
The Level Ball doubles the catch rate when the player's Pokémon is higher in level than the wild one, quadruples it when half the player's level is still higher, and multiplies it by 8 when a quarter is, capped at 255. It then skips the HP and status steps: its final rate is that multiplied catch rate alone.Code
Crystal adds 10 to X for a sleeping or frozen Pokémon, capped at 255, and nothing for burn, poison, or paralysis: the test meant to add 5 for them reads a value the sleep-and-freeze mask has already cleared. Gold and Silver have the same code, and their disassembly notes that those three statuses were meant to rank between sleep and none.Code
The final rate goes into wFinalCatchRate, and one random byte at most that rate catches, so the chance is (X+1)/256 and a final rate of 255 always catches. This one roll decides the throw; the wobbles come after.Code
Computed, counting every value of the roll as equally likely: a Bulbasaur (catch rate 45) with max HP 100 and no status in a Poké Ball has a final rate of 15 at full HP, so 16 in 256 (6.25%), and 44 at 1 HP, so 45 in 256 (17.6%).Code
The ball's wobbles are drawn after the throw is decided. A caught Pokémon always gets three. On a failed throw, each of up to three wobbles happens with chance p/256, where p is read from the first row of WobbleProbabilities whose catch rate is at least the final rate (63 for a rate of 1, up to 255 for 255). The table's comment gives nLeft/255 = (nRight/255) ** 4, so each p is a fourth root, p/255=(𝑟𝑎𝑡𝑒/255)1/4. The atlas reads that as the chance of passing one of four equal checks whose product is the catch chance; the comment doesn't say so.Code
Pokémon Ruby and Sapphire 2002Ruby 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
Pokémon Emerald 2004Cmd_handleballthrow reads the target species' catch rate (45 for Bulbasaur), except with a Safari Ball, which uses the Safari Zone's catch factor times 1275 / 100; the factor starts at the species' catch rate times 100 / 1275.Code
The ball multiplier is in tenths: 20 for an Ultra Ball, 15 for a Great or Safari Ball, 10 for a Poké Ball; a Net Ball 30 against a Water or Bug type, a Dive Ball 35 underwater, a Nest Ball 40 less the target's level below level 40 (at least 10), a Repeat Ball 30 for a species already caught, a Timer Ball 10 plus the turn count up to 40, and 10 for the Luxury and Premier Balls and for a Net, Dive, Nest, or Repeat Ball outside its condition.Code
Emerald computes a=⌊⌊Cm/10⌋(3M−2H)/3M⌋ from catch rate C, ball multiplier m, max HP M, and current HP H, then doubles it for sleep or freeze, or multiplies it by 15/10 (rounded down) for poison, bad poison, burn, or paralysis.Code
An a over 254 catches at once. Otherwise Emerald turns it into a threshold b=⌊1048560/Sqrt(Sqrt(⌊16711680/a⌋))⌋, with Sqrt the GBA BIOS call, and draws up to four 16-bit Random() values; each one below b is a shake. Four shakes catch; a throw that fails shows the shakes it passed, 0 to 3. A Master Ball's shakes are set to four after the draw.Code
Computed, counting every Random() value as equally likely and taking the BIOS square root as rounding down: a throw catches with chance (b/65536)4 when a≤254. Since 16,711,680 is 255 × 65,536 and 1,048,560 is 16 × 65,535, b is close to 65535(a/255)1/4 and four passes close to a/255, higher for small a because both roots round down. A Bulbasaur (catch rate 45) with max HP 100 in a Poké Ball has a=15 and b=32767 at full HP, about 6.25%, and a=44, b=43690 at 1 HP, about 19.8%.Code
Computed, for a Bulbasaur (catch rate 45) with max HP 100 and no status in a Poké Ball: at full HP it is caught about 6.0% of the time in Red and Blue, 6.25% in Crystal, and 6.25% in Emerald; at 1 HP, 18.0%, 17.6%, and 19.8%. Here the three formulas land close together, though they roll twice in Red and Blue, once in Crystal, and up to four times in Emerald.Code
Pokémon FireRed and LeafGreen 2004FireRed 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
Pokémon Platinum 2008Platinum's BattleScript_CalcCatchShakes keeps Emerald's capture math: the same a=⌊⌊Cm/10⌋(3M−2H)/3M⌋, the same status bonuses (×2 for sleep or freeze; ×15/10 for poison, bad poison, burn, or paralysis), a catch at once when a is 255 or more, and otherwise the threshold b=⌊1048560/⌊16711680/a⌋⌋ with up to four 16-bit rolls, each below b a shake, and the Master Ball's shakes set to four after the draw. The two square roots run on the DS hardware square-root unit (CP_SetSqrt32) instead of Emerald's GBA BIOS call, and both games roll with the same generator, multiplier 1,103,515,245 and increment 24,691, keeping the top 16 bits. A Pal Park battle or the catching tutorial always catches.Code
Platinum keeps Emerald's ball multipliers in tenths (Ultra 20, Great and Safari 15, Poké 10; Net 30 against Water or Bug, Nest 40 less the level below 40 with a floor of 10, Repeat 30, Timer 10 plus the turn count up to 40) and Emerald's 10 for the Luxury and Premier Balls. Two balls have new multipliers: a Dusk Ball gives 35 at night, late at night, or on cave terrain, and a Quick Ball 40 while the battle's turn count (totalTurns) is 0. The Dive Ball's 35 now asks for water terrain (TERRAIN_WATER) where Emerald asks for an underwater map. A Safari Ball multiplies the catch rate by one of 13 fractions from 10/40 to 40/10, picked by a stage that starts at 6 (×1), where Emerald uses a Safari catch factor. The Heal and Cherish Balls, also new, give 10.Code
Pokémon HeartGold and SoulSilver 2009HeartGold and SoulSilver's BattleSystem_CalculateBallShakes keeps Platinum's capture math: a=⌊⌊Cm/10⌋(3M−2H)/3M⌋ for catch rate C, ball multiplier m in tenths, max HP M and current HP H, ×2 for sleep or freeze and ×15/10 for burn, paralysis, poison, or bad poison, a catch at once when a is 255 or more, and otherwise four 16-bit rolls each below ⌊1048560/⌊16711680/a⌋⌋, with the Master Ball's shakes set to four after the draw. The Ultra, Great, Poké, and Safari Balls keep Platinum's 20, 15, 10, and 15 (an assembly data table in the decompilation), and a Pal Park or tutorial battle always catches.Code
In HeartGold and SoulSilver the Apricorn balls change the catch rate itself and leave the multiplier at 10, after which the rate is capped at 255 (a negative one becomes 1) and goes through the usual HP and status steps: the Fast Ball ×4 when the wild species' base Speed is 100 or more, the Level Ball ×2 when the attacking battler's (battlerIdAttacker) level is above the wild Pokémon's, ×4 when half its level (rounded down) is above it, and ×8 when a quarter of its level (rounded down) is, the Lure Ball ×3 when fishing, the Love Ball ×8 for the same species of the opposite gender, and the Moon Ball ×4 for the 14 species of the Nidoran, Clefairy, Jigglypuff, and Skitty families listed in an assembly data table. Crystal's Level Ball skips the HP and status steps, and its disassembly's comments mark the Moon Ball as never boosting, the Love Ball as boosting the same gender, and the Fast Ball as boosting only three species.Code
HeartGold and SoulSilver's Heavy Ball adds 40 to the catch rate at 409.6 kg or more, 30 at 307.2 kg, and 20 at 204.8 kg, reading weight in tenths of a kilogram from the Pokédex data. Below 204.8 kg its last branch tests the catch rate against 1024 instead of the weight, and a catch rate is at most 255, so every lighter Pokémon loses 20 (a result below 0 becomes 1); a comment in the decompilation calls this a mistake. Crystal subtracts 20 only below 102.4 kg and adds nothing from there to 204.8 kg.Code

References

  1. ^Computed, for a Bulbasaur (catch rate 45) with max HP 100 and no status in a Poké Ball: at full HP it is caught about 6.0% of the time in Red and Blue, 6.25% in Crystal, and 6.25% in Emerald; at 1 HP, 18.0%, 17.6%, and 19.8%. Here the three formulas land close together, though they roll twice in Red and Blue, once in Crystal, and up to four times in Emerald.Codepret/pokered · pret/pokecrystal · pret/pokeemeraldrevised
    How we know
    185.loop
    186	call Random
    187	ld b, a
    ⋮
    198	cp POKE_BALL
    199	jr z, .checkForAilments
    
    engine/items/item_effects.asm lines 185–199 at af51989 · upstream ↗
    241; Calculate MaxHP * 255.
    ⋮
    253; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
    ⋮
    284; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
    ⋮
    300; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon.
    301	ld a, [wEnemyMonActualCatchRate]
    302	cp b
    303	jr c, .failedToCapture
    ⋮
    310	call Random ; Let this random number be called Rand2.
    ⋮
    312; If Rand2 > X, the ball fails to capture the Pokémon.
    ⋮
    315	cp b
    316	jr c, .failedToCapture
    
    engine/items/item_effects.asm lines 241–316 at af51989 · upstream ↗
    7	db 45 ; catch rate
    
    data/pokemon/base_stats/bulbasaur.asm line 7 at af51989 · upstream ↗
    289	sla c
    290	rl b
    ⋮
    299	and a
    ⋮
    302	srl d
    303	rr e
    304	srl d
    305	rr e
    306	srl b
    307	rr c
    308	srl b
    309	rr c
    ⋮
    313	and a
    ⋮
    
    engine/items/item_effects.asm lines 289–338 at 97187cd · upstream ↗
    374	ld [wFinalCatchRate], a
    375	call Random
    ⋮
    377	cp b
    378	ld a, 0
    379	jr z, .catch_without_fail
    380	jr nc, .fail_to_catch
    
    engine/items/item_effects.asm lines 372–380 at 97187cd · upstream ↗
    7	db 45 ; catch rate
    
    data/pokemon/base_stats/bulbasaur.asm line 7 at 97187cd · upstream ↗
    9987        odds = (catchRate * ballMultiplier / 10)
    ⋮
    10009        if (odds > 254) // mon caught
    ⋮
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    ⋮
    10028            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    
    src/battle_script_commands.c lines 9987–10028 at 731ad5b · upstream ↗
    845    [ITEM_POKE_BALL - ITEM_ULTRA_BALL]   = 10,
    
    src/battle_script_commands.c line 845 at 731ad5b · upstream ↗
    48        .catchRate = 45,
    
    src/data/pokemon/species_info.h line 48 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  2. ^ abcItemUseBall first draws a random byte R1: any value for a Poké Ball, redrawn until it is at most 200 for a Great Ball and at most 150 for an Ultra or Safari Ball. A Master Ball catches before the range test.Codepret/pokered
    How we know
    177; Get the first random number. Let it be called Rand1.
    ⋮
    185.loop
    186	call Random
    187	ld b, a
    ⋮
    194	cp MASTER_BALL
    195	jp z, .captured
    ⋮
    198	cp POKE_BALL
    199	jr z, .checkForAilments
    ⋮
    202	ld a, 200
    203	cp b
    204	jr c, .loop
    ⋮
    208	cp GREAT_BALL
    ⋮
    
    engine/items/item_effects.asm lines 177–214 at af51989 · upstream ↗

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

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

    In the claim ledger

  3. ^ abcA status subtracts from R1: 25 for sleep or freeze, 12 for any other (burn, paralysis, poison), 0 for none. If R1 is below that value the Pokémon is caught at once; otherwise the ball fails when R1 less the value is greater than the catch rate, and passes on to the HP check when it is not.Codepret/pokered
    How we know
    221; no status ailment:     Status = 0
    222; Burn/Paralysis/Poison: Status = 12
    223; Freeze/Sleep:          Status = 25
    224; If Status is greater than Rand1, the Pokémon will be caught for sure.
    225	ld a, [wEnemyMonStatus]
    226	and a
    227	jr z, .skipAilmentValueSubtraction ; no ailments
    228	and (1 << FRZ) | SLP_MASK
    229	ld c, 12
    230	jr z, .notFrozenOrAsleep
    231	ld c, 25
    232.notFrozenOrAsleep
    ⋮
    
    engine/items/item_effects.asm lines 216–239 at af51989 · upstream ↗
    298	pop bc ; b = Rand1 - Status
    ⋮
    300; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon.
    301	ld a, [wEnemyMonActualCatchRate]
    302	cp b
    303	jr c, .failedToCapture
    
    engine/items/item_effects.asm lines 298–303 at af51989 · upstream ↗

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

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

    In the claim ledger

  4. ^ abcFor the HP check, ItemUseBall computes W=⌊⌊255M/F⌋/max⁡(⌊H/4⌋,1)⌋ from max HP M and current HP H, where the ball factor F is 8 for a Great Ball and 12 for every other ball. A W over 255 catches; otherwise a second random byte R2 catches when it is at most W. The check runs only after the status and catch-rate test has passed.Codepret/pokered
    How we know
    241; Calculate MaxHP * 255.
    ⋮
    253; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
    254	ld a, [wCurItem]
    255	cp GREAT_BALL
    256	ld a, 12
    257	jr nz, .skip1
    258	ld a, 8
    ⋮
    260.skip1
    ⋮
    268; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so
    269; the result should fit in a. If the division results in a quotient of 0,
    270; change it to 1.
    ⋮
    273	ld b, a
    ⋮
    
    engine/items/item_effects.asm lines 241–316 at af51989 · upstream ↗

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

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

    In the claim ledger

  5. ^ abcWhen the ball fails, Red and Blue choose its shakes without a roll: Y=⌊100C/B⌋, with B 255 for a Poké Ball, 200 for a Great Ball, and 150 otherwise; then Z=⌊min⁡(W,255)⋅Y/255⌋, plus 10 for sleep or freeze or 5 for another status. A Z under 10 is a miss ("You missed the Pokémon!"), under 30 one shake, under 70 two, and 70 or more three ("Shoot! It was so close too!").Codepret/pokered
    How we know
    321.failedToCapture
    322	ldh a, [hQuotient + 3]
    323	ld [wPokeBallCaptureCalcTemp], a ; Save X.
    ⋮
    336; Poké Ball:         BallFactor2 = 255
    337; Great Ball:        BallFactor2 = 200
    338; Ultra/Safari Ball: BallFactor2 = 150
    ⋮
    351; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
    ⋮
    377; no status ailment:     Status2 = 0
    378; Burn/Paralysis/Poison: Status2 = 5
    379; Freeze/Sleep:          Status2 = 10
    ⋮
    390	ldh a, [hQuotient + 3]
    ⋮
    398; 0  ≤ Z < 10: 0 shakes (the ball misses)
    ⋮
    
    engine/items/item_effects.asm lines 321–412 at af51989 · upstream ↗
    9_ItemUseBallText01::
    10	text "You missed the"
    11	line "#MON!"
    ⋮
    24_ItemUseBallText04::
    25	text "Shoot! It was so"
    26	line "close too!"
    
    data/text/text_6.asm lines 9–27 at af51989 · upstream ↗

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

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

    In the claim ledger

  6. ^ abComputed: because the Great Ball's ball factor is 8 and the Ultra Ball's is 12, a Great Ball can beat an Ultra Ball. With a catch rate of 200 or more, both first rolls always pass, so the Great Ball never catches less often. For a Bulbasaur (catch rate 45) with max HP 100 at full HP and no status, the Great Ball catches about 11.4% of the time and the Ultra Ball about 10.2%.Codepret/pokered
    How we know
    201; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again.
    202	ld a, 200
    203	cp b
    204	jr c, .loop
    ⋮
    207	ld a, [hl]
    208	cp GREAT_BALL
    209	jr z, .checkForAilments
    ⋮
    211; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again.
    212	ld a, 150
    213	cp b
    214	jr c, .loop
    
    engine/items/item_effects.asm lines 201–214 at af51989 · upstream ↗
    253; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
    254	ld a, [wCurItem]
    255	cp GREAT_BALL
    256	ld a, 12
    257	jr nz, .skip1
    258	ld a, 8
    
    engine/items/item_effects.asm lines 253–259 at af51989 · upstream ↗

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

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

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

    In the claim ledger

  7. ^ abYellow runs the same capture code as Red and Blue from the first roll to the shake count: the ranges, the status values, the ball factors, and the shake thresholds match line for line. Before the rolls it adds a Pikachu battle (BATTLE_TYPE_PIKACHU), which takes the old man's branch and catches outright.Codepret/pokeyellow · pret/pokered
    How we know
    197.loop
    198	call Random
    ⋮
    214	ld a, 200
    215	cp b
    216	jr c, .loop
    ⋮
    225	cp b
    226	jr c, .loop
    ⋮
    241	ld c, 12
    242	jr z, .notFrozenOrAsleep
    243	ld c, 25
    244.notFrozenOrAsleep
    ⋮
    265; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
    ⋮
    
    engine/items/item_effects.asm lines 197–428 at b6696f2 · upstream ↗
    185.loop
    186	call Random
    ⋮
    202	ld a, 200
    203	cp b
    204	jr c, .loop
    ⋮
    213	cp b
    214	jr c, .loop
    ⋮
    229	ld c, 12
    230	jr z, .notFrozenOrAsleep
    231	ld c, 25
    232.notFrozenOrAsleep
    ⋮
    253; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
    ⋮
    
    engine/items/item_effects.asm lines 185–414 at af51989 · upstream ↗
    157	ld a, [wBattleType]
    158	cp BATTLE_TYPE_OLD_MAN
    159	jr z, .oldManBattle
    160	cp BATTLE_TYPE_PIKACHU
    161	jr z, .oldManBattle ; pikachu battle technically old man battle
    ⋮
    164.oldManBattle
    ⋮
    169	ld a, [wBattleType]
    170	cp BATTLE_TYPE_OLD_MAN
    171	jp nz, .captured
    
    engine/items/item_effects.asm lines 157–171 at b6696f2 · upstream ↗

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

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

    In the claim ledger

  8. ^ abGold and Silver run the same capture code as Crystal: from the catch-rate load to the final roll, PokeBallEffect differs only in comments, and the wobble table is identical.Codepret/pokegold · pret/pokecrystalrevised
    How we know
    240	ld a, [wEnemyMonCatchRate]
    241	ld b, a
    ⋮
    272	cp LEVEL_BALL
    273	ld a, b
    274	jp z, .skip_hp_calc
    ⋮
    276	ld a, b
    ⋮
    309	; BUG: Catch rate formula breaks for Pokémon with max HP > 341 (see docs/bugs_and_glitches.md)
    ⋮
    318	ld a, b
    ⋮
    328	ld a, b
    ⋮
    343	ld b, a
    ⋮
    354	ld a, b
    ⋮
    368	ld a, b
    ⋮
    
    engine/items/item_effects.asm lines 240–388 at fc702b6 · upstream ↗
    242	ld a, [wEnemyMonCatchRate]
    243	ld b, a
    ⋮
    274	cp LEVEL_BALL
    275	ld a, b
    276	jp z, .skip_hp_calc
    ⋮
    278	ld a, b
    ⋮
    311	; BUG: Catch rate formula breaks for Pokémon with max HP > 341 (see docs/bugs_and_glitches.md)
    ⋮
    320	ld a, b
    ⋮
    330	ld a, b
    ⋮
    341	ld b, a
    ⋮
    351	ld a, b
    ⋮
    362	ld a, b
    ⋮
    
    engine/items/item_effects.asm lines 242–382 at 97187cd · upstream ↗
    1WobbleProbabilities:
    2; catch rate, chance of wobbling / 255
    3; nLeft/255 = (nRight/255) ** 4
    
    data/battle/wobble_probabilities.asm lines 1–27 at fc702b6 · upstream ↗
    1WobbleProbabilities:
    2; catch rate, chance of wobbling / 255
    3; nLeft/255 = (nRight/255) ** 4
    
    data/battle/wobble_probabilities.asm lines 1–27 at 97187cd · upstream ↗

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

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

    In the claim ledger

  9. ^ abcdeCrystal adds 10 to X for a sleeping or frozen Pokémon, capped at 255, and nothing for burn, poison, or paralysis: the test meant to add 5 for them reads a value the sleep-and-freeze mask has already cleared. Gold and Silver have the same code, and their disassembly notes that those three statuses were meant to rank between sleep and none.Codepret/pokecrystal · pret/pokegold
    How we know
    339.statuscheck
    340; BUG: BRN/PSN/PAR do not affect catch rate (see docs/bugs_and_glitches.md)
    341	ld b, a
    342	ld a, [wEnemyMonStatus]
    343	and 1 << FRZ | SLP_MASK
    344	ld c, 10
    345	jr nz, .addstatus
    346	and a
    347	ld c, 5
    348	jr nz, .addstatus
    349	ld c, 0
    350.addstatus
    ⋮
    
    engine/items/item_effects.asm lines 339–355 at 97187cd · upstream ↗
    337.statuscheck
    338; This routine is buggy. It was intended that SLP and FRZ provide a higher
    339; catch rate than BRN/PSN/PAR, which in turn provide a higher catch rate than
    340; no status effect at all. But instead, it makes BRN/PSN/PAR provide no
    341; benefit.
    ⋮
    344	ld a, [wEnemyMonStatus]
    345	and 1 << FRZ | SLP_MASK
    346	ld c, 10
    347	jr nz, .addstatus
    348	; ld a, [wEnemyMonStatus]
    349	and a
    350	ld c, 5
    ⋮
    
    engine/items/item_effects.asm lines 337–353 at fc702b6 · upstream ↗

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

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

    In the claim ledger

  10. ^ abcPokeBallEffect catches outright with a Master Ball or in the catching tutorial. Otherwise a ball's routine changes the catch rate: the Ultra Ball doubles it, and the Great, Safari, and Park Balls add half of it, each capped at 255. The Poké Ball has no routine and leaves it as it is.Codepret/pokecrystal
    How we know
    242	ld a, [wEnemyMonCatchRate]
    243	ld b, a
    244	ld a, [wBattleType]
    245	cp BATTLETYPE_TUTORIAL
    246	jp z, .catch_without_fail
    247	ld a, [wCurItem]
    248	cp MASTER_BALL
    249	jp z, .catch_without_fail
    250	ld a, [wCurItem]
    ⋮
    252	ld hl, BallMultiplierFunctionTable
    
    engine/items/item_effects.asm lines 242–270 at 97187cd · upstream ↗
    722BallMultiplierFunctionTable:
    ⋮
    725	dbw ULTRA_BALL,  UltraBallMultiplier
    726	dbw GREAT_BALL,  GreatBallMultiplier
    727	dbw SAFARI_BALL, SafariBallMultiplier ; Safari Ball, leftover from RBY
    ⋮
    737UltraBallMultiplier:
    738; multiply catch rate by 2
    739	sla b
    740	ret nc
    741	ld b, $ff
    742	ret
    ⋮
    744SafariBallMultiplier:
    745GreatBallMultiplier:
    ⋮
    
    engine/items/item_effects.asm lines 722–754 at 97187cd · upstream ↗

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

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

    In the claim ledger

  11. ^ abcdeExcept with a Level Ball, PokeBallEffect scales the ball-modified rate C′ by HP: X=max⁡(⌊C′(3M−2H)/3M⌋,1) for max HP M and current HP H. When 3M is 256 or more, both 3M and 2H are first divided by 4 (a quartered 2H of 0 becomes 1) and only each low byte is kept, so the formula breaks for max HP over 341.Codepret/pokecrystal
    How we know
    273	ld a, [wCurItem]
    274	cp LEVEL_BALL
    275	ld a, b
    276	jp z, .skip_hp_calc
    ⋮
    278	ld a, b
    ⋮
    289	sla c
    290	rl b
    ⋮
    292	ld h, d
    293	ld l, e
    294	add hl, de
    295	add hl, de
    ⋮
    298	ld a, d
    ⋮
    
    engine/items/item_effects.asm lines 272–338 at 97187cd · upstream ↗

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

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

    In the claim ledger

  12. ^ abcdThe final rate goes into wFinalCatchRate, and one random byte at most that rate catches, so the chance is (X+1)/256 and a final rate of 255 always catches. This one roll decides the throw; the wobbles come after.Codepret/pokecrystal
    How we know
    372.skip_hp_calc
    373	ld b, a
    374	ld [wFinalCatchRate], a
    375	call Random
    ⋮
    377	cp b
    378	ld a, 0
    379	jr z, .catch_without_fail
    380	jr nc, .fail_to_catch
    ⋮
    382.catch_without_fail
    383	ld a, [wEnemyMonSpecies]
    ⋮
    385.fail_to_catch
    386	ld [wWildMon], a
    
    engine/items/item_effects.asm lines 372–386 at 97187cd · upstream ↗

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

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

    In the claim ledger

  13. ^ abcdThe ball's wobbles are drawn after the throw is decided. A caught Pokémon always gets three. On a failed throw, each of up to three wobbles happens with chance p/256, where p is read from the first row of WobbleProbabilities whose catch rate is at least the final rate (63 for a rate of 1, up to 255 for 255). The table's comment gives nLeft/255 = (nRight/255) ** 4, so each p is a fourth root, p/255=(𝑟𝑎𝑡𝑒/255)1/4. The atlas reads that as the chance of passing one of four equal checks whose product is the catch chance; the comment doesn't say so.Codepret/pokecrystalrevised
    How we know
    1GetPokeBallWobble:
    2; Returns whether a Poke Ball will wobble in the catch animation.
    3; Whether a Pokemon is caught is determined beforehand.
    ⋮
    18; Wobble up to 3 times.
    19	cp 3 + 1
    20	jr z, .finished
    ⋮
    22	ld a, [wWildMon]
    23	and a
    24	ld c, 0 ; next
    25	jr nz, .done
    ⋮
    27	ld hl, WobbleProbabilities
    28	ld a, [wFinalCatchRate]
    ⋮
    
    engine/battle_anims/pokeball_wobble.asm lines 1–44 at 97187cd · upstream ↗
    1WobbleProbabilities:
    2; catch rate, chance of wobbling / 255
    3; nLeft/255 = (nRight/255) ** 4
    4	db   1,  63
    ⋮
    27	db 255, 255
    
    data/battle/wobble_probabilities.asm lines 1–27 at 97187cd · upstream ↗

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

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

    In the claim ledger

  14. ^ abcThe Level Ball doubles the catch rate when the player's Pokémon is higher in level than the wild one, quadruples it when half the player's level is still higher, and multiplies it by 8 when a quarter is, capped at 255. It then skips the HP and status steps: its final rate is that multiplied catch rate alone.Codepret/pokecrystal
    How we know
    1032LevelBallMultiplier:
    1033; multiply catch rate by 8 if player mon level / 4 > enemy mon level
    1034; multiply catch rate by 4 if player mon level / 2 > enemy mon level
    1035; multiply catch rate by 2 if player mon level > enemy mon level
    
    engine/items/item_effects.asm lines 1032–1058 at 97187cd · upstream ↗
    272.skip_or_return_from_ball_fn
    273	ld a, [wCurItem]
    274	cp LEVEL_BALL
    275	ld a, b
    276	jp z, .skip_hp_calc
    
    engine/items/item_effects.asm lines 272–276 at 97187cd · upstream ↗

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

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

    In the claim ledger

  15. ^ abcRuby 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.Codepret/pokeruby · pret/pokeemeraldrevised
    How we know
    9452        odds = (catch_rate * ball_multiplier / 10) * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2) / (3 * gBattleMons[gBattlerTarget].maxHP);
    9453        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
    9454            odds *= 2;
    9455        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS /*| STATUS1_TOXIC_POISON */)) //nice one gf
    9456            odds = (odds * 15) / 10;
    
    src/battle_script_commands.c lines 9452–9456 at 5784633 · upstream ↗
    9484            odds = Sqrt(Sqrt(16711680 / odds));
    9485            odds = 1048560 / odds;
    9486            for (shakes = 0; shakes < 4 && Random() < odds; shakes++) {}
    
    src/battle_script_commands.c lines 9484–9486 at 5784633 · upstream ↗
    1033static const u8 sBallCatchBonuses[] =
    ⋮
    1035    20, 15, 10, 15 // Ultra, Great, Poke, Safari
    
    src/battle_script_commands.c lines 1033–1036 at 5784633 · upstream ↗
    85#define STATUS1_POISON           (1 << 3)
    ⋮
    89#define STATUS1_TOXIC_POISON     (1 << 7)
    
    include/constants/battle.h lines 85–89 at 5784633 · upstream ↗
    9987        odds = (catchRate * ballMultiplier / 10)
    9988            * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
    9989            / (3 * gBattleMons[gBattlerTarget].maxHP);
    ⋮
    9991        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
    9992            odds *= 2;
    9993        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
    9994            odds = (odds * 15) / 10;
    
    src/battle_script_commands.c lines 9987–9994 at 731ad5b · upstream ↗
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    ⋮
    10028            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    
    src/battle_script_commands.c lines 10025–10028 at 731ad5b · upstream ↗
    841static const u8 sBallCatchBonuses[] =
    ⋮
    843    [ITEM_ULTRA_BALL - ITEM_ULTRA_BALL]  = 20,
    844    [ITEM_GREAT_BALL - ITEM_ULTRA_BALL]  = 15,
    845    [ITEM_POKE_BALL - ITEM_ULTRA_BALL]   = 10,
    
    src/battle_script_commands.c lines 841–846 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  16. ^The ball multiplier is in tenths: 20 for an Ultra Ball, 15 for a Great or Safari Ball, 10 for a Poké Ball; a Net Ball 30 against a Water or Bug type, a Dive Ball 35 underwater, a Nest Ball 40 less the target's level below level 40 (at least 10), a Repeat Ball 30 for a species already caught, a Timer Ball 10 plus the turn count up to 40, and 10 for the Luxury and Premier Balls and for a Net, Dive, Nest, or Repeat Ball outside its condition.Codepret/pokeemerald
    How we know
    840// - ITEM_ULTRA_BALL skips Master Ball and ITEM_NONE
    841static const u8 sBallCatchBonuses[] =
    ⋮
    843    [ITEM_ULTRA_BALL - ITEM_ULTRA_BALL]  = 20,
    844    [ITEM_GREAT_BALL - ITEM_ULTRA_BALL]  = 15,
    845    [ITEM_POKE_BALL - ITEM_ULTRA_BALL]   = 10,
    846    [ITEM_SAFARI_BALL - ITEM_ULTRA_BALL] = 15
    
    src/battle_script_commands.c lines 840–847 at 731ad5b · upstream ↗
    9941            case ITEM_NET_BALL:
    9942                if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_BUG))
    9943                    ballMultiplier = 30;
    ⋮
    9945                    ballMultiplier = 10;
    ⋮
    9947            case ITEM_DIVE_BALL:
    9948                if (GetCurrentMapType() == MAP_TYPE_UNDERWATER)
    9949                    ballMultiplier = 35;
    ⋮
    9951                    ballMultiplier = 10;
    ⋮
    9953            case ITEM_NEST_BALL:
    9954                if (gBattleMons[gBattlerTarget].level < 40)
    ⋮
    9956                    ballMultiplier = 40 - gBattleMons[gBattlerTarget].level;
    9957                    if (ballMultiplier <= 9)
    ⋮
    
    src/battle_script_commands.c lines 9937–9985 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  17. ^ abEmerald computes a=⌊⌊Cm/10⌋(3M−2H)/3M⌋ from catch rate C, ball multiplier m, max HP M, and current HP H, then doubles it for sleep or freeze, or multiplies it by 15/10 (rounded down) for poison, bad poison, burn, or paralysis.Codepret/pokeemerald
    How we know
    9987        odds = (catchRate * ballMultiplier / 10)
    9988            * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
    9989            / (3 * gBattleMons[gBattlerTarget].maxHP);
    ⋮
    9991        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
    9992            odds *= 2;
    9993        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
    9994            odds = (odds * 15) / 10;
    
    src/battle_script_commands.c lines 9987–9994 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  18. ^ abcdeAn a over 254 catches at once. Otherwise Emerald turns it into a threshold b=⌊1048560/Sqrt(Sqrt(⌊16711680/a⌋))⌋, with Sqrt the GBA BIOS call, and draws up to four 16-bit Random() values; each one below b is a shake. Four shakes catch; a throw that fails shows the shakes it passed, 0 to 3. A Master Ball's shakes are set to four after the draw.Codepret/pokeemerald
    How we know
    10009        if (odds > 254) // mon caught
    ⋮
    10011            BtlController_EmitBallThrowAnim(B_COMM_TO_CONTROLLER, BALL_3_SHAKES_SUCCESS);
    ⋮
    10018            else
    ⋮
    10021        else // mon may be caught, calculate shakes
    ⋮
    10023            u8 shakes;
    ⋮
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    ⋮
    10028            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    ⋮
    10030            if (gLastUsedItem == ITEM_MASTER_BALL)
    10031                shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check?
    ⋮
    10036            if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above
    ⋮
    10043                else
    ⋮
    
    src/battle_script_commands.c lines 10009–10050 at 731ad5b · upstream ↗
    134enum {
    135    BALL_NO_SHAKES,
    136    BALL_1_SHAKE,
    137    BALL_2_SHAKES,
    138    BALL_3_SHAKES_FAIL,
    139    BALL_3_SHAKES_SUCCESS,
    140    BALL_TRAINER_BLOCK,
    
    include/battle_controllers.h lines 134–141 at 731ad5b · upstream ↗
    11u16 Random(void)
    ⋮
    15    return gRngValue >> 16;
    
    src/random.c lines 11–16 at 731ad5b · upstream ↗
    72	.ifdef L_Sqrt
    73	thumb_func_start Sqrt
    74Sqrt:
    75	svc #8
    
    libagbsyscall/libagbsyscall.s lines 72–78 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  19. ^Computed, counting every Random() value as equally likely and taking the BIOS square root as rounding down: a throw catches with chance (b/65536)4 when a≤254. Since 16,711,680 is 255 × 65,536 and 1,048,560 is 16 × 65,535, b is close to 65535(a/255)1/4 and four passes close to a/255, higher for small a because both roots round down. A Bulbasaur (catch rate 45) with max HP 100 in a Poké Ball has a=15 and b=32767 at full HP, about 6.25%, and a=44, b=43690 at 1 HP, about 19.8%.Codepret/pokeemerald
    How we know
    9987        odds = (catchRate * ballMultiplier / 10)
    9988            * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
    9989            / (3 * gBattleMons[gBattlerTarget].maxHP);
    
    src/battle_script_commands.c lines 9987–9989 at 731ad5b · upstream ↗
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    ⋮
    10028            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    
    src/battle_script_commands.c lines 10025–10028 at 731ad5b · upstream ↗
    48        .catchRate = 45,
    
    src/data/pokemon/species_info.h line 48 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  20. ^ abcdFireRed 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.Codepret/pokefirered · pret/pokeemerald
    How we know
    9473    if (gBattleTypeFlags & BATTLE_TYPE_GHOST)
    ⋮
    9475        BtlController_EmitBallThrowAnim(BUFFER_A, BALL_GHOST_DODGE);
    
    src/battle_script_commands.c lines 9473–9477 at ce6406d · upstream ↗
    9549        odds = (catchRate * ballMultiplier / 10)
    9550            * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
    9551            / (3 * gBattleMons[gBattlerTarget].maxHP);
    ⋮
    9555        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
    9556            odds = (odds * 15) / 10;
    
    src/battle_script_commands.c lines 9549–9556 at ce6406d · upstream ↗
    9587            odds = Sqrt(Sqrt(16711680 / odds));
    9588            odds = 1048560 / odds;
    ⋮
    9590            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    
    src/battle_script_commands.c lines 9587–9590 at ce6406d · upstream ↗
    9987        odds = (catchRate * ballMultiplier / 10)
    ⋮
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    
    src/battle_script_commands.c lines 9987–10028 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  21. ^ abcPlatinum's BattleScript_CalcCatchShakes keeps Emerald's capture math: the same a=⌊⌊Cm/10⌋(3M−2H)/3M⌋, the same status bonuses (×2 for sleep or freeze; ×15/10 for poison, bad poison, burn, or paralysis), a catch at once when a is 255 or more, and otherwise the threshold b=⌊1048560/⌊16711680/a⌋⌋ with up to four 16-bit rolls, each below b a shake, and the Master Ball's shakes set to four after the draw. The two square roots run on the DS hardware square-root unit (CP_SetSqrt32) instead of Emerald's GBA BIOS call, and both games roll with the same generator, multiplier 1,103,515,245 and increment 24,691, keeping the top 16 bits. A Pal Park battle or the catching tutorial always catches.Codepret/pokeplatinum · pret/pokeemeraldrevised
    How we know
    10904static int BattleScript_CalcCatchShakes(BattleSystem *battleSys, BattleContext *battleCtx)
    ⋮
    10906    if (BattleSystem_GetBattleType(battleSys) & BATTLE_TYPE_ALWAYS_CATCH) {
    10907        return BALL_3_SHAKES_SUCCESS;
    
    src/battle/battle_script.c lines 10904–10907 at 49f78f3 · upstream ↗
    56#define BATTLE_TYPE_ALWAYS_CATCH             (BATTLE_TYPE_PAL_PARK | BATTLE_TYPE_CATCH_TUTORIAL)
    
    include/constants/battle.h line 56 at 49f78f3 · upstream ↗
    10978    u32 catchRate = (speciesMod * ballMod / 10)
    10979        * (battleCtx->battleMons[battleCtx->defender].maxHP * 3 - battleCtx->battleMons[battleCtx->defender].curHP * 2)
    10980        / (battleCtx->battleMons[battleCtx->defender].maxHP * 3);
    ⋮
    10982    if (battleCtx->battleMons[battleCtx->defender].status & (MON_CONDITION_SLEEP | MON_CONDITION_FREEZE)) {
    10983        catchRate *= 2;
    ⋮
    10986    if (battleCtx->battleMons[battleCtx->defender].status & (MON_CONDITION_POISON | MON_CONDITION_BURN | MON_CONDITION_PARALYSIS | MON_CONDITION_TOXIC)) {
    10987        catchRate = catchRate * 15 / 10;
    
    src/battle/battle_script.c lines 10978–10988 at 49f78f3 · upstream ↗
    10990    int shakes;
    10991    if (catchRate >= 255) {
    10992        shakes = BALL_3_SHAKES_SUCCESS;
    10993    } else {
    10994        u32 sqrtRate = (0xFF << 16) / catchRate;
    10995        CP_SetSqrt32(sqrtRate);
    10996        CP_WaitSqrt();
    ⋮
    10998        sqrtRate = CP_GetSqrtResult32();
    10999        CP_SetSqrt32(sqrtRate);
    11000        CP_WaitSqrt();
    ⋮
    11002        catchRate = CP_GetSqrtResult32();
    11003        catchRate = (0xFFFF << 4) / catchRate;
    ⋮
    
    src/battle/battle_script.c lines 10990–11013 at 49f78f3 · upstream ↗
    8#define BALL_3_SHAKES_SUCCESS 4
    
    include/constants/battle/battle_script.h line 8 at 49f78f3 · upstream ↗
    1308u16 BattleSystem_RandNext(BattleSystem *battleSys)
    ⋮
    1310    battleSys->seedRandNext = battleSys->seedRandNext * LCRNG_MULTIPLIER + LCRNG_INCREMENT;
    1311    return (u16)(battleSys->seedRandNext / LCRNG_DIVISOR);
    
    src/battle/battle_system.c lines 1308–1312 at 49f78f3 · upstream ↗
    8#define LCRNG_MULTIPLIER 1103515245L
    9#define LCRNG_INCREMENT  24691
    10#define LCRNG_DIVISOR    65536L
    
    include/math_util.h lines 8–10 at 49f78f3 · upstream ↗
    9987        odds = (catchRate * ballMultiplier / 10)
    9988            * (gBattleMons[gBattlerTarget].maxHP * 3 - gBattleMons[gBattlerTarget].hp * 2)
    9989            / (3 * gBattleMons[gBattlerTarget].maxHP);
    ⋮
    9991        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
    9992            odds *= 2;
    9993        if (gBattleMons[gBattlerTarget].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON))
    9994            odds = (odds * 15) / 10;
    ⋮
    9998            if (gLastUsedItem == ITEM_MASTER_BALL)
    ⋮
    10009        if (odds > 254) // mon caught
    ⋮
    10025            odds = Sqrt(Sqrt(16711680 / odds));
    10026            odds = 1048560 / odds;
    ⋮
    10028            for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
    ⋮
    
    src/battle_script_commands.c lines 9987–10031 at 731ad5b · upstream ↗
    20u16 Sqrt(u32 num);
    
    include/gba/syscall.h line 20 at 731ad5b · upstream ↗
    72	.ifdef L_Sqrt
    73	thumb_func_start Sqrt
    74Sqrt:
    75	svc #8
    
    libagbsyscall/libagbsyscall.s lines 72–78 at 731ad5b · upstream ↗
    16#define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691)
    
    include/random.h line 16 at 731ad5b · upstream ↗
    11u16 Random(void)
    ⋮
    13    gRngValue = ISO_RANDOMIZE1(gRngValue);
    ⋮
    15    return gRngValue >> 16;
    
    src/random.c lines 11–16 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  22. ^ abPlatinum keeps Emerald's ball multipliers in tenths (Ultra 20, Great and Safari 15, Poké 10; Net 30 against Water or Bug, Nest 40 less the level below 40 with a floor of 10, Repeat 30, Timer 10 plus the turn count up to 40) and Emerald's 10 for the Luxury and Premier Balls. Two balls have new multipliers: a Dusk Ball gives 35 at night, late at night, or on cave terrain, and a Quick Ball 40 while the battle's turn count (totalTurns) is 0. The Dive Ball's 35 now asks for water terrain (TERRAIN_WATER) where Emerald asks for an underwater map. A Safari Ball multiplies the catch rate by one of 13 fractions from 10/40 to 40/10, picked by a stage that starts at 6 (×1), where Emerald uses a Safari catch factor. The Heal and Cherish Balls, also new, give 10.Codepret/pokeplatinum · pret/pokeemeraldrevised
    How we know
    10868static const u8 sBasicBallMod[] = {
    10869    20, // ITEM_ULTRA_BALL
    10870    15, // ITEM_GREAT_BALL
    10871    10, // ITEM_POKE_BALL
    10872    15, // ITEM_SAFARI_BALL
    ⋮
    10875static const struct Fraction sSafariCatchRate[] = {
    10876    { 10, 40 },
    ⋮
    10882    { 10, 10 },
    ⋮
    10888    { 40, 10 }
    
    src/battle/battle_script.c lines 10868–10889 at 49f78f3 · upstream ↗
    10911    if (battleCtx->msgItemTemp == ITEM_SAFARI_BALL) {
    ⋮
    10913        speciesMod = speciesMod * sSafariCatchRate[battleCtx->safariCatchStage].numerator / sSafariCatchRate[battleCtx->safariCatchStage].denominator;
    ⋮
    10918    u32 ballMod = 10;
    ⋮
    10922    if (battleCtx->msgItemTemp > ITEM_SAFARI_BALL) {
    10923        switch (battleCtx->msgItemTemp) {
    10924        case ITEM_NET_BALL:
    ⋮
    10927                ballMod = 30;
    ⋮
    10931        case ITEM_DIVE_BALL:
    10932            if (BattleSystem_GetTerrain(battleSys) == TERRAIN_WATER) {
    10933                ballMod = 35;
    ⋮
    10937        case ITEM_NEST_BALL:
    10938            if (battleCtx->battleMons[battleCtx->defender].level < 40) {
    ⋮
    
    src/battle/battle_script.c lines 10910–10975 at 49f78f3 · upstream ↗
    2036    battleCtx->safariCatchStage = 6;
    
    src/battle/battle_lib.c line 2036 at 49f78f3 · upstream ↗
    1ITEM_NONE
    2ITEM_MASTER_BALL
    3ITEM_ULTRA_BALL
    4ITEM_GREAT_BALL
    5ITEM_POKE_BALL
    6ITEM_SAFARI_BALL
    7ITEM_NET_BALL
    8ITEM_DIVE_BALL
    9ITEM_NEST_BALL
    10ITEM_REPEAT_BALL
    11ITEM_TIMER_BALL
    12ITEM_LUXURY_BALL
    ⋮
    
    generated/items.txt lines 1–17 at 49f78f3 · upstream ↗
    9932        if (gLastUsedItem == ITEM_SAFARI_BALL)
    9933            catchRate = gBattleStruct->safariCatchFactor * 1275 / 100;
    ⋮
    9941            case ITEM_NET_BALL:
    9942                if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_BUG))
    9943                    ballMultiplier = 30;
    ⋮
    9945                    ballMultiplier = 10;
    ⋮
    9947            case ITEM_DIVE_BALL:
    9948                if (GetCurrentMapType() == MAP_TYPE_UNDERWATER)
    9949                    ballMultiplier = 35;
    ⋮
    9951                    ballMultiplier = 10;
    ⋮
    9953            case ITEM_NEST_BALL:
    9954                if (gBattleMons[gBattlerTarget].level < 40)
    ⋮
    
    src/battle_script_commands.c lines 9932–9985 at 731ad5b · upstream ↗
    8    // Note: If moving ball IDs around, updating FIRST_BALL/LAST_BALL is not sufficient
    ⋮
    10    ITEM_MASTER_BALL,
    ⋮
    19    ITEM_TIMER_BALL,
    20    ITEM_LUXURY_BALL,
    21    ITEM_PREMIER_BALL,
    
    include/constants/items.h lines 8–21 at 731ad5b · upstream ↗
    841static const u8 sBallCatchBonuses[] =
    ⋮
    843    [ITEM_ULTRA_BALL - ITEM_ULTRA_BALL]  = 20,
    844    [ITEM_GREAT_BALL - ITEM_ULTRA_BALL]  = 15,
    845    [ITEM_POKE_BALL - ITEM_ULTRA_BALL]   = 10,
    846    [ITEM_SAFARI_BALL - ITEM_ULTRA_BALL] = 15
    
    src/battle_script_commands.c lines 841–846 at 731ad5b · upstream ↗

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

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

    In the claim ledger

  23. ^ abcHeartGold and SoulSilver's BattleSystem_CalculateBallShakes keeps Platinum's capture math: a=⌊⌊Cm/10⌋(3M−2H)/3M⌋ for catch rate C, ball multiplier m in tenths, max HP M and current HP H, ×2 for sleep or freeze and ×15/10 for burn, paralysis, poison, or bad poison, a catch at once when a is 255 or more, and otherwise four 16-bit rolls each below ⌊1048560/⌊16711680/a⌋⌋, with the Master Ball's shakes set to four after the draw. The Ultra, Great, Poké, and Safari Balls keep Platinum's 20, 15, 10, and 15 (an assembly data table in the decompilation), and a Pal Park or tutorial battle always catches.Codepret/pokeheartgold · pret/pokeplatinum
    How we know
    7145static u32 BattleSystem_CalculateBallShakes(BattleSystem *bsys, BattleContext *ctx) {
    ⋮
    7150    if (BattleSystem_GetBattleType(bsys) & (BATTLE_TYPE_PAL_PARK | BATTLE_TYPE_TUTORIAL)) {
    7151        return BALL_SHAKE_MAX;
    
    src/battle/battle_command.c lines 7145–7152 at 6988158 · upstream ↗
    7290    } else {
    7291        // Item IDs from 2-5: Ultra Ball, Great Ball, Pokeball, Safari Ball.
    7292        ballMultiplier = sStandardBallCatchRates[ctx->itemTemp - 2];
    ⋮
    7295    s32 maxHpTimes3 = ctx->battleMons[ctx->battlerIdTarget].maxHp * 3;
    7296    u32 lostHp = maxHpTimes3 - (ctx->battleMons[ctx->battlerIdTarget].hp * 2);
    ⋮
    7300    u32 baseCatchMultiplier = catchRate * ballMultiplier;
    7301    u32 modifiedCatchRate = ((baseCatchMultiplier / 10) * lostHp) / maxHpTimes3;
    ⋮
    7303    s32 status = ctx->battleMons[ctx->battlerIdTarget].status;
    7304    if ((STATUS_SLEEP | STATUS_FREEZE) & status) {
    7305        modifiedCatchRate *= 2;
    ⋮
    7307    if ((STATUS_BURN | STATUS_PARALYSIS | STATUS_BAD_POISON | STATUS_POISON) & status) {
    7308        modifiedCatchRate = (modifiedCatchRate * 15) / 10;
    ⋮
    
    src/battle/battle_command.c lines 7290–7327 at 6988158 · upstream ↗
    721#define BALL_SHAKE_MAX 4
    
    include/constants/battle.h line 721 at 6988158 · upstream ↗
    17sStandardBallCatchRates: ; 0x0226C2EC
    18	.byte 20, 15, 10, 15
    
    asm/overlay_12_battle_command.s lines 17–18 at 6988158 · upstream ↗
    1112u16 BattleSystem_Random(BattleSystem *battleSystem) {
    1113    battleSystem->rand = battleSystem->rand * 1103515245L + 24691;
    1114    return battleSystem->rand / 65536L;
    
    src/battle/battle_system.c lines 1112–1114 at 6988158 · upstream ↗
    10978    u32 catchRate = (speciesMod * ballMod / 10)
    10979        * (battleCtx->battleMons[battleCtx->defender].maxHP * 3 - battleCtx->battleMons[battleCtx->defender].curHP * 2)
    10980        / (battleCtx->battleMons[battleCtx->defender].maxHP * 3);
    ⋮
    10982    if (battleCtx->battleMons[battleCtx->defender].status & (MON_CONDITION_SLEEP | MON_CONDITION_FREEZE)) {
    10983        catchRate *= 2;
    ⋮
    10986    if (battleCtx->battleMons[battleCtx->defender].status & (MON_CONDITION_POISON | MON_CONDITION_BURN | MON_CONDITION_PARALYSIS | MON_CONDITION_TOXIC)) {
    10987        catchRate = catchRate * 15 / 10;
    
    src/battle/battle_script.c lines 10978–10988 at 49f78f3 · upstream ↗
    10991    if (catchRate >= 255) {
    10992        shakes = BALL_3_SHAKES_SUCCESS;
    10993    } else {
    10994        u32 sqrtRate = (0xFF << 16) / catchRate;
    ⋮
    11003        catchRate = (0xFFFF << 4) / catchRate;
    ⋮
    11011        if (battleCtx->msgItemTemp == ITEM_MASTER_BALL) {
    11012            shakes = BALL_3_SHAKES_SUCCESS;
    
    src/battle/battle_script.c lines 10990–11013 at 49f78f3 · upstream ↗
    10868static const u8 sBasicBallMod[] = {
    10869    20, // ITEM_ULTRA_BALL
    10870    15, // ITEM_GREAT_BALL
    10871    10, // ITEM_POKE_BALL
    10872    15, // ITEM_SAFARI_BALL
    
    src/battle/battle_script.c lines 10868–10873 at 49f78f3 · upstream ↗

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

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

    In the claim ledger

  24. ^ abcIn HeartGold and SoulSilver the Apricorn balls change the catch rate itself and leave the multiplier at 10, after which the rate is capped at 255 (a negative one becomes 1) and goes through the usual HP and status steps: the Fast Ball ×4 when the wild species' base Speed is 100 or more, the Level Ball ×2 when the attacking battler's (battlerIdAttacker) level is above the wild Pokémon's, ×4 when half its level (rounded down) is above it, and ×8 when a quarter of its level (rounded down) is, the Lure Ball ×3 when fishing, the Love Ball ×8 for the same species of the opposite gender, and the Moon Ball ×4 for the 14 species of the Nidoran, Clefairy, Jigglypuff, and Skitty families listed in an assembly data table. Crystal's Level Ball skips the HP and status steps, and its disassembly's comments mark the Moon Ball as never boosting, the Love Ball as boosting the same gender, and the Fast Ball as boosting only three species.Codepret/pokeheartgold · pret/pokecrystalrevised
    How we know
    7218        // All the apricorn balls directly alter catchRate instead of setting ballMultiplier.
    ⋮
    7221        case ITEM_FAST_BALL: {
    7222            u32 speed = GetMonBaseStat(ctx->battleMons[ctx->battlerIdTarget].species, BASE_SPEED);
    7223            if (speed >= 100) {
    7224                catchRate *= 4;
    ⋮
    7228        case ITEM_LEVEL_BALL: {
    7229            u8 attackerLevel = ctx->battleMons[ctx->battlerIdAttacker].level;
    7230            u8 defenderLevel = ctx->battleMons[ctx->battlerIdTarget].level;
    7231            if (attackerLevel <= defenderLevel) {
    7232            } else if (attackerLevel / 2 <= defenderLevel) {
    7233                catchRate *= 2;
    7234            } else if (attackerLevel / 4 <= defenderLevel) {
    ⋮
    
    src/battle/battle_command.c lines 7218–7245 at 6988158 · upstream ↗
    7260        case ITEM_LOVE_BALL: {
    7261            if (ctx->battleMons[ctx->battlerIdAttacker].species == ctx->battleMons[ctx->battlerIdTarget].species && ctx->battleMons[ctx->battlerIdAttacker].gender != ctx->battleMons[ctx->battlerIdTarget].gender) {
    7262                catchRate *= 8;
    ⋮
    7266        case ITEM_MOON_BALL: {
    ⋮
    7268            for (i = 0; i < NELEMS(sMoonBallPokemon); i++) {
    7269                if (sMoonBallPokemon[i] == ctx->battleMons[ctx->battlerIdTarget].species) {
    7270                    catchRate *= 4;
    ⋮
    7285        if (catchRate > 0xFF) {
    7286            catchRate = 0xFF;
    7287        } else if (catchRate < 0) {
    7288            catchRate = 1;
    
    src/battle/battle_command.c lines 7259–7288 at 6988158 · upstream ↗
    7161    ballMultiplier = 10; // All ball multipliers are /10, so this is x1.
    ⋮
    7165    if (ctx->itemTemp > ITEM_SAFARI_BALL) { // Skip all balls that have no condition.
    
    src/battle/battle_command.c lines 7161–7166 at 6988158 · upstream ↗
    132sMoonBallPokemon: ; 0x0226C3E8
    133	.short SPECIES_NIDORAN_F
    134	.short SPECIES_NIDORINA
    135	.short SPECIES_NIDOQUEEN
    136	.short SPECIES_NIDORAN_M
    137	.short SPECIES_NIDORINO
    138	.short SPECIES_NIDOKING
    139	.short SPECIES_CLEFFA
    140	.short SPECIES_CLEFAIRY
    141	.short SPECIES_CLEFABLE
    142	.short SPECIES_IGGLYBUFF
    143	.short SPECIES_JIGGLYPUFF
    ⋮
    
    asm/overlay_12_battle_command.s lines 132–146 at 6988158 · upstream ↗
    272.skip_or_return_from_ball_fn
    273	ld a, [wCurItem]
    274	cp LEVEL_BALL
    275	ld a, b
    276	jp z, .skip_hp_calc
    
    engine/items/item_effects.asm lines 272–276 at 97187cd · upstream ↗
    917; BUG: Moon Ball does not boost catch rate (see docs/bugs_and_glitches.md)
    ⋮
    925	cp MOON_STONE_RED ; BURN_HEAL
    
    engine/items/item_effects.asm lines 917–925 at 97187cd · upstream ↗
    977; BUG: Love Ball boosts catch rate for the wrong gender (see docs/bugs_and_glitches.md)
    978	ld a, d
    979	pop de
    980	cp d
    981	pop bc
    982	ret nz
    
    engine/items/item_effects.asm lines 977–982 at 97187cd · upstream ↗
    1001FastBallMultiplier:
    1002	ld a, [wTempEnemyMonSpecies]
    1003	ld c, a
    1004	ld hl, FleeMons
    1005	ld d, 3
    ⋮
    1008; BUG: Fast Ball only boosts catch rate for three Pokémon (see docs/bugs_and_glitches.md)
    
    engine/items/item_effects.asm lines 1001–1008 at 97187cd · upstream ↗

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

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

    In the claim ledger

  25. ^ abHeartGold and SoulSilver's Heavy Ball adds 40 to the catch rate at 409.6 kg or more, 30 at 307.2 kg, and 20 at 204.8 kg, reading weight in tenths of a kilogram from the Pokédex data. Below 204.8 kg its last branch tests the catch rate against 1024 instead of the weight, and a catch rate is at most 255, so every lighter Pokémon loses 20 (a result below 0 becomes 1); a comment in the decompilation calls this a mistake. Crystal subtracts 20 only below 102.4 kg and adds nothing from there to 204.8 kg.Codepret/pokeheartgold · pret/pokecrystal
    How we know
    7246        case ITEM_HEAVY_BALL: {
    7247            s32 weight = GetMonWeight(ctx->battleMons[ctx->battlerIdTarget].species);
    7248            // Weight is in kilograms, moved to the left by 1 decimal point.
    7249            if (weight >= 4096) { // 409.6 kg / 903.0 lbs. or more.
    7250                catchRate += 40;
    7251            } else if (weight >= 3072) { // 307.2 kg / 677.3 lbs. or more.
    7252                catchRate += 30;
    7253            } else if (weight >= 2048) { // 204.8 kg / 451.5 lbs. or more.
    7254                catchRate += 20;
    7255            } else if (catchRate < 1024) { // Catch rate is mistakenly checked here instead of weight, causing all Pokemon that do not benefit from the Heavy Ball to be penalized by it.
    7256                catchRate -= 20;
    
    src/battle/battle_command.c lines 7246–7260 at 6988158 · upstream ↗
    7286            catchRate = 0xFF;
    7287        } else if (catchRate < 0) {
    7288            catchRate = 1;
    
    src/battle/battle_command.c lines 7286–7288 at 6988158 · upstream ↗
    779HeavyBallMultiplier:
    780; subtract 20 from catch rate if weight < 102.4 kg
    781; else add 0 to catch rate if weight < 204.8 kg
    782; else add 20 to catch rate if weight < 307.2 kg
    783; else add 30 to catch rate if weight < 409.6 kg
    784; else add 40 to catch rate
    
    engine/items/item_effects.asm lines 779–784 at 97187cd · upstream ↗
    843	cp HIGH(1024) ; 102.4 kg
    844	jr c, .lightmon
    ⋮
    857	ld a, b
    ⋮
    859	ld b, a
    860	ret nc
    ⋮
    862	ret
    ⋮
    864.lightmon
    865	ld a, b
    866	sub 20
    867	ld b, a
    868	ret nc
    869	ld b, $1
    ⋮
    
    engine/items/item_effects.asm lines 843–870 at 97187cd · upstream ↗

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

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

    In the claim ledger

Sources

Code