genie_dat/
task.rs

1use crate::sound::SoundID;
2use crate::sprite::SpriteID;
3use crate::unit_type::UnitTypeID;
4use byteorder::{ReadBytesExt, WriteBytesExt, LE};
5use genie_support::read_opt_u16;
6use std::convert::TryInto;
7use std::io::{Read, Result, Write};
8use std::ops::Deref;
9
10#[derive(Debug, Default, Clone)]
11pub struct TaskList(Vec<Task>);
12
13#[derive(Debug, Default, Clone)]
14pub struct Task {
15    id: u16,
16    is_default: bool,
17    action_type: u16,
18    object_class: i16,
19    object_id: Option<UnitTypeID>,
20    terrain_id: i16,
21    attribute_types: (i16, i16, i16, i16),
22    work_values: (f32, f32),
23    work_range: f32,
24    auto_search_targets: bool,
25    search_wait_time: f32,
26    enable_targeting: bool,
27    combat_level: u8,
28    work_flags: (u16, u16),
29    owner_type: u8,
30    holding_attribute: u8,
31    state_building: u8,
32    move_sprite: Option<SpriteID>,
33    work_sprite: Option<SpriteID>,
34    work_sprite2: Option<SpriteID>,
35    carry_sprite: Option<SpriteID>,
36    work_sound: Option<SoundID>,
37    work_sound2: Option<SoundID>,
38}
39
40impl Deref for TaskList {
41    type Target = Vec<Task>;
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl TaskList {
48    pub fn read_from(mut input: impl Read) -> Result<Self> {
49        let num_tasks = input.read_u16::<LE>()?;
50        let mut tasks = vec![];
51        for _ in 0..num_tasks {
52            let task_type = input.read_u16::<LE>()?;
53            assert_eq!(task_type, 1);
54            tasks.push(Task::read_from(&mut input)?);
55        }
56
57        Ok(Self(tasks))
58    }
59
60    pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
61        output.write_u16::<LE>(self.len().try_into().unwrap())?;
62        for task in self.iter() {
63            output.write_u16::<LE>(1)?;
64            task.write_to(output)?;
65        }
66        Ok(())
67    }
68}
69
70impl Task {
71    pub fn read_from(mut input: impl Read) -> Result<Self> {
72        let mut task = Self::default();
73        task.id = input.read_u16::<LE>()?;
74        task.is_default = input.read_u8()? != 0;
75        task.action_type = input.read_u16::<LE>()?;
76        task.object_class = input.read_i16::<LE>()?;
77        task.object_id = read_opt_u16(&mut input)?;
78        task.terrain_id = input.read_i16::<LE>()?;
79        task.attribute_types = (
80            input.read_i16::<LE>()?,
81            input.read_i16::<LE>()?,
82            input.read_i16::<LE>()?,
83            input.read_i16::<LE>()?,
84        );
85        task.work_values = (input.read_f32::<LE>()?, input.read_f32::<LE>()?);
86        task.work_range = input.read_f32::<LE>()?;
87        task.auto_search_targets = input.read_u8()? != 0;
88        task.search_wait_time = input.read_f32::<LE>()?;
89        task.enable_targeting = input.read_u8()? != 0;
90        task.combat_level = input.read_u8()?;
91        task.work_flags = (input.read_u16::<LE>()?, input.read_u16::<LE>()?);
92        task.owner_type = input.read_u8()?;
93        task.holding_attribute = input.read_u8()?;
94        task.state_building = input.read_u8()?;
95        task.move_sprite = read_opt_u16(&mut input)?;
96        task.work_sprite = read_opt_u16(&mut input)?;
97        task.work_sprite2 = read_opt_u16(&mut input)?;
98        task.carry_sprite = read_opt_u16(&mut input)?;
99        task.work_sound = read_opt_u16(&mut input)?;
100        task.work_sound2 = read_opt_u16(&mut input)?;
101
102        Ok(task)
103    }
104
105    pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
106        output.write_u16::<LE>(self.id)?;
107        output.write_u8(if self.is_default { 1 } else { 0 })?;
108        output.write_u16::<LE>(self.action_type)?;
109        output.write_i16::<LE>(self.object_class)?;
110        output.write_i16::<LE>(
111            self.object_id
112                .map(|id| id.try_into().unwrap())
113                .unwrap_or(-1),
114        )?;
115        output.write_i16::<LE>(self.terrain_id)?;
116        output.write_i16::<LE>(self.attribute_types.0)?;
117        output.write_i16::<LE>(self.attribute_types.1)?;
118        output.write_i16::<LE>(self.attribute_types.2)?;
119        output.write_i16::<LE>(self.attribute_types.3)?;
120        output.write_f32::<LE>(self.work_values.0)?;
121        output.write_f32::<LE>(self.work_values.1)?;
122        output.write_f32::<LE>(self.work_range)?;
123        output.write_u8(if self.auto_search_targets { 1 } else { 0 })?;
124        output.write_f32::<LE>(self.search_wait_time)?;
125        output.write_u8(if self.enable_targeting { 1 } else { 0 })?;
126        output.write_u8(self.combat_level)?;
127        output.write_u16::<LE>(self.work_flags.0)?;
128        output.write_u16::<LE>(self.work_flags.1)?;
129        output.write_u8(self.owner_type)?;
130        output.write_u8(self.holding_attribute)?;
131        output.write_u8(self.state_building)?;
132        output.write_i16::<LE>(
133            self.move_sprite
134                .map(|id| id.try_into().unwrap())
135                .unwrap_or(-1),
136        )?;
137        output.write_i16::<LE>(
138            self.work_sprite
139                .map(|id| id.try_into().unwrap())
140                .unwrap_or(-1),
141        )?;
142        output.write_i16::<LE>(
143            self.work_sprite2
144                .map(|id| id.try_into().unwrap())
145                .unwrap_or(-1),
146        )?;
147        output.write_i16::<LE>(
148            self.carry_sprite
149                .map(|id| id.try_into().unwrap())
150                .unwrap_or(-1),
151        )?;
152        output.write_i16::<LE>(
153            self.work_sound
154                .map(|id| id.try_into().unwrap())
155                .unwrap_or(-1),
156        )?;
157        output.write_i16::<LE>(
158            self.work_sound2
159                .map(|id| id.try_into().unwrap())
160                .unwrap_or(-1),
161        )?;
162        Ok(())
163    }
164}