From 5454dd0755182566d48fc13e431f63458487fe65 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Mon, 13 Dec 2021 15:22:59 -0500 Subject: [PATCH] Add initial room vaults --- src/map_builders.rs | 2 +- src/map_builders/prefab_builder.rs | 146 ++++++++++++++++-- .../prefab_builder/prefab_rooms.rs | 64 ++++++++ 3 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 src/map_builders/prefab_builder/prefab_rooms.rs diff --git a/src/map_builders.rs b/src/map_builders.rs index f60ba60..0be014d 100644 --- a/src/map_builders.rs +++ b/src/map_builders.rs @@ -69,6 +69,6 @@ pub fn random_builder(new_depth: i32) -> Box { Box::new(PrefabBuilder::new( new_depth, - Some(Box::new(CellularAutomataBuilder::new(new_depth))), + Some(Box::new(SimpleMapBuilder::new(new_depth))), )) } diff --git a/src/map_builders/prefab_builder.rs b/src/map_builders/prefab_builder.rs index 7a5071d..e0221ef 100644 --- a/src/map_builders/prefab_builder.rs +++ b/src/map_builders/prefab_builder.rs @@ -1,4 +1,5 @@ mod prefab_levels; +mod prefab_rooms; mod prefab_sections; use rltk::RandomNumberGenerator; @@ -19,6 +20,7 @@ pub enum PrefabMode { Sectional { section: prefab_sections::PrefabSection, }, + RoomVaults, } pub struct PrefabBuilder { @@ -71,9 +73,7 @@ impl PrefabBuilder { starting_position: Position { x: 0, y: 0 }, depth: new_depth, history: Vec::new(), - mode: PrefabMode::Sectional { - section: prefab_sections::UNDERGROUND_FORT, - }, + mode: PrefabMode::RoomVaults, previous_builder, spawn_list: Vec::new(), } @@ -84,6 +84,7 @@ impl PrefabBuilder { PrefabMode::RexLevel { template } => self.load_rex_map(template), PrefabMode::Constant { level } => self.load_ascii_map(&level), PrefabMode::Sectional { section } => self.apply_sectional(§ion), + PrefabMode::RoomVaults => self.apply_room_vaults(), } self.take_snapshot(); @@ -206,6 +207,28 @@ impl PrefabBuilder { } } + fn apply_previous_iteration(&mut self, mut filter: F) + where + F: FnMut(i32, i32, &(usize, String)) -> bool, + { + // Build the map + let prev_builder = self.previous_builder.as_mut().unwrap(); + prev_builder.build_map(); + self.starting_position = prev_builder.get_starting_position(); + self.map = prev_builder.get_map(); + self.history = prev_builder.get_snapshot_history(); + for e in prev_builder.get_spawn_list().iter() { + let idx = e.0; + let x = idx as i32 % self.map.width; + let y = idx as i32 / self.map.width; + + if filter(x, y, e) { + self.spawn_list.push((idx, e.1.to_string())) + } + } + self.take_snapshot(); + } + pub fn apply_sectional(&mut self, section: &prefab_sections::PrefabSection) { use prefab_sections::*; @@ -225,23 +248,12 @@ impl PrefabBuilder { }; // Build the map - let prev_builder = self.previous_builder.as_mut().unwrap(); - prev_builder.build_map(); - self.starting_position = prev_builder.get_starting_position(); - self.map = prev_builder.get_map(); - for e in prev_builder.get_spawn_list().iter() { - let idx = e.0; - let x = idx as i32 % self.map.width; - let y = idx as i32 / self.map.width; - if x < chunk_x + self.apply_previous_iteration(|x, y, e| { + x < chunk_x || x > (chunk_x + section.width as i32) || y < chunk_y || y > (chunk_y + section.height as i32) - { - self.spawn_list.push((idx, e.1.to_string())) - } - } - self.take_snapshot(); + }); let mut i = 0; for ty in 0..section.height { @@ -255,4 +267,104 @@ impl PrefabBuilder { } self.take_snapshot(); } + + fn apply_room_vaults(&mut self) { + use prefab_rooms::*; + let mut rng = RandomNumberGenerator::new(); + + // Apply the previous builder, and keep all entities it spawns (for now) + self.apply_previous_iteration(|_x, _y, _e| true); + + // Note that this is a place-holder and will be moved out of this function + let master_vault_list = vec![TOTALLY_NOT_A_TRAP, CHECKERBOARD, SILLY_SMILE]; + + // Filter the possible vault list down to ones that are application to the current depth + let possible_vaults: Vec<&PrefabRoom> = master_vault_list + .iter() + .filter(|v| self.depth >= v.first_depth && self.depth <= v.last_depth) + .collect(); + + // Bail out if there's nothing to build + if possible_vaults.is_empty() { + return; + } + + let vault_index = if possible_vaults.len() == 1 { + 0 + } else { + (rng.roll_dice(1, possible_vaults.len() as i32) - 1) as usize + }; + let vault = possible_vaults[vault_index]; + + // We'll make a list of places in which the vault could fit + let mut vault_positions: Vec = Vec::new(); + + let mut idx = 0_usize; + loop { + let x = (idx % self.map.width as usize) as i32; + let y = (idx / self.map.width as usize) as i32; + + // Check that we won't overflow the map + if x > 1 + && (x + vault.width as i32) < self.map.width - 2 + && y > 1 + && (y + vault.height as i32) < self.map.height - 2 + { + let mut possible = true; + for ty in 0..vault.height as i32 { + for tx in 0..vault.width as i32 { + let idx = self.map.xy_idx(tx + x, ty + y); + if self.map.tiles[idx] != TileType::Floor { + possible = false; + } + } + } + + if possible { + vault_positions.push(Position { x, y }); + break; + } + + idx += 1; + if idx >= self.map.tiles.len() - 1 { + break; + } + } + } + + if !vault_positions.is_empty() { + let pos_idx = if vault_positions.len() == 1 { + 0 + } else { + (rng.roll_dice(1, vault_positions.len() as i32) - 1) as usize + }; + let pos = &vault_positions[pos_idx]; + + let chunk_x = pos.x; + let chunk_y = pos.y; + + let width = self.map.width; + let height = self.map.height; + self.spawn_list.retain(|e| { + let idx = e.0 as i32; + let x = idx % width; + let y = idx / height; + x < chunk_x + || x > chunk_x + vault.width as i32 + || y < chunk_y + || y > chunk_y + vault.height as i32 + }); + + let string_vec = PrefabBuilder::read_ascii_to_vec(vault.template); + let mut i = 0; + for ty in 0..vault.height { + for tx in 0..vault.width { + let idx = self.map.xy_idx(tx as i32 + chunk_x, ty as i32 + chunk_y); + self.char_to_map(string_vec[i], idx); + i += 1; + } + } + self.take_snapshot(); + } + } } diff --git a/src/map_builders/prefab_builder/prefab_rooms.rs b/src/map_builders/prefab_builder/prefab_rooms.rs new file mode 100644 index 0000000..aa6a8af --- /dev/null +++ b/src/map_builders/prefab_builder/prefab_rooms.rs @@ -0,0 +1,64 @@ +#[allow(dead_code)] +#[derive(PartialEq, Copy, Clone)] +pub struct PrefabRoom { + pub template: &'static str, + pub width: usize, + pub height: usize, + pub first_depth: i32, + pub last_depth: i32, +} + +#[allow(dead_code)] +pub const TOTALLY_NOT_A_TRAP: PrefabRoom = PrefabRoom { + template: TOTALLY_NOT_A_TRAP_MAP, + width: 5, + height: 5, + first_depth: 0, + last_depth: 100, +}; + +#[allow(dead_code)] +const TOTALLY_NOT_A_TRAP_MAP: &str = " + + ^^^ + ^!^ + ^^^ + +"; + +#[allow(dead_code)] +pub const SILLY_SMILE: PrefabRoom = PrefabRoom { + template: SILLY_SMILE_MAP, + width: 6, + height: 6, + first_depth: 0, + last_depth: 100, +}; + +#[allow(dead_code)] +const SILLY_SMILE_MAP: &str = " + + ^ ^ + # + + ### + +"; + +#[allow(dead_code)] +pub const CHECKERBOARD: PrefabRoom = PrefabRoom { + template: CHECKERBOARD_MAP, + width: 6, + height: 6, + first_depth: 0, + last_depth: 100, +}; + +#[allow(dead_code)] +const CHECKERBOARD_MAP: &str = " + + g#%# + #!# + ^# # + +";