Skip to main content

Stages and Dialogues

The dialogue system is built on two lists inside a stage: texts (what's said) and transfers (where you can go). Both lists use the same trick — conditional visibility: each option carries its own condition, and the engine picks the first one that matches, in order. An empty condition {} always matches — a convenient way to define a "default" option at the end of the list.

texts — scene text variants

"texts": [
{ "text": "Come in if it's business — I'm busy right now.", "condition": { "has": ["sidorovich_job"] } },
{ "text": "Oh, a shooter! Come in, we need to talk.", "condition": {} }
]

This lets the same stage say different things depending on the player's progress, without creating a separate stage for every variant. A typical pattern: the last item in the list is a variant with an empty condition ({}) as a fallback in case none of the more specific variants matched.

transfers — transitions to other stages

"transfers": [
{ "text": "I'll take the job", "stage": "stage_accept", "condition": { "!has": ["sidorovich_job"] } },
{ "text": "How's the job going?", "stage": "stage_progress", "condition": { "has": ["sidorovich_job"] } },
{ "text": "Bye, things to do", "stage": "stage_exit", "condition": {} }
]

Each transfer is a choice button the player sees, but only if its condition is satisfied. This is how branching dialogues are made: reply options appear or disappear depending on inventory, flags, or progress.

In practice

Build your dialogue so a stage's last line always has at least one transfer with the condition {} — otherwise a player can get stuck on a stage with no available options (if none of the other conditions were met).

Placeholders in Text

You can interpolate the current player's data into texts and message:

PlaceholderSubstituted with
@nameCharacter's name
@nicknameCallsign
@moneyAmount of money
@xpAmount of experience
@loginAccount login
@locationCurrent location
@gangPlayer's faction
@pdaIdPDA identifier
{ "text": "Hey, @nickname! You've got @money RU on your account — enough for a new piece." }

Transfer stages (utility types)

Not every stage shows text. Three stage types serve a technical role and don't need texts:

  • type_stage: 4 (map transfer) — uses data: { map, pos } to open the game map at a given point. Dialogues typically end this way: "go there" → the player sees the map.
  • type_stage: 5 (load another chapter) — hands off execution to another chapter of the story via the openStage action, convenient for splitting a long story into chapters without duplicating logic.
  • type_stage: 6 (transfer to a trader) — opens a specific trader's trading window via the openSeller action.

Node position on the canvas (editor.x / editor.y)

The editor: { x, y } field only stores the node's coordinates on the canvas in the story editor — it has no effect on gameplay. You don't need to touch it by hand when working with "raw" JSON — the editor lays out new nodes itself via automatic graph layout (dagre).

Next

  • Conditions — a detailed look at how the condition language works.
  • Actions — the full list of commands a stage can execute.