1use std::collections::VecDeque;
2
3use common::{
4 comp,
5 resources::TimeOfDay,
6 rtsim::{FactionId, Role},
7};
8use enum_map::EnumMap;
9use serde::{Deserialize, Serialize};
10
11use super::Npc;
12
13#[derive(Clone, Serialize, Deserialize)]
14pub struct Death {
15 pub time: TimeOfDay,
16 pub body: comp::Body,
17 pub role: Role,
18 pub faction: Option<FactionId>,
19}
20
21#[derive(enum_map::Enum)]
22pub enum TrackedPopulation {
23 Adventurers,
24 Merchants,
25 Guards,
26 Captains,
27 OtherTownNpcs,
28
29 PirateCaptains,
30 Pirates,
31 Cultists,
32
33 GigasFrost,
34 GigasFire,
35 OtherMonsters,
36
37 CloudWyvern,
38 FrostWyvern,
39 SeaWyvern,
40 FlameWyvern,
41 WealdWyvern,
42 Phoenix,
43 Roc,
44 Cockatrice,
45
46 Other,
47}
48
49impl TrackedPopulation {
50 pub fn from_body_and_role(body: &comp::Body, role: &Role) -> Self {
51 match (body, role) {
52 (_, Role::Civilised(role)) => match role {
53 Some(role) => match role {
54 common::rtsim::Profession::Farmer
55 | common::rtsim::Profession::Herbalist
56 | common::rtsim::Profession::Blacksmith
57 | common::rtsim::Profession::Chef
58 | common::rtsim::Profession::Alchemist
59 | common::rtsim::Profession::Hunter => Self::OtherTownNpcs,
60 common::rtsim::Profession::Merchant => Self::Merchants,
61 common::rtsim::Profession::Guard => Self::Guards,
62 common::rtsim::Profession::Adventurer(_) => Self::Adventurers,
63 common::rtsim::Profession::Pirate(false) => Self::Pirates,
64 common::rtsim::Profession::Pirate(true) => Self::PirateCaptains,
65 common::rtsim::Profession::Cultist => Self::Cultists,
66 common::rtsim::Profession::Captain => Self::Captains,
67 },
68 None => Self::OtherTownNpcs,
69 },
70 (comp::Body::BirdLarge(bird), Role::Wild) => match bird.species {
71 comp::bird_large::Species::Phoenix => Self::Phoenix,
72 comp::bird_large::Species::Cockatrice => Self::Cockatrice,
73 comp::bird_large::Species::Roc => Self::Roc,
74 comp::bird_large::Species::FlameWyvern => Self::FlameWyvern,
75 comp::bird_large::Species::CloudWyvern => Self::CloudWyvern,
76 comp::bird_large::Species::FrostWyvern => Self::FrostWyvern,
77 comp::bird_large::Species::SeaWyvern => Self::SeaWyvern,
78 comp::bird_large::Species::WealdWyvern => Self::WealdWyvern,
79 },
80 (comp::Body::BipedLarge(biped), Role::Monster) => match biped.species {
81 comp::biped_large::Species::Gigasfrost => Self::GigasFrost,
82 comp::biped_large::Species::Gigasfire => Self::GigasFire,
83 _ => Self::OtherMonsters,
84 },
85
86 _ => Self::Other,
87 }
88 }
89}
90
91#[derive(Default, Clone)]
92pub struct Population {
93 populations: EnumMap<TrackedPopulation, u32>,
94}
95
96impl Population {
97 pub fn total(&self) -> u32 { self.populations.values().sum::<u32>() }
98
99 pub fn iter(&self) -> impl ExactSizeIterator<Item = (TrackedPopulation, u32)> + use<'_> {
100 self.populations.iter().map(|(k, v)| (k, *v))
101 }
102
103 pub fn of_death(&self, death: &Death) -> u32 {
104 let pop = TrackedPopulation::from_body_and_role(&death.body, &death.role);
105 self.populations[pop]
106 }
107
108 fn of_death_mut(&mut self, death: &Death) -> &mut u32 {
109 let pop = TrackedPopulation::from_body_and_role(&death.body, &death.role);
110 &mut self.populations[pop]
111 }
112
113 pub fn on_death(&mut self, death: &Death) {
114 let n = self.of_death_mut(death);
115
116 *n = n.saturating_sub(1);
117 }
118
119 pub fn on_spawn(&mut self, death: &Death) {
120 let n = self.of_death_mut(death);
121
122 *n = n.saturating_add(1);
123 }
124
125 pub fn add(&mut self, pop: TrackedPopulation, amount: u32) { self.populations[pop] += amount; }
126}
127
128#[derive(Default, Clone, Serialize, Deserialize)]
136pub struct Architect {
137 pub deaths: VecDeque<Death>,
138
139 #[serde(skip)]
141 pub population: Population,
142 #[serde(skip)]
145 pub wanted_population: Population,
146}
147
148impl Architect {
149 pub fn on_death(&mut self, npc: &Npc, time: TimeOfDay) {
150 let death = Death {
151 time,
152 body: npc.body,
153 role: npc.role.clone(),
154 faction: npc.faction,
155 };
156 self.deaths.push_back(death)
157 }
158}