1use super::*;
4
5impl Agents {
6 pub fn apply_commands(
9 &mut self,
10 citizens: &mut Vec<Citizen>,
11 env: &mut Env,
12 groups: &[Option<&AnimationGroup>],
13 newborn: &mut dyn FnMut(&mut Random, &Citizen, bool) -> Citizen,
14 ) {
15 self.sync_map(env.cells);
16 let commands = std::mem::take(&mut env.construction.commands);
17 let placed = std::mem::take(&mut env.construction.placed);
18 let destroy = std::mem::take(&mut env.construction.destroy);
19 if commands.is_empty() && placed.is_empty() && destroy.is_empty() {
20 return;
21 }
22 let entities = entity_views(env.placed, env.templates, env.construction);
23 let adult = self.adults(citizens);
24 let mut admission = None;
27 let mut road_markers = Vec::new();
28 let (mut sim, jobs) = self.sim(citizens, env, groups, &adult, &entities);
29 for e in placed {
31 sim.activate(jobs, e);
32 jobs.drain(&mut sim);
33 }
34 for e in destroy {
35 sim.destroy_entity(jobs, e);
36 jobs.drain(&mut sim);
37 }
38 let mut queue = commands.into_iter();
39 while let Some(command) = queue.next() {
40 match command {
41 crate::work::professions::Command::SetCrop { entity, crop } => {
42 if sim.wildlife.pastures.contains_key(&entity) {
43 if sim.wildlife.pastures[&entity].livestock.is_empty() {
46 sim.set_pasture_kind(jobs, entity, crop);
47 }
48 } else if sim.sites.get(&entity).is_some_and(|s| s.orchard.is_some()) {
49 sim.set_orchard_tree(entity, crop);
50 } else {
51 sim.set_crop(entity, crop);
52 }
53 jobs.drain(&mut sim);
54 continue;
55 }
56 crate::work::professions::Command::FieldAction { entity, action } => {
57 if sim.wildlife.pastures.contains_key(&entity) {
58 sim.pasture_action(jobs, entity, action);
59 } else if sim.sites.get(&entity).is_some_and(|s| s.orchard.is_some()) {
60 sim.orchard_action(entity, action);
61 } else {
62 sim.field_action(entity, action);
63 }
64 jobs.drain(&mut sim);
65 continue;
66 }
67 crate::work::professions::Command::SetLimit { entity, limit } => {
68 sim.set_pasture_limit(entity, limit);
69 continue;
70 }
71 crate::work::professions::Command::SetEnabled { entity, enabled } => {
72 sim.enable_workplace(entity, enabled);
73 jobs.drain(&mut sim);
74 continue;
75 }
76 crate::work::professions::Command::PlanRoad {
77 cell,
78 kind,
79 ty,
80 material,
81 } => {
82 sim.plan_road(jobs, cell, kind, ty, material);
83 jobs.drain(&mut sim);
84 continue;
85 }
86 crate::work::professions::Command::ClearRoad { cell, marker } => {
87 if sim.unplan_road(jobs, cell) {
88 road_markers.push((cell, marker));
89 }
90 jobs.drain(&mut sim);
91 continue;
92 }
93 crate::work::professions::Command::Demolish { entity } => {
94 sim.demolish(jobs, entity);
95 jobs.drain(&mut sim);
96 continue;
97 }
98 crate::work::professions::Command::StateMessage { entity, message } => {
99 if message == 7 {
100 if let Some(band) = sim.take_band(entity) {
101 admission = Some((entity, band));
102 break;
103 }
104 }
105 sim.destroy_message(jobs, entity, message);
106 sim.immigration_message(entity, message);
107 sim.trade_message(entity, message);
108 jobs.drain(&mut sim);
109 continue;
110 }
111 crate::work::professions::Command::Control {
112 entity,
113 kind,
114 index,
115 } => {
116 sim.control(jobs, entity, kind, index);
117 jobs.drain(&mut sim);
118 continue;
119 }
120 crate::work::professions::Command::SetRecipe { entity, recipe } => {
121 if let Some(p) = sim.sites.get_mut(&entity).and_then(|s| s.produce.as_mut()) {
122 p.selector = recipe;
123 }
124 continue;
125 }
126 crate::work::professions::Command::Exchange { entity, sell, buy } => {
127 sim.exchange(entity, &sell, &buy);
128 continue;
129 }
130 crate::work::professions::Command::Trade { entity, setting } => {
131 sim.trade_setting(entity, setting);
132 continue;
133 }
134 crate::work::professions::Command::Upgrade { entity, template } => {
135 sim.upgrade(jobs, entity, template);
136 jobs.drain(&mut sim);
137 continue;
138 }
139 crate::work::professions::Command::CancelDemolition { entity } => {
140 sim.cancel_demolition(jobs, entity);
141 jobs.drain(&mut sim);
142 continue;
143 }
144 _ => {}
145 }
146 let mut workers = sim.workers();
147 let town = TownView {
148 size: sim.size,
149 types: &sim.cells.types,
150 regions: sim.regions,
151 occupants: &sim.cells.occupants,
152 objects: &sim.cells.objects,
153 floors: &sim.cells.floors,
154 entities: sim.entities,
155 happiness: sim.happiness,
156 };
157 let (size, terrain) = (sim.size, sim.terrain);
158 let floors = &sim.cells.floors;
159 let ground = move |c: i32| crate::town::floor_ground(floors, size, terrain, c);
160 let mut geometry = StorageGeometry {
161 town: &town,
162 sectors: sim.sectors,
163 ground: &ground,
164 };
165 let characters = &*sim.characters;
166 let cell = |c: usize| town.cell_of(characters[c].position);
167 let professions = sim.professions;
168 let anywhere = |p: usize| professions.works_anywhere(p);
169 let sites = &*sim.sites;
170 let priority = |e: usize| {
171 sites
172 .get(&e)
173 .and_then(|s| s.work_priority)
174 .unwrap_or(i32::MAX)
175 };
176 let mut search = crate::behaviour::activities::TownSearch {
177 town: &town,
178 cell: &cell,
179 anywhere: &anywhere,
180 priority: &priority,
181 rng: &mut *sim.rng,
182 };
183 sim.workforce.apply(
184 command,
185 &mut workers,
186 sim.professions,
187 sim.homes,
188 &mut geometry,
189 &mut search,
190 );
191 sim.set_workers(&workers);
192 }
193 let rest: Vec<_> = queue.collect();
194 env.construction.road_markers.extend(road_markers);
195 if let Some((entity, band)) = admission {
196 self.admit_band(citizens, env, groups, entity, &band, newborn);
197 if !rest.is_empty() {
198 let later = std::mem::replace(&mut env.construction.commands, rest);
199 env.construction.commands.extend(later);
200 self.apply_commands(citizens, env, groups, newborn);
201 }
202 }
203 }
204
205 pub fn set_tree_slot(&mut self, i: usize, slot: i32) {
207 if let Some(ch) = self.characters.get_mut(i) {
208 ch.tree_slot = slot;
209 }
210 }
211
212 pub(super) fn join_tree(&mut self, i: usize, env: &mut Env) {
214 let ch = &mut self.characters[i];
215 if ch.tree_slot < 0 {
216 ch.tree_slot = env.wildlife.tree.insert(
217 crate::behaviour::character_tree::Who::Citizen(i),
218 ch.position,
219 ch.desc.radius,
220 );
221 }
222 }
223
224 pub(super) fn admit_band(
230 &mut self,
231 citizens: &mut Vec<Citizen>,
232 env: &mut Env,
233 groups: &[Option<&AnimationGroup>],
234 entity: usize,
235 band: &[(usize, [f32; 3])],
236 newborn: &mut dyn FnMut(&mut Random, &Citizen, bool) -> Citizen,
237 ) {
238 env.construction.nomads_admitted += band.len() as i32;
239 let laborer = env.construction.professions.laborer;
240 let r = self.life.clone();
241 let (lo, hi) = (r.f(0x50), r.f(0x54));
242 let mut make = |agents: &mut Self,
243 citizens: &mut Vec<Citizen>,
244 rng: &mut Random,
245 position: [f32; 3],
246 male: bool,
247 guardian: Option<usize>| {
248 let child = guardian.is_some();
249 let age = if child {
250 rng.rand_float() * lo
251 } else {
252 rng.rand_float() * (hi - lo) + lo
253 };
254 let _flag = rng.rand_below(1);
255 let template = Citizen {
256 position,
257 ..citizens.first().cloned().unwrap_or_else(|| Citizen {
258 name: String::new(),
259 male,
260 age: 0.0,
261 lifespan: 0.0,
262 appearance: 0,
263 educated: false,
264 education: 0,
265 position,
266 spouse: None,
267 parent: None,
268 school: None,
269 alive: true,
270 })
271 };
272 let mut c = newborn(rng, &template, male);
273 c.position = position;
274 c.age = age;
275 c.alive = true;
276 let id = citizens.len();
277 citizens.push(c);
278 let mut state = CitizenState::newborn(&r);
279 state.profession = laborer;
280 state.carried = agents.carried.clone();
281 agents.states.push(state);
282 agents.registry.push(id);
283 let scale = if child { CHILD_SCALE } else { 1.0 };
284 agents
285 .characters
286 .push(Character::new(agents.desc, position, scale));
287 agents.ais.push(CitizenAi::default());
288 if let Some(g) = guardian {
289 agents.states[g].dependents.push(id);
290 citizens[id].parent = Some(g);
291 }
292 id
293 };
294 let first = citizens.len();
295 let mut k = 0;
296 while k < band.len() {
297 let man = make(self, citizens, env.rng, band[k].1, true, None);
298 if band.len() <= k + 1 {
299 break;
300 }
301 let woman = make(self, citizens, env.rng, band[k + 1].1, false, None);
302 citizens[man].spouse = Some(woman);
303 citizens[woman].spouse = Some(man);
304 if band.len() <= k + 2 {
305 break;
306 }
307 make(self, citizens, env.rng, band[k + 2].1, false, Some(woman));
308 if band.len() <= k + 3 {
309 break;
310 }
311 make(self, citizens, env.rng, band[k + 3].1, true, Some(woman));
312 k += 4;
313 }
314 for i in first..citizens.len() {
317 self.join_tree(i, env);
318 }
319 let entities = entity_views(env.placed, env.templates, env.construction);
320 let adult = self.adults(citizens);
321 let (mut sim, jobs) = self.sim(citizens, env, groups, &adult, &entities);
322 sim.band_taken(entity);
323 jobs.drain(&mut sim);
324 }
325}