bsp_interior.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. use super::{MapBuilder, Map, Rect, TileType, Position, spawner, SHOW_MAPGEN_VISUALIZER,
  2. draw_corridor};
  3. use rltk::RandomNumberGenerator;
  4. use specs::prelude::*;
  5. const MIN_ROOM_SIZE : i32 = 8;
  6. pub struct BspInteriorBuilder {
  7. map : Map,
  8. starting_position : Position,
  9. depth: i32,
  10. rooms: Vec<Rect>,
  11. history: Vec<Map>,
  12. rects: Vec<Rect>
  13. }
  14. impl MapBuilder for BspInteriorBuilder {
  15. fn get_map(&self) -> Map {
  16. self.map.clone()
  17. }
  18. fn get_starting_position(&self) -> Position {
  19. self.starting_position.clone()
  20. }
  21. fn get_snapshot_history(&self) -> Vec<Map> {
  22. self.history.clone()
  23. }
  24. fn build_map(&mut self) {
  25. self.build();
  26. }
  27. fn spawn_entities(&mut self, ecs : &mut World) {
  28. for room in self.rooms.iter().skip(1) {
  29. spawner::spawn_room(ecs, room, self.depth);
  30. }
  31. }
  32. fn take_snapshot(&mut self) {
  33. if SHOW_MAPGEN_VISUALIZER {
  34. let mut snapshot = self.map.clone();
  35. for v in snapshot.revealed_tiles.iter_mut() {
  36. *v = true;
  37. }
  38. self.history.push(snapshot);
  39. }
  40. }
  41. }
  42. impl BspInteriorBuilder {
  43. pub fn new(new_depth : i32) -> BspInteriorBuilder {
  44. BspInteriorBuilder{
  45. map : Map::new(new_depth),
  46. starting_position : Position{ x: 0, y : 0 },
  47. depth : new_depth,
  48. rooms: Vec::new(),
  49. history: Vec::new(),
  50. rects: Vec::new()
  51. }
  52. }
  53. fn build(&mut self) {
  54. let mut rng = RandomNumberGenerator::new();
  55. self.rects.clear();
  56. self.rects.push( Rect::new(1, 1, self.map.width-2, self.map.height-2) ); // Start with a single map-sized rectangle
  57. let first_room = self.rects[0];
  58. self.add_subrects(first_room, &mut rng); // Divide the first room
  59. let rooms = self.rects.clone();
  60. for r in rooms.iter() {
  61. let room = *r;
  62. //room.x2 -= 1;
  63. //room.y2 -= 1;
  64. self.rooms.push(room);
  65. for y in room.y1 .. room.y2 {
  66. for x in room.x1 .. room.x2 {
  67. let idx = self.map.xy_idx(x, y);
  68. if idx > 0 && idx < ((self.map.width * self.map.height)-1) as usize {
  69. self.map.tiles[idx] = TileType::Floor;
  70. }
  71. }
  72. }
  73. self.take_snapshot();
  74. }
  75. // Now we want corridors
  76. for i in 0..self.rooms.len()-1 {
  77. let room = self.rooms[i];
  78. let next_room = self.rooms[i+1];
  79. let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2))-1);
  80. let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2))-1);
  81. let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2))-1);
  82. let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2))-1);
  83. draw_corridor(&mut self.map, start_x, start_y, end_x, end_y);
  84. self.take_snapshot();
  85. }
  86. // Don't forget the stairs
  87. let stairs = self.rooms[self.rooms.len()-1].center();
  88. let stairs_idx = self.map.xy_idx(stairs.0, stairs.1);
  89. self.map.tiles[stairs_idx] = TileType::DownStairs;
  90. self.take_snapshot();
  91. // Place the player
  92. let start = self.rooms[0].center();
  93. self.starting_position = Position{ x: start.0, y: start.1 };
  94. }
  95. fn add_subrects(&mut self, rect : Rect, rng : &mut RandomNumberGenerator) {
  96. // Remove the last rect from the list
  97. if !self.rects.is_empty() {
  98. self.rects.remove(self.rects.len() - 1);
  99. }
  100. // Calculate boundaries
  101. let width = rect.x2 - rect.x1;
  102. let height = rect.y2 - rect.y1;
  103. let half_width = width / 2;
  104. let half_height = height / 2;
  105. let split = rng.roll_dice(1, 4);
  106. if split <= 2 {
  107. // Horizontal split
  108. let h1 = Rect::new( rect.x1, rect.y1, half_width-1, height );
  109. self.rects.push( h1 );
  110. if half_width > MIN_ROOM_SIZE { self.add_subrects(h1, rng); }
  111. let h2 = Rect::new( rect.x1 + half_width, rect.y1, half_width, height );
  112. self.rects.push( h2 );
  113. if half_width > MIN_ROOM_SIZE { self.add_subrects(h2, rng); }
  114. } else {
  115. // Vertical split
  116. let v1 = Rect::new( rect.x1, rect.y1, width, half_height-1 );
  117. self.rects.push(v1);
  118. if half_height > MIN_ROOM_SIZE { self.add_subrects(v1, rng); }
  119. let v2 = Rect::new( rect.x1, rect.y1 + half_height, width, half_height );
  120. self.rects.push(v2);
  121. if half_height > MIN_ROOM_SIZE { self.add_subrects(v2, rng); }
  122. }
  123. }
  124. }