ProcessQueue() references the global 'profile' at line 366 without
declaring it locally, causing 'attempt to index global profile (a nil)'
when called from the timer queue. All other functions in this file
declare local profile = Questie.db.profile before use.
Use tracker wrapping helpers that fall back when Ascension font strings do not expose GetNumLines or GetWrappedWidth.
(cherry picked from commit c9b7de2a636ca918c2549a13de87a688861c831f)
- Swap single-frame SetRotation arrow back to 9x12 sprite sheet (512px TGA).
- Recompute cell UVs from bearing each frame via modulo math.
- Keep arrowold.tga on disk; routing to it comes in follow-up commit.
- Add /radiusdebug slash command. Dumps zoom, shape, size, scale,
Minimap:GetViewRadius() (3.3.5a), C_Minimap.GetViewRadius()
(Retail/WoTLK), CVars, fallback radius (outdoor/indoor), active
pin count, and 8 sample pin metrics (screen offset, normalized
radius, edge error). Includes an interpretation block.
- Add /terraindebug slash command. Dumps Minimap, MinimapCluster,
zoom buttons, border, backdrop, north tag, compass texture,
mask state, MMHolder, and 5 levels of parent chain. Detects
ElvUI presence and prints interpretation hints.
- All API calls are defensive with pcall/conditional guards and
tostring() fallbacks. Slash commands lazy-load _G.Questie*Debug
so they work even if the function table is updated post-load.
These commands were used during the minimap drift investigation
to verify that radius, scale, and frame hierarchy were not the
drift source. They are invaluable for future regression
investigation and have zero runtime cost when not invoked.
- Refactor button positioning and visibility into _PositionMapButton and
_RefreshMapButtonVisibility helpers. Single source of truth for both.
- WorldMapButton.Initialize now hooks OnShow/OnHide on WorldMapFrame so
the button self-updates when the user opens/closes the world map.
No more manual show/hide calls required from elsewhere in the code.
- Toggle(shouldShow) now persists to Questie.db.profile.mapShowHideEnabled
and calls _RefreshMapButtonVisibility, so the user's choice survives
/reload and is consistent with the world map's current visibility.
- Special-case Mapster offset: -50, -72.3 vs default -50, -40. Without
this, the button overlapped Mapster's UI elements when both addons
were loaded.
- Frame level set to 99 to ensure the button draws above other map
elements.
All helpers are no-op-safe when mapButton is nil. IsAddOnLoaded
('Mapster') is optional — falls through to default offset if Mapster
is not loaded.
- Add local _CountUniqueSpawnPositions helper (counts unique {x, y}
across all zone buckets in a spawn table).
- Gate the prioritizeMyData check on ld.settings.enabled, matching the
Database/QuestieDB.lua fix — when the learner is fully disabled,
the override lookup is skipped entirely.
- Replace the NPC-15274-specific debug print in the monster() spawn
selector with a universal reliability check: the learner data is
only used when CountUniqueSpawnPositions(learnedSpawns) > 1.
This is the consumer-side enforcement of the QuestieLearner cleanup
(commit e71e072). Singleton-position spawn entries are typically the
player's current position captured during quest dialog (accept/turn-in)
rather than real kill evidence. By requiring at least 2 unique
positions, we avoid letting that pollution clobber AscensionDB curated
spawn data.
The NPC-15274-specific debug print was removed — the universal check
replaces it, and the diagnostic it provided is now expressed through
the Questie DEBUG_DEVELOP log line (which still emits when the new
condition is met).
In _CalculateAvailableQuests, when a quest is found in the quest log
(IsComplete ~= -1), explicitly unload any available-quest pin frame
for that questId, remove its tooltip, and clear the cached entry
before returning.
Previously the early-return left stale state behind: the pin frame
and tooltip would persist until the next sweep, causing a brief window
where the same quest was visible as both 'available' (yellow !) on
the map and 'in log' (yellow ?) in the quest log.
The cleanup order is correct: unload frame, then remove tooltip,
then clear cache. narrow scope (only 'available' data type) — does
not affect other pin categories.
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.
Adds a print() block in _Qframe:FakeHide and _Qframe:FakeShow, gated by
_G.QuestieDebugPins. Dumps frame name, shown/hidden state, parent, and
anchor point. Used to diagnose why minimap pins reappear or fail to hide
after zone transitions or anchor re-registration.
Default state: GATE IS OFF. The block is a no-op unless the user
explicitly sets _G.QuestieDebugPins = true. Zero runtime cost in
production. All API calls defensive with tostring() and parent.GetName
fallbacks.
Real bug fixes (no behavior additions that risk regressions):
- LearnNPC: require both spawnX/spawnY AND x/y before accepting a spawn
entry. Previously quest-giver/finisher dialog polluted spawn lists
with the player's current position.
- _MergeSpawnEvidence: respect IsAscensionProtected ownership gate
unconditionally. The 'test mode' comment-out is removed; AscensionDB
curated spawn data is now protected from learner overwrite (fixes
the Sunstrider Mana Wyrm pin regression).
- _PruneSpawnOutliers and PruneLearnedSpawnOutliers: fix broken
next() iteration. The old code used 'coord = next(spawnTable); while
coord do ... coord = next(spawnTable, coord)' which treated the
KEY as the value. For numeric spawn arrays this returned indices
(1, 2, ...) but the code did coord[1] and coord[2] on those indices,
which are nil. The outlier pruning was effectively dead code. Now
iterates with 'coordKey, coord = next(spawnTable)' correctly, sorts
toRemove keys descending for safe table.remove, and compacts numeric
arrays.
- InjectLearnedData: early-exit when learner disabled, strip [7] on
initial npcDataOverrides creation (only _MergeSpawnEvidence should
populate spawns), versioned cleanup that retroactively clears
singleton-position spawn entries (≤1 unique position) from pollution
caused by the prior LearnNPC bug.
Supporting utilities added: CopyWithoutField, CountUniqueSpawnPositions,
NormalizeCoordPair reuse (replaces inline floor(x*100+0.5)/100).
- Add CopySpawnTable and MergeSpawnTables helpers to deep-merge spawn
coordinate lists (zoneId -> {{x,y}, ...}) instead of replacing them
wholesale. Previously an override containing spawns would clobber the
base list, reducing visible pins for any NPC with partial overrides
(Sunstrider Isle calibration, Ascension area-specific fixes, etc.).
- _MergeOverride now special-cases the 'spawns' key to call the merger
with the base spawn table as a fallback when override is empty.
- GetSuppressedNPCs/Objects now check ld.settings.enabled alongside
prioritizeMyData. When the learner is fully disabled, the suppression
pass is skipped entirely (additive and AND-only).
- Use 3.3.5a-native Minimap:GetViewRadius() (instance method) instead of
C_Minimap.GetViewRadius (nil on 3.3.5a) with C_Minimap fallback. Returns
116.67 at zoom 5 instead of the hardcoded 125 from the broken lookup table.
- Replace minimapWidth = (GetWidth()/2) * (mapRadius/155.52) with
minimapWidth = GetWidth() * GetScale() / 2. The new formula yields the
actual half-width of the visible minimap in screen pixels, the correct
multiplier for diffX*minimapWidth when diffX is normalized by mapRadius.
- Comment out (do not delete) all QDMATH / UPDATE entering / ICON debug
blocks as --[[ DEBUG: ... --]] for future regression investigation.
- Remove loaded debug scripts from Questie-X.toc and add to .gitignore
(drift_test, radius_debug, spawn_calibration, etc.). Scripts preserved
in tests/ for reference.
- Add .gitignore entries for tests/ lowercase variant (case-sensitive
on Linux/macOS) and additional debug script patterns.
- Update CHANGELOG.md and docs/changelog.html with fix entry.
- Refresh handoff.md to reflect RESOLVED status and iteration 4 history.
Verified: pins now stay anchored to world positions across all zoom levels
on both Stock UI and ElvUI. Per-frame diffX ~0.35 yards during walking
translates to ~0.21 pixels of pin movement (correct for 1 yard of world
movement).
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.
The uiMapID==1241 branch in drawMinimapPin was an experimental overlay
that ran BEFORE the standard minimap projection and rotation transforms.
It duplicated the projection math while bypassing the rotation matrix,
used a different edge-clamp path, and is the primary suspect for why
pins visually follow the player on Sunstrider Isle.
The standard minimap path (handle rotation -> adapt delta to mapRadius
-> apply shape mask -> float-on-edge or clamp) already handles all
pins uniformly regardless of zone. Removing this experimental branch
lets 1241 pins use the same proven path as every other zone.
Also cleaned up:
- stale lastInstanceId reference in throttled PIN debug trace
- unnecessary data.uiMapID guard in QuestieDebugMinimapPin gate
- Sunstrider-specific minimap debug block in UpdateMinimapPins