1pub mod stability;
5
6use crate::city::stability::Stability;
7use crate::continent::coord::Coord;
8use crate::error::Result;
9use crate::infrastructure::Infrastructure;
10use crate::infrastructure::building::StorageId;
11use crate::infrastructure::stats::InfrastructureStats;
12use crate::infrastructure::storage::OverallStorageCapacity;
13use crate::npc::bot::BotId;
14use crate::npc::precursor::PrecursorId;
15use crate::player::PlayerId;
16use crate::ranking::score::Score;
17use crate::resources::Resources;
18use crate::resources::maintenance::Maintenance;
19use crate::ruler::Ruler;
20use bon::Builder;
21use derive_more::{Deref, DerefMut, From};
22use serde::{Deserialize, Serialize};
23use std::sync::Arc;
24
25#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
26#[serde(rename_all = "camelCase")]
27#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
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()
87 }
88
89 pub fn is_owned_by<R>(&self, ruler: R) -> bool
90 where
91 R: Into<Ruler>,
92 {
93 let ruler: Ruler = ruler.into();
94 self.owner == ruler
95 }
96
97 #[inline]
99 pub fn is_owned_by_player(&self) -> bool {
100 self.owner.player().is_some()
101 }
102
103 pub fn is_owned_by_player_and<F>(&self, f: F) -> bool
104 where
105 F: FnOnce(&PlayerId) -> bool,
106 {
107 self.owner.player().is_some_and(f)
108 }
109
110 #[inline]
112 pub fn is_owned_by_bot(&self) -> bool {
113 self.owner.bot().is_some()
114 }
115
116 pub fn is_owned_by_bot_and<F>(&self, f: F) -> bool
117 where
118 F: FnOnce(&BotId) -> bool,
119 {
120 self.owner.bot().is_some_and(f)
121 }
122
123 #[inline]
125 pub fn is_owned_by_precursor(&self) -> bool {
126 self.owner.precursor().is_some()
127 }
128
129 pub fn is_owned_by_precursor_and<F>(&self, f: F) -> bool
130 where
131 F: FnOnce(PrecursorId) -> bool,
132 {
133 self.owner.precursor().is_some_and(f)
134 }
135
136 #[inline]
137 pub fn score(&self, stats: &InfrastructureStats) -> Result<Score> {
138 self.infrastructure.score(stats)
139 }
140
141 pub fn round_production(&self, stats: &InfrastructureStats) -> Result<Resources> {
144 let mut resources = self
145 .infrastructure
146 .round_base_production(stats)?;
147
148 resources.food *= self.stability;
149 resources.iron *= self.stability;
150 resources.stone *= self.stability;
151 resources.wood *= self.stability;
152
153 Ok(resources)
154 }
155
156 pub fn maintenance(&self, stats: &InfrastructureStats) -> Result<Maintenance> {
158 self.infrastructure.base_maintenance(stats)
159 }
160
161 pub fn storage_capacity(&self, stats: &InfrastructureStats) -> Result<OverallStorageCapacity> {
162 let silo_stats = stats.storage(StorageId::Silo)?;
163 let warehouse_stats = stats.storage(StorageId::Warehouse)?;
164
165 Ok(OverallStorageCapacity {
166 silo: self
167 .infrastructure
168 .storage(StorageId::Silo)
169 .capacity(silo_stats)?,
170 warehouse: self
171 .infrastructure
172 .storage(StorageId::Warehouse)
173 .capacity(warehouse_stats)?,
174 })
175 }
176}
177
178impl From<&City> for Ruler {
179 fn from(city: &City) -> Self {
180 city.owner.clone()
181 }
182}
183
184#[derive(Clone, Debug, Deref, DerefMut, From, Deserialize, Serialize)]
185#[from(String, &str)]
186#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
187pub struct CityName(String);
188
189impl CityName {
190 pub fn new(name: impl AsRef<str>) -> Self {
191 Self(name.as_ref().to_owned())
192 }
193}
194
195#[derive(Clone, Debug, Deserialize, Serialize)]
197#[serde(rename_all = "camelCase")]
198#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
199pub struct PublicCity {
200 coord: Coord,
201 name: Arc<str>,
202 owner: Ruler,
203}
204
205impl From<&City> for PublicCity {
206 fn from(city: &City) -> Self {
207 Self {
208 coord: city.coord,
209 name: Arc::from(city.name.as_str()),
210 owner: city.owner.clone(),
211 }
212 }
213}
214
215#[derive(Builder, Clone, Debug, Default, Deserialize, Serialize)]
216#[serde(default, rename_all = "camelCase")]
217#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
218#[cfg_attr(feature = "typescript", ts(optional_fields))]
219pub struct CitySearch {
220 #[builder(default, with = FromIterator::from_iter)]
221 #[cfg_attr(feature = "typescript", ts(as = "Option<Vec<Coord>>"))]
222 pub coord: Vec<Coord>,
223
224 #[builder(default, with = FromIterator::from_iter)]
225 #[cfg_attr(feature = "typescript", ts(as = "Option<Vec<CityName>>"))]
226 pub name: Vec<CityName>,
227}
228
229impl From<Coord> for CitySearch {
230 fn from(coord: Coord) -> Self {
231 Self::from_iter([coord])
232 }
233}
234
235impl From<CityName> for CitySearch {
236 fn from(name: CityName) -> Self {
237 Self::from_iter([name])
238 }
239}
240
241impl FromIterator<Coord> for CitySearch {
242 fn from_iter<T>(iter: T) -> Self
243 where
244 T: IntoIterator<Item = Coord>,
245 {
246 Self::builder().coord(iter).build()
247 }
248}
249
250impl FromIterator<CityName> for CitySearch {
251 fn from_iter<T>(iter: T) -> Self
252 where
253 T: IntoIterator<Item = CityName>,
254 {
255 Self::builder().name(iter).build()
256 }
257}