Writing Dialogues
Dialogues are written in .dlg files using a simple DSL (domain-specific language): a small, purpose-built scripting format designed specifically for writing branching conversations. The DSL uses plain keywords like NODE, CHOICE, GOTO, and SET to describe dialogue flow, so no prior knowledge of programming is required. Place dialogue files in content/dialogues/.
Quick Start (No Localization Needed)
Section titled “Quick Start (No Localization Needed)”You can write dialogue text directly (no locale files required). There are three forms:
BARTENDER: Hello there # plain text, fine for simple linesBARTENDER: "Hello, friend!" # quotes when text has special characters or starts with @BARTENDER: @bartender.greeting # localization key for multi-language supportUse plain text for most things. Add quotes when your text contains :, #, or starts with @. Use @keys only when you need multiple languages.
Here’s a complete example using plain and quoted text:
NODE start BARTENDER: Well, well. A new face. What brings you to the Salty Dog?
CHOICE Any news around town? SET flag heardRumors ADD relationship bartender 1 GOTO rumors END
CHOICE Nothing. Just passing through. GOTO farewell END
NODE rumors BARTENDER: Word is the merchant at the market square is looking for help. Pays well, too. # Player sees this text and clicks Continue, then engine goes to farewell GOTO farewell
NODE farewell BARTENDER: Safe travels. END dialogueSee Localization when you’re ready to support multiple languages.
Basic Structure
Section titled “Basic Structure”A dialogue is a graph of nodes. Each node has a speaker, text, and optional choices:
NODE start BARTENDER: @bartender.greeting
CHOICE @bartender.choice.ask_news GOTO news END
CHOICE @bartender.choice.goodbye GOTO farewell END
NODE news BARTENDER: @bartender.news GOTO farewell
NODE farewell BARTENDER: @bartender.farewell END dialogueKey rules:
Section titled “Key rules:”- The first
NODEis the start node SPEAKER:lines set who’s talking (matched to character ID, case-insensitive)NARRATOR:lines have no speaker and are used for descriptionsGOTOroutes to another nodeEND dialoguecloses the conversationEND(withoutdialogue) closes a CHOICE or IF block- A node with text but no choices shows a Continue button. The player must click to advance.
- A node with no text and no choices is a silent processing node that auto-advances instantly
Choices with Effects
Section titled “Choices with Effects”Choices can trigger effects that modify game state:
CHOICE @bartender.choice.buy_drink REQUIRE variableGreaterThan gold 4 ADD variable gold -5 ADD variable _drinksBought 1 ADD relationship bartender 1 NOTIFY @notification.bought_drink GOTO after_drinkENDREQUIREonly shows this choice if the condition passes- Multiple effects run in order when the choice is selected
Conditional Branching
Section titled “Conditional Branching”Use IF blocks for automatic branching based on conditions:
NODE check_quest IF questAtStage odd_jobs started GOTO quest_update END IF questAtStage odd_jobs complete GOTO quest_done END GOTO default_greetingIf the condition passes, the GOTO fires. Otherwise, the engine falls through to the next block.
Triggered Dialogues
Section titled “Triggered Dialogues”Dialogues can auto-trigger when the player enters a location:
TRIGGER tavernREQUIRE notFlag seenTavernIntro
NODE start NARRATOR: @narrator.tavern_intro SET flag seenTavernIntro
CHOICE @narrator.choice.look_around END dialogue ENDTRIGGER <locationId>fires when the player enters this locationREQUIREat the top level sets conditions that must pass for the trigger- Use
notFlagto ensure one-time intros only play once
Voice and Portrait Overrides
Section titled “Voice and Portrait Overrides”NODE emotional_scene VOICE bartender_sad.ogg PORTRAIT bartender_sad.png BARTENDER: @bartender.sad_dialogueVOICEsets an audio file to play for this nodePORTRAIToverrides the character’s default portrait
Comments
Section titled “Comments”Lines starting with # are comments:
# This node handles the quest rewardNODE quest_complete MERCHANT: @merchant.quest_complete SET questStage odd_jobs complete ADD variable gold 50Comments can appear anywhere. If a # appears inside quotes, it’s preserved as text.
Starting Other Dialogues
Section titled “Starting Other Dialogues”You can chain dialogues using the START dialogue effect:
CHOICE @bartender.choice.talk_to_merchant START dialogue merchant_introENDComplete Example
Section titled “Complete Example”Triggered intro and character conversation live in separate files. The triggered file auto-plays when the player enters the location. The character file plays when the player clicks the character.
content/dialogues/tavern_intro.dlg:
# Plays automatically the first time the player enters the tavernTRIGGER tavernREQUIRE notFlag seenTavernIntro
NODE start NARRATOR: @narrator.tavern_intro SET flag seenTavernIntro
CHOICE @narrator.choice.look_around END dialogue ENDcontent/dialogues/bartender_greeting.dlg:
# Plays when the player clicks the bartender characterNODE start BARTENDER: @bartender.greeting
CHOICE @bartender.choice.ask_rumors REQUIRE notFlag heardRumors SET flag heardRumors ADD relationship bartender 1 GOTO rumors END
CHOICE @bartender.choice.buy_drink REQUIRE variableGreaterThan gold 4 ADD variable gold -5 NOTIFY @notification.bought_drink GOTO after_drink END
CHOICE @bartender.choice.goodbye GOTO farewell END
NODE rumors BARTENDER: @bartender.rumors ADD item old_coin NOTIFY @notification.found_coin GOTO start
NODE after_drink BARTENDER: @bartender.after_drink GOTO start
NODE farewell BARTENDER: @bartender.farewell END dialogueSee DSL Syntax Reference for the complete keyword list.