Skip to content

Adding Quests

Status: Current Last reviewed: 2026-07-07

Quests are JSON. They live in server/data/quests/starter_quests.json, seeded from DEFAULT_QUESTS in shared/src/quests.ts. Edit them in the /admin Quests modal (then Save Quests) or in the file directly (then restart the server). Players load the current definitions on their next join.

Anatomy

{
  "id": "clear_the_well",
  "title": "Clear the Well",
  "giverNpcId": "npc_mera",
  "description": "Healer Mera says something has fouled the village well. Deal with it and bring back proof.",
  "objectives": [
    { "id": "kill", "type": "kill_mob", "description": "Kill goblin slingers", "target": "slinger", "count": 2 },
    { "id": "ears", "type": "loot_item", "description": "Loot goblin ears", "target": "goblin_ear", "count": 2 }
  ],
  "rewards": {
    "items": [{ "itemId": "healing_draught", "qty": 2 }],
    "skillUses": [{ "skill": "defense", "uses": 3 }]
  },
  "requires": ["goblins_at_fenline"],
  "repeatable": false
}
  • giverNpcId must match an NPC's npcId, and that NPC's questIds must include this quest's id for it to appear in dialogue. See Adding NPCs.
  • requires is a list of quest ids that must be turned in first.
  • rewards.skillUses feed the normal use-based progression, so a reward can nudge a skill without a fake XP grant.

Objective Types and Event Keys

Each objective matches a gameplay event key of the form type:target.

Type Target format Example
talk_to_npc npcId talk_to_npc:npc_rusk
kill_mob variant kill_mob:scrapper
collect_item itemId collect_item:goblin_coin
loot_item itemId loot_item:goblin_ear
reach_area trigger id reach_area:shrine_area
interact_object object/prefab id interact_object:loot_container
hit_target_weapon <prefab>:<weaponId> hit_target_weapon:training_dummy:mace
hit_target_spell <prefab>:<spellId> hit_target_spell:magic_target:fireball
hit_target_arrow prefab hit_target_arrow:archery_target
raise_ember level raise_ember:awakened
defeat_boss variant defeat_boss:champion

count is how many times the event must fire (or, for collect_item, the inventory count to reach).

Testing

  1. Save the quest and make sure its NPC lists the id in questIds.
  2. In /admin, use Reset Quests to clear your own log, then rejoin as a player.
  3. Talk to the giver, accept, and complete the objectives. The HUD tracker and combat log show progress; the quest flips to ready when all objectives are met, and turning it in at the giver grants the rewards.

The questtest.mjs bot in tools/ is a working example of driving a quest end to end over the protocol.