Crusader_Decomp/docs/command-line-parameters.md

12 KiB
Raw Permalink Blame History

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.

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.