A from-scratch World of Warcraft 1.12.1 client in Rust + Bevy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
959 lines
56 KiB
XML
959 lines
56 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's player + target unit frames (decision 0068 slice-1 game shell), RE-SKINNED to the
|
||
real 1.12 UI-TargetingFrame art + geometry (dressing arc, decision 0084). The geometry below
|
||
is QUOTED from the real FrameXML (scratchpad ref-PlayerFrame.xml, ref-TargetFrame.xml; line
|
||
citations inline), turned onto our own snapshot → Unit* → event data flow. The player and
|
||
target are horizontal MIRRORS of one shared art (Interface\TargetingFrame\UI-TargetingFrame):
|
||
the player samples it flipped (portrait window on the LEFT), the target un-flipped (window on
|
||
the RIGHT). The mirror is a `<TexCoords left> right`; it reaches the vertex buffer un-normalized
|
||
via the engine's UvRect (see crates/benilla/src/ui_pass.rs).
|
||
|
||
LAYERING (matches the ref's structure). The draw order must be trough < bars < ring art < text:
|
||
the frame's metal well-edges overlap the bar edges so the bars read RECESSED, not pasted on top.
|
||
The ref gets this with a child `TargetFrameTextureFrame` (ring art) and `SetFrameLevel(bar,
|
||
textureFrame-1)` to push the bars beneath it. Our z-model tie-breaks a `(strata, level)` bucket by
|
||
frame *insertion* order (crates/benilla-ui/src/order.rs), so we get the same result structurally
|
||
and without SetFrameLevel: the parent holds trough + portrait (+ target's name plate) in
|
||
BACKGROUND; the `$parentHealthBar`/`$parentPowerBar` StatusBars come next; then
|
||
`$parentTextureFrame` (232×100, filling the parent) holds the ring art (BACKGROUND) + name/level/dead text
|
||
(OVERLAY), declared LAST so it draws over the bar edges and the portrait. The ring's art is a THIN
|
||
band with transparent corners (not an opaque surround), so the square is hidden by the portrait
|
||
itself — set via SetPortraitToTexture, masked to its inscribed circle (the client's portraits are
|
||
always round: a model render or a circular-cropped icon), so no corner reaches the ring's gap. The
|
||
text lives under the TextureFrame, so its globals carry the `…TextureFrame…` name prefix (OnLoad).
|
||
The shared black `…Background` trough sits behind the unfilled bar portion.
|
||
|
||
DATA FLOW UNCHANGED (pin: re-anchor + re-skin, don't rewrite the eventing): BenillaUnitFrame_*
|
||
handlers, the power-color table, hide-on-nonexistent-unit. Names resolve asynchronously through
|
||
the name-query cache (UNIT_NAME_UPDATE repaints). A powerless unit (maxPower 0) hides its power
|
||
bar, as the real frames do. The target frame's "DEAD" text shows when the target's health hits
|
||
zero (ref TargetFrame_CheckDead, ref-TargetFrame.lua l.220-228).
|
||
|
||
DEVIATIONS (noted, not bugs):
|
||
- Portrait: the live model bake (SetPortraitTexture(region, unit) → crates/benilla/src/portrait.rs),
|
||
the modern high-res 2D take on the ref's low-res model snapshot (director's call; wow-re
|
||
portrait RE §5-verified). Circle-cut at draw (ui_quad.wgsl, the ref's stencil shape); the
|
||
TemporaryPortrait stand-in shows while a model streams in; the bake poses a fresh
|
||
instance at Stand through the model's authored portrait camera, helms/shoulders/held
|
||
items riding their bones (portrait/).
|
||
- Bar value FontStrings (ref-PlayerFrame.xml l.79-96) are omitted — the real client hides them
|
||
unless the statusText CVar is set; we match the default look.
|
||
- TargetFrameNameBackground (the level plate) is faction-tinted (TargetFrame_CheckFaction,
|
||
ref-TargetFrame.lua l.144-191). A PLAYER-controlled target takes the player branch (red when
|
||
mutually hostile, else blue — a friendly player is BLUE, never the reaction green); an NPC
|
||
takes the reaction swatch, resolved from the same faction-template / reputation decode the
|
||
selection ring uses (ui_unit.rs → UnitState.reaction → UnitReaction). DEFERRED (no PvP/tap
|
||
wire): the player branch's two middle legs — yellow "attackable but not hostile" (l.158) and
|
||
green "assist + PvP-flagged" (l.163) — and the tapped-by-other grey (l.176); they collapse
|
||
into red/blue, correct for every same-/opposite-faction player. The ref gates the player
|
||
branch on UnitPlayerControlled (which also covers pets); we resolve its player half via
|
||
UnitIsPlayer, so a player-controlled PET takes the NPC reaction branch until that flag lands.
|
||
- The classification border swap (elite/rare art, ref-TargetFrame.lua l.205-218) is a named
|
||
gap: the creature `rank` DOES surface now (the query's record caches it — names.rs, the
|
||
tooltip's rank word and the plate's world-boss skull read it), but UnitClassification is
|
||
not yet bound and the elite/rare border art swap is unbuilt.
|
||
- The level slot runs the full CheckLevel law (ref-TargetFrame.lua l.119-142, transcribed in
|
||
Update below): corpse or "can't tell" (UnitLevel ≤ 0) → the HighLevelTexture skull;
|
||
otherwise the number, GetDifficultyColor-tinted when attackable, gold when not.
|
||
- OUT (no wire / future arcs): PVP/leader/master/rest/attack icons, group indicator, dropdowns,
|
||
hit indicators, raid target icon, playtime, target-of-target.
|
||
|
||
TARGET AURA ROWS (0255's deferred slice): 5 buffs / 16 debuffs under the frame, geometry +
|
||
law QUOTED from ref-TargetFrame.xml (button templates l.26-87, instances l.293-481) and
|
||
TargetDebuffButton_Update (ref-TargetFrame.lua l.263-387): friend ⇒ buff row first, else
|
||
debuffs first and buffs below row 2; icons 21px shrinking to 17 when the debuff count
|
||
reaches the wrap; dispel-tinted UI-Debuff-Overlays border; stack count above 1; NO timers
|
||
(the 1.12 wire carries no duration for another unit — byte-verified, decision 0257 B6). The
|
||
list UnitBuff/UnitDebuff enumerate for the target is the app's straight descriptor read,
|
||
ascending raw slot within the half — the verified other-unit law (0257) — so icons sit in
|
||
server slot order, not insertion order, exactly like the reference. The target-of-target
|
||
branches take the not-shown leg (wrap 6, buffs under Debuff7) until a ToT frame exists.
|
||
-->
|
||
<Script><![CDATA[
|
||
-- The client's PowerBarColor values, keyed by the UnitPowerType token.
|
||
BENILLA_POWER_COLORS = {
|
||
MANA = { r = 0.0, g = 0.0, b = 1.0 },
|
||
RAGE = { r = 1.0, g = 0.0, b = 0.0 },
|
||
FOCUS = { r = 1.0, g = 0.5, b = 0.25 },
|
||
ENERGY = { r = 1.0, g = 1.0, b = 0.0 },
|
||
HAPPINESS = { r = 0.0, g = 1.0, b = 1.0 },
|
||
}
|
||
|
||
-- The client's UnitReactionColor table (ref-TargetFrame.lua l.6-14), indexed by
|
||
-- UnitReaction 1..8 (hated..exalted): 1-2 red, 3 orange, 4 neutral yellow, 5-7 green. The
|
||
-- name-plate reaction tint (TargetFrame_CheckFaction) reads it — this is what makes a neutral
|
||
-- beast's plate yellow, a hostile's red, a friendly's green.
|
||
BENILLA_REACTION_COLORS = {
|
||
{ r = 1.0, g = 0.0, b = 0.0 },
|
||
{ r = 1.0, g = 0.0, b = 0.0 },
|
||
{ r = 1.0, g = 0.5, b = 0.0 },
|
||
{ r = 1.0, g = 1.0, b = 0.0 },
|
||
{ r = 0.0, g = 1.0, b = 0.0 },
|
||
{ r = 0.0, g = 1.0, b = 0.0 },
|
||
{ r = 0.0, g = 1.0, b = 0.0 },
|
||
}
|
||
|
||
-- Wire an instance to its unit token (called from each frame's OnLoad), cache its child
|
||
-- widgets, register the event set, and do the first paint. deadText is target-only
|
||
-- (getglobal returns nil for the player, which has no DEAD region) — guarded at use.
|
||
function BenillaUnitFrame_OnLoad(frame, unit)
|
||
frame.unit = unit
|
||
local name = frame:GetName()
|
||
frame.healthBar = getglobal(name .. "HealthBar")
|
||
frame.powerBar = getglobal(name .. "PowerBar")
|
||
-- The name/level/dead text live inside $parentTextureFrame (so they draw over the ring art
|
||
-- that draws over the bars), so their global names carry the TextureFrame prefix.
|
||
local tf = name .. "TextureFrame"
|
||
frame.nameText = getglobal(tf .. "NameText")
|
||
frame.levelText = getglobal(tf .. "LevelText")
|
||
frame.deadText = getglobal(tf .. "DeadText")
|
||
-- Target-only (the "??" skull on the level slot); getglobal returns nil for the
|
||
-- player, guarded at use.
|
||
frame.highLevel = getglobal(tf .. "HighLevelTexture")
|
||
-- Target-only (the level/name plate); getglobal returns nil for the player, guarded at use.
|
||
frame.nameBackground = getglobal(name .. "NameBackground")
|
||
-- The live model portrait (the real API's global, ref-UnitFrame.lua): bind the portrait
|
||
-- region to this frame's unit token; the app renders that unit's model off-screen and feeds
|
||
-- the bake back into the region (crates/benilla/src/portrait.rs). The binding is a token, so
|
||
-- one call suffices — the app keeps the image current per token (it re-bakes on target /
|
||
-- model change), which is why the ref's UNIT_PORTRAIT_UPDATE re-call isn't needed here (the
|
||
-- event joins the surface when addon parity wants it). Until a bake lands (no unit / model
|
||
-- still loading) the circle is simply empty.
|
||
frame.portrait = getglobal(name .. "Portrait")
|
||
SetPortraitTexture(frame.portrait, unit)
|
||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||
frame:RegisterEvent("UNIT_HEALTH")
|
||
frame:RegisterEvent("UNIT_MAXHEALTH")
|
||
frame:RegisterEvent("UNIT_LEVEL")
|
||
frame:RegisterEvent("UNIT_POWER_UPDATE")
|
||
frame:RegisterEvent("UNIT_MAXPOWER")
|
||
frame:RegisterEvent("UNIT_DISPLAYPOWER")
|
||
frame:RegisterEvent("UNIT_NAME_UPDATE")
|
||
frame:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||
-- The aura rows are target-only (ref TargetFrame_OnLoad registers UNIT_AURA).
|
||
if unit == "target" then
|
||
frame:RegisterEvent("UNIT_AURA")
|
||
end
|
||
-- The portrait hit indicator (decision 0576): only the player frame registers
|
||
-- UNIT_COMBAT in 1.12 (ref PlayerFrame_OnLoad — the target frame has no feedback
|
||
-- text). Ref: CombatFeedback_Initialize(PlayerHitIndicator, 30).
|
||
if unit == "player" then
|
||
frame.feedbackText = getglobal(tf .. "HitIndicator")
|
||
frame.feedbackFontHeight = 30
|
||
frame:RegisterEvent("UNIT_COMBAT")
|
||
end
|
||
-- A plain Frame isn't mouse-enabled by construction (only Button/EditBox are); enable it so
|
||
-- the hover tooltip fires (the real client's unit frames take the mouse to target/tooltip).
|
||
frame:EnableMouse(true)
|
||
BenillaUnitFrame_Update(frame)
|
||
end
|
||
|
||
-- Hover: the engine's SetUnit — the byte-verified unit line law (decision 0276: name/
|
||
-- subtitle/level composition/PvP/Skinnable + the health bar), then the ref's reaction
|
||
-- recolor of line 1 (ref UnitFrame_OnEnter l.68-76: the FrameXML half of the split).
|
||
-- The plate goes to the DEFAULT corner, not beside the frame — ref UnitFrame_OnEnter
|
||
-- l.56 is GameTooltip_SetDefaultAnchor(GameTooltip, this): unit-frame tooltips live at
|
||
-- the screen's bottom-right like world hovers. (The ref's newbie-tip fork and the
|
||
-- TOOLTIP_UPDATE_TIME re-poll are not ours: no newbie-tip option; the engine's health
|
||
-- watcher is the live half of the re-poll, and name/level don't drift mid-hover yet.)
|
||
function BenillaUnitFrame_OnEnter(frame)
|
||
local unit = frame.unit
|
||
if not UnitExists(unit) then return end
|
||
GameTooltip_SetDefaultAnchor(GameTooltip, frame)
|
||
if GameTooltip:SetUnit(unit) then
|
||
getglobal("GameTooltipTextLeft1"):SetTextColor(GameTooltip_UnitColor(unit))
|
||
end
|
||
end
|
||
|
||
-- ref UnitFrame_OnLeave l.88-93: the unit-frame tooltip FADES on leave (items Hide;
|
||
-- units fade — the same ramp the world mouseover uses).
|
||
function BenillaUnitFrame_OnLeave(frame)
|
||
GameTooltip:FadeOut()
|
||
end
|
||
|
||
function BenillaUnitFrame_OnEvent(frame)
|
||
-- UNIT_* events name their unit in arg1; ignore other units' updates.
|
||
if string.sub(event, 1, 5) == "UNIT_" and arg1 ~= frame.unit then
|
||
return
|
||
end
|
||
-- The hit-indicator feed (ref PlayerFrame_OnEvent's UNIT_COMBAT arm): no repaint —
|
||
-- the event carries feedback, not state.
|
||
if event == "UNIT_COMBAT" then
|
||
CombatFeedback_OnCombatEvent(frame, arg2, arg3, arg4, arg5)
|
||
return
|
||
end
|
||
BenillaUnitFrame_Update(frame)
|
||
end
|
||
|
||
-- ── Combat feedback: the portrait hit indicator (decision 0576) ──────────────────────
|
||
-- Ref CombatFeedback.lua, transcribed onto frame-param style (the ref reads `this`).
|
||
-- Timings/colors/size factors verbatim; the word strings are the shipped enUS
|
||
-- GlobalStrings values, hardcoded like the rest of our enUS-only data.
|
||
COMBATFEEDBACK_FADEINTIME = 0.2
|
||
COMBATFEEDBACK_HOLDTIME = 0.7
|
||
COMBATFEEDBACK_FADEOUTTIME = 0.3
|
||
|
||
CombatFeedbackText = {
|
||
INTERRUPT = "Interrupt",
|
||
MISS = "Miss",
|
||
RESIST = "Resist",
|
||
DODGE = "Dodge",
|
||
PARRY = "Parry",
|
||
BLOCK = "Block",
|
||
EVADE = "Evade",
|
||
IMMUNE = "Immune",
|
||
DEFLECT = "Deflect",
|
||
ABSORB = "Absorb",
|
||
REFLECT = "Reflect",
|
||
}
|
||
|
||
function CombatFeedback_OnCombatEvent(frame, event, flags, amount, type)
|
||
local feedbackText = frame.feedbackText
|
||
if not feedbackText then return end
|
||
local fontHeight = frame.feedbackFontHeight
|
||
local text = ""
|
||
local r, g, b = 1.0, 1.0, 1.0
|
||
|
||
if event == "IMMUNE" then
|
||
fontHeight = fontHeight * 0.5
|
||
text = CombatFeedbackText[event]
|
||
elseif event == "WOUND" then
|
||
if amount ~= 0 then
|
||
if flags == "CRITICAL" or flags == "CRUSHING" then
|
||
fontHeight = fontHeight * 1.5
|
||
elseif flags == "GLANCING" then
|
||
fontHeight = fontHeight * 0.75
|
||
end
|
||
-- type > 0 = a spell school: the number reads yellow, physical white.
|
||
if type > 0 then
|
||
r, g, b = 1.0, 1.0, 0.0
|
||
end
|
||
text = amount
|
||
elseif flags == "ABSORB" then
|
||
fontHeight = fontHeight * 0.75
|
||
text = CombatFeedbackText["ABSORB"]
|
||
elseif flags == "BLOCK" then
|
||
fontHeight = fontHeight * 0.75
|
||
text = CombatFeedbackText["BLOCK"]
|
||
elseif flags == "RESIST" then
|
||
fontHeight = fontHeight * 0.75
|
||
text = CombatFeedbackText["RESIST"]
|
||
else
|
||
text = CombatFeedbackText["MISS"]
|
||
end
|
||
elseif event == "BLOCK" then
|
||
fontHeight = fontHeight * 0.75
|
||
text = CombatFeedbackText[event]
|
||
elseif event == "HEAL" then
|
||
text = amount
|
||
r, g, b = 0.0, 1.0, 0.0
|
||
if flags == "CRITICAL" then
|
||
fontHeight = fontHeight * 1.5
|
||
end
|
||
elseif event == "ENERGIZE" then
|
||
text = amount
|
||
r, g, b = 0.41, 0.8, 0.94
|
||
if flags == "CRITICAL" then
|
||
fontHeight = fontHeight * 1.5
|
||
end
|
||
else
|
||
text = CombatFeedbackText[event]
|
||
end
|
||
|
||
frame.feedbackStartTime = GetTime()
|
||
|
||
feedbackText:SetTextHeight(fontHeight)
|
||
feedbackText:SetText(text)
|
||
feedbackText:SetTextColor(r, g, b)
|
||
feedbackText:SetAlpha(0.0)
|
||
feedbackText:Show()
|
||
end
|
||
|
||
-- The fade envelope (ref CombatFeedback_OnUpdate): 0.2 s ramp in, 0.7 s hold, 0.3 s
|
||
-- ramp out, then Hide. GetTime-based like the ref — no per-tick accumulation.
|
||
function CombatFeedback_OnUpdate(frame)
|
||
local feedbackText = frame.feedbackText
|
||
if not (feedbackText and feedbackText:IsVisible()) then return end
|
||
local elapsedTime = GetTime() - frame.feedbackStartTime
|
||
local fadeInTime = COMBATFEEDBACK_FADEINTIME
|
||
if elapsedTime < fadeInTime then
|
||
feedbackText:SetAlpha(elapsedTime / fadeInTime)
|
||
return
|
||
end
|
||
local holdTime = COMBATFEEDBACK_HOLDTIME
|
||
if elapsedTime < fadeInTime + holdTime then
|
||
feedbackText:SetAlpha(1.0)
|
||
return
|
||
end
|
||
local fadeOutTime = COMBATFEEDBACK_FADEOUTTIME
|
||
if elapsedTime < fadeInTime + holdTime + fadeOutTime then
|
||
feedbackText:SetAlpha(1.0 - (elapsedTime - holdTime - fadeInTime) / fadeOutTime)
|
||
return
|
||
end
|
||
feedbackText:Hide()
|
||
end
|
||
|
||
-- Pull the unit's current state and repaint. A non-existent unit hides the whole frame.
|
||
function BenillaUnitFrame_Update(frame)
|
||
local unit = frame.unit
|
||
if not UnitExists(unit) then
|
||
frame:Hide()
|
||
return
|
||
end
|
||
frame:Show()
|
||
|
||
frame.healthBar:SetMinMaxValues(0, UnitHealthMax(unit))
|
||
frame.healthBar:SetValue(UnitHealth(unit))
|
||
|
||
local maxPower = UnitPowerMax(unit)
|
||
if maxPower > 0 then
|
||
frame.powerBar:Show()
|
||
local _, token = UnitPowerType(unit)
|
||
local c = BENILLA_POWER_COLORS[token] or BENILLA_POWER_COLORS.MANA
|
||
frame.powerBar:SetStatusBarColor(c.r, c.g, c.b)
|
||
frame.powerBar:SetMinMaxValues(0, maxPower)
|
||
frame.powerBar:SetValue(UnitPower(unit))
|
||
else
|
||
frame.powerBar:Hide()
|
||
end
|
||
|
||
frame.nameText:SetText(UnitName(unit) or "Unknown")
|
||
|
||
-- The level slot (TargetFrame_CheckLevel, ref-TargetFrame.lua l.119-142): a corpse
|
||
-- target or one whose level "can't be told" (UnitLevel ≤ 0 — the −1 return for a
|
||
-- world boss / a hostile 10+ levels up) shows the skull instead of the number; a
|
||
-- told level is difficulty-colored when the target is attackable (GetDifficultyColor,
|
||
-- the same con law the V-plate paints its level with) and plain gold when not.
|
||
-- The player frame has no skull region and shows its own level, always gold.
|
||
local level = UnitLevel(unit)
|
||
if frame.highLevel then
|
||
if UnitIsCorpse(unit) or level <= 0 then
|
||
frame.levelText:Hide()
|
||
frame.highLevel:Show()
|
||
else
|
||
frame.levelText:SetText(level)
|
||
if UnitCanAttack("player", unit) then
|
||
local color = GetDifficultyColor(level)
|
||
frame.levelText:SetVertexColor(color.r, color.g, color.b)
|
||
else
|
||
frame.levelText:SetVertexColor(1.0, 0.82, 0.0)
|
||
end
|
||
frame.levelText:Show()
|
||
frame.highLevel:Hide()
|
||
end
|
||
else
|
||
frame.levelText:SetText(level)
|
||
end
|
||
|
||
-- Tint the name/level plate (target only; TargetFrame_CheckFaction, ref-TargetFrame.lua
|
||
-- l.144-191). A PLAYER-CONTROLLED target takes the player branch (l.145-174): its plate is
|
||
-- RED when we're mutually hostile (UnitReactionColor[2]) and BLUE otherwise — a friendly,
|
||
-- non-attackable player is blue, NOT the reaction green. Only an NPC takes the reaction
|
||
-- swatch (l.179-190): the resolved UnitReactionColor (neutral → yellow), or blue when the
|
||
-- reaction can't be told (nil). The ref's two middle player legs — yellow "attackable but
|
||
-- not hostile" (l.158) and green "assist + PvP-flagged" (l.163) — plus the tapped-by-other
|
||
-- grey (l.176) need the PvP/tap wire we don't carry; until it lands they collapse into
|
||
-- red/blue, which is the right answer for every same-/opposite-faction player we can
|
||
-- resolve. (The ref gates on UnitPlayerControlled, which also covers pets; UnitIsPlayer is
|
||
-- the player half we can resolve — see the header deviation.)
|
||
if frame.nameBackground then
|
||
if UnitIsPlayer(unit) then
|
||
if UnitIsEnemy(unit, "player") then
|
||
local c = BENILLA_REACTION_COLORS[2]
|
||
frame.nameBackground:SetVertexColor(c.r, c.g, c.b)
|
||
else
|
||
frame.nameBackground:SetVertexColor(0.0, 0.0, 1.0)
|
||
end
|
||
else
|
||
local reaction = UnitReaction(unit, "player")
|
||
local c = reaction and BENILLA_REACTION_COLORS[reaction]
|
||
if c then
|
||
frame.nameBackground:SetVertexColor(c.r, c.g, c.b)
|
||
else
|
||
frame.nameBackground:SetVertexColor(0.0, 0.0, 1.0)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- DEAD text (target only): shown at zero health (ref TargetFrame_CheckDead). Blanked
|
||
-- via SetText when alive — a site that predates region Show/Hide (region.rs has the
|
||
-- real pair now, the level slot above uses it); equivalent either way.
|
||
if frame.deadText then
|
||
if UnitHealth(unit) <= 0 then
|
||
frame.deadText:SetText("DEAD")
|
||
else
|
||
frame.deadText:SetText("")
|
||
end
|
||
end
|
||
|
||
-- The aura rows (target only) — the ref's TargetFrame_Update →
|
||
-- TargetDebuffButton_Update: repainted on PLAYER_TARGET_CHANGED and UNIT_AURA alike.
|
||
if unit == "target" then
|
||
BenillaTargetAuras_Update()
|
||
end
|
||
end
|
||
|
||
-- ref TargetFrame.lua l.2-3.
|
||
MAX_TARGET_DEBUFFS = 16
|
||
MAX_TARGET_BUFFS = 5
|
||
|
||
-- TargetDebuffButton_Update (ref-TargetFrame.lua l.263-387), transcribed onto the Era API
|
||
-- (decision 0255: UnitBuff returns name,icon,count,debuffType,… — the 1.12 original returned
|
||
-- the texture first). Only called with a live target (BenillaUnitFrame_Update guards).
|
||
-- DebuffTypeColor is defined by BuffFrame.xml, which loads AFTER this file — safe, because
|
||
-- this function only runs on events, never at load (no target exists at load).
|
||
function BenillaTargetAuras_Update()
|
||
local button
|
||
local numBuffs = 0
|
||
for i = 1, MAX_TARGET_BUFFS do
|
||
local name, icon = UnitBuff("target", i)
|
||
button = getglobal("BenillaTargetFrameBuff" .. i)
|
||
if name then
|
||
getglobal(button:GetName() .. "Icon"):SetTexture(icon or BENILLA_FALLBACK_ICON)
|
||
button:Show()
|
||
numBuffs = numBuffs + 1
|
||
else
|
||
button:Hide()
|
||
end
|
||
end
|
||
|
||
local numDebuffs = 0
|
||
for i = 1, MAX_TARGET_DEBUFFS do
|
||
local name, icon, count, debuffType = UnitDebuff("target", i)
|
||
button = getglobal("BenillaTargetFrameDebuff" .. i)
|
||
if name then
|
||
getglobal(button:GetName() .. "Icon"):SetTexture(icon or BENILLA_FALLBACK_ICON)
|
||
local color = DebuffTypeColor[debuffType] or DebuffTypeColor["none"]
|
||
local countText = getglobal(button:GetName() .. "Count")
|
||
if count and count > 1 then
|
||
countText:SetText(count)
|
||
else
|
||
countText:SetText("")
|
||
end
|
||
getglobal(button:GetName() .. "Border"):SetVertexColor(color.r, color.g, color.b)
|
||
button:Show()
|
||
numDebuffs = numDebuffs + 1
|
||
else
|
||
button:Hide()
|
||
end
|
||
end
|
||
|
||
-- The dynamic anchors (ref l.312-331). No target-of-target frame exists yet, so its
|
||
-- branches take the not-shown leg: wrap 6, buffs open under Debuff7.
|
||
local targetofTarget = false
|
||
local debuffWrap = 6
|
||
|
||
if UnitIsFriend("player", "target") then
|
||
BenillaTargetFrameBuff1:SetPoint("TOPLEFT", "BenillaTargetFrame", "BOTTOMLEFT", 5, 32)
|
||
BenillaTargetFrameDebuff1:SetPoint("TOPLEFT", "BenillaTargetFrameBuff1", "BOTTOMLEFT", 0, -2)
|
||
else
|
||
BenillaTargetFrameDebuff1:SetPoint("TOPLEFT", "BenillaTargetFrame", "BOTTOMLEFT", 5, 32)
|
||
BenillaTargetFrameBuff1:SetPoint("TOPLEFT", "BenillaTargetFrameDebuff7", "BOTTOMLEFT", 0, -2)
|
||
end
|
||
|
||
-- Shrink when the debuffs would overlap the frame (ref l.340-347): 21→17 icons,
|
||
-- 23→19 borders.
|
||
local debuffSize, debuffFrameSize
|
||
if (targetofTarget and numBuffs == 5) or numDebuffs >= debuffWrap then
|
||
debuffSize = 17
|
||
debuffFrameSize = 19
|
||
else
|
||
debuffSize = 21
|
||
debuffFrameSize = 23
|
||
end
|
||
|
||
for i = 1, 5 do
|
||
button = getglobal("BenillaTargetFrameBuff" .. i)
|
||
button:SetWidth(debuffSize)
|
||
button:SetHeight(debuffSize)
|
||
end
|
||
-- The ref resizes only the FIRST ROW's debuffs (l.358-368) — rows 2+ stay 17px always.
|
||
for i = 1, 6 do
|
||
button = getglobal("BenillaTargetFrameDebuff" .. i)
|
||
local border = getglobal(button:GetName() .. "Border")
|
||
border:SetWidth(debuffFrameSize)
|
||
border:SetHeight(debuffFrameSize)
|
||
button:SetWidth(debuffSize)
|
||
button:SetHeight(debuffSize)
|
||
end
|
||
|
||
-- Re-seat the wrap points (ref l.370-385) — constant with wrap pinned at 6, kept
|
||
-- verbatim so the ToT wrap-5 leg drops in unchanged.
|
||
getglobal("BenillaTargetFrameDebuff" .. debuffWrap):ClearAllPoints()
|
||
getglobal("BenillaTargetFrameDebuff" .. debuffWrap):SetPoint("LEFT", getglobal("BenillaTargetFrameDebuff" .. (debuffWrap - 1)), "RIGHT", 3, 0)
|
||
getglobal("BenillaTargetFrameDebuff" .. (debuffWrap + 1)):ClearAllPoints()
|
||
getglobal("BenillaTargetFrameDebuff" .. (debuffWrap + 1)):SetPoint("TOPLEFT", "BenillaTargetFrameDebuff1", "BOTTOMLEFT", 0, -2)
|
||
getglobal("BenillaTargetFrameDebuff" .. (debuffWrap + 2)):ClearAllPoints()
|
||
getglobal("BenillaTargetFrameDebuff" .. (debuffWrap + 2)):SetPoint("LEFT", getglobal("BenillaTargetFrameDebuff" .. (debuffWrap + 1)), "RIGHT", 3, 0)
|
||
if debuffWrap == 5 then
|
||
BenillaTargetFrameDebuff11:ClearAllPoints()
|
||
BenillaTargetFrameDebuff11:SetPoint("TOPLEFT", "BenillaTargetFrameDebuff6", "BOTTOMLEFT", 0, -2)
|
||
else
|
||
BenillaTargetFrameDebuff11:ClearAllPoints()
|
||
BenillaTargetFrameDebuff11:SetPoint("LEFT", "BenillaTargetFrameDebuff10", "RIGHT", 3, 0)
|
||
end
|
||
end
|
||
|
||
-- The aura hover (ref TargetDebuffButtonTemplate/TargetBuffButtonTemplate OnEnter,
|
||
-- l.60-62/l.79-81): the aura tooltip, seated BOTTOMRIGHT of the button.
|
||
function BenillaTargetAuraButton_OnEnter(button, harmful)
|
||
if not GameTooltip then return end -- engine tests load file subsets
|
||
GameTooltip:SetOwner(button, "ANCHOR_BOTTOMRIGHT", 15, -25)
|
||
if harmful then
|
||
GameTooltip:SetUnitDebuff("target", button:GetID())
|
||
else
|
||
GameTooltip:SetUnitBuff("target", button:GetID())
|
||
end
|
||
end
|
||
|
||
-- Left-click the player frame to target yourself (ref PlayerFrame_OnClick, the LeftButton
|
||
-- branch: an item on the cursor auto-equips, otherwise TargetUnit("player")); right-click
|
||
-- opens the SELF menu (ref's ToggleDropDownMenu at (106, 27), decision 0434 phase 5). The
|
||
-- ref's frame is a Button; ours is a mouse-enabled Frame, which fires OnClick on release
|
||
-- with arg1 = the button. The self-target itself is the byte-verified way the client
|
||
-- selects its own unit; the world-model click is a separate path, deliberately left out
|
||
-- (director's call).
|
||
function BenillaPlayerFrame_OnClick(button)
|
||
if button == "RightButton" then
|
||
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "BenillaPlayerFrame", 106, 27)
|
||
return
|
||
end
|
||
if button ~= "LeftButton" then return end
|
||
if CursorHasItem() then
|
||
AutoEquipCursorItem()
|
||
else
|
||
TargetUnit("player")
|
||
end
|
||
end
|
||
|
||
-- The right-click dropdowns (decision 0434 phase 5; ref TargetFrame.lua l.431-455,
|
||
-- PlayerFrame.lua l.235-241): MENU displayMode over the shared kit (UIDropDownMenu.xml),
|
||
-- the menus themselves from UnitPopup.xml. The menu pick is the ref's law: self → SELF,
|
||
-- party member → PARTY, other player → PLAYER, NPC → the bare raid-target icon list.
|
||
function TargetFrameDropDown_OnLoad()
|
||
UIDropDownMenu_Initialize(this, TargetFrameDropDown_Initialize, "MENU")
|
||
end
|
||
|
||
function TargetFrameDropDown_Initialize()
|
||
local menu
|
||
local name
|
||
if UnitIsUnit("target", "player") then
|
||
menu = "SELF"
|
||
elseif UnitIsPlayer("target") then
|
||
if UnitInParty("target") then
|
||
menu = "PARTY"
|
||
else
|
||
menu = "PLAYER"
|
||
end
|
||
else
|
||
-- The ref checks UnitIsUnit("target", "pet") → PET before this branch; no "pet"
|
||
-- token exists until the pet slice (phase 4).
|
||
menu = "RAID_TARGET_ICON"
|
||
name = RAID_TARGET_ICON
|
||
end
|
||
if menu then
|
||
UnitPopup_ShowMenu(TargetFrameDropDown, menu, "target", name)
|
||
end
|
||
end
|
||
|
||
function PlayerFrameDropDown_OnLoad()
|
||
UIDropDownMenu_Initialize(this, PlayerFrameDropDown_Initialize, "MENU")
|
||
end
|
||
|
||
function PlayerFrameDropDown_Initialize()
|
||
UnitPopup_ShowMenu(PlayerFrameDropDown, "SELF", "player")
|
||
end
|
||
|
||
-- ref TargetFrame_OnClick: right-click opens the unit menu at (120, 10). The ref's
|
||
-- LeftButton branch (SpellTargetUnit / DropItemOnUnit) rides the spell-cursor and
|
||
-- item-drop slices — a bare left-click is a no-op on the ref too.
|
||
function BenillaTargetFrame_OnClick(button)
|
||
if button == "RightButton" then
|
||
ToggleDropDownMenu(1, nil, TargetFrameDropDown, "BenillaTargetFrame", 120, 10)
|
||
end
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
PLAYER FRAME (ref-PlayerFrame.xml). Button 232×100 at UIParent TOPLEFT (-19,-4) (l.4-13); the
|
||
negative x trims the art's transparent left padding, seating the visible frame flush at the
|
||
screen's top-left, exactly as the real client does (our UIParent is the screen).
|
||
-->
|
||
<!-- frameStrata BACKGROUND is the ref's own (`PlayerFrame.xml` l.4) — the unit frames live
|
||
BELOW the MEDIUM panel windows on purpose, and the player frame shares the top-left corner
|
||
with the left-slot panel. See the note on PartyFrame.xml's template (decision 0597) for why
|
||
the default MEDIUM makes a unit frame's bar children draw through a window's background. -->
|
||
<Frame name="BenillaPlayerFrame" frameStrata="BACKGROUND">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="-19" y="-4"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- The bar trough: 119×41 black a=0.5 behind both bars (ref l.20-32). -->
|
||
<Texture name="$parentBackground">
|
||
<Size><AbsDimension x="119" y="41"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="106" y="-22"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Color r="0" g="0" b="0" a="0.5"/>
|
||
</Texture>
|
||
<!-- Portrait 64×64 TOPLEFT (42,-12) (ref l.35-46, moved ARTWORK→BACKGROUND so the ring
|
||
art draws over it). Texture set in OnLoad via SetPortraitToTexture (circle-masked). -->
|
||
<Texture name="$parentPortrait">
|
||
<Size><AbsDimension x="64" y="64"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="42" y="-12"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<!-- The ring art + name/level text live in $parentTextureFrame below (declared AFTER the
|
||
bars) so they draw OVER the bar edges — the recessed-bar look. See the LAYERING note. -->
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Health bar 119×12 TOPLEFT (106,-41), UI-StatusBar, green (ref l.288-315). -->
|
||
<StatusBar name="$parentHealthBar">
|
||
<Size><AbsDimension x="119" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="106" y="-41"/></Offset></Anchor>
|
||
</Anchors>
|
||
<BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
|
||
<BarColor r="0.0" g="1.0" b="0.0"/>
|
||
</StatusBar>
|
||
<!-- Power bar 119×12 TOPLEFT (106,-52), UI-StatusBar; color set at runtime (ref l.316-341). -->
|
||
<StatusBar name="$parentPowerBar">
|
||
<Size><AbsDimension x="119" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="106" y="-52"/></Offset></Anchor>
|
||
</Anchors>
|
||
<BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
|
||
<BarColor r="0.0" g="0.0" b="1.0"/>
|
||
</StatusBar>
|
||
<!-- The ring art + text, over the bars (ref TargetFrameTextureFrame). 232×100 fills the
|
||
parent; declared after the StatusBars so it draws over their edges — our z-model's
|
||
insertion-order equivalent of the ref's SetFrameLevel(bar, textureFrame-1). -->
|
||
<Frame name="$parentTextureFrame">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- Ring art, MIRRORED: TexCoords left=1.0 right=0.09375 top=0 bottom=0.78125 (ref l.55-57). -->
|
||
<Texture name="$parentTexture" file="Interface\TargetingFrame\UI-TargetingFrame">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="1.0" right="0.09375" top="0" bottom="0.78125"/>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<!-- Name 100×10 CENTER (50,19) (ref l.58-69). -->
|
||
<FontString name="$parentNameText" inherits="GameFontNormalSmall" text="Unknown">
|
||
<Size><AbsDimension x="100" y="10"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="50" y="19"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
<!-- Level number CENTER (-63,-16) (ref l.70-78). -->
|
||
<FontString name="$parentLevelText" inherits="GameFontNormalSmall">
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="-63" y="-16"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
<!-- The portrait hit indicator (ref PlayerHitIndicator, decision 0576):
|
||
CENTER at (73,-42) from the frame's TOPLEFT — the portrait circle's
|
||
center. Hidden until a UNIT_COMBAT event lands; CombatFeedback drives
|
||
text/size/color and the fade. -->
|
||
<FontString name="$parentHitIndicator" hidden="true" inherits="NumberFontNormalHuge">
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="TOPLEFT"><Offset><AbsDimension x="73" y="-42"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad><![CDATA[BenillaUnitFrame_OnLoad(this, "player")]]></OnLoad>
|
||
<OnEvent><![CDATA[BenillaUnitFrame_OnEvent(this)]]></OnEvent>
|
||
<OnUpdate><![CDATA[CombatFeedback_OnUpdate(this)]]></OnUpdate>
|
||
<OnEnter><![CDATA[BenillaUnitFrame_OnEnter(this)]]></OnEnter>
|
||
<OnLeave><![CDATA[BenillaUnitFrame_OnLeave(this)]]></OnLeave>
|
||
<OnClick><![CDATA[BenillaPlayerFrame_OnClick(arg1)]]></OnClick>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!-- The SELF-menu dropdown host (ref $parentDropDown, PlayerFrame.xml): hidden state-holder
|
||
only — the list anchors to the player frame by name, never to this. -->
|
||
<Frame name="PlayerFrameDropDown" parent="BenillaPlayerFrame" inherits="UIDropDownMenuTemplate" hidden="true">
|
||
<Size><AbsDimension x="10" y="10"/></Size>
|
||
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="-20" y="-10"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>PlayerFrameDropDown_OnLoad()</OnLoad>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!-- ref TargetDebuffButtonTemplate (l.26-68): 17×17 icon, 19×19 UI-Debuff-Overlays border
|
||
(dispel-tinted at update), bottom-right stack count. Sizes are re-set every update by the
|
||
shrink law (first row only, verbatim ref quirk). -->
|
||
<Button name="BenillaTargetDebuffTemplate" virtual="true">
|
||
<Size><AbsDimension x="17" y="17"/></Size>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentBorder" file="Interface\Buttons\UI-Debuff-Overlays">
|
||
<Size><AbsDimension x="19" y="19"/></Size>
|
||
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0.296875" right="0.5703125" top="0" bottom="0.515625"/>
|
||
</Texture>
|
||
<FontString name="$parentCount" inherits="NumberFontNormalSmall">
|
||
<Anchors><Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-1" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnEnter>BenillaTargetAuraButton_OnEnter(this, true)</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<!-- ref TargetBuffButtonTemplate (l.69-87): 21×21 icon, no border, no count. -->
|
||
<Button name="BenillaTargetBuffTemplate" virtual="true">
|
||
<Size><AbsDimension x="21" y="21"/></Size>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnEnter>BenillaTargetAuraButton_OnEnter(this, false)</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<!--
|
||
TARGET FRAME (ref-TargetFrame.xml). Button 232×100 at UIParent TOPLEFT (250,-4) (l.88-98). The
|
||
un-mirrored twin of the player frame: portrait window on the RIGHT, bars anchored TOPRIGHT.
|
||
-->
|
||
<!-- hidden="true" is a deliberate deviation from the ref (whose TargetFrame starts shown and
|
||
gets its no-target Hide behind the loading screen, before audio is live): our OnLoad
|
||
Update runs with audio up, so starting shown would fire OnHide's lost-target sound at
|
||
every login. Steady-state behavior is identical — Update Shows/Hides on target changes. -->
|
||
<!-- frameStrata LOW is the ref's own (`TargetFrame.xml` l.88) — one above the player frame's
|
||
BACKGROUND, still below the MEDIUM panels. Same reasoning as PlayerFrame above. -->
|
||
<Frame name="BenillaTargetFrame" hidden="true" frameStrata="LOW">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="250" y="-4"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- Bar trough 119×41 black a=0.5 TOPRIGHT (-106,-22) (ref l.104-116). -->
|
||
<Texture name="$parentBackground">
|
||
<Size><AbsDimension x="119" y="41"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-106" y="-22"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Color r="0" g="0" b="0" a="0.5"/>
|
||
</Texture>
|
||
<!-- The level/name plate 119×19 TOPRIGHT (-106,-22) (ref l.117-128) — target only,
|
||
untinted (see the header deviation on faction tinting). -->
|
||
<Texture name="$parentNameBackground" file="Interface\TargetingFrame\UI-TargetingFrame-LevelBackground">
|
||
<Size><AbsDimension x="119" y="19"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-106" y="-22"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
<!-- Portrait 64×64 TOPRIGHT (-42,-12) (ref l.131-142, BORDER→BACKGROUND for the same
|
||
ring-over-portrait layering as the player). -->
|
||
<Texture name="$parentPortrait">
|
||
<Size><AbsDimension x="64" y="64"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-42" y="-12"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<!-- The ring art + name/level/dead text live in $parentTextureFrame below (declared AFTER
|
||
the bars) so they draw OVER the bar edges — the recessed-bar look. -->
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Health bar 119×12 TOPRIGHT (-106,-41), UI-StatusBar, green (ref l.252-273). -->
|
||
<StatusBar name="$parentHealthBar">
|
||
<Size><AbsDimension x="119" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-106" y="-41"/></Offset></Anchor>
|
||
</Anchors>
|
||
<BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
|
||
<BarColor r="0.0" g="1.0" b="0.0"/>
|
||
</StatusBar>
|
||
<!-- Power bar 119×12 TOPRIGHT (-106,-52), UI-StatusBar; color set at runtime (ref l.274-292). -->
|
||
<StatusBar name="$parentPowerBar">
|
||
<Size><AbsDimension x="119" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-106" y="-52"/></Offset></Anchor>
|
||
</Anchors>
|
||
<BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
|
||
<BarColor r="0.0" g="0.0" b="1.0"/>
|
||
</StatusBar>
|
||
<!-- The ring art + text, over the bars (ref TargetFrameTextureFrame); declared after the
|
||
StatusBars so it draws over their edges (our z-model's insertion-order equivalent of
|
||
the ref's SetFrameLevel(bar, textureFrame-1)). -->
|
||
<Frame name="$parentTextureFrame">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- Ring art, UN-mirrored: TexCoords left=0.09375 right=1.0 (ref l.146-151). -->
|
||
<Texture name="$parentTexture" file="Interface\TargetingFrame\UI-TargetingFrame">
|
||
<Size><AbsDimension x="232" y="100"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="0.09375" right="1.0" top="0" bottom="0.78125"/>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<!-- Name 100×10 CENTER (-50,19) (ref l.152-163). -->
|
||
<FontString name="$parentNameText" inherits="GameFontNormalSmall" text="Unknown">
|
||
<Size><AbsDimension x="100" y="10"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="-50" y="19"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
<!-- Level number CENTER (63,-16) (ref l.164-172). -->
|
||
<FontString name="$parentLevelText" inherits="GameFontNormalSmall">
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="63" y="-16"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
<!-- The "too high to tell" skull, 16×16 on the level slot (ref
|
||
TargetHighLevelTexture, l.184-195): shown for a corpse target or
|
||
UnitLevel ≤ 0, replacing the number (TargetFrame_CheckLevel). -->
|
||
<Texture name="$parentHighLevelTexture" file="Interface\TargetingFrame\UI-TargetingFrame-Skull">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="63" y="-16"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
<!-- DEAD, CENTER (-50,3), shown at zero health (ref l.173-181). Blank while alive. -->
|
||
<FontString name="$parentDeadText" inherits="GameFontNormalSmall">
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="-50" y="3"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<!-- The aura rows (ref l.293-481, names re-based on $parent). Static anchors are the
|
||
ref's; the update re-seats Debuff1/6/7/8/11 and Buff1 every pass (the friend swap +
|
||
the wrap law). Row 1 debuffs 1-6 (+3 gaps), row 2 debuffs 7-16, buffs below. -->
|
||
<Button name="$parentDebuff1" inherits="BenillaTargetDebuffTemplate" id="1">
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="5" y="32"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff2" inherits="BenillaTargetDebuffTemplate" id="2">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff1" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff3" inherits="BenillaTargetDebuffTemplate" id="3">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff2" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff4" inherits="BenillaTargetDebuffTemplate" id="4">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff3" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff5" inherits="BenillaTargetDebuffTemplate" id="5">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff4" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff6" inherits="BenillaTargetDebuffTemplate" id="6">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff5" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff7" inherits="BenillaTargetDebuffTemplate" id="7">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="$parentDebuff1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff8" inherits="BenillaTargetDebuffTemplate" id="8">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff7" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff9" inherits="BenillaTargetDebuffTemplate" id="9">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff8" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff10" inherits="BenillaTargetDebuffTemplate" id="10">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff9" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff11" inherits="BenillaTargetDebuffTemplate" id="11">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff10" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff12" inherits="BenillaTargetDebuffTemplate" id="12">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff11" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff13" inherits="BenillaTargetDebuffTemplate" id="13">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff12" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff14" inherits="BenillaTargetDebuffTemplate" id="14">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff13" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff15" inherits="BenillaTargetDebuffTemplate" id="15">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff14" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentDebuff16" inherits="BenillaTargetDebuffTemplate" id="16">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentDebuff15" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentBuff1" inherits="BenillaTargetBuffTemplate" id="1">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="$parentDebuff1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentBuff2" inherits="BenillaTargetBuffTemplate" id="2">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentBuff1" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentBuff3" inherits="BenillaTargetBuffTemplate" id="3">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentBuff2" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentBuff4" inherits="BenillaTargetBuffTemplate" id="4">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentBuff3" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="$parentBuff5" inherits="BenillaTargetBuffTemplate" id="5">
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentBuff4" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad><![CDATA[BenillaUnitFrame_OnLoad(this, "target")]]></OnLoad>
|
||
<OnEvent><![CDATA[BenillaUnitFrame_OnEvent(this)]]></OnEvent>
|
||
<OnEnter><![CDATA[BenillaUnitFrame_OnEnter(this)]]></OnEnter>
|
||
<OnLeave><![CDATA[BenillaUnitFrame_OnLeave(this)]]></OnLeave>
|
||
<!-- The select/deselect pair rides the frame's visibility, exactly the ref
|
||
(TargetFrame_OnShow/OnHide, TargetFrame.lua l.104-117). In 5875 data all three
|
||
select kits resolve to the same iSelectTarget.wav — the reaction branch is
|
||
data-plumbing fidelity, not an audible difference. -->
|
||
<OnShow><![CDATA[
|
||
if UnitIsEnemy("target", "player") then
|
||
PlaySound("igCreatureAggroSelect")
|
||
elseif UnitIsFriend("player", "target") then
|
||
PlaySound("igCharacterNPCSelect")
|
||
else
|
||
PlaySound("igCreatureNeutralSelect")
|
||
end
|
||
]]></OnShow>
|
||
<!-- ref TargetFrame_OnHide: the lost-target sound + close any open unit menu (a
|
||
cleared target must not leave its menu acting on a stale unit). -->
|
||
<OnHide><![CDATA[
|
||
PlaySound("INTERFACESOUND_LOSTTARGETUNIT")
|
||
CloseDropDownMenus()
|
||
]]></OnHide>
|
||
<OnClick><![CDATA[BenillaTargetFrame_OnClick(arg1)]]></OnClick>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!-- The target-menu dropdown host (ref $parentDropDown, TargetFrame.xml): hidden
|
||
state-holder only, like the player's above. -->
|
||
<Frame name="TargetFrameDropDown" parent="BenillaTargetFrame" inherits="UIDropDownMenuTemplate" hidden="true">
|
||
<Size><AbsDimension x="10" y="10"/></Size>
|
||
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="-20" y="-10"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnLoad>TargetFrameDropDown_OnLoad()</OnLoad>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|