world books open, and anvils stop offering a cursor gear
- clicking a book in the world opens it and turns its pages: letters and world books share one reader - the cursor's object rules are the client's own 31-row strategy table now, so decorative objects stop pretending to be usable - trainer and tradeskill windows draw each row's icon by the reference's own law, and the trainer's filter dropdown toggles again - water color follows the zone's light blend, so lakes stop snapping between area tints Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -251,6 +251,7 @@ pub(super) fn drain_container_uses(
|
||||
use_spell: t.use_spell.map(|u| u.spell_id),
|
||||
unwraps_gift: t.unwraps_gift(inst_flags),
|
||||
opens_loot: t.opens_loot(),
|
||||
page_text: t.page_text,
|
||||
})
|
||||
});
|
||||
|
||||
@@ -334,23 +335,38 @@ pub(super) fn drain_container_uses(
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// #5 — readable: an item TEMPLATE carrying `PageText` (`0x5d8e4c`) — a book — opens the
|
||||
// reader on its page chain, client-side, no permission packet (`0x4e32e0(itemGuid)`;
|
||||
// decision 1105). Above #6 and above the open arm, which is the reference's own order and
|
||||
// the INVERSE of the tooltip's, where OPENABLE wins over READABLE: a template that is both
|
||||
// readable and lootable *shows* `<Right Click to Open>` and *reads* on click —
|
||||
// byte-verified, not a slip of ours.
|
||||
if let Some(c) = clicked.filter(|c| c.page_text != 0) {
|
||||
if item_text.toggle_closed(c.guid) {
|
||||
debug!("ui_items: re-click closes the book {:#x}", c.guid);
|
||||
} else {
|
||||
debug!(
|
||||
"ui_items: read book {:#x} (page {}, lua bag {bag} slot {slot})",
|
||||
c.guid, c.page_text
|
||||
);
|
||||
item_text.open_pages(c.guid);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// #6 — readable: an item INSTANCE carrying `ITEM_FIELD_ITEM_TEXT_ID` (a mail-made
|
||||
// permanent letter) opens the reader — client-side, no permission packet (vmangos'
|
||||
// `CMSG_READ_ITEM` handler gates on the *template*'s PageText, which is 0 for the Plain
|
||||
// Letter; the text rides the ask-once `CMSG_ITEM_TEXT_QUERY` instead).
|
||||
//
|
||||
// The dispatcher's arm **#5** — the same local open off the *template*'s `PageText`
|
||||
// (`0x5d8e4c`) — has no feed here yet (books/pages aren't built). When it lands it belongs
|
||||
// immediately above this one, and still above the open arm: the send order is the INVERSE
|
||||
// of the tooltip's, where OPENABLE wins over READABLE. A template that is both readable
|
||||
// and lootable therefore *shows* `<Right Click to Open>` and *reads* on click — the
|
||||
// reference's own inversion, byte-verified, not a slip of ours.
|
||||
if let Some(c) = clicked.filter(|c| c.item_text_id != 0) {
|
||||
debug!(
|
||||
"ui_items: read item {:#x} (text {}, lua bag {bag} slot {slot})",
|
||||
c.guid, c.item_text_id
|
||||
);
|
||||
item_text.open(c.guid, c.item_text_id);
|
||||
if item_text.toggle_closed(c.guid) {
|
||||
debug!("ui_items: re-click closes the letter {:#x}", c.guid);
|
||||
} else {
|
||||
debug!(
|
||||
"ui_items: read letter {:#x} (text {}, lua bag {bag} slot {slot})",
|
||||
c.guid, c.item_text_id
|
||||
);
|
||||
item_text.open_letter(c.guid, c.item_text_id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// #8 — the open arm (`0x5d8f7c: test al,4` → emitter `0x5edc80`): a **bare** template
|
||||
@@ -439,6 +455,10 @@ struct Clicked {
|
||||
unwraps_gift: bool,
|
||||
/// `ItemInfo::opens_loot` for this template — dispatcher arm #8.
|
||||
opens_loot: bool,
|
||||
/// The template's `PageText` — dispatcher arm #5's book gate (decision 1105); `0` = not a
|
||||
/// book. The reader re-reads the head (and the material) off the template itself as it paints,
|
||||
/// like the reference, so only the fork's predicate is carried here.
|
||||
page_text: u32,
|
||||
}
|
||||
|
||||
/// Drain the pick/place/swap/split moves `PickupContainerItem`/`SplitContainerItem` queued and
|
||||
|
||||
@@ -386,7 +386,7 @@ pub(super) fn feed_player_req(
|
||||
actions
|
||||
.spells
|
||||
.iter()
|
||||
.any(|&id| s.catalog.get(id).is_some_and(|sd| sd.effect_1 == 40))
|
||||
.any(|&id| s.catalog.get(id).is_some_and(|sd| sd.effects[0] == 40))
|
||||
});
|
||||
let state = benilla_ui::script::PlayerReqState {
|
||||
level: store.0.unit_level().unwrap_or(0),
|
||||
|
||||
@@ -256,6 +256,24 @@ pub(crate) fn slot_guid_count(
|
||||
}
|
||||
}
|
||||
|
||||
/// An item template's icon path — its `DisplayInfoID` joined through `ItemDisplayInfo.dbc` (the
|
||||
/// [`ItemDisplays`] catalog the equipment feed already loads).
|
||||
///
|
||||
/// This is the **one** thing the client's spell-icon surfaces genuinely share. The *laws* do not:
|
||||
/// wow-re's `system/ui/scratch/spell-icon-substitution-law.md` settled that there is no shared
|
||||
/// spell-icon resolver at all — six Lua getters, six laws inlined per binding, disagreeing even
|
||||
/// between the TradeSkill and Craft windows. But every arm that ends at an item ends *here*, at the
|
||||
/// same `ItemTemplate+0x18 → 0x5d88b0 → rec+0x14` chain (§5 of that note). So the join lives once,
|
||||
/// and each window keeps its own law above it.
|
||||
pub(crate) fn item_icon(
|
||||
icons: Option<&crate::entities::ItemDisplays>,
|
||||
display_info_id: u32,
|
||||
) -> Option<String> {
|
||||
icons
|
||||
.and_then(|i| i.catalog.get(display_info_id))
|
||||
.and_then(|d| d.icon.clone())
|
||||
}
|
||||
|
||||
/// Count of item `entry` across the backpack + equipped bags. The quest-log feed
|
||||
/// ([`crate::ui_quest_log`]) needs this for an item-collection objective: unlike a creature/GO
|
||||
/// objective, item-objective progress is *not* one of the `PLAYER_QUEST_LOG` slot's 6-bit counters
|
||||
|
||||
Reference in New Issue
Block a user