- forty files that carried the reference's literal Lua are rewritten as our own expression of the behaviour — worst identical run 61 lines down to 7 — and the README now says exactly that - the overlap gate measures the code itself across all four reference corpora, and ratchets: the number may only go down - a lost session ends at the login screen instead of silently re-authenticating and stealing the account back - a building's skybox is a real model: Caverns of Time's white ceiling becomes its painted nebula and additive stars 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" 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>
|