feat: m1 vertikaler durchstich — mod-lader, registries, attributberechnung, screen-stack
Ersetzt src/ vollstaendig: print_box, include_str! und enum ItemType fallen, wie Ticket 01-03 es vorgezeichnet haben. - data/: Mod-Lader mit zwei Suchpfaden, selbstheilender load_order.toml, drei Phasen und zweistufiger Deserialisierung (03/04) - game/: Attributkatalog, Creature, Game::attribute ueber mehrere Quellen, Command mit Outcome (01/07/11/12) - ui/: Screen-Stack mit Response, Grid-Widget, Press-Filter (06/11/12) - mods/core/: echte TOML-Dateien auf der Platte statt include_str! 10 Tests, darunter der Borrow-Beweis fuer Registries-neben-Game, den Ticket 12 nicht fuehren konnte.
This commit is contained in:
91
src/game/floor.rs
Normal file
91
src/game/floor.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
//! Etage — Ticket 10 entscheidet den Innenbau, M1 baut einen Testraum von Hand.
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Tile {
|
||||
Wall,
|
||||
Floor,
|
||||
Door,
|
||||
Stairs,
|
||||
Entrance,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Floor {
|
||||
pub number: u8,
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub tiles: Vec<Tile>,
|
||||
// TODO(M2): `rooms: Vec<Room>` und `player_room: Option<usize>` aus Ticket
|
||||
// 10 — mit ihnen kommen `room_entered`, Kampfbeginn und die
|
||||
// Raum-Beutetabellen. M1 hat genau einen Raum und braucht die
|
||||
// Buchfuehrung noch nicht.
|
||||
}
|
||||
|
||||
impl Floor {
|
||||
pub fn tile(&self, x: u16, y: u16) -> Tile {
|
||||
if x >= self.width || y >= self.height {
|
||||
return Tile::Wall;
|
||||
}
|
||||
self.tiles[y as usize * self.width as usize + x as usize]
|
||||
}
|
||||
|
||||
/// Handgebauter Testraum. Ticket 10 legt fest, dass Prefabs als ASCII-Bloecke
|
||||
/// geschrieben werden — deshalb steht der Raum hier schon in derselben Form,
|
||||
/// auch wenn der Generator erst in M2 kommt.
|
||||
pub fn test_room() -> Self {
|
||||
const LAYOUT: &[&str] = &[
|
||||
"########################",
|
||||
"#......................#",
|
||||
"#..####....######......#",
|
||||
"#..#..........#........#",
|
||||
"#..#..........#...##...#",
|
||||
"#.....####....#...##...#",
|
||||
"#........#........>....#",
|
||||
"#..<.....#.............#",
|
||||
"########################",
|
||||
];
|
||||
|
||||
let width = LAYOUT[0].len() as u16;
|
||||
let height = LAYOUT.len() as u16;
|
||||
let tiles = LAYOUT
|
||||
.iter()
|
||||
.flat_map(|row| row.chars())
|
||||
.map(|c| match c {
|
||||
'#' => Tile::Wall,
|
||||
'>' => Tile::Stairs,
|
||||
'<' => Tile::Entrance,
|
||||
'+' => Tile::Door,
|
||||
_ => Tile::Floor,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self { number: 1, width, height, tiles }
|
||||
}
|
||||
|
||||
/// Startfeld: das `<` im Layout, sonst das erste begehbare Feld.
|
||||
pub fn entrance(&self) -> (u16, u16) {
|
||||
for y in 0..self.height {
|
||||
for x in 0..self.width {
|
||||
if self.tile(x, y) == Tile::Entrance {
|
||||
return (x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
(1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn testraum_ist_rechteckig_und_hat_eingang() {
|
||||
let f = Floor::test_room();
|
||||
assert_eq!(f.tiles.len(), f.width as usize * f.height as usize);
|
||||
assert_eq!(f.tile(f.entrance().0, f.entrance().1), Tile::Entrance);
|
||||
// Rand ist geschlossen, sonst laeuft der Held aus der Karte.
|
||||
assert_eq!(f.tile(0, 0), Tile::Wall);
|
||||
assert_eq!(f.tile(f.width - 1, f.height - 1), Tile::Wall);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user