9.3 KiB
No Regret Game_Start Flow
Scope
This note documents the currently opened live REGRET.EXE startup lane around Game_Start and the later helper that performs the actual new-game mission hop.
The immediate goals of this pass were:
- name the directly involved startup helpers in Ghidra
- annotate the startup-state globals that feed the new-game path
- explain why No Regret appears to set the start map twice
Named Functions
The following previously-unnamed functions are now promoted in the live REGRET.EXE database.
| Address | New name | Why the name is justified |
|---|---|---|
1058:0bbe |
HandleCommandlineArgs |
Matches the already-recovered Remorse-side parser role. It compares argv entries against a startup-option table and writes g_warpToLevelNoArg, the difficulty override, map offset, egg override, and the extra startup-video flag. |
1030:032d |
Game_RunNewGameFlow |
This is the full No Regret new-game helper. It plays the ORIGIN/ANIM01 intro lane, opens the difficulty modal when not warping, rebuilds the world/avatar state, and then performs the actual mission-start teleporter hop or the debug -warp path. |
1030:022e |
Game_DrawCenteredStartupSplash |
Called immediately before the teleporter hop in both the normal and -warp startup lanes. It fades black, clears the active gameplay state, centers one startup screen object, and redraws the viewport. |
11c8:0d96 |
Game_EnterFrontendMenuViewport |
Used before modal-gump dispatch. It clears the gameplay-style viewport flag, expands the mouse Y range to the taller menu height, and refreshes the screen object. |
11c8:0d39 |
Game_RestoreGameplayViewport |
Used after the modal/front-end phase. It restores the gameplay-style viewport state, notifies NPC update lanes, restores the shorter mouse Y range, and refreshes the screen object again. |
Game_Start Structure
Game_Start in No Regret still looks like the top-level frontend entry point.
High-level shape:
- Freeze the current gameplay/process state enough to enter a frontend/modal lane.
- Enter the taller frontend viewport mode and dispatch the startup modal gump.
- Handle non-new-game modal results such as exit/other menu actions.
- For the new-game path, clear world/gameplay state, rebuild the avatar and starter items, and do an early teleporter hop to map
1, egg0x1e. - Fade/reset again and hand back into the wider startup framework.
The key early selector is still:
1008:1446 PUSH 0x11008:1448 PUSH 0x1e00011008:144e CALLF 0x1030:0000
That early site is real, but it is not the only startup teleporter call that matters.
Actual New-Game Mission Start
The function now named Game_RunNewGameFlow is the important second lane.
It is called from at least two concrete places:
CreditsProcess_Runat1008:0056- another startup/control lane at
1058:0a2a
That already shows it is not dead duplicate code. It is a standalone startup helper reused by the frontend.
Its normal no-warp branch does all of the following in one place:
- Play the ORIGIN/ANIM01 intro-video lane.
- Open the difficulty-selection modal.
- Reinitialize NPC/world/tracker state.
- Apply any command-line difficulty override.
- Recreate starter inventory items.
- Draw the centered startup splash.
- Perform the actual mission-start teleporter hop.
The effective mission-start selector is:
1030:05c3 PUSH 0x11030:05c5 PUSH 0x1e00011030:05cb PUSH CS1030:05cc CALL 0x1030:0000
This is the selector that redirected real new games only after the script was updated to patch it together with the earlier Game_Start site.
Startup Globals
These data roles are now annotated in the live Ghidra session.
| Address | Current best role |
|---|---|
1480:1453 |
Startup-world transition flag. Game_Start clears it before the early menu-start teleporter hop. Game_RunNewGameFlow sets it during world/NPC rebuild and clears it again immediately before the actual mission-start teleporter hop. |
1480:0ac8 |
Optional command-line warp X override. 0xffff means no direct coordinate warp is requested. |
1480:0aca |
Optional command-line warp Y override. |
1480:0acc |
Optional command-line warp Z override. |
1480:0ace |
Command-line difficulty override parsed by HandleCommandlineArgs. If greater than zero, the new-game flow copies it into g_difficultyLevel before the teleporter hop. |
1480:0ad0 |
Command-line -mapoff additive map offset used by the debug -warp path. |
1480:0ad2 |
Command-line egg override used by the -warp path. When negative or 0x001e, the code falls back to the default startup egg. |
1480:0ad4 |
Extra startup-video behavior flag parsed by HandleCommandlineArgs. Clear means the ORIGIN/ANIM01 lane is played once; set means the same lane is repeated until 1480:95f0 becomes nonzero. |
1480:95f0 |
Startup-video loop exit latch used by Game_RunNewGameFlow and CreditsProcess_Run. |
Command-Line Warp Controls
The startup parser exposes more real gameplay-side command-line controls than just -warp.
Currently proven from the recovered parser strings and control flow:
-warp-skill-mapoff-egg-debug-demo-setver-asylum
The same executables also contain the runtime status strings:
Warping to mission %d.Warping to mission %d @ x:%d y:%d z:%d.Defaulting to skill level %dDestination Egg = %d
That parser behavior is now tight enough to promote the actual syntax:
-warp <mission>= mission-only manual warp-warp <mission> <x> <y> <z>= direct coordinate warp
The key parser detail is that there are no separately recovered -x, -y, or -z switches in this lane. After HandleCommandlineArgs parses the mission number, it checks the next argv token. If the next token is missing or begins with -, the parser takes the mission-only path and prints Warping to mission %d.. Otherwise it consumes the next three argv tokens as X, Y, and Z and prints Warping to mission %d @ x:%d y:%d z:%d..
There is one important precedence rule in Game_RunNewGameFlow: -egg wins over the coordinate override path. When X is present but the egg override is nonnegative, the code still routes back into the egg-based teleporter lane. The direct NPC_Teleport path only runs when X/Y/Z are present and the egg override is still negative.
Could Parameters Replace The Executable Hack?
For a normal fresh game, no.
The executable patch was needed because the stock new-game path still hardcodes the startup selector payload (map = 1, egg = 0x1e) in code. No Regret does that twice, once in Game_Start and once again in Game_RunNewGameFlow.
The command-line warp lane is different:
- it only runs when
g_warpToLevelNoArg != -1 - it uses a debug/manual warp flow rather than the ordinary fresh-game path
- it computes the target map from an embedded mission-to-map table plus
-mapoff - it can also change the destination egg
- it can apply explicit X/Y/Z destination overrides through
-warp <mission> <x> <y> <z>
So a command line could likely have reproduced the practical destination change for a manual debug warp session, but not the ordinary fresh-game mission-1 behavior that the patch script changed.
For maps with no usable teleport egg, the parameter-only workaround is now clearer too: use -warp <mission> <x> <y> <z> together with -mapoff, and do not pass -egg. That path bypasses the egg lookup and calls NPC_Teleport directly. The current inspected teleport lane does not show any automatic snap-to-ground rescue, so this only works if the supplied coordinate triple is already valid for the target map.
Current best distinction:
- executable patch = changes the stock fresh-game startup behavior
- command-line warp args = invoke a separate manual/debug startup path that can land on a different mission/map/egg and likely a different coordinate triple
Likely Reason Map 1 Is Set Twice
The most likely explanation is that No Regret preserved two valid entry paths into an in-engine gameplay state instead of refactoring them into one shared startup selector.
Evidence for that read:
Game_Startcontains an early teleporter hop immediately after rebuilding the avatar and starter items.Game_RunNewGameFlowis a separate, live helper called fromCreditsProcess_Runand another startup/control lane.Game_RunNewGameFlowowns the full intro-video, difficulty-modal, world-reset, and real mission-start sequence.- Both paths call the same local teleporter wrapper with the same literal
(1, 0x1e, 1)payload.
Current best model:
- the early
Game_Starthop is a frontend/bootstrap entry into a playable engine state - the later
Game_RunNewGameFlowhop is the authoritative mission-start step for a real new game after the intro/difficulty flow - both kept their own literal selector instead of sharing one startup-map global or helper constant
So the duplication looks more like split control-flow ownership and startup code reuse than a deliberate “set it twice just in case” pattern.
Practical Patch Implication
For No Regret, changing the fresh-game destination map must update both hardcoded selectors:
- early
Game_Startselector at1008:1448 - actual mission-start selector at
1030:05c5
Patching only the early site is insufficient because the later new-game helper can silently overwrite that choice during the real mission-start sequence.