From ed524ab1849f99a5eb04818f2efbc141aba2a012 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 2 Sep 2026 17:00:40 +0700 Subject: [PATCH] druids get their relic slot, and the loot window is the reference's own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `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 --- .../benilla-app/assets/ui/CharacterFrame.xml | 62 +- crates/benilla-app/assets/ui/GameTooltip.xml | 17 +- crates/benilla-app/assets/ui/InspectFrame.xml | 13 +- crates/benilla-app/assets/ui/LootFrame.xml | 727 ------------------ .../benilla-app/assets/ui/MerchantFrame.xml | 133 ---- crates/benilla-app/assets/ui/MoneyFrame.xml | 151 +++- crates/benilla-app/assets/ui/UIParent.xml | 67 ++ crates/benilla-app/assets/ui/UiPanels.xml | 68 ++ crates/benilla-app/assets/ui/benilla.toc | 41 +- crates/benilla-app/src/chr_classes.rs | 46 ++ crates/benilla-app/src/cursor.rs | 4 + crates/benilla-app/src/lib.rs | 3 + crates/benilla-app/src/net.rs | 12 + crates/benilla-app/src/net/io.rs | 7 + crates/benilla-app/src/sound/ui.rs | 12 +- crates/benilla-app/src/target/mod.rs | 20 + crates/benilla-app/src/ui_items/mod.rs | 20 +- crates/benilla-app/src/ui_loot.rs | 24 +- crates/benilla-app/src/ui_merchant.rs | 68 +- crates/benilla-app/src/ui_party/feed.rs | 23 +- crates/benilla-app/src/ui_pet/unit.rs | 5 +- crates/benilla-app/src/ui_pet_book.rs | 60 +- .../benilla-app/src/ui_script/escape_tests.rs | 13 +- .../benilla-app/src/ui_script/extract/mod.rs | 1 + .../src/ui_script/game_menu_tests.rs | 16 +- .../benilla-app/src/ui_script/loot_tests.rs | 159 ++-- .../src/ui_script/merchant_tests.rs | 6 +- .../src/ui_script/questlog_tests.rs | 5 +- .../benilla-app/src/ui_script/reference_ui.rs | 138 +++- crates/benilla-app/src/ui_script/test_ui.rs | 31 + crates/benilla-app/src/ui_tooltip/mod.rs | 32 +- crates/benilla-app/src/ui_unit.rs | 75 +- crates/benilla-formats/src/chr_classes.rs | 208 +++++ crates/benilla-formats/src/lib.rs | 4 +- crates/benilla-formats/src/pet_name_token.rs | 121 --- crates/benilla-protocol/src/messages/mod.rs | 4 +- .../benilla-protocol/src/messages/opcode.rs | 5 +- .../benilla-protocol/src/messages/vendor.rs | 33 +- crates/benilla-protocol/src/world/session.rs | 15 + .../src/world/writer/vendor.rs | 18 + crates/benilla-ui/src/script/button.rs | 69 +- crates/benilla-ui/src/script/char_stats.rs | 11 +- crates/benilla-ui/src/script/container.rs | 25 + crates/benilla-ui/src/script/cursor.rs | 47 +- crates/benilla-ui/src/script/cursor/bar.rs | 4 + crates/benilla-ui/src/script/cursor/doll.rs | 21 + .../benilla-ui/src/script/editbox/methods.rs | 19 +- crates/benilla-ui/src/script/loot.rs | 241 +++++- crates/benilla-ui/src/script/merchant.rs | 243 ++++++ crates/benilla-ui/src/script/mod.rs | 7 +- crates/benilla-ui/src/script/model.rs | 8 + crates/benilla-ui/src/script/object.rs | 11 + .../src/script/object/frame_state.rs | 4 + crates/benilla-ui/src/script/pointer.rs | 2 +- crates/benilla-ui/src/script/unit/bindings.rs | 30 + crates/benilla-ui/src/script/unit/mod.rs | 12 + crates/benilla-ui/src/script/unit/tests.rs | 53 ++ crates/benilla-ui/src/widget/kinds/mod.rs | 37 + crates/benilla-ui/src/widget/mod.rs | 4 +- 59 files changed, 2084 insertions(+), 1231 deletions(-) delete mode 100644 crates/benilla-app/assets/ui/LootFrame.xml create mode 100644 crates/benilla-app/src/chr_classes.rs create mode 100644 crates/benilla-formats/src/chr_classes.rs delete mode 100644 crates/benilla-formats/src/pet_name_token.rs diff --git a/crates/benilla-app/assets/ui/CharacterFrame.xml b/crates/benilla-app/assets/ui/CharacterFrame.xml index e9e5251d..5386e79d 100644 --- a/crates/benilla-app/assets/ui/CharacterFrame.xml +++ b/crates/benilla-app/assets/ui/CharacterFrame.xml @@ -76,10 +76,15 @@ forced-show path). A real forced-highlight affordance is a `benilla-ui` follow-up, not blocking this slice — `BenillaPaperDollSlot_LockHighlight`/`_UnlockHighlight` below tint the slot's Quickslot2 ring instead, flagged at their own definition. - - The relic slot: `UnitHasRelicSlot` is vanilla-always-false (there is no relic slot in - 1.12), so the ref's `CharacterAmmoSlot:Hide()`/relic-texture branches are DEAD CODE even - in the real client — omitted outright rather than transcribing unreachable branches; the - ammo slot always shows. + - The relic slot: **restored, and this note used to be wrong** (decision 1785). It read + "`UnitHasRelicSlot` is vanilla-always-false (there is no relic slot in 1.12), so the + ref's branches are DEAD CODE" — they are not. `ChrClasses.dbc` field 16 is set for + Paladin, Shaman and Druid, and INVSLOT 17 doubles as their relic slot. All four of the + ref's relic branches are live for three of nine classes and are transcribed here: the + ammo slot hides (ref l.580), ranged Attack/Damage/Attack Power force `NOT_APPLICABLE` + through `PaperDollFrame.noRanged` (l.437/449/482/552), the empty ranged-slot art + becomes `UI-PaperDoll-Slot-Relic.blp` (l.680), and its empty-slot tooltip reads + "Relic" (l.744). - Class-specific stat-tooltip flavor text (`WARRIOR_STRENGTH_TOOLTIP` and its ~20 siblings): only the 5 `DEFAULT_*_TOOLTIP` fallbacks ship. `PaperDollStatTooltip` still looks the class-specific global up FIRST exactly like the ref, so dropping in the per-class @@ -232,6 +237,7 @@ SECONDARYHANDSLOT = SECONDARYHANDSLOT or "Off Hand" -- :3400 RANGEDSLOT = RANGEDSLOT or "Ranged" -- :3291 AMMOSLOT = AMMOSLOT or "Ammo" -- :53 + RELICSLOT = RELICSLOT or "Relic" -- :3312 -- The font color codes/tables live in our Fonts.xml (the ref's own home for them, l.8-19 — -- verified this session), loaded before every window. @@ -519,11 +525,16 @@ end -- ref PaperDollFrame_OnShow (l.568-585): SetGuild OMITTED (named deferral, this file's - -- header). The relic Hide/Show branch is DROPPED outright — UnitHasRelicSlot is - -- vanilla-always-false, so CharacterAmmoSlot simply never has a reason to hide; it ships - -- with no hidden="true" at all (see its own Button below). + -- header). The relic branch (l.580-584) is transcribed verbatim — a relic class has no + -- ranged weapon and therefore no ammo, so its ammo slot hides. This used to be dropped on + -- the belief that UnitHasRelicSlot is always false; decision 1785. function PaperDollFrame_OnShow() paintRows(paperDollRows) + if UnitHasRelicSlot("player") then + CharacterAmmoSlot:Hide() + else + CharacterAmmoSlot:Show() + end end -- ref PaperDollFrame_OnHide (l.587-592) is entirely commented-out in the ref itself (the -- ShoppingTooltip/compare-tooltip lines, OMIT) — nothing to transcribe, no OnHide wired. @@ -811,8 +822,12 @@ getglobal(prefix .. "AttackFrameStatText"), mainHandAttackBase, mainHandAttackMod) end - -- ref PaperDollFrame_SetRangedAttack (l.419-466). `hasRelic`/UnitHasRelicSlot DROPPED - -- outright (this file's header comment: vanilla-always-false, dead code in the ref itself). + -- ref PaperDollFrame_SetRangedAttack (l.419-466). `hasRelic` is transcribed (it used to + -- be dropped — decision 1785). It is the whole reason a paladin's ranged block reads + -- "n/a" rather than the stats of the libram sitting in that slot: `noRanged` is set when + -- there is no ranged texture OR the class has a relic slot, and `SetRangedDamage` / + -- `SetRangedAttackPower` both read it (ref l.482 / l.552), so one flag blanks all three + -- rows. -- The literal slot id 18 is the ref's OWN hardcoded value (l.435) — quoted verbatim; what -- GetInventoryItemTexture resolves id 18 to is the parallel binding's call, not re-derived -- here. @@ -823,10 +838,11 @@ local frame = getglobal(prefix .. "RangedAttackFrame") local text = getglobal(prefix .. "RangedAttackFrameStatText") local paperDoll = getglobal("PaperDollFrame") + local hasRelic = UnitHasRelicSlot(unit) local rangedAttackBase, rangedAttackMod = UnitRangedAttack(unit) local rangedTexture = GetInventoryItemTexture("player", 18) local oldValue = paperDoll.noRanged - if rangedTexture then + if rangedTexture and not hasRelic then paperDoll.noRanged = nil else text:SetText(NOT_APPLICABLE) @@ -837,7 +853,7 @@ PaperDollFrame_SetRangedAttackPower() PaperDollFrame_SetRangedDamage() end - if not rangedTexture then return end + if not rangedTexture or hasRelic then return end setAttackRating(frame, text, rangedAttackBase, rangedAttackMod) end @@ -1002,7 +1018,10 @@ button.invSlotId = id button.slotName = slotName button.emptyTexture = texture - button.checkRelic = checkRelic -- UnitHasRelicSlot is vanilla-always-false (header OMIT): never read + -- `checkRelic` is the number 1 for the ranged slot alone (a property of the SLOT); the + -- class half is `UnitHasRelicSlot`, and the ref reads the two as a conjunction. Both + -- halves are live — decision 1785. + button.checkRelic = checkRelic button.icon = getglobal(button:GetName() .. "IconTexture") button.count = getglobal(button:GetName() .. "Count") -- Equip interactions on the 19 named slots use the equip-swap wire (PickupInventoryItem @@ -1084,7 +1103,14 @@ button.count:SetText("") end else - button.icon:SetTexture(button.emptyTexture) + -- ref l.678-681: the empty ranged slot of a relic class shows the relic plate, + -- not the bow plate. The art ships (`UI-PaperDoll-Slot-Relic.blp`, 3916 bytes, + -- patch.MPQ). Restored — decision 1785. + local emptyTexture = button.emptyTexture + if button.checkRelic and UnitHasRelicSlot("player") then + emptyTexture = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp" + end + button.icon:SetTexture(emptyTexture) button.count:SetText("") end -- A BROKEN item (durability 0) tints icon + slot ring red — ref @@ -1118,14 +1144,20 @@ -- arm (a worn item compared with itself is no comparison; director-caught: shift over -- the doll popped a "Currently Equipped" 0/XX beside a template-full main tooltip). -- The ref's repair-mode branch (l.757-762) is INTERIM-omitted with the binding's - -- repairCost. checkRelic (l.744-746) is TBC-flagged dead weight in 1.12 — omitted. + -- repairCost. checkRelic (l.744-746) is transcribed — it was called TBC-flagged dead + -- weight here, which was wrong (decision 1785): a paladin hovering their empty ranged + -- slot reads "Relic", not "Ranged". function BenillaPaperDollSlot_OnEnter(button) GameTooltip:SetOwner(button, "ANCHOR_RIGHT") local hasItem = GameTooltip:SetInventoryItem("player", button.invSlotId) if not hasItem then -- Empty slot: the slot-name tooltip (ref strupper(strsub(name,10)) -> the matching -- GlobalStrings key, e.g. "HeadSlot" -> HEADSLOT -> "Head"). - GameTooltip:SetText(getglobal(strupper(button.slotName)) or button.slotName) + local text = getglobal(strupper(button.slotName)) or button.slotName + if button.checkRelic and UnitHasRelicSlot("player") then + text = RELICSLOT + end + GameTooltip:SetText(text) end GameTooltip:Show() end diff --git a/crates/benilla-app/assets/ui/GameTooltip.xml b/crates/benilla-app/assets/ui/GameTooltip.xml index be11b962..bee2b863 100644 --- a/crates/benilla-app/assets/ui/GameTooltip.xml +++ b/crates/benilla-app/assets/ui/GameTooltip.xml @@ -54,12 +54,19 @@ return name or link end - -- Reuse the quality→colour source the loot window already ships (BENILLA_LOOT_QUALITY_COLORS, - -- LootFrame.xml — itself matching ui_items.rs quality_color / the client's GetItemQualityColor). - -- Unknown/nil quality falls back to common white. All FrameXML files load before any hover - -- fires, so the table is defined by the time this runs regardless of file order. + -- The shared quality→colour table, `ITEM_QUALITY_COLORS` — Fonts.xml's, matching + -- `ui_items.rs`'s `quality_color` and the client's `GetItemQualityColor`. Unknown/nil + -- quality falls back to common white. All FrameXML files load before any hover fires, so + -- the table is defined by the time this runs regardless of file order. + -- + -- This read `BENILLA_LOOT_QUALITY_COLORS` until 1751 took the loot window to the player's + -- chain. That name was only ever an alias our own `LootFrame.xml` set to this same table + -- ("the local name kept for this file's existing readers"), and the stock file does not + -- set it — so the alias went from harmless indirection to a nil the moment its definer + -- stopped shipping. The `t and` guard would have made that silent: every tooltip would + -- have quietly gone white. function BenillaTooltip_QualityColor(quality) - local t = BENILLA_LOOT_QUALITY_COLORS + local t = ITEM_QUALITY_COLORS local c = (t and (t[quality] or t[1])) or { r = 1, g = 1, b = 1 } return c.r, c.g, c.b end diff --git a/crates/benilla-app/assets/ui/InspectFrame.xml b/crates/benilla-app/assets/ui/InspectFrame.xml index c3e269d1..028e21ec 100644 --- a/crates/benilla-app/assets/ui/InspectFrame.xml +++ b/crates/benilla-app/assets/ui/InspectFrame.xml @@ -47,8 +47,17 @@ `InspectPaperDollFrame.lua:104-112`) — 0208's named deferrals, both LANDED (decisions 1059/1060): ctrl previews the inspected item on your own body, shift posts its link. Nothing else happens on a click, which is still the reference's own shape. - - `UnitHasRelicSlot` (ref l.123, l.22) — vanilla-always-false, so the relic branch can - never fire. Dropped outright, as CharacterFrame.xml drops it. + - `UnitHasRelicSlot` (ref l.123, l.22) — this note used to say "vanilla-always-false, so + the relic branch can never fire". **That is wrong** (decision 1785): the flag is set + for Paladin, Shaman and Druid, and the binding now exists and answers for any token, + with no `"player"` fast path — inspecting an enemy druid answers 1. The branch is + still not transcribed here, but for a different and honest reason: 1.12's inspect pane + ships inside `Blizzard_InspectUI`, which is a packed `.pub` on this install, so there + is no reference source to transcribe from. Restoring it is part of migrating this + window, not something to reconstruct from memory. The shared + `PaperDollFrame_SetRangedAttack(unit, prefix)` in CharacterFrame.xml — which the ref's + inspect pane drives with the inspected unit and the "Inspect" prefix — does honour + `hasRelic` now. - The held-button continuous spin (ref `InspectModelFrame_OnUpdate`, l.7-22) needs `GetButtonState() == "PUSHED"`, which this engine's Button has no method for (CharacterFrame.xml hit the identical wall) — click-only, so no OnUpdate is wired. diff --git a/crates/benilla-app/assets/ui/LootFrame.xml b/crates/benilla-app/assets/ui/LootFrame.xml deleted file mode 100644 index 06d5747b..00000000 --- a/crates/benilla-app/assets/ui/LootFrame.xml +++ /dev/null @@ -1,727 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LootFrame_OnLoad() - LootFrame_OnEvent(event) - LootFrame_OnShow() - LootFrame_OnHide() - - - - - - - - - - GroupLootDropDown_OnLoad() - - - diff --git a/crates/benilla-app/assets/ui/MerchantFrame.xml b/crates/benilla-app/assets/ui/MerchantFrame.xml index 2b07b87f..3df57f39 100644 --- a/crates/benilla-app/assets/ui/MerchantFrame.xml +++ b/crates/benilla-app/assets/ui/MerchantFrame.xml @@ -35,139 +35,6 @@ MERCHANT_ITEMS_PER_PAGE = 10 -- MERCHANT_ITEMS_PER_PAGE (ref MerchantFrame.lua l.1) BUYBACK_ITEMS_PER_PAGE = 12 -- BUYBACK_ITEMS_PER_PAGE (ref l.2; rows 11/12 are buyback-only) - -- The coin display, quoted from the real SmallMoneyFrame (ref MoneyFrame.xml/lua): a copper - -- amount renders as a number + a 13px coin icon per NONZERO denomination, cut from the one - -- shared texture Interface\MoneyFrame\UI-MoneyIcons by TexCoord (gold 0..0.25, silver - -- 0.25..0.5, copper 0.5..0.75 — ref l.115/74/33), the real collapse that hides zero coins - -- (MoneyFrame.lua l.221-267). Each money display owns three position-"slots"; the XML chains - -- them either left-to-right (row prices + the quest reward: Coin1 leftmost, gold first) or - -- right-to-left (the purses: Coin1 rightmost, copper first). BenillaMoney_Set fills the - -- visible denominations into slots 1.. in DISPLAY order (highestFirst=true for the - -- left-aligned chains) and — the real shrink, MoneyFrame.lua l.202/269 — sizes each slot to - -- exactly its number + its 13px coin (`SetWidth(GetTextWidth() + iconWidth)` there; the - -- same read here, off the number FontString the slot already owns). The static ±4px - -- chain-anchor offsets are the real MONEY_BUTTON_SPACING gap, so a shrunk group packs tight, - -- left-flush in the ltr chains and right-flush in the rtl ones. BenillaMoney_Clear hides - -- all three slots (the real collapse hides, see the helper). - -- - -- NOTE (for the loot window's fold): the reusable helpers are - -- BenillaMoney_Set(prefix, copper) and BenillaMoney_Clear(prefix) - -- where `prefix` names the slot frames `Coin1..3` (each with a `CoinNIcon` - -- texture + `CoinNNum` fontstring child). They live in this file. - BENILLA_COIN_TC = { - { 0.0, 0.25 }, -- [1] gold - { 0.25, 0.5 }, -- [2] silver - { 0.5, 0.75 }, -- [3] copper - } - - -- Unused slots HIDE (the real collapse — MoneyFrame.lua l.230/247 goldButton:Hide()), never - -- SetWidth(0): a 0 width means "derive from opposing anchors" to the layout (the client's - -- own G+0x50 convention), not "zero px". Fills are contiguous from Coin1, so a chain never - -- anchors THROUGH a hidden slot. - function BenillaMoney_Clear(prefix) - for i = 1, 3 do - getglobal(prefix .. "Coin" .. i):Hide() - end - end - - function BenillaMoney_Set(prefix, copper, highestFirst) - copper = copper or 0 - local vals = { - math.floor(copper / 10000), -- gold - math.floor((copper % 10000) / 100), -- silver - copper % 100, -- copper - } - -- Fill slots 1.. in display order (see the module comment); a zero denomination is - -- skipped (the real collapse), except copper always shows when the whole amount is - -- zero so a free item / empty purse isn't blank. - local first, last, step = 3, 1, -1 - if highestFirst then first, last, step = 1, 3, 1 end - local slot = 0 - for d = first, last, step do - if vals[d] > 0 or (d == 3 and vals[1] == 0 and vals[2] == 0) then - slot = slot + 1 - -- The real shrink: this slot is exactly its number + its 13px coin, and the - -- XML anchor chain re-flows off the new width. - -- Text first, then measure it: the engine answers a width read inside the - -- tick that set the text, so the number IS this number and not the last one. - local num = getglobal(prefix .. "Coin" .. slot .. "Num") - num:SetText(vals[d]) - local numW = num:GetStringWidth() - local slotFrame = getglobal(prefix .. "Coin" .. slot) - slotFrame:SetWidth(numW + 13) - slotFrame:Show() - local icon = getglobal(prefix .. "Coin" .. slot .. "Icon") - icon:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons") - icon:SetTexCoord(BENILLA_COIN_TC[d][1], BENILLA_COIN_TC[d][2], 0, 1) - num:SetWidth(numW) - end - end - for i = slot + 1, 3 do - getglobal(prefix .. "Coin" .. i):Hide() - end - end - - -- Recolor the coin *numbers* (the ref's SetMoneyFrameColor — the digits redden, the coin icons - -- keep their own texture). The trainer detail cost calls this white when affordable / red - -- (1.0, 0.1, 0.1) when not; a plain purse never calls it, so its coins stay default. Applies to - -- all 3 slots (hidden ones are harmless) and must be re-called after each BenillaMoney_Set, - -- which fills the numbers but does not reset their color. - function BenillaMoney_SetColor(prefix, r, g, b) - for i = 1, 3 do - getglobal(prefix .. "Coin" .. i .. "Num"):SetTextColor(r, g, b) - end - end - - -- ── The editable money-input kit (ref MoneyInputFrame.lua) ──────────────────────────────── - -- A naming three numeric EditBoxes Gold/Silver/Copper — the shared money entry - -- both the send-mail and trade windows inline (decision 0592 P2 builds it here, the money home, - -- so both reuse it). GetCopper folds the three digits into a copper total; SetCopper splits a - -- copper amount back across the boxes. SetCopper is a *programmatic* fill, so it must not re-fire - -- a box's OnTextChanged value-changed callback (the loop the reference's `expectChanges` counter - -- guards, MoneyInputFrame.lua l.44-73). Because benilla fires OnTextChanged synchronously inside - -- SetText, a bracket flag is exact and simpler than the counter: a window's box calls - -- BenillaMoneyInput_Consume(prefix) at the top of its OnTextChanged — false (swallow) while a - -- SetCopper is in flight, true for a genuine keystroke. - BENILLA_MONEYINPUT_SUPPRESS = {} - - function BenillaMoneyInput_ResetMoney(prefix) - getglobal(prefix .. "Gold"):SetText("") - getglobal(prefix .. "Silver"):SetText("") - getglobal(prefix .. "Copper"):SetText("") - end - - function BenillaMoneyInput_GetCopper(prefix) - local function n(box) return tonumber(getglobal(prefix .. box):GetText()) or 0 end - return n("Gold") * 10000 + n("Silver") * 100 + n("Copper") - end - - function BenillaMoneyInput_ClearFocus(prefix) - getglobal(prefix .. "Gold"):ClearFocus() - getglobal(prefix .. "Silver"):ClearFocus() - getglobal(prefix .. "Copper"):ClearFocus() - end - - function BenillaMoneyInput_SetCopper(prefix, money) - money = money or 0 - local parts = { - Gold = math.floor(money / 10000), - Silver = math.floor((money % 10000) / 100), - Copper = money % 100, - } - BENILLA_MONEYINPUT_SUPPRESS[prefix] = true - for box, val in pairs(parts) do - local eb = getglobal(prefix .. box) - if (tonumber(eb:GetText()) or 0) ~= val then - eb:SetText(val == 0 and "" or tostring(val)) - end - end - BENILLA_MONEYINPUT_SUPPRESS[prefix] = false - end - - function BenillaMoneyInput_Consume(prefix) - return not BENILLA_MONEYINPUT_SUPPRESS[prefix] - end - function BenillaMerchantItem_OnLoad(button, index) button.merchantIndex = index local n = button:GetName() diff --git a/crates/benilla-app/assets/ui/MoneyFrame.xml b/crates/benilla-app/assets/ui/MoneyFrame.xml index 7353f8a7..3708b358 100644 --- a/crates/benilla-app/assets/ui/MoneyFrame.xml +++ b/crates/benilla-app/assets/ui/MoneyFrame.xml @@ -18,8 +18,9 @@ ── THE OTHER COIN KIT, and why there are still two ────────────────────────────────────────── Eight of our windows (merchant, bank, trade, mail, quest, quest log, taxi, trainer) do NOT use - this file. They render coins through `BenillaMoney_Set`/`_Clear`/`_SetColor` in - MerchantFrame.xml: a three-SLOT chain (`Coin1..3`) that fills only the non-zero + this file. They render coins through `BenillaMoney_Set`/`_Clear`/`_SetColor`, which live + below in this same file (they were in MerchantFrame.xml until 1751 took that window to the + stock chain): a three-SLOT chain (`Coin1..3`) that fills only the non-zero denominations in display order and re-flows, rather than three fixed GoldButton/SilverButton/ CopperButton frames that hide themselves. That kit takes its coin TexCoords, its collapse and its shrink from the same specification as this one, and its layout is the one the director has @@ -67,6 +68,152 @@ here as they are there. They exist because the table's shape is the contract. -->