Kirby: Nightmare in Dream Land
OrigenGame Boy Advance
TecnologíaPort Nativo C/C++ (Reimplementación de Motor)
Disponible paraWindows, Linux, macOS
Ver proyecto oficialSobre el proyecto
Kirby's Adventure, conocido como Hoshi no Kirby: Yume no Izumi no Monogatari en Japón, es un videojuego de plataformas de 1993 desarrollado por HAL Laboratory y publicado por Nintendo para Nintendo Entertainment System (NES). Es el segundo juego de la serie Kirby después de Kirby's Dream Land (1992) en Game Boy y el primero en incluir la habilidad de copia, que permite al personaje principal Kirby obtener nuevos poderes al comerse a ciertos enemigos.
Información oficial del proyecto
Kirby: Nightmare in Dream Land
A matching decompilation of Kirby: Nightmare in Dream Land (Game Boy Advance, 2002), developed by HAL Laboratory and published by Nintendo.
The goal is C/C++ source that compiles into a byte-for-byte identical copy of the original ROM — not a port, rewrite, or recreation. All compilation happens inside a pinned Docker toolchain (agbcc family), so no toolchain needs to be installed on your machine. See INSTALL.md to get started.
ROM
The repository builds the following USA retail ROM:
| Built file | knidl.gba (8 MiB) |
| Internal title | AGB KIRBY DX |
| Game code | A7KE (USA) |
| Maker code | 01 (Nintendo) |
| Version | 0 (Rev 0, no other retail revision exists) |
| SHA-1 | 37a476567d133c146fee6b5e2eb0b07a215da6b0 |
make compare verifies the built ROM byte-for-byte against this SHA-1.
You must supply your own legally dumped cartridge image as baserom.gba
(see INSTALL.md); the same hash is expected.
Building, verifying and testing
Docker and GNU make are the only requirements; every target below runs
inside the knidl-builder image (the boot test in its own knidl-boottest
image). Full instructions, including baserom.gba placement and hash
verification: INSTALL.md.
make image # build the knidl-builder toolchain image (Debian 12 + pinned agbcc)
make # build knidl.gba from source + baserom.gba
make compare # build and verify the SHA-1 (byte-for-byte match)
| Command | What it checks | Needs baserom.gba |
|---|---|---|
make compare | the built ROM's SHA-1 against knidl.sha1 | yes |
make shifttest | the shift test and pointer census: relinks with padding at section boundaries and proves every pointer-like word that did not move is not a pointer (docs/data.md section 8) | yes |
make boottest | the boot test: runs shifted ROMs against knidl.gba in mGBA, frame for frame (the first run builds the knidl-boottest image, also make boottest-image) | yes |
make audit | the final audit: .incbin only where allowed, no unjustified raw bytes or addresses, the sanctioned asm and code-exception lists, the placeholder census (docs/audit.md) | no |
make check-data | the data policy: data/*.s holds only labels, symbolic pointers and .incbin slices | no |
make check-headers | compile-only smoke test of include/gba/*.h and the game headers | no |
make datastats | data-structure metrics (symbolic vs raw pointer-like words) | yes |
make progress | code/data/symbol percentages from the linker map | yes |
make symbols, make split, make modmap | regenerate the committed symbol database, asm//data/ and the module map; a clean tree must show no diff afterwards (git status --porcelain empty) | yes |
Progress
The project started as a full ROM split and was decompiled module by module
into src/, following the pret conventions (see AGENTS.md and
docs/history.md).
The decomp.dev badge reports 100%:
every byte of code in the ROM is built from source in this repository, C
for the game and labeled assembly for the runtime zones kept as asm by
design (each its own [asm] unit there, docs/decomp-dev.md). It measures
code only; naming and data readability are the figures below.
851196 total bytes of code
847028 bytes of code in src (99.5103%)
4168 bytes of code in asm (0.4897%)
0 bytes of code remaining to be decompiled
0 bytes in 0 functions in asm/nonmatching
4168 bytes excluded from decompilation tracking
34017 total symbols
28312 symbols documented (83.2290%)
5705 symbols undocumented (16.7710%)
7537432 total bytes of data
95640 bytes of data in src (1.2689%)
7441560 bytes of data in data (98.7281%)
232 bytes of data from asm (0.0031%)
7316608 bytes of data in 24725 baserom incbins (97.0703%)
- Code: complete. All of the game's code is byte-exact C: everything from
AgbInit(0x08000310) to the sound engine's asm core, the sound engine's C driver and the SRAM driver. The 4,168 bytes of asm are kept by design and excluded from tracking: the ROM header, crt0 and the master interrupt handler, the ARM task switcher, the m4a engine's hand-scheduled core (asm/m4a_1.s, as in pret projects), the BIOS call thunks andSoftReset, libgcc's division routines with_call_via_rNand the task trampolines, and the interworking veneer. Each is justified in docs/audit.md section 2. - Code exceptions. The C is plain C apart from the sites
docs/audit.md section 3 lists: no register pin is left,
and one function keeps two zero-byte
asm("")levers by design (BootLogoUpdateObjects, lesson 3.527); the rest areBLOCK_CROSS_JUMPtails, the SDK's own inline asm and documented zero-code stand-ins. - Data (#36, closed; #167). The ROM's data is structure, not bytes:
labeled, symbolic
data/*.sfiles whose contents are.incbinslices of your ownbaserom.gba, and typed C tables insrc/data/where a decompiled consumer proves the layout: since #167 every functional record family (the BG animation scripts, the frame tables, the RoomDef headers, the actor records and seg 18's handler tables). Assets are never committed (docs/data.md). The shift test proves the ROM movable and the boot test runs it moved (see "For modders"). - Names (#155, closed; #183; #186). 4,937 of the 5,348 functions and 265 of
the 266 task bodies have real names, each with its evidence in
docs/analysis/renames.csv(convention: docs/naming.md). 28,312 symbols are documented: semantic names and position names (data records, palette-buffer cells, the player's frame records, and state bodies and scripts named after their slot in a state or dispatch table), and since #183 and #186 14,098 asset labels named after the record that owns them, by the pointer chain alone:gBonkersFrames[3]is theTaskGfxrecordgBonkersFrame3, whose OAM template, palette and tiles aregBonkersFrame3OamTemplate,...Paletteand...Tiles(5,024 under a semantic owner, 9,019 under a position owner such asgPlayerFrame189, a RoomDef or a BG animation script, 55 by a frame list or their one consumer). The player's frame records arestruct TaskGfxExtended(#186): aTaskGfxplus the upper half of the player's sprite slot,nextBankPaletteandupperTiles, sogPlayerFrame883points atgPlayerFrame883NextBankPaletteandgPlayerFrame883UpperTiles.make assetsnames its files after them.struct Task's per-family registers and the player's per-action scratch read by name through 1,186 alias macros (include/task_vars.h, as pret's#define tState data[0]), and the code spells its magic numbers and flag bits as 1,572 named constants (include/constants/, as in pret and katam:CreateChildTaskHere(TASK_FIRE_LION_FLAME, 0),ActorSetState(FIRE_LION_STATE_POUNCE),t->spriteFlags &= ~SPRITE_FLAG_FLIP_X). Every placeholder left has its reason: the 411sub_*functions, 62 RAM cells and theunk*fields indocs/analysis/unnamed.csv, the functional ROM labels in their referrers, and the 2,975 asset labels without one owner in their chains (shared by several owners, reached through an unnamed record, or pointed at by a word with no field name);make auditkeeps that census in docs/naming.md section 5.1. - File names (#182). The source files are named after what they hold,
<subsystem>_<content>.cin a flatsrc/(src/enemy_fire_lion.c,src/actor_defeat.c,src/player_ladder_inhale.c,src/task.c; docs/naming.md section 8). The address names they had before, which closed issues and PRs quote, resolve throughdocs/analysis/file-renames.csv.
For modders
make MATCHING=0 links without linker.ld's per-section address asserts, so
a modified ROM builds: every section after the cartridge header is placed by
the linker right after the previous one. Moving code or data is safe as far as
it has been measured: the shift test (docs/data.md section 8)
proves every insertion point after crt0 safe (no pointer-like word that fails
to move is a pointer or unexplained), and the boot test runs shifted images
frame for frame against the original through four scripted runs from boot (the
menus, stages 1-1 to 1-3 with two goal games and a mid-boss, the three
sub-games and a game over; docs/data.md section 8.4). The data policy sets the
limits: assets (graphics, audio, text, level maps) are .incbin slices of
your own baserom.gba and are never committed. make assets decodes the
census-proven graphics (palettes, tiles, LZ77 streams, maps, OAM templates)
from your dump into the gitignored assets/ directory for editing, and make assets-check verifies that tree byte for byte; make assets-mod rebuilds a
modded knidl-mod.gba from the edited tree, re-encoding only what changed and
splicing it in place (docs/assets.md). Functional tables are
C only where a decompiled consumer proves their layout, and stay
structure-only (labels and symbolic pointers) everywhere else.
CI
Continuous integration (.github/workflows/build.yml) is designed to be
green without a baserom: it builds the full Docker toolchain image, syntax
checks the Python/Perl tooling, compiles crt0 plus every file in src/, and
runs the checks that need no ROM (make check-headers, make check-data,
make audit). The ROM-dependent steps additionally run when a baserom.gba
is available on the runner: make compare, make progress, the regeneration
checks of make symbols, make split and make modmap (the committed
outputs must regenerate with no diff, git diff --exit-code),
make datastats, make shifttest and make boottest. The baserom can come
from any of these mechanisms:
- Self-hosted runner with
baserom.gbaplaced in the runner user's home directory ($HOME/baserom.gba; files inside the workspace itself are removed by the checkout step, so the ROM must live outside it), - Actions cache seeded by an earlier run, or
- a
BASEROM_URLrepository secret (optionally withBASEROM_TOKEN) pointing at a private artifact holding the USA ROM; the download is cached for subsequent runs.
If the baserom's SHA-1 does not match 37a476567d133c146fee6b5e2eb0b07a215da6b0,
or the built ROM differs from it, CI fails closed — a mismatch can never
pass. When no baserom is available, the ROM-dependent steps are skipped
explicitly and visibly (a notice annotation and a step summary banner).
A second workflow (.github/workflows/report.yml) generates the objdiff-schema
progress report and publishes it as the A7KE_report artifact for
decomp.dev — see docs/decomp-dev.md.
Disclaimer
This project is not affiliated with, endorsed by, or connected to Nintendo or HAL Laboratory. Kirby: Nightmare in Dream Land and its characters, names, and assets are trademarks/copyright of Nintendo / HAL Laboratory.
No ROM image, Nintendo logo, or any other copyrighted game asset is included
in, or distributed from, this repository. The Nintendo logo used by the build
is extracted from your own baserom.gba at compile time. You must dump your
own legitimately owned cartridge to build; do not ask for or share ROMs here.
Licensing
There is no open-source license attached to this repository: all rights are reserved (the convention used by pret-style decompilation projects). Do not reuse the code without explicit permission.
See also
- INSTALL.md — setup and build instructions
- katam — matching decompilation of Kirby & The Amazing Mirror (the closest sibling project)
- pret/pokeemerald — the reference GBA decompilation project this repo's conventions follow
docs/research/— research notes (ROM facts, toolchain validation, prior art)
