- the select screen's ghost is four mechanisms off one roster-row bit, and the rest of them land: the FFX pass swap — the reference builds TWO pass pairs, world and glue, and a ghost row installs the glue DEATH pass over the whole diorama while the character list and buttons composite clean above it; the ghost-gated sun — the scene's light gather is wiped and one hardcoded overhead directional injected, its colours turning out to be Light.dbc's death preset (diffuse (94,153,198), ambient (26,56,85)) rather than the live capture we had parked them as, with the sign settled at the bytes (an authored light already carries one negation, so reusing that convention lights the ghost from underneath); and three glow weights corrected — the glue screens pin 0.30 login / 0.40 living select / 0.15 ghost where we rendered a flat 0.5 everywhere, so login and create get slightly less glow too, a fidelity correction to a value we had never verified - a press brings its window to the front: the mouse-DOWN handler raises the capture-or-hover frame unguarded, the toplevel gate living inside the worker — which is what makes a click on a child raise the window that owns it — and the release never raises; behind it, a frame-by-frame diff against the reference put back what the transcription dropped: toplevel on 47 frames (without it every raise trigger was a silent no-op across the whole interface), the mouse on 16 window bodies (a click on the bank's or merchant's own background was turning the camera or dropping your target), and id= on 81 frames — the slot index a 1.12 addon reads, where GetID() answered 0; a new gate reads our flags off the LOADED engine against the reference's, both directions with a reason each, so the next drift can't hide behind renamed templates - the jump stops being frame-rate dependent: the fall step becomes the reference's closed form (the mean of the endpoint velocities is the exact displacement rate, and both our movers had the error in opposite directions), taking the apex from 1.668 yd at 144 fps and 1.844 at 20 to a flat 1.640 against the analytic 1.640 — a live run apexed at 1.6410; and the knockback's freeze is its PLANTED direction bit, not a velocity test — air control opens exactly while the direction nibble is clear, the launch plants forward whatever its speed, and the bit now rides the wire, which we had never sent at all - the walk-away leash belongs to the OBJECT: the reference's watchdog overwrites the opener's stored range on the player typemask bit alone with (10+4)², so a player-shared quest panel is leashed at 14 yards — not at the 5.56-yard NPC reach, and not never, as two earlier readings had it — while a census of all 14 arming sites confirms every other NPC window already closed at the right distance; the walk-away also sends strictly LESS than the button: an NPC panel closes silently while a share still owes its decline 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" toplevel="true" parent="UIParent" 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>
|