Claim set · data/claims/pokecrystal-capture.yaml

Pokémon Crystal's capture formula (pret/pokecrystal)

Game: Pokémon Crystal. Concept: Capture.

A wild Pokémon's catch rate is its species' catch-rate byte, copied into wEnemyMonCatchRate when the battle loads it (45 for Bulbasaur). pokecrystal-capture/catch-rate

Codepokecrystal: disassembly of Pokémon Crystal · engine/battle/core.asm#L6383-L6385ld a, [wBaseCatchRate] ld [de], a inc depokecrystal: disassembly of Pokémon Crystal · data/pokemon/base_stats/bulbasaur.asm#L7db 45 ; catch rateChecked by claude, 2026-10-22 — read the end of LoadEnemyMon (L6370-L6386): after the five base stats it writes wBaseCatchRate into the next byte, which ram/wram.asm L2714-L2715 names wEnemyMonCatchRate

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. pokecrystal-capture/ball-modifier

Value
{
 "kind": "ball-modifier",
 "ultra": "2C",
 "great": "C + floor(C/2)",
 "safari": "C + floor(C/2)",
 "park": "C + floor(C/2)",
 "poke": "C",
 "cap": 255,
 "master": "caught"
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L242-L270ld a, [wEnemyMonCatchRate] ld b, a ld a, [wBattleType] cp BATTLETYPE_TUTORIAL jp z, .catch_without_fail ld a, [wCurItem] cp MASTER_BALL jp z, .catch_without_fail … ld hl, BallMultiplierFunctionTablepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L722-L754BallMultiplierFunctionTable: … dbw ULTRA_BALL, UltraBallMultiplier dbw GREAT_BALL, GreatBallMultiplier dbw SAFARI_BALL, SafariBallMultiplier ; Safari Ball, leftover from RBY … UltraBallMultiplier: ; multiply catch rate by 2 sla b ret nc ld b, $ff ret …Checked by claude, 2026-10-22 — read the two outright-catch tests, the table walk (a ball not in the table, such as POKE_BALL, reaches -1 and skips to .skip_or_return_from_ball_fn with b unchanged), and the Ultra and Great routines with their carry caps

Cited by: Capture

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. pokecrystal-capture/hp-term

Value
{
 "kind": "hp-term",
 "maxFactor": 3,
 "hpFactor": 2,
 "quarterAbove": 255,
 "min": 1
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L272-L338ld a, [wCurItem] cp LEVEL_BALL ld a, b jp z, .skip_hp_calc … sla c rl b ld h, d ld l, e add hl, de add hl, de … …Checked by claude, 2026-10-22 — traced the registers: bc = current HP doubled (sla c / rl b), de = max HP tripled (hl = de + de + de); if d is nonzero both are shifted right twice and a zero c is raised to 1; b = e, then C' × (b - c) / b with a zero quotient raised to 1. The max HP > 341 bug is pret's comment, and 3 × 342 / 4 = 256 overflows a byte

Cited by: Capture

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. pokecrystal-capture/level-ball

Value
{
 "kind": "ball-modifier",
 "levelBall": [
  2,
  4,
  8
 ],
 "cap": 255,
 "skipsHP": true
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L1032-L1058LevelBallMultiplier: ; multiply catch rate by 8 if player mon level / 4 > enemy mon level ; multiply catch rate by 4 if player mon level / 2 > enemy mon level ; multiply catch rate by 2 if player mon level > enemy mon levelpokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L272-L276.skip_or_return_from_ball_fn ld a, [wCurItem] cp LEVEL_BALL ld a, b jp z, .skip_hp_calcChecked by claude, 2026-10-22 — read LevelBallMultiplier (three level compares, each sla b with a carry cap) and the jump: ld a, b leaves the flags from cp LEVEL_BALL, so a Level Ball jumps to .skip_hp_calc with the multiplied rate, past the HP term (L278-L338) and the status bonus (L340-L355)

Cited by: Capture

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. pokecrystal-capture/status-bonus

Value
{
 "kind": "status-add",
 "sleepOrFreeze": 10,
 "burnParalysisPoison": 0,
 "intended": 5,
 "cap": 255
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L339-L355.statuscheck ; BUG: BRN/PSN/PAR do not affect catch rate (see docs/bugs_and_glitches.md) ld b, a ld a, [wEnemyMonStatus] and 1 << FRZ | SLP_MASK ld c, 10 jr nz, .addstatus and a ld c, 5 jr nz, .addstatus ld c, 0 .addstatus …pokegold: disassembly of Pokémon Gold and Silver · engine/items/item_effects.asm#L337-L353.statuscheck ; This routine is buggy. It was intended that SLP and FRZ provide a higher ; catch rate than BRN/PSN/PAR, which in turn provide a higher catch rate than ; no status effect at all. But instead, it makes BRN/PSN/PAR provide no ; benefit. … and 1 << FRZ | SLP_MASK ld c, 10 jr nz, .addstatus ; ld a, [wEnemyMonStatus] and a ld c, 5 …Checked by claude, 2026-10-22 — read both: after and 1 << FRZ | SLP_MASK falls through (zero), a is already 0, so and a is zero and c becomes 0; Gold's copy is the same instructions with the fixing load commented out

Cited by: Capture

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. pokecrystal-capture/roll

Value
{
 "kind": "single-roll",
 "range": [
  0,
  255
 ],
 "catchIf": "Random() <= X"
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L372-L386.skip_hp_calc ld b, a ld [wFinalCatchRate], a call Random cp b ld a, 0 jr z, .catch_without_fail jr nc, .fail_to_catch .catch_without_fail ld a, [wEnemyMonSpecies] .fail_to_catch ld [wWildMon], aChecked by claude, 2026-10-22 — read the compare: equal jumps to the catch, a larger byte (no carry) fails, a smaller one falls through to the catch; wWildMon then holds the species or 0, and the animation that follows reads it

Cited by: Capture

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%). pokecrystal-capture/chance

Value
{
 "kind": "example",
 "catchRate": 45,
 "maxHP": 100,
 "ball": "poke",
 "status": "none",
 "fullHP": 0.0625,
 "oneHP": 0.1758
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L289-L338sla c rl b … srl d rr e srl d rr e srl b rr c srl b rr c … …pokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L372-L380call Random cp b ld a, 0 jr z, .catch_without_fail jr nc, .fail_to_catchpokecrystal: disassembly of Pokémon Crystal · data/pokemon/base_stats/bulbasaur.asm#L7db 45 ; catch rateChecked by claude, 2026-10-22 — 3M = 300 has a high byte, so it becomes 75; at full HP 2H = 200 becomes 50, X = floor(45 × 25 / 75) = 15; at 1 HP 2H = 2 becomes 0, raised to 1, X = floor(45 × 74 / 75) = 44; the roll passes for X + 1 of 256 bytes

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. pokecrystal-capture/wobbles

Value
{
 "kind": "wobble-table",
 "maxWobbles": 3,
 "rows": [
  [
   1,
   63
  ],
  [
   2,
   75
  ],
  [
   3,
   84
  ],
  [
   4,
   90
  ],
  [
   5,
   95
  ],
  [
   7,
   103
  ],
  [
   10,
   113
  ],
  [
   15,
   126
  ],
  [
   20,
   134
  ],
  [
   30,
   149
  ],
  [
   40,
   160
  ],
  [
   50,
   169
  ],
  [
   60,
   177
  ],
  [
   80,
   191
  ],
  [
   100,
   201
  ],
  [
   120,
   211
  ],
  [
   140,
   220
  ],
  [
   160,
   227
  ],
  [
   180,
   234
  ],
  [
   200,
   240
  ],
  [
   220,
   246
  ],
  [
   240,
   251
  ],
  [
   254,
   253
  ],
  [
   255,
   255
  ]
 ]
}
Codepokecrystal: disassembly of Pokémon Crystal · engine/battle_anims/pokeball_wobble.asm#L1-L44GetPokeBallWobble: ; Returns whether a Poke Ball will wobble in the catch animation. ; Whether a Pokemon is caught is determined beforehand. … ; Wobble up to 3 times. cp 3 + 1 jr z, .finished ld a, [wWildMon] and a ld c, 0 ; next jr nz, .done ld hl, WobbleProbabilities …pokecrystal: disassembly of Pokémon Crystal · data/battle/wobble_probabilities.asm#L1-L27WobbleProbabilities: ; catch rate, chance of wobbling / 255 ; nLeft/255 = (nRight/255) ** 4 db 1, 63 … db 255, 255Checked by claude, 2026-10-22 — read GetPokeBallWobble: a nonzero wWildMon (caught) returns "next" until the count reaches 4 and .finished returns caught; otherwise the table walk stops at the first row with rate ≥ the final rate and a byte below p wobbles. Every row of the table copied into value

Cited by: Capture

Gold 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. pokecrystal-capture/gold-silver-same

About: Pokémon Gold and Silver Capture

Codepokegold: disassembly of Pokémon Gold and Silver · engine/items/item_effects.asm#L240-L388ld a, [wEnemyMonCatchRate] ld b, a … cp LEVEL_BALL ld a, b jp z, .skip_hp_calc … ; BUG: Catch rate formula breaks for Pokémon with max HP > 341 (see docs/bugs_and_glitches.md) … .skip_hp_calc ld b, a ld [wFinalCatchRate], a …pokecrystal: disassembly of Pokémon Crystal · engine/items/item_effects.asm#L242-L382ld a, [wEnemyMonCatchRate] ld b, a … cp LEVEL_BALL ld a, b jp z, .skip_hp_calc … ; BUG: Catch rate formula breaks for Pokémon with max HP > 341 (see docs/bugs_and_glitches.md) … .skip_hp_calc ld b, a ld [wFinalCatchRate], a …pokegold: disassembly of Pokémon Gold and Silver · data/battle/wobble_probabilities.asm#L1-L27WobbleProbabilities: ; catch rate, chance of wobbling / 255 ; nLeft/255 = (nRight/255) ** 4pokecrystal: disassembly of Pokémon Crystal · data/battle/wobble_probabilities.asm#L1-L27WobbleProbabilities: ; catch rate, chance of wobbling / 255 ; nLeft/255 = (nRight/255) ** 4Checked by claude, 2026-10-22 — diffed PokeBallEffect from its label to .catch_without_fail between the pinned pokecrystal and pokegold: the only differences are comment lines (the BUG notes, and Gold's commented-out fixes); diffed the two wobble tables (identical) and the wobble routines (Gold returns directly instead of restoring a WRAM bank)

Cited by: Capture