//! `Weapon` type.

use crate::durandal::{bin::OptU16, err::*, fixed::Fixed};
use bitflags::bitflags;
use std::convert::TryFrom;

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
