refactor: eliminate pointer arithmetic from FireWeapon impl
Browse files- Rename WeaponEntry.fire_complete β fire_params_start (u32), since
its address is passed to sub-functions as a params base pointer
- Add CTaskWorm::fire_complete() / set_fire_complete() for the
completion flag at CGameTask.subclass_data[12] (worm+0x3C)
- Rename params β fire_params, worm_u32 β w for clarity
- All field reads now go through typed struct access, no raw offsets
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/game/weapon.rs
CHANGED
|
@@ -135,9 +135,9 @@ pub struct WeaponEntry {
|
|
| 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:
|
| 139 |
-
///
|
| 140 |
-
pub
|
| 141 |
/// +0x40-0x1CF: Unknown fields.
|
| 142 |
pub _unknown_40: [u8; 0x1D0 - 0x40],
|
| 143 |
}
|
|
|
|
| 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: Weapon fire params start. Address of this field is passed
|
| 139 |
+
/// to fire sub-functions as the params base pointer.
|
| 140 |
+
pub fire_params_start: u32,
|
| 141 |
/// +0x40-0x1CF: Unknown fields.
|
| 142 |
pub _unknown_40: [u8; 0x1D0 - 0x40],
|
| 143 |
}
|
crates/openwa-core/src/task/worm.rs
CHANGED
|
@@ -186,9 +186,20 @@ impl CTaskWorm {
|
|
| 186 |
unsafe { *((self as *const CTaskWorm as *const u8).add(0x44) as *const u32) }
|
| 187 |
}
|
| 188 |
|
| 189 |
-
// Weapon fire
|
| 190 |
-
//
|
| 191 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
|
| 193 |
/// Returns a reference to the vtable.
|
| 194 |
///
|
|
|
|
| 186 |
unsafe { *((self as *const CTaskWorm as *const u8).add(0x44) as *const u32) }
|
| 187 |
}
|
| 188 |
|
| 189 |
+
// Weapon fire dispatch state:
|
| 190 |
+
// - Fire type/subtypes live in the WeaponEntry (via active_weapon_entry at +0x36C)
|
| 191 |
+
// - Completion flag lives in CGameTask.subclass_data[12] (this object, at +0x3C)
|
| 192 |
+
|
| 193 |
+
/// Weapon fire completion flag at CGameTask+0x3C (subclass_data[12]).
|
| 194 |
+
/// Set to 0 before FireWeapon dispatch, 1 after.
|
| 195 |
+
pub fn fire_complete(&self) -> i32 {
|
| 196 |
+
i32::from_ne_bytes(self.base.subclass_data[12..16].try_into().unwrap())
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
/// Set the weapon fire completion flag.
|
| 200 |
+
pub fn set_fire_complete(&mut self, value: i32) {
|
| 201 |
+
self.base.subclass_data[12..16].copy_from_slice(&value.to_ne_bytes());
|
| 202 |
+
}
|
| 203 |
|
| 204 |
/// Returns a reference to the vtable.
|
| 205 |
///
|
crates/openwa-wormkit/src/replacements/weapon.rs
CHANGED
|
@@ -196,48 +196,47 @@ unsafe extern "cdecl" fn fire_weapon_impl(
|
|
| 196 |
let weapon_type = (*entry).fire_type;
|
| 197 |
let subtype_34 = (*entry).fire_subtype_34;
|
| 198 |
let subtype_38 = (*entry).fire_subtype_38;
|
| 199 |
-
let
|
| 200 |
-
let
|
| 201 |
|
| 202 |
// Log weapon fire
|
| 203 |
let weapon_id = (*worm).selected_weapon;
|
| 204 |
let weapon_name = Weapon::try_from(weapon_id)
|
| 205 |
-
.map(|
|
| 206 |
.unwrap_or_else(|id| format!("Unknown({})", id));
|
| 207 |
let _ = log_line(&format!(
|
| 208 |
"[Weapon] FireWeapon: {} (id={}) type={} sub34={} sub38={}",
|
| 209 |
weapon_name, weapon_id, weapon_type, subtype_34, subtype_38
|
| 210 |
));
|
| 211 |
|
| 212 |
-
|
| 213 |
-
*(worm as *mut u8).add(0x3C).cast::<i32>() = 0;
|
| 214 |
|
| 215 |
match weapon_type {
|
| 216 |
1 => match subtype_38 {
|
| 217 |
-
1 => call_fire_stdcall1(
|
| 218 |
-
2 => call_fire_stdcall3(
|
| 219 |
-
3 => call_fire_thiscall2(
|
| 220 |
-
4 => call_fire_stdcall2(
|
| 221 |
_ => {}
|
| 222 |
},
|
| 223 |
2 => match subtype_38 {
|
| 224 |
-
1 => call_fire_stdcall3(
|
| 225 |
-
2 => call_fire_thiscall2(
|
| 226 |
-
3 => call_fire_stdcall3(
|
| 227 |
_ => {}
|
| 228 |
},
|
| 229 |
3 => {
|
| 230 |
-
let
|
| 231 |
-
call_fire_stdcall3(
|
| 232 |
}
|
| 233 |
4 => {
|
| 234 |
-
let
|
| 235 |
-
fire_weapon_special(subtype_34,
|
| 236 |
}
|
| 237 |
_ => {}
|
| 238 |
}
|
| 239 |
|
| 240 |
-
|
| 241 |
}
|
| 242 |
|
| 243 |
// ββ Sub-function bridges ββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 196 |
let weapon_type = (*entry).fire_type;
|
| 197 |
let subtype_34 = (*entry).fire_subtype_34;
|
| 198 |
let subtype_38 = (*entry).fire_subtype_38;
|
| 199 |
+
let fire_params = &raw const (*entry).fire_params_start as u32;
|
| 200 |
+
let w = worm as u32;
|
| 201 |
|
| 202 |
// Log weapon fire
|
| 203 |
let weapon_id = (*worm).selected_weapon;
|
| 204 |
let weapon_name = Weapon::try_from(weapon_id)
|
| 205 |
+
.map(|wp| format!("{:?}", wp))
|
| 206 |
.unwrap_or_else(|id| format!("Unknown({})", id));
|
| 207 |
let _ = log_line(&format!(
|
| 208 |
"[Weapon] FireWeapon: {} (id={}) type={} sub34={} sub38={}",
|
| 209 |
weapon_name, weapon_id, weapon_type, subtype_34, subtype_38
|
| 210 |
));
|
| 211 |
|
| 212 |
+
(*worm).set_fire_complete(0);
|
|
|
|
| 213 |
|
| 214 |
match weapon_type {
|
| 215 |
1 => match subtype_38 {
|
| 216 |
+
1 => call_fire_stdcall1(w, fire_params, rb(0x51EC80)), // PlacedExplosive
|
| 217 |
+
2 => call_fire_stdcall3(w, fire_params, local_struct, rb(0x51DFB0)), // Projectile
|
| 218 |
+
3 => call_fire_thiscall2(w, fire_params, local_struct, rb(0x51E0F0)), // CreateWeaponProjectile
|
| 219 |
+
4 => call_fire_stdcall2(w, fire_params, local_struct, rb(0x51ED90)), // Shotgun
|
| 220 |
_ => {}
|
| 221 |
},
|
| 222 |
2 => match subtype_38 {
|
| 223 |
+
1 => call_fire_stdcall3(w, fire_params, local_struct, rb(0x51E1C0)), // RopeType1
|
| 224 |
+
2 => call_fire_thiscall2(w, fire_params, local_struct, rb(0x51E0F0)), // CreateWeaponProjectile
|
| 225 |
+
3 => call_fire_stdcall3(w, fire_params, local_struct, rb(0x51E240)), // RopeType3
|
| 226 |
_ => {}
|
| 227 |
},
|
| 228 |
3 => {
|
| 229 |
+
let subtype_34_ptr = &raw const (*entry).fire_subtype_34 as u32;
|
| 230 |
+
call_fire_stdcall3(w, subtype_34_ptr, local_struct, rb(0x51E2C0)); // GrenadeMortar
|
| 231 |
}
|
| 232 |
4 => {
|
| 233 |
+
let subtype_38_ptr = &raw const (*entry).fire_subtype_38 as u32;
|
| 234 |
+
fire_weapon_special(subtype_34, subtype_38_ptr, w, local_struct);
|
| 235 |
}
|
| 236 |
_ => {}
|
| 237 |
}
|
| 238 |
|
| 239 |
+
(*worm).set_fire_complete(1);
|
| 240 |
}
|
| 241 |
|
| 242 |
// ββ Sub-function bridges ββββββββββββββββββββββββββββββββββββ
|