386 lines
20 KiB
Lua
386 lines
20 KiB
Lua
--------------------------------------------------------------------------------
|
|
-- Nanami-UI: Zone Level Range Module (ZoneLevelRange.lua)
|
|
-- Displays zone level ranges, territory status, instances and raids
|
|
-- on the world map continent view using Nanami-themed tooltip.
|
|
-- Self-contained data; supersedes LevelRange-Turtle's display.
|
|
--------------------------------------------------------------------------------
|
|
|
|
SFrames = SFrames or {}
|
|
SFrames.ZoneLevelRange = {}
|
|
local ZLR = SFrames.ZoneLevelRange
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Locale helper
|
|
--------------------------------------------------------------------------------
|
|
local isZH = (GetLocale() == "zhCN")
|
|
local function N(en, zh) return isZH and zh or en end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Faction constants
|
|
--------------------------------------------------------------------------------
|
|
local F_A = "Alliance"
|
|
local F_H = "Horde"
|
|
local F_C = "Contested"
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Zone Level Ranges: [localizedName] = { min, max, factionType }
|
|
--------------------------------------------------------------------------------
|
|
local ZONE_RANGES = {
|
|
-- Eastern Kingdoms
|
|
[N("Elwynn Forest", "艾尔文森林")] = { 1, 10, F_A },
|
|
[N("Dun Morogh", "丹莫罗")] = { 1, 10, F_A },
|
|
[N("Tirisfal Glades", "提瑞斯法林地")] = { 1, 10, F_H },
|
|
[N("Loch Modan", "洛克莫丹")] = { 10, 20, F_A },
|
|
[N("Silverpine Forest", "银松森林")] = { 10, 20, F_H },
|
|
[N("Westfall", "西部荒野")] = { 10, 20, F_A },
|
|
[N("Redridge Mountains", "赤脊山")] = { 15, 25, F_C },
|
|
[N("Duskwood", "暮色森林")] = { 18, 30, F_C },
|
|
[N("Hillsbrad Foothills", "希尔斯布莱德丘陵")] = { 20, 30, F_C },
|
|
[N("Wetlands", "湿地")] = { 20, 30, F_C },
|
|
[N("Alterac Mountains", "奥特兰克山脉")] = { 30, 40, F_C },
|
|
[N("Arathi Highlands", "阿拉希高地")] = { 30, 40, F_C },
|
|
[N("Stranglethorn Vale", "荆棘谷")] = { 30, 45, F_C },
|
|
[N("Badlands", "荒芜之地")] = { 35, 45, F_C },
|
|
[N("Swamp of Sorrows", "悲伤沼泽")] = { 35, 45, F_C },
|
|
[N("The Hinterlands", "辛特兰")] = { 40, 50, F_C },
|
|
[N("Searing Gorge", "灼热峡谷")] = { 43, 50, F_C },
|
|
[N("Blasted Lands", "诅咒之地")] = { 45, 55, F_C },
|
|
[N("Burning Steppes", "燃烧平原")] = { 50, 58, F_C },
|
|
[N("Western Plaguelands", "西瘟疫之地")] = { 51, 58, F_C },
|
|
[N("Eastern Plaguelands", "东瘟疫之地")] = { 53, 60, F_C },
|
|
[N("Deadwind Pass", "逆风小径")] = { 55, 60, F_C },
|
|
|
|
-- Kalimdor
|
|
[N("Durotar", "杜隆塔尔")] = { 1, 10, F_H },
|
|
[N("Mulgore", "莫高雷")] = { 1, 10, F_H },
|
|
[N("Teldrassil", "泰达希尔")] = { 1, 10, F_A },
|
|
[N("Darkshore", "黑海岸")] = { 10, 20, F_A },
|
|
[N("The Barrens", "贫瘠之地")] = { 10, 25, F_H },
|
|
[N("Stonetalon Mountains", "石爪山脉")] = { 15, 27, F_C },
|
|
[N("Ashenvale", "灰谷")] = { 18, 30, F_C },
|
|
[N("Thousand Needles", "千针石林")] = { 25, 35, F_C },
|
|
[N("Desolace", "凄凉之地")] = { 30, 40, F_C },
|
|
[N("Dustwallow Marsh", "尘泥沼泽")] = { 35, 45, F_C },
|
|
[N("Feralas", "菲拉斯")] = { 40, 50, F_C },
|
|
[N("Tanaris", "塔纳利斯")] = { 40, 50, F_C },
|
|
[N("Azshara", "艾萨拉")] = { 45, 55, F_C },
|
|
[N("Felwood", "费伍德森林")] = { 48, 55, F_C },
|
|
[N("Un'Goro Crater", "安戈洛环形山")] = { 48, 55, F_C },
|
|
[N("Silithus", "希利苏斯")] = { 55, 60, F_C },
|
|
[N("Winterspring", "冬泉谷")] = { 55, 60, F_C },
|
|
[N("Moonglade", "月光林地")] = { 1, 60, F_C },
|
|
|
|
-- Turtle WoW
|
|
[N("Thalassian Highlands", "阿尔萨拉斯")] = { 1, 10, F_A },
|
|
[N("Blackstone Island", "黑石岛")] = { 1, 10, F_H },
|
|
[N("Gilneas", "吉尔尼斯")] = { 39, 46, F_C },
|
|
[N("Gillijim's Isle", "吉利吉姆之岛")] = { 48, 53, F_C },
|
|
[N("Lapidis Isle", "拉匹迪斯之岛")] = { 48, 53, F_C },
|
|
[N("Tel'Abim", "泰拉比姆")] = { 54, 60, F_C },
|
|
[N("Scarlet Enclave", "东瘟疫之地:血色领地")] = { 55, 60, F_C },
|
|
[N("Hyjal", "海加尔山")] = { 58, 60, F_C },
|
|
[N("Grim Reaches", "冷酷海岸")] = { 33, 38, F_C },
|
|
[N("Northwind", "北风领")] = { 28, 34, F_C },
|
|
[N("Balor", "巴洛")] = { 29, 34, F_C },
|
|
[N("Moonsong Coast", "月语海岸")] = { 53, 58, F_C },
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Instances: [zoneName] = { { instanceName, levelString }, ... }
|
|
--------------------------------------------------------------------------------
|
|
local ZONE_INSTANCES = {
|
|
[N("Westfall", "西部荒野")] = { { N("Deadmines", "死亡矿井"), "17-26" } },
|
|
[N("The Barrens", "贫瘠之地")] = { { N("Wailing Caverns", "哀嚎洞穴"), "17-24" },
|
|
{ N("Razorfen Kraul", "剃刀高地"), "25-30" },
|
|
{ N("Razorfen Downs", "剃刀沼泽"), "33-45" } },
|
|
[N("Silverpine Forest", "银松森林")] = { { N("Shadowfang Keep", "影牙城堡"), "22-30" } },
|
|
[N("Dun Morogh", "丹莫罗")] = { { N("Gnomeregan", "诺莫瑞根"), "29-38" } },
|
|
[N("Tirisfal Glades", "提瑞斯法林地")] = { { N("The Scarlet Monastery","血色修道院"), "34-45" } },
|
|
[N("Badlands", "荒芜之地")] = { { N("Uldaman", "奥达曼"), "35-47" } },
|
|
[N("Desolace", "凄凉之地")] = { { N("Maraudon", "玛拉顿"), "46-55" } },
|
|
[N("Swamp of Sorrows", "悲伤沼泽")] = { { N("The Sunken Temple", "沉没的神庙"), "45-55" } },
|
|
[N("Searing Gorge", "灼热峡谷")] = { { N("Blackrock Depths", "黑石深渊"), "52-60" },
|
|
{ N("Blackrock Spire", "黑石塔"), "58-60" } },
|
|
[N("Eastern Plaguelands", "东瘟疫之地")] = { { N("Stratholme", "斯坦索姆"), "58-60" } },
|
|
[N("Feralas", "菲拉斯")] = { { N("Dire Maul", "厄运之槌"), "55-60" } },
|
|
[N("Western Plaguelands", "西瘟疫之地")] = { { N("Scholomance", "通灵学院"), "57-60" } },
|
|
[N("Durotar", "杜隆塔尔")] = { { N("Ragefire Chasm", "怒焰裂谷"), "13-18" } },
|
|
[N("Ashenvale", "灰谷")] = { { N("Blackfathom Deeps", "黑暗深渊"), "24-32" },
|
|
{ N("The Crescent Grove", "新月林地"), "32-38" } },
|
|
[N("Gilneas", "吉尔尼斯")] = { { N("Gilneas City", "吉尔尼斯城"), "43-49" } },
|
|
[N("Burning Steppes", "燃烧平原")] = { { N("Hateforge Quarry", "仇恨熔炉采石场"), "52-60" },
|
|
{ N("Blackrock Depths", "黑石深渊"), "52-60" },
|
|
{ N("Blackrock Spire", "黑石塔"), "58-60" } },
|
|
[N("Deadwind Pass", "逆风小径")] = { { N("Karazhan Crypt", "卡拉赞地穴"), "58-60" } },
|
|
[N("Elwynn Forest", "艾尔文森林")] = { { N("The Stockades", "监狱"), "24-32" },
|
|
{ N("Stormwind Vault", "暴风城地窖"), "60+" } },
|
|
[N("Tanaris", "塔纳利斯")] = { { N("Zul'Farrak", "祖尔法拉克"), "44-54" },
|
|
{ N("Caverns of Time: The Black Morass", "时光之穴:黑色沼泽"), "60+" } },
|
|
[N("Balor", "巴洛")] = { { N("Stormwrought Ruins", "风暴废墟"), "35-41" } },
|
|
[N("Wetlands", "湿地")] = { { N("Dragonmaw Retreat", "龙喉要塞"), "27-33" } },
|
|
[N("Moonsong Coast", "月语海岸")] = { { N("Timbermaw Hold", "木喉要塞"), "60+" } },
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Raids
|
|
--------------------------------------------------------------------------------
|
|
local ZONE_RAIDS = {
|
|
[N("Eastern Plaguelands", "东瘟疫之地")] = { { N("Naxxramas", "纳克萨玛斯"), "60+" } },
|
|
[N("Dustwallow Marsh", "尘泥沼泽")] = { { N("Onyxia's Lair", "奥妮克希亚的巢穴"), "60+" } },
|
|
[N("Silithus", "希利苏斯")] = { { N("Ruins of Ahn'Qiraj", "安其拉废墟"), "60+" },
|
|
{ N("Temple of Ahn'Qiraj", "安其拉神庙"), "60+" } },
|
|
[N("Stranglethorn Vale", "荆棘谷")] = { { N("Zul'Gurub", "祖尔格拉布"), "60+" } },
|
|
[N("Hyjal", "海加尔山")] = { { N("Emerald Sanctum", "翡翠圣所"), "60+" } },
|
|
[N("Deadwind Pass", "逆风小径")] = { { N("Lower Karazhan Halls", "下层卡拉赞大厅"), "60+" } },
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Fishing Level Requirements
|
|
--------------------------------------------------------------------------------
|
|
local ZONE_FISHING = {
|
|
[N("Elwynn Forest", "艾尔文森林")] = 25,
|
|
[N("Dun Morogh", "丹莫罗")] = 25,
|
|
[N("Tirisfal Glades", "提瑞斯法林地")] = 25,
|
|
[N("Loch Modan", "洛克莫丹")] = 75,
|
|
[N("Silverpine Forest", "银松森林")] = 75,
|
|
[N("Westfall", "西部荒野")] = 75,
|
|
[N("Redridge Mountains", "赤脊山")] = 150,
|
|
[N("Duskwood", "暮色森林")] = 150,
|
|
[N("Hillsbrad Foothills", "希尔斯布莱德丘陵")] = 150,
|
|
[N("Wetlands", "湿地")] = 150,
|
|
[N("Alterac Mountains", "奥特兰克山脉")] = 225,
|
|
[N("Arathi Highlands", "阿拉希高地")] = 225,
|
|
[N("Stranglethorn Vale", "荆棘谷")] = 225,
|
|
[N("Swamp of Sorrows", "悲伤沼泽")] = 225,
|
|
[N("The Hinterlands", "辛特兰")] = 300,
|
|
[N("Western Plaguelands", "西瘟疫之地")] = 300,
|
|
[N("Durotar", "杜隆塔尔")] = 25,
|
|
[N("Mulgore", "莫高雷")] = 25,
|
|
[N("Teldrassil", "泰达希尔")] = 25,
|
|
[N("Darkshore", "黑海岸")] = 75,
|
|
[N("The Barrens", "贫瘠之地")] = 75,
|
|
[N("Stonetalon Mountains","石爪山脉")] = 150,
|
|
[N("Ashenvale", "灰谷")] = 150,
|
|
[N("Thousand Needles", "千针石林")] = 225,
|
|
[N("Desolace", "凄凉之地")] = 225,
|
|
[N("Dustwallow Marsh", "尘泥沼泽")] = 225,
|
|
[N("Feralas", "菲拉斯")] = 300,
|
|
[N("Tanaris", "塔纳利斯")] = 300,
|
|
[N("Azshara", "艾萨拉")] = 300,
|
|
[N("Felwood", "费伍德森林")] = 300,
|
|
[N("Un'Goro Crater", "安戈洛环形山")] = 300,
|
|
[N("Moonglade", "月光林地")] = 300,
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Sub-zone -> Parent Zone Mapping
|
|
--------------------------------------------------------------------------------
|
|
local ZONE_SUBZONES = {
|
|
[N("Orgrimmar", "奥格瑞玛")] = N("Durotar", "杜隆塔尔"),
|
|
[N("Thunder Bluff", "雷霆崖")] = N("Mulgore", "莫高雷"),
|
|
[N("Undercity", "幽暗城")] = N("Tirisfal Glades", "提瑞斯法林地"),
|
|
[N("Ironforge", "铁炉堡")] = N("Dun Morogh", "丹莫罗"),
|
|
[N("Stormwind City", "暴风城")] = N("Elwynn Forest", "艾尔文森林"),
|
|
[N("Darnassus", "达纳苏斯")] = N("Teldrassil", "泰达希尔"),
|
|
[N("Alah'Thalas", "萨拉斯高地")] = N("Thalassian Highlands", "阿尔萨拉斯"),
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Display strings & colors
|
|
--------------------------------------------------------------------------------
|
|
local S_LEVELS = N("Level %d-%d", "等级 %d-%d")
|
|
local S_FISHING = N("Fishing Level %d", "钓鱼等级 %d")
|
|
local S_INSTANCES = N("Instances:", "地下城:")
|
|
local S_RAIDS = N("Raids:", "团队副本:")
|
|
local S_FRIENDLY = N("Friendly Territory", "友好领土")
|
|
local S_HOSTILE = N("Hostile Territory", "敌对领土")
|
|
local S_CONTESTED = N("Contested Territory", "争夺中的领土")
|
|
|
|
local COLORS = {
|
|
friendly = { 0.20, 0.90, 0.20 },
|
|
hostile = { 0.90, 0.20, 0.20 },
|
|
contested = { 0.80, 0.60, 0.40 },
|
|
levels = { 0.80, 0.60, 0.00 },
|
|
header = { 1.00, 0.84, 0.00 },
|
|
instance = { 0.81, 0.81, 0.81 },
|
|
fishing = { 0.50, 0.70, 0.90 },
|
|
}
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Tooltip frame & display logic
|
|
--------------------------------------------------------------------------------
|
|
local zlrTT
|
|
local zlrCurrentZone, zlrCurrentArea
|
|
local zlrOldUpdate
|
|
|
|
local function CreateZLRTooltip()
|
|
if zlrTT then return end
|
|
zlrTT = CreateFrame("GameTooltip", "NanamiZoneLevelTT", UIParent, "GameTooltipTemplate")
|
|
zlrTT:SetFrameStrata("TOOLTIP")
|
|
zlrTT:SetFrameLevel(255)
|
|
end
|
|
|
|
local function StyleTooltip()
|
|
if not zlrTT then return end
|
|
local _A = SFrames.ActiveTheme
|
|
if not _A then return end
|
|
zlrTT:SetBackdrop({
|
|
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
tile = true, tileSize = 16, edgeSize = 14,
|
|
insets = { left = 3, right = 3, top = 3, bottom = 3 },
|
|
})
|
|
zlrTT:SetBackdropColor(_A.panelBg[1], _A.panelBg[2], _A.panelBg[3], _A.panelBg[4] or 0.95)
|
|
zlrTT:SetBackdropBorderColor(_A.panelBorder[1], _A.panelBorder[2], _A.panelBorder[3], _A.panelBorder[4] or 1)
|
|
end
|
|
|
|
local function UpdateZLRTooltip(zoneName)
|
|
if not zlrTT then return end
|
|
|
|
if not zoneName or zoneName == "" then
|
|
zlrTT:Hide()
|
|
return
|
|
end
|
|
|
|
local data = ZONE_RANGES[zoneName]
|
|
if not data then
|
|
zlrTT:Hide()
|
|
return
|
|
end
|
|
|
|
zlrTT:SetOwner(UIParent, "ANCHOR_NONE")
|
|
zlrTT:ClearAllPoints()
|
|
if WorldMapDetailFrame then
|
|
zlrTT:SetPoint("BOTTOMLEFT", WorldMapDetailFrame, "BOTTOMLEFT", 2, 2)
|
|
end
|
|
|
|
local minLv, maxLv, faction = data[1], data[2], data[3]
|
|
|
|
zlrTT:SetText(zoneName, 1, 1, 1)
|
|
|
|
local lvStr = string.format(S_LEVELS, minLv, maxLv)
|
|
zlrTT:AddLine(lvStr, COLORS.levels[1], COLORS.levels[2], COLORS.levels[3])
|
|
|
|
local _, playerFaction = UnitFactionGroup("player")
|
|
local territoryText, territoryColor
|
|
if faction == F_C then
|
|
territoryText = S_CONTESTED
|
|
territoryColor = COLORS.contested
|
|
elseif playerFaction == faction then
|
|
territoryText = S_FRIENDLY
|
|
territoryColor = COLORS.friendly
|
|
else
|
|
territoryText = S_HOSTILE
|
|
territoryColor = COLORS.hostile
|
|
end
|
|
zlrTT:AddLine(territoryText, territoryColor[1], territoryColor[2], territoryColor[3])
|
|
|
|
local instances = ZONE_INSTANCES[zoneName]
|
|
if instances then
|
|
zlrTT:AddLine(" ")
|
|
zlrTT:AddLine(S_INSTANCES, COLORS.header[1], COLORS.header[2], COLORS.header[3])
|
|
for _, inst in ipairs(instances) do
|
|
local iName, iLevels = inst[1], inst[2]
|
|
zlrTT:AddDoubleLine(
|
|
iName, "(" .. iLevels .. ")",
|
|
COLORS.instance[1], COLORS.instance[2], COLORS.instance[3],
|
|
COLORS.instance[1], COLORS.instance[2], COLORS.instance[3]
|
|
)
|
|
end
|
|
end
|
|
|
|
local raids = ZONE_RAIDS[zoneName]
|
|
if raids then
|
|
zlrTT:AddLine(" ")
|
|
zlrTT:AddLine(S_RAIDS, COLORS.header[1], COLORS.header[2], COLORS.header[3])
|
|
for _, raid in ipairs(raids) do
|
|
local rName, rLevels = raid[1], raid[2]
|
|
zlrTT:AddDoubleLine(
|
|
rName, "(" .. rLevels .. ")",
|
|
COLORS.instance[1], COLORS.instance[2], COLORS.instance[3],
|
|
COLORS.instance[1], COLORS.instance[2], COLORS.instance[3]
|
|
)
|
|
end
|
|
end
|
|
|
|
local fishLv = ZONE_FISHING[zoneName]
|
|
if fishLv then
|
|
zlrTT:AddLine(" ")
|
|
zlrTT:AddLine(string.format(S_FISHING, fishLv), COLORS.fishing[1], COLORS.fishing[2], COLORS.fishing[3])
|
|
end
|
|
|
|
StyleTooltip()
|
|
zlrTT:Show()
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Hook WorldMapButton_OnUpdate
|
|
--------------------------------------------------------------------------------
|
|
local function HookWorldMapUpdate()
|
|
zlrOldUpdate = WorldMapButton_OnUpdate
|
|
WorldMapButton_OnUpdate = function(a1)
|
|
if zlrOldUpdate then zlrOldUpdate(a1) end
|
|
|
|
local areaNameRaw = WorldMapFrame and WorldMapFrame.areaName or ""
|
|
local _, _, trimmed = string.find(areaNameRaw, "^%s*(.-)%s*$")
|
|
if not trimmed then trimmed = areaNameRaw end
|
|
local zoneNum = GetCurrentMapZone and GetCurrentMapZone() or -1
|
|
|
|
if ZONE_SUBZONES[trimmed] then
|
|
trimmed = ZONE_SUBZONES[trimmed]
|
|
end
|
|
|
|
if zoneNum == zlrCurrentZone and areaNameRaw == zlrCurrentArea then
|
|
return
|
|
end
|
|
zlrCurrentZone = zoneNum
|
|
zlrCurrentArea = areaNameRaw
|
|
|
|
if zoneNum == 0 then
|
|
UpdateZLRTooltip(trimmed)
|
|
else
|
|
UpdateZLRTooltip(nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Suppress LevelRange-Turtle's original tooltip
|
|
--------------------------------------------------------------------------------
|
|
local function SuppressLevelRangeTooltip()
|
|
local _G = getfenv(0)
|
|
if _G["LevelRangeTooltip"] then
|
|
_G["LevelRangeTooltip"]:Hide()
|
|
_G["LevelRangeTooltip"].Show = function(self) self:Hide() end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Hook WorldMapFrame hide to dismiss tooltip
|
|
--------------------------------------------------------------------------------
|
|
local function HookMapHide()
|
|
if not WorldMapFrame then return end
|
|
local prevOnHide = WorldMapFrame:GetScript("OnHide")
|
|
WorldMapFrame:SetScript("OnHide", function(a1,a2,a3,a4,a5)
|
|
if prevOnHide then prevOnHide(a1,a2,a3,a4,a5) end
|
|
if zlrTT then zlrTT:Hide() end
|
|
zlrCurrentZone = nil
|
|
zlrCurrentArea = nil
|
|
end)
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Initialize
|
|
--------------------------------------------------------------------------------
|
|
function ZLR:Initialize()
|
|
local wmCfg = SFramesDB and SFramesDB.WorldMap
|
|
if wmCfg and wmCfg.enabled == false then return end
|
|
|
|
CreateZLRTooltip()
|
|
HookWorldMapUpdate()
|
|
HookMapHide()
|
|
SuppressLevelRangeTooltip()
|
|
|
|
self.initialized = true
|
|
end
|