Files
benilla-octo/crates/benilla-app/assets/ui/WorldMapFrame.xml
T
SamandClaude Fable 5 11a0b68da6 party members show on the world map, and the leader wears the crown
- party members appear on the world map at their position and hovering names them — the party wire has carried each member's zone and coordinates since the group arc; the blip and the minimap dot read one shared position so they can never disagree, and the member's zone picks which continent the position belongs to
- the player's own frame wears the leader crown and the master-looter icon, with the reference's own asymmetry (the crown asks IsPartyLeader, the member frames compare a leader index)
- a party member outside your local area gets the generic race/sex portrait instead of an empty circle — their race and sex ride the name query, and nothing had asked for a member we never see; the roster now warms that cache, which also fills the raid grid's class column
- right-clicking a member who is nowhere near grays Trade, Inspect, Duel and Follow: the reference's bindings answer nil for a unit the object manager does not hold (carved this session), where ours defaulted "absent = in range" for exactly the farthest member; and the group-invite popup's background is measured faithful — the plate draws at the BLP's own 60% alpha

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:30:24 +07:00

818 lines
45 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 fullscreen world map — our implementation of the behaviour the 1.12 FrameXML
WorldMapFrame.xml/.lua specifies (decision 0203 phase 2; decision 0221 settled the layout on
the fullscreen sheet — the windowed / 1.14-header direction of 0214/0217/0219 is parked, and
this faithful fullscreen sheet is the baseline we return to). The reference is the SPEC, not
the source of this text: the names are its contract (globals addons call, frame and template
names, art paths, every constant and texcoord) and the code that uses them is ours. The map
is pure FrameXML over the worldmap host API (benilla-ui script/worldmap.rs): detail tiles are
plain textures whose art the Lua swaps per selection (GetMapInfo →
Interface\WorldMap\<name>\<name>1..12), the player blip is positioned from
GetPlayerMapPosition in the same 0..1 map space the reference uses, navigation is
SetMapZoom/-ToCurrentZone/ProcessMapClick.
IN (this file): the FULLSCREEN frame + blackout, the 12-piece parchment chrome, the title,
the 1002×668 detail frame with its 12 tiles + ADD highlight, the discovery-overlay pool
(0222 — the explored sub-areas paint their detail over the base parchment), the click/hover
button layer, the continent/zone dropdowns (over UIDropDownMenu.xml's kit), the zoom-out
button (panel-button shape — our engine ships no UIPanelButtonTemplate), the close X (the
QuestLog/BagFrame hand-drawn shape), the area label pair, and the player arrow (MinimapArrow
art spun by SetRotation(GetPlayerFacing()) — the reference renders an engine arrow model;
0203 flags the stand-in).
OUT (later slices, per 0203): the AreaPOI.dbc landmarks (the POI pool IS here — the guard's
directions marker fills it today, and the DBC rows join through the same GetNumMapLandmarks);
raid/battlefield/ping children (the PARTY blips landed with report B320 — the raid pool
waits on `GetPlayerMapPosition` answering a `raid` token); the magnifying-glass zoom-out
shortcut (redundant with the button); SetupFullscreenScale (the map renders at its native
1024×768 centered; a scale pass is a taste knob); WorldMapTooltip (only unit blips used it).
Deviations from the reference, deliberate: BlackoutWorld fills via anchors instead of the
GetScreenWidth resize dance (same pixels); OnShow calls WorldMapFrame_Update() directly after
SetMapToCurrentZone (the reference repaints off the synchronous WORLD_MAP_UPDATE; ours fires
next tick — the direct call keeps the open paint flicker-free); ESC/M close via the app key
arm, not OnKeyDown+RunBinding (no binding system).
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script><![CDATA[
NUM_WORLDMAP_DETAIL_TILES = 12;
NUM_WORLDMAP_OVERLAYS = 0;
NUM_WORLDMAP_POIS = 0;
-- ref WorldMapFrame.lua l.509-515 is the spec. Through the PANEL MANAGER, not a bare
-- Show/Hide: the map is registered `area = "full"` (UiPanels.xml), which is what makes it
-- take the screen from the other windows on the way in and — the reason this changed —
-- what stops it opening from behind the game menu, the one window that still could
-- (director-reported, decision 0674).
function ToggleWorldMap()
if ( WorldMapFrame:IsVisible() ) then
HideUIPanel(WorldMapFrame);
else
ShowUIPanel(WorldMapFrame);
end
end
-- Fill the screen: scale the native 1024×768 sheet up until it touches the constraining
-- screen edge — full height on any screen wider than 4:3 (the common case), full width on
-- a narrower one (ref SetupFullscreenScale, deferred at 0203, wired at 0224). The blackout
-- is a SEPARATE unscaled frame behind the sheet, so only the sheet grows.
function SetupFullscreenScale()
local xScale = GetScreenWidth() / 1024;
local yScale = GetScreenHeight() / 768;
local scale = xScale;
if ( yScale < xScale ) then
scale = yScale;
end
WorldMapFrame:SetScale(scale);
end
-- One overlay tile's extent along one axis: how many pixels of art it draws, and how wide
-- the FILE holding them is. Every tile is a full 256 except the last of a row or column,
-- which carries whatever remains of the overlay — and its file is padded up to the next
-- power of two (16 the smallest the art uses), so that tile shows only the leading
-- pixels/file fraction of it. Both axes want the same answer, so they ask the same way.
local function overlayTileExtent(index, count, span)
if ( index < count ) then
return 256, 256;
end
local pixels = mod(span, 256);
if ( pixels == 0 ) then
pixels = 256;
end
local file = 16;
while ( file < pixels ) do
file = file * 2;
end
return pixels, file;
end
-- The repaint (spec: ref WorldMapFrame.lua WorldMapFrame_Update): the tile swap, the
-- discovery-overlay pool, and the zoom-out arming (POI landmarks are still deferred). The
-- "World" fallback is the reference's own hack for the nil GetMapInfo at the world level,
-- kept because our host answers nil at that level for the same reason.
function WorldMapFrame_Update()
local mapFileName = GetMapInfo();
if ( not mapFileName ) then
mapFileName = "World";
end
for i=1, NUM_WORLDMAP_DETAIL_TILES, 1 do
getglobal("WorldMapDetailTile"..i):SetTexture("Interface\\WorldMap\\"..mapFileName.."\\"..mapFileName..i);
end
-- The discovery overlays (spec: ref WorldMapFrame.lua, "Setup the overlays"): the base
-- tiles are the unexplored parchment, and each REVEALED sub-area (GetNumMapOverlays /
-- GetMapOverlayInfo, filtered host-side by the explored bitset) paints its detailed
-- art over them. That art is cut into a grid of 256-px tiles, numbered 1..n across
-- then down, which we lay onto ARTWORK textures pooled on WorldMapDetailFrame — the
-- pool grows on demand, never shrinks, and the tail left over from a busier map is
-- parked hidden below. Offsets are native pixels: the map renders at its native
-- 1024×768 (no WORLDMAP_SX/SY scale, unlike the parked windowed layout), so the
-- overlays share the detail tiles' coordinate space untouched.
local used = 0;
for overlay = 1, GetNumMapOverlays() do
local art, artWidth, artHeight, originX, originY = GetMapOverlayInfo(overlay);
local columns = ceil(artWidth/256);
local rows = ceil(artHeight/256);
local wanted = used + (columns * rows);
if ( wanted > NUM_WORLDMAP_OVERLAYS ) then
for slot = NUM_WORLDMAP_OVERLAYS + 1, wanted do
WorldMapDetailFrame:CreateTexture("WorldMapOverlay"..slot, "ARTWORK");
end
NUM_WORLDMAP_OVERLAYS = wanted;
end
-- Tile n of the overlay is file <art>n, and its place in the grid follows from n.
for tile = 1, columns * rows do
local column = mod(tile - 1, columns) + 1;
local row = ceil(tile / columns);
local wide, fileWide = overlayTileExtent(column, columns, artWidth);
local tall, fileTall = overlayTileExtent(row, rows, artHeight);
used = used + 1;
local texture = getglobal("WorldMapOverlay"..used);
texture:SetWidth(wide);
texture:SetHeight(tall);
texture:SetTexCoord(0, wide/fileWide, 0, tall/fileTall);
texture:ClearAllPoints();
texture:SetPoint("TOPLEFT", originX + (256 * (column - 1)), -(originY + (256 * (row - 1))));
texture:SetTexture(art..tile);
texture:Show();
end
end
for slot = used + 1, NUM_WORLDMAP_OVERLAYS do
getglobal("WorldMapOverlay"..slot):Hide();
end
-- The POI icons (spec: ref WorldMapFrame.lua's landmark pass). One frame per landmark
-- the host reports for the displayed map, grown on demand from WorldMapPOITemplate and
-- never shrunk — the tail from a busier map is parked hidden, like the overlay pool
-- above. Today the host reports exactly one kind, the guard-directions marker
-- (SMSG_GOSSIP_POI); the AreaPOI.dbc landmarks are 0203's deferred slice and arrive
-- through this same list.
local numPOIs = GetNumMapLandmarks();
if ( numPOIs > NUM_WORLDMAP_POIS ) then
for slot = NUM_WORLDMAP_POIS + 1, numPOIs do
CreateFrame("Button", "WorldMapFramePOI"..slot, WorldMapButton, "WorldMapPOITemplate");
end
NUM_WORLDMAP_POIS = numPOIs;
end
for slot = 1, NUM_WORLDMAP_POIS do
local poi = getglobal("WorldMapFramePOI"..slot);
if ( slot > numPOIs ) then
poi:Hide();
else
local name, description, textureIndex, x, y = GetMapLandmarkInfo(slot);
WorldMapPOI_SetTexture(poi, textureIndex);
poi.name = name;
poi.description = description;
poi:ClearAllPoints();
poi:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT",
x * WorldMapDetailFrame:GetWidth(), -y * WorldMapDetailFrame:GetHeight());
poi:Show();
end
end
if ( GetCurrentMapContinent() == 0 ) then
WorldMapZoomOutButton:Disable();
else
WorldMapZoomOutButton:Enable();
end
end
-- Point a POI frame's texture at its cell of Interface\Minimap\POIIcons — an 8x8 grid of
-- icons indexed across then down, the same atlas and the same indexing the minimap's
-- landmark blips use (the corpse marker below hardcodes its own cell of it).
function WorldMapPOI_SetTexture(poi, textureIndex)
local column = mod(textureIndex, 8);
local row = floor(textureIndex / 8);
getglobal(poi:GetName().."Texture"):SetTexCoord(
column * 0.125, (column + 1) * 0.125, row * 0.125, (row + 1) * 0.125);
end
-- Every marker on the sheet — the corpse, a POI — names itself in the shared GameTooltip,
-- and every one of them wants the plate opening AWAY from the edge it sits nearest, so the
-- side pick lives here once instead of in each OnEnter. `subtitle` is the second line the
-- landmarks that carry a live status use; the rest pass nothing.
-- The party blips (ref WorldMapFrame.lua:391-403's party arm, report B320): the same
-- (0,0)-means-hide law as the player and the corpse, one frame per slot.
--
-- It rides the per-frame pass beside those two rather than WorldMapFrame_Update, where the
-- reference keeps it: a member's position moves continuously and the map has no event that
-- fires when it does, so placing it on the repaint alone would freeze every blip between
-- roster changes. Its own function so the live pass and the tests enter it identically.
--
-- The reference's RAID arm is not taken — see the blip frames' note.
function WorldMapParty_Update()
for i = 1, 4 do
local blip = getglobal("WorldMapParty" .. i)
local px, py = GetPlayerMapPosition("party" .. i)
if ( px == 0 and py == 0 ) then
blip:Hide()
else
px = px * WorldMapDetailFrame:GetWidth()
py = -py * WorldMapDetailFrame:GetHeight()
blip:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", px, py)
blip:Show()
end
end
end
-- A party blip's hover names the member (ref WorldMapUnit_OnEnter, which reads the
-- frame's own `unit`). The frame id IS the party slot, so the token needs no bookkeeping.
function WorldMapParty_OnEnter(blip)
local unit = "party" .. blip:GetID()
WorldMapMarker_ShowTooltip(blip, UnitName(unit) or UNKNOWN)
end
function WorldMapMarker_ShowTooltip(marker, title, subtitle)
local markerX = marker:GetCenter();
local sheetX = marker:GetParent():GetCenter();
if ( markerX > sheetX ) then
GameTooltip:SetOwner(marker, "ANCHOR_LEFT");
else
GameTooltip:SetOwner(marker, "ANCHOR_RIGHT");
end
GameTooltip:SetText(title);
if ( subtitle and subtitle ~= "" ) then
GameTooltip:AddLine(subtitle, 1, 1, 1);
end
GameTooltip:Show();
end
-- The reference's rule: zone view → its continent; continent view → the world.
function WorldMapZoomOutButton_OnClick()
if ( GetCurrentMapZone() ~= 0 ) then
SetMapZoom(GetCurrentMapContinent());
else
SetMapZoom(0);
end
end
-- ── The continent/zone dropdowns (the reference's wiring; its `arg.n` vararg walk is
-- written here as select("#", ...), the 5.1-native spelling and this tree's house style
-- for it). ────────────────────────────────────────────────────────────────────────────
function WorldMapContinentsDropDown_OnLoad()
UIDropDownMenu_Initialize(this, WorldMapContinentsDropDown_Initialize);
UIDropDownMenu_SetWidth(130);
end
function WorldMapContinentsDropDown_Initialize()
WorldMapFrame_LoadContinents(GetMapContinents());
end
function WorldMapFrame_LoadContinents(...)
local info;
for i=1, select("#", ...), 1 do
info = {};
info.text = select(i, ...);
info.func = WorldMapContinentButton_OnClick;
UIDropDownMenu_AddButton(info);
end
end
function WorldMapZoneDropDown_OnLoad()
UIDropDownMenu_Initialize(this, WorldMapZoneDropDown_Initialize);
UIDropDownMenu_SetWidth(130);
end
function WorldMapZoneDropDown_Initialize()
WorldMapFrame_LoadZones(GetMapZones(GetCurrentMapContinent()));
end
function WorldMapFrame_LoadZones(...)
local info;
for i=1, select("#", ...), 1 do
info = {};
info.text = select(i, ...);
info.func = WorldMapZoneButton_OnClick;
UIDropDownMenu_AddButton(info);
end
end
function WorldMapContinentButton_OnClick()
UIDropDownMenu_SetSelectedID(WorldMapContinentDropDown, this:GetID());
SetMapZoom(this:GetID());
end
function WorldMapZoneButton_OnClick()
UIDropDownMenu_SetSelectedID(WorldMapZoneDropDown, this:GetID());
SetMapZoom(GetCurrentMapContinent(), this:GetID());
end
function WorldMap_UpdateZoneDropDownText()
if ( GetCurrentMapZone() == 0 ) then
UIDropDownMenu_ClearAll(WorldMapZoneDropDown);
else
UIDropDownMenu_SetSelectedID(WorldMapZoneDropDown, GetCurrentMapZone());
end
end
function WorldMap_UpdateContinentDropDownText()
if ( GetCurrentMapContinent() == 0 ) then
UIDropDownMenu_ClearAll(WorldMapContinentDropDown);
else
UIDropDownMenu_SetSelectedID(WorldMapContinentDropDown, GetCurrentMapContinent());
end
end
-- Where the cursor sits inside a map-sized frame, as a fraction of it measured from the
-- TOPLEFT: (0,0) the top-left corner of the map art, (1,1) the bottom-right. Both sides of
-- the host's map API — the click (ProcessMapClick) and the hover (UpdateMapHighlight) —
-- take a position in exactly that space, and the cursor arrives in screen pixels with the
-- y axis pointing the other way, so this is the one conversion between them: undo the
-- frame's effective scale, then measure from its edges, which a frame gives up as its
-- center and its size (each edge being half the size away from the center).
local function cursorMapPosition(frame)
local cursorX, cursorY = GetCursorPosition();
local scale = frame:GetEffectiveScale();
local midX, midY = frame:GetCenter();
local frameWidth = frame:GetWidth();
local frameHeight = frame:GetHeight();
local fromLeft = (cursorX / scale) - (midX - (frameWidth/2));
local fromTop = (midY + (frameHeight/2)) - (cursorY / scale);
return fromLeft / frameWidth, fromTop / frameHeight;
end
-- Left click drills into whatever the host finds at that map position; every other button
-- is the zoom-out shortcut (ref WorldMapButton_OnClick — ours takes no button argument,
-- since nothing but the map button itself routes here).
function WorldMapButton_OnClick(mouseButton)
CloseDropDownMenus();
if ( mouseButton == "LeftButton" ) then
ProcessMapClick(cursorMapPosition(WorldMapButton));
else
WorldMapZoomOutButton_OnClick();
end
end
-- The per-frame hover pass (spec: ref WorldMapButton_OnUpdate), reduced to the area
-- highlight + the player blip (raid/flags/ping are still deferred; the party blips
-- landed with B320 and ride WorldMapFrame_Update, not this pass).
-- UpdateMapHighlight is a stub until the area-bitmap source lands (wow-re dispatch) — a
-- nil area/art takes the hide paths.
function WorldMapButton_OnUpdate(elapsed)
local width = this:GetWidth();
local height = this:GetHeight();
local area, art, cropX, cropY, sizeX, sizeY, atX, atY =
UpdateMapHighlight(cursorMapPosition(this));
WorldMapFrameAreaLabel:SetText(area or "");
if ( art ) then
-- The sub-area under the cursor lights up: <zone>Highlight holds one shape per
-- sub-area, of which crop names the fraction actually used (the file is padded to
-- a power of two), while size and at are the shape's extent and top-left corner as
-- fractions of the map — so both scale by the button's pixel size. Nothing to draw
-- for a degenerate shape, but the art is still swapped in for the next frame.
WorldMapHighlight:SetTexCoord(0, cropX, 0, cropY);
WorldMapHighlight:SetTexture("Interface\\WorldMap\\"..art.."\\"..art.."Highlight");
local drawWidth = sizeX * width;
local drawHeight = sizeY * height;
if ( drawWidth > 0 and drawHeight > 0 ) then
WorldMapHighlight:SetWidth(drawWidth);
WorldMapHighlight:SetHeight(drawHeight);
WorldMapHighlight:SetPoint("TOPLEFT", "WorldMapDetailFrame", "TOPLEFT", atX * width, -atY * height);
WorldMapHighlight:Show();
end
else
WorldMapHighlight:Hide();
end
-- The player blip: the reference's engine arrow, as our rotating texture stand-in.
WorldMapPlayerIcon:SetRotation(GetPlayerFacing());
local playerX, playerY = GetPlayerMapPosition("player");
if ( playerX == 0 and playerY == 0 ) then
WorldMapPlayer:Hide();
else
playerX = playerX * WorldMapDetailFrame:GetWidth();
playerY = -playerY * WorldMapDetailFrame:GetHeight();
WorldMapPlayer:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", playerX, playerY);
WorldMapPlayer:Show();
end
WorldMapParty_Update()
-- Position corpse (ref WorldMapFrame.lua:443-452 — the law is that (0,0) means hide).
local corpseX, corpseY = GetCorpseMapPosition();
if ( corpseX == 0 and corpseY == 0 ) then
WorldMapCorpse:Hide();
else
corpseX = corpseX * WorldMapDetailFrame:GetWidth();
corpseY = -corpseY * WorldMapDetailFrame:GetHeight();
WorldMapCorpse:SetPoint("CENTER", "WorldMapDetailFrame", "TOPLEFT", corpseX, corpseY);
WorldMapCorpse:Show();
end
end
]]></Script>
<!-- The fullscreen blackout — a separate, UNSCALED frame behind the map sheet (0224). The map
itself (WorldMapFrame) is now the native 1024×768 sheet that SetupFullscreenScale grows to
fill the screen; the blackout stays screen-sized so the world never shows through the
margins, and eats clicks so nothing leaks to the world behind it. -->
<Frame name="WorldMapBlackout" frameStrata="FULLSCREEN" hidden="true" enableMouse="true" parent="UIParent">
<Anchors>
<Anchor point="TOPLEFT"/>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture setAllPoints="true"><Color r="0.0" g="0.0" b="0.0"/></Texture>
</Layer>
</Layers>
</Frame>
<!-- One POI icon on the map (spec: ref WorldMapPOITemplate, WorldMapFrameTemplates.xml): a
16x16 cell of Interface\Minimap\POIIcons picked by the landmark's own textureIndex, with a
name/description tooltip. Grown on demand by WorldMapFrame_Update into WorldMapButton. -->
<Button name="WorldMapPOITemplate" virtual="true" enableMouse="true">
<Size><AbsDimension x="16" y="16"/></Size>
<Layers>
<Layer level="ARTWORK">
<Texture name="$parentTexture" file="Interface\Minimap\POIIcons" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>
WorldMapMarker_ShowTooltip(this, this.name, this.description);
</OnEnter>
<OnLeave>
GameTooltip:Hide();
</OnLeave>
</Scripts>
</Button>
<Frame name="WorldMapFrame" frameStrata="FULLSCREEN_DIALOG" hidden="true" enableMouse="true" parent="UIParent">
<Size><AbsDimension x="1024" y="768"/></Size>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\WorldMap\UI-WorldMap-Top1">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-512" y="384"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Top2">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-256" y="384"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Top3">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="0" y="384"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Top4">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="256" y="384"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Middle1">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-512" y="128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Middle2">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-256" y="128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Middle3">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="0" y="128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Middle4">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="256" y="128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Bottom1">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-512" y="-128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Bottom2">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="-256" y="-128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Bottom3">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-128"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\WorldMap\UI-WorldMap-Bottom4">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativePoint="CENTER"><Offset><AbsDimension x="256" y="-128"/></Offset></Anchor></Anchors>
</Texture>
<FontString inherits="GameFontNormal" text="World Map">
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="372"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Frame name="WorldMapPositioningGuide">
<Size><AbsDimension x="1024" y="768"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
</Frame>
<!-- ref: the continent picker (id 1) at the top row's left, the zone picker (id 2)
chained to its right, the zoom-out button closing the row. OnLoad instead of the
ref's OnShow (our engine fires OnShow only on the frame itself, not children of
a shown parent; OnLoad + the WORLD_MAP_UPDATE re-init below cover every open). -->
<Frame name="WorldMapContinentDropDown" inherits="UIDropDownMenuTemplate" id="1">
<Anchors>
<Anchor point="TOP" relativePoint="TOP" relativeTo="WorldMapPositioningGuide">
<Offset><AbsDimension x="-80" y="-35"/></Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="OVERLAY">
<FontString inherits="GameFontNormalSmall" text="Continent">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="20" y="10"/></Offset></Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
WorldMapContinentsDropDown_OnLoad();
</OnLoad>
</Scripts>
</Frame>
<Frame name="WorldMapZoneDropDown" inherits="UIDropDownMenuTemplate" id="2">
<Anchors>
<Anchor point="LEFT" relativeTo="WorldMapContinentDropDown" relativePoint="RIGHT">
<Offset><AbsDimension x="-33" y="0"/></Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="OVERLAY">
<FontString inherits="GameFontNormalSmall" text="Zone">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="20" y="10"/></Offset></Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
WorldMapZoneDropDown_OnLoad();
this:RegisterEvent("WORLD_MAP_UPDATE");
</OnLoad>
<OnEvent>
if ( this:IsVisible() ) then
WorldMapContinentsDropDown_OnLoad();
WorldMap_UpdateContinentDropDownText();
WorldMapZoneDropDown_OnLoad();
WorldMap_UpdateZoneDropDownText();
end
</OnEvent>
</Scripts>
</Frame>
<Button name="WorldMapZoomOutButton" text="Zoom Out">
<Size><AbsDimension x="110" y="22"/></Size>
<Anchors>
<Anchor point="LEFT" relativeTo="WorldMapZoneDropDown" relativePoint="RIGHT">
<Offset><AbsDimension x="-10" y="3"/></Offset>
</Anchor>
</Anchors>
<NormalFont inherits="GameFontNormal"/>
<HighlightFont inherits="GameFontHighlight"/>
<DisabledFont inherits="GameFontDisable"/>
<NormalTexture file="Interface\Buttons\UI-Panel-Button-Up"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></NormalTexture>
<PushedTexture file="Interface\Buttons\UI-Panel-Button-Down"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></PushedTexture>
<DisabledTexture file="Interface\Buttons\UI-Panel-Button-Disabled"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></DisabledTexture>
<HighlightTexture file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></HighlightTexture>
<Scripts>
<OnClick>WorldMapZoomOutButton_OnClick();</OnClick>
</Scripts>
</Button>
<Button name="WorldMapFrameCloseButton">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors>
<Anchor point="TOPRIGHT" relativePoint="TOP" relativeTo="WorldMapPositioningGuide">
<Offset><AbsDimension x="516" y="4"/></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>HideUIPanel(WorldMapFrame);</OnClick>
</Scripts>
</Button>
<Frame name="WorldMapDetailFrame">
<Size><AbsDimension x="1002" y="668"/></Size>
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOP" relativeTo="WorldMapPositioningGuide">
<Offset><AbsDimension x="-502" y="-69"/></Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="WorldMapDetailTile1">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile2">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile1" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile3">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile2" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile4">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile3" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile5">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile1" relativePoint="BOTTOMLEFT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile6">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile5" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile7">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile6" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile8">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile7" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile9">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile5" relativePoint="BOTTOMLEFT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile10">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile9" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile11">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile10" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="WorldMapDetailTile12">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailTile11" relativePoint="TOPRIGHT"/></Anchors>
</Texture>
</Layer>
<Layer level="ARTWORK">
<Texture name="WorldMapHighlight" alphaMode="ADD" hidden="true">
<Size><AbsDimension x="128" y="128"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
</Texture>
</Layer>
</Layers>
</Frame>
<Button name="WorldMapButton" enableMouse="true">
<Size><AbsDimension x="1002" y="668"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="WorldMapDetailFrame"/></Anchors>
<Frames>
<Frame name="WorldMapPlayer">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="OVERLAY">
<Texture name="WorldMapPlayerIcon" file="Interface\Minimap\MinimapArrow" setAllPoints="true"/>
</Layer>
</Layers>
</Frame>
<!-- The corpse marker (decision 0308 §5) — ref WorldMapCorpseTemplate
(WorldMapFrameTemplates.xml l.55-88) inlined: 16x16, the POIIcons skull
cell (0.875-1.0 / 0-0.125), hover names it CORPSE_RED. The ref anchors its
tooltip to a WorldMapTooltip; ours rides the shared GameTooltip (this
map ships no separate tooltip — header note) through the side-pick every
marker on the sheet shares. -->
<Frame name="WorldMapCorpse" hidden="true" enableMouse="true">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\Minimap\POIIcons" setAllPoints="true">
<TexCoords left="0.875" right="1.0" top="0" bottom="0.125"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnEnter>
WorldMapMarker_ShowTooltip(this, "|cffff2020Corpse|r")
</OnEnter>
<OnLeave>
GameTooltip:Hide()
</OnLeave>
</Scripts>
</Frame>
<!-- The party blips (report B320) — ref WorldMapUnitTemplate
(WorldMapFrameTemplates.xml l.3-28) re-expressed: 16x16 centered,
WorldMapPartyIcon art, one frame per `party1..4` slot, placed by
GetPlayerMapPosition in the Update above. The reference hovers them into
its own WorldMapTooltip; this map ships none (header note), so they take
the shared GameTooltip through WorldMapMarker_ShowTooltip exactly as the
corpse marker beside them does.
The reference's RAID pool (25 more frames, its `GetNumRaidMembers() > 0`
arm) is NOT here: `GetPlayerMapPosition` answers no `raid` token yet, so
a raid would show these four filled from its own subgroup and nothing
else. That is the honest half-step, and it is named in the OUT list. -->
<Frame name="WorldMapParty1" hidden="true" enableMouse="true" id="1">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\WorldMap\WorldMapPartyIcon" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>WorldMapParty_OnEnter(this)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Frame>
<Frame name="WorldMapParty2" hidden="true" enableMouse="true" id="2">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\WorldMap\WorldMapPartyIcon" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>WorldMapParty_OnEnter(this)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Frame>
<Frame name="WorldMapParty3" hidden="true" enableMouse="true" id="3">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\WorldMap\WorldMapPartyIcon" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>WorldMapParty_OnEnter(this)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Frame>
<Frame name="WorldMapParty4" hidden="true" enableMouse="true" id="4">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture file="Interface\WorldMap\WorldMapPartyIcon" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>WorldMapParty_OnEnter(this)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Frame>
<Frame name="WorldMapFrameAreaFrame">
<Size><AbsDimension x="400" y="128"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-10"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="OVERLAY">
<FontString name="WorldMapFrameAreaLabel" inherits="WorldMapTextFont">
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="20" y="-20"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="WorldMapFrameAreaDescription" inherits="SubZoneTextFont">
<Anchors><Anchor point="TOP" relativeTo="WorldMapFrameAreaLabel" relativePoint="BOTTOM"/></Anchors>
</FontString>
</Layer>
</Layers>
</Frame>
</Frames>
<Scripts>
<OnLoad>
this:RegisterForClicks("LeftButtonUp", "RightButtonUp");
</OnLoad>
<OnClick>
WorldMapButton_OnClick(arg1);
</OnClick>
<OnUpdate>
WorldMapButton_OnUpdate(arg1);
</OnUpdate>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>
this:RegisterEvent("WORLD_MAP_UPDATE");
-- The hover area label inherits WorldMapTextFont (nominal 102). 33 was the
-- director's taste call (0235) — which the one-to-one raster cap (the fold-back
-- record; wow-re fontstring-overflow.md) now clamps to the byte law's 32, one
-- unit under that call and closer to it than the 36 the atlas snap used to
-- deliver. The real client draws this SetFont(33) at 32 too. Still a taste dial:
-- any value ≤ 32 is honored exactly.
WorldMapFrameAreaLabel:SetFont("Fonts\\FRIZQT__.TTF", 33);
WorldMapFrame_Update();
</OnLoad>
<!-- UpdateMicroButtons leads both, as in the ref (WorldMapFrame.xml l.599/606) — live
since the micro-menu slice (MicroMenu.xml). -->
<OnShow>
WorldMapBlackout:Show();
SetupFullscreenScale();
SetMapToCurrentZone();
WorldMapFrame_Update();
if UpdateMicroButtons then UpdateMicroButtons() end;
PlaySound("igQuestLogOpen");
CloseDropDownMenus();
</OnShow>
<OnHide>
WorldMapBlackout:Hide();
if UpdateMicroButtons then UpdateMicroButtons() end;
PlaySound("igQuestLogClose");
</OnHide>
<OnEvent>
if ( WorldMapFrame:IsVisible() ) then
WorldMapFrame_Update();
end
</OnEvent>
</Scripts>
</Frame>
</Ui>