drunkard, and prefabs

This commit is contained in:
Tyrel Souza 2021-08-31 13:33:30 -04:00
parent 35f8e4cc73
commit fae5608d91
3 changed files with 169 additions and 2 deletions

View File

@ -0,0 +1,78 @@
use super::MapArchitect;
use crate::prelude::*;
pub struct DrunkardsWalkArchitect {}
const STAGGER_DISTANCE: usize = 400;
const NUM_TILES: usize = (SCREEN_HEIGHT * SCREEN_WIDTH) as usize;
const DESIRED_FLOOR: usize = NUM_TILES / 3;
impl MapArchitect for DrunkardsWalkArchitect {
fn new(&mut self, rng: &mut RandomNumberGenerator) -> MapBuilder {
let mut mb = MapBuilder {
map: Map::new(),
rooms: Vec::new(),
monster_spawns: Vec::new(),
player_start: Point::zero(),
amulet_start: Point::zero(),
};
mb.fill(TileType::Wall);
let center = Point::new(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
self.drunkard(&center, rng, &mut mb.map);
while mb
.map
.tiles
.iter()
.filter(|t| **t == TileType::Floor)
.count()
< DESIRED_FLOOR
{
self.drunkard(
&Point::new(rng.range(0, SCREEN_WIDTH), rng.range(0, SCREEN_HEIGHT)),
rng,
&mut mb.map,
);
let dijkstra_map = DijkstraMap::new(
SCREEN_WIDTH,
SCREEN_HEIGHT,
&vec![mb.map.point2d_to_index(center)],
&mb.map,
1024.0,
);
dijkstra_map
.map
.iter()
.enumerate()
.filter(|(_, distance)| *distance > &2000.0)
.for_each(|(idx, _)| mb.map.tiles[idx] = TileType::Wall);
}
mb.monster_spawns = mb.spawn_monsters(&center, rng);
mb.player_start = center;
mb.amulet_start = mb.find_most_distant();
mb
}
}
impl DrunkardsWalkArchitect {
fn drunkard(&mut self, start: &Point, rng: &mut RandomNumberGenerator, map: &mut Map) {
let mut drunkard_pos = start.clone();
let mut distance_staggered = 0;
loop {
let drunk_idx = map.point2d_to_index(drunkard_pos);
map.tiles[drunk_idx] = TileType::Floor;
match rng.range(0, 4) {
0 => drunkard_pos.x -= 1,
1 => drunkard_pos.x += 1,
2 => drunkard_pos.y -= 1,
_ => drunkard_pos.y += 1,
}
if !map.in_bounds(drunkard_pos) {
break;
}
distance_staggered += 1;
if distance_staggered > STAGGER_DISTANCE {
break;
}
}
}
}

View File

@ -1,11 +1,15 @@
mod automata; mod automata;
mod drunkard;
mod empty; mod empty;
mod prefab;
mod rooms; mod rooms;
use automata::AutomataArchitect; use automata::AutomataArchitect;
use drunkard::DrunkardsWalkArchitect;
use empty::EmptyArchitect; use empty::EmptyArchitect;
use rooms::RoomsArchitect; use rooms::RoomsArchitect;
use crate::map_builder::prefab::apply_prefab;
use crate::prelude::*; use crate::prelude::*;
trait MapArchitect { trait MapArchitect {
@ -23,9 +27,16 @@ pub struct MapBuilder {
impl MapBuilder { impl MapBuilder {
pub fn new(rng: &mut RandomNumberGenerator) -> Self { pub fn new(rng: &mut RandomNumberGenerator) -> Self {
let mut architecht = AutomataArchitect {}; let mut architect: Box<dyn MapArchitect> = match rng.range(0, 3) {
0 => Box::new(DrunkardsWalkArchitect {}),
1 => Box::new(RoomsArchitect {}),
_ => Box::new(AutomataArchitect {}),
};
architecht.new(rng) let mut mb = architect.new(rng);
apply_prefab(&mut mb, rng);
mb
} }
fn fill(&mut self, tile: TileType) { fn fill(&mut self, tile: TileType) {

78
src/map_builder/prefab.rs Normal file
View File

@ -0,0 +1,78 @@
use crate::prelude::*;
const FORTRESS: (&str, i32, i32) = (
"
------------
---######---
---#----#---
---#-M--#---
-###----###-
--M---------
-###----###-
---#----#---
---#----#---
---######---
------------
",
12,
11,
);
pub fn apply_prefab(mb: &mut MapBuilder, rng: &mut RandomNumberGenerator) {
let mut placement = None;
let dijkstra_map = DijkstraMap::new(
SCREEN_WIDTH,
SCREEN_HEIGHT,
&vec![mb.map.point2d_to_index(mb.player_start)],
&mb.map,
1024.0,
);
let mut attempts = 0;
while placement.is_none() && attempts < 10 {
let dimensions = Rect::with_size(
rng.range(0, SCREEN_WIDTH - FORTRESS.1),
rng.range(0, SCREEN_HEIGHT - FORTRESS.2),
FORTRESS.1,
FORTRESS.2,
);
let mut can_place = false;
dimensions.for_each(|pt| {
let idx = mb.map.point2d_to_index(pt);
let distance = dijkstra_map.map[idx];
if distance < 2000.0 && distance > 20.0 && mb.amulet_start != pt {
can_place = true;
}
});
if can_place {
placement = Some(Point::new(dimensions.x1, dimensions.y1));
let points = dimensions.point_set();
mb.monster_spawns.retain(|pt| !points.contains(pt));
}
attempts += 1;
}
if let Some(placement) = placement {
let string_vec: Vec<char> = FORTRESS
.0
.chars()
.filter(|a| *a != '\r' && *a != '\n')
.collect();
let mut i = 0;
for ty in placement.y..placement.y + FORTRESS.2 {
for tx in placement.x..placement.x + FORTRESS.1 {
let idx = map_idx(tx, ty);
let c = string_vec[i];
match c {
'M' => {
mb.map.tiles[idx] = TileType::Floor;
mb.monster_spawns.push(Point::new(tx, ty));
}
'-' => mb.map.tiles[idx] = TileType::Floor,
'#' => mb.map.tiles[idx] = TileType::Wall,
_ => println!("No idea what to do with [{}]", c),
}
i += 1;
}
}
}
}