Crusader_Decomp/docs/command-line-parameters.md
2026-04-05 09:55:21 +02:00

272 lines
No EOL
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Crusader Command-Line Parameters
## Scope
This note consolidates the currently recovered startup/debug argument set across the retail Crusader executables.
The current strongest parser/control-flow evidence now comes from both live targets:
- `REGRET.EXE`
- `CRUSADER.EXE`
Two conclusions matter most for the recent startup-map work:
- the executable patch was still required to change the stock fresh-game start map
- the built-in manual/debug warp lane is real, and its direct-coordinate form is `-warp <mission> [x y z]`
That direct-coordinate syntax is now confirmed in both retail games, not just Regret.
## Short Answer
If the question is `could the normal first-mission executable hack have been replaced by parameters all along?`, the answer is still no.
The stock new-game path hardcodes map `1`, egg `0x1e` in code. The parameterized warp path is a separate startup/debug branch that only runs when `-warp` is present.
If the question is `can the executable already warp into another map without patching files?`, the answer is yes.
The current best-proven forms are:
- `-warp <mission>`
- `-warp <mission> <x> <y> <z>`
- optional `-mapoff <delta>` and `-egg <id>` modifiers
The important restriction is that `-egg` beats X/Y/Z. If you supply a nonnegative egg override, the game routes through the teleporter-egg path and does not use the direct-coordinate teleport.
That precedence rule is also now confirmed in both retail games:
- `REGRET.EXE` routes through `Game_RunNewGameFlow`
- `CRUSADER.EXE` routes through `Game_Start`
For the specific `-u` question, the current live No Remorse answer is now yes.
The regular non-Japanese `CRUSADER.EXE` still contains a real `-u` lane, and the current best read is no longer `unresolved leftover token`. In this build it is a live startup override for the usecode/EUSECODE load source.
## Parameter Table
| Argument | Current best syntax | Confidence | Current best effect |
|------|------|------|------|
| `-?` | `-?` | Medium | Help/usage-style startup path. The option is present in the parser table, and the nearby startup strings include `You DO need help!`. The exact REGRET-side case-to-string tie was not re-closed in this pass. |
| `-u` | `-u <arg>` | High | Live in retail `CRUSADER.EXE`. The parser copies the following token into `1478:065a`, and `startup_apply_u_override_if_present` later uses that buffer as a startup usecode/EUSECODE load-source override. The JP build matches the same interpretation. |
| `-debug` | `-debug` | High | Live parser branch. Raises the debug-print threshold, prints `Debugging mode ON.`, and enables the known movie-player timing overlay / debug-print lane. |
| `-setver` | `-setver <text>` | Medium | Still present in the broader Crusader parser-family tables, but the earlier CRUSADER-side assignment of the string-copy branch now belongs to `-u`. Treat the exact retail `CRUSADER.EXE` `-setver` behavior as still unresolved here; the older version/banner read is now best treated as REGRET-weighted rather than closed for both games. |
| `-asylum` | `-asylum` | High | Joke/no-op style switch. Current best recovered effect is printing `Enabling ENHANCED mode. (NOT!)` with no stronger gameplay-side state change recovered in this pass. |
| `-warp` | `-warp <mission>` | High | Enables the manual/debug warp lane by setting `g_warpToLevelNoArg`. The runtime then computes `target_map = mission_table[mission] + mapoff`. |
| `-warp` with coordinates | `-warp <mission> <x> <y> <z>` | High | Direct coordinate warp. After parsing the mission number, the parser checks the next argv token. If it is present and does not begin with `-`, the next three argv tokens are parsed as X, Y, and Z. |
| `-skill` | `-skill <n>` | High | Parses a difficulty override into `1480:0ace`. The parser clamps `0` up to `1`, then `Game_RunNewGameFlow` copies the value into the difficulty level before the mission-start hop. |
| `-mapoff` | `-mapoff <delta>` | High | Adds an offset to the mission-table result inside the manual/debug warp path. It does not affect the stock fresh-game selector when `-warp` is absent. |
| `-egg` | `-egg <id>` | High | Sets the destination egg override used by the warp path. When the value is nonnegative, it takes precedence over the direct-coordinate teleport branch. |
| `-demo` | `-demo` | High | Sets `1480:0ad4`, prints `Demo mode.`, and changes the ORIGIN/ANIM01 startup-video behavior in `Game_RunNewGameFlow`. |
| `-laurie` | `-laurie` | High | Separate from the main `HandleCommandlineArgs` switch table. This is the broader cheat/debug-enablement argument already documented in the live No Remorse notes. |
## Warp Syntax And Precedence
The current best evidence-backed parser behavior is now confirmed in both `REGRET.EXE` and `CRUSADER.EXE`.
In the No Remorse live database, the exact matching parser case is `HandleCommandlineArgs` at `1048:0adc`, and the matching consumer branch is in `Game_Start` at `1020:029e` / `1020:02d0`.
In the Regret live database, the matching parser case is `HandleCommandlineArgs` at `1058:0cd2`, and the matching consumer branch is in `Game_RunNewGameFlow` at `1030:0628` / `1030:069a`.
The shared behavior is:
1. `-warp` always consumes one numeric mission argument.
2. The parser then peeks at the next argv token.
3. If that token is missing or begins with `-`, the game takes the mission-only path and prints `Warping to mission %d.`.
4. Otherwise the parser consumes the next three argv tokens as X, Y, and Z, stores them in `1480:0ac8`, `1480:0aca`, and `1480:0acc`, and prints `Warping to mission %d @ x:%d y:%d z:%d.`.
For No Remorse the corresponding X/Y/Z globals are the earlier siblings:
- `1478:084c` = X override
- `1478:084e` = Y override
- `1478:0850` = Z override
That means the recovered syntax is positional:
- `-warp <mission>`
- `-warp <mission> <x> <y> <z>`
This pass did not recover any separate literal `-x`, `-y`, or `-z` switches in the startup parser.
At runtime, both games apply the same precedence:
1. Compute the target map from the embedded mission-to-map table plus `-mapoff`.
2. If X is unset (`0xffff` / `-1`), use the egg teleporter path.
3. If X is set but `-egg` is also nonnegative, still use the egg teleporter path.
4. Only when X/Y/Z are present and the egg override is still negative does the game bypass egg lookup and call `NPC_Teleport` directly.
No Remorses direct consumer branch is especially clear:
- `1020:029e` checks whether X is still `-1`
- `1020:02a5` / `1020:02d0` check whether `-egg` is nonnegative
- `1020:02d7..02eb` call `NPC_Teleport` only when X/Y/Z are present and egg override is still negative
## Eggless Maps And The Non-Patching Workaround
This directly answers the recent map-254 style question.
There is a parameter-only route into maps with no usable destination egg, but it is not `-egg`.
The working shape is:
- `-warp <mission> <x> <y> <z> -mapoff <delta>`
with `-egg` omitted.
Why that matters:
- `-egg` keeps the code on the teleporter/egg path
- the direct-coordinate form falls into `NPC_Teleport`
- the inspected `NPC_Teleport` lane writes the exact map/X/Y/Z values and moves the camera there
- the currently inspected teleport path does not show any automatic `snap-to-ground` or `find a safe spawn` rescue
So the non-patching workaround for an eggless map is `known-good coordinates`, not `some hidden eggless-map flag`.
If the supplied X/Y/Z values are bad, the game can still strand the avatar in empty space even though the warp itself succeeded.
## What `-u` Does In Retail `CRUSADER.EXE`
The live non-Japanese No Remorse database now closes `-u` much more tightly than the older note.
In `HandleCommandlineArgs`, the retail parser case at `1048:0a46` consumes the next argv token and copies it into the fixed startup buffer at `1478:065a`.
The only recovered consumer of that buffer in the same retail executable is `startup_apply_u_override_if_present` at `1420:0cdf`.
Recovered behavior in that helper:
- check whether `1478:065a` is non-empty
- if empty, leave the default startup path alone and return
- if non-empty, route startup through an alternate load/resolve path using the copied string
- store the resulting far pointer in `1478:6611/6613`
- set the loaded-state byte at `1478:6615`
- rebuild the cumulative slot-base words at `1478:8c7c..8c82`
That is strong retail No Remorse evidence for this meaning:
> `-u <arg>` is a live startup override for the usecode/EUSECODE load source.
What is still not fully closed from this static pass is the exact Filespec path syntax for the copied token.
What is now materially tighter:
- the helper does **not** treat the argv token as the final archive filename
- it uses the token as the `path` component to `Filespec_GetFullPath`
- it uses the mutable filename template at `1478:07a0`, which is `eusecode.flx`, as the fixed `filename` component
- it forces that template's first byte to `'e'` before the existence probe and final load call
- the path builder uses DOS-style backslashes via the literal `"\\"` string from `FILE\\FILESPEC.C`
- the existence probe goes through the DOS file-search path in `File_Exists`, so the override must resolve inside the game's DOS-visible filesystem
- the parser copies the token into the `0x1e`-byte buffer at `1478:065a`, so the practical maximum is `29` visible characters plus the terminator
So the safest current retail read is:
- `-u <arg>` expects a directory/resource-root style path argument for the standard `eusecode.flx` archive family
- it does **not** currently look like a free-form arbitrary filename override
- the safest token spelling uses DOS-style backslashes, not forward slashes
That gives a direct explanation for failed attempts like:
- `-u USECODE/FLICTEST.FLX`
- `-u FLICTEST.FLX`
- `-u C:\MADDOCODE` when that path only exists on the Windows host and not inside the guest DOS drive mapping
Those forms fit the recovered helper badly because the token is used as the `Filespec_GetFullPath` path component while the filename remains the fixed template `eusecode.flx`. Current safest interpretation is therefore:
- pass a directory or resource-root to `-u`
- put the replacement archive at `<that root>/EUSECODE.FLX`
- do not expect `-u` to open `FLICTEST.FLX` directly as the final archive name
The current safest syntax examples are:
- `-u MADDOCODE`
- `-u .\MADDOCODE`
- `-u \MADDOCODE`
- `-u C:\MADDOCODE`
But for real DOS-facing installs, the safer practical examples are the `8.3`-safe variants:
- `-u MADDOC~1`
- `-u .\MADDOC~1`
with these current best path interpretations:
- `MADDOCODE` = relative to the game's current DOS working directory
- `.\MADDOCODE` = explicit relative DOS path
- `\MADDOCODE` = root-relative path on the current DOS drive
- `C:\MADDOCODE` = absolute DOS path on drive `C:` as seen by the DOS game, not automatically the Windows host path
In the current GOG install used for this investigation, Windows reports the short alias:
- `MADDOCODE` -> `MADDOC~1`
That makes `MADDOC~1` the highest-probability next token for this specific setup.
Current safest negative guidance:
- avoid forward slashes for `-u`
- avoid long path tokens because silent truncation at `1478:065a` can change the real lookup target
- do not use the archive filename itself as the `-u` argument
- prefer `8.3`-safe directory names or explicit DOS short aliases when testing under DOSBox-like environments
But the important uncertainty is now only `exact naming rules`, not `whether the switch is real`. In the regular non-Japanese `CRUSADER.EXE`, the switch is clearly still live.
## Expected Console Output For `-u`
Current best answer: probably none.
The recovered `-u` parser case does not print a banner, and the startup helper that probes and swaps the override path also has no recovered `ConsolePrintf` call. So unlike `-debug`, `-warp`, `-skill`, `-mapoff`, `-egg`, or `-demo`, `-u` does not currently appear to advertise itself on the console before the game loads.
The safest current expectation is:
- success: no dedicated `-u` console message
- missing path/file: no dedicated `-u` console message, likely silent fallback to stock usecode
- malformed but existing replacement: no dedicated `-u` status line from the parser/helper path; later behavior depends on the deeper loader/runtime path
This also sharpens the practical diagnosis for the current `MADDOCODE` setup. In the tested GOG install, only `EUSECODE.FLX` differs between `USECODE` and `MADDOCODE`; the sidecar files are byte-identical. So if replacing `USECODE\EUSECODE.FLX` with the hacked file produces the expected obvious no-usecode-style breakage, but `-u MADDOCODE` behaves like stock gameplay instead, the strongest current read is that the override path was probably not accepted and startup silently fell back to the stock usecode root.
This also aligns with the already-stronger JP Win32 result, where the matching `-u` lane was recovered as the same kind of usecode override.
For the deeper runtime-side investigation of whether `-u` replaces or augments the stock usecode root, and what game systems that replacement feeds, see [docs/usecode-startup-override.md](docs/usecode-startup-override.md).
Current best answer from that follow-up is:
- `-u` behaves like a replacement of the live usecode runtime root, not an additive overlay
- the replaced root is then used by normal item-event dispatch, usecode process creation, interpreter bytecode stepping, and gameplay-side scripted capability checks
The current best replacement-vs-addition answer is also now stronger:
- there is one live root at `1478:6611/6613`
- `startup_apply_u_override_if_present` overwrites that root directly when `-u` is present
- later event/process/interpreter consumers read the replacement root through the same global pair
So the safest current retail read is `full runtime root replacement for the session`, not `load one extra add-on script beside stock usecode`.
## What `-setver` Most Likely Does
`-setver` should now be treated more cautiously in this consolidated note.
For retail `CRUSADER.EXE`, the string-copy branch that had previously been grouped under `-setver` is now better closed as the live `-u` handler described above.
That means the older `displayed version/build string override` reading is no longer closed for the non-Japanese No Remorse executable itself.
Current evidence bundle:
- the option name is still present in the broader Crusader parser-family tables
- older REGRET-side evidence still points toward a startup/UI presentation role rather than gameplay control
- but this pass did not directly re-close the exact retail No Remorse `-setver` consumer after reassigning the resolved string-copy branch to `-u`
Current best read:
- `-setver <text>` still looks more like a presentation/version banner switch than a gameplay/startup-map selector
- but that statement is now provisional for consolidated retail notes until the retail `CRUSADER.EXE` handler is isolated directly
The exact retail No Remorse `-setver` branch is therefore an open cleanup item again, while `-u` is now the closed string-consuming retail startup override.
## No Remorse Cross-Check Summary
The main recent uncertainty was whether Regret had gained an extra direct-coordinate warp feature that No Remorse lacked. The live `CRUSADER.EXE` pass now closes that question.
Current best answer:
- No Remorse supports the same positional `-warp <mission> [x y z]` syntax.
- No Remorse uses the same `-egg` precedence rule over X/Y/Z.
- No Remorse reaches the same direct `NPC_Teleport` style fallback when coordinates are present and the egg override is still negative.
So the parameter-only workaround for eggless maps is not Regret-specific. The same approach should work in No Remorse too, as long as the supplied coordinates are valid for the chosen target map.