/target, /assist and /follow, and right click opens a clam

- /target and /assist find units by name like the original, and /follow walks you behind your target
- right click opens clams and lockboxes, and the tooltip promises it
- the freeze thaws clean, poses release instead of sticking, and you drop to neutral standing before it grips
- unit frame art layers over the bars like the original

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-02 18:02:44 +07:00
co-authored by Claude Fable 5
parent 2f40b6a9a0
commit 94de741cb1
36 changed files with 2086 additions and 204 deletions
@@ -425,8 +425,9 @@ fn required_level_one_is_hidden() {
/// (white) when the instance carries letter text, the green-escaped "<Made by %s>" otherwise —
/// then READABLE off the instance text id (its template's PageText is 0 — the
/// director-reported gap). An unresolved creator (name query in flight) emits no line. LOCKED
/// yields to the instance UNLOCKED bit — and ITEM_OPENABLE never emits from `SetBagItem` (a
/// p6=1 source: the `0x52e2e8` bypass), so the unlocked chest shows its bare name.
/// yields to the instance UNLOCKED bit — which is also what un-gates ITEM_OPENABLE: a bag hover
/// on an openable instance DOES show the green `<Right Click to Open>` (director-observed on a
/// clam; see `ItemInstance::openable_source` for why this overrides §1-OPENABLE's p6 reading).
#[test]
fn instance_tail_creator_and_readable() {
let mut s = script();
@@ -458,16 +459,26 @@ fn instance_tail_creator_and_readable() {
flags,
..Default::default()
};
s.set_item_template(
7973,
ItemTemplateView {
name: "Small Barnacled Clam".into(),
quality: 1,
flags: 0x4,
..Default::default()
},
);
let mut slots = HashMap::new();
slots.insert(1, slot(889, true, Some("One"), 0)); // the mail letter
slots.insert(2, slot(889, true, None, 0)); // creator name still in flight
slots.insert(3, slot(2589, false, Some("Geoffrey"), 0)); // crafted, still locked
slots.insert(4, slot(2589, false, None, 0x4)); // unlocked → LOCKED gone, and NO open line
slots.insert(4, slot(2589, false, None, 0x4)); // unlocked → LOCKED gone, open line on
slots.insert(5, slot(7973, false, None, 0)); // the clam: lockless, openable outright
s.set_container(
0,
Some(ContainerState {
name: Some("Backpack".into()),
num_slots: 4,
num_slots: 5,
slots,
}),
);
@@ -502,11 +513,18 @@ fn instance_tail_creator_and_readable() {
vec!["Heavy Chest", "Locked", "|cff00ff00<Made by Geoffrey>|r"],
"CREATED_BY carries the string's own green escape; locked chest hides OPENABLE"
);
// The instance UNLOCKED bit retires the LOCKED line — and OPENABLE still never emits
// (SetBagItem is p6=1; only send-mail/auction/buyback sources reach the emitter in 5875).
// The instance UNLOCKED bit retires the LOCKED line AND satisfies the openable lock sub-gate.
s.run(r#"TT:SetOwner(getglobal("SlotL"), "ANCHOR_RIGHT"); TT:SetBagItem(0, 4)"#)
.unwrap();
let lines = lines_of(&mut s);
let texts: Vec<&str> = lines.iter().map(|(t, _)| t.as_str()).collect();
assert_eq!(texts, vec!["Heavy Chest", "<Right Click to Open>"]);
assert_eq!(lines[1].1, [0.0, 1.0, 0.0, 1.0], "OPENABLE is green");
// The director's case: a lockless LOOTABLE template (a clam) is openable outright — name +
// the green line, nothing between them.
s.run(r#"TT:SetOwner(getglobal("SlotL"), "ANCHOR_RIGHT"); TT:SetBagItem(0, 5)"#)
.unwrap();
let texts: Vec<String> = lines_of(&mut s).into_iter().map(|(t, _)| t).collect();
assert_eq!(texts, vec!["Heavy Chest"]);
assert_eq!(texts, vec!["Small Barnacled Clam", "<Right Click to Open>"]);
assert!(s.take_errors().is_empty());
}
@@ -309,7 +309,10 @@ pub(super) fn install_methods(lua: &Lua, m: &Table) -> mlua::Result<()> {
creator: s.creator.clone(),
has_text: false,
flags: s.flags,
// p6=1 in the ref — SetInventoryItem can never emit OPENABLE.
// Unobservable either way: nothing openable is equippable, so the
// doll hover has no case to show. Left `false` (wow-re
// §1-OPENABLE's p6 reading) rather than flipped on the bag's
// evidence — see `ItemInstance::openable_source`.
openable_source: false,
},
)
@@ -375,8 +378,11 @@ pub(super) fn install_methods(lua: &Lua, m: &Table) -> mlua::Result<()> {
creator: s.creator.clone(),
has_text: s.readable,
flags: s.flags,
// p6=1 in the ref — SetBagItem can never emit OPENABLE (§1-OPENABLE).
openable_source: false,
// The bag hover DOES emit `<Right Click to Open>` — director-observed
// (a clam in a bag), against wow-re §1-OPENABLE's p6 reading. See
// `ItemInstance::openable_source`: that gate is under re-derivation,
// and the observation is the ground truth we build on.
openable_source: true,
},
),
None => return Ok(MultiValue::from_vec(vec![Value::Nil])),
@@ -29,11 +29,24 @@ pub(super) struct ItemInstance {
/// Instance `ITEM_FIELD_FLAGS` — the openable lock sub-gate reads UNLOCKED `0x4`
/// (`0x52e30c`) and the wrapped-gift arm WRAPPED `0x8` (`0x52e31d`).
pub flags: u32,
/// The ref's `p6=0` source class (wow-re §1-OPENABLE, byte-census 2026-07-20): ITEM_OPENABLE
/// is reachable ONLY from object-present p6=0 sources (SetSendMailItem, SetAuctionSellItem,
/// SetBuybackItem) — `SetBagItem`/`SetInventoryItem` pass p6=1 and a `[this+0x440]` gate
/// (`0x52e2e8`) bypasses the openable tree entirely. Every current benilla source is p6=1
/// or template-only, so this stays `false` until those tooltips carry real instances.
/// May this source emit the ITEM_OPENABLE line at all?
///
/// wow-re §1-OPENABLE (byte-census 2026-07-20) reads a `[this+0x440]` gate at `0x52e2e8` as
/// bypassing the whole openable tree for every `p6=1` binding, and concludes that
/// `SetBagItem` — the binding your own bags hover through — can NEVER emit it. **That
/// conclusion is contradicted by ground truth:** the director's screenshot shows a Small
/// Barnacled Clam hovered IN A BAG with the green `<Right Click to Open>` line, and vmangos's
/// own `ITEM_FLAG_LOOTABLE` comment names that exact client behaviour ("It or lockid set
/// enable for client show 'Right click to open'"). A line that could only ever appear on the
/// send-mail / auction-sell / buyback tooltips would also be behaviourally absurd. The note is
/// additionally self-inconsistent there (§1-CREATOR puts the GIFTCREATOR read at `0x52e32a`,
/// inside the region §1-OPENABLE calls the openable emit + jump), so the transcription — not
/// the observation — is the suspect. A wow-re §5 re-derivation of `[0x52e2e0, 0x52e376)` is in
/// flight; until it lands, the bag hover follows the director's eyes.
///
/// The flag is kept rather than deleted because the *template-vs-instance* distinction it also
/// carries is settled (gate 1, `0x52e2e0`: no object ⇒ no line — you can't right-click a
/// hyperlink), and because the p6 split may still be real for the sources we cannot observe.
pub openable_source: bool,
}