Capture
A throw that may add a wild monster to the player's party, using a chance set by the target, its condition, and the item.
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, Yellow | Gold and Silver, Crystal | Ruby and Sapphire onward | |
|---|---|---|---|
| Catch decision | A 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 throw | The 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
| Game | Year | How | Note |
|---|---|---|---|
| Pokémon Red and Blue | 1996 | Two rolls | 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 |
| Pokémon Yellow | 1998 | Two rolls | Red and Blue's capture code line for line, plus a Pikachu battle that catches outright |
| Pokémon Gold and Silver | 1999 | Single catch roll | 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 |
| Pokémon Crystal | 2000 | Single catch roll | 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 |
| Pokémon Ruby and Sapphire | 2002 | Four shake checks | Emerald's four shake checks, but bad poison gives no status bonus |
| Pokémon Emerald | 2004 | Four shake checks | 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 |
| Pokémon FireRed and LeafGreen | 2004 | Four shake checks | Emerald's formula and shake checks, plus a dodge in ghost battles |
| Pokémon Platinum | 2008 | Four shake checks | Emerald's formula and four shake checks, with the Dusk and Quick Balls added |
| Pokémon HeartGold and SoulSilver | 2009 | Four shake checks | Platinum's formula and four shake checks; the Apricorn balls change the catch rate itself |
Every claim about this mechanic, by game (31)
References
- ^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 ratedata/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 ratedata/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.
- ^ abc
ItemUseBallfirst draws a random byte : 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/pokeredHow 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.
- ^ abcA status subtracts from : 25 for sleep or freeze, 12 for any other (burn, paralysis, poison), 0 for none. If is below that value the Pokémon is caught at once; otherwise the ball fails when 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.
- ^ abcFor the HP check,
ItemUseBallcomputes from max HP and current HP , where the ball factor is 8 for a Great Ball and 12 for every other ball. A over 255 catches; otherwise a second random byte catches when it is at most . The check runs only after the status and catch-rate test has passed.Codepret/pokeredHow 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.
- ^ abcWhen the ball fails, Red and Blue choose its shakes without a roll: , with 255 for a Poké Ball, 200 for a Great Ball, and 150 otherwise; then , plus 10 for sleep or freeze or 5 for another status. A 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.
- ^ 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.
- ^ 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/pokeredHow 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.
- ^ abGold and Silver run the same capture code as Crystal: from the catch-rate load to the final roll,
PokeBallEffectdiffers only in comments, and the wobble table is identical.Codepret/pokegold · pret/pokecrystalrevisedHow 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.
- ^ abcdeCrystal adds 10 to 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.
- ^ abc
PokeBallEffectcatches 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/pokecrystalHow 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.
- ^ abcdeExcept with a Level Ball,
PokeBallEffectscales the ball-modified rate by HP: for max HP and current HP . When is 256 or more, both and are first divided by 4 (a quartered of 0 becomes 1) and only each low byte is kept, so the formula breaks for max HP over 341.Codepret/pokecrystalHow 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.
- ^ abcdThe final rate goes into
wFinalCatchRate, and one random byte at most that rate catches, so the chance is and a final rate of 255 always catches. This one roll decides the throw; the wobbles come after.Codepret/pokecrystalHow 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.
- ^ 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 , where is read from the first row of
WobbleProbabilitieswhose catch rate is at least the final rate (63 for a rate of 1, up to 255 for 255). The table's comment givesnLeft/255 = (nRight/255) ** 4, so each is a fourth root, . 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/pokecrystalrevisedHow 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.
- ^ 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.
- ^ 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/pokeemeraldrevisedHow 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.
- ^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.
- ^ abEmerald computes from catch rate , ball multiplier , max HP , and current HP , 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.
- ^ abcdeAn over 254 catches at once. Otherwise Emerald turns it into a threshold , with
Sqrtthe GBA BIOS call, and draws up to four 16-bitRandom()values; each one below 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/pokeemeraldHow 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.
- ^Computed, counting every
Random()value as equally likely and taking the BIOS square root as rounding down: a throw catches with chance when . Since 16,711,680 is 255 × 65,536 and 1,048,560 is 16 × 65,535, is close to and four passes close to , higher for small because both roots round down. A Bulbasaur (catch rate 45) with max HP 100 in a Poké Ball has and at full HP, about 6.25%, and , at 1 HP, about 19.8%.Codepret/pokeemeraldHow 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.
- ^ 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_GHOSTis dodged.Codepret/pokefirered · pret/pokeemeraldHow 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.
- ^ abcPlatinum's
BattleScript_CalcCatchShakeskeeps Emerald's capture math: the same , the same status bonuses (×2 for sleep or freeze; ×15/10 for poison, bad poison, burn, or paralysis), a catch at once when is 255 or more, and otherwise the threshold with up to four 16-bit rolls, each below 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/pokeemeraldrevisedHow 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 4include/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.
- ^ 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/pokeemeraldrevisedHow 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.
- ^ abcHeartGold and SoulSilver's
BattleSystem_CalculateBallShakeskeeps Platinum's capture math: for catch rate , ball multiplier in tenths, max HP and current HP , ×2 for sleep or freeze and ×15/10 for burn, paralysis, poison, or bad poison, a catch at once when is 255 or more, and otherwise four 16-bit rolls each below , 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/pokeplatinumHow 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 4include/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.
- ^ 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/pokecrystalrevisedHow 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.
- ^ 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.
Sources
Code
- pret contributors. 2026. “pokered: disassembly of Pokémon Red and Blue.” pret. Commit af51989. pret/pokered @ af51989 · licence, all uses
- pret contributors. 2026. “pokecrystal: disassembly of Pokémon Crystal.” pret. Commit 97187cd. pret/pokecrystal @ 97187cd · licence, all uses
- pret contributors. 2026. “pokeemerald: decompilation of Pokémon Emerald.” pret. Commit 731ad5b. pret/pokeemerald @ 731ad5b · licence, all uses
- pret contributors. 2026. “pokegold: disassembly of Pokémon Gold and Silver.” pret. Commit fc702b6. pret/pokegold @ fc702b6 · licence, all uses
- pret contributors. 2026. “pokeyellow: disassembly of Pokémon Yellow.” pret. Commit b6696f2. pret/pokeyellow @ b6696f2 · licence, all uses
- pret contributors. 2026. “pokeruby: decompilation of Pokémon Ruby and Sapphire.” pret. Commit 5784633. pret/pokeruby @ 5784633 · licence, all uses
- pret contributors. 2026. “pokefirered: decompilation of Pokémon FireRed and LeafGreen.” pret. Commit ce6406d. pret/pokefirered @ ce6406d · licence, all uses
- pret contributors. 2026. “pokeplatinum: decompilation of Pokémon Platinum.” pret. Commit 49f78f3. pret/pokeplatinum @ 49f78f3 · licence, all uses
- pret contributors. 2026. “pokeheartgold: decompilation of Pokémon HeartGold and SoulSilver.” pret. Commit 6988158. pret/pokeheartgold @ 6988158 · licence, all uses