//! `Info` type. use crate::{err::*, text::*}; use bitflags::bitflags; /// Reads a `Minf` chunk. pub fn read(b: &[u8]) -> ResultS { read_data! { endian: BIG, buf: b, size: 88, start: 0, data { let texture_id = u16[0]; let physics_id = u16[2]; let skypict_id = u16[4]; let miss_flags = u16[6] flag MissionFlags; let envi_flags = u16[8] flag EnvironmentFlags; let level_name = mac_roman_cstr[18; 66] no_try; let entr_flags = u32[84] flag EntryFlags; } } Ok(Info{texture_id, physics_id, skypict_id, miss_flags, envi_flags, entr_flags, level_name}) } /// Writes a `Minf` chunk. pub fn write(v: &Info) -> Vec { let mut o = Vec::with_capacity(4); o.extend(&v.texture_id.to_be_bytes()); o.extend(&v.physics_id.to_be_bytes()); o.extend(&v.skypict_id.to_be_bytes()); o.extend(&v.miss_flags.bits().to_be_bytes()); o.extend(&v.envi_flags.bits().to_be_bytes()); o.extend(&pad_zero(to_mac_roman(&v.level_name), 66)); o.extend(&v.entr_flags.bits().to_be_bytes()); o } /// Reads an old `Minf` chunk. pub fn read_old(b: &[u8]) -> ResultS { let minf = read(b)?; let mut entr_flags = if minf.entr_flags.is_empty() { EntryFlags::SOLO } else { minf.entr_flags }; if entr_flags.intersects(EntryFlags::SOLO | EntryFlags::CARNAGE) { entr_flags.insert(EntryFlags::CO_OP) } Ok(Info{entr_flags, ..minf}) } impl Default for Info { fn default() -> Self { Self{texture_id: 0, physics_id: 1, skypict_id: 0, miss_flags: MissionFlags::empty(), envi_flags: EnvironmentFlags::empty(), entr_flags: EntryFlags::SOLO, level_name: "Map".to_string()} } } /// Static map information. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[derive(Clone, Debug, Eq, PartialEq)] pub struct Info { pub texture_id: u16, pub physics_id: u16, pub skypict_id: u16, pub miss_flags: MissionFlags, pub envi_flags: EnvironmentFlags, pub entr_flags: EntryFlags, pub level_name: String, } bitflags! { /// Static environment flags. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] pub struct EnvironmentFlags: u16 { const VACUUM = 1; const MAGNETIC = 1 << 1; const REBELLION = 1 << 2; const LOW_GRAV = 1 << 3; const M1_GLUE = 1 << 4; const LAVA_FLOOR = 1 << 5; const REBELLION2 = 1 << 6; const MUSIC = 1 << 7; const TERM_PAUSE = 1 << 8; const M1_MONSTER = 1 << 9; const M1_WEPS = 1 << 10; } } bitflags! { /// Static entry point flags. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] pub struct EntryFlags: u32 { const SOLO = 1; const CO_OP = 1 << 1; const CARNAGE = 1 << 2; const KTMWTB = 1 << 3; const KOTH = 1 << 4; const DEFENSE = 1 << 5; const RUGBY = 1 << 6; const CTF = 1 << 7; } } bitflags! { /// Static mission flags. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] pub struct MissionFlags: u16 { const EXTERMINATION = 1; const EXPLORATION = 1 << 1; const RETRIEVAL = 1 << 2; const REPAIR = 1 << 3; const RESCUE = 1 << 4; const M1_EXPLORATION = 1 << 5; const M1_RESCUE = 1 << 6; const M1_REPAIR = 1 << 7; } } // EOF