paavohtl Claude Opus 4.6 (1M context) commited on
Commit
2d4b740
·
1 Parent(s): 3e3755a

fix: CheckWeaponAvail — double deref weapon table, fix condition logic

Browse files

Two bugs in the agent-generated port:
1. DDGame+0x510 is a POINTER to the weapon table (needs double deref),
not an inline offset. Was reading from wrong memory.
2. Condition was inverted: (777C==0 || entry!=0) → main path with
super weapon checks. The else branch (777C!=0 && entry==0) returns
-2 or 0. Original code had these swapped.

All 7 usercall InitGameState sub-functions now ported and passing:
- SpriteGfxTable__Init, RingBuffer__Init (Group A)
- InitTeamScoring, InitAllianceData (Group B)
- InitTurnState, IsSuperWeapon, InitLandscapeFlags, CheckWeaponAvail (Group C)

Headful + headless replay tests PASS.

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

crates/openwa-core/src/engine/game_state_init.rs CHANGED
@@ -383,35 +383,36 @@ pub unsafe fn check_weapon_avail(ddgame: *mut u8, weapon_index: u32) -> i32 {
383
  _ => {}
384
  }
385
 
386
- // Step 2: Check weapon table entry
387
- // weapon_table_entry is at ddgame+0x510 + 0x10 + weapon_index*0x1D0
388
- let weapon_table_entry =
389
- *(ddgame.add(0x510 + 0x10 + (weapon_index as usize) * 0x1D0) as *const u8);
390
-
391
- if *(ddgame.add(0x777C) as *const u32) == 0 && weapon_table_entry == 0 {
392
- if game_version > 0x29 && *(game_info.add(0xD959) as *const u8) != 0 {
393
- return -2;
 
 
 
 
394
  }
395
- return 0;
396
- }
397
 
398
- // Step 3: Super weapon check
399
- let super_result = is_super_weapon(weapon_index, *(ddgame.add(0x7E3F) as *const u8));
400
- if super_result != 0 && *(game_info.add(0xD93C) as *const u8) == 0 {
401
- // (game_version < 0x2A) - 1: if version < 0x2A → 0, else → -1
402
- return if game_version < 0x2A { 0 } else { -1 };
403
- }
404
 
405
- // Step 4: Check DDGame+0x7E25 and weapon_index condition
406
- if *(ddgame.add(0x7E25) as *const u8) == 0 {
407
- return 1;
 
 
 
 
408
  }
409
 
410
- // weapon_index != (0x19 - (game_info+0xD956 != 0))
411
- let d956_nonzero = *(game_info.add(0xD956) as *const u8) != 0;
412
- let threshold = 0x19u32 - d956_nonzero as u32;
413
- if weapon_index != threshold {
414
- return 1;
415
  }
416
 
417
  0
 
383
  _ => {}
384
  }
385
 
386
+ // Step 2: Branch on weapon table entry + DDGame+0x777C
387
+ // DDGame+0x510 is a POINTER to the weapon table (double deref)
388
+ let weapon_table = *(ddgame.add(0x510) as *const *const u8);
389
+ let weapon_entry = *(weapon_table.add(0x10 + (weapon_index as usize) * 0x1D0) as *const i32);
390
+
391
+ if *(ddgame.add(0x777C) as *const i32) == 0 || weapon_entry != 0 {
392
+ // Main path: check super weapon, 7E25, etc.
393
+ let super_result = is_super_weapon(weapon_index, *(ddgame.add(0x7E3F) as *const u8));
394
+ // After is_super_weapon, re-read ddgame (ECX may change in original — doesn't matter in Rust)
395
+ if super_result != 0 && *(game_info.add(0xD93C) as *const u8) == 0 {
396
+ // (game_version < 0x2A) - 1: if < 0x2A → 1-1=0, else → 0-1=-1
397
+ return (game_version < 0x2A) as i32 - 1;
398
  }
 
 
399
 
400
+ if *(ddgame.add(0x7E25) as *const u8) == 0 {
401
+ return 1;
402
+ }
 
 
 
403
 
404
+ // Check if weapon_index == (0x19 - (game_info+0xD956 != 0))
405
+ let d956_nonzero = (*(game_info.add(0xD956) as *const u8) != 0) as u32;
406
+ if weapon_index != 0x19 - d956_nonzero {
407
+ return 1;
408
+ }
409
+
410
+ return 0;
411
  }
412
 
413
+ // Else branch: 777C != 0 AND weapon_entry == 0
414
+ if game_version > 0x29 && *(game_info.add(0xD959) as *const u8) != 0 {
415
+ return -2;
 
 
416
  }
417
 
418
  0
crates/openwa-wormkit/src/replacements/ddgame_init.rs CHANGED
@@ -235,8 +235,11 @@ pub fn install() -> Result<(), String> {
235
  init_turn_state_trampoline as *const (),
236
  )?;
237
 
238
- // TODO: CheckWeaponAvail has a porting bug — disabled until fixed
239
- // hook::install("DDGame__CheckWeaponAvail", va::CHECK_WEAPON_AVAIL, check_weapon_avail_trampoline as *const ())?;
 
 
 
240
 
241
  hook::install(
242
  "CGameTask__InitLandscapeFlags",
 
235
  init_turn_state_trampoline as *const (),
236
  )?;
237
 
238
+ hook::install(
239
+ "DDGame__CheckWeaponAvail",
240
+ va::CHECK_WEAPON_AVAIL,
241
+ check_weapon_avail_trampoline as *const (),
242
+ )?;
243
 
244
  hook::install(
245
  "CGameTask__InitLandscapeFlags",