272 lines
No EOL
16 KiB
Markdown
272 lines
No EOL
16 KiB
Markdown
# 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 Remorse’s 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. |