1use crate::FileVersion;
2use arrayvec::ArrayString;
3use byteorder::{ReadBytesExt, WriteBytesExt, LE};
4use genie_support::{fallible_try_from, fallible_try_into, infallible_try_into};
5use std::convert::TryInto;
6use std::io::{Read, Result, Write};
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
10pub struct SoundID(u16);
11impl From<u16> for SoundID {
12 fn from(n: u16) -> Self {
13 SoundID(n)
14 }
15}
16
17impl From<SoundID> for u16 {
18 fn from(n: SoundID) -> Self {
19 n.0
20 }
21}
22
23impl From<SoundID> for usize {
24 fn from(n: SoundID) -> Self {
25 n.0.into()
26 }
27}
28
29fallible_try_into!(SoundID, i16);
30infallible_try_into!(SoundID, i32);
31infallible_try_into!(SoundID, u32);
32fallible_try_from!(SoundID, i16);
33fallible_try_from!(SoundID, i32);
34fallible_try_from!(SoundID, u32);
35
36#[derive(Debug, Default, Clone)]
41pub struct Sound {
42 pub id: SoundID,
44 pub play_delay: i16,
46 pub cache_time: i32,
48 pub items: Vec<SoundItem>,
50}
51
52#[derive(Debug, Default, Clone)]
54pub struct SoundItem {
55 pub filename: ArrayString<[u8; 13]>,
57 pub resource_id: i32,
59 pub probability: i16,
61 pub civilization: Option<i16>,
63 pub icon_set: Option<i16>,
65}
66
67impl SoundItem {
68 pub fn read_from<R: Read>(input: &mut R, _version: FileVersion) -> Result<Self> {
70 let mut item = SoundItem::default();
71 let mut filename = [0u8; 13];
73 input.read_exact(&mut filename)?;
74 item.resource_id = input.read_i32::<LE>()?;
75 item.probability = input.read_i16::<LE>()?;
76 item.civilization = Some(input.read_i16::<LE>()?);
78 item.icon_set = Some(input.read_i16::<LE>()?);
79
80 Ok(item)
81 }
82
83 pub fn write_to<W: Write>(&self, output: &mut W, _version: FileVersion) -> Result<()> {
85 output.write_all(&[0; 13])?;
86 output.write_i32::<LE>(self.resource_id)?;
87 output.write_i16::<LE>(self.probability)?;
88 assert!(self.civilization.is_some());
90 assert!(self.icon_set.is_some());
91 output.write_i16::<LE>(self.civilization.unwrap())?;
92 output.write_i16::<LE>(self.icon_set.unwrap())?;
93 Ok(())
94 }
95}
96
97impl Sound {
98 pub fn read_from<R: Read>(input: &mut R, version: FileVersion) -> Result<Self> {
100 let mut sound = Sound::default();
101 sound.id = input.read_u16::<LE>()?.into();
102 sound.play_delay = input.read_i16::<LE>()?;
103 let num_items = input.read_u16::<LE>()?;
104 sound.cache_time = input.read_i32::<LE>()?;
105 if version.is_de2() {
106 let _total_probability = input.read_u16::<LE>()?;
107 }
108 for _ in 0..num_items {
109 sound.items.push(SoundItem::read_from(input, version)?);
110 }
111 Ok(sound)
112 }
113
114 pub fn write_to<W: Write>(&self, output: &mut W, version: FileVersion) -> Result<()> {
116 output.write_u16::<LE>(self.id.into())?;
117 output.write_i16::<LE>(self.play_delay)?;
118 output.write_u16::<LE>(self.len().try_into().unwrap())?;
119 output.write_i32::<LE>(self.cache_time)?;
120 for item in &self.items {
121 item.write_to(output, version)?;
122 }
123 Ok(())
124 }
125
126 pub fn len(&self) -> usize {
128 self.items.len()
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.items.is_empty()
134 }
135}