File size: 8,012 Bytes
e3a0527
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2b4011e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e3a0527
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# WA Configuration System

WA uses three configuration layers: Windows Registry (primary), theme files, and weapon scheme files.

## Registry

### Path

```
HKEY_CURRENT_USER\Software\Team17SoftwareLTD\WormsArmageddon\
β”œβ”€β”€ Data
β”œβ”€β”€ Options
β”œβ”€β”€ ExportVideo
└── VSyncAssist
```

Company name string at `0x6623DC` ("Team17SoftwareLTD"), app name at `0x66237C`.

### MFC CWinApp Integration

WA uses MFC's `CWinApp` registry helpers. Dual-mode: if `CWinApp+0x54 == 0`, falls back to INI file via `GetPrivateProfileIntA`. Otherwise uses the registry.

| Function | Address | Xrefs | Notes |
|----------|---------|-------|-------|
| `CWinApp::GetAppRegistryKey` | 0x5CC4FB | β€” | Opens `HKCU\Software\{company}\{app}` |
| `CWinApp::GetSectionKey` | 0x5CC58C | β€” | Opens subsection (Options, Data, etc.) |
| `CWinApp::GetProfileIntW` | 0x5CC5D2 | 68 | Reads int from registry or INI |
| `CWinApp::WriteProfileInt` | 0x5CC63B | 55 | Writes int to registry or INI |
| `CWinApp::WriteProfileStringA` | 0x5CC6C2 | β€” | Writes string to registry or INI |
| `CWinApp::GetProfileStringA` | 0x5CC758 | β€” | Reads string from registry or INI |

Registry access flags: `0x2001F` (KEY_READ | KEY_WRITE).

### Registry Cleanup

`Registry__CleanAll` (0x4C90D0) deletes all 4 subsections recursively via `Registry__DeleteKeyRecursive` (0x4E4D10), also clears the "NetSettings" INI section.

## Game Options

`GameInfo__LoadOptions` (0x460AC0) reads options from the "Options" registry section into the GameInfo struct. Called from `GameInfo__InitSession` (0x4608E0).

| Registry Key | Default | GameInfo Offset | Type | Notes |
|-------------|---------|-----------------|------|-------|
| DetailLevel | 5 | +0xF3A1 | byte | |
| EnergyBar | 1 | +0xF3A2 | byte | |
| InfoTransparency | 0 | +0xF3A3 | byte | |
| InfoSpy | 1 | +0xF3A4 | bool | Stored as `!= 0` |
| ChatPinned | 0 | +0xF3A5 | byte | |
| ChatLines | 0 | +0xF3A8 | u32 | |
| PinnedChatLines | -1 | +0xF3AC | u32 | |
| HomeLock | 0 | +0xF3B0 | byte | |
| BackgroundDebrisParallax | 0x50 | +0xF3E8 | fixed16.16 | Clamped to i16 range, then `<< 16` |
| TopmostExplosionOnomatopoeia | 0 | +0xF3EC | u32 | |
| CaptureTransparentPNGs | 0 | +0xF3DC | u32 | |
| CameraUnlockMouseSpeed | 0x10 | +0xF3E0 | u32 | Squared; clamped to max 0xB504 before squaring |

Additional values loaded from globals (not registry) into offsets: +0xF3B4..+0xF3D0, +0xF3D4..+0xF3D8, +0xF3F4..+0xF400 (conditional on `DAT_0088C374`), +0xDAE8, +0xF3E4.

The struct also stores:
- Speech path at +0xF404: `sprintf("%s\\user\\speech", baseDir)`
- Land data path at +0xDAEC: `"data\land.dat"` (from string at 0x64DA58)

`Options__GetCrashReportURL` (0x5A63F0) reads "CrashReportURL" from the Options section for crash reporting.

## Theme File (`data\current.thm`)

Binary format, variable length. Contains visual/audio theme settings.

| Function | Address | Notes |
|----------|---------|-------|
| `Theme__GetFileSize` | 0x44BA80 | Opens file, returns length (0 if missing) |
| `Theme__Load` | 0x44BB20 | Reads entire file into buffer; `AfxMessageBox` if missing |
| `Theme__Save` | 0x44BBC0 | Writes buffer to file; `AfxMessageBox` on create failure |

### Save Flow

`Frontend__OnOptionsAccept` (0x48DAB0) triggers on screen 0x27:
1. Calls `FUN_0048D7C0` (unknown setup)
2. Calls `Frontend__ApplyOptions` (0x440940) with frontend data
3. Calls `Frontend__SaveTheme` (0x490E60) with path `"data\current.thm"`
4. Calls `FrontendChangeScreen` to navigate away

## Weapon Schemes (.wsc)

Stored as `.wsc` files under `User\Schemes\`. Full format spec: [worms2d.info/Game_scheme_file](https://worms2d.info/Game_scheme_file).

### Functions

| Function | Address | Signature | Notes |
|----------|---------|-----------|-------|
| `Scheme__ReadFile` | 0x4D3890 | stdcall(dest, path, flag, out_ptr) β†’ u32, RET 0x10 | Reads .wsc into dest+0x14 |
| `Scheme__SaveFile` | 0x4D44F0 | thiscall(this, name, flag), RET 0x8 | Writes struct to .wsc |
| `Scheme__DetectVersion` | 0x4D4480 | Uses ESI (non-standard) β†’ 1/2/3 | Compares V3 extension bytes |
| `Scheme__FileExists` | 0x4D4CD0 | stdcall(name) β†’ 0/1, RET 0x4 | Path: `User\Schemes\%s.wsc` |
| `Scheme__FileExistsNumbered` | 0x4D4E00 | stdcall(...) | Path: `User\Schemes\{%02d} %s.wsc` |
| `Scheme__InitFromData` | 0x4D5020 | fastcall(?, data, dest, name) | Copies payload + V3 defaults |
| `Scheme__CheckWeaponLimits` | 0x4D50E0 | β€” β†’ 0/1 | Validates ammo vs max table (39 weapons) |
| `Scheme__ValidateExtendedOptions` | 0x4D5110 | Uses EAX β†’ 0/1 | V3 field range checks |
| `Scheme__ScanDirectory` | 0x4D54E0 | β€” | Finds `{NN} name.wsc` files |
| `Scheme__ExtractBuiltins` | 0x4D5720 | β€” | Extracts PE resources (IDs 0x3CA-0x3D6) |

### Data

| Symbol | Address | Size | Notes |
|--------|---------|------|-------|
| `SCHEME_V3_DEFAULTS` | 0x649AB8 | 110 bytes | Default extended options for V1/V2 |
| `SCHEME_WEAPON_AMMO_LIMITS` | 0x6AD130 | 39 bytes | Max ammo per weapon (V1 set) |

### File Format

Binary, little-endian. Header: `"SCHM"` (4 bytes) + version byte (1 byte) + payload.

| Version | Payload | Total | Content |
|---------|---------|-------|---------|
| V1 (0x01) | 0xD8 (216) | 221 | 36 options + 45 weapons Γ— 4 |
| V2 (0x02) | 0x124 (292) | 297 | V1 + 19 super weapons Γ— 4 |
| V3 (0x03) | 0x192 (402) | 407 | V2 + 110 extended options |

### Payload Layout

**Game Options (36 bytes, payload +0x00):**

| Offset | Size | Field | Notes |
|--------|------|-------|-------|
| +0x00 | 1 | hot_seat_delay | Seconds between turns |
| +0x01 | 1 | retreat_time | Seconds after weapon use |
| +0x02 | 1 | rope_retreat_time | Seconds after rope weapon use |
| +0x03 | 1 | display_total_round_time | bool |
| +0x04 | 1 | automatic_replays | bool |
| +0x05 | 1 | fall_damage | Damage at critical velocity |
| +0x06 | 1 | artillery_mode | bool |
| +0x07 | 1 | bounty_mode | 0x00/0x5F/0x89 |
| +0x08 | 1 | stockpiling | 0=Off, 1=On, 2=Anti |
| +0x09 | 1 | worm_select | 0=Sequential, 1=Manual, 2=Random |
| +0x0A | 1 | sudden_death_event | 0=RoundEnds, 1=Nuke, 2=HP→1, 3=Nothing |
| +0x0B | 1 | water_rise_rate | Flooding speed |
| +0x0C | 1 | weapon_crate_probability | i8, -100 to 100 |
| +0x0D | 1 | donor_cards | bool |
| +0x0E | 1 | health_crate_probability | i8 |
| +0x0F | 1 | health_crate_energy | Energy from health crate |
| +0x10 | 1 | utility_crate_probability | i8 |
| +0x11 | 1 | hazardous_object_types | Bitmask |
| +0x12 | 1 | mine_delay | i8, seconds (0x80+=random) |
| +0x13 | 1 | dud_mines | bool |
| +0x14 | 1 | manual_worm_placement | bool |
| +0x15 | 1 | worm_energy | 0=instant death |
| +0x16 | 1 | turn_time | Seconds |
| +0x17 | 1 | round_time | Minutes (0=immediate SD) |
| +0x18 | 1 | number_of_wins | Rounds to win match |
| +0x19 | 1 | blood | false=pink, true=red |
| +0x1A | 1 | aqua_sheep | bool |
| +0x1B | 1 | sheep_heaven | bool |
| +0x1C | 1 | god_worms | bool |
| +0x1D | 1 | indestructible_land | bool |
| +0x1E | 1 | upgraded_grenade | bool |
| +0x1F | 1 | upgraded_shotgun | bool |
| +0x20 | 1 | upgraded_clusters | bool |
| +0x21 | 1 | upgraded_longbow | bool |
| +0x22 | 1 | team_weapons | bool |
| +0x23 | 1 | super_weapons | bool |

**Per-Weapon (4 bytes each, payload +0x24):**

`[ammo, power, delay, crate_probability]` β€” 45 weapons (V1), 64 weapons (V2+).

**V3 Extended Options (110 bytes, payload +0x124):**

Physics (gravity, friction, wind), RubberWorm modifiers, glitch toggles, and gameplay extensions. See `scheme.rs::ExtendedOptions` for full field list. Uses fixed-point 16.16 and tri-state (0/1/0x80) types.

### Callers of Scheme__ReadFile

| Address | Context |
|---------|---------|
| 0x4A1D18 | Frontend/options dialog |
| 0x4B4B92 | Multiplayer scheme loading |
| 0x4CC425 | Mission/campaign loading |

## Data Files

| File | String Address | Notes |
|------|---------------|-------|
| `data\land.dat` | 0x64DA58 | Landscape/terrain data |
| `custom.dat` | 0x64DA88 | Custom content |
| `steam.dat` | 0x662808 | Steam integration data |