mapgen/filter/
drunkard.rs1use rand::prelude::*;
17use crate::MapFilter;
18use crate::{
19 map_buffer::{MapBuffer, Symmetry},
20 geometry::Point,
21 random::Rng
22};
23
24
25#[derive(PartialEq, Copy, Clone)]
26pub enum DrunkSpawnMode { StartingPoint, Random }
27
28pub struct DrunkardsWalk {
29 spawn_mode : DrunkSpawnMode,
30 drunken_lifetime : i32,
31 floor_percent: f32,
32 brush_size: usize,
33 symmetry: Symmetry
34}
35
36impl MapFilter for DrunkardsWalk {
37 fn modify_map(&self, rng: &mut StdRng, map: &MapBuffer) -> MapBuffer {
38 self.build(rng, map)
39 }
40}
41
42impl DrunkardsWalk {
43 pub fn new( spawn_mode: DrunkSpawnMode,
44 drunken_lifetime: i32,
45 floor_percent: f32,
46 brush_size: usize,
47 symmetry: Symmetry) -> Box<DrunkardsWalk>
48 {
49 Box::new(DrunkardsWalk{
50 spawn_mode,
51 drunken_lifetime,
52 floor_percent,
53 brush_size,
54 symmetry
55 })
56 }
57
58 pub fn open_area() -> Box<DrunkardsWalk> {
59 Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
60 }
61
62 pub fn open_halls() -> Box<DrunkardsWalk> {
63 Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
64 }
65
66 pub fn winding_passages() -> Box<DrunkardsWalk> {
67 Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
68 }
69
70 pub fn fat_passages() -> Box<DrunkardsWalk> {
71 Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
72 }
73
74 pub fn fearful_symmetry() -> Box<DrunkardsWalk> {
75 Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both)
76 }
77
78 fn build(&self, rng: &mut StdRng, map: &MapBuffer) -> MapBuffer {
79 let mut new_map = map.clone();
80 let starting_position = Point::new( new_map.width / 2, new_map.height / 2 );
82 new_map.set_walkable(starting_position.x, starting_position.y, true);
83
84 let total_tiles = new_map.width * new_map.height;
85 let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize;
86 let mut floor_tile_count = new_map.walkables.iter().filter(|&&a| a).count();
87 let mut digger_count = 0;
88 while floor_tile_count < desired_floor_tiles {
89 let mut drunk_x;
90 let mut drunk_y;
91 match self.spawn_mode {
92 DrunkSpawnMode::StartingPoint => {
93 drunk_x = starting_position.x;
94 drunk_y = starting_position.y;
95 }
96 DrunkSpawnMode::Random => {
97 if digger_count == 0 {
98 drunk_x = starting_position.x;
99 drunk_y = starting_position.y;
100 } else {
101 drunk_x = rng.roll_dice(1, new_map.width - 3) + 1;
102 drunk_y = rng.roll_dice(1, new_map.height - 3) + 1;
103 }
104 }
105 }
106 let mut drunk_life = self.drunken_lifetime;
107
108 while drunk_life > 0 {
109 new_map.set_walkable(drunk_x, drunk_y, false);
110 new_map.paint(self.symmetry, self.brush_size, drunk_x, drunk_y);
111
112 let stagger_direction = rng.roll_dice(1, 4);
113 match stagger_direction {
114 1 => { if drunk_x > 1 { drunk_x -= 1; } }
115 2 => { if drunk_x < new_map.width-2 { drunk_x += 1; } }
116 3 => { if drunk_y > 1 { drunk_y -=1; } }
117 _ => { if drunk_y < new_map.height-2 { drunk_y += 1; } }
118 }
119
120 drunk_life -= 1;
121 }
122
123 digger_count += 1;
124 floor_tile_count = new_map.walkables.iter().filter(|&&a| a).count();
125 }
126
127 new_map
128 }
129}