paavohtl Claude Opus 4.6 (1M context) commited on
Commit
d7f1232
·
1 Parent(s): 8c440e6

fix: read weapon ID from CTaskWorm in FireWeapon logger

Browse files

The stack param to FireWeapon is the CTaskWorm pointer (pushed by
WeaponRelease as EDI=EAX from its usercall convention). Read
selected_weapon at CTaskWorm+0x170 for accurate weapon names.

Previous version read from wrong offset in weapon context, producing
garbage (Skunk, SheepStrike, None). Now correctly shows:
Bazooka(27), Uzi(10), Grenade(9), Teleport(4), etc.

Also reveals dispatch table correction: Bazooka uses sub38=3
(CreateWeaponProjectile), not sub38=2 (FireWeapon__Projectile).

Verified: headless PASS, headful 133+3 / 0 FAIL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

crates/openwa-wormkit/src/replacements/weapon.rs CHANGED
@@ -137,32 +137,42 @@ usercall_trampoline!(fn trampoline_count_alive_worms; impl_fn = count_alive_worm
137
 
138
  static ORIG_FIRE_WEAPON: AtomicU32 = AtomicU32::new(0);
139
 
140
- /// Logger called from the naked passthrough. EAX = weapon launch context.
141
- /// Context+0x30 = weapon type (1-4), +0x34 = subtype for types 3/4,
142
- /// +0x38 = subtype for types 1/2, +0x3C = params base.
143
- unsafe extern "cdecl" fn fire_weapon_log(weapon_ctx: u32) {
144
  let ctx = weapon_ctx as *const u8;
145
  let weapon_type = *(ctx.add(0x30) as *const i32);
146
  let subtype_34 = *(ctx.add(0x34) as *const i32);
147
  let subtype_38 = *(ctx.add(0x38) as *const i32);
148
 
 
 
 
 
 
 
149
  let _ = log_line(&format!(
150
- "[Weapon] FireWeapon: type={} sub34={} sub38={}",
151
- weapon_type, subtype_34, subtype_38
152
  ));
153
  }
154
 
155
  /// Naked passthrough: save regs → call logger → restore → jmp original.
 
 
156
  #[unsafe(naked)]
157
  unsafe extern "C" fn trampoline_fire_weapon() {
158
  core::arch::naked_asm!(
159
  "push eax",
160
  "push ecx",
161
  "push edx",
162
- // call logger with EAX (weapon_ctx) as cdecl arg
 
 
163
  "push eax",
164
  "call {log_fn}",
165
- "add esp, 4",
166
  "pop edx",
167
  "pop ecx",
168
  "pop eax",
 
137
 
138
  static ORIG_FIRE_WEAPON: AtomicU32 = AtomicU32::new(0);
139
 
140
+ /// Logger called from the naked passthrough.
141
+ /// `weapon_ctx` = EAX = pointer to weapon data (from CTaskWorm+0x36C).
142
+ /// `worm_ptr` = stack param = CTaskWorm pointer (pushed by WeaponRelease).
143
+ unsafe extern "cdecl" fn fire_weapon_log(weapon_ctx: u32, worm_ptr: u32) {
144
  let ctx = weapon_ctx as *const u8;
145
  let weapon_type = *(ctx.add(0x30) as *const i32);
146
  let subtype_34 = *(ctx.add(0x34) as *const i32);
147
  let subtype_38 = *(ctx.add(0x38) as *const i32);
148
 
149
+ // Read selected weapon from CTaskWorm+0x170
150
+ let weapon_id = *((worm_ptr as *const u8).add(0x170) as *const u32);
151
+ let weapon_name = Weapon::try_from(weapon_id)
152
+ .map(|w| format!("{:?}", w))
153
+ .unwrap_or_else(|id| format!("Unknown({})", id));
154
+
155
  let _ = log_line(&format!(
156
+ "[Weapon] FireWeapon: {} (id={}) type={} sub34={} sub38={}",
157
+ weapon_name, weapon_id, weapon_type, subtype_34, subtype_38
158
  ));
159
  }
160
 
161
  /// Naked passthrough: save regs → call logger → restore → jmp original.
162
+ /// Stack layout at entry: [ret_addr] [wrapper_param]
163
+ /// We read wrapper_param to pass to the logger as the worm pointer.
164
  #[unsafe(naked)]
165
  unsafe extern "C" fn trampoline_fire_weapon() {
166
  core::arch::naked_asm!(
167
  "push eax",
168
  "push ecx",
169
  "push edx",
170
+ // call logger(weapon_ctx=EAX, worm_ptr=[ESP+16])
171
+ // ESP+16 because: 3 pushes (12 bytes) + ret_addr (4) = 16 to stack param
172
+ "push [esp+16]",
173
  "push eax",
174
  "call {log_fn}",
175
+ "add esp, 8",
176
  "pop edx",
177
  "pop ecx",
178
  "pop eax",