- 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>
558 lines
32 KiB
XML
558 lines
32 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's taxi-map window (decision 0484 phase 2), written on the taxi engine seam
|
||
(`crates/benilla-ui/src/script/taxi.rs`) fed by `crates/benilla/src/ui_taxi.rs`.
|
||
|
||
This is **our implementation**. Its specification is the real 1.12 `TaxiFrame.{xml,lua}`
|
||
(patch chain; scratchpad `ref-TaxiFrame.xml/.lua`, line citations inline as `ref l.N`): the
|
||
globals, the art paths, the geometry and the behaviour of every branch are the
|
||
specification's, because addons and the engine both address this window by those names, and
|
||
because the numbers are measurements of the shipped art (384×512, the four TaxiFrame
|
||
quadrant slabs at a 256/128 split, the 316×352 map rect at TOP -13,-75) rather than
|
||
anything for us to re-derive. How it is written is ours. The deviations below are where
|
||
THIS ENGINE, not taste, draws the line, each flagged and reasoned like every other window
|
||
of ours (Gossip/Merchant/Trainer's own header notes).
|
||
|
||
Modeled on MerchantFrame.xml/TrainerFrame.xml for the framing: the NPC-session lifecycle
|
||
(RegisterEvent pair, OPENED/CLOSED dispatch, OnShow/OnHide PlaySound with a client-side
|
||
close on hide), the "npc" model-portrait binding, the minimize-button close X (this engine
|
||
ships no UIPanelCloseButton), and the UIPanel slot system (NO hardcoded `<Anchors>` on the
|
||
root — ShowUIPanel/SetLeftFrame SetPoints it to the left slot on open, exactly like every
|
||
other NPC window).
|
||
|
||
DEVIATIONS from the literal reference, each forced by this engine (never taste):
|
||
|
||
1. NODE BUTTONS ARE A STATIC POOL, not `CreateFrame(..., "TaxiButtonTemplate")` grown on
|
||
demand (ref l.36-42/TaxiFrame.lua:36-42). This engine's runtime `CreateFrame`'s 4th
|
||
`inherits` argument is explicitly a no-op — template expansion is the XML LOADER's job
|
||
only (`benilla-ui/src/script/object.rs`'s `create_frame`: "inherits/template expansion
|
||
is the XML loader's job — ignored"). Every other list window in this codebase hits the
|
||
identical wall and solves it identically: Gossip's 8-row pool, Trainer's service-row
|
||
pool, QuestLog's row pool — a fixed set of concrete `inherits=` instances (which DOES
|
||
expand at LOAD time), shown/hidden/repositioned per repaint instead of created on
|
||
demand. `BENILLA_TAXI_MAX_NODES = 50` below comfortably covers the real 5875
|
||
`TaxiNodes.dbc`'s per-continent max (43 nodes on Eastern Kingdoms, 39 on Kalimdor —
|
||
counted this session, `crate::ui_taxi`'s module doc). The route-line textures stay
|
||
genuinely dynamic (`TaxiRouteMap:CreateTexture(...)`, ref l.101/142) — plain
|
||
region creation carries no template/inherits, so that half is created on demand exactly
|
||
as specified.
|
||
2. THE TITLE READS AN EVENT ARG, not `UnitName("npc")` (ref TaxiFrame.lua:27). This
|
||
engine's `"npc"` unit token (decision 0421) only feeds the PORTRAIT bake — there is no
|
||
backing `UnitState` for `UnitName` to read from it. Gossip/Merchant/Trainer hit the
|
||
identical gap and all solve it the same way: the app resolves the flight master's name
|
||
through the `NameCache` and rides it in as the open event's arg1 — done here too
|
||
(`BenillaTaxiFrame_SetTitle`, fed by `TAXIMAP_OPENED`'s arg1).
|
||
3. (Retired.) The "no single-hop destination" refusal (`DrawOneHopLines`, ref l.161-164)
|
||
used to call a plain `BenillaErrorsFrame_AddMessage` global because this engine had no
|
||
MessageFrame widget for `UIErrorsFrame` to be. It has one now, so the refusal below posts
|
||
to `UIErrorsFrame` under the specified name. `ErrorsFrame.xml` loads well before this file
|
||
in the shipped list (`ui_script/mod.rs`), so the frame already exists by the time this
|
||
ever runs.
|
||
|
||
`<TaxiRouteFrame>` (an intrinsic type this engine doesn't have) becomes a plain `<Frame>`
|
||
(`TaxiRouteMap`) per the house rule for every non-shipped intrinsic (decision 0246's
|
||
patch-chain rule; the `Cooldown`/`GameTooltip`/etc. precedents) — it carries no behavior of
|
||
its own beyond being a Frame that owns child regions/buttons, so the plain type loses
|
||
nothing.
|
||
|
||
Money (the fare) renders as plain text via `SetTooltipMoney` on the shared `GameTooltip`
|
||
(`GameTooltip.xml`'s own seam) exactly as specified — no `BenillaMoney_*` coin rig needed
|
||
here (that lives on the merchant/trainer purse displays, a different job).
|
||
-->
|
||
<Script><![CDATA[
|
||
-- The continent map's size in pixels — a published pair, because scaling a node's
|
||
-- normalised position onto the map needs them and so does anything that wants to put its own
|
||
-- marker there. The values are the specification's (ref TaxiFrame.lua:2-3): a measurement of
|
||
-- the shipped map art.
|
||
TAXI_MAP_WIDTH = 316
|
||
TAXI_MAP_HEIGHT = 352
|
||
|
||
-- The static node-button pool's size — see deviation 1 above.
|
||
BENILLA_TAXI_MAX_NODES = 50
|
||
|
||
-- What each node state draws (ref TaxiFrame.lua:7-16): CURRENT green, REACHABLE white,
|
||
-- DISTANT yellow — all three art files verified present in the MPQ. Published as a table of
|
||
-- `{ file = }` keyed by the state string `TaxiNodeGetType` answers, which is both the shape
|
||
-- the node paint below reads and the shape an addon adding a state of its own writes.
|
||
TaxiButtonTypes = {
|
||
CURRENT = { file = "Interface\\TaxiFrame\\UI-Taxi-Icon-Green" },
|
||
REACHABLE = { file = "Interface\\TaxiFrame\\UI-Taxi-Icon-White" },
|
||
DISTANT = { file = "Interface\\TaxiFrame\\UI-Taxi-Icon-Yellow" },
|
||
}
|
||
|
||
-- The two strings this window shows, byte-exact from the 1.12 enUS GlobalStrings
|
||
-- (interface.MPQ `GlobalStrings.lua`, line-cited) — user-visible text, so its bytes are the
|
||
-- spec, not our expression. `TEXT(x)` (ref l.121) is the real client's build-time no-op
|
||
-- localization macro, so every `TEXT(FOO)` resolves to the bare `FOO` global
|
||
-- (CharacterFrame.xml's own convention); with no engine `TEXT` global at all, and nothing
|
||
-- outside this window reading either string, they are plain locals here instead.
|
||
local TAXINODEYOUAREHERE = "You are here" -- GlobalStrings.lua:4232
|
||
-- GlobalStrings.lua:1864 — the reference's own byte, including its curly apostrophe
|
||
-- (U+2019, "don\226\128\153t"), not a straight one.
|
||
local ERR_TAXINOPATHS = "You don\226\128\153t know any flight locations connected to this one."
|
||
|
||
function TaxiFrame_OnLoad()
|
||
local frame = this
|
||
-- The "npc" portrait token (decision 0421): the open taxi session's flight master
|
||
-- bakes into the ring, resolved exactly like Gossip/Merchant/Trainer's own OnLoad.
|
||
SetPortraitTexture(getglobal(frame:GetName() .. "Portrait"), "npc")
|
||
frame:RegisterEvent("TAXIMAP_OPENED")
|
||
frame:RegisterEvent("TAXIMAP_CLOSED")
|
||
end
|
||
|
||
-- Deviation 2 above: the flight master's name rides TAXIMAP_OPENED's arg1 (the app
|
||
-- resolves it through the NameCache) rather than a live UnitName("npc") read.
|
||
function BenillaTaxiFrame_SetTitle(name)
|
||
getglobal("TaxiNameText"):SetText(name or "")
|
||
end
|
||
|
||
-- Paint the node buttons (ref l.44-63): every pool slot up to the pushed node count takes
|
||
-- that node's state icon and its pushed position, and the rest of the pool hides. Positions
|
||
-- arrive normalised 0..1 from the map's BOTTOMLEFT, which is what the map size above scales.
|
||
local function PaintNodes()
|
||
local pushed = NumTaxiNodes()
|
||
for index = 1, BENILLA_TAXI_MAX_NODES do
|
||
local button = getglobal("TaxiButton" .. index)
|
||
local state = TaxiNodeGetType(index)
|
||
if index <= pushed and state ~= "NONE" then
|
||
local x, y = TaxiNodePosition(button:GetID())
|
||
button:ClearAllPoints()
|
||
button:SetPoint("CENTER", "TaxiMap", "BOTTOMLEFT", x * TAXI_MAP_WIDTH, y * TAXI_MAP_HEIGHT)
|
||
button:SetNormalTexture(TaxiButtonTypes[state].file)
|
||
button:Show()
|
||
else
|
||
button:Hide()
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Opening and closing the window (ref TaxiFrame.lua:24-80). Opening repaints everything from
|
||
-- the pushed snapshot and then asks the panel manager for a slot; if it will not give one,
|
||
-- the session is closed again rather than left running behind a window nobody can see.
|
||
function TaxiFrame_OnEvent(event)
|
||
local frame = this
|
||
if event == "TAXIMAP_OPENED" then
|
||
BenillaTaxiFrame_SetTitle(arg1)
|
||
-- Reset the map's sampling, then hand the region to the app's continent-art pick.
|
||
TaxiMap:SetTexCoord(0, 1, 0, 1)
|
||
SetTaxiMap(TaxiMap)
|
||
PaintNodes()
|
||
ShowUIPanel(frame)
|
||
if not frame:IsVisible() then
|
||
CloseTaxiMap()
|
||
end
|
||
return
|
||
end
|
||
if event == "TAXIMAP_CLOSED" then
|
||
HideUIPanel(frame)
|
||
return
|
||
end
|
||
end
|
||
|
||
-- ── The route-line pool ──────────────────────────────────────────────────────────────────
|
||
--
|
||
-- A flight path draws as a chain of straight segments, one texture per segment. Those
|
||
-- textures are a pool that grows to the longest chain ever asked for and is never shrunk:
|
||
-- `NUM_TAXI_ROUTES` is how many exist and `TaxiRoute<n>` is each one's global name — both
|
||
-- published, since the count is a global the specification exports and the names are what
|
||
-- `getglobal` finds. Unlike the node buttons, this half really is created on demand: plain
|
||
-- region creation carries no template, so deviation 1's CreateFrame wall never applies.
|
||
NUM_TAXI_ROUTES = 0
|
||
|
||
-- Grow the pool to hold at least `n` lines; answer what it holds.
|
||
local function GrowRoutePool(n)
|
||
while NUM_TAXI_ROUTES < n do
|
||
NUM_TAXI_ROUTES = NUM_TAXI_ROUTES + 1
|
||
local line = TaxiRouteMap:CreateTexture("TaxiRoute" .. NUM_TAXI_ROUTES, "BACKGROUND")
|
||
line:SetTexture("Interface\\TaxiFrame\\UI-Taxi-Line")
|
||
end
|
||
return NUM_TAXI_ROUTES
|
||
end
|
||
|
||
-- Draw one line per `{ node, hop }` in `segments`, and hide whatever the pool holds beyond
|
||
-- them. Each hop's endpoints arrive normalised on the map, so they scale by the canvas the
|
||
-- lines live on. 32 is the specified line thickness (ref l.114/153), in those same pixels.
|
||
local function PaintRoutes(segments)
|
||
local count = table.getn(segments)
|
||
local pool = GrowRoutePool(count)
|
||
local w = TaxiRouteMap:GetWidth()
|
||
local h = TaxiRouteMap:GetHeight()
|
||
for i = 1, pool do
|
||
local line = getglobal("TaxiRoute" .. i)
|
||
if i <= count then
|
||
local node, hop = segments[i][1], segments[i][2]
|
||
DrawRouteLine(line, "TaxiRouteMap",
|
||
TaxiGetSrcX(node, hop) * w, TaxiGetSrcY(node, hop) * h,
|
||
TaxiGetDestX(node, hop) * w, TaxiGetDestY(node, hop) * h, 32)
|
||
line:Show()
|
||
else
|
||
line:Hide()
|
||
end
|
||
end
|
||
end
|
||
|
||
-- The tooltip, and the route, for the node under the cursor (ref TaxiFrame.lua:82-126). A
|
||
-- reachable node prices the flight and draws every hop of it; the node we are standing on
|
||
-- says so and draws the whole neighbourhood instead.
|
||
--
|
||
-- `this:GetID()` in the fare read is the SAME button as the `button` parameter — the engine
|
||
-- binds the shared `this` global to the invoking frame before OnEnter runs (decision 0068's
|
||
-- event-dispatch convention), exactly like the real client, so the two reads agree.
|
||
function TaxiNodeOnButtonEnter(button)
|
||
local index = button:GetID()
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
GameTooltip:AddLine(TaxiNodeName(index), "", 1.0, 1.0, 1.0)
|
||
|
||
local state = TaxiNodeGetType(index)
|
||
if state == "REACHABLE" then
|
||
SetTooltipMoney(GameTooltip, TaxiNodeCost(this:GetID()))
|
||
TaxiNodeSetCurrent(index)
|
||
local hops = { }
|
||
for hop = 1, GetNumRoutes(index) do
|
||
hops[hop] = { index, hop }
|
||
end
|
||
PaintRoutes(hops)
|
||
elseif state == "CURRENT" then
|
||
GameTooltip:AddLine(TAXINODEYOUAREHERE, "", 0.5, 1.0, 0.5)
|
||
DrawOneHopLines()
|
||
end
|
||
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
-- Every flight path within one hop of where we stand (ref TaxiFrame.lua:129-165) — what the
|
||
-- map shows the moment it opens, before anything is hovered. A node exactly one segment away
|
||
-- is one this flight master can send us to directly.
|
||
function DrawOneHopLines()
|
||
local hops = { }
|
||
for node = 1, NumTaxiNodes() do
|
||
if GetNumRoutes(node) == 1 then
|
||
table.insert(hops, { node, 1 })
|
||
end
|
||
end
|
||
PaintRoutes(hops)
|
||
|
||
-- A flight point with nothing one hop away is a dead end: say so, and take the window
|
||
-- back down rather than leave an empty map up.
|
||
if table.getn(hops) == 0 then
|
||
UIErrorsFrame:AddMessage(ERR_TAXINOPATHS, 1.0, 0.1, 0.1)
|
||
HideUIPanel(TaxiFrame)
|
||
end
|
||
end
|
||
|
||
|
||
-- ── Route lines ───────────────────────────────────────────────────────────────────────
|
||
--
|
||
-- A flight path is one straight line between two map points, drawn as a texture. The
|
||
-- engine can only place an AXIS-ALIGNED rectangle, so the rotation has to live in the
|
||
-- texture coordinates instead: SetTexCoord's 8-argument form places each of the four
|
||
-- source corners independently, which is exactly enough to spin (and shear) the art
|
||
-- inside its bounding box. The bounding box then has to grow to hold the rotated line.
|
||
--
|
||
-- The geometry — how a rotation angle turns into those four corners and that box — is
|
||
-- the specification, and it is the reference's (ref TaxiFrame.lua:168-226; the credit
|
||
-- their copy carries is to Daniel Stephens <iriel@vigilance-committee.org>). Every value
|
||
-- below is theirs, and the multiplications are grouped the way theirs are so the rounding
|
||
-- matches; how it is written — the naming, the shear terms hoisted out of both branches,
|
||
-- the anchoring helper — is ours. The reference derives each corner from the last
|
||
-- (`BRx = 1 - BLy`, `TRy = BRx`, …); we state each one directly instead, which is the
|
||
-- same number everywhere but one: the downward branch's top-left U is `-shearU` here
|
||
-- against their `1 - (1 + shearU)`. MEASURED, both implementations run side by side on
|
||
-- the real Lua 5.1 over 50k randomised segments plus the degenerate/axis-aligned/reversed
|
||
-- edges: every anchor identical to the last bit, and every texture coordinate identical
|
||
-- once narrowed to f32 — which the engine does to all eight on the way in
|
||
-- (`region::paint`'s `Variadic<f32>`). The lone survivor is the SIGN OF ZERO on an exactly
|
||
-- vertical downward line, where that corner is -0 here and +0 there: the same coordinate,
|
||
-- and the same sample.
|
||
--
|
||
-- Engine seam, all three proved by the phase-1 seam test: CreateTexture, SetTexCoord's
|
||
-- 8-arg form, and SetPoint against a canvas named by string.
|
||
|
||
-- The reference's two scale globals, value for value. Only the halved one is ever read —
|
||
-- by the bounding-box extents below, which are half-widths, hence the /2; the whole one
|
||
-- is a published global that nothing in the reference reads either. 32/30 is unexplained
|
||
-- there and carried unchanged here — a measurement of the shipped art, not ours to
|
||
-- re-derive.
|
||
TAXIROUTE_LINEFACTOR = 32/30
|
||
TAXIROUTE_LINEFACTOR_2 = TAXIROUTE_LINEFACTOR / 2
|
||
|
||
-- Seat `texture` as the box centred on (cx, cy) that reaches `halfW` / `halfH` out along
|
||
-- each axis, measured from `canvas`'s `relPoint` corner. Both ends always move together,
|
||
-- so clearing first is what keeps a stale anchor from outliving a move. (The reference
|
||
-- re-seats the two points without clearing on its degenerate path; a route texture only
|
||
-- ever holds these two anchors and SetPoint replaces one of the same name, so the box
|
||
-- that comes out is the same either way.)
|
||
local function AnchorCenteredBox(texture, canvas, relPoint, cx, cy, halfW, halfH)
|
||
texture:ClearAllPoints()
|
||
texture:SetPoint("BOTTOMLEFT", canvas, relPoint, cx - halfW, cy - halfH)
|
||
texture:SetPoint("TOPRIGHT", canvas, relPoint, cx + halfW, cy + halfH)
|
||
end
|
||
|
||
-- Draw the segment (sx,sy) -> (ex,ey), `width` thick, into `texture`, placed against
|
||
-- `canvas` in the coordinate space of its `relPoint` corner (BOTTOMLEFT by default).
|
||
function DrawRouteLine(texture, canvas, sx, sy, ex, ey, width, relPoint)
|
||
relPoint = relPoint or "BOTTOMLEFT"
|
||
|
||
local dx, dy = ex - sx, ey - sy
|
||
local cx, cy = (sx + ex) / 2, (sy + ey) / 2
|
||
|
||
-- A segment drawn back-to-front is the same segment: face it rightwards so only the
|
||
-- two upward/downward cases below have to exist.
|
||
if dx < 0 then
|
||
dx, dy = -dx, -dy
|
||
end
|
||
|
||
local len = sqrt((dx * dx) + (dy * dy))
|
||
if len == 0 then
|
||
-- Nothing to draw: collapse the quad onto its own midpoint and show no art.
|
||
texture:SetTexCoord(0, 0, 0, 0, 0, 0, 0, 0)
|
||
AnchorCenteredBox(texture, canvas, relPoint, cx, cy, 0, 0)
|
||
return
|
||
end
|
||
|
||
-- Sine and cosine of the segment's angle, and the two shear terms every corner is
|
||
-- built from — one walking the texture's horizontal axis, one its vertical axis.
|
||
local sinA, cosA = -dy / len, dx / len
|
||
local sinSq = sinA * sinA
|
||
local shear = sinA * cosA
|
||
local shearU = (width / len) * shear
|
||
local shearV = (len / width) * shear
|
||
|
||
-- Half the bounding box the rotated line needs, and the four source corners that lay
|
||
-- the art across it. Upward and downward are the same algebra mirrored: the four
|
||
-- quantities are the same, and which corner each lands on is what flips.
|
||
local halfW, halfH
|
||
local blU, blV, tlU, tlV, trU, trV, brU, brV
|
||
if dy >= 0 then
|
||
halfW = ((len * cosA) - (width * sinA)) * TAXIROUTE_LINEFACTOR_2
|
||
halfH = ((width * cosA) - (len * sinA)) * TAXIROUTE_LINEFACTOR_2
|
||
blU, blV = shearU, sinSq
|
||
tlU, tlV = sinSq, 1 - shearV
|
||
trU, trV = 1 - shearU, 1 - sinSq
|
||
brU, brV = 1 - sinSq, shearV
|
||
else
|
||
halfW = ((len * cosA) + (width * sinA)) * TAXIROUTE_LINEFACTOR_2
|
||
halfH = ((width * cosA) + (len * sinA)) * TAXIROUTE_LINEFACTOR_2
|
||
blU, blV = sinSq, -shearV
|
||
tlU, tlV = -shearU, 1 - sinSq
|
||
trU, trV = 1 - sinSq, 1 + shearV
|
||
brU, brV = 1 + shearU, sinSq
|
||
end
|
||
|
||
-- SetTexCoord's corner order is top-left, bottom-left, top-right, bottom-right.
|
||
texture:SetTexCoord(tlU, tlV, blU, blV, trU, trV, brU, brV)
|
||
AnchorCenteredBox(texture, canvas, relPoint, cx, cy, halfW, halfH)
|
||
end
|
||
|
||
-- Appearing and disappearing. The sounds are the MainMenu pair, not the CharacterInfo pair
|
||
-- Merchant/Trainer use — the specification genuinely names a different one for this window
|
||
-- (ref l.162-169). Showing also draws the neighbourhood straight away, so an untouched map
|
||
-- is not blank; hiding ends the session, which is what fires TAXIMAP_CLOSED back at us.
|
||
function BenillaTaxiFrame_OnShow()
|
||
PlaySound("igMainMenuOpen")
|
||
DrawOneHopLines()
|
||
end
|
||
|
||
function BenillaTaxiFrame_OnHide()
|
||
CloseTaxiMap()
|
||
PlaySound("igMainMenuClose")
|
||
end
|
||
|
||
function BenillaTaxiCloseButton_OnClick()
|
||
-- vanilla's client-side close sends no packet; the app clears TaxiState on this
|
||
-- intent (which fires TAXIMAP_CLOSED), and we hide immediately so there's no lag.
|
||
CloseTaxiMap()
|
||
HideUIPanel(TaxiFrame)
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
The node-button pool's virtual template (ref TaxiButtonTemplate, l.4-32): a 16×16 button,
|
||
the state icon assigned per repaint via SetNormalTexture (deviation 1's static pool — see
|
||
the header note), the 32×32 CENTER highlight glow. The three handlers dispatch to the same
|
||
three verbs the specification's do (l.12-20) — including the click firing UNCONDITIONALLY
|
||
regardless of node state (a DISTANT/CURRENT click still queues TakeTaxiNode; the app-side
|
||
drain treats a routeless click as a no-op — there is no RE'd finding for what the real
|
||
client's native TakeTaxiNode does with an unreachable index, so this is the safe,
|
||
undocumented-but-reasonable inference, not an asserted fact).
|
||
-->
|
||
<Button name="BenillaTaxiButtonTemplate" hidden="true" virtual="true">
|
||
<Size>
|
||
<AbsDimension x="16" y="16"/>
|
||
</Size>
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT"/>
|
||
</Anchors>
|
||
<Scripts>
|
||
<OnEnter>
|
||
TaxiNodeOnButtonEnter(this)
|
||
</OnEnter>
|
||
<OnLeave>
|
||
GameTooltip:Hide()
|
||
</OnLeave>
|
||
<OnClick>
|
||
TakeTaxiNode(this:GetID())
|
||
</OnClick>
|
||
</Scripts>
|
||
<HighlightTexture file="Interface\TaxiFrame\UI-Taxi-Icon-Highlight">
|
||
<Size x="32" y="32"/>
|
||
<Anchors>
|
||
<Anchor point="CENTER">
|
||
<Offset>
|
||
<AbsDimension x="0" y="0"/>
|
||
</Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
</HighlightTexture>
|
||
</Button>
|
||
|
||
<Frame name="TaxiFrame" enableMouse="true" toplevel="true" parent="UIParent" hidden="true">
|
||
<!-- The real 384×512 window (ref l.34-36). No <Anchors> — ShowUIPanel/SetLeftFrame
|
||
SetPoints this to the left slot on open, exactly like Gossip/Merchant/Trainer. -->
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Layers>
|
||
<!-- NPC portrait 58×58 TOPLEFT (8,-9) (ref TaxiPortrait, l.46-57), BACKGROUND —
|
||
drawn under the ARTWORK quadrant slabs below so their frame art rings it. -->
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentPortrait">
|
||
<Size><AbsDimension x="58" y="58"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="8" y="-9"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<!-- The four TaxiFrame quadrant slabs that ARE the window art (ref l.59-103): 256-wide
|
||
left halves, 128-wide right halves, each 256 tall, pinned to their corner. No
|
||
<TexCoords> — each samples its whole texture. -->
|
||
<Layer level="ARTWORK">
|
||
<Texture file="Interface\TaxiFrame\UI-TaxiFrame-TopLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\TaxiFrame\UI-TaxiFrame-TopRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="0"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\TaxiFrame\UI-TaxiFrame-BotLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="-256"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\TaxiFrame\UI-TaxiFrame-BotRight">
|
||
<Size><AbsDimension x="128" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="-256"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<!-- The flight master's name banner (ref TaxiMerchant, l.104-115): GameFontNormal,
|
||
CENTER, TOP -17, 192 wide — deviation 2 above (arg1, not UnitName("npc")). -->
|
||
<FontString name="TaxiNameText" inherits="GameFontNormal" justifyH="CENTER">
|
||
<Size><AbsDimension x="192" y="0"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOP"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
<!-- The continent map art (ref TaxiMap, l.117-129): 316×352, TOP -13,-75. No file —
|
||
SetTaxiMap assigns the app's TAXIMAP<continentId> pick (byte-verified — decision 0496). -->
|
||
<Layer level="OVERLAY">
|
||
<Texture name="TaxiMap">
|
||
<Size><AbsDimension x="316" y="352"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOP"><Offset><AbsDimension x="-13" y="-75"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Close: the real UIPanelCloseButton position (TOPRIGHT -29,-8; ref l.133-141), on
|
||
the minimize-button art (this engine ships no UIPanelCloseButton — the Gossip/
|
||
Trainer/Merchant precedent). -->
|
||
<Button name="TaxiCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT"><Offset><AbsDimension x="-29" y="-8"/></Offset></Anchor>
|
||
</Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts><OnClick>BenillaTaxiCloseButton_OnClick()</OnClick></Scripts>
|
||
</Button>
|
||
|
||
<!-- `<TaxiRouteFrame>` (ref l.142-153) — an intrinsic type this engine doesn't have —
|
||
becomes a plain <Frame> (see the header note): 316×352, TOP -13,-75, exactly
|
||
overlaid on TaxiMap. Houses the node-button pool + the dynamically-created
|
||
route-line textures, both parented here exactly like the reference (ref l.39,101). -->
|
||
<Frame name="TaxiRouteMap">
|
||
<Size><AbsDimension x="316" y="352"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOP"><Offset><AbsDimension x="-13" y="-75"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Frames>
|
||
<Button name="TaxiButton1" inherits="BenillaTaxiButtonTemplate" id="1"/>
|
||
<Button name="TaxiButton2" inherits="BenillaTaxiButtonTemplate" id="2"/>
|
||
<Button name="TaxiButton3" inherits="BenillaTaxiButtonTemplate" id="3"/>
|
||
<Button name="TaxiButton4" inherits="BenillaTaxiButtonTemplate" id="4"/>
|
||
<Button name="TaxiButton5" inherits="BenillaTaxiButtonTemplate" id="5"/>
|
||
<Button name="TaxiButton6" inherits="BenillaTaxiButtonTemplate" id="6"/>
|
||
<Button name="TaxiButton7" inherits="BenillaTaxiButtonTemplate" id="7"/>
|
||
<Button name="TaxiButton8" inherits="BenillaTaxiButtonTemplate" id="8"/>
|
||
<Button name="TaxiButton9" inherits="BenillaTaxiButtonTemplate" id="9"/>
|
||
<Button name="TaxiButton10" inherits="BenillaTaxiButtonTemplate" id="10"/>
|
||
<Button name="TaxiButton11" inherits="BenillaTaxiButtonTemplate" id="11"/>
|
||
<Button name="TaxiButton12" inherits="BenillaTaxiButtonTemplate" id="12"/>
|
||
<Button name="TaxiButton13" inherits="BenillaTaxiButtonTemplate" id="13"/>
|
||
<Button name="TaxiButton14" inherits="BenillaTaxiButtonTemplate" id="14"/>
|
||
<Button name="TaxiButton15" inherits="BenillaTaxiButtonTemplate" id="15"/>
|
||
<Button name="TaxiButton16" inherits="BenillaTaxiButtonTemplate" id="16"/>
|
||
<Button name="TaxiButton17" inherits="BenillaTaxiButtonTemplate" id="17"/>
|
||
<Button name="TaxiButton18" inherits="BenillaTaxiButtonTemplate" id="18"/>
|
||
<Button name="TaxiButton19" inherits="BenillaTaxiButtonTemplate" id="19"/>
|
||
<Button name="TaxiButton20" inherits="BenillaTaxiButtonTemplate" id="20"/>
|
||
<Button name="TaxiButton21" inherits="BenillaTaxiButtonTemplate" id="21"/>
|
||
<Button name="TaxiButton22" inherits="BenillaTaxiButtonTemplate" id="22"/>
|
||
<Button name="TaxiButton23" inherits="BenillaTaxiButtonTemplate" id="23"/>
|
||
<Button name="TaxiButton24" inherits="BenillaTaxiButtonTemplate" id="24"/>
|
||
<Button name="TaxiButton25" inherits="BenillaTaxiButtonTemplate" id="25"/>
|
||
<Button name="TaxiButton26" inherits="BenillaTaxiButtonTemplate" id="26"/>
|
||
<Button name="TaxiButton27" inherits="BenillaTaxiButtonTemplate" id="27"/>
|
||
<Button name="TaxiButton28" inherits="BenillaTaxiButtonTemplate" id="28"/>
|
||
<Button name="TaxiButton29" inherits="BenillaTaxiButtonTemplate" id="29"/>
|
||
<Button name="TaxiButton30" inherits="BenillaTaxiButtonTemplate" id="30"/>
|
||
<Button name="TaxiButton31" inherits="BenillaTaxiButtonTemplate" id="31"/>
|
||
<Button name="TaxiButton32" inherits="BenillaTaxiButtonTemplate" id="32"/>
|
||
<Button name="TaxiButton33" inherits="BenillaTaxiButtonTemplate" id="33"/>
|
||
<Button name="TaxiButton34" inherits="BenillaTaxiButtonTemplate" id="34"/>
|
||
<Button name="TaxiButton35" inherits="BenillaTaxiButtonTemplate" id="35"/>
|
||
<Button name="TaxiButton36" inherits="BenillaTaxiButtonTemplate" id="36"/>
|
||
<Button name="TaxiButton37" inherits="BenillaTaxiButtonTemplate" id="37"/>
|
||
<Button name="TaxiButton38" inherits="BenillaTaxiButtonTemplate" id="38"/>
|
||
<Button name="TaxiButton39" inherits="BenillaTaxiButtonTemplate" id="39"/>
|
||
<Button name="TaxiButton40" inherits="BenillaTaxiButtonTemplate" id="40"/>
|
||
<Button name="TaxiButton41" inherits="BenillaTaxiButtonTemplate" id="41"/>
|
||
<Button name="TaxiButton42" inherits="BenillaTaxiButtonTemplate" id="42"/>
|
||
<Button name="TaxiButton43" inherits="BenillaTaxiButtonTemplate" id="43"/>
|
||
<Button name="TaxiButton44" inherits="BenillaTaxiButtonTemplate" id="44"/>
|
||
<Button name="TaxiButton45" inherits="BenillaTaxiButtonTemplate" id="45"/>
|
||
<Button name="TaxiButton46" inherits="BenillaTaxiButtonTemplate" id="46"/>
|
||
<Button name="TaxiButton47" inherits="BenillaTaxiButtonTemplate" id="47"/>
|
||
<Button name="TaxiButton48" inherits="BenillaTaxiButtonTemplate" id="48"/>
|
||
<Button name="TaxiButton49" inherits="BenillaTaxiButtonTemplate" id="49"/>
|
||
<Button name="TaxiButton50" inherits="BenillaTaxiButtonTemplate" id="50"/>
|
||
</Frames>
|
||
</Frame>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>
|
||
TaxiFrame_OnLoad()
|
||
</OnLoad>
|
||
<OnEvent>
|
||
TaxiFrame_OnEvent(event)
|
||
</OnEvent>
|
||
<OnShow>
|
||
BenillaTaxiFrame_OnShow()
|
||
</OnShow>
|
||
<OnHide>
|
||
BenillaTaxiFrame_OnHide()
|
||
</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|