//! 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! {
      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))
}

/// Reads a `FXpx` chunk.
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))
}

/// Reads a `WPpx` chunk.
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))
}

/// Reads a `PRpx` chunk.
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))
}

/// Reads a `MNpx` chunk.
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))
}

/// Reads a `Trigger` object.
fn read_trigger(b: &[u8]) -> ResultS<Trigger>
{
   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})
}

/// Reads a `Damage` object.
fn read_damage(b: &[u8]) -> ResultS<Damage>
{
   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})
}

/// Reads an `Attack` object.
fn read_attack(b: &[u8]) -> ResultS<Attack>
{
   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})
}

/// 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
   {
      0      => Rifle,
      1      => Pistol,
      2      => PistolLeft,
      3      => PistolRight,
      4      => SMG,
      0xFFFF => None,
   }
}

c_enum! {
   /// The type of functionality a weapon provides.
   #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
   #[derive(Debug)]
   pub enum WeaponType: u16
   {
      0 => Melee,
      1 => Normal,
      2 => DualFunc,
      3 => DualPistol,
      4 => Multipurpose,
   }
}

c_enum! {
   /// A named type of damage taken by something.
   #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
   #[derive(Debug)]
   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
