1mod stability;
5
6use crate::continent::Coord;
7use crate::error::Result;
8use crate::infrastructure::Infrastructure;
9use crate::infrastructure::building::StorageId;
10use crate::infrastructure::stats::InfrastructureStats;
11use crate::infrastructure::storage::OverallStorageCapacity;
12use crate::npc::bot::BotId;
13use crate::npc::precursor::PrecursorId;
14use crate::player::PlayerId;
15use crate::ranking::score::Score;
16use crate::resources::Resources;
17use crate::resources::maintenance::Maintenance;
18use crate::ruler::Ruler;
19use bon::Builder;
20use derive_more::{Deref, DerefMut, From};
21use serde::{Deserialize, Serialize};
22use std::sync::Arc;
23
24pub use stability::Stability;
25
26#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
27#[serde(rename_all = "camelCase")]
28pub struct City {
29 #[builder(start_fn, into)]
30 coord: Coord,
31
32 #[builder(into)]
33 name: CityName,
34
35 #[builder(into)]
36 owner: Ruler,
37
38 #[builder(default)]
39 infrastructure: Infrastructure,
40
41 #[builder(default)]
42 stability: Stability,
43}
44
45impl City {
46 #[inline]
47 pub fn coord(&self) -> Coord {
48 self.coord
49 }
50
51 #[inline]
52 pub fn name(&self) -> &CityName {
53 &self.name
54 }
55
56 pub(crate) fn name_mut(&mut self) -> &mut CityName {
57 &mut self.name
58 }
59
60 #[inline]
61 pub fn owner(&self) -> &Ruler {
62 &self.owner
63 }
64
65 #[inline]
66 pub fn infrastructure(&self) -> &Infrastructure {
67 &self.infrastructure
68 }
69
70 #[inline]
71 pub fn infrastructure_mut(&mut self) -> &mut Infrastructure {
72 &mut self.infrastructure
73 }
74
75 #[inline]
76 pub fn stability(&self) -> Stability {
77 self.stability
78 }
79
80 pub(crate) fn stability_mut(&mut self) -> &mut Stability {
81 &mut self.stability
82 }
83
84 #[inline]
85 pub fn player(&self) -> Option<PlayerId> {
86 self.owner().player().cloned()
87 }
88
89 #[inline]
91 pub fn is_owned_by_player(&self) -> bool {
92 self.owner.player().is_some()
93 }
94
95 pub fn is_owned_by_player_and<F>(&self, f: F) -> bool
96 where
97 F: FnOnce(&PlayerId) -> bool,
98 {
99 self.owner.player().is_some_and(f)
100 }
101
102 #[inline]
104 pub fn is_owned_by_bot(&self) -> bool {
105 self.owner.bot().is_some()
106 }
107
108 pub fn is_owned_by_bot_and<F>(&self, f: F) -> bool
109 where
110 F: FnOnce(&BotId) -> bool,
111 {
112 self.owner.bot().is_some_and(f)
113 }
114
115 #[inline]
117 pub fn is_owned_by_precursor(&self) -> bool {
118 self.owner.precursor().is_some()
119 }
120
121 pub fn is_owned_by_precursor_and<F>(&self, f: F) -> bool
122 where
123 F: FnOnce(PrecursorId) -> bool,
124 {
125 self.owner.precursor().is_some_and(f)
126 }
127
128 #[inline]
129 pub fn score(&self, stats: &InfrastructureStats) -> Result<Score> {
130 self.infrastructure.score(stats)
131 }
132
133 pub fn round_production(&self, stats: &InfrastructureStats) -> Result<Resources> {
136 let mut resources = self
137 .infrastructure
138 .round_base_production(stats)?;
139
140 resources.food *= self.stability;
141 resources.iron *= self.stability;
142 resources.stone *= self.stability;
143 resources.wood *= self.stability;
144
145 Ok(resources)
146 }
147
148 pub fn maintenance(&self, stats: &InfrastructureStats) -> Result<Maintenance> {
150 self.infrastructure.base_maintenance(stats)
151 }
152
153 pub fn storage_capacity(&self, stats: &InfrastructureStats) -> Result<OverallStorageCapacity> {
154 let silo_stats = stats.storage(StorageId::Silo)?;
155 let warehouse_stats = stats.storage(StorageId::Warehouse)?;
156
157 Ok(OverallStorageCapacity {
158 silo: self
159 .infrastructure
160 .storage(StorageId::Silo)
161 .capacity(silo_stats)?,
162 warehouse: self
163 .infrastructure
164 .storage(StorageId::Warehouse)
165 .capacity(warehouse_stats)?,
166 })
167 }
168}
169
170impl From<&City> for Ruler {
171 fn from(city: &City) -> Self {
172 city.owner.clone()
173 }
174}
175
176#[derive(Clone, Debug, Deref, DerefMut, From, Deserialize, Serialize)]
177#[from(String, &str)]
178pub struct CityName(String);
179
180impl CityName {
181 pub fn new(name: impl AsRef<str>) -> Self {
182 Self(name.as_ref().to_owned())
183 }
184}
185
186#[derive(Clone, Debug, Deserialize, Serialize)]
188#[serde(rename_all = "camelCase")]
189pub struct PublicCity {
190 coord: Coord,
191 name: Arc<str>,
192 owner: Ruler,
193}
194
195impl From<&City> for PublicCity {
196 fn from(city: &City) -> Self {
197 Self {
198 coord: city.coord,
199 name: Arc::from(city.name.as_str()),
200 owner: city.owner.clone(),
201 }
202 }
203}
204
205#[derive(Builder, Clone, Debug, Default, Deserialize, Serialize)]
206#[serde(default, rename_all = "camelCase")]
207pub struct CitySearch {
208 #[builder(default, with = FromIterator::from_iter)]
209 pub coord: Vec<Coord>,
210 #[builder(default, with = FromIterator::from_iter)]
211 pub name: Vec<CityName>,
212}
213
214impl From<Coord> for CitySearch {
215 fn from(coord: Coord) -> Self {
216 Self::from_iter([coord])
217 }
218}
219
220impl From<CityName> for CitySearch {
221 fn from(name: CityName) -> Self {
222 Self::from_iter([name])
223 }
224}
225
226impl FromIterator<Coord> for CitySearch {
227 fn from_iter<T>(iter: T) -> Self
228 where
229 T: IntoIterator<Item = Coord>,
230 {
231 Self::builder().coord(iter).build()
232 }
233}
234
235impl FromIterator<CityName> for CitySearch {
236 fn from_iter<T>(iter: T) -> Self
237 where
238 T: IntoIterator<Item = CityName>,
239 {
240 Self::builder().name(iter).build()
241 }
242}