aoe2_probe/tweak/
triggers.rs

1use std::collections::HashMap;
2
3use crate::{parse::Token, Scenario, TriggerTweak};
4
5pub struct TriggersTweak {}
6
7impl TriggersTweak {
8    /// Push the given trigger to the end of the trigger data
9    /// This method will check the correctness and version compatible.
10    /// # Examples
11    ///
12    /// ```
13    /// use aoe2_probe::{Scenario, TriggersTweak};
14    /// use aoe2_probe::prebuilt::ver1_46::Trigger;
15    ///
16    /// let mut scenario = Scenario::from_file("./resources/chapter_1.aoe2scenario").unwrap();
17    /// let trigger = Trigger::default();
18    ///
19    /// TriggersTweak::push(&mut scenario, trigger).unwrap();
20    /// ```
21    pub fn push(scenario: &mut Scenario, trigger: Token) -> Result<(), String> {
22        let version = scenario.version().to_string();
23        match version.as_str() {
24            "1.46" | "1.47" => {
25                TriggerTweak::is_trigger(&trigger, &version)?;
26
27                let trigger_data = scenario
28                    .versio
29                    .get_by_path_mut("/triggers/trigger_data")
30                    .try_mut_vec();
31                trigger_data.push(trigger);
32
33                let trigger_display_order_array = scenario
34                    .versio
35                    .get_by_path_mut("/triggers/trigger_display_order_array")
36                    .try_mut_vec();
37                trigger_display_order_array.push((trigger_display_order_array.len() as u32).into());
38
39                let trigger_count = scenario
40                    .versio
41                    .get_by_path("/triggers/number_of_triggers")
42                    .try_u32();
43                Self::set_trigger_count(scenario, &version, *trigger_count + 1).unwrap();
44
45                Ok(())
46            }
47            _ => Err("Incompatible version!".to_string()),
48        }
49    }
50
51    pub fn insert(
52        scenario: &mut Scenario,
53        trigger: Token,
54        display_index: usize,
55        execute_index: usize,
56    ) -> Result<(), String> {
57        let version = scenario.version().to_string();
58        match version.as_str() {
59            "1.46" | "1.47" => {
60                TriggerTweak::is_trigger(&trigger, &version)?;
61
62                let trigger_display_order_array = scenario
63                    .versio
64                    .get_by_path_mut("/triggers/trigger_display_order_array")
65                    .try_mut_vec();
66
67                for index in trigger_display_order_array.iter_mut() {
68                    let index = index.try_mut_u32();
69                    if *index >= execute_index as u32 {
70                        *index += 1;
71                    }
72                }
73                trigger_display_order_array.insert(display_index, (execute_index as u32).into());
74
75                let trigger_data = scenario
76                    .versio
77                    .get_by_path_mut("/triggers/trigger_data")
78                    .try_mut_vec();
79
80                for trigger in trigger_data.iter_mut() {
81                    let map = trigger.try_mut_map();
82                    let effects = map["effect_data"].try_mut_vec();
83                    for effect in effects.iter_mut() {
84                        let map = effect.try_mut_map();
85                        let target_id = *map["trigger_id"].try_i32();
86                        if target_id >= execute_index.try_into().unwrap() {
87                            map.update("trigger_id", target_id + 1).unwrap();
88                        }
89                    }
90                }
91
92                trigger_data.insert(execute_index, trigger);
93
94                let trigger_count = scenario
95                    .versio
96                    .get_by_path("/triggers/number_of_triggers")
97                    .try_u32();
98                Self::set_trigger_count(scenario, &version, *trigger_count + 1)?;
99
100                Ok(())
101            }
102            _ => Err("Incompatible version!".to_string()),
103        }
104    }
105
106    /// Sort the trigger data by the display order
107    /// This method will check the correctness and version compatible.
108    /// # Examples
109    ///
110    /// ```
111    /// use aoe2_probe::{Scenario, TriggersTweak};
112    /// use aoe2_probe::prebuilt::ver1_46::Trigger;
113    ///
114    /// let mut scenario = Scenario::from_file("./resources/chapter_1.aoe2scenario").unwrap();
115    ///
116    /// TriggersTweak::sort_by_display_order(&mut scenario).unwrap();
117    /// ```
118    pub fn sort_by_display_order(scenario: &mut Scenario) -> Result<(), String> {
119        let version = scenario.version().to_string();
120        match version.as_str() {
121            "1.46" | "1.47" => {
122                let display_order: Vec<u32> = scenario
123                    .versio
124                    .get_by_path("/triggers/trigger_display_order_array")
125                    .try_vec()
126                    .iter()
127                    .map(|token| *token.try_u32())
128                    .collect();
129
130                let trigger_data = scenario
131                    .versio
132                    .get_by_path("/triggers/trigger_data")
133                    .try_vec();
134
135                let mut sorted_triggers = vec![];
136                let mut order: Vec<Token> = vec![];
137                let mut map = HashMap::new();
138
139                for index in 0..display_order.len() as u32 {
140                    let position = display_order
141                        .iter()
142                        .position(|&value| value == index)
143                        .unwrap();
144                    map.insert(position, index);
145                    sorted_triggers.push(trigger_data[position].clone());
146                    order.push(index.into());
147                }
148
149                for token in sorted_triggers.iter_mut() {
150                    let effects = token.get_by_path_mut("/effect_data").try_mut_vec();
151                    for token in effects.iter_mut() {
152                        let target_trigger_id = token.get_by_path_mut("trigger_id").try_mut_i32();
153                        if *target_trigger_id >= 0 {
154                            let new_id = map[&(*target_trigger_id as usize)] as i32;
155                            *target_trigger_id = new_id;
156                        }
157                    }
158                }
159
160                let triggers = scenario.versio.get_by_path_mut("/triggers").try_mut_map();
161                triggers.update("trigger_data", sorted_triggers).unwrap();
162                triggers
163                    .update("trigger_display_order_array", order)
164                    .unwrap();
165
166                Ok(())
167            }
168            _ => Err("Incompatible version!".to_string()),
169        }
170    }
171
172    fn set_trigger_count(scenario: &mut Scenario, version: &str, count: u32) -> Result<(), String> {
173        match version {
174            "1.46" | "1.47" => {
175                let trigger_count = scenario
176                    .versio
177                    .get_by_path_mut("/file_header/trigger_count")
178                    .try_mut_u32();
179                *trigger_count = count;
180
181                let number_of_triggers = scenario
182                    .versio
183                    .get_by_path_mut("/options/number_of_triggers")
184                    .try_mut_u32();
185                *number_of_triggers = count;
186
187                let number_of_triggers = scenario
188                    .versio
189                    .get_by_path_mut("/triggers/number_of_triggers")
190                    .try_mut_u32();
191                *number_of_triggers = count;
192                Ok(())
193            }
194            _ => Err("Incompatible version!".to_string()),
195        }
196    }
197}