Quester
Provides quest interaction and management functionality.
Functions
core.quester.get_quest_state(quest_id: number) -> number
Returns the quest state for the specified quest.
Quest States:
-1- Not available0- Available1- In progress2- Completed
core.quester.get_quest_progress(quest_id: number) -> table | nil
Returns a read-only view of a quest's completion requirements and your live progress, built from the client's loaded quest data. Returns nil if the quest has no completion demand (an unknown quest, or one with no requirements).
Returned table:
id(number) — the quest id.name(string) — the quest's display name.state(string) —"available","in_progress","complete", or"not_available".objective(string) —"kill","collect","reach","talk","condition", or"unknown".target_npc(number | nil) — the turn-in / talk NPC.target_map(number | nil) — the destination map (for"reach"steps).min_level/max_level(number | nil) — the level range required to accept the quest.items(table) — item-collection requirements, each{ id, need, have }.mobs(table) — kill requirements, each{ id, need, have, order }(explained below).conditions(table) — record-based requirements, each{ key, need, have, cond }(explained below).
How kill requirements work
Kill quests carry a dedicated mob list. Each entry is one monster: id is the monster id, need is the required kill count, have is your live count (updated by the server on every kill), and order is the quest step the requirement belongs to (multi-step quests gate later entries behind earlier ones; single-step quests use 1 throughout).
{ id = 8220008, need = 200, have = 37, order = 1 }
-- "kill monster 8220008 two hundred times; you're at 37."How conditions work
Separately from kills, quests can require record conditions — scripted flags the game writes during cutscenes, events, or story progression. key names the record, need is the target, have is the current value, and cond is one of "==" / ">=" / "<=":
{ key = "bh3", need = 1, have = 0, cond = "==" }
-- "the record bh3 must equal 1; it's 0" — advance by playing the story, not by grinding.A handful of quests express kills as record conditions keyed by a monster id (a 6–8 digit numeric key) — the objective is still classified "kill" when that happens. A few event quests compare date stamps; those conditions carry a 14-digit timestamp in need.
Examples
Dump everything about a quest:
local q = core.quester.get_quest_progress(3301)
if q then
core.log(q.name .. " [" .. q.objective .. "]")
for _, it in ipairs(q.items) do core.log((" item %d: %d/%d"):format(it.id, it.have, it.need)) end
for _, m in ipairs(q.mobs) do core.log((" mob %d: %d/%d"):format(m.id, m.have, m.need)) end
for _, c in ipairs(q.conditions) do core.log((" %s %s %d (have %d)"):format(c.key, c.cond, c.need, c.have)) end
endCheck whether a quest is ready to hand in (all items, kills, and conditions satisfied):
local function is_ready(quest_id)
local q = core.quester.get_quest_progress(quest_id)
if not q then return false end
for _, it in ipairs(q.items) do
if it.have < it.need then return false end
end
for _, m in ipairs(q.mobs) do
if m.have < m.need then return false end
end
for _, c in ipairs(q.conditions) do
local ok = (c.cond == "==" and c.have == c.need)
or (c.cond == ">=" and c.have >= c.need)
or (c.cond == "<=" and c.have <= c.need)
if not ok then return false end
end
return true
endAuto-complete a kill quest when it's done:
if is_ready(quest_id) then
local q = core.quester.get_quest_progress(quest_id)
if q and q.target_npc then
core.quester.complete_quest(q.target_npc, quest_id)
end
endcore.quester.start_quest(npc_id: number, quest_id: number) -> boolean
Attempts to start the quest with the specified NPC. Check quest state first with get_quest_state().
Returns: true if the request was sent, false if the NPC is present on the current map but the player is out of interaction range.
If the NPC isn't on the current map, the call still proceeds — this supports auto-complete flows that don't require a live NPC. Proximity is only enforced when the NPC is actually spawned.
Proximity is checked, not corrected. Position the character within range before calling — this function will not teleport you to the NPC.
core.quester.complete_quest(npc_id: number, quest_id: number) -> boolean
Attempts to complete the quest with the specified NPC. Check if completable first with can_complete_quest().
Returns: true if the request was sent, false if the NPC is present on the current map but the player is out of interaction range.
If the NPC isn't on the current map, the call still proceeds — this supports auto-complete flows that don't require a live NPC. Proximity is only enforced when the NPC is actually spawned.
Proximity is checked, not corrected. Position the character within range before calling — this function will not teleport you to the NPC.
core.quester.can_complete_quest(npc_id: number, quest_id: number) -> boolean
Returns true if quest requirements are met and can be completed.
NPC Dialogue Selection
The quester uses a queue system for handling NPC dialogue choices and text inputs.
For full dialog control (reading dialog text, inspecting choices, conditionally responding), use the on_dialog callback instead. It fires before the queue system and lets scripts intercept, respond to, or block dialogs dynamically.
core.quester.queue_npc_selection(selection: string)
Enqueues a dialogue option substring. When the NPC dialogue appears with auto NPC enabled, the option containing this substring will be selected. For text input prompts, the queued string will be used as the answer.
core.quester.clear_npc_selection()
Clears the entire NPC selection queue.