paavohtl Claude Opus 4.6 (1M context) commited on
Commit
cb094bb
·
1 Parent(s): 934d6af

fix: pass display layer context to arrow sprite loading

Browse files

Arrow sprite loop was passing null as display_ctx to
call_gfx_load_and_wrap. The original passes the return value from
display->vtable[5](1) (set_layer) which is the active layer context.
Without this, palette/color lookups crash with null this pointer.

Also wrap cached GfxDir entries with DisplayGfx__Constructor_Maybe
(0x4F5E80) to match the original's behavior.

3/3 test runs pass with 119 validations.

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

crates/openwa-core/src/engine/ddgame.rs CHANGED
@@ -876,13 +876,11 @@ unsafe fn init_graphics_and_resources(
876
  name_buf[5] = b'0' + (i / 10) as u8;
877
  name_buf[6] = b'0' + (i % 10) as u8;
878
 
879
- // Display vtable[5](1) — set active layer
880
- {
881
- let disp_vt = *((*ddgame).display as *const *const u32);
882
- let set_layer: unsafe extern "thiscall" fn(*mut DDDisplay, i32) =
883
- core::mem::transmute(*disp_vt.add(5));
884
- set_layer((*ddgame).display, 1);
885
- }
886
 
887
  // GfxDir__FindEntry: usercall(EAX=name) + 1 stack(gfx_handler), RET 0x4
888
  let entry = call_gfx_find_entry(name_buf.as_ptr(), gfx_handler);
@@ -895,16 +893,15 @@ unsafe fn init_graphics_and_resources(
895
  core::mem::transmute(*gfx_vt.add(2));
896
  let cached = load_cached(gfx_handler, *(entry.add(4) as *const u32));
897
  if !cached.is_null() {
898
- sprite = cached;
 
 
 
899
  } else {
900
- sprite = call_gfx_load_and_wrap(
901
- gfx_handler, name_buf.as_ptr(), core::ptr::null_mut(),
902
- );
903
  }
904
  } else {
905
- sprite = call_gfx_load_and_wrap(
906
- gfx_handler, name_buf.as_ptr(), core::ptr::null_mut(),
907
- );
908
  }
909
 
910
  // Store arrow sprite at DDGame+0x38+i*4
 
876
  name_buf[5] = b'0' + (i / 10) as u8;
877
  name_buf[6] = b'0' + (i % 10) as u8;
878
 
879
+ // Display vtable[5](1) — set active layer, returns context ptr
880
+ let disp_vt = *((*ddgame).display as *const *const u32);
881
+ let set_layer: unsafe extern "thiscall" fn(*mut DDDisplay, i32) -> *mut u8 =
882
+ core::mem::transmute(*disp_vt.add(5));
883
+ let layer_ctx = set_layer((*ddgame).display, 1);
 
 
884
 
885
  // GfxDir__FindEntry: usercall(EAX=name) + 1 stack(gfx_handler), RET 0x4
886
  let entry = call_gfx_find_entry(name_buf.as_ptr(), gfx_handler);
 
893
  core::mem::transmute(*gfx_vt.add(2));
894
  let cached = load_cached(gfx_handler, *(entry.add(4) as *const u32));
895
  if !cached.is_null() {
896
+ // Wrap with DisplayGfx constructor
897
+ let ctor: unsafe extern "stdcall" fn(*mut u8) -> *mut u8 =
898
+ core::mem::transmute(rb(0x4F5E80) as usize);
899
+ sprite = ctor(cached);
900
  } else {
901
+ sprite = call_gfx_load_and_wrap(gfx_handler, name_buf.as_ptr(), layer_ctx);
 
 
902
  }
903
  } else {
904
+ sprite = call_gfx_load_and_wrap(gfx_handler, name_buf.as_ptr(), layer_ctx);
 
 
905
  }
906
 
907
  // Store arrow sprite at DDGame+0x38+i*4