49bc586c15
HideAscensionQuestLines ran on every tooltip and removed any line matching a quest-objective pattern (N/M, [N] ...), clobbering other tooltip addons' lines (durability, stack counts, etc.). Gate it behind a new General-tab option 'Hide Ascension quest progress lines' (default off) so Questie no longer modifies tooltip lines it does not own by default. Existing installs read the unset option as off automatically.
481 lines
18 KiB
Lua
481 lines
18 KiB
Lua
---@type QuestieTooltips
|
|
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips");
|
|
local _QuestieTooltips = QuestieTooltips.private
|
|
|
|
---@type l10n
|
|
local l10n = QuestieLoader:ImportModule("l10n")
|
|
|
|
---@type QuestieDB
|
|
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
|
---@type QuestiePlayer
|
|
local QuestiePlayer = QuestieLoader:ImportModule("QuestiePlayer")
|
|
---@type QuestieLib
|
|
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
|
|
|
--- COMPATIBILITY ---
|
|
local UnitGUID = QuestieCompat.UnitGUID
|
|
|
|
local lastGuid
|
|
|
|
-- ============================================================
|
|
-- NPCs that DROP an item which STARTS a quest (quest-starter drops)
|
|
-- Shows in tooltip like:
|
|
-- (yellow quest icon) Drops quest item !
|
|
-- (item icon) [ItemLink (quality colored)] [ID: <QuestId> (light blue)]
|
|
-- Works with Questie-335 compiled databases (binary + pointers).
|
|
-- ============================================================
|
|
|
|
local QUEST_START_LINE = "|TInterface\\GossipFrame\\AvailableQuestIcon:18:18:0:0|t |cFFFFD200Drops a quest !|r"
|
|
local QUEST_ID_COLOR = "|cFF80C8FF" -- light blue
|
|
local RESET_COLOR = "|r"
|
|
|
|
local _npcQuestStarterDrops = nil
|
|
local _npcQuestStarterDropsBuilt = false
|
|
|
|
-- ============================================================
|
|
-- Quest state cache (so we don't scan the log for every tooltip)
|
|
-- Hide lines if:
|
|
-- - quest is in quest log
|
|
-- - quest is flagged completed (turned in)
|
|
-- ============================================================
|
|
|
|
local _questInLogCache = {}
|
|
local _questInLogCacheBuilt = false
|
|
|
|
local function _WipeTable(t)
|
|
if wipe then
|
|
wipe(t)
|
|
else
|
|
for k in next, t do
|
|
t[k] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
local function _RebuildQuestInLogCache()
|
|
_WipeTable(_questInLogCache)
|
|
_questInLogCacheBuilt = true
|
|
|
|
if not GetNumQuestLogEntries or not GetQuestLogTitle then
|
|
return
|
|
end
|
|
|
|
local n = GetNumQuestLogEntries()
|
|
for i = 1, n do
|
|
-- WotLK: title, level, suggestedGroup, isHeader, isCollapsed, isComplete, frequency, questID
|
|
local _, _, _, isHeader, _, _, _, questID = GetQuestLogTitle(i)
|
|
if not isHeader and questID then
|
|
questID = tonumber(questID)
|
|
if questID then
|
|
_questInLogCache[questID] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function _QuestInLog(questId)
|
|
if not questId then return false end
|
|
if not _questInLogCacheBuilt then
|
|
_RebuildQuestInLogCache()
|
|
end
|
|
return _questInLogCache[questId] == true
|
|
end
|
|
|
|
-- Invalidate cache on quest log changes
|
|
do
|
|
local f = CreateFrame("Frame")
|
|
f:RegisterEvent("QUEST_LOG_UPDATE")
|
|
f:RegisterEvent("QUEST_ACCEPTED")
|
|
f:RegisterEvent("QUEST_REMOVED")
|
|
f:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
f:SetScript("OnEvent", function()
|
|
_questInLogCacheBuilt = false
|
|
end)
|
|
end
|
|
|
|
local function _GetItemPointers()
|
|
-- QuestieDB exposes these after DB init:
|
|
-- QuestieDB.ItemPointers = QuestieDB.QueryItem.pointers
|
|
if QuestieDB and type(QuestieDB.ItemPointers) == "table" then
|
|
return QuestieDB.ItemPointers
|
|
end
|
|
if QuestieDB and QuestieDB.QueryItem and type(QuestieDB.QueryItem.pointers) == "table" then
|
|
return QuestieDB.QueryItem.pointers
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Check if player already has the quest (in log or turned in)
|
|
local function _PlayerHasQuest(questId)
|
|
questId = tonumber(questId)
|
|
if not questId then return false end
|
|
|
|
-- 1) Active in log
|
|
if _QuestInLog(questId) then
|
|
return true
|
|
end
|
|
|
|
-- 2) Turned in / completed
|
|
if IsQuestFlaggedCompleted and IsQuestFlaggedCompleted(questId) and not QuestiePlayer.currentQuestlog[questId] then
|
|
return true
|
|
end
|
|
|
|
-- Optional fallback (some cores implement this reliably)
|
|
if GetQuestLogIndexByID then
|
|
local idx = GetQuestLogIndexByID(questId)
|
|
if idx and idx > 0 then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function _TryBuildNpcQuestStarterDrops()
|
|
if _npcQuestStarterDropsBuilt and _npcQuestStarterDrops then
|
|
return true
|
|
end
|
|
|
|
-- DB not ready yet? Try again later.
|
|
if not QuestieDB or type(QuestieDB.QueryItemSingle) ~= "function" then
|
|
return false
|
|
end
|
|
|
|
local pointers = _GetItemPointers()
|
|
if type(pointers) ~= "table" then
|
|
return false
|
|
end
|
|
|
|
_npcQuestStarterDrops = {}
|
|
|
|
-- Helper function to process an item and add it to the lookup table
|
|
local function processItem(itemId)
|
|
local questId = QuestieDB.QueryItemSingle(itemId, "startQuest")
|
|
if questId and questId ~= 0 then
|
|
local npcDrops = QuestieDB.QueryItemSingle(itemId, "npcDrops")
|
|
if npcDrops and type(npcDrops) == "table" then
|
|
local itemName = QuestieDB.QueryItemSingle(itemId, "name")
|
|
for _, npcId in next, npcDrops do
|
|
local list = _npcQuestStarterDrops[npcId]
|
|
if not list then
|
|
list = {}
|
|
_npcQuestStarterDrops[npcId] = list
|
|
end
|
|
list[table.getn(list) + 1] = { itemId = itemId, questId = tonumber(questId), name = itemName }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Iterate all items from compiled database
|
|
for itemId, _ in next, pointers do
|
|
processItem(itemId)
|
|
end
|
|
|
|
-- Also iterate Ascension override items (they don't have pointers)
|
|
if QuestieDB.itemDataOverrides and type(QuestieDB.itemDataOverrides) == "table" then
|
|
for itemId, _ in next, QuestieDB.itemDataOverrides do
|
|
processItem(itemId)
|
|
end
|
|
end
|
|
|
|
_npcQuestStarterDropsBuilt = true
|
|
return true
|
|
end
|
|
|
|
local function _TooltipHasQuestStarterLine(tooltip)
|
|
local n = tooltip:NumLines()
|
|
local base = tooltip:GetName() .. "TextLeft"
|
|
for i = 1, n do
|
|
local left = _G[base .. i]
|
|
if left then
|
|
local t = left:GetText()
|
|
if t and t:find("Drops quest item", 1, true) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function _AddQuestStarterDropsToTooltip(npcId)
|
|
if not _TryBuildNpcQuestStarterDrops() then return end
|
|
if not _npcQuestStarterDrops then return end
|
|
|
|
local drops = _npcQuestStarterDrops[npcId]
|
|
if not drops or table.getn(drops) == 0 then return end
|
|
|
|
if _TooltipHasQuestStarterLine(GameTooltip) then
|
|
return
|
|
end
|
|
|
|
-- Filter drops to only show items where player doesn't have the quest yet
|
|
local filteredDrops = {}
|
|
local dropsCount = table.getn(drops)
|
|
for i = 1, dropsCount do
|
|
local info = drops[i]
|
|
if info.questId and (not _PlayerHasQuest(info.questId)) then
|
|
filteredDrops[table.getn(filteredDrops) + 1] = info
|
|
end
|
|
end
|
|
|
|
if table.getn(filteredDrops) == 0 then
|
|
return
|
|
end
|
|
|
|
GameTooltip:AddLine(QUEST_START_LINE)
|
|
|
|
local filteredCount = table.getn(filteredDrops)
|
|
for i = 1, filteredCount do
|
|
local info = filteredDrops[i]
|
|
local itemId = info.itemId
|
|
local questId = info.questId
|
|
|
|
-- Item link with correct quality color when cached by client
|
|
local itemLink = select(2, GetItemInfo(itemId))
|
|
if not itemLink then
|
|
local itemName = info.name
|
|
if not itemName or itemName == "" then
|
|
itemName = "Item " .. tostring(itemId)
|
|
end
|
|
itemLink = ("|Hitem:%d:::::::::|h[%s]|h"):format(itemId, itemName)
|
|
end
|
|
|
|
local icon = GetItemIcon and GetItemIcon(itemId)
|
|
local qid = ("%s[ID: %d]%s"):format(QUEST_ID_COLOR, questId, RESET_COLOR)
|
|
|
|
if icon then
|
|
GameTooltip:AddLine(("|T%s:14:14:0:0|t %s %s"):format(icon, itemLink, qid))
|
|
else
|
|
GameTooltip:AddLine(("%s %s"):format(itemLink, qid))
|
|
end
|
|
end
|
|
end
|
|
|
|
function _QuestieTooltips:HideAscensionQuestLines(tooltip)
|
|
if not Questie.db.profile.enableTooltips then return end
|
|
-- Opt-in only. This strips lines matching quest-objective patterns ("N/M", "[N] ...")
|
|
-- from tooltips to hide Ascension's server-injected quest progress. It runs on every
|
|
-- tooltip, so by default it must NOT touch them — otherwise it clobbers other tooltip
|
|
-- addons' lines that happen to look like "N/M" (durability, stack counts, etc.). Users
|
|
-- who want the Ascension quest-spam hidden can enable it explicitly. (#16)
|
|
if not Questie.db.profile.hideAscensionTooltipQuestLines then return end
|
|
local numLines = tooltip:NumLines()
|
|
if not numLines or numLines < 1 then return end
|
|
|
|
for i = 2, numLines do
|
|
local fontString = _G[tooltip:GetName() .. "TextLeft" .. i]
|
|
if fontString then
|
|
local text = fontString:GetText()
|
|
if text then
|
|
local cleanText = string.gsub(text, "|[cC]%x%x%x%x%x%x%x%x", "")
|
|
cleanText = string.gsub(cleanText, "|[rR]", "")
|
|
cleanText = string.match(cleanText, "^%s*(.-)%s*$") or cleanText
|
|
|
|
-- Hide ONLY the Ascension-injected objective progress lines themselves
|
|
-- (e.g. "0/8 Arcane Wraith slain", "[1] ...", "- 0/2 ...").
|
|
--
|
|
-- We intentionally do NOT hide the lines that follow. The previous
|
|
-- behavior set a "questBlockActive" flag and then wiped every later
|
|
-- non-indented line until it hit an indented one — which also removed
|
|
-- Questie's own "Item ID"/"NPC ID"/"Object ID" lines and any other
|
|
-- addon's tooltip additions (e.g. an item-count overlay), because those
|
|
-- are appended at the BOTTOM of the tooltip, after the objective block.
|
|
-- Matching each objective line individually removes the Ascension spam
|
|
-- without touching anything else on the tooltip.
|
|
if string.match(cleanText, "^%[%d+.-%]") or string.match(cleanText, "^%d+/%d+") or string.match(cleanText, "^%-.-%d+/%d+") then
|
|
fontString:SetText("")
|
|
fontString:Hide()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _QuestieTooltips:AddUnitDataToTooltip()
|
|
if (self.IsForbidden and self:IsForbidden()) or (not Questie.db.profile.enableTooltips) then
|
|
return
|
|
end
|
|
|
|
_QuestieTooltips:HideAscensionQuestLines(self)
|
|
|
|
local name, unitToken = self:GetUnit();
|
|
if not unitToken then return end
|
|
local guid = UnitGUID(unitToken);
|
|
if (not guid) then
|
|
guid = UnitGUID("mouseover");
|
|
end
|
|
|
|
local guidType, _, _, _, _, npcId, _ = strsplit("-", guid or "");
|
|
if name and (guidType == "Creature" or guidType == "Vehicle") and (
|
|
name ~= QuestieTooltips.lastGametooltipUnit or
|
|
(not QuestieTooltips.lastGametooltipCount) or
|
|
_QuestieTooltips:CountTooltip() < QuestieTooltips.lastGametooltipCount or
|
|
QuestieTooltips.lastGametooltipType ~= "monster" or
|
|
lastGuid ~= guid
|
|
) then
|
|
QuestieTooltips.lastGametooltipUnit = name
|
|
|
|
-- Suppress System A's inline learner lines here: QuestieLearner's OnTooltipSetUnit
|
|
-- hook already renders learner spawn/kill data for the hovered unit (into the main
|
|
-- tooltip, or the separate secondary learner frame when that option is enabled).
|
|
local tooltipData = QuestieTooltips:GetTooltip("m_" .. npcId, true);
|
|
|
|
if tooltipData then
|
|
if Questie.db.profile.enableTooltipsNPCID == true then
|
|
GameTooltip:AddDoubleLine("NPC ID", "|cFFFFFFFF" .. npcId .. "|r")
|
|
end
|
|
for _, v in next, tooltipData do
|
|
GameTooltip:AddLine(v)
|
|
end
|
|
else
|
|
-- Even if Questie has no objective tooltip for this NPC, we still want to show quest-starter drops.
|
|
if Questie.db.profile.enableTooltipsNPCID == true then
|
|
GameTooltip:AddDoubleLine("NPC ID", "|cFFFFFFFF" .. npcId .. "|r")
|
|
end
|
|
end
|
|
|
|
-- Data-source attribution is rendered by QuestieLearner's secondary tooltip frame
|
|
-- (only when the secondary learner tooltip is enabled), never inline in the main
|
|
-- tooltip — see _AddLearnedSpawnTooltipLine.
|
|
|
|
local npcNum = tonumber(npcId)
|
|
if npcNum then
|
|
_AddQuestStarterDropsToTooltip(npcNum)
|
|
end
|
|
|
|
if QuestieTooltips.ResizeTooltip then
|
|
QuestieTooltips:ResizeTooltip(GameTooltip)
|
|
end
|
|
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
|
|
end
|
|
lastGuid = guid;
|
|
QuestieTooltips.lastGametooltipType = "monster";
|
|
end
|
|
|
|
-- =======================
|
|
-- Rest of original file
|
|
-- =======================
|
|
|
|
local lastItemId = 0;
|
|
function _QuestieTooltips:AddItemDataToTooltip()
|
|
if (self.IsForbidden and self:IsForbidden()) or (not Questie.db.profile.enableTooltips) then
|
|
return
|
|
end
|
|
|
|
_QuestieTooltips:HideAscensionQuestLines(self)
|
|
|
|
local name, link = self:GetItem()
|
|
local itemId
|
|
if link then
|
|
itemId = select(3,
|
|
string.match(link,
|
|
"|?c?f?f?(%x*)|?H?([^:]*):?(%d+):?(%d*):?(%d*):?(%d*):?(%d*):?(%d*):?(%-?%d*):?(%-?%d*):?(%d*):?(%d*):?(%-?%d*)|?h?%[?([^%[%]]*)%]?|?h?|?r?"))
|
|
end
|
|
if name and itemId and (lastItemId ~= itemId) then
|
|
QuestieTooltips.lastGametooltipItem = name
|
|
local tooltipData = QuestieTooltips:GetTooltip("i_" .. (itemId or 0));
|
|
-- Item ID is shown unconditionally for every item hover (matches the
|
|
-- behavior of NPC/Object tooltips), so users can always copy/paste
|
|
-- the ID even for items that have no quest objective or starter
|
|
-- data attached. The line is always added when the itemId changes
|
|
-- regardless of whether tooltipData is non-nil.
|
|
if Questie.db.profile.enableTooltipsItemID == true then
|
|
self:AddDoubleLine("Item ID", "|cFFFFFFFF" .. itemId .. "|r")
|
|
end
|
|
-- If the item starts a quest (the player must right-click/use it,
|
|
-- or talk to an NPC while it's in their bag), surface that so the
|
|
-- player can see which quest the item unlocks without first
|
|
-- having to look it up. We never knew the item's startQuest
|
|
-- until runtime, so this is read directly from the static DB /
|
|
-- Ascension override table.
|
|
local startQuestId = QuestieDB and QuestieDB.QueryItemSingle
|
|
and tonumber(QuestieDB.QueryItemSingle(itemId, "startQuest") or 0) or 0
|
|
if startQuestId and startQuestId > 0 and (not _PlayerHasQuest(startQuestId)) then
|
|
local questTitle = QuestieLib and QuestieLib.GetColoredQuestName
|
|
and QuestieLib:GetColoredQuestName(startQuestId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
|
|
or nil
|
|
if questTitle and questTitle ~= "" then
|
|
self:AddDoubleLine(QUEST_START_LINE, questTitle)
|
|
end
|
|
end
|
|
if tooltipData then
|
|
for _, v in next, tooltipData do
|
|
self:AddLine(v)
|
|
end
|
|
end
|
|
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
|
|
end
|
|
lastItemId = itemId;
|
|
QuestieTooltips.lastGametooltipType = "item";
|
|
QuestieTooltips.lastFrameName = self:GetName();
|
|
end
|
|
|
|
function _QuestieTooltips:AddObjectDataToTooltip(name)
|
|
if (not Questie.db.profile.enableTooltips) then
|
|
return
|
|
end
|
|
|
|
_QuestieTooltips:HideAscensionQuestLines(GameTooltip)
|
|
|
|
if name then
|
|
local titleAdded = false
|
|
local lookup = l10n.objectNameLookup[name] or {}
|
|
local count = table.getn(lookup)
|
|
|
|
if Questie.db.profile.enableTooltipsObjectID == true and count ~= 0 then
|
|
if count == 1 then
|
|
GameTooltip:AddDoubleLine("Object ID", "|cFFFFFFFF" .. lookup[1] .. "|r")
|
|
else
|
|
GameTooltip:AddDoubleLine("Object ID", "|cFFFFFFFF" .. lookup[1] .. " (" .. count .. ")|r")
|
|
end
|
|
end
|
|
|
|
local alreadyAddedObjectiveLines = {}
|
|
for _, gameObjectId in next, lookup do
|
|
local tooltipData = QuestieTooltips:GetTooltip("o_" .. gameObjectId);
|
|
|
|
if type(gameObjectId) == "number" and tooltipData then
|
|
if (not titleAdded) then
|
|
GameTooltip:AddLine(tooltipData[1])
|
|
titleAdded = true
|
|
end
|
|
|
|
if tooltipData[2] then
|
|
-- Quest has objectives
|
|
for index, line in next, tooltipData do
|
|
if index > 1 and (not alreadyAddedObjectiveLines[line]) then -- skip the first entry, it's the title
|
|
local _, _, acquired, needed = string.find(line, "(%d+)/(%d+)")
|
|
-- We need "tonumber", because acquired can contain parts of the color string
|
|
if acquired and tonumber(acquired) == tonumber(needed) then
|
|
-- We don't want to show completed objectives on game objects
|
|
break;
|
|
end
|
|
alreadyAddedObjectiveLines[line] = true
|
|
GameTooltip:AddLine(line)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if QuestieTooltips.ResizeTooltip then
|
|
QuestieTooltips:ResizeTooltip(GameTooltip)
|
|
end
|
|
GameTooltip:Show()
|
|
end
|
|
QuestieTooltips.lastGametooltipType = "object";
|
|
end
|
|
|
|
function _QuestieTooltips:CountTooltip()
|
|
local tooltipCount = 0
|
|
for i = 1, GameTooltip:NumLines() do
|
|
local frame = _G["GameTooltipTextLeft" .. i]
|
|
if frame and frame:GetText() then
|
|
tooltipCount = tooltipCount + 1
|
|
else
|
|
return tooltipCount
|
|
end
|
|
end
|
|
return tooltipCount
|
|
end
|