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}