
BattleTech: The Crescent Hawk's Inception reverse engeneering
Reverse engineering of BattleTech: The Crescent Hawk's Inception (1988, MS-DOS; published by Infocom, engine by Westwood Associates) — and an in-progress Godot 4 / C# recreation of it.
Read this section before trusting anything else in this repo. The project is two efforts with very different maturity, and the word "phase" elsewhere in the docs means code written, not behaviour proven.
This project produces two artifacts at the same time, and the second one poses on the first:
(1) The documented reverse engineering. The reko/ decompilation, docs/ specifications, the
Spice86 emulator with BattleTech-specific MCP tools, and the Python tooling. This is the real RE work:
file formats, story text, memory map, and a large part of engine logic are documented and
cross-checked against decompiler output and live emulator traces. It is a deliverable in its own
right, and it is also the specification for (2).
(2) The recreation (BattleTechCHI/). A Godot 4 C# program that derives from (1): it reads
original data files (.BLD, .MTP, .ANM, GAME* saves) and re-implements the engine behaviour
as documented by (1). It is data-faithful, not behaviour-faithful, and has never been
validated end-to-end against the original.
They run in parallel, but the dependency direction is fixed:
(2) can only be as faithful as (1) is complete and verified. Where (1) says inferred or open, (2) is a guess.
That is why the roadmap puts closing the RE gaps (Track 1) and differential validation of (2) against the emulator (Track 3) ahead of feature work. A recreation is only as good as the reverse engineering that poses it.
If you are looking for a bit-exact port, it does not exist yet. If you are looking for a tool-assisted RE environment plus a data-driven reconstruction that runs on original assets, that is what is here.
Legend: ✅ true / done · ⚠️ partial, approximate, or with silent gaps · ❓ unknown / unverified · ❌ absent
| System | Reads original files at runtime | Behaviour matches the original | Validation |
|---|---|---|---|
| BLD decrypt + cipher text | ✅ BldLoader.cs | ✅ (text) | ✅ round-trip BLD↔JSON byte-identical (tools/bld) |
| BLD opcode interpreter (28 slots 0xE4–0xFF) | ✅ | ⚠️ partial | ❓ never played end-to-end; operand sizes fixed (EB/EC/F6/F7); all slots handled (no silent drop) |
Fn1CD3 dispatch (47 cases) | ✅ | ⚠️ partial | ❓ implemented from decomp; several cases are approximations |
| MTP map header/tiles | ✅ MapLoader.cs / LocalMapView.cs | ✅ (structure) | ⚠️ layout decoded, not diffed frame-by-frame |
| ANM animation (XOR-delta RLE) | ✅ runtime, PNG fallback | ⚠️ | ❓; repo has no ANM spritesheets (Assets/Animations/ empty) |
| ICN/CMP tiles | ❌ (pre-converted) | — | TileManager loads BMP; Assets/Tilesets/ empty |
Save files GAME1–6 (4096 B) | ✅ parser SaveManager.cs | ❓ | ❌ round-trip not verified against original saves |
Story state (b0057, props) | ✅ (reads) | ❓ meaning inferred | ❓ semantics not confirmed in play |
| Combat (to-hit, damage, AI, heat, ammo, fog) | — (own logic) | ❌ approximate | ❌ RNG/formulas never diffed against the original |
| Viewport / screen layout | — | ⚠️ approximate | ❓ no canonical viewport struct located |
| Sound / music | ❌ | ❌ | ❌ format undecoded |
| Map→BLD trigger mapping | ⚠️ partial | ❓ | tile-property table + [0x5460]:0x4602 translation not decoded |
.BLD scripts and interpret them (dialogue, menus, shops, many dispatch
cases) — with silent gaps on unimplemented opcodes..MTP maps, and read/write the real 4096-byte save layout.| Area | State | Canonical doc |
|---|---|---|
| BLD format, cipher, opcodes | 🟢 solid | docs/formats/bld-bytecode.md |
| Story text (all 26 BLD) | 🟢 extracted | docs/story/STORY_TEXT.txt |
| Memory map (100+ addresses, segments) | 🟢 solid | docs/formats/memory-map.md |
| World map / local maps | 🟢 solid | docs/world-map.md |
| Combat model | 🟡 ~90%, some inferred | docs/combat-system.md |
| Economy / shops / stock | 🟡 UI flow now observed live | docs/story/story-system.md |
| ANM format | 🟢 documented | docs/formats/anm-format.md |
| Viewport abstraction | 🔴 incomplete | docs/engine/viewport.md |
| Sound | 🔴 0% | — |
These are the real blockers; the roadmap in §6 is gated on them.
docs/combat-system.md)19EF / 1000 is missing from the
Reko output; those routines must be recovered. (docs/UNVERIFIED_DISCOVERIES.md §7)b0057 (0/1/2) and neighbours b0055/b0056/b0058 are inferred;
property IDs 0x1C–0x23 unmapped. (§5)0x32C6) + translation table
([0x5460]:0x4602) not decoded; entrances are currently found by hand-walking the map
(Citadel (34,10), ComStar (51,10) on the start map). (docs/context.md)0x246C config struct is only
partly mapped; push/pop semantics unknown. (docs/engine/viewport.md)0x32C6 for
movement. (§2)GAME* load→save→compare has not been done.docs/story/story-system.md)BldInterpreter.cs default branch)2A02 vs elsewhere). (§1)RE from the executable alone has limits (compiler-optimised code, absent segments, inferred semantics). To understand what is actually in the game we cross-check several kinds of source — none can replace the binary, but together they resolve intent and fill gaps: