Download docs/re-notes/frontend-screens.md from nmarshall/wormz-a: direct link, hf CLI and curl.
- Browser
- Download file 9.26 kB
-
https://huggingface.co/nmarshall/wormz-a/resolve/main/docs/re-notes/frontend-screens.md
- Command line
-
hf download hf://nmarshall/wormz-a/docs/re-notes/frontend-screens.md
-
curl -L -o frontend-screens.md https://huggingface.co/nmarshall/wormz-a/resolve/main/docs/re-notes/frontend-screens.md
Frontend Navigation State Machine
Overview
The WA frontend uses MFC CDialog modal dialogs driven by a main navigation loop.
The loop is at 0x4E6440 (Frontend__MainNavigationLoop), which is the CWinApp::Run()
virtual method override β a 19KB function that handles initialization and screen dispatch.
Architecture
g_CurrentScreen (0x6B3504)
β
βΌ
ββββββββββββββββββββββββ
β Main Navigation Loop β (0x4E6440)
β do { β
β switch(screenId) { β
β case 10: ... ββββΊ Create dialog βββΊ DoModal() βββΊ result
β case 11: ... β β
β ... β β
β } ββββββ store result in g_CurrentScreen ββ
β } while(true); β
β β
β case 15: EXIT ββββΊ cleanup, return
ββββββββββββββββββββββββ
Each iteration:
- Reads
g_CurrentScreen(0x6B3504) - Dispatches to the matching case β allocates dialog β calls constructor β DoModal
FrontendChangeScreen(screen_id)inside the dialog callsEndDialog(screen_id)- DoModal returns the result code β stored back into
g_CurrentScreen - Previous dialog destroyed via
Frontend__PostScreenCleanup(0x4EB450) - Loop continues
FrontendChangeScreen (0x447A20)
stdcall(screen_id) with ESI = dialog this pointer (MSVC __usercall).
Two modes based on g_FrontendFrame (0x6B3908):
- Normal (g_FrontendFrame != 0): Disable window β palette transition (0x422180) β call vtable[0x15C] twice (args 1, 2) β re-enable window β CDialog::EndDialog(screen_id)
- Init (g_FrontendFrame == 0): Store screen_id at dialog+0x44, clear flag bit 0x10 at dialog+0x3C
Screen Dispatch Table
Valid main-loop screens (10β30)
| ID | Hex | Name | Constructor | Notes |
|---|---|---|---|---|
| 10 | 0x0A | Deathmatch | 0x440F40 | PreTransitionCleanup before |
| 11 | 0x0B | LocalMultiplayer | 0x49C420 | PreTransitionCleanup before |
| 12 | 0x0C | Training | 0x4E0880 | Palette load before |
| 14 | 0x0E | Missions | 0x499190 | Palette load before |
| 15 | 0x0F | Exit | β | Cleanup + return from CWinApp::Run |
| 16 | 0x10 | PostInitMenu | 0x4C91B0 | Calls 0x4E4BD0 after |
| 17 | 0x11 | MainMenuRedirect | β | Sets g_CurrentScreen = 18 |
| 18 | 0x12 | MainMenu | 0x4866C0 | Primary menu dialog |
| 21 | 0x15 | SinglePlayer | 0x4D69F0 | Palette load before |
| 22 | 0x16 | CampaignA | 0x4A2B70 | PreTransitionCleanup after |
| 23 | 0x17 | CampaignB | 0x4A24D0 | PreTransitionCleanup after |
| 24 | 0x18 | AdvancedSettings | 0x4279E0 | Calls 0x4E4BD0 after |
| 25 | 0x19 | IntroMovie | 0x470870 | Hardcodes next=18, sets g_SkipToMainMenu |
| 27 | 0x1B | NetworkHostSetup | 0x4ADCA0 | PreTransitionCleanup after |
| 28 | 0x1C | NetworkOnlineSetup | 0x4ACBC0 | PreTransitionCleanup after |
| 29 | 0x1D | NetworkDialogA | 0x4BC970 | PreTransitionCleanup after |
| 30 | 0x1E | NetworkDialogB | 0x4BBC00 | PreTransitionCleanup after |
Network/lobby screens (1700β1707)
| ID | Hex | Name | Constructor | Notes |
|---|---|---|---|---|
| 1700 | 0x6A4 | NetworkProviderSelect | 0x4A7990 | Special post-DoModal logic |
| 1701 | 0x6A5 | NetworkSettings | 0x4C23C0 | |
| 1702 | 0x6A6 | LAN | 0x480A80 | |
| 1703 | 0x6A7 | WormNet | 0x472400 | |
| 1704 | 0x6A8 | LobbyHost | 0x4B0160 | Fall-through from setup |
| 1705 | 0x6A9 | LobbyHostContinued | (fall-through) | |
| 1706 | 0x6AA | LobbyClient | (fall-through) | |
| 1707 | 0x6AB | LobbyGameStart | 0x4BDBE0 |
Dialog result codes (NOT dispatched by main loop)
These are returned by EndDialog from sub-dialogs (button handlers, options screens).
If they reach the main loop, they hit the default case β g_CurrentScreen = 0x0F β exit.
By that point, the game has already launched or the action has been taken.
| ID | Hex | Name | Meaning |
|---|---|---|---|
| 0 | 0x00 | Cancel | Return to previous / back |
| 1 | 0x01 | Splash | Splash/intro trigger |
| 2 | 0x02 | NetworkOptionA | Network option result |
| 4 | 0x04 | SinglePlayerPrep | SP prep result |
| 5 | 0x05 | SinglePlayerConfirm | SP confirm result |
| 32 | 0x20 | SchemeEditorDone | Return from scheme/weapon editor |
| 35 | 0x23 | StartGameOffline | Start game, no network |
| 36 | 0x24 | StartGameOnline | Start game, network available |
| 37 | 0x25 | MultiplayerLocal | Multiplayer, no network |
| 38 | 0x26 | MultiplayerOnline | Multiplayer, network available |
| 39 | 0x27 | OptionsAccepted | Return after applying options + saving theme |
| 50 | 0x32 | InGameA | In-game state |
| 52 | 0x34 | InGameB | In-game state |
| 58 | 0x3A | InGameC | In-game state |
Offline/Online pairs
The "Start Game" and "Multiplayer" paths each check a network availability flag and branch to an offline/online result code:
- Start Game (
this+0x244flag): 35 (offline) / 36 (online) - Multiplayer (
this+0x140flag): 37 (offline) / 38 (online)
Both paths use 0 (Cancel) as the "back to main menu" value.
Key Functions
| Address | Name | Purpose |
|---|---|---|
| 0x4E6440 | Frontend__MainNavigationLoop | CWinApp::Run override β main dispatch loop |
| 0x447A20 | FrontendChangeScreen | Ends current dialog via EndDialog(screen_id) |
| 0x447960 | Frontend__DoModalWrapper | Palette transition + custom DoModal |
| 0x40FD60 | CDialog__DoModal_Custom | Custom MFC DoModal |
| 0x40FBE0 | CDialog__CustomMsgPump | Custom message pump (replaces RunModalLoop) |
| 0x40FF90 | FrontendDialog__OnIdle | Per-frame idle: cursor, mouse, paint dispatch |
| 0x40BF60 | FrontendDialog__PaintControlTree | Traverse control tree, paint dirty controls |
| 0x4EB450 | Frontend__PostScreenCleanup | Destroys previous dialog |
| 0x4E4AE0 | Frontend__PreTransitionCleanup | Cleanup before certain transitions |
| 0x422180 | Frontend__PaletteAnimation | Palette transition effect |
| 0x446BA0 | FrontendDialog__Constructor | Base frontend dialog constructor |
| 0x44E850 | Frontend__OnMultiplayerButton | Multiplayer button handler |
| 0x44EC10 | Frontend__OnNetworkButton | Network button handler |
| 0x48DAB0 | Frontend__OnOptionsAccept | Options accept handler |
| 0x4F14A0 | Frontend__OnStartGameButton | Start game button handler |
| 0x4D4920 | Network__IsAvailable | Check network availability |
Key Globals
| Address | Name | Type | Description |
|---|---|---|---|
| 0x6B3504 | g_CurrentScreen | u32 | Screen ID driving the main dispatch loop |
| 0x6B3908 | g_FrontendFrame | CFrameWnd* | Main frame window |
| 0x6B390C | g_FrontendHwnd | HWND | Main window handle |
| 0x79D6D4 | g_DDDisplayWrapper | void* | Display backend wrapper (valid during entire frontend) |
| 0x7A083D | g_SkipToMainMenu | u8 | Skip splash, go directly to main menu |
| 0x7A083F | g_AutoNetworkFlag | u8 | Auto-network mode flag |
| 0x7C0A20 | g_MainMenuActive | u8 | 0xFF during screen 18 |
| 0x7C03D0 | g_CWinApp | CWinApp* | MFC application singleton |
| 0x7C0D40 | g_NetworkMode | u32 | 0=LAN, nonzero=WormNET |
| 0x7C0D68 | g_NetworkSubtype | u32 | Network sub-type selector |
Bitmap Font System
WA uses a custom bitmap font renderer, NOT GDI, for all game/frontend text.
Font files
Graphics\Font.bmp+Data\Gfx\FontExt\%s2.fex(extended glyphs)- Four sizes:
SmlFont2.bmp(12px),StdFont2.bmp(17px),MedFont2.bmp(25px),BigFont2.bmp(33px)
Key structures
- Font array at
0x7A0F58, each font is0x241Cbytes - Glyph table: 256 entries at
font+0x14, each0x24bytes - Character width table at
0x6B2DD9(256 bytes) - Registry options:
LargerFonts(font+0x20),FrontendFontDynamicAntialiasing(font+0x70)
Key functions
| Address | Name | Description |
|---|---|---|
| 0x414680 | Font__LoadFonts | Loads all four font sizes from BMP files |
| 0x4143D0 | Font__RenderGlyphs | Core glyph renderer: iterates chars, blits from sprite sheet |
| 0x427830 | Font__DrawText | Higher-level: measures string, creates surface, renders |
| 0x5236B0 | DDDisplay__DrawTextOnBitmap | thiscall(font_id, bitmap, hAlign, vAlign, msg, a7, a8) |
| 0x4FAF00 | DDDisplay__ConstructTextbox | thiscall(dst, length, fontid) |
| 0x4FB070 | SetTextboxText | stdcall(textbox, msg, textcolor, color1, color2, a6, a7, opacity) |
| 0x542200 | DrawTextboxLocal | Draws textbox at screen position |
Rendering pipeline
- Create surface via
g_DDDisplayWrapper->vtable[22](CreateSurface factory) Font__RenderGlyphsiterates characters, looks up glyph data in font table- Each glyph is blitted from the font sprite sheet onto the surface
- Surface blitted to screen via
Surface__Blit(0x403BF0 β surface->vtable[11])
Display backends
The display wrapper at 0x79D6D4 (vtable 0x662EC8, size 0x1C) delegates to one of 6 backends:
DirectDraw legacy, DirectDraw classic, D3D9 basic, D3D9 shader, OpenGL CPU, OpenGL GPU.
Concrete backend stored at wrapper+0x18. Initialized in the main navigation loop
before any dialog is created.