diff --git a/source/marathon/map.rs b/source/marathon/map.rs index 9a70c6b..05fcb99 100644 --- a/source/marathon/map.rs +++ b/source/marathon/map.rs @@ -1,1291 +1,24 @@ //! Structures used by Marathon's Map format. -use crate::{durandal::{bin::*, err::*, fixed::*}, - marathon::{text::*, xfer::TransferMode}}; -use bitflags::bitflags; - -/// Reads a `LightFunc` object. -pub fn read_lightfunc(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 14, start: 0, data { - let ftype = u16[0] enum LightFuncType; - let prd_nrm = u16[2]; - let prd_dta = u16[4]; - let val_nrm = Fixed[6]; - let val_dta = Fixed[10]; - } - } - - Ok(LightFunc{ftype, prd_nrm, prd_dta, val_nrm, val_dta}) -} - -/// Writes a `LightFunc` object. -pub fn write_lightfunc(v: &LightFunc) -> Vec -{ - let mut o = Vec::with_capacity(14); - o.extend(&(v.ftype as u16).to_be_bytes()); - o.extend(&v.prd_nrm.to_be_bytes()); - o.extend(&v.prd_dta.to_be_bytes()); - o.extend(&v.val_nrm.to_be_bytes()); - o.extend(&v.val_dta.to_be_bytes()); - o -} - -/// Reads a `SideTex` object. -pub fn read_sidetex(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 6, start: 0, data { - let offs = read_point[0; 4]; - let tex_id = OptU16[4]; - } - } - - Ok(SideTex{offs, tex_id}) -} - -/// Writes a `SideTex` object. -pub fn write_sidetex(v: &SideTex) -> Vec -{ - let mut o = Vec::with_capacity(6); - o.extend(write_point(v.offs)); - o.extend(&v.tex_id.to_be_bytes()); - o -} - -/// Reads a `Point` object. -pub fn read_point(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 4, start: 0, data { - let x = Unit[0]; - let y = Unit[2]; - } - } - - Ok(Point{x, y}) -} - -/// Writes a `Point` object. -pub fn write_point(v: Point) -> Vec -{ - let mut o = Vec::with_capacity(4); - o.extend(&v.x.to_be_bytes()); - o.extend(&v.y.to_be_bytes()); - o -} - -/// Reads a `Minf` chunk. -pub fn read_minf(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 MsnFlags; - let envi_flags = u16[8] flag EnvFlags; - let level_name = mac_roman_cstr[18; 66] no_try; - let entr_flags = u32[84] flag EntFlags; - } - } - - Ok(Minf{texture_id, physics_id, skypict_id, miss_flags, envi_flags, - entr_flags, level_name}) -} - -/// Writes a `Minf` chunk. -pub fn write_minf(v: &Minf) -> 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_minf(b: &[u8]) -> ResultS -{ - let minf = read_minf(b)?; - - let mut entr_flags = if minf.entr_flags.is_empty() { - EntFlags::SOLO - } else { - minf.entr_flags - }; - - if entr_flags.intersects(EntFlags::SOLO | EntFlags::CARNAGE) { - entr_flags.insert(EntFlags::CO_OP) - } - - Ok(Minf{entr_flags, ..minf}) -} - -/// Reads an `iidx` chunk. -pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)> -{ - check_data!(2, b); - - Ok((u16b(b), 2)) -} - -/// Reads an `EPNT` chunk. -pub fn read_epnt(b: &[u8]) -> ResultS<(Point, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 16, start: 0, data { - let pnt = read_point[6; 4]; - } - } - - Ok((pnt, 16)) -} - -/// Reads a `PNTS` chunk. -pub fn read_pnts(b: &[u8]) -> ResultS<(Point, usize)> -{ - Ok((read_point(b)?, 4)) -} - -/// Reads a `LINS` chunk. -pub fn read_lins(b: &[u8]) -> ResultS<(Line, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 32, start: 0, data { - let pnt_beg = u16[0]; - let pnt_end = u16[2]; - let flags = u16[4] flag LineFlags; - let side_fr = OptU16[12]; - let side_bk = OptU16[14]; - let poly_fr = OptU16[16]; - let poly_bk = OptU16[18]; - } - } - - Ok((Line{flags, pnt_beg, pnt_end, side_fr, side_bk, poly_fr, poly_bk}, 32)) -} - -/// Reads a `SIDS` chunk. -pub fn read_sids(b: &[u8]) -> ResultS<(Side, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 64, start: 0, data { - let stype = u16[0] enum SideType; - let flags = u16[2] flag SideFlags; - let tex_pri = read_sidetex[4; 6]; - let tex_sec = read_sidetex[10; 6]; - let tex_tra = read_sidetex[16; 6]; - let paneltyp = u16[38]; - let paneldat = i16[40]; - let xfer_pri = u16[42] enum TransferMode; - let xfer_sec = u16[44] enum TransferMode; - let xfer_tra = u16[46] enum TransferMode; - let shade = Fixed[48]; - } - } - - Ok((Side{stype, flags, tex_pri, tex_sec, tex_tra, paneltyp, paneldat, - xfer_pri, xfer_sec, xfer_tra, shade}, 64)) -} - -/// Reads an old `SIDS` chunk. -pub fn read_old_sids(b: &[u8]) -> ResultS<(Side, usize)> -{ - let (side, siz) = read_sids(b)?; - - Ok((Side{tex_tra: SideTex{tex_id: OptU16::none(), ..side.tex_tra}, - shade: 0.into(), - flags: side.flags | SideFlags::ITEM_OPT, - ..side}, siz)) -} - -/// Reads a polygon for either M1 or M2. -fn read_poly_inter(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 128, start: 0, data { - let tex_flr = OptU16[40]; - let tex_cei = OptU16[42]; - let hei_flr = Unit[44]; - let hei_cei = Unit[46]; - let lit_flr = u16[48]; - let lit_cei = u16[50]; - let xfr_flr = u16[64] enum TransferMode; - let xfr_cei = u16[66] enum TransferMode; - } - } - - Ok(Polygon{tex_flr, tex_cei, hei_flr, hei_cei, lit_flr, lit_cei, xfr_flr, - xfr_cei, ..Polygon::default()}) -} - -/// Reads a `POLY` chunk. -pub fn read_poly(b: &[u8]) -> ResultS<(Polygon, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 128, start: 0, data { - let ptype = u16[0]; - let pdata = u16[4]; - let ori_flr = read_point[108; 4]; - let ori_cei = read_point[112; 4]; - let med_ind = OptU16[116]; - let med_ctl = u16[118]; - let snd_amb = OptU16[122]; - let snd_ind = u16[120]; - let snd_rnd = OptU16[124]; - } - } - - let poly = read_poly_inter(b)?; - let ptype = PolyType::new(ptype, pdata)?; - - Ok((Polygon{ptype, ori_flr, ori_cei, med_ind, med_ctl, snd_ind, snd_amb, - snd_rnd, ..poly}, 128)) -} - -/// Reads an old `POLY` chunk. -pub fn read_old_poly(b: &[u8]) -> ResultS<(Polygon, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 128, start: 0, data { - let ptype = u16[0]; - let pdata = u16[4]; - } - } - - let poly = read_poly_inter(b)?; - let ptype = PolyType::new_old(ptype, pdata)?; - - Ok((Polygon{ptype, ..poly}, 128)) -} - -/// Reads a `LITE` chunk. -pub fn read_lite(b: &[u8]) -> ResultS<(Light, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 100, start: 0, data { - let ltype = u16[0] enum LightType; - let flags = u16[2] flag LightFlags; - let phase = i16[4]; - let act_pri = read_lightfunc[6; 14]; - let act_sec = read_lightfunc[20; 14]; - let act_mid = read_lightfunc[34; 14]; - let ina_pri = read_lightfunc[48; 14]; - let ina_sec = read_lightfunc[62; 14]; - let ina_mid = read_lightfunc[76; 14]; - let tag = u16[90]; - } - } - - Ok((Light{ltype, flags, phase, act_pri, act_sec, act_mid, ina_pri, ina_sec, - ina_mid, tag}, 100)) -} - -/// Reads an old `LITE` chunk. -pub fn read_old_lite(b: &[u8]) -> ResultS<(Light, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 32, start: 0, data { - let ltype = u16[2] usize; - let mode = u16[4]; - let phase = i16[6]; - let min = Fixed[8]; - let max = Fixed[12]; - let prd = u16[16]; - } - } - - if OLD_LIGHT_DEFINITIONS.len() < ltype { - bail!("bad old light type"); - } - - let lite = &OLD_LIGHT_DEFINITIONS[ltype]; - let on = mode == 0 || mode == 1; - let strobe = ltype == 3; - let flags = if on {lite.flags | LightFlags::INIT_ACTIVE} else {lite.flags}; - - // modify each old light function accordingly - let old_lfun = move |func: &LightFunc| -> LightFunc { - LightFunc{ftype: func.ftype, - prd_nrm: if strobe {prd / 4 + 1} else {func.prd_nrm}, - prd_dta: func.prd_dta, - val_nrm: if func.val_nrm > 0.into() {max} else {min}, - val_dta: func.val_dta} - }; - - Ok((Light{flags, - phase, - act_pri: old_lfun(&lite.act_pri), - act_sec: old_lfun(&lite.act_sec), - act_mid: old_lfun(&lite.act_mid), - ina_pri: old_lfun(&lite.ina_pri), - ina_sec: old_lfun(&lite.ina_sec), - ina_mid: old_lfun(&lite.ina_mid), - tag: 0, - ..*lite}, 32)) -} - -/// Reads an `OBJS` chunk. -pub fn read_objs(b: &[u8]) -> ResultS<(Object, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 16, start: 0, data { - let group = u16[0]; - let index = u16[2]; - let angle = Angle[4]; - let poly = u16[6]; - let pos_x = Unit[8]; - let pos_y = Unit[10]; - let pos_z = Unit[12]; - let flags = u16[14]; - } - } - - let bias = flags & 0xF0_00; - let flags = flags & 0x0F_FF; - let bias = bias >> 12; - let flags = flag_ok!(ObjectFlags, flags)?; - - Ok((Object{group, index, angle, poly, pos_x, pos_y, pos_z, flags, bias}, 16)) -} - -/// Reads a `plac` chunk. -pub fn read_plac(b: &[u8]) -> ResultS<(ObjectFreq, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 12, start: 0, data { - let flags = u16[0]; - let cnt_ini = u16[2]; - let cnt_min = u16[4]; - let cnt_max = u16[6]; - let cnt_rnd = u16[8]; - let chance = u16[10]; - } - } - - let rnd_loc = flags != 0; - - Ok((ObjectFreq{rnd_loc, cnt_ini, cnt_min, cnt_max, cnt_rnd, chance}, 12)) -} - -/// Reads an `ambi` chunk. -pub fn read_ambi(b: &[u8]) -> ResultS<(SoundAmbi, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 16, start: 0, data { - let index = u16[2]; - let volume = u16[4]; - } - } - - Ok((SoundAmbi{index, volume}, 16)) -} - -/// Reads a `bonk` chunk. -pub fn read_bonk(b: &[u8]) -> ResultS<(SoundRand, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 32, start: 0, data { - let flags = u16[0]; - let index = u16[2]; - let vol_nrm = u16[4]; - let vol_dta = u16[6]; - let prd_nrm = u16[8]; - let prd_dta = u16[10]; - let yaw_nrm = Angle[12]; - let yaw_dta = Angle[14]; - let pit_nrm = Fixed[16]; - let pit_dta = Fixed[20]; - } - } - - let no_dir = flags != 0; - - Ok((SoundRand{no_dir, index, vol_nrm, vol_dta, prd_nrm, prd_dta, yaw_nrm, - yaw_dta, pit_nrm, pit_dta}, 32)) -} - -/// Reads a `medi` chunk. -pub fn read_medi(b: &[u8]) -> ResultS<(Media, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 32, start: 0, data { - let mtype = u16[0] enum MediaType; - let flags = u16[2]; - let control = u16[4]; - let dir = Angle[6]; - let mag = Unit[8]; - let hei_lo = Unit[10]; - let hei_hi = Unit[12]; - let orig = read_point[14; 4]; - let hei_nrm = Unit[18]; - let min_lt = Fixed[20]; - let texture = OptU16[24]; - let xfer = u16[26] enum TransferMode; - } - } - - let flr_obs = flags != 0; - - Ok((Media{mtype, flr_obs, control, dir, mag, hei_lo, hei_hi, orig, hei_nrm, - min_lt, texture, xfer}, 32)) -} - -/// Reads a `plat` chunk. -pub fn read_plat(b: &[u8]) -> ResultS<(Platform, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 32, start: 0, data { - let ptype = u16[0]; - let speed = u16[2]; - let delay = u16[4]; - let hei_max = Unit[6]; - let hei_min = Unit[8]; - let flags = u32[10] flag PlatformFlags; - let index = u16[14]; - let tag = u16[16]; - } - } - - Ok((Platform{ptype, speed, delay, hei_min, hei_max, flags, index, tag}, 32)) -} - -/// Reads a `NOTE` chunk. -pub fn read_note(b: &[u8]) -> ResultS<(Note, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 72, start: 0, data { - let pos = read_point[2; 4]; - let poly = u16[6]; - let text = mac_roman_cstr[8; 64] no_try; - } - } - - Ok((Note{pos, poly, text}, 72)) -} - -impl PolyType -{ - /// Creates a `PolyType` from a `n`/`pdata` pair. - pub fn new(n: u16, pdata: u16) -> Result - { - match n { - 0 => Ok(PolyType::Normal), - 1 => Ok(PolyType::ImpassItem), - 2 => Ok(PolyType::ImpassMons), - 3 => Ok(PolyType::Hill), - 4 => Ok(PolyType::Base), - 5 => Ok(PolyType::Platform(pdata)), - 6 => Ok(PolyType::TrigLightOn(pdata)), - 7 => Ok(PolyType::TrigPlatOn(pdata)), - 8 => Ok(PolyType::TrigLightOff(pdata)), - 9 => Ok(PolyType::TrigPlatOff(pdata)), - 10 => Ok(PolyType::Teleporter(pdata)), - 11 => Ok(PolyType::ZoneBorder), - 12 => Ok(PolyType::Goal), - 13 => Ok(PolyType::TrigMonsVis), - 14 => Ok(PolyType::TrigMonsInv), - 15 => Ok(PolyType::TrigMonsDual), - 16 => Ok(PolyType::TrigItems), - 17 => Ok(PolyType::MustExplore), - 18 => Ok(PolyType::AutoExit), - 19 => Ok(PolyType::OuchMinor), - 20 => Ok(PolyType::OuchMajor), - 21 => Ok(PolyType::Glue), - 22 => Ok(PolyType::GlueTrigger(pdata)), - 23 => Ok(PolyType::GlueSuper), - n => Err(ReprError::new(n)), - } - } - - /// Creates a `PolyType` from a Marathon 1 compatible `n`/`pdata` pair. - fn new_old(n: u16, pdata: u16) -> Result - { - match n { - 0 => Ok(PolyType::Normal), - 1 => Ok(PolyType::ImpassItem), - 2 => Ok(PolyType::ImpassMons), - 3 => Ok(PolyType::OuchMinor), - 4 => Ok(PolyType::OuchMajor), - 5 => Ok(PolyType::Platform(pdata)), - 6 => Ok(PolyType::TrigLightOn(pdata)), - 7 => Ok(PolyType::TrigPlatOn(pdata)), - 8 => Ok(PolyType::TrigLightOff(pdata)), - 9 => Ok(PolyType::TrigPlatOff(pdata)), - 10 => Ok(PolyType::Teleporter(pdata)), - 11 => Ok(PolyType::Glue), - 12 => Ok(PolyType::GlueTrigger(pdata)), - 13 => Ok(PolyType::GlueSuper), - 14 => Ok(PolyType::MustExplore), - 15 => Ok(PolyType::AutoExit), - n => Err(ReprError::new(n)), - } - } -} - -impl Default for PolyType -{ - fn default() -> Self {PolyType::Normal} -} - -impl Default for Minf -{ - fn default() -> Self - { - Self{texture_id: 0, - physics_id: 1, - skypict_id: 0, - miss_flags: MsnFlags::empty(), - envi_flags: EnvFlags::empty(), - entr_flags: EntFlags::SOLO, - level_name: "Map".to_string()} - } -} - -/// A point in world-space. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] -pub struct Point -{ - pub x: Unit, - pub y: Unit, -} - -/// A line segment. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Line -{ - pub flags: LineFlags, - pub pnt_beg: u16, - pub pnt_end: u16, - pub side_fr: OptU16, - pub side_bk: OptU16, - pub poly_fr: OptU16, - pub poly_bk: OptU16, -} - -/// The texture of a side segment. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct SideTex -{ - pub offs: Point, - pub tex_id: OptU16, -} - -/// One side of a line segment. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Side -{ - pub stype: SideType, - pub flags: SideFlags, - pub tex_pri: SideTex, - pub tex_sec: SideTex, - pub tex_tra: SideTex, - pub paneltyp: u16, - pub paneldat: i16, - pub xfer_pri: TransferMode, - pub xfer_sec: TransferMode, - pub xfer_tra: TransferMode, - pub shade: Fixed, -} - -/// A polygon segment. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Default, Eq, PartialEq)] -pub struct Polygon -{ - pub ptype: PolyType, - pub tex_flr: OptU16, - pub tex_cei: OptU16, - pub hei_flr: Unit, - pub hei_cei: Unit, - pub lit_flr: u16, - pub lit_cei: u16, - pub xfr_flr: TransferMode, - pub xfr_cei: TransferMode, - pub ori_flr: Point, - pub ori_cei: Point, - pub med_ind: OptU16, - pub med_ctl: u16, - pub snd_ind: u16, - pub snd_amb: OptU16, - pub snd_rnd: OptU16, -} - -/// A light function. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct LightFunc -{ - pub ftype: LightFuncType, - pub prd_nrm: u16, - pub prd_dta: u16, - pub val_nrm: Fixed, - pub val_dta: Fixed, -} - -/// A dynamic polygon light. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Light -{ - pub ltype: LightType, - pub flags: LightFlags, - pub phase: i16, - pub act_pri: LightFunc, - pub act_sec: LightFunc, - pub act_mid: LightFunc, - pub ina_pri: LightFunc, - pub ina_sec: LightFunc, - pub ina_mid: LightFunc, - pub tag: u16, -} - -/// An object in the world. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Object -{ - pub group: u16, - pub index: u16, - pub angle: Angle, - pub poly: u16, - pub pos_x: Unit, - pub pos_y: Unit, - pub pos_z: Unit, - pub flags: ObjectFlags, - pub bias: u16, -} - -/// The difficulty definition for various object types. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct ObjectFreq -{ - pub rnd_loc: bool, - pub cnt_ini: u16, - pub cnt_min: u16, - pub cnt_max: u16, - pub cnt_rnd: u16, - pub chance: u16, -} - -/// An ambient sound definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct SoundAmbi -{ - pub index: u16, - pub volume: u16, -} - -/// A randomly played sound definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct SoundRand -{ - pub no_dir: bool, - pub index: u16, - pub vol_nrm: u16, - pub vol_dta: u16, - pub prd_nrm: u16, - pub prd_dta: u16, - pub yaw_nrm: Angle, - pub yaw_dta: Angle, - pub pit_nrm: Fixed, - pub pit_dta: Fixed, -} - -/// 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)] -pub struct Media -{ - pub mtype: MediaType, - pub flr_obs: bool, - pub control: u16, - pub dir: Angle, - pub mag: Unit, - pub hei_lo: Unit, - pub hei_hi: Unit, - pub orig: Point, - pub hei_nrm: Unit, - pub min_lt: Fixed, - pub texture: OptU16, - pub xfer: TransferMode, -} - -/// Extra information for polygons with platforms. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Platform -{ - pub ptype: u16, - pub speed: u16, - pub delay: u16, - pub hei_min: Unit, - pub hei_max: Unit, - pub flags: PlatformFlags, - pub index: u16, - pub tag: u16, -} - -/// Overhead map annotations. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Note -{ - pub pos: Point, - pub poly: u16, - pub text: String, -} - -/// Static map information. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Minf -{ - pub texture_id: u16, - pub physics_id: u16, - pub skypict_id: u16, - pub miss_flags: MsnFlags, - pub envi_flags: EnvFlags, - pub entr_flags: EntFlags, - pub level_name: String, -} - -/// The action type of a `Polygon`. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub enum PolyType -{ - Normal, - ImpassItem, - ImpassMons, - Hill, - Base, - Platform(u16), - TrigLightOn(u16), - TrigPlatOn(u16), - TrigLightOff(u16), - TrigPlatOff(u16), - Teleporter(u16), - ZoneBorder, - Goal, - TrigMonsVis, - TrigMonsInv, - TrigMonsDual, - TrigItems, - MustExplore, - AutoExit, - OuchMinor, - OuchMajor, - Glue, - GlueTrigger(u16), - GlueSuper, -} - -bitflags! { - /// Flags for `Line`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct LineFlags: u16 - { - const TRANS_SIDE = 1 << 9; - const ELEV_VAR = 1 << 10; - const ELEVATION = 1 << 11; - const LANDSCAPE = 1 << 12; - const TRANSPARENT = 1 << 13; - const SOLID = 1 << 14; - } -} - -bitflags! { - /// Flags for `Side`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct SideFlags: u16 - { - const STATUS = 1; - const PANEL = 1 << 1; - const REPAIR = 1 << 2; - const ITEM_USE = 1 << 3; - const LIGHTED = 1 << 4; - const CAN_DESTROY = 1 << 5; - const HIT_ONLY = 1 << 6; - const ITEM_OPT = 1 << 7; - } -} - -bitflags! { - /// Static environment flags. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct EnvFlags: 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 EntFlags: 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 MsnFlags: u16 - { - const EXTERMINATION = 1; - const EXPLORATION = 1 << 1; - const RETRIEVAL = 1 << 2; - const REPAIR = 1 << 3; - const RESCUE = 1 << 4; - } -} - -bitflags! { - /// Flags for `Polygon`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct PolyFlags: u16 - { - const DETACHED = 1 << 14; - } -} - -bitflags! { - /// Flags for `Light`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct LightFlags: u16 - { - const INIT_ACTIVE = 1; - const SLAVE_VALUE = 1 << 1; - const STATELESS = 1 << 2; - } -} - -bitflags! { - /// Flags for `Object`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct ObjectFlags: u16 - { - const INVISIBLE = 1; - const CEILING = 1 << 1; - const BLIND = 1 << 2; - const DEAF = 1 << 3; - const FLOATING = 1 << 4; - const NET_ONLY = 1 << 5; - } -} - -bitflags! { - /// Flags for `Platform`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct PlatformFlags: u32 - { - const INIT_ACTIVE = 1; - const INIT_EXTENDED = 1 << 1; - const STOP_AT_EACH_LEVEL = 1 << 2; - const STOP_AT_INIT_LEVEL = 1 << 3; - const START_ADJ_ON_STOP = 1 << 4; - const EXTENDS_FLOOR_TO_CEIL = 1 << 5; - const COMES_FROM_FLOOR = 1 << 6; - const COMES_FROM_CEIL = 1 << 7; - const CAUSES_DAMAGE = 1 << 8; - const NO_ACTIVATE_PARENT = 1 << 9; - const ACTIVATES_ONCE = 1 << 10; - const ACTIVATES_LIGHT = 1 << 11; - const DEACTIVATES_LIGHT = 1 << 12; - const PLAYER_CONTROLS = 1 << 13; - const MONSTER_CONTROLS = 1 << 14; - const REVERSE_ON_OBSTRUCT = 1 << 15; - const NO_EXT_DEACTIVATION = 1 << 16; - const USE_POLYGON_HEIGHTS = 1 << 17; - const DELAYED_ACTIVATION = 1 << 18; - const START_ADJ_ON_START = 1 << 19; - const STOP_ADJ_ON_START = 1 << 20; - const STOP_ADJ_ON_STOP = 1 << 21; - const SLOW = 1 << 22; - const START_AT_EACH_LEVEL = 1 << 23; - const LOCKED = 1 << 24; - const SECRET = 1 << 25; - const DOOR = 1 << 26; - } -} - -c_enum! { - /// The texture type of a `Side`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum SideType: u16 - { - Full = 0, - High = 1, - Low = 2, - Composite = 3, - Split = 4, - } -} - -c_enum! { - /// The type of function for a `LightFunc`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum LightFuncType: u16 - { - Constant = 0, - Linear = 1, - Smooth = 2, - Flicker = 3, - Random = 4, - Fluorescent = 5, - } -} - -c_enum! { - /// The type of a `Light`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum LightType: u16 - { - Normal = 0, - Strobe = 1, - Media = 2, - } -} - -c_enum! { - /// The liquid type of a `Media`. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum MediaType: u16 - { - Water = 0, - Lava = 1, - Goo = 2, - Sewage = 3, - } -} +pub mod ambi; +pub mod bonk; +pub mod epnt; +pub mod iidx; +pub mod lins; +pub mod lite; +pub mod ltfn; +pub mod medi; +pub mod minf; +pub mod note; +pub mod objs; +pub mod plac; +pub mod plat; +pub mod pnts; +pub mod poly; +pub mod sids; +pub mod stex; /// The number of game ticks per second. pub const TICKS_PER_SECOND: u16 = 30; -const OLD_LIGHT_DEFINITIONS: [Light; 8] = [ - // Normal - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Rheostat - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 3, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 3, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Flourescent - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Fluorescent, - prd_nrm: TICKS_PER_SECOND * 3, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Strobe - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Flicker - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Flicker, - prd_nrm: TICKS_PER_SECOND * 3, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Pulsate - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2 - 1, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2 - 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2 - 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Smooth, - prd_nrm: TICKS_PER_SECOND * 2, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Annoying - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Random, - prd_nrm: 2, - prd_dta: 1, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: 2, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Random, - prd_nrm: 1, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, - - // Energy Efficient - Light{ltype: LightType::Normal, - flags: LightFlags::SLAVE_VALUE, - phase: 0, - act_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - act_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - act_mid: LightFunc{ftype: LightFuncType::Linear, - prd_nrm: TICKS_PER_SECOND * 2, - prd_dta: 0, - val_nrm: Fixed::from_int(1), - val_dta: Fixed::from_int(0)}, - ina_pri: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_sec: LightFunc{ftype: LightFuncType::Constant, - prd_nrm: TICKS_PER_SECOND, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - ina_mid: LightFunc{ftype: LightFuncType::Linear, - prd_nrm: TICKS_PER_SECOND * 2, - prd_dta: 0, - val_nrm: Fixed::from_int(0), - val_dta: Fixed::from_int(0)}, - tag: 0}, -]; - // EOF diff --git a/source/marathon/map/ambi.rs b/source/marathon/map/ambi.rs new file mode 100644 index 0000000..88328ba --- /dev/null +++ b/source/marathon/map/ambi.rs @@ -0,0 +1,27 @@ +//! `SoundAmbi` type. + +use crate::durandal::err::*; + +/// Reads an `ambi` chunk. +pub fn read(b: &[u8]) -> ResultS<(SoundAmbi, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 16, start: 0, data { + let index = u16[2]; + let volume = u16[4]; + } + } + + Ok((SoundAmbi{index, volume}, 16)) +} + +/// An ambient sound definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct SoundAmbi +{ + pub index: u16, + pub volume: u16, +} + +// EOF diff --git a/source/marathon/map/bonk.rs b/source/marathon/map/bonk.rs new file mode 100644 index 0000000..0a7be1d --- /dev/null +++ b/source/marathon/map/bonk.rs @@ -0,0 +1,46 @@ +//! `SoundRand` type. + +use crate::durandal::{err::*, fixed::{Angle, Fixed}}; + +/// Reads a `bonk` chunk. +pub fn read(b: &[u8]) -> ResultS<(SoundRand, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 32, start: 0, data { + let flags = u16[0]; + let index = u16[2]; + let vol_nrm = u16[4]; + let vol_dta = u16[6]; + let prd_nrm = u16[8]; + let prd_dta = u16[10]; + let yaw_nrm = Angle[12]; + let yaw_dta = Angle[14]; + let pit_nrm = Fixed[16]; + let pit_dta = Fixed[20]; + } + } + + let no_dir = flags != 0; + + Ok((SoundRand{no_dir, index, vol_nrm, vol_dta, prd_nrm, prd_dta, yaw_nrm, + yaw_dta, pit_nrm, pit_dta}, 32)) +} + +/// A randomly played sound definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct SoundRand +{ + pub no_dir: bool, + pub index: u16, + pub vol_nrm: u16, + pub vol_dta: u16, + pub prd_nrm: u16, + pub prd_dta: u16, + pub yaw_nrm: Angle, + pub yaw_dta: Angle, + pub pit_nrm: Fixed, + pub pit_dta: Fixed, +} + +// EOF diff --git a/source/marathon/map/epnt.rs b/source/marathon/map/epnt.rs new file mode 100644 index 0000000..a4828d9 --- /dev/null +++ b/source/marathon/map/epnt.rs @@ -0,0 +1,18 @@ +//! `EndPoint` type. + +use crate::durandal::err::*; +use super::pnts::*; + +/// Reads an `EPNT` chunk. +pub fn read(b: &[u8]) -> ResultS<(Point, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 16, start: 0, data { + let pnt = read_point[6; 4]; + } + } + + Ok((pnt, 16)) +} + +// EOF diff --git a/source/marathon/map/iidx.rs b/source/marathon/map/iidx.rs new file mode 100644 index 0000000..0559754 --- /dev/null +++ b/source/marathon/map/iidx.rs @@ -0,0 +1,13 @@ +//! `iidx` chunk. + +use crate::durandal::{bin::u16b, err::*}; + +/// Reads an `iidx` chunk. +pub fn read(b: &[u8]) -> ResultS<(u16, usize)> +{ + check_data!(2, b); + + Ok((u16b(b), 2)) +} + +// EOF diff --git a/source/marathon/map/lins.rs b/source/marathon/map/lins.rs new file mode 100644 index 0000000..bf3ef57 --- /dev/null +++ b/source/marathon/map/lins.rs @@ -0,0 +1,52 @@ +//! `Line` type. + +use crate::durandal::{bin::OptU16, err::*}; +use bitflags::bitflags; + +/// Reads a `LINS` chunk. +pub fn read(b: &[u8]) -> ResultS<(Line, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 32, start: 0, data { + let pnt_beg = u16[0]; + let pnt_end = u16[2]; + let flags = u16[4] flag LineFlags; + let side_fr = OptU16[12]; + let side_bk = OptU16[14]; + let poly_fr = OptU16[16]; + let poly_bk = OptU16[18]; + } + } + + Ok((Line{flags, pnt_beg, pnt_end, side_fr, side_bk, poly_fr, poly_bk}, 32)) +} + +/// A line segment. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Line +{ + pub flags: LineFlags, + pub pnt_beg: u16, + pub pnt_end: u16, + pub side_fr: OptU16, + pub side_bk: OptU16, + pub poly_fr: OptU16, + pub poly_bk: OptU16, +} + +bitflags! { + /// Flags for `Line`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct LineFlags: u16 + { + const TRANS_SIDE = 1 << 9; + const ELEV_VAR = 1 << 10; + const ELEVATION = 1 << 11; + const LANDSCAPE = 1 << 12; + const TRANSPARENT = 1 << 13; + const SOLID = 1 << 14; + } +} + +// EOF diff --git a/source/marathon/map/lite.rs b/source/marathon/map/lite.rs new file mode 100644 index 0000000..8b82197 --- /dev/null +++ b/source/marathon/map/lite.rs @@ -0,0 +1,403 @@ +//! `Light` type. + +use crate::durandal::{err::*, fixed::Fixed}; +use super::{ltfn::{self, LightFunc, LightFuncType}, TICKS_PER_SECOND}; +use bitflags::bitflags; + +/// Reads a `LITE` chunk. +pub fn read(b: &[u8]) -> ResultS<(Light, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 100, start: 0, data { + let ltype = u16[0] enum LightType; + let flags = u16[2] flag LightFlags; + let phase = i16[4]; + let act_pri = ltfn::read[6; 14]; + let act_sec = ltfn::read[20; 14]; + let act_mid = ltfn::read[34; 14]; + let ina_pri = ltfn::read[48; 14]; + let ina_sec = ltfn::read[62; 14]; + let ina_mid = ltfn::read[76; 14]; + let tag = u16[90]; + } + } + + Ok((Light{ltype, flags, phase, act_pri, act_sec, act_mid, ina_pri, ina_sec, + ina_mid, tag}, 100)) +} + +/// Reads an old `LITE` chunk. +pub fn read_old(b: &[u8]) -> ResultS<(Light, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 32, start: 0, data { + let ltype = u16[2] usize; + let mode = u16[4]; + let phase = i16[6]; + let min = Fixed[8]; + let max = Fixed[12]; + let prd = u16[16]; + } + } + + if OLD_LIGHT_DEFINITIONS.len() < ltype { + bail!("bad old light type"); + } + + let lite = &OLD_LIGHT_DEFINITIONS[ltype]; + let on = mode == 0 || mode == 1; + let strobe = ltype == 3; + let flags = if on {lite.flags | LightFlags::INIT_ACTIVE} else {lite.flags}; + + // modify each old light function accordingly + let old_lfun = move |func: &LightFunc| -> LightFunc { + LightFunc{ftype: func.ftype, + prd_nrm: if strobe {prd / 4 + 1} else {func.prd_nrm}, + prd_dta: func.prd_dta, + val_nrm: if func.val_nrm > 0.into() {max} else {min}, + val_dta: func.val_dta} + }; + + Ok((Light{flags, + phase, + act_pri: old_lfun(&lite.act_pri), + act_sec: old_lfun(&lite.act_sec), + act_mid: old_lfun(&lite.act_mid), + ina_pri: old_lfun(&lite.ina_pri), + ina_sec: old_lfun(&lite.ina_sec), + ina_mid: old_lfun(&lite.ina_mid), + tag: 0, + ..*lite}, 32)) +} + +/// A dynamic polygon light. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Light +{ + pub ltype: LightType, + pub flags: LightFlags, + pub phase: i16, + pub act_pri: LightFunc, + pub act_sec: LightFunc, + pub act_mid: LightFunc, + pub ina_pri: LightFunc, + pub ina_sec: LightFunc, + pub ina_mid: LightFunc, + pub tag: u16, +} + +bitflags! { + /// Flags for `Light`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct LightFlags: u16 + { + const INIT_ACTIVE = 1; + const SLAVE_VALUE = 1 << 1; + const STATELESS = 1 << 2; + } +} + +c_enum! { + /// The type of a `Light`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum LightType: u16 + { + Normal = 0, + Strobe = 1, + Media = 2, + } +} + +const OLD_LIGHT_DEFINITIONS: [Light; 8] = [ + // Normal + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Rheostat + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 3, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 3, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Flourescent + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Fluorescent, + prd_nrm: TICKS_PER_SECOND * 3, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Strobe + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Flicker + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Flicker, + prd_nrm: TICKS_PER_SECOND * 3, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Pulsate + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2 - 1, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2 - 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2 - 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Smooth, + prd_nrm: TICKS_PER_SECOND * 2, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Annoying + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Random, + prd_nrm: 2, + prd_dta: 1, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: 2, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Random, + prd_nrm: 1, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, + + // Energy Efficient + Light{ltype: LightType::Normal, + flags: LightFlags::SLAVE_VALUE, + phase: 0, + act_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + act_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + act_mid: LightFunc{ftype: LightFuncType::Linear, + prd_nrm: TICKS_PER_SECOND * 2, + prd_dta: 0, + val_nrm: Fixed::from_int(1), + val_dta: Fixed::from_int(0)}, + ina_pri: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_sec: LightFunc{ftype: LightFuncType::Constant, + prd_nrm: TICKS_PER_SECOND, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + ina_mid: LightFunc{ftype: LightFuncType::Linear, + prd_nrm: TICKS_PER_SECOND * 2, + prd_dta: 0, + val_nrm: Fixed::from_int(0), + val_dta: Fixed::from_int(0)}, + tag: 0}, +]; + +// EOF diff --git a/source/marathon/map/ltfn.rs b/source/marathon/map/ltfn.rs new file mode 100644 index 0000000..54e0364 --- /dev/null +++ b/source/marathon/map/ltfn.rs @@ -0,0 +1,60 @@ +//! `LightFunc` type. + +use crate::durandal::{err::*, fixed::Fixed}; + +/// Reads a `LightFunc` object. +pub fn read(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 14, start: 0, data { + let ftype = u16[0] enum LightFuncType; + let prd_nrm = u16[2]; + let prd_dta = u16[4]; + let val_nrm = Fixed[6]; + let val_dta = Fixed[10]; + } + } + + Ok(LightFunc{ftype, prd_nrm, prd_dta, val_nrm, val_dta}) +} + +/// Writes a `LightFunc` object. +pub fn write(v: &LightFunc) -> Vec +{ + let mut o = Vec::with_capacity(14); + o.extend(&(v.ftype as u16).to_be_bytes()); + o.extend(&v.prd_nrm.to_be_bytes()); + o.extend(&v.prd_dta.to_be_bytes()); + o.extend(&v.val_nrm.to_be_bytes()); + o.extend(&v.val_dta.to_be_bytes()); + o +} + +/// A light function. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct LightFunc +{ + pub ftype: LightFuncType, + pub prd_nrm: u16, + pub prd_dta: u16, + pub val_nrm: Fixed, + pub val_dta: Fixed, +} + +c_enum! { + /// The type of function for a `LightFunc`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum LightFuncType: u16 + { + Constant = 0, + Linear = 1, + Smooth = 2, + Flicker = 3, + Random = 4, + Fluorescent = 5, + } +} + +// EOF diff --git a/source/marathon/map/medi.rs b/source/marathon/map/medi.rs new file mode 100644 index 0000000..af888ba --- /dev/null +++ b/source/marathon/map/medi.rs @@ -0,0 +1,65 @@ +//! `Light` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::{Angle, Fixed, Unit}}, + marathon::xfer::TransferMode}; +use super::pnts::*; + +/// Reads a `medi` chunk. +pub fn read(b: &[u8]) -> ResultS<(Media, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 32, start: 0, data { + let mtype = u16[0] enum MediaType; + let flags = u16[2]; + let control = u16[4]; + let dir = Angle[6]; + let mag = Unit[8]; + let hei_lo = Unit[10]; + let hei_hi = Unit[12]; + let orig = read_point[14; 4]; + let hei_nrm = Unit[18]; + let min_lt = Fixed[20]; + let texture = OptU16[24]; + let xfer = u16[26] enum TransferMode; + } + } + + let flr_obs = flags != 0; + + Ok((Media{mtype, flr_obs, control, dir, mag, hei_lo, hei_hi, orig, hei_nrm, + min_lt, texture, xfer}, 32)) +} + +/// 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)] +pub struct Media +{ + pub mtype: MediaType, + pub flr_obs: bool, + pub control: u16, + pub dir: Angle, + pub mag: Unit, + pub hei_lo: Unit, + pub hei_hi: Unit, + pub orig: Point, + pub hei_nrm: Unit, + pub min_lt: Fixed, + pub texture: OptU16, + pub xfer: TransferMode, +} + +c_enum! { + /// The liquid type of a `Media`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum MediaType: u16 + { + Water = 0, + Lava = 1, + Goo = 2, + Sewage = 3, + } +} + +// EOF diff --git a/source/marathon/map/minf.rs b/source/marathon/map/minf.rs new file mode 100644 index 0000000..364f091 --- /dev/null +++ b/source/marathon/map/minf.rs @@ -0,0 +1,133 @@ +//! `Minf` type. + +use crate::{durandal::err::*, marathon::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 MsnFlags; + let envi_flags = u16[8] flag EnvFlags; + let level_name = mac_roman_cstr[18; 66] no_try; + let entr_flags = u32[84] flag EntFlags; + } + } + + Ok(Minf{texture_id, physics_id, skypict_id, miss_flags, envi_flags, + entr_flags, level_name}) +} + +/// Writes a `Minf` chunk. +pub fn write(v: &Minf) -> 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() { + EntFlags::SOLO + } else { + minf.entr_flags + }; + + if entr_flags.intersects(EntFlags::SOLO | EntFlags::CARNAGE) { + entr_flags.insert(EntFlags::CO_OP) + } + + Ok(Minf{entr_flags, ..minf}) +} + +impl Default for Minf +{ + fn default() -> Self + { + Self{texture_id: 0, + physics_id: 1, + skypict_id: 0, + miss_flags: MsnFlags::empty(), + envi_flags: EnvFlags::empty(), + entr_flags: EntFlags::SOLO, + level_name: "Map".to_string()} + } +} + +/// Static map information. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Minf +{ + pub texture_id: u16, + pub physics_id: u16, + pub skypict_id: u16, + pub miss_flags: MsnFlags, + pub envi_flags: EnvFlags, + pub entr_flags: EntFlags, + pub level_name: String, +} + +bitflags! { + /// Static environment flags. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct EnvFlags: 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 EntFlags: 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 MsnFlags: u16 + { + const EXTERMINATION = 1; + const EXPLORATION = 1 << 1; + const RETRIEVAL = 1 << 2; + const REPAIR = 1 << 3; + const RESCUE = 1 << 4; + } +} + +// EOF diff --git a/source/marathon/map/note.rs b/source/marathon/map/note.rs new file mode 100644 index 0000000..1973d69 --- /dev/null +++ b/source/marathon/map/note.rs @@ -0,0 +1,30 @@ +//! `Note` type. + +use crate::{durandal::err::*, marathon::text::*}; +use super::pnts::*; + +/// Reads a `NOTE` chunk. +pub fn read(b: &[u8]) -> ResultS<(Note, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 72, start: 0, data { + let pos = read_point[2; 4]; + let poly = u16[6]; + let text = mac_roman_cstr[8; 64] no_try; + } + } + + Ok((Note{pos, poly, text}, 72)) +} + +/// Overhead map annotations. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Note +{ + pub pos: Point, + pub poly: u16, + pub text: String, +} + +// EOF diff --git a/source/marathon/map/objs.rs b/source/marathon/map/objs.rs new file mode 100644 index 0000000..6616c99 --- /dev/null +++ b/source/marathon/map/objs.rs @@ -0,0 +1,60 @@ +//! `Object` type. + +use crate::durandal::{err::*, fixed::{Angle, Unit}}; +use bitflags::bitflags; + +/// Reads an `OBJS` chunk. +pub fn read(b: &[u8]) -> ResultS<(Object, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 16, start: 0, data { + let group = u16[0]; + let index = u16[2]; + let angle = Angle[4]; + let poly = u16[6]; + let pos_x = Unit[8]; + let pos_y = Unit[10]; + let pos_z = Unit[12]; + let flags = u16[14]; + } + } + + let bias = flags & 0xF0_00; + let flags = flags & 0x0F_FF; + let bias = bias >> 12; + let flags = flag_ok!(ObjectFlags, flags)?; + + Ok((Object{group, index, angle, poly, pos_x, pos_y, pos_z, flags, bias}, 16)) +} + +/// An object in the world. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Object +{ + pub group: u16, + pub index: u16, + pub angle: Angle, + pub poly: u16, + pub pos_x: Unit, + pub pos_y: Unit, + pub pos_z: Unit, + pub flags: ObjectFlags, + pub bias: u16, +} + +bitflags! { + /// Flags for `Object`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct ObjectFlags: u16 + { + const INVISIBLE = 1; + const CEILING = 1 << 1; + const BLIND = 1 << 2; + const DEAF = 1 << 3; + const FLOATING = 1 << 4; + const NET_ONLY = 1 << 5; + } +} + +// EOF diff --git a/source/marathon/map/plac.rs b/source/marathon/map/plac.rs new file mode 100644 index 0000000..6c8bc25 --- /dev/null +++ b/source/marathon/map/plac.rs @@ -0,0 +1,37 @@ +//! `ObjectFreq` type. + +use crate::durandal::err::*; + +/// Reads a `plac` chunk. +pub fn read(b: &[u8]) -> ResultS<(ObjectFreq, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 12, start: 0, data { + let flags = u16[0]; + let cnt_ini = u16[2]; + let cnt_min = u16[4]; + let cnt_max = u16[6]; + let cnt_rnd = u16[8]; + let chance = u16[10]; + } + } + + let rnd_loc = flags != 0; + + Ok((ObjectFreq{rnd_loc, cnt_ini, cnt_min, cnt_max, cnt_rnd, chance}, 12)) +} + +/// The difficulty definition for various object types. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct ObjectFreq +{ + pub rnd_loc: bool, + pub cnt_ini: u16, + pub cnt_min: u16, + pub cnt_max: u16, + pub cnt_rnd: u16, + pub chance: u16, +} + +// EOF diff --git a/source/marathon/map/plat.rs b/source/marathon/map/plat.rs new file mode 100644 index 0000000..a5fc021 --- /dev/null +++ b/source/marathon/map/plat.rs @@ -0,0 +1,75 @@ +//! `Platform` type. + +use crate::durandal::{err::*, fixed::Unit}; +use bitflags::bitflags; + +/// Reads a `plat` chunk. +pub fn read(b: &[u8]) -> ResultS<(Platform, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 32, start: 0, data { + let ptype = u16[0]; + let speed = u16[2]; + let delay = u16[4]; + let hei_max = Unit[6]; + let hei_min = Unit[8]; + let flags = u32[10] flag PlatformFlags; + let index = u16[14]; + let tag = u16[16]; + } + } + + Ok((Platform{ptype, speed, delay, hei_min, hei_max, flags, index, tag}, 32)) +} + +/// Extra information for polygons with platforms. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Platform +{ + pub ptype: u16, + pub speed: u16, + pub delay: u16, + pub hei_min: Unit, + pub hei_max: Unit, + pub flags: PlatformFlags, + pub index: u16, + pub tag: u16, +} + +bitflags! { + /// Flags for `Platform`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct PlatformFlags: u32 + { + const INIT_ACTIVE = 1; + const INIT_EXTENDED = 1 << 1; + const STOP_AT_EACH_LEVEL = 1 << 2; + const STOP_AT_INIT_LEVEL = 1 << 3; + const START_ADJ_ON_STOP = 1 << 4; + const EXTENDS_FLOOR_TO_CEIL = 1 << 5; + const COMES_FROM_FLOOR = 1 << 6; + const COMES_FROM_CEIL = 1 << 7; + const CAUSES_DAMAGE = 1 << 8; + const NO_ACTIVATE_PARENT = 1 << 9; + const ACTIVATES_ONCE = 1 << 10; + const ACTIVATES_LIGHT = 1 << 11; + const DEACTIVATES_LIGHT = 1 << 12; + const PLAYER_CONTROLS = 1 << 13; + const MONSTER_CONTROLS = 1 << 14; + const REVERSE_ON_OBSTRUCT = 1 << 15; + const NO_EXT_DEACTIVATION = 1 << 16; + const USE_POLYGON_HEIGHTS = 1 << 17; + const DELAYED_ACTIVATION = 1 << 18; + const START_ADJ_ON_START = 1 << 19; + const STOP_ADJ_ON_START = 1 << 20; + const STOP_ADJ_ON_STOP = 1 << 21; + const SLOW = 1 << 22; + const START_AT_EACH_LEVEL = 1 << 23; + const LOCKED = 1 << 24; + const SECRET = 1 << 25; + const DOOR = 1 << 26; + } +} + +// EOF diff --git a/source/marathon/map/pnts.rs b/source/marathon/map/pnts.rs new file mode 100644 index 0000000..6427f6e --- /dev/null +++ b/source/marathon/map/pnts.rs @@ -0,0 +1,42 @@ +//! `Point` type. + +use crate::durandal::{err::*, fixed::Unit}; + +/// Reads a `Point` object. +pub fn read_point(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 4, start: 0, data { + let x = Unit[0]; + let y = Unit[2]; + } + } + + Ok(Point{x, y}) +} + +/// Writes a `Point` object. +pub fn write_point(v: Point) -> Vec +{ + let mut o = Vec::with_capacity(4); + o.extend(&v.x.to_be_bytes()); + o.extend(&v.y.to_be_bytes()); + o +} + +/// Reads a `PNTS` chunk. +pub fn read(b: &[u8]) -> ResultS<(Point, usize)> +{ + Ok((read_point(b)?, 4)) +} + +/// A point in world-space. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub struct Point +{ + pub x: Unit, + pub y: Unit, +} + +// EOF diff --git a/source/marathon/map/poly.rs b/source/marathon/map/poly.rs new file mode 100644 index 0000000..1f19b1f --- /dev/null +++ b/source/marathon/map/poly.rs @@ -0,0 +1,195 @@ +//! `Polygon` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::Unit}, + marathon::xfer::TransferMode}; +use super::pnts::*; +use bitflags::bitflags; + +/// Reads a polygon for either M1 or M2. +fn read_poly_inter(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 128, start: 0, data { + let tex_flr = OptU16[40]; + let tex_cei = OptU16[42]; + let hei_flr = Unit[44]; + let hei_cei = Unit[46]; + let lit_flr = u16[48]; + let lit_cei = u16[50]; + let xfr_flr = u16[64] enum TransferMode; + let xfr_cei = u16[66] enum TransferMode; + } + } + + Ok(Polygon{tex_flr, tex_cei, hei_flr, hei_cei, lit_flr, lit_cei, xfr_flr, + xfr_cei, ..Polygon::default()}) +} + +/// Reads a `POLY` chunk. +pub fn read(b: &[u8]) -> ResultS<(Polygon, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 128, start: 0, data { + let ptype = u16[0]; + let pdata = u16[4]; + let ori_flr = read_point[108; 4]; + let ori_cei = read_point[112; 4]; + let med_ind = OptU16[116]; + let med_ctl = u16[118]; + let snd_amb = OptU16[122]; + let snd_ind = u16[120]; + let snd_rnd = OptU16[124]; + } + } + + let poly = read_poly_inter(b)?; + let ptype = PolyType::new(ptype, pdata)?; + + Ok((Polygon{ptype, ori_flr, ori_cei, med_ind, med_ctl, snd_ind, snd_amb, + snd_rnd, ..poly}, 128)) +} + +/// Reads an old `POLY` chunk. +pub fn read_old(b: &[u8]) -> ResultS<(Polygon, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 128, start: 0, data { + let ptype = u16[0]; + let pdata = u16[4]; + } + } + + let poly = read_poly_inter(b)?; + let ptype = PolyType::new_old(ptype, pdata)?; + + Ok((Polygon{ptype, ..poly}, 128)) +} + +impl PolyType +{ + /// Creates a `PolyType` from a `n`/`pdata` pair. + pub fn new(n: u16, pdata: u16) -> Result + { + match n { + 0 => Ok(PolyType::Normal), + 1 => Ok(PolyType::ImpassItem), + 2 => Ok(PolyType::ImpassMons), + 3 => Ok(PolyType::Hill), + 4 => Ok(PolyType::Base), + 5 => Ok(PolyType::Platform(pdata)), + 6 => Ok(PolyType::TrigLightOn(pdata)), + 7 => Ok(PolyType::TrigPlatOn(pdata)), + 8 => Ok(PolyType::TrigLightOff(pdata)), + 9 => Ok(PolyType::TrigPlatOff(pdata)), + 10 => Ok(PolyType::Teleporter(pdata)), + 11 => Ok(PolyType::ZoneBorder), + 12 => Ok(PolyType::Goal), + 13 => Ok(PolyType::TrigMonsVis), + 14 => Ok(PolyType::TrigMonsInv), + 15 => Ok(PolyType::TrigMonsDual), + 16 => Ok(PolyType::TrigItems), + 17 => Ok(PolyType::MustExplore), + 18 => Ok(PolyType::AutoExit), + 19 => Ok(PolyType::OuchMinor), + 20 => Ok(PolyType::OuchMajor), + 21 => Ok(PolyType::Glue), + 22 => Ok(PolyType::GlueTrigger(pdata)), + 23 => Ok(PolyType::GlueSuper), + n => Err(ReprError::new(n)), + } + } + + /// Creates a `PolyType` from a Marathon 1 compatible `n`/`pdata` pair. + fn new_old(n: u16, pdata: u16) -> Result + { + match n { + 0 => Ok(PolyType::Normal), + 1 => Ok(PolyType::ImpassItem), + 2 => Ok(PolyType::ImpassMons), + 3 => Ok(PolyType::OuchMinor), + 4 => Ok(PolyType::OuchMajor), + 5 => Ok(PolyType::Platform(pdata)), + 6 => Ok(PolyType::TrigLightOn(pdata)), + 7 => Ok(PolyType::TrigPlatOn(pdata)), + 8 => Ok(PolyType::TrigLightOff(pdata)), + 9 => Ok(PolyType::TrigPlatOff(pdata)), + 10 => Ok(PolyType::Teleporter(pdata)), + 11 => Ok(PolyType::Glue), + 12 => Ok(PolyType::GlueTrigger(pdata)), + 13 => Ok(PolyType::GlueSuper), + 14 => Ok(PolyType::MustExplore), + 15 => Ok(PolyType::AutoExit), + n => Err(ReprError::new(n)), + } + } +} + +impl Default for PolyType +{ + fn default() -> Self {PolyType::Normal} +} + +/// A polygon segment. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Default, Eq, PartialEq)] +pub struct Polygon +{ + pub ptype: PolyType, + pub tex_flr: OptU16, + pub tex_cei: OptU16, + pub hei_flr: Unit, + pub hei_cei: Unit, + pub lit_flr: u16, + pub lit_cei: u16, + pub xfr_flr: TransferMode, + pub xfr_cei: TransferMode, + pub ori_flr: Point, + pub ori_cei: Point, + pub med_ind: OptU16, + pub med_ctl: u16, + pub snd_ind: u16, + pub snd_amb: OptU16, + pub snd_rnd: OptU16, +} + +/// The action type of a `Polygon`. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub enum PolyType +{ + Normal, + ImpassItem, + ImpassMons, + Hill, + Base, + Platform(u16), + TrigLightOn(u16), + TrigPlatOn(u16), + TrigLightOff(u16), + TrigPlatOff(u16), + Teleporter(u16), + ZoneBorder, + Goal, + TrigMonsVis, + TrigMonsInv, + TrigMonsDual, + TrigItems, + MustExplore, + AutoExit, + OuchMinor, + OuchMajor, + Glue, + GlueTrigger(u16), + GlueSuper, +} + +bitflags! { + /// Flags for `Polygon`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct PolyFlags: u16 + { + const DETACHED = 1 << 14; + } +} + +// EOF diff --git a/source/marathon/map/sids.rs b/source/marathon/map/sids.rs new file mode 100644 index 0000000..3612ea9 --- /dev/null +++ b/source/marathon/map/sids.rs @@ -0,0 +1,90 @@ +//! `Side` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::Fixed}, + marathon::xfer::TransferMode}; +use super::stex::{self, SideTex}; +use bitflags::bitflags; + +/// Reads a `SIDS` chunk. +pub fn read(b: &[u8]) -> ResultS<(Side, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 64, start: 0, data { + let stype = u16[0] enum SideType; + let flags = u16[2] flag SideFlags; + let tex_pri = stex::read[4; 6]; + let tex_sec = stex::read[10; 6]; + let tex_tra = stex::read[16; 6]; + let paneltyp = u16[38]; + let paneldat = i16[40]; + let xfer_pri = u16[42] enum TransferMode; + let xfer_sec = u16[44] enum TransferMode; + let xfer_tra = u16[46] enum TransferMode; + let shade = Fixed[48]; + } + } + + Ok((Side{stype, flags, tex_pri, tex_sec, tex_tra, paneltyp, paneldat, + xfer_pri, xfer_sec, xfer_tra, shade}, 64)) +} + +/// Reads an old `SIDS` chunk. +pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)> +{ + let (side, siz) = read(b)?; + + Ok((Side{tex_tra: SideTex{tex_id: OptU16::none(), ..side.tex_tra}, + shade: 0.into(), + flags: side.flags | SideFlags::ITEM_OPT, + ..side}, siz)) +} + +/// One side of a line segment. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Side +{ + pub stype: SideType, + pub flags: SideFlags, + pub tex_pri: SideTex, + pub tex_sec: SideTex, + pub tex_tra: SideTex, + pub paneltyp: u16, + pub paneldat: i16, + pub xfer_pri: TransferMode, + pub xfer_sec: TransferMode, + pub xfer_tra: TransferMode, + pub shade: Fixed, +} + +bitflags! { + /// Flags for `Side`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct SideFlags: u16 + { + const STATUS = 1; + const PANEL = 1 << 1; + const REPAIR = 1 << 2; + const ITEM_USE = 1 << 3; + const LIGHTED = 1 << 4; + const CAN_DESTROY = 1 << 5; + const HIT_ONLY = 1 << 6; + const ITEM_OPT = 1 << 7; + } +} + +c_enum! { + /// The texture type of a `Side`. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum SideType: u16 + { + Full = 0, + High = 1, + Low = 2, + Composite = 3, + Split = 4, + } +} + +// EOF diff --git a/source/marathon/map/stex.rs b/source/marathon/map/stex.rs new file mode 100644 index 0000000..c196bd7 --- /dev/null +++ b/source/marathon/map/stex.rs @@ -0,0 +1,37 @@ +//! `SideTex` type. + +use crate::durandal::{bin::OptU16, err::*}; +use super::pnts::*; + +/// Reads a `SideTex` object. +pub fn read(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 6, start: 0, data { + let offs = read_point[0; 4]; + let tex_id = OptU16[4]; + } + } + + Ok(SideTex{offs, tex_id}) +} + +/// Writes a `SideTex` object. +pub fn write(v: &SideTex) -> Vec +{ + let mut o = Vec::with_capacity(6); + o.extend(write_point(v.offs)); + o.extend(&v.tex_id.to_be_bytes()); + o +} + +/// The texture of a side segment. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct SideTex +{ + pub offs: Point, + pub tex_id: OptU16, +} + +// EOF diff --git a/source/marathon/wad.rs b/source/marathon/wad.rs index c45f436..8ba69eb 100644 --- a/source/marathon/wad.rs +++ b/source/marathon/wad.rs @@ -11,10 +11,10 @@ pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize) let mut chunks = Vec::new(); let mut p = 0; - let map_read_minfo = if old_dat {map::read_old_minf} else {map::read_minf}; - let map_read_sides = if old_dat {map::read_old_sids} else {map::read_sids}; - let map_read_polys = if old_dat {map::read_old_poly} else {map::read_poly}; - let map_read_light = if old_dat {map::read_old_lite} else {map::read_lite}; + let rd_minf = if old_dat {map::minf::read_old} else {map::minf::read}; + let rd_sids = if old_dat {map::sids::read_old} else {map::sids::read}; + let rd_poly = if old_dat {map::poly::read_old} else {map::poly::read}; + let rd_lite = if old_dat {map::lite::read_old} else {map::lite::read}; while p < b.len() { read_data! { @@ -30,21 +30,21 @@ pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize) chunks.push(match &iden.0 { b"PICT" => Chunk::Pict(pict::load_pict(data)?), - b"Minf" => Chunk::Minf(map_read_minfo(data)?), - b"iidx" => Chunk::Iidx(rd_array(data, map::read_iidx)?), - b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?), - b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?), - b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?), - b"SIDS" => Chunk::Sids(rd_array(data, map_read_sides)?), - b"POLY" => Chunk::Poly(rd_array(data, map_read_polys)?), - b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?), - b"LITE" => Chunk::Lite(rd_array(data, map_read_light)?), - b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?), - b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?), - b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?), - b"medi" => Chunk::Medi(rd_array(data, map::read_medi)?), - b"plat" => Chunk::Plat(rd_array(data, map::read_plat)?), - b"NOTE" => Chunk::Note(rd_array(data, map::read_note)?), + b"Minf" => Chunk::Minf(rd_minf(data)?), + b"iidx" => Chunk::Iidx(rd_array(data, map::iidx::read)?), + b"EPNT" => Chunk::Pnts(rd_array(data, map::epnt::read)?), + b"PNTS" => Chunk::Pnts(rd_array(data, map::pnts::read)?), + b"LINS" => Chunk::Lins(rd_array(data, map::lins::read)?), + b"SIDS" => Chunk::Sids(rd_array(data, rd_sids)?), + b"POLY" => Chunk::Poly(rd_array(data, rd_poly)?), + b"OBJS" => Chunk::Objs(rd_array(data, map::objs::read)?), + b"LITE" => Chunk::Lite(rd_array(data, rd_lite)?), + b"plac" => Chunk::Plac(rd_array(data, map::plac::read)?), + b"ambi" => Chunk::Ambi(rd_array(data, map::ambi::read)?), + b"bonk" => Chunk::Bonk(rd_array(data, map::bonk::read)?), + b"medi" => Chunk::Medi(rd_array(data, map::medi::read)?), + b"plat" => Chunk::Plat(rd_array(data, map::plat::read)?), + b"NOTE" => Chunk::Note(rd_array(data, map::note::read)?), b"term" => Chunk::Term(rd_array(data, trm::read_term)?), b"FXpx" => Chunk::Fxpx(rd_array(data, phy::read_fxpx)?), b"MNpx" => Chunk::Mnpx(rd_array(data, phy::read_mnpx)?), @@ -143,20 +143,20 @@ pub fn read_wad(b: &[u8]) -> ResultS pub enum Chunk { /** A `PICT` chunk. */ Pict(image::Image8), - /** A `Minf` chunk. */ Minf(map::Minf), + /** A `Minf` chunk. */ Minf(map::minf::Minf), /** An `iidx` chunk. */ Iidx(Vec), - /** A `PNTS` chunk. */ Pnts(Vec), - /** A `LINS` chunk. */ Lins(Vec), - /** A `SIDS` chunk. */ Sids(Vec), - /** A `POLY` chunk. */ Poly(Vec), - /** A `LITE` chunk. */ Lite(Vec), - /** An `OBJS` chunk. */ Objs(Vec), - /** A `plac` chunk. */ Plac(Vec), - /** An `ambi` chunk. */ Ambi(Vec), - /** A `bonk` chunk. */ Bonk(Vec), - /** A `medi` chunk. */ Medi(Vec), - /** A `plat` chunk. */ Plat(Vec), - /** A `NOTE` chunk. */ Note(Vec), + /** A `PNTS` chunk. */ Pnts(Vec), + /** A `LINS` chunk. */ Lins(Vec), + /** A `SIDS` chunk. */ Sids(Vec), + /** A `POLY` chunk. */ Poly(Vec), + /** A `LITE` chunk. */ Lite(Vec), + /** An `OBJS` chunk. */ Objs(Vec), + /** A `plac` chunk. */ Plac(Vec), + /** An `ambi` chunk. */ Ambi(Vec), + /** A `bonk` chunk. */ Bonk(Vec), + /** A `medi` chunk. */ Medi(Vec), + /** A `plat` chunk. */ Plat(Vec), + /** A `NOTE` chunk. */ Note(Vec), /** A `term` chunk. */ Term(Vec), /** A `FXpx` chunk. */ Fxpx(Vec), /** A `MNpx` chunk. */ Mnpx(Vec), diff --git a/source/rozinante/editor/block.rs b/source/rozinante/editor/block.rs index 54b3532..b5e9903 100644 --- a/source/rozinante/editor/block.rs +++ b/source/rozinante/editor/block.rs @@ -5,7 +5,7 @@ impl Default for Block #[inline] fn default() -> Self { - Self{info: map::Minf::default()} + Self{info: map::minf::Minf::default()} } } @@ -13,7 +13,7 @@ impl Default for Block #[derive(Clone, Debug)] pub(super) struct Block { - pub(super) info: map::Minf, + pub(super) info: map::minf::Minf, } // EOF