From 72e78ebc92d526864345352288af24c01bdbb04c Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 4 Sep 2026 20:53:37 +0700 Subject: [PATCH] a 40-man raid costs less per frame, and the money frames go stock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - a 40-man raid cost +5 to +8 ms of CPU per frame — a population, not a hot function — and three cuts landed where it was measured: the rig palette upload sends one `write_buffer` per run, bridging the gaps parked bodies leave between live rigs (calls 93 → 3); a built material becomes an asset when something visible binds it, not when a spawner builds it — 9.9k material assets were alive for 36 drawn batches, so a material is realized only once bound and visible, readers that clone before binding doing it themselves through one new function in the engine's wall (172 → 173): a 17× cut in live GPU objects; and a body's batches spawn as material groups — a geared body stood as 12–27 mesh parts, its skin composite drawn as five separate batches, and two visible batches now join when nothing downstream can tell them apart: parts per body 17 → 12, the Stormwind raid leg 17.0–21.0 → 15.65–15.82 `cpu_ms` (1929, 1940) - the instruments that priced it, all on the probe line: wgpu's own resource census, because a sampled profile put roughly half of the pass encoder in usage trackers sized to the device's live buffer and texture counts — a term that scales with residency, not with what is drawn, and nothing printed the number; the active camera count, since every view is its own pass set; the UI's live texture-identity runs, one 2D draw each, which is the number a UI change moves, not the quad count; and parts and materials per dressed body on the dress census, the ceiling on merging a body's batches read off a real body instead of guessed from a model's batch table (1940) - the coin kit retires: every remaining money display — quest progress, the mail purse and postage, the trade recipient, the tooltip, the quest log, the trainer's purse and cost — moves onto the reference's `MoneyFrameTemplate`, each seat already matching ours; the progress panel's required-money flow is ported in full — `QuestFrame.lua:168-190` colours the FRAME red/white AND the LABEL black/dark-grey when the quest costs more than you hold, where ours had neither colour; the mail postage takes the reference's name and label, trade and mail issue no explicit update because the frames repaint on their own events, and the trainer's cost label is shown or hidden with its `local COSTS_LABEL` shadow deleted; with the trainer converted the hand-built coin trios have no consumer, so their templates and the `BenillaMoney_*` helpers are deleted and `MoneyFrame.xml` is the only money kit (1937) - the crowd-control ladder's aura exemption exists, and it is a join between two `Spell.dbc` records — each arm asks whether the spell being cast is itself an immunity covering the aura that blocks it (Ice Block cast while stunned), the school arm shifting because `School` is an index and `EffectMiscValue` a mask; what the scan mostly decides is WHICH message a refusal carries — a blocking aura the cast does not counter renames the reason to "Can't do that while %s" (1941); bevy_audio leaves the build — its plugin had been disabled since 0530, but disabling a plugin does not remove a crate, and rodio, a second cpal and an Ogg/Vorbis decoder were still linked into a client that mixes through kira (1932); and cpal has four stream errors, not two — a routine ALSA underrun was treated as "the device is gone", tearing the stream down on every hiccup; now only a lost or invalidated device rebuilds (1939) Co-Authored-By: Claude Fable 5.1 --- Cargo.lock | 21 - Cargo.toml | 22 +- crates/benilla-app/assets/ui/GameTooltip.xml | 107 ++--- crates/benilla-app/assets/ui/MailFrame.xml | 73 +--- crates/benilla-app/assets/ui/MoneyFrame.xml | 74 +--- crates/benilla-app/assets/ui/QuestFrame.xml | 55 ++- .../benilla-app/assets/ui/QuestLogFrame.xml | 37 +- crates/benilla-app/assets/ui/TradeFrame.xml | 28 +- crates/benilla-app/assets/ui/TrainerFrame.xml | 87 ++-- .../src/capture/probes/dress_census.rs | 30 +- .../src/capture/probes/live_fps.rs | 46 +- crates/benilla-app/src/entities.rs | 1 + .../benilla-app/src/entities/attach/dress.rs | 28 +- .../benilla-app/src/entities/attach/merge.rs | 409 ++++++++++++++++++ crates/benilla-app/src/entities/attach/mod.rs | 44 +- .../src/entities/attach/redress.rs | 64 ++- crates/benilla-app/src/entities/display.rs | 1 + .../benilla-app/src/entities/spell_fx/mod.rs | 4 + crates/benilla-app/src/perf/gpu.rs | 39 +- crates/benilla-app/src/perf/mod.rs | 2 +- crates/benilla-app/src/pipe_warm/menagerie.rs | 5 + crates/benilla-app/src/portrait/light.rs | 3 + crates/benilla-app/src/sound/output/cpal.rs | 32 +- crates/benilla-app/src/ui_action/cast_send.rs | 19 + crates/benilla-app/src/ui_action/state.rs | 148 ++++++- crates/benilla-app/src/ui_chat/tests.rs | 1 + crates/benilla-app/src/ui_pass.rs | 7 +- crates/benilla-app/src/ui_script/bag_tests.rs | 8 +- .../benilla-app/src/ui_script/buff_tests.rs | 1 + .../benilla-app/src/ui_script/chat_tests.rs | 1 + .../src/ui_script/combo_frame_tests.rs | 1 + .../src/ui_script/dropdown_tests.rs | 1 + .../src/ui_script/durability_tests.rs | 2 + .../benilla-app/src/ui_script/errors_tests.rs | 2 + .../src/ui_script/exp_bar_tests.rs | 1 + .../src/ui_script/game_menu_tests.rs | 3 + .../src/ui_script/help_frame_tests.rs | 1 + .../benilla-app/src/ui_script/loot_tests.rs | 1 + .../src/ui_script/micro_menu_tests.rs | 2 +- .../src/ui_script/minimap_tests.rs | 5 + .../src/ui_script/multibar_stance_tests.rs | 2 + .../src/ui_script/options_tests.rs | 1 + .../src/ui_script/perf_bar_tests.rs | 2 +- .../src/ui_script/pet_frame_tests.rs | 1 + .../benilla-app/src/ui_script/quest_tests.rs | 10 + .../src/ui_script/quest_timer_tests.rs | 1 + .../src/ui_script/questlog_tests.rs | 35 ++ .../src/ui_script/target_aura_tests.rs | 1 + .../src/ui_script/tooltip_anchor_tests.rs | 1 + .../src/ui_script/tooltip_template_tests.rs | 1 + .../src/ui_script/tot_frame_tests.rs | 1 + .../src/ui_script/trainer_tests.rs | 3 +- .../src/ui_script/unit_frame_tests.rs | 3 + crates/benilla-app/tests/mail_frame.rs | 5 +- crates/benilla-app/tests/trade_frame.rs | 14 +- crates/benilla-app/tests/world_api_wall.rs | 13 +- crates/benilla-formats/src/lib.rs | 9 +- crates/benilla-formats/src/models/types.rs | 2 +- crates/benilla-formats/src/spells/display.rs | 16 + crates/benilla-formats/src/spells/immunity.rs | 327 ++++++++++++++ crates/benilla-formats/src/spells/mod.rs | 13 + crates/benilla-formats/tests/spell_catalog.rs | 40 ++ .../src/messages/update_object/fields/unit.rs | 13 + crates/benilla-world/src/boot.rs | 10 +- crates/benilla-world/src/model_render.rs | 311 ++++++------- crates/benilla-world/src/model_render/lazy.rs | 223 ++++++++++ crates/benilla-world/src/particles/model.rs | 3 + crates/benilla-world/src/rig_palette.rs | 47 +- crates/benilla-world/src/world_census.rs | 4 + 69 files changed, 1942 insertions(+), 586 deletions(-) create mode 100644 crates/benilla-app/src/entities/attach/merge.rs create mode 100644 crates/benilla-formats/src/spells/immunity.rs create mode 100644 crates/benilla-world/src/model_render/lazy.rs diff --git a/Cargo.lock b/Cargo.lock index 4a0e4a52..ae593da8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4151,17 +4151,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -[[package]] -name = "lewton" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" -dependencies = [ - "byteorder", - "ogg", - "tinyvec", -] - [[package]] name = "libc" version = "0.2.186" @@ -5036,15 +5025,6 @@ dependencies = [ "nonmax", ] -[[package]] -name = "ogg" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" -dependencies = [ - "byteorder", -] - [[package]] name = "once_cell" version = "1.21.4" @@ -5707,7 +5687,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" dependencies = [ "cpal 0.15.3", - "lewton", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d3775ec9..cd531bfb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,27 @@ authors = ["sam "] # and a workspace default-features choice can't be subtracted from downstream. [workspace.dependencies] anyhow = "1.0.102" -bevy = "0.18.1" +# bevy's `default` is `["2d", "3d", "ui"]`, and every one of those three pulls `audio` +# (= `bevy_audio` + `vorbis`) — so a default bevy compiles rodio, a second cpal, a second ALSA +# binding and an ogg/vorbis decoder into a client that mixes through kira and has had bevy's +# `AudioPlugin` disabled at boot since 0530. This spells the same `default` out with `audio` +# taken away: `2d`/`3d`/`ui` decomposed into the parts they are made of, which is the whole +# union of the three minus that one entry (decision 1932 has the expansion, verified against a +# before/after feature tree). Nothing else in the graph asks for it — avian3d, bevy_egui and +# bevy_transform_interpolation all take bevy with `default-features = false`. +# +# If a future bevy needs another member, add it here by name; do not reach back for `2d`/`3d`/ +# `ui`, which would quietly bring the audio stack with it. +bevy = { version = "0.18.1", default-features = false, features = [ + "default_app", + "default_platform", + "2d_bevy_render", + "3d_bevy_render", + "ui_api", + "ui_bevy_render", + "scene", + "picking", +] } # The render app's raw GPU handles (the WOW_GPU_MS meter's query set): bevy 0.18 does not wrap # wgpu's QuerySet family, so the meter reaches for the same wgpu the workspace already builds. wgpu = "27" diff --git a/crates/benilla-app/assets/ui/GameTooltip.xml b/crates/benilla-app/assets/ui/GameTooltip.xml index bee2b863..0675bac3 100644 --- a/crates/benilla-app/assets/ui/GameTooltip.xml +++ b/crates/benilla-app/assets/ui/GameTooltip.xml @@ -114,7 +114,7 @@ -- -- Signature note: the ref reads the firing frame from the `this` global; the corpus -- convention is to keep the ref NAME and take that frame as a leading parameter - -- (GameTooltip_OnHide(self), GameTooltip_ClearMoney(frame) — same shift). Reference code + -- (GameTooltip_OnHide(self) — same shift; GameTooltip_ClearMoney went back to the reference's no-argument form in 1937). Reference code -- pasted in verbatim must therefore have the owner threaded in as arg 1. -- **The reference's exact signature, because a signature IS api (1199).** Ours used to take -- the owner as arg 1; the reference takes none and reads `this`. Outfitter calls it the @@ -181,30 +181,28 @@ -- engine fires OnTooltipAddMoney with the computed price (wow-re ui/scratch/tooltip-money.md -- 0x52b650@0x52e376: the engine computes, FrameXML renders) and this is its handler; Lua -- call sites (repair cost) call it directly, exactly like the ref's ContainerFrame does. + -- ref GameTooltip.lua:84-92, verbatim, on the reference's own widget (1937). The money row + -- is the $parentMoneyFrame SmallMoneyFrameTemplate instance below, not a coin trio. function SetTooltipMoney(frame, money) frame:AddLine(" ", 1.0, 1.0, 1.0) local numLines = frame:NumLines() - local line = getglobal(frame:GetName() .. "TextLeft" .. numLines) - local coin1 = getglobal(frame:GetName() .. "MoneyCoin1") - coin1:ClearAllPoints() - coin1:SetPoint("LEFT", line, "LEFT", 4, 0) - BenillaMoney_Set(frame:GetName() .. "Money", money, true) - local width = 4 - for i = 1, 3 do - local c = getglobal(frame:GetName() .. "MoneyCoin" .. i) - if c:IsShown() then width = width + c:GetWidth() + 4 end - end - frame:SetMinimumWidth(width) + local moneyFrame = getglobal(frame:GetName() .. "MoneyFrame") + moneyFrame:SetPoint("LEFT", frame:GetName() .. "TextLeft" .. numLines, "LEFT", 4, 0) + moneyFrame:Show() + MoneyFrame_Update(moneyFrame:GetName(), money) + frame:SetMinimumWidth(moneyFrame:GetWidth()) end -- The money row clears whenever the content does (the ref wires GameTooltip_ClearMoney to -- OnTooltipCleared; the engine fires it on ClearLines/SetOwner/Hide). BenillaMoney_Clear -- ships in MerchantFrame.xml (the money kit's home) — guard for engine tests that load -- this file alone; in the app every file is loaded. - function GameTooltip_ClearMoney(frame) - frame = frame or this - if BenillaMoney_Clear then - BenillaMoney_Clear(frame:GetName() .. "Money") + -- ref GameTooltip.lua:94-99, verbatim: reads `this`, takes no argument. The one XML + -- caller (OnTooltipCleared) is a handler, so `this` IS the tooltip. + function GameTooltip_ClearMoney() + local moneyFrame = getglobal(this:GetName() .. "MoneyFrame") + if moneyFrame then + moneyFrame:Hide() end end @@ -312,12 +310,12 @@ $parentStatusBar, and the OnLoad/OnHide pair (ref l.611-616). What is deliberately NOT here, and stays on the GameTooltip instance: - - The money coin trio and the OnTooltipAddMoney/OnTooltipCleared pair. The reference's - template carries a $parentMoneyFrame (l.598-608, a SmallMoneyFrameTemplate), so its - handler is safe on every instance; ours is a bespoke three-coin row that only - GameTooltip declares, so a templated OnTooltipAddMoney would index a MoneyCoin1 that - does not exist. Moving the row up would give ItemRefTooltip and every addon tooltip a - coin line they render today without — a visible change, so it waits for the director. + - The money row and the OnTooltipAddMoney/OnTooltipCleared pair. Since 1937 the row IS the + reference's widget (a $parentMoneyFrame SmallMoneyFrameTemplate), but it still lives on + the GameTooltip INSTANCE, where the reference's template carries it (l.598-608) so that + ItemRefTooltip and every addon tooltip get the coin line too. That hoist is the remaining + divergence here. It used to wait for the director; the 2026-09-03 ruling (faithful wins) + resolves it, and it is its own unit because 27 corpus addons inherit this template. - OnTooltipSetDefaultAnchor (ref l.617-619). The engine fires it by name on `GameTooltip` alone (script/tooltip_unit.rs looks the frame up), so on any other instance it is dead weight. @@ -471,64 +469,11 @@ screen center when the default-anchor script wasn't wired. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + SmallMoneyFrame_OnLoad(); MoneyFrame_SetType("STATIC"); @@ -559,7 +504,7 @@ computes a price and fires OnTooltipAddMoney(arg1 = copper); OnTooltipCleared fires whenever the content clears (ClearLines/SetOwner/Hide) and drops the coin row. --> SetTooltipMoney(this, arg1) - GameTooltip_ClearMoney(this) + GameTooltip_ClearMoney() diff --git a/crates/benilla-app/assets/ui/MailFrame.xml b/crates/benilla-app/assets/ui/MailFrame.xml index 04c766b6..d328d6ee 100644 --- a/crates/benilla-app/assets/ui/MailFrame.xml +++ b/crates/benilla-app/assets/ui/MailFrame.xml @@ -580,13 +580,13 @@ SendMailCODButtonText:SetTextColor(0.5, 0.5, 0.5) end getglobal("SendMailPackageButtonCount"):SetText(stackCount) - BenillaMoney_Set("SendMailMoneyFrame", GetMoney()) - -- The 30c postage (ref l.542-547); red when it exceeds the purse. - BenillaMoney_Set("SendMailCost", GetSendMailPrice()) + -- ref MailFrame.lua:542-547, verbatim. The purse (type PLAYER) and the postage (painted + -- in its own OnLoad) need no update here; only the postage COLOUR is decided per + -- refresh, and with the reference's own named colours rather than literals (1937). if GetSendMailPrice() > GetMoney() then - BenillaMoney_SetColor("SendMailCost", 1.0, 0.1, 0.1) + SetMoneyFrameColor("SendMailCostMoneyFrame", RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b) else - BenillaMoney_SetColor("SendMailCost", 1.0, 1.0, 1.0) + SetMoneyFrameColor("SendMailCostMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) end SendMailFrame_CanSend() end @@ -1030,33 +1030,21 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + SmallMoneyFrame_OnLoad(); MoneyFrame_SetType("STATIC"); + MoneyFrame_Update("SendMailCostMoneyFrame", GetSendMailPrice()); + @@ -1165,26 +1153,11 @@ UI-ClassTrainer-BotLeft left of the Send button (without it the recess reads as a broken empty input box). Inlined as the BenillaMoney coin trio; fed GetMoney() by SendMailFrame_Update + the PLAYER_MONEY event. --> - - + + - - - - - - - - - - - - - - - - - diff --git a/crates/benilla-app/assets/ui/MoneyFrame.xml b/crates/benilla-app/assets/ui/MoneyFrame.xml index 40d36788..355dc1e7 100644 --- a/crates/benilla-app/assets/ui/MoneyFrame.xml +++ b/crates/benilla-app/assets/ui/MoneyFrame.xml @@ -17,14 +17,14 @@ the top runtime walls the frame rename left standing. ── 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`, 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 - signed off across those eight windows. + There WAS a second coin kit — `BenillaMoney_Set`/`_Clear`/`_SetColor`, a three-SLOT chain + (`Coin1..3`) that filled only the non-zero denominations in display order and + re-flowed, born in MerchantFrame.xml and used by eight windows, with a layout the director had + signed off across them. The 2026-09-03 ruling — faithful wins, do not park on the director + what the reference already answers — superseded that sign-off: 1928 (quest reward money) and + 1937 (quest required money, mail, trade, tooltip, quest log, trainer) moved every window onto + this file's templates, and the helpers were deleted with the last consumer. This file is the + only money kit now. The auction house is the exception, and the reason the reconciliation started there rather than anywhere else: the three-slot kit has no notion of a money TYPE, so it cannot express @@ -106,64 +106,6 @@ { 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 - -- ── What a coin is worth ───────────────────────────────────────────────────────────────── -- Published globals: an addon that formats a price does the same split we do below, and -- reads these rather than spelling 100 twice. diff --git a/crates/benilla-app/assets/ui/QuestFrame.xml b/crates/benilla-app/assets/ui/QuestFrame.xml index ca96cf9e..26e5d700 100644 --- a/crates/benilla-app/assets/ui/QuestFrame.xml +++ b/crates/benilla-app/assets/ui/QuestFrame.xml @@ -211,8 +211,7 @@ end)(), ["QuestProgressScrollFrame"] = (function() local t = { "QuestProgressText", "QuestProgressRequiredItemsText", - "QuestProgressRequiredMoneyText", "QuestProgressMoneyCoin1", - "QuestProgressMoneyCoin2", "QuestProgressMoneyCoin3" } + "QuestProgressRequiredMoneyText", "QuestProgressRequiredMoneyFrame" } for i = 1, MAX_REQUIRED_ITEMS do table.insert(t, "QuestProgressItem" .. i) end return t end)(), @@ -570,21 +569,35 @@ local reqText = getglobal("QuestProgressRequiredItemsText") local moneyText = getglobal("QuestProgressRequiredMoneyText") local item1 = getglobal("QuestProgressItem1") + -- ref QuestFrame.lua:168-190, ported in full (1937): the money frame paints from + -- GetQuestMoneyToGet(); BOTH colours branch on whether the purse covers it — the frame + -- red/white and the LABEL black/dark-grey; the label and frame are Shown/Hidden rather + -- than blanked (the label's text is the XML's REQUIRED_MONEY); and the first required + -- item re-anchors to whichever text is showing. + local moneyFrame = getglobal("QuestProgressRequiredMoneyFrame") if numItems > 0 or (money and money > 0) then - reqText:SetText("Items Needed:") + reqText:Show() if money and money > 0 then - moneyText:SetText("Required Money:") - BenillaMoney_Set("QuestProgressMoney", money, true) + MoneyFrame_Update("QuestProgressRequiredMoneyFrame", money) + if money > GetMoney() then + moneyText:SetTextColor(0, 0, 0) + SetMoneyFrameColor("QuestProgressRequiredMoneyFrame", 1.0, 0.1, 0.1) + else + moneyText:SetTextColor(0.2, 0.2, 0.2) + SetMoneyFrameColor("QuestProgressRequiredMoneyFrame", 1.0, 1.0, 1.0) + end + moneyText:Show() + moneyFrame:Show() item1:SetPoint("TOPLEFT", moneyText, "BOTTOMLEFT", 0, -10) else - moneyText:SetText("") - BenillaMoney_Clear("QuestProgressMoney") + moneyText:Hide() + moneyFrame:Hide() item1:SetPoint("TOPLEFT", reqText, "BOTTOMLEFT", -3, -5) end else - reqText:SetText("") - moneyText:SetText("") - BenillaMoney_Clear("QuestProgressMoney") + reqText:Hide() + moneyText:Hide() + moneyFrame:Hide() end for i = 1, MAX_REQUIRED_ITEMS do if i <= numItems then @@ -909,16 +922,6 @@ - - - - - - - - - + + + SmallMoneyFrame_OnLoad(); MoneyFrame_SetType("STATIC"); + - - + + - - - - - - - - - - - - - - - - - - - - + QuestMoneyFrame_OnLoad() diff --git a/crates/benilla-app/assets/ui/TradeFrame.xml b/crates/benilla-app/assets/ui/TradeFrame.xml index 3c31b707..70bb2297 100644 --- a/crates/benilla-app/assets/ui/TradeFrame.xml +++ b/crates/benilla-app/assets/ui/TradeFrame.xml @@ -113,7 +113,9 @@ end -- Our gold is the editable input, reflected via PLAYER_TRADE_MONEY (not repainted here, so -- the repaint never clobbers mid-typing); only the partner's read-only gold repaints. - BenillaMoney_Set("TradeRecipientMoneyFrame", GetTargetTradeMoney()) + -- The recipient's money frame is type TARGET_TRADE and repaints itself on + -- TRADE_MONEY_CHANGED (MoneyFrame_OnEvent); the reference issues no explicit update + -- here and neither do we (1937). -- A repaint puts both glows down. TRADE_ACCEPT_UPDATE is the only thing that raises -- them, so whatever is standing comes straight back on the next one. setTradeGlow(TradeHighlightPlayer, TradeHighlightPlayerEnchant, false) @@ -492,26 +494,12 @@ - - + + - - - - - - - - - - - - - - - - - + SmallMoneyFrame_OnLoad(); MoneyFrame_SetType("TARGET_TRADE"); diff --git a/crates/benilla-app/assets/ui/TrainerFrame.xml b/crates/benilla-app/assets/ui/TrainerFrame.xml index b569a6f5..dc414b2d 100644 --- a/crates/benilla-app/assets/ui/TrainerFrame.xml +++ b/crates/benilla-app/assets/ui/TrainerFrame.xml @@ -14,7 +14,7 @@ - MerchantFrame.xml — the 384×512 four-quadrant window art (no : the art IS the frame), the NPC-session lifecycle (RegisterEvent trio + PLAYER_MONEY, SHOW/UPDATE/CLOSED dispatch, OnShow/OnHide PlaySound with CloseTrainer() on hide), the "npc" model-portrait - binding, and the BenillaMoney_* coin rig (detail cost + player purse). The close X reuses + binding, and the reference's own two money frames (detail cost + player purse). The close X reuses the minimize-button art (this engine ships no UIPanelCloseButton). - QuestLogFrame.xml — the list-row Button template shape ($parent-named child regions wired in ) and the persistent selection-highlight Frame (a child Frame whose ARTWORK Texture @@ -56,7 +56,7 @@ - GlobalStrings the ref reads (REQUIRES_LABEL, TRAINER_REQ_*, COSTS_LABEL, the labels) are defined LOCALLY below as the byte-exact 1.12 enUS values (interface.MPQ GlobalStrings.lua, line-cited); NORMAL/GRAY/HIGHLIGHT_FONT_COLOR are Fonts.xml globals. - - The affordability RED-TINT of the cost coins (ref SetMoneyFrameColor) is BenillaMoney_SetColor. + - The affordability RED-TINT of the cost is the reference's own SetMoneyFrameColor (1937). - The profession-confirm StaticPopup is skipped for v1 (Train buys directly); a later refinement. Registers at the left UIPanel slot like Gossip/Merchant/Quest/QuestLog (UiPanels.xml) — opening @@ -70,7 +70,6 @@ -- number/name (met = white, unmet = red), exactly as the real requirements line reads. local PARENS_TEMPLATE = "(%s)" -- GlobalStrings.lua:2468 local REQUIRES_LABEL = "Requires:" -- REQUIRES_LABEL (2768) - local COSTS_LABEL = "Cost:" -- COSTS_LABEL (667) local UNKNOWN_LABEL = "Unknown" -- UNKNOWN (3860) local FILTER_LABEL = "Filter" -- FILTER (1297) local TRAINER_REQ_LEVEL = "Level |cffffffff%d|r" -- TRAINER_REQ_LEVEL (3739) @@ -116,9 +115,9 @@ getglobal("BenillaTrainerSkillName"):SetText("") getglobal("BenillaTrainerSkillRequirements"):SetText("") getglobal("BenillaTrainerSkillDescription"):SetText("") - getglobal("BenillaTrainerCostLabel"):SetText("") + getglobal("BenillaTrainerCostLabel"):Hide() getglobal("BenillaTrainerSkillIcon"):Hide() - BenillaMoney_Clear("BenillaTrainerDetailMoney") + getglobal("ClassTrainerDetailMoneyFrame"):Hide() getglobal("BenillaTrainerTrainButton"):Disable() end @@ -177,21 +176,29 @@ getglobal("BenillaTrainerSkillRequirements"):SetText("") end - -- Cost (ref): a free service shows no coins/label; otherwise the "Cost:" label + coins, - -- reddened when unaffordable (BenillaMoney_SetColor: white when GetMoney() >= cost, else red). + -- ref Blizzard_TrainerUI.lua (the "Money Frame and cost" block), in full (1937): a free + -- service hides the frame AND the label and pulls the description up to the label's TOPLEFT; + -- a costed one shows both, seats the description under the label, and tints the frame white + -- when the purse covers it, red when not. The frame is repainted either way. local moneyCost = GetTrainerServiceCost(id) + local costFrame = getglobal("ClassTrainerDetailMoneyFrame") + local costLabel = getglobal("BenillaTrainerCostLabel") + local description = getglobal("BenillaTrainerSkillDescription") if moneyCost and moneyCost > 0 then - getglobal("BenillaTrainerCostLabel"):SetText(COSTS_LABEL) - BenillaMoney_Set("BenillaTrainerDetailMoney", moneyCost, true) + costFrame:Show() + costLabel:Show() + description:SetPoint("TOPLEFT", costLabel, "BOTTOMLEFT", 0, -10) if (GetMoney() or 0) >= moneyCost then - BenillaMoney_SetColor("BenillaTrainerDetailMoney", 1.0, 1.0, 1.0) + SetMoneyFrameColor("ClassTrainerDetailMoneyFrame", 1.0, 1.0, 1.0) else - BenillaMoney_SetColor("BenillaTrainerDetailMoney", 1.0, 0.1, 0.1) + SetMoneyFrameColor("ClassTrainerDetailMoneyFrame", 1.0, 0.1, 0.1) end else - getglobal("BenillaTrainerCostLabel"):SetText("") - BenillaMoney_Clear("BenillaTrainerDetailMoney") + costFrame:Hide() + costLabel:Hide() + description:SetPoint("TOPLEFT", costLabel, "TOPLEFT", 0, 0) end + MoneyFrame_Update("ClassTrainerDetailMoneyFrame", moneyCost or 0) getglobal("BenillaTrainerSkillDescription"):SetText(GetTrainerServiceDescription(id)) @@ -251,7 +258,7 @@ function BenillaTrainerFrame_Update() getglobal("BenillaTrainerGreetingText"):SetText(GetTrainerGreetingText()) - BenillaMoney_Set("BenillaTrainerMoney", GetMoney()) + getglobal("ClassTrainerMoneyFrame"):Show() -- ref ClassTrainerFrame_Show; type PLAYER paints itself local numServices = GetNumTrainerServices() if numServices == 0 then @@ -552,7 +559,6 @@ elseif event == "TRAINER_CLOSED" then HideUIPanel(frame) elseif event == "PLAYER_MONEY" then - BenillaMoney_Set("BenillaTrainerMoney", GetMoney()) -- A buy changes affordability without a TRAINER_UPDATE — repaint the detail's cost tint. if BenillaTrainerFrame:IsVisible() then BenillaTrainerFrame_Update() @@ -635,18 +641,6 @@ - - - - - - - - - - - - - - - - - - + + + + SmallMoneyFrame_OnLoad(); MoneyFrame_SetType("STATIC"); - - - - - - - - - + + +