druids get their relic slot, and the loot window is the reference's own
- `UnitHasRelicSlot` is real in 1.12 and benilla had no binding for it: `0x519e50` reads `ChrClasses.dbc` field 16 — set for Paladin, Shaman and Druid in `patch.MPQ`'s 17-column copy (the base `dbc.MPQ` copy has 16 columns and no such field, which is how the "always false in vanilla" belief survived twice in decisions and seven times in code) — and stock `PaperDollFrame.lua` calls it unconditionally, so the character sheet would have raised for EVERY class; a druid, paladin or shaman's sheet now hides the ammo slot, shows the relic plate where the bow was, tooltips "Relic", and reports ranged Attack/Damage/Power as N/A, all four branches transcribed from the reference - the loot window is the reference's own `LootFrame.xml`: `LootButton` is built as a real widget type rather than aliased (a Button plus one slot dword and one overridden OnClick — right-click loots exactly like left, no shift/ctrl/alt takes, a row whose Lua handler errored still loots, a fast double-click takes two slots), `LOOT_SLOT_CLEARED` fires per row again because the stock file hangs hide-in-place AND the emptied-page auto-advance off it, `EditBox:Insert(nil)` is a no-op as `lua_tostring` makes it, and an alias `GameTooltip.xml` had quietly become a reader of would have turned every item tooltip white, silently, had it just gone nil - the vendor cursor: `PickupMerchantItem` is two verbs behind one name, decided by what the cursor holds and never by the caller — a held bag item SELLS (index ignored, no merchant-open gate), otherwise the vendor row is grabbed as cursor mode 5, which is invisible to `CursorHasItem` (modes 1 and 9 only) so all thirteen stock gates stay closed while it is held; the drop is the buy, `CMSG_BUY_ITEM_IN_SLOT`, count 1, into a bag or an equipment slot, and every refusal is silent and clears the cursor; the four `Model_*` rotation handlers land in UIParent where the reference keeps them - the gap report reads `:Method(` sites now — it found `SetMerchantCompareItem`, which would have raised on the first vendor-row hover with every check green, and `LootButton:SetSlot`, and 28 "free" windows became 25; the shared coin kit moved out of the merchant window into `MoneyFrame.xml` so the eight windows that draw coins through it can reach it without loading a vendor Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -19,9 +19,9 @@ use benilla_ui::script::{TooltipTint, UiScript, UnitState};
|
||||
|
||||
use crate::items::Items;
|
||||
use crate::names::NameCache;
|
||||
use crate::net::{NetCommands, ObjectStore, Reputations, SelfPlayer};
|
||||
use crate::net::{NetCommands, ObjectStore, SelfPlayer};
|
||||
use crate::target::{
|
||||
go_is_nearest, ring_reaction, Factions, Hovered, HoveredObject, GO_FLAG_LOCKED, GO_TYPE_GENERIC,
|
||||
go_is_nearest, ring_reaction, Hovered, HoveredObject, GO_FLAG_LOCKED, GO_TYPE_GENERIC,
|
||||
};
|
||||
use crate::ui_action::{PlayerActions, Spells};
|
||||
use crate::ui_script::UiInput;
|
||||
@@ -602,8 +602,9 @@ fn drive_mouseover_tooltip(
|
||||
self_q: Query<&ObjectStore, With<SelfPlayer>>,
|
||||
mut names: ResMut<NameCache>,
|
||||
commands: Res<NetCommands>,
|
||||
factions: Option<Res<Factions>>,
|
||||
reputations: Res<Reputations>,
|
||||
// The standing pair as one param — see [`crate::target::ReactionInputs`]. Bundled here and
|
||||
// not elsewhere because this system sits on Bevy's tuple limit.
|
||||
rx: crate::target::ReactionInputs,
|
||||
// The lock chain's own data set, shared verbatim with the click router (`target::lock`) so the
|
||||
// hover and the click can never disagree about whether a lock is satisfiable — the same reason
|
||||
// `usable` and the click share one resolver (0752). Carries the go-template, Lock.dbc and
|
||||
@@ -615,6 +616,9 @@ fn drive_mouseover_tooltip(
|
||||
ui_scale: Res<crate::ui_script::UiScaleCvar>,
|
||||
mut last: Local<crate::ui_script::VmMemo<LastHover>>,
|
||||
mut last_lines: Local<crate::ui_script::VmMemo<Option<UnitState>>>,
|
||||
// `ChrClasses.dbc` field 16 — `UnitHasRelicSlot`'s only input. Absent when the client data
|
||||
// failed to load, in which case no class reads as having a relic slot.
|
||||
classes: Option<Res<crate::chr_classes::ChrClassTable>>,
|
||||
) {
|
||||
let Some(mut script) = script else {
|
||||
return;
|
||||
@@ -622,15 +626,27 @@ fn drive_mouseover_tooltip(
|
||||
let last = last.get(&script);
|
||||
let last_lines = last_lines.get(&script);
|
||||
let self_store = self_q.iter().next();
|
||||
let chr = classes.as_deref().map(|t| &t.0);
|
||||
|
||||
// The hovered UNIT's snapshot (a hovered non-unit resolves no store here).
|
||||
let unit = hovered.target.zip(hovered.guid).and_then(|(entity, guid)| {
|
||||
let store = stores.get(entity).ok()?;
|
||||
let name = names.resolve(guid, &commands).map(str::to_string);
|
||||
let reaction =
|
||||
ring_reaction(factions.as_deref(), &reputations, Some(store), self_store) + 1;
|
||||
let mut s = snapshot(store, name, reaction);
|
||||
enrich_unit(&mut s, guid, &names, store, factions.as_deref(), self_store);
|
||||
let reaction = ring_reaction(
|
||||
rx.factions.as_deref(),
|
||||
&rx.reputations,
|
||||
Some(store),
|
||||
self_store,
|
||||
) + 1;
|
||||
let mut s = snapshot(store, name, reaction, chr);
|
||||
enrich_unit(
|
||||
&mut s,
|
||||
guid,
|
||||
&names,
|
||||
store,
|
||||
rx.factions.as_deref(),
|
||||
self_store,
|
||||
);
|
||||
Some((guid, s))
|
||||
});
|
||||
// The hovered GAMEOBJECT, when it is the nearer pick (the click router's own arbitration).
|
||||
|
||||
Reference in New Issue
Block a user