use crate::FileVersion;
use arrayvec::ArrayString;
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use genie_support::{fallible_try_from, fallible_try_into, infallible_try_into};
use std::convert::TryInto;
use std::io::{Read, Result, Write};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct SoundID(u16);
impl From<u16> for SoundID {
fn from(n: u16) -> Self {
SoundID(n)
}
}
impl From<SoundID> for u16 {
fn from(n: SoundID) -> Self {
n.0
}
}
impl From<SoundID> for usize {
fn from(n: SoundID) -> Self {
n.0.into()
}
}
fallible_try_into!(SoundID, i16);
infallible_try_into!(SoundID, i32);
infallible_try_into!(SoundID, u32);
fallible_try_from!(SoundID, i16);
fallible_try_from!(SoundID, i32);
fallible_try_from!(SoundID, u32);
#[derive(Debug, Default, Clone)]
pub struct Sound {
pub id: SoundID,
pub play_delay: i16,
pub cache_time: i32,
pub items: Vec<SoundItem>,
}
#[derive(Debug, Default, Clone)]
pub struct SoundItem {
pub filename: ArrayString<[u8; 13]>,
pub resource_id: i32,
pub probability: i16,
pub civilization: Option<i16>,
pub icon_set: Option<i16>,
}
impl SoundItem {
pub fn read_from<R: Read>(input: &mut R, _version: FileVersion) -> Result<Self> {
let mut item = SoundItem::default();
let mut filename = [0u8; 13];
input.read_exact(&mut filename)?;
item.resource_id = input.read_i32::<LE>()?;
item.probability = input.read_i16::<LE>()?;
item.civilization = Some(input.read_i16::<LE>()?);
item.icon_set = Some(input.read_i16::<LE>()?);
Ok(item)
}
pub fn write_to<W: Write>(&self, output: &mut W, _version: FileVersion) -> Result<()> {
output.write_all(&[0; 13])?;
output.write_i32::<LE>(self.resource_id)?;
output.write_i16::<LE>(self.probability)?;
assert!(self.civilization.is_some());
assert!(self.icon_set.is_some());
output.write_i16::<LE>(self.civilization.unwrap())?;
output.write_i16::<LE>(self.icon_set.unwrap())?;
Ok(())
}
}
impl Sound {
pub fn read_from<R: Read>(input: &mut R, version: FileVersion) -> Result<Self> {
let mut sound = Sound::default();
sound.id = input.read_u16::<LE>()?.into();
sound.play_delay = input.read_i16::<LE>()?;
let num_items = input.read_u16::<LE>()?;
sound.cache_time = input.read_i32::<LE>()?;
if version.is_de2() {
let _total_probability = input.read_u16::<LE>()?;
}
for _ in 0..num_items {
sound.items.push(SoundItem::read_from(input, version)?);
}
Ok(sound)
}
pub fn write_to<W: Write>(&self, output: &mut W, version: FileVersion) -> Result<()> {
output.write_u16::<LE>(self.id.into())?;
output.write_i16::<LE>(self.play_delay)?;
output.write_u16::<LE>(self.len().try_into().unwrap())?;
output.write_i32::<LE>(self.cache_time)?;
for item in &self.items {
item.write_to(output, version)?;
}
Ok(())
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}