//! Structures used by Marathon's Map format. use crate::{durandal::{bin::*, err::*, fixed::*, text::*}, marathon::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}) } /// 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}) } /// 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}) } /// 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}) } /// 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, ..Default::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(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, } } /// 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