atomises rooms and corridors

- room sorter
- rounding room corners
- dogleg and bsp corridors
- room exploder
This commit is contained in:
Llywelwyn 2023-07-23 16:44:14 +01:00
parent b7b2061228
commit 2ceb20a822
9 changed files with 411 additions and 59 deletions

View file

@ -13,6 +13,7 @@ use drunkard::DrunkardsWalkBuilder;
mod maze;
use maze::MazeBuilder;
mod simple_map;
use simple_map::SimpleMapBuilder;
mod voronoi;
use voronoi::VoronoiBuilder;
mod prefab_builder;
@ -35,6 +36,16 @@ use common::*;
use specs::prelude::*;
use voronoi_spawning::VoronoiSpawning;
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
pub struct BuilderMap {
@ -119,38 +130,139 @@ pub trait MetaMapBuilder {
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) {
let builder = rng.roll_dice(1, 17);
let result: (Box<dyn InitialMapBuilder>, bool);
match builder {
1 => result = (BspDungeonBuilder::new(), true),
2 => result = (BspInteriorBuilder::new(), true),
3 => result = (CellularAutomataBuilder::new(), false),
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),
fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
let x;
let xroll = rng.roll_dice(1, 3);
match xroll {
1 => x = XStart::LEFT,
2 => x = XStart::CENTRE,
_ => x = XStart::RIGHT,
}
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 {
let mut builder = BuilderChain::new(new_depth);
builder.start_with(simple_map::SimpleMapBuilder::new());
builder.with(DLABuilder::heavy_erosion());
builder.with(AreaStartingPosition::new(XStart::CENTRE, YStart::CENTRE));
builder.with(CullUnreachable::new());
builder.with(VoronoiSpawning::new());
builder.with(DistantExit::new());
let type_roll = rng.roll_dice(1, 2);
match type_roll {
1 => random_room_builder(rng, &mut builder),
_ => random_shape_builder(rng, &mut builder),
}
/* 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
}