paavohtl Claude Opus 4.6 commited on
Commit
1f2d77a
Β·
1 Parent(s): 4d4fb5b

Add frontend screen system: ScreenId enum and 21 named functions

Browse files

Map the MFC CDialog-based menu system from 65 decompiled call sites.
Add ScreenId enum with 18 screen IDs (main menu through lobby).
Name 21 frontend/lobby functions and 4 global variables in Ghidra.
Add 25 new addresses to address.rs (14 frontend + 7 lobby + 4 globals).
Document screen transition architecture in frontend-screens.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

crates/openwa-types/src/address.rs CHANGED
@@ -163,18 +163,53 @@ pub mod va {
163
  pub const SHOW_CHAT_MESSAGE: u32 = 0x0052_ACB0;
164
  pub const ON_CHAT_INPUT: u32 = 0x0052_B730;
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  // === Lobby / network ===
167
 
168
  pub const LOBBY_HOST_COMMANDS: u32 = 0x004B_9B00;
169
  pub const LOBBY_CLIENT_COMMANDS: u32 = 0x004A_ABB0;
170
  pub const SEND_GAME_PACKET_WRAPPED: u32 = 0x0054_1130;
171
- pub const FRONTEND_CHANGE_SCREEN: u32 = 0x0044_7A20;
 
 
 
 
 
 
 
172
 
173
  // === Memory ===
174
 
175
  pub const WA_MALLOC_MEMSET: u32 = 0x0053_E910;
176
  pub const WA_FREE: u32 = 0x005D_0D2B;
177
 
 
 
 
 
 
 
 
 
 
 
 
178
  // === Game context (DDGame struct offsets) ===
179
  // These are offsets from the DDGame base pointer, not absolute addresses.
180
  // DDGame pointer is obtained from hookConstructDDGameWrapper param.
 
163
  pub const SHOW_CHAT_MESSAGE: u32 = 0x0052_ACB0;
164
  pub const ON_CHAT_INPUT: u32 = 0x0052_B730;
165
 
166
+ // === Frontend / menu screens ===
167
+
168
+ pub const FRONTEND_CHANGE_SCREEN: u32 = 0x0044_7A20;
169
+ pub const FRONTEND_FRAME_CONSTRUCTOR: u32 = 0x004E_CCA0;
170
+ pub const FRONTEND_DIALOG_CONSTRUCTOR: u32 = 0x0044_6BA0;
171
+ pub const FRONTEND_PALETTE_ANIMATION: u32 = 0x0042_2180;
172
+ pub const FRONTEND_LOAD_TRANSITION_PAL: u32 = 0x0044_7AA0;
173
+ pub const FRONTEND_PRE_TRANSITION_CLEANUP: u32 = 0x004E_4AE0;
174
+ pub const FRONTEND_ON_INITIAL_LOAD: u32 = 0x0042_9830;
175
+ pub const FRONTEND_LAUNCH_SINGLE_PLAYER: u32 = 0x0044_1D80;
176
+ pub const FRONTEND_ON_MULTIPLAYER: u32 = 0x0044_E850;
177
+ pub const FRONTEND_ON_NETWORK: u32 = 0x0044_EC10;
178
+ pub const FRONTEND_ON_MINIMIZE: u32 = 0x0048_6A10;
179
+ pub const FRONTEND_ON_OPTIONS_ACCEPT: u32 = 0x0048_DAB0;
180
+ pub const FRONTEND_ON_START_GAME: u32 = 0x004F_14A0;
181
+ pub const CDIALOG_DO_MODAL_CUSTOM: u32 = 0x0040_FD60;
182
+
183
  // === Lobby / network ===
184
 
185
  pub const LOBBY_HOST_COMMANDS: u32 = 0x004B_9B00;
186
  pub const LOBBY_CLIENT_COMMANDS: u32 = 0x004A_ABB0;
187
  pub const SEND_GAME_PACKET_WRAPPED: u32 = 0x0054_1130;
188
+ pub const LOBBY_DISPLAY_MESSAGE: u32 = 0x0049_3CB0;
189
+ pub const LOBBY_SEND_GREENTEXT: u32 = 0x004A_A990;
190
+ pub const LOBBY_PRINT_USED_VERSION: u32 = 0x004B_7E20;
191
+ pub const LOBBY_ON_DISCONNECT: u32 = 0x004B_AE40;
192
+ pub const LOBBY_ON_GAME_END: u32 = 0x004B_AEC0;
193
+ pub const LOBBY_ON_MESSAGE: u32 = 0x004B_D400;
194
+ pub const LOBBY_DIALOG_CONSTRUCTOR: u32 = 0x004C_D9A0;
195
+ pub const NETWORK_IS_AVAILABLE: u32 = 0x004D_4920;
196
 
197
  // === Memory ===
198
 
199
  pub const WA_MALLOC_MEMSET: u32 = 0x0053_E910;
200
  pub const WA_FREE: u32 = 0x005D_0D2B;
201
 
202
+ // === Global variables (in .data) ===
203
+
204
+ /// Main frontend frame window (CWnd*)
205
+ pub const G_FRONTEND_FRAME: u32 = 0x006B_3908;
206
+ /// Main frontend HWND
207
+ pub const G_FRONTEND_HWND: u32 = 0x006B_390C;
208
+ /// Network mode (0=LAN, nonzero=WormNET)
209
+ pub const G_NETWORK_MODE: u32 = 0x007C_0D40;
210
+ /// Network sub-type selector
211
+ pub const G_NETWORK_SUBTYPE: u32 = 0x007C_0D68;
212
+
213
  // === Game context (DDGame struct offsets) ===
214
  // These are offsets from the DDGame base pointer, not absolute addresses.
215
  // DDGame pointer is obtained from hookConstructDDGameWrapper param.
crates/openwa-types/src/frontend.rs ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /// Frontend screen identifiers.
2
+ ///
3
+ /// Used by FrontendChangeScreen (0x447A20) to transition between
4
+ /// menu screens. The screen ID is passed to CDialog::EndDialog as
5
+ /// the result code, then returned from DoModal to drive navigation.
6
+ ///
7
+ /// The frontend uses MFC CDialog modal dialogs, not the CTask hierarchy.
8
+ /// The main frame window is stored at global 0x6B3908.
9
+ ///
10
+ /// Source: Ghidra decompilation of 65 call sites + wkJellyWorm Lobby.cpp
11
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12
+ #[repr(i32)]
13
+ pub enum ScreenId {
14
+ /// Return to previous screen / cancel action
15
+ Cancel = 0,
16
+ /// Main menu screen
17
+ MainMenu = 10,
18
+ /// Local multiplayer setup
19
+ LocalMultiplayer = 11,
20
+ /// Window minimized / inactive state (checked via IsIconic)
21
+ Minimized = 15,
22
+ /// Initial game loading screen
23
+ InitialLoad = 16,
24
+ /// Single player game (Deathmatch)
25
+ SinglePlayer = 21,
26
+ /// Network options sub-screen
27
+ NetworkSubScreen = 26,
28
+ /// Start game path A (game setup, param+0x244 == 0)
29
+ StartGameA = 35,
30
+ /// Start game path B (game setup fallthrough)
31
+ StartGameB = 36,
32
+ /// Network setup path A (param+0x140 == 0)
33
+ NetworkSetupA = 37,
34
+ /// Network setup path B (fallthrough)
35
+ NetworkSetupB = 38,
36
+ /// Options accepted / theme saved (writes current.thm)
37
+ OptionsAccept = 39,
38
+ /// Network provider selection screen
39
+ NetworkSelection = 1700,
40
+ /// LAN game
41
+ Lan = 1702,
42
+ /// WormNET online lobby
43
+ WormNet = 1703,
44
+ /// Lobby as host
45
+ LobbyHost = 1704,
46
+ /// Lobby as client / join game
47
+ LobbyClient = 1706,
48
+ /// Lobby game start
49
+ LobbyGameStart = 1707,
50
+ }
51
+
52
+ impl TryFrom<i32> for ScreenId {
53
+ type Error = i32;
54
+
55
+ fn try_from(value: i32) -> Result<Self, Self::Error> {
56
+ match value {
57
+ 0 => Ok(Self::Cancel),
58
+ 10 => Ok(Self::MainMenu),
59
+ 11 => Ok(Self::LocalMultiplayer),
60
+ 15 => Ok(Self::Minimized),
61
+ 16 => Ok(Self::InitialLoad),
62
+ 21 => Ok(Self::SinglePlayer),
63
+ 26 => Ok(Self::NetworkSubScreen),
64
+ 35 => Ok(Self::StartGameA),
65
+ 36 => Ok(Self::StartGameB),
66
+ 37 => Ok(Self::NetworkSetupA),
67
+ 38 => Ok(Self::NetworkSetupB),
68
+ 39 => Ok(Self::OptionsAccept),
69
+ 1700 => Ok(Self::NetworkSelection),
70
+ 1702 => Ok(Self::Lan),
71
+ 1703 => Ok(Self::WormNet),
72
+ 1704 => Ok(Self::LobbyHost),
73
+ 1706 => Ok(Self::LobbyClient),
74
+ 1707 => Ok(Self::LobbyGameStart),
75
+ _ => Err(value),
76
+ }
77
+ }
78
+ }
crates/openwa-types/src/lib.rs CHANGED
@@ -10,4 +10,5 @@ pub mod ddgame_wrapper;
10
  pub mod landscape;
11
  pub mod dssound;
12
  pub mod opengl;
 
13
  pub mod address;
 
10
  pub mod landscape;
11
  pub mod dssound;
12
  pub mod opengl;
13
+ pub mod frontend;
14
  pub mod address;
docs/re-notes/frontend-screens.md ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Frontend Screen System
2
+
3
+ ## Architecture
4
+
5
+ The frontend uses **MFC CDialog modal dialogs**, not the CTask class hierarchy.
6
+ Screen transitions work through a centralized dispatcher:
7
+
8
+ ```
9
+ FrontendFrame (global at 0x6B3908, constructed at 0x4ECCA0)
10
+ └── CDialog modal loop (CDialog__DoModal_Custom at 0x40FD60)
11
+ β”œβ”€β”€ Button handler calls FrontendChangeScreen(screen_id)
12
+ β”œβ”€β”€ FrontendChangeScreen calls CDialog::EndDialog(screen_id)
13
+ β”œβ”€β”€ DoModal returns screen_id to caller
14
+ └── Caller decides next dialog based on return value
15
+ ```
16
+
17
+ ## FrontendChangeScreen (0x447A20)
18
+
19
+ Two modes based on `g_FrontendFrame` (0x6B3908):
20
+
21
+ - **Normal** (g_FrontendFrame != 0): Disable window β†’ palette transition
22
+ (0x422180) β†’ call vtable method at +0x15C twice β†’ re-enable window β†’
23
+ CDialog::EndDialog(screen_id)
24
+ - **Init** (g_FrontendFrame == 0): Store screen_id at ESI+0x44, clear flag bit
25
+
26
+ ## Screen IDs
27
+
28
+ | ID | Hex | Name | Context |
29
+ |----|-----|------|---------|
30
+ | 0 | 0x00 | Cancel | Return to previous / close dialog |
31
+ | 10 | 0x0A | MainMenu | Main menu screen |
32
+ | 11 | 0x0B | LocalMultiplayer | Local multiplayer setup |
33
+ | 15 | 0x0F | Minimized | Window minimized (IsIconic check) |
34
+ | 16 | 0x10 | InitialLoad | Initial game loading screen |
35
+ | 21 | 0x15 | SinglePlayer | Single player / Deathmatch |
36
+ | 26 | 0x1A | NetworkSubScreen | Network options sub-screen |
37
+ | 35 | 0x23 | StartGameA | Start game (path A) |
38
+ | 36 | 0x24 | StartGameB | Start game (path B) |
39
+ | 37 | 0x25 | NetworkSetupA | Network setup (path A) |
40
+ | 38 | 0x26 | NetworkSetupB | Network setup (path B) |
41
+ | 39 | 0x27 | OptionsAccept | Options saved (writes current.thm) |
42
+ | 1700 | 0x6A4 | NetworkSelection | Network provider selection |
43
+ | 1702 | 0x6A6 | Lan | LAN game |
44
+ | 1703 | 0x6A7 | WormNet | WormNET online lobby |
45
+ | 1704 | 0x6A8 | LobbyHost | Hosting a game |
46
+ | 1706 | 0x6AA | LobbyClient | Joining a game |
47
+ | 1707 | 0x6AB | LobbyGameStart | Lobby β†’ game start |
48
+
49
+ Note: Some callers pass dynamic screen IDs. There may be additional IDs not
50
+ discovered through static analysis.
51
+
52
+ ## Key Globals
53
+
54
+ | Address | Name | Type | Description |
55
+ |---------|------|------|-------------|
56
+ | 0x6B3908 | g_FrontendFrame | CWnd* | Main application frame window |
57
+ | 0x6B390C | g_FrontendHwnd | HWND | Main window handle |
58
+ | 0x7C0D40 | g_NetworkMode | int | 0=LAN, nonzero=WormNET |
59
+ | 0x7C0D68 | g_NetworkSubtype | int | Network sub-type selector |
60
+
61
+ ## Key Functions
62
+
63
+ | Address | Name | Purpose |
64
+ |---------|------|---------|
65
+ | 0x40FD60 | CDialog__DoModal_Custom | Custom DoModal returning screen ID |
66
+ | 0x422180 | Frontend__PaletteAnimation | Palette transition effect |
67
+ | 0x429830 | Frontend__OnInitialLoad | Initial game load handler |
68
+ | 0x441D80 | Frontend__LaunchSinglePlayer | Single player launch |
69
+ | 0x446BA0 | FrontendDialog__Constructor | Dialog constructor |
70
+ | 0x447A20 | FrontendChangeScreen | Central screen transition dispatcher |
71
+ | 0x447AA0 | Frontend__LoadTransitionPalette | Load transition palette |
72
+ | 0x44E850 | Frontend__OnMultiplayerButton | Multiplayer button handler |
73
+ | 0x44EC10 | Frontend__OnNetworkButton | Network button handler |
74
+ | 0x486A10 | Frontend__OnMinimize | Window minimize handler |
75
+ | 0x48DAB0 | Frontend__OnOptionsAccept | Options accept handler |
76
+ | 0x493CB0 | Lobby__DisplayMessage | Display lobby chat message |
77
+ | 0x4AA990 | Lobby__SendGreentext | Send colored lobby text |
78
+ | 0x4B7E20 | Lobby__PrintUsedVersion | Print version to lobby |
79
+ | 0x4BAE40 | Lobby__OnDisconnect | Handle lobby disconnect |
80
+ | 0x4BAEC0 | Lobby__OnGameEnd | Handle game end in lobby |
81
+ | 0x4BD400 | Lobby__OnMessage | Handle lobby message |
82
+ | 0x4CD9A0 | LobbyDialog__Constructor | Lobby dialog constructor |
83
+ | 0x4D4920 | Network__IsAvailable | Check network availability |
84
+ | 0x4E4AE0 | Frontend__PreTransitionCleanup | Pre-transition cleanup |
85
+ | 0x4ECCA0 | FrontendFrame__Constructor | Frame window constructor |
86
+ | 0x4F14A0 | Frontend__OnStartGameButton | Start game button handler |