ck3_history_extractor/structures/
memory.rs1use jomini::common::Date;
2use serde::Serialize;
3
4use super::{
5 super::{
6 game_data::{GameData, Localizable, LocalizationError, Localize},
7 parser::{
8 GameObjectMap, GameObjectMapping, GameState, ParsingError, SaveFileObject,
9 SaveFileValue,
10 },
11 types::{GameId, GameString, HashMap, Wrapper},
12 },
13 Character, EntityRef, FromGameObject, GameObjectDerived, GameRef,
14};
15
16#[derive(Serialize, Clone, Debug)]
17enum MemoryVariable {
18 Id(GameId),
19 String(GameString),
20 Bool(bool),
21 None,
22}
23
24impl From<&GameObjectMap> for MemoryVariable {
25 fn from(value: &GameObjectMap) -> Self {
26 let tp = value.get_string("type").unwrap();
27 match tp.as_ref() {
28 "value" => MemoryVariable::None,
29 "boolean" => MemoryVariable::Bool(value.get_integer("identity").unwrap() != 0),
30 "trait" => MemoryVariable::String(value.get_string("key").unwrap()),
31 "flag" => {
32 if let Some(v) = value.get("flag") {
33 match v {
34 SaveFileValue::Integer(int) => MemoryVariable::Bool(*int != 0),
35 SaveFileValue::Boolean(b) => MemoryVariable::Bool(*b),
36 SaveFileValue::String(s) => MemoryVariable::String(s.clone()),
37 _ => unimplemented!("Unsupported type for flag: {:?}", v),
38 }
39 } else {
40 MemoryVariable::None
41 }
42 }
43 _ => value
44 .get_game_id("identity")
45 .and_then(|id| Ok(MemoryVariable::Id(id)))
46 .unwrap_or(MemoryVariable::None),
47 }
48 }
49}
50
51#[derive(Serialize)]
53pub struct Memory {
54 date: Date,
55 r#type: GameString,
56 participants: HashMap<String, GameRef<Character>>,
57 variables: HashMap<GameString, MemoryVariable>,
58}
59
60impl FromGameObject for Memory {
61 fn from_game_object(
62 base: &GameObjectMap,
63 game_state: &mut GameState,
64 ) -> Result<Self, ParsingError> {
65 let mut val = Self {
66 date: base.get_date("creation_date")?,
67 r#type: base.get_string("type")?,
68 participants: HashMap::new(),
69 variables: HashMap::new(),
70 };
71 if let Some(participants_node) = base.get("participants") {
72 for part in participants_node.as_object()?.as_map()? {
73 val.participants.insert(
74 part.0.clone(),
75 game_state.get_character(&part.1.as_id()?).clone(),
76 );
77 }
78 }
79 if let Some(variables_node) = base.get("variables") {
80 let data_node = variables_node
81 .as_object()?
82 .as_map()?
83 .get_object("data")?
84 .as_array()?;
85 for variable in data_node {
86 let variable = variable.as_object()?.as_map()?;
87 let key = variable.get_string("flag")?;
88 if let SaveFileObject::Map(data) = variable.get_object("data")? {
89 val.variables
90 .insert(key.clone(), MemoryVariable::from(data));
91 }
92 }
93 }
94 Ok(val)
95 }
96}
97
98impl GameObjectDerived for Memory {
99 fn get_name(&self) -> GameString {
100 self.r#type.clone()
101 }
102
103 fn get_references<E: From<EntityRef>, C: Extend<E>>(&self, collection: &mut C) {
104 for part in self.participants.iter() {
105 collection.extend([E::from(part.1.clone().into())]);
106 }
107 }
108}
109
110impl Localizable for Memory {
111 fn localize(&mut self, localization: &GameData) -> Result<(), LocalizationError> {
112 self.r#type = localization.localize_query(&self.r#type, |stack| {
113 match stack.len() {
114 4 => {
115 if stack[1].0 == "Var" {
116 if stack[2].0 == "GetProvince" {
117 if let Some(province_id) = self.variables.get(stack[1].1[0].as_str()) {
118 if let MemoryVariable::Id(id) = province_id {
119 if let Some(province_name) = localization.lookup_title(id) {
120 if let Ok(province_name) =
121 localization.localize(province_name)
122 {
123 return Some(province_name);
124 }
125 }
126 }
127 } else {
128 return Some(stack[1].1[0].clone().into());
129 }
130 } else if stack[2].0 == "Trait" {
131 if let Some(trait_name) = self.variables.get(stack[1].1[0].as_str()) {
132 if let MemoryVariable::String(trait_name) = trait_name {
133 return Some(trait_name.clone());
134 }
135 }
136 }
137 }
138 }
139 3 => {
140 if stack[1].0 == "Var" {
141 if let Some(var_name) = self.variables.get(stack[1].1[0].as_str()) {
142 if let MemoryVariable::String(var_name) = var_name {
143 return Some(var_name.clone());
144 }
145 }
146 }
147 }
148 2 => {
149 if stack[0].0 == "owner" {
150 if stack[1].0 == "GetName" || stack[1].0 == "GetTitledFirstName" {
151 return Some("".into());
152 } else if stack[1].0 == "GetHerHis" {
153 return Some("my".into());
154 } else if stack[1].1[0] == "RelationToMeShort"
155 || stack[1].1[1] == "RelationToMeShort"
156 {
157 if let Some(guy) =
158 self.participants.get(stack[1].1[1].as_str().trim_start())
159 {
160 return Some(guy.get_internal().inner().unwrap().get_name());
161 }
162 }
163 } else if stack[0].0 == "predecessor" {
164 if stack[1].0 == "GetHerHis" {
165 return Some("their".into());
166 } else if stack[1].0 == "GetHerHim" {
167 return Some("them".into());
168 }
169 } else if let Some(part) = self.participants.get(stack[0].0.as_str()) {
170 if stack[1].0 == "GetName" || stack[1].0 == "GetTitledFirstName" {
171 return Some(part.get_internal().inner().unwrap().get_name());
172 } else if stack[1].0 == "GetHerHis" || stack[1].0 == "GetNamePossessive" {
173 if part.get_internal().inner().unwrap().get_female() {
174 return Some("Her".into());
175 } else {
176 return Some("His".into());
177 }
178 }
179 } else if stack[1].0 == "GetName" || stack[1].0 == "GetTitledFirstName" {
180 return Some(stack[0].1[0].clone().into());
181 }
182 if stack[1].0 == "Custom" {
183 if stack[1].1[0] == "KnightCultureNoTooltip" {
184 return Some("Knight".into());
185 }
186 }
187 }
188 _ => {}
189 }
190 None
191 })?;
192 Ok(())
193 }
194}
195
196impl Serialize for GameRef<Memory> {
197 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
198 where
199 S: serde::Serializer,
200 {
201 self.get_internal().serialize(serializer)
202 }
203}