paavohtl Claude Opus 4.6 (1M context) commited on
Commit
5dd0ca9
Β·
1 Parent(s): 6fb8b23

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: 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
  }
 
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 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
  ///
 
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 params = &raw const (*entry).fire_complete as u32;
200
- let worm_u32 = 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(|w| format!("{:?}", w))
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
- // Completion flag at CGameTask.subclass_data[12] (worm+0x3C), NOT WeaponEntry
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(worm_u32, params, rb(0x51EC80)), // PlacedExplosive
218
- 2 => call_fire_stdcall3(worm_u32, params, local_struct, rb(0x51DFB0)), // Projectile
219
- 3 => call_fire_thiscall2(worm_u32, params, local_struct, rb(0x51E0F0)), // CreateWeaponProjectile
220
- 4 => call_fire_stdcall2(worm_u32, params, local_struct, rb(0x51ED90)), // Shotgun
221
  _ => {}
222
  },
223
  2 => match subtype_38 {
224
- 1 => call_fire_stdcall3(worm_u32, params, local_struct, rb(0x51E1C0)), // RopeType1
225
- 2 => call_fire_thiscall2(worm_u32, params, local_struct, rb(0x51E0F0)), // CreateWeaponProjectile
226
- 3 => call_fire_stdcall3(worm_u32, params, local_struct, rb(0x51E240)), // RopeType3
227
  _ => {}
228
  },
229
  3 => {
230
- let params_34 = &raw const (*entry).fire_subtype_34 as u32;
231
- call_fire_stdcall3(worm_u32, params_34, local_struct, rb(0x51E2C0)); // GrenadeMortar
232
  }
233
  4 => {
234
- let params_38 = &raw const (*entry).fire_subtype_38 as u32;
235
- fire_weapon_special(subtype_34, params_38, worm_u32, local_struct);
236
  }
237
  _ => {}
238
  }
239
 
240
- *(worm as *mut u8).add(0x3C).cast::<i32>() = 1;
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 ────────────────────────────────────