1use super::*;
4
5impl Sim<'_, '_> {
6 pub(crate) fn drop_loose_pile(&mut self, c: usize, material: usize, count: i32) {
10 let Some(at) = self.free_flat_cell(self.citizen_cell(c)) else {
11 return;
12 };
13 let reference = &self.materials[material].reference;
15 let Some(template) = self
16 .templates
17 .iter()
18 .position(|t| &t.reference == reference && t.pile_material == Some(material))
19 .or_else(|| {
20 self.templates
21 .iter()
22 .position(|t| t.pile_material == Some(material))
23 })
24 else {
25 return;
26 };
27 let yaw = self.rng.rand_tol(2) as f32 * 90.0;
28 let n = self.size as i32;
29 self.spawn_pile(template, (at % n, at / n), count, yaw, None);
30 *self.models_dirty = true;
31 }
32
33 pub(crate) fn spawn_pile(
37 &mut self,
38 pile_t: usize,
39 cell: (i32, i32),
40 amount: i32,
41 yaw: f32,
42 priority: Option<i32>,
43 ) -> usize {
44 let Some(material) = self.templates[pile_t].pile_material else {
45 return usize::MAX;
46 };
47 let pt = &self.templates[pile_t];
48 let n = self.size as i32;
49 let index = cell.1 * n + cell.0;
50 let id = self.placed.len();
51 let mut yaw = yaw as i32;
52 while yaw < 0 {
53 yaw += 360;
54 }
55 let (variant, mesh) = pt.model.as_ref().map_or((0, 0), |m| {
56 (m.variant.max(0) as usize, m.mesh.max(0) as usize)
57 });
58 self.placed.push(Placed {
59 template: pile_t,
60 bucket: pt.bucket,
61 cell,
62 footprint: (1, 1),
63 position: self.ground_at(index),
64 yaw: yaw as f32,
65 variant,
66 mesh,
67 growth: 0.0,
68 growth_state: None,
69 spawn_state: None,
70 alive: true,
71 removal_requested: false,
72 animation: None,
73 scale: [1.0; 4],
74 });
75 self.stamp(id);
77 self.piles.insert(
78 id,
79 Pile {
80 material,
81 count: amount,
82 age: 0,
83 work: -1,
84 mask: pile_mask(self.materials[material].flags),
85 priority,
86 auto_pickup: None,
87 state: 0,
88 claimer: None,
89 },
90 );
91 self.new_piles.push(id);
92 id
93 }
94
95 pub fn activate_piles(&mut self, jobs: &mut Jobs) {
99 for id in std::mem::take(self.new_piles) {
100 let Some(pile) = self.piles.get(&id) else {
101 continue;
102 };
103 let (mask, priority, auto_pickup) = (pile.mask, pile.priority, pile.auto_pickup);
104 self.discover(pile.material);
106 let cell = self.rect_cell(id);
107 let work = Work::new(
108 id,
109 cell,
110 self.professions.laborer,
111 WorkKind::Pickup(PickupWork),
112 );
113 let w = jobs.add(work, mask, priority);
114 self.piles.get_mut(&id).unwrap().work = w;
115 if let Some(wp) = auto_pickup {
116 self.auto_pickup_add(wp, w);
117 }
118 }
119 }
120
121 pub fn destroy_pile(&mut self, jobs: &mut Jobs, id: usize) {
123 let Some(pile) = self.piles.remove(&id) else {
124 return;
125 };
126 if pile.work >= 0 {
127 jobs.remove(pile.work, self);
128 }
129 let p = &mut self.placed[id];
130 p.alive = false;
131 let (x, y) = p.cell;
132 let i = (y as usize) * self.size + x as usize;
133 if self.cells.objects[i] == Some(id) {
134 self.cells.objects[i] = None;
135 self.cells
136 .set_type(i, self.terrain.natural_cell_type(self.size, i));
137 }
138 *self.models_dirty = true;
139 }
140
141 pub(crate) fn absorb_piles(&mut self, jobs: &mut Jobs, e: usize) {
144 let Some(storage) = self.sites.get(&e).map(|s| s.storage) else {
145 return;
146 };
147 let n = self.size as i32;
148 let (x, y) = self.placed[e].cell;
149 let (w, h) = self.placed[e].footprint;
150 for cy in y..y + h {
151 for cx in x..x + w {
152 let Some(o) = self.cells.objects[(cy * n + cx) as usize] else {
153 continue;
154 };
155 let Some(pile) = self.piles.get(&o) else {
156 continue;
157 };
158 let (material, count) = (pile.material, pile.count);
159 if self.storages[storage].fits(self.materials, material, count) {
160 self.storages[storage].add(material, count);
161 self.destroy_pile(jobs, o);
162 }
163 }
164 }
165 }
166
167 pub fn take_pile(&mut self, jobs: &mut Jobs, c: usize, id: usize) {
171 let Some(pile) = self.piles.get(&id) else {
172 return;
173 };
174 let (material, count) = (pile.material, pile.count);
175 self.states[c].carried.add(material, count);
176 self.destroy_pile(jobs, id);
177 }
178
179 pub fn age_piles(&mut self, jobs: &mut Jobs, visits: &[(usize, i64)]) {
184 let old: Vec<usize> = visits
185 .iter()
186 .filter_map(|&(id, elapsed)| {
187 let p = self.piles.get_mut(&id)?;
188 p.age += elapsed;
189 (p.age > ticks(3600.0)).then_some(id)
190 })
191 .collect();
192 for id in old {
193 self.destroy_pile(jobs, id);
194 }
195 }
196}