1use crate::unit_type::UnitTypeID;
2use byteorder::{ReadBytesExt, WriteBytesExt, LE};
3use std::convert::TryInto;
4use std::io::{Read, Result, Write};
5
6#[derive(Debug, Default, Clone)]
7pub struct RandomMapInfo {
8 id: i32,
9 borders: (i32, i32, i32, i32),
10 border_fade: i32,
11 water_border: i32,
12 base_terrain: i32,
13 land_percent: i32,
14 lands: Vec<RandomMapLand>,
15 terrains: Vec<RandomMapTerrain>,
16 objects: Vec<RandomMapObject>,
17 elevations: Vec<RandomMapElevation>,
18}
19
20impl RandomMapInfo {
21 pub fn read_from<R: Read>(input: &mut R) -> Result<Self> {
22 let mut info = Self::default();
23 info.id = input.read_i32::<LE>()?;
24 info.borders = (
25 input.read_i32::<LE>()?,
26 input.read_i32::<LE>()?,
27 input.read_i32::<LE>()?,
28 input.read_i32::<LE>()?,
29 );
30 info.border_fade = input.read_i32::<LE>()?;
31 info.water_border = input.read_i32::<LE>()?;
32 info.base_terrain = input.read_i32::<LE>()?;
33 info.land_percent = input.read_i32::<LE>()?;
34
35 let _some_id = input.read_i32::<LE>()?;
36 let num_lands = input.read_u32::<LE>()?;
37 let _pointer = input.read_u32::<LE>()?;
38 let num_terrains = input.read_u32::<LE>()?;
39 let _pointer = input.read_u32::<LE>()?;
40 let num_objects = input.read_u32::<LE>()?;
41 let _pointer = input.read_u32::<LE>()?;
42 let num_elevations = input.read_u32::<LE>()?;
43 let _pointer = input.read_u32::<LE>()?;
44
45 info.lands = vec![RandomMapLand::default(); num_lands.try_into().unwrap()];
46 info.terrains = vec![RandomMapTerrain::default(); num_terrains.try_into().unwrap()];
47 info.objects = vec![RandomMapObject::default(); num_objects.try_into().unwrap()];
48 info.elevations = vec![RandomMapElevation::default(); num_elevations.try_into().unwrap()];
49
50 Ok(info)
51 }
52
53 pub fn finish<R: Read>(&mut self, input: &mut R) -> Result<()> {
54 std::io::copy(&mut input.by_ref().take(44), &mut std::io::sink())?;
56 for land in self.lands.iter_mut() {
57 *land = RandomMapLand::read_from(input)?;
58 }
59
60 std::io::copy(&mut input.by_ref().take(8), &mut std::io::sink())?;
62 for terrain in self.terrains.iter_mut() {
63 *terrain = RandomMapTerrain::read_from(input)?;
64 }
65
66 std::io::copy(&mut input.by_ref().take(8), &mut std::io::sink())?;
68 for object in self.objects.iter_mut() {
69 *object = RandomMapObject::read_from(input)?;
70 }
71
72 std::io::copy(&mut input.by_ref().take(8), &mut std::io::sink())?;
74 for elevation in self.elevations.iter_mut() {
75 *elevation = RandomMapElevation::read_from(input)?;
76 }
77 Ok(())
78 }
79
80 pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
81 output.write_i32::<LE>(self.id)?;
82 output.write_i32::<LE>(self.borders.0)?;
83 output.write_i32::<LE>(self.borders.1)?;
84 output.write_i32::<LE>(self.borders.2)?;
85 output.write_i32::<LE>(self.borders.3)?;
86 output.write_i32::<LE>(self.border_fade)?;
87 output.write_i32::<LE>(self.water_border)?;
88 output.write_i32::<LE>(self.base_terrain)?;
89 output.write_i32::<LE>(self.land_percent)?;
90
91 output.write_i32::<LE>(0)?; output.write_u32::<LE>(self.lands.len().try_into().unwrap())?;
93 output.write_u32::<LE>(0)?; output.write_u32::<LE>(self.terrains.len().try_into().unwrap())?;
95 output.write_u32::<LE>(0)?; output.write_u32::<LE>(self.objects.len().try_into().unwrap())?;
97 output.write_u32::<LE>(0)?; output.write_u32::<LE>(self.elevations.len().try_into().unwrap())?;
99 output.write_u32::<LE>(0)?; Ok(())
102 }
103
104 pub fn write_commands_to<W: Write>(&self, output: &mut W) -> Result<()> {
105 output.write_i32::<LE>(self.borders.0)?;
106 output.write_i32::<LE>(self.borders.1)?;
107 output.write_i32::<LE>(self.borders.2)?;
108 output.write_i32::<LE>(self.borders.3)?;
109 output.write_i32::<LE>(self.border_fade)?;
110 output.write_i32::<LE>(self.water_border)?;
111 output.write_i32::<LE>(self.base_terrain)?;
112 output.write_i32::<LE>(self.land_percent)?;
113 output.write_u32::<LE>(0)?; output.write_u32::<LE>(self.lands.len().try_into().unwrap())?;
116 output.write_u32::<LE>(0)?; for land in &self.lands {
118 land.write_to(output)?;
119 }
120 output.write_u32::<LE>(self.terrains.len().try_into().unwrap())?;
121 output.write_u32::<LE>(0)?; for terrain in &self.terrains {
123 terrain.write_to(output)?;
124 }
125 output.write_u32::<LE>(self.objects.len().try_into().unwrap())?;
126 output.write_u32::<LE>(0)?; for object in &self.objects {
128 object.write_to(output)?;
129 }
130 output.write_u32::<LE>(self.elevations.len().try_into().unwrap())?;
131 output.write_u32::<LE>(0)?; for elevation in &self.elevations {
133 elevation.write_to(output)?;
134 }
135 Ok(())
136 }
137}
138
139#[derive(Debug, Default, Clone)]
140pub struct RandomMapLand {
141 id: i32,
142 terrain_type: u8,
143 land_avoidance_tiles: i32,
144 base_square_radius: i32,
145 zone: i8,
146 placement_type: i8,
147 x: i32,
148 y: i32,
149 amount_of_land_used_percent: i8,
150 by_player_flag: i8,
151 radius: i32,
152 fade: i32,
153 clumpiness_factor: i32,
154}
155
156impl RandomMapLand {
157 pub fn read_from<R: Read>(input: &mut R) -> Result<Self> {
158 let mut land = Self::default();
159 land.id = input.read_i32::<LE>()?;
160 land.terrain_type = input.read_u8()?;
161 let _padding = input.read_u16::<LE>()?;
162 let _padding = input.read_u8()?;
163 land.land_avoidance_tiles = input.read_i32::<LE>()?;
164 land.base_square_radius = input.read_i32::<LE>()?;
165 land.zone = input.read_i8()?;
166 land.placement_type = input.read_i8()?;
167 let _padding = input.read_u16::<LE>()?;
168 land.x = input.read_i32::<LE>()?;
169 land.y = input.read_i32::<LE>()?;
170 land.amount_of_land_used_percent = input.read_i8()?;
171 land.by_player_flag = input.read_i8()?;
172 let _padding = input.read_u16::<LE>()?;
173 land.radius = input.read_i32::<LE>()?;
174 land.fade = input.read_i32::<LE>()?;
175 land.clumpiness_factor = input.read_i32::<LE>()?;
176 Ok(land)
177 }
178
179 pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
180 output.write_i32::<LE>(self.id)?;
181 output.write_u8(self.terrain_type)?;
182 output.write_u16::<LE>(0)?;
183 output.write_u8(0)?;
184 output.write_i32::<LE>(self.land_avoidance_tiles)?;
185 output.write_i32::<LE>(self.base_square_radius)?;
186 output.write_i8(self.zone)?;
187 output.write_i8(self.placement_type)?;
188 output.write_u16::<LE>(0)?;
189 output.write_i32::<LE>(self.x)?;
190 output.write_i32::<LE>(self.y)?;
191 output.write_i8(self.amount_of_land_used_percent)?;
192 output.write_i8(self.by_player_flag)?;
193 output.write_u16::<LE>(0)?;
194 output.write_i32::<LE>(self.radius)?;
195 output.write_i32::<LE>(self.fade)?;
196 output.write_i32::<LE>(self.clumpiness_factor)?;
197 Ok(())
198 }
199}
200
201#[derive(Debug, Default, Clone)]
202pub struct RandomMapTerrain {
203 percent: i32,
204 terrain_type: i32,
205 clumps: i32,
206 spacing: i32,
207 base_terrain_type: i32,
208 clumpiness_factor: i32,
209}
210
211impl RandomMapTerrain {
212 pub fn read_from<R: Read>(input: &mut R) -> Result<Self> {
213 let mut terrain = Self::default();
214 terrain.percent = input.read_i32::<LE>()?;
215 terrain.terrain_type = input.read_i32::<LE>()?;
216 terrain.clumps = input.read_i32::<LE>()?;
217 terrain.spacing = input.read_i32::<LE>()?;
218 terrain.base_terrain_type = input.read_i32::<LE>()?;
219 terrain.clumpiness_factor = input.read_i32::<LE>()?;
220 Ok(terrain)
221 }
222
223 pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
224 output.write_i32::<LE>(self.percent)?;
225 output.write_i32::<LE>(self.terrain_type)?;
226 output.write_i32::<LE>(self.clumps)?;
227 output.write_i32::<LE>(self.spacing)?;
228 output.write_i32::<LE>(self.base_terrain_type)?;
229 output.write_i32::<LE>(self.clumpiness_factor)?;
230 Ok(())
231 }
232}
233
234#[derive(Debug, Default, Clone)]
235pub struct RandomMapObject {
236 unit_type: UnitTypeID,
237 terrain_type: i32,
238 group_flag: i8,
239 scale_flag: i8,
240 group_size: i32,
241 group_size_variance: i32,
242 group_count: i32,
243 group_area: i32,
244 player_id: i32,
245 land_id: i32,
246 min_distance_to_players: i32,
247 max_distance_to_players: i32,
248}
249
250impl RandomMapObject {
251 pub fn read_from<R: Read>(input: &mut R) -> Result<Self> {
252 let mut object = Self::default();
253 object.unit_type = input.read_u32::<LE>()?.try_into().unwrap();
254 object.terrain_type = input.read_i32::<LE>()?;
255 object.group_flag = input.read_i8()?;
256 object.scale_flag = input.read_i8()?;
257 let _padding = input.read_u16::<LE>()?;
258 object.group_size = input.read_i32::<LE>()?;
259 object.group_size_variance = input.read_i32::<LE>()?;
260 object.group_count = input.read_i32::<LE>()?;
261 object.group_area = input.read_i32::<LE>()?;
262 object.player_id = input.read_i32::<LE>()?;
263 object.land_id = input.read_i32::<LE>()?;
264 object.min_distance_to_players = input.read_i32::<LE>()?;
265 object.max_distance_to_players = input.read_i32::<LE>()?;
266 Ok(object)
267 }
268
269 pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
270 output.write_u32::<LE>(self.unit_type.try_into().unwrap())?;
271 output.write_i32::<LE>(self.terrain_type)?;
272 output.write_i8(self.group_flag)?;
273 output.write_i8(self.scale_flag)?;
274 output.write_u16::<LE>(0)?;
275 output.write_i32::<LE>(self.group_size)?;
276 output.write_i32::<LE>(self.group_size_variance)?;
277 output.write_i32::<LE>(self.group_count)?;
278 output.write_i32::<LE>(self.group_area)?;
279 output.write_i32::<LE>(self.player_id)?;
280 output.write_i32::<LE>(self.land_id)?;
281 output.write_i32::<LE>(self.min_distance_to_players)?;
282 output.write_i32::<LE>(self.max_distance_to_players)?;
283 Ok(())
284 }
285}
286
287#[derive(Debug, Default, Clone)]
288pub struct RandomMapElevation {
289 percent: i32,
290 height: i32,
291 clumps: i32,
292 spacing: i32,
293 base_terrain_type: i32,
294 base_elevation_type: i32,
295}
296
297impl RandomMapElevation {
298 pub fn read_from<R: Read>(input: &mut R) -> Result<Self> {
299 let mut elevation = Self::default();
300 elevation.percent = input.read_u32::<LE>()?.try_into().unwrap();
301 elevation.height = input.read_i32::<LE>()?;
302 elevation.clumps = input.read_i32::<LE>()?;
303 elevation.spacing = input.read_i32::<LE>()?;
304 elevation.base_terrain_type = input.read_i32::<LE>()?;
305 elevation.base_elevation_type = input.read_i32::<LE>()?;
306 Ok(elevation)
307 }
308
309 pub fn write_to<W: Write>(&self, output: &mut W) -> Result<()> {
310 output.write_i32::<LE>(self.percent)?;
311 output.write_i32::<LE>(self.height)?;
312 output.write_i32::<LE>(self.clumps)?;
313 output.write_i32::<LE>(self.spacing)?;
314 output.write_i32::<LE>(self.base_terrain_type)?;
315 output.write_i32::<LE>(self.base_elevation_type)?;
316 Ok(())
317 }
318}