multilinear-story
A game-facing story runtime over a multilinear net.
It loads a multilinear net (a single .mld: aspect defaults before the first header, then events)
together with a presentation wiring file, then routes the currently callable events to their
owners and reads aspect state for presentation. This is the shared substrate behind the
callable-events-as-options pattern: an
interactable's options are the callable events wired to it, applying one is a transition, and the net
re-derives availability on its own.
The split
- Events are the actions (dialog options, interactions). An owner's options are its callable events — no variant selection, no conflict resolution. Multiple callable events simply mean multiple options.
- Aspects are exclusive, readable state (clothing, mood, location). Read via
value/value_nameto present, never to decide which events exist.
Save and restore
Story::state() returns the current aspect state as raw value indices (a Vec<usize>), and
Story::load_with_state(net, wiring, state) reloads a story with that state restored instead of
starting fresh. Serialize the Vec<usize> however you like; only restore it against the same net.
Jumping to a situation
Story::set_value(aspect, value) sets an aspect by name, bypassing the events that would normally
reach it, and Story::values(aspect) lists the value names an aspect can take. Together they let a
debug console or a command-line flag start a session anywhere in the net ("give the player the
sword, skip the tutorial"). Regular play still goes through options/play.
Wiring format
Header-based (via header-parsing); event names are header segments, so they may contain whitespace:
# events
## bibo talk
owner bibo
dialog bibo_talk
# idle
## bibo
dialog bibo_idle
Every wired event must exist in the net, or Story::load fails with LoadError::UnknownEvent. Net
events without wiring are reported as warnings (reachable but never surfaced).
Example
use Path;
use Story;
let mut story = load?;
for event in story.options
if let Some = story.options.first
println!; // present aspect state
AI-coding-friendly properties
- Errors are an explicit
thiserrorenum (LoadError) withDisplay;loadreturnsResultrather than silently falling back to an empty story. - No implicit state: routing is
options/play, reading isvalue/value_name— no hidden coupling. AspectandEventare re-exported, so consumers need not depend onmultilineardirectly.