Crusader_Decomp/crusader_decompilation_notes.md

13 KiB

Crusader: No Remorse — Decompilation Notes

This file is an index. Detailed notes have been split into the docs/ folder by topic.

Active live analysis target is now CRUSADER.EXE. Existing CRUSADER-RAW.EXE notes remain in scope as cross-reference evidence and should be cited alongside live NE addresses when they support a rename, variable role, or behavior claim.

Recent verified localized-build batch: docs/spanish-cheat-differences.md now records a tighter live-Ghidra comparison against /es/CRUSADER.EXE for the known cheat/debug control areas. Current best read is now narrower than the earlier "moved matcher" theory: the Spanish executable still preserves the same broad cheat/debug framework as the English build with relocated addresses rather than different behavior, but it does not preserve the English jassica16 table as the same static data object and this pass also failed to recover any replacement compiled matcher or any translated ~ cheat-latch toggle. The -laurie parser still sets the broad cheat/debug gate (1478:0910), the gameplay-input gate still exists at 1478:0927, and Hack Mover still toggles through 13e8:24a5; but the old English-side slot at 1478:2833 now contains pointer-like words, the old English immortality-string slots at 1478:2850/2866 are also repurposed as non-string data in Spanish, 1478:0910 has only the -laurie write at 1050:0985, 1478:5fb3 only has the Laurie-hint helper writes at 13e8:0071/0077, World_HandleKeyboardInput does not expose a recovered 0x7e / tilde branch, and 1478:8ad6 still has no recovered writer even though Hack Mover checks it. The new keyboard-side conclusion is stronger too: 1478:5fb3 does not act like a live positive enable latch in Spanish, because every recovered consumer requires it to be zero and the Laurie-hint helper pulses it back to zero immediately, while the nearby 8ad7/8ad8/8ad9 runtime-state writes still do not explain 8ad6. The Hack Mover runtime chain is also tighter now: 1478:5fb2 is the actual on/off toggle, 13e8:0ef9 / 13e8:0f77 clear it, 13e8:282f is the adjacent runtime helper using 1478:8ad9, and 13e8:2f0e / 13e8:3009 bracket the active drag state via 1478:8ac0, 1478:8acc, and 1478:8ace. Current safest localized-build read is therefore -laurie is the only recovered positive enabler for the surviving broad Spanish cheat/debug family; no replacement hidden matcher, no runtime keyboard-latch bootstrap, and no direct Spanish F10 cheat branch have been recovered, with the remaining open question narrowed to whether 1478:8ad6 is written through an analysis-dark path or is just a dead leftover gate.

Recent verified batch: docs/retail-debug-arg.md now records the live NE proof that retail CRUSADER.EXE still recognizes and executes a real -debug command-line branch. That branch prints Debugging mode ON., sets g_debugMsgLevel at 1478:87e0, and toggles two debug globals at 1478:0845/0859. The later sink pass also closes the text-output target more tightly: ProbablyPrintDebugMessage formats through the static stdio-style table at 1478:6c32..6c81 and writes to the handle-1 entry at 1478:6c46, so the non-video side is ordinary DOS stdout gated by the debug threshold, plus the already-confirmed AVI timing overlay. Current best read remains surviving debug-output / instrumentation switch, not the missing bootstrap for the hidden seg109/seg1408 usecode debugger. The same batch also leaves the earlier -laurie and 0x659c/659e debugger-state conclusions intact: -debug is a separate switch and is not currently evidenced as constructing the hidden usecode-debugger break-state object.

Recent tooling batch: docs/map-rendering.md now starts a dedicated offline map-rendering lane. tools/render_crusader_map.py can load FIXED.DAT, expand GLOB.FLX, decode the required SHAPES.FLX entries with Crusader frame headers, apply GAMEPAL.PAL, and write a first-pass PNG, with a --fixed-dat override so the same pipeline can be pointed at either game's map file. The current renderer is intentionally limited to fixed-map content and a simple deterministic painter rather than the full Pentagram/ScummVM dependency sorter, and the current workspace caveat is that STATIC_REGRET still lacks a copied FIXED.DAT, so No Regret rendering needs that file supplied explicitly.

Latest doc-reconciliation batch: docs/ne-segment1.md now has a combined hidden-debugger component table that explicitly separates the seg109/raw-reference UI wrappers (000b:9a86, 000b:9c0d, 000b:b3b1, 000b:b62c, 000b:2882) from the live seg1408 breakpoint-state helpers (1408:0000, 1408:0053, 1408:00dd, 1408:029e, 1408:03b0, 1408:03f7, 1408:0419, 1408:0432, 1408:0444) and the interpreter hook at 1418:04aa..04b5. Current best read remains two connected layers of one hidden usecode debugger, not conflicting address claims for the same function family.

Follow-up cheat-key correction pass: docs/ne-segment1.md now also records a live NE cleanup of several folklore keyboard-cheat claims. ~ is a real runtime cheat-latch toggle at 13e8:203d, Ctrl+C is wrong for this build and should be Ctrl+L for the coordinate popup at 13e8:255e, and the third F7-family overlay really does exist as a separate Ctrl+F7 path at 13e8:1a20 alongside the other two cheat-gated F7 overlay toggles.

That same note now also separates ~ from jassica16 more cleanly: jassica16 is the raw scan-code unlock path that toggles both 1478:0844 and 1478:6045 and sets the extra post-sequence latch 1478:8c52, while ~ is only the later translated logical-0x7e hotkey that flips 1478:6045 after 1478:0844 is already on. The F7-family clarification is tighter too: Ctrl+F7 is best read as an egg-hatcher trigger-range overlay rather than a third generic background grid.

The same docs/ne-segment1.md note now also has the first consolidated cheat/debug key matrix for the live NE target, including which paths need the broader Laurie/debug master gate (1478:0844), which ones need the full keyboard-cheat latch (1478:6045), and which ones depend on the extra post-jassica16 latch (1478:8c52). That pass also expands the egg-hatcher explanation: Ctrl+F7 is now documented as a live EggHatcherProcess range visualizer, with practical guidance on where to look for egg-trigger regions in gameplay.

Documentation Structure

File Contents
docs/overview.md Binary overview, installed copy findings, address space layout, NE fixup placeholder, segment map, NE import details, next steps
docs/phar-lap-extender.md DOS extender architecture, named functions (entry, loading, memory, I/O, interrupts), key string references
docs/ne-segment1.md NE Segment 1 full analysis: cursor, input, entity system, shot lifecycle, combat, weapons, AI, player/HUD, destruction, entity constants, vtable index, cheat system
docs/spanish-cheat-differences.md Focused comparison note for /es/CRUSADER.EXE versus the English build's known cheat/debug lanes: -laurie, broad cheat gate, gameplay-input gate, low-level keyboard latch, Ctrl+Q, Hack Mover, and the current status of the unresolved secret sequence
docs/raw-porting-progress.md seg091 RNG, 0x4588 callback lifecycle batches 1-6, 0007 gameplay helper batches, snap_entity_to_ground, AI sweep, animation/range/command globals, seg043 boundary recovery
docs/raw-000e.md 000e parser helper cluster (record table init/parse/dispatch), 000e RIFF/animation cluster (animation object field map, RIFF format, constructor variants)
docs/raw-0007-rendering.md Draw list node format and functions, world-to-screen isometric, tile visibility system, scroll/camera functions, scroll region table, save slot system, string/memory utilities, coordinate transform deep analysis
docs/raw-0008-000c.md 0008 dispatch helpers (init, pair-sync, flag helpers, word-list, gate-callbacks) and 000c state machine (tick dispatch, flag guards, palette fade, mini-VM, cursor nav)
docs/raw-000a-000d.md 000d proximity/visibility buckets, 000a tracked handles, cache manager, init/shutdown, seg082 allocator, seg137/138 palette helpers, seg004/005 startup, 0x4588 object-role evidence, 000d VM owner/resource loader follow-up
docs/far-call-targets.md Top-104 most-called far-call targets (Tiers 1-5, ranks 1-104), supporting functions discovered, analysis gaps and seg043 reconciliation
docs/crusader-disasm-reference.md Local auxiliary disassembly corpus at K:/ghidra/crusader-disasm: handwritten notes, shape tables, map dumps, opcode lists, intrinsic/function dumps, and the safe reuse rules for porting into CRUSADER.EXE
docs/ne-hole-filling-priorities.md Ranked CRUSADER.EXE hole-filling tracker: NE-side unclear lanes, the verified raw-side knowledge that can close them, and the recommended order for old-to-new porting passes
docs/retail-debugger-patch-attempts.md Chronological log of retail CRUSADER.EXE debugger-unlock patch attempts, byte-level designs, runtime failures, root-cause findings, and the current live candidate
docs/retail-debug-arg.md Focused note on the retail -debug command-line switch: live parser evidence, exact startup message, surviving globals, segment 1468 instrumentation path, and why it is currently separate from the hidden usecode debugger bootstrap
docs/scummvm-crusader-reference.md ScummVM Ultima8/Pentagram Crusader integration survey: USECODE/event tables, FLEX/resource formats, world/map loaders, HUD/media, and RE follow-up priorities
docs/pentagram-crusader-reference.md Pentagram-source Crusader/U8 reference: direct Crusader USECODE parser and VM evidence, U8 usecode docs, runtime-confidence limits, and cross-checks against the ScummVM note
docs/map-rendering.md Offline map-rendering lane: FIXED.DAT/GLOB.FLX/SHAPES.FLX/GAMEPAL.PAL format notes, current Python renderer, supported inputs, and fidelity gaps
docs/usecode-roundtrip-ir.md ScummVM-to-binary USECODE cross-walk, owner-loaded class-layout and header/event-count reconciliation, conservative IR v0 plan, and the generated class-event/body-window outputs that now ground reversible _BOOT, SURCAM*, and environmental family decompile artifacts plus repeated-family regression checks
docs/usecode-pentagram-ghidra-path.md Pentagram-derived Crusader USECODE parser plan, proof-of-concept workflow, canonical IR v1 goals, and the Ghidra-side annotation import path
docs/usecode-tooling-comparison.md Comparison of Pentagram's converter/disassembler, the local crusader-disasm corpus/scripts, and the current workspace parser/pseudocode exporter, with emphasis on assumptions, strengths, and repo-specific differences
docs/usecode-tool-improvement-plan.md Concrete next-step plan for the local USECODE parser/decompiler, distilled from the Pentagram and crusader-disasm comparison into prioritized parser, loop-decoding, intrinsic, trailer, corpus, and runtime-bridge upgrades
docs/usecode-jelyhack-analysis.md Focused analysis of exported JELYHACK / JELYH2 pseudocode, the tiny shared use stub, and why the current best model remains referent anchor + neighboring event-bearing attachment
docs/usecode-equipment-system.md Evidence-backed note on Crusader's surviving equip / unequip event system, including live compiled-side dispatcher proof, corpus-wide slot counts, actor/turret/environment examples, and the current best model of equip as a generalized inherited Ultima-style item event
docs/usecode-alarmhat-analysis.md Focused analysis of exported ALARMHAT::equip, the nearby shape 0x04D0 equip loops, alarm-family comparisons, and the current gameplay-facing read of ALARMHAT as a local alarm-state driver
docs/usecode/windsurf-regret-vs-remorse.md Side-by-side comparison of WINDSURF in Regret and No Remorse, including shared slot behavior, helper-family drift, body-size differences, and the current best read of WINDSURF as a directional wind-force helper used by vent scripts