banished_game/behaviour/character/
stack.rs1use super::*;
5
6#[derive(Debug, Clone)]
7pub(super) struct Task {
8 action: Action,
9 started: bool,
10}
11
12#[derive(Debug, Clone, Default)]
15pub struct ActionStack {
16 chains: Vec<Vec<Task>>,
17 on_empty: Vec<Task>,
18 pub outbox: Vec<Message>,
23}
24
25impl ActionStack {
26 pub fn restored(entries: Vec<(Action, bool)>, on_empty: Option<Action>) -> ActionStack {
32 ActionStack {
33 chains: entries
34 .into_iter()
35 .map(|(action, started)| vec![Task { action, started }])
36 .collect(),
37 on_empty: on_empty
38 .into_iter()
39 .map(|action| Task {
40 action,
41 started: false,
42 })
43 .collect(),
44 outbox: Vec::new(),
45 }
46 }
47
48 pub fn saved(&self) -> (Vec<(&Action, bool)>, Option<&Action>) {
53 (
54 self.chains
55 .iter()
56 .filter_map(|c| c.first().map(|t| (&t.action, t.started)))
57 .collect(),
58 self.on_empty.first().map(|t| &t.action),
59 )
60 }
61
62 pub fn depth(&self) -> usize {
65 self.chains.len()
66 }
67
68 pub fn is_active(&self) -> bool {
71 !self.chains.is_empty()
72 }
73
74 pub fn clear(&mut self, ch: &mut Character, group: &AnimationGroup, storages: &mut [Storage]) {
79 for chain in &mut self.chains {
80 for t in chain.iter_mut() {
81 if let Action::CompleteTask { work, param } = t.action {
82 if work >= 0 {
83 self.outbox.push(Message {
84 component: Component::Jobs,
85 message: 1,
86 entity: None,
87 a: work,
88 b: param,
89 });
90 }
91 }
92 if let Action::RemoveResource { entity, .. } = t.action {
94 self.outbox.push(Message {
95 component: Component::NaturalResource,
96 message: 1,
97 entity: Some(entity),
98 a: 0,
99 b: 0,
100 });
101 }
102 t.action.abort(ch, group, storages);
103 }
104 }
105 self.chains.clear();
106 self.on_empty.clear();
107 }
108
109 pub fn pending_reservations(&self) -> Vec<(usize, usize, i32)> {
112 let mut out = Vec::new();
113 for t in self.chains.iter().flatten().filter(|t| !t.started) {
114 match &t.action {
115 Action::PickupStoredRawMaterial { storage, items, .. }
116 | Action::ConsumeStoredRawMaterial {
117 storage,
118 items,
119 reserved: true,
120 } => out.extend(items.iter().map(|&(m, n)| (*storage, m, n))),
121 _ => {}
122 }
123 }
124 out
125 }
126
127 pub fn holds_task(&self, work: i32) -> Option<i32> {
131 self.chains
132 .iter()
133 .find_map(|c| match c.first().map(|t| &t.action) {
134 Some(Action::CompleteTask { work: w, param }) if *w == work => Some(*param),
135 _ => None,
136 })
137 }
138
139 pub fn attach(&mut self, action: Action) {
142 if let Some(top) = self.chains.last_mut() {
143 top.push(Task {
144 action,
145 started: false,
146 });
147 }
148 }
149
150 pub fn hunt_watch(&mut self) -> Option<(usize, &mut bool)> {
152 self.chains
153 .last_mut()?
154 .iter_mut()
155 .filter(|t| t.started)
156 .find_map(|t| match &mut t.action {
157 Action::HuntAnimal { lodge, done } => Some((*lodge, done)),
158 _ => None,
159 })
160 }
161
162 pub fn notify_moves(&mut self, following: bool) {
168 let Some(chain) = self.chains.last_mut() else {
169 return;
170 };
171 for t in chain.iter_mut().filter(|t| t.started) {
172 if let Action::MoveTo(m) = &mut t.action {
173 m.following = following;
174 }
175 }
176 }
177
178 pub fn set_on_empty(&mut self, actions: Vec<Action>) {
180 self.on_empty = actions
181 .into_iter()
182 .map(|action| Task {
183 action,
184 started: false,
185 })
186 .collect();
187 }
188
189 pub fn push(&mut self, ch: &mut Character, group: &AnimationGroup, action: Action) {
193 if let Some(top) = self.chains.last_mut() {
194 for t in top.iter_mut().filter(|t| t.started) {
195 t.started = false;
196 t.action.stop(ch, group);
197 }
198 }
199 self.chains.push(vec![Task {
200 action,
201 started: false,
202 }]);
203 }
204
205 pub(super) fn run(
207 &mut self,
208 ch: &mut Character,
209 world: &mut World,
210 group: &AnimationGroup,
211 dt: f32,
212 ) {
213 let dt = ticks(dt);
214 while let Some(top) = self.chains.last_mut() {
215 let mut status = Status::Running;
216 if !top.first().is_some_and(|t| t.started) {
217 for t in top.iter_mut() {
218 t.started = true;
219 status = t.action.start(ch, world, group);
220 if status != Status::Running || !world.pushes.is_empty() {
221 break;
222 }
223 }
224 }
225 if !world.pushes.is_empty() {
228 for action in std::mem::take(&mut world.pushes) {
229 self.push(ch, group, action);
230 }
231 if status == Status::Failed {
232 self.clear(ch, group, world.storages);
233 }
234 continue;
235 }
236 let mut ran = false;
237 if status == Status::Running {
238 for t in top.iter_mut() {
239 status = t.action.update(ch, world, group, dt);
240 if status != Status::Running {
241 break;
242 }
243 }
244 ran = status == Status::Running;
245 }
246 match status {
247 Status::Done => {
248 let mut chain = self.chains.pop().unwrap_or_default();
249 for t in chain.iter_mut().filter(|t| t.started) {
250 t.started = false;
251 t.action.stop(ch, group);
252 }
253 }
254 Status::Failed => self.clear(ch, group, world.storages),
256 Status::Running => {}
257 }
258 if ran {
259 break;
260 }
261 }
262 if self.chains.is_empty() && !self.on_empty.is_empty() {
263 for t in self.on_empty.iter_mut() {
264 t.started = true;
265 if t.action.start(ch, world, group) != Status::Running {
266 break;
267 }
268 }
269 self.on_empty.clear();
270 }
271 }
272}