diff --git a/CHANGELOG.md b/CHANGELOG.md index 44887e7..d39bb0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ ### Features +- **[Map - Hide Repeatable/Callboard Quests Below Level 60]** (#10) Added "Hide repeatable quests below level 60" (Icons tab, off by default) which hides repeatable available `!` quests — such as the Ascension Callboard — from the map and minimap until the character reaches level 60, where they become relevant. Enforced both at draw time (`_DrawQuestIfAvailable`) and in `ShouldBeHidden`, so already-drawn pins are removed on the minimap too, and they reappear automatically on hitting 60. Only affects repeatable available quests and only when the option is enabled. + - **[Tooltip - ElvUI Style Without ElvUI]** Added "ElvUI tooltip style" (General tab, on by default) which skins Questie's tooltips — the NPC/item/object and world-map-pin tooltips plus the secondary learner tooltip — with ElvUI's transparent flat look (dark `0.06/0.06/0.06/0.8` background and a thin 1px border) even when ElvUI is not installed, so they match instead of falling back to the chunky default WoW border. `QuestieTooltips:SkinDefaultTooltips` applies it to `GameTooltip`, `WorldMapTooltip`, `ItemRefTooltip` and the shopping tooltips (re-asserted on show), and the secondary learner frame's fallback style was corrected to the same thin border. No-op when ElvUI is loaded, since ElvUI skins the frames itself. - **[Map - Looted Object Pins Disappear On Loot]** When you open/loot a quest object node (e.g. Fell Wood piles), that specific node's map/minimap pin now disappears immediately even if the objective is not yet fully collected, instead of all node pins staying until turn-in. On `LOOT_OPENED`, `QuestieQuest:RemoveLootedObjectivePins` finds the active object-objective spawn nearest the player's world position (within ~12 yards, since you stand on the node to loot it), records it as consumed in `Questie.db.char.lootedObjectSpawns`, and redraws just that objective so clustering recomputes with the looted node skipped. `_DetermineIconsToDraw` skips consumed object spawns, so removal persists across redraws and `/reload`. The looted history is cleared on quest accept (`QuestieQuest:ClearLootedSpawns`), so abandoning and re-doing the quest — including after an Ascension prestige — shows every node again. Scoped to `object`-type objectives; monster/kill pins are unchanged. Works in every data source mode (auto / learner / static / none): the suppression is centralized in the single shared `_DetermineIconsToDraw` draw path that all redraw routes funnel through (core `UpdateQuest`, the learner's debounced `_DoFlushActiveQuestPins`, slider redraws), and it operates on the already mode-resolved `objective.spawnList`. Matching is radius-based (1.5 zone units) rather than exact-coordinate so that in learner/auto mode a spawn the learner re-adds at the player's position for the just-looted node is also suppressed instead of re-appearing. @@ -30,6 +32,9 @@ ### Bug Fixes +- **[Map - Completed Quests Still Shown As Available]** (#7) The server's completed-quest list is delivered asynchronously (the `QUEST_QUERY_COMPLETE` event), often after available quests were first drawn — so quests that were actually already complete kept showing as available `!` until something forced a redraw (e.g. `/reload`). Questie now recalculates available quests once `char.complete` is populated by that event, removing the completed ones. This also clears the "already completed" subset of the false-available pins reported in #8. +- **[Map - Available '!' Lingered On Minimap For Accepted Quests]** (#9) When a quest was accepted, its available `!` icon could remain on the minimap until a `/reload`. `QuestieMap:UnloadQuestFramesByDataType` unloaded the frame but left its name in the frame registry and `_G`, so the minimap icon was not fully torn down. It now removes the registry/global reference as well, so the available icon is cleared immediately on accept for both the map and minimap. + - **[Tooltip - Data Source In Secondary Tooltip Only]** The `Source:` attribution line now appears only inside the secondary learner tooltip (when "Use secondary learner tooltip" is enabled) and is never added to the main NPC/object/item tooltip; with the secondary tooltip disabled it does not appear at all. The map-pin source line is gated the same way. The "Show data source" option now depends on the secondary-tooltip option being enabled. - **[Tooltip - Learner Pin Mislabelled As AscensionDB]** A spawn freshly learned via the learner was shown as `Source: AscensionDB` instead of `Learner`. `QuestieDB.GetPinDataSource` resolved AscensionDB-curated ownership before checking the learner, but in learner-only mode the displayed spawns are the learner's (curated coords are discarded by `GetNPC`/`GetObject`). It is now mode-aware: in learner mode, an entity with a learner record reports `Learner` even when AscensionDB also curates it. - **[Learner - Learner-Only Mode No Longer Draws AscensionDB/Static Pins]** In learner-only mode the map/minimap drew curated AscensionDB (and static) spawns for every quest NPC/object the player had not personally recorded, instead of only the learner's own spawns. `QuestieDB:GetNPC`/`GetObject` fall back to the `npcDataOverrides`/`objectDataOverrides` entry for metadata when there is no learner record, and that entry's spawns (AscensionDB-curated for un-recorded entities) were being used as pins. Both functions now track whether a real learner record exists and, in learner mode, strip the spawns when it does not — so learner-only mode shows exclusively what the learner has recorded (the metadata fallback for names/tooltips is kept). Added a regression test. Recorded entities still show their learner spawns; auto/static/none modes are unchanged. diff --git a/Compat/Compat.lua b/Compat/Compat.lua index fa51e2d..e78705a 100644 --- a/Compat/Compat.lua +++ b/Compat/Compat.lua @@ -755,6 +755,14 @@ function QuestieCompat:QUEST_QUERY_COMPLETE(event) QuestieCompat.Merge(Questie.db.char.complete, Questie.db.char.weekly) end end + + -- The completed-quest list arrives asynchronously from the server (this event), often + -- AFTER available quests were first drawn — so quests that are actually already complete + -- kept showing as available '!' until something else forced a redraw (e.g. /reload). + -- Recalculate now that char.complete is populated so completed quests are removed. (#7) + if QuestieQuest and QuestieQuest.started and AvailableQuests and AvailableQuests.CalculateAndDrawAll then + AvailableQuests.CalculateAndDrawAll() + end end -- https://wowpedia.fandom.com/wiki/API_IsQuestFlaggedCompleted diff --git a/Modules/FramePool/QuestieFrame.lua b/Modules/FramePool/QuestieFrame.lua index 8d5f387..c311cf4 100644 --- a/Modules/FramePool/QuestieFrame.lua +++ b/Modules/FramePool/QuestieFrame.lua @@ -542,6 +542,7 @@ function _Qframe:ShouldBeHidden() and ((not DailyQuests:IsActiveDailyQuest(questId)) -- hide not-today-dailies or ((not profile.enableAvailable) and normal) or ((not profile.showRepeatableQuests) and repeatable) + or (profile.hideRepeatableBelowMaxLevel and repeatable and (UnitLevel("player") or 0) < 60) -- Hide Callboard/repeatable quests below 60 (#10) or ((not profile.showEventQuests) and event) or ((not profile.showDungeonQuests) and dungeon) or ((not profile.showRaidQuests) and raid) diff --git a/Modules/Map/QuestieMap.lua b/Modules/Map/QuestieMap.lua index cad19bf..62947c7 100644 --- a/Modules/Map/QuestieMap.lua +++ b/Modules/Map/QuestieMap.lua @@ -129,9 +129,14 @@ end function QuestieMap:UnloadQuestFramesByDataType(questId, dataType) if QuestieMap.questIdFrames[questId] then - for _, frame in pairs(QuestieMap:GetFramesForQuest(questId)) do + for name, frame in pairs(QuestieMap:GetFramesForQuest(questId)) do if frame and frame.data and frame.data.Type == dataType then frame:Unload() + -- Also drop the registry/global reference. Without this the frame name + -- lingered in questIdFrames and _G, so the available '!' could stay on the + -- minimap after a quest was accepted until a full /reload rebuilt frames. (#9) + QuestieMap.questIdFrames[questId][name] = nil + _G[name] = nil end end diff --git a/Modules/Options/IconsTab/QuestieOptionsIcons.lua b/Modules/Options/IconsTab/QuestieOptionsIcons.lua index 1361b54..c16e4d4 100644 --- a/Modules/Options/IconsTab/QuestieOptionsIcons.lua +++ b/Modules/Options/IconsTab/QuestieOptionsIcons.lua @@ -187,6 +187,23 @@ function QuestieOptions.tabs.icons:Initialize() QuestieQuest:ToggleNotes(value) end, }, + hideRepeatableBelowMaxLevel = { + type = "toggle", + order = 2.035, + name = function() return l10n('Hide repeatable quests below level 60'); end, + desc = function() return l10n('Hides repeatable available quests (such as the Ascension Callboard) from the map and minimap until the character reaches level 60, where they become relevant.'); end, + width = 1.595, + disabled = function() return (not Questie.db.profile.enabled) or (not Questie.db.profile.showRepeatableQuests); end, + get = function(info) return Questie.db.profile.hideRepeatableBelowMaxLevel end, + set = function(info, value) + Questie.db.profile.hideRepeatableBelowMaxLevel = value + QuestieQuest:ToggleNotes(true) + local AvailableQuests = QuestieLoader:ImportModule("AvailableQuests") + if AvailableQuests and AvailableQuests.CalculateAndDrawAll then + AvailableQuests.CalculateAndDrawAll() + end + end, + }, showPvPQuests = { type = "toggle", order = 2.04, diff --git a/Modules/Options/QuestieOptionsDefaults.lua b/Modules/Options/QuestieOptionsDefaults.lua index cb0e1b3..5da0d93 100644 --- a/Modules/Options/QuestieOptionsDefaults.lua +++ b/Modules/Options/QuestieOptionsDefaults.lua @@ -177,6 +177,7 @@ function QuestieOptionsDefaults:Load() hideUnexploredMapIcons = false, hideUntrackedQuestsMapIcons = false, showRepeatableQuests = true, + hideRepeatableBelowMaxLevel = false, showEventQuests = true, showDungeonQuests = true, showRaidQuests = true, diff --git a/Modules/Quest/AvailableQuests.lua b/Modules/Quest/AvailableQuests.lua index 51578d6..1bab3f9 100644 --- a/Modules/Quest/AvailableQuests.lua +++ b/Modules/Quest/AvailableQuests.lua @@ -122,6 +122,9 @@ _CalculateAvailableQuests = function() local completedQuests = Questie.db.char.complete local showRepeatableQuests = Questie.db.profile.showRepeatableQuests + -- Hide repeatable available quests (e.g. the Ascension Callboard '!') below level 60, + -- where they aren't relevant yet. (#10) + local hideRepeatableBelowMax = Questie.db.profile.hideRepeatableBelowMaxLevel and playerLevel < 60 local showDungeonQuests = Questie.db.profile.showDungeonQuests local showRaidQuests = Questie.db.profile.showRaidQuests local showPvPQuests = Questie.db.profile.showPvPQuests @@ -163,6 +166,7 @@ _CalculateAvailableQuests = function() if ( ((not showRepeatableQuests) and QuestieDB.IsRepeatable(questId)) or -- Don't show repeatable quests if option is disabled + (hideRepeatableBelowMax and QuestieDB.IsRepeatable(questId)) or -- Hide repeatable (Callboard) quests below level 60 (#10) ((not showPvPQuests) and QuestieDB.IsPvPQuest(questId)) or -- Don't show PvP quests if option is disabled ((not showDungeonQuests) and QuestieDB.IsDungeonQuest(questId)) or -- Don't show dungeon quests if option is disabled ((not showRaidQuests) and QuestieDB.IsRaidQuest(questId)) or -- Don't show raid quests if option is disabled