QuestieOptions.tabs.{auto,dbm,icons,nameplate} were initialized with {...}
instead of {}. At file scope in Lua 5.1 this silently captures the addon
varargs into the table; in Lua 5.0 it is a parse error. All sibling tabs use
{}. No behavioral change (Initialize repopulates the table).
Lua 5.0 (Vanilla 1.12) has no % operator outside string formatting; it is a
parse error. Route the 9 arithmetic modulo sites through the existing math.mod
shim (Compat/Compat.lua) so the addon parses on 5.0 through Retail.
Sites: QuestieDB daily/weekly flag tests, QuestieEvent DMF cycle math,
QuestieLearner GUID/flag math, QuestiePlayer race/class flag tests.
Brings the still-needed changes from questie-phase1perf that main lacked.
Main already had the Lua 5.0 shims (QuestieLoader bit/strsplit, QuestieStream
and QuestieSerializer math.mod sweep), so those are omitted.
- QuestieNameplate: skip missing entries instead of return-aborting the whole
activeGUIDs loop (one bad unit no longer stalls every nameplate update)
- QuestieQuest.ClearAllNotes: skip DB-missing quests instead of aborting, so
remaining quests' notes still get cleared
- QuestieOptionsTracker: fix fadeTickerValue:Cancel -> fadeTicker:Cancel (3x);
fadeTickerValue is a number, the ticker handle is fadeTicker
- QuestieCommsData: nil-guard GetNPC/GetObject before reading .name
- QuestieAnnounce: bound the alreadySentBandaid dedup cache (reset at 1000)
- QuestieDB.IsComplete: hoist GetQuest into expectedQuest (one call, not two)
- QuestieFramePool/QuestieFrame: drop the dead BaseOnUpdate ticker branch
(BaseOnUpdate was never defined; behavior was always OnUpdate=nil)
- QuestieLib: document unused questId arg on Ascension_IsScalingEnabled
- Database/Corrections x3: strip stray UTF-8 BOM
- Questie-X.toc: remove duplicate QuestieSlash.lua load line
Uncredited kills (mobs other players killed that you never engaged)
passed px,py=nil to LearnNPC, whose GetPlayerCoords fallback stored YOUR
position as the mob's spawn and incremented the kill count. Gate spawn
recording (LearnNPC + _StoreGuidSpawnEvidence) on a captured position, so
only credited kills with a real position store a spawn. Bystander kills
no longer pollute coordinates or inflate counts.
ShowQuestIcons/HideQuestIcons indexed icon (=_G[frameName]) when it can
be nil for a registry entry whose frame was already reset, crashing the
fade pass (attempt to index local 'icon'). Guard icon/icon.data/
icon.data.QuestData and skip stale frames; ShowQuestIcons no longer
error()s on the desync.
The dedupe helper was a local function defined after
AddUnitDataToTooltip, so that function resolved it as a nil global and
every unit tooltip errored (attempt to call global '_TooltipHasLeftLine').
Moved it above all Add*DataToTooltip functions.
Expose QuestieLearner:GetIdAndTypeFromGUID / GetObjectIdFromGUID /
GetNpcIdFromGUID (they handle modern dash GUIDs AND legacy 0x hex /
GameObject GUIDs). Tooltips now fall back to these when strsplit('-',guid)
can't parse the GUID, so NPC IDs no longer silently fail to write on
hex-GUID units; the Object ID line resolves from the object's GUID when
its name isn't in the lookup. IDs deduped per tooltip.
The ID lines were gated by lastItemId/lastGuid (only added when the
hovered item/unit changed). WoW clears and re-fires OnTooltipSetItem/
OnTooltipSetUnit for the same item/unit and rebuilds the tooltip, so the
gate skipped re-adding the line on the rebuilt tooltip and the ID
disappeared. Add the ID line on every render instead, deduped per
tooltip via _TooltipHasLeftLine so it shows exactly once.
- Critters are never quest-relevant. Added a static CRITTER_NPC_SET (common
classic critters) plus runtime detection via UnitCreatureType on
mouseover/target (covers Ascension custom critters). LearnNPC and the kill
handler skip critters; InjectLearnedData purges already-recorded ones; and
critters are purged on sight when a unit token is available.
- Object/NPC spawns mis-stored under Eversong parent areaId 3430 (e.g. object
180516 'Shrine of Dath'Remar' on Sunstrider) now migrate to uiMapId 1241,
along with the [9]/[5] home-zone field. Legit Eversong data is keyed 1941,
so any 3430 key is mis-stored Sunstrider data.
Verified in Tests/QuestieLearnerCritterPurge_spec.lua.
Two bugs made saved learner spawns collapse to one pin on every login:
1. The spawn zone-key migration was inverted: it ran
GetAreaIdByUiMapId(1241) -> Eversong parent areaId 3430 and moved
Sunstrider coords there (wrong map / NE corner), deduping distinct
coords via InsertIfNewBucket along the way. Now it converts only
legacy areaId keys FORWARD to the canonical uiMapId and leaves uiMapId
keys untouched. Same for the [9]/[5] home-zone fields.
2. Sanitize de-duplicated coords with the flat COORD_GRID (2.0) instead
of the per-zone grid, collapsing Sunstrider's tightly-packed spawns
(grid 0.5). Now uses GetCoordGridForZone(zoneId).
Both rewrote learned.npcs in place, persisting the damage to
SavedVariables. Regression test in QuestieLearnerMultiSpawn_spec.lua.
A prior change (dd630fd) kept clustering enabled on Sunstrider Isle in
learner mode to avoid pin fan-out, but that collapsed several distinct
learned coordinates (e.g. 7 Arcane Wraith spots) into a single pin --
breaking the DB-building workflow where every learned spawn must be
visible. The SavedVariables data was correct the whole time; this was a
display regression. Sunstrider (1241) now shows every distinct pin by
default in all data-source modes; consolidation only happens when the
player explicitly raises the Dense Pin Clustering Aggressiveness knob.
The Ascension server appends a new progress line on every objective
update instead of replacing it, so tooltips stacked 0/8 1/8 2/8 3/8 for
one objective. New always-on DedupeAscensionProgressLines collapses each
stack to its most-progressed line. It only hides a line when the same
tooltip holds another progress line with the same objective text AND
denominator, so other addons' lines and Questie's own single-line
objectives are never touched. Separate from the opt-in full-strip option
(#16). Unit-tested in Tests/QuestieTooltipDedupe_spec.lua.
Draw-queue race: ProcessQueue processes the world-map and minimap queues
independently. When a frame was unloaded while still queued, its
minimap-queue entry could trigger the deferred Unload first (removing
both icons and clearing _needsUnload), then a later map-queue entry
re-added the world-map icon -- orphaned, since Unload had nil'd the
questIdFrames/_G reference, so it lingered until /reload while the
minimap cleared. Unload now drops the frame's pending draw-queue entries
(new QuestieMap:DequeueFrameDrawCalls) so an unloaded frame can never be
re-added to a map.
The kill handler's position capture ran inside 'if credited then', but
credited was read before its 'local credited = ...' assignment a few
lines below, so it was always nil and px,py were never captured -- every
killed NPC stayed spawnSource='fallback' with no [7] and drew no learner
pins regardless of kill count. Move the credited computation above the
capture and nil-guard a 0,0 position. GetPlayerCoords now uses the robust
GetCurrentPlayerPosition (Sunstrider-corrected), returning nil when
invalid so no 0,0 pins are recorded. Reverts the earlier HBD GetPlayerCoords
approach which treated the wrong symptom and caused spurious pins.
FadeLogic only re-checked ShouldBeHidden when deciding whether to
re-show an already-hidden icon, so a filtered quest (e.g. a dungeon
quest) that was already visible -- or that HBD's pin renderer showed on
coming into range -- was never hidden on the minimap while the world map
hid it. FadeLogic now proactively FakeHides any in-range icon whose
ShouldBeHidden is true, in both minimap fade paths; the second path also
gains the #17 minimap-radius cutoff gating it was missing.
GetPlayerCoords used raw GetPlayerMapPosition('player'), which returns
0,0 when the world map isn't on the player's zone (the usual case) and
mis-reports on Ascension subzones like Sunstrider. Learn events captured
no position, so NPCs were saved spawnSource='fallback' with no [7]
spawns and their learner-only pins never persisted -- showing briefly
after a live kill then vanishing. Read from HBD:GetPlayerZonePosition()
(robust SetMapToCurrentZone/Sunstrider-corrected, cached), falling back
to the old API only if HBD is unavailable.
HideAscensionQuestLines ran on every tooltip and removed any line
matching a quest-objective pattern (N/M, [N] ...), clobbering other
tooltip addons' lines (durability, stack counts, etc.). Gate it behind a
new General-tab option 'Hide Ascension quest progress lines' (default
off) so Questie no longer modifies tooltip lines it does not own by
default. Existing installs read the unset option as off automatically.
Ascension board bounties (e.g. NPC 24 'Outlaw's Contract Board') aren't
reliably flagged repeatable, so IsRepeatable missed them and their ! kept
showing below 60. Add QuestieDB.IsBoardQuest (detects starter NPC/object
names containing 'board', cached per quest); the hide-below-60 option now
hides repeatable OR board quests in both the draw path and ShouldBeHidden.
The ElvUI tooltip style shipped on by default, so Questie restyled every
default WoW tooltip (stripping the border) for users who never asked for
it and don't run ElvUI. Default is now false, plus migration [8] resets
it off once for existing profiles.
Some Ascension turn-ins (crafting/auto-complete) fire QUEST_REMOVED with
no preceding QUEST_TURNED_IN, so the 1s abandon timer runs after
QuestLogCache.RemoveQuest has cleared the quest, making IsComplete return
0 and the turned-in quest get marked abandoned -- its objective pins and
turn-in ? then linger. Capture IsComplete at QUEST_REMOVED time and use
that snapshot in MarkQuestAsAbandoned.
The cutoff hid icons beyond its yard value before checking the minimap's
visible radius, so the default 100 hid icons that were clearly on the
minimap (view radius is 133-466 yd by zoom). Now it only clips icons
outside the visible circle: HBD's pin renderer gates the cutoff on
dist > 1, and QuestieMap FadeLogic raises the effective cutoff to at
least the current minimap view radius via new HBDPins:GetMinimapRadius().
HideAscensionQuestLines kept a questBlockActive flag and hid every
following non-indented line after an objective line until an indented
one. Questie's own Item/NPC/Object ID lines and other addons' additions
(e.g. an item-count overlay) are appended at the bottom of the tooltip,
so they were wiped too. Now only lines matching an Ascension objective
pattern are hidden; trailing lines are left intact.
QuestieLearnerExport:
- Extract _Encode helper to consolidate serialize+deflate+encode
- Add ExportZone(serverKey, zoneId) to export only the learned data
for a specific zone (NPCs/objects with spawns in that zone, plus
their dropped items and related quests) for smaller, faster exports
- Cap ValidateImport at 200k entries to guard against pathological
payloads that could stall the client during merge
- Call SmoothReset after MergeImport so newly imported spawns appear
on the map without requiring /reload
QuestieOptionsDatabase:
- Refresh AceConfigRegistry after import so Database tab stats update
immediately (previously required /reload or opening Options)
- Add Export Current Zone button tied to ExportZone()
Hardens the learner data-ingestion paths against malformed/partial data
across NPC/object/item/quest types:
- _ValidateLearnedSpawnData now validates object spawn coordinates (key 4)
in addition to NPC spawns (key 7); object coords were previously
unvalidated. Extracted a shared _ValidateCoordTable helper.
- _ApplyIncomingNetworkMerge coordinate merge skips malformed zone keys and
coordinates (non-number / out-of-range) per entry instead of erroring,
and guards the item drop-list merge against non-number NPC ids.
- The live comms-merge flush isolates each broadcast in a pcall so one
malformed entry can't abort the batch or break the live-update loop;
the post-merge InjectLearnedData is also guarded.
Live Learn* entry points already validate id/type. selene 0 errors;
busted 145 successes / same 7 pre-existing failures.
Importing learned data merged from several players must not corrupt the
store. Fixes:
- ValidateImport prefix check was a no-op: parsed
as (always false), so non-Questie strings were
never rejected. Now a proper inequality check.
- MergeImport now ensures the learner stores exist (fresh profile can
import), merges each entry synchronously via _ApplyIncomingNetworkMerge
(validates structure, only adopts missing fields, never overwrites good
local data), wraps each entry in pcall so one malformed entry is
skipped/counted rather than aborting the whole import, and returns
accurate merged/skipped/rejected counts.
- Synchronous merge also fixes InjectLearnedData previously running before
the async-queued merges landed.
selene 0 errors; busted 145 successes / same 7 pre-existing failures.
Players who run fully zoomed-out minimaps need a larger visibility radius
since quest objective spawns can be far apart. Raise the slider max from
200 to 1000 (yards). Default (100) and minimum (25) unchanged.
Reverts the previous approach of stripping char.complete (which mutated
completed-quest data). Correct rule: a quest in the player's log is active
and should show its turn-in location regardless of the completed flag.
- AddFinisher now trusts the live quest log: if the quest is in
currentQuestlog and not failed, the '?' finisher draws regardless of the
(possibly stale, e.g. prior-prestige) char.complete flag. No completion
data is modified. Reverts the AcceptQuest and QUEST_QUERY_COMPLETE strips.
- Learner: OnTargetChanged now learns quest-giver/turn-in NPC spawns
(it previously only cached the GUID), so targeting a turn-in NPC records
its location. OnQuestComplete/OnQuestTurnedIn fall back to the 'target'
unit when the 'npc' gossip unit is already cleared, so the finisher NPC
is reliably learned on turn-in.
selene 0 errors; busted 145 successes / same 7 pre-existing failures.
A quest completed in a prior Ascension prestige stays in char.complete.
On re-accept it is active in the log again, but the stale completion flag
was never cleared — and AddFinisher only draws the turn-in '?' when
not char.complete[questId]. So the finisher was suppressed and the quest
showed '(Complete)' with stale objective text while standing at the
turn-in NPC (e.g. Aggression 8334 at Lanthan Perilon 15281).
An active in-log quest is now kept out of char.complete:
- QuestieQuest:AcceptQuest clears char.complete[questId] on accept.
- The async QUEST_QUERY_COMPLETE handler also strips any quest currently
in QuestiePlayer.currentQuestlog, so the server's completed list can't
re-flag a re-accepted quest.
Restores the turn-in '?' and normal objective tracking. selene 0 errors;
busted 145 successes / same 7 pre-existing failures.
#7: Completed quests kept showing as available '!'. The server completed-
quest list arrives async via QUEST_QUERY_COMPLETE, often after available
quests were first drawn. Recalculate available quests once char.complete is
populated by that event so completed quests are removed (also clears the
already-completed subset of #8).
#9: An accepted quest's available '!' could linger on the minimap until
/reload. UnloadQuestFramesByDataType unloaded the frame but left its name in
questIdFrames and _G; it now removes those references so the icon is torn
down immediately on both map and minimap.
#10: Added 'Hide repeatable quests below level 60' (Icons tab, off by
default) to hide repeatable available quests (e.g. the Ascension Callboard)
from map/minimap until level 60. Enforced in _DrawQuestIfAvailable and
ShouldBeHidden so existing minimap pins are removed too; reappear at 60.
Lint: selene 0 errors. Tests: 145 successes / same 7 pre-existing failures.
The previous ElvUI-style border was too thick and uneven (thicker at the
top): it used Interface\ChatFrame\ChatFrameBackground with edgeSize = 1 UI
*unit*, which renders several physical pixels thick at the user's UI scale,
and a 1x1 texture that samples unevenly along edges.
Now copies ElvUI/Core/Toolkit.lua SetTemplate exactly: the blank texture
E.media.blankTex (Interface\Buttons\WHITE8X8) for bg + edge, and edgeSize =
E.mult (one physical pixel = (768 / screenHeight) / uiScale) so the border
is a true even 1px. Colors unchanged (ElvUI defaults the user runs):
backdropfadecolor {0.06,0.06,0.06} @ colorAlpha 0.8, bordercolor black.
Factored into QuestieTooltips:ApplyElvUISkin so the secondary learner frame
and the default tooltips share one implementation.
The InjectLearnedData purge loop was deleting entire NPC entries from
Questie.dbLearner.global.npcs whenever data[7] (spawns) was empty,
even if the entry still had a name, home zone, recorded kills, or
quest references. This caused learner data to silently disappear on
/reload for NPCs that had been learned but never killed in a position
the learner could record (e.g. party-kill position attribution fix
now passes nil coords for uncredited kills).
Now only purges when ALL of name, zone, kills, and quest references
are missing. Entries with other useful state get data[7] set to nil
instead so the row stays.
- ElvUI tooltip style: new 'ElvUI tooltip style' option (General tab, on by
default) skins GameTooltip/WorldMapTooltip/ItemRefTooltip/shopping tooltips
and the secondary learner frame with ElvUI's transparent flat look (dark bg
+ thin 1px border) when ElvUI is not installed. Corrected the secondary
frame fallback that used the chunky WoW border. No-op when ElvUI is loaded.
- Source attribution now shows ONLY inside the secondary learner tooltip when
'Use secondary learner tooltip' is enabled; removed from the main NPC/object/
item tooltip and gated off entirely when the secondary tooltip is disabled
(map-pin source gated the same way).
- Fixed learner-learned pins mislabelled 'AscensionDB': GetPinDataSource is now
mode-aware and returns 'Learner' in learner mode when the entity has a learner
record, even if AscensionDB also curates it (curated coords are discarded by
GetNPC/GetObject in learner mode anyway).
Test-neutral (145 successes / same 7 pre-existing failures + 1 error).
Quest-type filters (Available Dungeon/Raid/PvP/Repeatable/Event quests and
other ShouldBeHidden rules) were honored on the world map but not the
minimap. At toggle time HideQuestIcons FakeHides both map and minimap
filtered icons, but the minimap icon's per-frame FadeLogic re-showed any
hidden icon once in range via 'elseif self.hidden then self:FakeShow()',
undoing the filter on the minimap only (the world icon has no FadeLogic).
FadeLogic now re-checks ShouldBeHidden before re-showing, in both the
world-icon and manual-icon minimap fade paths, so filters apply to both.
Two crashes reported in #15 on Elune (1.6.3):
- TrackerUtils:IsVoiceOverLoaded only verified the VoiceOver addons were
loaded, not that VoiceOver.QuestOverlayUI.questPlayButtons exists. Some
VoiceOver builds expose a QuestOverlayUI without that table, so
UpdateVoiceOverPlayButtons and SetAllPlayButtonAlpha crashed with
'attempt to index field questPlayButtons (a nil value)'. Now verified in
IsVoiceOverLoaded, which all play-button call sites gate on.
- AceGUIContainer-TreeGroup crashed indexing a nil AceGUI.tooltip when a
conflicting addon registered a broken AceGUI-3.0 core (version 1.#INF)
that won LibStub but never created the shared tooltip frame. The tree
button handlers now lazily recreate it; widget version bumped 47->48 so
the fixed widget wins registration.
The 'Use secondary learner tooltip' option's off-path appended learner
spawn/kill lines directly to the main GameTooltip. The toggle now gates
the data entirely: on = shown in the separate secondary frame, off = not
shown anywhere. Learner spawn/kill data is never inline in the main NPC
tooltip under any setting.
Removed the now-unused _AddTooltipSeparator helper and updated the option
description.
Re-adds the 'Show data source' tooltip option (General tab, default off),
but accurate this time. The previous version was removed because it
guessed the source from the global data-source mode (showing Learner when
data was AscensionDB, etc.). This tags each pin with its real provenance
at creation and reads that tag.
- QuestieDB.GetPinDataSource(entityType, id, spawnData): resolves
Learner (per-spawn isLearned or learner record), AscensionDB (curated
ascensionOverrideKeys override), or base Questie DB. Never guesses.
- Objective pins tagged per-spawn in _DetermineIconsToDraw; available/
finisher pins defaulted by quest in DrawWorldIcon; manual notes tagged
Townsfolk in DrawManualIcon.
- World-map pins read the per-pin tag (MapIconTooltip); unit/object/item
hovers derive per-id at the render layer (TooltipHandler via
QuestieTooltips:GetDataSourceLine). Comms appended via KeyExists.
- No line shown when source is genuinely unknown (never misleading).
Hovering an NPC right after turning in one of its associated quests
spammed a debugstack trace in DEVELOP mode: the learner objective-
correlation block in GetTooltip called QuestLogCache.GetQuestObjectives
for a quest no longer in QuestLogCache (which gracefully returns {} but
logs the stack at line 306).
Guard the NPC and object correlation loops on
QuestiePlayer.currentQuestlog[questId] so live objective progress is only
looked up for quests the player is currently on. Not a crash and no
functional change for active quests.