CBaseCombatCharacter: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
mNo edit summary
No edit summary
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{stub}}
{{stub}}
{{CD|CBaseCombatCharacter|base=CBaseFlex|file1=[https://github.com/ValveSoftware/source-sdk-2013/blob/master/mp/src/game/server/basecombatcharacter.cpp basecombatcharacter.cpp]}}
{{CD|CBaseCombatCharacter|base=CBaseFlex|file1=[https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/server/basecombatcharacter.cpp basecombatcharacter.cpp]}}


<code>CBaseCombatCharacter</code> is the class base used for characters, NPCs and players alike, without AI.
<code>CBaseCombatCharacter</code> is the class base used for characters, NPCs and players alike, without AI.


==Keyvalues==
<!--==Keyvalues==
{{KV BaseCombatCharacter}}
{{KV BaseCombatCharacter}}


==Inputs==
==Inputs==
{{I BaseCombatCharacter}}
{{I BaseCombatCharacter}}-->
 
==Keyfields==
{{DEFINE_KEYFIELD|m_RelationshipString|FIELD_STRING|Relationship|<[[string]]&#124;[[targetname]] or [[classname]]> <[[string]]&#124;disposition> <[[int]]&#124;rank>
:Changes whether this entity likes or dislikes certain other things. Used like the {{ent|ai_relationship}} entity, with this entity as the subject.
:Values for <code>disposition</code> are:
:*<code>D_HT</code>: Hate
:*<code>D_FR</code>: Fear
:*<code>D_LI</code>: Like
:*<code>D_NU</code>: Neutral}}
{{DEFINE_INPUT|m_impactEnergyScale|FIELD_FLOAT|physdamagescale|Scales damage energy when this character is hit by a physics object. With a value of 0 the NPC will take no damage from physics.}}
 
==Inputs==
{{DEFINE_INPUTFUNC|FIELD_VOID|KilledNPC|InputKilledNPC|Tells the entity it killed something. Despite the name, this can include a player. This input will be automatically sent by the victim when they die.}}
 
==Fields==
{{DEFINE_FIELD|m_flNextAttack|FIELD_TIME}}
{{DEFINE_FIELD|m_eHull|FIELD_INTEGER}}
{{DEFINE_FIELD|m_bloodColor|FIELD_INTEGER}}
{{DEFINE_FIELD|m_iDamageCount|FIELD_INTEGER}}
 
{{DEFINE_FIELD|m_flFieldOfView|FIELD_FLOAT}}
{{DEFINE_FIELD|m_HackedGunPos|FIELD_VECTOR}}
 
{{DEFINE_FIELD|m_LastHitGroup|FIELD_INTEGER}}
{{DEFINE_FIELD|m_flDamageAccumulator|FIELD_FLOAT}}
{{DEFINE_FIELD|m_CurrentWeaponProficiency|FIELD_INTEGER}}
 
{{DEFINE_ARRAY|m_iAmmo|FIELD_INTEGER|}}
{{DEFINE_ARRAY|m_hMyWeapons|FIELD_EHANDLE|}}
{{DEFINE_FIELD|m_hActiveWeapon|FIELD_EHANDLE}}
{{DEFINE_FIELD|m_bForceServerRagdoll|FIELD_BOOLEAN}}
{{DEFINE_FIELD|m_bPreventWeaponPickup|FIELD_BOOLEAN}}
 
{{DEFINE_FIELD|m_iPowerups|FIELD_INTEGER|game={{tf2|in}}}}
{{DEFINE_FIELD|m_flFractionalBoost|FIELD_FLOAT|game={{tf2|in}}}}
{{DEFINE_ARRAY|m_flPowerupAttemptTimes|FIELD_TIME|MAX_POWERUPS|game={{tf2|in}}}}
{{DEFINE_ARRAY|m_flPowerupEndTimes|FIELD_TIME|MAX_POWERUPS|game={{tf2|in}}}}
 
<!-- classdefs -->
{{Class def section}}

Latest revision as of 09:37, 18 July 2025

Stub

This article or section is a stub. You can help by expanding it.

C++ Class hierarchy
CBaseCombatCharacter
CBaseFlex
CBaseAnimatingOverlay
CBaseAnimating
CBaseEntity
C++ basecombatcharacter.cpp

CBaseCombatCharacter is the class base used for characters, NPCs and players alike, without AI.


Keyfields

m_RelationshipString <FIELD_STRING> (Relationship)

<string|targetname or classname> <string|disposition> <int|rank>
Changes whether this entity likes or dislikes certain other things. Used like the ai_relationship entity, with this entity as the subject.
Values for disposition are:
  • D_HT: Hate
  • D_FR: Fear
  • D_LI: Like
  • D_NU: Neutral

m_impactEnergyScale <FIELD_FLOAT> (physdamagescale)

Scales damage energy when this character is hit by a physics object. With a value of 0 the NPC will take no damage from physics.

Inputs

KilledNPC <FIELD_VOID> linked function: InputKilledNPC

Tells the entity it killed something. Despite the name, this can include a player. This input will be automatically sent by the victim when they die.

Fields

m_flNextAttack <FIELD_TIME>

m_eHull <FIELD_INTEGER>

m_bloodColor <FIELD_INTEGER>

m_iDamageCount <FIELD_INTEGER>


m_flFieldOfView <FIELD_FLOAT>

m_HackedGunPos <FIELD_VECTOR>


m_LastHitGroup <FIELD_INTEGER>

m_flDamageAccumulator <FIELD_FLOAT>

m_CurrentWeaponProficiency <FIELD_INTEGER>


m_iAmmo[] <FIELD_INTEGER>

m_hMyWeapons[] <FIELD_EHANDLE>

m_hActiveWeapon <FIELD_EHANDLE>

m_bForceServerRagdoll <FIELD_BOOLEAN>

m_bPreventWeaponPickup <FIELD_BOOLEAN>


m_iPowerups (in Team Fortress 2)<FIELD_INTEGER>

m_flFractionalBoost (in Team Fortress 2)<FIELD_FLOAT>

m_flPowerupAttemptTimes[MAX_POWERUPS] (in Team Fortress 2)<FIELD_TIME>

m_flPowerupEndTimes[MAX_POWERUPS] (in Team Fortress 2)<FIELD_TIME>


C++ definitions from Source 2013 Multiplayer Source 2013 Multiplayer [edit]

Serverside

basecombatcharacter.h

//-----------------------------------------------------------------------------
// Purpose: This should contain all of the combat entry points / functionality 
// that are common between NPCs and players
//-----------------------------------------------------------------------------
class CBaseCombatCharacter : public CBaseFlex
{
	DECLARE_CLASS( CBaseCombatCharacter, CBaseFlex );

public:
	CBaseCombatCharacter(void);
	~CBaseCombatCharacter(void);

	DECLARE_SERVERCLASS();
	DECLARE_DATADESC();
	DECLARE_PREDICTABLE();
	DECLARE_ENT_SCRIPTDESC();

public:

	virtual void		Spawn( void );
	virtual void		Precache();

	virtual int			Restore( IRestore &restore );

	virtual const impactdamagetable_t	&GetPhysicsImpactDamageTable( void );

	int					TakeHealth( float flHealth, int bitsDamageType );
	void				CauseDeath( const CTakeDamageInfo &info );

	virtual	bool		FVisible ( CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL ); // true iff the parameter can be seen by me.
	virtual bool		FVisible( const Vector &vecTarget, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL )	{ return BaseClass::FVisible( vecTarget, traceMask, ppBlocker ); }
	static void			ResetVisibilityCache( CBaseCombatCharacter *pBCC = NULL );

#ifdef PORTAL
	virtual	bool		FVisibleThroughPortal( const CProp_Portal *pPortal, CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS, CBaseEntity **ppBlocker = NULL );
#endif

	virtual bool		FInViewCone( CBaseEntity *pEntity );
	virtual bool		FInViewCone( const Vector &vecSpot );

#ifdef PORTAL
	virtual CProp_Portal*	FInViewConeThroughPortal( CBaseEntity *pEntity );
	virtual CProp_Portal*	FInViewConeThroughPortal( const Vector &vecSpot );
#endif

	virtual bool		FInAimCone( CBaseEntity *pEntity );
	virtual bool		FInAimCone( const Vector &vecSpot );
	
	virtual bool		ShouldShootMissTarget( CBaseCombatCharacter *pAttacker );
	virtual CBaseEntity *FindMissTarget( void );

	// Do not call HandleInteraction directly, use DispatchInteraction
	bool				DispatchInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt )	{ return ( interactionType > 0 ) ? HandleInteraction( interactionType, data, sourceEnt ) : false; }
	virtual bool		HandleInteraction( int interactionType, void *data, CBaseCombatCharacter* sourceEnt );

	virtual QAngle		BodyAngles();
	virtual Vector		BodyDirection2D( void );
	virtual Vector		BodyDirection3D( void );
	virtual Vector		HeadDirection2D( void )	{ return BodyDirection2D( ); }; // No head motion so just return body dir
	virtual Vector		HeadDirection3D( void )	{ return BodyDirection2D( ); }; // No head motion so just return body dir
	virtual Vector		EyeDirection2D( void ) 	{ return HeadDirection2D( );  }; // No eye motion so just return head dir
	virtual Vector		EyeDirection3D( void ) 	{ return HeadDirection3D( );  }; // No eye motion so just return head dir

	virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );

	// -----------------------
	// Fog
	// -----------------------
	virtual bool		IsHiddenByFog( const Vector &target ) const;	///< return true if given target cant be seen because of fog
	virtual bool		IsHiddenByFog( CBaseEntity *target ) const;		///< return true if given target cant be seen because of fog
	virtual bool		IsHiddenByFog( float range ) const;				///< return true if given distance is too far to see through the fog
	virtual float		GetFogObscuredRatio( const Vector &target ) const;///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured
	virtual float		GetFogObscuredRatio( CBaseEntity *target ) const;	///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured
	virtual float		GetFogObscuredRatio( float range ) const;		///< return 0-1 ratio where zero is not obscured, and 1 is completely obscured


	// -----------------------
	// Vision
	// -----------------------
	enum FieldOfViewCheckType { USE_FOV, DISREGARD_FOV };

	// Visible starts with line of sight, and adds all the extra game checks like fog, smoke, camo...
	bool IsAbleToSee( const CBaseEntity *entity, FieldOfViewCheckType checkFOV );
	bool IsAbleToSee( CBaseCombatCharacter *pBCC, FieldOfViewCheckType checkFOV );

	virtual bool IsLookingTowards( const CBaseEntity *target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const;	// return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.
	virtual bool IsLookingTowards( const Vector &target, float cosTolerance = BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE ) const;	// return true if our view direction is pointing at the given target, within the cosine of the angular tolerance. LINE OF SIGHT IS NOT CHECKED.

	virtual bool IsInFieldOfView( CBaseEntity *entity ) const;	// Calls IsLookingTowards with the current field of view.  
	virtual bool IsInFieldOfView( const Vector &pos ) const;

	enum LineOfSightCheckType
	{
		IGNORE_NOTHING,
		IGNORE_ACTORS
	};
	virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations
	virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const;

	// -----------------------
	// Ammo
	// -----------------------
	virtual int			GiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound = false );
	int					GiveAmmo( int iCount, const char *szName, bool bSuppressSound = false );
	virtual void		RemoveAmmo( int iCount, int iAmmoIndex );
	virtual void		RemoveAmmo( int iCount, const char *szName );
	void				RemoveAllAmmo( );
	virtual int			GetAmmoCount( int iAmmoIndex ) const;
	int					GetAmmoCount( char *szName ) const;

	virtual Activity	NPC_TranslateActivity( Activity baseAct );

	// -----------------------
	// Weapons
	// -----------------------
	CBaseCombatWeapon*	Weapon_Create( const char *pWeaponName );
	virtual Activity	Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL );
	void				Weapon_SetActivity( Activity newActivity, float duration );
	virtual void		Weapon_FrameUpdate( void );
	virtual void		Weapon_HandleAnimEvent( animevent_t *pEvent );
	CBaseCombatWeapon*	Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const;  // True if already owns a weapon of this class
	virtual bool		Weapon_CanUse( CBaseCombatWeapon *pWeapon );		// True is allowed to use this class of weapon
	virtual void		Weapon_Equip( CBaseCombatWeapon *pWeapon );			// Adds weapon to player
	virtual bool		Weapon_EquipAmmoOnly( CBaseCombatWeapon *pWeapon );	// Adds weapon ammo to player, leaves weapon
	bool				Weapon_Detach( CBaseCombatWeapon *pWeapon );		// Clear any pointers to the weapon.
	virtual void		Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
	virtual	bool		Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0 );		// Switch to given weapon if has ammo (false if failed)
	virtual	Vector		Weapon_ShootPosition( );		// gun position at current position/orientation
	bool				Weapon_IsOnGround( CBaseCombatWeapon *pWeapon );
	CBaseEntity*		Weapon_FindUsable( const Vector &range );			// search for a usable weapon in this range
	virtual	bool		Weapon_CanSwitchTo(CBaseCombatWeapon *pWeapon);
	virtual bool		Weapon_SlotOccupied( CBaseCombatWeapon *pWeapon );
	virtual CBaseCombatWeapon *Weapon_GetSlot( int slot ) const;
	CBaseCombatWeapon	*Weapon_GetWpnForAmmo( int iAmmoIndex );


	// For weapon strip
	void				Weapon_DropAll( bool bDisallowWeaponPickup = false );

	virtual bool			AddPlayerItem( CBaseCombatWeapon *pItem ) { return false; }
	virtual bool			RemovePlayerItem( CBaseCombatWeapon *pItem ) { return false; }

	virtual bool			CanBecomeServerRagdoll( void ) { return true; }

	// -----------------------
	// Damage
	// -----------------------
	// Don't override this for characters, override the per-life-state versions below
	virtual int				OnTakeDamage( const CTakeDamageInfo &info );

	// Override these to control how your character takes damage in different states
	virtual int				OnTakeDamage_Alive( const CTakeDamageInfo &info );
	virtual int				OnTakeDamage_Dying( const CTakeDamageInfo &info );
	virtual int				OnTakeDamage_Dead( const CTakeDamageInfo &info );

	virtual float			GetAliveDuration( void ) const;			// return time we have been alive (only valid when alive)

	virtual void 			OnFriendDamaged( CBaseCombatCharacter *pSquadmate, CBaseEntity *pAttacker ) {}
	virtual void 			NotifyFriendsOfDamage( CBaseEntity *pAttackerEntity ) {}
	virtual bool			HasEverBeenInjured( int team = TEAM_ANY ) const;			// return true if we have ever been injured by a member of the given team
	virtual float			GetTimeSinceLastInjury( int team = TEAM_ANY ) const;		// return time since we were hurt by a member of the given team


	virtual void			OnPlayerKilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) {}

		// utility function to calc damage force
	Vector					CalcDamageForceVector( const CTakeDamageInfo &info );

	virtual int				BloodColor();
	virtual Activity		GetDeathActivity( void );

	virtual bool			CorpseGib( const CTakeDamageInfo &info );
	virtual void			CorpseFade( void );	// Called instead of GibNPC() when gibs are disabled
	virtual bool			HasHumanGibs( void );
	virtual bool			HasAlienGibs( void );
	virtual bool			ShouldGib( const CTakeDamageInfo &info ) { return false; }	// Always ragdoll, unless specified by the leaf class

	float GetDamageAccumulator() { return m_flDamageAccumulator; }
	int	  GetDamageCount( void ) { return m_iDamageCount; }	// # of times NPC has been damaged.  used for tracking 1-shot kills.

	// Character killed (only fired once)
	virtual void			Event_Killed( const CTakeDamageInfo &info );

	// Killed a character
	void InputKilledNPC( inputdata_t &inputdata );
	virtual void OnKilledNPC( CBaseCombatCharacter *pKilled ) {}; 

	// Exactly one of these happens immediately after killed (gibbed may happen later when the corpse gibs)
	// Character gibbed or faded out (violence controls) (only fired once)
	// returns true if gibs were spawned
	virtual bool			Event_Gibbed( const CTakeDamageInfo &info );
	// Character entered the dying state without being gibbed (only fired once)
	virtual void			Event_Dying( const CTakeDamageInfo &info );
	virtual void			Event_Dying();
	// character died and should become a ragdoll now
	// return true if converted to a ragdoll, false to use AI death
	virtual bool			BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector );
	virtual void			FixupBurningServerRagdoll( CBaseEntity *pRagdoll );

	virtual bool			BecomeRagdollBoogie( CBaseEntity *pKiller, const Vector &forceVector, float duration, int flags );

	CBaseEntity				*FindHealthItem( const Vector &vecPosition, const Vector &range );


	virtual CBaseEntity		*CheckTraceHullAttack( float flDist, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float forceScale = 1.0f, bool bDamageAnyNPC = false );
	virtual CBaseEntity		*CheckTraceHullAttack( const Vector &vStart, const Vector &vEnd, const Vector &mins, const Vector &maxs, int iDamage, int iDmgType, float flForceScale = 1.0f, bool bDamageAnyNPC = false );

	virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; }

	// VPHYSICS
	virtual void			VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent );
	virtual void			VPhysicsUpdate( IPhysicsObject *pPhysics );
	float					CalculatePhysicsStressDamage( vphysics_objectstress_t *pStressOut, IPhysicsObject *pPhysics );
	void					ApplyStressDamage( IPhysicsObject *pPhysics, bool bRequireLargeObject );

	virtual void			PushawayTouch( CBaseEntity *pOther ) {}

	void SetImpactEnergyScale( float fScale ) { m_impactEnergyScale = fScale; }

	virtual void			UpdateOnRemove( void );

	virtual Disposition_t	IRelationType( CBaseEntity *pTarget );
	virtual int				IRelationPriority( CBaseEntity *pTarget );

	virtual void			SetLightingOriginRelative( CBaseEntity *pLightingOrigin );

protected:
	Relationship_t			*FindEntityRelationship( CBaseEntity *pTarget );

public:
	
	// Vehicle queries
	virtual bool IsInAVehicle( void ) const { return false; }
	virtual IServerVehicle *GetVehicle( void ) { return NULL; }
	virtual CBaseEntity *GetVehicleEntity( void ) { return NULL; }
	virtual bool ExitVehicle( void ) { return false; }

	// Blood color (see BLOOD_COLOR_* macros in baseentity.h)
	void SetBloodColor( int nBloodColor );

	// Weapons..
	CBaseCombatWeapon*	GetActiveWeapon() const;
	int					WeaponCount() const;
	CBaseCombatWeapon*	GetWeapon( int i ) const;
	bool				RemoveWeapon( CBaseCombatWeapon *pWeapon );
	virtual void		RemoveAllWeapons();
	WeaponProficiency_t GetCurrentWeaponProficiency() { return m_CurrentWeaponProficiency; }
	void				SetCurrentWeaponProficiency( WeaponProficiency_t iProficiency ) { m_CurrentWeaponProficiency = iProficiency; }
	virtual WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon );
	virtual	Vector		GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
	virtual	float		GetSpreadBias(  CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget );
	virtual void		DoMuzzleFlash();

	// Interactions
	static void			InitInteractionSystem();

	// Relationships
	static void			AllocateDefaultRelationships( );
	static void			SetDefaultRelationship( Class_T nClass, Class_T nClassTarget,  Disposition_t nDisposition, int nPriority );
	Disposition_t		GetDefaultRelationshipDisposition( Class_T nClassTarget );
	virtual void		AddEntityRelationship( CBaseEntity *pEntity, Disposition_t nDisposition, int nPriority );
	virtual bool		RemoveEntityRelationship( CBaseEntity *pEntity );
	virtual void		AddClassRelationship( Class_T nClass, Disposition_t nDisposition, int nPriority );

	virtual void		ChangeTeam( int iTeamNum ) OVERRIDE;

	// Nav hull type
	Hull_t	GetHullType() const				{ return m_eHull; }
	void	SetHullType( Hull_t hullType )	{ m_eHull = hullType; }

	// FIXME: The following 3 methods are backdoor hack methods
	
	// This is a sort of hack back-door only used by physgun!
	void SetAmmoCount( int iCount, int iAmmoIndex );

	// This is a hack to blat out the current active weapon...
	// Used by weapon_slam + game_ui
	void SetActiveWeapon( CBaseCombatWeapon *pNewWeapon );
	void ClearActiveWeapon() { SetActiveWeapon( NULL ); }
	virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon ) {}

	// I can't use my current weapon anymore. Switch me to the next best weapon.
	bool SwitchToNextBestWeapon(CBaseCombatWeapon *pCurrent);

	// This is a hack to copy the relationship strings used by monstermaker
	void SetRelationshipString( string_t theString ) { m_RelationshipString = theString; }

	float				GetNextAttack() const { return m_flNextAttack; }
	void				SetNextAttack( float flWait ) { m_flNextAttack = flWait; }

	bool				m_bForceServerRagdoll;

	// Pickup prevention
	bool				IsAllowedToPickupWeapons( void ) { return !m_bPreventWeaponPickup; }
	void				SetPreventWeaponPickup( bool bPrevent ) { m_bPreventWeaponPickup = bPrevent; }
	bool				m_bPreventWeaponPickup;

	virtual CNavArea *GetLastKnownArea( void ) const		{ return m_lastNavArea; }		// return the last nav area the player occupied - NULL if unknown
	HSCRIPT ScriptGetLastKnownArea( void ) const;
	virtual bool IsAreaTraversable( const CNavArea *area ) const;							// return true if we can use the given area 
	virtual void ClearLastKnownArea( void );
	virtual void UpdateLastKnownArea( void );										// invoke this to update our last known nav area (since there is no think method chained to CBaseCombatCharacter)
	virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ) { }	// invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL)
	virtual void OnNavAreaRemoved( CNavArea *removedArea );

	// -----------------------
	// Notification from INextBots.
	// -----------------------
	virtual void		OnPursuedBy( INextBot * RESTRICT pPursuer ){} // called every frame while pursued by a bot in DirectChase.

#ifdef TF_DLL
	virtual HalloweenBossType GetBossType() const { return HALLOWEEN_BOSS_INVALID; }
#endif // TF_DLL

#ifdef GLOWS_ENABLE
	// Glows
	void				AddGlowEffect( void );
	void				RemoveGlowEffect( void );
	bool				IsGlowEffectActive( void );
#endif // GLOWS_ENABLE

#ifdef INVASION_DLL
public:


	// TF2 Powerups
	virtual bool		CanBePoweredUp( void );
	bool				HasPowerup( int iPowerup );
	virtual	bool		CanPowerupNow( int iPowerup );		// Return true if I can be powered by this powerup right now
	virtual	bool		CanPowerupEver( int iPowerup );		// Return true if I ever accept this powerup type

	void				SetPowerup( int iPowerup, bool bState, float flTime = 0, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
	virtual	bool		AttemptToPowerup( int iPowerup, float flTime, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
	virtual	float		PowerupDuration( int iPowerup, float flTime );
	virtual	void		PowerupStart( int iPowerup, float flAmount = 0, CBaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL );
	virtual	void		PowerupEnd( int iPowerup );

	void				PowerupThink( void );
	virtual	void		PowerupThink( int iPowerup );

public:

	CNetworkVar( int, m_iPowerups );
	float				m_flPowerupAttemptTimes[ MAX_POWERUPS ];
	float				m_flPowerupEndTimes[ MAX_POWERUPS ];
	float				m_flFractionalBoost;	// POWERUP_BOOST health fraction - specific powerup data

#endif

public:
	// returns the last body region that took damage
	int	LastHitGroup() const				{ return m_LastHitGroup; }
protected:
	void SetLastHitGroup( int nHitGroup )	{ m_LastHitGroup = nHitGroup; }

public:
	CNetworkVar( float, m_flNextAttack );			// cannot attack again until this time

#ifdef GLOWS_ENABLE
protected:
	CNetworkVar( bool, m_bGlowEnabled );
#endif // GLOWS_ENABLE

private:
	Hull_t		m_eHull;

	void				UpdateGlowEffect( void );
	void				DestroyGlowEffect( void );

protected:
	int			m_bloodColor;			// color of blood particless

	// -------------------
	// combat ability data
	// -------------------
	float		m_flFieldOfView;		// cosine of field of view for this character
	Vector		m_HackedGunPos;			// HACK until we can query end of gun
	string_t	m_RelationshipString;	// Used to load up relationship keyvalues
	float		m_impactEnergyScale;// scale the amount of energy used to calculate damage this ent takes due to physics

public:
	static int					GetInteractionID();	// Returns the next interaction #

protected:
	// Visibility-related stuff
	bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const;
private:
	// For weapon strip
	void ThrowDirForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, Vector *pVecThrowDir );
	void DropWeaponForWeaponStrip( CBaseCombatWeapon *pWeapon, const Vector &vecForward, const QAngle &vecAngles, float flDiameter );

	friend class CScriptedTarget; // needs to access GetInteractionID()
	
	static int					m_lastInteraction;	// Last registered interaction #
	static Relationship_t**		m_DefaultRelationship;

	// attack/damage
	int					m_LastHitGroup;			// the last body region that took damage
	float				m_flDamageAccumulator;	// so very small amounts of damage do not get lost.
	int					m_iDamageCount;			// # of times NPC has been damaged.  used for tracking 1-shot kills.
	
	// Weapon proficiency gets calculated each time an NPC changes his weapon, and then
	// cached off as the CurrentWeaponProficiency.
	WeaponProficiency_t m_CurrentWeaponProficiency;

	// ---------------
	//  Relationships
	// ---------------
	CUtlVector<Relationship_t>		m_Relationship;						// Array of relationships

protected:
	// shared ammo slots
	CNetworkArrayForDerived( int, m_iAmmo, MAX_AMMO_SLOTS );

	// Usable character items 
	CNetworkArray( CBaseCombatWeaponHandle, m_hMyWeapons, MAX_WEAPONS );

	CNetworkHandle( CBaseCombatWeapon, m_hActiveWeapon );

	friend class CCleanupDefaultRelationShips;
	
	IntervalTimer m_aliveTimer;

	unsigned int m_hasBeenInjured;							// bitfield corresponding to team ID that did the injury	

	// we do this because MAX_TEAMS is 32, which is wasteful for most games
	enum { MAX_DAMAGE_TEAMS = 4 };
	struct DamageHistory
	{
		int team;					// which team hurt us (TEAM_INVALID means slot unused)
		IntervalTimer interval;		// how long has it been
	};
	DamageHistory m_damageHistory[ MAX_DAMAGE_TEAMS ];

	// last known navigation area of player - NULL if unknown
	CNavArea *m_lastNavArea;
	CAI_MoveMonitor m_NavAreaUpdateMonitor;
	int m_registeredNavTeam;	// ugly, but needed to clean up player team counts in nav mesh
};

basecombatcharacter.cpp

BEGIN_DATADESC( CBaseCombatCharacter )

#ifdef INVASION_DLL
	DEFINE_FIELD( m_iPowerups, FIELD_INTEGER ),
	DEFINE_ARRAY( m_flPowerupAttemptTimes, FIELD_TIME, MAX_POWERUPS ),
	DEFINE_ARRAY( m_flPowerupEndTimes, FIELD_TIME, MAX_POWERUPS ),
	DEFINE_FIELD( m_flFractionalBoost, FIELD_FLOAT ),
#endif

	DEFINE_FIELD( m_flNextAttack, FIELD_TIME ),
	DEFINE_FIELD( m_eHull, FIELD_INTEGER ),
	DEFINE_FIELD( m_bloodColor, FIELD_INTEGER ),
	DEFINE_FIELD( m_iDamageCount, FIELD_INTEGER ),
	
	DEFINE_FIELD( m_flFieldOfView, FIELD_FLOAT ),
	DEFINE_FIELD( m_HackedGunPos, FIELD_VECTOR ),
	DEFINE_KEYFIELD( m_RelationshipString, FIELD_STRING, "Relationship" ),

	DEFINE_FIELD( m_LastHitGroup, FIELD_INTEGER ),
	DEFINE_FIELD( m_flDamageAccumulator, FIELD_FLOAT ),
	DEFINE_INPUT( m_impactEnergyScale, FIELD_FLOAT, "physdamagescale" ),
	DEFINE_FIELD( m_CurrentWeaponProficiency, FIELD_INTEGER),

	DEFINE_UTLVECTOR( m_Relationship,	FIELD_EMBEDDED),

	DEFINE_AUTO_ARRAY( m_iAmmo, FIELD_INTEGER ),
	DEFINE_AUTO_ARRAY( m_hMyWeapons, FIELD_EHANDLE ),
	DEFINE_FIELD( m_hActiveWeapon, FIELD_EHANDLE ),
	DEFINE_FIELD( m_bForceServerRagdoll, FIELD_BOOLEAN ),
	DEFINE_FIELD( m_bPreventWeaponPickup, FIELD_BOOLEAN ),

	DEFINE_INPUTFUNC( FIELD_VOID, "KilledNPC", InputKilledNPC ),

END_DATADESC()