Skip to main content

Dialog System

The dialog system lets you create branching conversations with NPCs. Dialogs are defined as JSON files and support multiple node types, conditional branching, command macros and localization.

How Dialogs Work

When a player presses F on an NPC, the system follows this priority chain:

  1. Quest NPC Profile -- If the Quest mod has a profile for this citizen, the quest dialog system takes over.
  2. Citizen Dialogs -- The dialogs array in the citizen config is checked. The first dialog whose condition matches is opened.
  3. Messages -- If no dialog matches, simple chat messages are sent.
  4. Shop / Commands -- If no dialog or messages exist, the shop or command actions are executed.
info

Quest NPC Profiles always take priority. If a citizen has both a quest profile and legacy dialogs, only the quest profile dialog is shown. Do not mix both on the same NPC.

Dialog File Structure

Dialog files live in configs/kyuubisoft_core/dialogs/ as individual JSON files.

{
"id": "example_dialog",
"speakerName": "dialog.example.speaker",
"startNode": "greeting",
"nodes": [
{
"nodeId": "greeting",
"type": "TEXT",
"lines": ["dialog.example.greeting.line1", "dialog.example.greeting.line2"],
"next": "ask_help"
},
{
"nodeId": "ask_help",
"type": "CHOICE",
"lines": ["dialog.example.ask_help"],
"choices": [
{
"text": "dialog.example.choice.yes",
"next": "accepted"
},
{
"text": "dialog.example.choice.no",
"next": "declined"
},
{
"text": "dialog.example.choice.later",
"next": null
}
]
},
{
"nodeId": "accepted",
"type": "TEXT",
"lines": ["dialog.example.accepted.line1"],
"next": null
},
{
"nodeId": "declined",
"type": "TEXT",
"lines": ["dialog.example.declined.line1"],
"next": null
}
]
}

Top-Level Fields

FieldRequiredDescription
idYesUnique dialog ID. Referenced from citizen config.
speakerNameNoDisplay name for the speaker. Can be an i18n key or plain text. Falls back to the citizen's name if omitted.
startNodeYesID of the first node to display.
nodesYesArray of dialog nodes.

Node Types

TEXT Node

Displays one or more lines of text. The player clicks to advance to the next node.

{
"nodeId": "greeting",
"type": "TEXT",
"lines": ["Hello, traveler!", "Welcome to our village."],
"next": "ask_help"
}
  • lines -- Array of text strings or i18n keys (1-4 lines recommended).
  • next -- ID of the next node. Set to null to end the dialog.

CHOICE Node

Displays text with selectable response options.

{
"nodeId": "ask_help",
"type": "CHOICE",
"lines": ["Can you help me gather some herbs?"],
"choices": [
{ "text": "Sure, I will help!", "next": "accepted" },
{ "text": "Not right now.", "next": null }
]
}

Each choice has:

  • text -- Display text or i18n key.
  • next -- Node to jump to. null closes the dialog.
  • condition -- Optional condition to show/hide this choice (see below).
  • macro -- Optional commands to execute when this choice is selected.

INPUT Node

Prompts the player for text input. The input is dispatched to the citizen listeners.

{
"nodeId": "name_input",
"type": "INPUT",
"lines": ["What is your name, adventurer?"],
"next": "response"
}

Conditions

Conditions control which dialogs or choices are available based on the player's state.

On Citizens (Conditional Dialogs)

The citizen's dialogs array supports conditions to select which dialog opens:

{
"dialogs": [
{
"dialogId": "quest_complete_dialog",
"condition": { "type": "quest_completed", "value": "intro_quest" }
},
{
"dialogId": "quest_active_dialog",
"condition": { "type": "quest_active", "value": "intro_quest" }
},
{
"dialogId": "default_greeting"
}
]
}

The system checks conditions top to bottom. The first matching dialog is opened. An entry without a condition acts as a fallback.

On Choices

Individual choices can be shown or hidden based on conditions:

{
"choices": [
{
"text": "I have completed the trial.",
"next": "reward",
"condition": { "type": "quest_completed", "value": "trial_quest" }
},
{
"text": "Tell me about the trial.",
"next": "explain"
}
]
}

Available Condition Types

TypeValueDescription
permissionPermission stringPlayer has the specified permission.
quest_activeQuest IDPlayer has this quest active.
quest_completedQuest IDPlayer has completed this quest.
achievement_unlockedAchievement IDPlayer has unlocked this achievement.
has_itemItem IDPlayer has this item in their inventory.

All conditions support a negate flag. Set "negate": true to invert the result (e.g. show only if the quest is NOT completed).

Macros (Commands)

Macros let you execute commands when a dialog node is reached or a choice is selected.

{
"nodeId": "reward_node",
"type": "TEXT",
"lines": ["Here is your reward!"],
"next": null,
"macro": {
"commands": [
"give {player} Coin_Gold 50",
"ksquestadmin complete {player} intro_quest"
],
"runAsServer": true
}
}
FieldDefaultDescription
commands--List of commands to execute.
runAsServerfalsetrue = run as server console, false = run as the player.

Placeholders:

  • {player} -- replaced with the player's username.
  • {citizen} -- replaced with the citizen's ID.
warning

Commands in macros use the ks-prefixed command names (e.g. ksquestadmin, ksachievementadmin). Make sure you use the correct prefix.

Localization (i18n)

All text fields (lines, choices.text, speakerName) support i18n keys. Define translations in the core mod's localization files:

{
"dialog.example.speaker": "Elder Willowbark",
"dialog.example.greeting.line1": "Greetings, young adventurer.",
"dialog.example.greeting.line2": "The forest whispers of your arrival.",
"dialog.example.choice.yes": "I am ready to help!",
"dialog.example.choice.no": "Maybe later."
}

If a key is not found in the localization file, the raw key string is displayed as-is. This lets you use plain text directly in the JSON without needing a translation file.

Linking Dialogs to Quest NPC Profiles

For quest-related NPCs, the recommended approach is to use the Quest mod's NPC Profile system instead of the core dialog system. Quest NPC Profiles provide specialized dialogs for quest offer, active and complete states with built-in macros like start_quest and complete_quest.

See the Quest System documentation for details on quest NPC profiles.