roguelike-game/src/map_builders.rs

305 lines
8.8 KiB
Rust
Raw Normal View History

mod area_starting_points;
mod bsp_dungeon;
mod bsp_interior;
mod cellular_automata;
mod common;
mod cull_unreachable;
mod distant_exit;
mod dla;
mod drunkard;
mod maze;
mod prefab_builder;
mod room_based_spawner;
mod room_based_stairs;
mod room_based_starting_position;
mod room_corner_rounding;
mod room_corridor_spawner;
2021-12-16 16:07:33 -05:00
mod room_draw;
mod room_exploder;
mod room_sorter;
mod rooms_corridors_bsp;
mod rooms_corridors_dogleg;
2021-12-17 10:57:03 -05:00
mod rooms_corridors_lines;
2021-12-17 10:44:35 -05:00
mod rooms_corridors_nearest;
mod simple_map;
mod voronoi;
mod voronoi_spawning;
mod waveform_collapse;
use ::rltk::RandomNumberGenerator;
use area_starting_points::{AreaStartingPosition, XStart, YStart};
use bsp_dungeon::BspDungeonBuilder;
use bsp_interior::BspInteriorBuilder;
use cellular_automata::CellularAutomataBuilder;
use cull_unreachable::CullUnreachable;
use distant_exit::DistantExit;
use dla::DLABuilder;
use drunkard::DrunkardsWalkBuilder;
use maze::MazeBuilder;
use prefab_builder::PrefabBuilder;
use room_based_spawner::RoomBasedSpawner;
use room_based_stairs::RoomBasedStairs;
use room_based_starting_position::RoomBasedStartingPosition;
use room_corner_rounding::RoomCornerRounder;
use room_corridor_spawner::CorridorSpawner;
2021-12-16 16:07:33 -05:00
use room_draw::RoomDrawer;
use room_exploder::RoomExploder;
2021-12-16 13:48:36 -05:00
use room_sorter::{RoomSort, RoomSorter};
use rooms_corridors_bsp::BspCorridors;
use rooms_corridors_dogleg::DoglegCorridors;
2021-12-17 10:57:03 -05:00
use rooms_corridors_lines::StraightLineCorridors;
2021-12-17 10:44:35 -05:00
use rooms_corridors_nearest::NearestCorridors;
use simple_map::SimpleMapBuilder;
use specs::prelude::*;
use voronoi::VoronoiCellBuilder;
use voronoi_spawning::VoronoiSpawning;
use waveform_collapse::WaveformCollapseBuilder;
use crate::{spawner, Map, Position, Rect, SHOW_MAPGEN_VISUALIZER};
pub struct BuilderMap {
pub spawn_list: Vec<(usize, String)>,
pub map: Map,
pub starting_position: Option<Position>,
pub rooms: Option<Vec<Rect>>,
pub corridors: Option<Vec<Vec<usize>>>,
pub history: Vec<Map>,
}
impl BuilderMap {
fn new(new_depth: i32) -> BuilderMap {
BuilderMap {
spawn_list: Vec::new(),
map: Map::new(new_depth),
starting_position: None,
rooms: None,
corridors: None,
history: Vec::new(),
}
}
fn take_snapshot(&mut self) {
if SHOW_MAPGEN_VISUALIZER {
let mut snapshot = self.map.clone();
for v in snapshot.revealed_tiles.iter_mut() {
*v = true;
}
self.history.push(snapshot);
}
}
}
pub struct BuilderChain {
starter: Option<Box<dyn InitialMapBuilder>>,
builders: Vec<Box<dyn MetaMapBuilder>>,
pub build_data: BuilderMap,
}
impl BuilderChain {
pub fn new(new_depth: i32) -> BuilderChain {
BuilderChain {
starter: None,
builders: Vec::new(),
build_data: BuilderMap::new(new_depth),
}
}
pub fn start_with(&mut self, starter: Box<dyn InitialMapBuilder>) -> &mut Self {
match self.starter {
None => self.starter = Some(starter),
Some(_) => panic!("You can only have one starting builder."),
}
self
}
pub fn with(&mut self, metabuilder: Box<dyn MetaMapBuilder>) -> &mut Self {
self.builders.push(metabuilder);
self
}
pub fn build_map(&mut self, rng: &mut RandomNumberGenerator) -> &mut Self {
match &mut self.starter {
None => panic!("Cannot run a map builder chain without starting a build system"),
Some(starter) => {
// Build the starting map
starter.build_map(rng, &mut self.build_data);
}
}
// Build additional layers in turn
for metabuilder in self.builders.iter_mut() {
metabuilder.build_map(rng, &mut self.build_data);
}
self
}
pub fn spawn_entities(&mut self, ecs: &mut World) -> &mut Self {
for entity in self.build_data.spawn_list.iter() {
spawner::spawn_entity(ecs, &(&entity.0, &entity.1));
}
self
}
pub fn get_map(&self) -> Map {
self.build_data.map.clone()
}
pub fn get_starting_position(&self) -> Option<Position> {
self.build_data.starting_position
}
pub fn get_snapshot_history(&self) -> Vec<Map> {
self.build_data.history.clone()
}
pub fn get_spawn_list(&self) -> &Vec<(usize, String)> {
&self.build_data.spawn_list
}
}
pub trait InitialMapBuilder {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap);
}
pub trait MetaMapBuilder {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap);
}
2021-12-10 20:16:48 -05:00
fn random_start_position(rng: &mut rltk::RandomNumberGenerator) -> (XStart, YStart) {
let x = match rng.roll_dice(1, 3) {
1 => XStart::Left,
2 => XStart::Center,
_ => XStart::Right,
};
let y = match rng.roll_dice(1, 3) {
1 => YStart::Bottom,
2 => YStart::Center,
_ => YStart::Top,
};
(x, y)
}
fn random_room_builder(rng: &mut RandomNumberGenerator, builder: &mut BuilderChain) {
let build_roll = rng.roll_dice(1, 3);
match build_roll {
1 => builder.start_with(SimpleMapBuilder::new()),
2 => builder.start_with(BspDungeonBuilder::new()),
_ => builder.start_with(BspInteriorBuilder::new()),
};
// BSP Interior still makes holes in the walls
if build_roll != 3 {
// Sort by one of the 5 available algorithms
let room_sort = match rng.roll_dice(1, 5) {
1 => RoomSort::LeftMost,
2 => RoomSort::RightMost,
3 => RoomSort::TopMost,
4 => RoomSort::BottomMost,
_ => RoomSort::Central,
};
builder.with(RoomSorter::new(room_sort));
builder.with(RoomDrawer::new());
// Pick a corridor type
match rng.roll_dice(1, 2) {
1 => builder.with(DoglegCorridors::new()),
_ => builder.with(BspCorridors::new()),
};
// Add additional modifier
match rng.roll_dice(1, 6) {
1 => {
builder.with(RoomExploder::new());
}
2 => {
builder.with(RoomCornerRounder::new());
}
_ => {}
};
2021-12-15 12:08:44 -05:00
}
// Find a starting position
match rng.roll_dice(1, 2) {
1 => builder.with(RoomBasedStartingPosition::new()),
_ => {
let (start_x, start_y) = random_start_position(rng);
builder.with(AreaStartingPosition::new(start_x, start_y))
}
};
// Find an exit
match rng.roll_dice(1, 2) {
1 => builder.with(RoomBasedStairs::new()),
_ => builder.with(DistantExit::new()),
};
// Spawn stuff
match rng.roll_dice(1, 2) {
1 => builder.with(RoomBasedSpawner::new()),
_ => builder.with(VoronoiSpawning::new()),
};
2021-12-15 12:08:44 -05:00
}
fn random_shape_builder(rng: &mut RandomNumberGenerator, builder: &mut BuilderChain) {
let first_builder: Box<dyn InitialMapBuilder> = match rng.roll_dice(1, 16) {
1 => CellularAutomataBuilder::new(),
2 => DrunkardsWalkBuilder::open_area(),
3 => DrunkardsWalkBuilder::open_halls(),
4 => DrunkardsWalkBuilder::winding_passages(),
5 => DrunkardsWalkBuilder::fat_passages(),
6 => DrunkardsWalkBuilder::fearful_symmetry(),
7 => MazeBuilder::new(),
8 => DLABuilder::walk_inwards(),
9 => DLABuilder::walk_outwards(),
10 => DLABuilder::central_attractor(),
11 => DLABuilder::insectoid(),
12 => VoronoiCellBuilder::pythagoras(),
13 => VoronoiCellBuilder::manhattan(),
_ => PrefabBuilder::constant(prefab_builder::prefab_levels::WFC_POPULATED),
};
2021-12-15 12:08:44 -05:00
// Set the start to the center and cull
builder
.start_with(first_builder)
.with(AreaStartingPosition::new(XStart::Center, YStart::Center))
.with(CullUnreachable::new());
// Now set the start ot a random starting area
let (start_x, start_y) = random_start_position(rng);
builder.with(AreaStartingPosition::new(start_x, start_y));
// Setup an exit and spawn mobs
builder.with(VoronoiSpawning::new());
builder.with(DistantExit::new());
}
pub fn random_builder(new_depth: i32, rng: &mut RandomNumberGenerator) -> BuilderChain {
let mut builder = BuilderChain::new(new_depth);
match rng.roll_dice(1, 2) {
1 => random_room_builder(rng, &mut builder),
_ => random_shape_builder(rng, &mut builder),
};
if rng.roll_dice(1, 3) == 1 {
builder.with(WaveformCollapseBuilder::new());
}
if rng.roll_dice(1, 20) == 1 {
builder.with(PrefabBuilder::sectional(
prefab_builder::prefab_sections::UNDERGROUND_FORT,
));
}
builder.with(PrefabBuilder::vaults());
2021-12-14 14:16:18 -05:00
builder
}