First levels v0.1.0

This commit is contained in:
2026-05-21 17:12:23 +03:00
parent aa9cb6ea53
commit 19e39d220d
9 changed files with 749 additions and 22 deletions

View File

@@ -0,0 +1,67 @@
//! Levels — hand-written Rust generators paired with design notes.
//!
//! Each level is implemented in `l<XX>_<name>.rs` and is the authoritative
//! source of truth for what target YAML the player must reproduce and how
//! the description is rendered.
//!
//! The paired `l<XX>.md` file is a **design note only**: it documents the
//! intended scene and a minimal example of the target YAML. `.md` files
//! are *not* loaded at runtime — there is no `include_str!` and no
//! markdown parser. If a `.md` and its paired `.rs` ever disagree, the
//! `.rs` wins.
pub mod l01_minimum;
pub mod l02_kv;
use serde::{Deserialize, Serialize};
/// Game-wide difficulty. Chosen once on the TierSelect screen; persisted
/// in `Progress.tier`. Maps to a fixed passing threshold per level.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum Difficulty {
Easy,
Medium,
Hard,
}
impl Difficulty {
pub fn threshold(self) -> f64 {
match self {
Self::Easy => 0.70,
Self::Medium => 0.80,
Self::Hard => 0.95,
}
}
pub fn label(self) -> &'static str {
match self {
Self::Easy => "Easy (70%)",
Self::Medium => "Medium (80%)",
Self::Hard => "Hard (95%)",
}
}
}
/// What `Level::generate` returns: the canonical target YAML to grade
/// against, the player-facing description (already rendered), and the
/// dungeon flavor line.
pub struct Generated {
pub target_yaml: String,
pub description: String,
pub flavor: String,
}
/// One level's generator. Implementations live in `l<XX>_<name>.rs`.
pub trait Level {
fn id(&self) -> u8;
fn name(&self) -> &'static str;
fn generate(&self, seed: u64) -> Generated;
}
/// Ordered registry of all levels. `registry()[0]` is level 1.
pub fn registry() -> Vec<Box<dyn Level>> {
vec![
Box::new(l01_minimum::Minimum),
Box::new(l02_kv::KeyValue),
]
}