drunkard, and prefabs
This commit is contained in:
parent
35f8e4cc73
commit
fae5608d91
78
src/map_builder/drunkard.rs
Normal file
78
src/map_builder/drunkard.rs
Normal 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(¢er, 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(¢er, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,15 @@
|
||||
mod automata;
|
||||
mod drunkard;
|
||||
mod empty;
|
||||
mod prefab;
|
||||
mod rooms;
|
||||
|
||||
use automata::AutomataArchitect;
|
||||
use drunkard::DrunkardsWalkArchitect;
|
||||
use empty::EmptyArchitect;
|
||||
use rooms::RoomsArchitect;
|
||||
|
||||
use crate::map_builder::prefab::apply_prefab;
|
||||
use crate::prelude::*;
|
||||
|
||||
trait MapArchitect {
|
||||
@ -23,9 +27,16 @@ pub struct MapBuilder {
|
||||
|
||||
impl MapBuilder {
|
||||
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) {
|
||||
|
78
src/map_builder/prefab.rs
Normal file
78
src/map_builder/prefab.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user