Skip to content

LSDE Dialog Engine / LsdeUtils

Class: LsdeUtils ​

Defined in: lsde-utils.ts:33

Public utility class exposing common helpers for game developers integrating the LSDE engine.

Constructors ​

Constructor ​

new LsdeUtils(): LsdeUtils

Returns ​

LsdeUtils

Properties ​

evaluateConditionCases ​

static evaluateConditionCases: (cases, portPerCase, evaluator) => string

Defined in: lsde-utils.ts:184

The exit port of a condition block: out/default in if mode, K1… with portPerCase. Replaces the v1 evaluateConditionGroups, which returned an index and had a third, dispatcher mode that no longer exists.

Pick the exit port of a condition block. There are two modes and only two.

portPerCaseruleexit
absentevery case must holdout if they all do, default otherwise
truethe first case that holds, in orderits own port (K1…), default if none

A case with no when is always true — and makes every case below it unreachable in portPerCase mode. That is the writer's drawing, not an error to report.

A block with no cases at all leaves by out: nothing was asked, so nothing failed.

Parameters ​

cases ​

ConditionCase[] | undefined

portPerCase ​

boolean

evaluator ​

ConditionEvaluator

Returns ​

string


evaluateConditionChain ​

static evaluateConditionChain: (tests, evaluator) => boolean

Defined in: lsde-utils.ts:177

Evaluate a chain of tests left to right, with NO operator precedence. Absent or empty means true — which is how "always" is written in v2.

Evaluate a chain of tests left to right, with no operator precedence.

a AND b OR c reads as (a AND b) OR c, never as a AND (b OR c). That is deliberate: the editor draws a flat list, so the engine evaluates a flat list. A writer who needs grouping uses two condition blocks in a row, which is also what the reader of the graph sees.

join links a test to the one ABOVE it and is absent on the first. Missing means AND.

Every test is evaluated, even once the answer is settled. No short-circuit: the game's evaluator is also where a project logs, counts or displays what was asked, and skipping calls would make that log depend on the order the writer happened to use.

No tests at all = true. That is how "always" is written in v2 — by the ABSENCE of when, never by an empty list.

Parameters ​

tests ​

ConditionTest[] | undefined

evaluator ​

ConditionEvaluator

Returns ​

boolean


evaluateEachCase ​

static evaluateEachCase: (cases, evaluator) => boolean[]

Defined in: lsde-utils.ts:187

Each case on its own, in order — to show what matched without changing where the flow goes.

Evaluate every case on its own, without picking a port.

Handed to a game that wants to show what matched without changing where the flow goes. The engine fills context.cases[i].result with the same rule, then reads the exit port off those results, by the same rule evaluateConditionCases applies — never by calling this and deciding for itself.

Parameters ​

cases ​

ConditionCase[] | undefined

evaluator ​

ConditionEvaluator

Returns ​

boolean[]


isActionBlock ​

static isActionBlock: (block) => block is ActionBlock

Defined in: lsde-utils.ts:49

Returns true if the block is an action.

Parameters ​

block ​

Block

Returns ​

block is ActionBlock


isChoiceBlock ​

static isChoiceBlock: (block) => block is ChoiceBlock

Defined in: lsde-utils.ts:43

Returns true if the block is a choice.

Parameters ​

block ​

Block

Returns ​

block is ChoiceBlock


isChoiceCondition ​

static isChoiceCondition: (test) => boolean = isChoiceTest

Defined in: lsde-utils.ts:166

Does this test read a past answer of the player rather than game state?

choice is a reserved dictionary id that no project dictionary may take: entry is a CHOICE block id of this scene, value an option id of that block. The engine answers these from its own history, so a game never has to remember what it already told the engine.

Is this test about what the player already answered, rather than about game state?

choice is a reserved dictionary id — no project dictionary may take it. entry is a CHOICE block id of this scene and value an option id of that block. The engine answers these from the history it kept during the scene, so they never reach the game's evaluator: a game does not have to remember what it already told the engine.

Parameters ​

test ​

ConditionTest

Returns ​

boolean


isConditionBlock ​

static isConditionBlock: (block) => block is ConditionBlock

Defined in: lsde-utils.ts:45

Returns true if the block is a condition.

Parameters ​

block ​

Block

Returns ​

block is ConditionBlock


isDialogBlock ​

static isDialogBlock: (block) => block is DialogBlock

Defined in: lsde-utils.ts:41

Returns true if the block is a dialog.

Parameters ​

block ​

Block

Returns ​

block is DialogBlock


isNoteBlock ​

static isNoteBlock: (block) => block is NoteBlock

Defined in: lsde-utils.ts:51

Returns true if the block is a note.

Parameters ​

block ​

Block

Returns ​

block is NoteBlock


isRouterBlock ​

static isRouterBlock: (block) => block is RouterBlock

Defined in: lsde-utils.ts:47

Returns true if the block is a router.

Parameters ​

block ​

Block

Returns ​

block is RouterBlock


locale ​

static locale: string | null = null

Defined in: lsde-utils.ts:36

Current locale set by engine.setLocale(). Used as the default by the text helpers.


pickRouterPorts ​

static pickRouterPorts: (cases, results) => string[]

Defined in: lsde-utils.ts:194

The exits of a ROUTER, from case results already computed: the port of every true case, then then when they all held or catch when one did not — always last. The router's reading of the same cases a condition carries.

A ROUTER's exits: the port of every true case, then then or catch.

The opposite reading of the same cases a condition carries. A condition asks which one and leaves by a single port; a router asks which ones, launches each of them, and continues besides — by then when every case held, by catch when any did not.

Three rules this encodes, all of them from the format's own contract:

  • No break. Every case is counted, so a false one in the middle does not hide the true ones after it. That is the whole difference with a condition.
  • The tally is over CASES, not over ports. A port carrying several wires launches several tracks and still counts as one case — and two cases wired to the same block dispatch it twice.
  • No cases at all → then, the way Promise.all([]) resolves.

The continuation is LAST in the list on purpose: the traversal keeps the first non-async target as the main flow, so then/catch stays the main flow as long as the case routes are async.

catch cancels nothing. The tracks of the true cases are already running by the time the tally is read — exactly like a Promise.all that rejects while its promises carry on.

Parameters ​

cases ​

ConditionCase[] | undefined

results ​

boolean[]

Returns ​

string[]


tagOptionVisibility ​

static tagOptionVisibility: (options, evaluator) => RuntimeChoiceItem[]

Defined in: lsde-utils.ts:201

Tag every option of a choice with whether its when holds, returning them ALL. Replaces the v1 filterVisibleChoices, which shortened the list and took away the ability to show a locked answer.

Tag every option of a choice with whether its when holds.

The engine hands over all the options, tagged — never a shortened list. A game that wants only the offered ones writes options.filter( o => o.visible !== false ); a game that wants to grey out the others, or show "[locked]", still has them. Filtering here would take that away.

visible is left undefined when no evaluator is installed: unknown, not hidden.

Parameters ​

options ​

Option[] | undefined

evaluator ​

ConditionEvaluator | undefined

Returns ​

RuntimeChoiceItem[]

Methods ​

getBlockLabel() ​

static getBlockLabel(block): string

Defined in: lsde-utils.ts:62

How to name a block on screen or in a log.

There is no mandatory block name in v2, and none is needed: DIALOG-007 already reads better than the uuid it replaced. A designer note says far more than a three-word label would, so it comes next; a label wins when an export carries one.

Parameters ​

block ​

Block

Returns ​

string


getChoiceConditionBlockId() ​

static getChoiceConditionBlockId(test): string | undefined

Defined in: lsde-utils.ts:169

The CHOICE block a choice: test reads, or undefined for any other test.

Parameters ​

test ​

ConditionTest

Returns ​

string | undefined


getCustomProperties() ​

static getCustomProperties(block): PropertyBag

Defined in: lsde-utils.ts:145

The properties the DESIGNER declared, with the natives taken out — everything the game is free to give its own meaning to.

Parameters ​

block ​

Block

Returns ​

PropertyBag


getLocalizedText() ​

static getLocalizedText(text, locale?): string | undefined

Defined in: lsde-utils.ts:74

Pick a locale out of an inline text map — block.text, or an option's.

Only works when texts were exported INSIDE the payload. With the separate mode, the blocks carry no text at all and getTextFromTable is the one to use.

Parameters ​

text ​

TextByLocale | undefined

locale? ​

string

Returns ​

string | undefined

Throws ​

when no locale is set, by parameter or by engine.setLocale().


getNativeProperties() ​

static getNativeProperties(block): NativeProperties

Defined in: lsde-utils.ts:130

The properties the ENGINE acts on, pulled out of a block's props.

v2 puts natives and the designer's own properties in one bag, keyed by bare id, and ids cannot collide — LSDE refuses a project property that takes a native name. So this is a lookup against NATIVE_PROPERTY_IDS, not a guess.

delay and timeout are MILLISECONDS. They were seconds in v1 and nothing reports the change at runtime: a migrated project turns a 3-second pause into 3 ms.

Parameters ​

block ​

Block

Returns ​

NativeProperties


getTextFromTable() ​

static getTextFromTable(table, scene, blockId, optionId?): string | undefined

Defined in: lsde-utils.ts:91

Read a line out of a loaded localization/<locale>/__blueprints__.json, for the separate text mode.

The game loads the file — the engine does no IO, ever. Pass the block's scene and id, plus an option id for one answer of a choice.

ts
const fr = JSON.parse( await readFile( 'localization/fr/__blueprints__.json', 'utf-8' ) );
LsdeUtils.getTextFromTable( fr, 'reactor_breach', 'DIALOG-001' );
LsdeUtils.getTextFromTable( fr, 'reactor_breach', 'CHOICE-001', 'C1' );

Parameters ​

table ​

LocaleTable | undefined

scene ​

string

blockId ​

string

optionId? ​

string

Returns ​

string | undefined


getTextKey() ​

static getTextKey(block, optionId?): string

Defined in: lsde-utils.ts:114

The i18n key of a block, or of one option of a choice.

The key is already in the payload (block.key), so this only builds the option variant — useful for a voice file, whose name is derived from the key.

Parameters ​

block ​

Block

optionId? ​

string

Returns ​

string