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: 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: 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}