Clickthrough: lootable corpses prioritize over players

Lootable unit corpses (UNIT_DYNFLAG_LOOTABLE) now click-through over
blocking players, matching the existing behavior for interactable NPCs
and game objects. Adds isLootable() check to the interactable NPC test
and UNIT_DYNAMIC_FLAGS descriptor offset to shared offsets.

Also adds RELEASE_NOTES.md for tracking changes between releases, and
adds a checklist item in RELEASING.md to review it before publishing.
This commit is contained in:
MarcelineVQ
2026-03-13 22:22:54 -07:00
parent d9701c528d
commit e978710c44
5 changed files with 29 additions and 3 deletions
+5 -3
View File
@@ -49,12 +49,14 @@ fn isInteractableGO(guid_lo: u32, guid_hi: u32) bool {
return hook.call(fn (u32) callconv(hook.cc.fastcall) u8, offsets.FN_CALL_SPELL_CAST_HANDLER, .{obj}) != 0;
}
/// Check if the GUID refers to an NPC with interaction flags (vendor, quest giver, etc.)
/// Check if the GUID refers to an interactable unit: NPC with interaction flags,
/// or a lootable corpse (dead unit with UNIT_DYNFLAG_LOOTABLE).
fn isInteractableNPC(guid_lo: u32, guid_hi: u32) bool {
const obj = wow.getObjectByGUIDSplit(guid_lo, guid_hi);
if (obj == 0) return false;
if (wow.getObjectTypeRaw(obj) != @intFromEnum(wow.ObjectType.unit)) return false;
return wow.getNpcFlags(obj) != 0;
if (wow.getNpcFlags(obj) != 0) return true;
return wow.isLootable(obj);
}
/// Check if the second raycast result is something we should click through to.
@@ -107,7 +109,7 @@ fn worldIntersectDetour(world_frame: u32, ray_start: u32, ray_end: u32, flags: u
const type_mask = hook.readMem(u32, desc_ptr + OBJ_TYPE_MASK_OFFSET);
// Determine re-raycast flags and whether NPCs are valid targets:
// Player hit → remove player flag, allow NPCs + GOs
// Player hit → remove player flag, allow NPCs + GOs (including lootable corpses)
// Unit hit → GO-only flags, only allow GOs
const recast_flags: u32 = switch (type_mask) {
TYPE_PLAYER => flags & ~@as(u32, 0x10), // everything except players
+6
View File
@@ -42,6 +42,12 @@ pub const DESC_ENTRY: usize = 0x03 * 4;
/// UNIT_NPC_FLAGS = OBJECT_END(0x06) + 0x8D = 0x93
pub const DESC_NPC_FLAGS: usize = 0x93 * 4;
/// UNIT_DYNAMIC_FLAGS = OBJECT_END(0x06) + 0x90 = 0x96
pub const DESC_UNIT_DYNAMIC_FLAGS: usize = 0x96 * 4;
/// Bit 0: unit corpse is lootable by the local player.
pub const UNIT_DYNFLAG_LOOTABLE: u32 = 0x01;
/// GAMEOBJECT_TYPE_ID (index 0x15)
pub const DESC_GO_TYPE: usize = 0x15 * 4;
+6
View File
@@ -122,6 +122,12 @@ pub fn getNpcFlags(obj: u32) u32 {
return hook.readMem(u32, desc + o.DESC_NPC_FLAGS);
}
pub fn isLootable(obj: u32) bool {
const desc = getDescriptor(obj);
if (!isValidPtr(desc)) return 0 != 0;
return (hook.readMem(u32, desc + o.DESC_UNIT_DYNAMIC_FLAGS) & o.UNIT_DYNFLAG_LOOTABLE) != 0;
}
// =============================================================================
// Unit helpers
// =============================================================================