//! 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<Trigger>
{
   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<Damage>
{
   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<Attack>
{
   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,
   }
}

// EOF
