Renamed Play State
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ fn prompt_for(mode: &Mode) -> &'static str {
|
||||
Mode::Dialog(d) if !d.choices.is_empty() => " wahl> ",
|
||||
Mode::Dialog(_) => " [Enter] ",
|
||||
Mode::Menu => "menü> ",
|
||||
Mode::Play => "spiel> ",
|
||||
Mode::FirstPerson => "spiel> ",
|
||||
Mode::Free => "> ",
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -339,7 +339,7 @@ impl App {
|
||||
// die Maus (relativer Blick); Menü/Dialog geben sie frei fürs UI. So
|
||||
// gibt es keine parallele Lock-Logik.
|
||||
let fly = matches!(self.session.mode, Mode::Free);
|
||||
let play = matches!(self.session.mode, Mode::Play);
|
||||
let play = matches!(self.session.mode, Mode::FirstPerson);
|
||||
let grab = fly || play;
|
||||
if grab != self.input.grabbed { self.set_grab(grab); }
|
||||
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ pub(crate) fn layout(internal: [f32; 2], fonts: &Fonts, session: &Session, cur:
|
||||
match &session.mode {
|
||||
// Spiel und Flycam: nur HUD/Cursor, kein Panel (beide laufen
|
||||
// ohnehin gefangen — dieser Zweig greift nur im Übergang).
|
||||
Mode::Play | Mode::Free => {}
|
||||
Mode::FirstPerson | Mode::Free => {}
|
||||
Mode::Menu => menu(&mut ui, f, internal, cur.pos, &mut hover),
|
||||
Mode::Dialog(d) => dialog(&mut ui, f, internal, d, cur.pos, &mut hover),
|
||||
}
|
||||
|
||||
+12
-46
@@ -1,22 +1,3 @@
|
||||
//! Session: der geteilte Anwendungszustand über allen Frontends.
|
||||
//!
|
||||
//! Es existiert genau eine `Session` pro Lauf. CLI und Fenster steuern
|
||||
//! dieselbe — das Fenster besitzt sie, die Terminal-Eingabe schickt nur
|
||||
//! Befehlszeilen hinein. Dadurch kann es keinen Mismatch geben: ein
|
||||
//! `Game`-Zustand, ein `Mode`, beide Frontends stellen ihn nur dar.
|
||||
//!
|
||||
//! Schicht: `engine ← session ← { cli, render }`. Die Session kennt kein
|
||||
//! Frontend — `exec` nimmt eine Befehlszeile und *gibt* Ausgabezeilen
|
||||
//! zurück (statt zu drucken), damit jedes Frontend sie frei darstellt
|
||||
//! (Terminal jetzt, In-Fenster-Konsole später).
|
||||
//!
|
||||
//! Die Session ist auch der alleinige Besitzer der **Lauf-Simulation**:
|
||||
//! `Player` und `CollisionWorld`. Sie hat zwei Eingabe-Tore — `exec` für
|
||||
//! diskrete Befehle/Dialog und `tick` für die kontinuierliche Physik pro
|
||||
//! Frame. Die Frontends sammeln nur Eingaben und stellen den Zustand dar;
|
||||
//! die Flycam dagegen ist reine Frontend-Sicht (kein Sim-Zustand) und bleibt
|
||||
//! im `render`-Modul.
|
||||
|
||||
use crate::engine::collision::CollisionWorld;
|
||||
use crate::engine::game::{Action, Game, ModeTarget};
|
||||
use crate::engine::ink::StoryState;
|
||||
@@ -27,28 +8,13 @@ use crate::engine::{kv, signals, story_ctrl};
|
||||
/// Maus-Empfindlichkeit der Spieler-Sicht (Radiant/Pixel).
|
||||
const LOOK_SENS: f32 = 0.0025;
|
||||
|
||||
/// Was die Frontends gerade darstellen sollen. Geteilt, damit CLI und GUI
|
||||
/// nie uneins sind, ob ein Dialog läuft.
|
||||
pub enum Mode {
|
||||
/// First-Person-Spiel — der Player bewegt sich mit Physik durch die Welt
|
||||
/// (siehe engine::player). Der Renderer leitet seine View aus dem Player
|
||||
/// ab. Das ist der eigentliche Spielmodus.
|
||||
Play,
|
||||
/// Noclip-Debug-Flycam — frei schwebende Kamera ohne Physik. Per
|
||||
/// `noclip`-Befehl gegen `Play` getauscht.
|
||||
FirstPerson,
|
||||
Free,
|
||||
/// Menü offen — wie der Dialog pausiert das Fenster die Welt und gibt die
|
||||
/// Maus frei; Eingaben sind weiter Engine-Befehle (das Menü ist nur eine
|
||||
/// andere Darstellung). Per `menu`-Befehl getoggelt; „Fortsetzen" führt
|
||||
/// ins Spiel (`Play`).
|
||||
Menu,
|
||||
/// Ein Dialog läuft — das Fenster pausiert die Welt und zeigt Panels;
|
||||
/// Eingaben treiben den Dialog statt Befehle.
|
||||
Dialog(Dialog),
|
||||
}
|
||||
|
||||
/// Aktueller Dialogschritt, frontend-neutral. `choices` leer = reiner Text,
|
||||
/// der auf „weiter" (Leerzeile/Enter) wartet.
|
||||
pub struct Dialog {
|
||||
// Wird vom Panel-Renderer der UI-Phase gelesen; bis dahin läuft der
|
||||
// Dialogtext über die Konsolen-Ausgabe (siehe `step`).
|
||||
@@ -115,7 +81,7 @@ impl Session {
|
||||
/// `exec`. Nur im Spielmodus bewegt sich der Spieler; Menü/Dialog/Flycam
|
||||
/// pausieren die Sim (die Flycam ist reine Frontend-Sicht).
|
||||
pub fn tick(&mut self, input: &FrameInput, dt: f32) {
|
||||
if matches!(self.mode, Mode::Play) {
|
||||
if matches!(self.mode, Mode::FirstPerson) {
|
||||
self.player.look(input.look_dx, input.look_dy, LOOK_SENS);
|
||||
self.player.step(&self.collision, input.fwd, input.right, input.jump, dt);
|
||||
}
|
||||
@@ -135,7 +101,7 @@ impl Session {
|
||||
pub fn exec(&mut self, line: &str) -> ExecResult {
|
||||
match self.mode {
|
||||
Mode::Dialog(_) => self.dialog_input(line),
|
||||
Mode::Play | Mode::Free | Mode::Menu => self.command(line),
|
||||
Mode::FirstPerson | Mode::Free | Mode::Menu => self.command(line),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +125,7 @@ impl Session {
|
||||
// Debug: zwischen First-Person (Play) und freier Flycam (Free)
|
||||
// umschalten.
|
||||
let t = match self.mode {
|
||||
Mode::Play => ModeTarget::Free,
|
||||
Mode::FirstPerson => ModeTarget::Free,
|
||||
_ => ModeTarget::Play,
|
||||
};
|
||||
self.set_mode(t);
|
||||
@@ -219,7 +185,7 @@ impl Session {
|
||||
// geladen haben, während die alte auf End lief (mode → Play). Falls
|
||||
// das passiert ist, sofort den ersten Schritt der neuen Story ziehen
|
||||
// statt den Spieler im Play-Modus hängen zu lassen.
|
||||
if self.game.story.is_some() && matches!(self.mode, Mode::Play) {
|
||||
if self.game.story.is_some() && matches!(self.mode, Mode::FirstPerson) {
|
||||
out.extend(self.step(None));
|
||||
}
|
||||
ExecResult::lines(out)
|
||||
@@ -252,7 +218,7 @@ impl Session {
|
||||
let mut out = self.drain_actions();
|
||||
match state {
|
||||
None | Some(StoryState::End) => {
|
||||
self.mode = Mode::Play;
|
||||
self.mode = Mode::FirstPerson;
|
||||
}
|
||||
Some(StoryState::Text(text)) => {
|
||||
out.push(text.clone());
|
||||
@@ -293,7 +259,7 @@ impl Session {
|
||||
/// entsteht ausschließlich in `step` aus dem Story-Ablauf.)
|
||||
fn set_mode(&mut self, t: ModeTarget) {
|
||||
self.mode = match t {
|
||||
ModeTarget::Play => Mode::Play,
|
||||
ModeTarget::Play => Mode::FirstPerson,
|
||||
ModeTarget::Free => Mode::Free,
|
||||
ModeTarget::Menu => Mode::Menu,
|
||||
};
|
||||
@@ -376,7 +342,7 @@ mod tests {
|
||||
s.exec("menu");
|
||||
assert!(matches!(s.mode, Mode::Menu));
|
||||
s.exec("menu"); // „Fortsetzen" → ins Spiel
|
||||
assert!(matches!(s.mode, Mode::Play));
|
||||
assert!(matches!(s.mode, Mode::FirstPerson));
|
||||
s.exec("menu"); // aus dem Spiel wieder ins Menü
|
||||
assert!(matches!(s.mode, Mode::Menu));
|
||||
// Im Menü laufen Engine-Befehle weiter (gleiche Route wie Play/Free).
|
||||
@@ -388,7 +354,7 @@ mod tests {
|
||||
fn mode_command_sets_mode_directly() {
|
||||
let mut s = empty_session();
|
||||
s.exec("mode play");
|
||||
assert!(matches!(s.mode, Mode::Play));
|
||||
assert!(matches!(s.mode, Mode::FirstPerson));
|
||||
s.exec("mode free");
|
||||
assert!(matches!(s.mode, Mode::Free));
|
||||
s.exec("mode menu");
|
||||
@@ -405,17 +371,17 @@ mod tests {
|
||||
s.mode = Mode::Free;
|
||||
// `mode`-Verb direkt als Action (Ink-Tag-/signals.toml-Pfad).
|
||||
s.exec("signal mode play");
|
||||
assert!(matches!(s.mode, Mode::Play));
|
||||
assert!(matches!(s.mode, Mode::FirstPerson));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn noclip_toggles_play_and_free() {
|
||||
let mut s = empty_session();
|
||||
s.mode = Mode::Play;
|
||||
s.mode = Mode::FirstPerson;
|
||||
s.exec("noclip");
|
||||
assert!(matches!(s.mode, Mode::Free));
|
||||
s.exec("noclip");
|
||||
assert!(matches!(s.mode, Mode::Play));
|
||||
assert!(matches!(s.mode, Mode::FirstPerson));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user