You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2005 lines
75 KiB
2005 lines
75 KiB
5 years ago
|
//========= 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 );
|
||
|
|
||
|
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_
|
||
|
|