-- ---------------------------------------------------------------------------- -- Localized globals. -- ---------------------------------------------------------------------------- -- Lua Functions local pairs = _G.pairs -- Lua Libraries local table = _G.table -- WoW UI local C_PetJournal = _G.C_PetJournal local C_ToyBox = _G.C_ToyBox local GameTooltip = _G.GameTooltip -- ---------------------------------------------------------------------------- -- AddOn namespace. -- ---------------------------------------------------------------------------- local AddOnFolderName, private = ... local Data = private.Data local EventMessage = private.EventMessage local LibStub = _G.LibStub local LibQTip = LibStub("LibQTip-1.0") local NPCScan = LibStub("AceAddon-3.0"):GetAddon(AddOnFolderName) local FormatAtlasTexture = private.FormatAtlasTexture -- ---------------------------------------------------------------------------- -- Constants -- ---------------------------------------------------------------------------- local DataObject = LibStub("LibDataBroker-1.1"):NewDataObject( AddOnFolderName, { icon = [[Interface\LFGFRAME\BattlenetWorking0]], label = _G.OBJECTIVES_LABEL, scannerData = { NPCCount = 0, NPCs = {}, }, text = _G.NONE, type = "data source" } ) local npcAchievementNames = {} local npcDisplayNames = {} local npcIDs = {} local npcNames = {} local TitleFont = _G.CreateFont("NPCScanTitleFont") TitleFont:SetTextColor(1, 0.82, 0) TitleFont:SetFontObject("QuestTitleFont") local Tooltip -- ---------------------------------------------------------------------------- -- Helpers -- ---------------------------------------------------------------------------- local function SortByNPCNameThenByID(a, b) local nameA = npcNames[a] local nameB = npcNames[b] if nameA == nameB then return a < b end return nameA < nameB end local function SortByNPCAchievementNameThenByNameThenByID(a, b) local achievementNameA = npcAchievementNames[a] local achievementNameB = npcAchievementNames[b] if achievementNameA == achievementNameB then return SortByNPCNameThenByID(a, b) end if not achievementNameA then return false end if not achievementNameB then return true end return achievementNameA < achievementNameB end -- ---------------------------------------------------------------------------- -- Tooltip achievement headers. -- ---------------------------------------------------------------------------- local achievementProvider, achievementPrototype, baseCellPrototype = LibQTip:CreateCellProvider(LibQTip.LabelProvider) function achievementPrototype:getContentHeight() return 16 end function achievementPrototype:InitializeCell() baseCellPrototype.InitializeCell(self) if not self.atlas then local background = self:CreateTexture(nil, "TOOLTIP") background:SetBlendMode("ADD") background:SetAtlas("Objective-Header", true) background:SetPoint("CENTER", 0, -17) self.atlas = background end self.r, self.g, self.b = 1, 0.82, 0 self.fontString:SetTextColor(self.r, self.g, self.b, 1) end function achievementPrototype:ReleaseCell() self.r, self.g, self.b = 1, 1, 1 end function achievementPrototype:SetupCell(tooltip, value, justification, font, r, g, b) local width, height = baseCellPrototype.SetupCell(self, tooltip, value, justification, font, r, g, b) self.r, self.g, self.b = 1, 0.82, 0 return width, height end local function OpenToAchievement(_, achievementID) if not _G.AchievementFrame or not _G.AchievementFrame:IsShown() then _G.ToggleAchievementFrame() end _G.AchievementFrameBaseTab_OnClick(1) _G.AchievementFrame_SelectAchievement(achievementID) local categoryID = _G.GetAchievementCategory(achievementID) local _, parentCategoryID = _G.GetCategoryInfo(categoryID) if parentCategoryID == -1 then for _, entry in pairs(_G.ACHIEVEMENTUI_CATEGORIES) do if entry.id == categoryID then entry.collapsed = false elseif entry.parent == categoryID then entry.hidden = false end end _G.AchievementFrameCategories_Update() end end local function ShowAchievementTooltip(tooltipCell, achievementID) Tooltip:SetFrameStrata("DIALOG") _G.GameTooltip_SetDefaultAnchor(GameTooltip, tooltipCell) GameTooltip:SetText(Data.Achievements[achievementID].description, 1, 1, 1, 1, true) GameTooltip:Show() end local function HideAchievementTooltip() Tooltip:SetFrameStrata("TOOLTIP") GameTooltip:Hide() end -- ---------------------------------------------------------------------------- -- NPC tidbit helpers -- ---------------------------------------------------------------------------- local entryFromID = {} local function Tooltip_OnRelease() Tooltip = nil end local DataTooltip local function DataTooltip_OnRelease() DataTooltip = nil if Tooltip then Tooltip:SetFrameStrata("TOOLTIP") end end local function AddEntryDataIDs(list, fieldName) table.wipe(entryFromID) for index = 1, #list do entryFromID[list[index][fieldName]] = list[index] end end local function AddEntryToDataTooltip(iconPath, entryName, isCollected) local line = DataTooltip:AddLine(("|T%s:0:0|t %s"):format(iconPath, entryName)) if isCollected then DataTooltip:SetCell(line, 2, ("%s%s"):format(_G.GREEN_FONT_COLOR_CODE, _G.COLLECTED)) else DataTooltip:SetCell(line, 2, ("%s%s"):format(_G.RED_FONT_COLOR_CODE, _G.NOT_COLLECTED)) end end local function CleanupDataTooltip() if DataTooltip then DataTooltip:Hide() DataTooltip:Release() end if Tooltip then Tooltip:SetFrameStrata("TOOLTIP") end end local function InitializeDataTooltip(tooltipCell) if not DataTooltip then DataTooltip = LibQTip:Acquire(AddOnFolderName .. "DataTooltip", 2) DataTooltip:SetAutoHideDelay(0.1, tooltipCell, DataTooltip_OnRelease) DataTooltip:SmartAnchorTo(tooltipCell) DataTooltip:SetBackdropColor(0.05, 0.05, 0.05, 1) DataTooltip:SetCellMarginH(0) end Tooltip:SetFrameStrata("DIALOG") DataTooltip:Clear() return DataTooltip end local function DisplayText(tooltipCell, text) InitializeDataTooltip(tooltipCell) DataTooltip:AddLine(text) DataTooltip:Show() end local function DisplayMountInfo(tooltipCell, mountList) AddEntryDataIDs(mountList, "spellID") InitializeDataTooltip(tooltipCell) local mountIDs = _G.C_MountJournal.GetMountIDs() for index = 1, #mountIDs do local creatureName, spellID, iconPath, _, _, _, _, _, _, hideOnChar, isCollected = _G.C_MountJournal.GetMountInfoByID(mountIDs[index]) if creatureName and not hideOnChar and entryFromID[spellID] then AddEntryToDataTooltip(iconPath, creatureName, isCollected) end end DataTooltip:UpdateScrolling() DataTooltip:Show() end local function DisplayPetInfo(tooltipCell, petList) AddEntryDataIDs(petList, "npcID") InitializeDataTooltip(tooltipCell) C_PetJournal.SetFilterChecked(_G.LE_PET_JOURNAL_FILTER_COLLECTED, true) C_PetJournal.SetFilterChecked(_G.LE_PET_JOURNAL_FILTER_FAVORITES, false) C_PetJournal.SetFilterChecked(_G.LE_PET_JOURNAL_FILTER_NOT_COLLECTED, true) C_PetJournal.SetAllPetTypesChecked(true) C_PetJournal.SetAllPetSourcesChecked(true) C_PetJournal.ClearSearchFilter() if _G.PetJournalSearchBox then _G.PetJournalSearchBox:SetText(""); end local numPets = C_PetJournal.GetNumPets() for index = 1, numPets do local _, _, isCollected, _, _, _, _, petName, iconPath, _, npcID = C_PetJournal.GetPetInfoByIndex(index) if petName and entryFromID[npcID] then AddEntryToDataTooltip(iconPath, petName, isCollected) entryFromID[npcID] = nil -- Prevent multiples if already collected. end end DataTooltip:UpdateScrolling() DataTooltip:Show() end local function DisplayToyInfo(tooltipCell, toyList) AddEntryDataIDs(toyList, "itemID") InitializeDataTooltip(tooltipCell) C_ToyBox.SetAllSourceTypeFilters(true) C_ToyBox.SetCollectedShown(true) C_ToyBox.SetFilterString("") if _G.ToyBox then _G.ToyBox.searchBox:SetText(""); end local numToys = C_ToyBox.GetNumToys() for index = 1, numToys do local toyID = C_ToyBox.GetToyFromIndex(index) local itemID, toyName, iconPath = C_ToyBox.GetToyInfo(toyID) if toyName and entryFromID[itemID] then AddEntryToDataTooltip(iconPath, toyName, _G.PlayerHasToy(itemID)) end end DataTooltip:UpdateScrolling() DataTooltip:Show() end -- ---------------------------------------------------------------------------- -- DataBroker Tooltip helpers. -- ---------------------------------------------------------------------------- local function GetTooltipData() local hasMounts = false local hasPets = false local hasToys = false local hasTameable = false local hasWorldQuest = false local mountsColumn local petsColumn local tameableColumn local toysColumn local worldQuestColumn local numTooltipColumns = 1 table.wipe(npcAchievementNames) table.wipe(npcDisplayNames) table.wipe(npcIDs) table.wipe(npcNames) for npcID in pairs(DataObject.scannerData.NPCs) do local npc = Data.NPCs[npcID] -- The npcID may belong to a custom NPC, which will not have further information. if npc then npcAchievementNames[npcID] = npc.achievementID and Data.Achievements[npc.achievementID].name or nil npcDisplayNames[npcID] = private.GetNPCOptionsName(npcID) npcIDs[#npcIDs + 1] = npcID npcNames[npcID] = NPCScan:GetNPCNameFromID(npcID) if not hasTameable and npc.isTameable then hasTameable = true end if not hasMounts and npc.mounts then hasMounts = true end if not hasPets and npc.pets then hasPets = true end if not hasToys and npc.toys then hasToys = true end if not hasWorldQuest and npc:HasActiveWorldQuest() then hasWorldQuest = true end end end if hasMounts then numTooltipColumns = numTooltipColumns + 1 mountsColumn = numTooltipColumns end if hasPets then numTooltipColumns = numTooltipColumns + 1 petsColumn = numTooltipColumns end if hasToys then numTooltipColumns = numTooltipColumns + 1 toysColumn = numTooltipColumns end if hasTameable then numTooltipColumns = numTooltipColumns + 1 tameableColumn = numTooltipColumns end if hasWorldQuest then numTooltipColumns = numTooltipColumns + 1 worldQuestColumn = numTooltipColumns end table.sort(npcIDs, SortByNPCAchievementNameThenByNameThenByID) return { mountsColumn = mountsColumn, petsColumn = petsColumn, tameableColumn = tameableColumn, toysColumn = toysColumn, worldQuestColumn = worldQuestColumn, numTooltipColumns = numTooltipColumns } end -- ---------------------------------------------------------------------------- -- DataBroker Tooltip. -- ---------------------------------------------------------------------------- local ICON_MOUNT = FormatAtlasTexture("StableMaster") local ICON_PET = FormatAtlasTexture("WildBattlePetCapturable") local ICON_TAMEABLE do local textureFormat = [[|TInterface\TargetingFrame\UI-CLASSES-CIRCLES:0:0:0:0:256:256:%d:%d:%d:%d|t]] local textureSize = 256 local left, right, top, bottom = _G.unpack(_G.CLASS_ICON_TCOORDS["HUNTER"]) ICON_TAMEABLE = textureFormat:format(left * textureSize, right * textureSize, top * textureSize, bottom * textureSize) end local ICON_TOY = [[|TInterface\Worldmap\TreasureChest_64:0:0|t]] local ICON_WORLDQUEST = FormatAtlasTexture("worldquest-tracker-questmarker") local DataObjectDisplay -- Used for updates. local function DrawTooltip(displayFrame) if not displayFrame then return end DataObjectDisplay = displayFrame if LibQTip:IsAcquired(AddOnFolderName) then LibQTip:Release(AddOnFolderName) end local tooltipData = GetTooltipData() Tooltip = LibQTip:Acquire(AddOnFolderName, tooltipData.numTooltipColumns) Tooltip:SmartAnchorTo(displayFrame) Tooltip:SetAutoHideDelay(0.25, displayFrame) Tooltip:Clear() Tooltip:SetBackdropColor(0.05, 0.05, 0.05, 1) Tooltip:SetCellMarginH(0) Tooltip:SetCellMarginV(1) Tooltip.OnRelease = Tooltip_OnRelease Tooltip:SetCell(Tooltip:AddLine(), 1, AddOnFolderName, TitleFont, "CENTER", 0) Tooltip:AddSeparator(1, 0, 0, 0) if DataObject.scannerData.NPCCount == 0 then Tooltip:AddSeparator(1, 0, 0, 0) Tooltip:AddSeparator(1, 1, 0.82, 0) Tooltip:SetCell(Tooltip:AddLine(), 1, _G.ERR_GENERIC_NO_VALID_TARGETS, "CENTER", 0) return end local mountsColumn = tooltipData.mountsColumn local petsColumn = tooltipData.petsColumn local tameableColumn = tooltipData.tameableColumn local toysColumn = tooltipData.toysColumn local worldQuestColumn = tooltipData.worldQuestColumn local currentAchievementID for index = 1, #npcIDs do local npcID = npcIDs[index] local npc = Data.NPCs[npcID] if npc.achievementID then if npc.achievementID ~= currentAchievementID then currentAchievementID = npc.achievementID Tooltip:AddSeparator(1, 0, 0, 0) Tooltip:AddSeparator(1, 1, 0.82, 0) local achievementData = Data.Achievements[npc.achievementID] local achievementLine = Tooltip:AddLine() Tooltip:SetCell(achievementLine, 1, ("|T%s:0|t %s"):format(achievementData.iconTexturePath, achievementData.name), "CENTER", 0, achievementProvider) Tooltip:SetLineScript(achievementLine, "OnMouseUp", OpenToAchievement, npc.achievementID) Tooltip:SetLineScript(achievementLine, "OnEnter", ShowAchievementTooltip, npc.achievementID) Tooltip:SetLineScript(achievementLine, "OnLeave", HideAchievementTooltip) Tooltip:AddSeparator(1, 1, 0.82, 0) end elseif not currentAchievementID then -- No achievement section before this, and it's the first entry currentAchievementID = -1 Tooltip:AddSeparator(1, 0, 0, 0) Tooltip:AddSeparator(1, 1, 0.82, 0) elseif currentAchievementID >= 0 then -- End of achievements. currentAchievementID = -1 Tooltip:AddSeparator(1, 0, 0, 0) Tooltip:AddSeparator(1, 1, 0.82, 0) Tooltip:SetCell(Tooltip:AddLine(), 1, _G.MISCELLANEOUS, "CENTER", 0) Tooltip:AddSeparator(1, 1, 0.82, 0) end local line = Tooltip:AddLine() if line % 2 == 0 then Tooltip:SetLineColor(line, 0.20, 0.20, 0.20) end Tooltip:SetCell(line, 1, npcDisplayNames[npcID]) if worldQuestColumn and npc:HasActiveWorldQuest() then Tooltip:SetCell(line, worldQuestColumn, ICON_WORLDQUEST) Tooltip:SetCellScript(line, worldQuestColumn, "OnEnter", DisplayText, _G.TRACKER_HEADER_WORLD_QUESTS) Tooltip:SetCellScript(line, worldQuestColumn, "OnLeave", CleanupDataTooltip) end if tameableColumn and npc.isTameable then Tooltip:SetCell(line, tameableColumn, ICON_TAMEABLE) Tooltip:SetCellScript(line, tameableColumn, "OnEnter", DisplayText, _G.TAMEABLE) Tooltip:SetCellScript(line, tameableColumn, "OnLeave", CleanupDataTooltip) end if mountsColumn and npc.mounts then Tooltip:SetCell(line, mountsColumn, ICON_MOUNT) Tooltip:SetCellScript(line, mountsColumn, "OnEnter", DisplayMountInfo, npc.mounts) Tooltip:SetCellScript(line, mountsColumn, "OnLeave", CleanupDataTooltip) end if petsColumn and npc.pets then Tooltip:SetCell(line, petsColumn, ICON_PET) Tooltip:SetCellScript(line, petsColumn, "OnEnter", DisplayPetInfo, npc.pets) Tooltip:SetCellScript(line, petsColumn, "OnLeave", CleanupDataTooltip) end if toysColumn and npc.toys then Tooltip:SetCell(line, toysColumn, ICON_TOY) Tooltip:SetCellScript(line, toysColumn, "OnEnter", DisplayToyInfo, npc.toys) Tooltip:SetCellScript(line, toysColumn, "OnLeave", CleanupDataTooltip) end end end -- ---------------------------------------------------------------------------- -- DataObject methods. -- ---------------------------------------------------------------------------- function DataObject:OnClick() LibStub("AceConfigDialog-3.0"):Open(AddOnFolderName) end function DataObject:OnEnter() if not Tooltip or not Tooltip:IsShown() then DrawTooltip(self) Tooltip:UpdateScrolling() Tooltip:Show() end end function DataObject:OnLeave() -- Null operation: Some LDB displays get cranky if this method is missing. end function DataObject:Update(_, scannerData) self.text = scannerData.NPCCount > 0 and scannerData.NPCCount or _G.NONE self.scannerData = scannerData if DataObjectDisplay and Tooltip and Tooltip:IsShown() then DrawTooltip(DataObjectDisplay) end end LibStub("AceEvent-3.0"):Embed(DataObject) DataObject:RegisterMessage(EventMessage.ScannerDataUpdated, "Update")