Maraiah/source/marathon/trm.rs

164 lines
3.5 KiB
Rust

//! Structures used by Marathon's Map format's terminal definitions.
use crate::durandal::{err::*, text::*};
use bitflags::bitflags;
/// Reads a `Group`.
pub fn read_group(b: &[u8], text: &[u8]) -> ResultS<Group>
{
read_data! {
12, BE in b =>
flags = u16[0];
ttype = u16[2];
pdata = u16[4];
start = u16[6] usize;
size = u16[8] usize;
lines = u16[10];
}
let text = ok!(text.get(start..start + size), "not enough data")?;
let text = mac_roman_cstr(text)?;
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(Group{flags, ttype, lines, text})
}
/// Reads a `Face`.
pub fn read_face(b: &[u8]) -> ResultS<Face>
{
read_data! {
6, BE in b =>
start = u16[0] usize;
face = u16[2];
color = u16[4];
}
Ok(Face{start, face, color})
}
/// Reads a `term` chunk.
pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)>
{
const SIZE_GROUP: usize = 12;
const SIZE_FACE: usize = 6;
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 mut groups = Vec::with_capacity(group_n);
let mut faces = Vec::with_capacity(face_n);
let mut p = 10;
let text_st = p + SIZE_GROUP * group_n + SIZE_FACE * face_n;
let text = ok!(b.get(text_st..end), "bad offset")?;
let text = if encoded {
fuck_string(text)
} else {
text.to_vec()
};
for _ in 0..group_n {
groups.push(read_group(ok!(b.get(p..), "not enough data")?, &text)?);
p += SIZE_GROUP;
}
for _ in 0..face_n {
faces.push(read_face(ok!(b.get(p..), "not enough data")?)?);
p += SIZE_FACE;
}
Ok((Terminal{lines, groups, faces}, end))
}
/// A terminal definition, with collections of groups and faces.
#[derive(Debug, PartialEq, serde::Serialize)]
pub struct Terminal
{
pub lines: u16,
pub groups: Vec<Group>,
pub faces: Vec<Face>,
}
/// 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,
}
/// The command of a `Group`.
#[derive(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(serde::Serialize)]
pub struct GroupFlags: u16
{
const DrawOnRight = 1;
const DrawCenter = 1 << 1;
}
}
// EOF