Multi-Stage Quests
The Quest Stages system allows creating multi-phase quests where objectives are grouped into sequential stages. When all objectives in the current stage complete, the next stage's objectives appear. <span class="since-badge">v2.9.0</span>
💡 Stages are fully opt-in and backward compatible. Quests without a stages array continue to work exactly as before — no migration needed.
How It Works
A staged quest progresses through phases sequentially. Each stage contains its own set of objectives that must all be completed before the quest advances.
graph LR
S1["Stage 1
Gather"] --> S2["Stage 2
Travel"]
S2 --> S3["Stage 3
Kill Boss"]
S3 --> Rewards["Rewards
Complete!"]- When a quest starts, only Stage 1 objectives are active and visible to the player.
- Once all objectives in Stage 1 are completed, the system auto-advances to Stage 2.
- Stage completion actions (
onStageCompleteActions) fire between stages. - After the final stage completes, the quest's
actionRewardsare granted.
Quest Definition with Stages
To use stages, add a stages array to your quest definition. Each stage object contains its own objectives and optional completion actions.
{
"questId": "alstory:epic_journey",
"questGiverId": "alstory:elder_npc",
"titleLangKey": "alstory:quest-epic-journey-title",
"descriptionLangKey": "alstory:quest-epic-journey-desc",
"stages": [
{
"stageTitleLangKey": "alstory:quest-epic-journey-stage1",
"gatherObjectives": [
{ "validCodes": ["flaxfibers"], "demand": 10 },
{ "validCodes": ["stone-*"], "demand": 20 }
],
"onStageCompleteActions": [
{ "id": "notify", "args": ["Stage 1 complete! Prepare for the journey."] },
{ "id": "addjournalentry", "args": ["alstory:journal-epic-stage1-done"] }
]
},
{
"stageTitleLangKey": "alstory:quest-epic-journey-stage2",
"actionObjectives": [
{
"id": "reach_mountain",
"objectiveId": "reachwaypoint",
"args": ["5000,120,3000", "10"]
}
],
"onStageCompleteActions": [
{ "id": "playsound", "args": ["game:effect/reforge"] },
{ "id": "setplayervariable", "args": ["epic_journey_stage", "2"] }
]
},
{
"stageTitleLangKey": "alstory:quest-epic-journey-stage3",
"killObjectives": [
{ "validCodes": ["alstory:mountain_guardian"], "demand": 1 }
],
"onStageCompleteActions": [
{ "id": "notify", "args": ["The guardian has fallen!"] },
{ "id": "questitem", "args": ["alstory:guardian_heart", "1"] }
]
}
],
"actionRewards": [
{ "id": "giveitem", "args": ["alstory:epic_sword", "1"] },
{ "id": "notify", "args": ["Quest complete! You earned the Epic Sword."] }
]
}Stage Properties
Each object in the stages array supports the following properties:
| Property | Type | Required | Description |
|---|---|---|---|
stageTitleLangKey | string | Yes | Localization key for the stage title displayed in the HUD. |
gatherObjectives | array | No | Array of gather objectives for this stage. |
killObjectives | array | No | Array of kill objectives for this stage. |
actionObjectives | array | No | Array of action objectives for this stage (same format as regular quest objectives). |
onStageCompleteActions | array | No | Actions to execute when all objectives in this stage are completed. |
Objective Types in Stages
Stages support the same objective types as regular quests, organized into three categories:
Gather Objectives
Track item collection. The player must have matching items in their inventory.
{
"gatherObjectives": [
{ "validCodes": ["flaxfibers", "linen-*"], "demand": 15 }
]
}validCodes— Array of item/block codes to match (supports wildcard*).demand— Number of items required.
Kill Objectives
Track creature kills by entity code.
{
"killObjectives": [
{ "validCodes": ["wolf-male", "wolf-female"], "demand": 5 }
]
}validCodes— Array of entity codes to match (supports wildcard*).demand— Number of kills required.
Action Objectives
Action objectives use the same format as regular quest objectives — an array of objective objects with id, objectiveId, and args. See the Objectives page for all available action objective types.
{
"actionObjectives": [
{
"id": "reach_village",
"objectiveId": "reachwaypoint",
"args": ["1200,68,800", "5"]
},
{
"id": "wait_for_day",
"objectiveId": "timeofday",
"args": ["day"]
}
]
}Stage Completion Actions
The onStageCompleteActions array fires when all objectives in a stage are completed, right before the next stage activates. This is useful for narrative progression, sound effects, and state tracking.
"onStageCompleteActions": [
{ "id": "playsound", "args": ["game:effect/reforge"] },
{ "id": "notify", "args": ["Stage complete! New objectives unlocked."] },
{ "id": "setplayervariable", "args": ["quest_progress", "stage2"] },
{ "id": "addjournalentry", "args": ["alstory:journal-stage1-complete"] },
{ "id": "questitem", "args": ["alstory:stage_reward_token", "1"] }
]Common actions used in stage completion:
playsound— Play a sound effect to signal progression.notify— Display a message to the player.setplayervariable— Store progress state for persistence or branching logic.addjournalentry— Add a journal entry for narrative tracking.questitem— Give the player an intermediate reward item.
Localization
Each stage requires a stageTitleLangKey that maps to a localization entry. These keys are resolved from your quest pack's lang files.
{
"alstory:quest-epic-journey-stage1": "Gather Supplies",
"alstory:quest-epic-journey-stage2": "Journey to the Mountain",
"alstory:quest-epic-journey-stage3": "Defeat the Guardian"
}Stage titles appear in the quest HUD alongside the current objectives, helping the player understand where they are in the quest progression.
Backward Compatibility
The stages system is fully backward compatible:
- Quests without a
stagesarray work exactly as before — objectives are defined at the top level. - The
stagesarray is entirely opt-in. You only add it when you want multi-phase behavior. - Existing quest packs require no migration to work with newer versions of the framework.
- You can mix staged and non-staged quests freely within the same quest pack.
Real-World Example
Here is the alstory:last_breath_collect quest — a 3-stage quest where the player gathers ingredients, travels to a ritual site, and performs a ritual.
{
"questId": "alstory:last_breath_collect",
"questGiverId": "alstory:witch_npc",
"titleLangKey": "alstory:quest-last-breath-title",
"descriptionLangKey": "alstory:quest-last-breath-desc",
"stages": [
{
"stageTitleLangKey": "alstory:quest-last-breath-stage1",
"gatherObjectives": [
{ "validCodes": ["alstory:shadowmoss"], "demand": 5 },
{ "validCodes": ["alstory:voidpetal"], "demand": 3 }
],
"killObjectives": [
{ "validCodes": ["alstory:shade_wisp"], "demand": 2 }
],
"onStageCompleteActions": [
{ "id": "notify", "args": ["The ingredients pulse with dark energy..."] },
{ "id": "playsound", "args": ["game:effect/translocate-breakdimension"] },
{ "id": "addjournalentry", "args": ["alstory:journal-last-breath-gathered"] }
]
},
{
"stageTitleLangKey": "alstory:quest-last-breath-stage2",
"actionObjectives": [
{
"id": "reach_ritual_site",
"objectiveId": "reachwaypoint",
"args": ["3200,45,1800", "8"]
}
],
"onStageCompleteActions": [
{ "id": "notify", "args": ["You feel the ground tremble beneath you."] },
{ "id": "setplayervariable", "args": ["last_breath_progress", "at_site"] },
{ "id": "playsound", "args": ["game:effect/reforge"] }
]
},
{
"stageTitleLangKey": "alstory:quest-last-breath-stage3",
"actionObjectives": [
{
"id": "perform_ritual",
"objectiveId": "interactat",
"args": ["3200,45,1800"]
}
],
"gatherObjectives": [
{ "validCodes": ["alstory:ritual_essence"], "demand": 1 }
],
"onStageCompleteActions": [
{ "id": "notify", "args": ["The ritual is complete. The veil thins..."] },
{ "id": "addjournalentry", "args": ["alstory:journal-last-breath-ritual"] },
{ "id": "setplayervariable", "args": ["last_breath_progress", "complete"] }
]
}
],
"actionRewards": [
{ "id": "giveitem", "args": ["alstory:breath_of_shadow", "1"] },
{ "id": "notify", "args": ["You obtained the Breath of Shadow."] },
{ "id": "playsound", "args": ["game:effect/reforge"] }
]
}Tips
- Use meaningful stage titles — Stage titles appear in the HUD. Make them descriptive so players understand the current phase (e.g. "Gather Ritual Components" instead of "Stage 1").
- Add journal entries on stage completion — Use
addjournalentryinonStageCompleteActionsto give players a narrative record of their progress. - Use
setplayervariablefor persistence — Store stage progress in player variables so other systems (dialogues, NPCs, branching quests) can react to how far the player has progressed. - Keep stages focused — Each stage should represent a clear phase of the quest. Avoid cramming too many unrelated objectives into a single stage.
- Test stage transitions — Use the
/avq skipstagecommand to advance stages during development and verify thatonStageCompleteActionsfire correctly. The full syntax is/avq skipstage [playerName] [questId]. If no player is given, it uses the command caller. If no questId is given, it uses the currently active quest.