diff --git a/Database/QuestieDB.lua b/Database/QuestieDB.lua index 829a88b..445491f 100644 --- a/Database/QuestieDB.lua +++ b/Database/QuestieDB.lua @@ -15,12 +15,19 @@ local _QuestieDB = QuestieDB.private -- 1. override[stringKey] (string-keyed, e.g. from wotlkNPCFixes) -- 2. override[intKey] (numeric-keyed, e.g. from QuestieLearner / AscensionDB) -- 3. rawdata[intKey] (fallback to compiled DB) +-- +-- Empty tables from QuestieLearner (e.g. spawns={}) are treated as "not present" +-- so the base DB's real spawn data is preserved until actual coordinates are learned. ------------------------------------------------------------------------ +local function IsEmptyTable(val) + return type(val) == "table" and next(val) == nil +end + local function _MergeOverride(result, override, rawdata, keyMap) for stringKey, intKey in pairs(keyMap) do if override[stringKey] ~= nil then result[stringKey] = override[stringKey] - elseif override[intKey] ~= nil then + elseif override[intKey] ~= nil and not IsEmptyTable(override[intKey]) then result[stringKey] = override[intKey] elseif rawdata then result[stringKey] = rawdata[intKey] diff --git a/Modules/QuestieLearner.lua b/Modules/QuestieLearner.lua index f40f40f..4eb8370 100644 --- a/Modules/QuestieLearner.lua +++ b/Modules/QuestieLearner.lua @@ -308,6 +308,46 @@ local function _RefreshActiveQuestPins(questIdSet) end end +-- Invalidates cached objective.spawnList for any active quest whose objectives +-- reference the given npcId. This forces the map system to rebuild spawn lists +-- from QuestieDB on the next update, picking up newly learned coordinates. +local function _InvalidateSpawnListsForNPC(npcId) + if not QuestieQuest or not QuestiePlayer or not QuestiePlayer.currentQuestlog then return end + local timer = (C_Timer) or (QuestieCompat and QuestieCompat.C_Timer) + local questsToRefresh = {} + for questId, _ in pairs(QuestiePlayer.currentQuestlog) do + local quest = QuestieDB.GetQuest and QuestieDB.GetQuest(questId) + if quest and quest.Objectives then + for _, objective in pairs(quest.Objectives) do + local shouldInvalidate = false + -- Monster objectives reference NPCs directly in spawnList keys + if objective.spawnList then + if objective.spawnList[npcId] then + shouldInvalidate = true + end + -- Also check killcredit IdList + if not shouldInvalidate and objective.IdList then + for _, id in ipairs(objective.IdList) do + if id == npcId then shouldInvalidate = true; break end + end + end + end + -- Fallback: if objective Id matches the NPC (some objectives use NPC as their primary Id) + if not shouldInvalidate and objective.Id == npcId then + shouldInvalidate = true + end + if shouldInvalidate then + objective.spawnList = nil + objective.AlreadySpawned = nil + questsToRefresh[questId] = true + break -- one invalidation per quest is enough + end + end + end + end + _RefreshActiveQuestPins(questsToRefresh) +end + ------------------------------------------------------------------------ -- CrossLinkAfterNPC: called when a new NPC is first learned. -- Scans all learned quests for any reference to this npcId and stitches @@ -645,6 +685,11 @@ function QuestieLearner:LearnNPC(npcId, name, level, subName, npcFlags, factionS if isNew then Questie:Debug(Questie.DEBUG_LEARNER, "[QuestieLearner] New NPC learned:", npcId, name or "?") CrossLinkAfterNPC(npcId) + else + -- Existing NPC got new spawn data: invalidate cached spawnLists + -- for any active quest objective that references this NPC so the + -- map system rebuilds them with fresh data on next update. + _InvalidateSpawnListsForNPC(npcId) end _Learner:BroadcastIfCommsAvailable("NPC", npcId, existing) end