summaryrefslogtreecommitdiff
path: root/game/shared/cstrike/bot/bot_manager.h
blob: b7d2bd149d7931dbe1d426472361ce0414a4c1c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

// Author: Michael S. Booth ([email protected]), 2003

#ifndef BASE_CONTROL_H
#define BASE_CONTROL_H

#pragma warning( disable : 4530 )					// STL uses exceptions, but we are not compiling with them - ignore warning

extern float g_BotUpkeepInterval;					///< duration between bot upkeeps
extern float g_BotUpdateInterval;					///< duration between bot updates
const int g_BotUpdateSkipCount = 2;					///< number of upkeep periods to skip update

class CNavArea;

/// TODO: move CS-specific defines into CSBot files
enum
{
	SmokeGrenadeRadius = 155,
	FlashbangGrenadeRadius = 115,
	HEGrenadeRadius = 115,
};

//--------------------------------------------------------------------------------------------------------------
class CBaseGrenade;

/**
 * An ActiveGrenade is a representation of a grenade in the world
 * NOTE: Currently only used for smoke grenade line-of-sight testing
 * @todo Use system allow bots to avoid HE and Flashbangs
 */
class ActiveGrenade
{
public:
	ActiveGrenade( CBaseGrenade *grenadeEntity );

	void OnEntityGone( void );								///< called when the grenade in the world goes away
	void Update( void );									///< called every frame
	bool IsValid( void ) const	;							///< return true if this grenade is valid
	
	bool IsEntity( CBaseGrenade *grenade ) const		{ return (grenade == m_entity) ? true : false; }
	CBaseGrenade *GetEntity( void ) const				{ return m_entity; }

	const Vector &GetDetonationPosition( void ) const	{ return m_detonationPosition; }
	const Vector &GetPosition( void ) const;
	bool IsSmoke( void ) const							{ return m_isSmoke; }
	bool IsFlashbang( void ) const						{ return m_isFlashbang; }
	CBaseGrenade *GetGrenade( void ) { return m_entity; }
	float GetRadius( void ) const { return m_radius; }
	void SetRadius( float radius ) { m_radius = radius; }

private:
	CBaseGrenade *m_entity;									///< the entity
	Vector m_detonationPosition;							///< the location where the grenade detonated (smoke)
	float m_dieTimestamp;									///< time this should go away after m_entity is NULL
	bool m_isSmoke;											///< true if this is a smoke grenade
	bool m_isFlashbang;										///< true if this is a flashbang grenade
	float m_radius;
};

typedef CUtlLinkedList<ActiveGrenade *> ActiveGrenadeList;


//--------------------------------------------------------------------------------------------------------------
/**
 * This class manages all active bots, propagating events to them and updating them.
 */
class CBotManager
{
public:
	CBotManager();
	virtual ~CBotManager();

	CBasePlayer *AllocateAndBindBotEntity( edict_t *ed );			///< allocate the appropriate entity for the bot and bind it to the given edict
	virtual CBasePlayer *AllocateBotEntity( void ) = 0;				///< factory method to allocate the appropriate entity for the bot 

	virtual void ClientDisconnect( CBaseEntity *entity ) = 0;
	virtual bool ClientCommand( CBasePlayer *player, const CCommand &args ) = 0;

	virtual void ServerActivate( void ) = 0;
	virtual void ServerDeactivate( void ) = 0;
	virtual bool ServerCommand( const char * pcmd ) = 0;

	virtual void RestartRound( void );							///< (EXTEND) invoked when a new round begins
	virtual void StartFrame( void );							///< (EXTEND) called each frame

	virtual unsigned int GetPlayerPriority( CBasePlayer *player ) const = 0;	///< return priority of player (0 = max pri)
	

	void AddGrenade( CBaseGrenade *grenade );					///< add an active grenade to the bot's awareness
	void RemoveGrenade( CBaseGrenade *grenade );				///< the grenade entity in the world is going away
	void SetGrenadeRadius( CBaseGrenade *grenade, float radius );	///< the radius of the grenade entity (or associated smoke cloud)
	void ValidateActiveGrenades( void );						///< destroy any invalid active grenades
	void DestroyAllGrenades( void );
	bool IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat = 1.0f );	///< return true if line intersects smoke volume, with grenade radius increased by the grenadeBloat factor
	bool IsInsideSmokeCloud( const Vector *pos );				///< return true if position is inside a smoke cloud

	//
	// Invoke functor on all active grenades.
	// If any functor call return false, return false.  Otherwise, return true.
	//
	template < typename T >
	bool ForEachGrenade( T &func )
	{
		int it = m_activeGrenadeList.Head();

		while( it != m_activeGrenadeList.InvalidIndex() )
		{
			ActiveGrenade *ag = m_activeGrenadeList[ it ];

			int current = it;
			it = m_activeGrenadeList.Next( it );

			// lazy validation
			if (!ag->IsValid())
			{
				m_activeGrenadeList.Remove( current );
				delete ag;
				continue;
			}
			else
			{
				if (func( ag ) == false)
				{
					return false;
				}
			}
		}

		return true;
	}

	enum { MAX_DBG_MSG_SIZE = 1024 };
	struct DebugMessage
	{
		char m_string[ MAX_DBG_MSG_SIZE ];
		IntervalTimer m_age;
	};

	// debug message history -------------------------------------------------------------------------------
	int GetDebugMessageCount( void ) const;						///< get number of debug messages in history
	const DebugMessage *GetDebugMessage( int which = 0 ) const;	///< return the debug message emitted by the bot (0 = most recent)
	void ClearDebugMessages( void );
	void AddDebugMessage( const char *msg );


private:
	ActiveGrenadeList m_activeGrenadeList;///< the list of active grenades the bots are aware of

	enum { MAX_DBG_MSGS = 6 };
	DebugMessage m_debugMessage[ MAX_DBG_MSGS ];				///< debug message history
	int m_debugMessageCount;
	int m_currentDebugMessage;

	IntervalTimer m_frameTimer;									///< for measuring each frame's duration
};


inline CBasePlayer *CBotManager::AllocateAndBindBotEntity( edict_t *ed )
{
	CBasePlayer::s_PlayerEdict = ed;
	return AllocateBotEntity();
}

inline int CBotManager::GetDebugMessageCount( void ) const
{
	return m_debugMessageCount;
}

inline const CBotManager::DebugMessage *CBotManager::GetDebugMessage( int which ) const
{
	if (which >= m_debugMessageCount)
		return NULL;

	int i = m_currentDebugMessage - which;
	if (i < 0)
		i += MAX_DBG_MSGS;

	return &m_debugMessage[ i ];
}





// global singleton to create and control bots
extern CBotManager *TheBots;


#endif