439 lines
11 KiB
Lua
439 lines
11 KiB
Lua
local _G = _G
|
|
local ipairs = ipairs
|
|
local pairs = pairs
|
|
local string_format = string.format
|
|
local table_insert = table.insert
|
|
local table_remove = table.remove
|
|
local time = time
|
|
local type = type
|
|
local CreateFrame = CreateFrame
|
|
local GetCurrentMapAreaID = GetCurrentMapAreaID
|
|
local GetCurrentMapContinent = GetCurrentMapContinent
|
|
local GetMapNameByID = GetMapNameByID
|
|
local GetQuestsCompleted = GetQuestsCompleted
|
|
local IsAddOnLoaded = IsAddOnLoaded
|
|
local IsModifierKeyDown = IsModifierKeyDown
|
|
local UnitFactionGroup = UnitFactionGroup
|
|
|
|
local addonName, ns = ...
|
|
ns.modules = {}
|
|
ns.widgets = {}
|
|
ns.quests = {}
|
|
|
|
function ns.quests:CacheQuests(force)
|
|
if force or not self.updated or time() - self.updated >= 1 then
|
|
self.updated = time()
|
|
GetQuestsCompleted(self)
|
|
end
|
|
end
|
|
|
|
function ns.quests:IsCompleted(questID)
|
|
self:CacheQuests()
|
|
return self[questID]
|
|
end
|
|
|
|
-- local HBD = LibStub("HereBeDragons-1.0")
|
|
local HBDPins = LibStub("HereBeDragons-Pins-1.0")
|
|
local worldMapFrame = WorldMapButton
|
|
|
|
local IsAcceptedZone
|
|
do
|
|
local empty = {}
|
|
local useEmpty = false
|
|
|
|
IsAcceptedZone = setmetatable({}, {
|
|
__index = function(self, i)
|
|
if useEmpty then
|
|
self[i] = empty
|
|
return empty
|
|
end
|
|
self[i] = {}
|
|
return self[i]
|
|
end
|
|
})
|
|
|
|
local continents = { GetMapContinents() }
|
|
local numContinents = #continents
|
|
local continent = 0
|
|
local zones
|
|
local numZones
|
|
|
|
for i = 1, numContinents, 2 do
|
|
continent = continent + 1
|
|
zones = { GetMapZones(continent) }
|
|
numZones = #zones
|
|
|
|
for j = 1, numZones, 2 do
|
|
IsAcceptedZone[continent][zones[j]] = false
|
|
end
|
|
end
|
|
|
|
IsAcceptedZone[1][13] = true -- Kalimdor
|
|
IsAcceptedZone[2][14] = true -- Eastern Kingdoms
|
|
IsAcceptedZone[3][466] = true -- Outland
|
|
IsAcceptedZone[4][485] = true -- Northrend
|
|
IsAcceptedZone[5][751] = true -- The Maelstrom
|
|
IsAcceptedZone[6][862] = true -- Pandaria
|
|
IsAcceptedZone[7][962] = true -- Draenor
|
|
IsAcceptedZone[8][1007] = true -- Broken Isles
|
|
|
|
-- Vashj'ir
|
|
for k, v in ipairs({ 610, 613, 614, 615 }) do
|
|
IsAcceptedZone[2][v] = false
|
|
end
|
|
|
|
-- Northrend: Dalaran
|
|
for k, v in ipairs({ 485, 504, 510, 924 }) do -- Northrend, Dalaran#504, Crystalsong Forest, Dalaran#924
|
|
IsAcceptedZone[4][v] = false
|
|
end
|
|
|
|
-- Garrison
|
|
for k, v in ipairs({ 971, 973, 991, 974, 975, 976, 980, 990, 981, 982 }) do -- garrisonsmvalliance, garrisonsmvalliance_tier1, garrisonsmvalliance_tier2, garrisonsmvalliance_tier3, garrisonsmvalliance_tier4, garrisonffhorde, garrisonffhorde_tier1, garrisonffhorde_tier2, garrisonffhorde_tier3, garrisonffhorde_tier4
|
|
IsAcceptedZone[7][v] = true
|
|
end
|
|
|
|
useEmpty = true
|
|
end
|
|
|
|
local WaypointAddons = {}
|
|
do
|
|
-- enable for other parts of the addon to use this interface
|
|
ns.WaypointAddons = WaypointAddons
|
|
|
|
-- TomTom (v50400-1.0.0)
|
|
table_insert(WaypointAddons, {
|
|
name = "TomTom",
|
|
func = function(self, widget, everything)
|
|
if everything then
|
|
for _, node in ipairs(widget.module.nodes) do
|
|
TomTom:AddMFWaypoint(node.area, node.level, node.x, node.y, {
|
|
title = string_format("%s (%s, %d)", widget.module.title, GetMapNameByID(node.area), node.quest),
|
|
minimap = true,
|
|
crazy = true,
|
|
})
|
|
end
|
|
end
|
|
TomTom:AddMFWaypoint(widget.node.area, widget.node.level, widget.node.x, widget.node.y, {
|
|
title = string_format("%s (%s, %d)", widget.module.title, GetMapNameByID(widget.node.area),
|
|
widget.node.quest),
|
|
minimap = true,
|
|
crazy = true,
|
|
})
|
|
if everything then
|
|
TomTom:SetClosestWaypoint()
|
|
end
|
|
end,
|
|
})
|
|
|
|
-- TomTomLite (v50100-1.0.0)
|
|
table_insert(WaypointAddons, {
|
|
name = "TomTomLite",
|
|
func = function(self, widget, everything)
|
|
if everything then
|
|
for _, node in ipairs(widget.module.nodes) do
|
|
TomTomLite:AddWaypoint(node.area, node.level, node.x, node.y, {
|
|
title = string_format("%s (%s, %d)", widget.module.title, GetMapNameByID(node.area), node.quest),
|
|
})
|
|
end
|
|
end
|
|
TomTomLite:AddWaypoint(widget.node.area, widget.node.level, widget.node.x, widget.node.y, {
|
|
title = string_format("%s (%s, %d)", widget.module.title, GetMapNameByID(widget.node.area),
|
|
widget.node.quest),
|
|
})
|
|
end,
|
|
})
|
|
|
|
-- prepare some nice looking strings explaning what addons that are implemented
|
|
local numAddons = #WaypointAddons
|
|
local supportedAddons = "... darn! Seems like I forgot to actually add waypoint support"
|
|
|
|
if numAddons > 0 then
|
|
supportedAddons = ""
|
|
end
|
|
|
|
for index, addon in ipairs(WaypointAddons) do
|
|
supportedAddons = supportedAddons .. addon.name
|
|
|
|
if index < numAddons then
|
|
if index == numAddons - 1 then
|
|
supportedAddons = supportedAddons .. " or "
|
|
else
|
|
supportedAddons = supportedAddons .. ", "
|
|
end
|
|
end
|
|
end
|
|
|
|
supportedAddons = supportedAddons .. "."
|
|
|
|
-- get first loaded addon
|
|
function WaypointAddons:GetAddon()
|
|
for _, addon in ipairs(WaypointAddons) do
|
|
if IsAddOnLoaded(addon.name) then
|
|
return addon
|
|
end
|
|
end
|
|
end
|
|
|
|
-- apply a waypoint or all the waypoints on the first active addon
|
|
local informed
|
|
|
|
function WaypointAddons:Set(widget, everything)
|
|
local addon = WaypointAddons:GetAddon()
|
|
|
|
if addon then
|
|
addon:func(widget, everything)
|
|
elseif not informed then
|
|
DEFAULT_CHAT_FRAME:AddMessage("These waypoint addons are supported: " .. supportedAddons, 1, 1, 0)
|
|
informed = 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function ns:GetNormalizedHolidayTexture(texture)
|
|
if texture == 235461 or texture == 235462 then
|
|
return 235460
|
|
elseif texture == 235470 or texture == 235471 then
|
|
return 235469
|
|
elseif texture == 235473 or texture == 235474 then
|
|
return 235472
|
|
end
|
|
return texture
|
|
end
|
|
|
|
function ns:CanLoadEvent(texture)
|
|
return type(ns.modules[texture]) == "table" and not ns.modules[texture].loaded
|
|
end
|
|
|
|
function ns:CanUnloadEvent(texture)
|
|
return type(ns.modules[texture]) == "table" and ns.modules[texture].loaded
|
|
end
|
|
|
|
function ns:LoadEvent(texture)
|
|
local loaded = ns.modules[texture]:load()
|
|
|
|
if loaded then
|
|
ns:UpdateNodes()
|
|
end
|
|
|
|
return loaded
|
|
end
|
|
|
|
function ns:UnloadEvent(texture)
|
|
local module = ns.modules[texture]
|
|
local remove = {}
|
|
|
|
for _, node in pairs(module.nodes) do
|
|
if node then
|
|
ns:RemoveNode(node)
|
|
table_insert(remove, node)
|
|
end
|
|
end
|
|
|
|
while #remove > 0 do
|
|
local removeNode = table_remove(remove, 1)
|
|
|
|
for index, node in pairs(module.nodes) do
|
|
if node == removeNode then
|
|
table_remove(module.nodes, index)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
module.loaded = false
|
|
ns:UpdateNodes()
|
|
return true
|
|
end
|
|
|
|
function ns:GetPlayerFaction()
|
|
local faction = UnitFactionGroup("player")
|
|
|
|
local factionId
|
|
if faction == "Alliance" then
|
|
factionId = 1
|
|
elseif faction == "Horde" then
|
|
factionId = 2
|
|
end
|
|
|
|
return factionId
|
|
end
|
|
|
|
if not CandyBucketsDB then CandyBucketsDB = {} end
|
|
function ns:IsQuestCompleted(questID)
|
|
-- Hijack this and make it read from CandyBucketsDB
|
|
-- Something like CandyBucketsDB[UnitName("player")][questID]
|
|
-- Then write to this by listening for quest completed event
|
|
-- return ns.quests:IsCompleted(questID)
|
|
if not CandyBucketsDB then CandyBucketsDB = {} end
|
|
if not CandyBucketsDB[UnitName("player")] then CandyBucketsDB[UnitName("player")] = {} end
|
|
return CandyBucketsDB[UnitName("player")][questID]
|
|
end
|
|
|
|
local frame = CreateFrame("Frame")
|
|
frame:RegisterEvent("QUEST_TURNED_IN")
|
|
frame:SetScript("OnEvent", function(self, event, questID)
|
|
if not CandyBucketsDB then CandyBucketsDB = {} end
|
|
if not CandyBucketsDB[UnitName("player")] then CandyBucketsDB[UnitName("player")] = {} end
|
|
CandyBucketsDB[UnitName("player")][questID] = true
|
|
end)
|
|
|
|
function ns:QuestCompleted(questID)
|
|
ns.quests:CacheQuests(1)
|
|
ns.quests[questID] = true
|
|
|
|
for _, module in pairs(ns.modules) do
|
|
if module.loaded then
|
|
local remove = {}
|
|
|
|
for _, node in pairs(module.nodes) do
|
|
if node.quest == questID then
|
|
ns:RemoveNode(node)
|
|
table_insert(remove, node)
|
|
end
|
|
end
|
|
|
|
while #remove > 0 do
|
|
local removeNode = table_remove(remove, 1)
|
|
|
|
for index, node in pairs(module.nodes) do
|
|
if node == removeNode then
|
|
table_remove(module.nodes, index)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function ns:UpdateNodes()
|
|
if not worldMapFrame:IsVisible() then
|
|
return
|
|
end
|
|
|
|
local continent = IsAcceptedZone[GetCurrentMapContinent()]
|
|
local zone = continent[GetCurrentMapAreaID()]
|
|
|
|
for _, module in pairs(ns.modules) do
|
|
if module.loaded then
|
|
for _, node in pairs(module.nodes) do
|
|
if not ns:IsQuestCompleted(node.quest) then
|
|
if zone == false or (zone == true and continent[node.area] == false) then
|
|
ns:CreateOrUpdateWidget(node, module)
|
|
else
|
|
ns:RemoveNode(node)
|
|
end
|
|
else
|
|
ns:QuestCompleted(node.quest)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function ns:RemoveNode(node)
|
|
local widget = ns:GetWidget(node)
|
|
|
|
if widget then
|
|
widget:Hide()
|
|
|
|
HBDPins:RemoveWorldMapIcon(addonName, widget)
|
|
|
|
widget.node, widget.module = nil
|
|
end
|
|
end
|
|
|
|
function ns:GetWidget(node, createIfNotFound)
|
|
-- find node by reference
|
|
for i = 1, #ns.widgets do
|
|
local widget = ns.widgets[i]
|
|
|
|
if widget:IsShown() and widget.node == node then
|
|
return widget
|
|
end
|
|
end
|
|
|
|
if createIfNotFound then
|
|
-- find available
|
|
for i = 1, #ns.widgets do
|
|
local widget = ns.widgets[i]
|
|
|
|
if not widget:IsShown() then
|
|
return widget
|
|
end
|
|
end
|
|
|
|
-- create widget
|
|
local widget = ns:CreateWidget()
|
|
table_insert(ns.widgets, widget)
|
|
return widget
|
|
end
|
|
end
|
|
|
|
local function WidgetOnShowFullscreenCheck(widget, ...)
|
|
widget:SetFrameStrata(worldMapFrame:GetFrameStrata())
|
|
widget:SetFrameLevel(worldMapFrame:GetFrameLevel() + 1000)
|
|
|
|
if widget.node and widget.module then
|
|
widget.module.OnShow(widget)
|
|
end
|
|
end
|
|
|
|
function ns:CreateOrUpdateWidget(node, module)
|
|
local widget = ns:GetWidget(node, true)
|
|
widget.node, widget.module = node, module
|
|
|
|
if node and module then
|
|
widget.icon:SetTexture(module.texture)
|
|
widget:SetScript("OnEnter", module.OnEnter)
|
|
widget:SetScript("OnLeave", module.OnLeave)
|
|
widget:SetScript("OnClick", ns.WidgetOnClick)
|
|
else
|
|
widget.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
|
widget:SetScript("OnEnter", nil)
|
|
widget:SetScript("OnLeave", nil)
|
|
widget:SetScript("OnClick", nil)
|
|
end
|
|
|
|
widget:SetScript("OnShow", WidgetOnShowFullscreenCheck)
|
|
widget:SetScript("OnHide", WidgetOnShowFullscreenCheck)
|
|
|
|
widget:SetParent(worldMapFrame)
|
|
widget:SetFrameStrata("DIALOG")
|
|
widget:SetFrameLevel(255)
|
|
|
|
widget:Hide() -- will be shown by HBD when added to the world map (triggers OnShow)
|
|
HBDPins:AddWorldMapIconMF(addonName, widget, node.area, node.level, node.x, node.y)
|
|
end
|
|
|
|
function ns:CreateWidget()
|
|
local widget = CreateFrame("Button")
|
|
widget:Hide()
|
|
widget:SetSize(16, 16)
|
|
widget:RegisterForClicks("AnyUp")
|
|
|
|
widget.icon = widget:CreateTexture(nil, "OVERLAY", 2)
|
|
widget.icon:SetAllPoints()
|
|
widget.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
|
-- widget.icon:SetTexCoord(.15, .85, .15, .85) -- can't when we use a mask
|
|
widget.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask")
|
|
|
|
widget.border = widget:CreateTexture(nil, "OVERLAY", 1)
|
|
-- widget.border:SetPoint("TOPLEFT", -1, 1)
|
|
-- widget.border:SetPoint("BOTTOMRIGHT", 1, -1)
|
|
-- widget.border:SetTexture(0, 0, 0, 1)
|
|
|
|
return widget
|
|
end
|
|
|
|
function ns.WidgetOnClick(self, button)
|
|
if button == "LeftButton" then
|
|
WaypointAddons:Set(self, IsModifierKeyDown())
|
|
elseif button == "RightButton" then
|
|
if not CandyBucketsDB then CandyBucketsDB = {} end
|
|
if not CandyBucketsDB[UnitName("player")] then CandyBucketsDB[UnitName("player")] = {} end
|
|
CandyBucketsDB[UnitName("player")][self.node.quest] = true
|
|
self:RemoveNode(self.node)
|
|
end
|
|
end
|