Files
benilla-octo/crates/benilla-app/assets/ui/MinimapCluster.xml
T
SamandClaude Fable 5 a683d5524f the interface code is ours: the transcription debt is paid
- 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>
2026-08-14 19:21:03 +07:00

581 lines
30 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
The HUD minimap cluster — our own implementation of what the 1.12 FrameXML Minimap.xml
specifies (decision 0203 phase 1), which is cited throughout for the names, the geometry, the
art and the event wiring: that half is the API addons reposition and hook by name, and none of
it is ours to invent. The <Minimap> widget itself is the engine-rendered map hole: benilla-ui carries its
rect + zoom, and the app (`minimap.rs`) fills it with the streamed tile window, the
MinimapMask circle, and the player arrow; everything in THIS file is the chrome the reference
authors around that hole, at the reference's own geometry and art.
IN (this file): the cluster frame (192×192, TOPRIGHT), MinimapBorderTop, the zone-text button
(label fed by MINIMAP_ZONE_CHANGED → GetMinimapZoneText()), the minimap show/hide toggle, the
140×140 <Minimap> widget, MinimapBackdrop's round border art, the zoom in/out buttons
driving Minimap:SetZoom() with the reference's enable/disable-at-bounds law + sounds, and the
unread-mail icon (MiniMapMailFrame, decision 0544 P3 — the mail arc's arrival layer) driven by
UPDATE_PENDING_MAIL + HasNewMail(), and the tracking icon (MiniMapTrackingFrame) driven by
PLAYER_AURAS_CHANGED + GetTrackingTexture() (the aura rebuild's tracking-global law, `ui_aura`).
OUT (no wire / later arc slices, per 0203): meeting stone and battlefield buttons;
the ping model + MINIMAP_PING; the rotate-minimap CVar. The day/night indicator now lives in
its own GameTime.xml (the reference's own file split), loaded right after this file. The
reference's minimapPlayerModel/.mdx arrow renders app-side from its .blp for now (0203 flags
the simplification). The reference's <HitRectInsets> on the cluster is dropped (it only
enlarges the mouse-blocking hull; the loader models the tag now, so restore it if it ever
matters).
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script><![CDATA[
-- ref-Minimap.lua ToggleMinimap(), verbatim (the toggle button hides the MAP, not the chrome).
function ToggleMinimap()
if ( Minimap:IsVisible() ) then
PlaySound("igMiniMapClose");
Minimap:Hide();
else
PlaySound("igMiniMapOpen");
Minimap:Show();
end
end
-- The zone label's tint, keyed by the zone's PvP disposition. Colours quoted from
-- ref-Minimap.lua (they are measurements of the real interface, not choices of ours); the
-- table is ours, because five branches that differ only in three floats want to be data.
local ZONE_PVP_TINT = {
friendly = { r = 0.1, g = 1.0, b = 0.1 },
hostile = { r = 1.0, g = 0.1, b = 0.1 },
contested = { r = 1.0, g = 0.7, b = 0 },
};
-- Every line of the zone tooltip is drawn the same way — plain white, nothing in the
-- right-hand column — so the stanza is written once here instead of once per line.
local function AddZoneTooltipLine(text)
GameTooltip:AddLine(text, "", 1.0, 1.0, 1.0);
end
-- The zone's "whose land is this" line, or nil for a zone that is nobody's (sanctuary, or
-- a disposition we don't recognise). Free-for-all is deliberately NOT decided here: the
-- two callers below reach it by genuinely different routes and have to keep doing so — see
-- the note in Minimap_Update.
local function ZoneTerritoryLine(pvpType, factionName)
if ( pvpType == "friendly" or pvpType == "hostile" ) then
return format(FACTION_CONTROLLED_TERRITORY, factionName);
elseif ( pvpType == "contested" ) then
return CONTESTED_TERRITORY;
end
return nil;
end
-- Our implementation of what ref-Minimap.lua's Minimap_Update() specifies: relabel the
-- minimap's zone line, tint it for the zone's PVP state (decision 0287 — GetZonePVPInfo
-- closes the "zone PVP state we don't track yet" reduction that kept the label gold), and
-- refresh the hover tooltip if — and only if — the cursor is already parked on the label,
-- so a zone change under the mouse updates what is on screen.
function Minimap_Update()
local zoneName = GetMinimapZoneText();
MinimapZoneText:SetText(zoneName);
local pvpType, factionName, isArena = GetZonePVPInfo();
-- An arena zone is free-for-all, so it wears the hostile red whatever the zone's own
-- type says; resolving that override after the lookup keeps it in one place. A zone
-- with no tint of its own (sanctuary, or a type we don't know) stays normal gold.
local tint = ZONE_PVP_TINT[pvpType];
if ( isArena ) then
tint = ZONE_PVP_TINT.hostile;
end
if ( tint ) then
MinimapZoneText:SetTextColor(tint.r, tint.g, tint.b);
else
MinimapZoneText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
end
if ( not GameTooltip:IsOwned(MinimapZoneTextButton) ) then
return;
end
-- AT MOST ONE territory line on this path, and free-for-all is an ALTERNATIVE to the
-- faction line here, reached off `pvpType` rather than off `isArena` — so with the
-- live API (which never reports "arena" as a type) it never fires at all. That is the
-- reference's own asymmetry with MinimapZoneTextButton_OnEnter below, where the FFA
-- line is an EXTRA line gated on `isArena`. The two disagree, they are kept apart
-- deliberately, and converging them would be a behaviour change wearing a tidy-up's
-- clothes — which is why ZoneTerritoryLine stops short of this arm.
local territory = ZoneTerritoryLine(pvpType, factionName);
if ( pvpType == "arena" ) then
territory = FREE_FOR_ALL_TERRITORY;
end
GameTooltip:SetOwner(MinimapZoneTextButton, "ANCHOR_LEFT");
AddZoneTooltipLine(zoneName);
if ( territory ) then
AddZoneTooltipLine(territory);
end
GameTooltip:Show();
end
-- The zone label's own hover tooltip. Minimap_Update above refreshes this same tooltip in
-- place while the cursor is parked here, but the two are NOT one routine: this one adds
-- the free-for-all line as an EXTRA line gated on `isArena` (so an arena that is also
-- contested says both), while Minimap_Update reaches it off `pvpType == "arena"` INSTEAD
-- of the faction line. See the note there; the difference is the reference's, it is what
-- players actually see, and it is preserved on purpose.
function MinimapZoneTextButton_OnEnter()
GameTooltip:SetOwner(this, "ANCHOR_LEFT");
AddZoneTooltipLine(GetMinimapZoneText());
local pvpType, factionName, isArena = GetZonePVPInfo();
local territory = ZoneTerritoryLine(pvpType, factionName);
if ( territory ) then
AddZoneTooltipLine(territory);
end
if ( isArena ) then
AddZoneTooltipLine(FREE_FOR_ALL_TERRITORY);
end
GameTooltip:Show();
end
-- The end of the track a step of `step` is heading for. The two ends are not spelled the
-- same way — index 0 is a constant, the tight end rides however many levels the widget
-- carries — which is the only reason the +/- buttons need saying twice at all.
local function MinimapZoomLimit(step)
if ( step < 0 ) then
return 0;
end
return Minimap:GetZoomLevels() - 1;
end
-- One zoom step, either direction (ref-Minimap.lua's two click handlers say this twice in
-- mirror image; benilla says it once and hands it the direction). Three things happen: the
-- OPPOSITE button is re-armed, because a step this way always leaves room to come back;
-- the widget moves; and this button greys if the step landed on its own end of the track.
-- Note the limit is read AFTER the step, so a widget that clamps the move is still asked
-- where it actually ended up.
local function MinimapZoomStep(step, sound, button, opposite)
opposite:Enable();
PlaySound(sound);
Minimap:SetZoom(Minimap:GetZoom() + step);
if ( Minimap:GetZoom() == MinimapZoomLimit(step) ) then
button:Disable();
end
end
function Minimap_ZoomInClick()
MinimapZoomStep(1, "igMiniMapZoomIn", MinimapZoomIn, MinimapZoomOut);
end
function Minimap_ZoomOutClick()
MinimapZoomStep(-1, "igMiniMapZoomOut", MinimapZoomOut, MinimapZoomIn);
end
-- Re-sync BOTH buttons to the zoom as it stands, which is what a click cannot do: a click
-- knows which way it moved, this does not. The app fires MINIMAP_UPDATE_ZOOM when the
-- active zoom index switches (stepping inside/outside flips to the other, independent
-- level), so the +/- greying follows the map you are actually on instead of the one you
-- left. Both ends are re-armed first and then at most one is greyed again — a widget with
-- a single zoom level sits on both ends at once, and the tight end wins that tie.
function Minimap_UpdateZoom()
MinimapZoomIn:Enable();
MinimapZoomOut:Enable();
local zoom = Minimap:GetZoom();
if ( zoom == MinimapZoomLimit(1) ) then
MinimapZoomIn:Disable();
elseif ( zoom == MinimapZoomLimit(-1) ) then
MinimapZoomOut:Disable();
end
end
-- Byte-exact 1.12 enUS GlobalString (GlobalStrings.lua:2122) — the unread-mail tooltip.
local HAVE_MAIL = "You have unread mail";
-- ref-Minimap.xml MiniMapMailFrame's OnEvent, verbatim logic (l.281-289): UPDATE_PENDING_MAIL
-- is the ONLY event the reference registers on this frame — no MAIL_INBOX_UPDATE/MAIL_CLOSED
-- exists there despite the icon logically depending on inbox state. That is not an oversight
-- to paper over: reading your mail clears the icon through the pending-mail countdown, never
-- through the inbox (opening a letter arms a deferred refresh; closing the mailbox re-asks
-- the server). `ui_mail::MailPending` models that countdown and fires UPDATE_PENDING_MAIL at
-- exactly the reference's three signal sites — decision 0913.
function MiniMapMailFrame_OnEvent()
if ( event == "UPDATE_PENDING_MAIL" ) then
if ( HasNewMail() ) then
this:Show();
else
this:Hide();
end
end
end
-- ref-Minimap.xml l.290-293, verbatim.
function MiniMapMailFrame_OnEnter()
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT");
GameTooltip:SetText(HAVE_MAIL);
end
-- The tracking icon, same shape as the mail frame above. `GetTrackingTexture()` is the
-- WHOLE of the state: the icon path of the one tracking effect the aura rebuild diverts
-- out of the buff bar (`ui_aura`), or nil when nothing is tracked — so there is nothing to
-- reconcile, the answer is either an icon to wear or a reason to get out of the way.
-- PLAYER_AURAS_CHANGED is the only signal that can change it (ref-Minimap.xml l.109-174
-- registers nothing else on this frame). Note the icon is NOT cleared on the way out: the
-- frame is hidden, and the next tracking effect repaints it before it is seen again.
function MiniMapTrackingFrame_OnEvent()
if ( event ~= "PLAYER_AURAS_CHANGED" ) then
return;
end
local tracking = GetTrackingTexture();
if ( not tracking ) then
MiniMapTrackingFrame:Hide();
return;
end
MiniMapTrackingIcon:SetTexture(tracking);
MiniMapTrackingFrame:Show();
end
-- Hovering the icon names the tracking spell itself, which the tooltip knows how to build.
function MiniMapTrackingFrame_OnEnter()
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT");
GameTooltip:SetTrackingSpell();
end
]]></Script>
<Frame name="MinimapCluster" frameStrata="BACKGROUND" enableMouse="true" parent="UIParent">
<Size>
<AbsDimension x="192" y="192"/>
</Size>
<Anchors>
<Anchor point="TOPRIGHT"/>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture name="MinimapBorderTop" file="Interface\Minimap\UI-Minimap-Border">
<Size>
<AbsDimension x="192" y="32"/>
</Size>
<Anchors>
<Anchor point="TOPRIGHT"/>
</Anchors>
<TexCoords left="0.25" right="1.0" top="0.0" bottom="0.125"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="MinimapZoneTextButton">
<Size>
<AbsDimension x="128" y="12"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="-3" y="83"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<FontString name="MinimapZoneText" inherits="GameFontNormal" nonspacewrap="true">
<Size>
<AbsDimension x="128" y="12"/>
</Size>
<Anchors>
<Anchor point="TOP"/>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnEnter>
MinimapZoneTextButton_OnEnter();
</OnEnter>
<OnLeave>
GameTooltip:Hide();
</OnLeave>
</Scripts>
</Button>
<Button name="MinimapToggleButton">
<Size>
<AbsDimension x="32" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativePoint="TOPRIGHT">
<Offset>
<AbsDimension x="-15" y="-13"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
ToggleMinimap();
</OnClick>
</Scripts>
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
<HighlightTexture alphaMode="ADD" file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight"/>
</Button>
<Minimap name="Minimap" enableMouse="true">
<Size>
<AbsDimension x="140" y="140"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativePoint="TOP">
<Offset>
<AbsDimension x="9" y="-92"/>
</Offset>
</Anchor>
</Anchors>
<Frames>
<!-- ref-Minimap.xml l.109-174 for the names, geometry and art — the tracking
icon (the mail frame's nesting precedent: a child of the round Minimap
WIDGET, whose TOPLEFT the (-15,0) anchor hangs off). Driven by
PLAYER_AURAS_CHANGED →
GetTrackingTexture(): the reference's aura-cache rebuild diverts a
tracking-effect aura (Find Minerals, Track Beasts, …) out of the buff bar
into a tracking global this icon shows (byte-verified — the {0x2c,0x2d,0x97}
effect exclusion; `ui_aura` mirrors the law). Right-click cancels the
tracking aura, exactly the reference's CancelTrackingBuff. -->
<Frame name="MiniMapTrackingFrame" enableMouse="true" hidden="true">
<Size>
<AbsDimension x="33" y="33"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="-15" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="MiniMapTrackingIcon">
<Size>
<AbsDimension x="26" y="26"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="7" y="-6"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
</Layer>
<Layer level="OVERLAY">
<Texture name="MiniMapTrackingBorder" file="Interface\Minimap\MiniMap-TrackingBorder">
<Size>
<AbsDimension x="64" y="64"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnLoad>
this:RegisterEvent("PLAYER_AURAS_CHANGED");
</OnLoad>
<OnEvent>
MiniMapTrackingFrame_OnEvent();
</OnEvent>
<OnMouseUp>
if ( arg1 == "RightButton" ) then
CancelTrackingBuff();
end
</OnMouseUp>
<OnEnter>
MiniMapTrackingFrame_OnEnter();
</OnEnter>
<OnLeave>
GameTooltip:Hide();
</OnLeave>
</Scripts>
</Frame>
<!-- ref-Minimap.xml l.239-298, verbatim (decision 0544 P3) — the unread-mail
icon. A child of the round Minimap WIDGET, not the cluster: its TOPRIGHT
(21,-38) hangs off the 140×140 map's right edge, which sits well inside the
cluster — hoisted to the cluster the same offset lands past the screen edge.
Unprefixed (this file's own convention: every frame here keeps the
reference's bare name, unlike the newer Benilla*-prefixed windows). -->
<!-- **Two more of the reference's minimap icons, built and hidden** — the
fourth time this posture has been the answer (1219's vertical multibars,
1223's bonus bar, ReputationWatchBar, these). `ref-Minimap.xml` declares
both `hidden="true"`: real on the client from load, shown only when there
is a battleground queue or a meeting stone to advertise.
benilla drives neither, so they stay hidden — but addons reposition the
whole icon set by NAME. `CleanMinimap.lua:209` is
`getglobal(frameName):ClearAllPoints()` over a list that includes both, and
it died on the nil; `MiniMapBattlefieldFrame` alone is 5 addons in the
corrected ranking (1218). Their icon regions are declared with them, since
an addon that moves a frame expects its named children to exist.
Geometry quoted from the reference: both 33x33 with an 18x18 icon at
TOPLEFT (7,-6), Battlefield at BOTTOMLEFT (13,-13) of the cluster and
MeetingStone at TOPRIGHT (23,-65). -->
<Button name="MiniMapBattlefieldFrame" enableMouse="true" hidden="true">
<Size><AbsDimension x="33" y="33"/></Size>
<Anchors>
<Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="13" y="-13"/></Offset></Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture name="MiniMapBattlefieldIcon" file="Interface\BattlefieldFrame\UI-Battlefield-Icon">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors>
<Anchor point="CENTER"><Offset><AbsDimension x="-1" y="0"/></Offset></Anchor>
</Anchors>
</Texture>
</Layer>
</Layers>
</Button>
<Button name="MiniMapMeetingStoneFrame" enableMouse="true" hidden="true">
<Size><AbsDimension x="33" y="33"/></Size>
<Anchors>
<Anchor point="TOPRIGHT"><Offset><AbsDimension x="23" y="-65"/></Offset></Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture name="MiniMapMeetingStoneIcon" file="Interface\Icons\INV_Misc_Rune_06">
<Size><AbsDimension x="18" y="18"/></Size>
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="7" y="-6"/></Offset></Anchor>
</Anchors>
</Texture>
</Layer>
</Layers>
</Button>
<Frame name="MiniMapMailFrame" enableMouse="true" hidden="true">
<Size>
<AbsDimension x="33" y="33"/>
</Size>
<Anchors>
<Anchor point="TOPRIGHT">
<Offset>
<AbsDimension x="21" y="-38"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture name="MiniMapMailIcon" file="Interface\Icons\INV_Letter_15">
<Size>
<AbsDimension x="18" y="18"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="7" y="-6"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
</Layer>
<Layer level="OVERLAY">
<Texture name="MiniMapMailBorder" file="Interface\Minimap\MiniMap-TrackingBorder">
<Size>
<AbsDimension x="52" y="52"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnLoad>
this:RegisterEvent("UPDATE_PENDING_MAIL");
this:SetFrameLevel(this:GetFrameLevel()+1)
</OnLoad>
<OnEvent>
MiniMapMailFrame_OnEvent();
</OnEvent>
<OnEnter>
MiniMapMailFrame_OnEnter();
</OnEnter>
<OnLeave>
GameTooltip:Hide();
</OnLeave>
</Scripts>
</Frame>
<Frame name="MinimapBackdrop">
<Size>
<AbsDimension x="192" y="192"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativeTo="MinimapCluster">
<Offset>
<AbsDimension x="0" y="-20"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture name="MinimapBorder" file="Interface\Minimap\UI-Minimap-Border">
<TexCoords left="0.25" right="1.0" top="0.125" bottom="0.875"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="MinimapZoomIn">
<Size>
<AbsDimension x="32" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="77" y="-13"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Minimap_ZoomInClick();
</OnClick>
</Scripts>
<NormalTexture file="Interface\Minimap\UI-Minimap-ZoomInButton-Up"/>
<PushedTexture file="Interface\Minimap\UI-Minimap-ZoomInButton-Down"/>
<DisabledTexture file="Interface\Minimap\UI-Minimap-ZoomInButton-Disabled"/>
<HighlightTexture alphaMode="ADD" file="Interface\Minimap\UI-Minimap-ZoomButton-Highlight"/>
</Button>
<Button name="MinimapZoomOut">
<Size>
<AbsDimension x="32" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="51" y="-41"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Minimap_ZoomOutClick();
</OnClick>
</Scripts>
<NormalTexture file="Interface\Minimap\UI-Minimap-ZoomOutButton-Up"/>
<PushedTexture file="Interface\Minimap\UI-Minimap-ZoomOutButton-Down"/>
<DisabledTexture file="Interface\Minimap\UI-Minimap-ZoomOutButton-Disabled"/>
<HighlightTexture alphaMode="ADD" file="Interface\Minimap\UI-Minimap-ZoomButton-Highlight"/>
</Button>
</Frames>
</Frame>
</Frames>
</Minimap>
</Frames>
<Scripts>
<OnLoad>
Minimap_Update();
-- Seed the +/- state from the live zoom (default index 3 ⇒ both enabled) rather than
-- hardcoding a zoom-0 "can't zoom out" — the client's default is 3, not the widest.
Minimap_UpdateZoom();
this:RegisterEvent("MINIMAP_ZONE_CHANGED");
this:RegisterEvent("MINIMAP_UPDATE_ZOOM");
</OnLoad>
<OnEvent>
if ( event == "MINIMAP_UPDATE_ZOOM" ) then
Minimap_UpdateZoom();
else
Minimap_Update();
end
</OnEvent>
</Scripts>
</Frame>
</Ui>