diff --git a/src/map_builders/cellular_automata.rs b/src/map_builders/cellular_automata.rs index 9a1194e..76837e2 100644 --- a/src/map_builders/cellular_automata.rs +++ b/src/map_builders/cellular_automata.rs @@ -1,10 +1,11 @@ +use super::common::{ + generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant, +}; use super::MapBuilder; use crate::{components::Position, spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER}; use rltk::RandomNumberGenerator; use specs::prelude::*; use std::collections::HashMap; -use crate::map_builders::common::remove_unreachable_areas_returning_most_distant; -use super::common::generate_voronoi_spawn_regions; pub struct CellularAutomataBuilder { map: Map, diff --git a/src/map_builders/drunkard.rs b/src/map_builders/drunkard.rs index 498a978..cf34f1c 100644 --- a/src/map_builders/drunkard.rs +++ b/src/map_builders/drunkard.rs @@ -1,15 +1,31 @@ +use super::common::{ + generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant, +}; use super::MapBuilder; use crate::{components::Position, spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER}; use rltk::RandomNumberGenerator; use specs::prelude::*; use std::collections::HashMap; +#[derive(PartialEq, Copy, Clone)] +pub enum DrunkSpawnMode { + StaringPoint, + Random, +} + +pub struct DrunkardSettings { + pub spawn_mode: DrunkSpawnMode, + pub drunken_lifetime: i32, + pub floor_percent: f32, +} + pub struct DrunkardsWalkBuilder { map: Map, starting_position: Position, depth: i32, history: Vec, noise_areas: HashMap>, + settings: DrunkardSettings, } impl MapBuilder for DrunkardsWalkBuilder { @@ -47,19 +63,53 @@ impl MapBuilder for DrunkardsWalkBuilder { } impl DrunkardsWalkBuilder { - pub fn new(new_depth: i32) -> DrunkardsWalkBuilder { + pub fn new(new_depth: i32, settings: DrunkardSettings) -> DrunkardsWalkBuilder { DrunkardsWalkBuilder { map: Map::new(new_depth), starting_position: Position::default(), depth: new_depth, history: Vec::new(), noise_areas: HashMap::new(), + settings, } } + pub fn open_area(new_depth: i32) -> DrunkardsWalkBuilder { + DrunkardsWalkBuilder::new( + new_depth, + DrunkardSettings { + spawn_mode: DrunkSpawnMode::StaringPoint, + drunken_lifetime: 400, + floor_percent: 0.5, + }, + ) + } + + pub fn open_halls(new_depth: i32) -> DrunkardsWalkBuilder { + DrunkardsWalkBuilder::new( + new_depth, + DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 400, + floor_percent: 0.5, + }, + ) + } + + pub fn winding_passages(new_depth: i32) -> DrunkardsWalkBuilder { + DrunkardsWalkBuilder::new( + new_depth, + DrunkardSettings { + spawn_mode: DrunkSpawnMode::Random, + drunken_lifetime: 100, + floor_percent: 0.4, + }, + ) + } + #[allow(clippy::map_entry)] fn build(&mut self) { - // let mut rng = RandomNumberGenerator::new(); + let mut rng = RandomNumberGenerator::new(); // Set a central starting point self.starting_position = Position { @@ -71,6 +121,107 @@ impl DrunkardsWalkBuilder { .xy_idx(self.starting_position.x, self.starting_position.y); self.map.tiles[start_idx] = TileType::Floor; - // @TODO implement the rest + let total_tiles = self.map.width * self.map.height; + let desired_floor_tiles = (self.settings.floor_percent * total_tiles as f32) as usize; + let mut floor_tile_count = self + .map + .tiles + .iter() + .filter(|a| **a == TileType::Floor) + .count(); + let mut digger_count = 0; + let mut active_digger_count = 0; + + while floor_tile_count < desired_floor_tiles { + let mut did_something = false; + let mut drunk_x; + let mut drunk_y; + match self.settings.spawn_mode { + DrunkSpawnMode::StaringPoint => { + drunk_x = self.starting_position.x; + drunk_y = self.starting_position.y; + } + DrunkSpawnMode::Random => { + if digger_count == 0 { + drunk_x = self.starting_position.x; + drunk_y = self.starting_position.y; + } else { + drunk_x = rng.roll_dice(1, self.map.width - 3) + 1; + drunk_y = rng.roll_dice(1, self.map.height - 3) + 1; + } + } + } + + let mut drunk_life = self.settings.drunken_lifetime; + + while drunk_life > 0 { + let drunk_idx = self.map.xy_idx(drunk_x, drunk_y); + if self.map.tiles[drunk_idx] == TileType::Wall { + did_something = true; + } + + self.map.tiles[drunk_idx] = TileType::DownStairs; + + let stagger_direction = rng.roll_dice(1, 4); + match stagger_direction { + 1 => { + if drunk_x > 2 { + drunk_x -= 1; + } + } + 2 => { + if drunk_x < self.map.width - 2 { + drunk_x += 1 + } + } + 3 => { + if drunk_y > 2 { + drunk_y -= 1 + } + } + _ => { + if drunk_y < self.map.height - 2 { + drunk_y += 1 + } + } + } + + drunk_life -= 1; + } + + if did_something { + self.take_snapshot(); + active_digger_count += 1; + } + + digger_count += 1; + for t in self.map.tiles.iter_mut() { + if *t == TileType::DownStairs { + *t = TileType::Floor; + } + } + floor_tile_count = self + .map + .tiles + .iter() + .filter(|a| **a == TileType::Floor) + .count(); + } + + rltk::console::log(format!( + "{} dwarves gave up their sobriety, of whom {} actually found a wall.", + digger_count, active_digger_count + )); + + // Find all tiles we can reach from the starting point + let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx); + self.take_snapshot(); + + // Place the stairs + self.map.tiles[exit_tile] = TileType::DownStairs; + self.take_snapshot(); + + // Now we build a noise map for use in spawning entities later + self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng); } } diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index dbc808f..2925c72 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -25,11 +25,13 @@ pub trait MapBuilder { pub fn random_builder(new_depth: i32) -> Box { let mut rng = rltk::RandomNumberGenerator::new(); - match rng.roll_dice(1, 4) { + match rng.roll_dice(1, 7) { 1 => Box::new(BspDungeonBuilder::new(new_depth)), 2 => Box::new(BspInteriorBuilder::new(new_depth)), 3 => Box::new(CellularAutomataBuilder::new(new_depth)), + 4 => Box::new(DrunkardsWalkBuilder::open_area(new_depth)), + 5 => Box::new(DrunkardsWalkBuilder::open_halls(new_depth)), + 6 => Box::new(DrunkardsWalkBuilder::winding_passages(new_depth)), _ => Box::new(SimpleMapBuilder::new(new_depth)), } - // Box::new(DrunkardsWalkBuilder::new(new_depth)) }