diff --git a/source/marathon/phy.rs b/source/marathon/phy.rs index 80417d6..33d71e2 100644 --- a/source/marathon/phy.rs +++ b/source/marathon/phy.rs @@ -1,707 +1,12 @@ //! Structures used by Marathon's Physics format. -use crate::{durandal::{bin::*, err::*, fixed::*}}; -use bitflags::bitflags; - -/// Reads a `PXpx` chunk. -pub fn read_pxpx(b: &[u8]) -> ResultS<(Physics, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 104, start: 0, data { - let vel_fwd = Fixed[0]; - let vel_bkw = Fixed[4]; - let vel_prp = Fixed[8]; - let acc_nrm = Fixed[12]; - let dec_nrm = Fixed[16]; - let dec_air = Fixed[20]; - let acc_grv = Fixed[24]; - let acc_cli = Fixed[28]; - let vel_trm = Fixed[32]; - let dec_ext = Fixed[36]; - let acc_ang = Fixed[40]; - let dec_ang = Fixed[44]; - let vel_ang = Fixed[48]; - let vel_rec = Fixed[52]; - let fng_vel = Fixed[56]; - let fng_max = Fixed[60]; - let ele_max = Fixed[64]; - let dec_xng = Fixed[68]; - let stp_dta = Fixed[72]; - let stp_amp = Fixed[76]; - let ply_rad = Fixed[80]; - let ply_hei = Fixed[84]; - let ply_dhi = Fixed[88]; - let ply_cam = Fixed[92]; - let ply_spl = Fixed[96]; - let ply_hcm = Fixed[100]; - } - } - - Ok((Physics{acc_ang, acc_cli, acc_grv, acc_nrm, dec_air, dec_ang, dec_ext, - dec_nrm, dec_xng, ele_max, fng_max, fng_vel, ply_cam, ply_dhi, - ply_hcm, ply_hei, ply_rad, ply_spl, stp_amp, stp_dta, vel_ang, - vel_bkw, vel_fwd, vel_prp, vel_rec, vel_trm}, 104)) -} - -/// Reads a `FXpx` chunk. -pub fn read_fxpx(b: &[u8]) -> ResultS<(Effect, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 14, start: 0, data { - let collection = u16[0]; - let shape = u16[2]; - let pitch = Fixed[4]; - let flags = u16[8] flag EffectFlags; - let delay = OptU16[10]; - let delay_snd = OptU16[12]; - } - } - - Ok((Effect{collection, shape, pitch, flags, delay, delay_snd}, 14)) -} - -/// Reads a `WPpx` chunk. -pub fn read_wppx(b: &[u8]) -> ResultS<(Weapon, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 134, start: 0, data { - let typ_item = u16[0]; - let typ_powerup = OptU16[2]; - let typ_weapon = u16[4] enum WeaponType; - let flags = u16[6] flag WeaponFlags; - let lit_value = Fixed[8]; - let lit_decay = u16[12]; - let hei_idle = Fixed[14]; - let amp_bob = Fixed[18]; - let hei_kick = Fixed[22]; - let hei_reload = Fixed[26]; - let wid_idle = Fixed[30]; - let amp_horz = Fixed[34]; - let collection = u16[38]; - let frm_idle = u16[40]; - let frm_firing = u16[42]; - let frm_reload = OptU16[44]; - let frm_charge = OptU16[48]; - let frm_charged = OptU16[50]; - let tic_ready = u16[52]; - let tic_load_beg = u16[54]; - let tic_load_mid = u16[56]; - let tic_load_end = u16[58]; - let tic_powerup = u16[60]; - let trig_pri = read_trigger[62; 36]; - let trig_sec = read_trigger[98; 36]; - } - } - - Ok((Weapon{amp_bob, amp_horz, collection, flags, frm_charge, frm_charged, - frm_firing, frm_idle, frm_reload, hei_idle, hei_kick, hei_reload, - lit_decay, lit_value, tic_load_beg, tic_load_end, tic_load_mid, - tic_powerup, tic_ready, trig_pri, trig_sec, typ_item, - typ_powerup, typ_weapon, wid_idle}, 134)) -} - -/// Reads a `PRpx` chunk. -pub fn read_prpx(b: &[u8]) -> ResultS<(Projectile, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 48, start: 0, data { - let collection = OptU16[0]; - let shape = u16[2]; - let fxt_explode = OptU16[4]; - let fxt_exp_media = OptU16[6]; - let fxt_trail = OptU16[8]; - let tic_trail = u16[10]; - let max_trail = OptU16[12]; - let typ_media = OptU16[14]; - let radius = Unit[16]; - let dmg_rad = Unit[18]; - let dmg_def = read_damage[20; 12]; - let flags = u32[32] flag ProjectileFlags; - let speed = Unit[36]; - let range = Unit[38]; - let snd_pitch = Fixed[40]; - let snd_fly = OptU16[44]; - let snd_bounce = OptU16[46]; - } - } - - Ok((Projectile{collection, shape, fxt_explode, fxt_exp_media, fxt_trail, - tic_trail, max_trail, typ_media, radius, dmg_rad, dmg_def, - flags, speed, range, snd_pitch, snd_fly, snd_bounce}, 48)) -} - -/// Reads a `MNpx` chunk. -pub fn read_mnpx(b: &[u8]) -> ResultS<(Monster, usize)> -{ - read_data! { - endian: BIG, buf: b, size: 156, start: 0, data { - let collection = u16[0]; - let vitality = u16[2]; - let dty_immune = u32[4] flag DamageTypeFlags; - let dty_weak = u32[8] flag DamageTypeFlags; - let flags = u32[12] flag MonsterFlags; - let cls_self = u32[16] flag MonsterClass; - let cls_friend = u32[20]; - let cls_enemy = u32[24]; - let snd_pitch = Fixed[28]; - let snd_see_enemy = OptU16[32]; - let snd_see_friend = OptU16[34]; - let snd_seeclear = OptU16[36]; - let snd_kill = OptU16[38]; - let snd_apologize = OptU16[40]; - let snd_amicide = OptU16[42]; - let snd_flaming = OptU16[44]; - let snd_active = OptU16[46]; - let snd_active_mask = u16[48]; - let typ_item = OptU16[50]; - let radius = Unit[52]; - let height = Unit[54]; - let height_hover = Unit[56]; - let ledge_min = Unit[58]; - let ledge_max = Unit[60]; - let ext_vel_scale = Fixed[62]; - let fxt_impact = OptU16[66]; - let fxt_impact_melee = OptU16[68]; - let fxt_trail = OptU16[70]; - let half_fov_horz = u16[72]; - let half_fov_vert = u16[74]; - let view_range = Unit[76]; - let view_range_dark = Unit[78]; - let intelligence = u16[80]; - let speed = u16[82]; - let gravity = u16[84]; - let vel_terminal = u16[86]; - let door_try_mask = u16[88]; - let expl_radius = OptU16[90]; - let expl_damage = read_damage[92; 12]; - let seq_hit = OptU16[104]; - let seq_dying_hard = OptU16[106]; - let seq_dying_soft = OptU16[108]; - let seq_dead_hard = OptU16[110]; - let seq_dead_soft = OptU16[112]; - let seq_standing = u16[114]; - let seq_moving = u16[116]; - let seq_tele_in = OptU16[118]; - let seq_tele_out = OptU16[120]; - let atk_frequency = u16[122]; - let atk_melee = read_attack[124; 16]; - let atk_range = read_attack[140; 16]; - } - } - - // friend and enemy fields MUST truncate because the original source code - // used `-1` to represent "all classes" which should be invalid normally - - let cls_friend = MonsterClass::from_bits_truncate(cls_friend); - let cls_enemy = MonsterClass::from_bits_truncate(cls_enemy); - - Ok((Monster{collection, vitality, dty_immune, dty_weak, flags, cls_self, - cls_friend, cls_enemy, snd_pitch, snd_see_enemy, snd_see_friend, - snd_seeclear, snd_kill, snd_apologize, snd_amicide, snd_flaming, - snd_active, snd_active_mask, typ_item, radius, height, - height_hover, ledge_min, ledge_max, ext_vel_scale, fxt_impact, - fxt_impact_melee, fxt_trail, half_fov_horz, half_fov_vert, - view_range, view_range_dark, intelligence, speed, gravity, - vel_terminal, door_try_mask, expl_radius, expl_damage, seq_hit, - seq_dying_hard, seq_dying_soft, seq_dead_hard, seq_dead_soft, - seq_standing, seq_moving, seq_tele_in, seq_tele_out, - atk_frequency, atk_melee, atk_range}, 156)) -} - -/// Reads a `Trigger` object. -fn read_trigger(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 36, start: 0, data { - let magazine = u16[0]; - let typ_ammo = OptU16[2]; - let tic_round = OptU16[4]; - let tic_recover = u16[6]; - let tic_charge = u16[8]; - let recoil = Unit[10]; - let snd_fire = OptU16[12]; - let snd_click = OptU16[14]; - let snd_charge = OptU16[16]; - let snd_casing = OptU16[18]; - let snd_reload = OptU16[20]; - let snd_charged = OptU16[22]; - let typ_proj = u16[24]; - let theta = u16[26]; - let dx = i16[28]; - let dz = i16[30]; - let typ_casing = u16[32] enum CasingType; - let burst = u16[34]; - } - } - - Ok(Trigger{burst, dx, dz, magazine, recoil, snd_casing, snd_charge, - snd_charged, snd_click, snd_fire, snd_reload, theta, tic_charge, - tic_recover, tic_round, typ_ammo, typ_casing, typ_proj}) -} - -/// Reads a `Damage` object. -fn read_damage(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 12, start: 0, data { - let dtype = u16[0] enum DamageType; - let flags = u16[2]; - let dmg_base = u16[4]; - let dmg_rand = u16[6]; - let scale = Fixed[8]; - } - } - - let alien = flags != 0; - - Ok(Damage{dtype, alien, dmg_base, dmg_rand, scale}) -} - -/// Reads an `Attack` object. -fn read_attack(b: &[u8]) -> ResultS -{ - read_data! { - endian: BIG, buf: b, size: 16, start: 0, data { - let ptype = OptU16[0]; - let rep = u16[2]; - let error = Angle[4]; - let range = Unit[6]; - let shape = u16[8]; - let ofs_x = Unit[10]; - let ofs_y = Unit[12]; - let ofs_z = Unit[14]; - } - } - - Ok(Attack{ptype, rep, error, range, shape, ofs_x, ofs_y, ofs_z}) -} - -/// Static physics information. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Physics -{ - pub acc_ang: Fixed, - pub acc_cli: Fixed, - pub acc_grv: Fixed, - pub acc_nrm: Fixed, - pub dec_air: Fixed, - pub dec_ang: Fixed, - pub dec_ext: Fixed, - pub dec_nrm: Fixed, - pub dec_xng: Fixed, - pub ele_max: Fixed, - pub fng_max: Fixed, - pub fng_vel: Fixed, - pub ply_cam: Fixed, - pub ply_dhi: Fixed, - pub ply_hcm: Fixed, - pub ply_hei: Fixed, - pub ply_rad: Fixed, - pub ply_spl: Fixed, - pub stp_amp: Fixed, - pub stp_dta: Fixed, - pub vel_ang: Fixed, - pub vel_bkw: Fixed, - pub vel_fwd: Fixed, - pub vel_prp: Fixed, - pub vel_rec: Fixed, - pub vel_trm: Fixed, -} - -/// An effect definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Effect -{ - pub collection: u16, - pub shape: u16, - pub pitch: Fixed, - pub flags: EffectFlags, - pub delay: OptU16, - pub delay_snd: OptU16, -} - -/// A weapon definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Weapon -{ - pub amp_bob: Fixed, - pub amp_horz: Fixed, - pub collection: u16, - pub flags: WeaponFlags, - pub frm_charge: OptU16, - pub frm_charged: OptU16, - pub frm_firing: u16, - pub frm_idle: u16, - pub frm_reload: OptU16, - pub hei_idle: Fixed, - pub hei_kick: Fixed, - pub hei_reload: Fixed, - pub lit_decay: u16, - pub lit_value: Fixed, - pub tic_load_beg: u16, - pub tic_load_end: u16, - pub tic_load_mid: u16, - pub tic_powerup: u16, - pub tic_ready: u16, - pub trig_pri: Trigger, - pub trig_sec: Trigger, - pub typ_item: u16, - pub typ_powerup: OptU16, - pub typ_weapon: WeaponType, - pub wid_idle: Fixed, -} - -/// The definition of one of two triggers for a weapon. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Trigger -{ - pub burst: u16, - pub dx: i16, - pub dz: i16, - pub magazine: u16, - pub recoil: Unit, - pub snd_casing: OptU16, - pub snd_charge: OptU16, - pub snd_charged: OptU16, - pub snd_click: OptU16, - pub snd_fire: OptU16, - pub snd_reload: OptU16, - pub theta: u16, - pub tic_charge: u16, - pub tic_recover: u16, - pub tic_round: OptU16, - pub typ_ammo: OptU16, - pub typ_casing: CasingType, - pub typ_proj: u16, -} - -/// A projectile definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Projectile -{ - pub collection: OptU16, - pub shape: u16, - pub fxt_explode: OptU16, - pub fxt_exp_media: OptU16, - pub fxt_trail: OptU16, - pub tic_trail: u16, - pub max_trail: OptU16, - pub typ_media: OptU16, - pub radius: Unit, - pub dmg_rad: Unit, - pub dmg_def: Damage, - pub flags: ProjectileFlags, - pub speed: Unit, - pub range: Unit, - pub snd_pitch: Fixed, - pub snd_fly: OptU16, - pub snd_bounce: OptU16, -} - -/// A monster definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Monster -{ - pub collection: u16, - pub vitality: u16, - pub dty_immune: DamageTypeFlags, - pub dty_weak: DamageTypeFlags, - pub flags: MonsterFlags, - pub cls_self: MonsterClass, - pub cls_friend: MonsterClass, - pub cls_enemy: MonsterClass, - pub snd_pitch: Fixed, - pub snd_see_enemy: OptU16, - pub snd_see_friend: OptU16, - pub snd_seeclear: OptU16, - pub snd_kill: OptU16, - pub snd_apologize: OptU16, - pub snd_amicide: OptU16, - pub snd_flaming: OptU16, - pub snd_active: OptU16, - pub snd_active_mask: u16, - pub typ_item: OptU16, - pub radius: Unit, - pub height: Unit, - pub height_hover: Unit, - pub ledge_min: Unit, - pub ledge_max: Unit, - pub ext_vel_scale: Fixed, - pub fxt_impact: OptU16, - pub fxt_impact_melee: OptU16, - pub fxt_trail: OptU16, - pub half_fov_horz: u16, - pub half_fov_vert: u16, - pub view_range: Unit, - pub view_range_dark: Unit, - pub intelligence: u16, - pub speed: u16, - pub gravity: u16, - pub vel_terminal: u16, - pub door_try_mask: u16, - pub expl_radius: OptU16, - pub expl_damage: Damage, - pub seq_hit: OptU16, - pub seq_dying_hard: OptU16, - pub seq_dying_soft: OptU16, - pub seq_dead_hard: OptU16, - pub seq_dead_soft: OptU16, - pub seq_standing: u16, - pub seq_moving: u16, - pub seq_tele_in: OptU16, - pub seq_tele_out: OptU16, - pub atk_frequency: u16, - pub atk_melee: Attack, - pub atk_range: Attack, -} - -/// A damage definition. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Damage -{ - pub dtype: DamageType, - pub alien: bool, - pub dmg_base: u16, - pub dmg_rand: u16, - pub scale: Fixed, -} - -/// The definition of a monster's attack. -#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] -#[derive(Debug, Eq, PartialEq)] -pub struct Attack -{ - pub ptype: OptU16, - pub rep: u16, - pub error: Angle, - pub range: Unit, - pub shape: u16, - pub ofs_x: Unit, - pub ofs_y: Unit, - pub ofs_z: Unit, -} - -bitflags! { - /// Flags for an effect. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct EffectFlags: u16 - { - const END_ON_LOOP = 1; - const END_ON_XFER_LOOP = 1 << 1; - const SOUND_ONLY = 1 << 2; - const MAKE_TWIN_VISIBLE = 1 << 3; - const MEDIA_EFFECT = 1 << 4; - } -} - -bitflags! { - /// Flags for a weapon. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct WeaponFlags: u16 - { - const AUTOMATIC = 1; - const REMOVE_AFTER_USE = 1 << 1; - const INSTANT_CASING = 1 << 2; - const OVERLOADS = 1 << 3; - const RANDOM_AMMO = 1 << 4; - const TEMPORARY_POWER = 1 << 5; - const RELOAD_ONE_HAND = 1 << 6; - const FIRE_OUT_OF_PHASE = 1 << 7; - const FIRE_UNDER_MEDIA = 1 << 8; - const TRIGGER_SAME_AMMO = 1 << 9; - const SECONDARY_FLIP = 1 << 10; - } -} - -bitflags! { - /// Flags for a projectile. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct ProjectileFlags: u32 - { - const GUIDED = 1; - const STOP_ON_LOOP = 1 << 1; - const PERSISTENT = 1 << 2; - const ALIEN = 1 << 3; - const GRAVITY = 1 << 4; - const NO_HORZ_ERROR = 1 << 5; - const NO_VERT_ERROR = 1 << 6; - const TOGGLE_PANELS = 1 << 7; - const POS_VERT_ERROR = 1 << 8; - const MELEE = 1 << 9; - const RIPPER = 1 << 10; - const PASS_TRANS_RANDOM = 1 << 11; - const PASS_TRANS_MORE = 1 << 12; - const DOUBLE_GRAVITY = 1 << 13; - const REBOUND_FLOOR = 1 << 14; - const THROUGH_MEDIA = 1 << 15; - const BECOME_ITEM = 1 << 16; - const BLOODY = 1 << 17; - const WANDER_HORZ = 1 << 18; - const USE_LOW_GRAV = 1 << 19; - const PASS_MEDIA = 1 << 20; - } -} - -bitflags! { - /// Flags for a monster. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct MonsterFlags: u32 - { - const IGNORE_LOS = 1; - const FLYING = 1 << 1; - const ALIEN = 1 << 2; - const MAJOR = 1 << 3; - const MINOR = 1 << 4; - const NO_OMIT = 1 << 5; - const FLOATS = 1 << 6; - const NO_ATTACK = 1 << 7; - const SNIPE = 1 << 8; - const INVISIBLE = 1 << 9; - const SUBTLY_INVISIBLE = 1 << 10; - const KAMIKAZE = 1 << 11; - const BERSERKER = 1 << 12; - const ENLARGED = 1 << 13; - const DELAYED_DEATH = 1 << 14; - const FIRE_SYMMETRICAL = 1 << 15; - const NUCLEAR_DEATH = 1 << 16; - const NO_FIRE_BACKWARDS = 1 << 17; - const CAN_DIE_IN_FLAMES = 1 << 18; - const WAIT_FOR_GOOD_SHOT = 1 << 19; - const TINY = 1 << 20; - const FAST_ATTACK = 1 << 21; - const LIKES_WATER = 1 << 22; - const LIKES_SEWAGE = 1 << 23; - const LIKES_LAVA = 1 << 24; - const LIKES_GOO = 1 << 25; - const TELE_UNDER_MEDIA = 1 << 26; - const USE_RANDOM_WEAPON = 1 << 27; - } -} - -bitflags! { - /// The composite type of a monster. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct MonsterClass: u32 - { - const PLAYER = 1; - const CIVILIAN = 1 << 1; - const MADD = 1 << 2; - const POSSESSED_HUMMER = 1 << 3; - const DEFENDER = 1 << 4; - const FIGHTER = 1 << 5; - const TROOPER = 1 << 6; - const HUNTER = 1 << 7; - const ENFORCER = 1 << 8; - const JUGGERNAUT = 1 << 9; - const HUMMER = 1 << 10; - const COMPILER = 1 << 11; - const CYBORG = 1 << 12; - const ASSIMILATED = 1 << 13; - const TICK = 1 << 14; - const YETI = 1 << 15; - } -} - -bitflags! { - /// The composite type of damage taken by something. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - pub struct DamageTypeFlags: u32 - { - const EXPLOSION = 1; - const ELECTRICAL_STAFF = 1 << 1; - const PROJECTILE = 1 << 2; - const ABSORBED = 1 << 3; - const FLAME = 1 << 4; - const HOUND_CLAWS = 1 << 5; - const ALIEN_PROJECTILE = 1 << 6; - const HULK_SLAP = 1 << 7; - const COMPILER_BOLT = 1 << 8; - const FUSION_BOLT = 1 << 9; - const HUNTER_BOLT = 1 << 10; - const FIST = 1 << 11; - const TELEPORTER = 1 << 12; - const DEFENDER = 1 << 13; - const YETI_CLAWS = 1 << 14; - const YETI_PROJECTILE = 1 << 15; - const CRUSHING = 1 << 16; - const LAVA = 1 << 17; - const SUFFOCATION = 1 << 18; - const GOO = 1 << 19; - const ENERGY_DRAIN = 1 << 20; - const OXYGEN_DRAIN = 1 << 21; - const HUMMER_BOLT = 1 << 22; - const SHOTGUN_PROJECTILE = 1 << 23; - } -} - -c_enum! { - /// A bullet shell casing emitted by a weapon. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum CasingType: u16 - { - Rifle = 0, - Pistol = 1, - PistolLeft = 2, - PistolRight = 3, - SMG = 4, - None = 0xFFFF, - } -} - -c_enum! { - /// The type of functionality a weapon provides. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum WeaponType: u16 - { - Melee = 0, - Normal = 1, - DualFunc = 2, - DualPistol = 3, - Multipurpose = 4, - } -} - -c_enum! { - /// A named type of damage taken by something. - #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] - #[derive(Debug)] - pub enum DamageType: u16 - { - Explosion = 0, - ElectricalStaff = 1, - Projectile = 2, - Absorbed = 3, - Flame = 4, - HoundClaws = 5, - AlienProjectile = 6, - HulkSlap = 7, - CompilerBolt = 8, - FusionBolt = 9, - HunterBolt = 10, - Fist = 11, - Teleporter = 12, - Defender = 13, - YetiClaws = 14, - YetiProjectile = 15, - Crushing = 16, - Lava = 17, - Suffocation = 18, - Goo = 19, - EnergyDrain = 20, - OxygenDrain = 21, - HummerBolt = 22, - ShotgunProjectile = 23, - None = 0xFFFF, - } -} +pub mod attk; +pub mod damg; +pub mod fxpx; +pub mod mnpx; +pub mod prpx; +pub mod pxpx; +pub mod trig; +pub mod wppx; // EOF diff --git a/source/marathon/phy/attk.rs b/source/marathon/phy/attk.rs new file mode 100644 index 0000000..73764cc --- /dev/null +++ b/source/marathon/phy/attk.rs @@ -0,0 +1,39 @@ +//! `Attack` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::{Angle, Unit}}}; + +/// Reads an `Attack` object. +pub fn read(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 16, start: 0, data { + let ptype = OptU16[0]; + let rep = u16[2]; + let error = Angle[4]; + let range = Unit[6]; + let shape = u16[8]; + let ofs_x = Unit[10]; + let ofs_y = Unit[12]; + let ofs_z = Unit[14]; + } + } + + Ok(Attack{ptype, rep, error, range, shape, ofs_x, ofs_y, ofs_z}) +} + +/// The definition of a monster's attack. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Attack +{ + pub ptype: OptU16, + pub rep: u16, + pub error: Angle, + pub range: Unit, + pub shape: u16, + pub ofs_x: Unit, + pub ofs_y: Unit, + pub ofs_z: Unit, +} + +// EOF diff --git a/source/marathon/phy/damg.rs b/source/marathon/phy/damg.rs new file mode 100644 index 0000000..decaf26 --- /dev/null +++ b/source/marathon/phy/damg.rs @@ -0,0 +1,102 @@ +//! `Damage` type. + +use crate::{durandal::{err::*, fixed::Fixed}}; +use bitflags::bitflags; + +/// Reads a `Damage` object. +pub fn read(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 12, start: 0, data { + let dtype = u16[0] enum DamageType; + let flags = u16[2]; + let dmg_base = u16[4]; + let dmg_rand = u16[6]; + let scale = Fixed[8]; + } + } + + let alien = flags != 0; + + Ok(Damage{dtype, alien, dmg_base, dmg_rand, scale}) +} + +/// A damage definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Damage +{ + pub dtype: DamageType, + pub alien: bool, + pub dmg_base: u16, + pub dmg_rand: u16, + pub scale: Fixed, +} + +bitflags! { + /// The composite type of damage taken by something. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct DamageTypeFlags: u32 + { + const EXPLOSION = 1; + const ELECTRICAL_STAFF = 1 << 1; + const PROJECTILE = 1 << 2; + const ABSORBED = 1 << 3; + const FLAME = 1 << 4; + const HOUND_CLAWS = 1 << 5; + const ALIEN_PROJECTILE = 1 << 6; + const HULK_SLAP = 1 << 7; + const COMPILER_BOLT = 1 << 8; + const FUSION_BOLT = 1 << 9; + const HUNTER_BOLT = 1 << 10; + const FIST = 1 << 11; + const TELEPORTER = 1 << 12; + const DEFENDER = 1 << 13; + const YETI_CLAWS = 1 << 14; + const YETI_PROJECTILE = 1 << 15; + const CRUSHING = 1 << 16; + const LAVA = 1 << 17; + const SUFFOCATION = 1 << 18; + const GOO = 1 << 19; + const ENERGY_DRAIN = 1 << 20; + const OXYGEN_DRAIN = 1 << 21; + const HUMMER_BOLT = 1 << 22; + const SHOTGUN_PROJECTILE = 1 << 23; + } +} + +c_enum! { + /// A named type of damage taken by something. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum DamageType: u16 + { + Explosion = 0, + ElectricalStaff = 1, + Projectile = 2, + Absorbed = 3, + Flame = 4, + HoundClaws = 5, + AlienProjectile = 6, + HulkSlap = 7, + CompilerBolt = 8, + FusionBolt = 9, + HunterBolt = 10, + Fist = 11, + Teleporter = 12, + Defender = 13, + YetiClaws = 14, + YetiProjectile = 15, + Crushing = 16, + Lava = 17, + Suffocation = 18, + Goo = 19, + EnergyDrain = 20, + OxygenDrain = 21, + HummerBolt = 22, + ShotgunProjectile = 23, + None = 0xFFFF, + } +} + +// EOF diff --git a/source/marathon/phy/fxpx.rs b/source/marathon/phy/fxpx.rs new file mode 100644 index 0000000..7d91b2d --- /dev/null +++ b/source/marathon/phy/fxpx.rs @@ -0,0 +1,49 @@ +//! `Effect` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::Fixed}}; +use bitflags::bitflags; + +/// Reads a `FXpx` chunk. +pub fn read(b: &[u8]) -> ResultS<(Effect, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 14, start: 0, data { + let collection = u16[0]; + let shape = u16[2]; + let pitch = Fixed[4]; + let flags = u16[8] flag EffectFlags; + let delay = OptU16[10]; + let delay_snd = OptU16[12]; + } + } + + Ok((Effect{collection, shape, pitch, flags, delay, delay_snd}, 14)) +} + +/// An effect definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Effect +{ + pub collection: u16, + pub shape: u16, + pub pitch: Fixed, + pub flags: EffectFlags, + pub delay: OptU16, + pub delay_snd: OptU16, +} + +bitflags! { + /// Flags for an effect. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct EffectFlags: u16 + { + const END_ON_LOOP = 1; + const END_ON_XFER_LOOP = 1 << 1; + const SOUND_ONLY = 1 << 2; + const MAKE_TWIN_VISIBLE = 1 << 3; + const MEDIA_EFFECT = 1 << 4; + } +} + +// EOF diff --git a/source/marathon/phy/mnpx.rs b/source/marathon/phy/mnpx.rs new file mode 100644 index 0000000..9c0ff41 --- /dev/null +++ b/source/marathon/phy/mnpx.rs @@ -0,0 +1,204 @@ +//! `Monster` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::{Fixed, Unit}}}; +use bitflags::bitflags; + +use super::{attk, damg}; + +/// Reads a `MNpx` chunk. +pub fn read(b: &[u8]) -> ResultS<(Monster, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 156, start: 0, data { + let collection = u16[0]; + let vitality = u16[2]; + let dty_immune = u32[4] flag damg::DamageTypeFlags; + let dty_weak = u32[8] flag damg::DamageTypeFlags; + let flags = u32[12] flag MonsterFlags; + let cls_self = u32[16] flag MonsterClass; + let cls_friend = u32[20]; + let cls_enemy = u32[24]; + let snd_pitch = Fixed[28]; + let snd_see_enemy = OptU16[32]; + let snd_see_friend = OptU16[34]; + let snd_seeclear = OptU16[36]; + let snd_kill = OptU16[38]; + let snd_apologize = OptU16[40]; + let snd_amicide = OptU16[42]; + let snd_flaming = OptU16[44]; + let snd_active = OptU16[46]; + let snd_active_mask = u16[48]; + let typ_item = OptU16[50]; + let radius = Unit[52]; + let height = Unit[54]; + let height_hover = Unit[56]; + let ledge_min = Unit[58]; + let ledge_max = Unit[60]; + let ext_vel_scale = Fixed[62]; + let fxt_impact = OptU16[66]; + let fxt_impact_melee = OptU16[68]; + let fxt_trail = OptU16[70]; + let half_fov_horz = u16[72]; + let half_fov_vert = u16[74]; + let view_range = Unit[76]; + let view_range_dark = Unit[78]; + let intelligence = u16[80]; + let speed = u16[82]; + let gravity = u16[84]; + let vel_terminal = u16[86]; + let door_try_mask = u16[88]; + let expl_radius = OptU16[90]; + let expl_damage = damg::read[92; 12]; + let seq_hit = OptU16[104]; + let seq_dying_hard = OptU16[106]; + let seq_dying_soft = OptU16[108]; + let seq_dead_hard = OptU16[110]; + let seq_dead_soft = OptU16[112]; + let seq_standing = u16[114]; + let seq_moving = u16[116]; + let seq_tele_in = OptU16[118]; + let seq_tele_out = OptU16[120]; + let atk_frequency = u16[122]; + let atk_melee = attk::read[124; 16]; + let atk_range = attk::read[140; 16]; + } + } + + // friend and enemy fields MUST truncate because the original source code + // used `-1` to represent "all classes" which should be invalid normally + + let cls_friend = MonsterClass::from_bits_truncate(cls_friend); + let cls_enemy = MonsterClass::from_bits_truncate(cls_enemy); + + Ok((Monster{collection, vitality, dty_immune, dty_weak, flags, cls_self, + cls_friend, cls_enemy, snd_pitch, snd_see_enemy, snd_see_friend, + snd_seeclear, snd_kill, snd_apologize, snd_amicide, snd_flaming, + snd_active, snd_active_mask, typ_item, radius, height, + height_hover, ledge_min, ledge_max, ext_vel_scale, fxt_impact, + fxt_impact_melee, fxt_trail, half_fov_horz, half_fov_vert, + view_range, view_range_dark, intelligence, speed, gravity, + vel_terminal, door_try_mask, expl_radius, expl_damage, seq_hit, + seq_dying_hard, seq_dying_soft, seq_dead_hard, seq_dead_soft, + seq_standing, seq_moving, seq_tele_in, seq_tele_out, + atk_frequency, atk_melee, atk_range}, 156)) +} + +/// A monster definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Monster +{ + pub collection: u16, + pub vitality: u16, + pub dty_immune: damg::DamageTypeFlags, + pub dty_weak: damg::DamageTypeFlags, + pub flags: MonsterFlags, + pub cls_self: MonsterClass, + pub cls_friend: MonsterClass, + pub cls_enemy: MonsterClass, + pub snd_pitch: Fixed, + pub snd_see_enemy: OptU16, + pub snd_see_friend: OptU16, + pub snd_seeclear: OptU16, + pub snd_kill: OptU16, + pub snd_apologize: OptU16, + pub snd_amicide: OptU16, + pub snd_flaming: OptU16, + pub snd_active: OptU16, + pub snd_active_mask: u16, + pub typ_item: OptU16, + pub radius: Unit, + pub height: Unit, + pub height_hover: Unit, + pub ledge_min: Unit, + pub ledge_max: Unit, + pub ext_vel_scale: Fixed, + pub fxt_impact: OptU16, + pub fxt_impact_melee: OptU16, + pub fxt_trail: OptU16, + pub half_fov_horz: u16, + pub half_fov_vert: u16, + pub view_range: Unit, + pub view_range_dark: Unit, + pub intelligence: u16, + pub speed: u16, + pub gravity: u16, + pub vel_terminal: u16, + pub door_try_mask: u16, + pub expl_radius: OptU16, + pub expl_damage: damg::Damage, + pub seq_hit: OptU16, + pub seq_dying_hard: OptU16, + pub seq_dying_soft: OptU16, + pub seq_dead_hard: OptU16, + pub seq_dead_soft: OptU16, + pub seq_standing: u16, + pub seq_moving: u16, + pub seq_tele_in: OptU16, + pub seq_tele_out: OptU16, + pub atk_frequency: u16, + pub atk_melee: attk::Attack, + pub atk_range: attk::Attack, +} + +bitflags! { + /// Flags for a monster. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct MonsterFlags: u32 + { + const IGNORE_LOS = 1; + const FLYING = 1 << 1; + const ALIEN = 1 << 2; + const MAJOR = 1 << 3; + const MINOR = 1 << 4; + const NO_OMIT = 1 << 5; + const FLOATS = 1 << 6; + const NO_ATTACK = 1 << 7; + const SNIPE = 1 << 8; + const INVISIBLE = 1 << 9; + const SUBTLY_INVISIBLE = 1 << 10; + const KAMIKAZE = 1 << 11; + const BERSERKER = 1 << 12; + const ENLARGED = 1 << 13; + const DELAYED_DEATH = 1 << 14; + const FIRE_SYMMETRICAL = 1 << 15; + const NUCLEAR_DEATH = 1 << 16; + const NO_FIRE_BACKWARDS = 1 << 17; + const CAN_DIE_IN_FLAMES = 1 << 18; + const WAIT_FOR_GOOD_SHOT = 1 << 19; + const TINY = 1 << 20; + const FAST_ATTACK = 1 << 21; + const LIKES_WATER = 1 << 22; + const LIKES_SEWAGE = 1 << 23; + const LIKES_LAVA = 1 << 24; + const LIKES_GOO = 1 << 25; + const TELE_UNDER_MEDIA = 1 << 26; + const USE_RANDOM_WEAPON = 1 << 27; + } +} + +bitflags! { + /// The composite type of a monster. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct MonsterClass: u32 + { + const PLAYER = 1; + const CIVILIAN = 1 << 1; + const MADD = 1 << 2; + const POSSESSED_HUMMER = 1 << 3; + const DEFENDER = 1 << 4; + const FIGHTER = 1 << 5; + const TROOPER = 1 << 6; + const HUNTER = 1 << 7; + const ENFORCER = 1 << 8; + const JUGGERNAUT = 1 << 9; + const HUMMER = 1 << 10; + const COMPILER = 1 << 11; + const CYBORG = 1 << 12; + const ASSIMILATED = 1 << 13; + const TICK = 1 << 14; + const YETI = 1 << 15; + } +} + +// EOF diff --git a/source/marathon/phy/prpx.rs b/source/marathon/phy/prpx.rs new file mode 100644 index 0000000..eb31ba7 --- /dev/null +++ b/source/marathon/phy/prpx.rs @@ -0,0 +1,91 @@ +//! `Projectile` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::{Fixed, Unit}}}; +use bitflags::bitflags; + +use super::damg; + +/// Reads a `PRpx` chunk. +pub fn read(b: &[u8]) -> ResultS<(Projectile, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 48, start: 0, data { + let collection = OptU16[0]; + let shape = u16[2]; + let fxt_explode = OptU16[4]; + let fxt_exp_media = OptU16[6]; + let fxt_trail = OptU16[8]; + let tic_trail = u16[10]; + let max_trail = OptU16[12]; + let typ_media = OptU16[14]; + let radius = Unit[16]; + let dmg_rad = Unit[18]; + let dmg_def = damg::read[20; 12]; + let flags = u32[32] flag ProjectileFlags; + let speed = Unit[36]; + let range = Unit[38]; + let snd_pitch = Fixed[40]; + let snd_fly = OptU16[44]; + let snd_bounce = OptU16[46]; + } + } + + Ok((Projectile{collection, shape, fxt_explode, fxt_exp_media, fxt_trail, + tic_trail, max_trail, typ_media, radius, dmg_rad, dmg_def, + flags, speed, range, snd_pitch, snd_fly, snd_bounce}, 48)) +} + +/// A projectile definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Projectile +{ + pub collection: OptU16, + pub shape: u16, + pub fxt_explode: OptU16, + pub fxt_exp_media: OptU16, + pub fxt_trail: OptU16, + pub tic_trail: u16, + pub max_trail: OptU16, + pub typ_media: OptU16, + pub radius: Unit, + pub dmg_rad: Unit, + pub dmg_def: damg::Damage, + pub flags: ProjectileFlags, + pub speed: Unit, + pub range: Unit, + pub snd_pitch: Fixed, + pub snd_fly: OptU16, + pub snd_bounce: OptU16, +} + +bitflags! { + /// Flags for a projectile. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct ProjectileFlags: u32 + { + const GUIDED = 1; + const STOP_ON_LOOP = 1 << 1; + const PERSISTENT = 1 << 2; + const ALIEN = 1 << 3; + const GRAVITY = 1 << 4; + const NO_HORZ_ERROR = 1 << 5; + const NO_VERT_ERROR = 1 << 6; + const TOGGLE_PANELS = 1 << 7; + const POS_VERT_ERROR = 1 << 8; + const MELEE = 1 << 9; + const RIPPER = 1 << 10; + const PASS_TRANS_RANDOM = 1 << 11; + const PASS_TRANS_MORE = 1 << 12; + const DOUBLE_GRAVITY = 1 << 13; + const REBOUND_FLOOR = 1 << 14; + const THROUGH_MEDIA = 1 << 15; + const BECOME_ITEM = 1 << 16; + const BLOODY = 1 << 17; + const WANDER_HORZ = 1 << 18; + const USE_LOW_GRAV = 1 << 19; + const PASS_MEDIA = 1 << 20; + } +} + +// EOF diff --git a/source/marathon/phy/pxpx.rs b/source/marathon/phy/pxpx.rs new file mode 100644 index 0000000..1a83e0f --- /dev/null +++ b/source/marathon/phy/pxpx.rs @@ -0,0 +1,78 @@ +//! `Physics` type. + +use crate::{durandal::{err::*, fixed::Fixed}}; + +/// Reads a `PXpx` chunk. +pub fn read(b: &[u8]) -> ResultS<(Physics, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 104, start: 0, data { + let vel_fwd = Fixed[0]; + let vel_bkw = Fixed[4]; + let vel_prp = Fixed[8]; + let acc_nrm = Fixed[12]; + let dec_nrm = Fixed[16]; + let dec_air = Fixed[20]; + let acc_grv = Fixed[24]; + let acc_cli = Fixed[28]; + let vel_trm = Fixed[32]; + let dec_ext = Fixed[36]; + let acc_ang = Fixed[40]; + let dec_ang = Fixed[44]; + let vel_ang = Fixed[48]; + let vel_rec = Fixed[52]; + let fng_vel = Fixed[56]; + let fng_max = Fixed[60]; + let ele_max = Fixed[64]; + let dec_xng = Fixed[68]; + let stp_dta = Fixed[72]; + let stp_amp = Fixed[76]; + let ply_rad = Fixed[80]; + let ply_hei = Fixed[84]; + let ply_dhi = Fixed[88]; + let ply_cam = Fixed[92]; + let ply_spl = Fixed[96]; + let ply_hcm = Fixed[100]; + } + } + + Ok((Physics{acc_ang, acc_cli, acc_grv, acc_nrm, dec_air, dec_ang, dec_ext, + dec_nrm, dec_xng, ele_max, fng_max, fng_vel, ply_cam, ply_dhi, + ply_hcm, ply_hei, ply_rad, ply_spl, stp_amp, stp_dta, vel_ang, + vel_bkw, vel_fwd, vel_prp, vel_rec, vel_trm}, 104)) +} + +/// Static physics information. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Physics +{ + pub acc_ang: Fixed, + pub acc_cli: Fixed, + pub acc_grv: Fixed, + pub acc_nrm: Fixed, + pub dec_air: Fixed, + pub dec_ang: Fixed, + pub dec_ext: Fixed, + pub dec_nrm: Fixed, + pub dec_xng: Fixed, + pub ele_max: Fixed, + pub fng_max: Fixed, + pub fng_vel: Fixed, + pub ply_cam: Fixed, + pub ply_dhi: Fixed, + pub ply_hcm: Fixed, + pub ply_hei: Fixed, + pub ply_rad: Fixed, + pub ply_spl: Fixed, + pub stp_amp: Fixed, + pub stp_dta: Fixed, + pub vel_ang: Fixed, + pub vel_bkw: Fixed, + pub vel_fwd: Fixed, + pub vel_prp: Fixed, + pub vel_rec: Fixed, + pub vel_trm: Fixed, +} + +// EOF diff --git a/source/marathon/phy/trig.rs b/source/marathon/phy/trig.rs new file mode 100644 index 0000000..f9ec60b --- /dev/null +++ b/source/marathon/phy/trig.rs @@ -0,0 +1,76 @@ +//! `Monster` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::Unit}}; + +/// Reads a `Trigger` object. +pub fn read(b: &[u8]) -> ResultS +{ + read_data! { + endian: BIG, buf: b, size: 36, start: 0, data { + let magazine = u16[0]; + let typ_ammo = OptU16[2]; + let tic_round = OptU16[4]; + let tic_recover = u16[6]; + let tic_charge = u16[8]; + let recoil = Unit[10]; + let snd_fire = OptU16[12]; + let snd_click = OptU16[14]; + let snd_charge = OptU16[16]; + let snd_casing = OptU16[18]; + let snd_reload = OptU16[20]; + let snd_charged = OptU16[22]; + let typ_proj = u16[24]; + let theta = u16[26]; + let dx = i16[28]; + let dz = i16[30]; + let typ_casing = u16[32] enum CasingType; + let burst = u16[34]; + } + } + + Ok(Trigger{burst, dx, dz, magazine, recoil, snd_casing, snd_charge, + snd_charged, snd_click, snd_fire, snd_reload, theta, tic_charge, + tic_recover, tic_round, typ_ammo, typ_casing, typ_proj}) +} + +/// The definition of one of two triggers for a weapon. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Trigger +{ + pub burst: u16, + pub dx: i16, + pub dz: i16, + pub magazine: u16, + pub recoil: Unit, + pub snd_casing: OptU16, + pub snd_charge: OptU16, + pub snd_charged: OptU16, + pub snd_click: OptU16, + pub snd_fire: OptU16, + pub snd_reload: OptU16, + pub theta: u16, + pub tic_charge: u16, + pub tic_recover: u16, + pub tic_round: OptU16, + pub typ_ammo: OptU16, + pub typ_casing: CasingType, + pub typ_proj: u16, +} + +c_enum! { + /// A bullet shell casing emitted by a weapon. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum CasingType: u16 + { + Rifle = 0, + Pistol = 1, + PistolLeft = 2, + PistolRight = 3, + SMG = 4, + None = 0xFFFF, + } +} + +// EOF diff --git a/source/marathon/phy/wppx.rs b/source/marathon/phy/wppx.rs new file mode 100644 index 0000000..91b61aa --- /dev/null +++ b/source/marathon/phy/wppx.rs @@ -0,0 +1,113 @@ +//! `Weapon` type. + +use crate::{durandal::{bin::OptU16, err::*, fixed::Fixed}}; +use bitflags::bitflags; + +use super::trig; + +/// Reads a `WPpx` chunk. +pub fn read(b: &[u8]) -> ResultS<(Weapon, usize)> +{ + read_data! { + endian: BIG, buf: b, size: 134, start: 0, data { + let typ_item = u16[0]; + let typ_powerup = OptU16[2]; + let typ_weapon = u16[4] enum WeaponType; + let flags = u16[6] flag WeaponFlags; + let lit_value = Fixed[8]; + let lit_decay = u16[12]; + let hei_idle = Fixed[14]; + let amp_bob = Fixed[18]; + let hei_kick = Fixed[22]; + let hei_reload = Fixed[26]; + let wid_idle = Fixed[30]; + let amp_horz = Fixed[34]; + let collection = u16[38]; + let frm_idle = u16[40]; + let frm_firing = u16[42]; + let frm_reload = OptU16[44]; + let frm_charge = OptU16[48]; + let frm_charged = OptU16[50]; + let tic_ready = u16[52]; + let tic_load_beg = u16[54]; + let tic_load_mid = u16[56]; + let tic_load_end = u16[58]; + let tic_powerup = u16[60]; + let trig_pri = trig::read[62; 36]; + let trig_sec = trig::read[98; 36]; + } + } + + Ok((Weapon{amp_bob, amp_horz, collection, flags, frm_charge, frm_charged, + frm_firing, frm_idle, frm_reload, hei_idle, hei_kick, hei_reload, + lit_decay, lit_value, tic_load_beg, tic_load_end, tic_load_mid, + tic_powerup, tic_ready, trig_pri, trig_sec, typ_item, + typ_powerup, typ_weapon, wid_idle}, 134)) +} + +/// A weapon definition. +#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] +#[derive(Debug, Eq, PartialEq)] +pub struct Weapon +{ + pub amp_bob: Fixed, + pub amp_horz: Fixed, + pub collection: u16, + pub flags: WeaponFlags, + pub frm_charge: OptU16, + pub frm_charged: OptU16, + pub frm_firing: u16, + pub frm_idle: u16, + pub frm_reload: OptU16, + pub hei_idle: Fixed, + pub hei_kick: Fixed, + pub hei_reload: Fixed, + pub lit_decay: u16, + pub lit_value: Fixed, + pub tic_load_beg: u16, + pub tic_load_end: u16, + pub tic_load_mid: u16, + pub tic_powerup: u16, + pub tic_ready: u16, + pub trig_pri: trig::Trigger, + pub trig_sec: trig::Trigger, + pub typ_item: u16, + pub typ_powerup: OptU16, + pub typ_weapon: WeaponType, + pub wid_idle: Fixed, +} + +bitflags! { + /// Flags for a weapon. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + pub struct WeaponFlags: u16 + { + const AUTOMATIC = 1; + const REMOVE_AFTER_USE = 1 << 1; + const INSTANT_CASING = 1 << 2; + const OVERLOADS = 1 << 3; + const RANDOM_AMMO = 1 << 4; + const TEMPORARY_POWER = 1 << 5; + const RELOAD_ONE_HAND = 1 << 6; + const FIRE_OUT_OF_PHASE = 1 << 7; + const FIRE_UNDER_MEDIA = 1 << 8; + const TRIGGER_SAME_AMMO = 1 << 9; + const SECONDARY_FLIP = 1 << 10; + } +} + +c_enum! { + /// The type of functionality a weapon provides. + #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))] + #[derive(Debug)] + pub enum WeaponType: u16 + { + Melee = 0, + Normal = 1, + DualFunc = 2, + DualPistol = 3, + Multipurpose = 4, + } +} + +// EOF diff --git a/source/marathon/wad.rs b/source/marathon/wad.rs index 8ba69eb..3fb718b 100644 --- a/source/marathon/wad.rs +++ b/source/marathon/wad.rs @@ -46,11 +46,11 @@ pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize) 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)?), - b"PRpx" => Chunk::Prpx(rd_array(data, phy::read_prpx)?), - b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?), - b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?), + b"FXpx" => Chunk::Fxpx(rd_array(data, phy::fxpx::read)?), + b"MNpx" => Chunk::Mnpx(rd_array(data, phy::mnpx::read)?), + b"PRpx" => Chunk::Prpx(rd_array(data, phy::prpx::read)?), + b"PXpx" => Chunk::Pxpx(rd_array(data, phy::pxpx::read)?), + b"WPpx" => Chunk::Wppx(rd_array(data, phy::wppx::read)?), _ => Chunk::Data{iden, data: data.to_vec()}, }); @@ -158,11 +158,11 @@ pub enum Chunk /** 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), - /** A `PRpx` chunk. */ Prpx(Vec), - /** A `PXpx` chunk. */ Pxpx(Vec), - /** A `WPpx` chunk. */ Wppx(Vec), + /** A `FXpx` chunk. */ Fxpx(Vec), + /** A `MNpx` chunk. */ Mnpx(Vec), + /** A `PRpx` chunk. */ Prpx(Vec), + /** A `PXpx` chunk. */ Pxpx(Vec), + /** A `WPpx` chunk. */ Wppx(Vec), /// Any other type of chunk, which may have arbitrary data in it. Data{/** The name of the chunk. */ iden: Ident,