text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose:
  //
  // $Workfile:     $
  // $Date:         $
  // $NoKeywords: $
  //=============================================================================//
  #include "cbase.h"
  #include "util.h"
  #include "basehlcombatweapon.h"
  #include "player.h"
  #include "gamerules.h"
  #include "grenade_tripwire.h"
  #include "grenade_satchel.h"
  #include "entitylist.h"
  #include "weapon_tripwire.h"
  #include "npcevent.h"
  #include "in_buttons.h"
  #include "engine/IEngineSound.h"
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include "tier0/memdbgon.h"
  
  BEGIN_DATADESC( CWeapon_Tripwire )
  
      DEFINE_FIELD( m_bNeedReload, FIELD_BOOLEAN ),
      DEFINE_FIELD( m_bClearReload, FIELD_BOOLEAN ),
      DEFINE_FIELD( m_bAttachTripwire, FIELD_BOOLEAN ),
  
      // Function Pointers
      DEFINE_FUNCTION( TripwireTouch ),
  
  END_DATADESC()
  
  
  IMPLEMENT_SERVERCLASS_ST(CWeapon_Tripwire, DT_Weapon_Tripwire)
  END_SEND_TABLE()
  
  LINK_ENTITY_TO_CLASS( weapon_tripwire, CWeapon_Tripwire );
  
  // BUGBUG: Enable this when the script & resources are checked in.
  //PRECACHE_WEAPON_REGISTER(weapon_tripwire);
  
  acttable_t  CWeapon_Tripwire::m_acttable[] =
  {
      { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_TRIPWIRE, true },
  };
  
  IMPLEMENT_ACTTABLE(CWeapon_Tripwire);
  
  
  void CWeapon_Tripwire::Spawn( )
  {
      UTIL_Remove(this);
      return;
  
      BaseClass::Spawn();
  
      Precache( );
  
      UTIL_SetSize(this, Vector(-4,-4,-2),Vector(4,4,2));
  
  
      FallInit();// get ready to fall down
  
      SetThink( NULL );
  
      // Give one piece of default ammo when first picked up
      m_iClip2 = 1;
  }
  
  void CWeapon_Tripwire::Precache( void )
  {
      BaseClass::Precache();
  
      PrecacheScriptSound( "Weapon_Tripwire.Attach" );
  
      UTIL_PrecacheOther( "npc_tripwire" );
  }
  
  //------------------------------------------------------------------------------
  // Purpose : Override to use tripwire's pickup touch function
  // Input   :
  // Output  :
  //------------------------------------------------------------------------------
  void CWeapon_Tripwire::SetPickupTouch( void )
  {
      SetTouch(TripwireTouch);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Override so give correct ammo
  // Input  : pOther - the entity that touched me
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::TripwireTouch( CBaseEntity *pOther )
  {
      // ---------------------------------------------------
      //  First give weapon to touching entity if allowed
      // ---------------------------------------------------
      BaseClass::DefaultTouch(pOther);
  
      // ----------------------------------------------------
      //  Give ammo if touching client
      // ----------------------------------------------------
      if (pOther->GetFlags() & FL_CLIENT)
      {
          // ------------------------------------------------
          //  If already owned weapon of this type remove me
          // ------------------------------------------------
          CBaseCombatCharacter* pBCC = ToBaseCombatCharacter( pOther );
          CWeapon_Tripwire* oldWeapon = (CWeapon_Tripwire*)pBCC->Weapon_OwnsThisType( GetClassname() );
          if (oldWeapon != this)
          {
              UTIL_Remove( this );
          }
          else
          {
              pBCC->GiveAmmo( 1, m_iSecondaryAmmoType );
              SetThink(NULL);
          }
      }
  }
  
  //------------------------------------------------------------------------------
  // Purpose :
  // Input   :
  // Output  :
  //------------------------------------------------------------------------------
  bool CWeapon_Tripwire::Holster( CBaseCombatWeapon *pSwitchingTo )
  {
      SetThink(NULL);
      return BaseClass::Holster(pSwitchingTo);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Tripwire has no reload, but must call weapon idle to update state
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  bool CWeapon_Tripwire::Reload( void )
  {
      WeaponIdle( );
      return true;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::PrimaryAttack( void )
  {
      CBaseCombatCharacter *pOwner  = GetOwner();
      if (!pOwner)
      {
          return;
      }
  
      if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
      {
          return;
      }
  
      if (CanAttachTripwire())
      {
          StartTripwireAttach();
      }
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Secondary attack does nothing
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::SecondaryAttack( void )
  {
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::TripwireAttach( void )
  {
      CBaseCombatCharacter *pOwner  = GetOwner();
      if (!pOwner)
      {
          return;
      }
  
      m_bAttachTripwire = false;
  
      Vector vecSrc    = pOwner->Weapon_ShootPosition();
      Vector vecAiming = pOwner->BodyDirection2D( );
  
      trace_t tr;
  
      UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  
      if (tr.fraction < 1.0)
      {
          CBaseEntity *pEntity = tr.m_pEnt;
          if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
          {
              QAngle angles;
              VectorAngles(tr.plane.normal, angles);
              angles.x += 90;
  
              CBaseEntity *pEnt = CBaseEntity::Create( "npc_tripwire", tr.endpos + tr.plane.normal * 3, angles, NULL );
  
              CTripwireGrenade *pMine = (CTripwireGrenade *)pEnt;
              pMine->SetThrower( GetOwner() );
  
              pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType );
  
              EmitSound( "Weapon_Tripwire.Attach" );
          }
      }
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::StartTripwireAttach( void )
  {
      // Only the player fires this way so we can cast
      CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
      if (!pPlayer)
      {
          return;
      }
  
      Vector vecSrc    = pPlayer->Weapon_ShootPosition();
      Vector vecAiming = pPlayer->BodyDirection3D( );
  
      trace_t tr;
  
      UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  
      if (tr.fraction < 1.0)
      {
          // ALERT( at_console, "hit %f\n", tr.flFraction );
  
          CBaseEntity *pEntity = tr.m_pEnt;
          if (pEntity && !(pEntity->GetFlags() & FL_CONVEYOR))
          {
              // player "shoot" animation
              pPlayer->SetAnimation( PLAYER_ATTACK1 );
  
              // -----------------------------------------
              //  Play attach animation
              // -----------------------------------------
              SendWeaponAnim(ACT_SLAM_TRIPMINE_ATTACH);
  
              m_bNeedReload       = true;
              m_bAttachTripwire   = true;
          }
          else
          {
              // ALERT( at_console, "no deploy\n" );
          }
      }
      m_flNextPrimaryAttack   = gpGlobals->curtime + SequenceDuration();
      m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  //  SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  bool CWeapon_Tripwire::CanAttachTripwire( void )
  {
      CBaseCombatCharacter *pOwner  = GetOwner();
      if (!pOwner)
      {
          return false;
      }
  
      Vector vecSrc    = pOwner->Weapon_ShootPosition();
      Vector vecAiming = pOwner->BodyDirection2D( );
  
      trace_t tr;
  
      Vector  vecEnd = vecSrc + (vecAiming * 42);
      UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
  
      if (tr.fraction < 1.0)
      {
          // Don't attach to a living creature
          if (tr.m_pEnt)
          {
              CBaseEntity *pEntity = tr.m_pEnt;
              CBaseCombatCharacter *pBCC      = ToBaseCombatCharacter( pEntity );
              if (pBCC)
              {
                  return false;
              }
          }
          return true;
      }
      else
      {
          return false;
      }
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::ItemPostFrame( void )
  {
      CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
      if (!pOwner)
      {
          return;
      }
  
      if ((pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
      {
          SecondaryAttack();
      }
      else if (!m_bNeedReload && (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
      {
          PrimaryAttack();
      }
  
      // -----------------------
      //  No buttons down
      // -----------------------
      else
      {
          WeaponIdle( );
          return;
      }
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  void CWeapon_Tripwire::WeaponIdle( void )
  {
      // Ready to switch animations?
      if ( HasWeaponIdleTimeElapsed() )
      {
          if (m_bClearReload)
          {
              m_bNeedReload  = false;
              m_bClearReload = false;
          }
          CBaseCombatCharacter *pOwner  = GetOwner();
          if (!pOwner)
          {
              return;
          }
  
          int iAnim = 0;
  
          if (m_bAttachTripwire)
          {
              TripwireAttach();
              iAnim = ACT_SLAM_TRIPMINE_ATTACH2;
          }
          else if (m_bNeedReload)
          {
              // If owner had ammo draw the correct tripwire type
              if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) > 0)
              {
                  iAnim = ACT_SLAM_TRIPMINE_DRAW;
                  m_bClearReload          = true;
              }
              else
              {
                  pOwner->Weapon_Drop( this );
                  UTIL_Remove(this);
              }
          }
          else if (pOwner->GetAmmoCount(m_iSecondaryAmmoType) <= 0)
          {
              pOwner->Weapon_Drop( this );
              UTIL_Remove(this);
          }
  
          // If I don't need to reload just do the appropriate idle
          else
          {
              iAnim = ACT_SLAM_TRIPMINE_IDLE;
          }
          SendWeaponAnim( iAnim );
      }
  }
  
  bool CWeapon_Tripwire::Deploy( void )
  {
      CBaseCombatCharacter *pOwner  = GetOwner();
      if (!pOwner)
      {
          return false;
      }
  
      SetModel( GetViewModel() );
  
      // ------------------------------
      // Pick the right draw animation
      // ------------------------------
      int iActivity;
  
      // If detonator is already armed
      m_bNeedReload = false;
      iActivity = ACT_SLAM_STICKWALL_ND_DRAW;
      return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), iActivity, (char*)GetAnimPrefix() );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Constructor
  // Input  :
  // Output :
  //-----------------------------------------------------------------------------
  CWeapon_Tripwire::CWeapon_Tripwire(void)
  {
      m_bNeedReload           = true;
      m_bClearReload          = false;
      m_bAttachTripwire       = false;
  }
  