2020-04-22 18:56:21 +02:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
//
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
//
// NOTE: The CS Bot code uses Doxygen-style comments. If you run Doxygen over this code, it will
// auto-generate documentation. Visit www.doxygen.org to download the system for free.
//
# ifndef _CS_BOT_H_
# define _CS_BOT_H_
# include "bot/bot.h"
# include "bot/cs_bot_manager.h"
# include "bot/cs_bot_chatter.h"
# include "cs_gamestate.h"
# include "cs_player.h"
# include "weapon_csbase.h"
# include "cs_nav_pathfind.h"
# include "cs_nav_area.h"
class CBaseDoor ;
class CBasePropDoor ;
class CCSBot ;
class CPushAwayEnumerator ;
//--------------------------------------------------------------------------------------------------------------
/**
* For use with player - > m_rgpPlayerItems [ ]
*/
enum InventorySlotType
{
PRIMARY_WEAPON_SLOT = 1 ,
PISTOL_SLOT ,
KNIFE_SLOT ,
GRENADE_SLOT ,
C4_SLOT
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* The definition of a bot ' s behavior state . One or more finite state machines
* using these states implement a bot ' s behaviors .
*/
class BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) { } ///< when state is entered
virtual void OnUpdate ( CCSBot * bot ) { } ///< state behavior
virtual void OnExit ( CCSBot * bot ) { } ///< when state exited
virtual const char * GetName ( void ) const = 0 ; ///< return state name
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* The state is invoked when a bot has nothing to do , or has finished what it was doing .
* A bot never stays in this state - it is the main action selection mechanism .
*/
class IdleState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Idle " ; }
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is actively searching for an enemy .
*/
class HuntState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Hunt " ; }
void ClearHuntArea ( void ) { m_huntArea = NULL ; }
private :
CNavArea * m_huntArea ; ///< "far away" area we are moving to
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot has an enemy and is attempting to kill it
*/
class AttackState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Attack " ; }
void SetCrouchAndHold ( bool crouch ) { m_crouchAndHold = crouch ; }
protected :
enum DodgeStateType
{
STEADY_ON ,
SLIDE_LEFT ,
SLIDE_RIGHT ,
JUMP ,
NUM_ATTACK_STATES
} ;
DodgeStateType m_dodgeState ;
float m_nextDodgeStateTimestamp ;
CountdownTimer m_repathTimer ;
float m_scopeTimestamp ;
bool m_haveSeenEnemy ; ///< false if we haven't yet seen the enemy since we started this attack (told by a friend, etc)
bool m_isEnemyHidden ; ///< true we if we have lost line-of-sight to our enemy
float m_reacquireTimestamp ; ///< time when we can fire again, after losing enemy behind cover
float m_shieldToggleTimestamp ; ///< time to toggle shield deploy state
bool m_shieldForceOpen ; ///< if true, open up and shoot even if in danger
float m_pinnedDownTimestamp ; ///< time when we'll consider ourselves "pinned down" by the enemy
bool m_crouchAndHold ;
bool m_didAmbushCheck ;
bool m_shouldDodge ;
bool m_firstDodge ;
bool m_isCoward ; ///< if true, we'll retreat if outnumbered during this fight
CountdownTimer m_retreatTimer ;
void StopAttacking ( CCSBot * bot ) ;
void Dodge ( CCSBot * bot ) ; ///< do dodge behavior
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot has heard an enemy noise and is moving to find out what it was .
*/
class InvestigateNoiseState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " InvestigateNoise " ; }
private :
void AttendCurrentNoise ( CCSBot * bot ) ; ///< move towards currently heard noise
Vector m_checkNoisePosition ; ///< the position of the noise we're investigating
CountdownTimer m_minTimer ; ///< minimum time we will investigate our current noise
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is buying equipment at the start of a round .
*/
class BuyState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Buy " ; }
private :
bool m_isInitialDelay ;
int m_prefRetries ; ///< for retrying buying preferred weapon at current index
int m_prefIndex ; ///< where are we in our list of preferred weapons
int m_retries ;
bool m_doneBuying ;
bool m_buyDefuseKit ;
bool m_buyGrenade ;
bool m_buyShield ;
bool m_buyPistol ;
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is moving to a potentially far away position in the world .
*/
class MoveToState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " MoveTo " ; }
void SetGoalPosition ( const Vector & pos ) { m_goalPosition = pos ; }
void SetRouteType ( RouteType route ) { m_routeType = route ; }
private :
Vector m_goalPosition ; ///< goal position of move
RouteType m_routeType ; ///< the kind of route to build
bool m_radioedPlan ;
bool m_askedForCover ;
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a Terrorist bot is moving to pick up a dropped bomb .
*/
class FetchBombState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " FetchBomb " ; }
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a Terrorist bot is actually planting the bomb .
*/
class PlantBombState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " PlantBomb " ; }
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a CT bot is actually defusing a live bomb .
*/
class DefuseBombState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " DefuseBomb " ; }
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is hiding in a corner .
* NOTE : This state also includes MOVING TO that hiding spot , which may be all the way
* across the map !
*/
class HideState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Hide " ; }
void SetHidingSpot ( const Vector & pos ) { m_hidingSpot = pos ; }
const Vector & GetHidingSpot ( void ) const { return m_hidingSpot ; }
void SetSearchArea ( CNavArea * area ) { m_searchFromArea = area ; }
void SetSearchRange ( float range ) { m_range = range ; }
void SetDuration ( float time ) { m_duration = time ; }
void SetHoldPosition ( bool hold ) { m_isHoldingPosition = hold ; }
bool IsAtSpot ( void ) const { return m_isAtSpot ; }
float GetHideTime ( void ) const
{
if ( IsAtSpot ( ) )
{
return m_duration - m_hideTimer . GetRemainingTime ( ) ;
}
return 0.0f ;
}
private :
CNavArea * m_searchFromArea ;
float m_range ;
Vector m_hidingSpot ;
bool m_isLookingOutward ;
bool m_isAtSpot ;
float m_duration ;
CountdownTimer m_hideTimer ; ///< how long to hide
bool m_isHoldingPosition ;
float m_holdPositionTime ; ///< how long to hold our position after we hear nearby enemy noise
bool m_heardEnemy ; ///< set to true when we first hear an enemy
float m_firstHeardEnemyTime ; ///< when we first heard the enemy
int m_retry ; ///< counter for retrying hiding spot
Vector m_leaderAnchorPos ; ///< the position of our follow leader when we decided to hide
bool m_isPaused ; ///< if true, we have paused in our retreat for a moment
CountdownTimer m_pauseTimer ; ///< for stoppping and starting our pauses while we retreat
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is attempting to flee from a bomb that is about to explode .
*/
class EscapeFromBombState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " EscapeFromBomb " ; }
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is following another player .
*/
class FollowState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " Follow " ; }
void SetLeader ( CCSPlayer * player ) { m_leader = player ; }
private :
CHandle < CCSPlayer > m_leader ; ///< the player we are following
Vector m_lastLeaderPos ; ///< where the leader was when we computed our follow path
bool m_isStopped ;
float m_stoppedTimestamp ;
enum LeaderMotionStateType
{
INVALID ,
STOPPED ,
WALKING ,
RUNNING
} ;
LeaderMotionStateType m_leaderMotionState ;
IntervalTimer m_leaderMotionStateTime ;
bool m_isSneaking ;
float m_lastSawLeaderTime ;
CountdownTimer m_repathInterval ;
IntervalTimer m_walkTime ;
bool m_isAtWalkSpeed ;
float m_waitTime ;
CountdownTimer m_idleTimer ;
void ComputeLeaderMotionState ( float leaderSpeed ) ;
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is actually using another entity ( ie : facing towards it and pressing the use key )
*/
class UseEntityState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " UseEntity " ; }
void SetEntity ( CBaseEntity * entity ) { m_entity = entity ; }
private :
EHANDLE m_entity ; ///< the entity we will use
} ;
//--------------------------------------------------------------------------------------------------------------
/**
* When a bot is opening a door
*/
class OpenDoorState : public BotState
{
public :
virtual void OnEnter ( CCSBot * bot ) ;
virtual void OnUpdate ( CCSBot * bot ) ;
virtual void OnExit ( CCSBot * bot ) ;
virtual const char * GetName ( void ) const { return " OpenDoor " ; }
void SetDoor ( CBaseEntity * door ) ;
bool IsDone ( void ) const { return m_isDone ; } ///< return true if behavior is done
private :
CHandle < CBaseDoor > m_funcDoor ; ///< the func_door we are opening
CHandle < CBasePropDoor > m_propDoor ; ///< the prop_door we are opening
bool m_isDone ;
CountdownTimer m_timeout ;
} ;
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
/**
* The Counter - strike Bot
*/
class CCSBot : public CBot < CCSPlayer >
{
public :
DECLARE_CLASS ( CCSBot , CBot < CCSPlayer > ) ;
DECLARE_DATADESC ( ) ;
CCSBot ( void ) ; ///< constructor initializes all values to zero
virtual ~ CCSBot ( ) ;
virtual bool Initialize ( const BotProfile * profile , int team ) ; ///< (EXTEND) prepare bot for action
virtual void Spawn ( void ) ; ///< (EXTEND) spawn the bot into the game
virtual void Touch ( CBaseEntity * other ) ; ///< (EXTEND) when touched by another entity
virtual void Upkeep ( void ) ; ///< lightweight maintenance, invoked frequently
virtual void Update ( void ) ; ///< heavyweight algorithms, invoked less often
virtual void BuildUserCmd ( CUserCmd & cmd , const QAngle & viewangles , float forwardmove , float sidemove , float upmove , int buttons , byte impulse ) ;
virtual float GetMoveSpeed ( void ) ; ///< returns current movement speed (for walk/run)
virtual void Walk ( void ) ;
virtual bool Jump ( bool mustJump = false ) ; ///< returns true if jump was started
//- behavior properties ------------------------------------------------------------------------------------------
float GetCombatRange ( void ) const ;
bool IsRogue ( void ) const ; ///< return true if we dont listen to teammates or pursue scenario goals
void SetRogue ( bool rogue ) ;
bool IsHurrying ( void ) const ; ///< return true if we are in a hurry
void Hurry ( float duration ) ; ///< force bot to hurry
bool IsSafe ( void ) const ; ///< return true if we are in a safe region
bool IsWellPastSafe ( void ) const ; ///< return true if it is well past the early, "safe", part of the round
bool IsEndOfSafeTime ( void ) const ; ///< return true if we were in the safe time last update, but not now
float GetSafeTimeRemaining ( void ) const ; ///< return the amount of "safe time" we have left
float GetSafeTime ( void ) const ; ///< return what we think the total "safe time" for this map is
virtual void Blind ( float holdTime , float fadeTime , float startingAlpha = 255 ) ; // player blinded by a flashbang
bool IsUnhealthy ( void ) const ; ///< returns true if bot is low on health
bool IsAlert ( void ) const ; ///< return true if bot is in heightened "alert" mode
void BecomeAlert ( void ) ; ///< bot becomes "alert" for immediately nearby enemies
bool IsSneaking ( void ) const ; ///< return true if bot is sneaking
void Sneak ( float duration ) ; ///< sneak for given duration
//- behaviors ---------------------------------------------------------------------------------------------------
void Idle ( void ) ;
void Hide ( CNavArea * searchFromArea = NULL , float duration = - 1.0f , float hideRange = 750.0f , bool holdPosition = false ) ; ///< DEPRECATED: Use TryToHide() instead
# define USE_NEAREST true
bool TryToHide ( CNavArea * searchFromArea = NULL , float duration = - 1.0f , float hideRange = 750.0f , bool holdPosition = false , bool useNearest = false ) ; ///< try to hide nearby, return false if cannot
void Hide ( const Vector & hidingSpot , float duration = - 1.0f , bool holdPosition = false ) ; ///< move to the given hiding place
bool IsHiding ( void ) const ; ///< returns true if bot is currently hiding
bool IsAtHidingSpot ( void ) const ; ///< return true if we are hiding and at our hiding spot
float GetHidingTime ( void ) const ; ///< return number of seconds we have been at our current hiding spot
bool MoveToInitialEncounter ( void ) ; ///< move to a hiding spot and wait for initial encounter with enemy team (return false if no spots are available)
bool TryToRetreat ( float maxRange = 1000.0f , float duration = - 1.0f ) ; ///< retreat to a nearby hiding spot, away from enemies
void Hunt ( void ) ;
bool IsHunting ( void ) const ; ///< returns true if bot is currently hunting
void Attack ( CCSPlayer * victim ) ;
void FireWeaponAtEnemy ( void ) ; ///< fire our active weapon towards our current enemy
void StopAttacking ( void ) ;
bool IsAttacking ( void ) const ; ///< returns true if bot is currently engaging a target
void MoveTo ( const Vector & pos , RouteType route = SAFEST_ROUTE ) ; ///< move to potentially distant position
bool IsMovingTo ( void ) const ; ///< return true if we are in the MoveTo state
void PlantBomb ( void ) ;
void FetchBomb ( void ) ; ///< bomb has been dropped - go get it
bool NoticeLooseBomb ( void ) const ; ///< return true if we noticed the bomb on the ground or on radar
bool CanSeeLooseBomb ( void ) const ; ///< return true if we directly see the loose bomb
void DefuseBomb ( void ) ;
bool IsDefusingBomb ( void ) const ; ///< returns true if bot is currently defusing the bomb
bool CanSeePlantedBomb ( void ) const ; ///< return true if we directly see the planted bomb
void EscapeFromBomb ( void ) ;
bool IsEscapingFromBomb ( void ) const ; ///< return true if we are escaping from the bomb
void RescueHostages ( void ) ; ///< begin process of rescuing hostages
void UseEntity ( CBaseEntity * entity ) ; ///< use the entity
void OpenDoor ( CBaseEntity * door ) ; ///< open the door (assumes we are right in front of it)
bool IsOpeningDoor ( void ) const ; ///< return true if we are in the process of opening a door
void Buy ( void ) ; ///< enter the buy state
bool IsBuying ( void ) const ;
void Panic ( void ) ; ///< look around in panic
bool IsPanicking ( void ) const ; ///< return true if bot is panicked
void StopPanicking ( void ) ; ///< end our panic
void UpdatePanicLookAround ( void ) ; ///< do panic behavior
void TryToJoinTeam ( int team ) ; ///< try to join the given team
void Follow ( CCSPlayer * player ) ; ///< begin following given Player
void ContinueFollowing ( void ) ; ///< continue following our leader after finishing what we were doing
void StopFollowing ( void ) ; ///< stop following
bool IsFollowing ( void ) const ; ///< return true if we are following someone (not necessarily in the follow state)
CCSPlayer * GetFollowLeader ( void ) const ; ///< return the leader we are following
float GetFollowDuration ( void ) const ; ///< return how long we've been following our leader
bool CanAutoFollow ( void ) const ; ///< return true if we can auto-follow
bool IsNotMoving ( float minDuration = 0.0f ) const ; ///< return true if we are currently standing still and have been for minDuration
void AimAtEnemy ( void ) ; ///< point our weapon towards our enemy
void StopAiming ( void ) ; ///< stop aiming at enemy
bool IsAimingAtEnemy ( void ) const ; ///< returns true if we are trying to aim at an enemy
float GetStateTimestamp ( void ) const ; ///< get time current state was entered
bool IsDoingScenario ( void ) const ; ///< return true if we will do scenario-related tasks
//- scenario / gamestate -----------------------------------------------------------------------------------------
CSGameState * GetGameState ( void ) ; ///< return an interface to this bot's gamestate
const CSGameState * GetGameState ( void ) const ; ///< return an interface to this bot's gamestate
bool IsAtBombsite ( void ) ; ///< return true if we are in a bomb planting zone
bool GuardRandomZone ( float range = 500.0f ) ; ///< pick a random zone and hide near it
bool IsBusy ( void ) const ; ///< return true if we are busy doing something important
//- high-level tasks ---------------------------------------------------------------------------------------------
enum TaskType
{
SEEK_AND_DESTROY ,
PLANT_BOMB ,
FIND_TICKING_BOMB ,
DEFUSE_BOMB ,
GUARD_TICKING_BOMB ,
GUARD_BOMB_DEFUSER ,
GUARD_LOOSE_BOMB ,
GUARD_BOMB_ZONE ,
GUARD_INITIAL_ENCOUNTER ,
ESCAPE_FROM_BOMB ,
HOLD_POSITION ,
FOLLOW ,
VIP_ESCAPE ,
GUARD_VIP_ESCAPE_ZONE ,
COLLECT_HOSTAGES ,
RESCUE_HOSTAGES ,
GUARD_HOSTAGES ,
GUARD_HOSTAGE_RESCUE_ZONE ,
MOVE_TO_LAST_KNOWN_ENEMY_POSITION ,
MOVE_TO_SNIPER_SPOT ,
SNIPING ,
NUM_TASKS
} ;
void SetTask ( TaskType task , CBaseEntity * entity = NULL ) ; ///< set our current "task"
TaskType GetTask ( void ) const ;
CBaseEntity * GetTaskEntity ( void ) ;
const char * GetTaskName ( void ) const ; ///< return string describing current task
//- behavior modifiers ------------------------------------------------------------------------------------------
enum DispositionType
{
ENGAGE_AND_INVESTIGATE , ///< engage enemies on sight and investigate enemy noises
OPPORTUNITY_FIRE , ///< engage enemies on sight, but only look towards enemy noises, dont investigate
SELF_DEFENSE , ///< only engage if fired on, or very close to enemy
IGNORE_ENEMIES , ///< ignore all enemies - useful for ducking around corners, running away, etc
NUM_DISPOSITIONS
} ;
void SetDisposition ( DispositionType disposition ) ; ///< define how we react to enemies
DispositionType GetDisposition ( void ) const ;
const char * GetDispositionName ( void ) const ; ///< return string describing current disposition
void IgnoreEnemies ( float duration ) ; ///< ignore enemies for a short duration
enum MoraleType
{
TERRIBLE = - 3 ,
BAD = - 2 ,
NEGATIVE = - 1 ,
NEUTRAL = 0 ,
POSITIVE = 1 ,
GOOD = 2 ,
EXCELLENT = 3 ,
} ;
MoraleType GetMorale ( void ) const ;
const char * GetMoraleName ( void ) const ; ///< return string describing current morale
void IncreaseMorale ( void ) ;
void DecreaseMorale ( void ) ;
void Surprise ( float duration ) ; ///< become "surprised" - can't attack
bool IsSurprised ( void ) const ; ///< return true if we are "surprised"
//- listening for noises ----------------------------------------------------------------------------------------
bool IsNoiseHeard ( void ) const ; ///< return true if we have heard a noise
bool HeardInterestingNoise ( void ) ; ///< return true if we heard an enemy noise worth checking in to
void InvestigateNoise ( void ) ; ///< investigate recent enemy noise
bool IsInvestigatingNoise ( void ) const ; ///< return true if we are investigating a noise
const Vector * GetNoisePosition ( void ) const ; ///< return position of last heard noise, or NULL if none heard
CNavArea * GetNoiseArea ( void ) const ; ///< return area where noise was heard
void ForgetNoise ( void ) ; ///< clear the last heard noise
bool CanSeeNoisePosition ( void ) const ; ///< return true if we directly see where we think the noise came from
float GetNoiseRange ( void ) const ; ///< return approximate distance to last noise heard
bool CanHearNearbyEnemyGunfire ( float range = - 1.0f ) const ; ///< return true if we hear nearby threatening enemy gunfire within given range (-1 == infinite)
PriorityType GetNoisePriority ( void ) const ; ///< return priority of last heard noise
//- radio and chatter--------------------------------------------------------------------------------------------
void SendRadioMessage ( RadioType event ) ; ///< send a radio message
void SpeakAudio ( const char * voiceFilename , float duration , int pitch ) ; ///< send voice chatter
BotChatterInterface * GetChatter ( void ) ; ///< return an interface to this bot's chatter system
bool RespondToHelpRequest ( CCSPlayer * player , Place place , float maxRange = - 1.0f ) ; ///< decide if we should move to help the player, return true if we will
bool IsUsingVoice ( ) const ; ///< new-style "voice" chatter gets voice feedback
//- enemies ------------------------------------------------------------------------------------------------------
// BOTPORT: GetEnemy() collides with GetEnemy() in CBaseEntity - need to use different nomenclature
void SetBotEnemy ( CCSPlayer * enemy ) ; ///< set given player as our current enemy
CCSPlayer * GetBotEnemy ( void ) const ;
int GetNearbyEnemyCount ( void ) const ; ///< return max number of nearby enemies we've seen recently
unsigned int GetEnemyPlace ( void ) const ; ///< return location where we see the majority of our enemies
bool CanSeeBomber ( void ) const ; ///< return true if we can see the bomb carrier
CCSPlayer * GetBomber ( void ) const ;
int GetNearbyFriendCount ( void ) const ; ///< return number of nearby teammates
CCSPlayer * GetClosestVisibleFriend ( void ) const ; ///< return the closest friend that we can see
CCSPlayer * GetClosestVisibleHumanFriend ( void ) const ; ///< return the closest human friend that we can see
bool IsOutnumbered ( void ) const ; ///< return true if we are outnumbered by enemies
int OutnumberedCount ( void ) const ; ///< return number of enemies we are outnumbered by
# define ONLY_VISIBLE_ENEMIES true
CCSPlayer * GetImportantEnemy ( bool checkVisibility = false ) const ; ///< return the closest "important" enemy for the given scenario (bomb carrier, VIP, hostage escorter)
void UpdateReactionQueue ( void ) ; ///< update our reaction time queue
CCSPlayer * GetRecognizedEnemy ( void ) ; ///< return the most dangerous threat we are "conscious" of
bool IsRecognizedEnemyReloading ( void ) ; ///< return true if the enemy we are "conscious" of is reloading
bool IsRecognizedEnemyProtectedByShield ( void ) ; ///< return true if the enemy we are "conscious" of is hiding behind a shield
float GetRangeToNearestRecognizedEnemy ( void ) ; ///< return distance to closest enemy we are "conscious" of
CCSPlayer * GetAttacker ( void ) const ; ///< return last enemy that hurt us
float GetTimeSinceAttacked ( void ) const ; ///< return duration since we were last injured by an attacker
float GetFirstSawEnemyTimestamp ( void ) const ; ///< time since we saw any enemies
float GetLastSawEnemyTimestamp ( void ) const ;
float GetTimeSinceLastSawEnemy ( void ) const ;
float GetTimeSinceAcquiredCurrentEnemy ( void ) const ;
bool HasNotSeenEnemyForLongTime ( void ) const ; ///< return true if we haven't seen an enemy for "a long time"
const Vector & GetLastKnownEnemyPosition ( void ) const ;
bool IsEnemyVisible ( void ) const ; ///< is our current enemy visible
float GetEnemyDeathTimestamp ( void ) const ;
bool IsFriendInLineOfFire ( void ) ; ///< return true if a friend is in our weapon's way
bool IsAwareOfEnemyDeath ( void ) const ; ///< return true if we *noticed* that our enemy died
int GetLastVictimID ( void ) const ; ///< return the ID (entindex) of the last victim we killed, or zero
bool CanSeeSniper ( void ) const ; ///< return true if we can see an enemy sniper
bool HasSeenSniperRecently ( void ) const ; ///< return true if we have seen a sniper recently
float GetTravelDistanceToPlayer ( CCSPlayer * player ) const ; ///< return shortest path travel distance to this player
bool DidPlayerJustFireWeapon ( const CCSPlayer * player ) const ; ///< return true if the given player just fired their weapon
//- navigation --------------------------------------------------------------------------------------------------
bool HasPath ( void ) const ;
void DestroyPath ( void ) ;
float GetFeetZ ( void ) const ; ///< return Z of bottom of feet
enum PathResult
{
PROGRESSING , ///< we are moving along the path
END_OF_PATH , ///< we reached the end of the path
PATH_FAILURE ///< we failed to reach the end of the path
} ;
# define NO_SPEED_CHANGE false
PathResult UpdatePathMovement ( bool allowSpeedChange = true ) ; ///< move along our computed path - if allowSpeedChange is true, bot will walk when near goal to ensure accuracy
//bool AStarSearch( CNavArea *startArea, CNavArea *goalArea ); ///< find shortest path from startArea to goalArea - don't actually buid the path
bool ComputePath ( const Vector & goal , RouteType route = SAFEST_ROUTE ) ; ///< compute path to goal position
bool StayOnNavMesh ( void ) ;
CNavArea * GetLastKnownArea ( void ) const ; ///< return the last area we know we were inside of
const Vector & GetPathEndpoint ( void ) const ; ///< return final position of our current path
float GetPathDistanceRemaining ( void ) const ; ///< return estimated distance left to travel along path
void ResetStuckMonitor ( void ) ;
bool IsAreaVisible ( const CNavArea * area ) const ; ///< is any portion of the area visible to this bot
const Vector & GetPathPosition ( int index ) const ;
bool GetSimpleGroundHeightWithFloor ( const Vector & pos , float * height , Vector * normal = NULL ) ; ///< find "simple" ground height, treating current nav area as part of the floor
void BreakablesCheck ( void ) ;
void DoorCheck ( void ) ; ///< Check for any doors along our path that need opening
virtual void PushawayTouch ( CBaseEntity * pOther ) ;
Place GetPlace ( void ) const ; ///< get our current radio chatter place
bool IsUsingLadder ( void ) const ; ///< returns true if we are in the process of negotiating a ladder
void GetOffLadder ( void ) ; ///< immediately jump off of our ladder, if we're on one
void SetGoalEntity ( CBaseEntity * entity ) ;
CBaseEntity * GetGoalEntity ( void ) ;
bool IsNearJump ( void ) const ; ///< return true if nearing a jump in the path
float GetApproximateFallDamage ( float height ) const ; ///< return how much damage will will take from the given fall height
void ForceRun ( float duration ) ; ///< force the bot to run if it moves for the given duration
virtual bool IsRunning ( void ) const ;
void Wait ( float duration ) ; ///< wait where we are for the given duration
bool IsWaiting ( void ) const ; ///< return true if we are waiting
void StopWaiting ( void ) ; ///< stop waiting
void Wiggle ( void ) ; ///< random movement, for getting un-stuck
bool IsFriendInTheWay ( const Vector & goalPos ) ; ///< return true if a friend is between us and the given position
void FeelerReflexAdjustment ( Vector * goalPosition ) ; ///< do reflex avoidance movements if our "feelers" are touched
bool HasVisitedEnemySpawn ( void ) const ; ///< return true if we have visited enemy spawn at least once
bool IsAtEnemySpawn ( void ) const ; ///< return true if we are at the/an enemy spawn right now
//- looking around ----------------------------------------------------------------------------------------------
// BOTPORT: EVIL VILE HACK - why is EyePosition() not const?!?!?
const Vector & EyePositionConst ( void ) const ;
void SetLookAngles ( float yaw , float pitch ) ; ///< set our desired look angles
void UpdateLookAngles ( void ) ; ///< move actual view angles towards desired ones
void UpdateLookAround ( bool updateNow = false ) ; ///< update "looking around" mechanism
void InhibitLookAround ( float duration ) ; ///< block all "look at" and "looking around" behavior for given duration - just look ahead
/// @todo Clean up notion of "forward angle" and "look ahead angle"
void SetForwardAngle ( float angle ) ; ///< define our forward facing
void SetLookAheadAngle ( float angle ) ; ///< define default look ahead angle
/// look at the given point in space for the given duration (-1 means forever)
void SetLookAt ( const char * desc , const Vector & pos , PriorityType pri , float duration = - 1.0f , bool clearIfClose = false , float angleTolerance = 5.0f , bool attack = false ) ;
void ClearLookAt ( void ) ; ///< stop looking at a point in space and just look ahead
bool IsLookingAtSpot ( PriorityType pri = PRIORITY_LOW ) const ; ///< return true if we are looking at spot with equal or higher priority
bool IsViewMoving ( float angleVelThreshold = 1.0f ) const ; ///< returns true if bot's view angles are rotating (not still)
bool HasViewBeenSteady ( float duration ) const ; ///< how long has our view been "steady" (ie: not moving) for given duration
bool HasLookAtTarget ( void ) const ; ///< return true if we are in the process of looking at a target
enum VisiblePartType
{
NONE = 0x00 ,
GUT = 0x01 ,
HEAD = 0x02 ,
LEFT_SIDE = 0x04 , ///< the left side of the object from our point of view (not their left side)
RIGHT_SIDE = 0x08 , ///< the right side of the object from our point of view (not their right side)
FEET = 0x10
} ;
# define CHECK_FOV true
bool IsVisible ( const Vector & pos , bool testFOV = false , const CBaseEntity * ignore = NULL ) const ; ///< return true if we can see the point
bool IsVisible ( CCSPlayer * player , bool testFOV = false , unsigned char * visParts = NULL ) const ; ///< return true if we can see any part of the player
bool IsNoticable ( const CCSPlayer * player , unsigned char visibleParts ) const ; ///< return true if we "notice" given player
bool IsEnemyPartVisible ( VisiblePartType part ) const ; ///< if enemy is visible, return the part we see for our current enemy
const Vector & GetPartPosition ( CCSPlayer * player , VisiblePartType part ) const ; ///< return world space position of given part on player
float ComputeWeaponSightRange ( void ) ; ///< return line-of-sight distance to obstacle along weapon fire ray
bool IsAnyVisibleEnemyLookingAtMe ( bool testFOV = false ) const ; ///< return true if any enemy I have LOS to is looking directly at me
bool IsSignificantlyCloser ( const CCSPlayer * testPlayer , const CCSPlayer * referencePlayer ) const ; ///< return true if testPlayer is significantly closer than referencePlayer
//- approach points ---------------------------------------------------------------------------------------------
void ComputeApproachPoints ( void ) ; ///< determine the set of "approach points" representing where the enemy can enter this region
void UpdateApproachPoints ( void ) ; ///< recompute the approach point set if we have moved far enough to invalidate the current ones
void ClearApproachPoints ( void ) ;
void DrawApproachPoints ( void ) const ; ///< for debugging
float GetHidingSpotCheckTimestamp ( HidingSpot * spot ) const ; ///< return time when given spot was last checked
void SetHidingSpotCheckTimestamp ( HidingSpot * spot ) ; ///< set the timestamp of the given spot to now
const CNavArea * GetInitialEncounterArea ( void ) const ; ///< return area where we think we will first meet the enemy
void SetInitialEncounterArea ( const CNavArea * area ) ;
//- weapon query and equip --------------------------------------------------------------------------------------
# define MUST_EQUIP true
void EquipBestWeapon ( bool mustEquip = false ) ; ///< equip the best weapon we are carrying that has ammo
void EquipPistol ( void ) ; ///< equip our pistol
void EquipKnife ( void ) ; ///< equip the knife
# define DONT_USE_SMOKE_GRENADE true
bool EquipGrenade ( bool noSmoke = false ) ; ///< equip a grenade, return false if we cant
bool IsUsingKnife ( void ) const ; ///< returns true if we have knife equipped
bool IsUsingPistol ( void ) const ; ///< returns true if we have pistol equipped
bool IsUsingGrenade ( void ) const ; ///< returns true if we have grenade equipped
bool IsUsingSniperRifle ( void ) const ; ///< returns true if using a "sniper" rifle
bool IsUsing ( CSWeaponID weapon ) const ; ///< returns true if using the specific weapon
bool IsSniper ( void ) const ; ///< return true if we have a sniper rifle in our inventory
bool IsSniping ( void ) const ; ///< return true if we are actively sniping (moving to sniper spot or settled in)
bool IsUsingShotgun ( void ) const ; ///< returns true if using a shotgun
bool IsUsingMachinegun ( void ) const ; ///< returns true if using the big 'ol machinegun
void ThrowGrenade ( const Vector & target ) ; ///< begin the process of throwing the grenade
bool IsThrowingGrenade ( void ) const ; ///< return true if we are in the process of throwing a grenade
bool HasGrenade ( void ) const ; ///< return true if we have a grenade in our inventory
void AvoidEnemyGrenades ( void ) ; ///< react to enemy grenades we see
bool IsAvoidingGrenade ( void ) const ; ///< return true if we are in the act of avoiding a grenade
bool DoesActiveWeaponHaveSilencer ( void ) const ; ///< returns true if we are using a weapon with a removable silencer
bool CanActiveWeaponFire ( void ) const ; ///< returns true if our current weapon can attack
CWeaponCSBase * GetActiveCSWeapon ( void ) const ; ///< get our current Counter-Strike weapon
void GiveWeapon ( const char * weaponAlias ) ; ///< Debug command to give a named weapon
virtual void PrimaryAttack ( void ) ; ///< presses the fire button, unless we're holding a pistol that can't fire yet (so we can just always call PrimaryAttack())
enum ZoomType { NO_ZOOM , LOW_ZOOM , HIGH_ZOOM } ;
ZoomType GetZoomLevel ( void ) ; ///< return the current zoom level of our weapon
bool AdjustZoom ( float range ) ; ///< change our zoom level to be appropriate for the given range
bool IsWaitingForZoom ( void ) const ; ///< return true if we are reacquiring after our zoom
bool IsPrimaryWeaponEmpty ( void ) const ; ///< return true if primary weapon doesn't exist or is totally out of ammo
bool IsPistolEmpty ( void ) const ; ///< return true if pistol doesn't exist or is totally out of ammo
int GetHostageEscortCount ( void ) const ; ///< return the number of hostages following me
void IncreaseHostageEscortCount ( void ) ;
float GetRangeToFarthestEscortedHostage ( void ) const ; ///< return euclidean distance to farthest escorted hostage
void ResetWaitForHostagePatience ( void ) ;
//------------------------------------------------------------------------------------
// Event hooks
//
/// invoked when injured by something (EXTEND) - returns the amount of damage inflicted
virtual int OnTakeDamage ( const CTakeDamageInfo & info ) ;
/// invoked when killed (EXTEND)
virtual void Event_Killed ( const CTakeDamageInfo & info ) ;
virtual bool BumpWeapon ( CBaseCombatWeapon * pWeapon ) ; ///< invoked when in contact with a CWeaponBox
/// invoked when event occurs in the game (some events have NULL entity)
void OnPlayerFootstep ( IGameEvent * event ) ;
void OnPlayerRadio ( IGameEvent * event ) ;
void OnPlayerDeath ( IGameEvent * event ) ;
void OnPlayerFallDamage ( IGameEvent * event ) ;
void OnBombPickedUp ( IGameEvent * event ) ;
void OnBombPlanted ( IGameEvent * event ) ;
void OnBombBeep ( IGameEvent * event ) ;
void OnBombDefuseBegin ( IGameEvent * event ) ;
void OnBombDefused ( IGameEvent * event ) ;
void OnBombDefuseAbort ( IGameEvent * event ) ;
void OnBombExploded ( IGameEvent * event ) ;
void OnRoundEnd ( IGameEvent * event ) ;
void OnRoundStart ( IGameEvent * event ) ;
void OnDoorMoving ( IGameEvent * event ) ;
void OnBreakProp ( IGameEvent * event ) ;
void OnBreakBreakable ( IGameEvent * event ) ;
void OnHostageFollows ( IGameEvent * event ) ;
void OnHostageRescuedAll ( IGameEvent * event ) ;
void OnWeaponFire ( IGameEvent * event ) ;
void OnWeaponFireOnEmpty ( IGameEvent * event ) ;
void OnWeaponReload ( IGameEvent * event ) ;
void OnWeaponZoom ( IGameEvent * event ) ;
void OnBulletImpact ( IGameEvent * event ) ;
2024-07-25 18:10:35 +02:00
void OnBulletHitPlayer ( IGameEvent * event ) ;
void OnBulletPlayerHitboxes ( IGameEvent * event ) ;
void OnPlayerLagHitboxes ( IGameEvent * event ) ;
2020-04-22 18:56:21 +02:00
void OnHEGrenadeDetonate ( IGameEvent * event ) ;
void OnFlashbangDetonate ( IGameEvent * event ) ;
void OnSmokeGrenadeDetonate ( IGameEvent * event ) ;
void OnGrenadeBounce ( IGameEvent * event ) ;
void OnNavBlocked ( IGameEvent * event ) ;
void OnEnteredNavArea ( CNavArea * newArea ) ; ///< invoked when bot enters a nav area
private :
# define IS_FOOTSTEP true
void OnAudibleEvent ( IGameEvent * event , CBasePlayer * player , float range , PriorityType priority , bool isHostile , bool isFootstep = false , const Vector * actualOrigin = NULL ) ; ///< Checks if the bot can hear the event
private :
friend class CCSBotManager ;
/// @todo Get rid of these
friend class AttackState ;
friend class BuyState ;
// BOTPORT: Remove this vile hack
Vector m_eyePosition ;
void ResetValues ( void ) ; ///< reset internal data to initial state
void BotDeathThink ( void ) ;
char m_name [ 64 ] ; ///< copied from STRING(pev->netname) for debugging
void DebugDisplay ( void ) const ; ///< render bot debug info
//- behavior properties ------------------------------------------------------------------------------------------
float m_combatRange ; ///< desired distance between us and them during gunplay
mutable bool m_isRogue ; ///< if true, the bot is a "rogue" and listens to no-one
mutable CountdownTimer m_rogueTimer ;
MoraleType m_morale ; ///< our current morale, based on our win/loss history
bool m_diedLastRound ; ///< true if we died last round
float m_safeTime ; ///< duration at the beginning of the round where we feel "safe"
bool m_wasSafe ; ///< true if we were in the safe time last update
void AdjustSafeTime ( void ) ; ///< called when enemy seen to adjust safe time for this round
NavRelativeDirType m_blindMoveDir ; ///< which way to move when we're blind
bool m_blindFire ; ///< if true, fire weapon while blinded
CountdownTimer m_surpriseTimer ; ///< when we were surprised
bool m_isFollowing ; ///< true if we are following someone
CHandle < CCSPlayer > m_leader ; ///< the ID of who we are following
float m_followTimestamp ; ///< when we started following
float m_allowAutoFollowTime ; ///< time when we can auto follow
CountdownTimer m_hurryTimer ; ///< if valid, bot is in a hurry
CountdownTimer m_alertTimer ; ///< if valid, bot is alert
CountdownTimer m_sneakTimer ; ///< if valid, bot is sneaking
CountdownTimer m_panicTimer ; ///< if valid, bot is panicking
// instances of each possible behavior state, to avoid dynamic memory allocation during runtime
IdleState m_idleState ;
HuntState m_huntState ;
AttackState m_attackState ;
InvestigateNoiseState m_investigateNoiseState ;
BuyState m_buyState ;
MoveToState m_moveToState ;
FetchBombState m_fetchBombState ;
PlantBombState m_plantBombState ;
DefuseBombState m_defuseBombState ;
HideState m_hideState ;
EscapeFromBombState m_escapeFromBombState ;
FollowState m_followState ;
UseEntityState m_useEntityState ;
OpenDoorState m_openDoorState ;
/// @todo Allow multiple simultaneous state machines (look around, etc)
void SetState ( BotState * state ) ; ///< set the current behavior state
BotState * m_state ; ///< current behavior state
float m_stateTimestamp ; ///< time state was entered
bool m_isAttacking ; ///< if true, special Attack state is overriding the state machine
bool m_isOpeningDoor ; ///< if true, special OpenDoor state is overriding the state machine
TaskType m_task ; ///< our current task
EHANDLE m_taskEntity ; ///< an entity used for our task
//- navigation ---------------------------------------------------------------------------------------------------
Vector m_goalPosition ;
EHANDLE m_goalEntity ;
void MoveTowardsPosition ( const Vector & pos ) ; ///< move towards position, independant of view angle
void MoveAwayFromPosition ( const Vector & pos ) ; ///< move away from position, independant of view angle
void StrafeAwayFromPosition ( const Vector & pos ) ; ///< strafe (sidestep) away from position, independant of view angle
void StuckCheck ( void ) ; ///< check if we have become stuck
CCSNavArea * m_currentArea ; ///< the nav area we are standing on
CCSNavArea * m_lastKnownArea ; ///< the last area we were in
EHANDLE m_avoid ; ///< higher priority player we need to make way for
float m_avoidTimestamp ;
bool m_isStopping ; ///< true if we're trying to stop because we entered a 'stop' nav area
bool m_hasVisitedEnemySpawn ; ///< true if we have been at the enemy spawn
IntervalTimer m_stillTimer ; ///< how long we have been not moving
//- path navigation data ----------------------------------------------------------------------------------------
enum { MAX_PATH_LENGTH = 256 } ;
struct ConnectInfo
{
CNavArea * area ; ///< the area along the path
NavTraverseType how ; ///< how to enter this area from the previous one
Vector pos ; ///< our movement goal position at this point in the path
const CNavLadder * ladder ; ///< if "how" refers to a ladder, this is it
}
m_path [ MAX_PATH_LENGTH ] ;
int m_pathLength ;
int m_pathIndex ; ///< index of next area on path
float m_areaEnteredTimestamp ;
void BuildTrivialPath ( const Vector & goal ) ; ///< build trivial path to goal, assuming we are already in the same area
CountdownTimer m_repathTimer ; ///< must have elapsed before bot can pathfind again
bool ComputePathPositions ( void ) ; ///< determine actual path positions bot will move between along the path
void SetupLadderMovement ( void ) ;
void SetPathIndex ( int index ) ; ///< set the current index along the path
void DrawPath ( void ) ;
int FindOurPositionOnPath ( Vector * close , bool local = false ) const ; ///< compute the closest point to our current position on our path
int FindPathPoint ( float aheadRange , Vector * point , int * prevIndex = NULL ) ; ///< compute a point a fixed distance ahead along our path.
bool FindClosestPointOnPath ( const Vector & pos , int startIndex , int endIndex , Vector * close ) const ; ///< compute closest point on path to given point
bool IsStraightLinePathWalkable ( const Vector & goal ) const ; ///< test for un-jumpable height change, or unrecoverable fall
void ComputeLadderAngles ( float * yaw , float * pitch ) ; ///< computes ideal yaw/pitch for traversing the current ladder on our path
mutable CountdownTimer m_avoidFriendTimer ; ///< used to throttle how often we check for friends in our path
mutable bool m_isFriendInTheWay ; ///< true if a friend is blocking our path
CountdownTimer m_politeTimer ; ///< we'll wait for friend to move until this runs out
bool m_isWaitingBehindFriend ; ///< true if we are waiting for a friend to move
# define ONLY_JUMP_DOWN true
bool DiscontinuityJump ( float ground , bool onlyJumpDown = false , bool mustJump = false ) ; ///< check if we need to jump due to height change
enum LadderNavState
{
APPROACH_ASCENDING_LADDER , ///< prepare to scale a ladder
APPROACH_DESCENDING_LADDER , ///< prepare to go down ladder
FACE_ASCENDING_LADDER ,
FACE_DESCENDING_LADDER ,
MOUNT_ASCENDING_LADDER , ///< move toward ladder until "on" it
MOUNT_DESCENDING_LADDER , ///< move toward ladder until "on" it
ASCEND_LADDER , ///< go up the ladder
DESCEND_LADDER , ///< go down the ladder
DISMOUNT_ASCENDING_LADDER , ///< get off of the ladder
DISMOUNT_DESCENDING_LADDER , ///< get off of the ladder
MOVE_TO_DESTINATION , ///< dismount ladder and move to destination area
}
m_pathLadderState ;
bool m_pathLadderFaceIn ; ///< if true, face towards ladder, otherwise face away
const CNavLadder * m_pathLadder ; ///< the ladder we need to use to reach the next area
bool UpdateLadderMovement ( void ) ; ///< called by UpdatePathMovement()
NavRelativeDirType m_pathLadderDismountDir ; ///< which way to dismount
float m_pathLadderDismountTimestamp ; ///< time when dismount started
float m_pathLadderEnd ; ///< if ascending, z of top, if descending z of bottom
void ComputeLadderEndpoint ( bool ascending ) ;
float m_pathLadderTimestamp ; ///< time when we started using ladder - for timeout check
CountdownTimer m_mustRunTimer ; ///< if nonzero, bot cannot walk
CountdownTimer m_waitTimer ; ///< if nonzero, we are waiting where we are
void UpdateTravelDistanceToAllPlayers ( void ) ; ///< periodically compute shortest path distance to each player
CountdownTimer m_updateTravelDistanceTimer ; ///< for throttling travel distance computations
float m_playerTravelDistance [ MAX_PLAYERS ] ; ///< current distance from this bot to each player
unsigned char m_travelDistancePhase ; ///< a counter for optimizing when to compute travel distance
//- game scenario mechanisms -------------------------------------------------------------------------------------
CSGameState m_gameState ; ///< our current knowledge about the state of the scenario
byte m_hostageEscortCount ; ///< the number of hostages we're currently escorting
void UpdateHostageEscortCount ( void ) ; ///< periodic check of hostage count in case we lost some
float m_hostageEscortCountTimestamp ;
int m_desiredTeam ; ///< the team we want to be on
bool m_hasJoined ; ///< true if bot has actually joined the game
bool m_isWaitingForHostage ;
CountdownTimer m_inhibitWaitingForHostageTimer ; ///< if active, inhibits us waiting for lagging hostages
CountdownTimer m_waitForHostageTimer ; ///< stops us waiting too long
//- listening mechanism ------------------------------------------------------------------------------------------
Vector m_noisePosition ; ///< position we last heard non-friendly noise
float m_noiseTravelDistance ; ///< the travel distance to the noise
float m_noiseTimestamp ; ///< when we heard it (can get zeroed)
CNavArea * m_noiseArea ; ///< the nav area containing the noise
PriorityType m_noisePriority ; ///< priority of currently heard noise
bool UpdateLookAtNoise ( void ) ; ///< return true if we decided to look towards the most recent noise source
CountdownTimer m_noiseBendTimer ; ///< for throttling how often we bend our line of sight to the noise location
Vector m_bentNoisePosition ; ///< the last computed bent line of sight
bool m_bendNoisePositionValid ;
//- "looking around" mechanism -----------------------------------------------------------------------------------
float m_lookAroundStateTimestamp ; ///< time of next state change
float m_lookAheadAngle ; ///< our desired forward look angle
float m_forwardAngle ; ///< our current forward facing direction
float m_inhibitLookAroundTimestamp ; ///< time when we can look around again
enum LookAtSpotState
{
NOT_LOOKING_AT_SPOT , ///< not currently looking at a point in space
LOOK_TOWARDS_SPOT , ///< in the process of aiming at m_lookAtSpot
LOOK_AT_SPOT , ///< looking at m_lookAtSpot
NUM_LOOK_AT_SPOT_STATES
}
m_lookAtSpotState ;
Vector m_lookAtSpot ; ///< the spot we're currently looking at
PriorityType m_lookAtSpotPriority ;
float m_lookAtSpotDuration ; ///< how long we need to look at the spot
float m_lookAtSpotTimestamp ; ///< when we actually began looking at the spot
float m_lookAtSpotAngleTolerance ; ///< how exactly we must look at the spot
bool m_lookAtSpotClearIfClose ; ///< if true, the look at spot is cleared if it gets close to us
bool m_lookAtSpotAttack ; ///< if true, the look at spot should be attacked
const char * m_lookAtDesc ; ///< for debugging
void UpdateLookAt ( void ) ;
void UpdatePeripheralVision ( ) ; ///< update enounter spot timestamps, etc
float m_peripheralTimestamp ;
enum { MAX_APPROACH_POINTS = 16 } ;
struct ApproachPoint
{
Vector m_pos ;
CNavArea * m_area ;
} ;
ApproachPoint m_approachPoint [ MAX_APPROACH_POINTS ] ;
unsigned char m_approachPointCount ;
Vector m_approachPointViewPosition ; ///< the position used when computing current approachPoint set
CBaseEntity * FindEntitiesOnPath ( float distance , CPushAwayEnumerator * enumerator , bool checkStuck ) ;
IntervalTimer m_viewSteadyTimer ; ///< how long has our view been "steady" (ie: not moving)
bool BendLineOfSight ( const Vector & eye , const Vector & target , Vector * bend , float angleLimit = 135.0f ) const ; ///< "bend" our line of sight until we can see the target point. Return bend point, false if cant bend.
bool FindApproachPointNearestPath ( Vector * pos ) ; ///< find the approach point that is nearest to our current path, ahead of us
bool FindGrenadeTossPathTarget ( Vector * pos ) ; ///< find spot to throw grenade ahead of us and "around the corner" along our path
enum GrenadeTossState
{
NOT_THROWING , ///< not yet throwing
START_THROW , ///< lining up throw
THROW_LINED_UP , ///< pause for a moment when on-line
FINISH_THROW , ///< throwing
} ;
GrenadeTossState m_grenadeTossState ;
CountdownTimer m_tossGrenadeTimer ; ///< timeout timer for grenade tossing
const CNavArea * m_initialEncounterArea ; ///< area where we think we will initially encounter the enemy
void LookForGrenadeTargets ( void ) ; ///< look for grenade throw targets and throw our grenade at them
void UpdateGrenadeThrow ( void ) ; ///< process grenade throwing
CountdownTimer m_isAvoidingGrenade ; ///< if nonzero we are in the act of avoiding a grenade
SpotEncounter * m_spotEncounter ; ///< the spots we will encounter as we move thru our current area
float m_spotCheckTimestamp ; ///< when to check next encounter spot
/// @todo Add timestamp for each possible client to hiding spots
enum { MAX_CHECKED_SPOTS = 64 } ;
struct HidingSpotCheckInfo
{
HidingSpot * spot ;
float timestamp ;
}
m_checkedHidingSpot [ MAX_CHECKED_SPOTS ] ;
int m_checkedHidingSpotCount ;
//- view angle mechanism -----------------------------------------------------------------------------------------
float m_lookPitch ; ///< our desired look pitch angle
float m_lookPitchVel ;
float m_lookYaw ; ///< our desired look yaw angle
float m_lookYawVel ;
//- aim angle mechanism -----------------------------------------------------------------------------------------
Vector m_aimOffset ; ///< current error added to victim's position to get actual aim spot
Vector m_aimOffsetGoal ; ///< desired aim offset
float m_aimOffsetTimestamp ; ///< time of next offset adjustment
float m_aimSpreadTimestamp ; ///< time used to determine max spread as it begins to tighten up
void SetAimOffset ( float accuracy ) ; ///< set the current aim offset
void UpdateAimOffset ( void ) ; ///< wiggle aim error based on m_accuracy
Vector m_aimSpot ; ///< the spot we are currently aiming to fire at
struct PartInfo
{
Vector m_headPos ; ///< current head position
Vector m_gutPos ; ///< current gut position
Vector m_feetPos ; ///< current feet position
Vector m_leftSidePos ; ///< current left side position
Vector m_rightSidePos ; ///< current right side position
int m_validFrame ; ///< frame of last computation (for lazy evaluation)
} ;
static PartInfo m_partInfo [ MAX_PLAYERS ] ; ///< part positions for each player
void ComputePartPositions ( CCSPlayer * player ) ; ///< compute part positions from bone location
//- attack state data --------------------------------------------------------------------------------------------
DispositionType m_disposition ; ///< how we will react to enemies
CountdownTimer m_ignoreEnemiesTimer ; ///< how long will we ignore enemies
mutable CHandle < CCSPlayer > m_enemy ; ///< our current enemy
bool m_isEnemyVisible ; ///< result of last visibility test on enemy
unsigned char m_visibleEnemyParts ; ///< which parts of the visible enemy do we see
Vector m_lastEnemyPosition ; ///< last place we saw the enemy
float m_lastSawEnemyTimestamp ;
float m_firstSawEnemyTimestamp ;
float m_currentEnemyAcquireTimestamp ;
float m_enemyDeathTimestamp ; ///< if m_enemy is dead, this is when he died
float m_friendDeathTimestamp ; ///< time since we saw a friend die
bool m_isLastEnemyDead ; ///< true if we killed or saw our last enemy die
int m_nearbyEnemyCount ; ///< max number of enemies we've seen recently
unsigned int m_enemyPlace ; ///< the location where we saw most of our enemies
struct WatchInfo
{
float timestamp ; ///< time we last saw this player, zero if never seen
bool isEnemy ;
}
m_watchInfo [ MAX_PLAYERS ] ;
mutable CHandle < CCSPlayer > m_bomber ; ///< points to bomber if we can see him
int m_nearbyFriendCount ; ///< number of nearby teammates
mutable CHandle < CCSPlayer > m_closestVisibleFriend ; ///< the closest friend we can see
mutable CHandle < CCSPlayer > m_closestVisibleHumanFriend ; ///< the closest human friend we can see
IntervalTimer m_attentionInterval ; ///< time between attention checks
mutable CHandle < CCSPlayer > m_attacker ; ///< last enemy that hurt us (may not be same as m_enemy)
float m_attackedTimestamp ; ///< when we were hurt by the m_attacker
int m_lastVictimID ; ///< the entindex of the last victim we killed, or zero
bool m_isAimingAtEnemy ; ///< if true, we are trying to aim at our enemy
bool m_isRapidFiring ; ///< if true, RunUpkeep() will toggle our primary attack as fast as it can
IntervalTimer m_equipTimer ; ///< how long have we had our current weapon equipped
CountdownTimer m_zoomTimer ; ///< for delaying firing immediately after zoom
bool DoEquip ( CWeaponCSBase * gun ) ; ///< equip the given item
void ReloadCheck ( void ) ; ///< reload our weapon if we must
void SilencerCheck ( void ) ; ///< use silencer
float m_fireWeaponTimestamp ;
bool m_isEnemySniperVisible ; ///< do we see an enemy sniper right now
CountdownTimer m_sawEnemySniperTimer ; ///< tracking time since saw enemy sniper
//- reaction time system -----------------------------------------------------------------------------------------
enum { MAX_ENEMY_QUEUE = 20 } ;
struct ReactionState
{
// NOTE: player position & orientation is not currently stored separately
CHandle < CCSPlayer > player ;
bool isReloading ;
bool isProtectedByShield ;
}
m_enemyQueue [ MAX_ENEMY_QUEUE ] ; ///< round-robin queue for simulating reaction times
byte m_enemyQueueIndex ;
byte m_enemyQueueCount ;
byte m_enemyQueueAttendIndex ; ///< index of the timeframe we are "conscious" of
CCSPlayer * FindMostDangerousThreat ( void ) ; ///< return most dangerous threat in my field of view (feeds into reaction time queue)
//- stuck detection ---------------------------------------------------------------------------------------------
bool m_isStuck ;
float m_stuckTimestamp ; ///< time when we got stuck
Vector m_stuckSpot ; ///< the location where we became stuck
NavRelativeDirType m_wiggleDirection ;
CountdownTimer m_wiggleTimer ;
CountdownTimer m_stuckJumpTimer ; ///< time for next jump when stuck
enum { MAX_VEL_SAMPLES = 10 } ;
float m_avgVel [ MAX_VEL_SAMPLES ] ;
int m_avgVelIndex ;
int m_avgVelCount ;
Vector m_lastOrigin ;
//- radio --------------------------------------------------------------------------------------------------------
RadioType m_lastRadioCommand ; ///< last radio command we recieved
float m_lastRadioRecievedTimestamp ; ///< time we recieved a radio message
float m_lastRadioSentTimestamp ; ///< time when we send a radio message
CHandle < CCSPlayer > m_radioSubject ; ///< who issued the radio message
Vector m_radioPosition ; ///< position referred to in radio message
void RespondToRadioCommands ( void ) ;
bool IsRadioCommand ( RadioType event ) const ; ///< returns true if the radio message is an order to do something
/// new-style "voice" chatter gets voice feedback
float m_voiceEndTimestamp ;
BotChatterInterface m_chatter ; ///< chatter mechanism
} ;
//
// Inlines
//
inline float CCSBot : : GetFeetZ ( void ) const
{
return GetAbsOrigin ( ) . z ;
}
inline const Vector * CCSBot : : GetNoisePosition ( void ) const
{
if ( m_noiseTimestamp > 0.0f )
return & m_noisePosition ;
return NULL ;
}
inline bool CCSBot : : IsAwareOfEnemyDeath ( void ) const
{
if ( GetEnemyDeathTimestamp ( ) = = 0.0f )
return false ;
if ( m_enemy = = NULL )
return true ;
if ( ! m_enemy - > IsAlive ( ) & & gpGlobals - > curtime - GetEnemyDeathTimestamp ( ) > ( 1.0f - 0.8f * GetProfile ( ) - > GetSkill ( ) ) )
return true ;
return false ;
}
inline void CCSBot : : Panic ( void )
{
// we are stunned for a moment
Surprise ( RandomFloat ( 0.2f , 0.3f ) ) ;
const float panicTime = 3.0f ;
m_panicTimer . Start ( panicTime ) ;
const float panicRetreatRange = 300.0f ;
TryToRetreat ( panicRetreatRange , 0.0f ) ;
PrintIfWatched ( " *** PANIC *** \n " ) ;
}
inline bool CCSBot : : IsPanicking ( void ) const
{
return ! m_panicTimer . IsElapsed ( ) ;
}
inline void CCSBot : : StopPanicking ( void )
{
m_panicTimer . Invalidate ( ) ;
}
inline bool CCSBot : : IsNotMoving ( float minDuration ) const
{
return ( m_stillTimer . HasStarted ( ) & & m_stillTimer . GetElapsedTime ( ) > = minDuration ) ;
}
inline CWeaponCSBase * CCSBot : : GetActiveCSWeapon ( void ) const
{
return reinterpret_cast < CWeaponCSBase * > ( GetActiveWeapon ( ) ) ;
}
inline float CCSBot : : GetCombatRange ( void ) const
{
return m_combatRange ;
}
inline void CCSBot : : SetRogue ( bool rogue )
{
m_isRogue = rogue ;
}
inline void CCSBot : : Hurry ( float duration )
{
m_hurryTimer . Start ( duration ) ;
}
inline float CCSBot : : GetSafeTime ( void ) const
{
return m_safeTime ;
}
inline bool CCSBot : : IsUnhealthy ( void ) const
{
return ( GetHealth ( ) < = 40 ) ;
}
inline bool CCSBot : : IsAlert ( void ) const
{
return ! m_alertTimer . IsElapsed ( ) ;
}
inline void CCSBot : : BecomeAlert ( void )
{
const float alertCooldownTime = 10.0f ;
m_alertTimer . Start ( alertCooldownTime ) ;
}
inline bool CCSBot : : IsSneaking ( void ) const
{
return ! m_sneakTimer . IsElapsed ( ) ;
}
inline void CCSBot : : Sneak ( float duration )
{
m_sneakTimer . Start ( duration ) ;
}
inline bool CCSBot : : IsFollowing ( void ) const
{
return m_isFollowing ;
}
inline CCSPlayer * CCSBot : : GetFollowLeader ( void ) const
{
return m_leader ;
}
inline float CCSBot : : GetFollowDuration ( void ) const
{
return gpGlobals - > curtime - m_followTimestamp ;
}
inline bool CCSBot : : CanAutoFollow ( void ) const
{
return ( gpGlobals - > curtime > m_allowAutoFollowTime ) ;
}
inline void CCSBot : : AimAtEnemy ( void )
{
m_isAimingAtEnemy = true ;
}
inline void CCSBot : : StopAiming ( void )
{
m_isAimingAtEnemy = false ;
}
inline bool CCSBot : : IsAimingAtEnemy ( void ) const
{
return m_isAimingAtEnemy ;
}
inline float CCSBot : : GetStateTimestamp ( void ) const
{
return m_stateTimestamp ;
}
inline CSGameState * CCSBot : : GetGameState ( void )
{
return & m_gameState ;
}
inline const CSGameState * CCSBot : : GetGameState ( void ) const
{
return & m_gameState ;
}
inline bool CCSBot : : IsAtBombsite ( void )
{
return m_bInBombZone ;
}
inline void CCSBot : : SetTask ( TaskType task , CBaseEntity * entity )
{
m_task = task ;
m_taskEntity = entity ;
}
inline CCSBot : : TaskType CCSBot : : GetTask ( void ) const
{
return m_task ;
}
inline CBaseEntity * CCSBot : : GetTaskEntity ( void )
{
return static_cast < CBaseEntity * > ( m_taskEntity ) ;
}
inline CCSBot : : MoraleType CCSBot : : GetMorale ( void ) const
{
return m_morale ;
}
inline void CCSBot : : Surprise ( float duration )
{
m_surpriseTimer . Start ( duration ) ;
}
inline bool CCSBot : : IsSurprised ( void ) const
{
return ! m_surpriseTimer . IsElapsed ( ) ;
}
inline CNavArea * CCSBot : : GetNoiseArea ( void ) const
{
return m_noiseArea ;
}
inline void CCSBot : : ForgetNoise ( void )
{
m_noiseTimestamp = 0.0f ;
}
inline float CCSBot : : GetNoiseRange ( void ) const
{
if ( IsNoiseHeard ( ) )
return m_noiseTravelDistance ;
return 999999999.9f ;
}
inline PriorityType CCSBot : : GetNoisePriority ( void ) const
{
return m_noisePriority ;
}
inline BotChatterInterface * CCSBot : : GetChatter ( void )
{
return & m_chatter ;
}
inline CCSPlayer * CCSBot : : GetBotEnemy ( void ) const
{
return m_enemy ;
}
inline int CCSBot : : GetNearbyEnemyCount ( void ) const
{
return MIN ( GetEnemiesRemaining ( ) , m_nearbyEnemyCount ) ;
}
inline unsigned int CCSBot : : GetEnemyPlace ( void ) const
{
return m_enemyPlace ;
}
inline bool CCSBot : : CanSeeBomber ( void ) const
{
return ( m_bomber = = NULL ) ? false : true ;
}
inline CCSPlayer * CCSBot : : GetBomber ( void ) const
{
return m_bomber ;
}
inline int CCSBot : : GetNearbyFriendCount ( void ) const
{
return MIN ( GetFriendsRemaining ( ) , m_nearbyFriendCount ) ;
}
inline CCSPlayer * CCSBot : : GetClosestVisibleFriend ( void ) const
{
return m_closestVisibleFriend ;
}
inline CCSPlayer * CCSBot : : GetClosestVisibleHumanFriend ( void ) const
{
return m_closestVisibleHumanFriend ;
}
inline float CCSBot : : GetTimeSinceAttacked ( void ) const
{
return gpGlobals - > curtime - m_attackedTimestamp ;
}
inline float CCSBot : : GetFirstSawEnemyTimestamp ( void ) const
{
return m_firstSawEnemyTimestamp ;
}
inline float CCSBot : : GetLastSawEnemyTimestamp ( void ) const
{
return m_lastSawEnemyTimestamp ;
}
inline float CCSBot : : GetTimeSinceLastSawEnemy ( void ) const
{
return gpGlobals - > curtime - m_lastSawEnemyTimestamp ;
}
inline float CCSBot : : GetTimeSinceAcquiredCurrentEnemy ( void ) const
{
return gpGlobals - > curtime - m_currentEnemyAcquireTimestamp ;
}
inline const Vector & CCSBot : : GetLastKnownEnemyPosition ( void ) const
{
return m_lastEnemyPosition ;
}
inline bool CCSBot : : IsEnemyVisible ( void ) const
{
return m_isEnemyVisible ;
}
inline float CCSBot : : GetEnemyDeathTimestamp ( void ) const
{
return m_enemyDeathTimestamp ;
}
inline int CCSBot : : GetLastVictimID ( void ) const
{
return m_lastVictimID ;
}
inline bool CCSBot : : CanSeeSniper ( void ) const
{
return m_isEnemySniperVisible ;
}
inline bool CCSBot : : HasSeenSniperRecently ( void ) const
{
return ! m_sawEnemySniperTimer . IsElapsed ( ) ;
}
inline float CCSBot : : GetTravelDistanceToPlayer ( CCSPlayer * player ) const
{
if ( player = = NULL )
return - 1.0f ;
if ( ! player - > IsAlive ( ) )
return - 1.0f ;
return m_playerTravelDistance [ player - > entindex ( ) % MAX_PLAYERS ] ;
}
inline bool CCSBot : : HasPath ( void ) const
{
return ( m_pathLength ) ? true : false ;
}
inline void CCSBot : : DestroyPath ( void )
{
m_isStopping = false ;
m_pathLength = 0 ;
m_pathLadder = NULL ;
}
inline CNavArea * CCSBot : : GetLastKnownArea ( void ) const
{
return m_lastKnownArea ;
}
inline const Vector & CCSBot : : GetPathEndpoint ( void ) const
{
return m_path [ m_pathLength - 1 ] . pos ;
}
inline const Vector & CCSBot : : GetPathPosition ( int index ) const
{
return m_path [ index ] . pos ;
}
inline bool CCSBot : : IsUsingLadder ( void ) const
{
return ( m_pathLadder ) ? true : false ;
}
inline void CCSBot : : SetGoalEntity ( CBaseEntity * entity )
{
m_goalEntity = entity ;
}
inline CBaseEntity * CCSBot : : GetGoalEntity ( void )
{
return m_goalEntity ;
}
inline void CCSBot : : ForceRun ( float duration )
{
Run ( ) ;
m_mustRunTimer . Start ( duration ) ;
}
inline void CCSBot : : Wait ( float duration )
{
m_waitTimer . Start ( duration ) ;
}
inline bool CCSBot : : IsWaiting ( void ) const
{
return ! m_waitTimer . IsElapsed ( ) ;
}
inline void CCSBot : : StopWaiting ( void )
{
m_waitTimer . Invalidate ( ) ;
}
inline bool CCSBot : : HasVisitedEnemySpawn ( void ) const
{
return m_hasVisitedEnemySpawn ;
}
inline const Vector & CCSBot : : EyePositionConst ( void ) const
{
return m_eyePosition ;
}
inline void CCSBot : : SetLookAngles ( float yaw , float pitch )
{
m_lookYaw = yaw ;
m_lookPitch = pitch ;
}
inline void CCSBot : : SetForwardAngle ( float angle )
{
m_forwardAngle = angle ;
}
inline void CCSBot : : SetLookAheadAngle ( float angle )
{
m_lookAheadAngle = angle ;
}
inline void CCSBot : : ClearLookAt ( void )
{
//PrintIfWatched( "ClearLookAt()\n" );
m_lookAtSpotState = NOT_LOOKING_AT_SPOT ;
m_lookAtDesc = NULL ;
}
inline bool CCSBot : : IsLookingAtSpot ( PriorityType pri ) const
{
if ( m_lookAtSpotState ! = NOT_LOOKING_AT_SPOT & & m_lookAtSpotPriority > = pri )
return true ;
return false ;
}
inline bool CCSBot : : IsViewMoving ( float angleVelThreshold ) const
{
if ( m_lookYawVel < angleVelThreshold & & m_lookYawVel > - angleVelThreshold & &
m_lookPitchVel < angleVelThreshold & & m_lookPitchVel > - angleVelThreshold )
{
return false ;
}
return true ;
}
inline bool CCSBot : : HasViewBeenSteady ( float duration ) const
{
return ( m_viewSteadyTimer . GetElapsedTime ( ) > duration ) ;
}
inline bool CCSBot : : HasLookAtTarget ( void ) const
{
return ( m_lookAtSpotState ! = NOT_LOOKING_AT_SPOT ) ;
}
inline bool CCSBot : : IsEnemyPartVisible ( VisiblePartType part ) const
{
VPROF_BUDGET ( " CCSBot::IsEnemyPartVisible " , VPROF_BUDGETGROUP_NPCS ) ;
if ( ! IsEnemyVisible ( ) )
return false ;
return ( m_visibleEnemyParts & part ) ? true : false ;
}
inline bool CCSBot : : IsSignificantlyCloser ( const CCSPlayer * testPlayer , const CCSPlayer * referencePlayer ) const
{
if ( ! referencePlayer )
return true ;
if ( ! testPlayer )
return false ;
float testDist = ( GetAbsOrigin ( ) - testPlayer - > GetAbsOrigin ( ) ) . Length ( ) ;
float referenceDist = ( GetAbsOrigin ( ) - referencePlayer - > GetAbsOrigin ( ) ) . Length ( ) ;
const float significantRangeFraction = 0.7f ;
if ( testDist < referenceDist * significantRangeFraction )
return true ;
return false ;
}
inline void CCSBot : : ClearApproachPoints ( void )
{
m_approachPointCount = 0 ;
}
inline const CNavArea * CCSBot : : GetInitialEncounterArea ( void ) const
{
return m_initialEncounterArea ;
}
inline void CCSBot : : SetInitialEncounterArea ( const CNavArea * area )
{
m_initialEncounterArea = area ;
}
inline bool CCSBot : : IsThrowingGrenade ( void ) const
{
return m_grenadeTossState ! = NOT_THROWING ;
}
inline bool CCSBot : : IsAvoidingGrenade ( void ) const
{
return ! m_isAvoidingGrenade . IsElapsed ( ) ;
}
inline void CCSBot : : PrimaryAttack ( void )
{
if ( IsUsingPistol ( ) & & ! CanActiveWeaponFire ( ) )
return ;
BaseClass : : PrimaryAttack ( ) ;
}
inline CCSBot : : ZoomType CCSBot : : GetZoomLevel ( void )
{
if ( GetFOV ( ) > 60.0f )
return NO_ZOOM ;
if ( GetFOV ( ) > 25.0f )
return LOW_ZOOM ;
return HIGH_ZOOM ;
}
inline bool CCSBot : : IsWaitingForZoom ( void ) const
{
return ! m_zoomTimer . IsElapsed ( ) ;
}
inline int CCSBot : : GetHostageEscortCount ( void ) const
{
return m_hostageEscortCount ;
}
inline void CCSBot : : IncreaseHostageEscortCount ( void )
{
+ + m_hostageEscortCount ;
}
inline void CCSBot : : ResetWaitForHostagePatience ( void )
{
m_isWaitingForHostage = false ;
m_inhibitWaitingForHostageTimer . Invalidate ( ) ;
}
inline bool CCSBot : : IsUsingVoice ( ) const
{
return m_voiceEndTimestamp > gpGlobals - > curtime ;
}
inline bool CCSBot : : IsOpeningDoor ( void ) const
{
return m_isOpeningDoor ;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Return true if the given weapon is a sniper rifle
*/
inline bool IsSniperRifle ( CWeaponCSBase * weapon )
{
if ( weapon = = NULL )
return false ;
return weapon - > IsKindOf ( WEAPONTYPE_SNIPER_RIFLE ) ;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Functor used with NavAreaBuildPath ( )
*/
class PathCost
{
public :
PathCost ( CCSBot * bot , RouteType route = SAFEST_ROUTE )
{
m_bot = bot ;
m_route = route ;
}
// HPE_TODO[pmf]: check that these new parameters are okay to be ignored
float operator ( ) ( CNavArea * area , CNavArea * fromArea , const CNavLadder * ladder , const CFuncElevator * elevator , float length )
{
float baseDangerFactor = 100.0f ; // 100
// respond to the danger modulated by our aggression (even super-aggressives pay SOME attention to danger)
float dangerFactor = ( 1.0f - ( 0.95f * m_bot - > GetProfile ( ) - > GetAggression ( ) ) ) * baseDangerFactor ;
if ( fromArea = = NULL )
{
if ( m_route = = FASTEST_ROUTE )
return 0.0f ;
// first area in path, cost is just danger
return dangerFactor * area - > GetDanger ( m_bot - > GetTeamNumber ( ) ) ;
}
else if ( ( fromArea - > GetAttributes ( ) & NAV_MESH_JUMP ) & & ( area - > GetAttributes ( ) & NAV_MESH_JUMP ) )
{
// cannot actually walk in jump areas - disallow moving from jump area to jump area
return - 1.0f ;
}
if ( area - > GetAttributes ( ) & NAV_MESH_NO_HOSTAGES & & m_bot - > GetHostageEscortCount ( ) )
{
// if we're leading hostages, don't try to go where they can't
return - 1.0f ;
}
else
{
// compute distance from previous area to this area
float dist ;
if ( ladder )
{
// ladders are slow to use
const float ladderPenalty = 1.0f ; // 3.0f;
dist = ladderPenalty * ladder - > m_length ;
// if we are currently escorting hostages, avoid ladders (hostages are confused by them)
//if (m_bot->GetHostageEscortCount())
// dist *= 100.0f;
}
else
{
dist = ( area - > GetCenter ( ) - fromArea - > GetCenter ( ) ) . Length ( ) ;
}
// compute distance travelled along path so far
float cost = dist + fromArea - > GetCostSoFar ( ) ;
// zombies ignore all path penalties
if ( cv_bot_zombie . GetBool ( ) )
return cost ;
// add cost of "jump down" pain unless we're jumping into water
if ( ! area - > IsUnderwater ( ) & & area - > IsConnected ( fromArea , NUM_DIRECTIONS ) = = false )
{
// this is a "jump down" (one way drop) transition - estimate damage we will take to traverse it
float fallDistance = - fromArea - > ComputeGroundHeightChange ( area ) ;
// if it's a drop-down ladder, estimate height from the bottom of the ladder to the lower area
if ( ladder & & ladder - > m_bottom . z < fromArea - > GetCenter ( ) . z & & ladder - > m_bottom . z > area - > GetCenter ( ) . z )
{
fallDistance = ladder - > m_bottom . z - area - > GetCenter ( ) . z ;
}
float fallDamage = m_bot - > GetApproximateFallDamage ( fallDistance ) ;
if ( fallDamage > 0.0f )
{
// if the fall would kill us, don't use it
const float deathFallMargin = 10.0f ;
if ( fallDamage + deathFallMargin > = m_bot - > GetHealth ( ) )
return - 1.0f ;
// if we need to get there in a hurry, ignore minor pain
const float painTolerance = 15.0f * m_bot - > GetProfile ( ) - > GetAggression ( ) + 10.0f ;
if ( m_route ! = FASTEST_ROUTE | | fallDamage > painTolerance )
{
// cost is proportional to how much it hurts when we fall
// 10 points - not a big deal, 50 points - ouch!
cost + = 100.0f * fallDamage * fallDamage ;
}
}
}
// if this is a "crouch" or "walk" area, add penalty
if ( area - > GetAttributes ( ) & ( NAV_MESH_CROUCH | NAV_MESH_WALK ) )
{
// these areas are very slow to move through
float penalty = ( m_route = = FASTEST_ROUTE ) ? 20.0f : 5.0f ;
// avoid crouch areas if we are rescuing hostages
if ( ( area - > GetAttributes ( ) & NAV_MESH_CROUCH ) & & m_bot - > GetHostageEscortCount ( ) )
{
penalty * = 3.0f ;
}
cost + = penalty * dist ;
}
// if this is a "jump" area, add penalty
if ( area - > GetAttributes ( ) & NAV_MESH_JUMP )
{
// jumping can slow you down
//const float jumpPenalty = (m_route == FASTEST_ROUTE) ? 100.0f : 0.5f;
const float jumpPenalty = 1.0f ;
cost + = jumpPenalty * dist ;
}
// if this is an area to avoid, add penalty
if ( area - > GetAttributes ( ) & NAV_MESH_AVOID )
{
const float avoidPenalty = 20.0f ;
cost + = avoidPenalty * dist ;
}
if ( m_route = = SAFEST_ROUTE )
{
// add in the danger of this path - danger is per unit length travelled
cost + = dist * dangerFactor * area - > GetDanger ( m_bot - > GetTeamNumber ( ) ) ;
}
if ( ! m_bot - > IsAttacking ( ) )
{
// add in cost of teammates in the way
// approximate density of teammates based on area
float size = ( area - > GetSizeX ( ) + area - > GetSizeY ( ) ) / 2.0f ;
// degenerate check
if ( size > = 1.0f )
{
// cost is proportional to the density of teammates in this area
const float costPerFriendPerUnit = 50000.0f ;
cost + = costPerFriendPerUnit * ( float ) area - > GetPlayerCount ( m_bot - > GetTeamNumber ( ) ) / size ;
}
}
return cost ;
}
}
private :
CCSBot * m_bot ;
RouteType m_route ;
} ;
//--------------------------------------------------------------------------------------------------------------
//
// Prototypes
//
extern int GetBotFollowCount ( CCSPlayer * leader ) ;
extern const Vector * FindNearbyRetreatSpot ( CCSBot * me , float maxRange = 250.0f ) ;
extern const HidingSpot * FindInitialEncounterSpot ( CBaseEntity * me , const Vector & searchOrigin , float enemyArriveTime , float maxRange , bool isSniper ) ;
# endif // _CS_BOT_H_