Weapon making not working

Grab your favourite IDE and tinker with the innards of game engines

Weapon making not working

Postby GigaNova on Mon Jun 11, 2012 6:35 pm

Hello there, i got a seriouse problem.
I followed the "weapon creation" tutorial and it worked out just fine with my pistol.
But when trying to make anything else then a pisol, it wont work, whatever i try!

Code: Select all
DataTable warning: No matching RecvTable for SendTable 'DT_WeaponArnoshotty'.
DataTable warning: No matching RecvTable for SendTable 'DT_WeaponSMG2'.
Client missing DT class CWeaponArnoshotty
Client missing DT class CWeaponSMG2
Host_EndGame: CL_ParseClassInfo_EndClasses: CreateDecoders failed.

Dropped -=[UH]=- GigaNova ∞ from server (Disconnect by user.)


I keep getting that annoying error, i set everything up (c_weapon_stubb, weapon_*name*, weapon in script folder)

Can anybody PLEASE help me, it compiles without any errors.
GigaNova
Member
Member
 
Joined: Mon Jun 11, 2012 6:32 pm

Re: Weapon making not working

Postby [Steve] on Mon Jun 11, 2012 7:09 pm

As your console log says your client is missing its DT class for your weapons.

you may have just forgotten to build the Client . or you have forgotten to implement your weapons clientside . Take a look at the tutorial again and make a note of what client side changes are needed.

it could also be that you have added something somewhere but miss spelt.

If you still cant get it to work, paste your code here and ill take a closer look.
User avatar
[Steve]
Interlopers Staff
Interlopers Staff
 
Joined: Fri Mar 06, 2009 11:25 pm

Re: Weapon making not working

Postby GigaNova on Mon Jun 11, 2012 7:17 pm

greenglow2004 wrote:As your console log says your client is missing its DT class for your weapons.

you may have just forgotten to build the Client . or you have forgotten to implement your weapons clientside . Take a look at the tutorial again and make a note of what client side changes are needed.

it could also be that you have added something somewhere but miss spelt.

If you still cant get it to work, paste your code here and ill take a closer look.

Thanks for the fast reply.
The only clientside code needed is the c_weapon__stubb, and i did that.
I didnt misspel anything either, and i did build the client.
So, my only hope are these codes.
Code: Select all
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: SMG2 for npc_arno
//
//=============================================================================//

#include "cbase.h"
#include "basehlcombatweapon.h"
#include "NPCevent.h"
#include "basecombatcharacter.h"
#include "AI_BaseNPC.h"
#include "player.h"
#include "game.h"
#include "in_buttons.h"
#include "grenade_ar2.h"
#include "AI_Memory.h"
#include "soundent.h"
#include "rumble_shared.h"
#include "gamestats.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

extern ConVar    sk_plr_dmg_smg1_grenade;   

class CWeaponSMG2 : public CHLSelectFireMachineGun
{
   DECLARE_DATADESC();
public:
   DECLARE_CLASS( CWeaponSMG2, CHLSelectFireMachineGun );

   CWeaponSMG2();

   DECLARE_SERVERCLASS();
   
   void   Precache( void );
   void   AddViewKick( void );
   void   SecondaryAttack( void );

   int      GetMinBurst() { return 2; }
   int      GetMaxBurst() { return 5; }

   virtual void Equip( CBaseCombatCharacter *pOwner );
   bool   Reload( void );

   float   GetFireRate( void ) { return 0.075f; }   // 13.3hz
   int      CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
   int      WeaponRangeAttack2Condition( float flDot, float flDist );
   Activity   GetPrimaryAttackActivity( void );

   virtual const Vector& GetBulletSpread( void )
   {
      static const Vector cone = VECTOR_CONE_5DEGREES;
      return cone;
   }

   const WeaponProficiencyInfo_t *GetProficiencyValues();

   void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, Vector &vecShootOrigin, Vector &vecShootDir );
   void Operator_ForceNPCFire( CBaseCombatCharacter  *pOperator, bool bSecondary );
   void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );

   DECLARE_ACTTABLE();

protected:

   Vector   m_vecTossVelocity;
   float   m_flNextGrenadeCheck;
};

IMPLEMENT_SERVERCLASS_ST(CWeaponSMG2, DT_WeaponSMG2)
END_SEND_TABLE()

LINK_ENTITY_TO_CLASS( weapon_smg2, CWeaponSMG2 );
PRECACHE_WEAPON_REGISTER(weapon_smg2);

BEGIN_DATADESC( CWeaponSMG2 )

   DEFINE_FIELD( m_vecTossVelocity, FIELD_VECTOR ),
   DEFINE_FIELD( m_flNextGrenadeCheck, FIELD_TIME ),

END_DATADESC()

acttable_t   CWeaponSMG2::m_acttable[] =
{
   { ACT_RANGE_ATTACK1,         ACT_RANGE_ATTACK_SMG1,         true },
   { ACT_RELOAD,               ACT_RELOAD_SMG1,            true },
   { ACT_IDLE,                  ACT_IDLE_SMG1,               true },
   { ACT_IDLE_ANGRY,            ACT_IDLE_ANGRY_SMG1,         true },

   { ACT_WALK,                  ACT_WALK_RIFLE,               true },
   { ACT_WALK_AIM,               ACT_WALK_AIM_RIFLE,            true  },
   
// Readiness activities (not aiming)
   { ACT_IDLE_RELAXED,            ACT_IDLE_SMG1_RELAXED,         false },//never aims
   { ACT_IDLE_STIMULATED,         ACT_IDLE_SMG1_STIMULATED,      false },
   { ACT_IDLE_AGITATED,         ACT_IDLE_ANGRY_SMG1,         false },//always aims

   { ACT_WALK_RELAXED,            ACT_WALK_RIFLE_RELAXED,         false },//never aims
   { ACT_WALK_STIMULATED,         ACT_WALK_RIFLE_STIMULATED,      false },
   { ACT_WALK_AGITATED,         ACT_WALK_AIM_RIFLE,            false },//always aims

   { ACT_RUN_RELAXED,            ACT_RUN_RIFLE_RELAXED,         false },//never aims
   { ACT_RUN_STIMULATED,         ACT_RUN_RIFLE_STIMULATED,      false },
   { ACT_RUN_AGITATED,            ACT_RUN_AIM_RIFLE,            false },//always aims

// Readiness activities (aiming)
   { ACT_IDLE_AIM_RELAXED,         ACT_IDLE_SMG1_RELAXED,         false },//never aims   
   { ACT_IDLE_AIM_STIMULATED,      ACT_IDLE_AIM_RIFLE_STIMULATED,   false },
   { ACT_IDLE_AIM_AGITATED,      ACT_IDLE_ANGRY_SMG1,         false },//always aims

   { ACT_WALK_AIM_RELAXED,         ACT_WALK_RIFLE_RELAXED,         false },//never aims
   { ACT_WALK_AIM_STIMULATED,      ACT_WALK_AIM_RIFLE_STIMULATED,   false },
   { ACT_WALK_AIM_AGITATED,      ACT_WALK_AIM_RIFLE,            false },//always aims

   { ACT_RUN_AIM_RELAXED,         ACT_RUN_RIFLE_RELAXED,         false },//never aims
   { ACT_RUN_AIM_STIMULATED,      ACT_RUN_AIM_RIFLE_STIMULATED,   false },
   { ACT_RUN_AIM_AGITATED,         ACT_RUN_AIM_RIFLE,            false },//always aims
//End readiness activities

   { ACT_WALK_AIM,               ACT_WALK_AIM_RIFLE,            true },
   { ACT_WALK_CROUCH,            ACT_WALK_CROUCH_RIFLE,         true },
   { ACT_WALK_CROUCH_AIM,         ACT_WALK_CROUCH_AIM_RIFLE,      true },
   { ACT_RUN,                  ACT_RUN_RIFLE,               true },
   { ACT_RUN_AIM,               ACT_RUN_AIM_RIFLE,            true },
   { ACT_RUN_CROUCH,            ACT_RUN_CROUCH_RIFLE,         true },
   { ACT_RUN_CROUCH_AIM,         ACT_RUN_CROUCH_AIM_RIFLE,      true },
   { ACT_GESTURE_RANGE_ATTACK1,   ACT_GESTURE_RANGE_ATTACK_SMG1,   true },
   { ACT_RANGE_ATTACK1_LOW,      ACT_RANGE_ATTACK_SMG1_LOW,      true },
   { ACT_COVER_LOW,            ACT_COVER_SMG1_LOW,            false },
   { ACT_RANGE_AIM_LOW,         ACT_RANGE_AIM_SMG1_LOW,         false },
   { ACT_RELOAD_LOW,            ACT_RELOAD_SMG1_LOW,         false },
   { ACT_GESTURE_RELOAD,         ACT_GESTURE_RELOAD_SMG1,      true },
};

IMPLEMENT_ACTTABLE(CWeaponSMG2);

//=========================================================
CWeaponSMG2::CWeaponSMG2( )
{
   m_fMinRange1      = 0;// No minimum range.
   m_fMaxRange1      = 900;

   m_bAltFiresUnderwater = false;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::Precache( void )
{
   UTIL_PrecacheOther("grenade_ar2");

   BaseClass::Precache();
}

//-----------------------------------------------------------------------------
// Purpose: Give this weapon longer range when wielded by an ally NPC.
//-----------------------------------------------------------------------------
void CWeaponSMG2::Equip( CBaseCombatCharacter *pOwner )
{
   if( pOwner->Classify() == CLASS_PLAYER_ALLY )
   {
      m_fMaxRange1 = 1200;
   }
   else
   {
      m_fMaxRange1 = 1400;
   }

   BaseClass::Equip( pOwner );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, Vector &vecShootOrigin, Vector &vecShootDir )
{
   // FIXME: use the returned number of bullets to account for >10hz firerate
   WeaponSoundRealtime( SINGLE_NPC );

   CSoundEnt::InsertSound( SOUND_COMBAT|SOUND_CONTEXT_GUNFIRE, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_MACHINEGUN, 0.2, pOperator, SOUNDENT_CHANNEL_WEAPON, pOperator->GetEnemy() );
   pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED,
      MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), 0 );

   pOperator->DoMuzzleFlash();
   m_iClip1 = m_iClip1 - 1;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary )
{
   // Ensure we have enough rounds in the clip
   m_iClip1++;

   Vector vecShootOrigin, vecShootDir;
   QAngle   angShootDir;
   GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir );
   AngleVectors( angShootDir, &vecShootDir );
   FireNPCPrimaryAttack( pOperator, vecShootOrigin, vecShootDir );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
   switch( pEvent->event )
   {
   case EVENT_WEAPON_SMG1:
      {
         Vector vecShootOrigin, vecShootDir;
         QAngle angDiscard;

         // Support old style attachment point firing
         if ((pEvent->options == NULL) || (pEvent->options[0] == '\0') || (!pOperator->GetAttachment(pEvent->options, vecShootOrigin, angDiscard)))
         {
            vecShootOrigin = pOperator->Weapon_ShootPosition();
         }

         CAI_BaseNPC *npc = pOperator->MyNPCPointer();
         ASSERT( npc != NULL );
         vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );

         FireNPCPrimaryAttack( pOperator, vecShootOrigin, vecShootDir );
      }
      break;

      /*//FIXME: Re-enable
      case EVENT_WEAPON_AR2_GRENADE:
      {
      CAI_BaseNPC *npc = pOperator->MyNPCPointer();

      Vector vecShootOrigin, vecShootDir;
      vecShootOrigin = pOperator->Weapon_ShootPosition();
      vecShootDir = npc->GetShootEnemyDir( vecShootOrigin );

      Vector vecThrow = m_vecTossVelocity;

      CGrenadeAR2 *pGrenade = (CGrenadeAR2*)Create( "grenade_ar2", vecShootOrigin, vec3_angle, npc );
      pGrenade->SetAbsVelocity( vecThrow );
      pGrenade->SetLocalAngularVelocity( QAngle( 0, 400, 0 ) );
      pGrenade->SetMoveType( MOVETYPE_FLYGRAVITY );
      pGrenade->m_hOwner         = npc;
      pGrenade->m_pMyWeaponAR2   = this;
      pGrenade->SetDamage(sk_npc_dmg_ar2_grenade.GetFloat());

      // FIXME: arrgg ,this is hard coded into the weapon???
      m_flNextGrenadeCheck = gpGlobals->curtime + 6;// wait six seconds before even looking again to see if a grenade can be thrown.

      m_iClip2--;
      }
      break;
      */

   default:
      BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
      break;
   }
}

//-----------------------------------------------------------------------------
// Purpose:
// Output : Activity
//-----------------------------------------------------------------------------
Activity CWeaponSMG2::GetPrimaryAttackActivity( void )
{
   if ( m_nShotsFired < 2 )
      return ACT_VM_PRIMARYATTACK;

   if ( m_nShotsFired < 3 )
      return ACT_VM_RECOIL1;
   
   if ( m_nShotsFired < 4 )
      return ACT_VM_RECOIL2;

   return ACT_VM_RECOIL3;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CWeaponSMG2::Reload( void )
{
   bool fRet;
   float fCacheTime = m_flNextSecondaryAttack;

   fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
   if ( fRet )
   {
      // Undo whatever the reload process has done to our secondary
      // attack timer. We allow you to interrupt reloading to fire
      // a grenade.
      m_flNextSecondaryAttack = GetOwner()->m_flNextAttack = fCacheTime;

      WeaponSound( RELOAD );
   }

   return fRet;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::AddViewKick( void )
{
   #define   EASY_DAMPEN         0.5f
   #define   MAX_VERTICAL_KICK   1.0f   //Degrees
   #define   SLIDE_LIMIT         2.0f   //Seconds
   
   //Get the view kick
   CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

   if ( pPlayer == NULL )
      return;

   DoMachineGunKick( pPlayer, EASY_DAMPEN, MAX_VERTICAL_KICK, m_fFireDuration, SLIDE_LIMIT );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponSMG2::SecondaryAttack( void )
{
   // Only the player fires this way so we can cast
   CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
   
   if ( pPlayer == NULL )
      return;

   //Must have ammo
   if ( ( pPlayer->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) || ( pPlayer->GetWaterLevel() == 3 ) )
   {
      SendWeaponAnim( ACT_VM_DRYFIRE );
      BaseClass::WeaponSound( EMPTY );
      m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
      return;
   }

   if( m_bInReload )
      m_bInReload = false;

   // MUST call sound before removing a round from the clip of a CMachineGun
   BaseClass::WeaponSound( WPN_DOUBLE );

   pPlayer->RumbleEffect( RUMBLE_357, 0, RUMBLE_FLAGS_NONE );

   Vector vecSrc = pPlayer->Weapon_ShootPosition();
   Vector   vecThrow;
   // Don't autoaim on grenade tosses
   AngleVectors( pPlayer->EyeAngles() + pPlayer->GetPunchAngle(), &vecThrow );
   VectorScale( vecThrow, 1000.0f, vecThrow );
   
   //Create the grenade
   QAngle angles;
   VectorAngles( vecThrow, angles );
   CGrenadeAR2 *pGrenade = (CGrenadeAR2*)Create( "grenade_ar2", vecSrc, angles, pPlayer );
   pGrenade->SetAbsVelocity( vecThrow );

   pGrenade->SetLocalAngularVelocity( RandomAngle( -400, 400 ) );
   pGrenade->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
   pGrenade->SetThrower( GetOwner() );
   pGrenade->SetDamage( sk_plr_dmg_smg1_grenade.GetFloat() );

   SendWeaponAnim( ACT_VM_SECONDARYATTACK );

   CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 1000, 0.2, GetOwner(), SOUNDENT_CHANNEL_WEAPON );

   // player "shoot" animation
   pPlayer->SetAnimation( PLAYER_ATTACK1 );

   // Decrease ammo
   pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType );

   // Can shoot again immediately
   m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f;

   // Can blow up after a short delay (so have time to release mouse button)
   m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f;

   // Register a muzzleflash for the AI.
   pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );   

   m_iSecondaryAttacks++;
   gamestats->Event_WeaponFired( pPlayer, false, GetClassname() );
}

#define   COMBINE_MIN_GRENADE_CLEAR_DIST 256

//-----------------------------------------------------------------------------
// Purpose:
// Input  : flDot -
//         flDist -
// Output : int
//-----------------------------------------------------------------------------
int CWeaponSMG2::WeaponRangeAttack2Condition( float flDot, float flDist )
{
   CAI_BaseNPC *npcOwner = GetOwner()->MyNPCPointer();

   return COND_NONE;

/*
   // --------------------------------------------------------
   // Assume things haven't changed too much since last time
   // --------------------------------------------------------
   if (gpGlobals->curtime < m_flNextGrenadeCheck )
      return m_lastGrenadeCondition;
*/

   // -----------------------
   // If moving, don't check.
   // -----------------------
   if ( npcOwner->IsMoving())
      return COND_NONE;

   CBaseEntity *pEnemy = npcOwner->GetEnemy();

   if (!pEnemy)
      return COND_NONE;

   Vector vecEnemyLKP = npcOwner->GetEnemyLKP();
   if ( !( pEnemy->GetFlags() & FL_ONGROUND ) && pEnemy->GetWaterLevel() == 0 && vecEnemyLKP.z > (GetAbsOrigin().z + WorldAlignMaxs().z) )
   {
      //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to
      // be grenaded.
      // don't throw grenades at anything that isn't on the ground!
      return COND_NONE;
   }
   
   // --------------------------------------
   //  Get target vector
   // --------------------------------------
   Vector vecTarget;
   if (random->RandomInt(0,1))
   {
      // magically know where they are
      vecTarget = pEnemy->WorldSpaceCenter();
   }
   else
   {
      // toss it to where you last saw them
      vecTarget = vecEnemyLKP;
   }
   // vecTarget = m_vecEnemyLKP + (pEnemy->BodyTarget( GetLocalOrigin() ) - pEnemy->GetLocalOrigin());
   // estimate position
   // vecTarget = vecTarget + pEnemy->m_vecVelocity * 2;


   if ( ( vecTarget - npcOwner->GetLocalOrigin() ).Length2D() <= COMBINE_MIN_GRENADE_CLEAR_DIST )
   {
      // crap, I don't want to blow myself up
      m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second.
      return (COND_NONE);
   }

   // ---------------------------------------------------------------------
   // Are any friendlies near the intended grenade impact area?
   // ---------------------------------------------------------------------
   CBaseEntity *pTarget = NULL;

   while ( ( pTarget = gEntList.FindEntityInSphere( pTarget, vecTarget, COMBINE_MIN_GRENADE_CLEAR_DIST ) ) != NULL )
   {
      //Check to see if the default relationship is hatred, and if so intensify that
      if ( npcOwner->IRelationType( pTarget ) == D_LI )
      {
         // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while.
         m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second.
         return (COND_WEAPON_BLOCKED_BY_FRIEND);
      }
   }

   // ---------------------------------------------------------------------
   // Check that throw is legal and clear
   // ---------------------------------------------------------------------
   // FIXME: speed is based on difficulty...

   Vector vecToss = VecCheckThrow( this, npcOwner->GetLocalOrigin() + Vector(0,0,60), vecTarget, 600.0, 0.5 );
   if ( vecToss != vec3_origin )
   {
      m_vecTossVelocity = vecToss;

      // don't check again for a while.
      // JAY: HL1 keeps checking - test?
      //m_flNextGrenadeCheck = gpGlobals->curtime;
      m_flNextGrenadeCheck = gpGlobals->curtime + 0.3; // 1/3 second.
      return COND_CAN_RANGE_ATTACK2;
   }
   else
   {
      // don't check again for a while.
      m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second.
      return COND_WEAPON_SIGHT_OCCLUDED;
   }
}

//-----------------------------------------------------------------------------
const WeaponProficiencyInfo_t *CWeaponSMG2::GetProficiencyValues()
{
   static WeaponProficiencyInfo_t proficiencyTable[] =
   {
      { 7.0,      0.75   },
      { 5.00,      0.75   },
      { 10.0/3.0, 0.75   },
      { 5.0/3.0,   0.75   },
      { 1.00,      1.0      },
   };

   COMPILE_TIME_ASSERT( ARRAYSIZE(proficiencyTable) == WEAPON_PROFICIENCY_PERFECT + 1);

   return proficiencyTable;
}

SMG2

Code: Select all
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: A shotgun. (unused)
//
//         Primary attack: single barrel shot.
//         Secondary attack: double barrel shot.
//
//=============================================================================//

#include "cbase.h"
#include "NPCEvent.h"
#include "basehlcombatweapon_shared.h"
#include "basecombatcharacter.h"
#include "AI_BaseNPC.h"
#include "player.h"
#include "gamerules.h"      // For g_pGameRules
#include "in_buttons.h"
#include "soundent.h"
#include "vstdlib/random.h"
#include "gamestats.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

extern ConVar sk_auto_reload_time;
extern ConVar sk_plr_num_shotgun_pellets;

class CWeaponArnoshotty : public CBaseHLCombatWeapon
{
   DECLARE_DATADESC();
public:
   DECLARE_CLASS( CWeaponArnoshotty, CBaseHLCombatWeapon );

   DECLARE_SERVERCLASS();

private:
   bool   m_bNeedPump;      // When emptied completely
   bool   m_bDelayedFire1;   // Fire primary when finished reloading
   bool   m_bDelayedFire2;   // Fire secondary when finished reloading

public:
   void   Precache( void );

   int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }

   virtual const Vector& GetBulletSpread( void )
   {
      static Vector vitalAllyCone = VECTOR_CONE_3DEGREES;
      static Vector cone = VECTOR_CONE_10DEGREES;

      if( GetOwner() && (GetOwner()->Classify() == CLASS_PLAYER_ALLY_VITAL) )
      {
         // Give Alyx's shotgun blasts more a more directed punch. She needs
         // to be at least as deadly as she would be with her pistol to stay interesting (sjb)
         return vitalAllyCone;
      }

      return cone;
   }

   virtual int            GetMinBurst() { return 1; }
   virtual int            GetMaxBurst() { return 3; }

   virtual float         GetMinRestTime();
   virtual float         GetMaxRestTime();

   virtual float         GetFireRate( void );

   bool StartReload( void );
   bool Reload( void );
   void FillClip( void );
   void FinishReload( void );
   void CheckHolsterReload( void );
   void Pump( void );
//   void WeaponIdle( void );
   void ItemHolsterFrame( void );
   void ItemPostFrame( void );
   void PrimaryAttack( void );
   void SecondaryAttack( void );
   void DryFire( void );

   void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles );
   void Operator_ForceNPCFire( CBaseCombatCharacter  *pOperator, bool bSecondary );
   void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );

   DECLARE_ACTTABLE();

   CWeaponArnoshotty(void);
};

IMPLEMENT_SERVERCLASS_ST(CWeaponArnoshotty, DT_WeaponArnoshotty)
END_SEND_TABLE()

LINK_ENTITY_TO_CLASS( weapon_arnoshotty, CWeaponArnoshotty );
PRECACHE_WEAPON_REGISTER(weapon_arnoshotty);

BEGIN_DATADESC( CWeaponArnoshotty )

   DEFINE_FIELD( m_bNeedPump, FIELD_BOOLEAN ),
   DEFINE_FIELD( m_bDelayedFire1, FIELD_BOOLEAN ),
   DEFINE_FIELD( m_bDelayedFire2, FIELD_BOOLEAN ),

END_DATADESC()

acttable_t   CWeaponArnoshotty::m_acttable[] =
{
   { ACT_IDLE,                  ACT_IDLE_SMG1,               true },   // FIXME: hook to shotgun unique

   { ACT_RANGE_ATTACK1,         ACT_RANGE_ATTACK_SHOTGUN,         true },
   { ACT_RELOAD,               ACT_RELOAD_SHOTGUN,               false },
   { ACT_WALK,                  ACT_WALK_RIFLE,                  true },
   { ACT_IDLE_ANGRY,            ACT_IDLE_ANGRY_SHOTGUN,            true },

// Readiness activities (not aiming)
   { ACT_IDLE_RELAXED,            ACT_IDLE_SHOTGUN_RELAXED,      false },//never aims
   { ACT_IDLE_STIMULATED,         ACT_IDLE_SHOTGUN_STIMULATED,   false },
   { ACT_IDLE_AGITATED,         ACT_IDLE_SHOTGUN_AGITATED,      false },//always aims

   { ACT_WALK_RELAXED,            ACT_WALK_RIFLE_RELAXED,         false },//never aims
   { ACT_WALK_STIMULATED,         ACT_WALK_RIFLE_STIMULATED,      false },
   { ACT_WALK_AGITATED,         ACT_WALK_AIM_RIFLE,            false },//always aims

   { ACT_RUN_RELAXED,            ACT_RUN_RIFLE_RELAXED,         false },//never aims
   { ACT_RUN_STIMULATED,         ACT_RUN_RIFLE_STIMULATED,      false },
   { ACT_RUN_AGITATED,            ACT_RUN_AIM_RIFLE,            false },//always aims

// Readiness activities (aiming)
   { ACT_IDLE_AIM_RELAXED,         ACT_IDLE_SMG1_RELAXED,         false },//never aims   
   { ACT_IDLE_AIM_STIMULATED,      ACT_IDLE_AIM_RIFLE_STIMULATED,   false },
   { ACT_IDLE_AIM_AGITATED,      ACT_IDLE_ANGRY_SMG1,         false },//always aims

   { ACT_WALK_AIM_RELAXED,         ACT_WALK_RIFLE_RELAXED,         false },//never aims
   { ACT_WALK_AIM_STIMULATED,      ACT_WALK_AIM_RIFLE_STIMULATED,   false },
   { ACT_WALK_AIM_AGITATED,      ACT_WALK_AIM_RIFLE,            false },//always aims

   { ACT_RUN_AIM_RELAXED,         ACT_RUN_RIFLE_RELAXED,         false },//never aims
   { ACT_RUN_AIM_STIMULATED,      ACT_RUN_AIM_RIFLE_STIMULATED,   false },
   { ACT_RUN_AIM_AGITATED,         ACT_RUN_AIM_RIFLE,            false },//always aims
//End readiness activities

   { ACT_WALK_AIM,               ACT_WALK_AIM_SHOTGUN,            true },
   { ACT_WALK_CROUCH,            ACT_WALK_CROUCH_RIFLE,            true },
   { ACT_WALK_CROUCH_AIM,         ACT_WALK_CROUCH_AIM_RIFLE,         true },
   { ACT_RUN,                  ACT_RUN_RIFLE,                  true },
   { ACT_RUN_AIM,               ACT_RUN_AIM_SHOTGUN,            true },
   { ACT_RUN_CROUCH,            ACT_RUN_CROUCH_RIFLE,            true },
   { ACT_RUN_CROUCH_AIM,         ACT_RUN_CROUCH_AIM_RIFLE,         true },
   { ACT_GESTURE_RANGE_ATTACK1,   ACT_GESTURE_RANGE_ATTACK_SHOTGUN,   true },
   { ACT_RANGE_ATTACK1_LOW,      ACT_RANGE_ATTACK_SHOTGUN_LOW,      true },
   { ACT_RELOAD_LOW,            ACT_RELOAD_SHOTGUN_LOW,            false },
   { ACT_GESTURE_RELOAD,         ACT_GESTURE_RELOAD_SHOTGUN,         false },
};

IMPLEMENT_ACTTABLE(CWeaponArnoshotty);

void CWeaponArnoshotty::Precache( void )
{
   CBaseCombatWeapon::Precache();
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : *pOperator -
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles )
{
   Vector vecShootOrigin, vecShootDir;
   CAI_BaseNPC *npc = pOperator->MyNPCPointer();
   ASSERT( npc != NULL );
   WeaponSound( SINGLE_NPC );
   pOperator->DoMuzzleFlash();
   m_iClip1 = m_iClip1 - 1;

   if ( bUseWeaponAngles )
   {
      QAngle   angShootDir;
      GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir );
      AngleVectors( angShootDir, &vecShootDir );
   }
   else
   {
      vecShootOrigin = pOperator->Weapon_ShootPosition();
      vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );
   }

   pOperator->FireBullets( 8, vecShootOrigin, vecShootDir, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary )
{
   // Ensure we have enough rounds in the clip
   m_iClip1++;

   FireNPCPrimaryAttack( pOperator, true );
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
   switch( pEvent->event )
   {
      case EVENT_WEAPON_SHOTGUN_FIRE:
      {
         FireNPCPrimaryAttack( pOperator, false );
      }
      break;

      default:
         CBaseCombatWeapon::Operator_HandleAnimEvent( pEvent, pOperator );
         break;
   }
}


//-----------------------------------------------------------------------------
// Purpose:   When we shipped HL2, the shotgun weapon did not override the
//         BaseCombatWeapon default rest time of 0.3 to 0.6 seconds. When
//         NPC's fight from a stationary position, their animation events
//         govern when they fire so the rate of fire is specified by the
//         animation. When NPC's move-and-shoot, the rate of fire is
//         specifically controlled by the shot regulator, so it's imporant
//         that GetMinRestTime and GetMaxRestTime are implemented and provide
//         reasonable defaults for the weapon. To address difficulty concerns,
//         we are going to fix the combine's rate of shotgun fire in episodic.
//         This change will not affect Alyx using a shotgun in EP1. (sjb)
//-----------------------------------------------------------------------------
float CWeaponArnoshotty::GetMinRestTime()
{
   if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
   {
      return 1.2f;
   }
   
   return BaseClass::GetMinRestTime();
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
float CWeaponArnoshotty::GetMaxRestTime()
{
   if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
   {
      return 1.5f;
   }

   return BaseClass::GetMaxRestTime();
}

//-----------------------------------------------------------------------------
// Purpose: Time between successive shots in a burst. Also returned for EP2
//         with an eye to not messing up Alyx in EP1.
//-----------------------------------------------------------------------------
float CWeaponArnoshotty::GetFireRate()
{
   if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
   {
      return 0.8f;
   }

   return 0.7;
}

//-----------------------------------------------------------------------------
// Purpose: Override so only reload one shell at a time
// Input  :
// Output :
//-----------------------------------------------------------------------------
bool CWeaponArnoshotty::StartReload( void )
{
   CBaseCombatCharacter *pOwner  = GetOwner();
   
   if ( pOwner == NULL )
      return false;

   if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
      return false;

   if (m_iClip1 >= GetMaxClip1())
      return false;

   // If shotgun totally emptied then a pump animation is needed
   
   //NOTENOTE: This is kinda lame because the player doesn't get strong feedback on when the reload has finished,
   //         without the pump.  Technically, it's incorrect, but it's good for feedback...

   if (m_iClip1 <= 0)
   {
      m_bNeedPump = true;
   }

   int j = min(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));

   if (j <= 0)
      return false;

   SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );

   // Make shotgun shell visible
   SetBodygroup(1,0);

   pOwner->m_flNextAttack = gpGlobals->curtime;
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();

   m_bInReload = true;
   return true;
}

//-----------------------------------------------------------------------------
// Purpose: Override so only reload one shell at a time
// Input  :
// Output :
//-----------------------------------------------------------------------------
bool CWeaponArnoshotty::Reload( void )
{
   // Check that StartReload was called first
   if (!m_bInReload)
   {
      Warning("ERROR: Arnoshotty Reload called incorrectly!\n");
   }

   CBaseCombatCharacter *pOwner  = GetOwner();
   
   if ( pOwner == NULL )
      return false;

   if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
      return false;

   if (m_iClip1 >= GetMaxClip1())
      return false;

   int j = min(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));

   if (j <= 0)
      return false;

   FillClip();
   // Play reload on different channel as otherwise steals channel away from fire sound
   WeaponSound(RELOAD);
   SendWeaponAnim( ACT_VM_RELOAD );

   pOwner->m_flNextAttack = gpGlobals->curtime;
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();

   return true;
}

//-----------------------------------------------------------------------------
// Purpose: Play finish reload anim and fill clip
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::FinishReload( void )
{
   // Make shotgun shell invisible
   SetBodygroup(1,1);

   CBaseCombatCharacter *pOwner  = GetOwner();
   
   if ( pOwner == NULL )
      return;

   m_bInReload = false;

   // Finish reload animation
   SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );

   pOwner->m_flNextAttack = gpGlobals->curtime;
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}

//-----------------------------------------------------------------------------
// Purpose: Play finish reload anim and fill clip
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::FillClip( void )
{
   CBaseCombatCharacter *pOwner  = GetOwner();
   
   if ( pOwner == NULL )
      return;

   // Add them to the clip
   if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
   {
      if ( Clip1() < GetMaxClip1() )
      {
         m_iClip1++;
         pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
      }
   }
}

//-----------------------------------------------------------------------------
// Purpose: Play weapon pump anim
// Input  :
// Output :
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::Pump( void )
{
   CBaseCombatCharacter *pOwner  = GetOwner();

   if ( pOwner == NULL )
      return;
   
   m_bNeedPump = false;
   
   WeaponSound( SPECIAL1 );

   // Finish reload animation
   SendWeaponAnim( ACT_SHOTGUN_PUMP );

   pOwner->m_flNextAttack   = gpGlobals->curtime + SequenceDuration();
   m_flNextPrimaryAttack   = gpGlobals->curtime + SequenceDuration();
}

//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::DryFire( void )
{
   WeaponSound(EMPTY);
   SendWeaponAnim( ACT_VM_DRYFIRE );
   
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}

//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::PrimaryAttack( void )
{
   // Only the player fires this way so we can cast
   CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

   if (!pPlayer)
   {
      return;
   }

   // MUST call sound before removing a round from the clip of a CMachineGun
   WeaponSound(SINGLE);

   pPlayer->DoMuzzleFlash();

   SendWeaponAnim( ACT_VM_PRIMARYATTACK );

   // player "shoot" animation
   pPlayer->SetAnimation( PLAYER_ATTACK1 );

   // Don't fire again until fire animation has completed
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
   m_iClip1 -= 1;

   Vector   vecSrc      = pPlayer->Weapon_ShootPosition( );
   Vector   vecAiming   = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );   

   pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
   
   // Fire the bullets, and force the first shot to be perfectly accuracy
   pPlayer->FireBullets( sk_plr_num_shotgun_pellets.GetInt(), vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, true, true );
   
   pPlayer->ViewPunch( QAngle( random->RandomFloat( -2, -1 ), random->RandomFloat( -2, 2 ), 0 ) );

   CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2, GetOwner() );

   if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
   {
      // HEV suit - indicate out of ammo condition
      pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
   }

   if( m_iClip1 )
   {
      // pump so long as some rounds are left.
      m_bNeedPump = true;
   }

   m_iPrimaryAttacks++;
   gamestats->Event_WeaponFired( pPlayer, true, GetClassname() );
}

//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::SecondaryAttack( void )
{
   // Only the player fires this way so we can cast
   CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );

   if (!pPlayer)
   {
      return;
   }

   pPlayer->m_nButtons &= ~IN_ATTACK2;
   // MUST call sound before removing a round from the clip of a CMachineGun
   WeaponSound(WPN_DOUBLE);

   pPlayer->DoMuzzleFlash();

   SendWeaponAnim( ACT_VM_SECONDARYATTACK );

   // player "shoot" animation
   pPlayer->SetAnimation( PLAYER_ATTACK1 );

   // Don't fire again until fire animation has completed
   m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
   m_iClip1 -= 2;   // Arnoshotty uses same clip for primary and secondary attacks

   Vector vecSrc    = pPlayer->Weapon_ShootPosition();
   Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );   

   // Fire the bullets
   pPlayer->FireBullets( 12, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, false, false );
   pPlayer->ViewPunch( QAngle(random->RandomFloat( -5, 5 ),0,0) );

   pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );

   CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2 );

   if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
   {
      // HEV suit - indicate out of ammo condition
      pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
   }

   if( m_iClip1 )
   {
      // pump so long as some rounds are left.
      m_bNeedPump = true;
   }

   m_iSecondaryAttacks++;
   gamestats->Event_WeaponFired( pPlayer, false, GetClassname() );
}
   
//-----------------------------------------------------------------------------
// Purpose: Override so shotgun can do mulitple reloads in a row
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::ItemPostFrame( void )
{
   CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
   if (!pOwner)
   {
      return;
   }

   if (m_bInReload)
   {
      // If I'm primary firing and have one round stop reloading and fire
      if ((pOwner->m_nButtons & IN_ATTACK ) && (m_iClip1 >=1))
      {
         m_bInReload      = false;
         m_bNeedPump      = false;
         m_bDelayedFire1 = true;
      }
      // If I'm secondary firing and have one round stop reloading and fire
      else if ((pOwner->m_nButtons & IN_ATTACK2 ) && (m_iClip1 >=2))
      {
         m_bInReload      = false;
         m_bNeedPump      = false;
         m_bDelayedFire2 = true;
      }
      else if (m_flNextPrimaryAttack <= gpGlobals->curtime)
      {
         // If out of ammo end reload
         if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0)
         {
            FinishReload();
            return;
         }
         // If clip not full reload again
         if (m_iClip1 < GetMaxClip1())
         {
            Reload();
            return;
         }
         // Clip full, stop reloading
         else
         {
            FinishReload();
            return;
         }
      }
   }
   else
   {         
      // Make shotgun shell invisible
      SetBodygroup(1,1);
   }

   if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
   {
      Pump();
      return;
   }
   
   // Arnoshotty uses same timing and ammo for secondary attack
   if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2)&&(m_flNextPrimaryAttack <= gpGlobals->curtime))
   {
      m_bDelayedFire2 = false;
      
      if ( (m_iClip1 <= 1 && UsesClipsForAmmo1()))
      {
         // If only one shell is left, do a single shot instead   
         if ( m_iClip1 == 1 )
         {
            PrimaryAttack();
         }
         else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
         {
            DryFire();
         }
         else
         {
            StartReload();
         }
      }

      // Fire underwater?
      else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
      {
         WeaponSound(EMPTY);
         m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
         return;
      }
      else
      {
         // If the firing button was just pressed, reset the firing time
         if ( pOwner->m_afButtonPressed & IN_ATTACK )
         {
             m_flNextPrimaryAttack = gpGlobals->curtime;
         }
         SecondaryAttack();
      }
   }
   else if ( (m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime)
   {
      m_bDelayedFire1 = false;
      if ( (m_iClip1 <= 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType) ) )
      {
         if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
         {
            DryFire();
         }
         else
         {
            StartReload();
         }
      }
      // Fire underwater?
      else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
      {
         WeaponSound(EMPTY);
         m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
         return;
      }
      else
      {
         // If the firing button was just pressed, reset the firing time
         CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
         if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK )
         {
             m_flNextPrimaryAttack = gpGlobals->curtime;
         }
         PrimaryAttack();
      }
   }

   if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload )
   {
      // reload when reload is pressed, or if no buttons are down and weapon is empty.
      StartReload();
   }
   else
   {
      // no fire buttons down
      m_bFireOnEmpty = false;

      if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime )
      {
         // weapon isn't useable, switch.
         if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon( this ) )
         {
            m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
            return;
         }
      }
      else
      {
         // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
         if ( m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
         {
            if (StartReload())
            {
               // if we've successfully started to reload, we're done
               return;
            }
         }
      }

      WeaponIdle( );
      return;
   }

}



//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponArnoshotty::CWeaponArnoshotty( void )
{
   m_bReloadsSingly = true;

   m_bNeedPump      = false;
   m_bDelayedFire1 = false;
   m_bDelayedFire2 = false;

   m_fMinRange1      = 0.0;
   m_fMaxRange1      = 500;
   m_fMinRange2      = 0.0;
   m_fMaxRange2      = 200;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArnoshotty::ItemHolsterFrame( void )
{
   // Must be player held
   if ( GetOwner() && GetOwner()->IsPlayer() == false )
      return;

   // We can't be active
   if ( GetOwner()->GetActiveWeapon() == this )
      return;

   // If it's been longer than three seconds, reload
   if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
   {
      // Reset the timer
      m_flHolsterTime = gpGlobals->curtime;
   
      if ( GetOwner() == NULL )
         return;

      if ( m_iClip1 == GetMaxClip1() )
         return;

      // Just load the clip with no animations
      int ammoFill = min( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
      
      GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
      m_iClip1 += ammoFill;
   }
}

//==================================================
// Purpose:
//==================================================
/*
void CWeaponArnoshotty::WeaponIdle( void )
{
   //Only the player fires this way so we can cast
   CBasePlayer *pPlayer = GetOwner()

   if ( pPlayer == NULL )
      return;

   //If we're on a target, play the new anim
   if ( pPlayer->IsOnTarget() )
   {
      SendWeaponAnim( ACT_VM_IDLE_ACTIVE );
   }
}
*/

NPC-only shotgun.

Code: Select all
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//

#include "cbase.h"
#include "c_weapon__stubs.h"
#include "basehlcombatweapon_shared.h"
#include "c_basehlcombatweapon.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon );

STUB_WEAPON_CLASS( weapon_binoculars, WeaponBinoculars, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_bugbait, WeaponBugBait, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_flaregun, Flaregun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_annabelle, WeaponAnnabelle, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_gauss, WeaponGaussGun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
STUB_WEAPON_CLASS( weapon_alyxgun, WeaponAlyxGun, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_citizenpackage, WeaponCitizenPackage, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_citizensuitcase, WeaponCitizenSuitcase, C_WeaponCitizenPackage );


#ifndef HL2MP
STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun );
STUB_WEAPON_CLASS( weapon_frag, WeaponFrag, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_pistol, WeaponPistol, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_luger, WeaponLuger,C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_arnoshotty, WeaponArnoshotty, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_smg2, WeaponSMG2, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_357, Weapon357, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_crossbow, WeaponCrossbow, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_slam, Weapon_SLAM, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_crowbar, WeaponCrowbar, C_BaseHLBludgeonWeapon );
#ifdef HL2_EPISODIC
STUB_WEAPON_CLASS( weapon_hopwire, WeaponHopwire, C_BaseHLCombatWeapon );
//STUB_WEAPON_CLASS( weapon_proto1, WeaponProto1, C_BaseHLCombatWeapon );
#endif
#ifdef HL2_LOSTCOAST
STUB_WEAPON_CLASS( weapon_oldmanharpoon, WeaponOldManHarpoon, C_WeaponCitizenPackage );
#endif
#endif



The c_weapon__stubb, including the only working weapon_luger.
GigaNova
Member
Member
 
Joined: Mon Jun 11, 2012 6:32 pm

Re: Weapon making not working

Postby [Steve] on Mon Jun 11, 2012 10:47 pm

your code works for me !

The error is because the game cant find
Code: Select all
STUB_WEAPON_CLASS( weapon_arnoshotty, WeaponArnoshotty, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_smg2, WeaponSMG2, C_HLSelectFireMachineGun );

inside your c_weapon__stubb_hl2
Obviously from your code I can see it is there , so that leads me to believe your Client Dll isn't being built.


make sure your client dll is being compiled and copied to the bin folder, perhaps its just not copying the file to your source mods dir.
Also you could try a rebuild.
User avatar
[Steve]
Interlopers Staff
Interlopers Staff
 
Joined: Fri Mar 06, 2009 11:25 pm

Return to Programming

Who is online

Users browsing this forum: No registered users