1674 lines
67 KiB
Lua
1674 lines
67 KiB
Lua
--- COMPATIBILITY ---
|
|
local IsQuestFlaggedCompleted = QuestieCompat.IsQuestFlaggedCompleted or C_QuestLog.IsQuestFlaggedCompleted
|
|
|
|
---@class QuestieQuest
|
|
local QuestieQuest = QuestieLoader:CreateModule("QuestieQuest")
|
|
---@type QuestieQuestPrivate
|
|
QuestieQuest.private = QuestieQuest.private or {}
|
|
local _QuestieQuest = QuestieQuest.private
|
|
-------------------------
|
|
--Import modules.
|
|
-------------------------
|
|
---@type QuestieProfessions
|
|
local QuestieProfessions = QuestieLoader:ImportModule("QuestieProfessions")
|
|
---@type QuestieReputation
|
|
local QuestieReputation = QuestieLoader:ImportModule("QuestieReputation")
|
|
---@type QuestieTooltips
|
|
local QuestieTooltips = QuestieLoader:ImportModule("QuestieTooltips")
|
|
---@type QuestieTracker
|
|
local QuestieTracker = QuestieLoader:ImportModule("QuestieTracker")
|
|
---@type QuestieDBMIntegration
|
|
local QuestieDBMIntegration = QuestieLoader:ImportModule("QuestieDBMIntegration")
|
|
---@type QuestieMap
|
|
local QuestieMap = QuestieLoader:ImportModule("QuestieMap")
|
|
---@type QuestieLib
|
|
local QuestieLib = QuestieLoader:ImportModule("QuestieLib")
|
|
---@type QuestiePlayer
|
|
local QuestiePlayer = QuestieLoader:ImportModule("QuestiePlayer")
|
|
---@type TaskQueue
|
|
local TaskQueue = QuestieLoader:ImportModule("TaskQueue")
|
|
---@type QuestieDB
|
|
local QuestieDB = QuestieLoader:ImportModule("QuestieDB")
|
|
---@type ZoneDB
|
|
local ZoneDB = QuestieLoader:ImportModule("ZoneDB")
|
|
---@type QuestieCombatQueue
|
|
local QuestieCombatQueue = QuestieLoader:ImportModule("QuestieCombatQueue")
|
|
---@type QuestieAnnounce
|
|
local QuestieAnnounce = QuestieLoader:ImportModule("QuestieAnnounce")
|
|
---@type QuestieMenu
|
|
local QuestieMenu = QuestieLoader:ImportModule("QuestieMenu")
|
|
---@type l10n
|
|
local l10n = QuestieLoader:ImportModule("l10n")
|
|
---@type QuestLogCache
|
|
local QuestLogCache = QuestieLoader:ImportModule("QuestLogCache")
|
|
---@type ThreadLib
|
|
local ThreadLib = QuestieLoader:ImportModule("ThreadLib")
|
|
---@type AvailableQuests
|
|
local AvailableQuests = QuestieLoader:ImportModule("AvailableQuests")
|
|
|
|
--- COMPATIBILITY ---
|
|
local C_Timer = QuestieCompat.C_Timer
|
|
local GetQuestsCompleted = QuestieCompat.GetQuestsCompleted
|
|
local xpcall = QuestieCompat.xpcall
|
|
|
|
--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 yield = coroutine.yield
|
|
local NewThread = ThreadLib.ThreadSimple
|
|
|
|
local NOP_FUNCTION = function()
|
|
end
|
|
local ERR_FUNCTION = function(err)
|
|
print(err)
|
|
print(debugstack())
|
|
end
|
|
|
|
-- forward declaration
|
|
local _UnloadAlreadySpawnedIcons
|
|
local _RegisterObjectiveTooltips, _DetermineIconsToDraw, _GetIconsSortedByDistance
|
|
local _DrawObjectiveIcons, _DrawObjectiveWaypoints
|
|
|
|
local HBD = QuestieCompat.HBD or LibStub("HereBeDragonsQuestie-2.0")
|
|
|
|
function QuestieQuest:Initialize()
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest]: Getting all completed quests")
|
|
Questie.db.char.complete = GetQuestsCompleted()
|
|
|
|
QuestieProfessions:Update()
|
|
QuestieReputation:Update(true)
|
|
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
|
|
if questCategory == category then
|
|
QuestieDB.autoBlacklist[questId] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuestieQuest:ToggleNotes(showIcons)
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:ToggleNotes] showIcons:", showIcons)
|
|
QuestieQuest:GetAllQuestIds() -- add notes that weren't added from previous hidden state
|
|
|
|
if showIcons then
|
|
_QuestieQuest:ShowQuestIcons()
|
|
_QuestieQuest:ShowManualIcons()
|
|
else
|
|
_QuestieQuest:HideQuestIcons()
|
|
_QuestieQuest:HideManualIcons()
|
|
end
|
|
end
|
|
|
|
function _QuestieQuest:ShowQuestIcons()
|
|
local trackerHiddenQuests = Questie.db.char.TrackerHiddenQuests
|
|
for questId, frameList in pairs(QuestieMap.questIdFrames) 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
|
|
---@type IconFrame
|
|
local icon = _G[frameName];
|
|
if not icon.data then
|
|
error("Desync! Icon has not been removed correctly, but has already been reset. Skipping frame \"" ..
|
|
frameName .. "\" for quest " .. questId)
|
|
else
|
|
local objectiveString = tostring(questId) .. " " .. tostring(icon.data.ObjectiveIndex)
|
|
if (not Questie.db.char.TrackerHiddenObjectives) or (not Questie.db.char.TrackerHiddenObjectives[objectiveString]) then
|
|
if icon ~= nil and icon.hidden and (not icon:ShouldBeHidden()) then
|
|
icon:FakeShow()
|
|
|
|
if icon.data.lineFrames then
|
|
for _, lineIcon in pairs(icon.data.lineFrames) do
|
|
lineIcon:FakeShow()
|
|
end
|
|
end
|
|
end
|
|
if (icon.data.QuestData.FadeIcons or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
|
icon:FadeOut()
|
|
else
|
|
icon:FadeIn()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _QuestieQuest:ShowManualIcons()
|
|
for _, frameList in pairs(QuestieMap.manualFrames) do
|
|
for _, frameName in pairs(frameList) 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
|
|
end
|
|
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 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
|
|
icon:FakeHide()
|
|
|
|
-- Hides Objective Tooltips
|
|
QuestieTooltips:RemoveQuest(icon.data.Id)
|
|
|
|
if icon.data.lineFrames then
|
|
for _, lineIcon in pairs(icon.data.lineFrames) do
|
|
lineIcon:FakeHide()
|
|
end
|
|
end
|
|
end
|
|
if (icon.data.QuestData.FadeIcons or (icon.data.ObjectiveData and icon.data.ObjectiveData.FadeIcons)) and icon.data.Type ~= "complete" then
|
|
icon:FadeOut()
|
|
else
|
|
icon:FadeIn()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function _QuestieQuest:HideManualIcons()
|
|
for _, frameList in pairs(QuestieMap.manualFrames) do
|
|
for _, frameName in pairs(frameList) 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
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuestieQuest:ClearAllNotes()
|
|
for questId in pairs(QuestiePlayer.currentQuestlog) do
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if not quest then
|
|
return
|
|
end
|
|
|
|
for _, s in pairs(quest.Objectives) do
|
|
s.AlreadySpawned = {}
|
|
end
|
|
|
|
if next(quest.SpecialObjectives) then
|
|
for _, s in pairs(quest.SpecialObjectives) do
|
|
s.AlreadySpawned = {}
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, frameList in pairs(QuestieMap.questIdFrames) do
|
|
for _, frameName in pairs(frameList) do
|
|
local icon = _G[frameName]
|
|
if icon and icon.Unload then
|
|
icon:Unload()
|
|
end
|
|
end
|
|
end
|
|
|
|
QuestieMap.questIdFrames = {}
|
|
end
|
|
|
|
function QuestieQuest:ClearAllToolTips()
|
|
for questId in pairs(QuestiePlayer.currentQuestlog) do
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if not quest then
|
|
return
|
|
end
|
|
|
|
if quest.Objectives then
|
|
for _, objective in pairs(quest.Objectives) do
|
|
if objective.hasRegisteredTooltips then
|
|
objective.hasRegisteredTooltips = false
|
|
end
|
|
|
|
if objective.registeredItemTooltips then
|
|
objective.registeredItemTooltips = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if quest.ObjectiveData then
|
|
for _, objective in pairs(quest.ObjectiveData) do
|
|
if objective.hasRegisteredTooltips then
|
|
objective.hasRegisteredTooltips = false
|
|
end
|
|
|
|
if objective.registeredItemTooltips then
|
|
objective.registeredItemTooltips = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if next(quest.SpecialObjectives) then
|
|
for _, objective in pairs(quest.SpecialObjectives) do
|
|
if objective.hasRegisteredTooltips then
|
|
objective.hasRegisteredTooltips = false
|
|
end
|
|
|
|
if objective.registeredItemTooltips then
|
|
objective.registeredItemTooltips = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
QuestieTooltips.lookupByKey = {}
|
|
QuestieTooltips.lookupKeyByQuestId = {}
|
|
end
|
|
|
|
-- This is only needed for SmoothReset(), normally special objectives don't need to update
|
|
---@param questId number
|
|
local function _UpdateSpecials(questId)
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
if quest and next(quest.SpecialObjectives) then
|
|
for _, objective in pairs(quest.SpecialObjectives) do
|
|
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, 0, objective,
|
|
true)
|
|
if not result then
|
|
Questie:Error("[QuestieQuest]: [SpecialObjectives] " ..
|
|
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
|
|
end
|
|
end
|
|
end
|
|
|
|
function QuestieQuest:SmoothReset()
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:SmoothReset]")
|
|
if QuestieQuest._isResetting then
|
|
QuestieQuest._resetAgain = true
|
|
return
|
|
end
|
|
QuestieQuest._isResetting = true
|
|
QuestieQuest._resetNeedsAvailables = false
|
|
|
|
-- bit of a hack (there has to be a better way to do logic like this
|
|
QuestieDBMIntegration:ClearAll()
|
|
local stepTable = {
|
|
function()
|
|
-- Wait until game cache has quest log okay.
|
|
return QuestLogCache.TestGameCache()
|
|
end,
|
|
function()
|
|
return #QuestieMap._mapDrawQueue == 0 and
|
|
#QuestieMap._minimapDrawQueue == 0 -- wait until draw queue is finished
|
|
end,
|
|
function()
|
|
QuestieQuest:ClearAllNotes()
|
|
QuestieQuest:ClearAllToolTips()
|
|
return true
|
|
end,
|
|
function()
|
|
QuestieMenu:OnLogin(true) -- remove icons
|
|
return true
|
|
end,
|
|
function()
|
|
return #QuestieMap._mapDrawQueue == 0 and
|
|
#QuestieMap._minimapDrawQueue == 0 -- wait until draw queue is finished
|
|
end,
|
|
function()
|
|
-- reset quest log
|
|
QuestiePlayer.currentQuestlog = {}
|
|
|
|
--- reset the blacklist
|
|
QuestieDB.autoBlacklist = {}
|
|
|
|
-- make sure complete db is correct
|
|
Questie.db.char.complete = GetQuestsCompleted()
|
|
QuestieProfessions:Update()
|
|
QuestieReputation:Update(true)
|
|
|
|
-- populate QuestiePlayer.currentQuestlog
|
|
QuestieQuest:GetAllQuestIdsNoObjectives()
|
|
QuestieQuest._nextRestQuest = next(QuestiePlayer.currentQuestlog)
|
|
return true
|
|
end,
|
|
function()
|
|
QuestieMenu:OnLogin()
|
|
return true
|
|
end,
|
|
function()
|
|
QuestieQuest._resetNeedsAvailables = true
|
|
AvailableQuests.CalculateAndDrawAll(function() QuestieQuest._resetNeedsAvailables = false end)
|
|
return true
|
|
end,
|
|
function()
|
|
for _ = 1, 64 do
|
|
if QuestieQuest._nextRestQuest then
|
|
QuestieQuest:UpdateQuest(QuestieQuest._nextRestQuest)
|
|
_UpdateSpecials(QuestieQuest._nextRestQuest)
|
|
QuestieQuest._nextRestQuest = next(QuestiePlayer.currentQuestlog, QuestieQuest._nextRestQuest)
|
|
else
|
|
QuestieCombatQueue:Queue(function()
|
|
C_Timer.After(2.0, function()
|
|
QuestieTracker:Update()
|
|
end)
|
|
end)
|
|
break
|
|
end
|
|
end
|
|
return not QuestieQuest._nextRestQuest
|
|
end,
|
|
function()
|
|
return (not QuestieQuest._resetNeedsAvailables) and #QuestieMap._mapDrawQueue == 0 and
|
|
#QuestieMap._minimapDrawQueue == 0
|
|
end,
|
|
function()
|
|
QuestieQuest._isResetting = nil
|
|
if QuestieQuest._resetAgain then
|
|
QuestieQuest._resetAgain = nil
|
|
QuestieQuest:SmoothReset()
|
|
end
|
|
return true
|
|
end
|
|
}
|
|
local step = 1
|
|
local ticker
|
|
ticker = C_Timer.NewTicker(0.01, function()
|
|
if stepTable[step]() then
|
|
step = step + 1
|
|
if not stepTable[step] then
|
|
ticker:Cancel()
|
|
end
|
|
end
|
|
if QuestieQuest._resetAgain and not QuestieQuest._resetNeedsAvailables then -- we can stop the current reset
|
|
ticker:Cancel()
|
|
QuestieQuest._resetAgain = nil
|
|
QuestieQuest._isResetting = nil
|
|
QuestieQuest:SmoothReset()
|
|
end
|
|
end)
|
|
end
|
|
|
|
---@param questId number
|
|
---@return boolean
|
|
function QuestieQuest:ShouldShowQuestNotes(questId)
|
|
if not Questie.db.profile.hideUntrackedQuestsMapIcons then
|
|
return true
|
|
end
|
|
|
|
local autoWatch = Questie.db.profile.autoTrackQuests
|
|
local trackedAuto = autoWatch and
|
|
(not Questie.db.char.AutoUntrackedQuests or not Questie.db.char.AutoUntrackedQuests[questId])
|
|
local trackedManual = not autoWatch and (Questie.db.char.TrackedQuests and Questie.db.char.TrackedQuests[questId])
|
|
return trackedAuto or trackedManual
|
|
end
|
|
|
|
function QuestieQuest:HideQuest(id)
|
|
Questie.db.char.hidden[id] = true
|
|
QuestieMap:UnloadQuestFrames(id)
|
|
QuestieTooltips:RemoveQuest(id)
|
|
end
|
|
|
|
function QuestieQuest:UnhideQuest(id)
|
|
Questie.db.char.hidden[id] = nil
|
|
AvailableQuests.CalculateAndDrawAll()
|
|
end
|
|
|
|
local allianceTournamentMarkerQuests = { [13684] = true, [13685] = true, [13688] = true, [13689] = true, [13690] = true,
|
|
[13593] = true, [13703] = true, [13704] = true, [13705] = true, [13706] = true }
|
|
local hordeTournamentMarkerQuests = { [13691] = true, [13693] = true, [13694] = true, [13695] = true, [13696] = true,
|
|
[13707] = true, [13708] = true, [13709] = true, [13710] = true, [13711] = true }
|
|
|
|
---@param questId number
|
|
function QuestieQuest:AcceptQuest(questId)
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if quest then
|
|
local complete = QuestieDB.IsComplete(questId)
|
|
-- If any of these flags exsist then this quest has already once been accepted and is probobly in a failed state
|
|
if (quest.WasComplete or quest.isComplete or complete == 0 or complete == -1) and (QuestiePlayer.currentQuestlog[questId]) then
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Accepted Quest:", questId,
|
|
" Warning: This quest was once accepted and needs to be reset.")
|
|
|
|
-- Reset quest log
|
|
QuestiePlayer.currentQuestlog[questId] = nil
|
|
|
|
-- Reset quest objectives
|
|
quest.Objectives = {}
|
|
|
|
-- Reset quest flags
|
|
quest.WasComplete = nil
|
|
quest.isComplete = nil
|
|
|
|
-- Reset tooltips
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
end
|
|
|
|
if not QuestiePlayer.currentQuestlog[questId] then
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Accepted Quest:", questId)
|
|
|
|
QuestiePlayer.currentQuestlog[questId] = quest
|
|
|
|
if allianceTournamentMarkerQuests[questId] then
|
|
Questie.db.char.complete[13686] = true -- Alliance Tournament Eligibility Marker
|
|
elseif hordeTournamentMarkerQuests[questId] then
|
|
Questie.db.char.complete[13687] = true -- Horde Tournament Eligibility Marker
|
|
end
|
|
|
|
TaskQueue:Queue(
|
|
-- Get all the Frames for the quest and unload them, the available quest icon for example.
|
|
function() QuestieMap:UnloadQuestFrames(questId) end,
|
|
-- Make sure there isn't any lingering tooltip data hanging around in the quest table.
|
|
function() QuestieTooltips:RemoveQuest(questId) end,
|
|
function()
|
|
-- Re-accepted quest can be collapsed. Expand it. Especially dailies.
|
|
if Questie.db.char.collapsedQuests then
|
|
Questie.db.char.collapsedQuests[questId] = nil
|
|
end
|
|
-- Re-accepted quest can be untracked. Clear it. Especially timed quests.
|
|
if Questie.db.char.AutoUntrackedQuests[questId] then
|
|
Questie.db.char.AutoUntrackedQuests[questId] = nil
|
|
end
|
|
end,
|
|
function() QuestieQuest:PopulateQuestLogInfo(quest) end,
|
|
function()
|
|
-- This needs to happen after QuestieQuest:PopulateQuestLogInfo because that is the place where quest.Objectives is generated
|
|
Questie:SendMessage("QC_ID_BROADCAST_QUEST_UPDATE", questId)
|
|
end,
|
|
function() QuestieQuest:PopulateObjectiveNotes(quest) end,
|
|
function() AvailableQuests.CalculateAndDrawAll() end,
|
|
function()
|
|
QuestieCombatQueue:Queue(function()
|
|
QuestieTracker:Update()
|
|
end)
|
|
end
|
|
)
|
|
else
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Accepted Quest:", questId,
|
|
" Warning: Quest already exists, not adding")
|
|
end
|
|
end
|
|
end
|
|
|
|
local allianceChampionMarkerQuests = { [13699] = true, [13713] = true, [13723] = true, [13724] = true, [13725] = true }
|
|
local hordeChampionMarkerQuests = { [13726] = true, [13727] = true, [13728] = true, [13729] = true, [13731] = true }
|
|
|
|
---@param questId number
|
|
function QuestieQuest:CompleteQuest(questId)
|
|
-- Skip quests which are turn in only and are not added to the quest log in the first place
|
|
local questLogEntry = QuestiePlayer.currentQuestlog[questId]
|
|
if questLogEntry then
|
|
-- Only reset flags if the entry is a table (not a legacy number)
|
|
if type(questLogEntry) == "table" then
|
|
questLogEntry.WasComplete = nil
|
|
questLogEntry.isComplete = nil
|
|
end
|
|
QuestiePlayer.currentQuestlog[questId] = nil;
|
|
end
|
|
|
|
-- Only quests that are daily quests or aren't repeatable should be marked complete,
|
|
-- otherwise objectives for repeatable quests won't track correctly - #1433
|
|
if QuestieCompat.Is335 then
|
|
QuestieCompat.SetQuestComplete(questId)
|
|
else
|
|
Questie.db.char.complete[questId] = (not QuestieDB.IsRepeatable(questId)) or QuestieDB.IsDailyQuest(questId) or
|
|
QuestieDB.IsWeeklyQuest(questId);
|
|
end
|
|
|
|
if allianceChampionMarkerQuests[questId] then
|
|
Questie.db.char.complete[13700] = true -- Alliance Champion Marker
|
|
Questie.db.char.complete[13686] = nil -- Alliance Tournament Eligibility Marker
|
|
elseif hordeChampionMarkerQuests[questId] then
|
|
Questie.db.char.complete[13701] = true -- Horde Champion Marker
|
|
Questie.db.char.complete[13687] = nil -- Horde Tournament Eligibility Marker
|
|
end
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
|
|
if (QuestieMap.questIdFrames[questId]) then
|
|
Questie:Error("Just removed all frames but the framelist seems to still be there!", questId)
|
|
end
|
|
|
|
-- Delayed verification to ensure all objective icons are removed
|
|
-- This handles race conditions where AvailableQuests might redraw icons or UnloadQuestFrames misses some
|
|
C_Timer.After(0.5, function()
|
|
if QuestieMap.questIdFrames[questId] then
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:CompleteQuest] Lingering frames detected for quest:",
|
|
questId, "- forcing cleanup")
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
end
|
|
end)
|
|
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
QuestieTracker:RemoveQuest(questId)
|
|
QuestieCombatQueue:Queue(function()
|
|
QuestieTracker:Update()
|
|
end)
|
|
|
|
-- TODO: Should this be done first? Because CalculateAndDrawAll looks at QuestieMap.questIdFrames[QuestId] to add available
|
|
AvailableQuests.CalculateAndDrawAll()
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Completed Quest:", questId)
|
|
end
|
|
|
|
---@param questId number
|
|
function QuestieQuest:AbandonedQuest(questId)
|
|
-- NOTE: Some servers remove quests without firing QUEST_REMOVED reliably.
|
|
-- Always cleanup frames/tracker even if the quest isn't currently in QuestiePlayer.currentQuestlog.
|
|
if QuestiePlayer.currentQuestlog then
|
|
QuestiePlayer.currentQuestlog[questId] = nil
|
|
end
|
|
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
if quest then
|
|
-- Reset quest objectives
|
|
quest.Objectives = {}
|
|
|
|
-- Reset quest flags
|
|
quest.WasComplete = nil
|
|
quest.isComplete = nil
|
|
|
|
if allianceTournamentMarkerQuests[questId] then
|
|
Questie.db.char.complete[13686] = nil -- Alliance Tournament Eligibility Marker
|
|
elseif hordeTournamentMarkerQuests[questId] then
|
|
Questie.db.char.complete[13687] = nil -- Horde Tournament Eligibility Marker
|
|
end
|
|
|
|
local childQuests = QuestieDB.QueryQuestSingle(questId, "childQuests")
|
|
if childQuests then
|
|
for _, childQuestId in pairs(childQuests) do
|
|
Questie.db.char.complete[childQuestId] = nil
|
|
QuestLogCache.RemoveQuest(childQuestId)
|
|
end
|
|
end
|
|
end
|
|
|
|
AvailableQuests.UnloadUndoable()
|
|
|
|
QuestieTracker:RemoveQuest(questId)
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
QuestieCombatQueue:Queue(function()
|
|
QuestieTracker:Update()
|
|
end)
|
|
|
|
AvailableQuests.CalculateAndDrawAll()
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Abandoned Quest:", questId)
|
|
end
|
|
|
|
---@param questId number
|
|
function QuestieQuest:UpdateQuest(questId)
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:UpdateQuest]", questId)
|
|
|
|
---@type Quest
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
local sourceItemId = (quest and tonumber(quest.sourceItemId)) or 0
|
|
|
|
if quest and (not Questie.db.char.complete[questId]) then
|
|
QuestieQuest:PopulateQuestLogInfo(quest)
|
|
|
|
if QuestieQuest:ShouldShowQuestNotes(questId) then
|
|
QuestieQuest:UpdateObjectiveNotes(quest)
|
|
else
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
end
|
|
|
|
local isComplete = QuestieDB.IsComplete(questId)
|
|
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:UpdateQuest] QuestDB:IsComplete() flag is: " .. isComplete)
|
|
|
|
if isComplete == 1 then
|
|
-- Quest is complete
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:UpdateQuest] Quest is: Complete!")
|
|
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
QuestieQuest:AddFinisher(quest)
|
|
quest.WasComplete = true
|
|
elseif isComplete == -1 then
|
|
-- Failed quests should be shown as available again
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest:UpdateQuest] Quest has: Failed!")
|
|
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
AvailableQuests.DrawAvailableQuest(quest)
|
|
|
|
-- Reset any collapsed quest flags
|
|
if Questie.db.char.collapsedQuests then
|
|
Questie.db.char.collapsedQuests[questId] = nil
|
|
end
|
|
elseif isComplete == 0 then
|
|
-- Quest was somehow reset back to incomplete after being completed (quest.WasComplete == true).
|
|
-- The "or" check looks for a sourceItemId then checks to see if it's NOT in the players bag.
|
|
-- Player destroyed quest items? Or some other quest mechanic removed the needed quest item.
|
|
if quest and (quest.WasComplete or (sourceItemId > 0 and QuestieQuest:CheckQuestSourceItem(questId) == false)) then
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest:UpdateQuest] Quest was once complete or Quest Item(s) were removed. Resetting quest.")
|
|
|
|
-- Reset quest objectives
|
|
quest.Objectives = {}
|
|
|
|
-- Reset quest flags
|
|
quest.WasComplete = nil
|
|
quest.isComplete = nil
|
|
|
|
-- Reset tooltips
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
|
|
QuestieQuest:CheckQuestSourceItem(questId, true)
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
|
|
-- Reset any collapsed quest flags
|
|
if Questie.db.char.collapsedQuests then
|
|
Questie.db.char.collapsedQuests[questId] = nil
|
|
end
|
|
|
|
QuestieQuest:PopulateQuestLogInfo(quest)
|
|
QuestieQuest:PopulateObjectiveNotes(quest)
|
|
AvailableQuests.CalculateAndDrawAll()
|
|
else
|
|
-- 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
|
|
local numCompleteObjectives = 0
|
|
|
|
for i = 1, #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
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest:UpdateQuest] All Quest Objective(s) are Complete! Manually setting quest to Complete!")
|
|
QuestieMap:UnloadQuestFrames(questId)
|
|
QuestieQuest:AddFinisher(quest)
|
|
quest.WasComplete = true
|
|
quest.isComplete = true
|
|
else
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest:UpdateQuest] Quest Objective Status is: " ..
|
|
numCompleteObjectives .. ", out of: " .. #quest.Objectives .. ". No updates required.")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Questie:SendMessage("QC_ID_BROADCAST_QUEST_UPDATE", questId)
|
|
end
|
|
end
|
|
|
|
---@param questId number
|
|
function QuestieQuest:SetObjectivesDirty(questId)
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if quest then
|
|
for _, objective in pairs(quest.Objectives) do
|
|
objective.isUpdated = false
|
|
end
|
|
end
|
|
end
|
|
|
|
--Run this if you want to update the entire table
|
|
function QuestieQuest:GetAllQuestIds()
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Getting all quests")
|
|
|
|
QuestiePlayer.currentQuestlog = {}
|
|
|
|
for questId, data in pairs(QuestLogCache.questLog_DO_NOT_MODIFY) do -- DO NOT MODIFY THE RETURNED TABLE
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
|
|
if not quest then
|
|
if not Questie._sessionWarnings[questId] then
|
|
if not Questie.IsSoD then
|
|
Questie:Error(l10n(
|
|
"The quest %s is missing from Questie's database. Please report this on GitHub or Discord!",
|
|
tostring(questId)))
|
|
end
|
|
Questie._sessionWarnings[questId] = true
|
|
end
|
|
|
|
QuestiePlayer.currentQuestlog[questId] = questId -- legacy behavior
|
|
else
|
|
local complete = QuestieDB.IsComplete(questId)
|
|
|
|
QuestiePlayer.currentQuestlog[questId] = quest
|
|
quest.LocalizedName = data.title
|
|
|
|
if complete == -1 then
|
|
QuestieQuest:UpdateQuest(questId)
|
|
else
|
|
QuestieQuest:CheckQuestSourceItem(questId, true)
|
|
QuestieQuest:PopulateQuestLogInfo(quest)
|
|
|
|
if QuestieQuest:ShouldShowQuestNotes(questId) then
|
|
QuestieQuest:PopulateObjectiveNotes(quest)
|
|
else
|
|
QuestieTooltips:RemoveQuest(questId)
|
|
end
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Adding the quest", questId,
|
|
QuestiePlayer.currentQuestlog[questId])
|
|
end
|
|
end
|
|
|
|
QuestieCombatQueue:Queue(function()
|
|
QuestieTracker:Update()
|
|
end)
|
|
end
|
|
|
|
-- This checks and manually adds quest item tooltips for sourceItems
|
|
local function _AddSourceItemObjective(quest)
|
|
local sourceItemId = tonumber(quest.sourceItemId) or 0
|
|
if sourceItemId <= 0 then
|
|
return
|
|
end
|
|
|
|
local questObjectives = QuestieDB.QueryQuestSingle(quest.Id, "objectives")
|
|
local itemObjectives = questObjectives and questObjectives[3]
|
|
|
|
-- 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
|
|
if itemObjectiveId == sourceItemId then
|
|
Questie:Debug(Questie.DEBUG_INFO,
|
|
"[QuestieQuest:_AddSourceItemObjective] This item is already part of a quest objective.")
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local itemName = QuestieDB.QueryItemSingle(sourceItemId, "name")
|
|
if not itemName then
|
|
return
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:_AddSourceItemObjective] Adding Source Item Id for:", sourceItemId)
|
|
|
|
local fakeObjective = {
|
|
Id = quest.Id,
|
|
IsSourceItem = true,
|
|
QuestData = quest,
|
|
Index = 1,
|
|
Needed = 1,
|
|
Collected = 1,
|
|
text = itemName,
|
|
Description = itemName
|
|
}
|
|
|
|
QuestieTooltips:RegisterObjectiveTooltip(quest.Id, "i_" .. sourceItemId, fakeObjective);
|
|
end
|
|
|
|
-- This checks and manually adds quest item tooltips for SpellItems
|
|
local function _AddSpellItemObjective(quest)
|
|
if not quest.SpellItemId then
|
|
return
|
|
end
|
|
|
|
local questObjectives = QuestieDB.QueryQuestSingle(quest.Id, "objectives")
|
|
local spellObjectives = questObjectives and questObjectives[6]
|
|
if not spellObjectives then
|
|
return
|
|
end
|
|
|
|
local depthIndex = 1 -- TODO: What is better for this?
|
|
local needed = (quest.Objectives and quest.Objectives[depthIndex] and quest.Objectives[depthIndex].Needed) or 0
|
|
local collected = (quest.Objectives and quest.Objectives[depthIndex] and quest.Objectives[depthIndex].Collected) or 0
|
|
local desc = (quest.Objectives and quest.Objectives[depthIndex] and quest.Objectives[depthIndex].Description) or ""
|
|
|
|
local fakeObjective = {
|
|
Id = quest.Id,
|
|
IsSourceItem = true,
|
|
QuestData = quest,
|
|
Index = 1,
|
|
Needed = needed,
|
|
Collected = collected,
|
|
text = nil,
|
|
Description = desc,
|
|
}
|
|
|
|
QuestieTooltips:RegisterObjectiveTooltip(quest.Id, "i_" .. quest.SpellItemId, fakeObjective);
|
|
end
|
|
|
|
|
|
-- This checks and manually adds quest item tooltips for requiredSourceItems
|
|
local function _AddRequiredSourceItemObjective(quest)
|
|
if not quest.requiredSourceItems then
|
|
return
|
|
end
|
|
|
|
local questObjectives = QuestieDB.QueryQuestSingle(quest.Id, "objectives")
|
|
local itemObjectives = questObjectives and questObjectives[3]
|
|
|
|
for index, requiredSourceItemId in pairs(quest.requiredSourceItems) do
|
|
local alreadyInObjectives = false
|
|
|
|
if itemObjectives then
|
|
for _, itemObjectiveIndex in pairs(itemObjectives) do
|
|
for _, itemObjectiveId in pairs(itemObjectiveIndex) 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
|
|
end
|
|
if alreadyInObjectives then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if not alreadyInObjectives then
|
|
local itemName = QuestieDB.QueryItemSingle(requiredSourceItemId, "name")
|
|
if itemName then
|
|
Questie:Debug(Questie.DEBUG_INFO,
|
|
"[QuestieQuest:_AddRequiredSourceItemObjective] Adding Source Item Id for:", requiredSourceItemId)
|
|
|
|
local fakeObjective = {
|
|
Id = quest.Id,
|
|
IsRequiredSourceItem = true,
|
|
QuestData = quest,
|
|
Index = index,
|
|
text = itemName,
|
|
Description = itemName
|
|
}
|
|
|
|
QuestieTooltips:RegisterObjectiveTooltip(quest.Id, "i_" .. requiredSourceItemId, fakeObjective);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
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 quest = QuestieDB.GetQuest(questId)
|
|
|
|
if not quest then
|
|
if not Questie._sessionWarnings[questId] then
|
|
if not Questie.IsSoD then
|
|
Questie:Error(l10n(
|
|
"The quest %s is missing from Questie's database. Please report this on GitHub or Discord!",
|
|
tostring(questId)))
|
|
end
|
|
Questie._sessionWarnings[questId] = true
|
|
end
|
|
|
|
QuestiePlayer.currentQuestlog[questId] = questId
|
|
else
|
|
QuestiePlayer.currentQuestlog[questId] = quest
|
|
quest.LocalizedName = data.title
|
|
_AddSourceItemObjective(quest)
|
|
_AddRequiredSourceItemObjective(quest)
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Adding the quest", questId,
|
|
QuestiePlayer.currentQuestlog[questId])
|
|
end
|
|
end
|
|
end
|
|
|
|
-- iterate all notes, update / remove as needed
|
|
---@param quest Quest
|
|
function QuestieQuest:UpdateObjectiveNotes(quest)
|
|
if (not QuestiePlayer.currentQuestlog) or (not QuestiePlayer.currentQuestlog[quest.Id]) then
|
|
return
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] UpdateObjectiveNotes:", quest.Id)
|
|
for objectiveIndex, objective in pairs(quest.Objectives) do
|
|
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, objectiveIndex,
|
|
objective, false)
|
|
if (not result) then
|
|
Questie:Debug(Questie.DEBUG_ELEVATED, "[QuestieQuest] There was an error populating objectives for",
|
|
quest.name, quest.Id, objectiveIndex, err)
|
|
end
|
|
end
|
|
|
|
if next(quest.SpecialObjectives) then
|
|
for _, objective in pairs(quest.SpecialObjectives) do
|
|
local result, err = xpcall(QuestieQuest.PopulateObjective, ERR_FUNCTION, QuestieQuest, quest, 0, objective,
|
|
true)
|
|
if not result then
|
|
Questie:Error("[QuestieQuest]: [SpecialObjectives] " ..
|
|
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
|
|
end
|
|
end
|
|
end
|
|
|
|
-- This function is used to check the players bags for an item that matches quest.sourceItemId.
|
|
-- A good example for this edge case is [18] The Price of Shoes (118) where upon acceptance, Verner's Note (1283) is given
|
|
-- to the player and the Quest is immediately flagged as Complete. If the note is destroyed then a slightly modified version
|
|
-- of QuestieDB.IsComplete() that uses this function, returns zero allowing the quest updates to properly set the quests state.
|
|
---@param questId number @QuestID
|
|
---@param makeObjective boolean @If set to true, then this will create an incomplete objective for the missing quest item
|
|
---@return boolean @Returns true if quest.sourceItemId matches an item in a players bag
|
|
function QuestieQuest:CheckQuestSourceItem(questId, makeObjective)
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
local sourceItem = true
|
|
|
|
-- Ascension/custom quests may omit sourceItemId (nil). Normalize to 0.
|
|
local sourceItemId = (quest and tonumber(quest.sourceItemId)) or 0
|
|
|
|
if quest and sourceItemId > 0 then
|
|
for bag = -2, 4 do
|
|
local numSlots = QuestieCompat.GetContainerNumSlots(bag) or 0
|
|
for slot = 1, numSlots do
|
|
local itemId = select(10, QuestieCompat.GetContainerItemInfo(bag, slot))
|
|
if itemId == sourceItemId then
|
|
return true
|
|
end
|
|
end
|
|
|
|
sourceItem = false
|
|
end
|
|
|
|
-- If we are missing the sourceItem for zero objective quests then make an objective for it so the
|
|
-- player has a visual indication as to what item is missing and so the quest has a "tag" of some kind.
|
|
-- Also double check the quests leaderboard and make sure an objective doesn't already exist.
|
|
if (not sourceItem) and makeObjective and (not QuestieQuest:GetAllLeaderBoardDetails(quest.Id)[1]) then
|
|
local itemName = QuestieDB.QueryItemSingle(sourceItemId, "name") or ("Item " .. tostring(sourceItemId))
|
|
quest.Objectives = {
|
|
[1] = {
|
|
Description = itemName,
|
|
Type = "item",
|
|
Needed = 1,
|
|
Collected = 0,
|
|
Completed = false,
|
|
Id = sourceItemId,
|
|
questId = quest.Id
|
|
}
|
|
}
|
|
end
|
|
else
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function _GetIconScaleForAvailable()
|
|
return Questie.db.profile.availableScale or 1.3
|
|
end
|
|
|
|
---@param quest Quest
|
|
function QuestieQuest:AddFinisher(quest)
|
|
--We should never ever add the quest if IsQuestFlaggedComplete true.
|
|
local questId = quest.Id
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest] Adding finisher for quest", questId)
|
|
|
|
local complete = QuestieDB.IsComplete(questId)
|
|
|
|
if (QuestiePlayer.currentQuestlog[questId] and (IsQuestFlaggedCompleted(questId) == false) and (complete == 1 or complete == 0) and (not Questie.db.char.complete[questId])) then
|
|
local finisher, key
|
|
|
|
if quest.Finisher ~= nil then
|
|
if quest.Finisher.Type == "monster" then
|
|
finisher = QuestieDB:GetNPC(quest.Finisher.Id)
|
|
key = "m_" .. quest.Finisher.Id
|
|
elseif quest.Finisher.Type == "object" then
|
|
finisher = QuestieDB:GetObject(quest.Finisher.Id)
|
|
key = "o_" .. quest.Finisher.Id
|
|
else
|
|
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieQuest] Unhandled finisher type:", quest.Finisher.Type,
|
|
questId, quest.name)
|
|
end
|
|
else
|
|
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieQuest] Quest has no finisher:", questId, quest.name)
|
|
end
|
|
|
|
if finisher ~= nil then
|
|
-- Certain race conditions can occur when the NPC/Objects are both the Quest Starter and Quest Finisher
|
|
-- which can result in duplicate Quest Title tooltips appearing. DrawAvailableQuest() would have already
|
|
-- registered this NPC/Object so, the appropriate tooltip lines are already present. This checks and clears
|
|
-- any duplicate keys before registering the Quest Finisher.
|
|
|
|
-- 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
|
|
if (ttline == index) then
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest] AddFinisher - Removing duplicate Quest Title!")
|
|
|
|
-- Remove duplicate Quest Title
|
|
QuestieTooltips.lookupByKey[key][tostring(questId) .. " " .. finisher.name] = nil
|
|
|
|
-- Now check to see if the dup has a Special Objective
|
|
local objText = string.match(line, ".*|cFFcbcbcb.*")
|
|
|
|
if objText then
|
|
local objIndex
|
|
|
|
-- Grab the Special Objective index
|
|
if quest.SpecialObjectives[1] then
|
|
objIndex = quest.SpecialObjectives[1].Index
|
|
end
|
|
|
|
if objIndex then
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest] AddFinisher - Removing Special Objective!")
|
|
|
|
-- Remove Special Objective Text
|
|
QuestieTooltips.lookupByKey[key][tostring(questId) .. " " .. objIndex] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
QuestieTooltips:RegisterQuestStartTooltip(questId, finisher.name, finisher.id, key)
|
|
|
|
local finisherIcons = {}
|
|
local finisherLocs = {}
|
|
|
|
for finisherZone, spawns in pairs(finisher.spawns or {}) do
|
|
if (finisherZone ~= nil and spawns ~= nil) then
|
|
for _, coords in ipairs(spawns) do
|
|
local data = {
|
|
Id = questId,
|
|
Icon = Questie.ICON_TYPE_COMPLETE,
|
|
GetIconScale = _GetIconScaleForAvailable,
|
|
IconScale = _GetIconScaleForAvailable(),
|
|
Type = "complete",
|
|
QuestData = quest,
|
|
Name = finisher.name,
|
|
IsObjectiveNote = false,
|
|
}
|
|
|
|
if QuestieDB.IsActiveEventQuest(quest.Id) then
|
|
data.Icon = Questie.ICON_TYPE_EVENTQUEST_COMPLETE
|
|
elseif QuestieDB.IsPvPQuest(quest.Id) then
|
|
data.Icon = Questie.ICON_TYPE_PVPQUEST_COMPLETE
|
|
elseif quest.IsRepeatable then
|
|
data.Icon = Questie.ICON_TYPE_REPEATABLE_COMPLETE
|
|
end
|
|
|
|
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 zone = value[1];
|
|
local x = value[2];
|
|
local y = value[3];
|
|
|
|
QuestieMap:DrawWorldIcon(data, zone, x, y)
|
|
end
|
|
end
|
|
else
|
|
local x = coords[1];
|
|
local y = coords[2];
|
|
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Adding world icon as finisher:",
|
|
finisherZone, x, y)
|
|
finisherIcons[finisherZone] = QuestieMap:DrawWorldIcon(data, finisherZone, x, y)
|
|
|
|
if not finisherLocs[finisherZone] then
|
|
finisherLocs[finisherZone] = { x, y }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if finisher.waypoints then
|
|
for zone, waypoints in pairs(finisher.waypoints) 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 = {
|
|
Id = questId,
|
|
Icon = Questie.ICON_TYPE_COMPLETE,
|
|
GetIconScale = _GetIconScaleForAvailable,
|
|
IconScale = _GetIconScaleForAvailable(),
|
|
Type = "complete",
|
|
QuestData = quest,
|
|
Name = finisher.name,
|
|
IsObjectiveNote = false,
|
|
}
|
|
|
|
if QuestieDB.IsActiveEventQuest(quest.Id) then
|
|
data.Icon = Questie.ICON_TYPE_EVENTQUEST_COMPLETE
|
|
elseif QuestieDB.IsPvPQuest(quest.Id) then
|
|
data.Icon = Questie.ICON_TYPE_PVPQUEST_COMPLETE
|
|
elseif quest.IsRepeatable then
|
|
data.Icon = Questie.ICON_TYPE_REPEATABLE_COMPLETE
|
|
end
|
|
|
|
finisherIcons[zone] = QuestieMap:DrawWorldIcon(data, zone, waypoints[1][1][1],
|
|
waypoints[1][1][2])
|
|
finisherLocs[zone] = { waypoints[1][1][1], waypoints[1][1][2] }
|
|
end
|
|
|
|
QuestieMap:DrawWaypoints(finisherIcons[zone], waypoints, zone)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
Questie:Debug(Questie.DEBUG_CRITICAL, "[QuestieQuest] finisher or finisher.spawns == nil for questId",
|
|
questId)
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param quest Quest
|
|
---@param objectiveIndex ObjectiveIndex
|
|
---@param objective QuestObjective
|
|
---@param blockItemTooltips any
|
|
function QuestieQuest:PopulateObjective(quest, objectiveIndex, objective, blockItemTooltips) -- must be p-called
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:PopulateObjective]", objective.Description)
|
|
|
|
if (not objective.Update) then
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:PopulateObjective] - Quest is already updated. --> Exiting!")
|
|
return
|
|
end
|
|
|
|
objective:Update()
|
|
local completed = objective.Completed
|
|
local objectiveData = quest.ObjectiveData[objective.Index] or
|
|
objective -- the reason for "or objective" is to handle "SpecialObjectives" aka non-listed objectives (demonic runestones for closing the portal)
|
|
|
|
if (not objective.spawnList or (not next(objective.spawnList))) and _QuestieQuest.objectiveSpawnListCallTable[objectiveData.Type] then
|
|
objective.spawnList = _QuestieQuest.objectiveSpawnListCallTable[objectiveData.Type](objective.Id, objective,
|
|
objectiveData);
|
|
end
|
|
|
|
-- Tooltips should always show.
|
|
-- For completed and uncompleted objectives
|
|
_RegisterObjectiveTooltips(objective, quest.Id, blockItemTooltips)
|
|
|
|
if completed then
|
|
_UnloadAlreadySpawnedIcons(objective)
|
|
return
|
|
end
|
|
|
|
if (not objective.Color) then
|
|
objective.Color = QuestieLib:ColorWheel()
|
|
end
|
|
|
|
if objective.spawnList and next(objective.spawnList) then
|
|
local maxPerType = 300
|
|
|
|
if Questie.db.profile.enableIconLimit and Questie.db.profile.iconLimit < maxPerType then
|
|
maxPerType = Questie.db.profile.iconLimit
|
|
end
|
|
|
|
local closestStarter = QuestieMap:FindClosestStarter()
|
|
local objectiveCenter = closestStarter[quest.Id]
|
|
|
|
local zoneCount = 0
|
|
local zones = {}
|
|
local objectiveZone
|
|
|
|
for _, spawnData in pairs(objective.spawnList) do
|
|
for zone in pairs(spawnData.Spawns) do
|
|
zones[zone] = true
|
|
end
|
|
end
|
|
|
|
for zone in pairs(zones) do
|
|
objectiveZone = zone
|
|
zoneCount = zoneCount + 1
|
|
end
|
|
|
|
if zoneCount == 1 then -- this objective happens in 1 zone, clustering should be relative to that zone
|
|
local x, y = HBD:GetWorldCoordinatesFromZone(0.5, 0.5, ZoneDB:GetUiMapIdByAreaId(objectiveZone))
|
|
objectiveCenter = { x = x, y = y }
|
|
end
|
|
|
|
local iconsToDraw, _ = _DetermineIconsToDraw(quest, objective, objectiveIndex, objectiveCenter)
|
|
local icon, iconPerZone = _DrawObjectiveIcons(quest.Id, iconsToDraw, objective, maxPerType)
|
|
_DrawObjectiveWaypoints(objective, icon, iconPerZone)
|
|
end
|
|
end
|
|
|
|
_RegisterObjectiveTooltips = function(objective, questId, blockItemTooltips)
|
|
Questie:Debug(Questie.DEBUG_INFO, "Registering objective tooltips for", objective.Description)
|
|
|
|
if objective.spawnList then
|
|
if (not objective.hasRegisteredTooltips) then
|
|
for id, spawnData in pairs(objective.spawnList) do
|
|
if spawnData.TooltipKey and (not objective.AlreadySpawned[id]) then
|
|
QuestieTooltips:RegisterObjectiveTooltip(questId, spawnData.TooltipKey, objective)
|
|
end
|
|
end
|
|
|
|
objective.hasRegisteredTooltips = true
|
|
end
|
|
else
|
|
Questie:Error("[QuestieQuest]: [Tooltips] " ..
|
|
l10n("There was an error populating objectives for %s %s %s %s", objective.Description or "No objective text",
|
|
questId or "No quest id", 0 or "No objective", "No error"));
|
|
end
|
|
|
|
if (not objective.registeredItemTooltips) and objective.Type == "item" and (not blockItemTooltips) and objective.Id then
|
|
local itemName = QuestieDB.QueryItemSingle(objective.Id, "name")
|
|
|
|
if itemName then
|
|
QuestieTooltips:RegisterObjectiveTooltip(questId, "i_" .. objective.Id, objective)
|
|
end
|
|
|
|
objective.registeredItemTooltips = true
|
|
end
|
|
end
|
|
|
|
_UnloadAlreadySpawnedIcons = function(objective)
|
|
if next(objective.spawnList) then
|
|
for id, _ in pairs(objective.spawnList) do
|
|
local spawn = objective.AlreadySpawned[id]
|
|
if spawn then
|
|
for _, mapIcon in pairs(spawn.mapRefs) do
|
|
mapIcon:Unload()
|
|
end
|
|
for _, minimapIcon in pairs(spawn.minimapRefs) do
|
|
minimapIcon:Unload()
|
|
end
|
|
spawn.mapRefs = {}
|
|
spawn.minimapRefs = {}
|
|
end
|
|
end
|
|
objective.AlreadySpawned = {}
|
|
end
|
|
end
|
|
|
|
---@param quest Quest
|
|
---@param objective QuestObjective
|
|
---@param objectiveIndex ObjectiveIndex
|
|
---@param objectiveCenter {x:X, y:Y}
|
|
_DetermineIconsToDraw = function(quest, objective, objectiveIndex, objectiveCenter)
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:_DetermineIconsToDraw]")
|
|
|
|
local iconsToDraw = {}
|
|
local spawnItemId
|
|
|
|
for id, spawnData in pairs(objective.spawnList) do
|
|
if spawnData.ItemId then
|
|
spawnItemId = spawnData.ItemId
|
|
end
|
|
|
|
if (not objective.Icon) and spawnData.Icon then
|
|
objective.Icon = spawnData.Icon
|
|
end
|
|
|
|
if (not objective.AlreadySpawned[id]) and (not objective.Completed) and Questie.db.profile.enableObjectives then
|
|
local data = {
|
|
Id = quest.Id,
|
|
ObjectiveIndex = objectiveIndex,
|
|
QuestData = quest,
|
|
ObjectiveData = objective,
|
|
Icon = spawnData.Icon,
|
|
IconColor = quest.Color,
|
|
GetIconScale = spawnData.GetIconScale,
|
|
IconScale = spawnData.GetIconScale(),
|
|
Name = spawnData.Name,
|
|
Type = objective.Type,
|
|
ObjectiveTargetId = spawnData.Id
|
|
}
|
|
|
|
objective.AlreadySpawned[id] = {
|
|
data = data,
|
|
minimapRefs = {},
|
|
mapRefs = {},
|
|
}
|
|
|
|
for zone, spawns in pairs(spawnData.Spawns) do
|
|
local uiMapId = ZoneDB:GetUiMapIdByAreaId(zone)
|
|
for _, spawn in pairs(spawns) do
|
|
if (spawn[1] and spawn[2]) then
|
|
local drawIcon = {
|
|
AlreadySpawnedId = id,
|
|
data = data,
|
|
zone = zone,
|
|
AreaID = zone,
|
|
UiMapID = uiMapId,
|
|
x = spawn[1],
|
|
y = spawn[2],
|
|
worldX = 0,
|
|
worldY = 0,
|
|
distance = 0,
|
|
touched = nil, -- TODO change. This is meant to let lua reserve memory for all keys needed for sure.
|
|
}
|
|
local x, y, _ = HBD:GetWorldCoordinatesFromZone(drawIcon.x / 100, drawIcon.y / 100, uiMapId)
|
|
x = x or 0
|
|
y = y or 0
|
|
-- Cache world coordinates for clustering calculations
|
|
drawIcon.worldX = x
|
|
drawIcon.worldY = y
|
|
-- There are instances when X and Y are not in the same map such as in dungeons etc, we default to 0 if it is not set
|
|
-- This will create a distance of 0 but it doesn't matter.
|
|
local distance = QuestieLib:Euclid(objectiveCenter.x or 0, objectiveCenter.y or 0, x, y);
|
|
drawIcon.distance = distance or 0 -- cache for clustering
|
|
-- there can be multiple icons at same distance at different directions
|
|
--local distance = floor(distance)
|
|
local iconList = iconsToDraw[distance]
|
|
if iconList then
|
|
iconList[#iconList + 1] = drawIcon
|
|
else
|
|
iconsToDraw[distance] = { drawIcon }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return iconsToDraw, spawnItemId
|
|
end
|
|
|
|
_DrawObjectiveIcons = function(questId, iconsToDraw, objective, maxPerType)
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:_DrawObjectiveIcons] Adding Icons for quest:", questId)
|
|
|
|
local spawnedIconCount = 0
|
|
local icon
|
|
local iconPerZone = {}
|
|
|
|
local range = Questie.db.profile.clusterLevelHotzone
|
|
|
|
local iconCount, orderedList = _GetIconsSortedByDistance(iconsToDraw)
|
|
|
|
if orderedList[1] and orderedList[1].Icon == Questie.ICON_TYPE_OBJECT then -- new clustering / limit code should prevent problems, always show all object notes
|
|
range = range * 0.2; -- Only use 20% of the default range.
|
|
end
|
|
|
|
local hotzones = QuestieMap.utils:CalcHotzones(orderedList, range, iconCount);
|
|
|
|
for i = 1, #hotzones do
|
|
local hotzone = hotzones[i]
|
|
if (spawnedIconCount > maxPerType) then
|
|
Questie:Debug(Questie.DEBUG_DEVELOP, "[QuestieQuest] Too many icons for quest:", questId)
|
|
break;
|
|
end
|
|
|
|
--Any icondata will do because they are all the same
|
|
icon = hotzone[1];
|
|
|
|
local spawnsMapRefs = objective.AlreadySpawned[icon.AlreadySpawnedId].mapRefs
|
|
local spawnsMinimapRefs = objective.AlreadySpawned[icon.AlreadySpawnedId].minimapRefs
|
|
|
|
local centerX, centerY = QuestieMap.utils.CenterPoint(hotzone)
|
|
|
|
local dungeonLocation = ZoneDB:GetDungeonLocation(icon.zone)
|
|
|
|
if dungeonLocation and centerX == -1 and centerY == -1 then
|
|
if dungeonLocation[2] then -- We have more than 1 instance entrance (e.g. Blackrock dungeons)
|
|
local secondDungeonLocation = dungeonLocation[2]
|
|
|
|
icon.zone = secondDungeonLocation[1]
|
|
centerX = secondDungeonLocation[2]
|
|
centerY = secondDungeonLocation[3]
|
|
|
|
local iconMap, iconMini = QuestieMap:DrawWorldIcon(icon.data, icon.zone, centerX, centerY) -- clustering code takes care of duplicates as long as min-dist is more than 0
|
|
|
|
if iconMap and iconMini then
|
|
iconPerZone[icon.zone] = { iconMap, centerX, centerY }
|
|
spawnsMapRefs[#spawnsMapRefs + 1] = iconMap
|
|
spawnsMinimapRefs[#spawnsMinimapRefs + 1] = iconMini
|
|
end
|
|
|
|
spawnedIconCount = spawnedIconCount + 1;
|
|
end
|
|
|
|
local firstDungeonLocation = dungeonLocation[1]
|
|
icon.zone = firstDungeonLocation[1]
|
|
centerX = firstDungeonLocation[2]
|
|
centerY = firstDungeonLocation[3]
|
|
end
|
|
|
|
local iconMap, iconMini = QuestieMap:DrawWorldIcon(icon.data, icon.zone, centerX, centerY) -- clustering code takes care of duplicates as long as min-dist is more than 0
|
|
|
|
if iconMap and iconMini then
|
|
iconPerZone[icon.zone] = { iconMap, centerX, centerY }
|
|
spawnsMapRefs[#spawnsMapRefs + 1] = iconMap
|
|
spawnsMinimapRefs[#spawnsMinimapRefs + 1] = iconMini
|
|
end
|
|
|
|
spawnedIconCount = spawnedIconCount + 1;
|
|
end
|
|
|
|
return icon, iconPerZone
|
|
end
|
|
|
|
_GetIconsSortedByDistance = function(icons)
|
|
local iconCount = 0;
|
|
local orderedList = {}
|
|
local distances = {}
|
|
|
|
local i = 0
|
|
|
|
for distance in pairs(icons) do
|
|
i = i + 1
|
|
distances[i] = distance
|
|
end
|
|
|
|
table.sort(distances)
|
|
|
|
-- use the keys to retrieve the values in the sorted order
|
|
for distIndex = 1, #distances do
|
|
local iconsAtDisntace = icons[distances[distIndex]]
|
|
|
|
for iconIndex = 1, #iconsAtDisntace do
|
|
local icon = iconsAtDisntace[iconIndex]
|
|
|
|
iconCount = iconCount + 1
|
|
orderedList[iconCount] = icon
|
|
end
|
|
end
|
|
|
|
return iconCount, orderedList
|
|
end
|
|
|
|
_DrawObjectiveWaypoints = function(objective, icon, iconPerZone)
|
|
for _, spawnData in pairs(objective.spawnList) do -- spawnData.Name, spawnData.Spawns
|
|
if spawnData.Waypoints then
|
|
for zone, waypoints in pairs(spawnData.Waypoints) 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
|
|
local iconMap, iconMini = QuestieMap:DrawWorldIcon(icon.data, zone, firstWaypoint[1],
|
|
firstWaypoint[2]) -- clustering code takes care of duplicates as long as min-dist is more than 0
|
|
|
|
if iconMap and iconMini then
|
|
iconPerZone[zone] = { iconMap, firstWaypoint[1], firstWaypoint[2] }
|
|
tinsert(objective.AlreadySpawned[icon.AlreadySpawnedId].mapRefs, iconMap);
|
|
tinsert(objective.AlreadySpawned[icon.AlreadySpawnedId].minimapRefs, iconMini);
|
|
end
|
|
end
|
|
|
|
local ipz = iconPerZone[zone]
|
|
|
|
if ipz then
|
|
QuestieMap:DrawWaypoints(ipz[1], waypoints, zone, spawnData.Hostile and { 1, 0.2, 0, 0.7 } or nil)
|
|
end
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:_DrawObjectiveWaypoints]")
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param quest Quest
|
|
function QuestieQuest:PopulateObjectiveNotes(quest) -- this should be renamed to PopulateNotes as it also handles finishers now
|
|
if (not quest) then
|
|
return
|
|
end
|
|
|
|
if QuestieDB.IsComplete(quest.Id) == 1 then
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:PopulateObjectiveNotes] Quest Complete! Adding Finisher for:",
|
|
quest.Id)
|
|
|
|
QuestieQuest:UpdateQuest(quest.Id)
|
|
_AddSourceItemObjective(quest)
|
|
_AddRequiredSourceItemObjective(quest)
|
|
_AddSpellItemObjective(quest)
|
|
|
|
return
|
|
end
|
|
|
|
if (not quest.Color) then
|
|
quest.Color = QuestieLib:ColorWheel()
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:PopulateObjectiveNotes] Populating objectives for:", quest.Id)
|
|
|
|
QuestieQuest:UpdateObjectiveNotes(quest)
|
|
_AddSourceItemObjective(quest)
|
|
_AddRequiredSourceItemObjective(quest)
|
|
_AddSpellItemObjective(quest)
|
|
end
|
|
|
|
---@param quest Quest
|
|
---@return true?
|
|
function QuestieQuest:PopulateQuestLogInfo(quest)
|
|
if (not quest) then
|
|
return nil
|
|
end
|
|
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:PopulateQuestLogInfo] ", quest.Id)
|
|
|
|
local questLogEngtry = QuestLogCache.GetQuest(quest.Id) -- DO NOT MODIFY THE RETURNED TABLE
|
|
|
|
if (not questLogEngtry) then return end
|
|
|
|
if questLogEngtry.isComplete ~= nil and questLogEngtry.isComplete == 1 then
|
|
quest.isComplete = true
|
|
end
|
|
|
|
--Uses the category order to draw the quests and trusts the database order.
|
|
|
|
local questObjectives = QuestieQuest:GetAllLeaderBoardDetails(quest.Id) or {} -- DO NOT MODIFY THE RETURNED TABLE
|
|
|
|
for objectiveIndex, objective in pairs(questObjectives) do
|
|
if objective.type and string.len(objective.type) > 1 then
|
|
if (not quest.ObjectiveData) or (not quest.ObjectiveData[objectiveIndex]) then
|
|
Questie:Error(l10n("Missing objective data for quest "), quest.Id, " ", objective.text)
|
|
else
|
|
if not quest.Objectives[objectiveIndex] then
|
|
quest.Objectives[objectiveIndex] = {
|
|
Id = quest.ObjectiveData[objectiveIndex].Id,
|
|
Index = objectiveIndex,
|
|
questId = quest.Id,
|
|
_lastUpdate = 0,
|
|
Description = objective.text,
|
|
spawnList = {},
|
|
AlreadySpawned = {},
|
|
Update = _QuestieQuest.ObjectiveUpdate,
|
|
Coordinates = quest.ObjectiveData[objectiveIndex].Coordinates, -- Only for type "event"
|
|
RequiredRepValue = quest.ObjectiveData[objectiveIndex].RequiredRepValue
|
|
}
|
|
end
|
|
|
|
quest.Objectives[objectiveIndex]:Update()
|
|
end
|
|
end
|
|
|
|
if (not quest.Objectives[objectiveIndex]) or (not quest.Objectives[objectiveIndex].Id) then
|
|
Questie:Debug(Questie.DEBUG_DEVELOP,
|
|
"[QuestieQuest:PopulateQuestLogInfo] Error finding entry ID for objective", objectiveIndex,
|
|
objective.type, objective.text, "of questId:", quest.Id)
|
|
end
|
|
end
|
|
|
|
-- find special unlisted objectives
|
|
if next(quest.SpecialObjectives) then
|
|
for index, specialObjective in pairs(quest.SpecialObjectives) do
|
|
if (not specialObjective.Description) then
|
|
specialObjective.Description = "Special objective"
|
|
end
|
|
|
|
specialObjective.questId = quest.Id
|
|
|
|
if specialObjective.RealObjectiveIndex and quest.Objectives[specialObjective.RealObjectiveIndex] then
|
|
-- This specialObjective is an extraObjective and has a RealObjectiveIndex set
|
|
specialObjective.Completed = quest.Objectives[specialObjective.RealObjectiveIndex].Completed
|
|
specialObjective.Update = function(self)
|
|
self.Completed = quest.Objectives[self.RealObjectiveIndex].Completed
|
|
end
|
|
else
|
|
specialObjective.Update = NOP_FUNCTION
|
|
end
|
|
|
|
specialObjective.Index = 64 + index -- offset to not conflict with real objectives
|
|
specialObjective.AlreadySpawned = specialObjective.AlreadySpawned or {}
|
|
end
|
|
end
|
|
|
|
if #quest.Objectives == 0 and #quest.SpecialObjectives == 0 and ((quest.triggerEnd and #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().
|
|
QuestieMap:UnloadQuestFrames(quest.Id)
|
|
QuestieQuest:AddFinisher(quest)
|
|
quest.isComplete = true
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
---@param self QuestObjective @quest.Objectives[] entry
|
|
function _QuestieQuest.ObjectiveUpdate(self)
|
|
if self.isUpdated then
|
|
return
|
|
end
|
|
|
|
local questObjectives = QuestieQuest:GetAllLeaderBoardDetails(self.questId) -- DO NOT MODIFY THE RETURNED TABLE
|
|
|
|
if questObjectives and questObjectives[self.Index] then
|
|
local obj = questObjectives[self.Index] -- DO NOT EDIT THE TABLE
|
|
if (obj.type) then
|
|
-- fixes for api bug
|
|
local numFulfilled = obj.numFulfilled or 0
|
|
local numRequired = obj.numRequired or 0
|
|
local finished = obj.finished or false -- ensure its boolean false and not nil (hack)
|
|
|
|
self.Type = obj.type;
|
|
self.Description = obj.text
|
|
self.Collected = tonumber(numFulfilled);
|
|
self.Needed = tonumber(numRequired);
|
|
self.Completed = (self.Needed == self.Collected and self.Needed > 0) or
|
|
(finished and (self.Needed == 0 or (not self.Needed))) -- some objectives get removed on PLAYER_LOGIN because isComplete is set to true at random????
|
|
-- Mark objective updated
|
|
self.isUpdated = true
|
|
end
|
|
end
|
|
end
|
|
|
|
---@param questId number
|
|
---@return table<ObjectiveIndex, QuestLogCacheObjectiveData>|nil @DO NOT EDIT RETURNED TABLE
|
|
function QuestieQuest:GetAllLeaderBoardDetails(questId)
|
|
Questie:Debug(Questie.DEBUG_INFO, "[QuestieQuest:GetAllLeaderBoardDetails] for questId", 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
|
|
-- 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)
|
|
end
|
|
|
|
return questObjectives
|
|
end
|
|
|
|
function QuestieQuest.DrawDailyQuest(questId)
|
|
if QuestieDB.IsDoable(questId) then
|
|
local quest = QuestieDB.GetQuest(questId)
|
|
AvailableQuests.DrawAvailableQuest(quest)
|
|
end
|
|
end
|
|
|
|
return QuestieQuest
|