//! 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` 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, ctx: &mut ActionCtx) -> (Option, Vec) { 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) }