From 5c34390bc9ae1af6c4595956bb5894e65fc9edf9 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Mon, 10 Jan 2022 09:57:59 -0500 Subject: [PATCH] Add limestone cavern map builder --- src/map/themes.rs | 24 ++++++++ src/map/tiletype.rs | 7 ++- src/map_builders.rs | 3 + src/map_builders/limestone_cavern.rs | 86 ++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/map_builders/limestone_cavern.rs diff --git a/src/map/themes.rs b/src/map/themes.rs index eee58c1..9c31d16 100644 --- a/src/map/themes.rs +++ b/src/map/themes.rs @@ -4,6 +4,7 @@ use super::{Map, TileType}; pub fn tile_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) { let (glyph, mut fg, mut bg) = match map.depth { + 3 => get_limestone_cavern_glyph(idx, map), 2 => get_forest_glyph(idx, map), _ => get_tile_glyph_default(idx, map), }; @@ -20,6 +21,27 @@ pub fn tile_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) { (glyph, fg, bg) } +fn get_limestone_cavern_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) { + let bg = RGB::from_f32(0., 0., 0.); + + let (glyph, fg) = match map.tiles[idx] { + TileType::Wall => (to_cp437('▒'), RGB::from_f32(0.7, 0.7, 0.7)), + TileType::Bridge => (to_cp437('.'), RGB::named(rltk::CHOCOLATE)), + TileType::Road => (to_cp437('≡'), RGB::named(rltk::YELLOW)), + TileType::Grass => (to_cp437('"'), RGB::named(rltk::GREEN)), + TileType::ShallowWater => (to_cp437('░'), RGB::named(rltk::CYAN)), + TileType::DeepWater => (to_cp437('▓'), RGB::named(rltk::BLUE)), + TileType::Gravel => (to_cp437(';'), RGB::from_f32(0.5, 0.5, 0.5)), + TileType::DownStairs => (to_cp437('>'), RGB::from_f32(0., 1.0, 1.0)), + TileType::UpStairs => (to_cp437('<'), RGB::from_f32(0., 1.0, 1.0)), + TileType::Stalactite => (to_cp437('╨'), RGB::from_f32(0.5, 0.5, 0.5)), + TileType::Stalagmite => (to_cp437('╥'), RGB::from_f32(0.5, 0.5, 0.5)), + _ => (to_cp437('░'), RGB::from_f32(0.4, 0.4, 0.4)), + }; + + (glyph, fg, bg) +} + fn get_forest_glyph(idx: usize, map: &Map) -> (FontCharType, RGB, RGB) { let bg = RGB::from_f32(0., 0., 0.); @@ -58,6 +80,8 @@ fn get_tile_glyph_default(idx: usize, map: &Map) -> (rltk::FontCharType, RGB, RG TileType::DeepWater => (to_cp437('~'), RGB::named(rltk::NAVY_BLUE)), TileType::Gravel => (to_cp437(';'), RGB::named(rltk::GRAY)), TileType::UpStairs => (to_cp437('<'), RGB::from_f32(0., 1.0, 1.0)), + TileType::Stalactite => (to_cp437('╨'), RGB::from_f32(0.5, 0.5, 0.5)), + TileType::Stalagmite => (to_cp437('╥'), RGB::from_f32(0.5, 0.5, 0.5)), }; if map.bloodstains.contains(&idx) { diff --git a/src/map/tiletype.rs b/src/map/tiletype.rs index d12d640..10ce6bb 100644 --- a/src/map/tiletype.rs +++ b/src/map/tiletype.rs @@ -13,6 +13,8 @@ pub enum TileType { Bridge, Gravel, UpStairs, + Stalactite, + Stalagmite, } pub fn tile_walkable(tt: TileType) -> bool { @@ -31,7 +33,10 @@ pub fn tile_walkable(tt: TileType) -> bool { } pub fn tile_opaque(tt: TileType) -> bool { - matches!(tt, TileType::Wall) + matches!( + tt, + TileType::Wall | TileType::Stalactite | TileType::Stalagmite + ) } pub fn tile_cost(tt: TileType) -> f32 { diff --git a/src/map_builders.rs b/src/map_builders.rs index a731e7c..c307a5d 100644 --- a/src/map_builders.rs +++ b/src/map_builders.rs @@ -9,6 +9,7 @@ mod dla; mod door_placement; mod drunkard; mod forest; +mod limestone_cavern; mod maze; mod prefab_builder; mod room_based_spawner; @@ -41,6 +42,7 @@ use dla::DLABuilder; use door_placement::DoorPlacement; use drunkard::DrunkardsWalkBuilder; use forest::forest_builder; +use limestone_cavern::limestone_cavern_builder; use maze::MazeBuilder; use prefab_builder::PrefabBuilder; use room_based_spawner::RoomBasedSpawner; @@ -345,6 +347,7 @@ pub fn level_builder( match new_depth { 1 => town_builder(new_depth, rng, width, height), 2 => forest_builder(new_depth, rng, width, height), + 3 => limestone_cavern_builder(new_depth, rng, width, height), _ => random_builder(new_depth, rng, width, height), } } diff --git a/src/map_builders/limestone_cavern.rs b/src/map_builders/limestone_cavern.rs new file mode 100644 index 0000000..c0fc635 --- /dev/null +++ b/src/map_builders/limestone_cavern.rs @@ -0,0 +1,86 @@ +use ::rltk::RandomNumberGenerator; + +use super::{ + AreaStartingPosition, BuilderChain, BuilderMap, CullUnreachable, DistantExit, + DrunkardsWalkBuilder, MetaMapBuilder, VoronoiSpawning, XStart, YStart, +}; +use crate::map::{self, TileType}; + +pub fn limestone_cavern_builder( + new_depth: i32, + _rng: &mut RandomNumberGenerator, + width: i32, + height: i32, +) -> BuilderChain { + let mut chain = BuilderChain::new(new_depth, width, height, "Limestone Caverns"); + chain + .start_with(DrunkardsWalkBuilder::winding_passages()) + .with(AreaStartingPosition::new(XStart::Center, YStart::Center)) + .with(CullUnreachable::new()) + .with(AreaStartingPosition::new(XStart::Left, YStart::Center)) + .with(VoronoiSpawning::new()) + .with(DistantExit::new()) + .with(CaveDecorator::new()); + + chain +} + +pub struct CaveDecorator {} + +impl MetaMapBuilder for CaveDecorator { + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); + } +} + +impl CaveDecorator { + #[allow(dead_code)] + pub fn new() -> Box { + Box::new(CaveDecorator {}) + } + + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + let old_map = build_data.map.clone(); + for (idx, tt) in build_data.map.tiles.iter_mut().enumerate() { + // Gravel Spawning + if *tt == TileType::Floor && rng.roll_dice(1, 6) == 1 { + *tt = TileType::Gravel; + } else if *tt == TileType::Floor && rng.roll_dice(1, 10) == 1 { + // Spawn passable pools + *tt = TileType::ShallowWater; + } else if *tt == TileType::Wall { + // Spawn deep pools and stalactites + let mut neighbors = 0; + let x = idx as i32 % old_map.width; + let y = idx as i32 / old_map.width; + + if x > 0 && old_map.tiles[idx - 1] == TileType::Wall { + neighbors += 1; + } + if x < old_map.width - 2 && old_map.tiles[idx + 1] == TileType::Wall { + neighbors += 1 + } + if y > 0 && old_map.tiles[idx - old_map.width as usize] == TileType::Wall { + neighbors += 1 + } + if y < old_map.height - 2 + && old_map.tiles[idx + old_map.width as usize] == TileType::Wall + { + neighbors += 1 + } + + if neighbors == 2 { + *tt = TileType::DeepWater; + } else if neighbors == 1 { + *tt = match rng.roll_dice(1, 4) { + 1 => TileType::Stalactite, + 2 => TileType::Stalagmite, + _ => *tt, + } + } + } + } + + build_data.take_snapshot(); + } +}