# Retail `-debug` Argument in `CRUSADER.EXE` This note records the current evidence-backed read of the retail `-debug` command-line switch in the live NE `CRUSADER.EXE` database. Short version: - retail `CRUSADER.EXE` does recognize `-debug` - the switch is not fully disabled in the parser - it sets a global debug-print threshold and two debug-related globals - one surviving `-debug` feature is now concretely identified as an AVI/video-player timing overlay - current evidence does **not** show it constructing or wiring the hidden seg109/seg1408 usecode debugger state object at `1478:659c/659e` - current best read is `debug-print threshold plus movie-playback timing overlay`, not `the lost hidden debugger bootstrap` ## Verified Parser Evidence In the live NE image, `HandleCommandlineArgs` at `1048:09b9` contains a real branch for `"-debug"` at `1048:0a93`. The branch body does all of the following: - writes `0x000a` to `1478:87e0` (`g_debugMsgLevel`) - calls `ConsolePrintf(0x32, 1478:0ad6)` - writes `1` to `1478:0845` (`g_someDebugFlag`) - writes `1` to `1478:0859` (`g_someDebugFlag2`) So the parameter has exactly three direct state effects currently recovered: - it changes the global print threshold - it sets one still-unresolved debug latch at `1478:0845` - it enables the seg1468 video timing overlay through `1478:0859` The printed string at `1478:0ad6` is: `Debugging mode ON.` That is strong evidence against the narrow claim that retail only still recognizes the string but has the feature body disabled. The retail parser still executes real side effects when `-debug` is present. Nearby startup strings in the same table also confirm this is the normal command-line switch cluster: - `CRUSADER: No Remorse` - `Cheats are active.` - `You DO need help!` - `Debugging mode ON.` - `Enabling ENHANCED mode. (NOT!)` ## What Still Reacts To `-debug` ### 1. Debug message threshold is live `1478:87e0` is already symbolized as `g_debugMsgLevel` in the live export. Data-use recovery shows it is read by: - `ConsolePrintf` - `DebugPrintAndWaitForInput` - two adjacent positioned debug-print helpers in the same family (`12d0:0391`, `12d0:0442`) Current best read: - `-debug` sets the runtime print threshold to `10` - the compare in the wrappers is effectively `if (call_level < g_debugMsgLevel) skip` - so `-debug` does **not** create a new console sink by itself; it only changes which existing callsites are eligible to print - the shared print staging buffer at `1478:45a6` is allocated independently by `12d0:0513`, not by the `-debug` parser branch The low-level sink path is now tighter too: - `ProbablyPrintDebugMessage` at `1000:65cc` formats through the generic `ProbablySomethingDebuggy` / `FUN_1000_67ac` stream pipeline - that helper passes DS:`1478:6c46` as the target stream object - the surrounding DS data at `1478:6c32..1478:6c81` is a four-entry static stdio-style table with handle words `0`, `1`, `2`, and `3` - the `1478:6c46` entry is therefore the handle-`1` stream, i.e. the program's `stdout` slot Practical implication: - the text side of `-debug` is not a hidden second debugger UI and not a newly-created in-memory log sink - it is ordinary formatted DOS standard-output text gated by `g_debugMsgLevel` - the main reason it is easy to miss is that Crusader spends most of its runtime in graphics mode, while many eligible callsites are startup, shutdown, or failure diagnostics This matters because it narrows the real effect of the print side: - `-debug` definitely changes print gating - but it does not add a new visible on-screen text channel by itself - any visible text side effect depends on already-existing print callsites and on how DOS `stdout` is surfaced in the running environment ### 1a. What subsystems use that print gate Recovered `ConsolePrintf` callers show that the thresholded text/debug lane is not limited to video. Current caller families include: - command-line handling and startup/shutdown (`HandleCommandlineArgs`, `CheckForLaurieArg`, `Init_Everything`, `Uninitialize`) - config parsing (`LoadConfigFile`) - cache/shape rebuild work (`CacheShapeHand_1070_15a9`) - item/glob spawning failure paths (`ItemGlob_GlobEggHatch`) - drawlist or display initialization (`DList_Init`) - audio init (`Init_ASS`) - joystick init/calibration (`Joystick_Init`, `Joystick_Calibrate`, nearby helper `1400:0c7e`) - teleporter and several `UProcess_*` / `1428:*` runtime helpers The rarer blocking helper `DebugPrintAndWaitForInput` is much narrower. Current recovered callers are: - `Dispatch_Init_320_0281` - `Dispatch_1320_103e` - `NewGump_Alloc` Those are all failure/debug-stop style paths rather than normal AVI playback logic. Practical interpretation: - there **is** a non-video `-debug` lane - but the recovered non-video lane is primarily `thresholded debug/error text`, often in startup or failure handling - it is not currently a second confirmed visible feature on the level of the movie timing dots you observed ### 1c. Recovered printed strings and format strings The print inventory is now tighter than the earlier subsystem-only caller list. Recovered call levels so far: - `0x32` - `0xff` Because retail `-debug` sets `g_debugMsgLevel = 10`, both recovered levels are above threshold and therefore eligible to print when their code paths execute. #### Command-line and startup argument strings Recovered directly from `HandleCommandlineArgs` / `CheckForLaurieArg`: - `Cheats are active.` - `You DO need help!` - `Debugging mode ON.` - `Enabling ENHANCED mode. (NOT!)` - `Warping to mission %d.` - `Warping to mission %d @ x:%d y:%d z:%d.` - `Defaulting to skill level %d` - `Map offset = %d` - `Destination Egg = %d` - `Demo mode.` These are the cleanest first things to look for in DOSBox logging because they belong to deterministic early startup/argument paths. #### Init / config / install-status strings Recovered from `Init_Everything` and `LoadConfigFile`: - `Using map patch file.` - `Loading: [` - ` ]` - `.` - `Running with partial installation.` - `Running with full installation.` - `Redirecting mission %d tune to '%s'` Interpretation: - some of these are not human-readable status sentences so much as progress-bar fragments and single-character emitters - that means an `INT 21h` log may show very short writes rather than one tidy line of text #### Cache / rebuild strings Recovered from `CacheShapeHand_1070_15a9`: - `Creating Swap file [` - ` ]` - `] ` - `\n\r[` - ` ]\r[` - a single-byte progress marker at `1478:0e1e` Interpretation: - this lane appears to print progress scaffolding rather than rich prose - if DOSBox logs writes with counts but not payload text, many tiny startup writes may belong to this cache/swap-file progress path #### Runtime / failure diagnostics Recovered from narrower runtime and failure paths: - `dl init ` from `DList_Init` - `COULD NOT CREATE GLOB ITEM!` from `ItemGlob_GlobEggHatch` These are useful because they are strong “real debug text” fingerprints if they ever show up in a live log. #### Audio init marker Recovered from `Init_ASS`: - `.` Current best read: - this is another minimal progress marker, not a descriptive sentence #### Blocking `DebugPrintAndWaitForInput` strings Recovered from the three currently known `DebugPrintAndWaitForInput` callers: - `No room for Dispatcher Record/Playback.` - `End of script! (press any key)` - `Out of Memory! [%u]` Interpretation: - these are failure/debug-stop strings - they are good fingerprints for recognizing the lane, but they should not be expected during healthy normal gameplay #### Shutdown strings Recovered from `Uninitialize` and nearby startup/shutdown text: - `CRUSADER: No Remorse` - `No pity. No mercy. No remorse.` Current best read: - the first is a normal shutdown-side banner - the second is associated with the Laurie-enabled lane and is not a generic `-debug` print on its own ### 1b. How to read that text in practice Current best evidence-backed read is: - the messages go to the executable's normal DOS `stdout` stream, not to a bespoke debugger console - if `stdout` is left attached to `CON`, text may only be practically visible when Crusader is still in a text-ish startup/shutdown context or when a failure path forces a text-mode-style report - replacing `stdout` with a disk file via shell redirection is now a poor default recommendation, because live user testing showed `CRUSADER.EXE -debug > DEBUG.TXT` surviving startup but crashing after the intro cutscene What this does and does not mean: - plain file redirection probably changes the handle-1 stream semantics enough to destabilize later stdio/device logic in this executable or runtime - it will not magically produce extra chatter unless existing callsites actually execute at or above the threshold - it does not by itself surface the hidden seg109/seg1408 debugger UI, because that is a separate control path Remaining caution: - this is a strong static conclusion about the sink identity - runtime capture details still depend on the exact DOSBox / shell setup, because the game often runs after switching away from a normal text-console presentation - safest current guidance is to keep handle `1` attached to a character-device-style sink and capture around it, rather than redirecting directly to a regular file ### 2. `g_someDebugFlag2` is live `1478:0859` (`g_someDebugFlag2`) is written by the `-debug` parser branch and read later in segment `1468`. Recovered readers: - `VideoPlayer_AdvanceFrameAndHandleSkip` (`1468:2869`) - `VideoPlayer_StreamChunks` (`1468:2af4`) Both routines conditionally call `VideoPlayer_DrawDebugTimingOverlay` (`1468:2de9`) when `g_someDebugFlag2 != 0`. The current live export already places these functions in the `VideoPlayer_*` neighborhood: - preceding function `1468:283f..2868` is typed as `VideoPlayer_Run(struct Process * p_proc)` - `AVI_1468_2188` is an AVI-header parser that recognizes `AVI ` / `LIST` / `strl` / `strh` / `strf` - `FUN_1468_3904` is a later `movi`-chunk setup/prime path that calls `VideoPlayer_StreamChunks(..., 1)` Current best read of this lane: - this is part of a video / presentation / media-processing subsystem - `-debug` leaves behind an extra instrumentation path in that subsystem - the behavior does not currently look like debugger-object creation, breakpoint management, or usecode UI entry `VideoPlayer_DrawDebugTimingOverlay` is now specific enough to describe concretely: - it clears a temporary `0x1f4`-byte buffer (`500` bytes) - it computes marker positions from AVI timing fields using a divisor of `6000` - it writes marker bytes `8` and `9` into that temporary line buffer - it copies the resulting `500`-byte line into a video buffer near offset `0x1de * 0x280 + 0x78` - it builds and copies a second `500`-byte line into the next scanline at `+0x280` Because the helper writes into two adjacent scanlines of a `0x280`-wide (`640`-pixel) buffer near the bottom of the frame, current best read is: - this is a built-in movie-playback timing overlay or marker strip - it is probably intended to visualize AVI/video timing state while playback is running - it is a practical runtime feature that may be observable during intro/cutscene playback when launched with `-debug` - it is still unrelated to the seg109/seg1408 usecode debugger object model Runtime confirmation now matches the static read: - the observed moving dots at the bottom of played videos are consistent with this helper's two-line marker overlay - that closes the strongest user-visible effect of retail `-debug` ### 3. `g_someDebugFlag` is only weakly understood `1478:0845` is symbolized as `g_someDebugFlag` and is also written by the `-debug` branch. Current evidence is weaker here: - the parser write is confirmed - no equally clear downstream reader has been recovered yet Current safest read: - this is a real surviving `-debug` state cell - it may be vestigial, sparsely used, or hiding inside still-unrecovered data/indirect uses - it should not currently be overinterpreted as a debugger bootstrap flag At this point the absence evidence is fairly strong: - direct data-use recovery still finds only the parser write - nearby bytes `1478:0844` and `1478:0846` do have real readers/writers, so this is not just a search blind spot across the whole region - current best read is `orphaned or still-hidden latch`, not `known active second feature` ## Comprehensive Current Effect Summary Based on the current live NE evidence, retail `-debug` enables or changes the following and no more has yet been proven: ### Confirmed direct effects 1. It prints `Debugging mode ON.` during command-line handling. 2. It sets `g_debugMsgLevel` at `1478:87e0` to `10`. 3. It sets `g_someDebugFlag` at `1478:0845` to `1`. 4. It sets `g_someDebugFlag2` at `1478:0859` to `1`. ### Confirmed runtime-visible effect 1. It enables the seg1468 AVI/video-player timing overlay, which draws moving marker dots or traces near the bottom of played videos. ### Confirmed non-video effect class 1. It changes eligibility for existing debug/error print wrappers used across startup, config, cache, joystick, audio, item/glob, dispatch, and some runtime process code. 2. A smaller subset of those callsites are blocking `print-and-wait` diagnostics used on failure/debug-stop paths in dispatch/gump allocation code. 3. The recovered text sink for those wrappers is the program's handle-`1` stdio stream at `1478:6c46`, so the lane is standard-output text rather than a separate debugger-only channel. 4. The recovered printable inventory is currently dominated by startup/status/progress strings plus a smaller number of failure-only diagnostics; it is not a rich always-on gameplay console. ### Things not currently proven as practical effects 1. A new visible text console or new text window. 2. Any hidden usecode debugger bootstrap. 3. Any connection to the seg109/seg1408 debugger-state pointer at `1478:659c/659e`. 4. Any second confirmed user-visible feature beyond the AVI timing dots. 5. Any active downstream behavior for `1478:0845`. ## What `-debug` Does **Not** Currently Prove The hidden retail debugger / unit-inspector work already mapped elsewhere in this repo still centers on: - seg109 UI wrappers such as `usecode_debugger_open_for_current_unit` and `usecode_debugger_open_modal` - seg1408 debugger-state helpers such as `usecode_debugger_break_state_create` and `usecode_debugger_maybe_break_on_current_line` - the global debugger-state far pointer at `1478:659c/659e` That `1478:659c/659e` pointer is still read by the known interpreter-side debugger path, including the break callback lane around `1418:04aa..04b5` and the seg109 debugger-opening wrappers. What has **not** been shown in the current `-debug` pass: - no recovered write from the `-debug` branch to `1478:659c/659e` - no evidence that `-debug` calls `usecode_debugger_break_state_create` - no evidence that `-debug` enters `usecode_debugger_open_for_current_unit` - no evidence that `-debug` is the same switch as `-laurie` So the current answer is: - `-debug` is real - `-debug` still does something - but it is currently **not** the same evidence trail as the hidden usecode debugger bootstrap ## Relationship To `-laurie` The two switches should stay separated. Current repo evidence still supports: - `-laurie` / `CheckForLaurieArg(...)` writes the cheat/debugger gate at `1478:0844` (`g_wasLaurieSet` / prior `cheats_enabled` lane) - `-debug` is handled inside the normal command-line option loop in `HandleCommandlineArgs` - `-debug` writes `1478:0845`, `1478:0859`, and `1478:87e0`, not `1478:0844` That means the old hidden debugger/UI work and the `-debug` switch are adjacent only at a broad `debug features existed` level. They are not currently the same recovered control path. ## Best Current Conclusion The wiki claim is only partly right. Accurate part: - there really is a retail `-debug` command-line argument Inaccurate or currently unsupported parts: - it is not merely a dead recognized string; the parser branch is still live - the current evidence does not support `secondary monitor debug kernel` specifically - the current evidence does not support `-debug` as the missing bootstrap for the hidden seg109/seg1408 usecode debugger Best current evidence-backed replacement claim: > Retail `CRUSADER.EXE` still recognizes and executes a live `-debug` branch. That branch prints `Debugging mode ON.`, raises the debug message level, and enables a concrete seg1468 AVI/video-player timing overlay that draws two 500-byte marker traces into adjacent scanlines near the bottom of the playback buffer. However, current evidence does not show it creating the seg1408 debugger-state object at `1478:659c/659e`, so it should not currently be treated as the missing bootstrap for the hidden usecode debugger UI. ## Claim Check: `E69FB` And The "Secondary Monochrome Monitor" Idea An external claim said the potential debug instructions were at flat file offset `E69FB` and might only be visible on a secondary monochrome monitor. Current evidence does not support that. ### `E69FB` mapping Using the local NE segment map: - NE segment `144` begins at file offset `0xE3C00` - flat offset `0xE69FB` therefore lands at segment-relative offset `0x2dfb` - in the live NE image that maps to `1478:2dfb` The bytes around that location are not executable instructions for a hidden monitor-debug path. They fall inside a data/string cluster: - `KeyboardProcess` - `KEYIO.C` - `PRIORITY.C` - `SystemTimer` - `SYSTIMER.C` - `AccWait` `1478:2dfb` itself lands inside the `SYSTIMER.C` string, not inside a code body. Current safest read: - the cited flat offset is almost certainly a mistaken pointer into a data/descriptor/source-file-name region - it is not a useful anchor for `-debug` behavior and not evidence for hidden display-specific code by itself ### Secondary monochrome monitor check The current `-debug` evidence points elsewhere: - text/debug output goes through the normal `stdout` sink at `1478:6c46` - the user-visible runtime feature is the seg1468 AVI timing overlay drawn into the main video buffer Additional negative evidence from the live program: - no recovered text strings mentioning `mono`, `monochrome`, `hercules`, or `MDA` - no recovered instruction hits referencing obvious monochrome-adapter I/O ports such as `0x3b4`, `0x3b5`, `0x3b8`, or `0x3ba` - no recovered instruction hits referencing the `B000` monochrome text-memory window That does **not** mathematically prove that no historical or stripped monitor-debug code ever existed during development, but it does mean: - the current retail `-debug` evidence does not support the "secondary monochrome monitor" explanation - the current retail implementation is better explained as `stdout`-gated text plus the AVI timing overlay ## Ghidra Refinements Applied The live `CRUSADER.EXE` database now carries this batch's first-pass refinements too: - `1468:2869` -> `VideoPlayer_AdvanceFrameAndHandleSkip` - `1468:2af4` -> `VideoPlayer_StreamChunks` - `1468:2de9` -> `VideoPlayer_DrawDebugTimingOverlay` - parser and global comments at `1048:0a93`, `1478:0845`, `1478:0859`, and `1478:87e0` - overlay-gate comments at `1468:2920` and `1468:2dc8` - debug-print helper comments at `12d0:0391`, `12d0:03ee`, and `12d0:0442` - sink/init comments at `1000:65cc` and `12d0:0513` - stdio-table comments at `1478:6c32` and `1478:6c46` ## Follow-Up Targets If this lane is revisited, the highest-value remaining questions are: - identify a concrete behavioral name for `1478:0845` by finding a real downstream consumer - classify the remaining nearby seg1468 helpers so the AVI/video-player object layout around `+0x117/+0x11b/+0x11f/+0x123` can be named cleanly - test whether the overlay is visibly present during intro/cutscene playback in DOSBox or another live runtime - find meaningful callsites into the seg12d0 positioned debug-print helpers to learn whether `-debug` exposes additional text diagnostics beyond movie timing markers - determine the default runtime value path for `g_debugMsgLevel` more rigorously, since static initialized data alone does not yet explain the full practical print behavior - sample a few representative `ConsolePrintf` / `DebugPrintAndWaitForInput` format strings under live capture so the stdout lane can be characterized with runtime output rather than only static caller families