ck3_history_extractor/structures/
house.rs1use jomini::common::Date;
2
3use serde::Serialize;
4
5use super::{
6 super::{
7 display::{ProceduralPath, Renderable},
8 game_data::{GameData, Localizable, LocalizationError, Localize},
9 jinja_env::HOUSE_TEMPLATE_NAME,
10 parser::{
11 GameObjectMap, GameObjectMapping, GameState, KeyError, ParsingError, SaveFileValue,
12 SaveObjectError,
13 },
14 types::{GameString, HashMap, Wrapper, WrapperMut},
15 },
16 Character, Culture, Dynasty, EntityRef, Faith, FromGameObject, GameObjectDerived,
17 GameObjectEntity, GameRef,
18};
19
20#[derive(Serialize)]
21pub struct House {
22 name: GameString,
23 parent: GameRef<Dynasty>,
24 leaders: Vec<GameRef<Character>>,
25 motto: Option<(GameString, HashMap<i64, GameString>)>,
26 found_date: Option<Date>,
27}
28
29fn get_house_name(base: &GameObjectMap) -> Result<GameString, ParsingError> {
30 if let Some(name) = base.get("name").or(base.get("localized_name")) {
31 Ok(name.as_string()?)
32 } else {
33 match base.get_err("key")? {
34 SaveFileValue::Integer(id) => Ok(id.to_string().into()),
35 SaveFileValue::String(name) => Ok(name.clone()),
36 _ => Err(ParsingError::StructureError(SaveObjectError::KeyError(
37 KeyError::MissingKey("house_name or localized_name".to_string(), base.to_owned()),
38 ))),
39 }
40 }
41}
42
43impl FromGameObject for House {
44 fn from_game_object(
45 base: &GameObjectMap,
46 game_state: &mut GameState,
47 ) -> Result<Self, ParsingError> {
48 let mut this = Self {
49 name: get_house_name(base)?,
50 parent: game_state
51 .get_dynasty(&base.get_game_id("dynasty")?)
52 .clone(),
53 found_date: base.get("found_date").map(|n| n.as_date()).transpose()?,
54 leaders: Vec::new(),
55 motto: None,
56 };
57 if let Some(motto_node) = base.get("motto") {
58 if let SaveFileValue::Object(obj) = motto_node {
59 let o = obj.as_map()?;
60 let mut vars = HashMap::new();
61 for v in o.get_object("variables")?.as_array()? {
62 let pair = v.as_object()?.as_map()?;
63 vars.insert(pair.get_integer("key")?, pair.get_string("value")?);
64 }
65 this.motto = Some((o.get_string("key")?.clone(), vars));
66 } else {
67 this.motto = Some((motto_node.as_string()?, HashMap::default()));
68 }
69 }
70 if let Some(leaders_obj) = base.get("historical") {
71 for l in leaders_obj.as_object()?.as_array()? {
72 this.leaders
73 .push(game_state.get_character(&l.as_id()?).clone());
74 }
75 }
76 if let Some(leader) = base.get("head_of_house") {
77 let char = game_state.get_character(&leader.as_id()?);
78 if !this.leaders.contains(&char) {
79 this.leaders.push(char.clone());
80 }
81 }
82 Ok(this)
83 }
84
85 fn finalize(&mut self, reference: &GameRef<Self>) {
86 self.parent
87 .get_internal_mut()
88 .inner_mut()
89 .unwrap()
90 .register_house(reference.clone());
91 }
92}
93
94impl GameObjectDerived for House {
95 fn get_name(&self) -> GameString {
96 self.name.clone()
97 }
98
99 fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
100 for leader in self.leaders.iter() {
101 collection.extend([E::from(leader.clone().into())]);
102 }
103 collection.extend([E::from(self.parent.clone().into())]);
104 }
105}
106
107impl Localizable for House {
108 fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
109 self.name = localization.localize(&self.name)?;
110 let query = |stack: &Vec<(String, Vec<String>)>| {
111 match stack.len() {
112 2 => {
113 match stack[0].0.as_str() {
114 "CHARACTER" => {
115 if let Some(leader) = self
116 .leaders
117 .iter()
118 .find(|l| l.get_internal().inner().is_some())
119 {
120 let leader = leader.get_internal();
121 let leader = leader.inner().unwrap();
122 match stack[1].0.as_str() {
123 "Custom" => {
124 if stack[1].1[0] == "GetAppropriateGodname" {
125 return Some("God".into());
127 } else if stack[1].1[0] == "QueenKing" {
128 if leader.get_female() {
129 return Some("Queen".into());
130 } else {
131 return Some("King".into());
132 }
133 } else if stack[1].1[0] == "GetDaughterSon" {
134 if leader.get_female() {
135 return Some("Daughter".into());
136 } else {
137 return Some("Son".into());
138 }
139 }
140 }
141 "GetFirstName" => {
142 return Some(leader.get_name().clone());
143 }
144 "GetSheHe" => {
145 if leader.get_female() {
146 return Some("She".into());
147 } else {
148 return Some("He".into());
149 }
150 }
151 "GetWomenMen" => {
152 if leader.get_female() {
153 return Some("Women".into());
154 } else {
155 return Some("Men".into());
156 }
157 }
158 _ => {}
159 }
160 } else {
161 return Some("House".into());
162 }
163 }
164 _ => {}
165 }
166 }
167 3 => {
168 if stack[2].0 == "GetBaseNameNoTooltip" {
169 return Some(self.name.clone());
170 }
171 }
172 _ => {}
173 };
174 None
175 };
176 if let Some((motto, variables)) = &mut self.motto {
177 for (_, v) in variables.iter_mut() {
178 *v = localization.localize_query(&v, query)?;
179 }
180 *motto = localization.localize_query(&motto, |stack| {
181 match stack.len() {
182 1 => {
183 if let Ok(k) = stack[0].0.parse::<i64>() {
184 if let Some(v) = variables.get(&k) {
185 return Some(v.clone());
186 }
187 }
188 }
189 _ => {
190 return query(stack);
191 }
192 }
193 None
194 })?;
195 }
196 Ok(())
197 }
198}
199
200impl House {
201 pub fn get_faith(&self) -> GameRef<Faith> {
202 for leader in self.leaders.iter().rev() {
203 if let Ok(faith) = leader.try_get_internal() {
204 if let Some(faith) = faith.inner().unwrap().get_faith() {
205 return faith;
206 }
207 }
208 }
209 unimplemented!()
210 }
211
212 pub fn get_culture(&self) -> GameRef<Culture> {
213 for leader in self.leaders.iter().rev() {
214 if let Ok(culture) = leader.try_get_internal() {
215 if let Some(culture) = culture.inner().unwrap().get_culture() {
216 return culture;
217 }
218 }
219 }
220 unimplemented!()
221 }
222
223 pub fn get_founder(&self) -> GameRef<Character> {
224 if let Some(leader) = self.leaders.first() {
225 leader.clone()
226 } else {
227 self.parent
228 .get_internal()
229 .inner()
230 .unwrap()
231 .get_leader()
232 .unwrap()
233 }
234 }
235
236 pub fn get_dynasty(&self) -> GameRef<Dynasty> {
237 self.parent.clone()
238 }
239
240 pub fn get_found_date(&self) -> Option<Date> {
241 self.found_date
242 }
243}
244
245impl ProceduralPath for House {
246 fn get_subdir() -> &'static str {
247 "houses"
248 }
249}
250
251impl Renderable for GameObjectEntity<House> {
252 fn get_template() -> &'static str {
253 HOUSE_TEMPLATE_NAME
254 }
255}