Dialogue
NOTE: This document will be deprecated in the near future. Some items may be outdated/incorrect
Section titled “NOTE: This document will be deprecated in the near future. Some items may be outdated/incorrect”
Overview
Section titled “Overview”dialogue_compiler.py takes a .dlg script and produces a .h + .cpp pair
for your DialogueController system. One file = one scene. Each scene contains
any number of named interaction blocks.
Quick Start
Section titled “Quick Start”python dialogue_compiler.py park.dlg # -> park_dialogue.h / .cpppython dialogue_compiler.py park.dlg -o myparkpython dialogue_compiler.py park.dlg --stdoutIn your game code:
#include "park_dialogue.h"
// In scene init — call once before any dialogue runspark_init_all();
// Start a specific interaction (e.g. when player walks up to an NPC)dialogueCtrl.start(park_akihiko_meets_yuki_first());dialogueCtrl.start(park_merchant_greeting_first());dialogueCtrl.start(park_notice_board_first());Core Concept: Interactions
Section titled “Core Concept: Interactions”A scene file holds as many independent dialogue graphs as you need —
one per NPC, one per sign, one per cutscene, etc. Each is wrapped in a
named [interaction] block.
Each interaction compiles to:
- Its own
dialoguearray (no index bleed between interactions) - Its own
_init()and_first()accessor - Inline accessors for every
@labeldefined inside it
Labels are scoped to their interaction — the same label name (e.g. @decline)
can appear in multiple interactions without collision.
File Structure
Section titled “File Structure”# Top-level: comments, section headers, scene-wide @bg defaults. Should match the bg file name.@bg Akihiko bgAkihiko@bg Yuki bgYuki
[interaction: npc_one | Optional human description] # ... dialogue for this NPC ...
[interaction: npc_two | Another NPC] # ... dialogue for this NPC ...Full Syntax Reference
Section titled “Full Syntax Reference”Comments
Section titled “Comments”# Anything after a # is ignoredSection headers (cosmetic)
Section titled “Section headers (cosmetic)”== Scene: The Park ==Purely for readability in large files. Ignored by the compiler.
@bg — Set default background for a character
Section titled “@bg — Set default background for a character”@bg CharacterName bgVariableName- At the top of the file (before any
[interaction]): scene-wide default. All interactions inherit it. - Inside an
[interaction]block: overrides for that interaction only. - If a character has no
@bgat all, the compiler auto-derives a name:"Akihiko"becomesbgAkihiko.
[interaction: name | description]
Section titled “[interaction: name | description]”[interaction: akihiko_talk | Akihiko by the fountain]Starts a new interaction block. Everything until the next [interaction]
or end-of-file belongs to it.
name: becomes the C++ identifier. Usesnake_case. Producesscene_name_first(),scene_name_init(), etc.| description: optional human-readable comment written into the generated.cppas a section header.
Dialogue lines
Section titled “Dialogue lines”CHARACTER: Text the character says.Uses the current default bg for CHARACTER.
One-off bg override for a single line without changing the default:
Yuki(bgYukiClose): I come here to think.CHARACTER must start with a letter. Spaces are allowed (Old Man: ...).
@label — Name a line
Section titled “@label — Name a line”@label_nameCHARACTER: This line is now reachable by name.- Must be placed immediately before the target line.
- Becomes an inline accessor in the header:
park_hana_request_hana_agree()returns a pointer to that line. - Scoped to its interaction; the same name in another interaction is fine.
[choice] — Selection node
Section titled “[choice] — Selection node”CHARACTER: Question text?
[choice] > Option A -> @label_a > Option B -> @label_b > Option C -> @label_c- Place
[choice]immediately after the question line. - The question line becomes the selection node (
next = NULL,selectionspopulated). - Each
-> @labelmust point to a label defined in the same interaction. - Indentation of
>lines is optional but recommended for readability.
[end] — Explicit dead-end
Section titled “[end] — Explicit dead-end”CHARACTER: Goodbye.[end]Marks the previous line’s next = NULL. Required for branch termini inside
an interaction. The very last line of an interaction is automatically a
dead-end, so [end] is only needed inside branches.
[jump @label] — Unconditional redirect
Section titled “[jump @label] — Unconditional redirect”CHARACTER: See you tomorrow.[jump @day_start]Overrides the next pointer of the previous line to point at @label
instead of the physically following line. Useful for merging branches or
looping back.
All Syntax at a Glance
Section titled “All Syntax at a Glance”| Syntax | Meaning |
|---|---|
# text |
Comment |
== Title == |
Section header (cosmetic) |
@bg Char bgVar |
Default background for character |
[interaction: name | desc] |
Start an interaction block |
CHAR: text |
Dialogue line (default bg) |
CHAR(bgVar): text |
Dialogue line with one-off bg override |
@label |
Name the next line |
[choice] |
Make previous line a selection node |
> Text -> @label |
Choice option (inside [choice]) |
[end] |
Previous line’s next = NULL |
[jump @label] |
Previous line’s next points to @label |
Generated Output
Section titled “Generated Output”.h file
Section titled “.h file”For each interaction:
extern dialogue park_akihiko_meets_yuki_lines[8];void park_akihiko_meets_yuki_init();inline dialogue* park_akihiko_meets_yuki_first() { ... }inline dialogue* park_akihiko_meets_yuki_some_label() { ... } // per @labelPlus a scene-wide convenience initialiser:
inline void park_init_all() { park_akihiko_meets_yuki_init(); park_hana_request_init(); // ...}.cpp file
Section titled “.cpp file”One array + one _init() function per interaction. All prev/next
pointers and selections vectors are wired up. Selections are declared as
local variables inside _init(), matching your hand-written style exactly.
Usage Patterns
Section titled “Usage Patterns”Trigger dialogue when the player interacts with an NPC or object
Section titled “Trigger dialogue when the player interacts with an NPC or object”if (playerTouches(npcAkihiko)) { dialogueCtrl.start(park_akihiko_meets_yuki_first());}if (playerTouches(noticeBoard)) { dialogueCtrl.start(park_notice_board_first());}Conditional entry point (skip to a different part of the interaction)
Section titled “Conditional entry point (skip to a different part of the interaction)”// If the player already accepted Hana's quest, start from her thank-you lineif (questAccepted) { dialogueCtrl.start(park_hana_request_hana_agree());} else { dialogueCtrl.start(park_hana_request_first());}Check if dialogue is still running in your update loop
Section titled “Check if dialogue is still running in your update loop”void sceneUpdate(u32 keys) { if (dialogueCtrl.isActive()) { dialogueCtrl.update(keys); }}One .dlg per scene/view. park.dlg, market.dlg, inn.dlg. Each gets
its own namespace so there are no naming collisions between scenes.
Only label what you need to jump to. Auto-generated line names (@line_0)
don’t appear in the header. Only your custom @labels become accessors.
@bg overrides are interaction-local. Writing @bg Yuki bgYukiNight
inside one interaction does not affect Yuki’s background in other interactions.
Multiple characters per interaction is natural. Just write each character’s lines in sequence. Backgrounds switch per-character or per-line as needed.
Signs, narration, environmental text: Use any “character” name —
Sign, Narrator, [System]. Pair with a per-line bg override.
Never edit the generated files. They are fully regenerated on every
compile. Your source of truth is the .dlg.
