AtlasGB · Corrections
TACKLE is 95 per cent and we said 94
A section of ours literally headed "two things the cartridge settled" recorded that TACKLE's accuracy byte is 240 — 94%, where the community usually quotes 95. It is 242. The claim had propagated into a policy document, a Rust module's doc comments and a project memory file.
No run was affected — the code was reading the cartridge all along. Only the prose was wrong.
It was found by re-reading the move table while writing a page about discoveries, on the grounds that a page about discoveries which repeats a number without checking it is not worth having.
Read the table, and check the rows nobody disputes first
Six bytes per move, straight out of the cartridge:
| Move | Id | Power | Accuracy byte | As a percentage |
|---|---|---|---|---|
| POUND | 1 | 40 | 255 | 100% |
| SCRATCH | 10 | 40 | 255 | 100% |
| VINE WHIP | 22 | 35 | 255 | 100% |
| TACKLE | 33 | 35 | 242 | 94.9% |
| HYPER BEAM | 63 | 150 | 229 | 89.8% |
| HYDRO PUMP | 56 | 120 | 204 | 80.0% |
Every row but the one under investigation matches the values Generation 1 is known for. That is what says the table is being read at the right offset with the right stride.
python3 - "$ROM" <<'PY'
import sys
rom = open(sys.argv[1], 'rb').read()
e = 0x0E * 0x4000 + (33 - 1) * 6 # Moves, 0E:4000, TACKLE is move 33
print("power %d accuracy %d (%.1f%%)" % (rom[e+2], rom[e+4], rom[e+4] * 100 / 255))
PY
# power 35 accuracy 242 (94.9%)
$ROM at yours.
Where 240 came from
94% of 255 is 239.7, which rounds to 240. It is the byte you get by computing it from a percentage you already believed, instead of reading it.
When you write down a number the cartridge holds, write down the command that reads it.
And the accuracy byte is not the accuracy anyway
The hit calculation scales a move's accuracy byte by the attacker's accuracy stage and the inverse of the defender's evasion stage. A policy reading the ROM value is reading a number that has not been true since the first SAND-ATTACK landed.
A Pidgey's SAND-ATTACK takes a 95% TACKLE to 62% and then 47%. Both ratios come out of a stage-modifier table read from the cartridge, located by searching for its own opening bytes — a signature that occurs exactly once — and re-checked on every read against two properties: the first pair must be 0.25, and the middle pair must be exactly 1:1, because a table read from the wrong place almost never has a neutral stage in its middle.
Found only at N = 3,000
Three of 3,000 attempts at one scenario died in the same shape: at 2 HP against a Pokémon on 1 HP, the driver swung rather than escaped, because a good roll would end it first. Two separate 600-attempt runs were clean. The bug was not rare in the mechanic, it was rare in the route — it needs a Pidgey that has had time to use SAND-ATTACK twice.
There is a second trap underneath it, and the atlas carries its own warning about it: in the stat-stage block, 7 is neutral, not 0, and the block is zeroed work RAM until the battle-init routine writes the sevens. A sample taken on the first frames of a battle reads 0 everywhere and looks like every stat six stages down.
The move table and the stage-modifier ratios were read off a retail Pokémon Blue cartridge with the project's own tools. No ROM is distributed; the reproduction command points at your own.
← Back to devlog