banished_game/behaviour/character/
movement.rs1use super::*;
5
6#[derive(Debug, Clone)]
11pub struct MoveTo {
12 pub target: [f32; 3],
15 pub flags: u32,
18 pub walk: usize,
21 pub stand: usize,
23 pub mode: u32,
26 pub speed: f32,
29 pub following: bool,
34 pending: Option<Option<Vec<i32>>>,
36 index: i32,
38 count: i32,
39 path: [i32; PATH_CELLS],
40 resume: bool,
42}
43
44impl MoveTo {
45 pub fn new(
49 target: [f32; 3],
50 walk: usize,
51 stand: usize,
52 flags: u32,
53 mode: u32,
54 speed: f32,
55 rng: &mut Random,
56 ) -> MoveTo {
57 MoveTo {
58 target,
59 flags,
60 walk,
61 stand,
62 mode,
63 speed: if speed >= 0.0 {
64 speed
65 } else {
66 rng.rand_float_tol() * 0.1 + 1.0
67 },
68 following: false,
69 pending: None,
70 index: -1,
71 count: 0,
72 path: [0; PATH_CELLS],
73 resume: false,
74 }
75 }
76
77 #[allow(clippy::too_many_arguments)]
84 pub fn restored(
85 target: [f32; 3],
86 walk: usize,
87 stand: usize,
88 flags: u32,
89 mode: u32,
90 speed: f32,
91 following: bool,
92 index: i32,
93 path: &[i32],
94 ) -> MoveTo {
95 let n = path.len().min(PATH_CELLS);
96 let mut cells = [0; PATH_CELLS];
97 cells[..n].copy_from_slice(&path[..n]);
98 MoveTo {
99 target,
100 flags,
101 walk,
102 stand,
103 mode,
104 speed,
105 following,
106 pending: None,
107 index,
108 count: n as i32,
109 path: cells,
110 resume: true,
111 }
112 }
113
114 pub fn saved_way(&self) -> (i32, &[i32]) {
117 (
118 self.index,
119 &self.path[..(self.count.max(0) as usize).min(PATH_CELLS)],
120 )
121 }
122
123 pub(super) fn request(&mut self, from: [f32; 3], world: &mut World) {
124 let a = world.cell(from);
125 let b = world.cell(self.target);
126 self.index = -1;
127 if a == b {
128 self.count = 1;
129 self.path[0] = a;
130 self.index = 0;
131 return;
132 }
133 world.pathfinder.set_mode(self.mode);
134 self.pending = Some(pathfind::request(
135 world.pathfinder,
136 world.types,
137 world.regions,
138 self.flags,
139 a,
140 b,
141 ));
142 }
143
144 pub(super) fn face_waypoint(&self, ch: &mut Character, world: &World) {
145 let cell = self.path[(self.index as usize).min(PATH_CELLS - 1)];
146 ch.face(world.cell_centre(cell));
147 }
148
149 pub(super) fn start(
151 &mut self,
152 ch: &mut Character,
153 world: &mut World,
154 group: &AnimationGroup,
155 ) -> Status {
156 let d = [
157 ch.position[0] - self.target[0],
158 ch.position[1] - self.target[1],
159 ];
160 if (d[0] * d[0] + d[1] * d[1]).sqrt() < ARRIVE {
161 return Status::Done;
162 }
163 self.request(ch.position, world);
164 if self.index < 0 {
165 return match self.pending {
166 Some(Some(_)) => Status::Running,
167 _ => Status::Failed,
168 };
169 }
170 self.face_waypoint(ch, world);
171 ch.play(self.walk, group, 1.0);
172 Status::Running
173 }
174
175 pub(super) fn update(
177 &mut self,
178 ch: &mut Character,
179 world: &mut World,
180 group: &AnimationGroup,
181 ) -> Status {
182 if std::mem::take(&mut self.resume) && self.index >= 0 && self.index < self.count {
188 self.face_waypoint(ch, world);
189 ch.play(self.walk, group, 1.0);
190 }
191 if self.index != -1 {
192 let here = world.cell(ch.position);
193 if world.cell(self.target) == here {
194 let d = [
195 ch.position[0] - self.target[0],
196 ch.position[1] - self.target[1],
197 ];
198 if (d[0] * d[0] + d[1] * d[1]).sqrt() >= ARRIVE {
199 ch.face(self.target);
200 return Status::Running;
201 }
202 return Status::Done;
203 }
204 if self.count < 2 {
205 return Status::Running;
206 }
207 if self.index < self.count {
208 let t = world.types[here as usize].0;
209 let scale = if self.following {
210 ch.desc.follow_speed
211 } else if t == 1 || t == 9 {
212 ch.desc.road_speed
213 } else if t == 0 {
214 ch.desc.type0_speed
215 } else {
216 1.0
217 };
218 ch.speed = scale * self.speed;
219 if here != self.path[self.index as usize] {
220 return Status::Running;
221 }
222 self.index += 1;
223 self.face_waypoint(ch, world);
224 return Status::Running;
225 }
226 ch.play(self.stand, group, 1.0);
227 self.index = -1;
228 return Status::Running;
229 }
230 if let Some(result) = self.pending.take() {
231 let Some(path) = result else {
232 return Status::Failed;
233 };
234 let n = path.len().min(PATH_CELLS);
235 self.path[..n].copy_from_slice(&path[..n]);
236 self.count = n as i32;
237 if n == 0 {
238 return Status::Failed;
239 }
240 self.index = 1;
241 self.face_waypoint(ch, world);
242 ch.play(self.walk, group, 1.0);
243 return Status::Running;
244 }
245 match self.start(ch, world, group) {
246 Status::Failed => Status::Failed,
247 _ => Status::Running,
248 }
249 }
250}