Up stairs & down stairs

This commit is contained in:
Alex Bethel 2022-01-06 16:57:20 -06:00
parent 411b8091f9
commit 0ec5fbbe8c
3 changed files with 100 additions and 19 deletions

View file

@ -29,6 +29,12 @@ pub const LEVEL_SIZE: (usize, usize) = (80, 24);
pub struct DungeonLevel { pub struct DungeonLevel {
/// The tiles at every position in the level. /// The tiles at every position in the level.
tiles: [[DungeonTile; LEVEL_SIZE.0]; LEVEL_SIZE.1], tiles: [[DungeonTile; LEVEL_SIZE.0]; LEVEL_SIZE.1],
/// The location of each of the up-staircases.
upstairs: Vec<(i32, i32)>,
/// The location of each of the down-staircases.
downstairs: Vec<(i32, i32)>,
} }
/// The smallest measurable independent location in the dungeon, /// The smallest measurable independent location in the dungeon,
@ -38,14 +44,31 @@ pub enum DungeonTile {
Floor, Floor,
Wall, Wall,
Hallway, Hallway,
Upstair,
Downstair,
} }
impl DungeonLevel { impl DungeonLevel {
/// Creates a new level in a branch that has the given /// Creates a new level in a branch that has the given
/// configuration. /// configuration.
pub fn new(_cfg: &BranchConfig) -> Self { pub fn new(_cfg: &BranchConfig) -> Self {
// Self {
// tiles: rooms::generate_level(100, &mut rand::thread_rng()),
// }
rooms::generate_level(100, &mut rand::thread_rng(), 1, 1)
}
/// Creates a new level with the given set of tiles, upstairs, and
/// downstairs.
pub fn from_raw_parts(
tiles: [[DungeonTile; LEVEL_SIZE.0]; LEVEL_SIZE.1],
upstairs: Vec<(i32, i32)>,
downstairs: Vec<(i32, i32)>,
) -> Self {
Self { Self {
tiles: rooms::generate_level(100, &mut rand::thread_rng()), tiles,
upstairs,
downstairs,
} }
} }
@ -100,6 +123,8 @@ impl DungeonLevel {
} }
} }
DungeonTile::Hallway => '#', DungeonTile::Hallway => '#',
DungeonTile::Upstair => '<',
DungeonTile::Downstair => '>',
} }
} }
@ -108,6 +133,16 @@ impl DungeonLevel {
pub fn tile(&self, x: i32, y: i32) -> &DungeonTile { pub fn tile(&self, x: i32, y: i32) -> &DungeonTile {
&self.tiles[y as usize][x as usize] &self.tiles[y as usize][x as usize]
} }
/// Gets the list of up-stairs.
pub fn upstairs(&self) -> &[(i32, i32)] {
&self.upstairs
}
/// Gets the list of down-stairs.
pub fn downstairs(&self) -> &[(i32, i32)] {
&self.downstairs
}
} }
impl Display for DungeonLevel { impl Display for DungeonLevel {

View file

@ -22,12 +22,13 @@ fn main() {
let cfg = BranchConfig; let cfg = BranchConfig;
let level = DungeonLevel::new(&cfg); let level = DungeonLevel::new(&cfg);
let spawn_pos = level.upstairs()[0];
world.insert(level); world.insert(level);
world world
.create_entity() .create_entity()
.with(Position { x: 5, y: 6 }) .with(Position { x: spawn_pos.0, y: spawn_pos.1 })
.with(CharRender { glyph: '@' }) .with(CharRender { glyph: '@' })
.with(Player) .with(Player)
.with(Mobile { .with(Mobile {
@ -49,16 +50,14 @@ fn main() {
loop { loop {
dispatcher.dispatch(&world); dispatcher.dispatch(&world);
let players = world.read_storage::<Player>(); if (
let turns = world.read_storage::<TurnTaker>(); &world.read_storage::<Player>(),
&world.read_storage::<TurnTaker>(),
if (&players, &turns).join().any(|(_plr, turn)| turn.next == 0) { )
drop(players); .join()
drop(turns); .any(|(_plr, turn)| turn.next == 0)
{
player_turn(&mut world, &mut window); player_turn(&mut world, &mut window);
} else {
drop(players);
drop(turns);
} }
} }
} }

View file

@ -20,7 +20,7 @@ use pathfinding::directed::astar::astar;
use rand::Rng; use rand::Rng;
use crate::{ use crate::{
game::{DungeonTile, LEVEL_SIZE}, game::{DungeonLevel, DungeonTile, LEVEL_SIZE},
util::NiceFloat, util::NiceFloat,
}; };
@ -48,7 +48,13 @@ const HALLWAY_RANDOMNESS: f64 = 0.6;
/// Generates a grid of the given size containing rooms connected by /// Generates a grid of the given size containing rooms connected by
/// passages. /// passages.
pub fn generate(n_rooms: usize, size: (usize, usize), rng: &mut impl Rng) -> Grid<DungeonTile> { pub fn generate(
n_rooms: usize,
size: (usize, usize),
rng: &mut impl Rng,
upstairs: usize,
downstairs: usize,
) -> (Grid<DungeonTile>, Vec<(i32, i32)>, Vec<(i32, i32)>) {
let mut grid = Grid::init(size.1, size.0, DungeonTile::Wall); let mut grid = Grid::init(size.1, size.0, DungeonTile::Wall);
let rooms = RoomBounds::generate(n_rooms, size, rng); let rooms = RoomBounds::generate(n_rooms, size, rng);
@ -58,21 +64,24 @@ pub fn generate(n_rooms: usize, size: (usize, usize), rng: &mut impl Rng) -> Gri
} }
} }
cut_hallways(&mut grid, &rooms, rng); add_hallways(&mut grid, &rooms, rng);
let (upstairs, downstairs) = add_stairs(&mut grid, upstairs, downstairs, rng);
grid (grid, upstairs, downstairs)
} }
/// Generates a grid of the statically-known level size. /// Generates a grid of the statically-known level size.
pub fn generate_level( pub fn generate_level(
n_rooms: usize, n_rooms: usize,
rng: &mut impl Rng, rng: &mut impl Rng,
) -> [[DungeonTile; LEVEL_SIZE.0]; LEVEL_SIZE.1] { upstairs: usize,
downstairs: usize,
) -> DungeonLevel {
// FIXME: This function is atrocious. We do an allocation here // FIXME: This function is atrocious. We do an allocation here
// when we theoretically doesn't need to (we get a heap-allocated // when we theoretically doesn't need to (we get a heap-allocated
// Grid back, when we know statically that it's LEVEL_SIZE so we // Grid back, when we know statically that it's LEVEL_SIZE so we
// could allocate it on the stack)... // could allocate it on the stack)...
let grid = generate(n_rooms, LEVEL_SIZE, rng); let (grid, upstairs, downstairs) = generate(n_rooms, LEVEL_SIZE, rng, upstairs, downstairs);
// ...and then we use a pointless default of DungeonTile::Floor // ...and then we use a pointless default of DungeonTile::Floor
// here then copy in the real data from `grid`. // here then copy in the real data from `grid`.
@ -84,7 +93,7 @@ pub fn generate_level(
*slot = value; *slot = value;
} }
data DungeonLevel::from_raw_parts(data, upstairs, downstairs)
} }
/// The bounding box of a room. /// The bounding box of a room.
@ -171,7 +180,7 @@ impl RoomBounds {
} }
/// Adds a set of hallways connecting the given rooms to a dungeon. /// Adds a set of hallways connecting the given rooms to a dungeon.
fn cut_hallways(grid: &mut Grid<DungeonTile>, rooms: &[RoomBounds], rng: &mut impl Rng) { fn add_hallways(grid: &mut Grid<DungeonTile>, rooms: &[RoomBounds], rng: &mut impl Rng) {
// How hard we try to avoid traveling through stone at a pair of // How hard we try to avoid traveling through stone at a pair of
// coordinates. // coordinates.
let mut stone_weights = Grid::new(grid.rows(), grid.cols()); let mut stone_weights = Grid::new(grid.rows(), grid.cols());
@ -239,3 +248,41 @@ fn cut_hallways(grid: &mut Grid<DungeonTile>, rooms: &[RoomBounds], rng: &mut im
} }
} }
} }
/// Adds staircases leading upwards and downwards to the level.
fn add_stairs(
grid: &mut Grid<DungeonTile>,
n_upstairs: usize,
n_downstairs: usize,
rng: &mut impl Rng,
) -> (Vec<(i32, i32)>, Vec<(i32, i32)>) {
let (mut upstairs, mut downstairs) = (
Vec::with_capacity(n_upstairs),
Vec::with_capacity(n_downstairs),
);
for _ in 0..n_upstairs {
let (x, y) = empty_square(grid, rng);
upstairs.push((x, y));
grid[y as usize][x as usize] = DungeonTile::Upstair;
}
for _ in 0..n_downstairs {
let (x, y) = empty_square(grid, rng);
downstairs.push((x, y));
grid[y as usize][x as usize] = DungeonTile::Downstair;
}
(upstairs, downstairs)
}
/// Finds an unoccupied (floor) square of the level.
fn empty_square(grid: &Grid<DungeonTile>, rng: &mut impl Rng) -> (i32, i32) {
loop {
let (x, y) = (rng.gen_range(0..grid.cols()), rng.gen_range(0..grid.rows()));
if grid[y][x] == DungeonTile::Floor {
break (x as _, y as _);
}
}
}