diff --git a/Modules/QuestieLearner.lua b/Modules/QuestieLearner.lua index 0e833d7..de60266 100644 --- a/Modules/QuestieLearner.lua +++ b/Modules/QuestieLearner.lua @@ -648,18 +648,17 @@ function QuestieLearner:OnQuestComplete() end end --- Fires when a quest is accepted; in 3.3.5 the first (and only) arg IS the questID directly -function QuestieLearner:OnQuestAccepted(questId) - -- Fallback: scan log for an unknown quest in case the server sends log index instead - if not questId or questId <= 0 then - for i = 1, GetNumQuestLogEntries() do - local _, _, _, _, isHeader, _, _, _, id = GetQuestLogTitle(i) - if not isHeader and id and id > 0 and not Questie.db.global.learnedData.quests[id] then - if not (QuestieDB and QuestieDB.questData and QuestieDB.questData[id]) then - questId = id - break - end - end +-- Fires when a quest is accepted. +-- Ascension 3.3.5 passes the quest log index as the first arg; some builds pass questID directly. +-- We detect which by checking if the value could be a log index and resolving via GetQuestLogTitle. +function QuestieLearner:OnQuestAccepted(firstArg) + local questId = firstArg + local maxLog = GetNumQuestLogEntries and GetNumQuestLogEntries() or 25 + -- If arg looks like a log index (small int ≤ log size), resolve to quest ID via GetQuestLogTitle + if firstArg and firstArg > 0 and firstArg <= maxLog then + local resolvedId = select(8, GetQuestLogTitle(firstArg)) + if resolvedId and resolvedId > 0 then + questId = resolvedId end end Questie:Debug(Questie.DEBUG_LEARNER, "[QuestieLearner] OnQuestAccepted id=" .. tostring(questId)) diff --git a/Modules/Tracker/QuestieTracker.lua b/Modules/Tracker/QuestieTracker.lua index 0f8e7fa..d64c3de 100644 --- a/Modules/Tracker/QuestieTracker.lua +++ b/Modules/Tracker/QuestieTracker.lua @@ -2375,8 +2375,16 @@ function QuestieTracker:AQW_Insert(index, expire) if Questie.IsSoD then QuestieDebugOffer.QuestTracking(questId) else - Questie:Error("Missing quest " .. - tostring(questId) .. "," .. tostring(expire) .. " during tracker update") + -- Quest not in DB — try building a fallback object from the quest log + local fallback = TrackerUtils:BuildFallbackQuest(questId) + if fallback then + QuestiePlayer.currentQuestlog[questId] = fallback + QuestieCombatQueue:Queue(function() + QuestieTracker:Update() + end) + else + Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieTracker] Quest " .. tostring(questId) .. " not in DB and not in quest log, skipping") + end end end end diff --git a/Modules/Tracker/TrackerUtils.lua b/Modules/Tracker/TrackerUtils.lua index ffb29e4..aa4bd97 100644 --- a/Modules/Tracker/TrackerUtils.lua +++ b/Modules/Tracker/TrackerUtils.lua @@ -694,6 +694,54 @@ end ---@return table sortedQuestIds Table with sorted Quest ID's by Sort Type ---@return table questDetails Table with raw quest table from QuestiePlayer.currentQuestLog, percentage completed value per quest, and a "translated" zoneName +-- Builds a minimal quest-like object from the quest log for quests not in QuestieDB. +-- Returns nil if the quest is not currently in the quest log. +function TrackerUtils:BuildFallbackQuest(questId) + for i = 1, GetNumQuestLogEntries() do + local title, level, _, isHeader, _, isComplete, _, logQuestId = GetQuestLogTitle(i) + if not isHeader and logQuestId == questId then + -- Parse objectives from the leaderboard + local objectives = {} + local numObj = GetNumQuestLeaderBoards and GetNumQuestLeaderBoards(i) or 0 + for j = 1, numObj do + local text, _, finished = GetQuestLogLeaderBoard(j, i) + if text then + -- Parse "Description: X/Y" or just "Description" + local collected, needed = string.match(text, ":.-(%d+)/(%d+)%s*$") + collected = tonumber(collected) or (finished and 1 or 0) + needed = tonumber(needed) or 1 + objectives[j] = { + text = text, + Needed = needed, + Collected = collected, + Finished = finished or (collected >= needed), + Type = "fallback", + } + end + end + + local zoneId = GetCurrentMapAreaID and GetCurrentMapAreaID() or 0 + + local quest = { + Id = questId, + name = title or ("Quest " .. questId), + level = level or 0, + zoneOrSort = zoneId, + Objectives = objectives, + SpecialObjectives = {}, + isFallback = true, + } + -- IsComplete must be a method (called as quest:IsComplete()) + quest.IsComplete = function(self) + return (isComplete == 1 or IsQuestFlaggedCompleted(questId)) and 1 or 0 + end + + return quest + end + end + return nil +end + function TrackerUtils:GetSortedQuestIds() local sortedQuestIds = {} local questDetails = {} @@ -711,6 +759,16 @@ function TrackerUtils:GetSortedQuestIds() end end + -- Fallback for quests not in QuestieDB (e.g. custom server quests). + -- Build a minimal quest object from the quest log so the tracker can still display it. + if type(quest) ~= "table" or not quest.IsComplete or not quest.Objectives then + local fallback = TrackerUtils:BuildFallbackQuest(qid) + if fallback then + quest = fallback + QuestiePlayer.currentQuestlog[qid] = fallback + end + end + if type(quest) == "table" and quest.IsComplete and quest.Objectives then -- Insert Quest Ids into sortedQuestIds table tinsert(sortedQuestIds, qid)