1use banished_formats::game::{
12 GrowthDescription, MapDescription, ModelDescription, NaturalResourceDescription,
13 PlacedStructure,
14};
15
16use crate::behaviour::animation::Playback;
17use crate::nature::growth::{adjust_map_byte, Growth};
18use crate::nature::spawn::Spawn;
19use crate::noise::PerlinNoise;
20use crate::random::Random;
21use crate::scheduler::{ticks, EntityScheduler};
22use crate::terrain::{CellType, HeightGrid};
23use banished_formats::types::AnimationGroup;
24use std::sync::Arc;
25
26#[derive(Debug, Clone)]
28pub struct Template {
29 pub reference: String,
31 pub bucket: usize,
34 pub map: Option<MapDescription>,
36 pub model: Option<ModelDescription>,
38 pub animations: Vec<Option<Arc<AnimationGroup>>>,
40 pub audio_events: Vec<(String, Option<String>, f32)>,
42 pub natural: Option<NaturalResourceDescription>,
44 pub growth: Option<GrowthDescription>,
46 pub fruit: Option<crate::production::orchard::FruitTemplate>,
48 pub growth_reference: Option<String>,
51 pub spawn: Vec<(usize, f32, f32)>,
53 pub updates: Vec<ScheduledComponent>,
55 pub size: Option<(i32, i32)>,
58 pub storage: Option<(u32, i32, bool)>,
61 pub storage_location: bool,
63 pub storage_location_flags: u32,
65 pub storage_display: bool,
67 pub market_radius: Option<i32>,
69 pub market_location: bool,
71 pub has_interact: bool,
73 pub use_points: Vec<[f32; 3]>,
75 pub pile: Option<usize>,
78 pub pile_material: Option<usize>,
81 pub pile_yield: (i32, i32),
83 pub build_points: Vec<[f32; 3]>,
86 pub use_yaws: Vec<f32>,
88 pub create_points: Vec<[f32; 3]>,
90 pub named_points: Vec<(String, [f32; 3], f32)>,
93 pub floor: Option<std::sync::Arc<Vec<[[f32; 3]; 3]>>>,
96 pub floor_on_activate: bool,
102 pub terraform: Option<crate::world::terraform::TerraformTemplate>,
104 pub tornado: Option<crate::disasters::tornado::TornadoTemplate>,
106 pub quarry: Option<crate::production::quarry::QuarryTemplate>,
108 pub trading_post: bool,
110 pub tracker: bool,
112 pub fenced_area: bool,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub enum ScheduledComponent {
122 Growth,
124 Spawn,
126}
127
128#[derive(Debug, Clone, PartialEq)]
130pub struct Placed {
131 pub template: usize,
133 pub bucket: usize,
136 pub cell: (i32, i32),
138 pub footprint: (i32, i32),
141 pub position: [f32; 3],
143 pub yaw: f32,
145 pub variant: usize,
147 pub mesh: usize,
149 pub growth: f32,
152 pub growth_state: Option<Growth>,
154 pub spawn_state: Option<Spawn>,
156 pub alive: bool,
158 pub removal_requested: bool,
162 pub animation: Option<Playback>,
164 pub scale: [f32; 4],
167}
168
169impl Placed {
170 pub fn model(&self, t: &Template) -> crate::math::Transform {
174 if t.fenced_area {
175 crate::math::Transform {
176 q: [0.0, 0.0, 0.0, 1.0],
177 p: self.position,
178 }
179 } else {
180 crate::math::Transform::of_model(self.yaw, self.position)
181 }
182 }
183}
184
185static TYPES_REVISION: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
187
188fn next_types_revision() -> u64 {
189 TYPES_REVISION.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
190}
191
192pub struct Cells {
195 pub size: usize,
197 pub types: Vec<CellType>,
200 pub types_revision: u64,
203 pub objects: Vec<Option<usize>>,
206 pub occupants: Vec<Option<usize>>,
210 pub flags: Vec<u8>,
213 pub previous_template: Vec<Option<usize>>,
216 pub growth_bytes: Vec<u8>,
219 pub layers: Vec<[u8; 12]>,
224 pub layer_totals: [i16; 12],
227 pub road_kind: Vec<u8>,
230 pub road_built: Vec<u8>,
233 pub road_revision: u32,
237 pub floors: crate::world::floor::Floors,
240 pub sector_marks: Vec<u32>,
245}
246
247impl Cells {
248 pub fn entity_at(&self, i: usize) -> Option<usize> {
254 self.occupants[i].or(self.objects[i])
255 }
256
257 pub fn new(size: usize, types: Vec<CellType>) -> Cells {
259 Cells {
260 size,
261 types_revision: next_types_revision(),
262 objects: vec![None; types.len()],
263 occupants: vec![None; types.len()],
264 flags: vec![0; types.len()],
265 previous_template: vec![None; types.len()],
266 growth_bytes: vec![0; types.len()],
267 layers: vec![[0; 12]; types.len()],
268 layer_totals: [0; 12],
269 road_kind: vec![0xff; types.len()],
270 road_built: vec![0; types.len()],
271 floors: crate::world::floor::Floors::new(types.len()),
272 types,
273 road_revision: 0,
274 sector_marks: Vec::new(),
275 }
276 }
277
278 pub fn set_type(&mut self, i: usize, ty: CellType) {
282 let walk = |t: CellType| (1u32 << (t.0 & 0x1f)) & crate::pathfind::WALKABLE != 0;
283 if walk(self.types[i]) != walk(ty) {
284 self.sector_marks.push(i as u32);
285 }
286 self.types[i] = ty;
287 self.types_revision = next_types_revision();
288 }
289
290 pub fn add_layer(&mut self, layer: usize, cx: i32, cy: i32, radius: i32, delta: i32) {
295 let n = self.size as i32;
296 for y in cy - radius..=cy + radius {
297 for x in cx - radius..=cx + radius {
298 let (dx, dy) = (cx - x, cy - y);
299 if x < 0 || y < 0 || x >= n || y >= n || dx * dx + dy * dy > radius * radius {
300 continue;
301 }
302 let b = &mut self.layers[(n * y + x) as usize][layer];
303 *b = b.wrapping_add(delta as u8);
304 }
305 }
306 self.layer_totals[layer] = self.layer_totals[layer].wrapping_add(delta as i16);
307 }
308}
309
310const HALF: f32 = 0.5;
312const ONE: f32 = 1.0;
313pub(crate) const YAW_RANGE: f32 = 180.0;
315const SPAWN_NORMAL: f32 = 0.98;
317const SPAWN_HEIGHT_TOLERANCE: f32 = 1000.0;
318
319pub struct Seeder<'a> {
322 pub templates: &'a [Template],
324 pub terrain: &'a HeightGrid<'a>,
326 pub cells: &'a mut Cells,
328 pub rng: &'a mut Random,
330 pub placed: &'a mut Vec<Placed>,
332 pub removed: &'a mut Vec<usize>,
336 pub animation_events: &'a mut Vec<(usize, String)>,
341}
342
343impl<'a> Seeder<'a> {
344 fn n(&self) -> i32 {
345 self.cells.size as i32
346 }
347
348 fn cell_position(&self, index: i32) -> (f32, f32) {
350 let n = self.n();
351 let c = (n >> 1) as f32 - HALF;
352 ((index % n) as f32 - c, (index / n) as f32 - c)
353 }
354
355 fn ground(&self, x: f32, y: f32) -> (f32, f32) {
357 let mut normal = [0.0f32; 3];
358 let h = self
359 .cells
360 .floors
361 .ground_normal(self.cells.size, &self.terrain, x, y, &mut normal);
362 (h, normal[2])
363 }
364
365 pub fn place_structures(
374 &mut self,
375 structures: &[(PlacedStructure, Option<usize>)],
376 sx: i32,
377 sy: i32,
378 ) {
379 let n = self.n();
380 let corner = |s: &Self, x: i32, y: i32| {
381 let i = n * y + x;
382 let half = (n >> 1) as f32;
383 let (px, py) = ((i % n) as f32 - half, (i / n) as f32 - half);
384 let (z, _) = s.ground(px, py);
385 [px, py, z]
386 };
387 for (record, template) in structures {
388 let Some(t) = *template else { continue };
389 let (mut w, mut h) = self.templates[t].size.unwrap_or((record.a, record.b));
392 if matches!(record.rotation, 90 | -90 | 270) {
393 std::mem::swap(&mut w, &mut h);
394 }
395 let (x, y) = (sx + record.x, sy + record.y);
396 let p0 = corner(self, x, y);
397 let p1 = corner(self, x + w, y + h);
398 let position = [
399 (p1[0] + p0[0]) * HALF,
400 (p1[1] + p0[1]) * HALF,
401 (p1[2] + p0[2]) * HALF,
402 ];
403 self.construct(t);
404 let (variant, mesh) = self.templates[t].model.as_ref().map_or((0, 0), |model| {
407 let variant = self.rng.rand_below(model.variants.len() as u32) as usize;
408 let mesh = model
409 .variants
410 .get(variant)
411 .map_or(0, |v| v.meshes.len().saturating_sub(1));
412 (variant, mesh)
413 });
414 self.placed.push(Placed {
415 template: t,
416 bucket: self.templates[t].bucket,
417 cell: (x, y),
418 footprint: (w, h),
419 position,
420 yaw: record.rotation.rem_euclid(360) as f32,
421 variant,
422 mesh,
423 growth: 0.0,
424 growth_state: None,
425 spawn_state: None,
426 alive: true,
427 removal_requested: false,
428 animation: None,
429 scale: [ONE; 4],
430 });
431 }
432 }
433
434 fn construct(&mut self, template: usize) -> (usize, usize, f32) {
438 let t = &self.templates[template];
439 let (mut variant, mut mesh) = (0usize, 0usize);
440 if let Some(m) = &t.model {
441 variant = m.variant.max(0) as usize;
442 if m.random_variant {
443 variant = self.rng.rand_below(m.variants.len() as u32) as usize;
444 }
445 mesh = m.mesh.max(0) as usize;
446 }
447 let mut max_growth = 1.0;
448 if let Some(g) = &t.growth {
449 max_growth = if g.max_base <= 0.0 {
450 -1.0
451 } else {
452 self.rng.rand_float_tol() * g.max_range + g.max_base
453 };
454 }
455 (variant, mesh, max_growth)
456 }
457
458 fn position(&mut self, template: usize, index: i32) -> ([f32; 3], f32) {
460 let scale = self.templates[template]
461 .natural
462 .as_ref()
463 .map_or(0.0, |n| n.position_scale);
464 let (x, y) = self.cell_position(index);
465 let (z, _) = self.ground(x, y);
466 let dy = self.rng.rand_float_tol();
467 let dx = self.rng.rand_float_tol();
468 let position = [dx * scale + x, dy * scale + y, z + 0.0];
469 let yaw = self.rng.rand_float_tol() * YAW_RANGE;
470 (position, yaw)
471 }
472
473 fn set_growth(
475 &mut self,
476 template: usize,
477 max_growth: f32,
478 fraction: f32,
479 ) -> (Growth, f32, [f32; 4]) {
480 Growth::initialise(
481 self.templates[template].growth.as_ref().unwrap(),
482 max_growth,
483 fraction,
484 self.rng,
485 )
486 }
487
488 fn register(&mut self, placed: Placed) -> usize {
491 let id = self.placed.len();
492 if let Some(map) = self.templates[placed.template].map.clone() {
493 if map.stamp && !map.no_stamp {
494 let i = (placed.cell.1 * self.n() + placed.cell.0) as usize;
495 if let Some(old) = self.cells.objects[i] {
497 self.remove(old);
498 }
499 self.cells.set_type(i, CellType(map.cell_type as u8));
500 self.cells.objects[i] = Some(id);
501 }
502 }
503 self.placed.push(placed);
504 id
505 }
506
507 pub(crate) fn density_ok(&self, template: usize, x: i32, y: i32) -> bool {
511 let Some(growth) = &self.templates[template].growth else {
512 return true;
513 };
514 let n = self.n();
515 let (mut occupied, mut same) = (0, 0);
516 for cy in y - 1..y + 2 {
517 for cx in x - 1..x + 2 {
518 if (cx == x && cy == y) || cx < 0 || cy < 0 || cx >= n || cy >= n {
519 continue;
520 }
521 if let Some(o) = self.cells.objects[(cy * n + cx) as usize] {
522 occupied += 1;
523 if self.templates[self.placed[o].template].growth_reference
524 == self.templates[template].growth_reference
525 {
526 same += 1;
527 }
528 }
529 }
530 }
531 !(growth.max_same < same || growth.max_neighbours < occupied)
532 }
533
534 fn spawn_spot_ok(&self, x: i32, y: i32) -> bool {
537 let n = self.n();
538 if x < 0 || y < 0 || x >= n || y >= n {
539 return false;
540 }
541 let i = y * n + x;
542 if self.cells.types[i as usize] != CellType::GROUND {
543 return false;
544 }
545 if self.cells.occupants[i as usize].is_some() || self.cells.flags[i as usize] != 0 {
546 return false;
547 }
548 let (px, py) = self.cell_position(i);
549 let mut normal = [0.0f32; 3];
550 let h =
551 self.cells
552 .floors
553 .ground_normal(self.cells.size, &self.terrain, px, py, &mut normal);
554 SPAWN_NORMAL <= normal[2] && (h - 0.0).abs() <= SPAWN_HEIGHT_TOLERANCE
555 }
556
557 fn spawn(&mut self, parent: usize) {
559 let template = self.placed[parent].template;
560 let growth = self.placed[parent].growth;
561 for (entry, (child, lo, hi)) in self.templates[template]
562 .spawn
563 .clone()
564 .into_iter()
565 .enumerate()
566 {
567 if !(lo <= growth && growth <= hi) {
568 continue;
569 }
570 let step = self.templates[child]
571 .growth
572 .as_ref()
573 .map_or(1.0, |g| g.max_base);
574 let attempts = (growth / step) as i32 + 1;
575 for _ in 0..attempts {
576 self.spawn_child(parent, entry, true, false);
577 }
578 }
579 }
580
581 pub fn spawn_child(
586 &mut self,
587 parent: usize,
588 entry: usize,
589 random_growth: bool,
590 disabled: bool,
591 ) -> Option<usize> {
592 if disabled {
593 return None;
594 }
595 let parent_template = self.placed[parent].template;
596 let child = self.templates[parent_template].spawn[entry].0;
597 let (px, py) = self.placed[parent].cell;
598 let Some(g) = self.templates[child].growth.clone() else {
599 return None;
600 };
601 if self.rng.rand_float() > ONE / g.spawn_one_in as f32 {
602 return None;
603 }
604 let x = px + self.rng.rand_tol(g.spawn_radius);
605 let y = py + self.rng.rand_tol(g.spawn_radius);
606 let n = self.n();
607 if x < 0 || y < 0 || x >= n || y >= n || !self.spawn_spot_ok(x, y) {
608 return None;
609 }
610 if !self.density_ok(child, x, y) {
611 return None;
612 }
613 let (variant, mesh, max_growth) = self.construct(child);
614 let (position, yaw) = self.position(child, n * y + x);
615 let (state, growth, scale) = self.set_growth(child, max_growth, 0.0);
616 let id = self.register(Placed {
617 template: child,
618 bucket: self.templates[parent_template].bucket,
619 cell: (x, y),
620 footprint: (1, 1),
621 position,
622 yaw,
623 variant,
624 mesh,
625 growth,
626 growth_state: Some(state),
627 spawn_state: self.spawn_state(child),
628 alive: true,
629 removal_requested: false,
630 animation: None,
631 scale,
632 });
633 if random_growth {
634 let fraction = self.rng.rand_float();
635 let (state, growth, scale) = self.set_growth(child, max_growth, fraction);
636 self.placed[id].growth = growth;
637 self.placed[id].scale = scale;
638 self.placed[id].growth_state = Some(state);
639 }
640 Some(id)
641 }
642
643 pub fn plant(&mut self, template: usize, cell: i32) -> usize {
649 let (_, _, max_growth) = self.construct(template);
650 let (position, yaw) = self.position(template, cell);
651 let (state, growth, scale) = self.set_growth(template, max_growth, 0.0);
652 let variants = self.templates[template]
653 .model
654 .as_ref()
655 .map_or(1, |m| m.variants.len().max(1));
656 let variant = self.rng.rand_below(variants as u32) as usize;
657 let meshes = self.templates[template]
658 .model
659 .as_ref()
660 .and_then(|m| m.variants.get(variant))
661 .map_or(1, |v| v.meshes.len().max(1));
662 let mesh = self.rng.rand_below(meshes as u32) as usize;
663 let n = self.n();
664 self.register(Placed {
665 template,
666 bucket: self.templates[template].bucket,
667 cell: (cell % n, cell / n),
668 footprint: (1, 1),
669 position,
670 yaw,
671 variant,
672 mesh,
673 growth,
674 growth_state: Some(state),
675 spawn_state: self.spawn_state(template),
676 alive: true,
677 removal_requested: false,
678 animation: None,
679 scale,
680 })
681 }
682
683 fn spawn_state(&self, template: usize) -> Option<Spawn> {
684 self.templates[template]
685 .updates
686 .contains(&ScheduledComponent::Spawn)
687 .then(|| Spawn::new(self.templates[template].spawn.len()))
688 }
689
690 fn periodic_spawn(&mut self, parent: usize) -> Option<usize> {
694 let template = self.placed[parent].template;
695 let g = self.templates[template].growth.as_ref()?;
696 if self.rng.rand_float() > ONE / g.spawn_one_in as f32 {
697 return None;
698 }
699 let (px, py) = self.placed[parent].cell;
700 let x = px + self.rng.rand_tol(g.spawn_radius);
701 let y = py + self.rng.rand_tol(g.spawn_radius);
702 if !self.spawn_spot_ok(x, y) || !self.density_ok(template, x, y) {
703 return None;
704 }
705 let variant = self.placed[parent].variant;
706 let (_, _, maximum) = self.construct(template);
707 let (position, yaw) = self.position(template, y * self.n() + x);
708 let (state, growth, scale) = self.set_growth(template, maximum, 0.0);
709 let meshes = self.templates[template]
710 .model
711 .as_ref()?
712 .variants
713 .get(variant)?
714 .meshes
715 .len();
716 let mesh = self.rng.rand_below(meshes as u32) as usize;
717 Some(self.register(Placed {
718 template,
719 bucket: self.templates[template].bucket,
720 cell: (x, y),
721 footprint: (1, 1),
722 position,
723 yaw,
724 variant,
725 mesh,
726 growth,
727 growth_state: Some(state),
728 spawn_state: self.spawn_state(template),
729 alive: true,
730 removal_requested: false,
731 animation: None,
732 scale,
733 }))
734 }
735
736 fn remove(&mut self, id: usize) {
739 let p = &mut self.placed[id];
740 if !p.alive {
741 return;
742 }
743 p.alive = false;
744 self.removed.push(id);
745 let (x, y) = p.cell;
746 let i = y as usize * self.cells.size + x as usize;
747 if let Some(d) = &self.templates[p.template].growth {
748 if p.growth != 0.0 {
749 let factor = if self.cells.previous_template[i] == Some(p.template) {
750 d.f3c
751 } else {
752 d.f40
753 };
754 self.cells.growth_bytes[i] =
755 adjust_map_byte(self.cells.growth_bytes[i], p.growth.min(1.0) * factor);
756 self.cells.previous_template[i] = Some(p.template);
757 }
758 }
759 if self.cells.objects[i] == Some(id) {
760 let ty = self.terrain.natural_cell_type(self.cells.size, i);
761 self.cells.set_type(i, ty);
762 self.cells.objects[i] = None;
763 }
764 }
765
766 pub fn iterate(
773 &mut self,
774 scheduler: &mut EntityScheduler<usize>,
775 dt: f32,
776 temperature: f32,
777 disabled: bool,
778 ) -> bool {
779 self.iterate_with(scheduler, dt, temperature, disabled, &mut |_, _, _, _| {
780 false
781 })
782 }
783
784 pub fn iterate_with(
787 &mut self,
788 scheduler: &mut EntityScheduler<usize>,
789 dt: f32,
790 temperature: f32,
791 disabled: bool,
792 visit: &mut dyn FnMut(&mut Seeder, &mut EntityScheduler<usize>, usize, i64) -> bool,
793 ) -> bool {
794 scheduler.advance(dt);
795 let mut changed = self.animate(ticks(dt));
798 for bucket in 0..5 {
799 for (_, id, elapsed) in scheduler.visit_bucket(bucket) {
800 if id >= crate::scheduler::EXTRA {
802 continue;
803 }
804 changed |= self.scheduled_growth(scheduler, id, elapsed, temperature, disabled);
805 changed |= self.scheduled_spawn(scheduler, id, elapsed, disabled);
807 if self.placed[id].alive {
810 changed |= visit(self, scheduler, id, elapsed);
811 }
812 }
813 }
814 for id in self.removed.drain(..) {
816 scheduler.remove(id);
817 }
818 changed
819 }
820
821 fn scheduled_spawn(
825 &mut self,
826 scheduler: &mut EntityScheduler<usize>,
827 id: usize,
828 elapsed: i64,
829 disabled: bool,
830 ) -> bool {
831 let p = &self.placed[id];
832 if !p.alive || p.spawn_state.is_none() {
833 return false;
834 }
835 let growth = p.growth;
836 let entries: Vec<(f32, f32, f32)> = self.templates[p.template]
837 .spawn
838 .iter()
839 .map(|&(child, lo, hi)| {
840 let period = self.templates[child].growth.as_ref().map_or(0.0, |g| g.f28);
841 (lo, hi, period)
842 })
843 .collect();
844 let attempts = self.placed[id]
845 .spawn_state
846 .as_mut()
847 .unwrap()
848 .update(growth, elapsed, &entries);
849 let mut changed = false;
850 for (entry, count) in attempts {
851 for _ in 0..count {
852 if let Some(child) = self.spawn_child(id, entry, false, disabled) {
853 let handle = scheduler.register(child, self.placed[child].bucket);
854 debug_assert_eq!(handle, child);
855 changed = true;
856 }
857 }
858 }
859 changed
860 }
861
862 fn scheduled_growth(
864 &mut self,
865 scheduler: &mut EntityScheduler<usize>,
866 id: usize,
867 elapsed: i64,
868 temperature: f32,
869 disabled: bool,
870 ) -> bool {
871 let mut changed = false;
872 {
873 let p = &mut self.placed[id];
874 if !p.alive {
875 return changed;
876 }
877 let Some(state) = &mut p.growth_state else {
878 return changed;
879 };
880 let d = self.templates[p.template].growth.as_ref().unwrap();
881 let result = state.update(d, &mut p.growth, elapsed, temperature, disabled);
882 if !disabled {
883 for _ in 0..result.spawn_attempts {
884 if let Some(child) = self.periodic_spawn(id) {
885 let handle = scheduler
886 .register(child, self.templates[self.placed[child].template].bucket);
887 debug_assert_eq!(handle, child);
888 changed = true;
889 }
890 }
891 }
892 if let Some(adjustment) = result.map_adjustment {
893 let p = &self.placed[id];
894 let i = (p.cell.1 * self.n() + p.cell.0) as usize;
895 self.cells.growth_bytes[i] =
896 adjust_map_byte(self.cells.growth_bytes[i], adjustment);
897 self.cells.previous_template[i] = Some(p.template);
898 if self.templates[p.template]
899 .natural
900 .as_ref()
901 .is_some_and(|n| n.flag)
902 {
903 let p = &mut self.placed[id];
906 p.removal_requested = true;
907 p.animation = self.templates[p.template]
908 .animations
909 .get(p.variant)
910 .and_then(Option::as_ref)
911 .and_then(|g| g.clips.get(2))
912 .map(|_| Playback::new(2, 0));
913 } else {
914 self.remove(id);
915 changed = true;
916 }
917 }
918 }
919 changed
920 }
921
922 pub fn smooth(&mut self) -> bool {
926 let mut changed = false;
927 for p in self.placed.iter_mut() {
928 if !p.alive {
929 continue;
930 }
931 if let Some(state) = &mut p.growth_state {
932 let d = self.templates[p.template].growth.as_ref().unwrap();
933 changed |= state.smooth(d, p.growth, &mut p.scale);
934 }
935 }
936 changed
937 }
938
939 fn animate(&mut self, dt: i64) -> bool {
943 let mut finished = Vec::new();
944 let mut changed = false;
945 for (id, p) in self.placed.iter_mut().enumerate() {
946 if !p.alive {
947 continue;
948 }
949 let Some(playback) = &mut p.animation else {
950 if p.removal_requested {
951 finished.push(id);
952 }
953 continue;
954 };
955 let Some(clip) = self.templates[p.template]
956 .animations
957 .get(p.variant)
958 .and_then(Option::as_ref)
959 .and_then(|g| g.clips.get(playback.clip))
960 else {
961 continue;
962 };
963 if !playback.is_animating(clip) {
964 continue;
965 }
966 for event in playback.update(clip, dt) {
967 let Some(reference) = &clip.events[event].resource else {
968 continue;
969 };
970 let audio = self.templates[p.template]
973 .audio_events
974 .iter()
975 .find(|(r, _, _)| r == reference);
976 if let Some((_, effect, probability)) = audio {
977 if self.rng.rand_float() <= *probability {
978 if let Some(effect) = effect {
979 self.animation_events.push((id, effect.clone()));
980 }
981 }
982 }
983 }
984 changed = true;
985 if !playback.is_animating(clip) && p.removal_requested {
986 finished.push(id);
987 }
988 }
989 for id in finished {
990 self.remove(id);
991 changed = true;
992 }
993 changed
994 }
995
996 fn perlin(&mut self, persistence: f32, octaves: f32) -> PerlinNoise {
997 let a = self.rng.rand_tol(0x7ff_ffff);
998 let b = self.rng.rand_tol(0x7ff_ffff);
999 PerlinNoise::new(persistence, octaves, b, a)
1000 }
1001
1002 pub fn seed(&mut self, list: &[usize], sx: i32, sy: i32, radius_sq: i32) {
1007 for _ in 0..3 {
1009 self.perlin(ONE, ONE);
1010 }
1011 let n = self.n();
1012 for &template in list {
1013 let Some(nr) = self.templates[template].natural.clone() else {
1014 continue;
1015 };
1016 let variants = self.templates[template]
1017 .model
1018 .as_ref()
1019 .map_or(0, |m| m.variants.len());
1020 let clusters: Vec<PerlinNoise> = if nr.cluster {
1021 (0..variants)
1022 .map(|_| self.perlin(nr.cluster_persistence, nr.cluster_octaves))
1023 .collect()
1024 } else {
1025 Vec::new()
1026 };
1027 let field = self.perlin(nr.noise_persistence, nr.noise_octaves);
1028 let inv = ONE / nr.noise_scale;
1029 for y in 0..n {
1030 for x in 0..n {
1031 let v = field.generate(x as f32 * inv, y as f32 * inv);
1032 if nr.noise_min > v * HALF + HALF {
1033 continue;
1034 }
1035 if self.rng.rand_float() > nr.chance {
1036 continue;
1037 }
1038 let index = n * y + x;
1039 if self.cells.objects[index as usize].is_some()
1040 || (y - sy) * (y - sy) + (x - sx) * (x - sx) < radius_sq
1041 {
1042 continue;
1043 }
1044 let (cx, cy) = self.cell_position(index);
1045 let (h, up) = self.ground(cx, cy);
1046 if h < nr.height_min || (nr.height_max <= h && h != nr.height_max) {
1047 continue;
1048 }
1049 if up < nr.normal_min {
1050 continue;
1051 }
1052 if !self.density_ok(template, x, y) {
1053 continue;
1054 }
1055 let (mut variant, mut mesh, max_growth) = self.construct(template);
1056 let (position, yaw) = self.position(template, index);
1057 let (mut growth, mut scale, mut growth_state) = (1.0, [ONE; 4], None);
1058 if self.templates[template].growth.is_some() {
1059 let fraction = self.rng.rand_float();
1060 let (state, value, output) =
1061 self.set_growth(template, max_growth, fraction);
1062 growth = value;
1063 scale = output;
1064 growth_state = Some(state);
1065 }
1066 let id = self.register(Placed {
1067 template,
1068 bucket: self.templates[template].bucket,
1069 cell: (x, y),
1070 footprint: (1, 1),
1071 position,
1072 yaw,
1073 variant,
1074 mesh,
1075 growth,
1076 growth_state,
1077 spawn_state: self.spawn_state(template),
1078 alive: true,
1079 removal_requested: false,
1080 animation: None,
1081 scale,
1082 });
1083 if !self.templates[template].spawn.is_empty() {
1084 self.spawn(id);
1085 }
1086 if nr.cluster {
1087 let inv = ONE / nr.cluster_scale;
1088 variant = 0;
1089 for (k, c) in clusters.iter().enumerate() {
1090 let v = c.generate(x as f32 * inv, y as f32 * inv);
1091 if nr.cluster_threshold <= v * HALF + HALF {
1092 variant = k;
1093 break;
1094 }
1095 }
1096 if self.rng.rand_below(nr.random_variant_one_in as u32) == 0 {
1097 variant = self.rng.rand_below(variants as u32) as usize;
1098 }
1099 let meshes = self.templates[template].model.as_ref().unwrap().variants
1100 [variant]
1101 .meshes
1102 .len();
1103 mesh = self.rng.rand_below(meshes as u32) as usize;
1104 self.placed[id].variant = variant;
1105 self.placed[id].mesh = mesh;
1106 }
1107 }
1108 }
1109 }
1110 }
1111}
1112
1113#[cfg(test)]
1114mod tests;