1use super::*;
4
5impl Agents {
6 pub fn update(
9 &mut self,
10 citizens: &mut Vec<Citizen>,
11 env: &mut Env,
12 groups: &[Option<&AnimationGroup>],
13 dt: f32,
14 newborn: &mut dyn FnMut(&mut Random, &Citizen, bool) -> Citizen,
15 ) {
16 self.sync_map(env.cells);
17 let (extra, foreign) = (crate::scheduler::EXTRA, crate::scheduler::FOREIGN);
19 let site_visits: Vec<(usize, i64)> = env
20 .visits
21 .iter()
22 .copied()
23 .filter(|&(v, _)| v < extra)
24 .collect();
25 let citizen_visits: Vec<(usize, i64)> = env
26 .visits
27 .iter()
28 .filter(|&&(v, _)| (extra..foreign).contains(&v))
29 .map(|&(v, e)| (v - extra, e))
30 .collect();
31 {
34 let c = &mut *env.construction;
35 c.population = self.registry.len() as i32;
36 c.visitors.1 -= ticks(dt);
37 if c.visitors.1 < 0 {
38 c.visitors = (0.0, 0);
39 }
40 self.town_disease = c.visitors.0;
41 }
42 let professions = env.construction.professions.clone();
44 for state in &mut self.states {
45 let anywhere = if professions.list.is_empty() {
46 self.rules.profession_allows_idle
47 } else {
48 professions.works_anywhere(state.profession)
49 };
50 crate::people::status::set_icon(
51 &mut state.status,
52 3,
53 !anywhere && state.workplace.is_none(),
54 false,
55 );
56 }
57 self.sectors.age_cache(ticks(dt));
58 let mut entities = entity_views(env.placed, env.templates, env.construction);
59 let mut animating = crate::town::animating(env.placed, env.templates);
60 let adult = self.adults(citizens);
61 for (ch, group) in self.characters.iter_mut().zip(groups) {
62 if let Some(g) = group {
63 ch.animate(g, dt);
64 }
65 }
66 for i in 0..self.characters.len() {
71 let alive = groups.get(i).copied().flatten().is_some()
72 && citizens.get(i).is_some_and(|c| c.alive);
73 let ch = &mut self.characters[i];
74 if !alive && 0 <= ch.tree_slot {
75 env.wildlife.tree.remove(ch.tree_slot);
76 ch.tree_slot = -1;
77 }
78 }
79 for i in 0..self.characters.len() {
80 let alive = groups.get(i).copied().flatten().is_some()
81 && citizens.get(i).is_some_and(|c| c.alive);
82 let ch = &mut self.characters[i];
83 if alive && ch.tree_slot < 0 {
84 ch.tree_slot = env.wildlife.tree.insert(
85 crate::behaviour::character_tree::Who::Citizen(i),
86 ch.position,
87 ch.desc.radius,
88 );
89 }
90 }
91 for i in 0..self.characters.len() {
92 let Some(group) = groups[i] else { continue };
93 let mut messages = Vec::new();
94 let mut used = Vec::new();
95 {
96 let state = &mut self.states[i];
97 let accident_odds = (0 <= state.job)
99 .then(|| env.construction.jobs.works.get(&state.job))
100 .flatten()
101 .and_then(|w| {
102 let p = env.construction.professions.list.get(w.profession)?;
103 Some((w.profession, p.accident.0, p.accident.1))
104 });
105 let town = crate::behaviour::activities::TownView {
107 size: env.cells.size,
108 types: &env.cells.types,
109 regions: &self.regions,
110 occupants: &env.cells.occupants,
111 objects: &env.cells.objects,
112 floors: &env.cells.floors,
113 entities: &entities,
114 happiness: &env.construction.happiness,
115 };
116 let (size, terrain, sites, materials) =
117 (env.cells.size, env.terrain, env.sites, env.materials);
118 let floors = &env.cells.floors;
119 let sectors = &mut self.sectors;
120 let mut search = |storages: &[Storage],
121 rng: &mut Random,
122 m: usize,
123 n: i32,
124 cell: i32|
125 -> Option<(usize, [f32; 3])> {
126 let ground =
127 move |cell: i32| crate::town::floor_ground(floors, size, terrain, cell);
128 let mut geometry = crate::behaviour::activities::StorageGeometry {
129 town: &town,
130 sectors: &mut *sectors,
131 ground: &ground,
132 };
133 crate::work::stock::find_material_storage(
134 sites,
135 storages,
136 materials,
137 m,
138 n,
139 true,
140 cell,
141 None,
142 &mut geometry,
143 rng,
144 )
145 .map(|f| (f.storage, f.target))
146 };
147 let mut world = World {
148 size: env.cells.size,
149 types: &env.cells.types,
150 objects: &env.cells.objects,
151 occupants: &env.cells.occupants,
152 flags: &env.cells.flags,
153 roads: &env.cells.road_kind,
154 floors: &env.cells.floors,
155 regions: &self.regions,
156 terrain: env.terrain,
157 pathfinder: &mut self.pathfinder,
158 rng: env.rng,
159 messages: &mut messages,
160 used: &mut used,
161 materials: env.materials,
162 storages: env.storages,
163 storage_search: Some(&mut search),
164 pushes: Vec::new(),
165 carried: &mut state.carried,
166 tool_uses: &mut state.tool_uses,
167 shown_tool: &mut state.shown_tool,
168 animating: &mut animating,
169 accident: &mut state.accident,
170 accident_timer: &mut state.accident_timer,
171 accident_odds,
172 };
173 self.characters[i].update(&mut world, group, dt);
174 let ch = &self.characters[i];
176 env.wildlife
177 .tree
178 .place(ch.tree_slot, ch.position, ch.desc.radius);
179 env.wildlife.tree.set_direction(ch.tree_slot, ch.direction);
180 }
181 for (m, n) in used {
182 if let Some(slot) = crate::work::produce::production_group(env.materials[m].flags) {
183 env.construction.counters.used[slot] += n;
184 }
185 }
186 citizens[i].position = self.characters[i].position;
187 self.deliver(i, messages, citizens, env, groups, &adult, &mut entities);
188 }
189 {
192 let (mut sim, jobs) = self.sim(citizens, env, groups, &adult, &entities);
193 sim.update_sites(jobs, ticks(dt), &site_visits);
194 sim.update_nomads(ticks(dt));
195 sim.update_boats();
196 sim.update_attendance(&site_visits);
197 sim.age_piles(jobs, &site_visits);
198 sim.update_hunts(&site_visits);
199 sim.update_blight(&site_visits);
200 sim.update_fires(jobs, &site_visits);
201 sim.update_tornadoes(jobs, ticks(dt));
202 sim.place_burials();
203 jobs.drain(&mut sim);
204 }
205 for c in std::mem::take(&mut env.construction.tornado_kills) {
207 if !citizens[c].alive {
208 continue;
209 }
210 let mut born = Vec::new();
211 self.with_people(citizens, env, &entities, newborn, &mut born, |people| {
212 people.die(c, crate::people::life::reason::TORNADO, None);
213 });
214 }
215 {
218 let (mut sim, jobs) = self.sim(citizens, env, groups, &adult, &entities);
219 sim.residence_clear_storage(jobs, &site_visits);
220 jobs.drain(&mut sim);
221 }
222 {
223 let c = &mut *env.construction;
224 for &(e, elapsed) in &site_visits {
225 let Some(home) = c.homes.get_mut(&e) else {
226 continue;
227 };
228 crate::people::life::update_home(
229 home,
230 env.storages,
231 env.materials,
232 env.temperature,
233 elapsed,
234 &mut c.counters,
235 );
236 }
237 }
238 for &(i, elapsed) in &citizen_visits {
241 if i >= self.ais.len()
242 || groups.get(i).copied().flatten().is_none()
243 || !citizens[i].alive
244 {
245 continue;
246 }
247 refresh_views(&mut entities, env);
250 self.hunt_notify(i, env, groups);
251 let following = env.wildlife.tree.follows(self.characters[i].tree_slot);
252 self.characters[i].stack.notify_moves(following);
253 let born = self.live(i, citizens, env, &entities, elapsed, newborn);
256 for c in born {
257 let mut ch = Character::new(self.desc, citizens[c].position, CHILD_SCALE);
258 ch.yaw = self.characters[i].yaw;
259 self.characters.push(ch);
260 self.ais.push(CitizenAi::default());
261 self.states[c].carried = self.carried.clone();
262 self.join_tree(c, env);
264 }
265 if self.dying.iter().any(|&(d, _)| d == i) {
266 continue;
267 }
268 refresh_views(&mut entities, env);
269 self.think(i, citizens, env, groups, &adult, &entities, elapsed);
270 }
271 let mut k = 0;
274 while k < self.dying.len() {
275 let (c, _) = self.dying[k];
276 self.remove(c, citizens, env, groups, &entities);
277 k += 1;
278 }
279 self.dying.clear();
280 for (c, s) in citizens.iter_mut().zip(&self.states) {
281 c.school = s.school;
282 }
283 }
284
285 pub fn move_animals(
294 &mut self,
295 wildlife: &mut crate::nature::wildlife::Wildlife,
296 cells: &Cells,
297 terrain: &HeightGrid,
298 rng: &mut Random,
299 materials: &[RawMaterial],
300 dt: f32,
301 ) {
302 self.sync_map(cells);
303 let mut animating = Vec::new();
304 let mut storages: Vec<Storage> = Vec::new();
305 let ids: Vec<usize> = wildlife.animals.keys().copied().collect();
306 for a in ids {
307 let (template, variant) = {
308 let animal = &wildlife.animals[&a];
309 if animal.dying {
310 continue;
311 }
312 (animal.template, animal.variant)
313 };
314 let Some(group) = wildlife.groups.get(&(template, variant)).cloned() else {
315 continue;
316 };
317 let animal = wildlife.animals.get_mut(&a).unwrap();
318 let mut messages = Vec::new();
319 let (mut carried, mut tool_uses, mut shown_tool) = (Storage::default(), 0, -1);
320 let (mut accident, mut accident_timer) = (None, 0);
321 let mut world = World {
322 size: cells.size,
323 types: &cells.types,
324 objects: &cells.objects,
325 occupants: &cells.occupants,
326 flags: &cells.flags,
327 roads: &cells.road_kind,
328 floors: &cells.floors,
329 regions: &self.regions,
330 terrain,
331 pathfinder: &mut self.pathfinder,
332 rng,
333 messages: &mut messages,
334 used: &mut Vec::new(),
335 materials,
336 storages: &mut storages,
337 carried: &mut carried,
338 tool_uses: &mut tool_uses,
339 storage_search: None,
340 pushes: Vec::new(),
341 shown_tool: &mut shown_tool,
342 animating: &mut animating,
343 accident: &mut accident,
344 accident_timer: &mut accident_timer,
345 accident_odds: None,
346 };
347 animal.character.animate(&group, dt);
348 animal.character.update(&mut world, &group, dt);
349 let ch = &animal.character;
350 wildlife
351 .tree
352 .place(ch.tree_slot, ch.position, ch.desc.radius);
353 wildlife.tree.set_direction(ch.tree_slot, ch.direction);
354 }
355 let ids: Vec<usize> = wildlife.boats.keys().copied().collect();
357 for id in ids {
358 let b = &wildlife.boats[&id];
359 let Some(group) = wildlife.groups.get(&(b.template, 0)).cloned() else {
360 continue;
361 };
362 let boat = wildlife.boats.get_mut(&id).unwrap();
363 let mut messages = Vec::new();
364 let (mut carried, mut tool_uses, mut shown_tool) = (Storage::default(), 0, -1);
365 let (mut accident, mut accident_timer) = (None, 0);
366 let mut world = World {
367 size: cells.size,
368 types: &cells.types,
369 objects: &cells.objects,
370 occupants: &cells.occupants,
371 flags: &cells.flags,
372 roads: &cells.road_kind,
373 floors: &cells.floors,
374 regions: &self.regions,
375 terrain,
376 pathfinder: &mut self.pathfinder,
377 rng,
378 messages: &mut messages,
379 used: &mut Vec::new(),
380 materials,
381 storages: &mut storages,
382 carried: &mut carried,
383 tool_uses: &mut tool_uses,
384 storage_search: None,
385 pushes: Vec::new(),
386 shown_tool: &mut shown_tool,
387 animating: &mut animating,
388 accident: &mut accident,
389 accident_timer: &mut accident_timer,
390 accident_odds: None,
391 };
392 boat.character.animate(&group, dt);
393 boat.character.update(&mut world, &group, dt);
394 let ch = &boat.character;
395 wildlife
396 .tree
397 .place(ch.tree_slot, ch.position, ch.desc.radius);
398 wildlife.tree.set_direction(ch.tree_slot, ch.direction);
399 }
400 let ids: Vec<usize> = wildlife.nomads.keys().copied().collect();
402 for id in ids {
403 let n = &wildlife.nomads[&id];
404 let Some(group) = wildlife.groups.get(&(n.template, n.variant)).cloned() else {
405 continue;
406 };
407 let nomad = wildlife.nomads.get_mut(&id).unwrap();
408 let mut messages = Vec::new();
409 let (mut carried, mut tool_uses, mut shown_tool) = (Storage::default(), 0, -1);
410 let (mut accident, mut accident_timer) = (None, 0);
411 let mut world = World {
412 size: cells.size,
413 types: &cells.types,
414 objects: &cells.objects,
415 occupants: &cells.occupants,
416 flags: &cells.flags,
417 roads: &cells.road_kind,
418 floors: &cells.floors,
419 regions: &self.regions,
420 terrain,
421 pathfinder: &mut self.pathfinder,
422 rng,
423 messages: &mut messages,
424 used: &mut Vec::new(),
425 materials,
426 storages: &mut storages,
427 carried: &mut carried,
428 tool_uses: &mut tool_uses,
429 storage_search: None,
430 pushes: Vec::new(),
431 shown_tool: &mut shown_tool,
432 animating: &mut animating,
433 accident: &mut accident,
434 accident_timer: &mut accident_timer,
435 accident_odds: None,
436 };
437 nomad.character.animate(&group, dt);
438 nomad.character.update(&mut world, &group, dt);
439 let ch = &nomad.character;
440 wildlife
441 .tree
442 .place(ch.tree_slot, ch.position, ch.desc.radius);
443 wildlife.tree.set_direction(ch.tree_slot, ch.direction);
444 }
445 }
446
447 pub(super) fn hunt_notify(
453 &mut self,
454 i: usize,
455 env: &mut Env,
456 groups: &[Option<&AnimationGroup>],
457 ) {
458 let Some(group) = groups.get(i).copied().flatten() else {
459 return;
460 };
461 let Some((lodge, done)) = self.characters[i].stack.hunt_watch() else {
462 return;
463 };
464 if *done {
465 return;
466 }
467 let Some(site) = env.construction.sites.get(&lodge) else {
468 return;
469 };
470 let Some(d) = env.construction.templates[site.template].hunt else {
471 return;
472 };
473 if site.hunt_time.unwrap_or(0) < ticks(d.time * 300.0) {
474 return;
475 }
476 let pos = self.characters[i].position;
477 let animals = &env.wildlife.animals;
482 let best = env
483 .wildlife
484 .tree
485 .nearest(pos, 8.0, |who| match who {
486 crate::behaviour::character_tree::Who::Animal(a) => {
487 animals.get(&a).is_some_and(|x| x.livestock.is_none())
488 }
489 _ => false,
490 })
491 .and_then(|who| match who {
492 crate::behaviour::character_tree::Who::Animal(a) => Some(a),
493 _ => None,
494 });
495 let Some(a) = best else { return };
496 let animal = &env.wildlife.animals[&a];
497 if animal.flags & crate::nature::wildlife::HUNTED != 0 {
498 return;
499 }
500 let n = env.cells.size as i32;
501 let cell_of = |p: [f32; 3]| {
502 let half = (n >> 1) as f32;
503 let x = ((p[0] + half) as i32).clamp(0, n - 1);
504 let y = ((p[1] + half) as i32).clamp(0, n - 1);
505 n * y + x
506 };
507 let (here, at) = (cell_of(pos), cell_of(animal.character.position));
508 let Some(nb) = crate::pathfind::nearest_neighbour(
509 env.cells.size,
510 &env.cells.types,
511 at,
512 here,
513 WALKABLE,
514 ) else {
515 return;
516 };
517 let town = TownView {
518 size: env.cells.size,
519 types: &env.cells.types,
520 regions: &self.regions,
521 occupants: &env.cells.occupants,
522 objects: &env.cells.objects,
523 floors: &env.cells.floors,
524 entities: &[],
525 happiness: &[],
526 };
527 if !town.reachable(WALKABLE, nb, here) {
528 return;
529 }
530 if let Some((_, done)) = self.characters[i].stack.hunt_watch() {
531 *done = true;
532 }
533 let materials = env
534 .wildlife
535 .animal_kinds
536 .get(&animal.template)
537 .map(|k| k.materials.clone())
538 .unwrap_or_default();
539 let herd = animal.herd;
540 let batch = self.states[i].carried.capacity;
541 let workplace = self.states[i].workplace;
542 let mut duration = ticks(4.0);
543 if self.states[i].tool_uses < 1 {
544 duration = ticks(crate::scheduler::seconds(duration) * self.rules.no_tool_factor);
545 }
546 let target = crate::town::floor_ground(&env.cells.floors, env.cells.size, env.terrain, nb);
547 let walk = MoveTo::new(target, 1, 0, WALKABLE, 0, -1.0, env.rng);
548 let ch = &mut self.characters[i];
549 let mut stack = std::mem::take(&mut ch.stack);
550 for &m in &materials {
551 stack.push(
552 ch,
553 group,
554 Action::CreateRawMaterial {
555 template: m,
556 cell: at,
557 batch,
558 workplace,
559 factor: 1.0,
560 },
561 );
562 }
563 stack.push(ch, group, Action::RemoveAnimal { entity: a });
564 stack.push(
565 ch,
566 group,
567 Action::PerformWork {
568 facing: -1000.0,
569 anim: 0xb,
570 duration,
571 elapsed: 0,
572 consume: true,
573 },
574 );
575 stack.push(ch, group, Action::move_to(walk));
576 ch.stack = stack;
577 let mut scheduler = crate::scheduler::EntityScheduler::default();
579 let mut wild = crate::nature::wildlife::Wild {
580 wildlife: env.wildlife,
581 placed: env.placed,
582 templates: env.templates,
583 cells: env.cells,
584 terrain: env.terrain,
585 rng: env.rng,
586 scheduler: &mut scheduler,
588 };
589 wild.hunted(a);
590 if let Some(h) = herd {
591 wild.retarget(h);
592 }
593 if let Some(t) = env
594 .construction
595 .sites
596 .get_mut(&lodge)
597 .and_then(|s| s.hunt_time.as_mut())
598 {
599 *t = 0;
600 }
601 }
602}