From e978710c440b19ea81336e6759fd77e2b5089542 Mon Sep 17 00:00:00 2001 From: MarcelineVQ Date: Fri, 13 Mar 2026 22:22:54 -0700 Subject: [PATCH] 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. --- RELEASE_NOTES.md | 11 +++++++++++ RELEASING.md | 1 + src/clickthrough/clickthrough.zig | 8 +++++--- src/offsets.zig | 6 ++++++ src/wow.zig | 6 ++++++ 5 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 RELEASE_NOTES.md diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000..86651c2 --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,11 @@ +# Unreleased Changes + +Track notable changes here between releases. Clear this file when cutting a new release +(move contents into the release notes on Codeberg). + +## What's New + +- **Clickthrough**: Lootable corpses now click-through over players. Previously only + interactable NPCs (vendors, quest givers) and game objects would win over a blocking + player. Now dead units with the lootable flag are also prioritized, so you can loot + corpses through the player crowd without having to reposition. diff --git a/RELEASING.md b/RELEASING.md index 27f19e9..c5bf349 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -200,6 +200,7 @@ print(r[0]['id']) if r else print('not found') ## Checklist +- [ ] Check `RELEASE_NOTES.md` for unreleased changes — move into release notes - [ ] Built with `ReleaseSmall` (both default and `all-variants`) - [ ] Remote README updated — no unreleased module sections or names - [ ] `weirdutils_api.h` trimmed to released DLL names only and uploaded diff --git a/src/clickthrough/clickthrough.zig b/src/clickthrough/clickthrough.zig index 5697af8..d8c6668 100644 --- a/src/clickthrough/clickthrough.zig +++ b/src/clickthrough/clickthrough.zig @@ -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 diff --git a/src/offsets.zig b/src/offsets.zig index 359a7c8..b7bf94d 100644 --- a/src/offsets.zig +++ b/src/offsets.zig @@ -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; diff --git a/src/wow.zig b/src/wow.zig index f4cd3d3..f19bd5d 100644 --- a/src/wow.zig +++ b/src/wow.zig @@ -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 // =============================================================================