- benilla loads real 1.12 addons from Interface/AddOns — TOC, XML and Lua through one loader, with per-addon saved variables, Bindings.xml and the lifecycle events addons expect - both AddOns screens are in: the character-select list with per-addon enable state, and the ESC menu's in-game list - the API surface is measured, not guessed — a corpus harness runs hundreds of real 1.12 addons and ranks exactly which globals, templates and verbs they demand - the Lua dialect is the client's own, read off the binary — 5.0 semantics with the 1.12 additions, and UI source files are bytes, not UTF-8 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
260 lines
16 KiB
XML
260 lines
16 KiB
XML
<Ui>
|
|
<!--
|
|
The quest-timer window — the small dialog under the minimap that counts a timed quest down
|
|
(decision 1150, B234). Geometry, art, layout and behaviour are QUOTED from the real 1.12
|
|
QuestTimerFrame (extracted Interface\FrameXML\QuestTimerFrame.xml + .lua): a 160x72
|
|
UI-DialogBox backdrop with the 256x64 header art and the QUEST_TIMERS title on it, twenty
|
|
140x16 rows stacked flush from TOP -30, and a height of 45 + 16*n for n live timers.
|
|
|
|
It is a LIST OF TIMES, not a bar. The report this closes guessed a mirror-timer-style bar,
|
|
and the reference file settles it: one `SecondsToTime` line per timed quest ("14 Mins 20
|
|
Secs"), clickable to open the quest log at that quest, hovering to name it. The mirror
|
|
timers (MirrorTimer.xml, 0874) are a different mechanism entirely — those are server-pushed
|
|
values with a rate to integrate, this reads the quest log's own deadlines.
|
|
|
|
The feed is the engine's GetQuestTimers()/GetQuestIndexForTimer(), which subtract the
|
|
server's wall clock (SMSG_QUERY_TIME_RESPONSE) from each quest-log slot's absolute deadline
|
|
per call — the reference's own division of labour, and why the OnUpdate below can repaint a
|
|
ticking number without the quest-log snapshot changing under it. No timed quests → the
|
|
bindings return no values at all → the frame hides, which is the ref's own signal.
|
|
|
|
Departures, each named:
|
|
- BARE frame names (no `Benilla` prefix), like DurabilityFrame and GroupLootFrame1 before
|
|
it (decision 0591 §3): UIParent_ManageFramePositions resolves its stack through a literal
|
|
getglobal(name), and the ref's own Lua below reaches its rows by
|
|
getglobal("QuestTimer"..i.."Text"). Prefixing would silently unseat the frame and break
|
|
the row lookup at once.
|
|
- Lua 5.0 `arg`/`arg.n` varargs written as select("#", ...)/select(i, ...), the 5.1-native
|
|
spelling and this tree's house style (TalentFrame.xml / WorldMapFrame.xml's precedent).
|
|
- The ref's XML anchor (TOPRIGHT of MinimapCluster +10,0) is transcribed and, like every
|
|
managed HUD frame, DEAD ON ARRIVAL: UIParent_ManageFramePositions re-seats it at
|
|
-CONTAINER_OFFSET_X on every pass. Kept verbatim anyway so the file reads as the ref's.
|
|
- `toplevel="true"` is dropped, and the reason given here was half wrong: the raise's real
|
|
triggers are **Show**, drag-start and mouse-down, not "raise-on-click for movable dialogs"
|
|
(wow-re `ui/scratch/toplevel-raise.md`). The verb now exists (`script::object::toplevel`),
|
|
so the standing reason is only the second one — this frame is a managed HUD strip that
|
|
UIParent_ManageFramePositions re-seats and that overlaps nothing in its own stratum, so
|
|
the occlusion gate would decline every raise anyway. Re-adding it is one word if that
|
|
stops being true.
|
|
- QuestTimerFrame_OnShow/OnHide call the manage pass, as the ref does — that is what lets
|
|
the durability guy and the quest tracker drop below this window when a timer appears.
|
|
- The ref's own commented-out QuestTimerFrame_UpdatePosition (its pre-manage-pass
|
|
positioning) is left out rather than transcribed as dead code.
|
|
|
|
NOT a departure, though it looks like one: the row buttons are laid out flush (0,0 between
|
|
them) while each is 16 tall and the frame grows by exactly 16 per timer. That is the ref's
|
|
own arithmetic (45 + 16*n against a 72-tall empty frame), not a rounding of ours.
|
|
-->
|
|
<Script><![CDATA[
|
|
-- ref GlobalStrings.lua:3241 — the window's title, under its real key so the ref's own
|
|
-- `text="QUEST_TIMERS"` below resolves through the loader's global-string lookup verbatim
|
|
-- (loader/mod.rs `resolve_text`). Declared here because we load no GlobalStrings.lua;
|
|
-- guarded, in case a later file ships one.
|
|
QUEST_TIMERS = QUEST_TIMERS or "Quest Timers"
|
|
-- ref QuestLogFrame.lua:2. Declared here too because the ref's hide loop below runs to it
|
|
-- and this file may load before the quest log's own copy.
|
|
MAX_QUESTS = MAX_QUESTS or 20
|
|
|
|
-- ref QuestTimerFrame_OnLoad (QuestTimerFrame.lua:1-6).
|
|
function QuestTimerFrame_OnLoad(frame)
|
|
frame:RegisterEvent("QUEST_LOG_UPDATE")
|
|
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
QuestTimerFrameNumTimers = 0
|
|
QuestTimerFrameUpdating = nil
|
|
end
|
|
|
|
-- ref QuestTimerFrame_OnEvent (:8-14). The `updating` latch is the ref's own re-entrancy
|
|
-- guard: QuestTimerFrame_Update's Show() fires OnShow → the manage pass, and a
|
|
-- QUEST_LOG_UPDATE arriving inside that would re-enter this.
|
|
function QuestTimerFrame_OnEvent()
|
|
if not QuestTimerFrameUpdating then
|
|
QuestTimerFrame_Update(GetQuestTimers())
|
|
end
|
|
end
|
|
|
|
-- ref QuestTimerFrame_Update (:16-32), with select() for the 5.0 vararg table.
|
|
function QuestTimerFrame_Update(...)
|
|
QuestTimerFrameUpdating = 1
|
|
local n = select("#", ...)
|
|
for i = 1, n do
|
|
-- `select(i, ...)` expands to EVERY value from i on, and in a call's last argument
|
|
-- position they all get passed — so an inlined `SecondsToTime(select(i, ...))`
|
|
-- hands timer i+1 to SecondsToTime's `noSeconds` and silently drops the seconds
|
|
-- off every row but the last ("14 Mins" instead of "14 Mins 20 Secs"). The local
|
|
-- takes the first value only. The ref's `arg[i]` had no such hazard; this is the
|
|
-- 5.0→5.1 vararg swap's own trap, caught by the test that expected the seconds.
|
|
local seconds = select(i, ...)
|
|
getglobal("QuestTimer" .. i .. "Text"):SetText(SecondsToTime(seconds))
|
|
getglobal("QuestTimer" .. i):Show()
|
|
end
|
|
for i = n + 1, MAX_QUESTS do
|
|
getglobal("QuestTimer" .. i):Hide()
|
|
end
|
|
QuestTimerFrameNumTimers = n
|
|
local frame = getglobal("QuestTimerFrame")
|
|
if n > 0 then
|
|
frame:SetHeight(45 + (16 * n))
|
|
frame:Show()
|
|
else
|
|
frame:Hide()
|
|
end
|
|
QuestTimerFrameUpdating = nil
|
|
end
|
|
|
|
-- ref QuestTimerFrame_OnUpdate (:34-38): re-read every frame while any timer is live —
|
|
-- that, not an event, is what makes the number tick. Costs nothing while hidden (the
|
|
-- engine's OnUpdate gate is effective-visibility) and nothing while empty (numTimers 0).
|
|
function QuestTimerFrame_OnUpdate()
|
|
if QuestTimerFrameNumTimers > 0 then
|
|
QuestTimerFrame_Update(GetQuestTimers())
|
|
end
|
|
end
|
|
|
|
-- ref QuestTimerButton_OnClick (:40-44): open the log at that quest.
|
|
function QuestTimerButton_OnClick(id)
|
|
local index = GetQuestIndexForTimer(id)
|
|
if not index then
|
|
return
|
|
end
|
|
ShowUIPanel(getglobal("QuestLogFrame"))
|
|
SelectQuestLogEntry(index)
|
|
BenillaQuestLogFrame_Update()
|
|
end
|
|
]]></Script>
|
|
|
|
<Button name="QuestTimerTemplate" virtual="true">
|
|
<Size>
|
|
<AbsDimension x="140" y="16"/>
|
|
</Size>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<FontString name="$parentText" inherits="GameFontHighlightSmall">
|
|
<Anchors>
|
|
<Anchor point="TOP"/>
|
|
</Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Scripts>
|
|
<!-- ref QuestTimerFrame.xml:18-27. The tooltip names the quest the row belongs to;
|
|
GetQuestLogTitle's FIRST return only (the rest of its 6-tuple is level/tag/state). -->
|
|
<OnEnter>
|
|
local index = GetQuestIndexForTimer(self:GetID())
|
|
if index then
|
|
GameTooltip:SetOwner(self)
|
|
GameTooltip:SetText(GetQuestLogTitle(index), 1.0, 1.0, 1.0)
|
|
GameTooltip:Show()
|
|
end
|
|
</OnEnter>
|
|
<OnLeave>GameTooltip:Hide()</OnLeave>
|
|
<OnClick>QuestTimerButton_OnClick(self:GetID())</OnClick>
|
|
</Scripts>
|
|
</Button>
|
|
|
|
<Frame name="QuestTimerFrame" enableMouse="true" frameStrata="BACKGROUND" hidden="true">
|
|
<Size>
|
|
<AbsDimension x="160" y="72"/>
|
|
</Size>
|
|
<Anchors>
|
|
<Anchor point="TOPRIGHT" relativeTo="MinimapCluster" relativePoint="BOTTOMRIGHT">
|
|
<Offset>
|
|
<AbsDimension x="10" y="0"/>
|
|
</Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
|
|
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
|
|
<TileSize><AbsValue val="32"/></TileSize>
|
|
<EdgeSize><AbsValue val="32"/></EdgeSize>
|
|
</Backdrop>
|
|
<Layers>
|
|
<Layer level="ARTWORK">
|
|
<Texture name="QuestTimerHeader" file="Interface\DialogFrame\UI-DialogBox-Header">
|
|
<Size><AbsDimension x="256" y="64"/></Size>
|
|
<Anchors>
|
|
<Anchor point="TOP"><Offset><AbsDimension x="1" y="12"/></Offset></Anchor>
|
|
</Anchors>
|
|
</Texture>
|
|
<FontString inherits="GameFontNormal" text="QUEST_TIMERS">
|
|
<Anchors>
|
|
<Anchor point="TOP" relativeTo="QuestTimerHeader"><Offset><AbsDimension x="0" y="-13"/></Offset></Anchor>
|
|
</Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Frames>
|
|
<!-- The ref's twenty rows (MAX_QUESTS), first at TOP -30 and the rest flush beneath it.
|
|
Named/id'd 1..20 because both the ref's row lookup and its timer→quest mapping are
|
|
by ordinal. -->
|
|
<Button name="QuestTimer1" inherits="QuestTimerTemplate" hidden="true" id="1">
|
|
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-30"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer2" inherits="QuestTimerTemplate" hidden="true" id="2">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer1" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer3" inherits="QuestTimerTemplate" hidden="true" id="3">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer2" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer4" inherits="QuestTimerTemplate" hidden="true" id="4">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer3" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer5" inherits="QuestTimerTemplate" hidden="true" id="5">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer4" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer6" inherits="QuestTimerTemplate" hidden="true" id="6">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer5" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer7" inherits="QuestTimerTemplate" hidden="true" id="7">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer6" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer8" inherits="QuestTimerTemplate" hidden="true" id="8">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer7" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer9" inherits="QuestTimerTemplate" hidden="true" id="9">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer8" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer10" inherits="QuestTimerTemplate" hidden="true" id="10">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer9" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer11" inherits="QuestTimerTemplate" hidden="true" id="11">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer10" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer12" inherits="QuestTimerTemplate" hidden="true" id="12">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer11" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer13" inherits="QuestTimerTemplate" hidden="true" id="13">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer12" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer14" inherits="QuestTimerTemplate" hidden="true" id="14">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer13" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer15" inherits="QuestTimerTemplate" hidden="true" id="15">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer14" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer16" inherits="QuestTimerTemplate" hidden="true" id="16">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer15" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer17" inherits="QuestTimerTemplate" hidden="true" id="17">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer16" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer18" inherits="QuestTimerTemplate" hidden="true" id="18">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer17" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer19" inherits="QuestTimerTemplate" hidden="true" id="19">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer18" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
<Button name="QuestTimer20" inherits="QuestTimerTemplate" hidden="true" id="20">
|
|
<Anchors><Anchor point="TOP" relativeTo="QuestTimer19" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Button>
|
|
</Frames>
|
|
<Scripts>
|
|
<OnLoad>QuestTimerFrame_OnLoad(self)</OnLoad>
|
|
<OnUpdate>QuestTimerFrame_OnUpdate()</OnUpdate>
|
|
<OnEvent>QuestTimerFrame_OnEvent()</OnEvent>
|
|
<!-- ref :46-52 — the stack under the minimap re-flows when this window appears or goes. -->
|
|
<OnShow>UIParent_ManageFramePositions()</OnShow>
|
|
<OnHide>UIParent_ManageFramePositions()</OnHide>
|
|
</Scripts>
|
|
</Frame>
|
|
</Ui>
|