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 actionRewards are 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:

PropertyTypeRequiredDescription
stageTitleLangKeystringYesLocalization key for the stage title displayed in the HUD.
gatherObjectivesarrayNoArray of gather objectives for this stage.
killObjectivesarrayNoArray of kill objectives for this stage.
actionObjectivesarrayNoArray of action objectives for this stage (same format as regular quest objectives).
onStageCompleteActionsarrayNoActions 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 stages array work exactly as before — objectives are defined at the top level.
  • The stages array 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 addjournalentry in onStageCompleteActions to give players a narrative record of their progress.
  • Use setplayervariable for 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 skipstage command to advance stages during development and verify that onStageCompleteActions fire 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.

Press ESC to close