# Quests

> Quest database, markers, tooltips, quest levels

Page: https://polestar.guide/docs/contributors/architecture/quests (Polestar docs > Contributors > Architecture)

`addon/Polestar/Quests/` loads the load-on-demand data addon
`Polestar_QuestDB` through `Data.Pack` (≈ 1.3 MB of Lua, ≈ 6.4 MB resident)
at login, and only while `qol.questDB` is on and at least one feature that
needs it is (`QuestDB.IsWanted()`: map/minimap objectives, available quests,
turn-ins, tooltips, nameplates); turning the first one on later loads it then,
and a load refused in combat is retried when combat ends. It fires
`QUESTDB_LOADED`, then `QUESTDB_STARTED`; `QUESTDB_UPDATED` follows every
change to the tracked quest log. Record layouts: `tools/lib/questdb/build.js`.
An entity's spawn clusters (70 yd) cover every known spawn on each map (the
reference data's `pts` and `more`), with no cap on how many.

```lua
Polestar.QuestDB.IsLoaded() / IsEnabled() / IsRunning() / IsWanted()
Polestar.QuestDB.GetQuest(id)  -> { id, title, level, minLevel, races, classes, faction, start = { npc, object, item },
                                    finish = { npc, object }, pre (any-of), preAll, excl, zone, skill, holiday,
                                    objectives = { { kind = "kill"|"item"|"object"|"event", id, count, map, x, y, f } } } | nil
Polestar.QuestDB.GetNpc(id) / GetObject(id) -> { id, name, spawns = { { map, x, y, r (yd), f } } } | nil
Polestar.QuestDB.GetItem(id)   -> { id, name, droppers = { { id, name, chance } }, objects = { ... }, vendors = { { id, name } } } | nil
Polestar.QuestDB.GetItemDroppers(itemID) -> { { id, name, chance }, ... } | nil   -- best chance first
Polestar.QuestDB.GetObjectiveMobs(questID, oi) -> { name, ... } | nil            -- kill target or item droppers
Polestar.QuestDB.CheckAvailable(id, ctx, isDone, isOn, opts) -> ok, reason      -- opts: lowLevel, levelAbove, skillRank
Polestar.QuestDB.EachAvailabilityRef(id, fn) -> needsSkill                       -- fn(q) per quest whose done/in-log state CheckAvailable reads
Polestar.QuestDB.GetAvailableQuests() -> { questID, ... } ; IsAvailable(q) ; WhyUnavailable(q) -> reason | nil
   -- reasons: "eligibility" (faction, race incl. Skyborne high bits, class, holiday), "done", "active", "level"
   -- (minLevel), "grey", "high" (beyond qol.questLevelWindow), "prerequisite", "exclusive", "skill"
Polestar.QuestDB.ObjectivesForNpc(id) / ObjectivesForItem(id) / ObjectivesForObject(id)
                               -> { { q, kind, id, name, cur, max, done, entry = { q, title, ready } }, ... } | nil  -- quests in the log
Polestar.QuestDB.GetMarkers(map [, "objectives"|"turnin"|"available"]) -> { pin, ... }
Polestar.QuestDB.IsGuideQuest(q) -> bool                                         -- in the active guide's current step
```

"Done" comes from `C_QuestLog.GetAllCompletedQuestIDs` (one call per available
scan), else `C_QuestLog.IsQuestFlaggedCompleted` per quest. A scan rechecks every
candidate only after a level-up, a skill change, a filter setting or without the
bulk call; otherwise only the candidates that read a quest whose done or in-log
state moved since the last scan (`EachAvailabilityRef`), plus those needing a
profession skill.

Pins layers: `quests.objectives`, `quests.turnin`, `quests.available`, one pin
per entity spawn cluster and layer (a mob two objectives need carries both
under the higher-ranked glyph: kill > interact > collect > vendor). Objective
clusters at least `MIN_AREA` (12 yd) wide carry their radius as `area`. Markers
and the tooltip/nameplate indexes are rebuilt only when what they show
changed (a quest came or went, got ready or changed title, an objective was
done or undone); a progress count alone only fires `QUESTDB_UPDATED`, since
tooltips and nameplates read counts live. A rebuild reuses the pin tables
the last one kept for the same cluster, with their world position (`c`,
`wx`, `wy`) worked out once, so `Pins.SetLayer` converts only new pins. Look is
applied at publish: while a Polestar guide runs, pins of quests in its current
step (`Engine.GetGuide().steps[Engine.GetStepIndex()].goals[*].quest`, re-read on
`STEP_CHANGED`/`GUIDE_CHANGED`) are 1.3× inside an accent ring and on top;
with `qol.guideDim` every other quest pin drops to 0.6 alpha (`Q.DIM_ALPHA`).

Tooltips go through `Polestar.Hooks` (owner `"quests"`: UnitLines, ItemLines,
ObjectLines, registered only while running) with the suite's quest line,
`Hooks.AddLine(tt, "<Quest>:", "<what> cur/max", quest, textDim | success)`:
"Kill Kobold Vermin 3/10" on the target, "Large Candle 3/8" on a dropper, "3/8"
on the item; quest-starting items get "Starts a quest: <title>".
`Quests/QuestLevels.lua` prefixes "[12]" (and "+" for elite) to quest titles
the client lists without one (gossip, greeting, details; camelot's own log and
tracker already show it, so it adds there only when missing).
(camelot is Forever's game type in Blizzard's UI source: the files the Forever client loads carry `AllowLoadGameType camelot`, and its own overrides sit in `Camelot/` folders.)

Nameplate icons (`qol.nameplateIcons`): a mob an open objective still needs
gets a 16px objective icon (14–20) 3px left of the health bar the player
sees: EllesmereUI Nameplates' unit frame, Plater/ElvUI/oUF, KuiNameplates or
Threat Plates when present, else the shown child of the base plate holding
the largest status bar, else Blizzard's health bar, else the plate itself;
parented to that frame so it follows its fading and scaling. Beside it, left,
a font string of the icon frame (`.count`) shows the progress of the open
objectives with a count above 1 (`Q.ProgressText`, by quest, joined with
" · "), re-read on every `QUESTDB_UPDATED`; hidden when none has one. Every
access is guarded; `Quests.NameplateIcon(unit)` returns the icon and
`Quests.NameplateCount(unit)` the progress shown (tests).

Settings (`qol.*`, Questing → Quests; the markers under Map → Guide & quests →
Quest markers): `questDB`, `availableQuests`,
`questLevelWindow` (0–10, 10 = any; default 5), `lowLevelQuests`,
`mapObjectives`, `objectiveAreas`, `turnInMarkers`, `minimapObjectives`,
`guideHighlight`, `guideDim`, `questTooltips`, `nameplateIcons`, `questLevels`.
The four marker layers (`availableQuests`, `mapObjectives`, `turnInMarkers`,
`minimapObjectives`) and `objectiveAreas` default to off (Map → Guide & quests →
Quest markers); `guideHighlight` only restyles markers those layers draw.

---

Next page: [Gear](https://polestar.guide/docs/contributors/architecture/gear.md) · Every docs page: https://polestar.guide/llms.txt · All docs in one file: https://polestar.guide/llms-full.txt
