use crate::prelude::*;
use crate::wad::build::builder::DataBuilder;
use crate::wad::chunk::gm_named_list_chunk;
use crate::wad::elem::GMElement;
use crate::wad::elem::audio::Audio;
use crate::wad::elem::audio_group::AudioGroup;
use crate::wad::parse::reader::DataReader;
use crate::wad::reference::GMRef;
use crate::wad::version::GMVersion;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Sounds {
pub elems: Vec<Option<Sound>>,
pub exists: bool,
}
gm_named_list_chunk!(SOND, Sounds, Sound, nullable);
impl GMElement for Sounds {
fn deserialize(reader: &mut DataReader) -> Result<Self> {
let elems: Vec<Option<Sound>> = reader.read_pointer_list_opt()?;
Ok(Self { elems, exists: true })
}
fn serialize(&self, builder: &mut DataBuilder) -> Result<()> {
builder.write_pointer_list_opt(&self.elems)?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Sound {
pub name: GMRef<String>,
pub flags: Flags,
pub audio_type: GMRef<String>,
pub file: GMRef<String>,
pub effects: u32,
pub volume: f32,
pub pitch: f32,
pub audio_group: GMRef<AudioGroup>,
pub audio: GMRef<Audio>,
pub audio_length: Option<f32>,
}
impl GMElement for Sound {
fn deserialize(reader: &mut DataReader) -> Result<Self> {
let name: GMRef<String> = reader.read_gm_string()?;
let flags = reader.read_u32()?;
let flags =
Flags::from_bits(flags).ok_or_else(|| format!("Invalid Sound Flags {flags:08X}"))?;
let audio_type: GMRef<String> = reader.read_gm_string()?;
let file: GMRef<String> = reader.read_gm_string()?;
let effects = reader.read_u32()?;
let volume = reader.read_f32()?;
let pitch = reader.read_f32()?;
let audio_group: GMRef<AudioGroup> =
if reader.general_info.wad_version >= 14 && flags.contains(Flags::REGULAR) {
reader.read_resource_by_id()?
} else {
let preload = reader.read_bool32().ctx("reading preload")?;
reader.assert_bool(preload, true, "Preload")?;
GMRef::new(get_builtin_sound_group_id(reader.general_info.version))
};
let audio: GMRef<Audio> = reader.read_resource_by_id()?;
let audio_length: Option<f32> = reader.deserialize_if_gm_version((2024, 6))?;
Ok(Self {
name,
flags,
audio_type,
file,
effects,
volume,
pitch,
audio_group,
audio,
audio_length,
})
}
fn serialize(&self, builder: &mut DataBuilder) -> Result<()> {
builder.write_gm_string(self.name)?;
builder.write_u32(self.flags.bits());
builder.write_gm_string(self.audio_type)?;
builder.write_gm_string(self.file)?;
builder.write_u32(self.effects);
builder.write_f32(self.volume);
builder.write_f32(self.pitch);
if builder.wad_version() >= 14 && self.flags.contains(Flags::REGULAR) {
builder.write_resource_id(self.audio_group);
} else {
builder.write_bool32(true); }
builder.write_resource_id(self.audio);
builder.write_if_ver(&self.audio_length, "Audio Length", (2024, 6))?;
Ok(())
}
}
#[allow(clippy::bool_to_int_with_if)] fn get_builtin_sound_group_id(version: GMVersion) -> i32 {
if test_gms1_version(version, 1250, 161) {
0
} else {
1
}
}
#[must_use]
fn test_gms1_version(version: GMVersion, stable_build: u32, beta_build: u32) -> bool {
assert!(beta_build < 1000);
version > (1, 0, 0, stable_build) || version > (1, 0, 0, beta_build)
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Flags: u32 {
const EMBEDDED = 0x1;
const COMPRESSED = 0x2;
const REGULAR = 0x64;
}
}