dialogue
dialogue
¶
Branching dialogue with a typewriter reveal, choices and rich text.
This is an opt-in module, imported on its own with import nim2d/dialogue.
The core engine does not pull it in.
A conversation is a Script: nodes keyed by id, each with a speaker, an
optional portrait, one or more pages of text, and choices that branch to
other nodes. You build a script as plain Nim data (a parser for a file format
could target the same shape later), hand it to newDialogue, and start it.
Each frame the game calls update and draw, and routes keys through
handleKey.
Text is rich. A page is a string with a small markup the renderer understands:
*italic* and **bold** as in markdown, plus bracket tags closed with [/]
and nestable: [b] bold, [i] italic, [o] a per-character outline (a border
on the glyphs, not the box), [#ffcc00] a hex color and [gold] a palette
name. So "The [#ff5555]dragon[/] **roars**. *You* feel [o]afraid[/]." works.
Two ways to render. The simple path is a Style record (a font set, a box,
colors, padding) feeding the built-in renderer. The advanced path sets Hooks
to take over the box, the text or the choices, any left nil falling back to the
default, so a game can lay the message out however it likes while keeping the
markup.
Choice
¶
type Choice = object
Fields
-
textstring– the label shown -
gotostring– the node it leads to ("" ends the dialogue) -
condproc (): bool– when set, the choice is hidden while it returns false -
actionproc ()– when set, runs as the choice is picked
Node
¶
type Node = object
Fields
-
idstring -
speakerstring– optional name label -
portraitImage– optional image drawn beside the text -
pagesseq[string]– one or more screens of text, shown before the choices -
choicesseq[Choice]– empty means a plain line -
nextstring– where a choiceless node goes on advance ("" ends) -
onEnterproc ()– optional side effect when the node becomes current
Script
¶
type Script = ref object
Fields
-
nodesTable[string, Node]
RevealKind
¶
type RevealKind = enum
Values
-
rvTypewriter– one character at a time -
rvWord– one word at a time -
rvFade– all at once, fading in -
rvInstant– shown immediately
Reveal
¶
type Reveal = object
Fields
-
kindRevealKind -
cpsfloat– characters (or words for rvWord) per second -
punctuationPausefloat– extra seconds after . ! ? , ; : -
fadeTimefloat– seconds for rvFade -
onGlyphproc (r: Rune)– called for each character as it appears -
customproc (d: Dialogue; dt: float): bool– a fully custom reveal: advance it by `dt`, set `d.shown` (out of `d.totalRunes`), and return true when complete. Used when set, whatever `kind` is.
Style
¶
type Style = object
Fields
-
fontstuple[regular, bold, italic, boldItalic: Font]– the regular font is required; the others are used for bold/italic when set, and faked otherwise (bold by a double draw, italic by a shear) -
boxtuple[x, y, w, h: float]– where the box sits; leave w at 0 for an automatic strip across the bottom of the window -
paddingfloat -
roundnessfloat -
lineSpacingfloat -
alignAlign -
boxColorColor -
textColorColor -
speakerColorColor -
choiceColorColor -
choiceHighlightColor -
outlineColorColor -
outlineWidthfloat– border thickness for outlined text (0 uses 1.5) -
outlineTextbool– outline every character, not only `[o]` spans
Hooks
¶
type Hooks = object
Fields
-
drawBoxproc (nim2d: Nim2d; d: Dialogue) -
drawTextproc (nim2d: Nim2d; d: Dialogue) -
drawChoicesproc (nim2d: Nim2d; d: Dialogue)
DialogueState
¶
type DialogueState = enum
Values
-
dsRevealing– text is still appearing -
dsWaiting– a page is fully shown, waiting to advance -
dsChoosing– the last page is shown and choices are up -
dsDone– the conversation has ended
Dialogue
¶
type Dialogue = ref object
Fields
-
scriptScript -
styleStyle -
revealReveal -
hooksHooks -
currentstring– current node id -
pageint– current page within the node -
stateDialogueState -
cursorint– highlighted choice (index into the visible choices) -
shownint– revealed rune count -
totalRunesint -
onFinishproc ()– called once when the conversation ends
newScript ¶
proc newScript(): Script
add ¶
proc add(s: Script; node: Node)
Add a node, or replace one with the same id.
Parameters
-
s(Script) -
node(Node)
has ¶
proc has(s: Script; id: string): bool
Whether the script has a node with this id.
Parameters
-
s(Script) -
id(string)
Returns
bool
choice ¶
proc choice(text, goto: string; cond: proc (): bool = nil; action: proc () = nil): Choice
A choice leading to goto, optionally gated by cond and with the side
effect action that runs when it is picked.
Parameters
-
text(string) -
goto(string) -
cond(proc (): bool) -
action(proc ())
Returns
Choice
defaultReveal ¶
proc defaultReveal(): Reveal
A typewriter reveal at a readable speed with a small pause on punctuation.
Returns
Reveal
defaultStyle ¶
proc defaultStyle(font: Font): Style
A dark rounded box with light text, ready to use. Set box for a custom
position, or leave it for an automatic strip across the bottom of the window.
Parameters
-
font(Font)
Returns
Style
currentNode ¶
proc currentNode(d: Dialogue): Node
The node being shown, or an empty node if the current id is unknown.
Parameters
-
d(Dialogue)
Returns
Node
visibleChoices ¶
proc visibleChoices(d: Dialogue): seq[Choice]
The choices on the current node whose cond allows them.
Parameters
-
d(Dialogue)
Returns
seq[Choice]
start ¶
proc start(d: Dialogue; nodeId: string)
Begin (or jump to) a node, from its first page. Runs the node's onEnter.
Parameters
-
d(Dialogue) -
nodeId(string)
update ¶
proc update(d: Dialogue; nim2d: Nim2d; dt: float)
Advance the reveal. Call once a frame while the dialogue is active. Takes
nim2d because the text is laid out against the window and the box.
Parameters
-
d(Dialogue) -
nim2d(Nim2d) -
dt(float)
active ¶
proc active(d: Dialogue): bool
Whether a conversation is currently up.
Parameters
-
d(Dialogue)
Returns
bool
isRevealing ¶
proc isRevealing(d: Dialogue): bool
Whether the current page is still appearing.
Parameters
-
d(Dialogue)
Returns
bool
select ¶
proc select(d: Dialogue)
choose ¶
proc choose(d: Dialogue; index: int)
Pick a visible choice directly by index (for mouse selection).
Parameters
-
d(Dialogue) -
index(int)
advance ¶
proc advance(d: Dialogue)
The single "continue" action. While revealing it skips to the full text;
while waiting it moves to the next page or ends the line; while choosing it confirms the highlighted choice.
Parameters
-
d(Dialogue)
moveCursor ¶
proc moveCursor(d: Dialogue; delta: int)
Move the choice highlight, wrapping around.
Parameters
-
d(Dialogue) -
delta(int)
handleKey ¶
proc handleKey(d: Dialogue; key: Key)
Route a key: space or enter advances and confirms, the arrows move the
choice highlight. Call from the engine's keydown.
Parameters
-
d(Dialogue) -
key(Key)
draw ¶
proc draw(d: Dialogue; nim2d: Nim2d)
Draw the box, the revealed text and any choices. A no-op when the dialogue
is done. Call inside the engine's draw, after the world.
Parameters
-
d(Dialogue) -
nim2d(Nim2d)
choiceAt ¶
proc choiceAt(d: Dialogue; nim2d: Nim2d; mx, my: float): int
The index of the visible choice under (mx, my) with the default choice
layout, or -1. Useful for mouse selection.
Parameters
-
d(Dialogue) -
nim2d(Nim2d) -
mx(float) -
my(float)
Returns
int
newDialogue ¶
proc newDialogue(script: Script; style: Style; reveal: Reveal = defaultReveal()): Dialogue
A dialogue player over script, drawn with style. Call start to begin.
Parameters
-
script(Script) -
style(Style) -
reveal(Reveal)
Returns
Dialogue
DialogueScene
¶
type DialogueScene = ref object
A Scene wrapping a Dialogue, forwarding update, draw and input. Push it
on a SceneManager and set dlg.onFinish to pop it when the talk ends.
Fields
-
dlgDialogue
newDialogueScene ¶
proc newDialogueScene(dlg: Dialogue): DialogueScene
Wrap a dialogue as a scene.
Parameters
-
dlg(Dialogue)
Returns
DialogueScene