docs: frontend state machine RE + 47 Ghidra labels
Browse filesDocument the complete frontend navigation state machine:
- Main navigation loop at 0x4E6440 (CWinApp::Run, 19KB)
- g_CurrentScreen (0x6B3504) drives screen dispatch
- 20 dialog constructors mapped to screen IDs
- Bitmap font system: 4 font sizes, glyph renderer, textbox API
- Display wrapper at 0x79D6D4 with 6 backend variants
47 new Ghidra labels applied (functions, globals, dialog ctors).
38 new address.rs constants: dialog ctors, font system, display globals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- crates/openwa-types/src/address.rs +55 -0
- docs/re-notes/frontend-screens.md +164 -59
crates/openwa-types/src/address.rs
CHANGED
|
@@ -187,6 +187,36 @@ pub mod va {
|
|
| 187 |
pub const CDIALOG_DO_MODAL_CUSTOM: u32 = 0x0040_FD60;
|
| 188 |
/// Custom message pump (replaces MFC's RunModalLoop)
|
| 189 |
pub const CDIALOG_CUSTOM_MSG_PUMP: u32 = 0x0040_FBE0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
|
| 191 |
// === Lobby / network ===
|
| 192 |
|
|
@@ -207,10 +237,29 @@ pub mod va {
|
|
| 207 |
pub const WA_MALLOC_MEMSET: u32 = 0x0053_E910;
|
| 208 |
pub const WA_FREE: u32 = 0x005D_0D2B;
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
// === Global variables (in .data) ===
|
| 211 |
|
| 212 |
/// Current screen ID driving the main navigation loop dispatch
|
| 213 |
pub const G_CURRENT_SCREEN: u32 = 0x006B_3504;
|
|
|
|
|
|
|
| 214 |
/// Main frontend frame window (CWnd*)
|
| 215 |
pub const G_FRONTEND_FRAME: u32 = 0x006B_3908;
|
| 216 |
/// Main frontend HWND
|
|
@@ -219,8 +268,14 @@ pub mod va {
|
|
| 219 |
pub const G_SKIP_TO_MAIN_MENU: u32 = 0x007A_083D;
|
| 220 |
/// Auto-network mode flag
|
| 221 |
pub const G_AUTO_NETWORK_FLAG: u32 = 0x007A_083F;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
/// Main menu active flag (0xFF during screen 18)
|
| 223 |
pub const G_MAIN_MENU_ACTIVE: u32 = 0x007C_0A20;
|
|
|
|
|
|
|
| 224 |
/// Network mode (0=LAN, nonzero=WormNET)
|
| 225 |
pub const G_NETWORK_MODE: u32 = 0x007C_0D40;
|
| 226 |
/// Network sub-type selector
|
|
|
|
| 187 |
pub const CDIALOG_DO_MODAL_CUSTOM: u32 = 0x0040_FD60;
|
| 188 |
/// Custom message pump (replaces MFC's RunModalLoop)
|
| 189 |
pub const CDIALOG_CUSTOM_MSG_PUMP: u32 = 0x0040_FBE0;
|
| 190 |
+
/// Per-frame idle handler: cursor, mouse, paint dispatch
|
| 191 |
+
pub const FRONTEND_DIALOG_ON_IDLE: u32 = 0x0040_FF90;
|
| 192 |
+
/// Traverses control tree, paints dirty controls
|
| 193 |
+
pub const FRONTEND_DIALOG_PAINT_CONTROL_TREE: u32 = 0x0040_BF60;
|
| 194 |
+
/// Renders background image for frontend dialog
|
| 195 |
+
pub const FRONTEND_DIALOG_RENDER_BACKGROUND: u32 = 0x0040_4250;
|
| 196 |
+
/// Surface blit operation (calls surface->vtable[11])
|
| 197 |
+
pub const SURFACE_BLIT: u32 = 0x0040_3BF0;
|
| 198 |
+
|
| 199 |
+
// === Frontend dialog constructors (from main navigation loop) ===
|
| 200 |
+
|
| 201 |
+
pub const FRONTEND_DEATHMATCH_CTOR: u32 = 0x0044_0F40;
|
| 202 |
+
pub const FRONTEND_LOCAL_MP_CTOR: u32 = 0x0049_C420;
|
| 203 |
+
pub const FRONTEND_TRAINING_CTOR: u32 = 0x004E_0880;
|
| 204 |
+
pub const FRONTEND_MISSIONS_CTOR: u32 = 0x0049_9190;
|
| 205 |
+
pub const FRONTEND_POST_INIT_CTOR: u32 = 0x004C_91B0;
|
| 206 |
+
pub const FRONTEND_MAIN_MENU_CTOR: u32 = 0x0048_66C0;
|
| 207 |
+
pub const FRONTEND_SINGLE_PLAYER_CTOR: u32 = 0x004D_69F0;
|
| 208 |
+
pub const FRONTEND_CAMPAIGN_A_CTOR: u32 = 0x004A_2B70;
|
| 209 |
+
pub const FRONTEND_CAMPAIGN_B_CTOR: u32 = 0x004A_24D0;
|
| 210 |
+
pub const FRONTEND_ADV_SETTINGS_CTOR: u32 = 0x0042_79E0;
|
| 211 |
+
pub const FRONTEND_INTRO_MOVIE_CTOR: u32 = 0x0047_0870;
|
| 212 |
+
pub const FRONTEND_NETWORK_HOST_CTOR: u32 = 0x004A_DCA0;
|
| 213 |
+
pub const FRONTEND_NETWORK_ONLINE_CTOR: u32 = 0x004A_CBC0;
|
| 214 |
+
pub const FRONTEND_NETWORK_PROVIDER_CTOR: u32 = 0x004A_7990;
|
| 215 |
+
pub const FRONTEND_NETWORK_SETTINGS_CTOR: u32 = 0x004C_23C0;
|
| 216 |
+
pub const FRONTEND_LAN_CTOR: u32 = 0x0048_0A80;
|
| 217 |
+
pub const FRONTEND_WORMNET_CTOR: u32 = 0x0047_2400;
|
| 218 |
+
pub const FRONTEND_LOBBY_HOST_CTOR: u32 = 0x004B_0160;
|
| 219 |
+
pub const FRONTEND_LOBBY_GAME_START_CTOR: u32 = 0x004B_DBE0;
|
| 220 |
|
| 221 |
// === Lobby / network ===
|
| 222 |
|
|
|
|
| 237 |
pub const WA_MALLOC_MEMSET: u32 = 0x0053_E910;
|
| 238 |
pub const WA_FREE: u32 = 0x005D_0D2B;
|
| 239 |
|
| 240 |
+
// === Bitmap font system ===
|
| 241 |
+
|
| 242 |
+
/// Loads all four font sizes from BMP files
|
| 243 |
+
pub const FONT_LOAD_FONTS: u32 = 0x0041_4680;
|
| 244 |
+
/// Core glyph renderer: iterates chars, blits from sprite sheet
|
| 245 |
+
pub const FONT_RENDER_GLYPHS: u32 = 0x0041_43D0;
|
| 246 |
+
/// Higher-level text draw: measures string, creates surface, renders
|
| 247 |
+
pub const FONT_DRAW_TEXT: u32 = 0x0042_7830;
|
| 248 |
+
/// DDDisplay::DrawTextOnBitmap β thiscall(font_id, bitmap, hAlign, vAlign, msg, a7, a8)
|
| 249 |
+
pub const DDDISPLAY_DRAW_TEXT_ON_BITMAP: u32 = 0x0052_36B0;
|
| 250 |
+
/// DDDisplay::ConstructTextbox β thiscall(dst, length, fontid)
|
| 251 |
+
pub const DDDISPLAY_CONSTRUCT_TEXTBOX: u32 = 0x004F_AF00;
|
| 252 |
+
/// SetTextboxText β stdcall(textbox, msg, textcolor, color1, color2, a6, a7, opacity)
|
| 253 |
+
pub const SET_TEXTBOX_TEXT: u32 = 0x004F_B070;
|
| 254 |
+
/// DrawTextboxLocal β draws textbox at screen position
|
| 255 |
+
pub const DRAW_TEXTBOX_LOCAL: u32 = 0x0054_2200;
|
| 256 |
+
|
| 257 |
// === Global variables (in .data) ===
|
| 258 |
|
| 259 |
/// Current screen ID driving the main navigation loop dispatch
|
| 260 |
pub const G_CURRENT_SCREEN: u32 = 0x006B_3504;
|
| 261 |
+
/// Character width table (256 bytes)
|
| 262 |
+
pub const G_CHAR_WIDTH_TABLE: u32 = 0x006B_2DD9;
|
| 263 |
/// Main frontend frame window (CWnd*)
|
| 264 |
pub const G_FRONTEND_FRAME: u32 = 0x006B_3908;
|
| 265 |
/// Main frontend HWND
|
|
|
|
| 268 |
pub const G_SKIP_TO_MAIN_MENU: u32 = 0x007A_083D;
|
| 269 |
/// Auto-network mode flag
|
| 270 |
pub const G_AUTO_NETWORK_FLAG: u32 = 0x007A_083F;
|
| 271 |
+
/// DDDisplayWrapper pointer (valid during entire frontend lifetime)
|
| 272 |
+
pub const G_DD_DISPLAY_WRAPPER: u32 = 0x0079_D6D4;
|
| 273 |
+
/// Font array β 4 fonts, each 0x241C bytes
|
| 274 |
+
pub const G_FONT_ARRAY: u32 = 0x007A_0F58;
|
| 275 |
/// Main menu active flag (0xFF during screen 18)
|
| 276 |
pub const G_MAIN_MENU_ACTIVE: u32 = 0x007C_0A20;
|
| 277 |
+
/// MFC CWinApp singleton
|
| 278 |
+
pub const G_CWINAPP: u32 = 0x007C_03D0;
|
| 279 |
/// Network mode (0=LAN, nonzero=WormNET)
|
| 280 |
pub const G_NETWORK_MODE: u32 = 0x007C_0D40;
|
| 281 |
/// Network sub-type selector
|
docs/re-notes/frontend-screens.md
CHANGED
|
@@ -1,86 +1,191 @@
|
|
| 1 |
-
# Frontend
|
| 2 |
|
| 3 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
-
|
| 6 |
-
Screen transitions work through a centralized dispatcher:
|
| 7 |
|
| 8 |
```
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 23 |
CDialog::EndDialog(screen_id)
|
| 24 |
-
- **Init** (g_FrontendFrame == 0): Store screen_id at
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|----|-----|------|---------|
|
| 30 |
-
| 0 | 0x00 | Cancel | Return to previous /
|
| 31 |
-
|
|
| 32 |
-
|
|
| 33 |
-
|
|
| 34 |
-
|
|
| 35 |
-
|
|
| 36 |
-
|
|
| 37 |
-
|
|
| 38 |
-
|
|
| 39 |
-
|
|
| 40 |
-
|
|
| 41 |
-
|
|
| 42 |
-
|
|
| 43 |
-
|
|
| 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 |
-
##
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
|
|
|
| 60 |
|
| 61 |
## Key Functions
|
| 62 |
|
| 63 |
| Address | Name | Purpose |
|
| 64 |
|---------|------|---------|
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
| 0x422180 | Frontend__PaletteAnimation | Palette transition effect |
|
| 67 |
-
|
|
| 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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Frontend Navigation State Machine
|
| 2 |
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
The WA frontend uses MFC `CDialog` modal dialogs driven by a main navigation loop.
|
| 6 |
+
The loop is at `0x4E6440` (`Frontend__MainNavigationLoop`), which is the `CWinApp::Run()`
|
| 7 |
+
virtual method override β a 19KB function that handles initialization and screen dispatch.
|
| 8 |
|
| 9 |
+
## Architecture
|
|
|
|
| 10 |
|
| 11 |
```
|
| 12 |
+
g_CurrentScreen (0x6B3504)
|
| 13 |
+
β
|
| 14 |
+
βΌ
|
| 15 |
+
ββββββββββββββββββββββββ
|
| 16 |
+
β Main Navigation Loop β (0x4E6440)
|
| 17 |
+
β do { β
|
| 18 |
+
β switch(screenId) { β
|
| 19 |
+
β case 10: ... ββββΊ Create dialog βββΊ DoModal() βββΊ result
|
| 20 |
+
β case 11: ... β β
|
| 21 |
+
β ... β β
|
| 22 |
+
β } ββββββ store result in g_CurrentScreen ββ
|
| 23 |
+
β } while(true); β
|
| 24 |
+
β β
|
| 25 |
+
β case 15: EXIT ββββΊ cleanup, return
|
| 26 |
+
ββββββββββββββββββββββββ
|
| 27 |
```
|
| 28 |
|
| 29 |
+
Each iteration:
|
| 30 |
+
1. Reads `g_CurrentScreen` (0x6B3504)
|
| 31 |
+
2. Dispatches to the matching case β allocates dialog β calls constructor β DoModal
|
| 32 |
+
3. `FrontendChangeScreen(screen_id)` inside the dialog calls `EndDialog(screen_id)`
|
| 33 |
+
4. DoModal returns the result code β stored back into `g_CurrentScreen`
|
| 34 |
+
5. Previous dialog destroyed via `Frontend__PostScreenCleanup` (0x4EB450)
|
| 35 |
+
6. Loop continues
|
| 36 |
+
|
| 37 |
## FrontendChangeScreen (0x447A20)
|
| 38 |
|
| 39 |
+
`stdcall(screen_id)` with `ESI` = dialog this pointer (MSVC `__usercall`).
|
| 40 |
+
|
| 41 |
Two modes based on `g_FrontendFrame` (0x6B3908):
|
| 42 |
|
| 43 |
- **Normal** (g_FrontendFrame != 0): Disable window β palette transition
|
| 44 |
+
(0x422180) β call vtable[0x15C] twice (args 1, 2) β re-enable window β
|
| 45 |
CDialog::EndDialog(screen_id)
|
| 46 |
+
- **Init** (g_FrontendFrame == 0): Store screen_id at dialog+0x44, clear flag
|
| 47 |
+
bit 0x10 at dialog+0x3C
|
| 48 |
+
|
| 49 |
+
## Screen Dispatch Table
|
| 50 |
+
|
| 51 |
+
### Valid main-loop screens (10β30)
|
| 52 |
+
|
| 53 |
+
| ID | Hex | Name | Constructor | Notes |
|
| 54 |
+
|----|-----|------|-------------|-------|
|
| 55 |
+
| 10 | 0x0A | Deathmatch | 0x440F40 | `PreTransitionCleanup` before |
|
| 56 |
+
| 11 | 0x0B | LocalMultiplayer | 0x49C420 | `PreTransitionCleanup` before |
|
| 57 |
+
| 12 | 0x0C | Training | 0x4E0880 | Palette load before |
|
| 58 |
+
| 14 | 0x0E | Missions | 0x499190 | Palette load before |
|
| 59 |
+
| 15 | 0x0F | **Exit** | β | Cleanup + return from CWinApp::Run |
|
| 60 |
+
| 16 | 0x10 | PostInitMenu | 0x4C91B0 | Calls 0x4E4BD0 after |
|
| 61 |
+
| 17 | 0x11 | MainMenuRedirect | β | Sets g_CurrentScreen = 18 |
|
| 62 |
+
| 18 | 0x12 | **MainMenu** | 0x4866C0 | Primary menu dialog |
|
| 63 |
+
| 21 | 0x15 | SinglePlayer | 0x4D69F0 | Palette load before |
|
| 64 |
+
| 22 | 0x16 | CampaignA | 0x4A2B70 | `PreTransitionCleanup` after |
|
| 65 |
+
| 23 | 0x17 | CampaignB | 0x4A24D0 | `PreTransitionCleanup` after |
|
| 66 |
+
| 24 | 0x18 | AdvancedSettings | 0x4279E0 | Calls 0x4E4BD0 after |
|
| 67 |
+
| 25 | 0x19 | IntroMovie | 0x470870 | Hardcodes next=18, sets g_SkipToMainMenu |
|
| 68 |
+
| 27 | 0x1B | NetworkHostSetup | 0x4ADCA0 | `PreTransitionCleanup` after |
|
| 69 |
+
| 28 | 0x1C | NetworkOnlineSetup | 0x4ACBC0 | `PreTransitionCleanup` after |
|
| 70 |
+
| 29 | 0x1D | NetworkDialogA | 0x4BC970 | `PreTransitionCleanup` after |
|
| 71 |
+
| 30 | 0x1E | NetworkDialogB | 0x4BBC00 | `PreTransitionCleanup` after |
|
| 72 |
+
|
| 73 |
+
### Network/lobby screens (1700β1707)
|
| 74 |
|
| 75 |
+
| ID | Hex | Name | Constructor | Notes |
|
| 76 |
+
|----|-----|------|-------------|-------|
|
| 77 |
+
| 1700 | 0x6A4 | NetworkProviderSelect | 0x4A7990 | Special post-DoModal logic |
|
| 78 |
+
| 1701 | 0x6A5 | NetworkSettings | 0x4C23C0 | |
|
| 79 |
+
| 1702 | 0x6A6 | LAN | 0x480A80 | |
|
| 80 |
+
| 1703 | 0x6A7 | WormNet | 0x472400 | |
|
| 81 |
+
| 1704 | 0x6A8 | LobbyHost | 0x4B0160 | Fall-through from setup |
|
| 82 |
+
| 1705 | 0x6A9 | LobbyHostContinued | (fall-through) | |
|
| 83 |
+
| 1706 | 0x6AA | LobbyClient | (fall-through) | |
|
| 84 |
+
| 1707 | 0x6AB | LobbyGameStart | 0x4BDBE0 | |
|
| 85 |
|
| 86 |
+
### Dialog result codes (NOT dispatched by main loop)
|
| 87 |
+
|
| 88 |
+
These are returned by `EndDialog` from sub-dialogs (button handlers, options screens).
|
| 89 |
+
If they reach the main loop, they hit the default case β `g_CurrentScreen = 0x0F` β exit.
|
| 90 |
+
By that point, the game has already launched or the action has been taken.
|
| 91 |
+
|
| 92 |
+
| ID | Hex | Name | Meaning |
|
| 93 |
|----|-----|------|---------|
|
| 94 |
+
| 0 | 0x00 | Cancel | Return to previous / back |
|
| 95 |
+
| 1 | 0x01 | Splash | Splash/intro trigger |
|
| 96 |
+
| 2 | 0x02 | NetworkOptionA | Network option result |
|
| 97 |
+
| 4 | 0x04 | SinglePlayerPrep | SP prep result |
|
| 98 |
+
| 5 | 0x05 | SinglePlayerConfirm | SP confirm result |
|
| 99 |
+
| 32 | 0x20 | SchemeEditorDone | Return from scheme/weapon editor |
|
| 100 |
+
| 35 | 0x23 | StartGameOffline | Start game, no network |
|
| 101 |
+
| 36 | 0x24 | StartGameOnline | Start game, network available |
|
| 102 |
+
| 37 | 0x25 | MultiplayerLocal | Multiplayer, no network |
|
| 103 |
+
| 38 | 0x26 | MultiplayerOnline | Multiplayer, network available |
|
| 104 |
+
| 39 | 0x27 | OptionsAccepted | Return after applying options + saving theme |
|
| 105 |
+
| 50 | 0x32 | InGameA | In-game state |
|
| 106 |
+
| 52 | 0x34 | InGameB | In-game state |
|
| 107 |
+
| 58 | 0x3A | InGameC | In-game state |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
+
#### Offline/Online pairs
|
| 110 |
|
| 111 |
+
The "Start Game" and "Multiplayer" paths each check a network availability flag
|
| 112 |
+
and branch to an offline/online result code:
|
| 113 |
+
|
| 114 |
+
- **Start Game** (`this+0x244` flag): 35 (offline) / 36 (online)
|
| 115 |
+
- **Multiplayer** (`this+0x140` flag): 37 (offline) / 38 (online)
|
| 116 |
+
|
| 117 |
+
Both paths use 0 (Cancel) as the "back to main menu" value.
|
| 118 |
|
| 119 |
## Key Functions
|
| 120 |
|
| 121 |
| Address | Name | Purpose |
|
| 122 |
|---------|------|---------|
|
| 123 |
+
| 0x4E6440 | Frontend__MainNavigationLoop | CWinApp::Run override β main dispatch loop |
|
| 124 |
+
| 0x447A20 | FrontendChangeScreen | Ends current dialog via EndDialog(screen_id) |
|
| 125 |
+
| 0x447960 | Frontend__DoModalWrapper | Palette transition + custom DoModal |
|
| 126 |
+
| 0x40FD60 | CDialog__DoModal_Custom | Custom MFC DoModal |
|
| 127 |
+
| 0x40FBE0 | CDialog__CustomMsgPump | Custom message pump (replaces RunModalLoop) |
|
| 128 |
+
| 0x40FF90 | FrontendDialog__OnIdle | Per-frame idle: cursor, mouse, paint dispatch |
|
| 129 |
+
| 0x40BF60 | FrontendDialog__PaintControlTree | Traverse control tree, paint dirty controls |
|
| 130 |
+
| 0x4EB450 | Frontend__PostScreenCleanup | Destroys previous dialog |
|
| 131 |
+
| 0x4E4AE0 | Frontend__PreTransitionCleanup | Cleanup before certain transitions |
|
| 132 |
| 0x422180 | Frontend__PaletteAnimation | Palette transition effect |
|
| 133 |
+
| 0x446BA0 | FrontendDialog__Constructor | Base frontend dialog constructor |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
| 0x44E850 | Frontend__OnMultiplayerButton | Multiplayer button handler |
|
| 135 |
| 0x44EC10 | Frontend__OnNetworkButton | Network button handler |
|
|
|
|
| 136 |
| 0x48DAB0 | Frontend__OnOptionsAccept | Options accept handler |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
| 0x4F14A0 | Frontend__OnStartGameButton | Start game button handler |
|
| 138 |
+
| 0x4D4920 | Network__IsAvailable | Check network availability |
|
| 139 |
+
|
| 140 |
+
## Key Globals
|
| 141 |
+
|
| 142 |
+
| Address | Name | Type | Description |
|
| 143 |
+
|---------|------|------|-------------|
|
| 144 |
+
| 0x6B3504 | g_CurrentScreen | u32 | Screen ID driving the main dispatch loop |
|
| 145 |
+
| 0x6B3908 | g_FrontendFrame | CFrameWnd* | Main frame window |
|
| 146 |
+
| 0x6B390C | g_FrontendHwnd | HWND | Main window handle |
|
| 147 |
+
| 0x79D6D4 | g_DDDisplayWrapper | void* | Display backend wrapper (valid during entire frontend) |
|
| 148 |
+
| 0x7A083D | g_SkipToMainMenu | u8 | Skip splash, go directly to main menu |
|
| 149 |
+
| 0x7A083F | g_AutoNetworkFlag | u8 | Auto-network mode flag |
|
| 150 |
+
| 0x7C0A20 | g_MainMenuActive | u8 | 0xFF during screen 18 |
|
| 151 |
+
| 0x7C03D0 | g_CWinApp | CWinApp* | MFC application singleton |
|
| 152 |
+
| 0x7C0D40 | g_NetworkMode | u32 | 0=LAN, nonzero=WormNET |
|
| 153 |
+
| 0x7C0D68 | g_NetworkSubtype | u32 | Network sub-type selector |
|
| 154 |
+
|
| 155 |
+
## Bitmap Font System
|
| 156 |
+
|
| 157 |
+
WA uses a custom bitmap font renderer, NOT GDI, for all game/frontend text.
|
| 158 |
+
|
| 159 |
+
### Font files
|
| 160 |
+
- `Graphics\Font.bmp` + `Data\Gfx\FontExt\%s2.fex` (extended glyphs)
|
| 161 |
+
- Four sizes: `SmlFont2.bmp` (12px), `StdFont2.bmp` (17px), `MedFont2.bmp` (25px), `BigFont2.bmp` (33px)
|
| 162 |
+
|
| 163 |
+
### Key structures
|
| 164 |
+
- Font array at `0x7A0F58`, each font is `0x241C` bytes
|
| 165 |
+
- Glyph table: 256 entries at `font+0x14`, each `0x24` bytes
|
| 166 |
+
- Character width table at `0x6B2DD9` (256 bytes)
|
| 167 |
+
- Registry options: `LargerFonts` (font+0x20), `FrontendFontDynamicAntialiasing` (font+0x70)
|
| 168 |
+
|
| 169 |
+
### Key functions
|
| 170 |
+
|
| 171 |
+
| Address | Name | Description |
|
| 172 |
+
|---------|------|-------------|
|
| 173 |
+
| 0x414680 | Font__LoadFonts | Loads all four font sizes from BMP files |
|
| 174 |
+
| 0x4143D0 | Font__RenderGlyphs | Core glyph renderer: iterates chars, blits from sprite sheet |
|
| 175 |
+
| 0x427830 | Font__DrawText | Higher-level: measures string, creates surface, renders |
|
| 176 |
+
| 0x5236B0 | DDDisplay__DrawTextOnBitmap | thiscall(font_id, bitmap, hAlign, vAlign, msg, a7, a8) |
|
| 177 |
+
| 0x4FAF00 | DDDisplay__ConstructTextbox | thiscall(dst, length, fontid) |
|
| 178 |
+
| 0x4FB070 | SetTextboxText | stdcall(textbox, msg, textcolor, color1, color2, a6, a7, opacity) |
|
| 179 |
+
| 0x542200 | DrawTextboxLocal | Draws textbox at screen position |
|
| 180 |
+
|
| 181 |
+
### Rendering pipeline
|
| 182 |
+
1. Create surface via `g_DDDisplayWrapper->vtable[22]` (CreateSurface factory)
|
| 183 |
+
2. `Font__RenderGlyphs` iterates characters, looks up glyph data in font table
|
| 184 |
+
3. Each glyph is blitted from the font sprite sheet onto the surface
|
| 185 |
+
4. Surface blitted to screen via `Surface__Blit` (0x403BF0 β surface->vtable[11])
|
| 186 |
+
|
| 187 |
+
### Display backends
|
| 188 |
+
The display wrapper at `0x79D6D4` (vtable `0x662EC8`, size 0x1C) delegates to one of 6 backends:
|
| 189 |
+
DirectDraw legacy, DirectDraw classic, D3D9 basic, D3D9 shader, OpenGL CPU, OpenGL GPU.
|
| 190 |
+
Concrete backend stored at `wrapper+0x18`. Initialized in the main navigation loop
|
| 191 |
+
before any dialog is created.
|