//! 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! { 12, BE in b => flags = u16[0]; ttype = u16[2]; pdata = u16[4]; beg = u16[6] usize; len = u16[8] usize; lines = u16[10]; } let flags = flag_ok!(GroupFlags, flags)?; 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! { 6, BE in b => start = u16[0] usize; face = u16[2]; color = u16[4]; } Ok((Face{start, face, color}, 6)) } /// Reads a `term` chunk. pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)> { read_data! { 10, BE in b => end = u16[0] usize; encoded = u16[2]; lines = u16[4]; group_n = u16[6] usize; 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. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Terminal { pub lines: u16, pub groups: Vec, pub faces: Vec, } /// A text face. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Face { pub start: usize, pub face: u16, pub color: u16, } /// A terminal command grouping. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Group { pub flags: GroupFlags, pub ttype: GroupType, pub lines: u16, pub text: String, } /// Interim structure. #[derive(Debug)] pub struct InterGroup { pub flags: GroupFlags, pub ttype: GroupType, pub lines: u16, pub beg: usize, pub len: usize, } /// The command of a `Group`. #[derive(Clone, Copy, Debug, PartialEq, serde::Serialize)] 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`. #[derive(Default, 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