new layer model
This commit is contained in:
+67
-1
@@ -12,7 +12,63 @@
|
||||
|
||||
use crate::glyph::Glyph;
|
||||
use color::Rgba8;
|
||||
use tinyrand::{Probability, Rand, StdRand};
|
||||
use tinyrand::{Probability, Rand, Seeded, StdRand};
|
||||
|
||||
/// A board's floor: the cosmetic backdrop drawn beneath everything, replacing the
|
||||
/// old dedicated floor *layer*. A board has exactly one [`Floor`] (see
|
||||
/// [`Board::floor`](crate::board::Board)), given in the map file's `[map]` header
|
||||
/// as an optional `floor = { … }` attribute.
|
||||
///
|
||||
/// Three forms: [`Blank`](Floor::Blank) (the canonical empty/black cell shows
|
||||
/// through), [`Fixed`](Floor::Fixed) (one glyph tiled across the whole board), or
|
||||
/// [`Biome`](Floor::Biome) (a procedural [`FloorGenerator`] texture). A biome keeps
|
||||
/// its generator (so save re-emits the generator name) alongside a per-cell glyph
|
||||
/// buffer pre-rolled once at load from [`FLOOR_SEED`] — deterministic, and the
|
||||
/// direct replacement for the old per-cell floor-layer rolling.
|
||||
#[derive(Clone)]
|
||||
pub enum Floor {
|
||||
/// No floor: the canonical black empty cell shows.
|
||||
Blank,
|
||||
/// A single fixed glyph tiled across the whole board.
|
||||
Fixed(Glyph),
|
||||
/// A procedural biome floor: the `generator` (retained for save) plus a
|
||||
/// `glyphs` buffer holding one pre-rolled glyph per cell (row-major).
|
||||
Biome {
|
||||
/// The generator this biome was built from; re-emitted on save.
|
||||
generator: FloorGenerator,
|
||||
/// One pre-rolled glyph per cell (`width * height`, row-major).
|
||||
glyphs: Vec<Glyph>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Floor {
|
||||
/// A board with no declared floor is [`Floor::Blank`].
|
||||
fn default() -> Self {
|
||||
Floor::Blank
|
||||
}
|
||||
}
|
||||
|
||||
impl Floor {
|
||||
/// Builds a [`Floor::Biome`] for a `width × height` board, pre-rolling one glyph
|
||||
/// per cell from a [`FLOOR_SEED`]-seeded PRNG (so the result is deterministic and
|
||||
/// depends only on the board dimensions + generator).
|
||||
pub(crate) fn biome(generator: FloorGenerator, width: usize, height: usize) -> Floor {
|
||||
let mut rng = StdRand::seed(FLOOR_SEED);
|
||||
let glyphs = (0..width * height).map(|_| generator.generate(&mut rng)).collect();
|
||||
Floor::Biome { generator, glyphs }
|
||||
}
|
||||
|
||||
/// The floor glyph to draw at `(x, y)`, or `None` for [`Floor::Blank`].
|
||||
///
|
||||
/// `width` is the board width, needed to index a biome's row-major buffer.
|
||||
pub(crate) fn glyph_at(&self, x: usize, y: usize, width: usize) -> Option<Glyph> {
|
||||
match self {
|
||||
Floor::Blank => None,
|
||||
Floor::Fixed(g) => Some(*g),
|
||||
Floor::Biome { glyphs, .. } => glyphs.get(y * width + x).copied(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fixed seed for the floor PRNG, so a board's generated floor is deterministic
|
||||
/// for a given map (stable across reloads within a run, and testable). The layer
|
||||
@@ -46,6 +102,16 @@ impl FloorGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/// The generator's map-file name (inverse of [`from_name`](FloorGenerator::from_name)),
|
||||
/// re-emitted on save so a biome floor round-trips.
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
FloorGenerator::Grass => "grass",
|
||||
FloorGenerator::Dirt => "dirt",
|
||||
FloorGenerator::Stone => "stone",
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates one random floor [`Glyph`] for this generator.
|
||||
///
|
||||
/// Picks a background ground color within the generator's scheme, then with
|
||||
|
||||
Reference in New Issue
Block a user