Quest Givers

NPCs serve as quest givers in the Alegacy Quest Framework. This page covers the quest giver entity behavior and the dialogue system used for NPC conversations.


How It All Connects

A quest giver NPC is made of three files working together:

graph TD
    A([Player right-clicks NPC]) -->|conversable
behavior| B[Dialogue
config/dialogue/priest.json] B -->|NPC says 'Hello'| C([Player sees greeting]) C -->|Player clicks
'I need work'| D[Dialogue trigger:
openquests] D -->|opens quest UI| E[Quest
config/quests/priest.json] E -->|shows objectives
& rewards| F([Player accepts quest]) A -.->|questgiver behavior
lists quest IDs| E

How the flow works:

  • Player right-clicks NPC → The conversable behavior loads the dialogue file.
  • NPC says 'Hello' → The player sees the greeting text.
  • Player clicks 'I need work' → The dialogue reaches the trigger: "openquests" step.
  • Quest UI opens → The framework loads the quest file and displays it.
  • Player accepts → The quest becomes active and objectives start tracking.

The questgiver behavior (dotted line) tells the framework which quest IDs this NPC can offer, so the quest appears in the selection UI.


Minimal Quest Giver (Copy-Paste)

A complete quest-giving NPC needs exactly two behaviors:

{
  "code": "villager-helper",
  "class": "EntityAgent",
  "server": {
    "behaviors": [
      { "code": "nametag", "selectFromRandomName": ["Helper"] },
      { "code": "conversable", "dialogue": "config/dialogue/helper" },
      {
        "code": "questgiver",
        "quests": ["yourmod:helper-quest"],
        "noAvailableQuestDescLangKey": "yourmod:no-quests"
      }
    ]
  }
}

And the matching dialogue file config/dialogue/helper.json:

{
  "components": [
    {
      "code": "start",
      "owner": "npc",
      "type": "talk",
      "text": [{ "value": "yourmod:helper-greeting" }],
      "jumpTo": "main"
    },
    {
      "code": "main",
      "owner": "player",
      "type": "talk",
      "text": [
        { "value": "yourmod:helper-ask", "jumpTo": "quests" },
        { "value": "yourmod:helper-bye", "jumpTo": "close" }
      ]
    },
    {
      "code": "quests",
      "owner": "npc",
      "type": "talk",
      "trigger": "openquests",
      "text": [{ "value": "yourmod:helper-opening" }]
    },
    {
      "code": "close",
      "owner": "npc",
      "type": "talk",
      "text": [{ "value": "yourmod:helper-goodbye" }]
    }
  ]
}

That's it. Three files (entity + dialogue + quest) and a lang file and you have a working quest giver. See Getting Started for the full walkthrough.


Quest Giver Behavior

Add the questgiver entity behavior to any NPC entity to make it offer quests. Configure it in the entity's behavior list:

{
  "code": "questgiver",
  "quests": ["yourmod:intro", "yourmod:gather-herbs"],
  "alwaysquests": ["yourmod:daily-task"],
  "priorityquests": ["yourmod:main-story-1"],
  "rotationpool": ["yourmod:side-a", "yourmod:side-b", "yourmod:side-c"],
  "reputationnpc": "innkeeper",
  "singlequestatatime": true,
  "maxavailablequests": 3,
  "chaincooldowndays": 1.0,
  "bosshuntactiveonly": false,
  "trialactiveonly": false
}

Fields

FieldDescription
questsArray of quest IDs this NPC can offer
alwaysquestsQuests always shown regardless of rotation or cooldown
priorityquestsQuests shown first, before regular pool
rotationpoolQuests that rotate availability (only a subset shown at a time)
reputationnpcNPC identifier for the reputation system
singlequestatatimeIf true, player can only have one active quest from this NPC
maxavailablequestsMaximum number of quests shown in the quest selection UI
chaincooldowndaysDays before a completed chain quest becomes available again
bosshuntactiveonlyOnly show quests when Boss Hunt is active
trialactiveonlyOnly show quests when Hollow Trials are active

Dialogue System

Dialogues are part of the vanilla EntityBehaviorConversable system. NPCs with this behavior can have conversations with players through a dialogue UI. Alegacy VS Quest extends this by intercepting the trigger property to execute quest actions.

Dialogue files are placed in config/dialogue/.json within your mod's assets folder. Each file contains an array of components — individual steps in a conversation.

{
  "components": [
    { "code": "intro", "owner": "npc", "type": "talk", "text": [{ "value": "modid:greeting" }], "jumpTo": "main" },
    { "code": "main", "owner": "player", "type": "talk", "text": [
      { "value": "modid:option-quests", "jumpTo": "openquests" },
      { "value": "modid:option-leave", "jumpTo": "close" }
    ]},
    { "code": "openquests", "owner": "npc", "type": "talk", "trigger": "openquests", "text": [{ "value": "modid:quests-opening" }] }
  ]
}

Component Properties

PropertyDescription
codeUnique identifier for this component
ownernpc or player
typetalk or condition
textArray of text entries
jumpToNext component code to jump to
triggerAction string to execute
setVariablesVariables to set when this component is entered
soundSound to play when this component is entered

NPC Speech (owner: npc)

Displays the NPC's lines and automatically advances via jumpTo:

{
  "code": "greeting",
  "owner": "npc",
  "type": "talk",
  "text": [{ "value": "modid:dialogue-greeting" }],
  "jumpTo": "main"
}

Player Choices (owner: player)

Text entries become clickable options, each with its own jumpTo:

{
  "code": "main",
  "owner": "player",
  "type": "talk",
  "text": [
    { "value": "modid:option-quests", "jumpTo": "openquests" },
    { "value": "modid:option-shop", "jumpTo": "shop" },
    { "value": "modid:option-leave", "jumpTo": "close" }
  ]
}

Condition Check (type: condition)

Checks a variable and branches the dialogue:

{
  "code": "checkfirstmeet",
  "owner": "npc",
  "type": "condition",
  "variable": "entity.hasmet",
  "isNotValue": "true",
  "thenJumpTo": "firstmeet",
  "elseJumpTo": "welcomeback"
}

Conditional Text Options

Show or hide player choices based on conditions. All conditions in the array must be met:

{
  "value": "modid:special-option",
  "jumpTo": "special",
  "conditions": [
    { "variable": "entity.unlocked", "isValue": "true" },
    { "variable": "player.haskey", "isValue": "true" }
  ]
}

Variables & Scopes

Variables are stored with different scopes:

  • entity. — Stored on the NPC entity (per-NPC)
  • player. — Stored on the player entity (per-player)
  • global. — Global scope (shared across all)

Setting Variables

{
  "setVariables": {
    "entity.hasmet": "true",
    "player.talkedtoinnkeeper": "true"
  }
}

Triggers

The trigger property executes Alegacy VS Quest action strings when the component is entered:

{
  "code": "openquests",
  "owner": "npc",
  "type": "talk",
  "trigger": "openquests",
  "text": [{ "value": "modid:dialogue-quests-opening" }]
}

Multiple actions separated by ;:

{
  "trigger": "playsound 'sounds/effect/writing' 0.5;addjournalentry yourmod:questid yourmod:lorecode 'Title' 'Text'"
}

Per-Entry Triggers

Individual player choices can have their own trigger field:

{
  "code": "choices",
  "owner": "player",
  "type": "talk",
  "text": [
    { "value": "modid:accept", "jumpTo": "accepted", "trigger": "playsound 'sounds/effect/receptionbell' 0.5" },
    { "value": "modid:decline", "jumpTo": "close" }
  ]
}

💡 For a complete deep dive into the dialogue system with full examples, see the Dialogues page.

Press ESC to close