dla.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. use super::{MapBuilder, Map,
  2. TileType, Position, spawner, SHOW_MAPGEN_VISUALIZER,
  3. remove_unreachable_areas_returning_most_distant, generate_voronoi_spawn_regions,
  4. Symmetry, paint};
  5. use rltk::RandomNumberGenerator;
  6. use specs::prelude::*;
  7. use std::collections::HashMap;
  8. #[derive(PartialEq, Copy, Clone)]
  9. pub enum DLAAlgorithm { WalkInwards, WalkOutwards, CentralAttractor }
  10. pub struct DLABuilder {
  11. map : Map,
  12. starting_position : Position,
  13. depth: i32,
  14. history: Vec<Map>,
  15. noise_areas : HashMap<i32, Vec<usize>>,
  16. algorithm : DLAAlgorithm,
  17. brush_size: i32,
  18. symmetry: Symmetry,
  19. floor_percent: f32
  20. }
  21. impl MapBuilder for DLABuilder {
  22. fn get_map(&self) -> Map {
  23. self.map.clone()
  24. }
  25. fn get_starting_position(&self) -> Position {
  26. self.starting_position.clone()
  27. }
  28. fn get_snapshot_history(&self) -> Vec<Map> {
  29. self.history.clone()
  30. }
  31. fn build_map(&mut self) {
  32. self.build();
  33. }
  34. fn spawn_entities(&mut self, ecs : &mut World) {
  35. for area in self.noise_areas.iter() {
  36. spawner::spawn_region(ecs, area.1, self.depth);
  37. }
  38. }
  39. fn take_snapshot(&mut self) {
  40. if SHOW_MAPGEN_VISUALIZER {
  41. let mut snapshot = self.map.clone();
  42. for v in snapshot.revealed_tiles.iter_mut() {
  43. *v = true;
  44. }
  45. self.history.push(snapshot);
  46. }
  47. }
  48. }
  49. impl DLABuilder {
  50. pub fn new(new_depth : i32) -> DLABuilder {
  51. DLABuilder{
  52. map : Map::new(new_depth),
  53. starting_position : Position{ x: 0, y : 0 },
  54. depth : new_depth,
  55. history: Vec::new(),
  56. noise_areas : HashMap::new(),
  57. algorithm: DLAAlgorithm::WalkInwards,
  58. brush_size: 2,
  59. symmetry: Symmetry::None,
  60. floor_percent: 0.25
  61. }
  62. }
  63. pub fn walk_inwards(new_depth : i32) -> DLABuilder {
  64. DLABuilder{
  65. map : Map::new(new_depth),
  66. starting_position : Position{ x: 0, y : 0 },
  67. depth : new_depth,
  68. history: Vec::new(),
  69. noise_areas : HashMap::new(),
  70. algorithm: DLAAlgorithm::WalkInwards,
  71. brush_size: 1,
  72. symmetry: Symmetry::None,
  73. floor_percent: 0.25
  74. }
  75. }
  76. pub fn walk_outwards(new_depth : i32) -> DLABuilder {
  77. DLABuilder{
  78. map : Map::new(new_depth),
  79. starting_position : Position{ x: 0, y : 0 },
  80. depth : new_depth,
  81. history: Vec::new(),
  82. noise_areas : HashMap::new(),
  83. algorithm: DLAAlgorithm::WalkOutwards,
  84. brush_size: 2,
  85. symmetry: Symmetry::None,
  86. floor_percent: 0.25
  87. }
  88. }
  89. pub fn central_attractor(new_depth : i32) -> DLABuilder {
  90. DLABuilder{
  91. map : Map::new(new_depth),
  92. starting_position : Position{ x: 0, y : 0 },
  93. depth : new_depth,
  94. history: Vec::new(),
  95. noise_areas : HashMap::new(),
  96. algorithm: DLAAlgorithm::CentralAttractor,
  97. brush_size: 2,
  98. symmetry: Symmetry::None,
  99. floor_percent: 0.25
  100. }
  101. }
  102. pub fn insectoid(new_depth : i32) -> DLABuilder {
  103. DLABuilder{
  104. map : Map::new(new_depth),
  105. starting_position : Position{ x: 0, y : 0 },
  106. depth : new_depth,
  107. history: Vec::new(),
  108. noise_areas : HashMap::new(),
  109. algorithm: DLAAlgorithm::CentralAttractor,
  110. brush_size: 2,
  111. symmetry: Symmetry::Horizontal,
  112. floor_percent: 0.25
  113. }
  114. }
  115. #[allow(clippy::map_entry)]
  116. fn build(&mut self) {
  117. let mut rng = RandomNumberGenerator::new();
  118. // Carve a starting seed
  119. self.starting_position = Position{ x: self.map.width/2, y : self.map.height/2 };
  120. let start_idx = self.map.xy_idx(self.starting_position.x, self.starting_position.y);
  121. self.take_snapshot();
  122. self.map.tiles[start_idx] = TileType::Floor;
  123. self.map.tiles[start_idx-1] = TileType::Floor;
  124. self.map.tiles[start_idx+1] = TileType::Floor;
  125. self.map.tiles[start_idx-self.map.width as usize] = TileType::Floor;
  126. self.map.tiles[start_idx+self.map.width as usize] = TileType::Floor;
  127. // Random walker
  128. let total_tiles = self.map.width * self.map.height;
  129. let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize;
  130. let mut floor_tile_count = self.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
  131. while floor_tile_count < desired_floor_tiles {
  132. match self.algorithm {
  133. DLAAlgorithm::WalkInwards => {
  134. let mut digger_x = rng.roll_dice(1, self.map.width - 3) + 1;
  135. let mut digger_y = rng.roll_dice(1, self.map.height - 3) + 1;
  136. let mut prev_x = digger_x;
  137. let mut prev_y = digger_y;
  138. let mut digger_idx = self.map.xy_idx(digger_x, digger_y);
  139. while self.map.tiles[digger_idx] == TileType::Wall {
  140. prev_x = digger_x;
  141. prev_y = digger_y;
  142. let stagger_direction = rng.roll_dice(1, 4);
  143. match stagger_direction {
  144. 1 => { if digger_x > 2 { digger_x -= 1; } }
  145. 2 => { if digger_x < self.map.width-2 { digger_x += 1; } }
  146. 3 => { if digger_y > 2 { digger_y -=1; } }
  147. _ => { if digger_y < self.map.height-2 { digger_y += 1; } }
  148. }
  149. digger_idx = self.map.xy_idx(digger_x, digger_y);
  150. }
  151. paint(&mut self.map, self.symmetry, self.brush_size, prev_x, prev_y);
  152. }
  153. DLAAlgorithm::WalkOutwards => {
  154. let mut digger_x = self.starting_position.x;
  155. let mut digger_y = self.starting_position.y;
  156. let mut digger_idx = self.map.xy_idx(digger_x, digger_y);
  157. while self.map.tiles[digger_idx] == TileType::Floor {
  158. let stagger_direction = rng.roll_dice(1, 4);
  159. match stagger_direction {
  160. 1 => { if digger_x > 2 { digger_x -= 1; } }
  161. 2 => { if digger_x < self.map.width-2 { digger_x += 1; } }
  162. 3 => { if digger_y > 2 { digger_y -=1; } }
  163. _ => { if digger_y < self.map.height-2 { digger_y += 1; } }
  164. }
  165. digger_idx = self.map.xy_idx(digger_x, digger_y);
  166. }
  167. paint(&mut self.map, self.symmetry, self.brush_size, digger_x, digger_y);
  168. }
  169. DLAAlgorithm::CentralAttractor => {
  170. let mut digger_x = rng.roll_dice(1, self.map.width - 3) + 1;
  171. let mut digger_y = rng.roll_dice(1, self.map.height - 3) + 1;
  172. let mut prev_x = digger_x;
  173. let mut prev_y = digger_y;
  174. let mut digger_idx = self.map.xy_idx(digger_x, digger_y);
  175. let mut path = rltk::line2d(
  176. rltk::LineAlg::Bresenham,
  177. rltk::Point::new( digger_x, digger_y ),
  178. rltk::Point::new( self.starting_position.x, self.starting_position.y )
  179. );
  180. while self.map.tiles[digger_idx] == TileType::Wall && !path.is_empty() {
  181. prev_x = digger_x;
  182. prev_y = digger_y;
  183. digger_x = path[0].x;
  184. digger_y = path[0].y;
  185. path.remove(0);
  186. digger_idx = self.map.xy_idx(digger_x, digger_y);
  187. }
  188. paint(&mut self.map, self.symmetry, self.brush_size, prev_x, prev_y);
  189. }
  190. }
  191. self.take_snapshot();
  192. floor_tile_count = self.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
  193. }
  194. // Find all tiles we can reach from the starting point
  195. let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx);
  196. self.take_snapshot();
  197. // Place the stairs
  198. self.map.tiles[exit_tile] = TileType::DownStairs;
  199. self.take_snapshot();
  200. // Now we build a noise map for use in spawning entities later
  201. self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
  202. }
  203. }