Standing page · Gen 1 cartridge
Cartridge finds.
Things the cartridge actually does, collected as they are found — what it is, where it lives, and the mechanism underneath it. A fact about a ROM that nobody re-ran is a rumour with a hex number attached, so each entry ends with how it was checked.
01 — NINTEN and SONY are the real defaults
Before either naming screen runs, the player is already called NINTEN and the rival is already called SONY. Not merely two strings sitting in the ROM — two strings the game unconditionally copies into the live name fields on every single new game.
$50-terminated.wStatusFlags6 $D732 — cleared on every ordinary new game.The mechanism
The copy happens before the decision to run the naming screens
PrepareOakSpeech zero-fills the block from wPlayerName
through wBoxDataEnd and then copies two 11-byte fields in — the
labels at those two ROM addresses, DebugNewGamePlayerName and
DebugNewGameRivalName. Only afterwards does
OakSpeech test bit 1 of wStatusFlags6 and decide
whether to run ChoosePlayerName and ChooseRivalName
at all.
On a retail cartridge that bit is explicitly cleared by
StartNewGame every time, so the naming screens always run and
always overwrite the defaults a moment later. The defaults are real, they are
written on every new game, and they last a fraction of a second.
This is not an emulator quirk and not a Japanese-only leftover. It is the retail USA/Europe cartridge's own code path — one that exists, is reachable, and is simply never taken in ordinary play.
$45AA, read out of the
cartridge image. Both source strings are shorter than the 11-byte
field they are copied into, so each copy runs past its own terminator: the
player's name field ends up holding NINTEN, its terminator, and the first four
letters of SONY. Harmless — the game reads a name only as far as its
$50 — but it is a second, independent confirmation that the two
sit contiguously in exactly the order a straight-line copy would overrun. Drawn
from the real byte values, not a sketch.
How it was verified
Read, then run — and the control run is the half that matters
A one-off trace drives a genuine cold boot — no save file, deliberately, because the thing under test only exists before any save has a chosen name in it — through the title screen and into a new game, twice. The second run is the control, and it is what turns "the strings are there" into "the strings are the defaults":
| Run | wPlayerName $D158 |
wRivalName $D34A |
|---|---|---|
| Debug bit forced on every frame | NINTEN from frame 368, unchanged to frame 6600 | SONY from frame 368, unchanged to frame 6600 |
| Same script, bit not forced — a plain new game | NINTEN at frame 368, overwritten with BLUE at 1784 | SONY at frame 368, overwritten with RED at 2270 |
BLUE and RED are the first canned choices the two naming screens offer on this
cartridge — the button-mash landing on them is the naming screen behaving
exactly as a naming screen should, which is the entire point of running the
control. The bit is forced on every frame rather than once, because
StartNewGame's own reset of it lands at an unknown frame during
the mash, and a one-shot force could be silently undone.
0x45AA and 0x45B1, on the cartridge whose SHA-1
is d7037c83e1ae5b39bde3c30787637ba1d4c48ce2.
- Lives at
- ROM bank 1
$45AA(NINTEN) and$45B1(SONY) → WRAM$D158(wPlayerName) and$D34A(wRivalName), 11 bytes each - Gate
wStatusFlags6$D732, bit 1 — set means skip both naming screens- Kind
- Cartridge mechanic — an outside claim, checked against our own cartridge and confirmed
- Scope
- Pokémon Blue, USA/Europe only. Not checked against the Japanese release — no such cartridge is available here, so no claim is made about it either way
02 — The learnset table is not indexed by dex number
It is indexed by a species' internal index — the number the engine uses on the bus. Read the first 151 slots, which is the obvious thing to do, and you lose all three starters without a single error being raised.
The trap
Both wrong answers parse cleanly and look plausible
EvosMovesPointerTable has 190 slots. Internal
index 1 is RHYDON, not BULBASAUR. Thirty-nine of the 190 belong to no species
at all — the table that says which is PokedexOrder, and a zero
there is what everybody calls MissingNo.
So there are two ways to get this wrong and they are not the same mistake. Reading all 190 slots is fine. Reading the first 151 is not — and it is the one that looks right.
| How the table is read | Learn entries | Evolutions | By level | By stone | By trade |
|---|---|---|---|---|---|
| The first 151 slots | 580 | 56 | 40 | 12 | 4 |
Filtered by PokedexOrder | 728 | 72 | 52 | 16 | 4 |
| All 190 slots, unfiltered | 728 | 72 | 52 | 16 | 4 |
The third row names the mistake precisely. Every one of the 39 MissingNo slots has its own distinct pointer, and every one of those records is empty — so walking all 190 gives exactly the right totals. The error is not reading too many slots. It is reading the wrong 151.
What the wrong 151 loses
Twenty-seven real species, starting with all three starters
Exactly 27 real species sit at an internal index above 151, and the first 151 slots hold 27 MissingNo in their place. Among the 27: BULBASAUR (internal 153), CHARMANDER (176) and SQUIRTLE (177), with their whole evolution lines, plus ODDISH, BELLSPROUT, RATTATA, GEODUDE, PONYTA, AERODACTYL and PORYGON.
A tool built on the naive read reports that Charmander learns nothing at all, ever, and never says anything is wrong.
The discriminating check
Count the stone evolutions, not the trade ones
Gen 1 has 16 stone evolutions. The naive read produces 12, so that count catches the mistake immediately.
Trade evolutions are not a check. There are 4, and the wrong read also produces 4 — all four of KADABRA, MACHOKE, GRAVELER and HAUNTER happen to sit below internal index 152. A validator built on the trade count alone would have passed a table missing every starter in the game.
- Lives at
- ROM only — no WRAM address.
EvosMovesPointerTableat bank$0E$705C;PokedexOrderat file offset$41024, on this cartridge - Found by
- Property, not by a remembered address: the one offset in the image whose 190 consecutive little-endian words all land in
$4000-$7FFFand whose records parse as valid evolution and learnset bytes throughout - How it was verified
- Read out of the cartridge image: 190 slots located by that property (a unique hit across all 63 banks),
PokedexOrderread back as 39 zero entries and 151 real species, 27 of them above internal index 151 - Kind
- Cartridge mechanic, and the trap it sets for every reader of it
03 — Two species share one printable name
NIDORAN♂ and NIDORAN♀ are two species with two internal indices, two base-stat records and two different learnsets. Their names differ by one gender glyph.
Any name lookup that normalises away characters outside the alphabet collapses
both to NIDORAN and returns whichever the cartridge lists first.
There is nothing wrong with that rule; there is something wrong with using a
name to identify a species at all. The party stores an internal index,
and so does every table in the cartridge.
It stayed invisible until a second bug was fixed. A scale-out script filed each plan under a sanitised stem, so one of the two NIDORAN plans was written twice and the other silently never ran — 140 lines planned, 139 files on disk, and a total that looked complete. Giving them distinct filenames exposed the real fault underneath: the female's plan armed a male, which learned HORN ATTACK at level 8 where the plan said SCRATCH.
It was settled by reading the species byte the game had actually generated
(wPartyMon1Species = 3, the male) beside the plan that had asked
for 15. The screen said NIDORAN in both runs and could not have
told anybody apart.
- Lives at
wPartyMon1Species$D16B- How it was verified
- Both lines drill to 6 of 6 events once each is identified by index rather than by name — the male learning HORN ATTACK at level 8 and the female SCRATCH, as the tables say they should
- Kind
- A cartridge fact, and the trap it sets for every name lookup
04 — A trainer sees through walls
Gen 1's trainer detection is a coordinate comparison, not a raycast. It never asks what is between the trainer and the player.
Cerulean Gym's swimmer stands at (8,7) facing left,
with (7,7) and (6,7) both solid — the only walkable
ground beside him is to his right. He engages anyway, from (5,7):
three tiles away, with two walls in between.
It showed up on the first scripted attempt at that gym, when the player crossed open floor three tiles from the swimmer and the battle simply started, with no line of sight the terrain could plausibly have supplied. Reading the engagement check rather than assuming a sight cone settled it: it establishes that the player is somewhere on the row or column the trainer faces, within range, and tests nothing about the tiles the line crosses.
A trainer that "sees" through solid tiles is not a bug in the usual sense. The cartridge was never testing occlusion in the first place.
- Lives at
wXCoord$D362·wYCoord$D361— what the engagement check compares against the trainer's own facing and position- How it was verified
- Observed live on the cartridge, then confirmed by reading the check itself rather than inferring a cone from the behaviour
- Kind
- Cartridge mechanic
05 — Crossing two levels loses the move between them
Gen 1 announces one level per battle and checks the learnset for the level it ended on. Skip a boundary and the move belonging to it is never offered, and there is no second chance.
A level 6 BULBASAUR was pointed at a single level 5 CHANSEY — 182 experience,
the highest base-experience Pokémon in the cartridge — to make it learn LEECH
SEED at level 7. It reported LEARNER grew to level 8! and offered
no learn prompt of any kind. The first version of that drill read this as "the
prompt does not fire" and went looking for a bug in itself.
Nothing needed fixing. The arithmetic did: start the BULBASAUR at level 12 and feed it two CHANSEY, so that exactly one boundary falls inside the run — 973 experience for level 12, +182 → 1155 (still level 12), +182 → 1337, which is level 13 and VINE WHIP.
- Lives at
wPartyMon1Level$D18C, and the experience triple below it- How it was verified
- Measured on the cartridge with the full prompt trace recorded — the failing single-CHANSEY run and the two-CHANSEY run that produces the prompt, side by side
- Kind
- Cartridge mechanic
Where these come from. Every entry is drawn from the discovery log of AtlasGB's Gen 1 memory atlas, which records each finding with its addresses, the symptom that produced it, the wrong turns, and the run that settled it.
The cartridge. Pokémon Blue, USA/Europe, SHA-1
d7037c83e1ae5b39bde3c30787637ba1d4c48ce2, 1,048,576 bytes. Where a
finding is version-specific or region-specific, the entry says so rather than
generalising quietly.
This page grows. Entries are appended as they are found, and nothing goes on it that has only been read about.