Quests assembled from a Learner entry or a questDataOverrides entry that
never captured every field reach the tracker with nil fields, since GetQuest
copies rawdata key by key. Two of those show: a nil name printed as the
quest id, and a nil zoneOrSort that sent _GetZoneName down its very first
line, `if not zoneOrSort then return "Unknown Zone" end`, before it could
consult the quest log header the earlier fix added. Those objects are cached
for the session, so neither repaired itself.
GetQuest now fills a missing name from the quest log and defaults zoneOrSort
to 0, the value every caller already reads as "no zone on file" -- and which
some of them require, `quest.zoneOrSort > 0` erroring outright on nil.
_GetZoneName treats nil the same way rather than short-circuiting, which
also stops a nil quest from labelling its group Unknown Zone under the sort
modes that do not group by zone at all.
The tracker asks the quest log for a title before printing an id, so quests
already cached without a name come out right too, and the live-fallback
builder stops discarding the override data it just looked up.
Quests with no QuestieDB entry get a fallback object built from the quest
log, and three things were wrong with it.
Its objectives carried the leaderboard line in a `text` field, but the
tracker's objective loop skips any objective without a `Description`, so
those quests drew a title and nothing under it. Split the line into a
description and its counts instead, and set the same `Index`/`Completed`
fields a DB objective carries.
The object was then cached for the session and only rebuilt when it had no
zone info, so its counts stayed at whatever the log said when the quest was
first seen. `IsComplete` had the same problem one level down: it closed over
the completion flag read at build time, so the quest never went (Complete).
Both now re-read the log on every draw, in place, so the objective tables
the drawn lines hold stay valid.
Refreshing per draw needs the quest's log index, so the walk that already
builds the header map records it too.
Ascension's special quests are finished by the server the moment their
objectives are met, and one of them stayed in the tracker for the rest of
the session: currentQuestlog is only as good as the removal events that
maintain it, and nothing landed for that quest.
The tracker now checks the quest log itself, which it already walks once
per draw for the zone headers, and skips anything that is no longer in
it, dropping the fallback object built for it as well. Skipped rather
than pruned, so a redraw that catches the log mid-refresh does not throw
away state Questie is about to want back.
Three things on the event side that let it get that far:
- CleanupRemovedQuestsFallback now also runs after a full quest log scan.
UpdateAllQuests only inspects quests still in the log, so for as long
as something kept asking for full scans, nothing looked for removals.
- A removed quest counts as completed when the server has it flagged
complete. QuestieDB.IsComplete cannot answer for a quest the database
has never heard of, so these were filed as abandoned instead.
- The removal scan type-checks the quest id before comparing it, so a
stray string key cannot error out the pass for every other quest.
Ascension files its main quest chain under a header of its own,
"Ascension Main Quest", which exists in no zone table. The tracker fell
back to the quest's zoneOrSort, and for anything the Learner recorded
that is the zone the quest was picked up in -- so the whole chain showed
up under "Red Cloud Mesa".
A header that resolves to no area is a category the server invented, and
the client's own grouping is the only thing that knows about it, so use
it. Headers are now mapped in a single pass per draw instead of a walk of
the quest log per quest.
The button shared the quest gutter with the collapse button, the quest
item buttons and the zone header text, so anything past the default size
was clipped by the tracker edge or drawn on top of its neighbours.
Give it a gutter of its own instead. GetSuperTrackMarginReserve feeds
questMarginLeft, which every layout and width calculation already builds
on, and the quest item buttons and zone labels are shifted by the same
amount. The button then anchors flush left of the line and the tracker
widens to match, so nothing overlaps at any size. Raise the size cap to
70 now that it fits, and drop the hover tooltip.
Also stop relying on the SetSuperTrackedQuestID hook as the only source
of truth. It never fires while the player is a ghost -- the corpse arrow
takes over the marker -- and it has not fired yet on a login or reload,
which left the tracker with no idea what was tracked in both cases. The
client is now asked directly: the watch frame POI buttons flag their own
selection, the map pins say it through their art (the selected variant
sits half a texture above the normal one), and the quest log selection
answers for the login window when no pin is styled yet. Selection calls
are hooked for the same reason, so clicks repaint while dead, and the
requests are coalesced because callers select a quest log entry and
restore the previous one a line later.
Ascension's client backports retail's floating objective marker. This adds
a button to each tracker quest line that points the marker at that quest,
mirroring the quest pin the world map draws for it.
Supertracking is a slave of the map's quest selection: both the map and the
Blizzard watch frame funnel through SelectQuestLogEntry, and calling
C_SuperTrack.SetSuperTrackedQuestID directly only moves the marker until the
next map interaction stomps it. So the button clicks the same POI frame the
client clicks -- the watch frame button when one exists, otherwise the map's
quest frame.
The client dropped GetSuperTrackedQuestID, so the current quest is read by
hooking SetSuperTrackedQuestID instead. Every path ends up there, including
the automatic re-pick on zone change, so the highlight cannot fall out of
sync with tracking changed outside the addon. Caching what we last set would
have gone stale the moment the player used the map.
The button mirrors the pin's own textures rather than picking atlas cells, so
the digit, the "?" completed quests use and the selected variant all follow
whatever the client draws. Quests with no pin get no button, and the map's
POI frames are built on demand so buttons appear without opening the map.
Adds trackerShowSuperTrackButton and trackerSuperTrackButtonSize.
Quests with no static DB entry (e.g. Ascension custom quest 175206) made
GetColoredQuestName bail out early on a nil name lookup, before it ever
reached the (Complete)/(Failed) suffix logic. The tracker's existing
fallback for that case never added the suffix either, and it computed
level via QuestieLib.GetTbcLevel (static-DB-only), which silently defaults
to level 1 and then gets scaled from that wrong base by Ascension's level
scaling. Since these quests also auto-collapse once complete (hiding the
tracker's other "Quest Complete!" indicator line), the title was the only
place that could show completion status, and it was silently swallowing it.
- QuestieTracker.lua: the "no DB name" fallback branch now appends
(Complete) under the same collapseCompletedQuests/isMinimizable rule as
the normal path, and uses the live quest object's own level instead of
the static-only lookup.
- QuestieQuest.lua (PopulateQuestLogInfo): re-syncs quest.level from a live
GetQuestLogTitle scan every update, since QuestieDB.GetQuest caches quest
objects permanently and QuestLogCache never tracked level at all.
- TrackerUtils.lua (GetCompletionText): guards the Description[1] fallback
against quests that have no top-level Description array, which was
throwing and aborting that quest's tracker render entirely.
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.
- 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.