Crusader_Decomp/crusader_decompilation_notes.md
2026-04-12 14:45:08 +02:00

247 lines
98 KiB
Markdown

# 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 PSX CLUT override-routing follow-up: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now records a 2026-04-12 live MCP closure pass on `0x80041458`, `0x80041144`, `0x80044bdc`, `0x80044e9c`, `0x800a9f48`, and `0x800a9f66`. Current best read is now exporter-critical and executable-backed: main-visible injects authored high-byte palette token while special-visible does not, override selection is gated by `flags & 0xfffffff0`, active override resolution diverges by submitter/resource-format lane, and token `0` is effectively no-override in the world-object draw path.
Recent verified PSX palette/export follow-up: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now records the 2026-04-12 lock-in for the prior VRAM-dump `mode 1` palette proof. Current best read is now export-explicit: `mode 1` bundles should render against a shared contiguous 256-entry CLUT equivalent to live row `0xF0`, `x=0`, while the bundle header palette index stays diagnostic only as `defaultPaletteIndex`. The same follow-up also records that the processed PSX catalog already carried `62` maps, so the user-visible "single map" issue was export inclusion rather than cache enumeration.
Recent verified PSX no-placeholder exporter follow-up: [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now records the 2026-04-12 focused `map 104` cache pass that removes synthetic fallback atlases from the exporter path. Current best read is now provenance-explicit: unresolved mixed-role buckets are resolved per authored-family plus raw-`u5` cohort into actual PSX bundle art, and scene `mapSource` rows now preserve `mappingSource` plus optional `artCohort` so provisional donor matches remain auditable. Focused validation now exports `1002` art items, `0` fallback items, `1` atlas, and `136` shape definitions for scene fingerprint `3497e7f641856415`.
Recent verified PSX map-104 cohort follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) now records a 2026-04-12 final live pass on active writable `SLUS_002.68` anchored to scene fingerprint `3497e7f641856415` and fixed cohorts (root `0x0022` items `25/35`, root `0x0030` items `30/31`, constructor `0x0030` items `85/86`, control `0x0066` item `53`). Current best read is now cohort-safe and exporter-ready: constructors preserve authored route seed into `obj+0x1c`, stage-2 still requires object-local `0x0400`, draw submitter remains resource-kind based, and order-policy bits (`0x0600`) remain ordering-only; practical immediate change is to keep unresolved map-104 fallback partitioned by exact `record_u5` seed family (`0x0022` vs `0x0030`) while runtime `typePolicy`/resource-kind fields remain unsampled.
Recent verified PSX runtime/control-island follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) now records a 2026-04-12 live policy/island pass on active writable `SLUS_002.68` centered on `0x80063e54`, `0x80063e68`, `0x800675ec`, and `0x800675f8`. Current best read is now discriminator-explicit: the island is post-load control/runtime gating and policy bits influence ordering/render/publication behavior, but stage-1 versus stage-2 world-visible lane choice still depends primarily on object-local route bit `obj+0x1c & 0x0400` and submitter path remains resource-kind based. Practical exporter consequence is to keep island/policy capture as secondary modifiers while prioritizing resource-kind, latched frame token, and route bit for unresolved map-104 cohort splitting.
Recent verified PSX selector/transition follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) now records a 2026-04-12 live pre-latch closure pass on active writable `SLUS_002.68` centered on `0x80018578`, `0x8001bca0`, `0x8001e6e8`, `0x800260e8`, and `0x80025d68`, with direct type-`0x0042` row bytes recovered from `0x80063c1c` and `0x80063d68`. Current best read is now stage-explicit: selector reseat (`3/4` and peers) is early-gated by view margin and object lane bit `0x0020`, selector install writes `obj+0x9e` and script cursor, and final visible frame choice still latches at `obj+0x94`; practical exporter consequence is to keep pre-latch selector and latched frame token as separate channels for unresolved map-104 placeholder families.
Recent verified PSX descriptor-dispatch follow-up: [docs/psx/map-storage-model.md](docs/psx/map-storage-model.md) now records a 2026-04-12 live section-0 authored-family closure on active `SLUS_002.68` around `psx_dispatch_section0_dispatch_roots` (`0x800256b0`), `psx_dispatch_section0_constructor_placements` (`0x800258cc`), and descriptor table lane `0x80063118` / `0x80063220` / `0x800626f8`. Current best read is now dispatch-explicit: unresolved families `0x0042`, `0x0049`, and `0x0055..0x0063` converge on the same descriptor row (`0x800626f8`) and therefore share one callback chassis (compound-create + first state advance, main-visible refresh, release) at section-0 entry. Practical consequence is that exporter/model divergence for these families should be attributed to per-type bank/policy/state lanes rather than to a type-unique descriptor-row callback fork.
Recent verified PSX progression-latch follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a live timing pass on `0x80027548` and `psx_level_session_set_next_map_id` (`0x8002ba84`). Current best read is now rollover-explicit: progression callback writes deferred next-map latch `DAT_800678d0`, `current_map_id` switches only at level-session rollover (`0x80031edc`), and natural `54 -> 55` miss risk is therefore a deferred preemption window (transition exit before slot-`0x0f` tuple `(0x0a,0x04)` emit), not an immediate same-tick overwrite race.
Recent verified PSX transition-callback follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a live provenance pass on callbacks `0x8002745c` and `0x80027548`. Current best read is now callback-table explicit: both entries are indirect targets from the pointer region around `0x800641f0..0x80064220` with no direct caller xrefs, `0x8002745c` has a branch that can carry slot-family tuple opportunity via `0x80020f7c` and an alternate branch that skips it, and `0x80027548` progression apply increases natural slot-`0x0f` tuple timing sensitivity by advancing transition state before later control-event handling.
Recent verified PSX countdown-vs-slot follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a live structure check driven by the timed-segment clue. Current best read is now causality-tight: countdown logic (`0x8002b738 -> 0x80020794 -> 0x800205e8`) and natural JL-9 arm logic (`0x800214ac -> 0x800640a0[0x0f] -> 0x800230e4 -> 0x800232f0`) are adjacent lanes sharing control-state/timing helpers, with no recovered direct countdown-to-slot call edge in static flow.
Recent verified PSX slot-handler follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a live sibling-recovery pass on `psx_level_gate_slot_handler_table` (`0x800640a0`) with previously raw table-entry handlers defined and named at `0x800215fc`, `0x80021810`, `0x800219e4`, `0x80021fac`, `0x80022214`, `0x800222e8`, `0x800223cc`, `0x800226e0`, `0x800227ac`, `0x80022b50`, `0x80023854`, and `0x80023af0` plus a control-pair rename at `0x80022940`. Current best read is now sibling-explicit for the `0x0a` family: slot `0x0a/0x0b/0x0c` and slot `0x0d/0x0e` subcases are control/message/transition lanes, while slot `0x0f` case `(0x0a,0x04)` remains the only recovered sibling branch that writes `psx_debug_extra_channel_gate` at `0x800232f0`.
Recent verified PSX event-only synthesis continuation: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a conservative live Ghidra naming/comment durability pass around the natural gate-arm control-event core. Current best read is now semantics-tight but still cautious: `0x800230e4` is promoted to `psx_control_event_slot0f_handler` (slot-family role), slot-entry labels for `0x0d/0x0e/0x0f` are now explicit at `0x800640d4/0x800640d8/0x800640dc`, and upstream `54 -> 49 -> sink` remains preserved as structural topology rather than promoted active path until a second caller lane beyond the known `<0x0a` bound is recovered.
Recent verified PSX experiment follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records two more user emulator trials. Current best read is now sharper: a natural `MFM4` run did not yield `JL-9`, while `JFM4` plus manual gate byte `0x8006739d = 0x01`, then hidden `L0SR`, then `R1 + Circle`, still did. Practical consequence is that `MFM4` remains only the best natural prime candidate, while the natural in-level gate-arm event is now the dominant unresolved part of the mystery. Deferred follow-up experiments to revisit later are the current plan's `2`, `4`, `5`, and `6`.
Recent verified PSX event-only decoding pass: [docs/psx/jl-9-in-level-event.md](docs/psx/jl-9-in-level-event.md) now collects the natural gate-arm work into a dedicated note. Current best read is now event-centered instead of passcode-centered: the sink dispatcher at `0x800214ac..0x800215f8`, slot-family handlers `0x0d/0x0e/0x0f`, and the exact JL-9 arm tuple `(slot 0x0f, arg1 0x0a, arg2 0x04)` are separated from the broader JL-9 chain, while the remaining upstream uncertainty is explicitly narrowed to one authored in-level producer rather than the hidden-code half.
Recent verified PSX forced-test closure: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records user emulator confirmation that manual byte poke `0x8006739d = 0x01`, then hidden `L0SR`, then `R1 + Circle` successfully adds `JL-9`. Current best read is now causal-explicit: this proves the downstream hidden/input grant half and shows that the more direct thing being bypassed is the natural in-level gate-arm event rather than the passcode layer itself. Practical consequence is that `MFM4` is now best treated as the strongest natural prime candidate, not a required part of the forced memory-edit test.
Recent verified PSX hard-clear and manual-test follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` check of the "beat the game on hard, then enter `L0SR`" theory plus a practical emulator poke closure. Current best read is now split: the hard-clear story remains weak because completion-text flows were found but no direct bridge from ending handlers into `psx_debug_extra_channel_gate` was recovered; meanwhile the manual test is now strong because `psx_debug_extra_channel_gate` is confirmed as single byte `0x8006739d`, read as nonzero in the late JL-9 branch, with no recovered clear in inspected menu/session paths. Practical consequence is that the best forced test is now `0x8006739d = 0x01`, then hidden `L0SR`, then `R1 + Circle`.
Recent verified PSX published-code sweep: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` pass against the user-supplied mission-code table. Current best read is now candidate-explicit: `MFM4` (Level 15 hard) is the only strong published ordinary prime recovered so far because ordinary row `i=0x0e` returns selector `0x0f`, maps to current-level `54`, lands in gate family `DAT_80063e68[54]=0x0f`, and also sets `psx_level_runtime_header_state=3`. Practical consequence is narrower and more useful: if a real published-code JL-9 route exists, `MFM4` is now the lead prime, but it still requires the missing in-level gate-arm event before hidden `L0SR` plus `R1 + Circle`.
Recent verified PSX JL-9 step-2 clarification: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now makes the old JL-9 recipe less misleading. Current best read is now explicit that step 2 is not a second passcode-screen action but an in-level scripted/control dispatch through `0x800214ac..0x800215f8`, where handler slot `0x0f` resolves to `psx_set_debug_extra_channel_gate` and the exact writer tuple is `(param_2==0x0a, param_3==0x04)`. The same follow-up also tightens hidden-passcode semantics: `?0SR` / `L0SR` still routes through the shared passcode evaluator/decoder, but its selector-`0` branch does not take the normal mission/apply-load path. Practical consequence is that the current JL-9 model is now `normal passcode prime -> in-level scripted gate-arm event -> hidden passcode -> R1+Circle`, with the remaining blocker narrowed to the concrete in-level event label.
Recent verified PSX passcode-screen semantics follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` closure pass on user-facing step ordering for normal versus hidden passcodes. Current best read is now explicit for screen behavior: both normal and hidden entries route through the same evaluator/decoder path (`0x80034e38` -> `0x8003ec8c`), hidden `0x10` sets `psx_hidden_passcode_flag` in that shared decoder (`0x8003ed28`), and the unnamed caller block around `0x80034c14` has divergent immediate behavior for eval return `0` versus nonzero before transition setup. Practical consequence is that the existing JL-9 sequence remains directionally right on two-phase logic (`pre-hidden gate arm` then hidden/input trigger) but should be treated as operationally under-specified until the exact player-visible producer for `param_2==0x0a,param_3==4` is directly traced.
Recent verified PSX RP-16 startup/default hardening follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` pass that pushed on undefined nearby init stubs, startup mode-action callsites, selected-id writer closure, active-channel writes, and level mode/difficulty table resolution. Current best read is now stronger and still negative for startup RP-16: `committed_selected_item_id` has only two recovered writers (`0x80039f68` reset and `0x8002f170` table commit sink), startup dispatch stays `8 -> (optional 2) -> 4` without a direct commit call, and scanned `channel_commit_row_selected_item_id` rows (`0x00..0x19`, selected byte `+9`) contain no `0x01` selected-id entry. Practical classification remains `RP-16 not proven startup/default weapon` while preserving row `0x01` as real non-startup data.
Recent verified PSX JL-9 sequence follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` special-passcode priming closure pass on `?0SR/?RTN/?QQQ` against `psx_level_runtime_header_state`, `psx_hidden_passcode_flag`, and `psx_debug_extra_channel_gate`. Current best read is now explicit: `?RTN` clears header state to `0`, `?0SR` sets hidden flag to `1`, `?QQQ` returns sentinel `0x12` without priming header state, and none of the recovered specials alone satisfy gate-arm (`hidden==0 && header_state==3`) at `0x800232f0`, so strongest JL-9 model remains two-phase (pre-hidden gate arm, then hidden/input trigger).
Recent verified PSX RP-16 startup/default follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` startup-path closure pass over `psx_level_post_load_runtime_reset` (`0x80039ef4`), `psx_weapon_channels_init_mode_loadout` (`0x8002f814`), and `psx_weapon_channels_apply_mode_transition_state` (`0x8002f278`). Current best read is now explicit for the startup question: selected-id state is reset to `0` before init dispatch, no fixed selected-id `0x01` seed appears in the named loadout/mode-transition initializers, and fixed-immediate commit sites with `0x11/0x12/(contextual 0x01)` currently sit in gameplay/control lanes rather than fresh-start init. Practical classification is now `RP-16 not proven startup/default weapon` while still remaining a real row with unresolved non-startup acquisition role.
Recent verified PSX JL-9 gate follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` final-enable-sequence closure pass around `0x8002ba9c`, `0x800232f0`, `0x8002fd90`, and `0x8002fff4`. Current best read is now explicit at instruction level: the extra `0x0d` unlock (`JL-9` lane) is gated by `psx_debug_extra_channel_gate` read at `0x8002fff4`, that gate is written only when `psx_hidden_passcode_flag==0 && psx_level_runtime_header_state==3` at `0x800232f0`, and the grant helper entry still requires `psx_hidden_passcode_flag!=0` plus input code `0x1e` at `0x80013174`, making a two-phase hidden flow the strongest practical model.
Recent verified PSX RP-16 follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` row/acquisition pass for selected-id `0x01`. Current best read is now explicit: `RP-16` row `0x01` is real populated weapon-definition data (`0x80064690`), direct shop unlock progression still uses `03..0c` in the primary unlock branch, and the only observed shop-side `0x01` occurrence is in the secondary `0x0a..0x0e` ammo-top-up branch rather than a direct unlock call. This tightens `RP-16` away from "invalid slot" and toward a real early row with legacy/startup/placeholder-like behavior in the current image, pending one concrete non-debug normal acquisition writer.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused live `SLUS_002.68` legitimate-acquisition closure pass with emulator-grounded selected-id mapping (`0x8014577e`, `0x0c=JL-2`, `0x0d=JL-9`). Current best read is tighter by lane: normal loadout and shop direct unlocks remain capped at `<=0x0c`, hidden/debug gating still provides the only recovered fixed-immediate `unlock(0x0d)` site (`0x80030004`), and scripted packed-action dispatch remains the only plausible non-debug `0x0d` exception but is still data-dependent and unproven without a concrete shipped section0 marker/action row.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now incorporates the user-verified selected-weapon byte mapping at `0x8014577e` (`00..0d`) and corrects the earlier local-id shorthand into a stricter two-domain model: caller-side compact channel/local codes feed `psx_apply_channel_effect_and_commit_selected_item_id` (`0x8002ef34`), then `0x8002f15c` resolves through `channel_commit_row_selected_item_id[(channel*10)+9]` into committed row-id domain (`00..0d`) before `0x8002f168` writes the nested runtime `+0x1c` field.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records the starter-only RAM compare that retracts the earlier `0x1456fc` inventory-list interpretation. The attractive `0x1456fc..0x145748` `0x0002..0x000b` sequence is unchanged across the all-weapons and starter-only dumps, so it is not the live owned-weapon list; the dynamic region begins at `0x14574c`, and the strongest current executable-backed field closure is now byte `0x14577e` (`0x0c` all-weapons vs `0x02` starter-only) as selected/committed weapon row-id state inside a nested runtime block. The separate watch at `0x67944` still changes, but no direct static xrefs for `0x80067944` were recovered in the current image.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now incorporates the stronger emulator-grounded selected-weapon byte mapping at `0x8014577e`: `00` none, `01` `RP-16`, `02` `RP-22`, `03` `RP-32`, `04` `SG-A1`, `05` `AC-88`, `06` `PA-31`, `07` `EM-4`, `08` `PL-1`, `09` `UV-9`, `0A` `GL-303`, `0B` `AR-7`, `0C` `JL-2`, `0D` `JL-9`. This replaces the older `JL-?=11` inference and shifts the remaining open questions to legitimate JL-9 acquisition and RP-16 role/acquisition.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records the RAM-search blocker in a narrower form. The current best runtime-state lead is no longer the nearby commit-table neighborhood but denser small-byte clusters around file offsets `0x133000`, `0x133416`, and `0x1335d4`, with a weaker secondary candidate near `0x422c..0x4440`; the sampled `DAT_80064355[(channel*10)+9]` field does not behave like a plain final JL row id in this dump. The same pass also promotes `psx_handle_special_input_code` as the strongest upstream helper for the special `0x1e` trigger range while still leaving the exact controller-chord mapping open.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records the current RAM-search pivot more accurately. The earlier nearby commit-table neighborhood remains useful for the executable-side channel chain, but in the sampled main-RAM dump it does not show plain final JL ids at the tested byte field; the stronger current live-state candidates have moved to denser `0x0c/0x0d` table-like clusters around file offsets `0x133000`, `0x133416`, and `0x1335d4`. The same pass also names `psx_handle_special_input_code` as the strongest current upstream helper for the hidden `0x1e` input-code lane, while still stopping short of a closed `R1 + Circle` proof.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a six-agent pass that tightened both the JL-9 trigger story and the main-RAM angle. Current best read is: the code closes the path `hidden passcode active -> gated input code 0x1e -> psx_debug_grant_weapon_channels_and_ammo -> extra 0x0d unlock`, but still does not statically prove the exact folklore button chord; the 2 MiB `binary/Crusader - No Remorse Weapons Main Ram.bin` artifact is still plausible main RAM and now has candidate compact slot-like records, but it still needs one executable-side inventory/HUD anchor before it can decode the runtime weapon list cleanly.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now distinguishes the two checked dump artifacts instead of treating them as one generic memory lead. Current best read is: `binary/Crusader - No Remorse Memdump Weapons.bin` is still VRAM/HUD-side evidence, `binary/Crusader - No Remorse Weapons Main Ram.bin` is plausible main RAM but still not self-identifying enough to close the selected `JL-?` slot without the executable-side id resolver, and `JL-2 AMMO` remains the strongest next normal-lane clue while `JL-9` stays the stronger extra hidden/debug-conditioned lane.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) was normalized after a fresh six-agent `SLUS_002.68` pass so the note now reads as one fact-first summary instead of stacked dated rechecks. The strongest new practical deltas in that pass are: the checked `binary/Crusader - No Remorse Memdump Weapons.bin` artifact is still useful only as PSX VRAM/HUD evidence rather than direct slot RAM, and `JL-2` now becomes the clearer next unknown because `JL-2 AMMO` is present as a direct UI string while `JL-9` remains the stronger extra hidden/debug-conditioned lane.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now records a narrow live `SLUS_002.68` cleanup pass that promoted several previously documented JL-lane globals from raw `DAT_` placeholders to evidence-backed live symbols (`psx_hidden_passcode_flag`, `psx_debug_extra_channel_gate`, `psx_level_runtime_header_state`, `channel_commit_row_table`, `channel_commit_row_selected_item_id`, `committed_selected_item_id`, `psx_weapon_spawn_type`, `psx_weapon_spawn_audio_event_id`, `psx_weapon_spawn_state_selector`) and reclassified the checked `binary/Crusader - No Remorse Memdump Weapons.bin` artifact as a full 1 MiB PSX VRAM dump rather than weapon-slot RAM. The same note now also makes the next pivot explicit: if the extra hidden/debug lane remains `JL-9`, then `JL-2` becomes the next main unknown because `JL-2 AMMO` exists as a direct UI string while no matching plain `JL-9 AMMO` string has yet been recovered.
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes a focused four-lane MCP-only comparison on live `SLUS_002.68` across normal loadout (`0x8002f814`), shop (`0x8003de68`), scripted grant (`0x800311f4..0x800313b4`), and debug grant (`0x8002fd90`). The strongest new discriminator is explicit in disassembly: only debug grant performs the post-`0x0c` extra unlock (`0x80030004 -> ...unlock_and_seed_markers(0x0d)`) behind `DAT_8006739d` read at `0x8002fff4`, while the L0SR-linked chain still enters via `0x8003ed28 (DAT_80067454=1)` and `0x80013174`. Current best conclusion remains `JL-9` (`0x80064858`, index `0x0d`) as the extra post-L0SR non-PC lane over `JL-2` (`0x80064832`, index `0x0c`).
Recent verified PSX JL follow-up: [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) now includes an MCP-only row-field consumer trace on live `SLUS_002.68` for `JL-2` (`0x80064832`) versus `JL-9` (`0x80064858`). Current best read is stable and narrower: both rows still share base type-art lane `+0x1c=0x18` into the type-indexed active art-header path (`DAT_800758d8` via object constructors), while `+0x24` diverges (`0x4b` vs `0x0f`) as a transition/state selector lane rather than a direct base-resource pointer. Runtime capture remains required only for exact final frame/resource-token closure.
Recent verified PSX concrete-sample follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) and [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md) now capture another six-agent pass over the fixed `map 104` `0x0042` sample pack instead of broadening the search surface. The live PSX database now also names `psx_transition_selector_probe_nearby_overlap`, `psx_transition_selector_probe_marker_overlap`, `psx_snapshot_active_object_runtime_rows`, `psx_release_all_active_objects_and_reset_type_runtime_banks`, and a wider root marker/channel helper family. Current best read is tighter in three practical ways: the `64x64` versus `64x40` `0x0042` split still reads more like shared-resource / different-frame-state behavior than a different constructor bind path; the selector-to-frame bridge is now explicit through `obj+0x9e` install, `obj+0x94` latch, and the later frame-geometry consumers; and the stage-1 versus stage-2 branch point is now explicit at `psx_object_integrate_motion_and_route_visible`, even though the exact live `0x0400` provenance for the fixed sample pack still needs capture. The next `map 104` pass should therefore stay on items `25/30/31/35/85/86` and capture bound resource identity plus live frame/state and route-bit state at the decisive branch instead of widening heuristics.
Recent verified PSX concrete-sample follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) and [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md) now capture the first `map 104` `0x0042` pass grounded directly in exported `runtimeDiagnostic` scene items rather than generic family hypotheses. The live PSX database now names the spawn-side selector bridge `psx_transition_spawn_and_seed_selector_from_record`, the root-family decoder helper `psx_section0_dispatch_root_find_marker_record_by_channel`, the nearby resource-upload helpers `psx_upload_spec_wdl_image_pair_to_vram` and `psx_restore_display_draw_env_after_spec_upload`, the level-loaded policy pointer `psx_type_policy_table_ptr`, and the selector/policy row tables `psx_type_transition_mode_policy_rows` / `psx_type_transition_selector_rows`. Current best read is tighter in four viewer-facing ways: root and constructor section-0 families now have explicit named entry points but still converge through the same shared `0x0042` descriptor row; constructors directly copy the authored lane word into `obj+0x1c`, so exported `initialWord` values are real authored state; the strongest recovered `0x0400` stage-selection write is still nested-state-side rather than a direct object-local `0x0042` writer; and `DAT_800675f8` now reads as a level-loaded per-type policy pointer rather than a per-lane discriminator. The next `map 104` runtime pass should therefore stay on the fixed sample pack (`item:25/30/31/35/85/86`) and sample bound-resource identity plus live frame/state instead of broadening donor heuristics again.
Recent verified PSX exporter follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [map_renderer/src/lib/psx-cache.js](k:/ghidra/crusader_map_viewer/map_renderer/src/lib/psx-cache.js) now capture the viewer-side half of the current `0x0042` narrowing step. The PSX cache builder now emits scene version `psx-runtime-record-probe-v10` with a per-item `runtimeDiagnostic` payload that mirrors the current Ghidra-side channel split: object-local route flags, selector seed/pre-latch hint, exporter-side latched-state candidate, nested-runtime placeholders, resource-kind hints, and a placeholder slot for the live `DAT_800675f8` word. The next `map 104` runtime pass should therefore work against those exported channels directly instead of redefining the channel model again.
Recent verified PSX separate-batch follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/psx.md](docs/psx/psx.md) now capture another focused live `SLUS_002.68` round where six sub-passes covered non-overlapping areas: constructor-placement sample path, root-dispatch/mode gate, pre-latch `0x0042` transition path, anonymous route-bit writer islands, the `DAT_800675f8` policy lane, and the per-type art/cache lane. Current best read is tighter in three practical ways: the art/cache pair now reads as `psx_type_art_active_header_bank` plus `psx_type_art_built_resource_bank`; `psx_type42_transition_selector_tick` now clearly gates on `psx_object_is_within_view_margin` before emitting pre-latch selector `3/4`; and the anonymous island recovery proves wider runtime-state `0x0400` writes and related policy control without yet proving a direct object-local `obj+0x1c |= 0x0400` writer for `0x0042`. The next runtime sample should therefore log object-local flags, nested runtime state, pre-latch selector, latched state word, and bound resource kind as separate channels instead of collapsing them into one route/state summary.
Recent verified PSX static-discriminator follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/psx.md](docs/psx/psx.md) now capture the next focused live `SLUS_002.68` pass on unresolved `0x0042`. Current best read is tighter in four direct viewer-facing ways: type `0x0042` is now pinned to exact descriptor-table slot `0x80063220 -> 0x800626f8`; type `0x0042` also has a dedicated transition helper `psx_type42_transition_selector_tick` that can dispatch low selectors `3/4` before the `+0x94`-style runtime latch copy; constructors still seed `obj+0x1c` from authored `u5` while the named transition-table path only mutates bit `0x0002`; and `DAT_800675f8` now reads as policy bits for nearby-publication, stage-1 ordering, and semitrans draw policy rather than as the main missing route split. The next useful `0x0042` sample should therefore correlate pre-latch selector dispatch, latched `obj+0x94`, `obj+0x1c` bit `0x0400`, and resource kind on representative map-facing cases instead of widening generic family heuristics again.
Recent verified PSX route/state follow-up: [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/psx.md](docs/psx/psx.md) now capture the next focused live `SLUS_002.68` batch around unresolved `0x0042` routing rather than another broad helper sweep. Current best read is tighter in three ways that matter directly to the viewer: constructor and root-dispatch records both hand authored flags into `obj+0x1c`, where `0x0020` stays the broad world-visible gate, `0x0002` stays orientation/extents behavior, and `0x0400` is now the strongest recovered stage-2 selector; `psx_object_select_state_from_transition_table` now exposes a concrete per-type selector source through `DAT_80063b4c` ahead of `psx_object_select_state_script`; and the loader side is narrower because `psx_load_type_state_banks` owns `DAT_800758cc/d0/d4`, `psx_stream_install_type_runtime_banks` is the packed-stream all-bank installer, and `DAT_80067794` now reads as save/transition runtime-header state rather than the missing `0x0042` art-binding lane. The next viewer-facing sample should therefore correlate `type 0x0042` transition-table outputs with representative `map 104` `obj+0x1c` / `obj+0x10` / `obj+0x94` runtime values.
Recent verified PSX six-track consolidation: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) and [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md) now consolidate the latest live `SLUS_002.68` Ghidra sweep across descriptor callbacks, interaction/reselection, world-frame wrappers, visible-list ordering, resource submission, and HUD/overlay presentation. Current best read is narrower than before in three practical ways: `0x0042` still shares the generic `0x003e..0x0050` descriptor cluster instead of owning a special descriptor fork, constructor-placement `0x0042` still reads as a compound/main-visible route inside that shared family, and both world-facing draw lanes choose sprite versus image-table submission from the bound resource header kind while the HUD/overlay lane remains a non-map-facing exception. The next viewer-facing recovery step should therefore sample representative `map 104` `0x0042` runtime-bank/state/resource-kind combinations rather than widening donor reuse or looking for a hidden descriptor-table split.
Recent verified PSX interaction/reselection cleanup: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) now captures a focused live `SLUS_002.68` pass around `psx_type4_reselect_motion_state` / `psx_object_update_nearby_interactions` and nearby helpers. The PSX database now names `0x80028050 = psx_object_test_strict_nonoverlap_flag8_pair`, `0x800281d4 = psx_object_test_strict_nonoverlap_flag8_subject`, `0x80028700 = psx_object_adjust_param9c_by_view_side`, `0x800287bc = psx_object_update_param9c_from_contact_target`, `0x80028eb4 = psx_object_apply_contact_push_bias`, and `0x8002923c = psx_object_spawn_type11_contact_proxy`, with concise technical comments at each entry. Current best read is that this lane materially mutates runtime interaction state post-spawn (`+0x30..+0x38`, `+0x9c`) and can spawn type-`0x11` contact proxies in-flow, so exporter fallback logic should continue treating it as runtime behavior, not static authored placement metadata.
Recent verified PSX presentation-lane cleanup: [docs/psx/map-rendering.md](docs/psx/map-rendering.md) now captures a focused live `SLUS_002.68` pass around the HUD/overlay neighborhood. The PSX database now names `0x80035cc0 = psx_overlay_slot_create`, `0x80036000 = psx_overlay_slot_release`, `0x80038114 = psx_overlay_slot_step_color_fade`, and `0x800388a8 = psx_hud_overlay_init_resources`, and replaces the earlier generic in-database "verified by subagent pass" note on `psx_draw_hud_overlay_pass` with direct technical call-chain and table-behavior comments. Current best read remains that this helper cluster is a non-map-facing presentation lane layered after world stage-1/stage-2 draw submission; for viewer recovery it should be treated as a false-match guardrail, not as map-art placement evidence.
Recent verified PSX map-viewer batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md), and the new [docs/psx/map-storage-model.md](docs/psx/map-storage-model.md) now record both the latest executable-backed renderer findings and a focused evidence-backed write-up for how PSX level storage differs from the PC build. Current best read is that the cache builder still exports executable-named section-0 visible families (`section0_dispatch_roots`, `section0_constructor_placements`), runtime/state layers for `DAT_800758d8`, `DAT_800758d0`, `DAT_800758cc`, `DAT_800758d4`, and one offline `FUN_8003b00c` decode candidate for `DAT_8006b5d8 -> DAT_8006769c`, but it now also treats large zero-block `DAT_800758d8` constructor-placement bands as inherited-art candidates before falling back to placeholders. That donor-based recovery path moved the built cache from `58,262` fallback items / `1,714` bundle-mapped items down to `25,038` fallback items / `34,938` bundle-mapped items, making maps such as `0`, `9`, and `43` mostly real-art while leaving `map 104` as the clearest remaining outlier. The newest pass does not change the earlier `DAT_800758d4` conclusion: `psx_object_advance_state_script` still sign-extends those three bytes into `obj+0x30/+0x34/+0x38` for overlap/contact-style consumers rather than the draw path, and the unresolved blocker still sits later in the live state-to-resource/frame bridge for the remaining constructor-placement families. Follow-up live MCP passes now also tighten the per-frame interaction/control side in Ghidra: `psx_script_dispatch_audio_event` closes the `0xfffe` script sentinel as an audio/sequence side-effect opcode, `psx_heading16_lookup_unit_vector` closes the heading-token vector table used during target-vector reselection, `psx_authored_record_in_view_bounds` now closes the authored-record cull gate alongside `psx_world_point_in_view_bounds`, the old post-projection `FUN_80027f80` cleanup is now identified as the nearby-interaction active-set lane (`psx_reset_nearby_interaction_list`, `psx_nearby_interaction_list_add`, `psx_nearby_interaction_list_remove`, `psx_update_motion_and_nearby_interactions`) rather than a hidden render-only path, and the adjacent `0x80023c..2b1..` block is now grounded as a control-script lane (`psx_object_run_control_opcode`, `psx_control_move_player_to_point`, `psx_control_move_object_to_point`, `psx_control_wait_ticks`, `psx_control_configure_fixed_camera_anchor`, `psx_control_set_facing_direction`, `psx_queue_deferred_control_command`, `psx_flush_deferred_control_queue`, `psx_apply_deferred_control_command`, `psx_apply_deferred_control_to_dispatch_roots`, `psx_apply_deferred_control_to_live_objects`), with case `8` now narrowed further through direct callee naming as `psx_spawn_object_compound_effect_variant3`. The same pass also refreshes the live PSX naming census from MCP `list_functions`: `1274` local `0x800...` functions with `917` named and `357` still anonymous, for a current local naming floor of `71.98%`.
Recent verified combat-data batch: [docs/combat-dat.md](docs/combat-dat.md) now documents the shipped `COMBAT.DAT` archive end to end. Current best read is that all local Remorse/Regret variants ship the same `14`-record combat-tactic archive, each record contains a `16`-byte name plus four block offsets and bytecode, and the tactic VM is now grounded both in the live `CRUSADER.EXE` helpers (`Attack_SetupForTacticNo`, `Attack_SetupForBlockNo`, `NPC_Get/SetNPCTacticNo`) and in ScummVM's readable Crusader attack-process implementation. The new note also promotes the per-tactic human-readable catalog, including the midpoint-pressure, marker-shuttle, step-out-shoot, and stationary-chaos families.
Recent verified NE movement/collision batch: [docs/raw-0008-000c.md](docs/raw-0008-000c.md) now extends the live `AreaSearch_CollideMove` lane one helper layer deeper. Current best read is that the collision-storage queue is no longer only anchored at `StorageDataProcess_Create` / `Run` and the legal-move wrappers: the live database now also carries the step-aware seg029 sweep helpers `AreaSearch_SweepShapeBetweenPoints`, `AreaSearch_SweepItemToPointWithStepUp`, and `AreaSearch_SweepShapeBetweenPointsWithStepUp`, the seg031 release-side queue cleanup pair `StorageDataProcess_Release` and `storage_process_ref_list_terminate_item_matches`, and adjacent seg090 helper `ItemCache_PushAndPopToDirectionalOffset`. The practical remaining gap in this lane is now earlier caller policy rather than local helper identity.
Recent map-renderer egg-link follow-up: [docs/map_renderer/egg-identification.md](docs/map_renderer/egg-identification.md) now closes the old No Regret map-`3` destination-egg `102` gap. Current best read is that Regret uses a second elevator family at `shape:400` (`0x0190`) in addition to the earlier Remorse-focused `shape:542` rule: recovered Regret `ELEVATOR::gotHit` accepts `QLo >= 100`, treats `QLo < 0x00c8` as the generic same-map lane, and map `3` contains a concrete source object `item:664:fixed:400:0:44030:9662:0` with `quality 614` (`QLo 102`) that resolves the previously unexplained destination egg `102`.
Recent map-renderer editor-object follow-up: [docs/map_renderer/trigger-usecode-links.md](docs/map_renderer/trigger-usecode-links.md) and [docs/map_renderer/editor-object-survey.md](docs/map_renderer/editor-object-survey.md) now promote a Regret-only controller cluster that had still been sitting in the unresolved editor bucket. Current best read is that `0x04c6` / `0x04de` are `WATCHNS` / `WATCHEW` secret-door watcher controllers, `0x0510` is their nearby `SECRET_DOOR_POST` target keyed by shared `QLo`, `0x05e1` is `CRYOBOX`, and `0x05df` / `0x05e0` are the paired pressure-barrier faces it drives by shared `QLo`. The same batch also closes `0x0451` / `0x05ae` as `CRAZYEW` / `CRAZYNS` hit-driven NPC wake-up relays and `0x056d` as `VIDEOBOX`, then promotes cautious local viewer arrows for `WATCH* -> 0x0510` and `CRYOBOX -> 0x05DF/0x05E0` in the map renderer.
Recent map-renderer control-pad follow-up: [docs/map_renderer/egg-identification.md](docs/map_renderer/egg-identification.md), [docs/map_renderer/trigger-usecode-links.md](docs/map_renderer/trigger-usecode-links.md), and [docs/map_renderer/editor-object-survey.md](docs/map_renderer/editor-object-survey.md) now tighten the `0x0318` / `0x0366` read using the decompressed `.cache` scenes rather than the packed site export. Current best read is that `0x0318` is `CRUMORPH`, not a generic placeholder cube: both extracted usecode corpora expose class `0x0318` as `CRUMORPH`, and the recovered `equip` body is a control-transfer pad that scans nearby NPCs for a local-`QLo` actor-key match before bracketing `TRIGGER.slot_20`. The strongest current viewer promotion is still grounded in Regret scene evidence, where authored same-`QLo` local `CRUMORPH -> 0x04B1` matches are strong enough to expose, while `0x0366` remains `NPC_ONLY`, a hit-driven NPC-only trigger pad keyed by an internal actor field.
Recent map-renderer controller follow-up: [docs/map_renderer/trigger-usecode-links.md](docs/map_renderer/trigger-usecode-links.md) and [docs/map_renderer/editor-object-survey.md](docs/map_renderer/editor-object-survey.md) now tighten three more shared controller shapes. Current best read is that `0x00A2` is `PANELEW`, the east-west panel-switch counterpart to `PANELNS`; `0x03C1` is `GENERATR`, a destroyable generator/controller whose `gotHit` body immediately forwards into `TRIGGER.slot_20` lane `0`; and `0x04E7` is the same `DEATHBOX` class in both Remorse and Regret rather than a Remorse-only crosswalk. The map viewer now has enough evidence to label those shapes directly, open `PANELEW::use` / `GENERATR::gotHit`, and expose cautious same-`QLo` cmd-link arrows for `PANELEW` and `GENERATR`.
Recent actor-key follow-up: the same map-renderer notes now make the current blocker explicit instead of leaving it as an implied missing export. Current best read is that the hidden actor-side value behind `CRUMORPH` / `NPC_ONLY` is mutable actor field `0x63`, not a stable DTABLE row: sampled Regret DTABLE rows still read as zero at record byte `0x63`, while recovered `TRIGGER.slot_29` / `slot_2B` lanes can rewrite actor field `0x63` on nearby matched NPCs after load. The same pass also widens the sibling-family set that uses this mechanism: `WATCHNS` / `WATCHEW`, `THRMBCKN` / `THRMBCKE`, and `SURCAMNS` / `SURCAMEW` all compare controller-local bytes against actor field `0x63` in recovered lanes, so the viewer now documents a broader actor-key controller family while still withholding speculative actor-target arrows.
Recent verified PSX pre-alpha batch: [docs/psx/prealpha.md](docs/psx/prealpha.md) now records a focused Ghidra pass on `/psx/prealpha/SLUS_002.68` plus a disc-tree comparison against the released PlayStation `Crusader: No Remorse` build. Current best read is that this pre-pre alpha still looks much more like a trimmed early No Remorse PSX branch than a clearly rebranded `Crusader 2` executable: it still carries direct `Crusader: No Remorse` save/quit text, the renamed `wdl_resource_bundle_load_by_index` still embeds the full retail `\LSET1\L` through `\LSET7\L` prefix table and the same `10/20/30/40/50/60` threshold ladder, and the mission/passcode UI scaffolding is still present with the same visible `15` mission briefing strings and consonant/digit passcode alphabet. The main concrete differences in this batch are the heavily reduced shipped content (`3` level bundles, `1` XA, no `.STR` movies) and the surviving architectural leftovers that no longer match the current disc literally, especially the missing-file `\AUDIO\TALK1.XA;1` path and the `LoadExec` helper for `MENU.EXE` / `ENGINE.EXE` / `PSX.EXE`.
Recent verified PSX executable batch: [docs/psx/psx.md](docs/psx/psx.md) now records a focused Ghidra pass on `SLUS_002.68` for mission/map inventory, passcode handling, and catalog text. Current best read is that the PSX loader hardcodes seven `\LSETn\L` folder prefixes and the extracted disc ships `62` level bundles (`L0..L58`, `L62..L64`) with a real gap at `L59..L61`, while the executable still exposes only `15` plain-text `Mission Briefing ^Mission N` strings. The same pass closes the visible passcode-generation side too: mission-complete flow synthesizes `4`-character passcodes from the alphabet `BCDFGHJKLMNPQRSTVWXZ0123456789`, and the executable preserves direct ammo/item/weapon name tables. The hidden password-screen cheat codes remain less direct: public PSX references point to `XXXX` and `L0SR`/`L0SER`, but those values are not stored as plain ASCII in `SLUS_002.68`, so the compare path still looks numeric or transformed rather than table-driven.
Recent verified Japanese-build batch: [docs/jp-remorse-windows9x-investigation.md](docs/jp-remorse-windows9x-investigation.md) now records a focused live-Ghidra investigation of `/ja/CRUSADER.EXE` around the claim that the Japanese release runs natively on Windows 95 / Windows 9x instead of requiring a DOS boot path. Current best static-analysis read is strongly in favor: the JP executable is a flat Win32 image with PE-style sections, a Windows import table, native window creation, DirectDraw/DirectSound initialization, registry-backed config under `Software\Electronic Arts\Crusader: No Remorse\J1.21`, and a meaningful `GetVersion`-based Win9x compatibility branch that changes TLS allocation behavior when the classic Win9x high bit is set. The only remaining uncertainty is practical deployment rather than architecture: this pass did not runtime-test on real Win95 or prove which DirectX/runtime prerequisites are required.
Recent verified Japanese-build follow-up: [docs/jp-remorse-cheats-and-launch-params.md](docs/jp-remorse-cheats-and-launch-params.md) now records a focused pass on the surviving cheat/debug and startup-argument lanes in `/ja/CRUSADER.EXE`. Current best read is that the JP Win32 build kept real executable cheat/debug machinery, not just leftover strings: `-laurie` is still a special parser case, the hidden `JASSICA16` sequence matcher still toggles the cheat-active state with live `Cheats are now active/inactive.` messages, the option-key handler still contains the immortality toggle path, and the command-line parser still executes live handlers for `-debug`, `-u <arg>`, `-warp <mission>`, `-skill <n>`, `-mapoff <delta>`, `-egg <id>`, and `-demo`. The same pass also narrows one important difference from older DOS-side notes: the JP Win32 parser has not yet been proven to support positional `-warp <mission> <x> <y> <z>` consumption, so that form should not currently be assumed for this build.
Recent verified localized-build batch: [docs/spanish-cheat-differences.md](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 startup fixed-map patch batch: [docs/startup-map-patch-file.md](docs/startup-map-patch-file.md) now records the current evidence-backed read of the retail `Using map patch file.` startup line. Current best read is that `Init_Everything` at `1048:039b` prints that line only if `static\fixed.dat` exists, and the later fixed-map loader path treats that file as a preferred alternate `FIXED.DAT` source by loading it into `DAT_1478_1064` and choosing that handle over the base archive handle when present. The safest current wording is therefore `alternate fixed-map archive selected at startup`, not `the -u usecode override` and not a proven per-record merge overlay.
Recent Remorse NPC class-lift batch: new note [docs/npc-action-process-class-layout.md](docs/npc-action-process-class-layout.md) now records the first owner-first lift of the bounded seg033 NPC AI process family in live `CRUSADER.EXE`. Current best read is that this lane now has real class ownership rather than only flat function names: `Remorse::NPCActionProcess` owns the shared create/destroy/no-op surface, `Remorse::{StandProcess,PaceProcess,SurrenderProcess,GuardProcess,LoiterProcess}` now own their direct create/run/destroy methods, and the guard/loiter-only helper `NPC_DoRandomIdleAnimTwiceIfNotBusy` remains intentionally outside those class owners until stronger single-class ownership evidence appears. The remaining open work in this lane is now datatype and slot semantics, not basic object identity.
New roadmap note: [docs/function-knowledge-roadmap.md](docs/function-knowledge-roadmap.md) now turns the current decompilation state into a concrete path toward broad function coverage, with explicit completion criteria, lane priorities, and batch rules. The same note now also records the latest applied process-family rename work: `1100:0437` = `SurrenderProcess_Destroy`, `1100:0913` = `NPC_DoRandomIdleAnimTwiceIfNotBusy`, `1100:0d3e` = `LoiterProcess_VtableSlot10DispatchByShapeIfAlive`, `1100:0fe8` = `PaceProcess_Destroy`, `1100:0f95` = `GuardProcess_Destroy`, `1100:0f47` = `LoiterProcess_Destroy`, `1100:1036` = `StandProcess_Destroy`, `1100:1084` = `NPCActionProcess_RunNoop`, `1100:1089` = `NPCActionProcess_Destroy`, `1100:0fe3` = `NPCActionProcess_VtableSlot10Noop`, `1128:1e14` = `CruHealer_Destroy`, `1128:1fbe` = `BatteryChargerProcess_Destroy`, `1128:22ca` = `DeathSilenceProcess_Destroy`, `1110:0f19` = `PathfinderProcess_Destroy`, `1090:0aaf` = `TeleporterProcess_Destroy`, `1090:0a60` = `EggHatcherProcess_Destroy`, `1020:087e` = `MapJumpProcess_Destroy`, `1028:06bd` = `FadeProcess1_Destroy`, `1030:03cc` = `AnimProcess_Destroy`, `1058:08fc` = `SnapProcess_Destroy`, `10a0:4437` = `ItemProcess_Destroy`, `1138:0819` = `SuperSpriteProcess_Destroy`, `1150:32d3` = `OneFrameDelayProc_Destroy`, `1180:1e0a` = `CameraProcess_Destroy`, `11b8:0293` = `KeyDaemonProcess_Destroy`, `11b8:04c5` = `KeyboardProcess_Destroy`, `11c0:06df` = `AccWaitProcess_Destroy`, `11c0:0748` = `SystemTimerProcess_RunNoop`, `11c0:074d` = `SystemTimerProcess_Destroy`, `11c8:03fd` = `BiosProcess_Destroy`, `13b8:012e` = `CustomWaitProcess_Destroy`, `1430:0363` = `DumbTimerProcess_Destroy`, `1438:0557` = `CycleProcess_Destroy`, `1440:0f67` = `FadeProcAlt_Destroy`, `1468:4322` = `MyTimerProcess_Destroy`, `1468:0494` = `VideoPlayer_Destroy`, `1468:03e3` = `VideoPlayer_InitializePlayback`, `1468:2f7c` = `VideoPlayer_OpenMediaFiles`, `1468:32cb` = `VideoPlayer_AllocPlaybackBuffers`, `1468:3904` = `VideoPlayer_OpenMoviListAndPrimeStreams`, `1468:0483` = `VideoPlayer_StopAndDestroyWrapper`, `1468:431d` = `VideoPlayerProcess_VtableSlot11Noop`, `1468:001a` = `File_Exists`, `1468:03b4` = `VideoPlayer_FormatErrorMessage`, `1468:17b0` = `VideoPlayer_AdvanceChunkCursor`, `1468:1d3d` = `VideoPlayer_AdvanceChunkCursorWrapper`, `1468:1ef7` = `VideoPlayer_LoadAudioChunk`, `1468:1929` = `VideoPlayer_LoadVideoChunk`, `1468:1a92` = `VideoPlayer_BlitDecodedFrame`, `1030:0428` = `GameTimeProcess_Destroy`, `1030:03c7` = `AnimProcess_RunNoop`, `1048:0d3e` = `Process1048_0000_RunNoop`, `1048:0d43` = `Process1048_0000_Destroy`, `1050:051f` = `SavegameSlot_GetLabelPtr`, `1050:0532` = `SavegameSlot_SetLabel`, `1050:057e` = `File_CloseAndMaybeFree`, `10c0:00b9` = `MapJumpProcess_VtableSlot10AdvanceItemFind`, `10e8:4192` = `AnimPrimitiveProcessSomethingElse_Destroy`, `10f8:0120` = `ItemScript_AppendBytes`, `10f8:0161` = `ItemTypeflagRecord_ResetDefaults`, `1150:2f20` = `AnimPrimitiveProcessFamily_VtableSlot11CallSlot3`, `1188:0057` = `Process1188_0000_RunOnTimerDelta`, `1188:0979` = `Process1188_0000_Destroy`, `11c0:0483` = `WaitProcessFamily_VtableSlot10DispatchByPair`, `11c0:0691` = `WaitProcess_Destroy`, `11c0:02bf` = `AccWaitProcess_VtableSlot10DispatchByAnimation`, `1138:0444` = `SpriteProcess_Destroy`, `12e0:0151` = `ASS_StoreInitCallbackState`, `13c8:03f5` = `MainMenu_Destroy`, `13c8:04ee` = `MainMenu_DrawCornerDecorations`, `13c8:06a4` = `MainMenu_HandleButtonClick`, `13c8:06cd` = `MainMenu_HandleKey`, `13c8:082e` = `MainMenu_ActivateSelection`, `13c8:0ce7` = `MainMenuOptionButtonGump_Create`, `13c8:0dc0` = `MainMenuOptionButtonGump_HandlePointerEvent`, `13c8:0e2d` = `MainMenuOptionButtonGump_SelectPeer`, `13c8:0e94` = `MainMenuOptionButtonGump_Draw`, `13c8:0ece` = `MainMenuOptionsPanel_Create`, `13d0:0000` = `SavegameNameField_MapInputChar`, `13d0:0226` = `SavegameMenu_Destroy`, `13d0:02cb` = `SavegameMenu_HandleKey`, `13d0:03dd` = `SavegameMenu_HandleSlotAction`, `13d0:058c` = `SavegameSlot_DrawCornerDecorations`, `13d0:074e` = `SavegameSlotGump_Create`, `13d0:0841` = `SavegameSlotGump_Destroy`, `13d0:08a8` = `SavegameNameField_HandleKey`, `13d0:0b0a` = `SavegameSlot_HandleClick`, `13d0:0b89` = `SavegameSlot_BeginEditOrActivate`, `13d0:0cd5` = `SavegameNameField_Draw`, `13d0:0e18` = `SavegameSlot_Select`, `11c8:03c9` = `BiosProcess_VtableSlot10DosRealFarCall`, `1108:2259` = `AttackProcess_VtableSlot10DispatchByClip`, `1030:0183` = `AnimProcess_VtableSlot10DispatchByPort`, `1300:0d4e` = `BaseCameraProcess_VtableSlot10SetViewportRect`, `1300:0d76` = `BaseCameraProcess_VtableSlot11FreeBuffer`, `13b8:021a` = `CustomWaitProcess_VtableSlot11ArmAndRun`, `1440:03a0` = `FadeProcess2_VtableSlot10BlendTowardTargetPalette`, `1448:08fd` = `FlicPlayProcess_Destroy`, `1448:3290` = `FlicWaitProcess_Destroy`, `11f8:00a4` = `MusicPlayerProcess_RunNoop`, `11f8:035e` = `MusicPlayerProcess_Destroy`, `11f8:028e` = `Music_RestorePreviousTrackFromStack`, `11f8:02bf` = `Music_LoadStateAndReplayCurrentTrack`, `11f8:0311` = `Music_SaveState`, `12e0:0267` = `AssProcess_Destroy`, `1448:00eb` = `FlicWaitProcess_VtableSlot10TickAndMaybeAdvance`, `11f8:00a9` = `MusicPlayerProcess_VtableSlot10Noop`, `12e0:00ed` = `AssProcess_VtableSlot5ClearCreatedFlag`, `12e0:0105` = `AssProcess_VtableSlot6SetCreatedFlag`, `1020:08cd` = `Process_VtableSlot4Noop`, `1020:08d2` = `Process_VtableSlot8Noop`, `1028:0724` = `Process_VtableSlot9ReturnZero`, `1468:0114` = `MyTimerProcess_VtableSlot10IncrementCounterOnTick`, `11f0:02b9` = `StdIntHandlerProcess_Destroy`, `12f8:0530` = `GumpShared_DestroyNoop`, `12f8:0544` = `KeyboardInputHandler_DestroyNoop`, `12f8:0553` = `GumpShared_VtableSlot10Noop`, `12f8:0578` = `KeyboardInputHandler_VtableSlot10Noop`, `12f8:057d` = `KeyboardInputHandler_VtableSlot11Noop`, `1308:0616` = `ButtonGump_Destroy`, `13c0:04ee` = `KeypadGump_Destroy`, `13c0:0a94` = `KeypadButtonGump_Destroy`, `13e8:3aae` = `HelpGump_Destroy`, `13e8:3ba5` = `HelpGump_RefreshPage`, `13e8:3d53` = `HelpGump_HandleAdvanceAction`, `13e8:3d99` = `HelpGump_HandleNavigationKey`, `13e8:3ec8` = `HelpGump_RunAmbientSfxTick`, `13e8:3fd8` = `RunCreditsProcess_Destroy`, `13f8:01e9` = `QuickSaveLoadExitGump_Destroy`, `13f8:0510` = `Gump13f80383_Destroy`, `13f8:058c` = `Gump13f80383_Draw`, `13f8:05c6` = `Gump13f80383_VtableSlot10Noop`, and `13f8:05cb` = `Gump13f80383_VtableSlot11Noop`. That work is now live in Ghidra, and it also confirms the practical write-path rule for future work: read-only MCP analysis can stay on the live GUI session, while live write-capable scripts can land small verified rename/comment batches when the simpler edit-plan route refuses to commit.
Latest broad-sweep correction batch: several previously over-specific gump no-op names were generalized after direct table evidence showed they are shared across multiple gump families, not keyboard-only handlers. The live database now carries `12f8:0535 = GumpShared_VtableSlot3Noop`, `12f8:0544 = GumpShared_VtableSlot7Noop`, `12f8:0549 = GumpShared_VtableSlot8Noop`, `12f8:054e = GumpShared_VtableSlot9Noop`, `12f8:0578 = GumpShared_VtableSlot16Noop`, and `12f8:057d = GumpShared_VtableSlot17Noop` from direct `g_helpGumpFnPtr` / `g_gump13f80383FnPtr` slot reuse at `1478:6241` and `1478:6346`.
Latest broad-sweep UI follow-up: the same UI-heavy lane is now tighter in three more local families without requiring deeper subsystem claims. The live database now carries `12f8:02e4 = GumpShared_DestroyCommon`, `13f8:0237 = QuickSaveLoadExitGump_HandleChildButtonEvent`, `13f8:0299 = QuickSaveLoadExitGump_HandleKey`, `13f8:0349 = QuickSaveLoadExitGump_DrawLabel`, `13f8:0383 = QuickSaveLoadExitGump_Create`, `13c8:2f37 = MainMenuOptionsPanelButtonGump_Create`, `13c8:2fca = MainMenuOptionsPanelButtonGump_DrawLabel`, `13c8:3004 = MainMenuOptionsPanelButtonGump_Select`, `13c8:3030 = MainMenuOptionsPanelButtonGump_Deselect`, `13c8:1759 = MainMenuOptionsMenu_Destroy`, `13c8:17c5 = MainMenuOptionsMenu_Create`, `13c8:1e62 = MainMenuOptionsMenu_GetOptionRect`, `13c8:2975 = MainMenuOptionsMenu_HandleChildButtonEvent`, `13c8:29b3 = MainMenuOptionsMenu_HandleKey`, `13c8:2b16 = MainMenuOptionsMenu_DrawTitle`, and `13c8:2c56 = MainMenuOptionsMenuButtonGump_DrawLabel`. Current best read is that `12f8:02e4` is the shared gump base destroy path used by multiple UI families, the `13f8:` mini-cluster is the quick save/load/exit modal's constructor-plus-local input/draw surface, the `13c8:2f37..3030` cluster is the options-panel-specific button wrapper layered over the generic `1308:` button-gump create path, and the separate `13c8:1759..2c56` lane is now clearly the main options-menu create/destroy/input surface because its teardown path saves the current options back to config before the shared gump cleanup.
Recent retail debugger-entry follow-up: [docs/retail-debugger-entry-options.md](docs/retail-debugger-entry-options.md) now consolidates the hidden-debugger entry question with the newer live Ghidra evidence instead of leaving it split across the older `-debug` and patch-attempt notes. Current best read is now tighter in seven ways: first, fresh data-use recovery still finds reads but no writer for the debugger-state global at `1478:659c/659e`; second, fresh decompiles of `usecode_debugger_open_for_current_unit`, `usecode_debugger_open_modal`, `usecode_debugger_gump_create`, and `usecode_debugger_handle_event` confirm that the debugger UI and event bundle are real but only meaningful after a valid break-state object/gump already exists; third, the retail seg109 naming backlog is now partly landed live in `CRUSADER.EXE`; fourth, the follow-up live pass sharpened the retail child-pane split by identifying `13a0:16ee/1791/193f` as a watch-pane create/draw/click trio and `13a0:0ae8` as the source-pane line-state initializer from break-state current-line data; fifth, the latest MCP decompiles now make retail's surviving debugger surface explicit once the gump exists, including real file-open, run/step, go-to-line, watch, inspect, change-global, search, breakpoint-display, and pointer-to-source navigation logic; sixth, the same pass now closes the retail source-buffer lane far enough to describe the real file-ingestion path end to end, from source-buffer allocation/open through whole-file text load, in-place line splitting, and shared line-pointer lookup; and seventh, the decisive retail gap versus Regret remains unchanged and now better evidenced live: no caller to `1408:0000 Create`, no caller to the two open wrappers, and retail callback slot `0` still lands on the no-op `1408:046f` stub instead of a live frontend callback.
Recent No Regret debugger follow-up: [docs/regret-hidden-debugger-investigation.md](docs/regret-hidden-debugger-investigation.md) now also records the debugger-side cleanup pass after the first source-loader/runtime split, the final deep caller-recovery closure in the upstream Regret VM lane, and the first practical seeding model. The live `REGRET.EXE` database now has names and comments not just for the breakpoint/current-entry helpers, but also for the source-pane constructor/pointer/draw/viewport methods, the full source-buffer create/load/split/destroy chain, the interpreter saved-farptr helpers at `13f0:0000/003c`, the interpreter-context create/init pair at `13f0:00e8/0244`, and the shared slot-chunk accessor at `13f8:1d72`. The practical model is tighter in four ways: first, the broader `usecode_debugger_handle_event` map now shows explicit line-search, goto-line, and breakpoint-clear interactions over that loaded source buffer; second, the compiled-usecode question is no longer ambiguous, because retail Remorse already carries parsed `LINE_NUMBER` ops while Regret currently does not; third, the remaining debugger-seeding uncertainty is now narrowly bounded inside the already-identified interpreter dispatcher path rather than in some still-unmapped Regret-side subsystem; fourth, the seeding record itself now reads as a serialization of existing live interpreter pointers, which means a future bring-up can probably reuse in-process VM state with a small patch instead of depending on any hypothetical external preprocessor. It would improve source correlation, but even a future Regret-focused line-number injector would still not replace the missing interpreter-seeded current-entry stack needed for stable `RUN` / step behavior.
Recent JP hidden-debugger follow-up: [docs/jp-remorse-hidden-debugger-investigation.md](docs/jp-remorse-hidden-debugger-investigation.md) now records the first debugger-focused comparison pass on `/ja/CRUSADER.EXE`. Current best read is narrower than the No Regret result but still useful: the JP Win32 build clearly retains broad executable cheat/debug features, but this pass did not recover the classic hidden usecode-debugger UI signature bundle. Live byte searches on the active JP image found known positive-control strings like `JASSICA16`, `Immortality enabled.`, and `Cheats are now active.`, but returned no hits for the debugger-only strings `Goto Line`, `Watch what?`, `Inspect what?`, `Global name`, `Search for`, `FILE NOT FOUND`, `Unable to open this file`, `Nothing to find`, `Not found`, and `Done`. The practical outcome is that JP currently strengthens the `broad cheat/debug support survived in Win32` story, but not the `JP preserved the missing retail debugger bootstrap` theory; No Regret remains the stronger sibling-build anchor for the hidden-debugger unlock problem.
Recent verified batch: [docs/retail-debug-arg.md](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](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.
Recent map/editor visibility batch: [docs/editor-object-visibility.md](docs/editor-object-visibility.md) now records a focused live-Ghidra pass on whether retail `CRUSADER.EXE` explicitly hides editor-only map objects and whether any built-in switch re-enables them. The current best read is now tighter than the first pass: `Item_PaintSprite` at `1198:02e4` does contain a real downstream `flags2 & 1` (`SI_EDITOR`) early-out, but the active world-item renderer also has an upstream controlling skip at `1180:0951..095c` that filters editor-tagged shapes before draw-node allocation. That corrected render-path model explains why the first executable patch attempt, which only flipped the downstream draw-time branch, produced no visible change in-game. The same note still closes the negative side of the question more tightly: no recovered retail `-debug`, cheat/debug hotkey, Laurie/usecode-debugger path, or `0x410` event behavior currently reaches either gate or exposes a `show editor items` state. The closest confirmed toggle remains ScummVM's own `_showEditorItems` debugger command, which is an engine-added reimplementation feature rather than evidence of a retail built-in toggle.
Recent map-viewer trigger batch: [docs/map_renderer/trigger-usecode-links.md](docs/map_renderer/trigger-usecode-links.md) now records the evidence-backed editor/controller-object -> USECODE mapping used by the viewer when opening readable pseudocode from pinned tooltips. Current best read is that the stable viewer targets are `BOX_EW`, `PANELNS`, `CARD_NS`, and `SPANEL` -> `use`; `FASTSKIL` -> `enterFastArea`; `SKILLBOX`, `EVENT`, `ALARMHAT`, and `ALRMTRIG` -> `equip`; `TRIGPAD` and `NPC_ONLY` -> `gotHit`; and the `0x04B1` cmd helper itself -> `TRIGGER.slot_20`, the shared high-slot fan-out lane that nearby controller families keep spawning.
Recent usecode-event vocabulary note: [docs/usecode-event-slots-combine-cast-fast-area.md](docs/usecode-event-slots-combine-cast-fast-area.md) now records a focused evidence pass on the suspicious inherited `combine` / `cast` slot names and the current best meaning of `fast area`. Current best read is that shipped Crusader usecode exposes no recovered `slot_0C` handler bodies at all, while `slot_11 cast` is real but acts as a scripted activation/dispatch lane rather than a classic spell system. The same note also tightens `enterFastArea` / `leaveFastArea` to `authored proximity/activation region` callbacks instead of the older speed-zone-style shorthand.
Recent startup/map-selection batch: [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) now records the live proof that fresh-game map choice is code-selected rather than read from `CRUSADER.CFG` or another external mission-mapping file. For `CRUSADER.EXE`, the normal fresh-game path still hardcodes map `1`, egg `0x1e` inside `Game_Start`. For `REGRET.EXE`, the same values are hardcoded twice: once in an early `Game_Start` selector and again in the later `FUN_1030_032d` mission-start path that actually controls a real new game. The same note also captures the separate debug `-warp mission` path: it indexes a small executable-embedded mission-to-map word table at `1478:0488` (`0,1,3,5,...,0x1d,0x28`) and then applies `-mapoff`, while the actual map contents remain external in `FIXED.DAT`.
New REGRET startup-flow batch: [docs/regret-game-start.md](docs/regret-game-start.md) now documents the live `REGRET.EXE` `Game_Start` neighborhood more thoroughly. That note promotes `HandleCommandlineArgs`, `Game_RunNewGameFlow`, `Game_DrawCenteredStartupSplash`, `Game_EnterFrontendMenuViewport`, and `Game_RestoreGameplayViewport` in the live database, records the startup-state globals used by the new-game and `-warp` lanes, and explains the current best reason map `1` is set twice in No Regret: two separate live startup entry paths still own their own teleporter literals instead of sharing one final startup-map source.
New command-line argument batch: [docs/command-line-parameters.md](docs/command-line-parameters.md) now consolidates the currently recovered startup/debug argument set across the retail Crusader executables. The key new closure is the actual direct-warp syntax in `REGRET.EXE`: `-warp <mission> [x y z]` rather than separate `-x/-y/-z` switches. The same note also records the now-proven precedence rule that nonnegative `-egg` overrides beat the X/Y/Z teleport path, the practical parameter-only route into eggless maps (`-warp <mission> <x> <y> <z>` plus `-mapoff`, with `-egg` omitted), and the current best read of `-setver` as a displayed version/build-string override rather than a gameplay compatibility switch.
Follow-up No Remorse cross-check: the same command-line note and [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) now record the matching live `CRUSADER.EXE` proof. `HandleCommandlineArgs` at `1048:0adc` uses the same positional `-warp <mission> [x y z]` syntax as Regret, and `Game_Start` at `1020:029e` / `1020:02d0` applies the same precedence rule where nonnegative `-egg` overrides beat the direct-coordinate `NPC_Teleport` path.
Latest warp-table follow-up: the same [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) and [docs/regret-game-start.md](docs/regret-game-start.md) notes now close the missing No Regret table details directly. Live `REGRET.EXE` `Game_RunNewGameFlow` indexes the `-warp mission` base-map table at `1480:075c`, and retail byte checks now show the same 17-word payload as No Remorse: `0,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,40`, followed by a `0,0` terminator. The public renderer project now also has a dedicated extractor that writes both retail tables into `Crusader_Decomp_Public/map_renderer/.cache/mission-map-data.generated.json` for scene-metadata use.
Latest command-line follow-up: that same [docs/command-line-parameters.md](docs/command-line-parameters.md) note now closes the retail non-Japanese `-u` lane as well. In live `CRUSADER.EXE`, the parser case at `1048:0a46` copies the following token into `1478:065a`, and the newly named `startup_apply_u_override_if_present` at `1420:0cdf` consumes that buffer to load an alternate usecode/EUSECODE source into `1478:6611/6613` before rebuilding the cumulative slot-base words. Current best read is therefore `real startup usecode override`, not `JP-only feature` and not `dead parser-table residue`. The same follow-up also means the older consolidated `-setver` note is now weaker on the CRUSADER side and should be treated as needing a direct retail re-close.
Latest `-u` deep dive: new note [docs/usecode-startup-override.md](docs/usecode-startup-override.md) now follows that retail override into the live usecode runtime itself. Current best read is that `-u` replaces the single live usecode root at `1478:6611/6613` rather than adding a parallel overlay. The same root is later consumed by `Usecode_ItemCallEvent`, `UsecodeProcess_CreateProcess`, `Interpreter_NextUsecodeOp`, and `Item_GetDamaged`, so the override reaches ordinary scripted gameplay behavior, not just a startup-only side lane. Current safest tooling implication is `runtime replacement for the existing Crusader usecode VM`, not `arbitrary native plug-in system`.
Latest `-u` token-shape follow-up: the same [docs/usecode-startup-override.md](docs/usecode-startup-override.md) note now tightens the argument semantics materially. In live retail `CRUSADER.EXE`, `startup_apply_u_override_if_present` does not pass the copied argv token through as an arbitrary final filename. It loads the mutable filename template `eusecode.flx` from `1478:07a0` via the far pointer at `1478:06d6/06d8`, forces the first byte to `'e'`, and calls `Filespec_GetFullPath(0, s_usecode, "eusecode.flx", 0)`. Current safest read is therefore `path/root override for the standard EUSECODE archive family`, not `free-form arbitrary filename switch`. The same note now also separates the stock-path status more cleanly: the raw-side VM bootstrap is strongly cross-referenced, but the exact live-NE writer that seeds `1478:6611/6613` without `-u` is still not directly closed.
Latest `-u` practical follow-up: that same [docs/usecode-startup-override.md](docs/usecode-startup-override.md) and [docs/command-line-parameters.md](docs/command-line-parameters.md) notes now make the immediate user-facing consequence explicit. Failed attempts like `-u USECODE/FLICTEST.FLX` and `-u FLICTEST.FLX` fit the live helper badly because retail No Remorse still appends the fixed filename template `EUSECODE.FLX`; the copied argv token is only the path/root component. Current safest experiment shape is therefore `directory passed to -u, complete replacement archive named EUSECODE.FLX inside that directory`, not `free-form archive basename override`.
Latest `-u` loader-layout follow-up: the same [docs/usecode-startup-override.md](docs/usecode-startup-override.md) note now records the direct constructor/loader pair behind the override in the live NE session. `1420:1499` is now renamed `entity_vm_runtime_create` and currently reads as a `0x1319`-byte runtime-object constructor with a `0x1300`-byte front region that behaves like `0x80` stride-`0x26` slot/runtime records plus tail metadata at `0x1300..0x1318`. `1430:0000` is now renamed `entity_vm_runtime_owner_resource_create` and currently reads as the compact `0x14`-byte file-backed helper allocated from the resolved `eusecode.flx` path and attached to the runtime object at `+0x1315/+0x1317`.
Latest doc-reconciliation batch: [docs/ne-segment1.md](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`.
Latest hidden-debugger floor pass: [docs/retail-debugger-patch-attempts.md](docs/retail-debugger-patch-attempts.md) now records a fresh live-Ghidra constraint check on the smallest viable retail unlock patch. Current best read is tighter than the earlier "there must be one tiny jump" idea: retail still has no recovered writer for `1478:659c/659e`, the constructor still seeds only the inert shared callbacks `1478:65ab -> 1408:046f` / `1478:65af -> 1408:0474`, and the interpreter-side gate at `1418:049e..04b5` only checks for a non-null debugger object before handing off to `1408:0053`. That makes the current O/P interpreter-callsite-retarget family the smallest structurally defensible executable patch shape so far, because smaller one-site ideas lose either object bootstrap, one-shot deferred gating, or wrapper-argument sanitation.
Follow-up cheat-key correction pass: [docs/ne-segment1.md](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.
Latest F7 overlay follow-up: new note [docs/f7-overlays.md](docs/f7-overlays.md) now separates the three F7-family debug overlays more rigorously at the geometry level. The main correction is on `Alt+F7`: instead of treating it as broad egg coverage, the current best read now follows the live `SnapProcess` path directly, where `Snap_AddSnapEgg` is only reached for shape `0x04fe` and `Snap_GetSnapEggRange` derives the overlay rectangle from that item's `QHi`, `mapNum`, and `npcNum` bytes. The same note also clarifies the viewer-facing rule for plain `F7`: use an origin-aligned infinite `0x200`-unit world lattice across the visible viewport, not a screen-centered patch.
## Documentation Structure
| File | Contents |
|------|----------|
| [docs/overview.md](docs/overview.md) | Binary overview, installed copy findings, address space layout, NE fixup placeholder, segment map, NE import details, next steps |
| [docs/combat-dat.md](docs/combat-dat.md) | `COMBAT.DAT` archive layout, live `CRUSADER.EXE` tactic-field integration, shipped opcode subset, and a human-readable catalog of all `14` tactic records |
| [docs/phar-lap-extender.md](docs/phar-lap-extender.md) | DOS extender architecture, named functions (entry, loading, memory, I/O, interrupts), key string references |
| [docs/ne-segment1.md](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/f7-overlays.md](docs/f7-overlays.md) | Focused note on the three cheat-gated F7 debug overlays: toggle sites, live consumers, recovered geometry math, what each overlay represents, and the current viewer-safe reproduction rules |
| [docs/jp-remorse-windows9x-investigation.md](docs/jp-remorse-windows9x-investigation.md) | Focused note on the Japanese `/ja/CRUSADER.EXE` Windows-native claim: PE/Win32 image evidence, Win32 windowing, DirectDraw/DirectSound, registry config under `J1.21`, IME/DBCS clues, and the GetVersion-driven Win9x compatibility branch |
| [docs/jp-remorse-cheats-and-launch-params.md](docs/jp-remorse-cheats-and-launch-params.md) | Focused note on surviving JP `/ja/CRUSADER.EXE` cheat/debug and startup-argument lanes: `-laurie`, `JASSICA16`, immortality, the recovered Win32 parser table, the live `-u` usecode override, and the current caution that JP `-warp` is only directly proven in mission-only form |
| [docs/jp-remorse-hidden-debugger-investigation.md](docs/jp-remorse-hidden-debugger-investigation.md) | Focused first pass on whether the JP Win32 build kept the classic hidden usecode debugger: positive-control hits for surviving cheat/debug strings, but no live hits for the debugger-only UI string bundle (`Goto Line`, `Watch what?`, `Inspect what?`, `Global name`, `Search for`, `FILE NOT FOUND`, `Unable to open this file`, `Nothing to find`, `Not found`, `Done`) |
| [docs/spanish-cheat-differences.md](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](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](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](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](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](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](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/function-knowledge-roadmap.md](docs/function-knowledge-roadmap.md) | Concrete path to broad function coverage: completion criteria, prioritized workstreams, write-path discipline, staged rename batches, and immediate next steps |
| [docs/crusader-disasm-reference.md](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](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](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-debugger-entry-options.md](docs/retail-debugger-entry-options.md) | Focused retail hidden-debugger entry analysis: fresh live-Ghidra proof that `1478:659c/659e` still lacks a recovered writer, what the seg109 wrappers and gump constructor now prove about real reachability, why `-u` is the best low-risk experiment surface but still not a direct debugger bootstrap, and why No Regret / JP comparison is now the preferred next move |
| [docs/regret-hidden-debugger-investigation.md](docs/regret-hidden-debugger-investigation.md) | Focused live `REGRET.EXE` hidden-debugger comparison: recovered wrapper/gump/dispatcher equivalents, the seg13e0 break-state family, the seg13f0 interpreter-side consumer, the debugger global at `1480:712c/712e`, and the compact bootstrap stub at `1398:0000` that writes that global |
| [docs/retail-debug-arg.md](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/startup-map-patch-file.md](docs/startup-map-patch-file.md) | Focused note on the retail `Using map patch file.` startup line: exact `Init_Everything` print gate, `static\fixed.dat` detection, the later `ItemCache_InitAndLoadFixedDat` archive load, and the current evidence that fixed-map reads prefer the alternate archive when present |
| [docs/remorse-class-candidate-inventory.md](docs/remorse-class-candidate-inventory.md) | Evidence-backed inventory of the strongest current Remorse class families, with confidence, ctor/dtor/vtable/layout anchors, and recommended modeling order for later Ghidra class work |
| [docs/remorse-class-lift-index.md](docs/remorse-class-lift-index.md) | Central navigation note for the Remorse class-lift and C++-reconstruction prep lane, grouping the plan, candidate inventory, ABI notes, endpoint spec, and family-specific layout notes into one work order |
| [docs/remorse-first-class-authoring-checklist.md](docs/remorse-first-class-authoring-checklist.md) | Operational checklist for the first real Ghidra/MCP class-authoring batch, including pilot-family order, authoring rules, and source-emission readiness gates |
| [docs/remorse-cpp-decompilation-plan.md](docs/remorse-cpp-decompilation-plan.md) | Plan for shifting the current Remorse decompilation from flat C-like recovery toward evidence-backed C++ classes, typed object models, and an eventual recompilable source tree |
| [docs/remorse-cpp-compatibility-header-draft.md](docs/remorse-cpp-compatibility-header-draft.md) | Draft contract for the future compatibility/support header that early Remorse C++ skeletons should target: exact-width aliases, packing markers, calling-convention placeholders, segmented-pointer helpers, and slot-order guardrails |
| [docs/remorse-toolchain-fingerprint-evidence.md](docs/remorse-toolchain-fingerprint-evidence.md) | Focused evidence note for the current toolchain story behind Remorse reconstruction: bound `MZ -> NE` structure, Phar Lap runtime, loader-patched far calls, and the current High-C-related runtime fingerprints |
| [docs/ghidra-mcp-class-lifting-endpoint-spec.md](docs/ghidra-mcp-class-lifting-endpoint-spec.md) | Draft endpoint surface for future GhidraMCP class-lifting work: namespace/class creation, symbol moves, struct and vtable authoring, `this` typing, and transactional class-layout application |
| [docs/scummvm-crusader-reference.md](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](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](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/editor-object-visibility.md](docs/editor-object-visibility.md) | Focused note on retail editor-only map object hiding: the live `1198:02e4` `SI_EDITOR` early-out in the normal item paint path, the lack of a recovered retail visibility toggle, and the ScummVM/Pentagram cross-check that treats `show editor items` as an engine-side debug feature |
| [docs/entity-class-family-split.md](docs/entity-class-family-split.md) | Focused working note on the large seg001 `Entity` lane: shared base-layout evidence, conservative split into projectile, debris, corpse/remnant, and adjacent non-entity families, and the recommended promotion order for later class lifting |
| [docs/entity-dispatch-entry-class-layout.md](docs/entity-dispatch-entry-class-layout.md) | Focused working note for the `EntityDispatchEntry` family: base versus derived split, stable field groups, constructor and release surfaces, candidate method map, and conservative future Ghidra modeling order |
| [docs/entity-vm-runtime-owner-resource-layout.md](docs/entity-vm-runtime-owner-resource-layout.md) | Focused working note for the VM runtime lane: `EntityVmRuntime`, `EntityVmOwnerResource`, and `EntityVmContext` ownership, stable layout claims, masked-create helpers, and the safest current class-lift order |
| [docs/npc-action-process-class-layout.md](docs/npc-action-process-class-layout.md) | Focused working note for the seg033 NPC AI process family: current owner-first class lift, direct per-family create/run/destroy ownership, the shared guard/loiter idle helper, and the remaining slot/datatype gaps |
| [docs/presentation-callback-broker-layout.md](docs/presentation-callback-broker-layout.md) | Focused working note for the `0x4588` callback-object lane: install/teardown lifecycle, global state cluster, provisional vtable slots, payload-pair evidence, and conservative class-lift guidance |
| [docs/map_renderer/trigger-usecode-links.md](docs/map_renderer/trigger-usecode-links.md) | Evidence-backed map-viewer note for editor/controller shapes that now expose direct USECODE navigation, including the stable class/event targets and the special `TRIGGER.slot_20` handling for `0x04B1` cmd helpers |
| [docs/map_1_spawners_targeted_investigation.md](docs/map_1_spawners_targeted_investigation.md) | Focused map-1 note on suspicious `0x04D0` frame-paired spawners: decompressed-cache examples, the recovered `MONSTER -> ITEM.slot_2D -> create NPC` chain, QLo-based pairing, and the corrected `mapNum bit 0x08` enter-area interpretation |
| [docs/first-mission-map-selection.md](docs/first-mission-map-selection.md) | Focused note on fresh-game startup map selection: No Remorse `Game_Start`, No Regret's early and later mission-start selectors, the separate embedded `-warp mission` table, and the split between code-selected startup and external `FIXED.DAT` map content |
| [docs/regret-game-start.md](docs/regret-game-start.md) | Detailed `REGRET.EXE` startup-flow note: `Game_Start`, `Game_RunNewGameFlow`, newly named helpers, startup override globals, and the current best explanation for the duplicated map-1 selector |
| [docs/remorse-rebuild-abi-notes.md](docs/remorse-rebuild-abi-notes.md) | Working note for rebuild constraints: segmented-memory model, far-call provenance, runtime/toolchain evidence, ABI guardrails, and the split between original-style executable reconstruction and a behaviorally equivalent port |
| [docs/command-line-parameters.md](docs/command-line-parameters.md) | Consolidated startup/debug argument reference for the retail Crusader executables: live retail `-u` usecode override, the current `-setver` caution, `-debug`, `-asylum`, `-warp`, `-skill`, `-mapoff`, `-egg`, `-demo`, the `-laurie` cross-reference, and the evidence-backed direct-coordinate warp syntax/limits |
| [docs/psx/psx.md](docs/psx/psx.md) | PlayStation `SLUS_002.68` and disc-resource note: boot/load layout, `LSET`/menu WDL structure, executable-backed map inventory, passcode alphabet/display path, recovered PSX ammo/item/weapon tables, and current unresolved enemy/password-compare gaps |
| [docs/psx/jl-9-investigation.md](docs/psx/jl-9-investigation.md) | Focused PSX `SLUS_002.68` note on the `JL-9` weapon: recovered row/index evidence, the hidden transformed passcode branch that sets the debug gate, the bulk weapon-unlock helper's extra late channel, current art/level-placement status, and the remaining proof gaps |
| [docs/psx/map-rendering.md](docs/psx/map-rendering.md) | Detailed PlayStation map-rendering architecture note: `LSET*.WDL` storage model, constructor record layouts, runtime banks, state/variant/art bridge, stage-1 versus stage-2 render lanes, visible-list sorting, final primitive submission, and the current best recipe for reconstructing PSX maps in the viewer |
| [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) | Focused PSX viewer recovery note: extraction-versus-render diagnosis, zero-block `DAT_800758d8` constructor-family donor heuristics, measured fallback reduction, representative map stats, and the remaining outlier families/maps |
| [docs/psx/prealpha.md](docs/psx/prealpha.md) | PlayStation pre-pre alpha `/psx/prealpha/SLUS_002.68` comparison note: reduced disc inventory, retained retail-style `LSET` loader, surviving No Remorse branding, stale `TALK1.XA` and `LoadExec` leftovers, and the current read that this build is closer to an unfinished No Remorse PSX branch than to a visibly rebranded sequel executable |
| [docs/sprite-node-class-layout.md](docs/sprite-node-class-layout.md) | Focused working note for the `SpriteNode` family: current core layout, destructor and event-dispatch evidence, candidate virtual slots, and a conservative Ghidra modeling plan |
| [docs/usecode-startup-override.md](docs/usecode-startup-override.md) | Focused retail `-u` deep dive: startup call order, why the override looks like full live-root replacement rather than addition, which event/process/interpreter consumers use that root, and what that implies for future custom usecode experiments |
| [docs/usecode-roundtrip-ir.md](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-event-slots-combine-cast-fast-area.md](docs/usecode-event-slots-combine-cast-fast-area.md) | Focused note on whether inherited event labels `combine` and `cast` are actually live in shipped Crusader usecode, plus the current evidence-backed explanation of `enterFastArea` / `leaveFastArea` as proximity-trigger callbacks |
| [docs/usecode-pentagram-ghidra-path.md](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](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](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](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](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](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/flictest-investigation.md](docs/usecode/flictest-investigation.md) | Focused investigation of `FLICTEST`: class/body structure, Remorse versus Regret differences, confirmed caller scripts, and the stronger Regret finding that a hidden `KEYPADNS` `VIDEO PLAYER` route appears to have matching shipped placement evidence |
| [docs/usecode/windsurf-regret-vs-remorse.md](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 |
| [docs/removed_items.md](docs/removed_items.md) | Evidence summary for suspicious removed item shapes in old No Remorse maps: grenade-family leftovers `0343/034E/034F/0350`, the inventory-labeled `0548` `Invalid` item, and unresolved non-pickup shapes `0110/0112` |