dla.rs 11 KB

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