-- ---------------------------------------------------------------------------- -- Upvalued Lua API. -- ---------------------------------------------------------------------------- -- Functions local pairs = _G.pairs -- Libraries local string = _G.string local table = _G.table -- ---------------------------------------------------------------------------- -- AddOn namespace. -- ---------------------------------------------------------------------------- local AddOnFolderName, private = ... local Data = private.Data local Enum = private.Enum local LibStub = _G.LibStub local AceConfigDialog = LibStub("AceConfigDialog-3.0") local HereBeDragons = LibStub("HereBeDragons-2.0") local NPCScan = LibStub("AceAddon-3.0"):NewAddon(AddOnFolderName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceBucket-3.0", "LibSink-2.0", "LibToast-1.0") -- ---------------------------------------------------------------------------- -- Debugger. -- ---------------------------------------------------------------------------- do local TextDump = LibStub("LibTextDump-1.0") local DEBUGGER_WIDTH = 750 local DEBUGGER_HEIGHT = 800 local debugger local function GetDebugger() if not debugger then debugger = TextDump:New(("%s Debug Output"):format(AddOnFolderName), DEBUGGER_WIDTH, DEBUGGER_HEIGHT) end return debugger end private.GetDebugger = GetDebugger function private.Debug(...) local message = string.format(...) GetDebugger():AddLine(message, "%X") return message end end -- ---------------------------------------------------------------------------- -- Variables. -- ---------------------------------------------------------------------------- local NPCIDFromName = {} private.NPCIDFromName = NPCIDFromName local QuestIDFromName = {} private.QuestIDFromName = QuestIDFromName -- ---------------------------------------------------------------------------- -- AddOn Methods. -- ---------------------------------------------------------------------------- function NPCScan:OnInitialize() -- ---------------------------------------------------------------------------- -- Data initialization -- ---------------------------------------------------------------------------- local DefaultPreferences = private.DefaultPreferences local UIMapType = _G.Enum.UIMapType for _, achievementID in pairs(Enum.AchievementID) do DefaultPreferences.profile.detection.achievementIDs[achievementID] = Enum.DetectionGroupStatus.Enabled end for _, continentID in pairs(Enum.ContinentID) do local continent = Data.Continents[continentID] if not continent then continent = { Maps = {} } Data.Continents[continentID] = continent end continent.ID = continentID continent.name = HereBeDragons:GetLocalizedMap(Enum.ContinentMapID[continentID]) DefaultPreferences.profile.detection.continentIDs[continentID] = Enum.DetectionGroupStatus.Enabled end for mapID, map in pairs(Data.Maps) do local parentMapInfo = _G.MapUtil.GetMapParentInfo(mapID, UIMapType.Continent) or _G.MapUtil.GetMapParentInfo(mapID, UIMapType.World) or _G.MapUtil.GetMapParentInfo(mapID, UIMapType.Cosmic) local continentID = parentMapInfo and Enum.MapContinentID[parentMapInfo.mapID] or Enum.ContinentID.Cosmic local mapInfo = _G.C_Map.GetMapInfo(mapID) if mapInfo.mapType == UIMapType.Dungeon or mapInfo.mapType == UIMapType.Orphan then map.isDungeon = true end map.continentID = continentID map.ID = mapID map.name = HereBeDragons:GetLocalizedMap(mapID) or _G.UNKNOWN Data.Continents[continentID].Maps[mapID] = map end local db = LibStub("AceDB-3.0"):New("NPCScanDB", DefaultPreferences, "Default") db.RegisterCallback(self, "OnProfileChanged", "RefreshPreferences") db.RegisterCallback(self, "OnProfileCopied", "RefreshPreferences") db.RegisterCallback(self, "OnProfileReset", "RefreshPreferences") self:DefineSinkToast(AddOnFolderName, [[Interface\LFGFRAME\BattlenetWorking0]]) self:SetSinkStorage(db.profile.alert.output) private.db = db -- ---------------------------------------------------------------------------- -- DB migrations -- ---------------------------------------------------------------------------- local sharedMediaNames = db.profile.alert.sound.sharedMediaNames for index = 1, 50 do local actualName = sharedMediaNames[index] if actualName then sharedMediaNames[actualName] = true sharedMediaNames[index] = nil end end self:RegisterChatCommand("npcscan", "ChatCommand") end function NPCScan:OnEnable() -- ---------------------------------------------------------------------------- -- Build lookup tables. -- ---------------------------------------------------------------------------- for mapID, map in pairs(Data.Maps) do for npcID in pairs(map.NPCs) do local npc = private.InitializeNPC(npcID) map.NPCs[npcID] = npc npc.mapIDs = npc.mapIDs or {} npc.mapIDs[#npc.mapIDs + 1] = mapID table.sort(npc.mapIDs, private.SortByMapNameThenByID) end end private.InitializeAchievements() local hasChecked = {} local questMapIDs = { [Enum.MapID.Argus] = true, [Enum.MapID.BrokenIsles] = true, [Enum.MapID.KulTiras] = true, [Enum.MapID.Zandalar] = true, } local vignetteMapIDs = { [Enum.MapID.Argus] = true, [Enum.MapID.BrokenIsles] = true, [Enum.MapID.Draenor] = true, [Enum.MapID.KulTiras] = true, [Enum.MapID.Pandaria] = true, [Enum.MapID.Zandalar] = true, } for mapID, map in pairs(Data.Maps) do local continent = _G.MapUtil.GetMapParentInfo(mapID, _G.Enum.UIMapType.Continent, true) local missingData = {} local mapHeaderPrinted for npcID in pairs(map.NPCs) do local npc = map.NPCs[npcID] if not hasChecked[npcID] then local questID = npc.questID or npc.achievementQuestID if not questID and not npc.worldQuestID and (not continent or questMapIDs[continent.mapID]) then missingData[npcID] = "questID" end if not npc.vignetteID and (not continent or vignetteMapIDs[continent.mapID]) then if missingData[npcID] then missingData[npcID] = ("%s, vignetteID"):format(missingData[npcID]) else missingData[npcID] = "vignetteID" end end hasChecked[npcID] = true end end for npcID, missingText in pairs(missingData) do if not mapHeaderPrinted then mapHeaderPrinted = true private.Debug("-- ----------------------------------------------------------------------------") private.Debug("-- %s (%d)", HereBeDragons:GetLocalizedMap(mapID) or _G.UNKNOWN, mapID) private.Debug("-- ----------------------------------------------------------------------------") end private.Debug("NPC %d (%s) is missing: %s.", npcID, self:GetNPCNameFromID(npcID), missingText) end end -- Handle custom additions. for npcID, npcName in pairs(private.db.locale.npcNames) do NPCIDFromName[npcName] = npcID end self:SetupOptions() self:InitializeTargetButton() self:RegisterBucketEvent("CRITERIA_UPDATE", 5) self:RegisterEvent("LOOT_CLOSED") self:RegisterEvent("NAME_PLATE_UNIT_ADDED") self:RegisterEvent("PLAYER_ENTERING_WORLD") self:RegisterEvent("PLAYER_TARGET_CHANGED") self:RegisterEvent("UPDATE_MOUSEOVER_UNIT") self:RegisterEvent("VIGNETTE_MINIMAP_UPDATED") self:RegisterBucketEvent("VIGNETTES_UPDATED", 0.5) HereBeDragons.RegisterCallback(NPCScan, "PlayerZoneChanged", "UpdateScanList") self:UpdateScanList() private.Overlays.Register() end function NPCScan:RefreshPreferences() end do local DatamineTooltip = _G.CreateFrame("GameTooltip", "NPCScanDatamineTooltip", _G.UIParent, "GameTooltipTemplate") DatamineTooltip:SetOwner(_G.WorldFrame, "ANCHOR_NONE") function NPCScan:GetNPCNameFromID(npcID) local npcName = private.db.locale.npcNames[npcID] if not npcName then DatamineTooltip:SetHyperlink(("unit:Creature-0-0-0-0-%d"):format(npcID)) npcName = _G["NPCScanDatamineTooltipTextLeft1"]:GetText() if npcName and npcName ~= "" then private.db.locale.npcNames[npcID] = npcName NPCIDFromName[npcName] = npcID else npcName = _G.UNKNOWN end end return npcName end function NPCScan:GetQuestNameFromID(questID) local questName = private.db.locale.questNames[questID] if not questName then questName = _G.C_QuestLog.GetTitleForQuestID(questID) if questName and questName ~= "" then private.db.locale.questNames[questID] = questName private.QuestIDFromName[questName] = questID else questName = _G.UNKNOWN end end return questName:gsub("Vignette: ", "") end end do local SUBCOMMAND_FUNCS function NPCScan:ChatCommand(input) SUBCOMMAND_FUNCS = SUBCOMMAND_FUNCS or { ADD = private.AddUserDefinedNPC, COMPARE = private.CompareData, REMOVE = private.RemoveUserDefinedNPC, SEARCH = function(subject) AceConfigDialog:Open(AddOnFolderName) AceConfigDialog:SelectGroup(AddOnFolderName, "npcOptions", "search") private.PerformNPCSearch(subject) end, --[===[@debug@ DEBUG = function() local debugger = private.GetDebugger() if debugger:Lines() == 0 then debugger:AddLine("Nothing to report.") debugger:Display() debugger:Clear() return end debugger:Display() end, DUMP = function(dumpType, parameters) local func = private.DUMP_COMMANDS[dumpType] if func then private.TextDump = private.TextDump or _G.LibStub("LibTextDump-1.0"):New(AddOnFolderName) func(parameters) else NPCScan:Print("Unknown dump command. Valid commands:") for command in pairs(private.DUMP_COMMANDS) do NPCScan:Printf(" %s", command) end end end --@end-debug@]===] } local subcommand, arg1, arg2 = self:GetArgs(input, 3) if subcommand then local func = SUBCOMMAND_FUNCS[subcommand:upper()] if func then func(arg1, arg2) end else AceConfigDialog:Open(AddOnFolderName) end end end -- do-block