Mode als Action

This commit is contained in:
2026-06-15 09:46:13 +02:00
parent 201d3be322
commit 93480150e5
3 changed files with 133 additions and 13 deletions
+38
View File
@@ -30,6 +30,44 @@ pub enum Action {
HideObject(String),
/// WAV unter `assets/audio/<name>` als SFX abspielen.
PlaySound(String),
/// Anzeige-/Eingabemodus wechseln (Spiel, Flycam, Menü). Vom Frontend
/// auf seinen `Mode` gemappt; der Dialog-Modus ist hier bewusst nicht
/// wählbar — der entsteht nur aus dem Story-Ablauf.
SetMode(ModeTarget),
}
/// Frontend-neutrales Ziel eines Moduswechsels. Spiegelt die nicht-Dialog-
/// Varianten von `session::Mode`, ohne dass der Kern die rich `Mode`-Daten
/// (Dialog-State) kennen muss. So bleibt `game` ← `session` eine Einbahnstraße.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModeTarget {
/// First-Person-Spiel.
Play,
/// Noclip-Debug-Flycam.
Free,
/// Menü (pausiert die Welt, gibt die Maus frei).
Menu,
}
impl ModeTarget {
/// `play`/`free`/`menu` (case-insensitiv) → Ziel; sonst `None`.
pub fn parse(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"play" => Some(Self::Play),
"free" => Some(Self::Free),
"menu" => Some(Self::Menu),
_ => None,
}
}
/// Kanonischer Name fürs Echo/Logging.
pub fn label(self) -> &'static str {
match self {
Self::Play => "play",
Self::Free => "free",
Self::Menu => "menu",
}
}
}
pub struct Game {
+20 -1
View File
@@ -16,6 +16,8 @@
//! `clear <name>` KV-Eintrag entfernen
//! `hide_object <name>` → Action::HideObject (deferred)
//! `play_sound <file>` → Action::PlaySound (deferred)
//! `mode <play|free|menu>` → Action::SetMode (deferred): Anzeige-/
//! Eingabemodus wechseln
//!
//! Parameter-Substitution: vor dem Parsen ersetzt `execute` `$self` in den
//! Action-Args durch `ctx.instance_name`. Damit kann eine generische Action
@@ -30,7 +32,7 @@
use std::collections::HashMap;
use std::fs::read_to_string;
use crate::engine::game::{Action, ActionCtx, Signals};
use crate::engine::game::{Action, ActionCtx, ModeTarget, Signals};
use crate::engine::kv;
use crate::engine::story_ctrl;
@@ -82,6 +84,9 @@ fn execute(cmd: &str, ctx: &mut ActionCtx) {
"clear" => kv::apply_clear(args, ctx.kv),
"hide_object" => ctx.actions.push(Action::HideObject(args.to_string())),
"play_sound" => ctx.actions.push(Action::PlaySound(args.to_string())),
"mode" => if let Some(t) = ModeTarget::parse(args) {
ctx.actions.push(Action::SetMode(t));
},
_ => { /* Unbekannter Verb/Tag → still ignorieren */ }
}
}
@@ -176,6 +181,20 @@ mod tests {
]);
}
#[test]
fn mode_verb_queues_setmode_action() {
let mut game = Game::new(Signals::new());
let mut ctx = game.action_ctx(None);
dispatch("mode free", &mut ctx);
assert_eq!(game.actions, vec![Action::SetMode(ModeTarget::Free)]);
// Unbekanntes Ziel → kein Action (stilles No-Op).
game.actions.clear();
let mut ctx = game.action_ctx(None);
dispatch("mode wat", &mut ctx);
assert!(game.actions.is_empty());
}
#[test]
fn unknown_signal_falls_through_to_builtin() {
let mut game = Game::new(Signals::new());