1use std::{
2 ops::{Deref, DerefMut},
3 path::Path,
4 slice::Iter,
5 str::FromStr,
6};
7
8use jomini::common::{Date, PdsDate};
9use serde::Serialize;
10
11use super::{
12 super::{
13 display::{Grapher, ProceduralPath, Renderable, TreeNode},
14 game_data::{GameData, Localizable, LocalizationError, Localize, MapGenerator, MapImage},
15 jinja_env::TITLE_TEMPLATE_NAME,
16 parser::{
17 GameObjectMap, GameObjectMapping, GameState, ParsingError, SaveFileObject,
18 SaveFileValue,
19 },
20 types::{GameString, Wrapper, WrapperMut},
21 },
22 Character, Culture, EntityRef, Faith, FromGameObject, GameObjectDerived, GameObjectEntity,
23 GameRef,
24};
25
26#[derive(Serialize)]
27pub struct TitleData {
28 key: GameString,
29 name: GameString,
30 de_jure: Option<GameRef<Title>>,
31 de_facto: Option<GameRef<Title>>,
32 de_jure_vassals: Vec<GameRef<Title>>,
33 de_facto_vassals: Vec<GameRef<Title>>,
34 history: Vec<(Date, Option<GameRef<Character>>, GameString)>,
35 claims: Vec<GameRef<Character>>,
36 capital: Option<GameRef<Title>>,
37 color: [u8; 3],
38}
39
40impl TitleData {
41 fn new(
42 key: GameString,
43 base: &GameObjectMap,
44 game_state: &mut GameState,
45 ) -> Result<Self, ParsingError> {
46 let mut title = Self {
47 key: key,
48 name: base.get_string("name")?,
49 color: base
50 .get("color")
51 .map(|v| v.as_object().and_then(|obj| obj.as_array()))
52 .transpose()?
53 .map_or([70, 255, 70], |color_obj| {
54 [
55 color_obj[0].as_integer().unwrap() as u8,
56 color_obj[1].as_integer().unwrap() as u8,
57 color_obj[2].as_integer().unwrap() as u8,
58 ]
59 }),
60 de_jure: base
61 .get("de_jure_liege")
62 .map(|liege| {
63 liege
64 .as_id()
65 .and_then(|liege_id| Ok(game_state.get_title(&liege_id)))
66 })
67 .transpose()?,
68 de_facto: base
69 .get("de_facto_liege")
70 .map(|liege| {
71 liege
72 .as_id()
73 .and_then(|liege_id| Ok(game_state.get_title(&liege_id).clone()))
74 })
75 .transpose()?,
76 de_jure_vassals: Vec::default(),
77 de_facto_vassals: Vec::default(),
78 history: Vec::default(),
79 claims: Vec::default(),
80 capital: base
81 .get("capital")
82 .map(|capital| capital.as_id().and_then(|id| Ok(game_state.get_title(&id))))
83 .transpose()?,
84 };
85 if let Some(claims) = base.get("claim") {
86 if let SaveFileValue::Object(claims) = claims {
87 for claim in claims.as_array()? {
88 title
89 .claims
90 .push(game_state.get_character(&claim.as_id()?).clone());
91 }
92 } else {
93 title
94 .claims
95 .push(game_state.get_character(&claims.as_id()?).clone());
96 }
97 }
98
99 if let Some(hist) = base.get("history") {
100 for (h, val) in hist.as_object()?.as_map()? {
101 let character;
102 let action: GameString;
103 if let SaveFileValue::Object(o) = val {
104 match o {
105 SaveFileObject::Array(arr) => {
106 for entry in arr {
107 let loc_action;
108 let loc_character;
109 if let SaveFileValue::Object(o) = entry {
110 let o = o.as_map()?;
111 loc_action = o.get_string("type")?;
112 if let Some(holder) = o.get("holder") {
113 loc_character = Some(
114 game_state.get_character(&holder.as_id()?).clone(),
115 );
116 } else {
117 loc_character = None;
118 }
119 } else {
120 loc_action = GameString::from("Inherited");
121 loc_character =
122 Some(game_state.get_character(&entry.as_id()?).clone());
123 }
124 title
125 .history
126 .push((Date::from_str(h)?, loc_character, loc_action))
127 }
128 continue; }
130 SaveFileObject::Map(o) => {
131 action = o.get_string("type")?;
132 match o.get("holder") {
133 Some(h) => {
134 character = Some(game_state.get_character(&h.as_id()?).clone());
135 }
136 None => {
137 character = None;
138 }
139 }
140 }
141 }
142 } else {
143 action = GameString::from("Inherited");
144 character = Some(game_state.get_character(&val.as_id()?).clone());
145 }
146 title.history.push((Date::from_str(h)?, character, action));
147 }
148 }
149 title.history.sort_by(|a, b| a.0.cmp(&b.0));
151 Ok(title)
152 }
153}
154
155#[derive(Serialize)]
156#[serde(tag = "tier")]
157pub enum Title {
158 Empire(TitleData),
159 Kingdom(TitleData),
160 Duchy(TitleData),
161 County {
162 #[serde(flatten)]
163 data: TitleData,
164 culture: Option<GameRef<Culture>>,
165 faith: Option<GameRef<Faith>>,
166 },
167 Barony(TitleData),
168 Other(TitleData),
169}
170
171impl Deref for Title {
172 type Target = TitleData;
173
174 fn deref(&self) -> &Self::Target {
175 match self {
176 Title::Empire(data) => data,
177 Title::Kingdom(data) => data,
178 Title::Duchy(data) => data,
179 Title::County { data, .. } => data,
180 Title::Barony(data) => data,
181 Title::Other(data) => data,
182 }
183 }
184}
185
186impl DerefMut for Title {
187 fn deref_mut(&mut self) -> &mut Self::Target {
188 match self {
189 Title::Empire(data) => data,
190 Title::Kingdom(data) => data,
191 Title::Duchy(data) => data,
192 Title::County { data, .. } => data,
193 Title::Barony(data) => data,
194 Title::Other(data) => data,
195 }
196 }
197}
198
199impl Title {
200 pub fn add_jure_vassal(&mut self, vassal: GameRef<Title>) {
202 self.de_jure_vassals.push(vassal);
203 }
204
205 pub fn add_facto_vassal(&mut self, vassal: GameRef<Title>) {
207 self.de_facto_vassals.push(vassal);
208 }
209
210 pub fn get_barony_keys(&self) -> Vec<GameString> {
212 if let Title::Barony(_) = self {
213 return vec![self.key.clone()];
214 } else {
215 let mut provinces = Vec::new();
216 for v in &self.de_facto_vassals {
217 if let Some(v) = v.get_internal().inner() {
218 provinces.append(&mut v.get_barony_keys());
219 }
220 }
221 return provinces;
222 }
223 }
224
225 pub fn get_de_jure_barony_keys(&self) -> Vec<GameString> {
226 if let Title::Barony(_) = self {
227 return vec![self.key.clone()];
228 } else {
229 let mut provinces = Vec::new();
230 for v in &self.de_facto_vassals {
231 if let Some(v) = v.get_internal().inner() {
232 provinces.append(&mut v.get_de_jure_barony_keys());
233 }
234 }
235 return provinces;
236 }
237 }
238
239 pub fn get_key(&self) -> GameString {
241 self.key.clone()
242 }
243
244 pub fn get_history_iter(&self) -> Iter<(Date, Option<GameRef<Character>>, GameString)> {
246 self.history.iter()
247 }
248
249 pub fn get_capital(&self) -> Option<GameRef<Title>> {
251 self.capital.clone()
252 }
253
254 pub fn get_holder(&self) -> Option<GameRef<Character>> {
256 if let Some(entry) = self.history.last() {
257 return entry.1.clone();
258 }
259 None
260 }
261
262 pub fn get_type(&self) -> Option<&'static str> {
264 match self {
265 Title::Empire(_) => Some("Empire"),
266 Title::Kingdom(_) => Some("Kingdom"),
267 Title::Duchy(_) => Some("Duchy"),
268 Title::County { .. } => Some("County"),
269 Title::Barony(_) => Some("Barony"),
270 Title::Other(_) => None,
271 }
272 }
273}
274
275impl FromGameObject for Title {
276 fn from_game_object(
277 base: &GameObjectMap,
278 game_state: &mut GameState,
279 ) -> Result<Self, ParsingError> {
280 let key = if let Some(key) = base.get("key") {
281 key.as_string()?
282 } else {
283 base.get_string("name")?
284 };
285 let inner = TitleData::new(key.clone(), base, game_state)?;
286 Ok(match key.as_ref().chars().next().unwrap() {
287 'e' => Self::Empire(inner),
288 'k' => Self::Kingdom(inner),
289 'd' => Self::Duchy(inner),
290 'c' => Self::County {
291 data: inner,
292 culture: None,
293 faith: None,
294 },
295 'b' => Self::Barony(inner),
296 _ => Self::Other(inner),
297 })
298 }
299
300 fn finalize(&mut self, reference: &GameRef<Title>) {
301 if let Some(de_jure) = &self.de_jure {
302 if let Some(de_jure) = de_jure.get_internal_mut().inner_mut() {
303 de_jure.add_jure_vassal(reference.clone());
304 }
305 }
306 if let Some(de_facto) = &self.de_facto {
307 if let Some(de_facto) = de_facto.get_internal_mut().inner_mut() {
308 de_facto.add_facto_vassal(reference.clone());
309 }
310 }
311 }
312}
313
314impl GameObjectDerived for Title {
315 fn get_name(&self) -> GameString {
316 self.name.clone()
317 }
318
319 fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
320 if let Some(de_jure) = &self.de_jure {
321 collection.extend([E::from(de_jure.clone().into())]);
322 }
323 if let Some(de_facto) = &self.de_facto {
324 collection.extend([E::from(de_facto.clone().into())]);
325 }
326 for v in &self.de_jure_vassals {
327 collection.extend([E::from(v.clone().into())]);
328 }
329 for v in &self.de_facto_vassals {
330 collection.extend([E::from(v.clone().into())]);
331 }
332 for c in &self.claims {
333 collection.extend([E::from(c.clone().into())]);
334 }
335 if let Some(capital) = &self.capital {
336 collection.extend([E::from(capital.clone().into())]);
337 }
338 }
339}
340
341impl TreeNode<Vec<GameRef<Title>>> for Title {
342 fn get_children(&self) -> Option<Vec<GameRef<Title>>> {
343 if self.de_jure_vassals.is_empty() {
344 return None;
345 }
346 Some(self.de_jure_vassals.clone())
347 }
348
349 fn get_class(&self) -> Option<GameString> {
350 if let Some(tp) = self.get_type() {
351 return Some(tp.into());
352 }
353 None
354 }
355
356 fn get_parent(&self) -> Option<Vec<GameRef<Title>>> {
357 if let Some(de_jure) = &self.de_jure {
358 return Some(vec![de_jure.clone()]);
359 }
360 None
361 }
362}
363
364impl ProceduralPath for Title {
365 fn get_subdir() -> &'static str {
366 "titles"
367 }
368}
369
370impl Renderable for GameObjectEntity<Title> {
371 fn get_template() -> &'static str {
372 TITLE_TEMPLATE_NAME
373 }
374
375 fn render(&self, path: &Path, game_state: &GameState, _: Option<&Grapher>, data: &GameData) {
376 if let Some(map) = data.get_map() {
377 if let Some(title) = self.inner() {
378 if title.de_facto_vassals.len() == 0 {
379 return;
380 }
381 let mut buf = path.join(Title::get_subdir());
382 buf.push(self.id.to_string() + ".png");
383 let mut title_map = map.create_map_flat(title.get_barony_keys(), title.color);
384 title_map.draw_text(format!(
385 "{} at {}",
386 title.name,
387 game_state.get_current_date().unwrap().iso_8601()
388 ));
389 title_map.save_in_thread(&buf);
390 }
391 }
392 }
393}
394
395impl Localizable for Title {
396 fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
397 if self.name == self.key {
398 self.name = localization.localize(&self.key)?;
399 }
400 Ok(())
404 }
405}
406
407#[cfg(test)]
408mod tests {
409 use super::*;
410
411 #[test]
412 fn test_serialize_title_barony() {
413 let title = Title::Barony(TitleData {
414 key: "b_test".into(),
415 name: "Test".into(),
416 de_jure: None,
417 de_facto: None,
418 de_jure_vassals: Vec::new(),
419 de_facto_vassals: Vec::new(),
420 history: Vec::new(),
421 claims: Vec::new(),
422 capital: None,
423 color: [70, 255, 70],
424 });
425 let serialized = serde_json::to_string(&title).unwrap();
426 assert_eq!(
427 serialized,
428 r#"{"tier":"Barony","key":"b_test","name":"Test","de_jure":null,"de_facto":null,"de_jure_vassals":[],"de_facto_vassals":[],"history":[],"claims":[],"capital":null,"color":[70,255,70]}"#
429 );
430 }
431
432 #[test]
433 fn test_serialize_county() {
434 let title = Title::County {
435 data: TitleData {
436 key: "c_test".into(),
437 name: "Test".into(),
438 de_jure: None,
439 de_facto: None,
440 de_jure_vassals: Vec::new(),
441 de_facto_vassals: Vec::new(),
442 history: Vec::new(),
443 claims: Vec::new(),
444 capital: None,
445 color: [70, 255, 70],
446 },
447 culture: None,
448 faith: None,
449 };
450 let serialized = serde_json::to_string(&title).unwrap();
451 assert_eq!(
452 serialized,
453 r#"{"tier":"County","key":"c_test","name":"Test","de_jure":null,"de_facto":null,"de_jure_vassals":[],"de_facto_vassals":[],"history":[],"claims":[],"capital":null,"color":[70,255,70],"culture":null,"faith":null}"#
454 );
455 }
456}