Quest Structure

Quests are the core of the framework. This page covers the JSON structure, action hooks, rewards, and chaining. For objectives, actions, and stages see their dedicated pages.

💡 See also: Objectives — Actions — Stages

Anatomy of a Quest

Every quest follows this structure:

graph TD
    A([Player accepts quest]) --> B[onAcceptedActions
playsound, journal entry,
set attributes] B --> C[Objectives
kill / gather / reach / interact] C --> D{All objectives
completed?} D -->|NO| C D -->|YES| E[itemRewards
gear, items, loot] E --> F[actionRewards
notify, reputation,
next quest trigger] F --> G([Quest Complete]) C -->|Player dies / abandons| I([Quest remains active
or is abandoned])

How to read this flowchart:

  • Start — Player accepts the quest (via NPC dialogue or auto-assign)
  • onAcceptedActions — Fire immediately: play sound, add journal entry, set attributes
  • Objectives — The quest tracks player progress. This loops until all objectives are met
  • Rewards — When all objectives are done, itemRewards (gear/items) and actionRewards (notify, reputation, next quest trigger) execute
  • Quest Complete — The quest is marked finished
  • Abandon — If the player dies or abandons the quest, it either stays active (permanent) or is dropped. There is no automatic failure reward path.

Copy-Paste Templates

Here are three minimal quest templates. Each is a complete working quest — just adjust the IDs and values.

Gather Quest (collect items)

{
  "id": "yourmod:gather-herbs",
  "cooldown": -1,
  "perPlayer": true,
  "onAcceptedActions": [
    { "id": "playsound", "args": ["sounds/effect/writing", "0.5"] }
  ],
  "gatherObjectives": [
    { "validCodes": ["game:herb*"], "demand": 10 }
  ],
  "itemRewards": [
    { "itemCode": "game:gear-rusty", "amount": 3 }
  ],
  "actionRewards": [
    { "id": "notify", "args": ["yourmod:gather-done"] }
  ]
}

Kill Quest (slay creatures)

{
  "id": "yourmod:kill-wolves",
  "cooldown": 48,
  "perPlayer": true,
  "onAcceptedActions": [
    { "id": "playsound", "args": ["sounds/effect/writing", "0.5"] }
  ],
  "killObjectives": [
    { "validCodes": ["wolf-male", "wolf-female"], "demand": 5 }
  ],
  "itemRewards": [
    { "itemCode": "game:ingot-gold", "amount": 2 }
  ],
  "actionRewards": [
    { "id": "notify", "args": ["yourmod:kill-done"] }
  ]
}

Chain Quest (requires another quest first)

{
  "id": "yourmod:deliver-herbs",
  "cooldown": -1,
  "perPlayer": true,
  "predecessor": "yourmod:gather-herbs",
  "onAcceptedActions": [
    { "id": "playsound", "args": ["sounds/effect/writing", "0.5"] }
  ],
  "actionObjectives": [
    {
      "id": "reach_village",
      "objectiveId": "reachwaypoint",
      "args": ["5000,70,3000", "5"]
    }
  ],
  "actionRewards": [
    { "id": "notify", "args": ["yourmod:delivery-done"] },
    { "id": "questitem", "args": ["yourmod:delivery-receipt"] }
  ]
}

The predecessor field links quests. Quest 2 only appears after Quest 1 is completed.


Quest Structure

Quests are JSON files in config/quests/<folder>/<name>.json:

{
  "id": "yourmod:collect-herbs",
  "cooldown": 48,
  "perPlayer": true,
  "predecessor": "yourmod:intro-quest",
  "onAcceptedActions": [...],
  "actionObjectives": [...],
  "killObjectives": [...],
  "gatherObjectives": [...],
  "itemRewards": [...],
  "actionRewards": [...],
  "onFailedActions": [...],
  "stages": [...]
}

Core Fields

  • id — Unique quest identifier (e.g. yourmod:quest-name)
  • cooldown — Hours before quest can be retaken (-1 = one-time only)
  • perPlayer — Whether quest progress is per-player
  • predecessor — Quest ID that must be completed first (chains quests)

Action Hook Arrays

PropertyWhen it triggers
onAcceptedActionsWhen the player accepts the quest
actionRewardsWhen the quest is completed successfully
onStageCompleteActionsWhen a stage completes (multi-stage quests)
onCompleteActionsWhen a specific action-objective completes

💡 For the full list of action IDs (giveitem, playsound, setattribute, addreputation, etc.), see the Actions page.

Each array contains action objects with id and args:

"onAcceptedActions": [
  { "id": "playsound", "args": ["game:sounds/quest-accept", "0.8"] },
  { "id": "setattribute", "args": ["questStarted", "true"] }
]

Rewards

Item Rewards

"itemRewards": [
  { "itemCode": "game:ingot-gold", "amount": 5 },
  { "itemCode": "game:bread-spelt", "amount": 10 }
]

Random Item Rewards

"randomItemRewards": [
  {
    "lootTable": "yourmod:boss-loot",
    "count": 1
  }
]

Action Rewards

"actionRewards": [
  { "id": "questitem", "args": ["yourmod:shadow-earring"] },
  { "id": "addreputation", "args": ["guild", "guild-npc", "10"] },
  { "id": "playsound", "args": ["game:sounds/quest-complete"] }
]

Quest Chains

Use the predecessor field to create linear quest chains:

// Quest 1: intro-quest (no predecessor)
{ "id": "yourmod:intro-quest", "cooldown": -1 }

// Quest 2: requires intro-quest
{ "id": "yourmod:gather-herbs", "predecessor": "yourmod:intro-quest" }

// Quest 3: requires gather-herbs
{ "id": "yourmod:deliver-herbs", "predecessor": "yourmod:gather-herbs" }

A quest with a predecessor will only appear in quest giver dialogues after the predecessor is completed.

Action String Format

Action strings are a compact way to specify actions in dialogues and onCompleteActions:

actionId arg1 arg2 'argument with spaces'; anotherActionId arg1

Parsing Rules

  • Split by ; (semicolon) into individual action commands
  • Each command is tokenized — first token is the action ID, rest are arguments
  • Arguments wrapped in single quotes '...' preserve spaces inside them
  • The action ID is looked up in the action registry and executed
// Examples:
playsound 'game:sounds/effect' 0.8
giveitem 'game:ingot-gold' 5; playsound 'game:sounds/reward'
setattribute questProgress 3; completequest

Press ESC to close