wormz-a / docs /re-notes /weapon-system.md
paavohtl's picture
Claude Opus 4.6 (1M context)
docs: update weapon-system.md with SubtractAmmo investigation results
d085c78
|
Raw History Blame Contribute Delete
19.5 kB

Weapon System

Comprehensive reference for the Worms Armageddon 3.8.1 weapon system internals.

Overview

The weapon system spans multiple subsystems: a weapon table defining all 71 weapons, an ammo/delay tracker per team/alliance, a firing dispatch that routes weapon activation to type-specific handlers, CTaskMissile objects for in-flight projectiles, and an explosion system for terrain damage.

Object Relationships

graph TD
    DDGame["DDGame (0x98B8 bytes)"]
    WT["WeaponTable<br/>DDGame+0x510"]
    TAS["TeamArenaState<br/>DDGame+0x4628"]
    WP["WeaponPanel<br/>DDGame+0x548"]
    CTW["CTaskWorm<br/>(per-live-worm task)"]
    CTM["CTaskMissile<br/>(per-projectile task)"]
    EXP["CreateExplosion"]
    LAND["PCLandscape"]

    DDGame --> WT
    DDGame --> TAS
    DDGame --> WP
    CTW -->|"FireWeapon"| CTM
    CTW -->|"GetAmmo/SubtractAmmo"| TAS
    CTM -->|"impact"| EXP
    EXP -->|"terrain damage"| LAND
    WP -->|"reads availability"| WT
    WP -->|"reads ammo"| TAS

Firing Sequence

sequenceDiagram
    participant P as Player Input
    participant W as CTaskWorm
    participant FR as WeaponRelease
    participant FW as FireWeapon
    participant CW as CreateWeaponProjectile
    participant M as CTaskMissile
    participant E as CreateExplosion
    participant L as PCLandscape

    P->>W: Fire key pressed
    W->>FR: WeaponRelease(0x51C3D0)<br/>position, angle
    FR->>FW: FireWeapon(0x51EE60)<br/>weapon type dispatch
    FW->>CW: CreateWeaponProjectile(0x51E0F0)
    CW->>M: CTaskMissile__Constructor(0x507D10)<br/>allocate 0x40C bytes
    loop Every frame
        M->>M: PhysicsUpdate(0x508C90)<br/>gravity, wind, collision
    end
    M->>E: CreateExplosion(0x548080)
    E->>L: ApplyExplosion(0x57C820)<br/>terrain bitmap damage

WeaponEntry & WeaponTable

WeaponTable (DDGame+0x510)

Allocated by InitWeaponTable (0x53CAB0, stdcall(wrapper), RET 0x4). Called once during CTaskGameState__vmethod_7 at game start.

+0x00   [WeaponEntry; 71]   entries     Standard weapons (0..70)
Total:  71 Γ— 0x1D0 = 0x80B0 bytes (no header)

WeaponEntry (0x1D0 = 464 bytes per entry)

Source: wkJellyWorm/src/CustomWeapons.h (WeaponStruct) + InitWeaponTable analysis.

+0x00   *const c_char   name1           Primary weapon name string
+0x04   *const c_char   name2           Secondary weapon name string
+0x08   i32             panel_state     Panel state (init: 0xFFFFFFFF). wkJellyWorm: panelRow
+0x0C   i32             unknown_0c      Unknown
+0x10   i32             defined         Nonzero = weapon exists. Checked by CheckWeaponAvail.
+0x14   [u8; 0x10]      unknown_14      Unknown
+0x24   i32             availability    Init: 0xFFFFFFFF, then 0 or 1. None/SkipGo/Surrender = 0.
+0x28   i32             enabled         Init: 1
+0x2C   [u8; 0x1A4]     unknown_2c      Remaining fields (opaque)

InitWeaponTable per-entry initialization:

  • +0x08 = 0xFFFFFFFF (panel_state)
  • +0x24 = 0xFFFFFFFF (availability, then overwritten per-weapon)
  • +0x28 = 1 (enabled)
  • Weapon 0 (None), 57 (SkipGo), 58 (Surrender): availability forced to 0

Rust types: WeaponEntry, WeaponTable in openwa-core/src/game/weapon.rs.

Weapon Enum (71 entries)

Defined in openwa-core/src/game/weapon.rs. Key weapon IDs:

ID Hex Name Category
0 0x00 None -
1 0x01 Bazooka Projectile
2 0x02 HomingMissile Projectile (homing)
6 0x06 Grenade Thrown
10 0x0A Earthquake Special (net-disabled)
24 0x18 SuperSheep Animal (restricted)
25 0x19 AquaSheep Animal (restricted)
37 0x25 NinjaRope Rope
40 0x28 Teleport Utility (immune to sudden death)
54 0x36 Donkey Special (disable flag)
55 0x37 NuclearTest Special (net-disabled)
56 0x38 Armageddon Special (net-disabled)
59 0x3B SelectWorm Action (needs >1 alive worm)
66 0x42 Invisibility Power-up (mode flag)
69 0x45 DoubleTurnTime Power-up (threshold)

Ammunition & Delay System

Storage: TeamArenaState (DDGame+0x4628)

Ammo and delay are stored in a flat array indexed by alliance and weapon ID.

Flat index = alliance_id Γ— 142 + weapon_id

Ammo:  TeamArenaState + 0x1EB4 + flat_index Γ— 4
Delay: TeamArenaState + 0x1EB4 + (flat_index + 71) Γ— 4

Values: -1 = unlimited, 0 = none, >0 = count
Delay:  0 = available, >0 = turns until available

6 alliances Γ— 142 entries (71 ammo + 71 delay) = 852 total slots.

Alliance ID is read from the team's sentinel worm field at offset +0x80 (sentinel_weapon_alliance).

Functions

Function Address Convention Parameters
GetAmmo 0x5225E0 usercall EAX=team_index, ESI=arena_base, EDX=weapon_id β†’ EAX=ammo
AddAmmo 0x522640 usercall EAX=team_index, EDX=amount, stack(base, weapon_id), RET 0x8
SubtractAmmo 0x522680 usercall EAX=team_index, ECX=arena_base, stack(weapon_id), RET 0x4
SubtractAmmo_v2 0x558E80 fastcall ECX=param1, EDX=CTaskTeam*
CountAliveWorms 0x5225A0 usercall EAX=team_index, ECX=arena_base β†’ EAX=count

GetAmmo special rules:

  • Returns 0 if weapon delay > 0 (weapon on cooldown)
  • Sudden death (game_phase β‰₯ 484): returns 0 for all except Teleport (0x28)
  • SelectWorm (0x3B): returns 0 if team has ≀1 alive worm
  • Game mode flag at TeamArenaState+0x2C0C can override delay checks

SubtractAmmo call sites (verified):

  • CTaskWorm__HandleMessage (0x512C27): subtracts Teleport (0x28) ammo
  • CTaskTeam_vt2__vmethod_2 (0x558443): subtracts the team's selected weapon
  • FUN_0055f8c0 (3 sites): subtracts DamageX2 (0x43), CrateSpy (0x44), and others

Our hook reportedly never triggered β€” this was because the test replay (bots) doesn't use Teleport, DamageX2, or CrateSpy. The hook implementation is correct.

The second variant at 0x558E80 (fastcall) has 3 xrefs from CTaskTeam_vt2__vmethod_2.

Port status: All 4 functions ported in replacements/weapon.rs.

Weapon Availability

DDGame__CheckWeaponAvail (0x53FFC0)

Convention: fastcall(DDGame), ESI=weapon_id. Ported as check_weapon_avail in openwa-core/src/engine/game_state_init.rs.

Per-weapon disable rules:

Weapon(s) Condition Result
Earthquake (10), NuclearTest (55), Armageddon (56) net_config_2 != 0 && net_weapon_exception == 0 Disabled in network games
Donkey (54) donkey_disabled != 0 GameInfo+0xD94C flag
Invisibility (66) invisibility_mode == 0 && network_ecx == 0 Needs network or mode flag
DoubleTurnTime (69) game_version > 0xD1 && threshold > 0x7FFF GameInfo+0xD932 threshold

General availability path:

  1. Check weapon table entry: name1 non-null = weapon defined
  2. If level_width_raw == 0 OR weapon defined: check super weapon rules
  3. IsSuperWeapon (0x565960): if super and super_weapon_allowed == 0, disable (unless game_version < 0x2A)
  4. supersheep_restricted (DDGame+0x7E25): gates SuperSheep/AquaSheep check
  5. aquasheep_is_supersheep (GameInfo+0xD956): when set, AquaSheep slot becomes SuperSheep

DDGame__IsSuperWeapon (0x565960)

Convention: fastcall(weapon_id). Returns 1 for super weapons:

Super weapon IDs: 16, 19, 29-31, 36, 41-42, 45-46, 49-51, 54-56, 60-61

FireWeapon Dispatch (0x51EE60)

Convention: thiscall. in_EAX = weapon context structure where:

  • +0x30: weapon type (1-4)
  • +0x34: subtype for type 3 and type 4
  • +0x38: subtype for type 1 and type 2
  • +0x3C: parameters base (passed to sub-functions)

param_2 = DDGameWrapper pointer. Sets param_2[0xF] = 1 on completion.

Type 1: Projectile Weapons

Subtype Function Address Weapons
1 FireWeapon__PlacedExplosive 0x51EC80 Dynamite, Mine, Petrol Bomb
2 FireWeapon__Projectile 0x51DFB0 Bazooka, Mortar, Longbow
3 CreateWeaponProjectile 0x51E0F0 Homing Missile, Homing Pigeon
4 FireWeapon__Shotgun 0x51ED90 Shotgun, Handgun, Uzi, Minigun

Type 2: Rope Weapons

Subtype Function Address Weapons
1 FireWeapon__RopeType1 0x51E1C0 Ninja Rope (attach)
2 CreateWeaponProjectile 0x51E0F0 Ninja Rope (projectile mode)
3 FireWeapon__RopeType3 0x51E240 Bungee

Type 3: Thrown Weapons

Subtype Function Address Weapons
(all) FireWeapon__GrenadeMortar 0x51E2C0 Grenade, Cluster Bomb, Banana Bomb, Holy Grenade

Type 4: Special Weapons

Subtype Function Address Description
1 vtable0xE (indirect) Blowtorch
2 FireWeapon__Special_Type2 0x51E3E0 Pneumatic Drill
3 FireWeapon__Special_Type3 0x51E350 Girder
4 vtable0xE (indirect) Baseball Bat
5 vtable0xE (indirect) Fire Punch
6 vtable0xE (indirect) Dragon Ball
8 vtable0xE (indirect) Kamikaze
9 FireWeapon__Special_Type9 0x51E480 Prod
10 FireWeapon__Special_Type10 0x51E710 Air Strike
11 vtable0xE (indirect) Scales of Justice
13 FireWeapon__Special_Type13 0x51E5C0 Napalm Strike
14 FireWeapon__Special_Type14 0x51E670 Mail/Mine/Mole Strike
16 FUN_0051EB00 (conditional) 0x51EB00 Teleport (checks FUN_516930 first)
17 FireWeapon__Special_Type17 0x51E920 Freeze
18 vtable0xE (indirect) Suicide Bomber
19 FireWeapon__Special_Type19 0x51E8C0 Skip Go
20 FireWeapon__Special_Type20 0x51E600 Surrender
21 FireWeapon__Special_Type21 0x51EBE0 Select Worm
22 FireWeapon__Special_Type22 0x51EC30 Jet Pack
23 vtable0xE (indirect) Magic Bullet
24 FireWeapon__Special_Type24 0x51EA60 Low Gravity / Fast Walk

CTaskMissile (0x40C bytes)

Extends CGameTask (0xFC base). Represents an in-flight projectile.

Constructor:  0x507D10 (stdcall, 4 params)
Vtable:       0x664438
Class type:   0x0B
Allocation:   0x40C bytes via wa_malloc

Structure Layout

+0x000  CGameTask base          (0xFC bytes)
        +0x084  speed_x         Fixed16.16 horizontal velocity
        +0x088  speed_y         Fixed16.16 vertical velocity
        +0x090  pos_x           Fixed16.16 world X
        +0x094  pos_y           Fixed16.16 world Y

+0x128  u32     launch_seed     Position-derived seed
+0x12C  u32     slot_id         Object pool slot index

+0x130  spawn_params [11 DWORDs = 44 bytes]
        [0]     owner_id        Team that fired
        [2-3]   spawn_x/y       Fixed16.16 launch position
        [4-5]   speed_x/y       Fixed16.16 initial velocity
        [8]     pellet_index    Cluster volley index

+0x15C  weapon_data [94 DWORDs = 376 bytes]
        [0x0F]  gravity_pct     100 = 1.0Γ— gravity
        [0x10]  bounce_pct      Bounce coefficient
        [0x12]  friction_pct    Friction coefficient
        [0x1A]  missile_type    2=Standard, 3=Homing, 4=Sheep, 5=Cluster
        [0x1C]  render_timer    Fuse countdown

+0x2D4  render_data [42 DWORDs = 168 bytes]
        Physics parameters (shifted copy of weapon_data)

+0x3C8  i32     direction       -1 (left) or +1 (right)

Missile Type Enum

Value Type Behavior
2 Standard Straight trajectory with gravity
3 Homing Tracks target position
4 Sheep Walking behavior on terrain
5 Cluster Splits into sub-munitions on impact

Key Methods

Method Address Description
Constructor 0x507D10 Initialize physics, copy weapon data from scheme
Init 0x508640 Reset physics state
PhysicsUpdate 0x508C90 Per-frame trajectory, gravity, wind, collision
HandleMessage 0x50B400 Event processing (detonation triggers, etc.)
Free 0x508330 Cleanup and pool return
vt12 0x508C70 Vtable slot 12
vt18_GetField130 0x50BFA0 Returns spawn_params pointer

Missile Count Limit

DDGame+0x72A4 tracks active missile count. CreateWeaponProjectile checks:

  • If count + 7 < 0x2BD (701): create missile normally
  • If exceeded and game_version < 0x3C: set error code 6 at DDGame+0x4624, load string resource 0x70F as error message at DDGame+0x7EF4
  • Otherwise: silently fail

Projectile Creation (0x51E0F0)

CreateWeaponProjectile: thiscall(this=context, param_2=missile_params, param_3=launch_params).

  1. Read DDGame via this+0x2C (CTask.ddgame field)
  2. Check missile count limit (DDGame+0x72A4 + 7 < 0x2BD)
  3. Call FUN_004FDF90(this) β€” pool slot allocator
  4. wa_malloc(0x40C) + memset(0, 0x3EC)
  5. CTaskMissile__Constructor(slot, missile_params, launch_params)
  6. Return allocated missile pointer

Explosion & Terrain Damage

Function Address Convention Description
CreateExplosion 0x548080 usercall(ESI=context) Spawns explosion task via pool allocator + vtable dispatch
PCLandscape_ApplyExplosion 0x57C820 (unknown) Modifies terrain bitmap, creates crater

CreateExplosion is a thin wrapper: allocates via FUN_004FDF90, then calls vtable[2]() on the allocated object. The actual explosion logic (radius, damage, terrain removal) lives in the explosion task's ProcessFrame.

Weapon Panel UI

Function Address Description
DDGame__InitWeaponPanel_Maybe 0x567770 Initialize panel structures and availability grid
PrepareWeaponPanel 0x568220 Main panel renderer (~2000 lines). Iterates weapons by row, checks availability, renders tiles
WeaponPanelDrawTile 0x567AA0 Render individual weapon tile
WeaponPanelDescription 0x567F80 Show ammo/delay info on hover
WeaponPanelCheckClick 0x5690B0 Handle weapon selection clicks

Panel geometry: 5 columns Γ— 13 rows. Each tile is 29px wide. Custom weapons (wkJellyWorm): dynamic columns up to 256 weapons.

Weapon Crate System

  • CTaskCrate__Constructor (0x502490): creates a weapon crate in the game world
  • Crate probability per weapon defined in scheme (WeaponSettings.crate_probability, 0-100%)
  • Crate drops award random weapons weighted by probability

Scheme Integration

Weapon configuration flows from .wsc scheme files into GameInfo, then into the weapon table and ammo arrays at game start.

WeaponSettings (4 bytes per weapon)

+0x00   u8  ammo              0=none, 1-10=count, 0x80+=infinite
+0x01   u8  power             0-20 (max varies per weapon)
+0x02   u8  delay             Turn cooldown before available
+0x03   u8  crate_probability 0-100 percentage

Scheme Formats

Version Payload Weapons
V1 0xD8 bytes 45 standard weapons
V2 0x124 bytes V1 + 19 super weapons
V3 0x192 bytes V2 + 110 extended options (physics tweaks)

Port status: Scheme parsing fully ported in openwa-core/src/game/scheme.rs (10 hooks in replacements/scheme.rs).

Complete Function Address Table

Weapon Table & Initialization

Function Address Convention Port Status
InitWeaponTable 0x53CAB0 stdcall(wrapper), RET 0x4 Hooked (passthrough)
DDGame__CheckWeaponAvail 0x53FFC0 fastcall(DDGame) Ported
DDGame__IsSuperWeapon 0x565960 fastcall(weapon_id) Ported
DDGame__LoadHudAndWeaponSprites 0x53D0E0 stdcall(wrapper, ...) Bridge call

Ammo System

Function Address Convention Port Status
GetAmmo 0x5225E0 usercall(EAX,ESI,EDX) Ported
AddAmmo 0x522640 usercall(EAX,EDX,stack), RET 0x8 Ported
SubtractAmmo 0x522680 usercall(EAX,ECX,stack), RET 0x4 Ported (may not trigger)
SubtractAmmo_v2 0x558E80 fastcall(ECX,EDX) Unported
CountAliveWorms 0x5225A0 usercall(EAX,ECX) Ported

Firing & Projectiles

Function Address Convention Port Status
WeaponRelease 0x51C3D0 thiscall(CTaskWorm*, ...) Unported
FireWeapon 0x51EE60 thiscall, EAX=weapon_ctx Unported
CreateWeaponProjectile 0x51E0F0 thiscall(context, params, launch) Unported
CTaskMissile__Constructor 0x507D10 stdcall, 4 params Unported
CTaskMissile__PhysicsUpdate 0x508C90 (unknown) Unported
CTaskMissile__HandleMessage 0x50B400 thiscall Unported
CreateExplosion 0x548080 usercall(ESI=context) Unported
PCLandscape_ApplyExplosion 0x57C820 (unknown) Unported

Fire Dispatch Targets

Function Address Weapon Category
FireWeapon__Projectile 0x51DFB0 Bazooka-class
FireWeapon__PlacedExplosive 0x51EC80 Dynamite/Mine/Petrol
FireWeapon__Shotgun 0x51ED90 Shotgun/Handgun/Uzi
FireWeapon__RopeType1 0x51E1C0 Ninja Rope attach
FireWeapon__RopeType3 0x51E240 Bungee
FireWeapon__GrenadeMortar 0x51E2C0 Grenade/Cluster/Banana
FireWeapon__Special_Type2 0x51E3E0 Pneumatic Drill
FireWeapon__Special_Type3 0x51E350 Girder
FireWeapon__Special_Type9 0x51E480 Prod
FireWeapon__Special_Type10 0x51E710 Air Strike
FireWeapon__Special_Type13 0x51E5C0 Napalm Strike
FireWeapon__Special_Type14 0x51E670 Mail/Mine/Mole Strike

Weapon Panel

Function Address Convention Port Status
DDGame__InitWeaponPanel_Maybe 0x567770 thiscall Unported
PrepareWeaponPanel 0x568220 cdecl Unported
WeaponPanelDrawTile 0x567AA0 (unknown) Unported
WeaponPanelDescription 0x567F80 (unknown) Unported
WeaponPanelCheckClick 0x5690B0 (unknown) Unported

Scheme

Function Address Convention Port Status
Scheme__CheckWeaponLimits 0x4D50E0 stdcall Ported
Scheme__ValidateExtendedOptions 0x4D5110 stdcall Ported
Scheme__ReadFile 0x4D3890 stdcall Ported

Port Recommendations

Already Done

  • Weapon enum and struct types (WeaponEntry, WeaponTable)
  • Ammo system (4 hooks: GetAmmo, AddAmmo, SubtractAmmo, CountAliveWorms)
  • Availability checks (2 hooks: CheckWeaponAvail, IsSuperWeapon)
  • Scheme parsing (10 hooks covering all scheme I/O)
  • Team/worm state queries (8 hooks in replacements/team.rs)

Next Priority

  1. InitWeaponTable internals β€” populate WeaponEntry fields from scheme data
  2. SubtractAmmo investigation β€” verify hook triggers, check v2 variant
  3. Weapon panel init β€” DDGame__InitWeaponPanel_Maybe (self-contained)

Medium Term

  1. FireWeapon dispatch β€” the type/subtype routing logic
  2. CreateWeaponProjectile β€” missile allocation and pool management
  3. WeaponRelease β€” coordinate transform and launch logic

Long Term

  1. CTaskMissile physics β€” gravity, wind, collision, homing AI
  2. Individual weapon behaviors β€” each Fire__* handler
  3. Explosion system β€” terrain damage, damage calculation
  4. Weapon panel rendering β€” PrepareWeaponPanel (~2000 lines)