521 lines
24 KiB
Lua
521 lines
24 KiB
Lua
---@class QuestieTooltips
|
|
local QuestieTooltips = QuestieLoader:CreateModule("QuestieTooltips");
|
|
local _QuestieTooltips = QuestieTooltips.private
|
|
-------------------------
|
|
--Import modules.
|
|
-------------------------
|
|
---@type QuestieComms
|
|
local QuestieComms = QuestieLoader:ImportModule("QuestieComms");
|
|
---@type QuestieLib
|
|
local QuestieLib = QuestieLoader:ImportModule("QuestieLib");
|
|
---@type QuestiePlayer
|
|
local QuestiePlayer = QuestieLoader:ImportModule("QuestiePlayer");
|
|
---@type QuestieDB
|
|
local QuestieDB = QuestieLoader:ImportModule("QuestieDB");
|
|
---@type l10n
|
|
local l10n = QuestieLoader:ImportModule("l10n")
|
|
|
|
--- COMPATIBILITY ---
|
|
local UnitInParty = QuestieCompat.UnitInParty
|
|
local IsInGroup = QuestieCompat.IsInGroup
|
|
local GetClassColor = QuestieCompat.GetClassColor
|
|
|
|
local tinsert = table.insert
|
|
QuestieTooltips.lastGametooltip = ""
|
|
QuestieTooltips.lastGametooltipCount = -1;
|
|
QuestieTooltips.lastGametooltipType = "";
|
|
QuestieTooltips.lastFrameName = "";
|
|
|
|
QuestieTooltips.lookupByKey = {
|
|
--["u_Grell"] = {questid, {"Line 1", "Line 2"}}
|
|
}
|
|
QuestieTooltips.lookupKeysByQuestId = {
|
|
--["questId"] = {"u_Grell", ... }
|
|
}
|
|
|
|
local MAX_GROUP_MEMBER_COUNT = 6
|
|
|
|
local _InitObjectiveTexts
|
|
|
|
---@param questId number
|
|
---@param key string monster: m_, items: i_, objects: o_ + string name of the objective
|
|
---@param objective table
|
|
function QuestieTooltips:RegisterObjectiveTooltip(questId, key, objective)
|
|
if not QuestieTooltips.lookupByKey[key] then
|
|
QuestieTooltips.lookupByKey[key] = {};
|
|
end
|
|
if not QuestieTooltips.lookupKeysByQuestId[questId] then
|
|
QuestieTooltips.lookupKeysByQuestId[questId] = {}
|
|
end
|
|
local tooltip = {
|
|
questId = questId,
|
|
objective = objective,
|
|
};
|
|
QuestieTooltips.lookupByKey[key][tostring(questId) .. " " .. objective.Index] = tooltip
|
|
tinsert(QuestieTooltips.lookupKeysByQuestId[questId], key)
|
|
end
|
|
|
|
---@param questId number
|
|
---@param name string The name of the object or NPC the tooltip should show on
|
|
---@param starterId number The ID of the object or NPC the tooltip should show on
|
|
---@param key string @Either m_<npcId> or o_<objectId>
|
|
function QuestieTooltips:RegisterQuestStartTooltip(questId, name, starterId, key)
|
|
if not name then
|
|
return
|
|
end
|
|
if not QuestieTooltips.lookupByKey[key] then
|
|
QuestieTooltips.lookupByKey[key] = {};
|
|
end
|
|
if not QuestieTooltips.lookupKeysByQuestId[questId] then
|
|
QuestieTooltips.lookupKeysByQuestId[questId] = {}
|
|
end
|
|
local tooltip = {
|
|
questId = questId,
|
|
name = name,
|
|
starterId = starterId,
|
|
};
|
|
QuestieTooltips.lookupByKey[key][tostring(questId) .. " " .. name .. " " .. starterId] = tooltip
|
|
tinsert(QuestieTooltips.lookupKeysByQuestId[questId], key)
|
|
end
|
|
|
|
---@param questId number
|
|
function QuestieTooltips:RemoveQuest(questId)
|
|
if (not QuestieTooltips.lookupKeysByQuestId[questId]) then
|
|
-- Tooltip has already been removed
|
|
return
|
|
end
|
|
|
|
-- Remove tooltip related keys from quest table so that
|
|
-- it can be readded/registered by other quest functions.
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if quest then
|
|
for _, objective in next, quest.Objectives do
|
|
objective.AlreadySpawned = {}
|
|
objective.hasRegisteredTooltips = false
|
|
objective.registeredItemTooltips = false
|
|
end
|
|
|
|
for _, objective in next, quest.SpecialObjectives do
|
|
objective.AlreadySpawned = {}
|
|
objective.hasRegisteredTooltips = false
|
|
objective.registeredItemTooltips = false
|
|
end
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieTooltips:RemoveQuest]", questId)
|
|
|
|
for _, key in next, QuestieTooltips.lookupKeysByQuestId[questId] or {} do
|
|
--Count to see if we should remove the main object
|
|
local totalCount = 0
|
|
local totalRemoved = 0
|
|
for _, tooltipData in next, QuestieTooltips.lookupByKey[key] or {} do
|
|
--Remove specific quest
|
|
if (tooltipData.questId == questId and tooltipData.objective) then
|
|
QuestieTooltips.lookupByKey[key][tostring(tooltipData.questId) .. " " .. tooltipData.objective.Index] = nil
|
|
totalRemoved = totalRemoved + 1
|
|
elseif (tooltipData.questId == questId and tooltipData.name) then
|
|
QuestieTooltips.lookupByKey[key][tostring(tooltipData.questId) .. " " .. tooltipData.name .. " " .. tooltipData.starterId] = nil
|
|
totalRemoved = totalRemoved + 1
|
|
end
|
|
totalCount = totalCount + 1
|
|
end
|
|
if (totalCount == totalRemoved) then
|
|
QuestieTooltips.lookupByKey[key] = nil
|
|
end
|
|
end
|
|
|
|
QuestieTooltips.lookupKeysByQuestId[questId] = nil
|
|
end
|
|
|
|
-- This code is related to QuestieComms, here we fetch all the tooltip data that exist in QuestieCommsData
|
|
-- It uses a similar system like here with i_ID etc as keys.
|
|
local function _FetchTooltipsForGroupMembers(key, tooltipData)
|
|
local anotherPlayer = false;
|
|
if QuestieComms and QuestieComms.data:KeyExists(key) then
|
|
---@tooltipData @tooltipData[questId][playerName][objectiveIndex].text
|
|
local tooltipDataExternal = QuestieComms.data:GetTooltip(key);
|
|
for questId, playerList in next, tooltipDataExternal do
|
|
if (not tooltipData[questId]) then
|
|
tooltipData[questId] = {
|
|
title = QuestieLib:GetColoredQuestName(questId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
|
|
}
|
|
end
|
|
for playerName, _ in next, playerList do
|
|
local playerInfo = QuestiePlayer:GetPartyMemberByName(playerName);
|
|
if playerInfo or QuestieComms.remotePlayerEnabled[playerName] then
|
|
anotherPlayer = true
|
|
break
|
|
end
|
|
end
|
|
if anotherPlayer then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if QuestieComms.data:KeyExists(key) and anotherPlayer then
|
|
---@tooltipData @tooltipData[questId][playerName][objectiveIndex].text
|
|
local tooltipDataExternal = QuestieComms.data:GetTooltip(key);
|
|
for questId, playerList in next, tooltipDataExternal do
|
|
if (not tooltipData[questId]) then
|
|
tooltipData[questId] = {
|
|
title = QuestieLib:GetColoredQuestName(questId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
|
|
}
|
|
end
|
|
for playerName, objectives in next, playerList do
|
|
local playerInfo = QuestiePlayer:GetPartyMemberByName(playerName);
|
|
if playerInfo or QuestieComms.remotePlayerEnabled[playerName] then
|
|
anotherPlayer = true;
|
|
for objectiveIndex, objective in next, objectives do
|
|
if (not objective) then
|
|
objective = {}
|
|
end
|
|
|
|
tooltipData[questId].objectivesText = _InitObjectiveTexts(tooltipData[questId].objectivesText, objectiveIndex, playerName)
|
|
|
|
local text;
|
|
local color = QuestieLib:GetRGBForObjective(objective)
|
|
|
|
if objective.required then
|
|
text = " " .. color .. tostring(objective.fulfilled) .. "/" .. tostring(objective.required) .. " " .. objective.text;
|
|
else
|
|
text = " " .. color .. objective.text;
|
|
end
|
|
|
|
tooltipData[questId].objectivesText[objectiveIndex][playerName] = { ["color"] = color, ["text"] = text };
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return anotherPlayer
|
|
end
|
|
|
|
---@param key string
|
|
function QuestieTooltips:GetTooltip(key)
|
|
Questie:Debug(Questie.DEBUG_SPAM, "[QuestieTooltips:GetTooltip]", key)
|
|
if (not key) then
|
|
return nil
|
|
end
|
|
|
|
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
|
|
return nil -- temporary disable tooltips in raids, we should make a proper fix
|
|
end
|
|
|
|
--Do not remove! This is the datastrucutre for tooltipData!
|
|
--[[tooltipdata[questId] = {
|
|
title = coloredTitle,
|
|
objectivesText = {
|
|
[objectiveIndex] = {
|
|
[playerName] = {
|
|
[color] = color,
|
|
[text] = text
|
|
}
|
|
}
|
|
}
|
|
}]]
|
|
--
|
|
local tooltipData = {}
|
|
local tooltipLines = {}
|
|
|
|
if (not QuestieTooltips.lookupByKey[key]) then
|
|
local QuestieLearner = QuestieLoader:ImportModule("QuestieLearner")
|
|
local QuestLogCache = QuestieLoader:ImportModule("QuestLogCache")
|
|
if QuestieLearner and QuestieLearner.data then
|
|
-- Try to find in learned NPCs or objects
|
|
local id = tonumber(key:sub(3))
|
|
if id then
|
|
if key:sub(1,2) == "m_" then
|
|
local learnedNpc = QuestieLearner.data.npcs[id]
|
|
if learnedNpc and learnedNpc[10] then -- check questObjectives
|
|
for questId, objList in next, learnedNpc[10] do
|
|
local oIndex = 1
|
|
while objList[oIndex] do
|
|
local objText = objList[oIndex]
|
|
local needed, collected
|
|
local objectives = QuestLogCache.GetQuestObjectives(questId)
|
|
if objectives then
|
|
for _, obj in next, objectives do
|
|
if obj.text and objText and (obj.text == objText or string.find(obj.text, objText, 1, true) or string.find(objText, obj.text, 1, true)) then
|
|
needed = obj.numRequired
|
|
collected = obj.numFulfilled
|
|
break
|
|
end
|
|
end
|
|
end
|
|
QuestieTooltips:RegisterObjectiveTooltip(questId, key, {
|
|
Index = 0,
|
|
Description = objText,
|
|
Needed = needed,
|
|
Collected = collected,
|
|
Update = function(self)
|
|
local objs = QuestLogCache.GetQuestObjectives(questId)
|
|
if objs then
|
|
for _, o in next, objs do
|
|
if o.text and self.Description and (o.text == self.Description or string.find(o.text, self.Description, 1, true) or string.find(self.Description, o.text, 1, true)) then
|
|
self.Needed = o.numRequired
|
|
self.Collected = o.numFulfilled
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
oIndex = oIndex + 1
|
|
end
|
|
end
|
|
if learnedNpc.mc then
|
|
tinsert(tooltipLines, "|cFF5EBAF3(Learned - Confidence: " .. tostring(learnedNpc.mc) .. ")|r")
|
|
end
|
|
end
|
|
elseif key:sub(1,2) == "o_" then
|
|
local learnedObj = QuestieLearner.data.objects[id]
|
|
if learnedObj and learnedObj[10] then
|
|
for questId, objList in next, learnedObj[10] do
|
|
local oIndex = 1
|
|
while objList[oIndex] do
|
|
local objText = objList[oIndex]
|
|
local needed, collected
|
|
local objectives = QuestLogCache.GetQuestObjectives(questId)
|
|
if objectives then
|
|
for _, obj in next, objectives do
|
|
if obj.text and objText and (obj.text == objText or string.find(obj.text, objText, 1, true) or string.find(objText, obj.text, 1, true)) then
|
|
needed = obj.numRequired
|
|
collected = obj.numFulfilled
|
|
break
|
|
end
|
|
end
|
|
end
|
|
QuestieTooltips:RegisterObjectiveTooltip(questId, key, {
|
|
Index = 0,
|
|
Description = objText,
|
|
Needed = needed,
|
|
Collected = collected,
|
|
Update = function(self)
|
|
local objs = QuestLogCache.GetQuestObjectives(questId)
|
|
if objs then
|
|
for _, o in next, objs do
|
|
if o.text and self.Description and (o.text == self.Description or string.find(o.text, self.Description, 1, true) or string.find(self.Description, o.text, 1, true)) then
|
|
self.Needed = o.numRequired
|
|
self.Collected = o.numFulfilled
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
oIndex = oIndex + 1
|
|
end
|
|
end
|
|
if learnedObj.mc then
|
|
tinsert(tooltipLines, "|cFF5EBAF3(Learned - Confidence: " .. tostring(learnedObj.mc) .. ")|r")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if QuestieTooltips.lookupByKey[key] then
|
|
local playerName = UnitName("player")
|
|
for k, tooltip in next, QuestieTooltips.lookupByKey[key] do
|
|
if tooltip.name then
|
|
if Questie.db.profile.showQuestsInNpcTooltip then
|
|
local questString = QuestieLib:GetColoredQuestName(tooltip.questId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
|
|
tinsert(tooltipLines, questString)
|
|
end
|
|
else
|
|
local objective = tooltip.objective
|
|
if objective and not (objective.IsSourceItem or objective.IsRequiredSourceItem) and objective.Update then
|
|
-- Tooltip was registered for a sourceItem or requiredSourceItem and not a real "objective"
|
|
objective:Update()
|
|
end
|
|
|
|
local questId = tooltip.questId
|
|
local objectiveIndex = objective.Index;
|
|
if (not tooltipData[questId]) then
|
|
tooltipData[questId] = {
|
|
title = QuestieLib:GetColoredQuestName(questId, Questie.db.profile.enableTooltipsQuestLevel, true, true)
|
|
}
|
|
end
|
|
|
|
if not QuestiePlayer.currentQuestlog[questId] then
|
|
-- TODO: Is this still required?
|
|
QuestieTooltips.lookupByKey[key][k] = nil
|
|
else
|
|
tooltipData[questId].objectivesText = _InitObjectiveTexts(tooltipData[questId].objectivesText, objectiveIndex, playerName)
|
|
|
|
-- Try to get the name of the NPC/Object from the spawnList if possible
|
|
local creatureName
|
|
local idFromKey = tonumber(key:sub(3))
|
|
if idFromKey and objective.spawnList and objective.spawnList[idFromKey] then
|
|
creatureName = objective.spawnList[idFromKey].Name
|
|
end
|
|
|
|
local text;
|
|
local color = QuestieLib:GetRGBForObjective(objective)
|
|
|
|
if objective.Type == "spell" and objective.spawnList[idFromKey] and objective.spawnList[idFromKey].ItemId then
|
|
text = " " .. color .. tostring(QuestieDB.QueryItemSingle(objective.spawnList[idFromKey].ItemId, "name"));
|
|
elseif objective.Needed then
|
|
text = " " .. color .. tostring(objective.Collected) .. "/" .. tostring(objective.Needed) .. " " .. tostring(objective.Description);
|
|
else
|
|
text = " " .. color .. tostring(objective.Description);
|
|
end
|
|
|
|
-- If we found a creature name, prepend it to the text
|
|
if creatureName then
|
|
text = " |cFFDDDDDD" .. creatureName .. "|r\n " .. text
|
|
end
|
|
|
|
tooltipData[questId].objectivesText[objectiveIndex][playerName] = { ["color"] = color, ["text"] = text };
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local anotherPlayer = false
|
|
if IsInGroup() then
|
|
anotherPlayer = _FetchTooltipsForGroupMembers(key, tooltipData)
|
|
end
|
|
|
|
local playerName = UnitName("player")
|
|
|
|
for questId, questData in next, tooltipData do
|
|
local hasObjective = false
|
|
local tempObjectives = {}
|
|
for _, playerList in next, questData.objectivesText or {} do
|
|
for objectivePlayerName, objectiveInfo in next, playerList do
|
|
local playerInfo = QuestiePlayer:GetPartyMemberByName(objectivePlayerName)
|
|
local playerColor
|
|
local playerType = ""
|
|
if playerInfo then
|
|
playerColor = "|c" .. playerInfo.colorHex
|
|
elseif QuestieComms.remotePlayerEnabled[objectivePlayerName] and QuestieComms.remoteQuestLogs[questId] and QuestieComms.remoteQuestLogs[questId][objectivePlayerName] and (not Questie.db.profile.onlyPartyShared or UnitInParty(objectivePlayerName)) then
|
|
playerColor = QuestieComms.remotePlayerClasses[playerName]
|
|
if playerColor then
|
|
playerColor = Questie:GetClassColor(playerColor)
|
|
playerType = " (" .. l10n("Nearby") .. ")"
|
|
end
|
|
end
|
|
if objectivePlayerName == playerName and anotherPlayer then -- why did we have this case
|
|
local _, classFilename = UnitClass("player");
|
|
local _, _, _, argbHex = GetClassColor(classFilename)
|
|
objectiveInfo.text = objectiveInfo.text .. " (|c" .. argbHex .. objectivePlayerName .. "|r" .. objectiveInfo.color .. ")|r"
|
|
elseif playerColor and objectivePlayerName ~= playerName then
|
|
objectiveInfo.text = objectiveInfo.text .. " (" .. playerColor .. objectivePlayerName .. "|r" .. objectiveInfo.color .. ")|r" .. playerType
|
|
end
|
|
-- We want the player to be on top.
|
|
if objectivePlayerName == playerName then
|
|
tinsert(tempObjectives, 1, objectiveInfo.text);
|
|
hasObjective = true
|
|
elseif playerColor then
|
|
tinsert(tempObjectives, objectiveInfo.text);
|
|
hasObjective = true
|
|
end
|
|
end
|
|
end
|
|
if hasObjective then
|
|
tinsert(tooltipLines, questData.title);
|
|
for _, text in next, tempObjectives do
|
|
tinsert(tooltipLines, text);
|
|
end
|
|
end
|
|
end
|
|
return tooltipLines
|
|
end
|
|
|
|
_InitObjectiveTexts = function(objectivesText, objectiveIndex, playerName)
|
|
if (not objectivesText) then
|
|
objectivesText = {}
|
|
end
|
|
if (not objectivesText[objectiveIndex]) then
|
|
objectivesText[objectiveIndex] = {}
|
|
end
|
|
if (not objectivesText[objectiveIndex][playerName]) then
|
|
objectivesText[objectiveIndex][playerName] = {}
|
|
end
|
|
return objectivesText
|
|
end
|
|
|
|
function QuestieTooltips:Initialize()
|
|
-- For the clicked item frame.
|
|
ItemRefTooltip:HookScript("OnTooltipSetItem", _QuestieTooltips.AddItemDataToTooltip)
|
|
ItemRefTooltip:HookScript("OnHide", function(self)
|
|
if (not self.IsForbidden) or (not self:IsForbidden()) then -- do we need this here also
|
|
QuestieTooltips.lastGametooltip = ""
|
|
QuestieTooltips.lastItemRefTooltip = ""
|
|
QuestieTooltips.lastGametooltipItem = nil
|
|
QuestieTooltips.lastGametooltipUnit = nil
|
|
QuestieTooltips.lastGametooltipCount = 0
|
|
QuestieTooltips.lastFrameName = "";
|
|
end
|
|
end)
|
|
|
|
-- For the hover frame.
|
|
GameTooltip:HookScript("OnTooltipSetUnit", function(self)
|
|
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
|
|
-- When in a raid, we want as little code running as possible
|
|
return
|
|
end
|
|
|
|
_QuestieTooltips.AddUnitDataToTooltip(self)
|
|
end)
|
|
GameTooltip:HookScript("OnTooltipSetItem", _QuestieTooltips.AddItemDataToTooltip)
|
|
GameTooltip:HookScript("OnShow", function(self)
|
|
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
|
|
-- When in a raid, we want as little code running as possible
|
|
return
|
|
end
|
|
|
|
if (not self.IsForbidden) or (not self:IsForbidden()) then -- do we need this here also
|
|
QuestieTooltips.lastGametooltipItem = nil
|
|
QuestieTooltips.lastGametooltipUnit = nil
|
|
QuestieTooltips.lastGametooltipCount = 0
|
|
QuestieTooltips.lastFrameName = "";
|
|
end
|
|
end)
|
|
GameTooltip:HookScript("OnHide", function(self)
|
|
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
|
|
-- When in a raid, we want as little code running as possible
|
|
return
|
|
end
|
|
|
|
if (not self.IsForbidden) or (not self:IsForbidden()) then -- do we need this here also
|
|
QuestieTooltips.lastGametooltip = ""
|
|
QuestieTooltips.lastItemRefTooltip = ""
|
|
QuestieTooltips.lastGametooltipItem = nil
|
|
QuestieTooltips.lastGametooltipUnit = nil
|
|
QuestieTooltips.lastGametooltipCount = 0
|
|
end
|
|
end)
|
|
|
|
-- Fired whenever the cursor hovers something with a tooltip. And then on every frame
|
|
GameTooltip:HookScript("OnUpdate", function(self)
|
|
if QuestiePlayer.numberOfGroupMembers > MAX_GROUP_MEMBER_COUNT then
|
|
-- When in a raid, we want as little code running as possible
|
|
return
|
|
end
|
|
|
|
if (not self.IsForbidden) or (not self:IsForbidden()) then
|
|
--Because this is an OnUpdate we need to check that it is actually not a Unit or Item to think its a
|
|
local uName, unit = self:GetUnit()
|
|
local iName, link = self:GetItem()
|
|
local sName, spell = self:GetSpell()
|
|
if (uName == nil and unit == nil and iName == nil and link == nil and sName == nil and spell == nil) and (
|
|
QuestieTooltips.lastGametooltip ~= GameTooltipTextLeft1:GetText() or
|
|
(not QuestieTooltips.lastGametooltipCount) or
|
|
_QuestieTooltips:CountTooltip() < QuestieTooltips.lastGametooltipCount
|
|
or QuestieTooltips.lastGametooltipType ~= "object"
|
|
) and (not self.ShownAsMapIcon) then -- We are hovering over a Questie map icon which adds it's own tooltip
|
|
_QuestieTooltips:AddObjectDataToTooltip(GameTooltipTextLeft1:GetText())
|
|
QuestieTooltips.lastGametooltipCount = _QuestieTooltips:CountTooltip()
|
|
end
|
|
QuestieTooltips.lastGametooltip = GameTooltipTextLeft1:GetText()
|
|
end
|
|
end)
|
|
end
|
|
|
|
return QuestieTooltips
|