NPC Dialogue
NPC dialogue lets you give master NPCs branching conversations with JSON alone, with no Java. A dialogue tree is a set of nodes: each node is one line the NPC says, plus the choices the player can answer with. Choices can lead to another node, be hidden behind conditions, and run actions such as changing alignment, giving TP, running a command or starting a quest.
Dialogue is per-world data, like quests and wishes.
Where files go
<world save>/dragonminez/dialogues/*.json
The folder is created the first time the server starts, together with an _example.json you can copy. Every .json file in the folder (no subfolders) holds one tree for one NPC. Files are loaded in alphabetical order; if two files target the same NPC, the later one wins.
Dialogue loads at server start and reloads with /dmzreload story (or /dmzreload all); see Reloading and Updating Changes.
Source: src/main/java/com/dragonminez/common/dialogue/ (DialogueRegistry, DialogueParser, DialogueService, DialogueAction).
Which NPCs can use it
Dialogue trees work on master NPCs: the trainers placed by NPC Placement and Alignment, such as Roshi or Goku. The npc field is the master's id. The masters DragonMineZ places by default use these ids:
roshi, goku, karin, dende, popo, gero, guru, kingkai (King Kai), toribot, enma, baba, grandkai, otherworld_announcer
When a master has a tree, right-clicking it shows the tree instead of the master's usual options (Quests, Skills, Train and services; see Masters). The tree uses the same dialogue window: the line appears in the middle of the bottom band and the choices are listed on the right. Give one of your choices the OPEN_QUESTS action so players can still reach the master's quests. The player must have created a character first. A master's alignment requirement does not stop the conversation (a master who dislikes you greets you with a "disliked" line); it only locks Skills, Train and that master's new side quests, while saga quests and quests already in progress stay open (see Masters and Alignment).
The default quest NPCs (dragonminez:quest_npc, for example Bulma) keep their quest list and do not use dialogue trees.
File format
{
"npc": "roshi",
"start": "greet",
"nodes": {
"greet": {
"line": "Well, if it isn't %player%! What brings you here?",
"choices": [
{
"text": "I want to get stronger.",
"goto": "training",
"conditions": { "operator": "AND", "conditions": [ { "type": "LEVEL", "minLevel": 5 } ] }
},
{
"text": "Give me your money!",
"goto": "angry",
"actions": [ { "type": "ALIGNMENT", "amount": -5 } ]
},
{ "text": "Show me your quests.", "actions": [ { "type": "OPEN_QUESTS" } ] },
{ "text": "Goodbye." }
]
},
"training": {
"line": "Ha! I like your spirit. Take these training points and come back later.",
"choices": [
{ "text": "Thank you!", "actions": [ { "type": "TPS", "amount": 50 } ] }
]
},
"angry": {
"line": "How dare you! Leave my sight at once!"
}
}
}
Tree
| Field | Type | What it does |
|---|---|---|
npc |
String | Required. The id of the master the tree belongs to (case-insensitive). An id that starts with _ keeps the file inactive; that is how _example.json stays off.
|
start |
String | Id of the first node. Default "start".
|
nodes |
Object | Required. Map of node id to node. |
A tree is skipped (and the reason logged) when npc or nodes is missing, or when the start node does not exist.
Node
| Field | Type | What it does |
|---|---|---|
line |
String | Required. What the NPC says. A translation key or plain text; supports placeholders. A node without line is skipped.
|
choices |
Array | The player's answers, listed as options. A node without choices just shows its line; the player leaves with Close or Esc. |
Choice
| Field | Type | What it does |
|---|---|---|
text |
String | Required. Button text. A translation key or plain text; supports placeholders. A choice without text is skipped.
|
goto |
String | Node to show next. Leave it out (or point it at a node that doesn't exist) to end the conversation. |
conditions |
Object | Optional. The choice is only shown when the conditions are met. Same format as quest prerequisites (see below). If the block can't be read, the whole choice is dropped rather than shown to everyone.
|
actions |
Array | Optional. Actions run in order when the choice is picked (see below). |
Conditions
conditions uses the quest condition-tree format: an operator (AND or OR) and a list of conditions, which can be nested. Every quest condition type works, for example:
{ "operator": "OR", "conditions": [
{ "type": "RACE", "race": "saiyan" },
{ "type": "SAGA_QUEST", "sagaId": "saiyan_saga", "questId": 12 },
{ "type": "ALIGNMENT", "max": 40 }
] }
The available types are SAGA_QUEST, QUEST, LEVEL, STAT, RACE, CLASS, SKILL, BIOME, DIMENSION, STRUCTURE, ALIGNMENT and TIME. Field names are the same as in quests (for example, LEVEL uses minLevel); see Custom Quests.
Conditions are checked again on the server when the player picks the choice, so a hidden choice can't be forced.
Actions
type |
Fields | What it does |
|---|---|---|
ALIGNMENT |
amount |
Adds amount to the player's alignment (negative values lower it).
|
TPS |
amount |
Gives amount training points (positive amounts only).
|
COMMAND |
command |
Runs a command from the server with operator permissions. %player% is replaced with the player's name.
|
START_QUEST |
quest |
Starts a quest with the same rules as starting it from the quest log (prerequisites, start requirements, party). Use the side quest id (for example "bulma_gero_blueprints") or sagaId:questId for a saga quest (for example "saiyan_saga:3"). If the quest can't be started, nothing happens.
|
OPEN_QUESTS |
None | Switches the same window to the NPC's quest list (accept, turn in, see locked quests) and ends the tree (goto is ignored).
|
value is accepted as a generic alias for command and quest. An action with an unknown type is skipped and logged.
Placeholders
Lines and choice texts can contain these placeholders; they are filled in for the player reading them:
| Placeholder | Value |
|---|---|
%player% |
Player name |
%race% |
Race id |
%class% |
Class id |
%level% |
Player level |
%alignment% |
Alignment |
%deaths% |
Number of deaths |
%form% |
Active form (base when untransformed)
|
%dimension% |
Dimension name (for example overworld)
|
Placeholders also work inside your own translations. Java add-ons can add more with DMZTextPlaceholders.register(...); see Implementation and Events.
Translations
line and text are shown translated when they match a translation key in a language file, and as written otherwise. The name tab above the line shows the NPC's usual name (its entity name, for example entity.dragonminez.master_roshi). Custom translations merge with the Crowdin ones in the same way as for custom races.
Reload and validate
- Save your file under
<world save>/dragonminez/dialogues/. - Validate the JSON syntax (see How to JSON).
- Run
/dmzreload story; see Reloading and Updating Changes. - Check the server console: it logs how many trees were loaded, and names any node, choice or action that was skipped.
- Talk to the NPC and walk through every branch, including the choices gated by conditions.