1use crate::Result;
2use crate::UnitTypeID;
3use byteorder::{ReadBytesExt, WriteBytesExt, LE};
4use genie_support::{read_opt_u32, read_str, write_i32_str, write_opt_i32_str, StringKey};
5use std::convert::TryInto;
6use std::io::{Read, Write};
7
8#[derive(Debug, Default, Clone)]
10pub struct TriggerCondition {
11 condition_type: i32,
12 properties: Vec<i32>,
13}
14
15impl TriggerCondition {
16 pub fn read_from(mut input: impl Read, version: f64) -> Result<Self> {
18 let condition_type = input.read_i32::<LE>()?;
19 let num_properties = if version > 1.0 {
20 input.read_i32::<LE>()?
21 } else {
22 13
23 };
24 let mut properties = Vec::with_capacity(num_properties as usize);
25 for _ in 0..num_properties {
26 properties.push(input.read_i32::<LE>()?);
27 }
28
29 while properties.len() < 18 {
30 properties.push(-1);
31 }
32
33 Ok(Self {
34 condition_type,
35 properties,
36 })
37 }
38
39 pub fn write_to(&self, mut output: impl Write, version: f64) -> Result<()> {
41 output.write_i32::<LE>(self.condition_type)?;
42 if version > 1.0 {
43 output.write_i32::<LE>(self.properties.len() as i32)?;
44 for value in &self.properties {
45 output.write_i32::<LE>(*value)?;
46 }
47 } else {
48 for i in 0..13 {
49 output.write_i32::<LE>(*self.properties.get(i).unwrap_or(&0))?;
50 }
51 }
52
53 Ok(())
54 }
55
56 pub fn amount(&self) -> i32 {
58 self.properties[0]
59 }
60
61 pub fn set_amount(&mut self, amount: i32) {
63 self.properties[0] = amount;
64 }
65
66 pub fn resource(&self) -> i32 {
68 self.properties[1]
69 }
70
71 pub fn set_resource(&mut self, resource: i32) {
73 self.properties[1] = resource;
74 }
75
76 pub fn primary_object(&self) -> i32 {
78 self.properties[2]
79 }
80
81 pub fn set_primary_object(&mut self, primary_object: i32) {
83 self.properties[2] = primary_object;
84 }
85
86 pub fn secondary_object(&self) -> i32 {
88 self.properties[3]
89 }
90
91 pub fn set_secondary_object(&mut self, secondary_object: i32) {
93 self.properties[3] = secondary_object;
94 }
95
96 pub fn raw_unit_type(&self) -> i32 {
98 self.properties[4]
99 }
100
101 pub fn set_raw_unit_type(&mut self, unit_type: i32) {
103 self.properties[4] = unit_type;
104 }
105
106 pub fn unit_type(&self) -> UnitTypeID {
108 self.properties[4].try_into().unwrap()
109 }
110
111 pub fn set_unit_type(&mut self, unit_type: UnitTypeID) {
113 self.properties[4] = unit_type.try_into().unwrap();
114 }
115
116 pub fn player_id(&self) -> i32 {
118 self.properties[5]
119 }
120
121 pub fn set_player_id(&mut self, player_id: i32) {
123 self.properties[5] = player_id;
124 }
125
126 pub fn technology_id(&self) -> i32 {
128 self.properties[6]
129 }
130
131 pub fn set_technology_id(&mut self, technology_id: i32) {
133 self.properties[6] = technology_id;
134 }
135
136 pub fn timer(&self) -> i32 {
138 self.properties[7]
139 }
140
141 pub fn set_timer(&mut self, timer: i32) {
143 self.properties[7] = timer;
144 }
145
146 pub fn trigger_id(&self) -> i32 {
148 self.properties[8]
149 }
150
151 pub fn set_trigger_id(&mut self, trigger_id: i32) {
153 self.properties[8] = trigger_id;
154 }
155
156 pub fn area(&self) -> (i32, i32, i32, i32) {
160 (
161 self.properties[9],
162 self.properties[10],
163 self.properties[11],
164 self.properties[12],
165 )
166 }
167
168 pub fn set_area(&mut self, area: (i32, i32, i32, i32)) {
172 self.properties[9] = area.0;
173 self.properties[10] = area.1;
174 self.properties[11] = area.2;
175 self.properties[12] = area.3;
176 }
177
178 pub fn unit_group(&self) -> i32 {
180 self.properties[13]
181 }
182
183 pub fn set_unit_group(&mut self, unit_group: i32) {
185 self.properties[13] = unit_group;
186 }
187
188 pub fn object_type(&self) -> UnitTypeID {
190 self.properties[14].try_into().unwrap()
191 }
192
193 pub fn set_object_type(&mut self, object_type: UnitTypeID) {
195 self.properties[14] = i32::from(object_type);
196 }
197
198 pub fn ai_signal(&self) -> i32 {
200 self.properties[15]
201 }
202
203 pub fn set_ai_signal(&mut self, ai_signal: i32) {
205 self.properties[15] = ai_signal;
206 }
207
208 pub fn inverted(&self) -> bool {
210 self.properties[16] == 1
211 }
212
213 pub fn set_inverted(&mut self, inverted: i32) {
215 self.properties[16] = inverted;
216 }
217}
218
219#[derive(Debug, Default, Clone)]
221pub struct TriggerEffect {
222 effect_type: i32,
223 properties: Vec<i32>,
224 chat_text: Option<String>,
225 audio_file: Option<String>,
226 objects: Vec<i32>,
227}
228
229impl TriggerEffect {
230 pub fn read_from(mut input: impl Read, version: f64) -> Result<Self> {
232 let effect_type = input.read_i32::<LE>()?;
233 let num_properties = if version > 1.0 {
234 input.read_i32::<LE>()?
235 } else {
236 16
237 };
238 let mut properties = Vec::with_capacity(num_properties as usize);
239 for _ in 0..num_properties {
240 properties.push(input.read_i32::<LE>()?);
241 }
242
243 while properties.len() < 24 {
244 properties.push(-1);
245 }
246
247 let len = input.read_i32::<LE>()? as usize;
248 let chat_text = read_str(&mut input, len)?;
249 let len = input.read_i32::<LE>()? as usize;
250 let audio_file = read_str(&mut input, len)?;
251 let mut objects = vec![];
252
253 if version > 1.1 {
254 for _ in 0..properties[4] {
255 objects.push(input.read_i32::<LE>()?);
256 }
257 } else {
258 objects.push(properties[4]);
259 properties[4] = 1;
260 }
261
262 Ok(Self {
263 effect_type,
264 properties,
265 chat_text,
266 audio_file,
267 objects,
268 })
269 }
270
271 pub fn write_to(&self, mut output: impl Write, version: f64) -> Result<()> {
273 output.write_i32::<LE>(self.effect_type)?;
274 output.write_i32::<LE>(self.properties.len() as i32)?;
275 for value in &self.properties {
276 output.write_i32::<LE>(*value)?;
277 }
278
279 write_opt_i32_str(&mut output, &self.chat_text)?;
280 write_opt_i32_str(&mut output, &self.audio_file)?;
281
282 if version > 1.1 {
283 for i in 0..self.num_objects() {
284 output.write_i32::<LE>(*self.objects.get(i as usize).unwrap_or(&-1))?;
285 }
286 }
287
288 Ok(())
289 }
290
291 pub fn ai_goal(&self) -> i32 {
293 self.properties[0]
294 }
295
296 pub fn set_ai_goal(&mut self, ai_goal: i32) {
298 self.properties[0] = ai_goal;
299 }
300
301 pub fn amount(&self) -> i32 {
303 self.properties[1]
304 }
305
306 pub fn set_amount(&mut self, amount: i32) {
308 self.properties[1] = amount;
309 }
310
311 pub fn resource(&self) -> i32 {
313 self.properties[2]
314 }
315
316 pub fn set_resource(&mut self, resource: i32) {
318 self.properties[2] = resource;
319 }
320
321 pub fn diplomacy(&self) -> i32 {
323 self.properties[3]
324 }
325
326 pub fn set_diplomacy(&mut self, diplomacy: i32) {
328 self.properties[3] = diplomacy;
329 }
330
331 pub fn num_objects(&self) -> i32 {
333 self.properties[4]
334 }
335
336 pub fn set_num_objects(&mut self, num_objects: i32) {
338 self.properties[4] = num_objects;
339 }
340
341 pub fn object_id(&self) -> i32 {
343 self.properties[5]
344 }
345
346 pub fn set_object_id(&mut self, object_id: i32) {
348 self.properties[5] = object_id;
349 }
350
351 pub fn unit_type(&self) -> UnitTypeID {
353 self.properties[6].try_into().unwrap()
354 }
355
356 pub fn set_unit_type(&mut self, unit_type: UnitTypeID) {
358 self.properties[6] = i32::from(unit_type);
359 }
360
361 pub fn source_player_id(&self) -> i32 {
363 self.properties[7]
364 }
365
366 pub fn set_source_player_id(&mut self, source_player_id: i32) {
368 self.properties[7] = source_player_id;
369 }
370
371 pub fn target_player_id(&self) -> i32 {
373 self.properties[8]
374 }
375
376 pub fn set_target_player_id(&mut self, target_player_id: i32) {
378 self.properties[8] = target_player_id;
379 }
380
381 pub fn technology_id(&self) -> i32 {
383 self.properties[9]
384 }
385
386 pub fn set_technology_id(&mut self, technology_id: i32) {
388 self.properties[9] = technology_id;
389 }
390
391 pub fn text_id(&self) -> i32 {
393 self.properties[10]
394 }
395
396 pub fn set_text_id(&mut self, text_id: i32) {
398 self.properties[10] = text_id;
399 }
400
401 pub fn sound_id(&self) -> i32 {
403 self.properties[11]
404 }
405
406 pub fn set_sound_id(&mut self, sound_id: i32) {
408 self.properties[11] = sound_id;
409 }
410
411 pub fn timer(&self) -> i32 {
413 self.properties[12]
414 }
415
416 pub fn set_timer(&mut self, timer: i32) {
418 self.properties[12] = timer;
419 }
420
421 pub fn trigger_id(&self) -> i32 {
423 self.properties[13]
424 }
425
426 pub fn set_trigger_id(&mut self, trigger_id: i32) {
428 self.properties[13] = trigger_id;
429 }
430
431 pub fn location(&self) -> (i32, i32) {
433 (self.properties[14], self.properties[15])
434 }
435
436 pub fn set_location(&mut self, location: (i32, i32)) {
438 self.properties[14] = location.0;
439 self.properties[15] = location.1;
440 }
441
442 pub fn area(&self) -> (i32, i32, i32, i32) {
444 (
445 self.properties[16],
446 self.properties[17],
447 self.properties[18],
448 self.properties[19],
449 )
450 }
451
452 pub fn set_area(&mut self, area: (i32, i32, i32, i32)) {
454 self.properties[16] = area.0;
455 self.properties[17] = area.1;
456 self.properties[18] = area.2;
457 self.properties[19] = area.3;
458 }
459
460 pub fn object_group(&self) -> i32 {
462 self.properties[20]
463 }
464
465 pub fn set_object_group(&mut self, object_group: i32) {
467 self.properties[20] = object_group;
468 }
469
470 pub fn object_type(&self) -> UnitTypeID {
472 self.properties[21].try_into().unwrap()
473 }
474
475 pub fn set_object_type(&mut self, object_type: UnitTypeID) {
477 self.properties[21] = i32::from(object_type);
478 }
479
480 pub fn line_id(&self) -> i32 {
482 self.properties[22]
483 }
484
485 pub fn set_line_id(&mut self, line_id: i32) {
487 self.properties[22] = line_id;
488 }
489
490 pub fn stance(&self) -> i32 {
492 self.properties[23]
493 }
494
495 pub fn set_stance(&mut self, stance: i32) {
497 self.properties[23] = stance;
498 }
499}
500
501#[derive(Debug, Clone)]
503pub struct Trigger {
504 enabled: bool,
505 looping: bool,
506 name_id: i32,
507 is_objective: bool,
508 objective_order: i32,
509 start_time: u32,
510 description: Option<String>,
511 short_description_id: Option<StringKey>,
512 short_description: Option<String>,
513 display_short_description: bool,
514 short_description_state: u8,
515 mute_objective: bool,
516 name: Option<String>,
517 effects: Vec<TriggerEffect>,
518 effect_order: Vec<i32>,
519 conditions: Vec<TriggerCondition>,
520 condition_order: Vec<i32>,
521 make_header: bool,
522}
523
524impl Trigger {
525 pub fn read_from(mut input: impl Read, version: f64) -> Result<Self> {
527 let enabled = input.read_i32::<LE>()? != 0;
528 let looping = input.read_i8()? != 0;
529 let name_id = input.read_i32::<LE>()?;
530 let is_objective = input.read_i8()? != 0;
531 let objective_order = input.read_i32::<LE>()?;
532
533 let mut make_header = false;
534 let mut short_description_id = None;
535 let mut short_description_state = 0;
536 let mut display_short_description = false;
537 let mut mute_objective = false;
538 let start_time;
539 if version >= 1.8 {
540 make_header = input.read_u8()? != 0;
541 short_description_id = read_opt_u32(&mut input)?;
542 display_short_description = input.read_u8()? != 0;
543 short_description_state = input.read_u8()?;
544 start_time = input.read_u32::<LE>()?;
545 mute_objective = input.read_u8()? != 0;
546 } else {
547 start_time = input.read_u32::<LE>()?;
548 }
549
550 let description = {
551 let len = input.read_u32::<LE>()? as usize;
552 read_str(&mut input, len)?
553 };
554
555 let name = {
556 let len = input.read_u32::<LE>()? as usize;
557 read_str(&mut input, len)?
558 };
559
560 let short_description = if version >= 1.8 {
561 let len = input.read_u32::<LE>()? as usize;
562 read_str(&mut input, len)?
563 } else {
564 None
565 };
566
567 let num_effects = input.read_i32::<LE>()?;
568 let mut effects = vec![];
569 let mut effect_order = vec![];
570 for _ in 0..num_effects {
571 effects.push(TriggerEffect::read_from(&mut input, version)?);
572 }
573 for _ in 0..num_effects {
574 effect_order.push(input.read_i32::<LE>()?);
575 }
576
577 let num_conditions = input.read_i32::<LE>()?;
578 let mut conditions = vec![];
579 let mut condition_order = vec![];
580 for _ in 0..num_conditions {
581 conditions.push(TriggerCondition::read_from(&mut input, version)?);
582 }
583 for _ in 0..num_conditions {
584 condition_order.push(input.read_i32::<LE>()?);
585 }
586
587 Ok(Trigger {
588 enabled,
589 looping,
590 name_id,
591 is_objective,
592 objective_order,
593 start_time,
594 description,
595 short_description,
596 short_description_id,
597 display_short_description,
598 short_description_state,
599 mute_objective,
600 name,
601 effects,
602 effect_order,
603 conditions,
604 condition_order,
605 make_header,
606 })
607 }
608
609 pub fn write_to(&self, mut output: impl Write, version: f64) -> Result<()> {
611 output.write_i32::<LE>(if self.enabled { 1 } else { 0 })?;
612 output.write_i8(if self.looping { 1 } else { 0 })?;
613 output.write_i32::<LE>(self.name_id)?;
614 output.write_i8(if self.is_objective { 1 } else { 0 })?;
615 output.write_i32::<LE>(self.objective_order)?;
616
617 if version >= 1.8 {
618 output.write_u8(if self.make_header { 1 } else { 0 })?;
619 write_opt_string_key(&mut output, &self.short_description_id)?;
620 output.write_u8(if self.display_short_description { 1 } else { 0 })?;
621 output.write_u8(self.short_description_state)?;
622 output.write_u32::<LE>(self.start_time)?;
623 output.write_u8(if self.mute_objective { 1 } else { 0 })?;
624 } else {
625 output.write_u32::<LE>(self.start_time)?;
626 }
627
628 write_opt_i32_str(&mut output, &self.description)?;
629 write_opt_i32_str(&mut output, &self.name)?;
630 if version >= 1.8 {
631 write_opt_i32_str(&mut output, &self.short_description)?;
632 }
633
634 output.write_u32::<LE>(self.effects.len() as u32)?;
635 for effect in &self.effects {
636 effect.write_to(&mut output, version)?;
637 }
638 for order in &self.effect_order {
639 output.write_i32::<LE>(*order)?;
640 }
641 output.write_u32::<LE>(self.conditions.len() as u32)?;
642 for condition in &self.conditions {
643 condition.write_to(&mut output, version)?;
644 }
645 for order in &self.condition_order {
646 output.write_i32::<LE>(*order)?;
647 }
648
649 Ok(())
650 }
651
652 pub fn conditions(&self) -> impl Iterator<Item = &TriggerCondition> {
654 self.condition_order
655 .iter()
656 .map(move |index| &self.conditions[*index as usize])
657 }
658
659 pub fn conditions_unordered_mut(&mut self) -> impl Iterator<Item = &mut TriggerCondition> {
661 self.conditions.iter_mut()
662 }
663
664 pub fn effects(&self) -> impl Iterator<Item = &TriggerEffect> {
666 self.effect_order
667 .iter()
668 .map(move |index| &self.effects[*index as usize])
669 }
670
671 pub fn effects_unordered_mut(&mut self) -> impl Iterator<Item = &mut TriggerEffect> {
673 self.effects.iter_mut()
674 }
675}
676
677#[derive(Debug, Clone)]
679pub struct TriggerSystem {
680 version: f64,
681 objectives_state: i8,
682 triggers: Vec<Trigger>,
683 trigger_order: Vec<i32>,
684 enabled_techs: Vec<u32>,
685 variable_values: Vec<u32>,
686 variable_names: Vec<String>,
687}
688
689impl Default for TriggerSystem {
690 fn default() -> Self {
691 Self {
692 version: 1.6,
693 objectives_state: 0,
694 triggers: vec![],
695 trigger_order: vec![],
696 enabled_techs: vec![],
697 variable_values: vec![0; 256],
698 variable_names: vec![String::new(); 256],
699 }
700 }
701}
702
703impl TriggerSystem {
704 pub fn read_from(mut input: impl Read) -> Result<Self> {
706 let version = input.read_f64::<LE>()?;
707 log::debug!("Trigger system version {}", version);
708 let objectives_state = if version >= 1.5 { input.read_i8()? } else { 0 };
709
710 let num_triggers = input.read_i32::<LE>()?;
711 log::debug!("{} triggers", num_triggers);
712
713 let mut triggers = vec![];
714 let mut trigger_order = vec![];
715 for _ in 0..num_triggers {
716 triggers.push(Trigger::read_from(&mut input, version)?);
717 }
718 if version >= 1.4 {
719 for _ in 0..num_triggers {
720 trigger_order.push(input.read_i32::<LE>()?);
721 }
722 } else {
723 for i in 0..num_triggers {
724 trigger_order.push(i);
725 }
726 }
727
728 let mut variable_values = vec![];
729 let mut enabled_techs = vec![];
730 let mut variable_names = vec![];
731
732 if version >= 2.2 {
733 variable_values.resize(256, 0);
734 input.read_u32_into::<LE>(&mut variable_values)?;
735 enabled_techs = {
736 let num_enabled_techs = input.read_u32::<LE>()?;
737 let mut enabled_techs = vec![0; num_enabled_techs as usize];
738 input.read_u32_into::<LE>(&mut enabled_techs)?;
739 enabled_techs
740 };
741 variable_names = {
742 let num_var_names = input.read_u32::<LE>()?;
743 let mut variable_names = vec![String::new(); 256];
744 for _ in 0..num_var_names {
745 let id = input.read_u32::<LE>()?;
746 assert!(
747 id < 256,
748 "Unexpected variable number, this is probably a genie-scx bug"
749 );
750 let len = input.read_u32::<LE>()?;
751 variable_names[id as usize] =
752 read_str(&mut input, len as usize)?.unwrap_or_default();
753 }
754 variable_names
755 };
756 }
757
758 Ok(Self {
759 version,
760 objectives_state,
761 triggers,
762 trigger_order,
763 enabled_techs,
764 variable_values,
765 variable_names,
766 })
767 }
768
769 pub fn write_to(&self, mut output: impl Write, version: f64) -> Result<()> {
771 output.write_f64::<LE>(version)?;
772 if version >= 1.5 {
773 output.write_i8(self.objectives_state)?;
774 }
775 output.write_u32::<LE>(self.triggers.len().try_into().unwrap())?;
776 for trigger in &self.triggers {
777 trigger.write_to(&mut output, version)?;
778 }
779 if version >= 1.4 {
780 for order in &self.trigger_order {
781 output.write_i32::<LE>(*order)?;
782 }
783 }
784 if version >= 2.2 {
785 let padded_values = self
786 .variable_values
787 .iter()
788 .cloned()
789 .chain(std::iter::repeat(0))
790 .take(256);
791 for value in padded_values {
792 output.write_u32::<LE>(value)?;
793 }
794 output.write_u32::<LE>(self.enabled_techs.len() as u32)?;
795 for id in &self.enabled_techs {
796 output.write_u32::<LE>(*id)?;
797 }
798
799 let custom_names = self
800 .variable_names
801 .iter()
802 .enumerate()
803 .filter(|(_index, name)| !name.is_empty());
804 let num_custom_names = custom_names.clone().count();
805 output.write_u32::<LE>(num_custom_names as u32)?;
806 for (index, name) in custom_names {
807 output.write_u32::<LE>(index as u32)?;
808 write_i32_str(&mut output, &name)?;
809 }
810 }
811 Ok(())
812 }
813
814 pub fn version(&self) -> f64 {
816 self.version
817 }
818
819 pub fn num_triggers(&self) -> u32 {
821 self.triggers.len() as u32
822 }
823
824 pub fn triggers(&self) -> impl Iterator<Item = &Trigger> {
826 self.trigger_order
827 .iter()
828 .map(move |index| &self.triggers[*index as usize])
829 }
830
831 pub fn triggers_unordered_mut(&mut self) -> impl Iterator<Item = &mut Trigger> {
833 self.triggers.iter_mut()
834 }
835}
836
837fn write_opt_string_key(mut output: impl Write, opt_key: &Option<StringKey>) -> Result<()> {
838 use std::io::{Error, ErrorKind};
839 output.write_u32::<LE>(if let Some(key) = opt_key {
840 key.try_into()
841 .map_err(|err| Error::new(ErrorKind::InvalidData, err))?
842 } else {
843 0xFFFF_FFFF
844 })?;
845 Ok(())
846}