banished_game/work/construction/site.rs
1//! What a building site holds: its template, production, workers, decals, piles and the work it
2//! offers, and the town's list of sites (`Construction`).
3
4use super::*;
5
6/// The parts of a building's descriptions construction reads.
7#[derive(Debug, Clone, Default)]
8pub struct SiteTemplate {
9 /// `Template\X.rsc:resource`.
10 pub reference: String,
11 /// The controllers in component order.
12 pub controllers: Vec<Controller>,
13 // +0x20; +0x30
14 /// The materials to build it: `(count, raw material)`.
15 pub materials: Vec<(i32, usize)>,
16 /// The building work needed, in work units.
17 pub work: i32,
18 // +0x2c
19 /// ClearAreaDescription: present, flatten/stamp flag.
20 pub clear: Option<banished_formats::game::ClearAreaDescription>,
21 // +0x24
22 /// WorkDescription (most workers once built).
23 pub max_workers: i32,
24 // +0x34; +0x30; +0x24
25 /// Scale the most workers by the footprint's area over this many cells (from the work
26 /// description).
27 pub per_area: Option<i32>,
28 // +0x20; +0x28; +0x2c
29 /// Whether the player may change the most workers in the building's window.
30 pub adjustable: bool,
31 /// The fewest workers the player may set.
32 pub min_jobs: i32,
33 /// The most workers the player may set.
34 pub max_jobs: i32,
35 // +0x20
36 /// WorkPlaceDescription.
37 pub profession: Option<usize>,
38 /// ConsumeProduceDescription, resolved.
39 pub produce: Option<ProduceTemplate>,
40 /// StorageDescription: accepted flags, capacity, per footprint cell.
41 pub storage: Option<(u32, i32, bool)>,
42 /// ModelDescription meshes per variant (construction stages, the last finished).
43 pub meshes: Vec<usize>,
44 /// ResidenceDescription.
45 pub residence: Option<banished_formats::game::ResidenceDescription>,
46 /// AttendanceDescription capacity.
47 pub attendance: Option<i32>,
48 /// HerbalistDescription (gatherer, herbalist), resolved.
49 pub herbalist: Option<crate::production::herbalist::HerbalistTemplate>,
50 // +0x28
51 /// RadiusDescription.
52 pub radius: Option<i32>,
53 // +0x20
54 /// AutoPickupDescription.
55 pub auto_pickup: Option<bool>,
56 /// ForesterDescription, resolved.
57 pub forester: Option<crate::production::forester::ForesterTemplate>,
58 /// HappinessDescription.
59 pub happiness: Option<banished_formats::game::HappinessDescription>,
60 /// FishingDescription, resolved.
61 pub fishing: Option<crate::production::fishing::FishingTemplate>,
62 /// HuntDescription.
63 pub hunt: Option<banished_formats::game::HuntDescription>,
64 /// CropFieldDescription.
65 pub crop_field: Option<crate::production::farm::CropFieldTemplate>,
66 /// OrchardDescription.
67 pub orchard: Option<crate::production::orchard::OrchardTemplate>,
68 // +0x20
69 /// PastureDescription: the stock slot of its products' limit.
70 pub pasture: Option<i32>,
71 /// DiseaseDescription (fields, orchards, pastures).
72 pub disease: Option<banished_formats::game::DiseaseDescription>,
73 /// CemeteryDescription's tombstone template and its TombstoneDescription.
74 pub cemetery: Option<crate::people::cemetery::CemeteryTemplate>,
75 /// MarketDescription.
76 pub market: Option<banished_formats::game::MarketDescription>,
77 // ModelComponent +0x5c
78 /// StatusIconDescription (presentation), and the finished model's height its icons stand on
79 /// (`ModelComponent`).
80 pub status_icon: Option<banished_formats::game::StatusIconDescription>,
81 /// The height of the status icon above the building, if it has one.
82 pub icon_height: Option<f32>,
83 /// DestroyDescription, resolved.
84 pub destroy: Option<crate::work::destroy::DestroyTemplate>,
85 /// FireDescription (`Template\Common.rsc:fire*`).
86 pub fire: Option<banished_formats::game::FireDescription>,
87 /// ImmigrationDescription, resolved.
88 pub immigration: Option<crate::people::immigration::ImmigrationTemplate>,
89 /// TradeDescription, resolved.
90 pub trade: Option<crate::commerce::trade::TradeTemplate>,
91 // +0x68; +0x6c
92 /// TradeDescription /: the visitors' disease risk trading brings, and its months.
93 pub trade_risk: Option<(f32, i32)>,
94 /// The pile template of each BuildDescription material (the refunds' piles).
95 pub material_templates: Vec<Option<usize>>,
96}
97
98/// A resolved [`banished_formats::game::ConsumeProduceDescription`].
99#[derive(Debug, Clone, Default)]
100pub struct ProduceTemplate {
101 /// The recipes.
102 pub recipes: Vec<Recipe>,
103 // +0x40
104 /// Work cycles per production.
105 pub cycles: i32,
106 // +0x50
107 /// Work type (tool mesh, animation, walk).
108 pub work_type: u32,
109 // +0x38/+0x3c
110 /// A message to the building's component of that type after a production.
111 pub message: (u32, i32),
112 // +0x44
113 /// Seconds per cycle.
114 pub duration: f32,
115 // +0x48
116 /// Productions before exhaustion (−1 never).
117 pub lifetime: i32,
118 // +0x4c
119 /// Initial selector.
120 pub selector: i32,
121}
122
123/// A production alternative: inputs (raw material, count), the output pile template and its
124/// raw material, and the stock group the limit check reads.
125#[derive(Debug, Clone, Default)]
126pub struct Recipe {
127 /// What it uses: `(raw material, count)`.
128 pub inputs: Vec<(usize, i32)>,
129 /// The template of the output pile.
130 pub output: usize,
131 /// The raw material of the output.
132 pub output_material: usize,
133 /// The stock group whose limit is checked.
134 pub group: i32,
135}
136
137// +0x48; +0x50; +0x58; +0x68
138/// ConsumeProduceComponent state (switched off, selector, weights, productions so far).
139#[derive(Debug, Clone, Default)]
140pub struct ProduceState {
141 /// Whether production is switched off.
142 pub disabled: bool,
143 /// The recipe chosen in the window.
144 pub selector: i32,
145 /// The weight of each recipe, for choosing what to make.
146 pub weights: Vec<f32>,
147 /// The productions so far.
148 pub produced: i32,
149}
150
151// +0x58; +0x68; +0x48; +0x4c
152/// `ConsumeProduce` work state: the worker at each use point, each output point's state (0 free, 1
153/// a production is under way, 2 holds output), every output point was taken, work cycles towards
154/// the next production.
155#[derive(Debug, Clone, Default)]
156pub struct ProduceWork {
157 /// The worker at each use point.
158 pub workers: Vec<Option<usize>>,
159 /// The state of each output point: 0 free, 1 a production is under way, 2 holds output.
160 pub points: Vec<u8>,
161 /// Whether every output point was taken.
162 pub full: bool,
163 /// The work cycles towards the next production.
164 pub cycles: i32,
165}
166
167// vtable 0x140169400; +0x30; +0x28; +0x2c
168/// DecalComponent (0x38 bytes, serialized alpha, material): setup takes the description's alpha;
169/// entity event 1 (the ClearArea's state 2) and the build's state 8 make it opaque; a collapse
170/// switches to the DestroyDescription's material. Each change re-adds the map decal. See
171/// docs/DECALS.md.
172///
173/// Original: `FUN_140120ca0`, `FUN_14011ccc0`, `FUN_14010cfb0`, `FUN_140122aa0`, `FUN_140120c30`.
174#[derive(Debug, Clone, Copy, Default, PartialEq)]
175pub struct Decal {
176 // +0x30
177 /// is 1.
178 pub opaque: bool,
179 // +0x28
180 /// Index into the description's materials.
181 pub material: i32,
182}
183
184/// One building under construction (and, once built, its WorkComponent).
185#[derive(Debug, Clone)]
186pub struct Site {
187 /// The building's entity.
188 pub entity: usize,
189 /// Index into [`Construction::templates`].
190 pub template: usize,
191 /// The building's state machine.
192 pub machine: Machine,
193 // +0x48; +0x4c
194 /// BuildComponent progress, stages.
195 pub progress: i32,
196 /// The construction stages.
197 pub stages: i32,
198 // +0x28; +0x2c
199 /// WorkComponent registered work id (−1) and kept priority.
200 pub work_id: i32,
201 /// The priority to keep for its work, if any.
202 pub work_priority: Option<i32>,
203 /// The building's StorageComponent (index into the town's storages).
204 pub storage: usize,
205 /// State 2 reached.
206 pub complete: bool,
207 // +0x48
208 /// ClearAreaComponent: objects on the footprint when clearing began.
209 pub clear_total: i32,
210 /// The entity was destroyed during a state callback; the site goes once the machine has run.
211 ///
212 /// Original: `FUN_1400c8370`.
213 pub destroyed: bool,
214 // +0x48
215 /// ConsumeProduceComponent (ResourceProduceComponent's for the others).
216 pub produce: Option<ProduceState>,
217 /// AutoPickupComponent.
218 pub auto_pickup: Option<crate::production::herbalist::AutoPickup>,
219 /// ForesterComponent's toggles.
220 pub forester: Option<crate::production::forester::Forester>,
221 // +0x28
222 /// HappinessComponent: registered.
223 pub happiness_registered: bool,
224 /// FishingComponent.
225 pub fishing: Option<crate::production::fishing::Fishing>,
226 // +0x50
227 /// HuntComponent: the hunting time gathered.
228 pub hunt_time: Option<i64>,
229 /// CropFieldComponent.
230 pub crop_field: Option<crate::production::farm::CropField>,
231 /// OrchardComponent.
232 pub orchard: Option<crate::production::orchard::Orchard>,
233 // +0x48
234 /// MultiObjectComponent: the entities placed with this one (a pasture's shelter and fences), in
235 /// order.
236 pub parts: Vec<usize>,
237 // +0x58; +0x4c
238 /// MultiObjectComponent: the stages its construction counts (a bridge's cells, a fenced area's
239 /// border cells); `BuildComponent::EnterGather` takes it for.
240 pub multi_stages: Option<i32>,
241 /// DiseaseComponent.
242 pub disease: Option<crate::disasters::blight::Blight>,
243 // +0x48
244 /// CemeteryComponent: the grave cells.
245 ///
246 /// Original: `FUN_140047b60`.
247 pub graves: Vec<i32>,
248 /// DestroyComponent.
249 pub destroy: Option<crate::work::destroy::Destroy>,
250 /// FireComponent.
251 pub fire: Option<crate::disasters::fire::Fire>,
252 /// ImmigrationComponent.
253 pub immigration: Option<crate::people::immigration::Immigration>,
254 /// TradeComponent.
255 pub trade: Option<crate::commerce::trade::Trade>,
256 /// The ResidenceComponent while the residence is out of the town's (its states 3 to 7).
257 pub home: Option<crate::people::life::Home>,
258 // +0x28; +0x30; +0x20
259 /// UIComponent (bytes, the UIDescription's): the window's remembered settings
260 /// (`DialogInstance::SaveSettings`), empty until it is first closed.
261 pub ui_settings: Vec<u8>,
262}
263
264/// The job manager, professions, workforce and every construction site.
265#[derive(Debug, Clone, Default)]
266pub struct Construction {
267 // +0x1b8; +0x190
268 /// The town's commute optimisation (StockManager).
269 pub commute: crate::behaviour::commute::Commute,
270 /// The job manager.
271 pub jobs: Jobs,
272 /// The professions.
273 pub professions: Professions,
274 /// The citizens' workplaces and professions.
275 pub workforce: Workforce,
276 /// The building templates, as construction reads them.
277 pub templates: Vec<SiteTemplate>,
278 /// Entity → site.
279 pub sites: BTreeMap<usize, Site>,
280 // Game +0xf0 → +0xd0
281 /// `Game →`: sites in their gathering and building states.
282 pub site_list: Vec<usize>,
283 /// Sites placed since the last iteration (activated before the next one).
284 pub placed: Vec<usize>,
285 /// Player commands for the next iteration.
286 pub commands: Vec<Command>,
287 /// Loose raw-material piles (RawMaterialComponent), by entity.
288 pub piles: BTreeMap<usize, Pile>,
289 /// NaturalResourceComponent flag `0x100000`: a removal sequence holds the resource.
290 pub claimed_resources: BTreeSet<usize>,
291 /// Piles created since the last iteration (registered with the entity manager and
292 /// activated after the citizens' update).
293 pub new_piles: Vec<usize>,
294 /// Entities were created or removed (the models need refreshing).
295 pub models_dirty: bool,
296 /// Entities the player destroyed (RemovalTool cancel), before the next iteration.
297 pub destroy: Vec<usize>,
298 /// Finished residences' ResidenceComponents, by entity.
299 pub homes: BTreeMap<usize, crate::people::life::Home>,
300 // +0x60
301 /// AttendanceComponents, by entity, and the town manager's registry.
302 pub attendance: BTreeMap<usize, Attendance>,
303 /// The town manager's list of schools, chapels and doctors.
304 pub attendance_list: Vec<usize>,
305 // +0x70
306 /// The town manager's HealerComponents.
307 pub healers: Vec<usize>,
308 // +0x50
309 /// The town manager's registered HappinessComponents, by entity.
310 pub happiness: Vec<usize>,
311 // Game +0x128 → +8; +0
312 /// The calendar's seconds into the year, set before each iteration.
313 pub calendar: f32,
314 /// The calendar's year, set before each iteration.
315 pub year: u32,
316 /// FruitComponents of orchard trees, by entity.
317 pub fruits: BTreeMap<usize, crate::production::orchard::Fruit>,
318 // +0x2d
319 /// NaturalResourceComponent set by a crop field: whether harvesting leaves a pile.
320 pub keep_piles: BTreeMap<usize, bool>,
321 /// Event-log entries the sites posted: type, severity, entity; the game formats them with the
322 /// entity's toolbar name.
323 ///
324 /// Original: `FUN_14009a2d0`.
325 pub site_events: Vec<(i32, i32, usize)>,
326 // +0x00
327 /// StorageLocationComponents joining (`true`) or leaving the town's storages, in order; the
328 /// town applies them after the iteration's update.
329 pub storage_changes: Vec<(usize, bool)>,
330 // +0x40
331 /// The town's cemeteries, in order.
332 pub cemeteries: Vec<usize>,
333 // +0x28
334 /// TombstoneComponents and the time each has left.
335 pub tombstones: BTreeMap<usize, i64>,
336 /// Burials decided at a death (cemetery, grave cell), placed after the citizens' update.
337 pub burials: Vec<(usize, i32)>,
338 /// Entities a DestroyComponent puts in a torn-down building's place, created by the town after
339 /// the update.
340 ///
341 /// Original: `FUN_1400c9d70`.
342 pub rebuilds: Vec<crate::work::destroy::Rebuild>,
343 /// The town's water sources (built with the map).
344 ///
345 /// Original: `FUN_1400a43f0`.
346 pub water: crate::disasters::fire::Water,
347 // Game +0xd0; FUN_14009d530 sets 0xf0 with disasters off, else 0.
348 /// The game's flags (for example, disasters off).
349 pub game_flags: u32,
350 /// The sky's state is precipitation, set before each iteration.
351 pub precipitation: bool,
352 // +0xa8
353 /// Town manager: the population, set before each update.
354 pub population: i32,
355 // +0x1a8; +0x1a0
356 /// Town manager /: the visitors' disease risk and how long it lasts.
357 pub visitors: (f32, i64),
358 // +0x1b0
359 /// Town manager: nomads taken in.
360 pub nomads_admitted: i32,
361 // +0x30
362 /// Town manager: the trading posts.
363 pub trading_posts: Vec<usize>,
364 // +0x1ac
365 /// Town manager: the value traded away.
366 pub trade_value: i32,
367 // +0xe8
368 /// Map: the cells with a planned road, and their BuildRoad works.
369 pub pending_roads: BTreeMap<i32, i32>,
370 /// Tunnels to dig or fill back (TerraformComponent event 4 and removal), for the terrain's
371 /// owner, and each terraformed entity's kept heights and cells.
372 pub terraform_requests: Vec<crate::world::terraform::Terraform>,
373 /// Requests to flatten the ground: cell rectangles (`x0, y0, x1, y1`, inclusive) whose
374 /// cells' low corners go to height 0. They are applied to the terrain after the iteration.
375 ///
376 /// Original: `FUN_1400a35b0`.
377 pub flatten_requests: Vec<[i32; 4]>,
378 /// The tornadoes by entity, and the citizens they killed this iteration (death code 5; the
379 /// citizens' pass applies it).
380 pub tornadoes: BTreeMap<usize, crate::disasters::tornado::Tornado>,
381 /// The citizens killed by tornadoes this iteration.
382 pub tornado_kills: Vec<usize>,
383 /// TrackerComponents by entity, and the stock manager's made/used counters.
384 pub trackers: BTreeMap<usize, crate::work::tracker::Tracker>,
385 /// DecalComponents that left their setup state, by entity (the others show at their
386 /// description's alpha with material 0).
387 pub decals: BTreeMap<usize, Decal>,
388 /// What the town made and used since the last sample.
389 pub counters: crate::work::tracker::StockCounters,
390 /// The terraforming state of tunnels, by entity.
391 pub terraforms: BTreeMap<usize, crate::world::terraform::TerraformState>,
392 /// Built road cells Remove Roads marked, for the town to place their markers (cell,
393 /// marker template).
394 pub road_markers: Vec<(i32, usize)>,
395 /// The goods with a ValueDescription, in the factory's order (`GameResources`).
396 pub trade_goods: Vec<crate::commerce::trade::TradeGood>,
397 // +0x1e0
398 /// MapComponent 's first river centre line, the trader boats' way.
399 pub river: Vec<[f32; 2]>,
400 /// `Game/Names/Male` and `Female`, for the merchants' names.
401 pub names: Option<
402 std::sync::Arc<(
403 banished_formats::names::NameDatabase,
404 banished_formats::names::NameDatabase,
405 )>,
406 >,
407 /// The town manager's known crops, orchard trees and livestock, as placed-object templates.
408 ///
409 /// Original: `FUN_140096ef0`.
410 pub known: Vec<usize>,
411 // +0x110
412 /// The stock manager's known raw materials: the start profile's, then each as its first pile is
413 /// set up or it is traded for.
414 ///
415 /// Original: `FUN_140097330`.
416 pub known_materials: Vec<usize>,
417}
418
419// vtable 0x14015ee00
420/// AttendanceComponent: who attends a school, chapel or doctor.
421#[derive(Debug, Clone, PartialEq)]
422pub struct Attendance {
423 // +0x20
424 /// AttendanceDescription.
425 pub capacity: i32,
426 // +0x28
427 /// Attendees in arrival order.
428 pub attendees: Vec<usize>,
429 /// The workplace's profession (teacher, priest, doctor).
430 pub profession: Option<usize>,
431}
432
433// vtable 0x14016a5a0
434/// `RawMaterialComponent`: a loose pile.
435///
436/// Original: `FUN_14012e8d0`.
437#[derive(Debug, Clone, PartialEq)]
438pub struct Pile {
439 /// The raw material (RawMaterialDescription of the pile's template).
440 pub material: usize,
441 // +0x28
442 /// Units.
443 pub count: i32,
444 // +0x38
445 /// Age; after 3600 s the pile is destroyed.
446 ///
447 /// Original: `FUN_14012e600`.
448 pub age: i64,
449 /// The Pickup work its WorkComponent registered.
450 ///
451 /// Original: `FUN_14012e6a0`.
452 pub work: i32,
453 /// The work's category mask.
454 ///
455 /// Original: `FUN_14012e950`.
456 pub mask: u32,
457 /// A priority to keep from the work at its cell, applied on activation.
458 ///
459 /// Original: `FUN_1400fe220`.
460 pub priority: Option<i32>,
461 /// The workplace whose AutoPickup gets the Pickup work once registered.
462 pub auto_pickup: Option<usize>,
463 // +0x48; +0x50
464 /// The Pickup work's (0 free, 1 claimed, 2 picked up) and (claimer). Kept on the pile: one
465 /// Pickup try claims several piles' works.
466 pub state: i32,
467 /// The citizen who claimed the pile, if any.
468 pub claimer: Option<usize>,
469}
470
471// +0x48; +0x58; +0x68; +0x70..+0x72
472/// `ClearArea` state: claimed resources (entity → citizen), claimed cells, template filter,
473/// resources / cells / piles.
474#[derive(Debug, Clone, Default)]
475pub struct ClearWork {
476 /// The claimed resources: entity → citizen.
477 pub resources: BTreeMap<usize, usize>,
478 /// The claimed cells: cell → citizen.
479 pub cells: BTreeMap<i32, usize>,
480 /// Only resources of this template are cleared, when set.
481 pub filter: Option<String>,
482 /// Whether natural resources are cleared.
483 pub clear_resources: bool,
484 /// Whether cells are cleared.
485 pub clear_cells: bool,
486 /// Whether piles are cleared.
487 pub clear_piles: bool,
488}
489
490// +0x48; +0x50
491/// `Pickup` work: its state lives on the [`Pile`] it belongs to.
492#[derive(Debug, Clone, Default)]
493pub struct PickupWork;
494
495// +0x48; +0x58; +0x68
496/// `GatherRawMaterials` state (delivered per requirement, in transit, workers).
497#[derive(Debug, Clone, Default)]
498pub struct Gather {
499 /// The materials delivered, for each requirement.
500 pub stored: Vec<i32>,
501 /// The materials on their way, for each requirement.
502 pub transit: Vec<i32>,
503 /// The workers.
504 pub workers: BTreeSet<usize>,
505}
506
507// +0x48; +0x4c; +0x50; +0x60
508/// `BuildStructure` state (destroy flag, point cursor, occupied build points, workers).
509#[derive(Debug, Clone, Default)]
510pub struct BuildWork {
511 /// Whether this is demolition instead of construction.
512 pub destroy: bool,
513 /// The next build point to try.
514 pub cursor: i32,
515 /// Which build points are taken.
516 pub occupied: Vec<bool>,
517 /// The workers.
518 pub workers: BTreeSet<usize>,
519}
520
521impl SiteTemplate {
522 /// The default number of workers of a building of `footprint` cells.
523 ///
524 /// Original: `WorkComponent::MaxWorkers`, `FUN_140133a90`.
525 pub fn default_max_workers(&self, footprint: (i32, i32)) -> i32 {
526 let Some(area) = self.per_area else {
527 return self.max_workers;
528 };
529 let n = self.max_workers;
530 // `DAT_14017884c` = 1.0.
531 let scaled = ((footprint.0 * footprint.1) as f32 / area as f32 * n as f32 + 1.0) as i32;
532 if scaled <= n {
533 scaled.max(1)
534 } else {
535 n
536 }
537 }
538}