# Retail selected-object health policy pseudocode — 2026-07-11 ## Oracle - `gmToolbarUI::HandleSelectionChanged @ 0x004BF380`, health branch `0x004BF725..0x004BF76C`. - `ClientCombatSystem::ObjectIsAttackable @ 0x0056A600`. - `ACCWeenieObject::IsPlayer/IsPK/IsPKLite @ 0x0058C890/0x0058C8B0/0x0058C8A0`. - `PublicWeenieDesc::UnPack @ 0x005AD470`, second-header PetOwner read `0x005AD7EC..0x005AD7F8`. - Struct/flag definitions: `acclient.h` `PublicWeenieDesc`, `PublicWeenieDescPackHeader2::PWD2_Packed_PetOwner = 0x8`. ACE cross-check: `WorldObject_Networking.SerializeCreateObject` writes the second header after the ordinary optional tail in this order: IconUnderlay, MaterialType, CooldownId, CooldownDuration (`double`), PetOwner (`u32`), then alignment. Its `UpdateObjectDescriptionFlags` maps the same PWD player/attackable/PK/Free-PK/PKLite bits read by retail. Chorizite/holtburger cross-check: the independently generated `Chorizite.ACProtocol/Types/PublicWeenieDesc` schema and holtburger inventory client inventory are catalogued in `deepdives/r06-items-inventory.md`; that schema pins the same Header2 `0x01/0x02/0x04/0x08` order and field widths. Neither interpretation aid changes the client behavior above; the named retail branch order remains ground truth. ## Constants ```text ITEM_TYPE_CREATURE = 0x10 BF_PLAYER = 0x00000008 BF_ATTACKABLE = 0x00000010 BF_PLAYER_KILLER = 0x00000020 BF_FREE_PKSTATUS = 0x00200000 BF_PKLITE_PKSTATUS = 0x02000000 PWD2_PET_OWNER = 0x00000008 ``` ## Exact pseudocode ```text ToolbarShouldQueryHealth(selectedId): selected = lookup selectedId if selected missing: return false if selected.stackSize > 1: return false // stack UI is mutually exclusive isPlayer = (selected.pwd.bitfield & BF_PLAYER) != 0 isPet = selected.pwd.petOwner != 0 if isPlayer OR isPet OR ObjectIsAttackable(selectedId): QueryHealth(selectedId) return true return false ObjectIsAttackable(targetId): if targetId == 0 OR targetId == localPlayerId: return true target = lookup targetId if target missing OR (target.type & ITEM_TYPE_CREATURE) == 0: return false if (target.pwd.bitfield & BF_FREE_PKSTATUS) != 0: return true player = lookup localPlayerId if player missing: return false if (player.pwd.bitfield & BF_FREE_PKSTATUS) != 0: return true if target.IsPlayer(): if target.IsPK() AND player.IsPK(): return true if target.IsPKLite() AND player.IsPKLite(): return true return false if target.pwd.petOwner != 0: return false return (target.pwd.bitfield & BF_ATTACKABLE) != 0 ``` ## Toolbar consequence The toolbar's outer `IsPlayer || petOwner` test runs before `ObjectIsAttackable`. Therefore every selected player and every selected pet gets a health query regardless of PK pairing. The full PK/PKLite branches remain part of the faithful reusable `ObjectIsAttackable` port, but they do not decide toolbar player visibility. Relative to acdream's former PWD-only approximation, the observable missing toolbar cases are: 1. the local player/self (formerly rejected explicitly), 2. creatures with `PetOwner != 0`, 3. Free-PK creatures, or ordinary creatures while the local player is Free-PK. Friendly non-pet NPCs remain name-only. Non-creature objects remain name-only even when they carry `BF_ATTACKABLE` (the existing attackable-door regression guard).