A native Godot 4 reimplementation of Generation 2 Game Boy Color games Gold, Silver and Crystal. It is written from scratch in GDScript, not an emulator, static recompilation or disassembly. A user-supplied cartridge dump is SHA-1 verified, decoded once into a cache, then released. No game data ships here: bring your own ROM.
Inspired by gen1recomp.
Not a complete game yet. What works today:
- Import. Species, moves, items, types, the type chart, learnsets, evolutions, palettes, every Pokémon sprite, trainer pics and parties, the font, text-box borders, the battle HUD, maps, overworld menus, 34 mart lists, phone contacts, special calls and music/SFX pointers. A scene-free host resolves all of it without reopening the ROM.
- Battles. Parties, switching, stats, damage, accuracy, turn order, status and substatus effects, trainer AI, experience, levelling, move learning and capture input on a real 160x144 screen.
- Overworld. Real maps, map connections, script requests, trainer battles with imported win/loss text, map reloads, save-safe blackout recovery, object lifecycle, followers, block edits, emotes, surf, ledge hops, grass, fishing, roaming, repel and wild encounters. The service overlay covers menu selection, mart dialog variants and quantity purchases, source-timed phone dispatch and bounded music, effects and cries.
- Saves. Three slots,
.savimport, and a 14-box PC model with 20 slots per box. Gifts, eggs, NPC trades, HP/status items, repel and captures commit through a validated candidate save; a full party routes into the first free box slot and full storage refuses atomically. Format 1 saves migrate without inventing a world position.- Mods. A mod under
user://mods/can register a replacement world renderer, which is what a 3D or HD view needs.The real-data story preview walks the Crystal route from Elm's lab through Route 29, Cherrygrove, Route 30 and Mr. Pokémon's Mystery Egg event to the Zephyr Badge. Missing: full story state, dex, trainer card, options, the remaining special-call branches and story-driven permanent contacts.
You need Godot 4.8 or newer. Enable the commit guard once per clone:
git config core.hooksPath .githooksPut dumps in roms/, then verify them. See roms/README.md.
godot --headless --path . -s res://tools/verify_rom.gdMatching uses SHA-1, never filenames. Unknown hashes are refused because an uncharacterised bank layout could produce corrupt assets.
| Game | SHA-1 |
|---|---|
| Gold (USA/Europe) | d8b8a3600a465308c9953dfa04f0081c05bdcb94 |
| Silver (USA/Europe) | 49b163f7e57702bc939d642a18f591de55d92dae |
| Crystal (USA/Europe Rev 1) | f2f52230b536214ef7c9924f483392993e226cfb |
godot --headless --path . -s res://tools/import_rom.gdImport takes a few seconds per game. The cache is keyed by game and hash and
lives in Godot's user://, never in the project or an export. Use --verify
to check without writing.
| Data | Contents |
|---|---|
| Species | Names, base stats, types, held items, egg groups and TM/HM flags |
| Learnsets | All 251 species' level-up moves in cartridge order |
| Evolutions | Every evolution and method/requirements |
| Moves | Names, power, type, accuracy, PP, effect and chance |
| Items, types | 255 item names, prices, effects, menus, pockets, healing metadata and 28 type names |
| NPC trades | Gold/Silver six-row or Crystal seven-row records with requested/offered species, DVs, held item and OT data |
| Type chart | Every matchup and the two Foresight-cancelled entries |
| Trainers | Class names, pics, palettes, AI flags, DVs and every party |
| Palettes | Normal and shiny 15-bit cartridge colours |
| Sprites | Front/back for 251 species and all 26 Unown forms |
| Font and borders | 128 glyphs and eight six-tile text-box frames |
| Battle HUD | HP/EXP bars, panel borders and colours |
| Overworld | Maps, tilesets, collisions, events, scripts, movement, palettes, animation and object sprites |
| Wild encounters | Normal/swarm grass and water, 13 fishing groups with day/night substitutions, 16-row roaming graph, map-linked rates and slots, time-of-day selection, surf variance and repel checks |
| World services | Referenced menus, mart inventories, phone contacts, special calls, bounded scripts/text, music, SFX, cries and shared waveform assets |
Sprites remain colour indices and receive a palette at draw time, so shiny rendering needs no duplicate images.
Preview decoded graphics:
godot --headless --path . -s res://tools/preview_pics.gd -- gold /tmp/gold.png frontUse trainers, font or frames instead of front. Dump decoded tables
with species, moves, items, types, matchups, trainers, learnsets,
evolutions, growth or all:
godot --headless --path . -s res://tools/dump_tables.gd -- gold movesmatchups prints a grid; learnsets and evolutions resolve numbers into
names; growth checks all 251 species against the six curves and base EXP.
Smoke test the main scene:
godot --headless --path . --quit-after 30The launcher lists Gold, Silver and Crystal cache status, imports a selected
ROM, and opens its save screen: three validated slots, .sav import, party
inspection and the development battle. A new game starts with an empty party at
the Crystal home spawn with source starting money; Elm's imported lab scripts
offer Chikorita, Cyndaquil or Totodile at level 5 holding Berry. Continue enters
the overworld and F5 saves its map, inventory, event and clock snapshot. See
docs/SAVES.md for the save and SRAM contract.
Development scenes:
| Scene | Keys |
|---|---|
game/render/pic_viewer.tscn |
left/right species, S shiny, B front/back, T trainer classes |
game/render/text_viewer.tscn |
Space advances, F cycles borders, C shows every glyph |
game/battle/battle_screen.tscn |
A turn, Space events, W switch, left/right matchup, S/D damage either side; in wild battles B opens the ball selector, left/right changes ball, Space throws |
game/world/world_screen.tscn |
arrows/WASD move, Space or Z confirms, F fishes while facing water with an owned rod, P opens the phone list, Enter/Tab opens the start menu, Esc closes an overlay, V cycles world renderers, F5 saves |
Battle-screen moves are random and a full move set declines the learn offer; use
show_trainer(trainer_class) for a real party and trainer AI, or show_matchup
for a fallback pairing.
The world screen's start menu wires Pokemon, Pack, Pokegear, Save and Exit;
Pokedex, Player and Options appear in their source position but do nothing yet.
The Pack opens each item's own source submenu and can use one: a Potion asks
which Pokemon and heals it, a Repel sets its step count, and GIVE, TOSS and SEL
keep their source position marked unavailable.
The party submenu offers Cut, Surf and Whirlpool to a Pokemon that knows one; all
three show their message first and change the world on the acknowledge, and
stepping from water back onto land stops surfing. Standing on a whirlpool,
waterfall, door, staircase or cave tile overrides the pressed direction the way
the cartridge does.
The imported Players House PC opens the embedded box storage screen. The host
clock advances one game minute per real minute and crosses source day
boundaries. preview_emote(), preview_wild_encounter(),
preview_fishing_battle(), preview_script_event(), preview_battle_request(),
preview_world_battle_loss(), preview_capture() and
preview_party_transaction() drive their live paths; the API also exposes
swarm/roaming updates, repel countdowns and a JSON-safe snapshot.
Headless tools, all against a real imported cache:
| Tool | Checks |
|---|---|
preview_world_services.gd <png> |
mart overlay, deterministic integration cache |
preview_fishing.gd <png> [game map] |
fishing, for example silver 2 5; one-argument form is a fixture smoke test |
preview_world_story.gd |
map entry callbacks, event-flag visibility, facing interactions and the story route |
validate_crystal_route30_trainer.gd |
trainer record, sight line, approach, battle request, beaten flag, later interaction |
validate_ledge_hops.gd |
the eight hop codes, accepted directions, Route 30's ledge record and the two-cell landing, in both games |
validate_side_walls.gd |
the side-wall/side-buoy codes, their face masks and map census, in both games; Celadon Mansion Roof's fence and staircase landings on Crystal |
validate_cut.gd |
the cut block tables, the profile-split tileset numbers and cuttable-cell census, and Ilex Forest's tree, in all three games |
validate_surf.gd |
the surf sprites and music record, the surf-entry cell census, and New Bark Town's east shore, in all three games |
validate_whirlpool.gd |
the whirlpool block table, the forced-tile cell census, and Dragon's Den B1F's whirlpool, in all three games |
# Crystal map 3/19: block edits, hidden object, facing interaction
godot --headless --path . -s res://tools/preview_world_story.gd -- crystal 3 19 3 5 1 37,1744
# bedroom PC and the bedroom-to-town warp chain
godot --headless --path . -s res://tools/preview_world_story.gd -- crystal 24 7 2 2 1 none home
# the full walked route, ending at the Zephyr Badge
godot --headless --path . -s res://tools/preview_world_story.gd -- crystal 24 7 2 2 1 none home storyWorld text follows the cartridge command stream: $50 is a page break, $57
ends a text box and $58 pauses for a prompt. The story runner keeps the source
yes/no order, weekday wrapping and first eight temporary event flags, which
reset on a map reload.
GUT is in addons/gut; configuration is in
.gutconfig.json.
godot --headless -s res://addons/gut/gut_cmdln.gd -gdir=res://tests -ginclude_subdirs -gexitExit code 0 means all tests passed. They use synthetic files and a known
SHA-1 vector, never a real cartridge. Overworld integration suites can run
alone with -gdir=res://tests/integration; service coverage includes menus,
marts, phone calls and audio requests.
| Path | Contents |
|---|---|
game/ |
Feature folders with colocated scenes and scripts |
autoload/ |
Project singletons |
assets/ |
Authored or freely licensed assets |
assets/brand/ |
Logo and banner; see its README |
addons/ |
Third-party plugins |
tests/ |
GUT unit and integration tests |
tools/ |
Headless developer scripts |
roms/ |
User cartridges, excluded from Git and Godot imports |
game/mods/ |
Mod manifest and host |
mods/examples/ |
Example mods to copy into user://mods/ |
docs/ |
Contributor notes |
Windows, macOS, Linux, Android and iOS use GL Compatibility.
export_presets.cfg covers all five and writes into builds/. Install the
matching export templates first, then:
godot --headless --path . --export-release "Linux" builds/linux/gen2recomp.x86_64Tests, tools and GUT are excluded, and roms/ and the user:// cache are not
reachable from an export at all. Signing identities are placeholders: set the
bundle identifiers, Android SDK paths and Apple team ID before publishing.
iOS forbids JIT and runtime native code, so mods must be interpreted GDScript, not compiled extensions. The project is therefore GDScript-first. See docs/MODS.md.
Read docs/CONTRIBUTING.md. No cartridge-derived data
may enter the repository: no ROM, .sav, extracted sprites, text, maps or
audio. .gitignore, the pre-commit hook and tests enforce this; do not weaken
them. For reproducible comparisons with the upstream disassemblies, see
docs/REFERENCES.md.
MIT covers the engine source here, not the games or supplied dumps, which remain the property of their respective owners.
