Implement map builder for level 5

This commit is contained in:
Timothy Warren 2022-01-18 09:32:48 -05:00
parent e71c391f3a
commit 9e85abb29b
4 changed files with 174 additions and 5 deletions

View File

@ -5,6 +5,14 @@ use crate::colors;
pub fn tile_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) {
let (glyph, mut fg, mut bg) = match map.depth {
5 => {
let x = idx as i32 % map.width;
if x < map.width / 2 {
get_limestone_cavern_glyph(idx, map)
} else {
get_tile_glyph_default(idx, map)
}
}
3 | 4 => get_limestone_cavern_glyph(idx, map),
2 => get_forest_glyph(idx, map),
_ => get_tile_glyph_default(idx, map),

View File

@ -1,3 +1,4 @@
mod area_ending_point;
mod area_starting_points;
mod bsp_dungeon;
mod bsp_interior;
@ -32,6 +33,7 @@ mod waveform_collapse;
use ::rltk::RandomNumberGenerator;
use ::specs::prelude::*;
use area_ending_point::{AreaEndingPosition, XEnd, YEnd};
use area_starting_points::{AreaStartingPosition, XStart, YStart};
use bsp_dungeon::BspDungeonBuilder;
use bsp_interior::BspInteriorBuilder;
@ -42,7 +44,9 @@ use dla::DLABuilder;
use door_placement::DoorPlacement;
use drunkard::DrunkardsWalkBuilder;
use forest::forest_builder;
use limestone_cavern::{limestone_cavern_builder, limestone_deep_cavern_builder};
use limestone_cavern::{
limestone_cavern_builder, limestone_deep_cavern_builder, limestone_transition_builder,
};
use maze::MazeBuilder;
use prefab_builder::PrefabBuilder;
use room_based_spawner::RoomBasedSpawner;
@ -349,6 +353,7 @@ pub fn level_builder(
2 => forest_builder(new_depth, rng, width, height),
3 => limestone_cavern_builder(new_depth, rng, width, height),
4 => limestone_deep_cavern_builder(new_depth, rng, width, height),
5 => limestone_transition_builder(new_depth, rng, width, height),
_ => random_builder(new_depth, rng, width, height),
}
}

View File

@ -0,0 +1,73 @@
use ::rltk::{DistanceAlg, Point, RandomNumberGenerator};
use super::{BuilderMap, MetaMapBuilder};
use crate::{map, Map, TileType};
#[allow(dead_code)]
pub enum XEnd {
Left,
Center,
Right,
}
#[allow(dead_code)]
pub enum YEnd {
Top,
Center,
Bottom,
}
pub struct AreaEndingPosition {
x: XEnd,
y: YEnd,
}
impl MetaMapBuilder for AreaEndingPosition {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl AreaEndingPosition {
#[allow(dead_code)]
pub fn new(x: XEnd, y: YEnd) -> Box<AreaEndingPosition> {
Box::new(AreaEndingPosition { x, y })
}
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
let seed_x = match self.x {
XEnd::Left => 1,
XEnd::Center => build_data.map.width / 2,
XEnd::Right => build_data.map.width - 2,
};
let seed_y = match self.y {
YEnd::Top => 1,
YEnd::Center => build_data.map.height / 2,
YEnd::Bottom => build_data.map.height - 2,
};
let mut available_floors: Vec<(usize, f32)> = Vec::new();
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
if map::tile_walkable(*tiletype) {
available_floors.push((
idx,
DistanceAlg::PythagorasSquared.distance2d(
Point::new(
idx as i32 % build_data.map.width,
idx as i32 / build_data.map.width,
),
Point::new(seed_x, seed_y),
),
));
}
}
if available_floors.is_empty() {
panic!("No valid floors to start on");
}
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
build_data.map.tiles[available_floors[0].0] = TileType::DownStairs;
}
}

View File

@ -1,12 +1,12 @@
use ::rltk::RandomNumberGenerator;
use super::{
AreaStartingPosition, BuilderChain, BuilderMap, CullUnreachable, DistantExit,
DrunkardsWalkBuilder, MetaMapBuilder, VoronoiSpawning, XStart, YStart,
prefab_builder::prefab_sections, AreaEndingPosition, AreaStartingPosition, BspDungeonBuilder,
BuilderChain, BuilderMap, CellularAutomataBuilder, CullUnreachable, DLABuilder, DistantExit,
DrunkardsWalkBuilder, MetaMapBuilder, NearestCorridors, PrefabBuilder, RoomBasedSpawner,
RoomDrawer, RoomExploder, RoomSort, RoomSorter, VoronoiSpawning, XEnd, XStart, YEnd, YStart,
};
use crate::map::TileType;
use crate::map_builders::dla::DLABuilder;
use crate::map_builders::prefab_builder::{prefab_sections, PrefabBuilder};
pub fn limestone_cavern_builder(
new_depth: i32,
@ -45,6 +45,28 @@ pub fn limestone_deep_cavern_builder(
chain
}
pub fn limestone_transition_builder(
new_depth: i32,
_rng: &mut RandomNumberGenerator,
width: i32,
height: i32,
) -> BuilderChain {
let mut chain = BuilderChain::new(new_depth, width, height, "Dwarf Fort - Upper Reaches");
chain
.start_with(CellularAutomataBuilder::new())
.with(AreaStartingPosition::new(XStart::Center, YStart::Center))
.with(CullUnreachable::new())
.with(AreaStartingPosition::new(XStart::Left, YStart::Center))
.with(VoronoiSpawning::new())
.with(CaveDecorator::new())
.with(CaveTransition::new())
.with(AreaStartingPosition::new(XStart::Left, YStart::Center))
.with(CullUnreachable::new())
.with(AreaEndingPosition::new(XEnd::Right, YEnd::Center));
chain
}
pub struct CaveDecorator {}
impl MetaMapBuilder for CaveDecorator {
@ -105,3 +127,64 @@ impl CaveDecorator {
build_data.map.outdoors = false;
}
}
pub struct CaveTransition {}
impl MetaMapBuilder for CaveTransition {
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
self.build(rng, build_data);
}
}
impl CaveTransition {
#[allow(dead_code)]
pub fn new() -> Box<CaveTransition> {
Box::new(CaveTransition {})
}
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
build_data.map.depth = 5;
build_data.take_snapshot();
// Build a BSP-based dungeon
let mut builder = BuilderChain::new(5, build_data.width, build_data.height, "New Map");
builder
.start_with(BspDungeonBuilder::new())
.with(RoomDrawer::new())
.with(RoomSorter::new(RoomSort::RightMost))
.with(NearestCorridors::new())
.with(RoomExploder::new())
.with(RoomBasedSpawner::new());
builder.build_map(rng);
// Add the history to our history
for h in builder.build_data.history.iter() {
build_data.history.push(h.clone());
}
build_data.take_snapshot();
// Copy the right half of the BSP map into our map
for x in build_data.map.width / 2..build_data.map.width {
for y in 0..build_data.map.height {
let idx = build_data.map.xy_idx(x, y);
build_data.map.tiles[idx] = builder.build_data.map.tiles[idx];
}
}
build_data.take_snapshot();
// Keep Voronoi spawn data from the left half of the map
let w = build_data.map.width;
build_data.spawn_list.retain(|s| {
let x = s.0 as i32 / w;
x < w / 2
});
// Keep room spawn data from the right half of the map
for s in builder.build_data.spawn_list.iter() {
let x = s.0 as i32 / w;
if x < w / 2 {
build_data.spawn_list.push(s.clone());
}
}
}
}