v1.4.9: Validation fixes, Profiler fix, Quest link duplicate fix, Ascension fixes
This commit is contained in:
@@ -3,14 +3,24 @@ local QuestiePluginAPI = QuestieLoader:CreateModule("QuestiePluginAPI")
|
||||
|
||||
QuestiePluginAPI.registeredPlugins = {}
|
||||
QuestiePluginAPI.loadedDBFlavor = nil -- set by the first DB plugin that calls FinishLoading
|
||||
QuestiePluginAPI.pendingPluginsCount = 0 -- count of plugins that have registered but not yet FinishedLoading
|
||||
|
||||
--- Returns true if at least one DB plugin has fully loaded.
|
||||
---@return boolean
|
||||
function QuestiePluginAPI:IsAnyPluginLoaded()
|
||||
for _ in pairs(self.registeredPlugins) do return true end
|
||||
local name, _ = next(self.registeredPlugins)
|
||||
while name do
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Returns true if there are plugins that have registered but not yet finished loading.
|
||||
---@return boolean
|
||||
function QuestiePluginAPI:HasPendingPlugins()
|
||||
return self.pendingPluginsCount > 0
|
||||
end
|
||||
|
||||
--- Returns the flavor key of the loaded DB plugin ("WotLK", "Classic", "TBC", "Turtle", "Ascension", etc.)
|
||||
---@return string|nil
|
||||
function QuestiePluginAPI:GetLoadedFlavor()
|
||||
@@ -46,15 +56,8 @@ function QuestiePluginAPI:RegisterPlugin(pluginName)
|
||||
}, QuestiePlugin)
|
||||
|
||||
self.registeredPlugins[pluginName] = plugin
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestiePluginAPI] Successfully registered plugin: " .. pluginName)
|
||||
|
||||
if pluginName == "WotLKDB" and Questie.wotlkStatsCache then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestiePluginAPI] Applying cached WotLK stats...")
|
||||
plugin.stats.QUEST = Questie.wotlkStatsCache.QUEST or 0
|
||||
plugin.stats.NPC = Questie.wotlkStatsCache.NPC or 0
|
||||
plugin.stats.OBJECT = Questie.wotlkStatsCache.OBJECT or 0
|
||||
plugin.stats.ITEM = Questie.wotlkStatsCache.ITEM or 0
|
||||
end
|
||||
self.pendingPluginsCount = self.pendingPluginsCount + 1
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestiePluginAPI] Successfully registered plugin: " .. pluginName .. ". Total pending: " .. self.pendingPluginsCount)
|
||||
|
||||
return plugin
|
||||
end
|
||||
@@ -85,32 +88,30 @@ function QuestiePlugin:InjectDatabase(dbType, data)
|
||||
QuestieDB.questDataOverrides = QuestieDB.questDataOverrides or {}
|
||||
|
||||
local count = 0
|
||||
local targetOverride
|
||||
if dbType == "QUEST" then
|
||||
for id, entry in pairs(data) do
|
||||
QuestieDB.questDataOverrides[id] = entry
|
||||
if type(id) == "number" then count = count + 1 end
|
||||
end
|
||||
targetOverride = QuestieDB.questDataOverrides
|
||||
elseif dbType == "NPC" then
|
||||
for id, entry in pairs(data) do
|
||||
QuestieDB.npcDataOverrides[id] = entry
|
||||
if type(id) == "number" then count = count + 1 end
|
||||
end
|
||||
targetOverride = QuestieDB.npcDataOverrides
|
||||
elseif dbType == "OBJECT" then
|
||||
for id, entry in pairs(data) do
|
||||
QuestieDB.objectDataOverrides[id] = entry
|
||||
if type(id) == "number" then count = count + 1 end
|
||||
end
|
||||
targetOverride = QuestieDB.objectDataOverrides
|
||||
elseif dbType == "ITEM" then
|
||||
for id, entry in pairs(data) do
|
||||
QuestieDB.itemDataOverrides[id] = entry
|
||||
if type(id) == "number" then count = count + 1 end
|
||||
end
|
||||
targetOverride = QuestieDB.itemDataOverrides
|
||||
else
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestiePluginAPI] Plugin '" .. self.name .. "' passed unknown DB type to InjectDatabase: '" .. tostring(dbType) .. "'. Expected QUEST, NPC, OBJECT, or ITEM.")
|
||||
return
|
||||
end
|
||||
|
||||
self.stats[dbType] = self.stats[dbType] + count
|
||||
local qid, entry = next(data)
|
||||
while qid do
|
||||
targetOverride[qid] = entry
|
||||
if type(qid) == "number" then
|
||||
count = count + 1
|
||||
end
|
||||
qid, entry = next(data, qid)
|
||||
end
|
||||
|
||||
self.stats[dbType] = (self.stats[dbType] or 0) + count
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestiePluginAPI] Plugin '" .. self.name .. "' injected " .. tostring(count) .. " " .. dbType .. " records.")
|
||||
end
|
||||
|
||||
@@ -130,7 +131,8 @@ function QuestiePlugin:InjectZoneTables(customZoneTables)
|
||||
ZoneDB.private.dungeonParentZones = ZoneDB.private.dungeonParentZones or {}
|
||||
|
||||
if customZoneTables.uiMapIdToAreaId then
|
||||
for uiMapId, areaId in pairs(customZoneTables.uiMapIdToAreaId) do
|
||||
local uiMapId, areaId = next(customZoneTables.uiMapIdToAreaId)
|
||||
while uiMapId do
|
||||
if uiMapId and areaId then
|
||||
ZoneDB.private.uiMapIdToAreaId[uiMapId] = areaId
|
||||
ZoneDB.private.areaIdToUiMapId[uiMapId] = uiMapId
|
||||
@@ -143,37 +145,46 @@ function QuestiePlugin:InjectZoneTables(customZoneTables)
|
||||
ZoneDB.private.subZoneToParentZone[uiMapId] = areaId
|
||||
end
|
||||
end
|
||||
uiMapId, areaId = next(customZoneTables.uiMapIdToAreaId, uiMapId)
|
||||
end
|
||||
end
|
||||
|
||||
if type(customZoneTables.dungeons) == "table" then
|
||||
for areaId, data in pairs(customZoneTables.dungeons) do
|
||||
local areaId, data = next(customZoneTables.dungeons)
|
||||
while areaId do
|
||||
if areaId and data then
|
||||
ZoneDB.private.dungeons[areaId] = data
|
||||
end
|
||||
areaId, data = next(customZoneTables.dungeons, areaId)
|
||||
end
|
||||
end
|
||||
|
||||
if type(customZoneTables.dungeonLocations) == "table" then
|
||||
for areaId, data in pairs(customZoneTables.dungeonLocations) do
|
||||
local areaId, data = next(customZoneTables.dungeonLocations)
|
||||
while areaId do
|
||||
if areaId and data then
|
||||
ZoneDB.private.dungeonLocations[areaId] = data
|
||||
end
|
||||
areaId, data = next(customZoneTables.dungeonLocations, areaId)
|
||||
end
|
||||
end
|
||||
|
||||
if type(customZoneTables.dungeonParentZones) == "table" then
|
||||
for subZoneId, parentZoneId in pairs(customZoneTables.dungeonParentZones) do
|
||||
local subZoneId, parentZoneId = next(customZoneTables.dungeonParentZones)
|
||||
while subZoneId do
|
||||
if subZoneId and parentZoneId then
|
||||
ZoneDB.private.dungeonParentZones[subZoneId] = parentZoneId
|
||||
end
|
||||
subZoneId, parentZoneId = next(customZoneTables.dungeonParentZones, subZoneId)
|
||||
end
|
||||
end
|
||||
|
||||
if customZoneTables.zoneSort then
|
||||
ZoneDB.private.zoneSort = ZoneDB.private.zoneSort or {}
|
||||
for zoneId, zoneName in pairs(customZoneTables.zoneSort) do
|
||||
local zoneId, zoneName = next(customZoneTables.zoneSort)
|
||||
while zoneId do
|
||||
ZoneDB.private.zoneSort[zoneId] = zoneName
|
||||
zoneId, zoneName = next(customZoneTables.zoneSort, zoneId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -190,13 +201,15 @@ function QuestiePlugin:InjectUiMapData(customUiMapData)
|
||||
ZoneDB.private = ZoneDB.private or {}
|
||||
ZoneDB.private.areaIdToUiMapId = ZoneDB.private.areaIdToUiMapId or {}
|
||||
|
||||
for uiMapId, data in pairs(customUiMapData.uiMapData) do
|
||||
local uiMapId, data = next(customUiMapData.uiMapData)
|
||||
while uiMapId do
|
||||
if uiMapId and ZoneDB.private.areaIdToUiMapId[uiMapId] == nil then
|
||||
ZoneDB.private.areaIdToUiMapId[uiMapId] = uiMapId
|
||||
end
|
||||
if data and type(data.parentMapID) == "number" and ZoneDB.private.areaIdToUiMapId[data.parentMapID] == nil then
|
||||
ZoneDB.private.areaIdToUiMapId[data.parentMapID] = uiMapId
|
||||
end
|
||||
uiMapId, data = next(customUiMapData.uiMapData, uiMapId)
|
||||
end
|
||||
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestiePluginAPI] Plugin '" .. self.name .. "' injected Custom UI Map Data.")
|
||||
@@ -225,6 +238,12 @@ function QuestiePlugin:FinishLoading(flavorKey)
|
||||
QuestiePluginAPI.loadedDBFlavor = self.name
|
||||
end
|
||||
|
||||
if not self.isFinished then
|
||||
self.isFinished = true
|
||||
QuestiePluginAPI.pendingPluginsCount = math.max(0, QuestiePluginAPI.pendingPluginsCount - 1)
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestiePluginAPI] Plugin '" .. self.name .. "' set as FINISHED. Remaining pending: " .. QuestiePluginAPI.pendingPluginsCount)
|
||||
end
|
||||
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestiePluginAPI] Plugin '" .. self.name .. "' finished loading successfully.")
|
||||
end
|
||||
|
||||
|
||||
+74
-40
@@ -58,8 +58,6 @@ local HBDPins = QuestieCompat.HBDPins or LibStub("HereBeDragonsQuestie-Pins-2.0"
|
||||
--We should really try and squeeze out all the performance we can, especially in this.
|
||||
local tostring = tostring;
|
||||
local tinsert = table.insert;
|
||||
local pairs = pairs;
|
||||
local ipairs = ipairs;
|
||||
local tremove = table.remove;
|
||||
local tunpack = unpack;
|
||||
|
||||
@@ -77,7 +75,7 @@ function QuestieMap:GetFramesForQuest(questId)
|
||||
local frames = {}
|
||||
--If no frames exists or if the quest does not exist we just return an empty list
|
||||
if QuestieMap.questIdFrames[questId] then
|
||||
for _, name in pairs(QuestieMap.questIdFrames[questId]) do
|
||||
for _, name in next, QuestieMap.questIdFrames[questId] do
|
||||
if _G[name] then
|
||||
frames[name] = _G[name]
|
||||
end
|
||||
@@ -89,12 +87,14 @@ end
|
||||
function QuestieMap:UnloadQuestFrames(questId, iconType)
|
||||
if QuestieMap.questIdFrames[questId] then
|
||||
if not iconType then
|
||||
for _, frame in pairs(QuestieMap:GetFramesForQuest(questId)) do
|
||||
local frameList = QuestieMap:GetFramesForQuest(questId)
|
||||
for _, frame in next, frameList do
|
||||
frame:Unload();
|
||||
end
|
||||
QuestieMap.questIdFrames[questId] = nil;
|
||||
else
|
||||
for name, frame in pairs(QuestieMap:GetFramesForQuest(questId)) do
|
||||
local frameList = QuestieMap:GetFramesForQuest(questId)
|
||||
for name, frame in next, frameList do
|
||||
if frame and frame.data and frame.data.Icon == iconType then
|
||||
frame:Unload();
|
||||
QuestieMap.questIdFrames[questId][name] = nil
|
||||
@@ -113,7 +113,7 @@ function QuestieMap:GetManualFrames(id, typ)
|
||||
local frames = {}
|
||||
--If no frames exists or if the quest does not exist we just return an empty list
|
||||
if QuestieMap.manualFrames[typ] and (QuestieMap.manualFrames[typ][id]) then
|
||||
for _, name in pairs(QuestieMap.manualFrames[typ][id]) do
|
||||
for _, name in next, QuestieMap.manualFrames[typ][id] do
|
||||
tinsert(frames, _G[name])
|
||||
end
|
||||
end
|
||||
@@ -124,7 +124,8 @@ end
|
||||
function QuestieMap:UnloadManualFrames(id, typ)
|
||||
typ = typ or "any"
|
||||
if QuestieMap.manualFrames[typ] and (QuestieMap.manualFrames[typ][id]) then
|
||||
for _, frame in ipairs(QuestieMap:GetManualFrames(id, typ)) do
|
||||
local frameList = QuestieMap:GetManualFrames(id, typ)
|
||||
for _, frame in next, frameList do
|
||||
frame:Unload();
|
||||
end
|
||||
QuestieMap.manualFrames[typ][id] = nil;
|
||||
@@ -133,7 +134,7 @@ end
|
||||
|
||||
function QuestieMap:ResetManualFrames(typ)
|
||||
typ = typ or "any"
|
||||
for id, _ in pairs(QuestieMap.manualFrames[typ]) do
|
||||
for id in next, QuestieMap.manualFrames[typ] do
|
||||
QuestieMap:UnloadManualFrames(id, typ)
|
||||
end
|
||||
end
|
||||
@@ -141,14 +142,14 @@ end
|
||||
-- Rescale all the icons
|
||||
function QuestieMap:RescaleIcons()
|
||||
local mapScale = QuestieMap.GetScaleValue()
|
||||
for _, framelist in pairs(QuestieMap.questIdFrames) do
|
||||
for _, frameName in pairs(framelist) do
|
||||
for _, framelist in next, QuestieMap.questIdFrames do
|
||||
for _, frameName in next, framelist do
|
||||
QuestieMap.utils:RescaleIcon(frameName, mapScale)
|
||||
end
|
||||
end
|
||||
for _, frameTypeList in pairs(QuestieMap.manualFrames) do
|
||||
for _, framelist in pairs(frameTypeList) do
|
||||
for _, frameName in ipairs(framelist) do
|
||||
for _, frameTypeList in next, QuestieMap.manualFrames do
|
||||
for _, framelist in next, frameTypeList do
|
||||
for _, frameName in next, framelist do
|
||||
QuestieMap.utils:RescaleIcon(frameName, mapScale)
|
||||
end
|
||||
end
|
||||
@@ -258,7 +259,7 @@ function QuestieMap:ProcessShownMinimapIcons()
|
||||
end
|
||||
|
||||
---@param minimapFrame IconFrame
|
||||
for minimapFrame, data in pairs(HBDPins.activeMinimapPins) do
|
||||
for minimapFrame, data in next, HBDPins.activeMinimapPins do
|
||||
if minimapFrame.miniMapIcon and ((data.distanceFromMinimapCenter < 1.1) or doEdgeUpdate) then
|
||||
if minimapFrame.FadeLogic then
|
||||
minimapFrame:FadeLogic()
|
||||
@@ -305,7 +306,7 @@ function QuestieMap.ProcessQueue()
|
||||
end
|
||||
|
||||
local scaleValue = QuestieMap.GetScaleValue()
|
||||
for _ = 1, math.min(24, math.max(#mapDrawQueue, #minimapDrawQueue)) do
|
||||
for _ = 1, math.min(24, math.max(table.getn(mapDrawQueue), table.getn(minimapDrawQueue))) do
|
||||
local mapDrawCall = tremove(mapDrawQueue, 1);
|
||||
if mapDrawCall then
|
||||
local frame = mapDrawCall[2];
|
||||
@@ -381,25 +382,31 @@ function QuestieMap:ShowNPC(npcID, icon, scale, title, body, disableShiftToRemov
|
||||
|
||||
local manualIcons = {}
|
||||
-- draw the notes
|
||||
for zone, spawns in pairs(npc.spawns) do
|
||||
for zone, spawns in next, npc.spawns do
|
||||
if (zone ~= nil and spawns ~= nil) and ((not excludeDungeon) or (not ZoneDB.IsDungeonZone(zone))) then
|
||||
for _, coords in ipairs(spawns) do
|
||||
local spIndex = 1
|
||||
while spawns[spIndex] do
|
||||
local coords = spawns[spIndex]
|
||||
-- instance spawn, draw entrance on map
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(zone)
|
||||
if dungeonLocation ~= nil then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local dlIndex = 1
|
||||
while dungeonLocation[dlIndex] do
|
||||
local value = dungeonLocation[dlIndex]
|
||||
QuestieMap:DrawManualIcon(data, value[1], value[2], value[3], typ)
|
||||
dlIndex = dlIndex + 1
|
||||
end
|
||||
-- world spawn
|
||||
else
|
||||
manualIcons[zone] = QuestieMap:DrawManualIcon(data, zone, coords[1], coords[2], typ)
|
||||
end
|
||||
spIndex = spIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
-- draw waypoints
|
||||
if npc.waypoints then
|
||||
for zone, waypoints in pairs(npc.waypoints) do
|
||||
for zone, waypoints in next, npc.waypoints do
|
||||
if not ZoneDB:GetDungeonLocation(zone) and waypoints[1] and waypoints[1][1] and waypoints[1][1][1] then
|
||||
if not manualIcons[zone] then
|
||||
manualIcons[zone] = QuestieMap:DrawManualIcon(data, zone, waypoints[1][1][1], waypoints[1][1][2])
|
||||
@@ -444,19 +451,25 @@ function QuestieMap:ShowObject(objectID, icon, scale, title, body, disableShiftT
|
||||
data.ManualTooltipData.disableShiftToRemove = disableShiftToRemove
|
||||
|
||||
-- draw the notes
|
||||
for zone, spawns in pairs(object.spawns) do
|
||||
for zone, spawns in next, object.spawns do
|
||||
if (zone ~= nil and spawns ~= nil) then
|
||||
for _, coords in ipairs(spawns) do
|
||||
local spIndex = 1
|
||||
while spawns[spIndex] do
|
||||
local coords = spawns[spIndex]
|
||||
-- instance spawn, draw entrance on map
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(zone)
|
||||
if dungeonLocation ~= nil then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local dlIndex = 1
|
||||
while dungeonLocation[dlIndex] do
|
||||
local value = dungeonLocation[dlIndex]
|
||||
QuestieMap:DrawManualIcon(data, value[1], value[2], value[3], typ)
|
||||
dlIndex = dlIndex + 1
|
||||
end
|
||||
-- world spawn
|
||||
else
|
||||
QuestieMap:DrawManualIcon(data, zone, coords[1], coords[2], typ)
|
||||
end
|
||||
spIndex = spIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -728,7 +741,7 @@ local closestStarter = {}
|
||||
function QuestieMap:FindClosestStarter()
|
||||
local playerX, playerY, _ = HBD:GetPlayerWorldPosition();
|
||||
local playerZone = HBD:GetPlayerWorldPosition();
|
||||
for questId in pairs(QuestiePlayer.currentQuestlog) do
|
||||
for questId in next, QuestiePlayer.currentQuestlog do
|
||||
if (not closestStarter[questId]) then
|
||||
local quest = QuestieDB.GetQuest(questId);
|
||||
if quest then
|
||||
@@ -739,18 +752,24 @@ function QuestieMap:FindClosestStarter()
|
||||
zone = -1,
|
||||
type = "",
|
||||
}
|
||||
for starterType, starters in pairs(quest.Starts) do
|
||||
for starterType, starters in next, quest.Starts do
|
||||
if (starterType == "GameObject") then
|
||||
for _, ObjectID in ipairs(starters or {}) do
|
||||
local stIndex = 1
|
||||
while starters and starters[stIndex] do
|
||||
local ObjectID = starters[stIndex]
|
||||
local obj = QuestieDB:GetObject(ObjectID)
|
||||
if (obj ~= nil and obj.spawns ~= nil) then
|
||||
for Zone, Spawns in pairs(obj.spawns) do
|
||||
for Zone, Spawns in next, obj.spawns do
|
||||
if (Zone ~= nil and Spawns ~= nil) then
|
||||
for _, coords in ipairs(Spawns) do
|
||||
local spIndex = 1
|
||||
while Spawns[spIndex] do
|
||||
local coords = Spawns[spIndex]
|
||||
if (coords[1] == -1 or coords[2] == -1) then -- instace locations
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(Zone)
|
||||
if dungeonLocation ~= nil then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local dlIndex = 1
|
||||
while dungeonLocation[dlIndex] do
|
||||
local value = dungeonLocation[dlIndex]
|
||||
if (value[1] and value[2]) then
|
||||
local x, y, _ = HBD:GetWorldCoordinatesFromZone(value[1] / 100, value[2] / 100, ZoneDB:GetUiMapIdByAreaId(value[3]))
|
||||
if (x and y) then
|
||||
@@ -764,6 +783,7 @@ function QuestieMap:FindClosestStarter()
|
||||
end
|
||||
end
|
||||
end
|
||||
dlIndex = dlIndex + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -780,22 +800,30 @@ function QuestieMap:FindClosestStarter()
|
||||
end
|
||||
end
|
||||
end
|
||||
spIndex = spIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
stIndex = stIndex + 1
|
||||
end
|
||||
elseif (starterType == "NPC") then
|
||||
for _, NPCID in ipairs(starters or {}) do
|
||||
local stIndex = 1
|
||||
while starters and starters[stIndex] do
|
||||
local NPCID = starters[stIndex]
|
||||
local NPC = QuestieDB:GetNPC(NPCID)
|
||||
if (NPC ~= nil and NPC.spawns ~= nil and NPC.friendly) then
|
||||
for Zone, Spawns in pairs(NPC.spawns) do
|
||||
for Zone, Spawns in next, NPC.spawns do
|
||||
if (Zone ~= nil and Spawns ~= nil) then
|
||||
for _, coords in ipairs(Spawns) do
|
||||
local spIndex = 1
|
||||
while Spawns[spIndex] do
|
||||
local coords = Spawns[spIndex]
|
||||
if (coords[1] == -1 or coords[2] == -1) then
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(Zone)
|
||||
if dungeonLocation ~= nil then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local dlIndex = 1
|
||||
while dungeonLocation[dlIndex] do
|
||||
local value = dungeonLocation[dlIndex]
|
||||
if (value[1] and value[2]) then
|
||||
local uiMapId = ZoneDB:GetUiMapIdByAreaId(value[3])
|
||||
local x, y, _ = HBD:GetWorldCoordinatesFromZone(value[1] / 100, value[2] / 100, uiMapId)
|
||||
@@ -810,6 +838,7 @@ function QuestieMap:FindClosestStarter()
|
||||
end
|
||||
end
|
||||
end
|
||||
dlIndex = dlIndex + 1
|
||||
end
|
||||
end
|
||||
elseif (coords[1] and coords[2]) then
|
||||
@@ -826,10 +855,12 @@ function QuestieMap:FindClosestStarter()
|
||||
end
|
||||
end
|
||||
end
|
||||
spIndex = spIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
stIndex = stIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -855,9 +886,9 @@ function QuestieMap:GetNearestSpawn(objective)
|
||||
local bestSpawn, bestSpawnZone, bestSpawnId, bestSpawnType, bestSpawnName
|
||||
-- TODO: This is just a temporary workaround - We have to find out why "objective.spawnList" can be nil
|
||||
if objective and objective.spawnList and next(objective.spawnList) then
|
||||
for id, spawnData in pairs(objective.spawnList) do
|
||||
for zone, spawns in pairs(spawnData.Spawns) do
|
||||
for _, spawn in pairs(spawns) do
|
||||
for id, spawnData in next, objective.spawnList do
|
||||
for zone, spawns in next, spawnData.Spawns do
|
||||
for _, spawn in next, spawns do
|
||||
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
|
||||
local dX, dY, dInstance = HBD:GetWorldCoordinatesFromZone(spawn[1] / 100.0, spawn[2] / 100.0, uiMapId)
|
||||
local dist = HBD:GetWorldDistance(dInstance, playerX, playerY, dX, dY)
|
||||
@@ -902,8 +933,8 @@ function QuestieMap:GetNearestQuestSpawn(quest)
|
||||
local bestDistance = 999999999
|
||||
local playerX, playerY, playerI = HBD:GetPlayerWorldPosition()
|
||||
local bestSpawn, bestSpawnZone, bestSpawnType, bestSpawnName
|
||||
for zone, spawns in pairs(finisherSpawns) do
|
||||
for _, spawn in pairs(spawns) do
|
||||
for zone, spawns in next, finisherSpawns do
|
||||
for _, spawn in next, spawns do
|
||||
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
|
||||
local dX, dY, dInstance = HBD:GetWorldCoordinatesFromZone(spawn[1] / 100.0, spawn[2] / 100.0, uiMapId)
|
||||
local dist = HBD:GetWorldDistance(dInstance, playerX, playerY, dX, dY)
|
||||
@@ -929,7 +960,7 @@ function QuestieMap:GetNearestQuestSpawn(quest)
|
||||
local bestDistance = 999999999
|
||||
local bestSpawn, bestSpawnZone, bestSpawnId, bestSpawnType, bestSpawnName
|
||||
|
||||
for _, objective in pairs(quest.Objectives) do
|
||||
for _, objective in next, quest.Objectives do
|
||||
local spawn, zone, Name, id, Type, dist = QuestieMap:GetNearestSpawn(objective)
|
||||
if spawn and dist < bestDistance and ((not objective.Needed) or objective.Needed ~= objective.Collected) then
|
||||
bestDistance = dist
|
||||
@@ -941,7 +972,7 @@ function QuestieMap:GetNearestQuestSpawn(quest)
|
||||
end
|
||||
end
|
||||
|
||||
for _, objective in pairs(quest.SpecialObjectives) do
|
||||
for _, objective in next, quest.SpecialObjectives do
|
||||
local spawn, zone, Name, id, Type, dist = QuestieMap:GetNearestSpawn(objective)
|
||||
if spawn and dist < bestDistance and ((not objective.Needed) or objective.Needed ~= objective.Collected) then
|
||||
bestDistance = dist
|
||||
@@ -968,8 +999,11 @@ QuestieMap.zoneWaypointHoverColorOverrides = {
|
||||
function QuestieMap:DrawWaypoints(icon, waypoints, zone, color)
|
||||
if waypoints and waypoints[1] and waypoints[1][1] and waypoints[1][1][1] then -- check that waypoint data actually exists
|
||||
local lineFrames = QuestieFramePool:CreateWaypoints(icon, waypoints, nil, color or QuestieMap.zoneWaypointColorOverrides[zone], zone)
|
||||
for _, lineFrame in ipairs(lineFrames) do
|
||||
local lIndex = 1
|
||||
while lineFrames[lIndex] do
|
||||
local lineFrame = lineFrames[lIndex]
|
||||
QuestieMap:DrawLineIcon(lineFrame, zone, waypoints[1][1][1], waypoints[1][1][2])
|
||||
lIndex = lIndex + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ local ZOOM_MODIFIER = 1;
|
||||
|
||||
-- All the speed we can get is worth it.
|
||||
local tinsert = table.insert
|
||||
local pairs = pairs
|
||||
local next = next
|
||||
|
||||
function QuestieMap.utils:SetDrawOrder(frame)
|
||||
-- This is all fixes to always be on top of HandyNotes notes Let the frame level wars begin.
|
||||
@@ -69,7 +69,7 @@ end
|
||||
---@return number x, number y @Center coordinates
|
||||
function QuestieMap.utils.CenterPoint(points)
|
||||
local x, y = 0, 0
|
||||
local count = #points
|
||||
local count = table.getn(points)
|
||||
for i=1, count do
|
||||
local point = points[i]
|
||||
x = x + point.x
|
||||
@@ -88,7 +88,7 @@ function QuestieMap.utils:CalcHotzones(points, rangeR, count)
|
||||
-- if(points == nil) then return nil; end
|
||||
|
||||
local hotzones = {}
|
||||
local pointsCount = #points
|
||||
local pointsCount = table.getn(points)
|
||||
|
||||
if pointsCount == 1 then
|
||||
-- This is execution shortcut to skip loop in case table size == 1
|
||||
@@ -130,11 +130,11 @@ function QuestieMap.utils:CalcHotzones(points, rangeR, count)
|
||||
local distance = QuestieLib:Euclid(aX, aY, point2.worldX, point2.worldY)
|
||||
if (distance < movingRange) then
|
||||
point2.touched = true
|
||||
notes[#notes+1] = point2
|
||||
tinsert(notes, point2)
|
||||
end
|
||||
end
|
||||
end
|
||||
hotzones[#hotzones+1] = notes
|
||||
tinsert(hotzones, notes)
|
||||
end
|
||||
end
|
||||
return hotzones
|
||||
@@ -168,8 +168,8 @@ function QuestieMap.utils:IsExplored(uiMapId, x, y)
|
||||
end
|
||||
|
||||
function QuestieMap.utils:MapExplorationUpdate()
|
||||
for _, frameList in pairs(QuestieMap.questIdFrames) do
|
||||
for _, frameName in pairs(frameList) do
|
||||
for _, frameList in next, QuestieMap.questIdFrames do
|
||||
for _, frameName in next, frameList do
|
||||
local frame = _G[frameName]
|
||||
if (frame and frame.x and frame.y and frame.UiMapID and frame.hidden) then
|
||||
if (QuestieMap.utils:IsExplored(frame.UiMapID, frame.x, frame.y)) then
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
-------------------------
|
||||
--Import modules.
|
||||
-------------------------
|
||||
---@type Questie
|
||||
local Questie = QuestieLoader:ImportModule("Questie");
|
||||
---@type QuestieQuest
|
||||
local QuestieQuest = QuestieLoader:ImportModule("QuestieQuest");
|
||||
---@type QuestieOptions
|
||||
@@ -15,8 +17,10 @@ local QuestieTracker = QuestieLoader:ImportModule("QuestieTracker");
|
||||
local IsleOfQuelDanas = QuestieLoader:ImportModule("IsleOfQuelDanas");
|
||||
---@type l10n
|
||||
local l10n = QuestieLoader:ImportModule("l10n")
|
||||
---@type QuestieCompat
|
||||
local QuestieCompat = QuestieLoader:ImportModule("QuestieCompat")
|
||||
|
||||
QuestieOptions.tabs.advanced = {...}
|
||||
QuestieOptions.tabs.advanced = {}
|
||||
local optionsDefaults = QuestieOptionsDefaults:Load()
|
||||
local _GetLanguages
|
||||
|
||||
@@ -419,7 +423,71 @@ function QuestieOptions.tabs.advanced:Initialize()
|
||||
compat_header = {
|
||||
type = "header",
|
||||
order = 6,
|
||||
name = l10n('3.3.5 Compatibility Settings'),
|
||||
name = "3.3.5 Compatibility Settings",
|
||||
hidden = function() return not (Questie.IsWotlk or (QuestieCompat and QuestieCompat.Is335)) end,
|
||||
},
|
||||
useWotlkMapData = {
|
||||
type = "toggle",
|
||||
order = 6.1,
|
||||
name = "Use WotLK map data",
|
||||
desc = "Use WotLK map data for exploration and coordinates.",
|
||||
width = 1.65,
|
||||
hidden = function() return not (Questie.IsWotlk or (QuestieCompat and QuestieCompat.Is335)) end,
|
||||
get = function(info) return QuestieOptions:GetProfileValue(info); end,
|
||||
set = function(info, value)
|
||||
QuestieOptions:SetProfileValue(info, value)
|
||||
StaticPopup_Show("QUESTIE_RELOAD")
|
||||
end,
|
||||
},
|
||||
initDelay = {
|
||||
type = "range",
|
||||
order = 6.2,
|
||||
name = "Init rate delay",
|
||||
desc = "Adjust the initialization rate delay (seconds) for slower systems.",
|
||||
width = 1.65,
|
||||
min = 0.01,
|
||||
max = 0.5,
|
||||
step = 0.01,
|
||||
hidden = function() return not (Questie.IsWotlk or (QuestieCompat and QuestieCompat.Is335)) or not Questie.db.profile.debugEnabled end,
|
||||
get = function(info) return Questie.db.profile.initDelay or 0.05; end,
|
||||
set = function(info, value)
|
||||
Questie.db.profile.initDelay = value
|
||||
end,
|
||||
},
|
||||
resetDailyQuests = {
|
||||
type = "toggle",
|
||||
order = 6.3,
|
||||
name = "Reset Daily Quests",
|
||||
desc = "Force a daily quest reset check.",
|
||||
width = 1.65,
|
||||
hidden = function() return not (Questie.IsWotlk or (QuestieCompat and QuestieCompat.Is335)) end,
|
||||
get = function(info) return QuestieOptions:GetProfileValue(info); end,
|
||||
set = function(info, value)
|
||||
QuestieOptions:SetProfileValue(info, value)
|
||||
Questie.db.profile.dailyResetTime = nil
|
||||
StaticPopup_Show("QUESTIE_RELOAD")
|
||||
end,
|
||||
},
|
||||
weeklyResetDay = {
|
||||
type = "select",
|
||||
order = 6.4,
|
||||
values = {
|
||||
[1] = "Sunday",
|
||||
[2] = "Monday",
|
||||
[3] = "Tuesday",
|
||||
[4] = "Wednesday",
|
||||
[5] = "Thursday",
|
||||
[6] = "Friday",
|
||||
[7] = "Saturday",
|
||||
},
|
||||
style = 'dropdown',
|
||||
name = "Weekly Reset Day",
|
||||
disabled = function() return not Questie.db.profile.resetDailyQuests end,
|
||||
hidden = function() return not (Questie.IsWotlk or (QuestieCompat and QuestieCompat.Is335)) end,
|
||||
get = function(info) return QuestieOptions:GetProfileValue(info) or 3; end,
|
||||
set = function(info, value)
|
||||
QuestieOptions:SetProfileValue(info, value)
|
||||
end,
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ local function GetLearnedCounts()
|
||||
if not bucket then return none end
|
||||
local function Count(t)
|
||||
if not t then return 0 end
|
||||
local n = 0; for _ in pairs(t) do n = n + 1 end; return n
|
||||
local n = 0; local k, _ = next(t); while k do n = n + 1; k, _ = next(t, k) end; return n
|
||||
end
|
||||
local s = {
|
||||
npcs = Count(bucket.npcs),
|
||||
@@ -448,6 +448,7 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
name = function() return l10n("Contribute") end,
|
||||
},
|
||||
|
||||
|
||||
submit_desc = {
|
||||
type = "description",
|
||||
order = 6.1,
|
||||
@@ -501,7 +502,8 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
local output = ""
|
||||
local hasPlugins = false
|
||||
|
||||
for pluginName, plugin in pairs(QuestiePluginAPI.registeredPlugins) do
|
||||
local pluginName, plugin = next(QuestiePluginAPI.registeredPlugins)
|
||||
while pluginName do
|
||||
hasPlugins = true
|
||||
local q, n, o, i = GetPluginCounts(pluginName, plugin.stats or {})
|
||||
output = output .. "|cFF5EBAF3[Questie-" .. pluginName .. "]|r"
|
||||
@@ -509,6 +511,7 @@ function QuestieOptions.tabs.database:Initialize()
|
||||
output = output .. " NPCs: |cFFFFD700" .. tostring(n) .. "|r"
|
||||
output = output .. " Objects: |cFFFFD700" .. tostring(o) .. "|r"
|
||||
output = output .. " Items: |cFFFFD700" .. tostring(i) .. "|r\n"
|
||||
pluginName, plugin = next(QuestiePluginAPI.registeredPlugins, pluginName)
|
||||
end
|
||||
|
||||
if not hasPlugins then
|
||||
|
||||
@@ -204,17 +204,20 @@ function QuestieOptions.tabs.general:Initialize()
|
||||
desc = function() return l10n('Toggles the default Instant Quest Text option. This is just a shortcut for the WoW option in Interface.'); end,
|
||||
width = 1.55,
|
||||
get = function()
|
||||
if GetCVar("instantQuestText") == '1' then
|
||||
local val = GetCVar("instantQuestText")
|
||||
if val == '1' then
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
end
|
||||
end,
|
||||
set = function(info, value)
|
||||
if value then
|
||||
SetCVar("instantQuestText", 1);
|
||||
else
|
||||
SetCVar("instantQuestText", 0);
|
||||
if GetCVar("instantQuestText") ~= nil then
|
||||
if value then
|
||||
SetCVar("instantQuestText", "1");
|
||||
else
|
||||
SetCVar("instantQuestText", "0");
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
@@ -61,7 +61,7 @@ function AvailableQuests.DrawAvailableQuest(quest) -- prevent recursion
|
||||
|
||||
if quest.Starts["GameObject"] then
|
||||
local gameObjects = quest.Starts["GameObject"]
|
||||
for i = 1, #gameObjects do
|
||||
for i = 1, table.getn(gameObjects) do
|
||||
local objId = gameObjects[i]
|
||||
local obj = QuestieDB:GetObject(objId)
|
||||
if obj and obj.id then
|
||||
@@ -72,7 +72,7 @@ function AvailableQuests.DrawAvailableQuest(quest) -- prevent recursion
|
||||
|
||||
if quest.Starts["NPC"] then
|
||||
local npcs = quest.Starts["NPC"]
|
||||
for i = 1, #npcs do
|
||||
for i = 1, table.getn(npcs) do
|
||||
local starterId = npcs[i]
|
||||
local npc = QuestieDB:GetNPC(starterId)
|
||||
if npc and npc.id then
|
||||
@@ -90,10 +90,12 @@ end
|
||||
|
||||
|
||||
function AvailableQuests.UnloadUndoable()
|
||||
for questId, _ in pairs(availableQuests) do
|
||||
local questId, _ = next(availableQuests)
|
||||
while questId do
|
||||
if (not QuestieDB.IsDoable(questId)) then
|
||||
QuestieMap:UnloadQuestFrames(questId)
|
||||
end
|
||||
questId, _ = next(availableQuests, questId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -182,7 +184,10 @@ _CalculateAvailableQuests = function()
|
||||
|
||||
if QuestieMap.questIdFrames[questId] then
|
||||
-- We already drew this quest so we might need to update the icon (config changed/level up)
|
||||
for _, frame in ipairs(QuestieMap:GetFramesForQuest(questId)) do
|
||||
local frames = QuestieMap:GetFramesForQuest(questId)
|
||||
local i = 1
|
||||
while frames[i] do
|
||||
local frame = frames[i]
|
||||
if frame and frame.data and frame.data.QuestData then
|
||||
local newIcon = _GetQuestIcon(frame.data.QuestData)
|
||||
|
||||
@@ -190,6 +195,7 @@ _CalculateAvailableQuests = function()
|
||||
frame:UpdateTexture(Questie.usedIcons[newIcon])
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -200,7 +206,8 @@ _CalculateAvailableQuests = function()
|
||||
local questCount = 0
|
||||
|
||||
-- 1) Base Questie DB (compiled pointers)
|
||||
for questId in pairs(questData) do
|
||||
local questId, _ = next(questData)
|
||||
while questId do
|
||||
_DrawQuestIfAvailable(questId)
|
||||
|
||||
questCount = questCount + 1
|
||||
@@ -208,15 +215,15 @@ _CalculateAvailableQuests = function()
|
||||
questCount = 0
|
||||
yield()
|
||||
end
|
||||
questId, _ = next(questData, questId)
|
||||
end
|
||||
|
||||
-- 2) Ascension override quests (not present in QuestPointers)
|
||||
-- These are injected into QuestieDB.questDataOverrides by AscensionLoader.
|
||||
local ascensionQuestIds = QuestieDB.ascensionQuestIds or QuestieDB.questDataOverrides
|
||||
if type(ascensionQuestIds) == "table" then
|
||||
for questId in pairs(ascensionQuestIds) do
|
||||
if type(questId) == "number" then
|
||||
_DrawQuestIfAvailable(questId)
|
||||
-- 2) Plugin/Legacy/Ascension override quests (not present in QuestPointers)
|
||||
if type(QuestieDB.questDataOverrides) == "table" then
|
||||
local qid, _ = next(QuestieDB.questDataOverrides)
|
||||
while qid do
|
||||
if type(qid) == "number" then
|
||||
_DrawQuestIfAvailable(qid)
|
||||
|
||||
questCount = questCount + 1
|
||||
if questCount > QUESTS_PER_YIELD then
|
||||
@@ -224,6 +231,7 @@ _CalculateAvailableQuests = function()
|
||||
yield()
|
||||
end
|
||||
end
|
||||
qid, _ = next(QuestieDB.questDataOverrides, qid)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -238,16 +246,23 @@ _DrawChildQuests = function(questId, currentQuestlog, completedQuests)
|
||||
return
|
||||
end
|
||||
|
||||
for _, childQuestId in pairs(childQuests) do
|
||||
local childQuestId, _ = next(childQuests or {})
|
||||
while childQuestId do
|
||||
if (not completedQuests[childQuestId]) and (not currentQuestlog[childQuestId]) then
|
||||
local childQuestExclusiveTo = QuestieDB.QueryQuestSingle(childQuestId, "exclusiveTo")
|
||||
local blockedByExclusiveTo = false
|
||||
for _, exclusiveToQuestId in pairs(childQuestExclusiveTo or {}) do
|
||||
|
||||
local i = 1
|
||||
local exclusiveTo = childQuestExclusiveTo or {}
|
||||
while exclusiveTo[i] do
|
||||
local exclusiveToQuestId = exclusiveTo[i]
|
||||
if QuestiePlayer.currentQuestlog[exclusiveToQuestId] or completedQuests[exclusiveToQuestId] then
|
||||
blockedByExclusiveTo = true
|
||||
break
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if (not blockedByExclusiveTo) then
|
||||
QuestieDB.activeChildQuests[childQuestId] = true
|
||||
availableQuests[childQuestId] = true
|
||||
@@ -255,6 +270,7 @@ _DrawChildQuests = function(questId, currentQuestlog, completedQuests)
|
||||
_DrawAvailableQuest(childQuestId)
|
||||
end
|
||||
end
|
||||
childQuestId, _ = next(childQuests, childQuestId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -311,13 +327,14 @@ _AddStarter = function(starter, quest, tooltipKey)
|
||||
|
||||
local starterIcons = {}
|
||||
local starterLocs = {}
|
||||
for zone, spawns in pairs(starter.spawns or {}) do
|
||||
local zoneId, spawns = next(starter.spawns or {})
|
||||
while zoneId do
|
||||
local alreadyAddedSpawns = {}
|
||||
if (zone and spawns) then
|
||||
local coords
|
||||
for spawnIndex = 1, #spawns do
|
||||
coords = spawns[spawnIndex]
|
||||
if #spawns == 1 or _HasProperDistanceToAlreadyAddedSpawns(coords, alreadyAddedSpawns) then
|
||||
if spawns then
|
||||
local spawnIndex = 1
|
||||
while spawns[spawnIndex] do
|
||||
local coords = spawns[spawnIndex]
|
||||
if table.getn(spawns) == 1 or _HasProperDistanceToAlreadyAddedSpawns(coords, alreadyAddedSpawns) then
|
||||
local data = {
|
||||
Id = quest.Id,
|
||||
Icon = _GetQuestIcon(quest),
|
||||
@@ -330,31 +347,37 @@ _AddStarter = function(starter, quest, tooltipKey)
|
||||
}
|
||||
|
||||
if (coords[1] == -1 or coords[2] == -1) then
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(zone)
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(zoneId)
|
||||
if dungeonLocation then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local i = 1
|
||||
while dungeonLocation[i] do
|
||||
local value = dungeonLocation[i]
|
||||
QuestieMap:DrawWorldIcon(data, value[1], value[2], value[3])
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
local icon = QuestieMap:DrawWorldIcon(data, zone, coords[1], coords[2])
|
||||
local icon = QuestieMap:DrawWorldIcon(data, zoneId, coords[1], coords[2])
|
||||
if starter.waypoints then
|
||||
-- This is only relevant for waypoint drawing
|
||||
starterIcons[zone] = icon
|
||||
if not starterLocs[zone] then
|
||||
starterLocs[zone] = { coords[1], coords[2] }
|
||||
starterIcons[zoneId] = icon
|
||||
if not starterLocs[zoneId] then
|
||||
starterLocs[zoneId] = { coords[1], coords[2] }
|
||||
end
|
||||
end
|
||||
tinsert(alreadyAddedSpawns, coords)
|
||||
end
|
||||
end
|
||||
spawnIndex = spawnIndex + 1
|
||||
end
|
||||
end
|
||||
zoneId, spawns = next(starter.spawns, zoneId)
|
||||
end
|
||||
|
||||
-- Only for NPCs since objects do not move
|
||||
if starter.waypoints then
|
||||
for zone, waypoints in pairs(starter.waypoints or {}) do
|
||||
local zone, waypoints = next(starter.waypoints or {})
|
||||
while zone do
|
||||
if not dungeons[zone] and waypoints[1] and waypoints[1][1] and waypoints[1][1][1] then
|
||||
if not starterIcons[zone] then
|
||||
local data = {
|
||||
@@ -372,17 +395,20 @@ _AddStarter = function(starter, quest, tooltipKey)
|
||||
end
|
||||
QuestieMap:DrawWaypoints(starterIcons[zone], waypoints, zone)
|
||||
end
|
||||
zone, waypoints = next(starter.waypoints, zone)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_HasProperDistanceToAlreadyAddedSpawns = function(coords, alreadyAddedSpawns)
|
||||
for _, alreadyAdded in pairs(alreadyAddedSpawns) do
|
||||
local idx, alreadyAdded = next(alreadyAddedSpawns)
|
||||
while idx do
|
||||
local distance = QuestieLib.GetSpawnDistance(alreadyAdded, coords)
|
||||
-- 29 seems like a good distance. The "Undying Laborer" in Westfall shows both spawns for the "Horn of Lordaeron" rune
|
||||
if distance < 29 then
|
||||
return false
|
||||
end
|
||||
idx, alreadyAdded = next(alreadyAddedSpawns, idx)
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -404,19 +430,21 @@ local function StartPeriodicCleanup()
|
||||
-- Check every 5 seconds
|
||||
cleanupTimer = C_Timer.NewTicker(5, function()
|
||||
-- Only run if Questie isn't busy
|
||||
if QuestieMap._mapDrawQueue and #QuestieMap._mapDrawQueue == 0 and
|
||||
QuestieMap._minimapDrawQueue and #QuestieMap._minimapDrawQueue == 0 then
|
||||
if QuestieMap._mapDrawQueue and table.getn(QuestieMap._mapDrawQueue) == 0 and
|
||||
QuestieMap._minimapDrawQueue and table.getn(QuestieMap._minimapDrawQueue) == 0 then
|
||||
|
||||
local completedQuests = Questie.db.char.complete
|
||||
if not completedQuests then return end
|
||||
|
||||
for questId, frameList in pairs(QuestieMap.questIdFrames) do
|
||||
local questId, frameList = next(QuestieMap.questIdFrames)
|
||||
while questId do
|
||||
if completedQuests[questId] then
|
||||
-- This quest is complete but still has frames on the map
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[AvailableQuests] Cleanup: Removing lingering frames for completed quest:", questId)
|
||||
QuestieMap:UnloadQuestFrames(questId)
|
||||
QuestieTooltips:RemoveQuest(questId)
|
||||
end
|
||||
questId, frameList = next(QuestieMap.questIdFrames, questId)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -196,11 +196,14 @@ end
|
||||
function _QuestEventHandler:InitQuestLog()
|
||||
-- Fill the QuestLogCache for first time
|
||||
local cacheMiss, changes = QuestLogCache.CheckForChanges(nil)
|
||||
-- if cacheMiss then
|
||||
-- TODO actually can happen in rare edge case if player accepts new quest during questie init. *cough*
|
||||
-- or if someone managed to overflow game cache already at this point.
|
||||
--Questie:Error("Did you accept a quest during InitQuestLog? Please report on Github or Discord. Game's quest log cache is not ok. This shouldn't happen. Questie may malfunction.")
|
||||
-- end
|
||||
|
||||
if cacheMiss and (not Questie.started) then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestEventHandler:InitQuestLog] Cache miss during init, retrying in 0.5s...")
|
||||
C_Timer.After(0.5, function()
|
||||
_QuestEventHandler:InitQuestLog()
|
||||
end)
|
||||
return
|
||||
end
|
||||
|
||||
for questId, _ in pairs(changes) do
|
||||
questLog[questId] = {
|
||||
|
||||
@@ -223,10 +223,12 @@ function QuestLogCache.CheckForChanges(questIdsToCheck)
|
||||
|
||||
-- Debug / warning: ignore questId=0 and don't treat it as "missing" when the log has weird entries
|
||||
if questIdsToCheck then
|
||||
for questId in pairs(questIdsToCheck) do
|
||||
local questId, _ = next(questIdsToCheck)
|
||||
while questId do
|
||||
if questId and questId > 0 and (not questIdsChecked[questId]) then
|
||||
Questie:Warning("Please report on Github or Discord. QuestId doesn't exist in Game's quest log:", questId)
|
||||
end
|
||||
questId, _ = next(questIdsToCheck, questId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -279,9 +281,14 @@ end
|
||||
function QuestLogCache.GetQuest(questId)
|
||||
-- Fix the issue at function caller side if this error pops up.
|
||||
if (not cache[questId]) then
|
||||
-- Graceful degradation: return nil instead of throwing a fatal error if questId is 0 or Questie has not finished starting.
|
||||
-- This prevents many common initialization race conditions on custom clients like Ascension.
|
||||
if questId == 0 or (not Questie.started) then
|
||||
return nil
|
||||
end
|
||||
Questie:Print(debugstack(1, 20, 4))
|
||||
Questie:Error("Please report this error. GetQuest: The quest doesn't exist in QuestLogCache.", questId)
|
||||
return
|
||||
return nil
|
||||
end
|
||||
return cache[questId]
|
||||
end
|
||||
@@ -292,9 +299,13 @@ end
|
||||
function QuestLogCache.GetQuestObjectives(questId)
|
||||
-- Fix the issue at function caller side if this error pops up.
|
||||
if (not cache[questId]) then
|
||||
-- Graceful degradation: return an empty table instead of throwing a fatal error if questId is 0 or Questie has not finished starting.
|
||||
if questId == 0 or (not Questie.started) then
|
||||
return {}
|
||||
end
|
||||
Questie:Print(debugstack(1, 20, 4))
|
||||
Questie:Error("Please report this error. GetQuestObjectives: The quest doesn't exist in QuestLogCache.", questId)
|
||||
return
|
||||
return {}
|
||||
end
|
||||
return cache[questId].objectives
|
||||
end
|
||||
@@ -321,17 +332,21 @@ end
|
||||
function QuestLogCache.DebugPrintCache()
|
||||
print("DebugPrintCache", GetTime())
|
||||
local count = 0
|
||||
for questId, q in pairs(cache) do
|
||||
local questId, q = next(cache)
|
||||
while questId do
|
||||
count = count + 1
|
||||
print("Quest: (" .. questId .. ") \"" .. q.title .. "\" questTag=" .. tostring(q.questTag),
|
||||
"isComplete=" .. tostring(q.isComplete))
|
||||
if not next(q.objectives) then
|
||||
print(" no objectives")
|
||||
else
|
||||
for i, o in ipairs(q.objectives) do
|
||||
DebugPrintObjective(q, i, o)
|
||||
local i = 1
|
||||
while q.objectives[i] do
|
||||
DebugPrintObjective(q, i, q.objectives[i])
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
questId, q = next(cache, questId)
|
||||
end
|
||||
print("Total Quests ", count)
|
||||
end
|
||||
@@ -342,16 +357,21 @@ function QuestLogCache.DebugPrintCacheChanges(cacheMiss, changes)
|
||||
(cacheMiss and next(changes)) -- highlight untypical cases. they are okey, but sometimes interesting.
|
||||
print("DebugPrintCacheChanges", GetTime(), (highlight and "\124cffFF4444CacheMiss:\124r" or "CacheMiss"), cacheMiss)
|
||||
|
||||
for questId, objIndexes in pairs(changes) do
|
||||
local questId, objIndexes = next(changes)
|
||||
while questId do
|
||||
local q = cache[questId]
|
||||
print("Quest: (" .. questId .. ") \"" .. q.title .. "\" questTag=" .. tostring(q.questTag),
|
||||
"isComplete=" .. tostring(q.isComplete))
|
||||
if not next(objIndexes) then
|
||||
print(" no objectives changed (or quest doesn't have objectives)")
|
||||
else
|
||||
for _, i in ipairs(objIndexes) do
|
||||
local idx = 1
|
||||
while objIndexes[idx] do
|
||||
local i = objIndexes[idx]
|
||||
DebugPrintObjective(q, i, q.objectives[i])
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
questId, objIndexes = next(changes, questId)
|
||||
end
|
||||
end
|
||||
|
||||
+203
-84
@@ -84,10 +84,12 @@ end
|
||||
---@param category AutoBlacklistString
|
||||
function QuestieQuest.ResetAutoblacklistCategory(category)
|
||||
Questie:Debug(Questie.DEBUG_SPAM, "[QuestieQuest]: Resetting autoblacklist category", category)
|
||||
for questId, questCategory in pairs(QuestieDB.autoBlacklist) do
|
||||
local questId, questCategory = next(QuestieDB.autoBlacklist)
|
||||
while questId do
|
||||
if questCategory == category then
|
||||
QuestieDB.autoBlacklist[questId] = nil
|
||||
end
|
||||
questId, questCategory = next(QuestieDB.autoBlacklist, questId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,9 +108,11 @@ end
|
||||
|
||||
function _QuestieQuest:ShowQuestIcons()
|
||||
local trackerHiddenQuests = Questie.db.char.TrackerHiddenQuests
|
||||
for questId, frameList in pairs(QuestieMap.questIdFrames) do
|
||||
local questId, frameList = next(QuestieMap.questIdFrames)
|
||||
while questId do
|
||||
if (not trackerHiddenQuests) or (not trackerHiddenQuests[questId]) then -- Skip quests which are completely hidden from the Tracker menu
|
||||
for _, frameName in pairs(frameList) do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
local _, frameName = next(frameList)
|
||||
while _ do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
---@type IconFrame
|
||||
local icon = _G[frameName];
|
||||
if not icon.data then
|
||||
@@ -121,8 +125,10 @@ function _QuestieQuest:ShowQuestIcons()
|
||||
icon:FakeShow()
|
||||
|
||||
if icon.data.lineFrames then
|
||||
for _, lineIcon in pairs(icon.data.lineFrames) do
|
||||
local __, lineIcon = next(icon.data.lineFrames)
|
||||
while __ do
|
||||
lineIcon:FakeShow()
|
||||
__, lineIcon = next(icon.data.lineFrames, __)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -133,25 +139,33 @@ function _QuestieQuest:ShowQuestIcons()
|
||||
end
|
||||
end
|
||||
end
|
||||
_, frameName = next(frameList, _)
|
||||
end
|
||||
end
|
||||
questId, frameList = next(QuestieMap.questIdFrames, questId)
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieQuest:ShowManualIcons()
|
||||
for _, frameList in pairs(QuestieMap.manualFrames) do
|
||||
for _, frameName in pairs(frameList) do
|
||||
local _, frameList = next(QuestieMap.manualFrames)
|
||||
while _ do
|
||||
local __, frameName = next(frameList)
|
||||
while __ do
|
||||
local icon = _G[frameName];
|
||||
if icon ~= nil and icon.hidden and (not icon:ShouldBeHidden()) then -- check for function to make sure its a frame
|
||||
icon:FakeShow()
|
||||
end
|
||||
__, frameName = next(frameList, __)
|
||||
end
|
||||
_, frameList = next(QuestieMap.manualFrames, _)
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieQuest:HideQuestIcons()
|
||||
for _, frameList in pairs(QuestieMap.questIdFrames) do
|
||||
for _, frameName in pairs(frameList) do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
local _, frameList = next(QuestieMap.questIdFrames)
|
||||
while _ do
|
||||
local __, frameName = next(frameList)
|
||||
while __ do -- this may seem a bit expensive, but its actually really fast due to the order things are checked
|
||||
local icon = _G[frameName];
|
||||
if icon ~= nil and (not icon.hidden) and icon:ShouldBeHidden() then -- check for function to make sure its a frame
|
||||
-- Hides Objective Icons
|
||||
@@ -161,8 +175,10 @@ function _QuestieQuest:HideQuestIcons()
|
||||
QuestieTooltips:RemoveQuest(icon.data.Id)
|
||||
|
||||
if icon.data.lineFrames then
|
||||
for _, lineIcon in pairs(icon.data.lineFrames) do
|
||||
local ___, lineIcon = next(icon.data.lineFrames)
|
||||
while ___ do
|
||||
lineIcon:FakeHide()
|
||||
___, lineIcon = next(icon.data.lineFrames, ___)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -171,54 +187,71 @@ function _QuestieQuest:HideQuestIcons()
|
||||
else
|
||||
icon:FadeIn()
|
||||
end
|
||||
__, frameName = next(frameList, __)
|
||||
end
|
||||
_, frameList = next(QuestieMap.questIdFrames, _)
|
||||
end
|
||||
end
|
||||
|
||||
function _QuestieQuest:HideManualIcons()
|
||||
for _, frameList in pairs(QuestieMap.manualFrames) do
|
||||
for _, frameName in pairs(frameList) do
|
||||
local _, frameList = next(QuestieMap.manualFrames)
|
||||
while _ do
|
||||
local __, frameName = next(frameList)
|
||||
while __ do
|
||||
local icon = _G[frameName];
|
||||
if icon ~= nil and (not icon.hidden) and icon:ShouldBeHidden() then -- check for function to make sure its a frame
|
||||
icon:FakeHide()
|
||||
end
|
||||
__, frameName = next(frameList, __)
|
||||
end
|
||||
_, frameList = next(QuestieMap.manualFrames, _)
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieQuest:ClearAllNotes()
|
||||
for questId in pairs(QuestiePlayer.currentQuestlog) do
|
||||
local questId, _ = next(QuestiePlayer.currentQuestlog)
|
||||
while questId do
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if not quest then
|
||||
return
|
||||
end
|
||||
|
||||
for _, s in pairs(quest.Objectives) do
|
||||
local index, s = next(quest.Objectives)
|
||||
while index do
|
||||
s.AlreadySpawned = {}
|
||||
index, s = next(quest.Objectives, index)
|
||||
end
|
||||
|
||||
if next(quest.SpecialObjectives) then
|
||||
for _, s in pairs(quest.SpecialObjectives) do
|
||||
local sIndex, s = next(quest.SpecialObjectives)
|
||||
while sIndex do
|
||||
s.AlreadySpawned = {}
|
||||
sIndex, s = next(quest.SpecialObjectives, sIndex)
|
||||
end
|
||||
end
|
||||
questId, _ = next(QuestiePlayer.currentQuestlog, questId)
|
||||
end
|
||||
|
||||
for _, frameList in pairs(QuestieMap.questIdFrames) do
|
||||
for _, frameName in pairs(frameList) do
|
||||
local _, frameList = next(QuestieMap.questIdFrames)
|
||||
while _ do
|
||||
local __, frameName = next(frameList)
|
||||
while __ do
|
||||
local icon = _G[frameName]
|
||||
if icon and icon.Unload then
|
||||
icon:Unload()
|
||||
end
|
||||
__, frameName = next(frameList, __)
|
||||
end
|
||||
_, frameList = next(QuestieMap.questIdFrames, _)
|
||||
end
|
||||
|
||||
QuestieMap.questIdFrames = {}
|
||||
end
|
||||
|
||||
function QuestieQuest:ClearAllToolTips()
|
||||
for questId in pairs(QuestiePlayer.currentQuestlog) do
|
||||
local questId, _ = next(QuestiePlayer.currentQuestlog)
|
||||
while questId do
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if not quest then
|
||||
@@ -226,7 +259,8 @@ function QuestieQuest:ClearAllToolTips()
|
||||
end
|
||||
|
||||
if quest.Objectives then
|
||||
for _, objective in pairs(quest.Objectives) do
|
||||
local oId, objective = next(quest.Objectives)
|
||||
while oId do
|
||||
if objective.hasRegisteredTooltips then
|
||||
objective.hasRegisteredTooltips = false
|
||||
end
|
||||
@@ -234,11 +268,13 @@ function QuestieQuest:ClearAllToolTips()
|
||||
if objective.registeredItemTooltips then
|
||||
objective.registeredItemTooltips = false
|
||||
end
|
||||
oId, objective = next(quest.Objectives, oId)
|
||||
end
|
||||
end
|
||||
|
||||
if quest.ObjectiveData then
|
||||
for _, objective in pairs(quest.ObjectiveData) do
|
||||
local odId, objective = next(quest.ObjectiveData)
|
||||
while odId do
|
||||
if objective.hasRegisteredTooltips then
|
||||
objective.hasRegisteredTooltips = false
|
||||
end
|
||||
@@ -246,11 +282,13 @@ function QuestieQuest:ClearAllToolTips()
|
||||
if objective.registeredItemTooltips then
|
||||
objective.registeredItemTooltips = false
|
||||
end
|
||||
odId, objective = next(quest.ObjectiveData, odId)
|
||||
end
|
||||
end
|
||||
|
||||
if next(quest.SpecialObjectives) then
|
||||
for _, objective in pairs(quest.SpecialObjectives) do
|
||||
local soId, objective = next(quest.SpecialObjectives)
|
||||
while soId do
|
||||
if objective.hasRegisteredTooltips then
|
||||
objective.hasRegisteredTooltips = false
|
||||
end
|
||||
@@ -258,8 +296,10 @@ function QuestieQuest:ClearAllToolTips()
|
||||
if objective.registeredItemTooltips then
|
||||
objective.registeredItemTooltips = false
|
||||
end
|
||||
soId, objective = next(quest.SpecialObjectives, soId)
|
||||
end
|
||||
end
|
||||
questId, _ = next(QuestiePlayer.currentQuestlog, questId)
|
||||
end
|
||||
|
||||
QuestieTooltips.lookupByKey = {}
|
||||
@@ -271,7 +311,8 @@ end
|
||||
local function _UpdateSpecials(questId)
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
if quest and next(quest.SpecialObjectives) then
|
||||
for _, objective in pairs(quest.SpecialObjectives) do
|
||||
local _, objective = next(quest.SpecialObjectives)
|
||||
while _ do
|
||||
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, 0, objective,
|
||||
true)
|
||||
if not result then
|
||||
@@ -279,6 +320,7 @@ local function _UpdateSpecials(questId)
|
||||
l10n("There was an error populating objectives for %s %s %s %s", quest.name or "No quest name",
|
||||
quest.Id or "No quest id", 0 or "No objective", err or "No error"));
|
||||
end
|
||||
_, objective = next(quest.SpecialObjectives, _)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -300,8 +342,8 @@ function QuestieQuest:SmoothReset()
|
||||
return QuestLogCache.TestGameCache()
|
||||
end,
|
||||
function()
|
||||
return #QuestieMap._mapDrawQueue == 0 and
|
||||
#QuestieMap._minimapDrawQueue == 0 -- wait until draw queue is finished
|
||||
return table.getn(QuestieMap._mapDrawQueue) == 0 and
|
||||
table.getn(QuestieMap._minimapDrawQueue) == 0 -- wait until draw queue is finished
|
||||
end,
|
||||
function()
|
||||
QuestieQuest:ClearAllNotes()
|
||||
@@ -313,8 +355,8 @@ function QuestieQuest:SmoothReset()
|
||||
return true
|
||||
end,
|
||||
function()
|
||||
return #QuestieMap._mapDrawQueue == 0 and
|
||||
#QuestieMap._minimapDrawQueue == 0 -- wait until draw queue is finished
|
||||
return table.getn(QuestieMap._mapDrawQueue) == 0 and
|
||||
table.getn(QuestieMap._minimapDrawQueue) == 0 -- wait until draw queue is finished
|
||||
end,
|
||||
function()
|
||||
-- reset quest log
|
||||
@@ -360,8 +402,8 @@ function QuestieQuest:SmoothReset()
|
||||
return not QuestieQuest._nextRestQuest
|
||||
end,
|
||||
function()
|
||||
return (not QuestieQuest._resetNeedsAvailables) and #QuestieMap._mapDrawQueue == 0 and
|
||||
#QuestieMap._minimapDrawQueue == 0
|
||||
return (not QuestieQuest._resetNeedsAvailables) and table.getn(QuestieMap._mapDrawQueue) == 0 and
|
||||
table.getn(QuestieMap._minimapDrawQueue) == 0
|
||||
end,
|
||||
function()
|
||||
QuestieQuest._isResetting = nil
|
||||
@@ -588,9 +630,11 @@ function QuestieQuest:AbandonedQuest(questId)
|
||||
|
||||
local childQuests = QuestieDB.QueryQuestSingle(questId, "childQuests")
|
||||
if childQuests then
|
||||
for _, childQuestId in pairs(childQuests) do
|
||||
local _, childQuestId = next(childQuests)
|
||||
while _ do
|
||||
Questie.db.char.complete[childQuestId] = nil
|
||||
QuestLogCache.RemoveQuest(childQuestId)
|
||||
_, childQuestId = next(childQuests, _)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -675,14 +719,14 @@ function QuestieQuest:UpdateQuest(questId)
|
||||
-- the item leaves the bag, making CheckQuestSourceItem return false. Without this guard, Questie
|
||||
-- would reset the quest and draw the key-drop NPC on the map even though all objectives are done.
|
||||
local allObjectivesComplete = false
|
||||
if quest.Objectives and #quest.Objectives > 0 then
|
||||
if quest.Objectives and table.getn(quest.Objectives) > 0 then
|
||||
local doneCount = 0
|
||||
for i = 1, #quest.Objectives do
|
||||
for i = 1, table.getn(quest.Objectives) do
|
||||
if quest.Objectives[i] and quest.Objectives[i].Completed == true then
|
||||
doneCount = doneCount + 1
|
||||
end
|
||||
end
|
||||
allObjectivesComplete = (doneCount == #quest.Objectives)
|
||||
allObjectivesComplete = (doneCount == table.getn(quest.Objectives))
|
||||
end
|
||||
|
||||
if quest and not allObjectivesComplete and (quest.WasComplete or (sourceItemId > 0 and QuestieQuest:CheckQuestSourceItem(questId) == false)) then
|
||||
@@ -714,16 +758,16 @@ function QuestieQuest:UpdateQuest(questId)
|
||||
-- Sometimes objective(s) are all complete but the quest doesn't get flagged as "1". So far the only
|
||||
-- quests I've found that does this are quests involving an item(s). Checks all objective(s) and if they
|
||||
-- are all complete, simulate a "Complete Quest" so the quest finisher appears on the map.
|
||||
if quest.Objectives and #quest.Objectives > 0 then
|
||||
if quest.Objectives and table.getn(quest.Objectives) > 0 then
|
||||
local numCompleteObjectives = 0
|
||||
|
||||
for i = 1, #quest.Objectives do
|
||||
for i = 1, table.getn(quest.Objectives) do
|
||||
if quest.Objectives[i] and quest.Objectives[i].Completed and quest.Objectives[i].Completed == true then
|
||||
numCompleteObjectives = numCompleteObjectives + 1
|
||||
end
|
||||
end
|
||||
|
||||
if numCompleteObjectives == #quest.Objectives then
|
||||
if numCompleteObjectives == table.getn(quest.Objectives) then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieQuest:UpdateQuest] All Quest Objective(s) are Complete! Manually setting quest to Complete!")
|
||||
QuestieMap:UnloadQuestFrames(questId)
|
||||
@@ -733,7 +777,7 @@ function QuestieQuest:UpdateQuest(questId)
|
||||
else
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieQuest:UpdateQuest] Quest Objective Status is: " ..
|
||||
numCompleteObjectives .. ", out of: " .. #quest.Objectives .. ". No updates required.")
|
||||
numCompleteObjectives .. ", out of: " .. table.getn(quest.Objectives) .. ". No updates required.")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -748,8 +792,10 @@ function QuestieQuest:SetObjectivesDirty(questId)
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if quest then
|
||||
for _, objective in pairs(quest.Objectives) do
|
||||
local objKey, objective = next(quest.Objectives or {})
|
||||
while objKey do
|
||||
objective.isUpdated = false
|
||||
objKey, objective = next(quest.Objectives, objKey)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -760,7 +806,8 @@ function QuestieQuest:GetAllQuestIds()
|
||||
|
||||
QuestiePlayer.currentQuestlog = {}
|
||||
|
||||
for questId, data in pairs(QuestLogCache.questLog_DO_NOT_MODIFY) do -- DO NOT MODIFY THE RETURNED TABLE
|
||||
local questId, data = next(QuestLogCache.questLog_DO_NOT_MODIFY)
|
||||
while questId do
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if not quest then
|
||||
@@ -807,6 +854,7 @@ function QuestieQuest:GetAllQuestIds()
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Adding the quest", questId,
|
||||
QuestiePlayer.currentQuestlog[questId])
|
||||
end
|
||||
questId, data = next(QuestLogCache.questLog_DO_NOT_MODIFY, questId)
|
||||
end
|
||||
|
||||
QuestieCombatQueue:Queue(function()
|
||||
@@ -826,14 +874,18 @@ local function _AddSourceItemObjective(quest)
|
||||
|
||||
-- If sourceItemId is already part of an item objective, do nothing
|
||||
if itemObjectives then
|
||||
for _, itemObjectiveIndex in pairs(itemObjectives) do
|
||||
for _, itemObjectiveId in pairs(itemObjectiveIndex) do
|
||||
local k1, itemObjectiveIndex = next(itemObjectives)
|
||||
while k1 do
|
||||
local k2, itemObjectiveId = next(itemObjectiveIndex or {})
|
||||
while k2 do
|
||||
if itemObjectiveId == sourceItemId then
|
||||
Questie:Debug(Questie.DEBUG_INFO,
|
||||
"[QuestieQuest:_AddSourceItemObjective] This item is already part of a quest objective.")
|
||||
return
|
||||
end
|
||||
k2, itemObjectiveId = next(itemObjectiveIndex, k2)
|
||||
end
|
||||
k1, itemObjectiveIndex = next(itemObjectives, k1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -899,22 +951,27 @@ local function _AddRequiredSourceItemObjective(quest)
|
||||
local questObjectives = QuestieDB.QueryQuestSingle(quest.Id, "objectives")
|
||||
local itemObjectives = questObjectives and questObjectives[3]
|
||||
|
||||
for index, requiredSourceItemId in pairs(quest.requiredSourceItems) do
|
||||
local index, requiredSourceItemId = next(quest.requiredSourceItems or {})
|
||||
while index do
|
||||
local alreadyInObjectives = false
|
||||
|
||||
if itemObjectives then
|
||||
for _, itemObjectiveIndex in pairs(itemObjectives) do
|
||||
for _, itemObjectiveId in pairs(itemObjectiveIndex) do
|
||||
local k1, itemObjectiveIndex = next(itemObjectives)
|
||||
while k1 do
|
||||
local k2, itemObjectiveId = next(itemObjectiveIndex or {})
|
||||
while k2 do
|
||||
if itemObjectiveId == requiredSourceItemId or quest.sourceItemId == requiredSourceItemId then
|
||||
Questie:Debug(Questie.DEBUG_INFO,
|
||||
"[QuestieQuest:_AddRequiredSourceItemObjective] This item is already part of a quest objective.")
|
||||
alreadyInObjectives = true
|
||||
break
|
||||
end
|
||||
k2, itemObjectiveId = next(itemObjectiveIndex, k2)
|
||||
end
|
||||
if alreadyInObjectives then
|
||||
break
|
||||
end
|
||||
k1, itemObjectiveIndex = next(itemObjectives, k1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -936,6 +993,7 @@ local function _AddRequiredSourceItemObjective(quest)
|
||||
QuestieTooltips:RegisterObjectiveTooltip(quest.Id, "i_" .. requiredSourceItemId, fakeObjective);
|
||||
end
|
||||
end
|
||||
index, requiredSourceItemId = next(quest.requiredSourceItems, index)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -945,7 +1003,8 @@ function QuestieQuest:GetAllQuestIdsNoObjectives()
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Getting all quests without objectives")
|
||||
QuestiePlayer.currentQuestlog = {}
|
||||
|
||||
for questId, data in pairs(QuestLogCache.questLog_DO_NOT_MODIFY) do -- DO NOT MODIFY THE RETURNED TABLE
|
||||
local questId, data = next(QuestLogCache.questLog_DO_NOT_MODIFY)
|
||||
while questId do
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if not quest then
|
||||
@@ -968,6 +1027,7 @@ function QuestieQuest:GetAllQuestIdsNoObjectives()
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Adding the quest", questId,
|
||||
QuestiePlayer.currentQuestlog[questId])
|
||||
end
|
||||
questId, data = next(QuestLogCache.questLog_DO_NOT_MODIFY, questId)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -984,7 +1044,8 @@ function QuestieQuest:UpdateObjectiveNotes(quest)
|
||||
end
|
||||
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] UpdateObjectiveNotes:", quest.Id)
|
||||
for objectiveIndex, objective in pairs(quest.Objectives) do
|
||||
local objectiveIndex, objective = next(quest.Objectives or {})
|
||||
while objectiveIndex do
|
||||
-- Skip tracker-only fallback objectives — they have no DB Id and can't be populated
|
||||
if objective.Type ~= "fallback" then
|
||||
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, objectiveIndex,
|
||||
@@ -994,10 +1055,12 @@ function QuestieQuest:UpdateObjectiveNotes(quest)
|
||||
quest.name, quest.Id, objectiveIndex, err)
|
||||
end
|
||||
end
|
||||
objectiveIndex, objective = next(quest.Objectives, objectiveIndex)
|
||||
end
|
||||
|
||||
if quest.SpecialObjectives and next(quest.SpecialObjectives) then
|
||||
for _, objective in pairs(quest.SpecialObjectives) do
|
||||
local specKey, objective = next(quest.SpecialObjectives)
|
||||
while specKey do
|
||||
if objective.Type ~= "fallback" then
|
||||
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, 0, objective,
|
||||
true)
|
||||
@@ -1007,6 +1070,7 @@ function QuestieQuest:UpdateObjectiveNotes(quest)
|
||||
quest.Id or "No quest id", 0 or "No objective", err or "No error"));
|
||||
end
|
||||
end
|
||||
specKey, objective = next(quest.SpecialObjectives, specKey)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1100,9 +1164,12 @@ function QuestieQuest:AddFinisher(quest)
|
||||
|
||||
-- Clear duplicate keys if they exist
|
||||
if QuestieTooltips.lookupByKey[key] then
|
||||
if QuestieTooltips:GetTooltip(key) ~= nil and #QuestieTooltips:GetTooltip(key) > 1 then
|
||||
for ttline = 1, #QuestieTooltips:GetTooltip(key) do
|
||||
for index, line in pairs(QuestieTooltips:GetTooltip(key)) do
|
||||
local tooltip = QuestieTooltips:GetTooltip(key)
|
||||
if tooltip ~= nil and table.getn(tooltip) > 1 then
|
||||
local ttline = 1
|
||||
while ttline <= table.getn(tooltip) do
|
||||
local index, line = next(tooltip)
|
||||
while index do
|
||||
if (ttline == index) then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP,
|
||||
"[QuestieQuest] AddFinisher - Removing duplicate Quest Title!")
|
||||
@@ -1130,7 +1197,9 @@ function QuestieQuest:AddFinisher(quest)
|
||||
end
|
||||
end
|
||||
end
|
||||
index, line = next(tooltip, index)
|
||||
end
|
||||
ttline = ttline + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1140,9 +1209,11 @@ function QuestieQuest:AddFinisher(quest)
|
||||
local finisherIcons = {}
|
||||
local finisherLocs = {}
|
||||
|
||||
for finisherZone, spawns in pairs(finisher.spawns or {}) do
|
||||
local finisherZone, spawns = next(finisher.spawns or {})
|
||||
while finisherZone do
|
||||
if (finisherZone ~= nil and spawns ~= nil) then
|
||||
for _, coords in ipairs(spawns) do
|
||||
local _, coords = next(spawns)
|
||||
while _ do
|
||||
local data = {
|
||||
Id = questId,
|
||||
Icon = Questie.ICON_TYPE_COMPLETE,
|
||||
@@ -1165,12 +1236,14 @@ function QuestieQuest:AddFinisher(quest)
|
||||
if (coords[1] == -1 or coords[2] == -1) then
|
||||
local dungeonLocation = ZoneDB:GetDungeonLocation(finisherZone)
|
||||
if dungeonLocation ~= nil then
|
||||
for _, value in ipairs(dungeonLocation) do
|
||||
local __, value = next(dungeonLocation)
|
||||
while __ do
|
||||
local zone = value[1];
|
||||
local x = value[2];
|
||||
local y = value[3];
|
||||
|
||||
QuestieMap:DrawWorldIcon(data, zone, x, y)
|
||||
__, value = next(dungeonLocation, __)
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -1185,12 +1258,15 @@ function QuestieQuest:AddFinisher(quest)
|
||||
finisherLocs[finisherZone] = { x, y }
|
||||
end
|
||||
end
|
||||
_, coords = next(spawns, _)
|
||||
end
|
||||
end
|
||||
finisherZone, spawns = next(finisher.spawns or {}, finisherZone)
|
||||
end
|
||||
|
||||
if finisher.waypoints then
|
||||
for zone, waypoints in pairs(finisher.waypoints) do
|
||||
local zone, waypoints = next(finisher.waypoints)
|
||||
while zone do
|
||||
if (not ZoneDB.IsDungeonZone(zone)) then
|
||||
if not finisherIcons[zone] and waypoints[1] and waypoints[1][1] and waypoints[1][1][1] then
|
||||
local data = {
|
||||
@@ -1219,6 +1295,7 @@ function QuestieQuest:AddFinisher(quest)
|
||||
|
||||
QuestieMap:DrawWaypoints(finisherIcons[zone], waypoints, zone)
|
||||
end
|
||||
zone, waypoints = next(finisher.waypoints, zone)
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -1307,15 +1384,21 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI
|
||||
local zones = {}
|
||||
local objectiveZone
|
||||
|
||||
for _, spawnData in pairs(objective.spawnList) do
|
||||
for zone in pairs(spawnData.Spawns) do
|
||||
local _id, spawnData = next(objective.spawnList)
|
||||
while _id do
|
||||
local zone, _ = next(spawnData.Spawns)
|
||||
while zone do
|
||||
zones[zone] = true
|
||||
zone, _ = next(spawnData.Spawns, zone)
|
||||
end
|
||||
_id, spawnData = next(objective.spawnList, _id)
|
||||
end
|
||||
|
||||
for zone in pairs(zones) do
|
||||
objectiveZone = zone
|
||||
local z, _ = next(zones)
|
||||
while z do
|
||||
objectiveZone = z
|
||||
zoneCount = zoneCount + 1
|
||||
z, _ = next(zones, z)
|
||||
end
|
||||
|
||||
if zoneCount == 1 then -- this objective happens in 1 zone, clustering should be relative to that zone
|
||||
@@ -1325,10 +1408,12 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI
|
||||
|
||||
-- Filter static spawns if prioritizeMyData is enabled and we have high-confidence learned data
|
||||
if Questie.dbLearner and Questie.dbLearner.global and Questie.dbLearner.global.settings and Questie.dbLearner.global.settings.prioritizeMyData then
|
||||
for zone in pairs(zones) do
|
||||
local zone, _ = next(zones)
|
||||
while zone do
|
||||
local suppressed = (objectiveData.Type == "monster" and QuestieDB.GetSuppressedNPCs(zone)) or (objectiveData.Type == "object" and QuestieDB.GetSuppressedObjects(zone))
|
||||
if suppressed then
|
||||
for id, spawnData in pairs(objective.spawnList) do
|
||||
local id, spawnData = next(objective.spawnList)
|
||||
while id do
|
||||
if suppressed[id] and spawnData.Spawns and spawnData.Spawns[zone] then
|
||||
-- Only suppress if this isn't a learned spawn (learned spawns have .isLearned)
|
||||
if not spawnData.isLearned then
|
||||
@@ -1338,8 +1423,10 @@ function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockI
|
||||
end
|
||||
end
|
||||
end
|
||||
id, spawnData = next(objective.spawnList, id)
|
||||
end
|
||||
end
|
||||
zone, _ = next(zones, zone)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1354,10 +1441,12 @@ _RegisterObjectiveTooltips = function(objective, questId, blockItemTooltips)
|
||||
|
||||
if objective.spawnList then
|
||||
if (not objective.hasRegisteredTooltips) then
|
||||
for id, spawnData in pairs(objective.spawnList) do
|
||||
local id, spawnData = next(objective.spawnList)
|
||||
while id do
|
||||
if spawnData.TooltipKey and (not objective.AlreadySpawned[id]) then
|
||||
QuestieTooltips:RegisterObjectiveTooltip(questId, spawnData.TooltipKey, objective)
|
||||
end
|
||||
id, spawnData = next(objective.spawnList, id)
|
||||
end
|
||||
|
||||
objective.hasRegisteredTooltips = true
|
||||
@@ -1388,17 +1477,23 @@ end
|
||||
|
||||
_UnloadAlreadySpawnedIcons = function(objective)
|
||||
if objective.AlreadySpawned and next(objective.AlreadySpawned) then
|
||||
for id, spawn in pairs(objective.AlreadySpawned) do
|
||||
local id, spawn = next(objective.AlreadySpawned)
|
||||
while id do
|
||||
if spawn then
|
||||
for _, mapIcon in pairs(spawn.mapRefs) do
|
||||
local _, mapIcon = next(spawn.mapRefs)
|
||||
while _ do
|
||||
mapIcon:Unload()
|
||||
_, mapIcon = next(spawn.mapRefs, _)
|
||||
end
|
||||
for _, minimapIcon in pairs(spawn.minimapRefs) do
|
||||
local __, minimapIcon = next(spawn.minimapRefs)
|
||||
while __ do
|
||||
minimapIcon:Unload()
|
||||
__, minimapIcon = next(spawn.minimapRefs, __)
|
||||
end
|
||||
spawn.mapRefs = {}
|
||||
spawn.minimapRefs = {}
|
||||
end
|
||||
id, spawn = next(objective.AlreadySpawned, id)
|
||||
end
|
||||
objective.AlreadySpawned = {}
|
||||
end
|
||||
@@ -1414,7 +1509,8 @@ _DetermineIconsToDraw = function(quest, objective, objectiveIndex, objectiveCent
|
||||
local iconsToDraw = {}
|
||||
local spawnItemId
|
||||
|
||||
for id, spawnData in pairs(objective.spawnList) do
|
||||
local id, spawnData = next(objective.spawnList)
|
||||
while id do
|
||||
if spawnData.ItemId then
|
||||
spawnItemId = spawnData.ItemId
|
||||
end
|
||||
@@ -1444,9 +1540,11 @@ _DetermineIconsToDraw = function(quest, objective, objectiveIndex, objectiveCent
|
||||
mapRefs = {},
|
||||
}
|
||||
|
||||
for zone, spawns in pairs(spawnData.Spawns) do
|
||||
local zone, spawns = next(spawnData.Spawns)
|
||||
while zone do
|
||||
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
|
||||
for _, spawn in pairs(spawns) do
|
||||
local _, spawn = next(spawns)
|
||||
while _ do
|
||||
if (spawn[1] and spawn[2]) then
|
||||
local drawIcon = {
|
||||
AlreadySpawnedId = id,
|
||||
@@ -1475,14 +1573,17 @@ _DetermineIconsToDraw = function(quest, objective, objectiveIndex, objectiveCent
|
||||
--local distance = floor(distance)
|
||||
local iconList = iconsToDraw[distance]
|
||||
if iconList then
|
||||
iconList[#iconList + 1] = drawIcon
|
||||
table.insert(iconList, drawIcon)
|
||||
else
|
||||
iconsToDraw[distance] = { drawIcon }
|
||||
end
|
||||
end
|
||||
_, spawn = next(spawns, _)
|
||||
end
|
||||
zone = next(spawnData.Spawns, zone)
|
||||
end
|
||||
end
|
||||
id, spawnData = next(objective.spawnList, id)
|
||||
end
|
||||
|
||||
return iconsToDraw, spawnItemId
|
||||
@@ -1505,7 +1606,7 @@ _DrawObjectiveIcons = function(questId, iconsToDraw, objective, maxPerType)
|
||||
|
||||
local hotzones = QuestieMap.utils:CalcHotzones(orderedList, range, iconCount);
|
||||
|
||||
for i = 1, #hotzones do
|
||||
for i = 1, table.getn(hotzones) do
|
||||
local hotzone = hotzones[i]
|
||||
if (spawnedIconCount > maxPerType) then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Too many icons for quest:", questId)
|
||||
@@ -1534,8 +1635,8 @@ _DrawObjectiveIcons = function(questId, iconsToDraw, objective, maxPerType)
|
||||
|
||||
if iconMap and iconMini then
|
||||
iconPerZone[icon.zone] = { iconMap, centerX, centerY }
|
||||
spawnsMapRefs[#spawnsMapRefs + 1] = iconMap
|
||||
spawnsMinimapRefs[#spawnsMinimapRefs + 1] = iconMini
|
||||
table.insert(spawnsMapRefs, iconMap)
|
||||
table.insert(spawnsMinimapRefs, iconMini)
|
||||
end
|
||||
|
||||
spawnedIconCount = spawnedIconCount + 1;
|
||||
@@ -1551,8 +1652,8 @@ _DrawObjectiveIcons = function(questId, iconsToDraw, objective, maxPerType)
|
||||
|
||||
if iconMap and iconMini then
|
||||
iconPerZone[icon.zone] = { iconMap, centerX, centerY }
|
||||
spawnsMapRefs[#spawnsMapRefs + 1] = iconMap
|
||||
spawnsMinimapRefs[#spawnsMinimapRefs + 1] = iconMini
|
||||
table.insert(spawnsMapRefs, iconMap)
|
||||
table.insert(spawnsMinimapRefs, iconMini)
|
||||
end
|
||||
|
||||
spawnedIconCount = spawnedIconCount + 1;
|
||||
@@ -1568,18 +1669,20 @@ _GetIconsSortedByDistance = function(icons)
|
||||
|
||||
local i = 0
|
||||
|
||||
for distance in pairs(icons) do
|
||||
local distKey, _ = next(icons)
|
||||
while distKey do
|
||||
i = i + 1
|
||||
distances[i] = distance
|
||||
distances[i] = distKey
|
||||
distKey, _ = next(icons, distKey)
|
||||
end
|
||||
|
||||
table.sort(distances)
|
||||
|
||||
-- use the keys to retrieve the values in the sorted order
|
||||
for distIndex = 1, #distances do
|
||||
for distIndex = 1, table.getn(distances) do
|
||||
local iconsAtDisntace = icons[distances[distIndex]]
|
||||
|
||||
for iconIndex = 1, #iconsAtDisntace do
|
||||
for iconIndex = 1, table.getn(iconsAtDisntace) do
|
||||
local icon = iconsAtDisntace[iconIndex]
|
||||
|
||||
iconCount = iconCount + 1
|
||||
@@ -1591,9 +1694,11 @@ _GetIconsSortedByDistance = function(icons)
|
||||
end
|
||||
|
||||
_DrawObjectiveWaypoints = function(objective, icon, iconPerZone)
|
||||
for _, spawnData in pairs(objective.spawnList) do -- spawnData.Name, spawnData.Spawns
|
||||
local _, spawnData = next(objective.spawnList)
|
||||
while _ do -- spawnData.Name, spawnData.Spawns
|
||||
if spawnData.Waypoints then
|
||||
for zone, waypoints in pairs(spawnData.Waypoints) do
|
||||
local zone, waypoints = next(spawnData.Waypoints)
|
||||
while zone do
|
||||
local firstWaypoint = waypoints[1][1]
|
||||
|
||||
if (not iconPerZone[zone]) and icon and firstWaypoint[1] ~= -1 and firstWaypoint[2] ~= -1 then -- spawn an icon in this zone for the mob
|
||||
@@ -1612,10 +1717,12 @@ _DrawObjectiveWaypoints = function(objective, icon, iconPerZone)
|
||||
if ipz then
|
||||
QuestieMap:DrawWaypoints(ipz[1], waypoints, zone, spawnData.Hostile and { 1, 0.2, 0, 0.7 } or nil)
|
||||
end
|
||||
zone, waypoints = next(spawnData.Waypoints, zone)
|
||||
end
|
||||
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:_DrawObjectiveWaypoints]")
|
||||
end
|
||||
_, spawnData = next(objective.spawnList, _)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1673,7 +1780,8 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
if not next(quest.Objectives) then
|
||||
local cachedObjectives = QuestLogCache.GetQuestObjectives(quest.Id)
|
||||
if cachedObjectives then
|
||||
for index, obj in pairs(cachedObjectives) do
|
||||
local index, obj = next(cachedObjectives)
|
||||
while index do
|
||||
quest.Objectives[index] = {
|
||||
questId = quest.Id,
|
||||
Index = index,
|
||||
@@ -1685,12 +1793,15 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
isUpdated = false,
|
||||
Update = _QuestieQuest.ObjectiveUpdate,
|
||||
}
|
||||
index, obj = next(cachedObjectives, index)
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, obj in pairs(quest.Objectives) do
|
||||
local _, obj = next(quest.Objectives)
|
||||
while _ do
|
||||
obj.isUpdated = false
|
||||
obj:Update()
|
||||
_, obj = next(quest.Objectives, _)
|
||||
end
|
||||
return true
|
||||
end
|
||||
@@ -1700,7 +1811,8 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
local questObjectives = QuestieQuest:GetAllLeaderBoardDetails(quest.Id) or {} -- DO NOT MODIFY THE RETURNED TABLE
|
||||
|
||||
|
||||
for objectiveIndex, objective in pairs(questObjectives) do
|
||||
local objectiveIndex, objective = next(questObjectives)
|
||||
while objectiveIndex do
|
||||
if objective.type and string.len(objective.type) > 1 then
|
||||
if (not quest.ObjectiveData) or (not quest.ObjectiveData[objectiveIndex]) or (not quest.ObjectiveData[objectiveIndex].Id) then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Missing objective data for quest", quest.Id, objective.text, "creating fallback objective")
|
||||
@@ -1715,7 +1827,8 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
local function _GetIconScaleForMonster()
|
||||
return Questie.db.profile.monsterScale or 1
|
||||
end
|
||||
for _, npcId in ipairs(l10n.raresByZone[zoneId]) do
|
||||
local _, npcId = next(l10n.raresByZone[zoneId])
|
||||
while _ do
|
||||
local npcName = QuestieDB.QueryNPCSingle(npcId, "name")
|
||||
local npcSpawns = QuestieDB.QueryNPCSingle(npcId, "spawns")
|
||||
if npcName and npcSpawns and npcSpawns[zoneId] then
|
||||
@@ -1731,6 +1844,7 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
TooltipKey = "m_" .. npcId,
|
||||
}
|
||||
end
|
||||
_, npcId = next(l10n.raresByZone[zoneId], _)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1774,11 +1888,13 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
"[QuestieQuest:PopulateQuestLogInfo] Error finding entry ID for objective", objectiveIndex,
|
||||
objective.type, objective.text, "of questId:", quest.Id)
|
||||
end
|
||||
objectiveIndex, objective = next(questObjectives, objectiveIndex)
|
||||
end
|
||||
|
||||
-- find special unlisted objectives
|
||||
if next(quest.SpecialObjectives) then
|
||||
for index, specialObjective in pairs(quest.SpecialObjectives) do
|
||||
local index, specialObjective = next(quest.SpecialObjectives)
|
||||
while index do
|
||||
if (not specialObjective.Description) then
|
||||
specialObjective.Description = "Special objective"
|
||||
end
|
||||
@@ -1802,10 +1918,11 @@ function QuestieQuest:PopulateQuestLogInfo(quest)
|
||||
|
||||
specialObjective.Index = 64 + index -- offset to not conflict with real objectives
|
||||
specialObjective.AlreadySpawned = specialObjective.AlreadySpawned or {}
|
||||
index, specialObjective = next(quest.SpecialObjectives, index)
|
||||
end
|
||||
end
|
||||
|
||||
if #quest.Objectives == 0 and #quest.SpecialObjectives == 0 and (not quest.ObjectiveData or #quest.ObjectiveData == 0) and ((quest.triggerEnd and #quest.triggerEnd > 0) or (quest.Finisher and quest.Finisher.Id ~= nil)) then
|
||||
if table.getn(quest.Objectives) == 0 and table.getn(quest.SpecialObjectives) == 0 and (not quest.ObjectiveData or table.getn(quest.ObjectiveData) == 0) and ((quest.triggerEnd and table.getn(quest.triggerEnd) > 0) or (quest.Finisher and quest.Finisher.Id ~= nil)) then
|
||||
-- Some quests when picked up will be flagged isComplete == 0 but the quest.Objective table or quest.SpecialObjectives table is nil. This
|
||||
-- check assumes the Quest should have been flagged questLogEngtry.isComplete == 1. We're specifically looking for a quest.triggerEnd or
|
||||
-- a quest.Finisher.Id because this might throw an error if there is nothing to populate when we call QuestieQuest:AddFinisher().
|
||||
@@ -1856,10 +1973,12 @@ function QuestieQuest:GetAllLeaderBoardDetails(questId)
|
||||
local questObjectives = QuestLogCache.GetQuestObjectives(questId) -- DO NOT MODIFY THE RETURNED TABLE
|
||||
if (not questObjectives) then return end
|
||||
|
||||
for _, objective in pairs(questObjectives) do -- DO NOT MODIFY THE RETURNED TABLE
|
||||
local _, objective = next(questObjectives)
|
||||
while _ do -- DO NOT MODIFY THE RETURNED TABLE
|
||||
-- TODO Move this to QuestEventHandler module or QuestieQuest:AcceptQuest( ) + QuestieQuest:UpdateQuest( ) (accept quest one required to register objectives without progress)
|
||||
-- TODO After ^^^ moving remove this function and use "QuestLogCache.GetQuest(questId).objectives -- DO NOT MODIFY THE RETURNED TABLE" in place of it.
|
||||
QuestieAnnounce:ObjectiveChanged(questId, objective.text, objective.numFulfilled, objective.numRequired)
|
||||
_, objective = next(questObjectives, _)
|
||||
end
|
||||
|
||||
return questObjectives
|
||||
|
||||
@@ -32,15 +32,11 @@ function Hooks:HookQuestLogTitle()
|
||||
end
|
||||
|
||||
-- Handle Shift+Click quest linking
|
||||
-- NOTE: On WotLK/Era/Ascension, Blizzard's original function already handles
|
||||
-- shift-click quest linking. We removed the duplicate ChatEdit_InsertLink call
|
||||
-- that was causing "[Quest Name] [Quest Name]" duplicates.
|
||||
if (IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow()) then
|
||||
-- Follow Ascension's exact native pattern
|
||||
local questLink = GetQuestLink(questLogLineIndex)
|
||||
if questLink then
|
||||
ChatEdit_InsertLink(questLink)
|
||||
end
|
||||
QuestLog_SetSelection(questLogLineIndex)
|
||||
-- We can't return here to stop the execution of the original function in hooksecurefunc,
|
||||
-- but for chat links the original function usually just selects the quest anyway.
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -90,10 +90,25 @@ if not GetCurrentRegionName then
|
||||
end
|
||||
end
|
||||
|
||||
-- addon is running on 3.3.5 WotLK client
|
||||
-- Addon is running on a client without WOW_PROJECT_ID defined (e.g. 3.3.5 WotLK)
|
||||
do
|
||||
local _, _, _, build = GetBuildInfo()
|
||||
QuestieCompat.Is335 = (build == 30300)
|
||||
|
||||
-- Polyfill WOW_PROJECT_ID and constants if missing
|
||||
if WOW_PROJECT_ID == nil then
|
||||
_G.WOW_PROJECT_CLASSIC = _G.WOW_PROJECT_CLASSIC or 2
|
||||
_G.WOW_PROJECT_BURNING_CRUSADE_CLASSIC = _G.WOW_PROJECT_BURNING_CRUSADE_CLASSIC or 5
|
||||
_G.WOW_PROJECT_WRATH_CLASSIC = _G.WOW_PROJECT_WRATH_CLASSIC or 11
|
||||
|
||||
if build >= 30000 and build < 40000 then
|
||||
_G.WOW_PROJECT_ID = _G.WOW_PROJECT_WRATH_CLASSIC
|
||||
elseif build >= 20000 and build < 30000 then
|
||||
_G.WOW_PROJECT_ID = _G.WOW_PROJECT_BURNING_CRUSADE_CLASSIC
|
||||
elseif build < 20000 then
|
||||
_G.WOW_PROJECT_ID = _G.WOW_PROJECT_CLASSIC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local errorMsg = "Questie tried to call a blizzard API function that does not exist..."
|
||||
|
||||
+45
-86
@@ -107,12 +107,14 @@ end
|
||||
local function _dbStats(t)
|
||||
if type(t) ~= "table" then return "type=" .. type(t) end
|
||||
local n, minK, maxK = 0, math.huge, 0
|
||||
for k in pairs(t) do
|
||||
local k = next(t)
|
||||
while k do
|
||||
n = n + 1
|
||||
if type(k) == "number" then
|
||||
if k < minK then minK = k end
|
||||
if k > maxK then maxK = k end
|
||||
end
|
||||
k = next(t, k)
|
||||
end
|
||||
return "count=" .. n .. " minID=" .. (minK == math.huge and 0 or minK) .. " maxID=" .. maxK
|
||||
end
|
||||
@@ -285,9 +287,7 @@ QuestieInit.Stages[1] = function() -- run as a coroutine
|
||||
l10n:Initialize()
|
||||
coYield()
|
||||
QuestieCorrections:MinimalInit()
|
||||
-- DB is cached — LoadBaseDB never runs, so count the WotLKDB globals here
|
||||
-- and push them onto plugin.stats so the Database panel shows correct numbers.
|
||||
QuestieInit:UpdateWotLKDBStats()
|
||||
-- DB is cached — LoadBaseDB never runs, so the plugin loader will handle stats ingestion.
|
||||
end
|
||||
|
||||
local dbCompiledCount = Questie.IsSoD and Questie.db.global.sod.dbCompiledCount or Questie.db.global.dbCompiledCount
|
||||
@@ -310,12 +310,18 @@ QuestieInit.Stages[1] = function() -- run as a coroutine
|
||||
Tutorial.Initialize()
|
||||
|
||||
--? Only run the validator on recompile if debug is enabled, otherwise it's a waste of time.
|
||||
--? Note: Validation is skipped if plugins are pending because plugins inject data after Stage 1,
|
||||
--? so the compiled binary would be stale and validation would fail unnecessarily.
|
||||
if Questie.db.profile.debugEnabled and dbCompiled then
|
||||
if Questie.db.profile.skipValidation ~= true then
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
if QuestiePluginAPI:HasPendingPlugins() then
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieInit] Skipping validation - plugins are pending and will inject data after compilation")
|
||||
print("\124cFF4DDBFF Validation skipped (plugins pending), load complete.")
|
||||
elseif Questie.db.profile.skipValidation == true then
|
||||
print("\124cFF4DDBFF Validation skipped, load complete.")
|
||||
else
|
||||
runValidator()
|
||||
print("\124cFF4DDBFF Load and Validation complete.")
|
||||
else
|
||||
print("\124cFF4DDBFF Validation skipped, load complete.")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -333,8 +339,8 @@ QuestieInit.Stages[2] = function()
|
||||
local keepWaiting = true
|
||||
-- We had users reporting that a quest did not reach a valid state in the game cache.
|
||||
-- In this case we still need to continue the initialization process, even though a specific quest might be bugged
|
||||
-- 10-second timeout for cache validation (increased from 3s for slow servers)
|
||||
C_Timer.After(10, function()
|
||||
-- 30-second timeout for cache validation (increased from 10s for slow servers)
|
||||
C_Timer.After(30, function()
|
||||
if keepWaiting then
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieInit:Stage2] Quest cache validation timed out! Some data may still be loading.")
|
||||
keepWaiting = false
|
||||
@@ -441,6 +447,32 @@ QuestieInit.Stages[3] = function() -- run as a coroutine
|
||||
end
|
||||
end
|
||||
|
||||
-- Wait for registered plugins to finish loading (ensure data injection is complete)
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
local waitStart = GetTime()
|
||||
-- Give other addons/scripts a moment to fire and register if they were waiting for PLAYER_LOGIN
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieInit:Stage3] Waiting for plugins to register/finish. Initial pending: " .. QuestiePluginAPI.pendingPluginsCount)
|
||||
|
||||
while (GetTime() - waitStart < 2.0) do
|
||||
coYield()
|
||||
end
|
||||
|
||||
local timeout = 10
|
||||
local elapsed = GetTime() - waitStart
|
||||
while QuestiePluginAPI:HasPendingPlugins() and (elapsed < timeout) do
|
||||
if ((math.floor(elapsed * 10) % 10) == 0) then -- log every second
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieInit:Stage3] Still waiting for plugins... Pending: " .. QuestiePluginAPI.pendingPluginsCount .. " Elapsed: " .. string.format("%.1f", elapsed))
|
||||
end
|
||||
coYield()
|
||||
elapsed = GetTime() - waitStart
|
||||
end
|
||||
|
||||
if QuestiePluginAPI:HasPendingPlugins() then
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieInit:Stage3] TIMEOUT waiting for plugins! Proceeding anyway. Pending: " .. QuestiePluginAPI.pendingPluginsCount)
|
||||
else
|
||||
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieInit:Stage3] All registered plugins finished loading.")
|
||||
end
|
||||
|
||||
-- We do this last because it will run for a while and we don't want to block the rest of the init
|
||||
coYield()
|
||||
AvailableQuests.CalculateAndDrawAll()
|
||||
@@ -505,85 +537,12 @@ function QuestieInit:LoadDatabase(key)
|
||||
end
|
||||
end
|
||||
|
||||
function QuestieInit:UpdateWotLKDBStats()
|
||||
local function _countTable(t)
|
||||
if type(t) ~= "table" then return 0 end
|
||||
local n = 0
|
||||
for _ in pairs(t) do n = n + 1 end
|
||||
return n
|
||||
end
|
||||
local counts = {
|
||||
QUEST = _countTable(_G["QuestieX_WotLKDB_quest"]),
|
||||
NPC = _countTable(_G["QuestieX_WotLKDB_npc"]),
|
||||
OBJECT = _countTable(_G["QuestieX_WotLKDB_object"]),
|
||||
ITEM = _countTable(_G["QuestieX_WotLKDB_item"]),
|
||||
}
|
||||
Questie.wotlkStatsCache = counts
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
if QuestiePluginAPI then
|
||||
local wotlkPlugin = QuestiePluginAPI:GetPlugin("WotLKDB")
|
||||
if wotlkPlugin then
|
||||
wotlkPlugin.stats.QUEST = counts.QUEST
|
||||
wotlkPlugin.stats.NPC = counts.NPC
|
||||
wotlkPlugin.stats.OBJECT = counts.OBJECT
|
||||
wotlkPlugin.stats.ITEM = counts.ITEM
|
||||
end
|
||||
end
|
||||
|
||||
-- Fix #11: When the database is already compiled (cached), LoadBaseDB is never
|
||||
-- run, so the global cleanup there is skipped. We MUST clean the namespace here
|
||||
-- to prevent continuous ADDON_ACTION_BLOCKED taint errors during gameplay.
|
||||
-- (Doing this also frees ~20MB of redundant RAM since the data is cached!)
|
||||
_G["QuestieX_WotLKDB_quest"] = nil
|
||||
_G["QuestieX_WotLKDB_npc"] = nil
|
||||
_G["QuestieX_WotLKDB_object"] = nil
|
||||
_G["QuestieX_WotLKDB_item"] = nil
|
||||
end
|
||||
-- Stats are now managed via QuestiePluginAPI directly during injection.
|
||||
-- Redundant UpdateWotLKDBStats removed to prevent duplication and inaccuracies.
|
||||
|
||||
function QuestieInit:LoadBaseDB()
|
||||
local function _countTable(t)
|
||||
if type(t) ~= "table" then return 0 end
|
||||
local n = 0
|
||||
for _ in pairs(t) do n = n + 1 end
|
||||
return n
|
||||
end
|
||||
|
||||
local function _pullGlobal(dbKey, globalName)
|
||||
if type(_G[globalName]) == "table" then
|
||||
QuestieDB[dbKey] = _G[globalName]
|
||||
_G[globalName] = nil -- Remove tainted global from _G; data lives on through QuestieDB[dbKey]
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Count BEFORE pulling so we have accurate numbers even after the globals are cleared
|
||||
local _counts = {
|
||||
QUEST = _countTable(_G["QuestieX_WotLKDB_quest"]),
|
||||
NPC = _countTable(_G["QuestieX_WotLKDB_npc"]),
|
||||
OBJECT = _countTable(_G["QuestieX_WotLKDB_object"]),
|
||||
ITEM = _countTable(_G["QuestieX_WotLKDB_item"]),
|
||||
}
|
||||
|
||||
local _pulled = {
|
||||
quest = _pullGlobal("questData", "QuestieX_WotLKDB_quest"),
|
||||
npc = _pullGlobal("npcData", "QuestieX_WotLKDB_npc"),
|
||||
object = _pullGlobal("objectData", "QuestieX_WotLKDB_object"),
|
||||
item = _pullGlobal("itemData", "QuestieX_WotLKDB_item"),
|
||||
}
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[DBDiag] WotLKDB pull: quest=" .. tostring(_pulled.quest) .. " npc=" .. tostring(_pulled.npc) .. " obj=" .. tostring(_pulled.object) .. " item=" .. tostring(_pulled.item))
|
||||
|
||||
Questie.wotlkStatsCache = _counts
|
||||
local QuestiePluginAPI = QuestieLoader:ImportModule("QuestiePluginAPI")
|
||||
if QuestiePluginAPI then
|
||||
local wotlkPlugin = QuestiePluginAPI:GetPlugin("WotLKDB")
|
||||
if wotlkPlugin then
|
||||
wotlkPlugin.stats.QUEST = _counts.QUEST
|
||||
wotlkPlugin.stats.NPC = _counts.NPC
|
||||
wotlkPlugin.stats.OBJECT = _counts.OBJECT
|
||||
wotlkPlugin.stats.ITEM = _counts.ITEM
|
||||
end
|
||||
end
|
||||
-- Pointer compilation will look at npcDataOverrides etc, which are populated by plugins.
|
||||
-- Base tables (Classic) are loaded here.
|
||||
|
||||
QuestieInit:LoadDatabase("npcData")
|
||||
QuestieInit:LoadDatabase("objectData")
|
||||
|
||||
@@ -66,6 +66,27 @@ function QuestieProfiler:HookFunction(key, val, table, name)
|
||||
end
|
||||
|
||||
function QuestieProfiler:HookTable(table, name)
|
||||
-- Skip large pure data tables (e.g., npcDataOverrides entries with spawn coordinates)
|
||||
-- These tables contain only numeric/indexed data and don't benefit from profiling
|
||||
local count = 0
|
||||
local hasFunction = false
|
||||
for key, val in pairs(table) do
|
||||
count = count + 1
|
||||
if count > 1000 then -- Table is too large to be a module with functions
|
||||
QuestieProfiler.alreadyHooked[table] = true -- Mark to prevent re-processing
|
||||
return
|
||||
end
|
||||
if type(val) == "function" then
|
||||
hasFunction = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not hasFunction and count > 0 then
|
||||
-- Pure data table with no functions, skip profiling
|
||||
QuestieProfiler.alreadyHooked[table] = true -- Mark to prevent re-processing
|
||||
return
|
||||
end
|
||||
|
||||
QuestieProfiler.alreadyHooked[table] = true
|
||||
for key, val in pairs(table) do
|
||||
if QuestieProfiler.alreadyHooked[val] then
|
||||
@@ -101,10 +122,24 @@ function QuestieProfiler:HookTable(table, name)
|
||||
--print("["..QuestieProfiler.finishedHookCount.."/"..QuestieProfiler.needsHookCount.."]Hooking function " .. name .. "->" .. key)
|
||||
QuestieProfiler:HookFunction(key, val, table, name)
|
||||
elseif typ == "table" then
|
||||
--QuestieProfiler:HookTable(val, name .. "->"..key)
|
||||
|
||||
tinsert(QuestieProfiler.needsHook, { val, name .. "." .. tostring(key) })
|
||||
QuestieProfiler.needsHookCount = QuestieProfiler.needsHookCount + 1
|
||||
-- Skip large data tables (arrays with numeric keys only - no functions)
|
||||
-- These are data tables like npcDataOverrides that don't need profiling
|
||||
local isDataTable = false
|
||||
local hasFunction = false
|
||||
for k, v in pairs(val) do
|
||||
if type(k) == "number" and type(v) == "number" then
|
||||
isDataTable = true -- Array with numeric keys
|
||||
end
|
||||
if type(v) == "function" then
|
||||
hasFunction = true
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Only add tables that have functions or aren't pure data tables
|
||||
if hasFunction or not isDataTable then
|
||||
tinsert(QuestieProfiler.needsHook, { val, name .. "." .. tostring(key) })
|
||||
QuestieProfiler.needsHookCount = QuestieProfiler.needsHookCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,13 +13,13 @@ local WOW_PROJECT_MAINLINE = WOW_PROJECT_MAINLINE or 1
|
||||
|
||||
-- Expansion detection
|
||||
Questie.IsRetail = (WOW_PROJECT_ID == WOW_PROJECT_MAINLINE)
|
||||
Questie.IsWotLK = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC)
|
||||
Questie.IsWotlk = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC)
|
||||
Questie.IsTBC = (WOW_PROJECT_ID == WOW_PROJECT_BURNING_CRUSADE_CLASSIC)
|
||||
Questie.IsClassicEra = (WOW_PROJECT_ID == WOW_PROJECT_CLASSIC)
|
||||
|
||||
-- Try GetBuildInfo for Turtle WoW (Interface: 11200, no WOW_PROJECT globals)
|
||||
local _, _, _, tocVersion = GetBuildInfo()
|
||||
Questie.IsTurtle = (not Questie.IsRetail and not Questie.IsWotLK and not Questie.IsTBC and
|
||||
Questie.IsTurtle = (not Questie.IsRetail and not Questie.IsWotlk and not Questie.IsTBC and
|
||||
not Questie.IsClassicEra and tocVersion and tocVersion < 20000)
|
||||
|
||||
-- Custom server detection
|
||||
@@ -42,7 +42,7 @@ local function GetExpectedPluginFlavor()
|
||||
if Questie.IsEbonhold then return "EbonholdDB", "Questie-X-EbonholdDB" end
|
||||
if Questie.IsValanior then return "ValaniorDB", "Questie-X-ValaniorDB" end
|
||||
if Questie.IsTurtle then return "TurtleDB", "Questie-X-TurtleDB" end
|
||||
if Questie.IsWotLK then return "WotLKDB", "Questie-X-WotLKDB" end
|
||||
if Questie.IsWotlk then return "WotLKDB", "Questie-X-WotLKDB" end
|
||||
if Questie.IsTBC then return "TBCDB", "Questie-X-TBCDB" end
|
||||
if Questie.IsClassicEra then return "ClassicDB", "Questie-X-ClassicDB" end
|
||||
if Questie.IsRetail then return "RetailDB", "Questie-X-RetailDB" end
|
||||
@@ -52,7 +52,7 @@ end
|
||||
function QuestieServer:Init()
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieServer] Realm:", realmName)
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieServer] WOW_PROJECT_ID:", tostring(WOW_PROJECT_ID))
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieServer] IsWotLK:", tostring(Questie.IsWotLK), "IsTBC:", tostring(Questie.IsTBC),
|
||||
Questie:Debug(Questie.DEBUG_INFO, "[QuestieServer] IsWotlk:", tostring(Questie.IsWotlk), "IsTBC:", tostring(Questie.IsTBC),
|
||||
"IsClassicEra:", tostring(Questie.IsClassicEra), "IsTurtle:", tostring(Questie.IsTurtle),
|
||||
"IsAscension:", tostring(Questie.IsAscension), "IsEbonhold:", tostring(Questie.IsEbonhold))
|
||||
end
|
||||
|
||||
@@ -79,8 +79,8 @@ local function OnQuestLogUpdate()
|
||||
for _, objective in pairs(objectiveList) do
|
||||
-- Fix: Only fail if text is nil or empty.
|
||||
-- Leading spaces (ASCII 32) are common on some servers/quests and shouldn't block initialization.
|
||||
-- Ghost quests (removed from DB but still in log) may have no text - skip those silently.
|
||||
if (not objective.text) or (objective.text == "") then
|
||||
isQuestLogGood = false
|
||||
hasInvalidObjective = true
|
||||
break
|
||||
end
|
||||
@@ -88,8 +88,10 @@ local function OnQuestLogUpdate()
|
||||
if not hasInvalidObjective then
|
||||
goodQuestsCount = goodQuestsCount + 1
|
||||
end
|
||||
-- Don't fail validation for ghost quests with empty text, just skip them
|
||||
else
|
||||
isQuestLogGood = false
|
||||
-- Quest has objectives according to game but GetQuestObjectives returns nothing
|
||||
-- This is likely a ghost quest, skip it
|
||||
end
|
||||
else
|
||||
goodQuestsCount = goodQuestsCount + 1
|
||||
|
||||
@@ -106,7 +106,7 @@ function MapIconTooltip:Show()
|
||||
|
||||
local r, g, b, a = unpack(QuestieMap.zoneWaypointHoverColorOverrides[self.AreaID] or DEFAULT_WAYPOINT_HOVER_COLOR)
|
||||
--Highlight waypoints if they exist.
|
||||
for _, lineFrame in pairs(self.data.lineFrames or {}) do
|
||||
for _, lineFrame in next, self.data.lineFrames or {} do
|
||||
lineFrame.line:SetColorTexture(r, g, b, a)
|
||||
end
|
||||
|
||||
@@ -167,8 +167,8 @@ function MapIconTooltip:Show()
|
||||
|
||||
-- We need to check for duplicates.
|
||||
local add = true;
|
||||
for _, data in pairs(questOrder[key]) do
|
||||
for text, _ in pairs(data) do
|
||||
for _, data in next, questOrder[key] do
|
||||
for text, _ in next, data do
|
||||
if (text == iconData.ObjectiveData.Description) then
|
||||
add = false;
|
||||
break;
|
||||
@@ -180,10 +180,10 @@ function MapIconTooltip:Show()
|
||||
end
|
||||
else
|
||||
local tooltips = _MapIconTooltip:GetObjectiveTooltip(icon)
|
||||
for _, tip in pairs(tooltips) do
|
||||
for _, tip in next, tooltips do
|
||||
tinsert(orderedTooltips, 1, tip);
|
||||
end
|
||||
for _, tip in pairs(orderedTooltips) do
|
||||
for _, tip in next, orderedTooltips do
|
||||
local questData = questOrder[key]
|
||||
_MapIconTooltip:AddTooltipsForQuest(icon, tip, questData, usedText)
|
||||
end
|
||||
@@ -212,7 +212,7 @@ function MapIconTooltip:Show()
|
||||
end
|
||||
|
||||
if self.miniMapIcon then
|
||||
for icon, _ in pairs(HBDPins.activeMinimapPins) do
|
||||
for icon, _ in next, HBDPins.activeMinimapPins do
|
||||
handleMapIcon(icon)
|
||||
end
|
||||
else
|
||||
@@ -235,7 +235,8 @@ function MapIconTooltip:Show()
|
||||
local playerIsHonoredWithShaTar = (not QuestieReputation:HasReputation(nil, { 935, 8999 }))
|
||||
|
||||
-- tooltips for quest icons on the map
|
||||
for questTitleKey, data in pairs(self.npcAndObjectOrder) do -- this logic really needs to be improved
|
||||
-- tooltips for quest icons on the map
|
||||
for questTitleKey, data in next, self.npcAndObjectOrder do -- this logic really needs to be improved
|
||||
haveGiver = true
|
||||
if shift and (not firstLine) then
|
||||
-- Spacer between NPCs
|
||||
@@ -244,7 +245,7 @@ function MapIconTooltip:Show()
|
||||
|
||||
-- Display all NPC names for this quest group
|
||||
local names = {}
|
||||
for name, _ in pairs(data.npcNames) do
|
||||
for name, _ in next, data.npcNames do
|
||||
tinsert(names, name)
|
||||
end
|
||||
table.sort(names)
|
||||
@@ -262,7 +263,7 @@ function MapIconTooltip:Show()
|
||||
|
||||
local quests = data.quests
|
||||
|
||||
for _, questData in pairs(quests) do
|
||||
for _, questData in next, quests do
|
||||
local reputationReward = QuestieDB.QueryQuestSingle(questData.questId, "reputationReward")
|
||||
|
||||
if questData.title ~= nil then
|
||||
@@ -302,17 +303,17 @@ function MapIconTooltip:Show()
|
||||
if questData.subData and shift then
|
||||
local dataType = type(questData.subData)
|
||||
if dataType == "table" then
|
||||
for _, rawLine in pairs(questData.subData) do
|
||||
for _, rawLine in next, questData.subData do
|
||||
local lines = QuestieLib:TextWrap(rawLine, " ", false, math.max(375, Tooltip:GetWidth()),
|
||||
questData.questId) --275 is the default questlog width
|
||||
for _, line in pairs(lines) do
|
||||
for _, line in next, lines do
|
||||
self:AddLine(line, 0.86, 0.86, 0.86);
|
||||
end
|
||||
end
|
||||
elseif dataType == "string" then
|
||||
local lines = QuestieLib:TextWrap(questData.subData, " ", false,
|
||||
math.max(375, Tooltip:GetWidth())) --275 is the default questlog width
|
||||
for _, line in pairs(lines) do
|
||||
for _, line in next, lines do
|
||||
self:AddLine(line, 0.86, 0.86, 0.86);
|
||||
end
|
||||
end
|
||||
@@ -384,7 +385,7 @@ function MapIconTooltip:Show()
|
||||
local factionId, factionName
|
||||
local rewardValue
|
||||
local aldorPenalty, scryersPenalty
|
||||
for _, rewardPair in pairs(reputationReward) do
|
||||
for _, rewardPair in next, reputationReward do
|
||||
factionId = rewardPair[1]
|
||||
|
||||
if factionId == 935 and playerIsHonoredWithShaTar and (scryersPenalty or aldorPenalty) then
|
||||
@@ -408,17 +409,17 @@ function MapIconTooltip:Show()
|
||||
aldorPenalty = 0 - math.floor(rewardValue * 1.1)
|
||||
end
|
||||
|
||||
rewardTable[#rewardTable + 1] = (rewardValue > 0 and "+" or "") ..
|
||||
rewardValue .. " " .. factionName
|
||||
tinsert(rewardTable, (rewardValue > 0 and "+" or "") ..
|
||||
rewardValue .. " " .. factionName)
|
||||
end
|
||||
end
|
||||
|
||||
if aldorPenalty then
|
||||
factionName = select(1, GetFactionInfoByID(932))
|
||||
rewardTable[#rewardTable + 1] = aldorPenalty .. " " .. factionName
|
||||
tinsert(rewardTable, aldorPenalty .. " " .. factionName)
|
||||
elseif scryersPenalty then
|
||||
factionName = select(1, GetFactionInfoByID(934))
|
||||
rewardTable[#rewardTable + 1] = scryersPenalty .. " " .. factionName
|
||||
tinsert(rewardTable, scryersPenalty .. " " .. factionName)
|
||||
end
|
||||
|
||||
self:AddLine(
|
||||
@@ -430,7 +431,7 @@ function MapIconTooltip:Show()
|
||||
|
||||
-- tooltips for objectives of active quests
|
||||
---@param questId number
|
||||
for questId, textList in pairs(self.questOrder) do -- this logic really needs to be improved
|
||||
for questId, textList in next, self.questOrder do -- this logic really needs to be improved
|
||||
if type(questId) ~= "number" then
|
||||
-- Skip non-quest keys if any somehow ended up here
|
||||
break
|
||||
@@ -508,11 +509,11 @@ function MapIconTooltip:Show()
|
||||
|
||||
local hasRare = false
|
||||
if not shift then
|
||||
for _, textData in pairs(textList) do
|
||||
for textLine, nameData in pairs(textData) do
|
||||
for _, textData in next, textList do
|
||||
for textLine, nameData in next, textData do
|
||||
local dataType = type(nameData)
|
||||
if dataType == "table" then
|
||||
for name in pairs(nameData) do
|
||||
for name in next, nameData do
|
||||
if creatureLevels[name] and (creatureLevels[name][3] == 2 or creatureLevels[name][3] == 4) then
|
||||
hasRare = true
|
||||
break
|
||||
@@ -530,12 +531,12 @@ function MapIconTooltip:Show()
|
||||
end
|
||||
|
||||
local addedCreatureNames = {}
|
||||
for _, textData in pairs(textList) do
|
||||
for textLine, nameData in pairs(textData) do
|
||||
for _, textData in next, textList do
|
||||
for textLine, nameData in next, textData do
|
||||
local dataType = type(nameData)
|
||||
local hasName = false
|
||||
if dataType == "table" then
|
||||
for name in pairs(nameData) do
|
||||
for name in next, nameData do
|
||||
if (not addedCreatureNames[name]) then
|
||||
addedCreatureNames[name] = true
|
||||
name = _GetLevelString(creatureLevels, name)
|
||||
@@ -565,7 +566,7 @@ function MapIconTooltip:Show()
|
||||
local factionId, factionName
|
||||
local rewardValue
|
||||
local aldorPenalty, scryersPenalty
|
||||
for _, rewardPair in pairs(reputationReward) do
|
||||
for _, rewardPair in next, reputationReward do
|
||||
factionId = rewardPair[1]
|
||||
|
||||
if factionId == 935 and playerIsHonoredWithShaTar and (scryersPenalty or aldorPenalty) then
|
||||
@@ -589,17 +590,17 @@ function MapIconTooltip:Show()
|
||||
aldorPenalty = 0 - math.floor(rewardValue * 1.1)
|
||||
end
|
||||
|
||||
rewardTable[#rewardTable + 1] = (rewardValue > 0 and "+" or "") ..
|
||||
rewardValue .. " " .. factionName
|
||||
tinsert(rewardTable, (rewardValue > 0 and "+" or "") ..
|
||||
rewardValue .. " " .. factionName)
|
||||
end
|
||||
end
|
||||
|
||||
if aldorPenalty then
|
||||
factionName = select(1, GetFactionInfoByID(932))
|
||||
rewardTable[#rewardTable + 1] = aldorPenalty .. " " .. factionName
|
||||
tinsert(rewardTable, aldorPenalty .. " " .. factionName)
|
||||
elseif scryersPenalty then
|
||||
factionName = select(1, GetFactionInfoByID(934))
|
||||
rewardTable[#rewardTable + 1] = scryersPenalty .. " " .. factionName
|
||||
tinsert(rewardTable, scryersPenalty .. " " .. factionName)
|
||||
end
|
||||
|
||||
self:AddLine(
|
||||
@@ -674,16 +675,19 @@ function MapIconTooltip:Show()
|
||||
self:AddLine(" ")
|
||||
end
|
||||
|
||||
for title, data in pairs(self.manualOrder) do
|
||||
for title, data in next, self.manualOrder do
|
||||
local body = data.Body
|
||||
self:AddLine(title)
|
||||
for _, stringOrTable in ipairs(body) do
|
||||
local bIndex = 1
|
||||
while body[bIndex] do
|
||||
local stringOrTable = body[bIndex]
|
||||
local dataType = type(stringOrTable)
|
||||
if dataType == "string" then
|
||||
self:AddLine(stringOrTable)
|
||||
elseif dataType == "table" then
|
||||
self:AddDoubleLine(stringOrTable[1], '|cFFffffff' .. stringOrTable[2] .. '|r') --normal, white
|
||||
end
|
||||
bIndex = bIndex + 1
|
||||
end
|
||||
if self.miniMapIcon == false and not data.disableShiftToRemove then
|
||||
self:AddLine('|cFFa6a6a6Shift-click to hide|r') -- grey
|
||||
|
||||
@@ -90,13 +90,13 @@ function QuestieTooltips:RemoveQuest(questId)
|
||||
local quest = QuestieDB.GetQuest(questId)
|
||||
|
||||
if quest then
|
||||
for _, objective in pairs(quest.Objectives) do
|
||||
for _, objective in next, quest.Objectives do
|
||||
objective.AlreadySpawned = {}
|
||||
objective.hasRegisteredTooltips = false
|
||||
objective.registeredItemTooltips = false
|
||||
end
|
||||
|
||||
for _, objective in pairs(quest.SpecialObjectives) do
|
||||
for _, objective in next, quest.SpecialObjectives do
|
||||
objective.AlreadySpawned = {}
|
||||
objective.hasRegisteredTooltips = false
|
||||
objective.registeredItemTooltips = false
|
||||
@@ -105,11 +105,11 @@ function QuestieTooltips:RemoveQuest(questId)
|
||||
|
||||
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieTooltips:RemoveQuest]", questId)
|
||||
|
||||
for _, key in pairs(QuestieTooltips.lookupKeysByQuestId[questId] or {}) do
|
||||
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 pairs(QuestieTooltips.lookupByKey[key] or {}) do
|
||||
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
|
||||
@@ -135,13 +135,13 @@ local function _FetchTooltipsForGroupMembers(key, tooltipData)
|
||||
if QuestieComms and QuestieComms.data:KeyExists(key) then
|
||||
---@tooltipData @tooltipData[questId][playerName][objectiveIndex].text
|
||||
local tooltipDataExternal = QuestieComms.data:GetTooltip(key);
|
||||
for questId, playerList in pairs(tooltipDataExternal) do
|
||||
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 pairs(playerList) do
|
||||
for playerName, _ in next, playerList do
|
||||
local playerInfo = QuestiePlayer:GetPartyMemberByName(playerName);
|
||||
if playerInfo or QuestieComms.remotePlayerEnabled[playerName] then
|
||||
anotherPlayer = true
|
||||
@@ -157,17 +157,17 @@ local function _FetchTooltipsForGroupMembers(key, tooltipData)
|
||||
if QuestieComms.data:KeyExists(key) and anotherPlayer then
|
||||
---@tooltipData @tooltipData[questId][playerName][objectiveIndex].text
|
||||
local tooltipDataExternal = QuestieComms.data:GetTooltip(key);
|
||||
for questId, playerList in pairs(tooltipDataExternal) do
|
||||
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 pairs(playerList) do
|
||||
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 pairs(objectives) do
|
||||
for objectiveIndex, objective in next, objectives do
|
||||
if (not objective) then
|
||||
objective = {}
|
||||
end
|
||||
@@ -229,12 +229,14 @@ function QuestieTooltips:GetTooltip(key)
|
||||
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 pairs(learnedNpc[10]) do
|
||||
for _, objText in ipairs(objList) do
|
||||
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 pairs(objectives) do
|
||||
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
|
||||
@@ -250,7 +252,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
Update = function(self)
|
||||
local objs = QuestLogCache.GetQuestObjectives(questId)
|
||||
if objs then
|
||||
for _, o in pairs(objs) do
|
||||
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
|
||||
@@ -260,6 +262,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
end
|
||||
end
|
||||
})
|
||||
oIndex = oIndex + 1
|
||||
end
|
||||
end
|
||||
if learnedNpc.mc then
|
||||
@@ -269,12 +272,14 @@ function QuestieTooltips:GetTooltip(key)
|
||||
elseif key:sub(1,2) == "o_" then
|
||||
local learnedObj = QuestieLearner.data.objects[id]
|
||||
if learnedObj and learnedObj[10] then
|
||||
for questId, objList in pairs(learnedObj[10]) do
|
||||
for _, objText in ipairs(objList) do
|
||||
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 pairs(objectives) do
|
||||
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
|
||||
@@ -290,7 +295,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
Update = function(self)
|
||||
local objs = QuestLogCache.GetQuestObjectives(questId)
|
||||
if objs then
|
||||
for _, o in pairs(objs) do
|
||||
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
|
||||
@@ -300,6 +305,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
end
|
||||
end
|
||||
})
|
||||
oIndex = oIndex + 1
|
||||
end
|
||||
end
|
||||
if learnedObj.mc then
|
||||
@@ -313,7 +319,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
|
||||
if QuestieTooltips.lookupByKey[key] then
|
||||
local playerName = UnitName("player")
|
||||
for k, tooltip in pairs(QuestieTooltips.lookupByKey[key]) do
|
||||
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)
|
||||
@@ -376,11 +382,11 @@ function QuestieTooltips:GetTooltip(key)
|
||||
|
||||
local playerName = UnitName("player")
|
||||
|
||||
for questId, questData in pairs(tooltipData) do
|
||||
for questId, questData in next, tooltipData do
|
||||
local hasObjective = false
|
||||
local tempObjectives = {}
|
||||
for _, playerList in pairs(questData.objectivesText or {}) do
|
||||
for objectivePlayerName, objectiveInfo in pairs(playerList) do
|
||||
for _, playerList in next, questData.objectivesText or {} do
|
||||
for objectivePlayerName, objectiveInfo in next, playerList do
|
||||
local playerInfo = QuestiePlayer:GetPartyMemberByName(objectivePlayerName)
|
||||
local playerColor
|
||||
local playerType = ""
|
||||
@@ -412,7 +418,7 @@ function QuestieTooltips:GetTooltip(key)
|
||||
end
|
||||
if hasObjective then
|
||||
tinsert(tooltipLines, questData.title);
|
||||
for _, text in pairs(tempObjectives) do
|
||||
for _, text in next, tempObjectives do
|
||||
tinsert(tooltipLines, text);
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ local function _WipeTable(t)
|
||||
if wipe then
|
||||
wipe(t)
|
||||
else
|
||||
for k in pairs(t) do
|
||||
for k in next, t do
|
||||
t[k] = nil
|
||||
end
|
||||
end
|
||||
@@ -151,26 +151,26 @@ local function _TryBuildNpcQuestStarterDrops()
|
||||
local npcDrops = QuestieDB.QueryItemSingle(itemId, "npcDrops")
|
||||
if npcDrops and type(npcDrops) == "table" then
|
||||
local itemName = QuestieDB.QueryItemSingle(itemId, "name")
|
||||
for _, npcId in pairs(npcDrops) do
|
||||
for _, npcId in next, npcDrops do
|
||||
local list = _npcQuestStarterDrops[npcId]
|
||||
if not list then
|
||||
list = {}
|
||||
_npcQuestStarterDrops[npcId] = list
|
||||
end
|
||||
list[#list + 1] = { itemId = itemId, questId = tonumber(questId), name = itemName }
|
||||
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 pairs(pointers) do
|
||||
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 pairs(QuestieDB.itemDataOverrides) do
|
||||
for itemId, _ in next, QuestieDB.itemDataOverrides do
|
||||
processItem(itemId)
|
||||
end
|
||||
end
|
||||
@@ -199,7 +199,7 @@ local function _AddQuestStarterDropsToTooltip(npcId)
|
||||
if not _npcQuestStarterDrops then return end
|
||||
|
||||
local drops = _npcQuestStarterDrops[npcId]
|
||||
if not drops or #drops == 0 then return end
|
||||
if not drops or table.getn(drops) == 0 then return end
|
||||
|
||||
if _TooltipHasQuestStarterLine(GameTooltip) then
|
||||
return
|
||||
@@ -207,19 +207,23 @@ local function _AddQuestStarterDropsToTooltip(npcId)
|
||||
|
||||
-- Filter drops to only show items where player doesn't have the quest yet
|
||||
local filteredDrops = {}
|
||||
for _, info in ipairs(drops) do
|
||||
local dropsCount = table.getn(drops)
|
||||
for i = 1, dropsCount do
|
||||
local info = drops[i]
|
||||
if info.questId and (not _PlayerHasQuest(info.questId)) then
|
||||
filteredDrops[#filteredDrops + 1] = info
|
||||
filteredDrops[table.getn(filteredDrops) + 1] = info
|
||||
end
|
||||
end
|
||||
|
||||
if #filteredDrops == 0 then
|
||||
if table.getn(filteredDrops) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
GameTooltip:AddLine(QUEST_START_LINE)
|
||||
|
||||
for _, info in ipairs(filteredDrops) do
|
||||
local filteredCount = table.getn(filteredDrops)
|
||||
for i = 1, filteredCount do
|
||||
local info = filteredDrops[i]
|
||||
local itemId = info.itemId
|
||||
local questId = info.questId
|
||||
|
||||
@@ -256,9 +260,8 @@ function _QuestieTooltips:AddUnitDataToTooltip()
|
||||
guid = UnitGUID("mouseover");
|
||||
end
|
||||
|
||||
local type, _, _, _, _, npcId, _ = strsplit("-", guid or "");
|
||||
|
||||
if name and (type == "Creature" or type == "Vehicle") and (
|
||||
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
|
||||
@@ -273,7 +276,7 @@ function _QuestieTooltips:AddUnitDataToTooltip()
|
||||
if Questie.db.profile.enableTooltipsNPCID == true then
|
||||
GameTooltip:AddDoubleLine("NPC ID", "|cFFFFFFFF" .. npcId .. "|r")
|
||||
end
|
||||
for _, v in pairs(tooltipData) do
|
||||
for _, v in next, tooltipData do
|
||||
GameTooltip:AddLine(v)
|
||||
end
|
||||
else
|
||||
@@ -325,7 +328,7 @@ function _QuestieTooltips:AddItemDataToTooltip()
|
||||
if Questie.db.profile.enableTooltipsItemID == true then
|
||||
GameTooltip:AddDoubleLine("Item ID", "|cFFFFFFFF" .. itemId .. "|r")
|
||||
end
|
||||
for _, v in pairs(tooltipData) do
|
||||
for _, v in next, tooltipData do
|
||||
self:AddLine(v)
|
||||
end
|
||||
end
|
||||
@@ -354,7 +357,7 @@ function _QuestieTooltips:AddObjectDataToTooltip(name)
|
||||
end
|
||||
|
||||
local alreadyAddedObjectiveLines = {}
|
||||
for _, gameObjectId in pairs(lookup) do
|
||||
for _, gameObjectId in next, lookup do
|
||||
local tooltipData = QuestieTooltips:GetTooltip("o_" .. gameObjectId);
|
||||
|
||||
if type(gameObjectId) == "number" and tooltipData then
|
||||
@@ -365,7 +368,7 @@ function _QuestieTooltips:AddObjectDataToTooltip(name)
|
||||
|
||||
if tooltipData[2] then
|
||||
-- Quest has objectives
|
||||
for index, line in pairs(tooltipData) do
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user