feat: m2 etagengenerierung — prefabs, floors, korridore, abstieg und sieg
Der handgebaute Testraum ist weg; Etagen entstehen aus Daten. - game/rng.rs: xorshift64*, Seed im Game (Ticket 14) - game/generate.rs: freie Platzierung, Pflichtraeume zuerst, Kette i->i-1 fuer strukturelle Erreichbarkeit, acht Orientierungen - data/: [[prefabs]] und [[floors]] als neunte und zehnte Registry, Ladepruefungen fuer rechteckige Layouts und Pflichtraum-Flaeche - Descend plus Siegbedingung: keine [[floors]] mit der naechsten Nummer heisst gewonnen — die Zahl 5 steht nirgends im Code - GameOver-Screen, mitlaufender Bildausschnitt im Grid Befund: Korridore stanzten 2340 Loecher in gezeichnete Waende, weil sie AUF der Tuer starteten. Erst Schritt nach aussen, dann L-Form, sonst Wegsuche ueber den freien Raum — die kann eine Raumwand nicht beruehren. Der Test zaehlt jetzt null. 21 Tests.
This commit is contained in:
@@ -11,7 +11,7 @@ use super::grid::GridWidget;
|
||||
use super::screen::{Response, Screen};
|
||||
use super::theme;
|
||||
use crate::data::Registries;
|
||||
use crate::game::{Attribute, CreatureRef, Game, Outcome};
|
||||
use crate::game::{Attribute, CreatureRef, Game, Outcome, RunOutcome};
|
||||
|
||||
pub struct App {
|
||||
/// `game` und `registries` sind **getrennte Felder**, damit die disjunkten
|
||||
@@ -66,6 +66,11 @@ pub fn run(game: Game, registries: Registries, warnings: usize, log_name: Option
|
||||
while app.screens.last().is_some_and(Screen::is_overlay) {
|
||||
app.screens.pop();
|
||||
}
|
||||
// Ticket 10/14: Der Lauf endet ueber `Game`, nicht ueber
|
||||
// die UI — die reagiert nur darauf.
|
||||
if app.game.over.is_some() {
|
||||
app.screens.push(Screen::GameOver);
|
||||
}
|
||||
}
|
||||
Response::Quit => break Ok(()),
|
||||
}
|
||||
@@ -82,6 +87,7 @@ fn draw(frame: &mut Frame, app: &App) {
|
||||
Screen::MainMenu => draw_main_menu(frame, area, app),
|
||||
Screen::Explore => draw_explore(frame, area, app),
|
||||
Screen::CharacterSheet => draw_sheet(frame, area, app),
|
||||
Screen::GameOver => draw_game_over(frame, area, app),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +134,7 @@ fn draw_explore(frame: &mut Frame, area: Rect, app: &App) {
|
||||
};
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"Zug {} │ {} │ c Charakterbogen │ {}",
|
||||
"Zug {} │ {} │ hjkl/Pfeile .warten >absteigen c Bogen │ {}",
|
||||
app.game.turn, app.game.player.name, note
|
||||
))
|
||||
.right_aligned()
|
||||
@@ -137,6 +143,38 @@ fn draw_explore(frame: &mut Frame, area: Rect, app: &App) {
|
||||
);
|
||||
}
|
||||
|
||||
/// Der Lauf wird am Ende **erzaehlt** — das ist der Moment, fuer den man die
|
||||
/// Etagen gespielt hat, und der Grund, warum Ticket 14 hier keinen Einzeiler im
|
||||
/// Hauptmenue wollte.
|
||||
fn draw_game_over(frame: &mut Frame, area: Rect, app: &App) {
|
||||
let (titel, farbe, zeile) = match app.game.over {
|
||||
Some(RunOutcome::Won) => (
|
||||
" Gewonnen ",
|
||||
Color::Green,
|
||||
"Du steigst ans Licht — der Keep liegt hinter dir.",
|
||||
),
|
||||
_ => (" Gestorben ", Color::Red, "Der Keep behält dich."),
|
||||
};
|
||||
|
||||
let text = vec![
|
||||
Line::from(app.game.player.name.clone().bold()),
|
||||
Line::from(""),
|
||||
Line::from(zeile),
|
||||
Line::from(""),
|
||||
Line::from(format!("Etage {}", app.game.floor.number)),
|
||||
Line::from(format!("Züge {}", app.game.turn)),
|
||||
Line::from(""),
|
||||
Line::from("Taste drücken").style(Style::new().fg(Color::DarkGray)),
|
||||
];
|
||||
|
||||
frame.render_widget(
|
||||
Paragraph::new(text)
|
||||
.centered()
|
||||
.block(Block::bordered().title(titel).style(Style::new().fg(farbe))),
|
||||
area,
|
||||
);
|
||||
}
|
||||
|
||||
/// Der Charakterbogen ist eine **Schleife ueber Registries**, kein gemauertes
|
||||
/// Layout — Modder koennen Slots und Wahlkategorien ergaenzen (Ticket 02).
|
||||
fn draw_sheet(frame: &mut Frame, area: Rect, app: &App) {
|
||||
|
||||
Reference in New Issue
Block a user