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 = base.get_string("key")?;
281 let inner = TitleData::new(key.clone(), base, game_state)?;
282 Ok(match key.as_ref().chars().next().unwrap() {
283 'e' => Self::Empire(inner),
284 'k' => Self::Kingdom(inner),
285 'd' => Self::Duchy(inner),
286 'c' => Self::County {
287 data: inner,
288 culture: None,
289 faith: None,
290 },
291 'b' => Self::Barony(inner),
292 _ => Self::Other(inner),
293 })
294 }
295
296 fn finalize(&mut self, reference: &GameRef<Title>) {
297 if let Some(de_jure) = &self.de_jure {
298 if let Some(de_jure) = de_jure.get_internal_mut().inner_mut() {
299 de_jure.add_jure_vassal(reference.clone());
300 }
301 }
302 if let Some(de_facto) = &self.de_facto {
303 if let Some(de_facto) = de_facto.get_internal_mut().inner_mut() {
304 de_facto.add_facto_vassal(reference.clone());
305 }
306 }
307 }
308}
309
310impl GameObjectDerived for Title {
311 fn get_name(&self) -> GameString {
312 self.name.clone()
313 }
314
315 fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
316 if let Some(de_jure) = &self.de_jure {
317 collection.extend([E::from(de_jure.clone().into())]);
318 }
319 if let Some(de_facto) = &self.de_facto {
320 collection.extend([E::from(de_facto.clone().into())]);
321 }
322 for v in &self.de_jure_vassals {
323 collection.extend([E::from(v.clone().into())]);
324 }
325 for v in &self.de_facto_vassals {
326 collection.extend([E::from(v.clone().into())]);
327 }
328 for c in &self.claims {
329 collection.extend([E::from(c.clone().into())]);
330 }
331 if let Some(capital) = &self.capital {
332 collection.extend([E::from(capital.clone().into())]);
333 }
334 }
335}
336
337impl TreeNode<Vec<GameRef<Title>>> for Title {
338 fn get_children(&self) -> Option<Vec<GameRef<Title>>> {
339 if self.de_jure_vassals.is_empty() {
340 return None;
341 }
342 Some(self.de_jure_vassals.clone())
343 }
344
345 fn get_class(&self) -> Option<GameString> {
346 if let Some(tp) = self.get_type() {
347 return Some(tp.into());
348 }
349 None
350 }
351
352 fn get_parent(&self) -> Option<Vec<GameRef<Title>>> {
353 if let Some(de_jure) = &self.de_jure {
354 return Some(vec![de_jure.clone()]);
355 }
356 None
357 }
358}
359
360impl ProceduralPath for Title {
361 fn get_subdir() -> &'static str {
362 "titles"
363 }
364}
365
366impl Renderable for GameObjectEntity<Title> {
367 fn get_template() -> &'static str {
368 TITLE_TEMPLATE_NAME
369 }
370
371 fn render(&self, path: &Path, game_state: &GameState, _: Option<&Grapher>, data: &GameData) {
372 if let Some(map) = data.get_map() {
373 if let Some(title) = self.inner() {
374 if title.de_facto_vassals.len() == 0 {
375 return;
376 }
377 let mut buf = path.join(Title::get_subdir());
378 buf.push(self.id.to_string() + ".png");
379 let mut title_map = map.create_map_flat(title.get_barony_keys(), title.color);
380 title_map.draw_text(format!(
381 "{} at {}",
382 title.name,
383 game_state.get_current_date().unwrap().iso_8601()
384 ));
385 title_map.save_in_thread(&buf);
386 }
387 }
388 }
389}
390
391impl Localizable for Title {
392 fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
393 if self.name == self.key {
394 self.name = localization.localize(&self.key)?;
395 }
396 Ok(())
400 }
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406
407 #[test]
408 fn test_serialize_title_barony() {
409 let title = Title::Barony(TitleData {
410 key: "b_test".into(),
411 name: "Test".into(),
412 de_jure: None,
413 de_facto: None,
414 de_jure_vassals: Vec::new(),
415 de_facto_vassals: Vec::new(),
416 history: Vec::new(),
417 claims: Vec::new(),
418 capital: None,
419 color: [70, 255, 70],
420 });
421 let serialized = serde_json::to_string(&title).unwrap();
422 assert_eq!(
423 serialized,
424 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]}"#
425 );
426 }
427
428 #[test]
429 fn test_serialize_county() {
430 let title = Title::County {
431 data: TitleData {
432 key: "c_test".into(),
433 name: "Test".into(),
434 de_jure: None,
435 de_facto: None,
436 de_jure_vassals: Vec::new(),
437 de_facto_vassals: Vec::new(),
438 history: Vec::new(),
439 claims: Vec::new(),
440 capital: None,
441 color: [70, 255, 70],
442 },
443 culture: None,
444 faith: None,
445 };
446 let serialized = serde_json::to_string(&title).unwrap();
447 assert_eq!(
448 serialized,
449 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}"#
450 );
451 }
452}