//========= Copyright Valve Corporation, All rights reserved. ============//
//
//	Weapons.
//
//	CTFWeaponBase
//	|
//	|--> CTFWeaponBaseMelee
//	|		|
//	|		|--> CTFWeaponCrowbar
//	|		|--> CTFWeaponKnife
//	|		|--> CTFWeaponMedikit
//	|		|--> CTFWeaponWrench
//	|
//	|--> CTFWeaponBaseGrenade
//	|		|
//	|		|--> CTFWeapon
//	|		|--> CTFWeapon
//	|
//	|--> CTFWeaponBaseGun
//
//=============================================================================
#ifndef TF_WEAPONBASE_H
#define TF_WEAPONBASE_H
#ifdef _WIN32
#pragma once
#endif

#include "tf_playeranimstate.h"
#include "tf_weapon_parse.h"
#include "npcevent.h"
#include "ihasowner.h"
#include "tf_item_wearable.h"

// Client specific.
#if defined( CLIENT_DLL )
#define CTFWeaponBase C_TFWeaponBase
#define CTFWeaponAttachmentModel C_TFWeaponAttachmentModel
#define CTFWeaponBaseGrenadeProj C_TFWeaponBaseGrenadeProj
#include "tf_fx_muzzleflash.h"
#include "GameEventListener.h"
#endif

#define MAX_TRACER_NAME		128

class CTFPlayer;
class CBaseObject;
class CTFWeaponBaseGrenadeProj;
class CTFWeaponAttachmentModel;

// Given an ammo type (like from a weapon's GetPrimaryAmmoType()), this compares it
// against the ammo name you specify.
// TFTODO: this should use indexing instead of searching and strcmp()'ing all the time.
bool IsAmmoType( int iAmmoType, const char *pAmmoName );
void FindHullIntersection( const Vector &vecSrc, trace_t &tr, const Vector &mins, const Vector &maxs, CBaseEntity *pEntity );

// Reloading singly.
enum
{
	TF_RELOAD_START = 0,
	TF_RELOADING,
	TF_RELOADING_CONTINUE,
	TF_RELOAD_FINISH
};

// structure to encapsulate state of head bob
struct BobState_t
{
	BobState_t() 
	{ 
		m_flBobTime = 0; 
		m_flLastBobTime = 0;
		m_flLastSpeed = 0;
		m_flVerticalBob = 0;
		m_flLateralBob = 0;
	}

	float m_flBobTime;
	float m_flLastBobTime;
	float m_flLastSpeed;
	float m_flVerticalBob;
	float m_flLateralBob;
};

enum EWeaponStrangeType_t
{
	STRANGE_UNKNOWN = -1,
	STRANGE_NOT_STRANGE = 0,
	STRANGE_IS_STRANGE = 1,
};

enum EWeaponStatTrakModuleType_t
{
	MODULE_UNKNOWN = -1,
	MODULE_NONE = 0,
	MODULE_FOUND = 1,
};

#ifdef CLIENT_DLL
float CalcViewModelBobHelper( CBasePlayer *player, BobState_t *pBobState );
void AddViewModelBobHelper( Vector &origin, QAngle &angles, BobState_t *pBobState );
#endif

// Interface for weapons that have a charge time
class ITFChargeUpWeapon 
{
public:
	virtual bool CanCharge( void ) = 0;

	virtual float GetChargeBeginTime( void ) = 0;

	virtual float GetChargeMaxTime( void ) = 0;

	virtual float GetCurrentCharge( void )
	{ 
		return ( gpGlobals->curtime - GetChargeBeginTime() ) / GetChargeMaxTime();
	}
};

class CTraceFilterIgnoreTeammates : public CTraceFilterSimple
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS( CTraceFilterIgnoreTeammates, CTraceFilterSimple );

	CTraceFilterIgnoreTeammates( const IHandleEntity *passentity, int collisionGroup, int iIgnoreTeam )
		: CTraceFilterSimple( passentity, collisionGroup ), m_iIgnoreTeam( iIgnoreTeam )
	{
	}

	virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
	{
		CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );

		if ( ( pEntity->IsPlayer() || pEntity->IsCombatItem() ) && ( pEntity->GetTeamNumber() == m_iIgnoreTeam || m_iIgnoreTeam == TEAM_ANY ) )
		{
			return false;
		}

		return BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
	}

	int m_iIgnoreTeam;
};

class CTraceFilterIgnorePlayers : public CTraceFilterSimple
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS( CTraceFilterIgnorePlayers, CTraceFilterSimple );

	CTraceFilterIgnorePlayers( const IHandleEntity *passentity, int collisionGroup )
		: CTraceFilterSimple( passentity, collisionGroup )
	{
	}

	virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
	{
		CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
		if ( pEntity && pEntity->IsPlayer() )
			return false;

		return BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
	}
};

class CTraceFilterIgnoreFriendlyCombatItems : public CTraceFilterSimple
{
public:
	DECLARE_CLASS( CTraceFilterIgnoreFriendlyCombatItems, CTraceFilterSimple );

	CTraceFilterIgnoreFriendlyCombatItems( const IHandleEntity *passentity, int collisionGroup, int iIgnoreTeam, bool bIsProjectile = false )
		: CTraceFilterSimple( passentity, collisionGroup ), m_iIgnoreTeam( iIgnoreTeam )
	{
		m_bCallerIsProjectile = bIsProjectile;
	}

	virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
	{
		CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );

// 		if ( ( pEntity->MyCombatCharacterPointer() || pEntity->MyCombatWeaponPointer() ) && pEntity->GetTeamNumber() == m_iIgnoreTeam )
// 			return false;
// 
// 		if ( pEntity->IsPlayer() && pEntity->GetTeamNumber() == m_iIgnoreTeam )
// 			return false;

		if ( pEntity->IsCombatItem() )
		{
			if ( pEntity->GetTeamNumber() == m_iIgnoreTeam )
				return false;

			// If source is a enemy projectile, be explicit, otherwise we fail a "IsTransparent" test downstream
			if ( m_bCallerIsProjectile )
				return true;
		}

		return BaseClass::ShouldHitEntity( pServerEntity, contentsMask );
	}

	int m_iIgnoreTeam;
	bool m_bCallerIsProjectile;
};

#define ENERGY_WEAPON_MAX_CHARGE		20

#define TF_PARTICLE_WEAPON_BLUE_1	Vector( 0.345, 0.52, 0.635 )
#define TF_PARTICLE_WEAPON_BLUE_2	Vector( 0.145, 0.427, 0.55 )
#define TF_PARTICLE_WEAPON_RED_1	Vector( 0.72, 0.22, 0.23 )
#define TF_PARTICLE_WEAPON_RED_2	Vector( 0.5, 0.18, 0.125 )

//=============================================================================
//
// Base TF Weapon Class
//
#if defined( CLIENT_DLL )
class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner, public CGameEventListener
#else
class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner
#endif
{
	DECLARE_CLASS( CTFWeaponBase, CBaseCombatWeapon );
	DECLARE_NETWORKCLASS(); 
	DECLARE_PREDICTABLE();
#if !defined ( CLIENT_DLL )
	DECLARE_DATADESC();
#endif

	// Setup.
	CTFWeaponBase();
	~CTFWeaponBase();

	virtual void Spawn();
	virtual void Activate( void );
	virtual void Precache();
	virtual bool IsPredicted() const			{ return true; }
	virtual void FallInit( void );

	// Weapon Data.
	CTFWeaponInfo const	&GetTFWpnData() const;
	virtual int GetWeaponID( void ) const;
	bool IsWeapon( int iWeapon ) const;
	virtual int	GetDamageType() const { return g_aWeaponDamageTypes[ GetWeaponID() ]; }
	virtual int GetCustomDamageType() const { return TF_DMG_CUSTOM_NONE; }
	virtual int	GetMaxClip1( void ) const;
	virtual int GetDefaultClip1( void ) const;
	virtual bool UsesPrimaryAmmo();
	virtual float UberChargeAmmoPerShot( void ) { float fAmmo = 0; CALL_ATTRIB_HOOK_FLOAT( fAmmo, ubercharge_ammo ); return fAmmo * 0.01f; }

	virtual int	Clip1() { return IsEnergyWeapon() ? Energy_GetEnergy() : m_iClip1; }
	virtual int	Clip2() { return m_iClip2; }

	virtual bool HasAmmo( void );

	// View model.
	virtual const char *GetViewModel( int iViewModel = 0 ) const;
	virtual const char *GetWorldModel( void ) const;

	virtual bool SendWeaponAnim( int iActivity ) OVERRIDE;

	virtual CBaseEntity	*GetOwnerViaInterface( void ) { return GetOwner(); }

	virtual void Equip( CBaseCombatCharacter *pOwner );
	virtual void Drop( const Vector &vecVelocity );
	virtual void UpdateOnRemove( void );
	virtual bool CanHolster( void ) const;
	virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
	virtual bool Deploy( void );
	virtual bool ForceWeaponSwitch() const OVERRIDE;
	virtual void Detach( void );
	virtual void OnActiveStateChanged( int iOldState );
	virtual bool OwnerCanJump( void ) { return true; }
	virtual bool VisibleInWeaponSelection( void );
	virtual void UpdateHands( void );

	virtual bool OwnerCanTaunt( void ) { return true; }
	virtual bool CanBeCritBoosted( void );
	bool CanHaveRevengeCrits( void );

	// Extra wearables.
#ifdef GAME_DLL
	virtual void ChangeTeam( int iTeamNum ) OVERRIDE;	
	virtual void UpdateExtraWearables();
	virtual void ExtraWearableEquipped( CTFWearable *pExtraWearableItem );
	virtual void ExtraWearableViewModelEquipped( CTFWearable *pExtraWearableItem );
	virtual bool HideAttachmentsAndShowBodygroupsWhenPerformingWeaponIndependentTaunt() const { return true; }
#endif // GAME_DLL
	virtual void RemoveExtraWearables( void );

	// Attacks.
	virtual void Misfire( void );
	virtual void FireFullClipAtOnce( void );
	virtual void PrimaryAttack();
	virtual void SecondaryAttack();
	void CalcIsAttackCritical( void );
	virtual bool CalcIsAttackCriticalHelper();
	virtual bool CalcIsAttackCriticalHelperNoCrits();
	bool IsCurrentAttackACrit() const { return m_bCurrentAttackIsCrit; }
	bool IsCurrentAttackARandomCrit() const { return m_bCurrentAttackIsCrit && m_bCurrentCritIsRandom; }
	bool IsCurrentAttackDuringDemoCharge() const { return m_bCurrentAttackIsDuringDemoCharge; }
	virtual ETFDmgCustom GetPenetrateType() const;
	virtual void GetProjectileFireSetup( CTFPlayer *pPlayer, Vector vecOffset, Vector *vecSrc, QAngle *angForward, bool bHitTeammates = true, float flEndDist = 2000.f );
	virtual QAngle GetSpreadAngles( void );
	float GetLastPrimaryAttackTime( void ) const { return m_flLastPrimaryAttackTime; }
	virtual bool CanPerformSecondaryAttack() const OVERRIDE;
	virtual bool IsFiring( void ) const { return false; }
	virtual bool AreRandomCritsEnabled( void );

	// Reloads.
	virtual bool Reload( void );
	virtual void AbortReload( void );
	virtual bool DefaultReload( int iClipSize1, int iClipSize2, int iActivity );
	void SendReloadEvents();
	virtual bool IsReloading() const;			// is the weapon reloading right now?

	virtual bool AutoFiresFullClip( void ) const OVERRIDE;
	bool AutoFiresFullClipAllAtOnce( void ) const;
	bool CanOverload( void ) const;
	virtual bool CheckReloadMisfire( void ) { return false; }

	virtual bool CanDrop( void ) { return false; }
	virtual bool AllowTaunts( void ) { return true; }

	// Fire Rate
	float ApplyFireDelay( float flDelay ) const;

	// Sound.
	bool PlayEmptySound();
	bool IsSilentKiller();

	// Activities.
	virtual void ItemBusyFrame( void );
	virtual void ItemPostFrame( void );
	virtual void ItemHolsterFrame( void );

	virtual void SetWeaponVisible( bool visible );

	virtual int GetActivityWeaponRole() const;
	virtual acttable_t *ActivityList( int &iActivityCount ) OVERRIDE;

	virtual Activity	TranslateViewmodelHandActivityInternal( Activity actBase );
	virtual int			GetViewModelWeaponRole() { return GetTFWpnData().m_iWeaponType; }

#ifdef GAME_DLL
	virtual void	AddAssociatedObject( CBaseObject *pObject ) { }
	virtual void	RemoveAssociatedObject( CBaseObject *pObject ) { }

	virtual void	ApplyOnHitAttributes( CBaseEntity *pVictimBaseEntity, CTFPlayer *pAttacker, const CTakeDamageInfo &info );
	virtual void	ApplyPostHitEffects( const CTakeDamageInfo &inputInfo, CTFPlayer *pPlayer );
	virtual void	ApplyOnInjuredAttributes( CTFPlayer *pVictim, CTFPlayer *pAttacker, const CTakeDamageInfo &info );		// when owner of this weapon is hit

	virtual void	Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );

	virtual bool	DeflectProjectiles();
	virtual bool	DeflectPlayer( CTFPlayer *pTarget, CTFPlayer *pOwner, Vector &vecForward, Vector &vecCenter, Vector &vecSize );
	virtual bool	DeflectEntity( CBaseEntity *pTarget, CTFPlayer *pOwner, Vector &vecForward, Vector &vecCenter, Vector &vecSize );
	static void		SendObjectDeflectedEvent( CTFPlayer *pNewOwner, CTFPlayer *pPrevOwner, int iWeaponID, CBaseAnimating *pObject );
	static float	DeflectionForce( const Vector &size, float damage, float scale );
	virtual void	PlayDeflectionSound( bool bPlayer ) {}
	virtual Vector	GetDeflectionSize() { return Vector( 128, 128, 64 ); }

	virtual float	GetJarateTime() { return 0.f; }

	void			ApplyItemRegen( void );

	kill_eater_event_t GetKillEaterKillEventType() const;
#endif

	// Utility.
	CBasePlayer *GetPlayerOwner() const;
	CTFPlayer *GetTFPlayerOwner() const;

#ifdef CLIENT_DLL
	virtual bool	ShouldPlayClientReloadSound() { return false; }

	C_BaseEntity *GetWeaponForEffect();

	virtual const char* ModifyEventParticles( const char* token ) { return token; }

	// Shadows
	virtual ShadowType_t ShadowCastType( void ) OVERRIDE;
#endif

	virtual bool	CanAttack();
	virtual int		GetCanAttackFlags() const { return TF_CAN_ATTACK_FLAG_NONE; }

	// Raising & Lowering for grenade throws
	bool			WeaponShouldBeLowered( void );
	virtual bool	Ready( void );
	virtual bool	Lower( void );

	virtual void	WeaponIdle( void );

	virtual void	WeaponReset( void );
	virtual void	WeaponRegenerate( void );

	// Muzzleflashes
	virtual const char *GetMuzzleFlashEffectName_3rd( void ) { return NULL; }
	virtual const char *GetMuzzleFlashEffectName_1st( void ) { return NULL; }
	virtual const char *GetMuzzleFlashModel( void );
	virtual float	GetMuzzleFlashModelLifetime( void );
	virtual const char *GetMuzzleFlashParticleEffect( void );

	virtual const char	*GetTracerType( void );

	virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );

	// CEconEntity
	virtual const char *GetInventoryModel( void );
	virtual void		ReapplyProvision( void );
	virtual float		GetSpeedMod( void ) { return 1.f; };

	virtual bool		CanFireCriticalShot( bool bIsHeadshot = false );
	virtual bool		CanFireRandomCriticalShot( float flCritChance );

	virtual char const	*GetShootSound( int iIndex ) const;
	void			UpdateHiddenParentBodygroup( bool bHide );

	virtual void		OnControlStunned( void );

	virtual bool		HideWhileStunned( void ) { return true; }

	virtual bool IsViewModelFlipped( void );

	virtual int			GetMaxHealthMod() { return 0; }

	virtual float		GetLastDeployTime( void ) { return m_flLastDeployTime; }

	// Energy Weapons
	virtual bool		IsEnergyWeapon( void ) const { return false; }
	virtual bool		IsBlastImpactWeapon( void ) const { return false; }
	float				Energy_GetMaxEnergy( void ) const;
	float				Energy_GetEnergy( void ) const { return m_flEnergy; }
	void				Energy_SetEnergy( float flEnergy ) { m_flEnergy = flEnergy; }
	bool				Energy_FullyCharged( void ) const;
	bool				Energy_HasEnergy( void );
	void				Energy_DrainEnergy( void );
	void				Energy_DrainEnergy( float flDrain );
	bool				Energy_Recharge( void );
	virtual float		Energy_GetShotCost( void ) const { return 4.f; }
	virtual float		Energy_GetRechargeCost( void ) const { return 4.f; }

	virtual Vector		GetParticleColor( int iColor );

	virtual void		CheckReload( void );
	virtual void		FinishReload( void );

	virtual bool		HasLastShotCritical( void ) { return false; }

	virtual bool		UseServerRandomSeed( void ) const { return true; }

// Server specific.
#if !defined( CLIENT_DLL )

	// Spawning.
	virtual void CheckRespawn();
	virtual CBaseEntity* Respawn();
	void Materialize();
	void AttemptToMaterialize();

	// Death.
	void Die( void );
	void SetDieThink( bool bDie );

	// Disguise weapon.
	void DisguiseWeaponThink( void );

	// Ammo.
	virtual const Vector& GetBulletSpread();

	// Hit tracking for achievements
	// Track the number of kills we've had since we missed. Only works for bullet firing weapons right now.
	virtual void	OnBulletFire( int iEnemyPlayersHit );
	virtual void	OnPlayerKill( CTFPlayer *pVictim, const CTakeDamageInfo &info );
	virtual float	GetLastHitTime( void ) { return m_flLastHitTime; }

	virtual int		GetDropSkinOverride( void ) { return -1; }

	int				GetKillStreak () const { return m_iKillStreak; }
	void			SetKillStreak ( int value ) { m_iKillStreak = value; };

	float			GetClipScale () const { return m_flClipScale; }
	void			SetClipScale ( float flScale ) { m_flClipScale = flScale; }
// Client specific.
#else

	bool			IsFirstPersonView();
	bool			UsingViewModel();
	C_BaseAnimating *GetAppropriateWorldOrViewModel();

	virtual bool	ShouldDraw( void ) OVERRIDE;
	virtual void	UpdateVisibility( void ) OVERRIDE;

	virtual void	ProcessMuzzleFlashEvent( void );
	virtual void	DispatchMuzzleFlash( const char* effectName, C_BaseEntity* pAttachEnt );
	virtual int		InternalDrawModel( int flags );

	virtual bool	ShouldPredict();
	virtual void	PostDataUpdate( DataUpdateType_t updateType );
	virtual void	OnDataChanged( DataUpdateType_t type );
	virtual void	OnPreDataChanged( DataUpdateType_t updateType );
	virtual int		GetWorldModelIndex( void );
	virtual bool	ShouldDrawCrosshair( void );
	virtual void	Redraw( void );
	virtual void	FireGameEvent( IGameEvent *event );

	virtual void	AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles );
	virtual	float	CalcViewmodelBob( void );
	BobState_t		*GetBobState();
	virtual bool	AttachmentModelsShouldBeVisible( void ) OVERRIDE { return (m_iState == WEAPON_IS_ACTIVE) && !IsBeingRepurposedForTaunt(); }

	virtual bool ShouldEjectBrass() { return true; }

	bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );

	// ItemEffect Hud defaults
	virtual const char * GetEffectLabelText()	{ return ""; }
	virtual float GetProgress()					{ return 0; }

	// Model muzzleflashes
	CHandle<C_MuzzleFlashModel>		m_hMuzzleFlashModel[2];

	bool			IsUsingOverrideModel() const { return m_iWorldModelIndex != m_iCachedModelIndex; }

#endif

	virtual int		GetSkin();

	static void UpdateWeaponBodyGroups( CTFPlayer* pPlayer, bool bHandleDeployedBodygroups );
	void SetIsBeingRepurposedForTaunt( bool bCanOverride )	{ m_bBeingRepurposedForTaunt = bCanOverride; }
	bool IsBeingRepurposedForTaunt() const { return m_bBeingRepurposedForTaunt; }

	int GetKillComboClass( void ) const { return m_nKillComboClass; }
	int GetKillComboCount( void ) const { return m_nKillComboCount; }
	void ClearKillComboCount( void ) { m_nKillComboCount = 0; }
	void AddKillCombo( int nClassKilled )
	{
		if ( m_nKillComboClass != nClassKilled )
		{
			m_nKillComboClass = nClassKilled;
			ClearKillComboCount();
		}

		m_nKillComboCount = Min( 3, m_nKillComboCount + 1 );
	}

	// Effect / Regeneration bar handling
	virtual float	GetEffectBarProgress( void );			// Get the current bar state (will return a value from 0.0 to 1.0)
	bool			HasEffectBarRegeneration( void ) { return InternalGetEffectBarRechargeTime() > 0; }	// Check the base, not modified by attribute, because attrib may have reduced it to 0.
	float			GetEffectBarRechargeTime( void ) { float flTime = InternalGetEffectBarRechargeTime(); CALL_ATTRIB_HOOK_FLOAT( flTime, effectbar_recharge_rate ); return flTime; }
	void			DecrementBarRegenTime( float flTime ) { m_flEffectBarRegenTime -= flTime; }

	bool			IsHonorBound( void ) const;

	virtual bool	CanPickupOtherWeapon() const { return true; }

	EWeaponStrangeType_t	GetStrangeType();
	bool					BHasStatTrakModule();
#ifdef CLIENT_DLL
	// StatTrak View Model Test
	void					UpdateAllViewmodelAddons( void );

	void					AddStatTrakModel( CEconItemView *pItem, int nStatTrakType, AccountID_t holderAcctId );
	void					RemoveViewmodelStatTrak( void );
	void					RemoveWorldmodelStatTrak( void );

	CHandle< CTFWeaponAttachmentModel > m_viewmodelStatTrakAddon;
	CHandle< CTFWeaponAttachmentModel > m_worldmodelStatTrakAddon;

	virtual const Vector&	GetViewmodelOffset() OVERRIDE;
#endif

	virtual bool ShouldRemoveInvisibilityOnPrimaryAttack() const { return true; }

protected:
	virtual int		GetEffectBarAmmo( void ) { return m_iPrimaryAmmoType; }
	virtual float	InternalGetEffectBarRechargeTime( void ) { return 0; }	// Time it takes for this regeneration bar to fully recharge from 0 to full.

	void			StartEffectBarRegen( void );						// Call this when you want your bar to start recharging (usually when you've deployed your action)
	void			EffectBarRegenFinished( void );
	void			CheckEffectBarRegen( void );

private:
	CNetworkVar(	float, m_flEffectBarRegenTime );	// The time Regen is scheduled to complete

protected:
#ifdef CLIENT_DLL
	virtual void CreateMuzzleFlashEffects( C_BaseEntity *pAttachEnt, int nIndex );

	virtual void UpdateExtraWearablesVisibility();
#endif // CLIENT_DLL

	// Reloads.
	void UpdateReloadTimers( bool bStart );
	void SetReloadTimer( float flReloadTime );
	bool ReloadSingly( void );
	void ReloadSinglyPostFrame( void );
	void IncrementAmmo( void );

	bool NeedsReloadForAmmo1( int iClipSize1 ) const;
	bool NeedsReloadForAmmo2( int iClipSize2 ) const;

protected:

	void			PlayUpgradedShootSound( const char *pszSound );

	int				m_iWeaponMode;
	CNetworkVar(	int,	m_iReloadMode );
	CNetworkVar( float, m_flReloadPriorNextFire );
	CTFWeaponInfo	*m_pWeaponInfo;
	bool			m_bInAttack;
	bool			m_bInAttack2;
	bool			m_bCurrentAttackIsCrit;
	bool			m_bCurrentCritIsRandom;
	bool			m_bCurrentAttackIsDuringDemoCharge;

	EWeaponStrangeType_t			m_eStrangeType;
	EWeaponStatTrakModuleType_t		m_eStatTrakModuleType;

	CNetworkVar(	bool,	m_bLowered );

	int				m_iAltFireHint;

	int				m_iReloadStartClipAmount;

	float			m_flCritTime;
	CNetworkVar( float, m_flLastCritCheckTime );	// Deprecated
	int				m_iLastCritCheckFrame;
	int				m_iCurrentSeed;
	float			m_flLastRapidFireCritCheckTime;

	float			m_flLastDeployTime;

	char			m_szTracerName[MAX_TRACER_NAME];

	CNetworkVar(	bool, m_bResetParity );

	int				m_iAmmoToAdd;
	float			m_flLastPrimaryAttackTime;

#ifdef GAME_DLL
	// Stores the number of kills we've made since we last shot & didn't hit a player.
	// Only hooked up to bullet firing right now, so you'll need to do plumbing if you want it for other weaponry.
	int				m_iConsecutiveKills;

	// Accuracy tracking
	float			m_flLastHitTime;
	int				m_iHitsInTime;
	int				m_iFiredInTime;

	// Used to generate active-weapon-only regen
	float			m_flRegenTime;

	// for penetrating weapons with drain - only drain each victim once
	CHandle< CTFPlayer > m_hLastDrainVictim;
	CountdownTimer m_lastDrainVictimTimer;

	int				m_iKillStreak;
	float			m_flClipScale;
#endif

#ifdef CLIENT_DLL
	bool m_bOldResetParity;
	int m_iCachedModelIndex;
	int m_iEjectBrassAttachpoint;

#endif

	CNetworkVar(	bool,	m_bReloadedThroughAnimEvent );

	CNetworkVar( float, m_flEnergy );

public:
	CNetworkVar(	bool, m_bDisguiseWeapon );

	CNetworkVar(	float, m_flLastFireTime );

	CNetworkHandle( CTFWearable, m_hExtraWearable );
	CNetworkHandle( CTFWearable, m_hExtraWearableViewModel );

	CNetworkVar( float, m_flObservedCritChance );

	virtual bool CanInspect() const;
	void HandleInspect();

	enum TFWeaponInspectStage
	{
		INSPECT_INVALID = -1,
		INSPECT_START,
		INSPECT_IDLE,
		INSPECT_END,

		INSPECT_STAGE_COUNT
	};
	TFWeaponInspectStage GetInspectStage() const { return (TFWeaponInspectStage)m_nInspectStage.Get(); }
	float GetInspectAnimTime() const { return m_flInspectAnimTime; }

private:
	CTFWeaponBase( const CTFWeaponBase & );

	CNetworkVar( bool, m_bBeingRepurposedForTaunt );

	CNetworkVar( int,	m_nKillComboClass );
	CNetworkVar( int,	m_nKillComboCount );
	
	int GetInspectActivity( TFWeaponInspectStage inspectStage );
	bool IsInspectActivity( int iActivity );
	CNetworkVar( float, m_flInspectAnimTime );
	CNetworkVar( int, m_nInspectStage );
	bool m_bInspecting;

	friend class CTFDroppedWeapon;

#ifdef CLIENT_DLL
	bool m_bInitViewmodelOffset;
	Vector m_vecViewmodelOffset;
#endif // CLIENT_DLL
};

bool WeaponID_IsSniperRifle( int iWeaponID );
bool WeaponID_IsSniperRifleOrBow( int iWeaponID );

#define WEAPON_RANDOM_RANGE 10000

#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// CTFWeaponAttachmentModel 
//-----------------------------------------------------------------------------
class CTFWeaponAttachmentModel : public CBaseAnimating, public IHasOwner
{
	DECLARE_CLASS( CTFWeaponAttachmentModel, CBaseAnimating );
public:
	CTFWeaponAttachmentModel() { m_bIsViewModelAttachment = false; m_hWeaponAssociatedWith = NULL; }

	virtual bool ShouldDraw( void );
	
	void				Init( CBaseEntity *pParent, CTFWeaponBase *pAssociatedWeapon, bool bIsViewModel );
	void				SetWeaponAssociatedWith( CTFWeaponBase *pWeapon ) { m_hWeaponAssociatedWith = pWeapon; }
	CBaseEntity*		GetWeaponAssociatedWith( void ) const { return m_hWeaponAssociatedWith.Get(); }

	bool BIsViewModelAttachment() { return m_bIsViewModelAttachment; }
	
	virtual CBaseEntity	*GetOwnerViaInterface( void ) OVERRIDE { return m_hWeaponAssociatedWith.Get() ? m_hWeaponAssociatedWith.Get()->GetOwner() : NULL; }
private:

	bool m_bIsViewModelAttachment;
	CHandle< CTFWeaponBase > m_hWeaponAssociatedWith;
};
#endif // CLIENT_DLL

#endif // TF_WEAPONBASE_H