ck3_history_extractor/structures/
culture.rs

1use std::path::Path;
2
3use jomini::common::Date;
4use serde::Serialize;
5
6use super::{
7    super::{
8        display::{Grapher, ProceduralPath, Renderable, TreeNode},
9        game_data::{GameData, Localizable, LocalizationError, Localize, MapGenerator, MapImage},
10        jinja_env::CUL_TEMPLATE_NAME,
11        parser::{GameObjectMap, GameObjectMapping, GameState, ParsingError},
12        types::{GameString, Wrapper, WrapperMut},
13    },
14    EntityRef, FromGameObject, GameObjectDerived, GameObjectEntity, GameRef, Title,
15};
16
17/// A struct representing a culture in the game
18#[derive(Serialize)]
19pub struct Culture {
20    name: GameString,
21    ethos: Option<GameString>,
22    heritage: GameString,
23    martial: GameString,
24    date: Option<Date>,
25    children: Vec<GameRef<Culture>>,
26    parents: Vec<GameRef<Culture>>,
27    traditions: Vec<GameString>,
28    language: GameString,
29    eras: Vec<(GameString, Option<u16>, Option<u16>)>,
30    // TODO innovations
31}
32
33impl FromGameObject for Culture {
34    fn from_game_object(
35        base: &GameObjectMap,
36        game_state: &mut GameState,
37    ) -> Result<Self, ParsingError> {
38        let mut culture = Self {
39            name: base.get_string("name")?,
40            //this is possible, shoutout u/Kinc4id
41            ethos: base.get("ethos").map(|n| n.as_string()).transpose()?,
42            heritage: base.get_string("heritage")?,
43            martial: base.get_string("martial_custom")?,
44            date: base.get("created").map(|n| n.as_date()).transpose()?,
45            language: base.get_string("language")?,
46            traditions: base
47                .get("traditions")
48                .map(|n| n.as_object().and_then(|obj| obj.as_array()))
49                .transpose()?
50                .map_or(Vec::new(), |n| {
51                    n.iter().filter_map(|t| t.as_string().ok()).collect()
52                }),
53            children: Vec::new(),
54            parents: Vec::new(),
55            eras: Vec::with_capacity(4),
56        };
57        if let Some(parents_obj) = base.get("parents") {
58            for p in parents_obj.as_object()?.as_array()? {
59                culture.parents.push(game_state.get_culture(&p.as_id()?));
60            }
61        }
62        if let Some(era_data) = base.get("culture_era_data") {
63            for era in era_data.as_object()?.as_array()? {
64                let obj = era.as_object()?.as_map()?;
65                culture.eras.push((
66                    obj.get_string("type")?,
67                    obj.get("join")
68                        .and_then(|n| n.as_integer().ok().and_then(|n| Some(n as u16))),
69                    obj.get("left")
70                        .and_then(|n| n.as_integer().ok().and_then(|n| Some(n as u16))),
71                ));
72            }
73        }
74        return Ok(culture);
75    }
76
77    fn finalize(&mut self, reference: &GameRef<Culture>) {
78        for p in &self.parents {
79            if let Ok(mut r) = p.try_get_internal_mut() {
80                if let Some(parent) = r.inner_mut() {
81                    parent.register_child(reference.clone());
82                }
83            }
84        }
85    }
86}
87
88impl GameObjectDerived for Culture {
89    fn get_name(&self) -> GameString {
90        self.name.clone()
91    }
92
93    fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
94        for p in &self.parents {
95            collection.extend([E::from(p.clone().into())]);
96        }
97        for c in &self.children {
98            collection.extend([E::from(c.clone().into())]);
99        }
100    }
101}
102
103impl TreeNode<Vec<GameRef<Culture>>> for Culture {
104    fn get_children(&self) -> Option<Vec<GameRef<Culture>>> {
105        if self.children.is_empty() {
106            return None;
107        }
108        Some(self.children.clone())
109    }
110
111    fn get_parent(&self) -> Option<Vec<GameRef<Culture>>> {
112        if self.parents.is_empty() {
113            return None;
114        }
115        Some(self.parents.clone())
116    }
117
118    fn get_class(&self) -> Option<GameString> {
119        Some(self.heritage.clone())
120    }
121}
122
123impl Culture {
124    pub fn register_child(&mut self, child: GameRef<Culture>) {
125        self.children.push(child);
126    }
127}
128
129impl ProceduralPath for Culture {
130    fn get_subdir() -> &'static str {
131        "cultures"
132    }
133}
134
135impl Renderable for GameObjectEntity<Culture> {
136    fn get_template() -> &'static str {
137        CUL_TEMPLATE_NAME
138    }
139
140    fn render(
141        &self,
142        path: &Path,
143        game_state: &GameState,
144        grapher: Option<&Grapher>,
145        data: &GameData,
146    ) {
147        if let Some(grapher) = grapher {
148            let mut path = path.join(Culture::get_subdir());
149            path.push(self.id.to_string() + ".svg");
150            grapher.create_culture_graph(self.id, &path);
151        }
152        if let Some(map) = data.get_map() {
153            let filter = |title: &Title| {
154                if let Title::County { culture, .. } = title {
155                    if let Some(culture) = culture {
156                        return culture.get_internal().id == self.id;
157                    }
158                }
159                return false;
160            };
161            let keys = game_state.get_baronies_of_counties(filter);
162            if !keys.is_empty() {
163                let mut path = path.join(Culture::get_subdir());
164                path.push(self.id.to_string() + ".png");
165                let mut culture_map = map.create_map_flat(keys, [70, 255, 70]);
166                if let Some(inner) = self.inner() {
167                    culture_map.draw_text(format!("Map of the {} culture", &inner.name));
168                }
169                culture_map.save_in_thread(&path);
170            }
171        }
172    }
173}
174
175impl Localizable for Culture {
176    fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
177        self.name = localization.localize(&self.name)?;
178        if let Some(eth) = &self.ethos {
179            self.ethos = Some(localization.localize(eth.to_string() + "_name")?);
180        }
181        self.heritage = localization.localize(self.heritage.to_string() + "_name")?;
182        self.martial = localization.localize(self.martial.to_string() + "_name")?;
183        self.language = localization.localize(self.language.to_string() + "_name")?;
184        for t in &mut self.traditions {
185            *t = localization.localize(t.to_string() + "_name")?;
186        }
187        for (era, _, _) in &mut self.eras {
188            *era = localization.localize(era.to_string())?;
189        }
190        Ok(())
191    }
192}