34 lines
1.6 KiB
Rust
34 lines
1.6 KiB
Rust
//! Story-Lifecycle: Ink-Skript in den Story-Slot laden und schrittweise
|
|
//! treiben. Frontend-agnostisch — anders als in irl3d, wo `StoryState`
|
|
//! direkt in UI-Panels gegossen wurde, konsumiert hier der Aufrufer
|
|
//! (CLI-REPL jetzt, Panel-UI später) den Zustand selbst.
|
|
//!
|
|
//! Tags eines Schritts werden als `Vec<String>` zurückgegeben — der
|
|
//! Aufrufer entscheidet, ob/wie er sie via `signals::dispatch` weiterreicht
|
|
//! (vermeidet den Modul-Zyklus signals → story_ctrl → signals).
|
|
|
|
use crate::engine::assets;
|
|
use crate::engine::game::ActionCtx;
|
|
use crate::engine::ink::{Story, StoryState};
|
|
|
|
/// Lädt ein Ink-Skript (Pfad relativ zu `assets/interactions/`) in den
|
|
/// Story-Slot. Der erste Schritt passiert noch nicht — das Frontend ruft
|
|
/// dafür `advance(None, …)`.
|
|
pub fn start(script: &str, ctx: &mut ActionCtx) {
|
|
let path = assets::path(&format!("assets/interactions/{script}"));
|
|
*ctx.story = Some(Story::load(&path, ctx.kv));
|
|
}
|
|
|
|
/// Treibt die laufende Story einen Schritt weiter. `sel` ist die
|
|
/// Choice-Auswahl bzw. `None` beim ersten Schritt oder Text-Weiterklicken.
|
|
/// Bei `End` wird der Story-Slot geleert. Rückgabe: neuer Zustand (oder
|
|
/// `None` wenn gar keine Story läuft) plus Tags zum Dispatchen.
|
|
pub fn advance(sel: Option<usize>, ctx: &mut ActionCtx) -> (Option<StoryState>, Vec<String>) {
|
|
let Some(st) = ctx.story.as_mut() else { return (None, Vec::new()); };
|
|
if let Some(i) = sel { st.choose(i); }
|
|
let state = st.cont(ctx.kv);
|
|
let tags = st.take_tags();
|
|
if matches!(state, StoryState::End) { *ctx.story = None; }
|
|
(Some(state), tags)
|
|
}
|