//! Structures used by Marathon's Map format's terminal definitions. use crate::durandal::{bin::*, err::*, text::*}; use bitflags::bitflags; /// Reads an `InterGroup`. pub fn read_group(b: &[u8]) -> ResultS<(InterGroup, usize)> { read_data! { endian: BIG, buf: b, size: 12, start: 0, data { let flags = u16[0] flag GroupFlags; let ttype = u16[2]; let pdata = u16[4]; let beg = u16[6] usize; let len = u16[8] usize; let lines = u16[10]; } } let ttype = match ttype { 0 => GroupType::Logon(pdata), 1 => GroupType::Unfinished, 2 => GroupType::Success, 3 => GroupType::Failure, 4 => GroupType::Info, 5 => GroupType::End, 6 => GroupType::TeleInter(pdata), 7 => GroupType::TeleIntra(pdata), 8 => GroupType::Checkpoint(pdata), 9 => GroupType::Sound(pdata), 10 => GroupType::Movie(pdata), 11 => GroupType::Track(pdata), 12 => GroupType::Pict(pdata), 13 => GroupType::Logoff(pdata), 14 => GroupType::Camera(pdata), 15 => GroupType::Static(pdata), 16 => GroupType::Tag(pdata), n => return Err(ReprError::new(n).into()), }; Ok((InterGroup{flags, ttype, lines, beg, len}, 12)) } /// Reads a `Face`. pub fn read_face(b: &[u8]) -> ResultS<(Face, usize)> { read_data! { endian: BIG, buf: b, size: 6, start: 0, data { let start = u16[0] usize; let face = u16[2]; let color = u16[4]; } } Ok((Face{start, face, color}, 6)) } /// Reads a `term` chunk. pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)> { read_data! { endian: BIG, buf: b, size: 10, start: 0, data { let end = u16[0] usize; let encoded = u16[2]; let lines = u16[4]; let group_n = u16[6] usize; let face_n = u16[8] usize; } } let encoded = encoded != 0; let (i_grp, x) = rd_array_num(&b[10..], group_n, read_group)?; let (faces, y) = rd_array_num(&b[10 + x..], face_n, read_face)?; let text = ok!(b.get(10 + x + y..end), "not enough data")?; let text = if encoded {fuck_string(text)} else {text.to_vec()}; let mut groups = Vec::with_capacity(group_n); for grp in &i_grp { let flags = grp.flags; let ttype = grp.ttype; let lines = grp.lines; let beg = grp.beg; let len = grp.len; let text = ok!(text.get(beg..beg + len), "bad offset")?; let text = mac_roman_cstr(text); groups.push(Group{flags, ttype, lines, text}); } Ok((Terminal{lines, groups, faces}, end)) } impl Default for GroupType { fn default() -> Self {GroupType::Unfinished} } /// A terminal definition, with collections of groups and faces. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[derive(Debug, Eq, PartialEq)] pub struct Terminal { pub lines: u16, pub groups: Vec, pub faces: Vec, } /// A text face. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[derive(Debug, Eq, PartialEq)] pub struct Face { pub start: usize, pub face: u16, pub color: u16, } /// A terminal command grouping. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[derive(Debug, Eq, PartialEq)] pub struct Group { pub flags: GroupFlags, pub ttype: GroupType, pub lines: u16, pub text: String, } /// Interim structure. #[derive(Debug, Eq, PartialEq)] pub struct InterGroup { pub flags: GroupFlags, pub ttype: GroupType, pub lines: u16, pub beg: usize, pub len: usize, } /// The command of a `Group`. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum GroupType { Logon(u16), Unfinished, Success, Failure, Info, End, TeleInter(u16), TeleIntra(u16), Checkpoint(u16), Sound(u16), Movie(u16), Track(u16), Pict(u16), Logoff(u16), Camera(u16), Static(u16), Tag(u16), } bitflags! { /// Flags for `Group`. #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] pub struct GroupFlags: u16 { /// Draws the picture on the right. const DRAW_ON_RIGHT = 1; /// Draws the picture in the center. const DRAW_CENTER = 1 << 1; } } // EOF