feat: identify weapon_ctx as WeaponEntry pointer, add fire fields
Browse filesRuntime investigation confirmed CTaskWorm+0x36C points to the active
WeaponEntry in the WeaponTable (entry index matches selected_weapon).
Add newly discovered WeaponEntry fields:
- fire_type (+0x30): weapon dispatch type (1-4)
- fire_subtype_34 (+0x34): subtype for types 3/4
- fire_subtype_38 (+0x38): subtype for types 1/2
- fire_complete (+0x3C): completion flag / params base
Type CTaskWorm.active_weapon_entry as *mut WeaponEntry.
Remove incorrect CTaskWorm weapon accessors (they read from the worm's
subclass_data instead of the WeaponEntry).
Verified: headless PASS (byte-identical).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/game/weapon.rs
CHANGED
|
@@ -126,8 +126,20 @@ pub struct WeaponEntry {
|
|
| 126 |
pub availability: i32,
|
| 127 |
/// +0x28: Enabled flag (init: 1).
|
| 128 |
pub enabled: i32,
|
| 129 |
-
/// +0x2C-
|
| 130 |
-
pub _unknown_2c: [u8;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
}
|
| 132 |
const _: () = assert!(core::mem::size_of::<WeaponEntry>() == 0x1D0);
|
| 133 |
|
|
|
|
| 126 |
pub availability: i32,
|
| 127 |
/// +0x28: Enabled flag (init: 1).
|
| 128 |
pub enabled: i32,
|
| 129 |
+
/// +0x2C-0x2F: Unknown.
|
| 130 |
+
pub _unknown_2c: [u8; 4],
|
| 131 |
+
/// +0x30: Weapon fire type (1=projectile, 2=rope, 3=grenade, 4=special).
|
| 132 |
+
/// Read by FireWeapon to dispatch to the correct handler.
|
| 133 |
+
pub fire_type: i32,
|
| 134 |
+
/// +0x34: Fire subtype for weapon types 3 (grenade/mortar) and 4 (special).
|
| 135 |
+
pub fire_subtype_34: i32,
|
| 136 |
+
/// +0x38: Fire subtype for weapon types 1 (projectile) and 2 (rope).
|
| 137 |
+
pub fire_subtype_38: i32,
|
| 138 |
+
/// +0x3C: Fire completion flag / params base.
|
| 139 |
+
/// Set to 0 before dispatch, 1 after. Address also passed to fire handlers.
|
| 140 |
+
pub fire_complete: i32,
|
| 141 |
+
/// +0x40-0x1CF: Unknown fields.
|
| 142 |
+
pub _unknown_40: [u8; 0x1D0 - 0x40],
|
| 143 |
}
|
| 144 |
const _: () = assert!(core::mem::size_of::<WeaponEntry>() == 0x1D0);
|
| 145 |
|
crates/openwa-core/src/task/worm.rs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
use super::base::CTask;
|
| 2 |
use super::game_task::CGameTask;
|
|
|
|
| 3 |
|
| 4 |
/// Virtual method table for CTaskWorm (vtable at 0x6644C8, 20 slots).
|
| 5 |
///
|
|
@@ -151,11 +152,10 @@ pub struct CTaskWorm {
|
|
| 151 |
pub _unknown_338: [u8; 0x368 - 0x338],
|
| 152 |
/// 0x368: Animator / controller object (dispatched via vtable for state animations)
|
| 153 |
pub animator: *mut u8,
|
| 154 |
-
/// 0x36C:
|
| 155 |
-
///
|
| 156 |
-
/// NOT a self-pointer — weapon_ctx != worm (confirmed via runtime logging).
|
| 157 |
/// Used by WeaponRelease: `MOV EAX, [EDI+0x36C]` before calling FireWeapon.
|
| 158 |
-
pub
|
| 159 |
/// 0x370–0x3DB: Unknown (rope anchor, weapon-specific data, etc.)
|
| 160 |
pub _unknown_370: [u8; 0x3DC - 0x370],
|
| 161 |
/// 0x3DC: Facing direction. -1 = facing left, +1 = facing right.
|
|
@@ -186,13 +186,9 @@ impl CTaskWorm {
|
|
| 186 |
unsafe { *((self as *const CTaskWorm as *const u8).add(0x44) as *const u32) }
|
| 187 |
}
|
| 188 |
|
| 189 |
-
// Weapon fire state lives in the
|
| 190 |
-
// NOT in CTaskWorm itself.
|
| 191 |
-
//
|
| 192 |
-
// +0x34: weapon_fire_subtype_34 (for types 3/4)
|
| 193 |
-
// +0x38: weapon_fire_subtype_38 (for types 1/2)
|
| 194 |
-
// +0x3C: weapon_fire_complete (0 before, 1 after dispatch)
|
| 195 |
-
// Accessed via raw pointers in the FireWeapon hook (weapon.rs).
|
| 196 |
|
| 197 |
/// Returns a reference to the vtable.
|
| 198 |
///
|
|
|
|
| 1 |
use super::base::CTask;
|
| 2 |
use super::game_task::CGameTask;
|
| 3 |
+
use crate::game::weapon::WeaponEntry;
|
| 4 |
|
| 5 |
/// Virtual method table for CTaskWorm (vtable at 0x6644C8, 20 slots).
|
| 6 |
///
|
|
|
|
| 152 |
pub _unknown_338: [u8; 0x368 - 0x338],
|
| 153 |
/// 0x368: Animator / controller object (dispatched via vtable for state animations)
|
| 154 |
pub animator: *mut u8,
|
| 155 |
+
/// 0x36C: Active weapon entry pointer. Points to `&WeaponTable.entries[selected_weapon]`.
|
| 156 |
+
/// Contains fire type (+0x30), subtypes (+0x34/+0x38), and completion flag (+0x3C).
|
|
|
|
| 157 |
/// Used by WeaponRelease: `MOV EAX, [EDI+0x36C]` before calling FireWeapon.
|
| 158 |
+
pub active_weapon_entry: *mut WeaponEntry,
|
| 159 |
/// 0x370–0x3DB: Unknown (rope anchor, weapon-specific data, etc.)
|
| 160 |
pub _unknown_370: [u8; 0x3DC - 0x370],
|
| 161 |
/// 0x3DC: Facing direction. -1 = facing left, +1 = facing right.
|
|
|
|
| 186 |
unsafe { *((self as *const CTaskWorm as *const u8).add(0x44) as *const u32) }
|
| 187 |
}
|
| 188 |
|
| 189 |
+
// Weapon fire state lives in the WeaponEntry pointed to by active_weapon_entry
|
| 190 |
+
// (+0x36C), NOT in CTaskWorm itself. See WeaponEntry fields: fire_type (+0x30),
|
| 191 |
+
// fire_subtype_34 (+0x34), fire_subtype_38 (+0x38), fire_complete (+0x3C).
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
|
| 193 |
/// Returns a reference to the vtable.
|
| 194 |
///
|
crates/openwa-wormkit/src/replacements/weapon.rs
CHANGED
|
@@ -187,6 +187,9 @@ unsafe extern "cdecl" fn fire_weapon_impl(weapon_ctx: u32, local_struct: u32, wo
|
|
| 187 |
let params = weapon_ctx.wrapping_add(0x3C);
|
| 188 |
let worm_ptr = worm as *mut u8;
|
| 189 |
|
|
|
|
|
|
|
|
|
|
| 190 |
// Log weapon fire
|
| 191 |
let weapon_id = *(worm_ptr.add(0x170) as *const u32);
|
| 192 |
let weapon_name = Weapon::try_from(weapon_id)
|
|
|
|
| 187 |
let params = weapon_ctx.wrapping_add(0x3C);
|
| 188 |
let worm_ptr = worm as *mut u8;
|
| 189 |
|
| 190 |
+
// weapon_ctx = pointer to WeaponEntry in WeaponTable (confirmed via runtime logging).
|
| 191 |
+
// CTaskWorm+0x36C stores &WeaponTable.entries[selected_weapon].
|
| 192 |
+
|
| 193 |
// Log weapon fire
|
| 194 |
let weapon_id = *(worm_ptr.add(0x170) as *const u32);
|
| 195 |
let weapon_name = Weapon::try_from(weapon_id)
|