paavohtl Claude Opus 4.6 (1M context) commited on
Commit
8a0cd0d
Β·
1 Parent(s): e7f6be4

fix: enable arrow sprite loading fallback, fix SpriteRegion param order

Browse files

- Arrow loading now falls back to GfxDir__LoadImage when cached==0,
matching the original constructor behavior
- Fix arrow SpriteRegion params: EDX=half_h, p4=half_w (constructor
computes this[4]=EDX-p3 for height, this[3]=p4-p2 for width)
- Move gfx_resource release AFTER arrow loop (arrows need it for
SpriteRegion construction)
- Pass gfx_resource to arrow SpriteRegions as p6

Shadow comparison now shows only 3 field differences vs original
(was 67): color entries, +0x7338, and +0x041C/0x0420.

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

crates/openwa-core/src/engine/ddgame.rs CHANGED
@@ -1388,19 +1388,9 @@ unsafe fn init_graphics_and_resources(
1388
  *((ddgame as *mut u8).add(0x468) as *mut u32) = get_val(landscape);
1389
  }
1390
 
1391
- // Release gfx_resource if non-null
1392
- // vtable[3] = DisplayGfx__vmethod_3: thiscall(this, byte param_2), RET 4.
1393
- if !gfx_resource.is_null() {
1394
- let rvt = *(gfx_resource as *const *const u32);
1395
- let release: unsafe extern "thiscall" fn(*mut u8, u8) =
1396
- core::mem::transmute(*rvt.add(3));
1397
- release(gfx_resource, 1);
1398
- }
1399
 
1400
- // GfxDir addresses are resolved via statics (GFX_FIND_ENTRY_ADDR, GFX_LOAD_IMAGE_ADDR)
1401
- // and called through naked bridges (call_gfx_find_entry, call_gfx_load_image).
1402
-
1403
- // return moved further up
1404
  // ── Arrow sprites + collision regions (32 iterations) ──
1405
  {
1406
  let gfx_handler = (*wrapper)._field_4c0;
@@ -1446,12 +1436,12 @@ unsafe fn init_graphics_and_resources(
1446
  core::mem::transmute(rb(0x4F5E80) as usize);
1447
  sprite = ctor(cached);
1448
  } else {
1449
- // Fallback: load from file. Skip for now β€” may hang.
1450
- sprite = core::ptr::null_mut();
1451
  }
1452
  } else {
1453
- // Entry not found β€” skip loading
1454
- sprite = core::ptr::null_mut();
1455
  }
1456
  if i == 0 {
1457
  let _ = crate::log::log_line(&format!(
@@ -1472,7 +1462,19 @@ unsafe fn init_graphics_and_resources(
1472
  let alloc = wa_malloc(0x9C);
1473
  core::ptr::write_bytes(alloc, 0, 0x9C);
1474
  let region = if !alloc.is_null() {
1475
- call_sprite_region_ctor(alloc, 0, 0, 0, half_w as u32, 0, half_h as u32, 0)
 
 
 
 
 
 
 
 
 
 
 
 
1476
  } else {
1477
  core::ptr::null_mut()
1478
  };
@@ -1490,6 +1492,16 @@ unsafe fn init_graphics_and_resources(
1490
  }
1491
 
1492
  let _ = crate::log::log_line("[DDGame] arrow loop done");
 
 
 
 
 
 
 
 
 
 
1493
  // ── DisplayGfx at DDGame+0x138 ──
1494
  // Original: alloc 0x4C, memset 0x2C, PUSH 0x100, MOV ECX=8, MOV EDI=0x1E0,
1495
  // CALL 0x4F6370, MOV [alloc]=0x664144
 
1388
  *((ddgame as *mut u8).add(0x468) as *mut u32) = get_val(landscape);
1389
  }
1390
 
1391
+ // NOTE: gfx_resource is NOT released here β€” arrow SpriteRegions need it.
1392
+ // It's released after the arrow loop below.
 
 
 
 
 
 
1393
 
 
 
 
 
1394
  // ── Arrow sprites + collision regions (32 iterations) ──
1395
  {
1396
  let gfx_handler = (*wrapper)._field_4c0;
 
1436
  core::mem::transmute(rb(0x4F5E80) as usize);
1437
  sprite = ctor(cached);
1438
  } else {
1439
+ // Fallback: load from file via GfxDir__LoadImage + IMG_Decode
1440
+ sprite = call_gfx_load_and_wrap(gfx_handler, name_buf.as_ptr(), layer_ctx);
1441
  }
1442
  } else {
1443
+ // Entry not found β€” try direct file load
1444
+ sprite = call_gfx_load_and_wrap(gfx_handler, name_buf.as_ptr(), layer_ctx);
1445
  }
1446
  if i == 0 {
1447
  let _ = crate::log::log_line(&format!(
 
1462
  let alloc = wa_malloc(0x9C);
1463
  core::ptr::write_bytes(alloc, 0, 0x9C);
1464
  let region = if !alloc.is_null() {
1465
+ // SpriteRegion params: ECX, EDX, this, p2, p3, p4, p5, p6
1466
+ // this[3] = p4 - p2 (width), this[4] = EDX - p3 (height)
1467
+ // For arrows: region from (0,0) to (half_w, half_h)
1468
+ call_sprite_region_ctor(
1469
+ alloc,
1470
+ 0, // ECX (x_max for this[5])
1471
+ half_h as u32, // EDX (y_max β†’ this[4] = EDX - p3)
1472
+ 0, // p2 (x_offset)
1473
+ 0, // p3 (y_offset)
1474
+ half_w as u32, // p4 (x_limit β†’ this[3] = p4 - p2)
1475
+ half_h as u32, // p5 (y_limit for this[6])
1476
+ gfx_resource as u32, // p6 (gfx_resource)
1477
+ )
1478
  } else {
1479
  core::ptr::null_mut()
1480
  };
 
1492
  }
1493
 
1494
  let _ = crate::log::log_line("[DDGame] arrow loop done");
1495
+
1496
+ // Release gfx_resource AFTER arrow loop (arrows need it for SpriteRegions)
1497
+ // vtable[3] = DisplayGfx__vmethod_3: thiscall(this, byte param_2), RET 4.
1498
+ if !gfx_resource.is_null() {
1499
+ let rvt = *(gfx_resource as *const *const u32);
1500
+ let release: unsafe extern "thiscall" fn(*mut u8, u8) =
1501
+ core::mem::transmute(*rvt.add(3));
1502
+ release(gfx_resource, 1);
1503
+ }
1504
+
1505
  // ── DisplayGfx at DDGame+0x138 ──
1506
  // Original: alloc 0x4C, memset 0x2C, PUSH 0x100, MOV ECX=8, MOV EDI=0x1E0,
1507
  // CALL 0x4F6370, MOV [alloc]=0x664144