maraiah: rewrite how maps work
parent
be8d72df7d
commit
bfb91792ec
|
@ -3,11 +3,12 @@
|
|||
pub mod ambi;
|
||||
pub mod attk;
|
||||
pub mod bonk;
|
||||
pub mod chnk;
|
||||
pub mod damg;
|
||||
pub mod data;
|
||||
pub mod entr;
|
||||
pub mod epnt;
|
||||
pub mod fxpx;
|
||||
pub mod head;
|
||||
pub mod iidx;
|
||||
pub mod lins;
|
||||
pub mod lite;
|
||||
|
@ -32,74 +33,6 @@ pub mod trmf;
|
|||
pub mod trmg;
|
||||
pub mod wppx;
|
||||
|
||||
use crate::{err::*, text::mac_roman_cstr};
|
||||
|
||||
/// Reads a Map file.
|
||||
pub fn read(b: &[u8]) -> ResultS<Wad>
|
||||
{
|
||||
read_data! {
|
||||
endian: BIG, buf: b, size: 128, start: 0, data {
|
||||
let ver_wad = u16[0] enum Ver;
|
||||
let ver_dat = u16[2];
|
||||
let name = mac_roman_cstr[4; 64] no_try;
|
||||
let siz_app = u16[78] usize;
|
||||
let siz_wcnk = u16[80] usize;
|
||||
let siz_went = u16[82] usize;
|
||||
}
|
||||
}
|
||||
|
||||
let old_dat = ver_dat == 0;
|
||||
let old_wad = match ver_wad {
|
||||
Ver::Base => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let siz_ent = if old_wad {8 } else {10};
|
||||
let siz_cnk = if old_wad {12} else {16};
|
||||
|
||||
if !old_wad && siz_ent != siz_went {
|
||||
bail!("invalid entry size");
|
||||
}
|
||||
|
||||
if !old_wad && siz_cnk != siz_wcnk {
|
||||
bail!("invalid chunk size");
|
||||
}
|
||||
|
||||
let entries = entr::read(b, old_wad, siz_app, siz_ent, siz_cnk)?;
|
||||
|
||||
Ok(Wad{name, siz_app, old_dat, entries})
|
||||
}
|
||||
|
||||
/// A Map file containing entries.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Wad
|
||||
{
|
||||
/// The original name of this file.
|
||||
pub name: String,
|
||||
|
||||
/// The size of each `Entry`'s `appdata` field.
|
||||
pub siz_app: usize,
|
||||
|
||||
/// If the data is in Marathon 1 format.
|
||||
pub old_dat: bool,
|
||||
|
||||
/// All of the entries in this `Wad`.
|
||||
pub entries: entr::EntryMap,
|
||||
}
|
||||
|
||||
c_enum! {
|
||||
// The version of a `Wad`.
|
||||
#[derive(Debug)]
|
||||
enum Ver: u16
|
||||
{
|
||||
Base = 0,
|
||||
Dir = 1,
|
||||
Over = 2,
|
||||
Inf = 4,
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of game ticks per second.
|
||||
pub const TICKS_PER_SECOND: u16 = 30;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn read(b: &[u8]) -> ResultS<(SoundAmbi, usize)>
|
|||
|
||||
/// An ambient sound definition.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SoundAmbi
|
||||
{
|
||||
pub index: u16,
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn read(b: &[u8]) -> ResultS<(SoundRand, usize)>
|
|||
|
||||
/// A randomly played sound definition.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SoundRand
|
||||
{
|
||||
pub flags: SoundRandFlags,
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
//! Map file chunk type.
|
||||
|
||||
use crate::{bin::*, err::*, image::{self, pict}, map};
|
||||
|
||||
/// Reads all chunks in an entry.
|
||||
pub fn read(b: &[u8], siz_cnk: usize) -> ResultS<Vec<ChunkData>>
|
||||
{
|
||||
let mut chunks = Vec::new();
|
||||
let mut p = 0;
|
||||
|
||||
while p < b.len() {
|
||||
read_data! {
|
||||
endian: BIG, buf: b, size: siz_cnk, start: p, data {
|
||||
let iden = Ident[0];
|
||||
let size = u32[8] usize;
|
||||
}
|
||||
}
|
||||
|
||||
let beg = p + siz_cnk;
|
||||
let end = beg + size;
|
||||
let data = ok!(b.get(beg..end), "not enough data")?.to_vec();
|
||||
|
||||
chunks.push(ChunkData{iden, data});
|
||||
|
||||
p = end;
|
||||
}
|
||||
|
||||
Ok(chunks)
|
||||
}
|
||||
|
||||
/// Loads structured data from chunk data.
|
||||
pub fn load(chunk_data: &[ChunkData], old: bool) -> ResultS<Vec<Chunk>>
|
||||
{
|
||||
let mut chunks = Vec::new();
|
||||
|
||||
let read_chunk_minf = if old {map::minf::read_old} else {map::minf::read};
|
||||
let read_chunk_sids = if old {map::sids::read_old} else {map::sids::read};
|
||||
let read_chunk_poly = if old {map::poly::read_old} else {map::poly::read};
|
||||
let read_chunk_lite = if old {map::lite::read_old} else {map::lite::read};
|
||||
|
||||
for chunk in chunk_data.iter() {
|
||||
let data = &chunk.data;
|
||||
|
||||
let chunk = match &chunk.iden.0 {
|
||||
b"EPNT" => Chunk::Epnt(rd_array(data, map::epnt::read)?),
|
||||
b"FXpx" => Chunk::Fxpx(rd_array(data, map::fxpx::read)?),
|
||||
b"LINS" => Chunk::Lins(rd_array(data, map::lins::read)?),
|
||||
b"LITE" => Chunk::Lite(rd_array(data, read_chunk_lite)?),
|
||||
b"MNpx" => Chunk::Mnpx(rd_array(data, map::mnpx::read)?),
|
||||
b"Minf" => Chunk::Minf(read_chunk_minf(data)?),
|
||||
b"NAME" => Chunk::Name(rd_array(data, map::name::read)?),
|
||||
b"NOTE" => Chunk::Note(rd_array(data, map::note::read)?),
|
||||
b"OBJS" => Chunk::Objs(rd_array(data, map::objs::read)?),
|
||||
b"PICT" => Chunk::Pict(pict::read(data)?),
|
||||
b"PNTS" => Chunk::Pnts(rd_array(data, map::pnts::read)?),
|
||||
b"POLY" => Chunk::Poly(rd_array(data, read_chunk_poly)?),
|
||||
b"PRpx" => Chunk::Prpx(rd_array(data, map::prpx::read)?),
|
||||
b"PXpx" => Chunk::Pxpx(rd_array(data, map::pxpx::read)?),
|
||||
b"SIDS" => Chunk::Sids(rd_array(data, read_chunk_sids)?),
|
||||
b"WPpx" => Chunk::Wppx(rd_array(data, map::wppx::read)?),
|
||||
b"ambi" => Chunk::Ambi(rd_array(data, map::ambi::read)?),
|
||||
b"bonk" => Chunk::Bonk(rd_array(data, map::bonk::read)?),
|
||||
b"iidx" => Chunk::Iidx(rd_array(data, map::iidx::read)?),
|
||||
b"medi" => Chunk::Medi(rd_array(data, map::medi::read)?),
|
||||
b"plac" => Chunk::Plac(rd_array(data, map::plac::read)?),
|
||||
b"plat" => Chunk::Plat(rd_array(data, map::plat::read)?),
|
||||
b"term" => Chunk::Term(rd_array(data, map::term::read)?),
|
||||
_ => Chunk::Data(chunk.clone()),
|
||||
};
|
||||
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
Ok(chunks)
|
||||
}
|
||||
|
||||
/// The data of a Chunk read from a file.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ChunkData
|
||||
{
|
||||
/// The name of the chunk.
|
||||
pub iden: Ident,
|
||||
|
||||
/// The data.
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Any kind of chunk in an `Entry`.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum Chunk
|
||||
{
|
||||
/** `EPNT` chunks. */ Epnt(Vec<map::epnt::Endpoint>),
|
||||
/** `FXpx` chunks. */ Fxpx(Vec<map::fxpx::Effect>),
|
||||
/** `LINS` chunks. */ Lins(Vec<map::lins::Line>),
|
||||
/** `LITE` chunks. */ Lite(Vec<map::lite::Light>),
|
||||
/** `MNpx` chunks. */ Mnpx(Vec<map::mnpx::Monster>),
|
||||
/** `Minf` chunks. */ Minf(map::minf::Info),
|
||||
/** `NAME` chunks. */ Name(Vec<String>),
|
||||
/** `NOTE` chunks. */ Note(Vec<map::note::Note>),
|
||||
/** `OBJS` chunks. */ Objs(Vec<map::objs::Object>),
|
||||
/** `PICT` chunks. */ Pict(image::Image8),
|
||||
/** `PNTS` chunks. */ Pnts(Vec<map::pnts::Point>),
|
||||
/** `POLY` chunks. */ Poly(Vec<map::poly::Polygon>),
|
||||
/** `PRpx` chunks. */ Prpx(Vec<map::prpx::Projectile>),
|
||||
/** `PXpx` chunks. */ Pxpx(Vec<map::pxpx::Physics>),
|
||||
/** `SIDS` chunks. */ Sids(Vec<map::sids::Side>),
|
||||
/** `WPpx` chunks. */ Wppx(Vec<map::wppx::Weapon>),
|
||||
/** `ambi` chunks. */ Ambi(Vec<map::ambi::SoundAmbi>),
|
||||
/** `bonk` chunks. */ Bonk(Vec<map::bonk::SoundRand>),
|
||||
/** `iidx` chunks. */ Iidx(Vec<u16>),
|
||||
/** `medi` chunks. */ Medi(Vec<map::medi::Media>),
|
||||
/** `plac` chunks. */ Plac(Vec<map::plac::ObjectFreq>),
|
||||
/** `plat` chunks. */ Plat(Vec<map::plat::Platform>),
|
||||
/** `term` chunks. */ Term(Vec<map::term::Terminal>),
|
||||
/** Unknown chunk. */ Data(ChunkData),
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,114 @@
|
|||
//! Map file entry data.
|
||||
|
||||
use crate::{bin::*, err::*, image::{self, pict}, map};
|
||||
use super::{entr, head};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Reads all chunks in an entry.
|
||||
pub fn read(head: &head::Header, b: &[u8]) -> ResultS<EntryData>
|
||||
{
|
||||
let mut data = EntryData::default();
|
||||
|
||||
let old = head.old_data();
|
||||
|
||||
let rd_cminf = if old {map::minf::read_old} else {map::minf::read};
|
||||
let rd_csids = if old {map::sids::read_old} else {map::sids::read};
|
||||
let rd_cpoly = if old {map::poly::read_old} else {map::poly::read};
|
||||
let rd_clite = if old {map::lite::read_old} else {map::lite::read};
|
||||
|
||||
let mut p = 0;
|
||||
|
||||
while p < b.len() {
|
||||
read_data! {
|
||||
endian: BIG, buf: b, size: head.size_chunk(), start: p, data {
|
||||
let iden = Ident[0];
|
||||
let size = u32[8] usize;
|
||||
}
|
||||
}
|
||||
|
||||
let beg = p + head.size_chunk();
|
||||
let end = beg + size;
|
||||
let buf = ok!(b.get(beg..end), "not enough data")?;
|
||||
|
||||
match &iden.0 {
|
||||
b"EPNT" => data.epnt = Some(rd_array(buf, map::epnt::read)?),
|
||||
b"FXpx" => data.fxpx = Some(rd_array(buf, map::fxpx::read)?),
|
||||
b"LINS" => data.lins = Some(rd_array(buf, map::lins::read)?),
|
||||
b"LITE" => data.lite = Some(rd_array(buf, rd_clite)?),
|
||||
b"MNpx" => data.mnpx = Some(rd_array(buf, map::mnpx::read)?),
|
||||
b"Minf" => data.minf = Some(rd_cminf(buf)?),
|
||||
b"NAME" => data.name = Some(rd_array(buf, map::name::read)?),
|
||||
b"NOTE" => data.note = Some(rd_array(buf, map::note::read)?),
|
||||
b"OBJS" => data.objs = Some(rd_array(buf, map::objs::read)?),
|
||||
b"PICT" => data.pict = Some(pict::read(buf)?),
|
||||
b"PNTS" => data.pnts = Some(rd_array(buf, map::pnts::read)?),
|
||||
b"POLY" => data.poly = Some(rd_array(buf, rd_cpoly)?),
|
||||
b"PRpx" => data.prpx = Some(rd_array(buf, map::prpx::read)?),
|
||||
b"PXpx" => data.pxpx = Some(rd_array(buf, map::pxpx::read)?),
|
||||
b"SIDS" => data.sids = Some(rd_array(buf, rd_csids)?),
|
||||
b"WPpx" => data.wppx = Some(rd_array(buf, map::wppx::read)?),
|
||||
b"ambi" => data.ambi = Some(rd_array(buf, map::ambi::read)?),
|
||||
b"bonk" => data.bonk = Some(rd_array(buf, map::bonk::read)?),
|
||||
b"iidx" => data.iidx = Some(rd_array(buf, map::iidx::read)?),
|
||||
b"medi" => data.medi = Some(rd_array(buf, map::medi::read)?),
|
||||
b"plac" => data.plac = Some(rd_array(buf, map::plac::read)?),
|
||||
b"plat" => data.plat = Some(rd_array(buf, map::plat::read)?),
|
||||
b"term" => data.term = Some(rd_array(buf, map::term::read)?),
|
||||
_ => data.unkn.push((iden, buf.to_vec())),
|
||||
}
|
||||
|
||||
p = end;
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
/// Reads all of the data from an entry map.
|
||||
pub fn read_all(head: &head::Header,
|
||||
map: &entr::EntryMap<'_>) -> ResultS<EntryDataMap>
|
||||
{
|
||||
let mut dmap = EntryDataMap::new();
|
||||
|
||||
for (&index, entry) in map {
|
||||
dmap.insert(index, read(head, &entry.data)?);
|
||||
}
|
||||
|
||||
Ok(dmap)
|
||||
}
|
||||
|
||||
/// The loaded data of a Map file entry.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub struct EntryData
|
||||
{
|
||||
/** `EPNT` chunk data. */ pub epnt: Option<Vec<map::epnt::Endpoint>>,
|
||||
/** `FXpx` chunk data. */ pub fxpx: Option<Vec<map::fxpx::Effect>>,
|
||||
/** `LINS` chunk data. */ pub lins: Option<Vec<map::lins::Line>>,
|
||||
/** `LITE` chunk data. */ pub lite: Option<Vec<map::lite::Light>>,
|
||||
/** `MNpx` chunk data. */ pub mnpx: Option<Vec<map::mnpx::Monster>>,
|
||||
/** `Minf` chunk data. */ pub minf: Option<map::minf::Info>,
|
||||
/** `NAME` chunk data. */ pub name: Option<Vec<String>>,
|
||||
/** `NOTE` chunk data. */ pub note: Option<Vec<map::note::Note>>,
|
||||
/** `OBJS` chunk data. */ pub objs: Option<Vec<map::objs::Object>>,
|
||||
/** `PICT` chunk data. */ pub pict: Option<image::Image8>,
|
||||
/** `PNTS` chunk data. */ pub pnts: Option<Vec<map::pnts::Point>>,
|
||||
/** `POLY` chunk data. */ pub poly: Option<Vec<map::poly::Polygon>>,
|
||||
/** `PRpx` chunk data. */ pub prpx: Option<Vec<map::prpx::Projectile>>,
|
||||
/** `PXpx` chunk data. */ pub pxpx: Option<Vec<map::pxpx::Physics>>,
|
||||
/** `SIDS` chunk data. */ pub sids: Option<Vec<map::sids::Side>>,
|
||||
/** `WPpx` chunk data. */ pub wppx: Option<Vec<map::wppx::Weapon>>,
|
||||
/** `ambi` chunk data. */ pub ambi: Option<Vec<map::ambi::SoundAmbi>>,
|
||||
/** `bonk` chunk data. */ pub bonk: Option<Vec<map::bonk::SoundRand>>,
|
||||
/** `iidx` chunk data. */ pub iidx: Option<Vec<u16>>,
|
||||
/** `medi` chunk data. */ pub medi: Option<Vec<map::medi::Media>>,
|
||||
/** `plac` chunk data. */ pub plac: Option<Vec<map::plac::ObjectFreq>>,
|
||||
/** `plat` chunk data. */ pub plat: Option<Vec<map::plat::Platform>>,
|
||||
/** `term` chunk data. */ pub term: Option<Vec<map::term::Terminal>>,
|
||||
|
||||
pub unkn: Vec<(Ident, Vec<u8>)>,
|
||||
}
|
||||
|
||||
/// A map of indexed entries.
|
||||
pub type EntryDataMap = BTreeMap<u16, EntryData>;
|
||||
|
||||
// EOF
|
|
@ -1,61 +1,60 @@
|
|||
//! Wad file entry type.
|
||||
//! Map file entry type.
|
||||
|
||||
use crate::err::*;
|
||||
use super::chnk;
|
||||
use super::head;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Reads all entries in a `Wad`.
|
||||
pub fn read(b: &[u8],
|
||||
old_wad: bool,
|
||||
siz_app: usize,
|
||||
siz_ent: usize,
|
||||
siz_cnk: usize) -> ResultS<EntryMap>
|
||||
/// Read an entry from a Map file.
|
||||
pub fn read(map: &head::Map, i: usize) -> ResultS<(u16, Entry<'_>)>
|
||||
{
|
||||
let size = map.head().size_entry();
|
||||
|
||||
read_data! {
|
||||
endian: BIG, buf: b, size: 128, start: 0, data {
|
||||
let dirofs = u32[72] usize;
|
||||
let numents = u16[76] usize;
|
||||
endian: BIG, buf: map.dir(), size: size, start: size * i, data {
|
||||
let offset = u32[0] usize;
|
||||
let dsize = u32[4] usize;
|
||||
let index = u16[8];
|
||||
let app_data = u8[10; map.head().size_appl()];
|
||||
}
|
||||
}
|
||||
|
||||
let mut entries = EntryMap::new();
|
||||
let mut p = dirofs;
|
||||
let data = &map.data()[offset..offset + dsize];
|
||||
let index = if map.head().old_wad() {i as u16} else {index};
|
||||
|
||||
for i in 0..numents {
|
||||
read_data! {
|
||||
endian: BIG, buf: b, size: siz_ent, start: p, data {
|
||||
let offset = u32[0] usize;
|
||||
let size = u32[4] usize;
|
||||
let index = u16[8];
|
||||
}
|
||||
Ok((index, Entry{data, app_data}))
|
||||
}
|
||||
|
||||
/// Reads all entries in a Map file.
|
||||
pub fn read_all(map: &head::Map) -> ResultS<EntryMap<'_>>
|
||||
{
|
||||
let mut entries = EntryMap::new();
|
||||
|
||||
for i in 0..map.num_ent() {
|
||||
let (index, entry) = read(map, i)?;
|
||||
|
||||
if entries.contains_key(&index) {
|
||||
bail!("entry index already exists");
|
||||
}
|
||||
|
||||
let index = if old_wad {i as u16} else {index};
|
||||
|
||||
let chunks = chnk::read(&b[offset..offset + size], siz_cnk)?;
|
||||
let appdata = b[p..p + siz_app].to_vec();
|
||||
|
||||
entries.insert(index, Entry{chunks, appdata});
|
||||
|
||||
p += siz_ent + siz_app;
|
||||
entries.insert(index, entry);
|
||||
}
|
||||
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
/// An entry containing chunks and application-specific data.
|
||||
/// An entry containing chunked data and application-specific data.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Entry
|
||||
pub struct Entry<'a>
|
||||
{
|
||||
/// All of the chunks in this `Entry`.
|
||||
pub chunks: Vec<chnk::ChunkData>,
|
||||
/// The data in this `Entry`.
|
||||
pub data: &'a [u8],
|
||||
|
||||
/// The application specific data for this Entry.
|
||||
pub appdata: Vec<u8>,
|
||||
pub app_data: &'a [u8],
|
||||
}
|
||||
|
||||
/// A map of indexed entries.
|
||||
pub type EntryMap = BTreeMap<u16, Entry>;
|
||||
pub type EntryMap<'a> = BTreeMap<u16, Entry<'a>>;
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
//! Map file header.
|
||||
|
||||
use crate::{err::*, text::mac_roman_cstr};
|
||||
use std::io::prelude::*;
|
||||
|
||||
/// Reads a Map file.
|
||||
pub fn read(rd: &mut impl Read) -> ResultS<Map>
|
||||
{
|
||||
let mut data = Vec::new();
|
||||
rd.read_to_end(&mut data)?;
|
||||
|
||||
read_data! {
|
||||
endian: BIG, buf: &data, size: 128, start: 0, data {
|
||||
let ver_wad = u16[0] enum Ver;
|
||||
let ver_data = u16[2];
|
||||
let name = mac_roman_cstr[4; 64] no_try;
|
||||
let dir_ofs = u32[72] usize;
|
||||
let num_ent = u16[76] usize;
|
||||
let size_appl = u16[78] usize;
|
||||
let size_wcnk = u16[80] usize;
|
||||
let size_went = u16[82] usize;
|
||||
}
|
||||
}
|
||||
|
||||
let head = Header::new(size_appl, ver_data, ver_wad, Some(name));
|
||||
|
||||
if !head.old_wad() && head.size_entry_base() != size_went {
|
||||
bail!("invalid entry size");
|
||||
}
|
||||
|
||||
if !head.old_wad() && head.size_chunk() != size_wcnk {
|
||||
bail!("invalid chunk size");
|
||||
}
|
||||
|
||||
let map = Map{head, data, dir_ofs, num_ent};
|
||||
|
||||
if map.dir_end() > map.data.len() {
|
||||
bail!("not enough data in map file");
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
impl Header
|
||||
{
|
||||
/// Creates a new `Header`.
|
||||
pub fn new(size_appl: usize,
|
||||
ver_data: u16,
|
||||
ver_wad: Ver,
|
||||
name: Option<String>) -> Self
|
||||
{
|
||||
let name = name.unwrap_or(String::new());
|
||||
Header{name, size_appl, ver_data, ver_wad}
|
||||
}
|
||||
|
||||
/// Returns `true` if the data is in Marathon 1 format.
|
||||
#[inline]
|
||||
pub fn old_data(&self) -> bool {self.ver_data() == 0}
|
||||
|
||||
/// Returns `true` if the Map file is in Marathon 1 format.
|
||||
#[inline]
|
||||
pub fn old_wad(&self) -> bool {self.ver_wad() == Ver::Base}
|
||||
|
||||
/// The data version of this file.
|
||||
#[inline]
|
||||
pub const fn ver_data(&self) -> u16 {self.ver_data}
|
||||
|
||||
/// The format version of this file.
|
||||
#[inline]
|
||||
pub const fn ver_wad(&self) -> Ver {self.ver_wad}
|
||||
|
||||
/// The size of each `Entry`'s `appdata` field.
|
||||
#[inline]
|
||||
pub const fn size_appl(&self) -> usize {self.size_appl}
|
||||
|
||||
/// The size of each `Entry`'s data.
|
||||
#[inline]
|
||||
pub fn size_entry_base(&self) -> usize {if self.old_wad() {8} else {10}}
|
||||
|
||||
/// The size of each `Entry`.
|
||||
#[inline]
|
||||
pub fn size_entry(&self) -> usize {self.size_entry_base() + self.size_appl()}
|
||||
|
||||
/// The size of each chunk's header.
|
||||
#[inline]
|
||||
pub fn size_chunk(&self) -> usize {if self.old_wad() {12} else {16}}
|
||||
}
|
||||
|
||||
impl Map
|
||||
{
|
||||
/// The header for this map.
|
||||
pub fn head(&self) -> &Header {&self.head}
|
||||
|
||||
/// The data section of this map.
|
||||
pub fn data(&self) -> &[u8] {&self.data[..]}
|
||||
|
||||
/// The directory section of this map.
|
||||
pub fn dir(&self) -> &[u8] {&self.data[self.dir_beg()..self.dir_end()]}
|
||||
|
||||
/// The number of entries in the directory.
|
||||
pub fn num_ent(&self) -> usize {self.num_ent}
|
||||
|
||||
fn dir_beg(&self) -> usize {self.dir_ofs}
|
||||
|
||||
fn dir_end(&self) -> usize
|
||||
{
|
||||
self.dir_ofs + self.head.size_entry() * self.num_ent
|
||||
}
|
||||
}
|
||||
|
||||
/// A Map header.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Header
|
||||
{
|
||||
/// The original name of this file.
|
||||
pub name: String,
|
||||
|
||||
size_appl: usize,
|
||||
ver_data: u16,
|
||||
ver_wad: Ver,
|
||||
}
|
||||
|
||||
/// A Map file.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Map
|
||||
{
|
||||
head: Header,
|
||||
data: Vec<u8>,
|
||||
dir_ofs: usize,
|
||||
num_ent: usize,
|
||||
}
|
||||
|
||||
c_enum! {
|
||||
/// The version of a Map file.
|
||||
#[derive(Debug)]
|
||||
pub enum Ver: u16
|
||||
{
|
||||
Base = 0,
|
||||
Dir = 1,
|
||||
Over = 2,
|
||||
Inf = 4,
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -23,7 +23,7 @@ pub fn read(b: &[u8]) -> ResultS<(Line, usize)>
|
|||
|
||||
/// A line segment.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Line
|
||||
{
|
||||
pub flags: LineFlags,
|
||||
|
|
|
@ -72,7 +72,7 @@ pub fn read_old(b: &[u8]) -> ResultS<(Light, usize)>
|
|||
|
||||
/// A dynamic polygon light.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Light
|
||||
{
|
||||
pub ltype: LightType,
|
||||
|
|
|
@ -32,7 +32,7 @@ pub fn write(v: &LightFunc) -> Vec<u8>
|
|||
|
||||
/// A light function.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct LightFunc
|
||||
{
|
||||
pub ftype: LightFuncType,
|
||||
|
|
|
@ -33,7 +33,7 @@ pub fn read(b: &[u8]) -> ResultS<(Media, usize)>
|
|||
|
||||
/// A media, as in a part of a polygon which goes up the middle of the wall.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Media
|
||||
{
|
||||
pub mtype: MediaType,
|
||||
|
|
|
@ -19,7 +19,7 @@ pub fn read(b: &[u8]) -> ResultS<(Note, usize)>
|
|||
|
||||
/// Overhead map annotations.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Note
|
||||
{
|
||||
pub pos: pnts::Point,
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn read(b: &[u8]) -> ResultS<(Object, usize)>
|
|||
|
||||
/// An object in the world.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Object
|
||||
{
|
||||
pub group: u16,
|
||||
|
|
|
@ -22,7 +22,7 @@ pub fn read(b: &[u8]) -> ResultS<(ObjectFreq, usize)>
|
|||
|
||||
/// The difficulty definition for various object types.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ObjectFreq
|
||||
{
|
||||
pub flags: ObjectFreqFlags,
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn read(b: &[u8]) -> ResultS<(Platform, usize)>
|
|||
|
||||
/// Extra information for polygons with platforms.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Platform
|
||||
{
|
||||
pub ptype: u16,
|
||||
|
|
|
@ -130,7 +130,7 @@ impl Default for PolyType
|
|||
|
||||
/// A polygon segment.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Polygon
|
||||
{
|
||||
pub ptype: PolyType,
|
||||
|
@ -153,7 +153,7 @@ pub struct Polygon
|
|||
|
||||
/// The action type of a `Polygon`.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum PolyType
|
||||
{
|
||||
Normal,
|
||||
|
|
|
@ -40,7 +40,7 @@ pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)>
|
|||
|
||||
/// One side of a line segment.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct Side
|
||||
{
|
||||
pub stype: SideType,
|
||||
|
|
|
@ -27,7 +27,7 @@ pub fn write(v: &SideTex) -> Vec<u8>
|
|||
|
||||
/// The texture of a side segment.
|
||||
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SideTex
|
||||
{
|
||||
pub offs: pnts::Point,
|
||||
|
|
Loading…
Reference in New Issue