From ec6e44477bfe4d09c11db5b22d94880cdc76539b Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Tue, 14 Dec 2021 17:29:44 -0500 Subject: [PATCH] Refactor bsp_dungeon builder to use Rust builder pattern --- src/map_builders/bsp_dungeon.rs | 129 ++++++++------------------------ src/map_builders/common.rs | 20 +++++ 2 files changed, 50 insertions(+), 99 deletions(-) diff --git a/src/map_builders/bsp_dungeon.rs b/src/map_builders/bsp_dungeon.rs index 11bfd26..73fa0f1 100644 --- a/src/map_builders/bsp_dungeon.rs +++ b/src/map_builders/bsp_dungeon.rs @@ -1,74 +1,35 @@ use rltk::RandomNumberGenerator; -use super::MapBuilder; use crate::components::Position; -use crate::map_builders::common::apply_room_to_map; +use crate::map_builders::common::{apply_room_to_map, draw_corridor}; use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER}; +use crate::map_builders::{BuilderMap, InitialMapBuilder}; pub struct BspDungeonBuilder { - map: Map, - starting_position: Position, - depth: i32, - rooms: Vec, - history: Vec, rects: Vec, - spawn_list: Vec<(usize, String)>, } -impl MapBuilder for BspDungeonBuilder { - fn get_map(&self) -> Map { - self.map.clone() - } - - fn get_starting_position(&self) -> Position { - self.starting_position - } - - fn get_snapshot_history(&self) -> Vec { - self.history.clone() - } - - fn build_map(&mut self) { - self.build(); - } - - 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); - } - } - - fn get_spawn_list(&self) -> &Vec<(usize, String)> { - &self.spawn_list +impl InitialMapBuilder for BspDungeonBuilder { + #[allow(dead_code)] + fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + self.build(rng, build_data); } } impl BspDungeonBuilder { - pub fn new(new_depth: i32) -> BspDungeonBuilder { - BspDungeonBuilder { - map: Map::new(new_depth), - starting_position: Position { x: 0, y: 0 }, - depth: new_depth, - rooms: Vec::new(), - history: Vec::new(), + pub fn new() -> Box { + Box::new(BspDungeonBuilder { rects: Vec::new(), - spawn_list: Vec::new(), - } + }) } - fn build(&mut self) { - let mut rng = RandomNumberGenerator::new(); - + fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) { + let mut rooms: Vec = Vec::new(); self.rects.clear(); // Start with a single map-sized rectangle self.rects - .push(Rect::new(2, 2, self.map.width - 5, self.map.height - 5)); + .push(Rect::new(2, 2, build_data.map.width - 5, build_data.map.height - 5)); let first_room = self.rects[0]; self.add_subrects(first_room); // Divide the first room @@ -76,26 +37,26 @@ impl BspDungeonBuilder { // a room in there, we place it and add it to the rooms list. let mut n_rooms = 0; while n_rooms < 240 { - let rect = self.get_random_rect(&mut rng); - let candidate = self.get_random_sub_rect(rect, &mut rng); + let rect = self.get_random_rect(rng); + let candidate = self.get_random_sub_rect(rect, rng); - if self.is_possible(candidate) { - apply_room_to_map(&mut self.map, &candidate); - self.rooms.push(candidate); + if self.is_possible(candidate, &build_data.map) { + apply_room_to_map(&mut build_data.map, &candidate); + rooms.push(candidate); self.add_subrects(rect); - self.take_snapshot(); + build_data.take_snapshot(); } n_rooms += 1; } // Now we sort the rooms - self.rooms.sort_by(|a, b| a.x1.cmp(&b.x1)); + rooms.sort_by(|a, b| a.x1.cmp(&b.x1)); // Now we want corridors - for i in 0..self.rooms.len() - 1 { - let room = self.rooms[i]; - let next_room = self.rooms[i + 1]; + for i in 0..rooms.len() - 1 { + let room = rooms[i]; + let next_room = rooms[i + 1]; let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2)) - 1); let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2) - 1)); let end_x = @@ -103,21 +64,11 @@ impl BspDungeonBuilder { let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2)) - 1); - self.draw_corridor(start_x, start_y, end_x, end_y); - self.take_snapshot(); + draw_corridor(&mut build_data.map, start_x, start_y, end_x, end_y); + build_data.take_snapshot(); } - // Don't forget the stairs - let stairs = self.rooms[self.rooms.len() - 1].center(); - let stairs_idx = self.map.xy_idx(stairs.0, stairs.1); - self.map.tiles[stairs_idx] = TileType::DownStairs; - - self.starting_position = Position::from(self.rooms[0].center()); - - // Spawn some entities - for room in self.rooms.iter().skip(1) { - spawner::spawn_room(&self.map, &mut rng, room, self.depth, &mut self.spawn_list); - } + build_data.rooms = Some(rooms); } fn add_subrects(&mut self, rect: Rect) { @@ -173,7 +124,7 @@ impl BspDungeonBuilder { result } - fn is_possible(&self, rect: Rect) -> bool { + fn is_possible(&self, rect: Rect, map: &Map) -> bool { let mut expanded = rect; expanded.x1 -= 2; expanded.x2 += 2; @@ -184,10 +135,10 @@ impl BspDungeonBuilder { for y in expanded.y1..=expanded.y2 { for x in expanded.x1..=expanded.x2 { - if x > self.map.width - 2 { + if x > map.width - 2 { can_build = false; } - if y > self.map.height - 2 { + if y > map.height - 2 { can_build = false; } if x < 1 { @@ -198,8 +149,8 @@ impl BspDungeonBuilder { } if can_build { - let idx = self.map.xy_idx(x, y); - if self.map.tiles[idx] != TileType::Wall { + let idx = map.xy_idx(x, y); + if map.tiles[idx] != TileType::Wall { can_build = false; } } @@ -208,24 +159,4 @@ impl BspDungeonBuilder { can_build } - - fn draw_corridor(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) { - let mut x = x1; - let mut y = y1; - - while x != x2 || y != y2 { - if x < x2 { - x += 1; - } else if x > x2 { - x -= 1; - } else if y < y2 { - y += 1; - } else if y > y2 { - y -= 1; - } - - let idx = self.map.xy_idx(x, y); - self.map.tiles[idx] = TileType::Floor; - } - } } diff --git a/src/map_builders/common.rs b/src/map_builders/common.rs index b554c19..a3973a7 100644 --- a/src/map_builders/common.rs +++ b/src/map_builders/common.rs @@ -103,6 +103,26 @@ pub fn generate_voronoi_spawn_regions( noise_areas } +pub fn draw_corridor(map: &mut Map, x1: i32, y1: i32, x2: i32, y2: i32) { + let mut x = x1; + let mut y = y1; + + while x != x2 || y != y2 { + if x < x2 { + x += 1; + } else if x > x2 { + x -= 1; + } else if y < y2 { + y += 1; + } else if y > y2 { + y -= 1; + } + + let idx = map.xy_idx(x, y); + map.tiles[idx] = TileType::Floor; + } +} + pub fn paint(map: &mut Map, mode: Symmetry, brush_size: i32, x: i32, y: i32) { match mode { Symmetry::None => apply_paint(map, brush_size, x, y),