//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:		Player for HL1.
//
// $NoKeywords: $
//=============================================================================//

#ifndef CS_PLAYER_H
#define CS_PLAYER_H
#pragma once


#include "basemultiplayerplayer.h"
#include "server_class.h"
#include "cs_playeranimstate.h"
#include "cs_shareddefs.h"
#include "cs_autobuy.h"
#include "utldict.h"



class CWeaponCSBase;
class CMenu;
class CHintMessageQueue;
class CNavArea;

#include "cs_weapon_parse.h"


void UTIL_AwardMoneyToTeam( int iAmount, int iTeam, CBaseEntity *pIgnore );

#define MENU_STRING_BUFFER_SIZE	1024
#define MENU_MSG_TEXTCHUNK_SIZE	50

enum
{
	MIN_NAME_CHANGE_INTERVAL = 10,			// minimum number of seconds between name changes
	NAME_CHANGE_HISTORY_SIZE = 5,			// number of times a player can change names in NAME_CHANGE_HISTORY_INTERVAL
	NAME_CHANGE_HISTORY_INTERVAL = 600,	// no more than NAME_CHANGE_HISTORY_SIZE name changes can be made in this many seconds
};

extern ConVar bot_mimic;


// Function table for each player state.
class CCSPlayerStateInfo
{
public:
	CSPlayerState m_iPlayerState;
	const char *m_pStateName;
	
	void (CCSPlayer::*pfnEnterState)();	// Init and deinit the state.
	void (CCSPlayer::*pfnLeaveState)();

	void (CCSPlayer::*pfnPreThink)();	// Do a PreThink() in this state.
};


//=======================================
//Record of either damage taken or given.
//Contains the player name that we hurt or that hurt us,
//and the total damage
//=======================================
class CDamageRecord
{
public:
	CDamageRecord( const char *name, int iDamage, int iCounter )
	{
		Q_strncpy( m_szPlayerName, name, sizeof(m_szPlayerName) );
		m_iDamage = iDamage;
		m_iNumHits = 1;
		m_iLastBulletUpdate = iCounter;
	}

	void AddDamage( int iDamage, int iCounter )
	{
		m_iDamage += iDamage;

		if ( m_iLastBulletUpdate != iCounter )
			m_iNumHits++;

		m_iLastBulletUpdate = iCounter;
	}

	char *GetPlayerName( void ) { return m_szPlayerName; }
	int GetDamage( void ) { return m_iDamage; }
	int GetNumHits( void ) { return m_iNumHits; }

private:
	char m_szPlayerName[MAX_PLAYER_NAME_LENGTH];
	int m_iDamage;		//how much damage was done
	int m_iNumHits;		//how many hits
	int	m_iLastBulletUpdate; // update counter
};

// Message display history (CCSPlayer::m_iDisplayHistoryBits)
// These bits are set when hint messages are displayed, and cleared at
// different times, according to the DHM_xxx bitmasks that follow

#define DHF_ROUND_STARTED		( 1 << 1 )
#define DHF_HOSTAGE_SEEN_FAR	( 1 << 2 )
#define DHF_HOSTAGE_SEEN_NEAR	( 1 << 3 )
#define DHF_HOSTAGE_USED		( 1 << 4 )
#define DHF_HOSTAGE_INJURED		( 1 << 5 )
#define DHF_HOSTAGE_KILLED		( 1 << 6 )
#define DHF_FRIEND_SEEN			( 1 << 7 )
#define DHF_ENEMY_SEEN			( 1 << 8 )
#define DHF_FRIEND_INJURED		( 1 << 9 )
#define DHF_FRIEND_KILLED		( 1 << 10 )
#define DHF_ENEMY_KILLED		( 1 << 11 )
#define DHF_BOMB_RETRIEVED		( 1 << 12 )
#define DHF_AMMO_EXHAUSTED		( 1 << 15 )
#define DHF_IN_TARGET_ZONE		( 1 << 16 )
#define DHF_IN_RESCUE_ZONE		( 1 << 17 )
#define DHF_IN_ESCAPE_ZONE		( 1 << 18 ) // unimplemented
#define DHF_IN_VIPSAFETY_ZONE	( 1 << 19 ) // unimplemented
#define	DHF_NIGHTVISION			( 1 << 20 )
#define	DHF_HOSTAGE_CTMOVE		( 1 << 21 )
#define	DHF_SPEC_DUCK			( 1 << 22 )

// DHF_xxx bits to clear when the round restarts

#define DHM_ROUND_CLEAR ( \
	DHF_ROUND_STARTED | \
	DHF_HOSTAGE_KILLED | \
	DHF_FRIEND_KILLED | \
	DHF_BOMB_RETRIEVED )


// DHF_xxx bits to clear when the player is restored

#define DHM_CONNECT_CLEAR ( \
	DHF_HOSTAGE_SEEN_FAR | \
	DHF_HOSTAGE_SEEN_NEAR | \
	DHF_HOSTAGE_USED | \
	DHF_HOSTAGE_INJURED | \
	DHF_FRIEND_SEEN | \
	DHF_ENEMY_SEEN | \
	DHF_FRIEND_INJURED | \
	DHF_ENEMY_KILLED | \
	DHF_AMMO_EXHAUSTED | \
	DHF_IN_TARGET_ZONE | \
	DHF_IN_RESCUE_ZONE | \
	DHF_IN_ESCAPE_ZONE | \
	DHF_IN_VIPSAFETY_ZONE | \
	DHF_HOSTAGE_CTMOVE | \
	DHF_SPEC_DUCK )

// radio messages (these must be kept in sync with actual radio) -------------------------------------
enum RadioType
{
	RADIO_INVALID = 0,

	RADIO_START_1,							///< radio messages between this and RADIO_START_2 and part of Radio1()

	RADIO_COVER_ME,
	RADIO_YOU_TAKE_THE_POINT,
	RADIO_HOLD_THIS_POSITION,
	RADIO_REGROUP_TEAM,
	RADIO_FOLLOW_ME,
	RADIO_TAKING_FIRE,

	RADIO_START_2,							///< radio messages between this and RADIO_START_3 are part of Radio2()

	RADIO_GO_GO_GO,
	RADIO_TEAM_FALL_BACK,
	RADIO_STICK_TOGETHER_TEAM,
	RADIO_GET_IN_POSITION_AND_WAIT,
	RADIO_STORM_THE_FRONT,
	RADIO_REPORT_IN_TEAM,

	RADIO_START_3,							///< radio messages above this are part of Radio3()

	RADIO_AFFIRMATIVE,
	RADIO_ENEMY_SPOTTED,
	RADIO_NEED_BACKUP,
	RADIO_SECTOR_CLEAR,
	RADIO_IN_POSITION,
	RADIO_REPORTING_IN,
	RADIO_GET_OUT_OF_THERE,
	RADIO_NEGATIVE,
	RADIO_ENEMY_DOWN,

	RADIO_END,

	RADIO_NUM_EVENTS
};

extern const char *RadioEventName[ RADIO_NUM_EVENTS+1 ];

/**
 * Convert name to RadioType
 */
extern RadioType NameToRadioEvent( const char *name );

enum BuyResult_e
{
	BUY_BOUGHT,
	BUY_ALREADY_HAVE,
	BUY_CANT_AFFORD,
	BUY_PLAYER_CANT_BUY,	// not in the buy zone, is the VIP, is past the timelimit, etc
	BUY_NOT_ALLOWED,		// weapon is restricted by VIP mode, team, etc
	BUY_INVALID_ITEM,
};

//=============================================================================
// HPE_BEGIN:
//=============================================================================

// [tj] The phases for the "Goose Chase" achievement
enum GooseChaseAchievementStep
{
    GC_NONE,    
    GC_SHOT_DURING_DEFUSE,
    GC_STOPPED_AFTER_GETTING_SHOT
};

// [tj] The phases for the "Defuse Defense" achievement
enum DefuseDefenseAchivementStep
{
    DD_NONE,
    DD_STARTED_DEFUSE,
    DD_KILLED_TERRORIST       
};
 
//=============================================================================
// HPE_END
//=============================================================================


//=============================================================================
// >> CounterStrike player
//=============================================================================
class CCSPlayer : public CBaseMultiplayerPlayer, public ICSPlayerAnimStateHelpers
{
public:
	DECLARE_CLASS( CCSPlayer, CBaseMultiplayerPlayer );
	DECLARE_SERVERCLASS();
	DECLARE_PREDICTABLE();
	DECLARE_DATADESC();

	CCSPlayer();
	~CCSPlayer();

	static CCSPlayer *CreatePlayer( const char *className, edict_t *ed );
	static CCSPlayer* Instance( int iEnt );

	virtual const QAngle& GetRenderAngles( void );

	virtual void		Precache();
	virtual void		Spawn();
	virtual void		InitialSpawn( void );
	
	virtual void		CheatImpulseCommands( int iImpulse );
	virtual void		PlayerRunCommand( CUserCmd *ucmd, IMoveHelper *moveHelper );
	virtual void		PostThink();

	virtual int			OnTakeDamage( const CTakeDamageInfo &inputInfo );
	virtual int			OnTakeDamage_Alive( const CTakeDamageInfo &info );

	virtual void		Event_Killed( const CTakeDamageInfo &info );

	//=============================================================================
	// HPE_BEGIN:
	// [tj] We have a custom implementation so we can check for achievements.
	//=============================================================================
	
	virtual void		Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info );

	//=============================================================================
	// HPE_END
	//=============================================================================

	virtual void		TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );

	virtual CBaseEntity	*GiveNamedItem( const char *pszName, int iSubType = 0 );
	virtual bool		IsBeingGivenItem() const { return m_bIsBeingGivenItem; }
	
	virtual CBaseEntity *FindUseEntity( void );
	virtual bool		IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps );
	
	virtual void		CreateViewModel( int viewmodelindex = 0 );
	virtual void		ShowViewPortPanel( const char * name, bool bShow = true, KeyValues *data = NULL );

	// This passes the event to the client's and server's CPlayerAnimState.
	void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 );

	// from CBasePlayer
	virtual void		SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize );

	virtual int 		GetNextObserverSearchStartPoint( bool bReverse );

// In shared code.
public:

	// ICSPlayerAnimState overrides.
	virtual CWeaponCSBase* CSAnim_GetActiveWeapon();
	virtual bool CSAnim_CanMove();

    virtual float GetPlayerMaxSpeed();

    void FireBullet(
		int iBullet,
		Vector vecSrc, 
		const QAngle &shootAngles, 
		float flDistance, 
		int iPenetration, 
		int iBulletType, 
		int iDamage, 
		float flRangeModifier, 
		CBaseEntity *pevAttacker,
		bool bDoEffects,
		float xSpread, float ySpread );

	void KickBack(
		float up_base,
		float lateral_base,
		float up_modifier,
		float lateral_modifier,
		float up_max,
		float lateral_max,
		int direction_change );

    float GetBulletDiameter(int iBulletType);
	void GetBulletTypeParameters( 
		int iBulletType, 
		float &fPenetrationPower, 
		float &flPenetrationDistance,
		float &flBulletDiameter );

	// Returns true if the player is allowed to move.
	bool CanMove() const;

	void OnJump( float fImpulse );
	void OnLand( float fVelocity );

	bool HasC4() const;	// Is this player carrying a C4 bomb?
	bool IsVIP() const;

	int GetClass( void ) const;

	void MakeVIP( bool isVIP );

	virtual void SetAnimation( PLAYER_ANIM playerAnim );
	ICSPlayerAnimState *GetPlayerAnimState() { return m_PlayerAnimState; }

	virtual bool StartReplayMode( float fDelay, float fDuration, int iEntity );
	virtual void StopReplayMode();
	virtual void PlayUseDenySound();


public:

	// Simulates a single frame of movement for a player
	void RunPlayerMove( const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime );
	virtual void HandleAnimEvent( animevent_t *pEvent );

	virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity  );
	virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
	
	// from cbasecombatcharacter
	void InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity );
	void VPhysicsShadowUpdate( IPhysicsObject *pPhysics );
	
	bool HasShield() const;
	bool IsShieldDrawn() const;
	void GiveShield( void );
	void RemoveShield( void );
	bool IsProtectedByShield( void ) const;		// returns true if player has a shield and is currently hidden behind it

	bool HasPrimaryWeapon( void );
	bool HasSecondaryWeapon( void );

	bool IsReloading( void ) const;				// returns true if current weapon is reloading

	void GiveDefaultItems();
	void RemoveAllItems( bool removeSuit );	//overridden to remove the defuser

	// Reset account, get rid of shield, etc..
	void Reset();

	void RoundRespawn( void );
	void ObserverRoundRespawn( void );
	void CheckTKPunishment( void );

	// Add money to this player's account.
	void AddAccount( int amount, bool bTrackChange=true, bool bItemBought=false, const char *pItemName = NULL );

	void HintMessage( const char *pMessage, bool bDisplayIfDead, bool bOverrideClientSettings = false ); // Displays a hint message to the player
	CHintMessageQueue *m_pHintMessageQueue;
	unsigned int m_iDisplayHistoryBits;
	bool m_bShowHints;
	float m_flLastAttackedTeammate;
	float m_flNextMouseoverUpdate;
	void UpdateMouseoverHints();

	// mark this player as not receiving money at the start of the next round.
	void MarkAsNotReceivingMoneyNextRound();
	bool DoesPlayerGetRoundStartMoney(); // self-explanitory :)

	void DropC4();	// Get rid of the C4 bomb.
	
	bool HasDefuser();		// Is this player carrying a bomb defuser?
	void GiveDefuser(bool bPickedUp = false);		// give the player a defuser
	void RemoveDefuser();	// remove defuser from the player and remove the model attachment

    //=============================================================================
    // HPE_BEGIN:
    // [dwenger] Added for fun-fact support
    //=============================================================================

    bool PickedUpDefuser() { return m_bPickedUpDefuser; }
    void SetDefusedWithPickedUpKit(bool bDefusedWithPickedUpKit) { m_bDefusedWithPickedUpKit = bDefusedWithPickedUpKit; }
    bool GetDefusedWithPickedUpKit() { return m_bDefusedWithPickedUpKit; }

    //=============================================================================
    // HPE_END
    //=============================================================================


	//=============================================================================
	// HPE_BEGIN
	// [sbodenbender] Need a different test for player blindness for the achievements
	//=============================================================================

	bool IsBlindForAchievement();	// more stringent than IsBlind; more accurately represents when the player can see again

	//=============================================================================
	// HPE_END
	//=============================================================================

	bool IsBlind( void ) const;		// return true if this player is blind (from a flashbang)
	virtual void Blind( float holdTime, float fadeTime, float startingAlpha = 255 );	// player blinded by a flashbang
	float m_blindUntilTime;
	float m_blindStartTime;

	void Deafen( float flDistance );		//make the player deaf / apply dsp preset to muffle sound

	void ApplyDeafnessEffect();				// apply the deafness effect for a nearby explosion.

	bool IsAutoFollowAllowed( void ) const;		// return true if this player will allow bots to auto follow
	void InhibitAutoFollow( float duration );	// prevent bots from auto-following for given duration
	void AllowAutoFollow( void );				// allow bots to auto-follow immediately
	float m_allowAutoFollowTime;				// bots can auto-follow after this time

	// Have this guy speak a message into his radio.
	void Radio( const char *szRadioSound, const char *szRadioText = NULL );
	void ConstructRadioFilter( CRecipientFilter& filter );

	void EmitPrivateSound( const char *soundName );		///< emit given sound that only we can hear

	CWeaponCSBase* GetActiveCSWeapon() const;

	void PreThink();

	// This is the think function for the player when they first join the server and have to select a team
	void JoiningThink();

	virtual bool ClientCommand( const CCommand &args );

	bool HandleCommand_JoinClass( int iClass );
	bool HandleCommand_JoinTeam( int iTeam );

	BuyResult_e HandleCommand_Buy( const char *item );

    BuyResult_e HandleCommand_Buy_Internal( const char * item );

	void HandleMenu_Radio1( int slot );
	void HandleMenu_Radio2( int slot );
	void HandleMenu_Radio3( int slot );

	float m_flRadioTime;	
	int m_iRadioMessages;
	int iRadioMenu;

	void ListPlayers();

	bool m_bIgnoreRadio;

	// Returns one of the CS_CLASS_ enums.
	int PlayerClass() const;

	void MoveToNextIntroCamera();

	// Used to be GETINTOGAME state.
	void GetIntoGame();

	CBaseEntity* EntSelectSpawnPoint();
	
	void SetProgressBarTime( int barTime );
	virtual void PlayerDeathThink();

	void Weapon_Equip( CBaseCombatWeapon *pWeapon );
	virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon );
	virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon );

	void ClearFlashbangScreenFade ( void );
	bool ShouldDoLargeFlinch( int nHitGroup, CBaseEntity *pAttacker );

	void ResetStamina( void );
	bool IsArmored( int nHitGroup );
	void Pain( bool HasArmour );
	
	void DeathSound( const CTakeDamageInfo &info );
	
	bool Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon );

	void ChangeTeam( int iTeamNum );
	void SwitchTeam( int iTeamNum );	// Changes teams without penalty - used for auto team balancing

	void ModifyOrAppendPlayerCriteria( AI_CriteriaSet& set );

	virtual void OnDamagedByExplosion( const CTakeDamageInfo &info );

	// Called whenever this player fires a shot.
	void NoteWeaponFired();
	virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits );

// ------------------------------------------------------------------------------------------------ //
// Player state management.
// ------------------------------------------------------------------------------------------------ //
public:

	void State_Transition( CSPlayerState newState );	// Cleanup the previous state and enter a new state.
	CSPlayerState State_Get() const;				// Get the current state.


private:
	void State_Enter( CSPlayerState newState );		// Initialize the new state.
	void State_Leave();								// Cleanup the previous state.
	void State_PreThink();							// Update the current state.
	
	// Find the state info for the specified state.
	static CCSPlayerStateInfo* State_LookupInfo( CSPlayerState state );

	// This tells us which state the player is currently in (joining, observer, dying, etc).
	// Each state has a well-defined set of parameters that go with it (ie: observer is movetype_noclip, nonsolid,
	// invisible, etc).
	CNetworkVar( CSPlayerState, m_iPlayerState );

	CCSPlayerStateInfo *m_pCurStateInfo;			// This can be NULL if no state info is defined for m_iPlayerState.

	// tells us whether or not this player gets money at the start of the next round.
	bool m_receivesMoneyNextRound;


	// Specific state handler functions.
	void State_Enter_WELCOME();
	void State_PreThink_WELCOME();

	void State_Enter_PICKINGTEAM();
	void State_Enter_PICKINGCLASS();

	void State_Enter_ACTIVE();
	void State_PreThink_ACTIVE();

	void State_Enter_OBSERVER_MODE();
	void State_PreThink_OBSERVER_MODE();

	void State_Enter_DEATH_WAIT_FOR_KEY();
	void State_PreThink_DEATH_WAIT_FOR_KEY();

	void State_Enter_DEATH_ANIM();
	void State_PreThink_DEATH_ANIM();

	int FlashlightIsOn( void );
	void FlashlightTurnOn( void );
	void FlashlightTurnOff( void );

	void UpdateAddonBits();
	void UpdateRadar();

public:

	void				SetDeathPose( const int &iDeathPose ) { m_iDeathPose = iDeathPose; }
	void				SetDeathPoseFrame( const int &iDeathPoseFrame ) { m_iDeathFrame = iDeathPoseFrame; }
	
	void				SelectDeathPose( const CTakeDamageInfo &info );

private:
	int	m_iDeathPose;
	int	m_iDeathFrame;

//=============================================================================
// HPE_BEGIN:
// [menglish] Freeze cam function and variable declarations
//=============================================================================
	 
	bool m_bAbortFreezeCam;

protected:
	void AttemptToExitFreezeCam( void );
	 
//=============================================================================
// HPE_END
//=============================================================================

public:

	// Predicted variables.
	CNetworkVar( bool, m_bResumeZoom );
	CNetworkVar( int , m_iLastZoom ); // after firing a shot, set the FOV to 90, and after showing the animation, bring the FOV back to last zoom level.
	CNetworkVar( bool, m_bIsDefusing );			// tracks whether this player is currently defusing a bomb
	int m_LastHitGroup;			// the last body region that took damage
	//=============================================================================
	// HPE_BEGIN:
	// [menglish] Adding two variables, keeping track of damage to the player
	//=============================================================================
	 
	int m_LastHitBox;			// the last body hitbox that took damage
	Vector m_vLastHitLocationObjectSpace; //position where last hit occured in space of the bone associated with the hitbox
	EHANDLE		m_hDroppedEquipment[DROPPED_COUNT];

	// [tj] overriding the base suicides to trash CS specific stuff
	virtual void CommitSuicide( bool bExplode = false, bool bForce = false );
	virtual void CommitSuicide( const Vector &vecForce, bool bExplode = false, bool bForce = false );

    void WieldingKnifeAndKilledByGun( bool bState ) { m_bWieldingKnifeAndKilledByGun = bState; }
    bool WasWieldingKnifeAndKilledByGun() { return m_bWieldingKnifeAndKilledByGun; }

    // [dwenger] adding tracking for weapon used fun fact
    void PlayerUsedFirearm( CBaseCombatWeapon* pBaseWeapon );
    int GetNumFirearmsUsed() { return m_WeaponTypesUsed.Count(); }

	//=============================================================================
	// HPE_END
	//=============================================================================

	CNetworkVar( bool, m_bHasHelmet );				// Does the player have helmet armor
	bool m_bEscaped;			// Has this terrorist escaped yet?

	// Other variables.
	bool m_bIsVIP;				// Are we the VIP?
	int m_iNumSpawns;			// Number of times player has spawned this round
	int m_iOldTeam;				// Keep what team they were last on so we can allow joining spec and switching back to their real team
	bool m_bTeamChanged;		// Just allow one team change per round
	CNetworkVar( int, m_iAccount );	// How much cash this player has.
	int m_iShouldHaveCash;
	
	bool m_bJustKilledTeammate;
	bool m_bPunishedForTK;
	int m_iTeamKills;
	float m_flLastMovement;
	int m_iNextTimeCheck;		// Next time the player can execute a "timeleft" command

	float m_flNameChangeHistory[NAME_CHANGE_HISTORY_SIZE]; // index 0 = most recent change

	bool CanChangeName( void );	// Checks if the player can change his name
	void ChangeName( const char *pszNewName );

	void SetClanTag( const char *pTag );
	const char *GetClanTag( void ) const;


	CNetworkVar( bool, m_bHasDefuser );			    // Does this player have a defuser kit?
	CNetworkVar( bool, m_bHasNightVision );		    // Does this player have night vision?
	CNetworkVar( bool, m_bNightVisionOn );		    // Is the NightVision turned on ?

    //=============================================================================
    // HPE_BEGIN:
    // [dwenger] Added for fun-fact support
    //=============================================================================

    //CNetworkVar( bool, m_bPickedUpDefuser );        // Did player pick up the defuser kit as opposed to buying it?
    //CNetworkVar( bool, m_bDefusedWithPickedUpKit);  // Did player defuse the bomb with a picked-up defuse kit?

    //=============================================================================
    // HPE_END
    //=============================================================================

	float m_flLastRadarUpdateTime;

	// last known navigation area of player - NULL if unknown
	CNavArea *m_lastNavArea;

	// Backup copy of the menu text so the player can change this and the menu knows when to update.
	char	m_MenuStringBuffer[MENU_STRING_BUFFER_SIZE];

	// When the player joins, it cycles their view between trigger_camera entities.
	// This is the current camera, and the time that we'll switch to the next one.
	EHANDLE m_pIntroCamera;
	float m_fIntroCamTime;

	// Set to true each frame while in a bomb zone.
	// Reset after prediction (in PostThink).
	CNetworkVar( bool, m_bInBombZone );
	CNetworkVar( bool, m_bInBuyZone );
	int m_iBombSiteIndex;

	bool IsInBuyZone();
	bool CanPlayerBuy( bool display );

	CNetworkVar( bool, m_bInHostageRescueZone );
	void RescueZoneTouch( inputdata_t &inputdata );

	CNetworkVar( float, m_flStamina );
	CNetworkVar( int, m_iDirection );	// The current lateral kicking direction; 1 = right,  0 = left
	CNetworkVar( int, m_iShotsFired );	// number of shots fired recently

	// Make sure to register changes for armor.
	IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_ArmorValue );

	CNetworkVar( float, m_flVelocityModifier );

	int	m_iHostagesKilled;

	void SetShieldDrawnState( bool bState );
	void DropShield( void );
	
	char m_szNewName [MAX_PLAYER_NAME_LENGTH]; // not empty if player requested a namechange
	char m_szClanTag[MAX_CLAN_TAG_LENGTH];

	Vector m_vecTotalBulletForce;	//Accumulator for bullet force in a single frame
	
	CNetworkVar( float, m_flFlashDuration );
	CNetworkVar( float, m_flFlashMaxAlpha );
	
	CNetworkVar( float, m_flProgressBarStartTime );
	CNetworkVar( int, m_iProgressBarDuration );
	CNetworkVar( int, m_iThrowGrenadeCounter );	// used to trigger grenade throw animations.
	
	// Tracks our ragdoll entity.
	CNetworkHandle( CBaseEntity, m_hRagdoll );	// networked entity handle 

	// Bots and hostages auto-duck during jumps
	bool m_duckUntilOnGround;

	Vector m_lastStandingPos; // used by the gamemovement code for finding ladders

	void SurpressLadderChecks( const Vector& pos, const Vector& normal );
	bool CanGrabLadder( const Vector& pos, const Vector& normal );

	CNetworkVar( bool, m_bDetected );

private:
	CountdownTimer m_ladderSurpressionTimer;
	Vector m_lastLadderNormal;
	Vector m_lastLadderPos;

protected:

	void CreateRagdollEntity();

	bool IsHittingShield( const Vector &vecDirection, trace_t *ptr );

	void PhysObjectSleep();
	void PhysObjectWake();

	bool RunMimicCommand( CUserCmd& cmd );

	bool SelectSpawnSpot( const char *pEntClassName, CBaseEntity* &pSpot );

	void SetModelFromClass( void );
	CNetworkVar( int, m_iClass ); // One of the CS_CLASS_ enums.

	bool CSWeaponDrop( CBaseCombatWeapon *pWeapon, bool bDropShield = true, bool bThrow = false );
	bool DropRifle( bool fromDeath = false );
	bool DropPistol( bool fromDeath = false );
	
    //=============================================================================
    // HPE_BEGIN:
    // [tj] Added a parameter so we know if it was death that caused the drop
	// [menglish] New parameter to always know if this is from death and not just an enemy death
    //=============================================================================
     
    void DropWeapons( bool fromDeath, bool friendlyFire );
     
    //=============================================================================
    // HPE_END
    //=============================================================================
    

	virtual int SpawnArmorValue( void ) const { return ArmorValue(); }

	BuyResult_e AttemptToBuyAmmo( int iAmmoType );
	BuyResult_e AttemptToBuyAmmoSingle( int iAmmoType );
	BuyResult_e AttemptToBuyVest( void );
	BuyResult_e AttemptToBuyAssaultSuit( void );
	BuyResult_e AttemptToBuyDefuser( void );
	BuyResult_e AttemptToBuyNightVision( void );
	BuyResult_e AttemptToBuyShield( void );
	
	BuyResult_e BuyAmmo( int nSlot, bool bBlinkMoney );
	BuyResult_e BuyGunAmmo( CBaseCombatWeapon *pWeapon, bool bBlinkMoney );

	void PushawayThink();

public:

	ICSPlayerAnimState *m_PlayerAnimState;

	// Aiming heuristics code
	float						m_flIdleTime;		//Amount of time we've been motionless
	float						m_flMoveTime;		//Amount of time we've been in motion
	float						m_flLastDamageTime;	//Last time we took damage
	float						m_flTargetFindTime;

	int							m_lastDamageHealth;		// Last damage given to our health
	int							m_lastDamageArmor;		// Last damage given to our armor

    //=============================================================================
    // HPE_BEGIN:
    // [dwenger] Added for fun-fact support
    //=============================================================================

    bool                        m_bPickedUpDefuser;         // Did player pick up the defuser kit as opposed to buying it?
    bool                        m_bDefusedWithPickedUpKit;  // Did player defuse the bomb with a picked-up defuse kit?

    //=============================================================================
    // HPE_END
    //=============================================================================


	// Last usercmd we shot a bullet on.
	int m_iLastWeaponFireUsercmd;

	// Copyed from EyeAngles() so we can send it to the client.
	CNetworkQAngle( m_angEyeAngles );
	CNetworkQAngle( m_angRenderAngles );

	bool m_bVCollisionInitted;

// AutoBuy functions.
public:
	void			AutoBuy(); // this should take into account what the player can afford and should buy the best equipment for them.

	bool			IsInAutoBuy( void ) { return m_bIsInAutoBuy; }
	bool			IsInReBuy( void ) { return m_bIsInRebuy; }

private:
	bool			ShouldExecuteAutoBuyCommand(const AutoBuyInfoStruct *commandInfo, bool boughtPrimary, bool boughtSecondary);
	void			PostAutoBuyCommandProcessing(const AutoBuyInfoStruct *commandInfo, bool &boughtPrimary, bool &boughtSecondary);
	void			ParseAutoBuyString(const char *string, bool &boughtPrimary, bool &boughtSecondary);
	AutoBuyInfoStruct *GetAutoBuyCommandInfo(const char *command);
	void			PrioritizeAutoBuyString(char *autobuyString, const char *priorityString); // reorders the tokens in autobuyString based on the order of tokens in the priorityString.
	BuyResult_e	CombineBuyResults( BuyResult_e prevResult, BuyResult_e newResult );

	bool			m_bIsInAutoBuy;
	bool			m_bAutoReload;

//ReBuy functions

public:
	void			Rebuy();
private:
	void			BuildRebuyStruct();

	BuyResult_e	RebuyPrimaryWeapon();
	BuyResult_e	RebuyPrimaryAmmo();
	BuyResult_e	RebuySecondaryWeapon();
	BuyResult_e	RebuySecondaryAmmo();
	BuyResult_e	RebuyHEGrenade();
	BuyResult_e	RebuyFlashbang();
	BuyResult_e	RebuySmokeGrenade();
	BuyResult_e	RebuyDefuser();
	BuyResult_e	RebuyNightVision();
	BuyResult_e	RebuyArmor();

	bool			m_bIsInRebuy;
	RebuyStruct		m_rebuyStruct;
	bool			m_bUsingDefaultPistol;

	bool			m_bIsBeingGivenItem;

#ifdef CS_SHIELD_ENABLED
	CNetworkVar( bool, m_bHasShield );
	CNetworkVar( bool, m_bShieldDrawn );
#endif
	
	// This is a combination of the ADDON_ flags in cs_shareddefs.h.
	CNetworkVar( int, m_iAddonBits );

	// Clients don't know about holstered weapons, so we need to tell them the weapon type here
	CNetworkVar( int, m_iPrimaryAddon );
	CNetworkVar( int, m_iSecondaryAddon );

//Damage record functions
public:

	static void	StartNewBulletGroup();	// global function

	void RecordDamageTaken( const char *szDamageDealer, int iDamageTaken );
	void RecordDamageGiven( const char *szDamageTaker, int iDamageGiven );

	void ResetDamageCounters();	//Reset all lists

	void OutputDamageTaken( void );
	void OutputDamageGiven( void );

	void StockPlayerAmmo( CBaseCombatWeapon *pNewWeapon = NULL );

	CUtlLinkedList< CDamageRecord *, int >& GetDamageGivenList() {return m_DamageGivenList;}
	CUtlLinkedList< CDamageRecord *, int >& GetDamageTakenList() {return m_DamageTakenList;}

private:
	//A list of damage given
	CUtlLinkedList< CDamageRecord *, int >	m_DamageGivenList;

	//A list of damage taken
	CUtlLinkedList< CDamageRecord *, int >	m_DamageTakenList;

protected:
	float m_applyDeafnessTime;
	int m_currentDeafnessFilter;

	bool m_isVIP;

// Command rate limiting.
private:

	bool ShouldRunRateLimitedCommand( const CCommand &args );

	// This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers.
	CUtlDict<float,int>	m_RateLimitLastCommandTimes;

//=============================================================================
// HPE_BEGIN:
// [menglish, tj] Achievement-based addition to CS player class.
//=============================================================================
 
public:
	void ResetRoundBasedAchievementVariables();
	void OnRoundEnd(int winningTeam, int reason);
    void OnPreResetRound();

	int GetNumEnemyDamagers();
	int GetNumEnemiesDamaged();
	CBaseEntity* GetNearestSurfaceBelow(float maxTrace);

    // Returns the % of the enemies this player killed in the round
    int GetPercentageOfEnemyTeamKilled();

	//List of times of recent kills to check for sprees
	CUtlVector<float>			m_killTimes; 

    //List of all players killed this round
    CUtlVector<CHandle<CCSPlayer> >      m_enemyPlayersKilledThisRound;

	//List of weapons we have used to kill players with this round
	CUtlVector<int>				m_killWeapons; 

	int m_NumEnemiesKilledThisRound;
	int m_NumEnemiesAtRoundStart;
	int m_KillingSpreeStartTime;

	float m_firstKillBlindStartTime; //This is the start time of the blind effect during which we got our most recent kill.
	int m_killsWhileBlind;
 
    bool m_bIsRescuing;         // tracks whether this player is currently rescuing a hostage
    bool m_bInjuredAHostage;    // tracks whether this player injured a hostage
    int  m_iNumFollowers;       // Number of hostages following this player
	bool m_bSurvivedHeadshotDueToHelmet;

    void IncrementNumFollowers() { m_iNumFollowers++; }
    void DecrementNumFollowers() { m_iNumFollowers--; if (m_iNumFollowers < 0) m_iNumFollowers = 0; }
    int GetNumFollowers() { return m_iNumFollowers; }
    void SetIsRescuing(bool in_bRescuing) { m_bIsRescuing = in_bRescuing; }
    bool IsRescuing() { return m_bIsRescuing; }
    void SetInjuredAHostage(bool in_bInjured) { m_bInjuredAHostage = in_bInjured; }
    bool InjuredAHostage() { return m_bInjuredAHostage; }
    float GetBombPickuptime() { return m_bombPickupTime; }
    void SetBombPickupTime(float time) { m_bombPickupTime = time; }
    CCSPlayer* GetLastFlashbangAttacker() { return m_lastFlashBangAttacker; }
    void SetLastFlashbangAttacker(CCSPlayer* attacker) { m_lastFlashBangAttacker = attacker; }

	static CSWeaponID GetWeaponIdCausingDamange( const CTakeDamageInfo &info );
	static void ProcessPlayerDeathAchievements( CCSPlayer *pAttacker, CCSPlayer *pVictim, const CTakeDamageInfo &info );

    void                        OnCanceledDefuse();
    void                        OnStartedDefuse();
    GooseChaseAchievementStep   m_gooseChaseStep;
    DefuseDefenseAchivementStep m_defuseDefenseStep;
    CHandle<CCSPlayer>          m_pGooseChaseDistractingPlayer;

    int                         m_lastRoundResult; //save the reason for the last round ending.

    bool                        m_bMadeFootstepNoise;

    float                       m_bombPickupTime;

    bool                        m_bMadePurchseThisRound;

    int                         m_roundsWonWithoutPurchase;

	bool						m_bKilledDefuser;
	bool						m_bKilledRescuer;
	int							m_maxGrenadeKills;

	int							m_grenadeDamageTakenThisRound;

	bool						GetKilledDefuser() { return m_bKilledDefuser; } 
	bool						GetKilledRescuer() { return m_bKilledRescuer; } 
	int							GetMaxGrenadeKills() { return m_maxGrenadeKills; }

	void						CheckMaxGrenadeKills(int grenadeKills);

    CHandle<CCSPlayer>                  m_lastFlashBangAttacker;

    void	SetPlayerDominated( CCSPlayer *pPlayer, bool bDominated );    
    void	SetPlayerDominatingMe( CCSPlayer *pPlayer, bool bDominated );
    bool	IsPlayerDominated( int iPlayerIndex );
    bool	IsPlayerDominatingMe( int iPlayerIndex );

	bool	m_wasNotKilledNaturally; //Set if the player is dead from a kill command or late login

	bool	WasNotKilledNaturally() { return m_wasNotKilledNaturally; }

	//=============================================================================
	// [menglish] MVP functions
	//=============================================================================
	 
	void	SetNumMVPs( int iNumMVP );
	void	IncrementNumMVPs( CSMvpReason_t mvpReason );
	int		GetNumMVPs();
	 
	//=============================================================================
	// HPE_END
	//=============================================================================
    void    RemoveNemesisRelationships();
	void	SetDeathFlags( int iDeathFlags ) { m_iDeathFlags = iDeathFlags; }
	int		GetDeathFlags() { return m_iDeathFlags; }

private:
    CNetworkArray( bool, m_bPlayerDominated, MAX_PLAYERS+1 );		// array of state per other player whether player is dominating other players
    CNetworkArray( bool, m_bPlayerDominatingMe, MAX_PLAYERS+1 );	// array of state per other player whether other players are dominating this player

	//=============================================================================
	// HPE_BEGIN:
	//=============================================================================

    // [menglish] number of rounds this player has caused to be won for their team
	int m_iMVPs;

    // [dwenger] adding tracking for fun fact
    bool m_bWieldingKnifeAndKilledByGun;

    // [dwenger] adding tracking for which weapons this player has used in a round
    CUtlVector<CSWeaponID> m_WeaponTypesUsed; 

    //=============================================================================
	// HPE_END
	//=============================================================================
	int m_iDeathFlags; // Flags holding revenge and domination info about a death

	// We really need to keep in sync with the server <=> client.
	struct Events
	{
		PlayerAnimEvent_t m_currentWantedEvent;
		int m_currentnData;
	};

	CUtlVector< Events > m_allEvents;

	//=============================================================================
	// HPE_END
	//=============================================================================
};


inline CSPlayerState CCSPlayer::State_Get() const
{
	return m_iPlayerState;
}

inline CCSPlayer *ToCSPlayer( CBaseEntity *pEntity )
{
	if ( !pEntity || !pEntity->IsPlayer() )
		return NULL;

	return dynamic_cast<CCSPlayer*>( pEntity );
}

inline bool CCSPlayer::IsReloading( void ) const
{
	CBaseCombatWeapon *gun = GetActiveWeapon();
	if (gun == NULL)
		return false;

	return gun->m_bInReload;
}

inline bool CCSPlayer::IsProtectedByShield( void ) const
{ 
	return HasShield() && IsShieldDrawn();
}

inline bool CCSPlayer::IsBlind( void ) const
{ 
	return gpGlobals->curtime < m_blindUntilTime;
}

//=============================================================================
// HPE_BEGIN
// [sbodenbender] Need a different test for player blindness for the achievements
//=============================================================================
inline bool CCSPlayer::IsBlindForAchievement()
{
	return (m_blindStartTime + m_flFlashDuration) > gpGlobals->curtime;
}
//=============================================================================
// HPE_END
//=============================================================================

inline bool CCSPlayer::IsAutoFollowAllowed( void ) const		
{ 
	return (gpGlobals->curtime > m_allowAutoFollowTime); 
}

inline void CCSPlayer::InhibitAutoFollow( float duration )	
{ 
	m_allowAutoFollowTime = gpGlobals->curtime + duration; 
}

inline void CCSPlayer::AllowAutoFollow( void )	
{ 
	m_allowAutoFollowTime = 0.0f; 
}

inline int CCSPlayer::GetClass( void ) const
{
	return m_iClass;
}

inline const char *CCSPlayer::GetClanTag( void ) const
{
	return m_szClanTag;
}

#endif	//CS_PLAYER_H