Crusader_Decomp/docs/command-line-parameters.md

210 lines
12 KiB
Markdown
Raw Normal View History

2026-03-29 01:14:09 +01:00
# 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
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
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.
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.