Turok 2: Seeds of Evil
OriginNintendo 64
TechnologyNative C/C++ port (engine reimplementation)
Available forWindows, Linux, macOS
View official projectAbout the project
Turok 2: Seeds of Evil es un videojuego de disparos en primera persona para Nintendo 64, Windows 9x y Game Boy Color. Fue lanzado en 1998 y está basado en una serie de cómics de Acclaim Comics, Turok. Fue un juego adelantado a su época, mostrando unos gráficos excelentes, una excelente banda sonora, además de un vasto y creativo arsenal de armas. También fue uno de los primeros juegos de Nintendo 64 en utilizar el aumento de RAM del Expansion Pak, como Star Wars: Rogue Squadron, Top Gear Overdrive y NFL Quarterback Club '99.
Official project information
turok2-decomp
Work-in-progress matching decompilation of Turok 2: Seeds of Evil (Nintendo 64, US 1.0): C source that compiles back to the exact original ROM.
Status: all the C is matched. The ROM rebuilds byte-exact (
make verifypasses the SHA1), and the compiler is identified: engine code matches through SN64 GCC 2.8.1cc1 -O2 -mno-fix4300+asn64. Every function that was C in the original is now matched C linked into the ROM: 2,531 engine functions and 1,311 functions of the paged VM modules, which build with the same toolchain (100% of the C-origin code; 99.07% of all code bytes, the rest being hand-written asm, below). 23 of them are FAKEMATCH, documented in their files and in docs/MATCHING.md. The VM modules' second copy (81 KB, the first copy's bytes again, which cannot be C of its own) is left out of both sides of that figure. 99.83% of the C-origin code is also readable C, with named fields rather than m2c's offset macros (docs/MATCHING.md);tools/progress.pytracks the share. The matched badges are over C-origin code: the 9 KB that is hand-written asm by origin (libultra's.sfiles, SN64's boot and TLB code, the RNC unpacker, the exception stubs) and three dead fragments can never be C, sotools/progress.pylists them in their ownasm (by origin)row (docs/ASM_ORIGIN.md) and the badges reach 100% when all the C is matched; itsall coderow (--badge --raw) keeps the share of every byte.A parallel native-port track recompiles the same ELF with N64Recomp; it runs clean, and the TLB is its open question.
Why
This decomp is a stepping stone. The end goals are:
- A native macOS (Apple Silicon) port via N64Recomp + RT64.
- Reusing the work to port Armorines: Project S.W.A.R.M., which Acclaim Studios London built on the Turok 2 engine.
- Stretch goal: Android via RT64's Vulkan backend.
If you only want to play Turok 2, an emulator is 100× less work and totally fine. This project exists for native ports, modding (HD textures, real widescreen, 60 FPS), and preservation.
Engine
Turok engine (Iguana Entertainment / Acclaim Studios Austin) — descended from Turok 1's, and reused by Turok 3, Turok: Rage Wars, and by Acclaim Studios London for Armorines.
Required input
baserom.us.z64— ROM dump from your own cartridge. Not committed, never will be.- Expected SHA1:
fb0400f21e3f043939ab56500c7b12a3231006f1 - Internal name:
Turok 2: Seeds of Ev, cartridge IDNT2E, 32 MB.
- Expected SHA1:
Setup (Apple Silicon macOS)
On an x86_64 Linux host the same steps run without containers: install
binutils-mips-linux-gnu, cpp, dos2unix and the i386 C runtime
(libc6:i386), and cc1 runs natively, far faster than emulated.
# 1. Clone reference projects (gitignored, not part of this repo)
mkdir -p references && cd references
git clone --recursive https://github.com/Drahsid/turok3.git
git clone https://github.com/Drahsid/LibTEngine.git
cd ..
# 2. Pull SN64 toolchain + LibTEngine headers into the working tree
./scripts/setup-from-references.sh
# 3. Disasm the ROM. splat is pure Python and runs natively on arm64 in ~7s —
# no container needed for this step.
python3 -m venv .venv && ./.venv/bin/pip install -r tools/requirements.txt
make setup PYTHON=./.venv/bin/python
# 4. The recovered function entry points (versions/symbols_from_scan.us.txt,
# undefined_funcs_extra.us.txt) are committed; re-derive them only when
# changing the seeding: ./.venv/bin/python tools/function_seed.py --write
# 5. Build the linux/amd64 container. Only the assemble/link path needs it:
# cc1 is an i386 ELF and asn64.exe is Win32.
docker build --platform=linux/amd64 -t turok2-build .
# 6. Assemble and link
docker run --platform=linux/amd64 --rm -v "$PWD":/work turok2-build \
bash -c "make rom C_FILES="
# 7. Recompile to C. Use the mac-port branch of mgrz18/N64Recomp: upstream
# assumes a jump table shares its function's section and crashes here.
path/to/N64Recomp turok2.us.toml
Progress is measured with ./.venv/bin/python tools/metrics.py, which reports decode
and symbol coverage rather than matched-function counts.
Standing on the shoulders of
- Drahsid/turok3 — in-progress decomp of Turok 3 (same engine). Foundation for the official Turok 3 Remastered.
- AbuN64/ragewars-decomp — matching decomp of Turok: Rage Wars, the same engine a year later. Hundreds of Turok 2 functions compile from its C unchanged; those files carry its C, cut down to the one function and with Turok 2's symbol names (
tools/xmatch_ref.py,tools/import_ref.py), and say so in their header. Hundreds more are near copies: the same code over structs laid out differently (Turok 2's level actor is 0x288 bytes, Rage Wars' 0x2E8) or with other constants; those were retyped by hand to Turok 2's layouts. - thejunkman9000/Turok-Rage-Wars-Decomp — another Rage Wars decomp, with a native PC port; Turok 2 functions taken from its C the same way say so in their header.
- Drahsid/LibTEngine — reverse-engineered structs and function signatures for the Turok 2 / Turok 3 engine. Major head start.
- Mr-Wiseguy/N64Recomp + N64ModernRuntime + RT64 — the native-port pipeline.
- ethteck/splat — disassembler / segment splitter.
- matt-kempster/m2c — MIPS → C decompiler for matching.
- simonlindholm/decomp-permuter — randomized C rewrites for near-matches (
tools/permuter/). - Ghidra — analysis and readable decompilation for understanding systems (HUD, camera, player) before they are matched. Every name, prototype, struct and comment lives in the repo (
versions/names.us.txt,tools/ghidra/annotations.json,include/structs/) and is re-applied to the Ghidra project bytools/ghidra/, so the project is a disposable working copy.
Roadmap
The goal is readable C that rebuilds the original ROM byte for byte. That source is what makes real modding possible, and it is also the way out of the TLB for a native port: GoldenEye's and Perfect Dark's ports both stand on a decomp.
Phase 1 — Bootstrap (complete)
- Confirm ROM dump (SHA1 verified)
- Toolchain working (SN64 binaries; splat runs natively on arm64)
- First splat pass produces asm + linker script
- Entry point confirmed at
0x80000400(romMain)
Phase 2 — Microcode triage (complete)
- Dump RSP
ucode_text/ucode_dataand diff against stock - Verdict: stock
F3DEX.NoN fifo 2.05+aspMain. No custom RSP code, so RT64 needs no microcode work — go on the native-port path
Phase 3 — Segmentation and symbols (in progress)
- Recover the memory map: code in useg (TLB-mapped), data and libultra in KSEG0
- 95.2% of the ROM decoded, 13,275 functions delimited
- ELF links and the ROM rebuilds byte-exact from asm:
make verifypasses the SHA1 - Locate the
virtualsegment's real start (#23)
Phase 4 — Matching decomp (in progress)
- ROM rebuilds byte-exact from asm (
make verify) - Compiler identified: SN64 GCC 2.8.1
cc1 -O2, confirmed on 8 engine functions - Per-function check against the ROM:
tools/match_func.py - Matched C linked into the ROM (
make verifystill passes), with a progress metric - Fast C path: GNU as reproducing asn64 (
tools/sn_as.sh), a full build in seconds - Bulk matching from m2c drafts (
tools/auto_match.py): 840 functions over three passes - Readability pass: name the structs behind
M2C_FIELDaccesses — 1,140 files named, 10 left in m2c form;CGameObjectInstance,CPlayer,COverlay,CCameraininclude/structs/(offsets checked withtools/check_structs.py); next: hoist the repeated local structs (docs/STRUCTS_TODO.md) - Ghidra in the loop: structs, names and prototypes loaded into a Ghidra project (
tools/ghidra/) to read systems before matching them - Function names from the ROM's LNK records and from Turok 3's decomp (
versions/names.us.txt,tools/xmatch_t3.py) - Hand-match the functions m2c gets close to but not exact — started with the HUD: overlay script interpreter matched (docs/HUD.md)
- decomp-permuter batches for near-matches (
tools/permuter/) - Functions own their
.rdataslice from C: switch tables and float pools (--switch,--rdata) - Recover the original source-file boundaries
- libultra from decompals/ultralib (
libgultra) - Settle C vs C++: sources are
.CPP; C-style code matches withcc1
Phase 5 — Native-port track: recomp (in progress)
- N64Recomp runs against the ELF
- Full C output without errors: 31.4 MB of C, 5,525 functions, every sized function in the ELF (needs the jump-table fix in mgrz18/N64Recomp@mac-port)
- TLB: the engine pages code through the TLB and N64Recomp does not support it yet — see the note below
- First window opens with RT64
Phase 6 — Input
- Keyboard and mouse, with a patch on the aim path for real mouse-look
The TLB question
Turok 2 runs its code TLB-mapped: the boot stub programs a 2 MB page mapping vaddr
0x00200000 to paddr 0x0, and the virtual modules are paged in on demand by
VMASM.S / VMEMORY.C.
N64Recomp does not support TLB — its README lists relocations for TLB mapping as planned. Every TLB-using N64 game that runs natively today got there through a full decompilation: GoldenEye rebuilds a TLB-free ROM from a dedicated decomp branch, and Perfect Dark ships as a decomp-based port. Neither route is open here, so this is the project's real unknown.
Built with
Developed with Claude Code (Opus 5) under human direction — reverse engineering, splat configuration, tooling, and most of the prose here.
Legal
The ROM is not distributed here. Provide your own dump from a cartridge you own. Original game code and assets are property of the Turok IP rights holders.
The reverse-engineered work in this repository (symbol names, struct definitions, splat configs, Makefiles, scripts) is released under CC0-1.0 — public domain. See LICENSE for the full text.