fix: CheckWeaponAvail — double deref weapon table, fix condition logic
Browse filesTwo 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:
|
| 387 |
-
//
|
| 388 |
-
let
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
if *(ddgame.add(0x777C) as *const
|
| 392 |
-
|
| 393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 394 |
}
|
| 395 |
-
return 0;
|
| 396 |
-
}
|
| 397 |
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
// (game_version < 0x2A) - 1: if version < 0x2A → 0, else → -1
|
| 402 |
-
return if game_version < 0x2A { 0 } else { -1 };
|
| 403 |
-
}
|
| 404 |
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
}
|
| 409 |
|
| 410 |
-
//
|
| 411 |
-
|
| 412 |
-
|
| 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 |
-
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
| 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",
|