use crate::{durandal::{bin::*, err::*, fixed::*}}; use bitflags::bitflags; use serde::Serialize; pub fn read_pxpx(b: &[u8]) -> ResultS<(Physics, usize)> { read_data! { 104, BE in b => vel_fwd = Fixed[0]; vel_bkw = Fixed[4]; vel_prp = Fixed[8]; acc_nrm = Fixed[12]; dec_nrm = Fixed[16]; dec_air = Fixed[20]; acc_grv = Fixed[24]; acc_cli = Fixed[28]; vel_trm = Fixed[32]; dec_ext = Fixed[36]; acc_ang = Fixed[40]; dec_ang = Fixed[44]; vel_ang = Fixed[48]; vel_rec = Fixed[52]; fng_vel = Fixed[56]; fng_max = Fixed[60]; ele_max = Fixed[64]; dec_xng = Fixed[68]; stp_dta = Fixed[72]; stp_amp = Fixed[76]; ply_rad = Fixed[80]; ply_hei = Fixed[84]; ply_dhi = Fixed[88]; ply_cam = Fixed[92]; ply_spl = Fixed[96]; 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)) } pub fn read_fxpx(b: &[u8]) -> ResultS<(Effect, usize)> { read_data! { 14, BE in b => collection = u16[0]; shape = u16[2]; pitch = Fixed[4]; flags = u16[8]; delay = OptU16[10]; delay_snd = OptU16[12]; } let flags = flag_ok!(EffectFlags, flags)?; Ok((Effect{collection, shape, pitch, flags, delay, delay_snd}, 14)) } pub fn read_wppx(b: &[u8]) -> ResultS<(Weapon, usize)> { read_data! { 134, BE in b => typ_item = u16[0]; typ_powerup = OptU16[2]; typ_weapon = u16[4]; flags = u16[6]; lit_value = Fixed[8]; lit_decay = u16[12]; hei_idle = Fixed[14]; amp_bob = Fixed[18]; hei_kick = Fixed[22]; hei_reload = Fixed[26]; wid_idle = Fixed[30]; amp_horz = Fixed[34]; collection = u16[38]; frm_idle = u16[40]; frm_firing = u16[42]; frm_reload = OptU16[44]; frm_charge = OptU16[48]; frm_charged = OptU16[50]; tic_ready = u16[52]; tic_load_beg = u16[54]; tic_load_mid = u16[56]; tic_load_end = u16[58]; tic_powerup = u16[60]; trig_pri = read_trigger[62..98]; trig_sec = read_trigger[98..134]; } let typ_weapon = WeaponType::from_repr(typ_weapon)?; let flags = flag_ok!(WeaponFlags, flags)?; 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)) } pub fn read_prpx(b: &[u8]) -> ResultS<(Projectile, usize)> { read_data! { 48, BE in b => collection = OptU16[0]; shape = u16[2]; fxt_explode = OptU16[4]; fxt_exp_media = OptU16[6]; fxt_trail = OptU16[8]; tic_trail = u16[10]; max_trail = OptU16[12]; typ_media = OptU16[14]; radius = Unit[16]; dmg_rad = Unit[18]; dmg_def = read_damage[20..32]; flags = u32[32]; speed = Unit[36]; range = Unit[38]; snd_pitch = Fixed[40]; snd_fly = OptU16[44]; snd_bounce = OptU16[46]; } let flags = flag_ok!(ProjectileFlags, flags)?; 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)) } pub fn read_mnpx(b: &[u8]) -> ResultS<(Monster, usize)> { read_data! { 156, BE in b => collection = u16[0]; vitality = u16[2]; dty_immune = u32[4]; dty_weak = u32[8]; flags = u32[12]; cls_self = u32[16]; cls_friend = u32[20]; cls_enemy = u32[24]; snd_pitch = Fixed[28]; snd_see_enemy = OptU16[32]; snd_see_friend = OptU16[34]; snd_seeclear = OptU16[36]; snd_kill = OptU16[38]; snd_apologize = OptU16[40]; snd_amicide = OptU16[42]; snd_flaming = OptU16[44]; snd_active = OptU16[46]; snd_active_mask = u16[48]; typ_item = OptU16[50]; radius = Unit[52]; height = Unit[54]; height_hover = Unit[56]; ledge_min = Unit[58]; ledge_max = Unit[60]; ext_vel_scale = Fixed[62]; fxt_impact = OptU16[66]; fxt_impact_melee = OptU16[68]; fxt_trail = OptU16[70]; half_fov_horz = u16[72]; half_fov_vert = u16[74]; view_range = Unit[76]; view_range_dark = Unit[78]; intelligence = u16[80]; speed = u16[82]; gravity = u16[84]; vel_terminal = u16[86]; door_try_mask = u16[88]; expl_radius = OptU16[90]; expl_damage = read_damage[92..104]; seq_hit = OptU16[104]; seq_dying_hard = OptU16[106]; seq_dying_soft = OptU16[108]; seq_dead_hard = OptU16[110]; seq_dead_soft = OptU16[112]; seq_standing = u16[114]; seq_moving = u16[116]; seq_tele_in = OptU16[118]; seq_tele_out = OptU16[120]; atk_frequency = u16[122]; atk_melee = read_attack[124..140]; atk_range = read_attack[140..156]; } // friend and enemy fields MUST truncate because the original source code // used `-1` to represent "all classes" which should be invalid normally let dty_immune = flag_ok!(DamageTypeFlags, dty_immune)?; let dty_weak = flag_ok!(DamageTypeFlags, dty_weak)?; let flags = flag_ok!(MonsterFlags, flags)?; let cls_self = flag_ok!(MonsterClass, cls_self)?; 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)) } fn read_trigger(b: &[u8]) -> ResultS { read_data! { 36, BE in b => magazine = u16[0]; typ_ammo = OptU16[2]; tic_round = OptU16[4]; tic_recover = u16[6]; tic_charge = u16[8]; recoil = Unit[10]; snd_fire = OptU16[12]; snd_click = OptU16[14]; snd_charge = OptU16[16]; snd_casing = OptU16[18]; snd_reload = OptU16[20]; snd_charged = OptU16[22]; typ_proj = u16[24]; theta = u16[26]; dx = i16[28]; dz = i16[30]; typ_casing = u16[32]; burst = u16[34]; } let typ_casing = CasingType::from_repr(typ_casing)?; 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}) } fn read_damage(b: &[u8]) -> ResultS { read_data! { 12, BE in b => dtype = u16[0]; flags = u16[2]; dmg_base = u16[4]; dmg_rand = u16[6]; scale = Fixed[8]; } let dtype = DamageType::from_repr(dtype)?; let alien = flags != 0; Ok(Damage{dtype, alien, dmg_base, dmg_rand, scale}) } fn read_attack(b: &[u8]) -> ResultS { read_data! { 16, BE in b => ptype = OptU16[0]; rep = u16[2]; error = Angle[4]; range = Unit[6]; shape = u16[8]; ofs_x = Unit[10]; ofs_y = Unit[12]; ofs_z = Unit[14]; } Ok(Attack{ptype, rep, error, range, shape, ofs_x, ofs_y, ofs_z}) } #[derive(Debug, Serialize)] 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, } #[derive(Debug, Serialize)] pub struct Effect { pub collection: u16, pub shape: u16, pub pitch: Fixed, pub flags: EffectFlags, pub delay: OptU16, pub delay_snd: OptU16, } #[derive(Debug, Serialize)] 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, } #[derive(Debug, Serialize)] 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, } #[derive(Debug, Serialize)] 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, } #[derive(Debug, Serialize)] 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, } #[derive(Debug, Serialize)] pub struct Damage { pub dtype: DamageType, pub alien: bool, pub dmg_base: u16, pub dmg_rand: u16, pub scale: Fixed, } #[derive(Debug, Serialize)] 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! { #[derive(Serialize)] pub struct EffectFlags: u16 { const EndOnLoop = 1; const EndOnXferLoop = 1 << 1; const SoundOnly = 1 << 2; const MakeTwinVisible = 1 << 3; const MediaEffect = 1 << 4; } } bitflags! { #[derive(Serialize)] pub struct WeaponFlags: u16 { const Automatic = 1; const RemoveAfterUse = 1 << 1; const InstantCasing = 1 << 2; const Overloads = 1 << 3; const RandomAmmo = 1 << 4; const TemporaryPower = 1 << 5; const ReloadOneHand = 1 << 6; const FireOutOfPhase = 1 << 7; const FireUnderMedia = 1 << 8; const TriggerSameAmmo = 1 << 9; const SecondaryFlip = 1 << 10; } } bitflags! { #[derive(Serialize)] pub struct ProjectileFlags: u32 { const Guided = 1; const StopOnLoop = 1 << 1; const Persistent = 1 << 2; const Alien = 1 << 3; const Gravity = 1 << 4; const NoHorzError = 1 << 5; const NoVertError = 1 << 6; const TogglePanels = 1 << 7; const PosVertError = 1 << 8; const Melee = 1 << 9; const Ripper = 1 << 10; const PassTransRandom = 1 << 11; const PassTransMore = 1 << 12; const DoubleGravity = 1 << 13; const ReboundFloor = 1 << 14; const ThroughMedia = 1 << 15; const BecomeItem = 1 << 16; const Bloody = 1 << 17; const WanderHorz = 1 << 18; const UseLowGrav = 1 << 19; const PassMedia = 1 << 20; } } bitflags! { #[derive(Serialize)] pub struct MonsterFlags: u32 { const IgnoreLOS = 1; const Flying = 1 << 1; const Alien = 1 << 2; const Major = 1 << 3; const Minor = 1 << 4; const NoOmit = 1 << 5; const Floats = 1 << 6; const NoAttack = 1 << 7; const Snipe = 1 << 8; const Invisible = 1 << 9; const SubtlyInvisible = 1 << 10; const Kamikaze = 1 << 11; const Berserker = 1 << 12; const Enlarged = 1 << 13; const DelayedDeath = 1 << 14; const FireSymmetrical = 1 << 15; const NuclearDeath = 1 << 16; const NoFireBackwards = 1 << 17; const CanDieInFlames = 1 << 18; const WaitForGoodShot = 1 << 19; const Tiny = 1 << 20; const FastAttack = 1 << 21; const LikesWater = 1 << 22; const LikesSewage = 1 << 23; const LikesLava = 1 << 24; const LikesGoo = 1 << 25; const TeleUnderMedia = 1 << 26; const UseRandomWeapon = 1 << 27; } } bitflags! { #[derive(Serialize)] pub struct MonsterClass: u32 { const Player = 1; const Civilian = 1 << 1; const Madd = 1 << 2; const PossessedHummer = 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! { #[derive(Serialize)] pub struct DamageTypeFlags: u32 { const Explosion = 1; const ElectricalStaff = 1 << 1; const Projectile = 1 << 2; const Absorbed = 1 << 3; const Flame = 1 << 4; const HoundClaws = 1 << 5; const AlienProjectile = 1 << 6; const HulkSlap = 1 << 7; const CompilerBolt = 1 << 8; const FusionBolt = 1 << 9; const HunterBolt = 1 << 10; const Fist = 1 << 11; const Teleporter = 1 << 12; const Defender = 1 << 13; const YetiClaws = 1 << 14; const YetiProjectile = 1 << 15; const Crushing = 1 << 16; const Lava = 1 << 17; const Suffocation = 1 << 18; const Goo = 1 << 19; const EnergyDrain = 1 << 20; const OxygenDrain = 1 << 21; const HummerBolt = 1 << 22; const ShotgunProjectile = 1 << 23; } } c_enum! { #[derive(Debug, Serialize)] pub enum CasingType: u16 { 0 => Rifle, 1 => Pistol, 2 => PistolLeft, 3 => PistolRight, 4 => SMG, 0xFFFF => None, } } c_enum! { #[derive(Debug, Serialize)] pub enum WeaponType: u16 { 0 => Melee, 1 => Normal, 2 => DualFunc, 3 => DualPistol, 4 => Multipurpose, } } c_enum! { #[derive(Debug, Serialize)] pub enum DamageType: u16 { 0 => Explosion, 1 => ElectricalStaff, 2 => Projectile, 3 => Absorbed, 4 => Flame, 5 => HoundClaws, 6 => AlienProjectile, 7 => HulkSlap, 8 => CompilerBolt, 9 => FusionBolt, 10 => HunterBolt, 11 => Fist, 12 => Teleporter, 13 => Defender, 14 => YetiClaws, 15 => YetiProjectile, 16 => Crushing, 17 => Lava, 18 => Suffocation, 19 => Goo, 20 => EnergyDrain, 21 => OxygenDrain, 22 => HummerBolt, 23 => ShotgunProjectile, 0xFFFF => None, } } // EOF