Skip to main content

banished_game/people/
status.rs

1//! Read-only StatusBarUI calculations.
2//!
3//! Original: `FUN_14007eda0`, `FUN_14006b830`.
4
5/// What the status bar reads of one citizen.
6#[derive(Debug, Clone, Copy, Default)]
7pub struct CitizenValue {
8    /// The age.
9    pub age: f32,
10    /// The age at which a citizen is an adult.
11    pub adult_age: f32,
12    /// Whether it attends school.
13    pub school: bool,
14    /// The health.
15    pub health: f32,
16    /// The happiness.
17    pub happiness: f32,
18    // +0xf0; +0x88
19    /// StatusIconComponent, not Citizen.
20    pub status: u32,
21}
22
23/// The status bar's counts: adults, students, children and the other values.
24#[derive(Debug, Clone, Copy, Default, PartialEq)]
25pub struct TownStatus {
26    /// The adults.
27    pub adults: u32,
28    /// The students.
29    pub students: u32,
30    /// The children.
31    pub children: u32,
32    /// The citizens with each of the first six status icons.
33    pub counts: [u32; 6],
34    /// The mean health.
35    pub health: f32,
36    /// The mean happiness.
37    pub happiness: f32,
38}
39
40/// Preserve creation-list float summation order.
41///
42/// Original: `FUN_14007eda0` (citizen loop).
43pub fn aggregate(citizens: impl IntoIterator<Item = CitizenValue>) -> TownStatus {
44    let mut result = TownStatus::default();
45    let mut count = 0;
46    for c in citizens {
47        if c.school {
48            result.students += 1;
49        } else if c.age < c.adult_age {
50            result.children += 1;
51        } else {
52            result.adults += 1;
53        }
54        for (i, n) in result.counts.iter_mut().enumerate() {
55            *n += (c.status >> i) & 1;
56        }
57        result.health += c.health;
58        result.happiness += c.happiness;
59        count += 1;
60    }
61    if count != 0 {
62        result.health /= count as f32;
63        result.happiness /= count as f32;
64    }
65    result
66}
67
68/// Each group has a `whole` and `half` image. Keep the container visible so all five
69/// resource-defined slots occupy their original geometry.
70///
71/// Original: `FUN_14006b830`.
72pub fn meter(value: f32, maximum: f32, icons: usize) -> Vec<(bool, bool)> {
73    let halves = ((value / maximum) * (icons as i32 * 2) as f32 + 0.5) as i32;
74    (0..icons)
75        .map(|i| {
76            let boundary = i as i32 * 2 + 1;
77            (boundary < halves, boundary == halves)
78        })
79        .collect()
80}
81
82/// Deleting an icon is permitted on disabled owners.
83///
84/// Original: `FUN_1401318c0` (mask mutation).
85pub fn set_icon(mask: &mut u32, bit: u8, on: bool, owner_disabled: bool) {
86    if !on {
87        *mask &= !(1 << (bit & 31));
88    } else if !owner_disabled {
89        *mask |= 1 << (bit & 31);
90    }
91}