init
This commit is contained in:
337
MapIcons.lua
Normal file
337
MapIcons.lua
Normal file
@@ -0,0 +1,337 @@
|
||||
--------------------------------------------------------------------------------
|
||||
-- Nanami-UI: MapIcons - Class-colored party/raid icons on maps
|
||||
-- Shows class icon circles on World Map, Battlefield Minimap, and Minimap
|
||||
-- Uses UI-Classes-Circles.tga for class-specific circular portraits
|
||||
-- Zone size data: prefers pfQuest DB, falls back to built-in table
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
SFrames.MapIcons = SFrames.MapIcons or {}
|
||||
local MI = SFrames.MapIcons
|
||||
|
||||
local CLASS_ICON_PATH = "Interface\\AddOns\\Nanami-UI\\img\\UI-Classes-Circles"
|
||||
local CLASS_ICON_TCOORDS = SFrames.CLASS_ICON_TCOORDS
|
||||
local CLASS_COLORS = SFrames.Config.colors.class
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Minimap zoom yard ranges: [indoor/outdoor][zoomLevel] = diameter in yards
|
||||
-- indoor=0, outdoor=1
|
||||
--------------------------------------------------------------------------------
|
||||
local MM_ZOOM = {
|
||||
[0] = { [0]=300, [1]=240, [2]=180, [3]=120, [4]=80, [5]=50 },
|
||||
[1] = { [0]=466.67, [1]=400, [2]=333.33, [3]=266.67, [4]=200, [5]=133.33 },
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Built-in zone sizes (width, height in yards) keyed by GetMapInfo() file name
|
||||
-- Fallback when pfQuest is not installed
|
||||
--------------------------------------------------------------------------------
|
||||
local ZONE_SIZES = {
|
||||
["Ashenvale"] = { 5766.67, 3843.75 },
|
||||
["Aszhara"] = { 5533.33, 3689.58 },
|
||||
["Darkshore"] = { 6550.00, 4366.66 },
|
||||
["Desolace"] = { 4600.00, 3066.67 },
|
||||
["Durotar"] = { 4925.00, 3283.34 },
|
||||
["Dustwallow"] = { 5250.00, 3500.00 },
|
||||
["Felwood"] = { 5750.00, 3833.33 },
|
||||
["Feralas"] = { 6950.00, 4633.33 },
|
||||
["Moonglade"] = { 2308.33, 1539.59 },
|
||||
["Mulgore"] = { 5250.00, 3500.00 },
|
||||
["Silithus"] = { 3483.33, 2322.92 },
|
||||
["StonetalonMountains"] = { 4883.33, 3256.25 },
|
||||
["Tanaris"] = { 6900.00, 4600.00 },
|
||||
["Teldrassil"] = { 4925.00, 3283.34 },
|
||||
["Barrens"] = { 10133.34, 6756.25 },
|
||||
["ThousandNeedles"] = { 4400.00, 2933.33 },
|
||||
["UngoroCrater"] = { 3677.08, 2452.08 },
|
||||
["Winterspring"] = { 7100.00, 4733.33 },
|
||||
["Alterac"] = { 2800.00, 1866.67 },
|
||||
["ArathiHighlands"] = { 3600.00, 2400.00 },
|
||||
["Badlands"] = { 2487.50, 1658.34 },
|
||||
["BlastedLands"] = { 3350.00, 2233.30 },
|
||||
["BurningSteppes"] = { 2929.16, 1952.08 },
|
||||
["DeadwindPass"] = { 2500.00, 1666.63 },
|
||||
["DunMorogh"] = { 4925.00, 3283.34 },
|
||||
["Duskwood"] = { 2700.00, 1800.03 },
|
||||
["EasternPlaguelands"] = { 4031.25, 2687.50 },
|
||||
["ElwynnForest"] = { 3470.84, 2314.62 },
|
||||
["Hilsbrad"] = { 3200.00, 2133.33 },
|
||||
["Hinterlands"] = { 3850.00, 2566.67 },
|
||||
["LochModan"] = { 2758.33, 1839.58 },
|
||||
["RedridgeMountains"] = { 2170.84, 1447.90 },
|
||||
["SearingGorge"] = { 1837.50, 1225.00 },
|
||||
["SilverpineForest"] = { 4200.00, 2800.00 },
|
||||
["Stranglethorn"] = { 6381.25, 4254.10 },
|
||||
["SwampOfSorrows"] = { 2293.75, 1529.17 },
|
||||
["Tirisfal"] = { 4518.75, 3012.50 },
|
||||
["WesternPlaguelands"] = { 4300.00, 2866.67 },
|
||||
["Westfall"] = { 3500.00, 2333.30 },
|
||||
["Wetlands"] = { 4300.00, 2866.67 },
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Indoor detection (CVar trick from pfQuest)
|
||||
-- Returns 0 = indoor, 1 = outdoor
|
||||
--------------------------------------------------------------------------------
|
||||
local cachedIndoor = 1
|
||||
local indoorCheckTime = 0
|
||||
|
||||
local function DetectIndoor()
|
||||
if pfMap and pfMap.minimap_indoor then
|
||||
return pfMap.minimap_indoor()
|
||||
end
|
||||
local ok1, zoomVal = pcall(GetCVar, "minimapZoom")
|
||||
local ok2, insideVal = pcall(GetCVar, "minimapInsideZoom")
|
||||
if not ok1 or not ok2 then return 1 end
|
||||
local tempzoom = 0
|
||||
local state = 1
|
||||
if zoomVal == insideVal then
|
||||
local cur = Minimap:GetZoom()
|
||||
if cur >= 3 then
|
||||
Minimap:SetZoom(cur - 1)
|
||||
tempzoom = 1
|
||||
else
|
||||
Minimap:SetZoom(cur + 1)
|
||||
tempzoom = -1
|
||||
end
|
||||
end
|
||||
local ok3, zoomVal2 = pcall(GetCVar, "minimapZoom")
|
||||
local ok4, insideVal2 = pcall(GetCVar, "minimapInsideZoom")
|
||||
if ok3 and ok4 and zoomVal2 ~= insideVal2 then
|
||||
state = 0
|
||||
end
|
||||
if tempzoom ~= 0 then
|
||||
Minimap:SetZoom(Minimap:GetZoom() + tempzoom)
|
||||
end
|
||||
return state
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Get current zone dimensions in yards
|
||||
--------------------------------------------------------------------------------
|
||||
local function GetZoneYards()
|
||||
if pfMap and pfMap.GetMapIDByName and pfDB and pfDB["minimap"] then
|
||||
local name = GetRealZoneText and GetRealZoneText() or ""
|
||||
if name ~= "" then
|
||||
local id = pfMap:GetMapIDByName(name)
|
||||
if id and pfDB["minimap"][id] then
|
||||
return pfDB["minimap"][id][1], pfDB["minimap"][id][2]
|
||||
end
|
||||
end
|
||||
end
|
||||
if GetMapInfo then
|
||||
local ok, info = pcall(GetMapInfo)
|
||||
if ok and info and ZONE_SIZES[info] then
|
||||
return ZONE_SIZES[info][1], ZONE_SIZES[info][2]
|
||||
end
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 1. World Map + Battlefield Minimap: class icon overlays
|
||||
--------------------------------------------------------------------------------
|
||||
local mapButtons
|
||||
|
||||
local function InitMapButtons()
|
||||
if mapButtons then return end
|
||||
mapButtons = {}
|
||||
for i = 1, 4 do
|
||||
mapButtons["WorldMapParty" .. i] = "party" .. i
|
||||
mapButtons["BattlefieldMinimapParty" .. i] = "party" .. i
|
||||
end
|
||||
for i = 1, 40 do
|
||||
mapButtons["WorldMapRaid" .. i] = "raid" .. i
|
||||
mapButtons["BattlefieldMinimapRaid" .. i] = "raid" .. i
|
||||
end
|
||||
end
|
||||
|
||||
local mapTickTime = 0
|
||||
|
||||
local function UpdateMapClassIcons()
|
||||
mapTickTime = mapTickTime + (arg1 or 0)
|
||||
if mapTickTime < 0.15 then return end
|
||||
mapTickTime = 0
|
||||
|
||||
if not mapButtons then InitMapButtons() end
|
||||
|
||||
local _G = getfenv(0)
|
||||
for name, unit in pairs(mapButtons) do
|
||||
local frame = _G[name]
|
||||
if frame and frame:IsVisible() and UnitExists(unit) then
|
||||
local defIcon = _G[name .. "Icon"]
|
||||
if defIcon then defIcon:SetTexture() end
|
||||
|
||||
if not frame.nanamiClassTex then
|
||||
frame.nanamiClassTex = frame:CreateTexture(nil, "OVERLAY")
|
||||
frame.nanamiClassTex:SetTexture(CLASS_ICON_PATH)
|
||||
frame.nanamiClassTex:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, -2)
|
||||
frame.nanamiClassTex:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -2, 2)
|
||||
end
|
||||
|
||||
local _, class = UnitClass(unit)
|
||||
if class and CLASS_ICON_TCOORDS and CLASS_ICON_TCOORDS[class] then
|
||||
local tc = CLASS_ICON_TCOORDS[class]
|
||||
frame.nanamiClassTex:SetTexCoord(tc[1], tc[2], tc[3], tc[4])
|
||||
frame.nanamiClassTex:Show()
|
||||
else
|
||||
frame.nanamiClassTex:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- 2. Minimap: class-colored party dot overlays
|
||||
--------------------------------------------------------------------------------
|
||||
local MAX_PARTY = 4
|
||||
local mmDots = {}
|
||||
|
||||
local function CreateMinimapDot(index)
|
||||
local dot = CreateFrame("Frame", "NanamiMMDot" .. index, Minimap)
|
||||
dot:SetWidth(10)
|
||||
dot:SetHeight(10)
|
||||
dot:SetFrameStrata("MEDIUM")
|
||||
dot:SetFrameLevel(Minimap:GetFrameLevel() + 5)
|
||||
|
||||
dot.icon = dot:CreateTexture(nil, "ARTWORK")
|
||||
dot.icon:SetTexture("Interface\\Minimap\\UI-Minimap-Background")
|
||||
dot.icon:SetAllPoints()
|
||||
dot.icon:SetVertexColor(1, 0.82, 0, 1)
|
||||
|
||||
dot:Hide()
|
||||
return dot
|
||||
end
|
||||
|
||||
local mmTickTime = 0
|
||||
|
||||
local function UpdateMinimapDots()
|
||||
mmTickTime = mmTickTime + (arg1 or 0)
|
||||
if mmTickTime < 0.25 then return end
|
||||
mmTickTime = 0
|
||||
|
||||
if not Minimap or not Minimap:IsVisible() then
|
||||
for i = 1, MAX_PARTY do
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local numParty = GetNumPartyMembers and GetNumPartyMembers() or 0
|
||||
if numParty == 0 then
|
||||
for i = 1, MAX_PARTY do
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if WorldMapFrame and WorldMapFrame:IsVisible() then
|
||||
return
|
||||
end
|
||||
|
||||
if SetMapToCurrentZone then
|
||||
pcall(SetMapToCurrentZone)
|
||||
end
|
||||
|
||||
local px, py = GetPlayerMapPosition("player")
|
||||
if not px or not py or (px == 0 and py == 0) then
|
||||
for i = 1, MAX_PARTY do
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local zw, zh = GetZoneYards()
|
||||
if not zw or not zh or zw == 0 or zh == 0 then
|
||||
for i = 1, MAX_PARTY do
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local now = GetTime()
|
||||
if now - indoorCheckTime > 3 then
|
||||
indoorCheckTime = now
|
||||
cachedIndoor = DetectIndoor()
|
||||
end
|
||||
|
||||
local zoom = Minimap:GetZoom()
|
||||
local mmYards = MM_ZOOM[cachedIndoor] and MM_ZOOM[cachedIndoor][zoom]
|
||||
or MM_ZOOM[1][zoom] or 466.67
|
||||
local mmHalfYards = mmYards / 2
|
||||
local mmHalfPx = Minimap:GetWidth() / 2
|
||||
|
||||
local facing = 0
|
||||
local doRotate = false
|
||||
local okCvar, rotateVal = pcall(GetCVar, "rotateMinimap")
|
||||
if okCvar and rotateVal == "1" and GetPlayerFacing then
|
||||
local ok2, f = pcall(GetPlayerFacing)
|
||||
if ok2 and f then
|
||||
facing = f
|
||||
doRotate = true
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, MAX_PARTY do
|
||||
local unit = "party" .. i
|
||||
if i <= numParty and UnitExists(unit) and UnitIsConnected(unit) then
|
||||
local mx, my = GetPlayerMapPosition(unit)
|
||||
if mx and my and (mx ~= 0 or my ~= 0) then
|
||||
local dx = (mx - px) * zw
|
||||
local dy = (py - my) * zh
|
||||
|
||||
if doRotate then
|
||||
local s = math.sin(facing)
|
||||
local c = math.cos(facing)
|
||||
dx, dy = dx * c + dy * s, -dx * s + dy * c
|
||||
end
|
||||
|
||||
local dist = math.sqrt(dx * dx + dy * dy)
|
||||
if dist < mmHalfYards * 0.92 then
|
||||
local scale = mmHalfPx / mmHalfYards
|
||||
|
||||
if not mmDots[i] then
|
||||
mmDots[i] = CreateMinimapDot(i)
|
||||
end
|
||||
local dot = mmDots[i]
|
||||
|
||||
local _, class = UnitClass(unit)
|
||||
local cc = class and CLASS_COLORS and CLASS_COLORS[class]
|
||||
if cc then
|
||||
dot.icon:SetVertexColor(cc.r, cc.g, cc.b, 1)
|
||||
else
|
||||
dot.icon:SetVertexColor(1, 0.82, 0, 1)
|
||||
end
|
||||
|
||||
dot:ClearAllPoints()
|
||||
dot:SetPoint("CENTER", Minimap, "CENTER", dx * scale, dy * scale)
|
||||
dot:Show()
|
||||
else
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
else
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
else
|
||||
if mmDots[i] then mmDots[i]:Hide() end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Initialize
|
||||
--------------------------------------------------------------------------------
|
||||
function MI:Initialize()
|
||||
InitMapButtons()
|
||||
|
||||
local updater = CreateFrame("Frame", "NanamiMapIconsUpdater", UIParent)
|
||||
updater._elapsed = 0
|
||||
updater:SetScript("OnUpdate", function()
|
||||
this._elapsed = (this._elapsed or 0) + arg1
|
||||
if this._elapsed < 0.2 then return end
|
||||
this._elapsed = 0
|
||||
UpdateMapClassIcons()
|
||||
UpdateMinimapDots()
|
||||
end)
|
||||
|
||||
SFrames:Print("地图职业图标模块已加载")
|
||||
end
|
||||
Reference in New Issue
Block a user