atomises rooms and corridors
- room sorter - rounding room corners - dogleg and bsp corridors - room exploder
This commit is contained in:
parent
b7b2061228
commit
2ceb20a822
9 changed files with 411 additions and 59 deletions
|
|
@ -50,14 +50,14 @@ pub fn delete_the_dead(ecs: &mut World) {
|
||||||
.append("The")
|
.append("The")
|
||||||
.npc_name(&victim_name.name)
|
.npc_name(&victim_name.name)
|
||||||
.colour(rltk::WHITE)
|
.colour(rltk::WHITE)
|
||||||
.append("was destroyed!")
|
.append("is destroyed!")
|
||||||
.log();
|
.log();
|
||||||
} else {
|
} else {
|
||||||
gamelog::Logger::new()
|
gamelog::Logger::new()
|
||||||
.append("The")
|
.append("The")
|
||||||
.npc_name(&victim_name.name)
|
.npc_name(&victim_name.name)
|
||||||
.colour(rltk::WHITE)
|
.colour(rltk::WHITE)
|
||||||
.append("died!")
|
.append("dies!")
|
||||||
.log();
|
.log();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,20 +42,6 @@ impl BspDungeonBuilder {
|
||||||
n_rooms += 1;
|
n_rooms += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we sort the rooms
|
|
||||||
rooms.sort_by(|a, b| a.x1.cmp(&b.x1));
|
|
||||||
|
|
||||||
// Now we want corridors
|
|
||||||
for i in 0..rooms.len() - 1 {
|
|
||||||
let room = rooms[i];
|
|
||||||
let next_room = rooms[i + 1];
|
|
||||||
let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1);
|
|
||||||
let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2)) - 1);
|
|
||||||
let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
|
|
||||||
let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
|
|
||||||
draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y);
|
|
||||||
build_data.take_snapshot();
|
|
||||||
}
|
|
||||||
build_data.rooms = Some(rooms);
|
build_data.rooms = Some(rooms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use drunkard::DrunkardsWalkBuilder;
|
||||||
mod maze;
|
mod maze;
|
||||||
use maze::MazeBuilder;
|
use maze::MazeBuilder;
|
||||||
mod simple_map;
|
mod simple_map;
|
||||||
|
use simple_map::SimpleMapBuilder;
|
||||||
mod voronoi;
|
mod voronoi;
|
||||||
use voronoi::VoronoiBuilder;
|
use voronoi::VoronoiBuilder;
|
||||||
mod prefab_builder;
|
mod prefab_builder;
|
||||||
|
|
@ -35,6 +36,16 @@ use common::*;
|
||||||
use specs::prelude::*;
|
use specs::prelude::*;
|
||||||
use voronoi_spawning::VoronoiSpawning;
|
use voronoi_spawning::VoronoiSpawning;
|
||||||
use wfc::WaveFunctionCollapseBuilder;
|
use wfc::WaveFunctionCollapseBuilder;
|
||||||
|
mod room_exploder;
|
||||||
|
use room_exploder::RoomExploder;
|
||||||
|
mod room_corner_rounding;
|
||||||
|
use room_corner_rounding::RoomCornerRounder;
|
||||||
|
mod rooms_corridors_dogleg;
|
||||||
|
use rooms_corridors_dogleg::DoglegCorridors;
|
||||||
|
mod rooms_corridors_bsp;
|
||||||
|
use rooms_corridors_bsp::BspCorridors;
|
||||||
|
mod room_sorter;
|
||||||
|
use room_sorter::{RoomSort, RoomSorter};
|
||||||
|
|
||||||
// Shared data to be passed around build chain
|
// Shared data to be passed around build chain
|
||||||
pub struct BuilderMap {
|
pub struct BuilderMap {
|
||||||
|
|
@ -119,38 +130,139 @@ pub trait MetaMapBuilder {
|
||||||
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap);
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_initial_builder(rng: &mut rltk::RandomNumberGenerator) -> (Box<dyn InitialMapBuilder>, bool) {
|
fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
|
||||||
let builder = rng.roll_dice(1, 17);
|
let x;
|
||||||
let result: (Box<dyn InitialMapBuilder>, bool);
|
let xroll = rng.roll_dice(1, 3);
|
||||||
match builder {
|
match xroll {
|
||||||
1 => result = (BspDungeonBuilder::new(), true),
|
1 => x = XStart::LEFT,
|
||||||
2 => result = (BspInteriorBuilder::new(), true),
|
2 => x = XStart::CENTRE,
|
||||||
3 => result = (CellularAutomataBuilder::new(), false),
|
_ => x = XStart::RIGHT,
|
||||||
4 => result = (DrunkardsWalkBuilder::open_area(), false),
|
|
||||||
5 => result = (DrunkardsWalkBuilder::open_halls(), false),
|
|
||||||
6 => result = (DrunkardsWalkBuilder::winding_passages(), false),
|
|
||||||
7 => result = (DrunkardsWalkBuilder::fat_passages(), false),
|
|
||||||
8 => result = (DrunkardsWalkBuilder::fearful_symmetry(), false),
|
|
||||||
9 => result = (MazeBuilder::new(), false),
|
|
||||||
10 => result = (DLABuilder::walk_inwards(), false),
|
|
||||||
11 => result = (DLABuilder::walk_outwards(), false),
|
|
||||||
12 => result = (DLABuilder::central_attractor(), false),
|
|
||||||
13 => result = (DLABuilder::insectoid(), false),
|
|
||||||
14 => result = (VoronoiBuilder::pythagoras(), false),
|
|
||||||
15 => result = (VoronoiBuilder::manhattan(), false),
|
|
||||||
16 => result = (PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED), false),
|
|
||||||
_ => result = (simple_map::SimpleMapBuilder::new(), true),
|
|
||||||
}
|
}
|
||||||
result
|
|
||||||
|
let y;
|
||||||
|
let yroll = rng.roll_dice(1, 3);
|
||||||
|
match yroll {
|
||||||
|
1 => y = YStart::BOTTOM,
|
||||||
|
2 => y = YStart::CENTRE,
|
||||||
|
_ => y = YStart::TOP,
|
||||||
|
}
|
||||||
|
|
||||||
|
(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_room_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut BuilderChain) {
|
||||||
|
let build_roll = rng.roll_dice(1, 3);
|
||||||
|
// Start with a room builder.
|
||||||
|
match build_roll {
|
||||||
|
1 => builder.start_with(SimpleMapBuilder::new()),
|
||||||
|
2 => builder.start_with(BspDungeonBuilder::new()),
|
||||||
|
_ => builder.start_with(BspInteriorBuilder::new()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// BspInterior makes its own doorways. If we're not using that one,
|
||||||
|
// select a sorting method, a type of corridor, and modifiers.
|
||||||
|
if build_roll != 3 {
|
||||||
|
// Sort by one of the 5 available algorithms
|
||||||
|
let sort_roll = rng.roll_dice(1, 5);
|
||||||
|
match sort_roll {
|
||||||
|
1 => builder.with(RoomSorter::new(RoomSort::LEFTMOST)),
|
||||||
|
2 => builder.with(RoomSorter::new(RoomSort::RIGHTMOST)),
|
||||||
|
3 => builder.with(RoomSorter::new(RoomSort::TOPMOST)),
|
||||||
|
4 => builder.with(RoomSorter::new(RoomSort::BOTTOMMOST)),
|
||||||
|
_ => builder.with(RoomSorter::new(RoomSort::CENTRAL)),
|
||||||
|
}
|
||||||
|
|
||||||
|
let corridor_roll = rng.roll_dice(1, 2);
|
||||||
|
match corridor_roll {
|
||||||
|
1 => builder.with(DoglegCorridors::new()),
|
||||||
|
_ => builder.with(BspCorridors::new()),
|
||||||
|
}
|
||||||
|
|
||||||
|
let modifier_roll = rng.roll_dice(1, 6);
|
||||||
|
match modifier_roll {
|
||||||
|
1 => builder.with(RoomExploder::new()),
|
||||||
|
2 => builder.with(RoomCornerRounder::new()),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick a starting position, in a room or elsewhere.
|
||||||
|
let start_roll = rng.roll_dice(1, 2);
|
||||||
|
match start_roll {
|
||||||
|
1 => builder.with(RoomBasedStartingPosition::new()),
|
||||||
|
_ => {
|
||||||
|
let (start_x, start_y) = random_start_position(rng);
|
||||||
|
builder.with(AreaStartingPosition::new(start_x, start_y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide where to put the exit - in a room or far away, anywhere.
|
||||||
|
let exit_roll = rng.roll_dice(1, 2);
|
||||||
|
match exit_roll {
|
||||||
|
1 => builder.with(RoomBasedStairs::new()),
|
||||||
|
_ => builder.with(DistantExit::new()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide whether to spawn entities only in rooms, or with voronoi noise.
|
||||||
|
let spawn_roll = rng.roll_dice(1, 2);
|
||||||
|
match spawn_roll {
|
||||||
|
1 => builder.with(RoomBasedSpawner::new()),
|
||||||
|
_ => builder.with(VoronoiSpawning::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_shape_builder(rng: &mut rltk::RandomNumberGenerator, builder: &mut BuilderChain) {
|
||||||
|
// Pick an initial builder
|
||||||
|
let builder_roll = rng.roll_dice(1, 16);
|
||||||
|
match builder_roll {
|
||||||
|
1 => builder.start_with(CellularAutomataBuilder::new()),
|
||||||
|
2 => builder.start_with(DrunkardsWalkBuilder::open_area()),
|
||||||
|
3 => builder.start_with(DrunkardsWalkBuilder::open_halls()),
|
||||||
|
4 => builder.start_with(DrunkardsWalkBuilder::winding_passages()),
|
||||||
|
5 => builder.start_with(DrunkardsWalkBuilder::fat_passages()),
|
||||||
|
6 => builder.start_with(DrunkardsWalkBuilder::fearful_symmetry()),
|
||||||
|
7 => builder.start_with(MazeBuilder::new()),
|
||||||
|
8 => builder.start_with(DLABuilder::walk_inwards()),
|
||||||
|
9 => builder.start_with(DLABuilder::walk_outwards()),
|
||||||
|
10 => builder.start_with(DLABuilder::central_attractor()),
|
||||||
|
11 => builder.start_with(DLABuilder::insectoid()),
|
||||||
|
12 => builder.start_with(VoronoiBuilder::pythagoras()),
|
||||||
|
13 => builder.start_with(VoronoiBuilder::manhattan()),
|
||||||
|
_ => builder.start_with(PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'Select' the centre by placing a starting position, and cull everywhere unreachable.
|
||||||
|
builder.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
|
||||||
|
builder.with(CullUnreachable::new());
|
||||||
|
|
||||||
|
// Now set the start to a random spot in our remaining area.
|
||||||
|
let (start_x, start_y) = random_start_position(rng);
|
||||||
|
builder.with(AreaStartingPosition::new(start_x, start_y));
|
||||||
|
|
||||||
|
// Place the exit and spawn mobs
|
||||||
|
builder.with(VoronoiSpawning::new());
|
||||||
|
builder.with(DistantExit::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn random_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator) -> BuilderChain {
|
pub fn random_builder(new_depth: i32, rng: &mut rltk::RandomNumberGenerator) -> BuilderChain {
|
||||||
let mut builder = BuilderChain::new(new_depth);
|
let mut builder = BuilderChain::new(new_depth);
|
||||||
builder.start_with(simple_map::SimpleMapBuilder::new());
|
let type_roll = rng.roll_dice(1, 2);
|
||||||
builder.with(DLABuilder::heavy_erosion());
|
match type_roll {
|
||||||
builder.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
|
1 => random_room_builder(rng, &mut builder),
|
||||||
builder.with(CullUnreachable::new());
|
_ => random_shape_builder(rng, &mut builder),
|
||||||
builder.with(VoronoiSpawning::new());
|
}
|
||||||
builder.with(DistantExit::new());
|
|
||||||
|
/* WFC needs some fixes.
|
||||||
|
if rng.roll_dice(1, 3) == 1 {
|
||||||
|
builder.with(WaveFunctionCollapseBuilder::new());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if rng.roll_dice(1, 20) == 1 {
|
||||||
|
builder.with(PrefabBuilder::sectional(prefab_builder::prefab_sections::UNDERGROUND_FORT));
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.with(PrefabBuilder::vaults());
|
||||||
|
|
||||||
builder
|
builder
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
src/map_builders/room_corner_rounding.rs
Normal file
57
src/map_builders/room_corner_rounding.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use super::{BuilderMap, MetaMapBuilder, Rect, TileType};
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
pub struct RoomCornerRounder {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for RoomCornerRounder {
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoomCornerRounder {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<RoomCornerRounder> {
|
||||||
|
return Box::new(RoomCornerRounder {});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_if_corner(&mut self, x: i32, y: i32, build_data: &mut BuilderMap) {
|
||||||
|
let w = build_data.map.width;
|
||||||
|
let h = build_data.map.height;
|
||||||
|
let idx = build_data.map.xy_idx(x, y);
|
||||||
|
let mut neighbour_walls = 0;
|
||||||
|
if x > 0 && build_data.map.tiles[idx - 1] == TileType::Wall {
|
||||||
|
neighbour_walls += 1;
|
||||||
|
}
|
||||||
|
if y > 0 && build_data.map.tiles[idx - w as usize] == TileType::Wall {
|
||||||
|
neighbour_walls += 1;
|
||||||
|
}
|
||||||
|
if x < w - 2 && build_data.map.tiles[idx + 1] == TileType::Wall {
|
||||||
|
neighbour_walls += 1;
|
||||||
|
}
|
||||||
|
if y < h - 2 && build_data.map.tiles[idx + w as usize] == TileType::Wall {
|
||||||
|
neighbour_walls += 1;
|
||||||
|
}
|
||||||
|
if neighbour_walls == 2 {
|
||||||
|
build_data.map.tiles[idx] = TileType::Wall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let rooms: Vec<Rect>;
|
||||||
|
if let Some(rooms_builder) = &build_data.rooms {
|
||||||
|
rooms = rooms_builder.clone();
|
||||||
|
} else {
|
||||||
|
panic!("RoomCornerRounding requires a builder with rooms.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for room in rooms.iter() {
|
||||||
|
self.fill_if_corner(room.x1 + 1, room.y1 + 1, build_data);
|
||||||
|
self.fill_if_corner(room.x2, room.y1 + 1, build_data);
|
||||||
|
self.fill_if_corner(room.x1 + 1, room.y2, build_data);
|
||||||
|
self.fill_if_corner(room.x2, room.y2, build_data);
|
||||||
|
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/map_builders/room_exploder.rs
Normal file
82
src/map_builders/room_exploder.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
use super::{paint, BuilderMap, MetaMapBuilder, Rect, Symmetry, TileType};
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
pub struct RoomExploder {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for RoomExploder {
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.build(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoomExploder {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<RoomExploder> {
|
||||||
|
return Box::new(RoomExploder {});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let rooms: Vec<Rect>;
|
||||||
|
if let Some(rooms_builder) = &build_data.rooms {
|
||||||
|
rooms = rooms_builder.clone();
|
||||||
|
} else {
|
||||||
|
panic!("RoomExploder requires a builder with rooms.");
|
||||||
|
}
|
||||||
|
for room in rooms.iter() {
|
||||||
|
let start = room.centre();
|
||||||
|
let n_diggers = rng.roll_dice(1, 20) - 5;
|
||||||
|
if n_diggers > 0 {
|
||||||
|
for _i in 0..n_diggers {
|
||||||
|
let mut drunk_x = start.0;
|
||||||
|
let mut drunk_y = start.1;
|
||||||
|
let mut drunk_life = 20;
|
||||||
|
let mut did_something = false;
|
||||||
|
|
||||||
|
while drunk_life > 0 {
|
||||||
|
let drunk_idx = build_data.map.xy_idx(drunk_x, drunk_y);
|
||||||
|
if build_data.map.tiles[drunk_idx] == TileType::Wall {
|
||||||
|
did_something = true;
|
||||||
|
}
|
||||||
|
paint(&mut build_data.map, Symmetry::None, 1, drunk_x, drunk_y);
|
||||||
|
build_data.map.tiles[drunk_idx] = TileType::DownStair;
|
||||||
|
|
||||||
|
let stagger_direction = rng.roll_dice(1, 4);
|
||||||
|
match stagger_direction {
|
||||||
|
1 => {
|
||||||
|
if drunk_x > 2 {
|
||||||
|
drunk_x -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
if drunk_x < build_data.map.width - 2 {
|
||||||
|
drunk_x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
if drunk_y > 2 {
|
||||||
|
drunk_y -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if drunk_y < build_data.map.height - 2 {
|
||||||
|
drunk_y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drunk_life -= 1;
|
||||||
|
}
|
||||||
|
if did_something {
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
for t in build_data.map.tiles.iter_mut() {
|
||||||
|
if *t == TileType::DownStair {
|
||||||
|
*t = TileType::Floor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/map_builders/room_sorter.rs
Normal file
47
src/map_builders/room_sorter.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
use super::{BuilderMap, MetaMapBuilder, Rect};
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
pub enum RoomSort {
|
||||||
|
LEFTMOST,
|
||||||
|
RIGHTMOST,
|
||||||
|
TOPMOST,
|
||||||
|
BOTTOMMOST,
|
||||||
|
CENTRAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RoomSorter {
|
||||||
|
sort_by: RoomSort,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for RoomSorter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.sorter(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoomSorter {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(sort_by: RoomSort) -> Box<RoomSorter> {
|
||||||
|
return Box::new(RoomSorter { sort_by });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sorter(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
match self.sort_by {
|
||||||
|
RoomSort::LEFTMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| a.x1.cmp(&b.x1)),
|
||||||
|
RoomSort::RIGHTMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| b.x2.cmp(&a.x2)),
|
||||||
|
RoomSort::TOPMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| a.y1.cmp(&b.y1)),
|
||||||
|
RoomSort::BOTTOMMOST => build_data.rooms.as_mut().unwrap().sort_by(|a, b| b.y2.cmp(&a.y2)),
|
||||||
|
RoomSort::CENTRAL => {
|
||||||
|
let map_centre = rltk::Point::new(build_data.map.width / 2, build_data.map.height / 2);
|
||||||
|
build_data.rooms.as_mut().unwrap().sort_by(|a: &Rect, b: &Rect| {
|
||||||
|
let a_centre_pt = rltk::Point::new(a.centre().0, a.centre().1);
|
||||||
|
let b_centre_pt = rltk::Point::new(b.centre().0, b.centre().1);
|
||||||
|
let distance_a = rltk::DistanceAlg::Pythagoras.distance2d(a_centre_pt, map_centre);
|
||||||
|
let distance_b = rltk::DistanceAlg::Pythagoras.distance2d(b_centre_pt, map_centre);
|
||||||
|
return distance_a.partial_cmp(&distance_b).unwrap();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/map_builders/rooms_corridors_bsp.rs
Normal file
38
src/map_builders/rooms_corridors_bsp.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use super::{draw_corridor, BuilderMap, MetaMapBuilder, Rect};
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
pub struct BspCorridors {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for BspCorridors {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.corridors(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BspCorridors {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<BspCorridors> {
|
||||||
|
Box::new(BspCorridors {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn corridors(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let rooms: Vec<Rect>;
|
||||||
|
if let Some(rooms_builder) = &build_data.rooms {
|
||||||
|
rooms = rooms_builder.clone();
|
||||||
|
} else {
|
||||||
|
panic!("BSP Corridors require a builder with room structures");
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..rooms.len() - 1 {
|
||||||
|
let room = rooms[i];
|
||||||
|
let next_room = rooms[i + 1];
|
||||||
|
let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1);
|
||||||
|
let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2)) - 1);
|
||||||
|
let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2)) - 1);
|
||||||
|
let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1);
|
||||||
|
draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y);
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/map_builders/rooms_corridors_dogleg.rs
Normal file
42
src/map_builders/rooms_corridors_dogleg.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use super::{apply_horizontal_tunnel, apply_vertical_tunnel, BuilderMap, MetaMapBuilder, Rect};
|
||||||
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
|
pub struct DoglegCorridors {}
|
||||||
|
|
||||||
|
impl MetaMapBuilder for DoglegCorridors {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
self.corridors(rng, build_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DoglegCorridors {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new() -> Box<DoglegCorridors> {
|
||||||
|
Box::new(DoglegCorridors {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn corridors(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
|
let rooms: Vec<Rect>;
|
||||||
|
if let Some(rooms_builder) = &build_data.rooms {
|
||||||
|
rooms = rooms_builder.clone();
|
||||||
|
} else {
|
||||||
|
panic!("DoglegCorridors require a builder with rooms.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, room) in rooms.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
let (new_x, new_y) = room.centre();
|
||||||
|
let (prev_x, prev_y) = rooms[i as usize - 1].centre();
|
||||||
|
if rng.range(0, 2) == 1 {
|
||||||
|
apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, prev_y);
|
||||||
|
apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, new_x);
|
||||||
|
} else {
|
||||||
|
apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, prev_x);
|
||||||
|
apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, new_y);
|
||||||
|
}
|
||||||
|
build_data.take_snapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{apply_horizontal_tunnel, apply_room_to_map, apply_vertical_tunnel, BuilderMap, InitialMapBuilder, Rect};
|
use super::{apply_room_to_map, apply_vertical_tunnel, BuilderMap, InitialMapBuilder, Rect};
|
||||||
use rltk::RandomNumberGenerator;
|
use rltk::RandomNumberGenerator;
|
||||||
|
|
||||||
pub struct SimpleMapBuilder {}
|
pub struct SimpleMapBuilder {}
|
||||||
|
|
@ -6,7 +6,7 @@ pub struct SimpleMapBuilder {}
|
||||||
impl InitialMapBuilder for SimpleMapBuilder {
|
impl InitialMapBuilder for SimpleMapBuilder {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build_map(&mut self, rng: &mut rltk::RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
self.rooms_and_corridors(rng, build_data);
|
self.build_rooms(rng, build_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ impl SimpleMapBuilder {
|
||||||
Box::new(SimpleMapBuilder {})
|
Box::new(SimpleMapBuilder {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rooms_and_corridors(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
fn build_rooms(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||||
const MAX_ROOMS: i32 = 30;
|
const MAX_ROOMS: i32 = 30;
|
||||||
const MIN_SIZE: i32 = 6;
|
const MIN_SIZE: i32 = 6;
|
||||||
const MAX_SIZE: i32 = 10;
|
const MAX_SIZE: i32 = 10;
|
||||||
|
|
@ -38,18 +38,6 @@ impl SimpleMapBuilder {
|
||||||
apply_room_to_map(&mut build_data.map, &new_room);
|
apply_room_to_map(&mut build_data.map, &new_room);
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
|
|
||||||
if !rooms.is_empty() {
|
|
||||||
let (new_x, new_y) = new_room.centre();
|
|
||||||
let (prev_x, prev_y) = rooms[rooms.len() - 1].centre();
|
|
||||||
if rng.range(0, 2) == 1 {
|
|
||||||
apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, prev_y);
|
|
||||||
apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, new_x);
|
|
||||||
} else {
|
|
||||||
apply_vertical_tunnel(&mut build_data.map, prev_y, new_y, prev_x);
|
|
||||||
apply_horizontal_tunnel(&mut build_data.map, prev_x, new_x, new_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rooms.push(new_room);
|
rooms.push(new_room);
|
||||||
build_data.take_snapshot();
|
build_data.take_snapshot();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue