Quests (Advanced)
quests
Quests are pre-authored story objectives that start hidden and become visible only when a trigger fires quest-init. Every quest needs at least one trigger pointing to it - quests with no trigger are permanently unreachable.
"Quests that can be used by story starts or triggers"
- Editor location
- World → Advanced → Quests
- Editor type
- JSON + ADD ITEM
- API endpoint
-
/api/sections/quests.json/api/sections/quests.md - Size limits
-
No character-length caps for this section. See the validation reference for the complete table.
Schema
{
"quests": {
"<key>": {
"name": "string",
"questSource": "string",
"questStatement": "string",
"mainObjective": "string",
"completionCondition": "string",
"conclusive": "boolean",
"questDesignBrief": "string",
"detailType": "basic",
"spatialRelationship": "existingLocalArea | newLocalArea | nearbyNewLocation | distantNewLocation | existingLocationNewAreas"
}
}
}
Example
{
"The Missing Documents": {
"name": "The Missing Documents",
"questType": "side",
"questSource": "Archivist Sera Vane",
"questStatement": "Side quest. Vane is a guild archivist who has identified a set of classified records being quietly prepared for destruction — documents that contradict the official history of a major land dispute. She cannot retrieve them herself without triggering a mandatory audit of her clearance. She needs an outside agent to enter the restricted archive during the next scheduled maintenance window and remove the records before they are incinerated.",
"mainObjective": "Recover the classified documents from the guild archive and deliver them to Vane's contact at the docks.",
"completionCondition": "The documents have been physically delivered to the dock contact and confirmed received.",
"detailType": "detailed",
"questLocation": "The Capital",
"questDesignBrief": "Vane is trusting the player with materials the guild would destroy. Frame this as a genuine trust exchange - she cannot do this herself. The documents matter; do not reduce the retrieval to a single skill check. Let the risk of exposure feel real."
},
"The Final Reckoning": {
"name": "The Final Reckoning",
"questType": "main",
"questSource": "The Resistance",
"questStatement": "Main quest — final arc. The evidence gathered across the investigation is complete: financial records, witness depositions, and the incriminating vault documents. The Resistance has secured access to the tribunal hall and a sympathetic magistrate willing to hear a formal case. The player must present the full evidence cache at a scheduled tribunal session and hold the case together under cross-examination by council-appointed advocates.",
"mainObjective": "Bring the full evidence cache to the tribunal hall and formally present the case against the council.",
"completionCondition": "The evidence has been presented at the tribunal and the verdict delivered.",
"detailType": "detailed",
"questLocation": "The Tribunal",
"questDesignBrief": "The primary ending. The tribunal is the culmination of everything gathered across the scenario. Give it weight - let the verdict land with gravity. Do not compress the resolution."
}
}
Fields
completionCondition
Required. Missing it causes a deeply nested Zod error like quests.Name.1.0.0.completionCondition.
Detailed quests auto-generate a completion trigger from completionCondition. Basic quests need manual triggers. If completionCondition is empty, no auto-trigger is created for either type. (Documented in the upstream quests skill.)
detailType
Determines which location field is required and how the AI handles quest location:
detailType
|
Location source | What the AI does |
|---|---|---|
"detailed"
|
questLocation (required) — exact pre-built location name |
Quest is pinned to that location; AI generates quest content there |
"basic"
|
spatialRelationship (required) — spatial hint enum |
AI generates a location on the fly based on the spatial hint |
Valid detailType values: Only "basic" and "detailed". "brief" is not valid — using it causes a Zod error listing every expected field. The error message is misleading (it looks like the whole quest schema is wrong) but the root cause is always the invalid detailType string.
questLocation
Required when detailType is "detailed". Must be a location name, not a region name. Must exactly match a key in locations
— a specific location display name like "Capital City Docks", not its parent region name like "The Capital Region". Region names cause “Invalid questLocation” warnings. Always use the specific location, not its parent region.
spatialRelationship
Required when detailType is "basic". Codec enum with five accepted values:
existingLocalArea | newLocalArea | nearbyNewLocation | distantNewLocation | existingLocationNewAreas
What each tells the narrator to construct: existingLocalArea - the quest stays in the current area (no travel needed); newLocalArea - moving to a new part of the current location that didn’t previously exist (e.g. a hidden basement); nearbyNewLocation - travel within the same region, framed as a short trip; distantNewLocation - a journey to a different region or far-off part of the world; existingLocationNewAreas - returning to a known location and discovering entirely new sections of it.
For
basicquests, useexistingLocalArea(or make the questdetailType: "detailed"with aquestLocation). The location-generating valuesnearbyNewLocationanddistantNewLocationresolve a new location relative to the player’s current position, which can fail when the quest is accepted — the engine aborts with “Failed to accept quest”. This bites starting quests (accepted at spawn, before any movement) and arc/chained quests offered before the player has travelled. Anchor the quest at the player’s area and let outward travel emerge through play; reserve named destinations fordetailType: "detailed"+questLocation.
questStatement
In practice carries most of the AI guidance load for individual quests — not just “the situation that creates the quest” but the full scene context: who is involved, what the player must do, where the encounter happens, and how success is judged. A well-written questStatement runs 100–500 characters. For authored quest chains, many authors open questStatement with a category label on its own line (Premade Questline: Arc Name, AI Generated Quest) before the narrative setup paragraph — this helps the AI understand the quest’s origin and treat it accordingly.
Note:
questStatementand the globalstorySettings.questGenerationGuidancework as a general-to-specific pair. The global guidance carries world-wide quest tone so any quest feels like it belongs in the scenario;questStatementcarries the mission-specific context so the objective lands with the right weight.questDesignBriefadds tone and feel guidance on top of that when the quest’s emotional register is non-obvious from the other fields.
questDesignBrief
Optional string — authoring notes about how the quest should feel and be run. Not player-visible. Include it for quests where the tone or pacing is non-obvious from the other fields alone.
"questDesignBrief": "Direct confrontation with the mastermind at their stronghold. They are willing to negotiate - this should feel like a revelation, not an automatic fight. No violence unless the player chooses it. Their account should answer questions and raise new ones."
questType
Extra-codec string. Category label used by the AI to frame the quest in the journal and in narration. Common values: "main", "side", "task", "investigation", "defense", "infiltration", "progression". Not in the formal schema, but widely used and present in the editor UI. Include it on every quest.
npcs (extra-codec)
Array of strings. NPC name keys central to this quest. Used by the engine to resolve “NPC X is not referenced by any quest” warnings in the editor. List every NPC the player will interact with during the quest. Strings must exactly match keys in npcs
.
description (extra-codec)
Player-facing summary shown in the quest log detail view. One to three sentences describing the situation and what the player needs to do. Different from questDesignBrief which is internal AI guidance only.
Validation gotchas
Warning:
completionConditionis required - omitting it causes a deeply nested Zod error.- The correct trigger effect format for
quest-initis{ "type": "quest-init", "operator": "set", "value": "Quest Name" }-"operator": "set"must be present.questLocationmust be a location name (a key inlocations), not a region name. Region names produce “Invalid questLocation” warnings.detailTypeaccepts only"basic"and"detailed"-"brief"is invalid.
Quest lifecycle
Status flow
Hidden → (trigger fires quest-init) → Available → Accepted → Phase 1: goToLocation
(move to the quest’s region/location) → Phase 2: goToArea
(move to the specific area within that location) → Phase 3: completeObjectives
(player completes mainObjective) → Completed.
From Available the player may also reject the offer (→ rejected) or the quest may expire. From Accepted the player may abandon (→ abandoned).
Valid quest statuses: hidden, available, accepted, completed, abandoned, rejected, expired.
Expiry conditions
From available state, a quest expires when:
- Expiry tick reached (3 ticks after offer)
- Party leaves the location where the quest was offered
- Quest giver dies, becomes incapacitated, or is no longer near the party
Acceptance and rejection are immediate — there is no pending state between offer and decision.
Quest chains
Use a quests-completed trigger condition to detect completion, then fire quest-init for the next quest.
acceptQuest UI prompt
When a quest becomes available, the engine surfaces an accept prompt to the player as a UI element after the turn ends — accepted quests are tracked in the journal (top-left in the game). Use quest-init triggers with story conditions for quest discovery logic rather than relying on prose dialogue.
Trigger naming convention
Use the pattern {questId}_objective or {questId}_objective_N (e.g. the_missing_documents_objective, the_missing_documents_objective_2) to name objective-phase triggers consistently. Triggers named with this pattern are automatically filtered out of the active pool while the quest is unaccepted or abandoned — they will not fire unless the quest is in an accepted state.
Authoring tips
Coverage requirement
Every quest must have at least one trigger with a quest-init effect pointing to it, or it will never become available to the player. Quests without triggers remain permanently in the Hidden state — they exist in the data but can never be discovered or accepted. This is the most common cause of “quests not showing up.” Ensure 100% coverage: one trigger per quest at minimum.
Quality checklist
questStatement— reads as a briefing: who, what, where, why, and how success is judged. One sentence to a full paragraph depending on quest complexity. For authored quest chains, consider opening with a category label (Premade Quest,AI Generated Quest) on its own line before the narrative setup.mainObjective— starts with an imperative verb. The engine parses this to evaluate completion.completionCondition— write what “done” looks like in plain language. Be specific.detailType: "detailed"+questLocationfor pre-built locations;detailType: "basic"+spatialRelationshipfor AI-generated locations.
Discovery pattern (first quests at a location)
- Arrival trigger (
start_[location]) sets scene and writes a boolean flag — noquest-init. - Discovery trigger (
discover_[quest_slug]) checks the flag + astoryAI condition (“has the player spoken with the quest-giver?”) → firesquest-init. - The quest appears in the player’s journal only after they have organically encountered the hook.
Chain pattern (multi-step storylines)
- Quest A surfaces via the two-step discovery pattern above.
- Quest B trigger has condition
quests-completed contains "Quest A"— fires only after A is done. - Quest C trigger chains from B in the same way.
This creates a natural investigation/escalation arc without the player being handed everything at once.
Encounter quests
For encounter/spawn-able enemies: create one quest per enemy faction with questSource: "Regional Danger". These quests don’t need complex objectives — they serve as AI context for encounter spawning.
NPC reference warnings
The editor shows “NPC X is not referenced by any story start or quest” for NPCs that have no structural linkage in the scenario. The quest schema has no built-in NPC linkage field — questSource is intentionally a plain string. To resolve these warnings, add every NPC to the npcs
array of at least one quest. For enemy/encounter NPCs, create dedicated encounter quests (questSource: "Regional Danger") with an npcs
array listing the enemies. These quests give the AI context for encounter spawning and resolve the warnings entirely.