ck3_history_extractor/structures/
culture.rs1use 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#[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: Option<GameString>,
29 eras: Vec<(GameString, Option<u16>, Option<u16>)>,
30 }
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 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: None,
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(language) = base.get("language") {
58 culture.language = Some(language.as_string()?);
59 }
60
61 if let Some(parents_obj) = base.get("parents") {
62 for p in parents_obj.as_object()?.as_array()? {
63 culture.parents.push(game_state.get_culture(&p.as_id()?));
64 }
65 }
66 if let Some(era_data) = base.get("culture_era_data") {
67 for era in era_data.as_object()?.as_array()? {
68 let obj = era.as_object()?.as_map()?;
69 culture.eras.push((
70 obj.get_string("type")?,
71 obj.get("join")
72 .and_then(|n| n.as_integer().ok().and_then(|n| Some(n as u16))),
73 obj.get("left")
74 .and_then(|n| n.as_integer().ok().and_then(|n| Some(n as u16))),
75 ));
76 }
77 }
78 return Ok(culture);
79 }
80
81 fn finalize(&mut self, reference: &GameRef<Culture>) {
82 for p in &self.parents {
83 if let Ok(mut r) = p.try_get_internal_mut() {
84 if let Some(parent) = r.inner_mut() {
85 parent.register_child(reference.clone());
86 }
87 }
88 }
89
90 if self.language.is_none() {
91 for p in &self.parents {
92 if let Some(lang) = p.get_internal().inner().unwrap().get_language() {
93 self.language = Some(lang);
94 break;
95 }
96 }
97 }
98 }
99}
100
101impl GameObjectDerived for Culture {
102 fn get_name(&self) -> GameString {
103 self.name.clone()
104 }
105
106 fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
107 for p in &self.parents {
108 collection.extend([E::from(p.clone().into())]);
109 }
110 for c in &self.children {
111 collection.extend([E::from(c.clone().into())]);
112 }
113 }
114}
115
116impl TreeNode<Vec<GameRef<Culture>>> for Culture {
117 fn get_children(&self) -> Option<Vec<GameRef<Culture>>> {
118 if self.children.is_empty() {
119 return None;
120 }
121 Some(self.children.clone())
122 }
123
124 fn get_parent(&self) -> Option<Vec<GameRef<Culture>>> {
125 if self.parents.is_empty() {
126 return None;
127 }
128 Some(self.parents.clone())
129 }
130
131 fn get_class(&self) -> Option<GameString> {
132 Some(self.heritage.clone())
133 }
134}
135
136impl Culture {
137 pub fn register_child(&mut self, child: GameRef<Culture>) {
138 self.children.push(child);
139 }
140
141 pub fn get_language(&self) -> Option<GameString> {
142 self.language.clone()
143 }
144}
145
146impl ProceduralPath for Culture {
147 fn get_subdir() -> &'static str {
148 "cultures"
149 }
150}
151
152impl Renderable for GameObjectEntity<Culture> {
153 fn get_template() -> &'static str {
154 CUL_TEMPLATE_NAME
155 }
156
157 fn render(
158 &self,
159 path: &Path,
160 game_state: &GameState,
161 grapher: Option<&Grapher>,
162 data: &GameData,
163 ) {
164 if let Some(grapher) = grapher {
165 let mut path = path.join(Culture::get_subdir());
166 path.push(self.id.to_string() + ".svg");
167 grapher.create_culture_graph(self.id, &path);
168 }
169 if let Some(map) = data.get_map() {
170 let filter = |title: &Title| {
171 if let Title::County { culture, .. } = title {
172 if let Some(culture) = culture {
173 return culture.get_internal().id == self.id;
174 }
175 }
176 return false;
177 };
178 let keys = game_state.get_baronies_of_counties(filter);
179 if !keys.is_empty() {
180 let mut path = path.join(Culture::get_subdir());
181 path.push(self.id.to_string() + ".png");
182 let mut culture_map = map.create_map_flat(keys, [70, 255, 70]);
183 if let Some(inner) = self.inner() {
184 culture_map.draw_text(format!("Map of the {} culture", &inner.name));
185 }
186 culture_map.save_in_thread(&path);
187 }
188 }
189 }
190}
191
192impl Localizable for Culture {
193 fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
194 self.name = localization.localize(&self.name)?;
195 if let Some(eth) = &self.ethos {
196 self.ethos = Some(localization.localize(eth.to_string() + "_name")?);
197 }
198 self.heritage = localization.localize(self.heritage.to_string() + "_name")?;
199 self.martial = localization.localize(self.martial.to_string() + "_name")?;
200 if let Some(language) = &self.language {
201 self.language = Some(localization.localize(language.to_string() + "_name")?);
202 }
203 for t in &mut self.traditions {
204 *t = localization.localize(t.to_string() + "_name")?;
205 }
206 for (era, _, _) in &mut self.eras {
207 *era = localization.localize(era.to_string())?;
208 }
209 Ok(())
210 }
211}