diff --git a/src/map_builders/bsp_dungeon.rs b/src/map_builders/bsp_dungeon.rs index 33fff2d..362657f 100644 --- a/src/map_builders/bsp_dungeon.rs +++ b/src/map_builders/bsp_dungeon.rs @@ -3,7 +3,7 @@ use crate::map_builders::common::apply_room_to_map; use crate::spawner; use crate::{components::Position, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER}; use rltk::RandomNumberGenerator; -use specs::World; +use specs::prelude::*; pub struct BspDungeonBuilder { map: Map, diff --git a/src/map_builders/bsp_interior.rs b/src/map_builders/bsp_interior.rs new file mode 100644 index 0000000..29b142f --- /dev/null +++ b/src/map_builders/bsp_interior.rs @@ -0,0 +1,140 @@ +use super::MapBuilder; +use crate::map_builders::common::apply_room_to_map; +use crate::spawner; +use crate::{components::Position, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER}; +use rltk::RandomNumberGenerator; +use specs::prelude::*; + +const MIN_ROOM_SIZE: i32 = 8; + +pub struct BspInteriorBuilder { + map: Map, + starting_position: Position, + depth: i32, + rooms: Vec, + history: Vec, + rects: Vec, +} + +impl MapBuilder for BspInteriorBuilder { + fn get_map(&self) -> Map { + self.map.clone() + } + + fn get_starting_position(&self) -> Position { + self.starting_position.clone() + } + + fn get_snapshot_history(&self) -> Vec { + self.history.clone() + } + + fn build_map(&mut self) { + self.build(); + } + + fn spawn_entities(&mut self, ecs: &mut World) { + for room in self.rooms.iter().skip(1) { + spawner::spawn_room(ecs, room, self.depth); + } + } + + 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); + } + } +} + +impl BspInteriorBuilder { + pub fn new(new_depth: i32) -> BspInteriorBuilder { + BspInteriorBuilder { + map: Map::new(new_depth), + starting_position: Position { x: 0, y: 0 }, + depth: new_depth, + rooms: Vec::new(), + history: Vec::new(), + rects: Vec::new(), + } + } + + fn build(&mut self) { + let mut rng = RandomNumberGenerator::new(); + + self.rects.clear(); + + // Start with a single map-sized rectangle + self.rects + .push(Rect::new(1, 1, self.map.width - 2, self.map.height - 2)); + + let first_room = self.rects[0]; + self.add_subrects(first_room, &mut rng); // Divide the first room + + let rooms = self.rects.clone(); + for r in rooms.iter() { + let room = *r; + + self.rooms.push(room); + for y in room.y1..room.y2 { + for x in room.x1..room.x2 { + let idx = self.map.xy_idx(x, y); + if idx > 0 && idx < ((self.map.width * self.map.height) - 1) as usize { + self.map.tiles[idx] = TileType::Floor; + } + } + } + + self.take_snapshot(); + } + + let start = self.rooms[0].center(); + self.starting_position = start.into(); + } + + fn add_subrects(&mut self, rect: Rect, rng: &mut RandomNumberGenerator) { + // Remove the last rect from the list + if !self.rects.is_empty() { + self.rects.remove(self.rects.len() - 1); + } + + // Calculate boundaries + let width = rect.x2 - rect.x1; + let height = rect.y2 - rect.y1; + let half_width = width / 2; + let half_height = height / 2; + + let split = rng.roll_dice(1, 4); + + if split <= 2 { + // Horizontal split + let h1 = Rect::new(rect.x1, rect.y1, half_width - 1, height); + self.rects.push(h1); + if half_width > MIN_ROOM_SIZE { + self.add_subrects(h1, rng); + } + + let h2 = Rect::new(rect.x1 + half_width, rect.y1, half_width, height); + self.rects.push(h2); + if half_width > MIN_ROOM_SIZE { + self.add_subrects(h2, rng); + } + } else { + // Vertical split + let v1 = Rect::new(rect.x1, rect.y1, width, half_height - 1); + self.rects.push(v1); + if half_height > MIN_ROOM_SIZE { + self.add_subrects(v1, rng); + } + + let v2 = Rect::new(rect.x1, rect.y1 + half_height, width, half_height); + self.rects.push(v2); + if half_height > MIN_ROOM_SIZE { + self.add_subrects(v2, rng); + } + } + } +} diff --git a/src/map_builders/mod.rs b/src/map_builders/mod.rs index 9ae675b..31a6138 100644 --- a/src/map_builders/mod.rs +++ b/src/map_builders/mod.rs @@ -1,9 +1,11 @@ mod bsp_dungeon; +mod bsp_interior; mod common; mod simple_map; use crate::{Map, Position}; use bsp_dungeon::BspDungeonBuilder; +use bsp_interior::BspInteriorBuilder; use common::*; use simple_map::SimpleMapBuilder; use specs::prelude::*;