Completed objectives could leave their map/minimap pins on screen until
turn-in. Pin removal relied solely on _UnloadAlreadySpawnedIcons, which
walks objective.AlreadySpawned; that table desyncs from the live frames
after learner spawn-list invalidation or complete->abandon->reaccept
cycles, so when reset to {} the frames leaked.
Add QuestieMap:UnloadQuestFramesForObjective(questId, objectiveIndex)
which unloads frames off the map's own questIdFrames registry by matching
frame.data.ObjectiveIndex, and call it from every completion path in
PopulateObjective. Restricted to positive standard-objective indices;
SpecialObjectives (sentinel index 0) keep using AlreadySpawned.
Adds a print() block in QuestieMap.utils:SetDrawOrder, gated by
_G.QuestieDebugPins. Dumps frame name, parent (QuestieFrameGroup or
Minimap), frame level, strata, shown/hidden state, and anchor point.
Used to diagnose why minimap pins appear on the wrong layer (behind
border or terrain texture) — the trace fires before SetParent /
SetFrameStrata / SetFrameLevel so the post-call result can be compared
to the pre-call printed values.
Default state: GATE IS OFF. Zero runtime cost in production. All API
calls defensive with tostring() and parent.GetName fallbacks.
Previously DrawWorldIcon and DrawManualIcon both set floatOnEdge=false
for uiMapId 1241, forcing icons to always show regardless of distance.
This caused pins to render at minimap center when near a spawn, making
them appear to orbit/follow the player as they rotated.
The zone->world coordinate pipeline was verified correct: zoneW matches
dataW exactly for 1241 icons, and playerW is in the same coordinate
space. The problem was purely the floatOnEdge=false behavior combined
with the icon being essentially at the minimap center (1% of radius).
Enabling floatOnEdge=true lets the standard edge-floating path handle
1241 pins like every other zone: icons clamp to the edge when far,
slide along the rim when approaching, and occupy their correct angular
bearing from the player rather than sitting at dead center.
- Fix: isSunstrider block in _MergeSpawnEvidence now checks IsAscensionProtected
before writing learner data to npcDataOverrides. Without this guard, each Mana
Wyrm kill overwrote AscensionDB's z1241=5 data with learner z3431 coords.
- Fix: Clustering disabled for zone 1241 (Sunstrider Isle) in _DrawObjectiveIcons
so all 5 AscensionDB spawn pins display individually instead of collapsing to 2.
- Fix: Ghost pin loop in AvailableQuests.lua -- 'while frames[i]' was iterating a
string-keyed table with a numeric index (never iterated). Changed to pairs().
- Fix: NormalizeSpawnZoneKey now uses ZoneDB.areaIdToUiMapId for all zones so
learner evidence is stored under map IDs (e.g. 1241) not area IDs (e.g. 3431),
matching AscensionDB's key space. Applied in LearnNPC and _StoreGuidSpawnEvidence.
- Fix: isSunstrider detection in _MergeSpawnEvidence updated from hardcoded
zoneId==3431 check to IsSunstriderNativeZone() since zone IDs are now normalized
to map IDs at storage time.
- zoneDB: remap areaId 3431 → uiMapId 1241 (Sunstrider Isle) so quest 8335
pins render on correct map instead of Eversong Woods (1941)
- compat/HBD: remove 1241→1941 redirect (Sunstrider pins now handled by zoneDB)
- compiler: QuerySingle override check skips empty tables (next() guard) so
spawn data overrides don't fall through to nil base DB values
- MapIconTooltip: nil guards for minLevel/maxLevel to prevent crashes
- Map/QuestieMap: remove stale 1241→1941 redirect comment