2015-06-30 12:46:07 +03:00
# include "precompiled.h"
/*
* Globals initialization
*/
# ifndef HOOK_GAMEDLL
CBotManager * TheBots = NULL ;
2016-01-19 14:54:31 +03:00
float CCSBotManager : : m_flNextCVarCheck = 0.0f ;
bool CCSBotManager : : m_isMapDataLoaded = false ;
bool CCSBotManager : : m_isLearningMap = false ;
bool CCSBotManager : : m_isAnalysisRequested = false ;
NavEditCmdType CCSBotManager : : m_editCmd = EDIT_NONE ;
2015-06-30 12:46:07 +03:00
2016-02-23 02:13:52 +03:00
# endif
2015-06-30 12:46:07 +03:00
2016-02-04 03:18:26 +03:00
CCSBotManager : : CCSBotManager ( )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
IMPL ( m_flNextCVarCheck ) = 0.0f ;
m_zoneCount = 0 ;
SetLooseBomb ( NULL ) ;
m_isBombPlanted = false ;
m_bombDefuser = NULL ;
2016-02-04 03:18:26 +03:00
2016-01-19 14:54:31 +03:00
IMPL ( m_isLearningMap ) = false ;
IMPL ( m_isAnalysisRequested ) = false ;
IMPL ( m_editCmd ) = EDIT_NONE ;
2016-02-23 02:13:52 +03:00
m_navPlace = 0 ;
2016-01-19 14:54:31 +03:00
m_roundStartTimestamp = 0.0f ;
m_bServerActive = false ;
2016-01-28 02:50:27 +03:00
TheBotPhrases = new BotPhraseManager ;
2016-01-19 14:54:31 +03:00
// load the database of bot radio chatter
TheBotPhrases - > Initialize ( " BotChatter.db " , 0 ) ;
TheBotProfiles = new BotProfileManager ;
// make sure default voice bank is first
TheBotProfiles - > FindVoiceBankIndex ( " BotChatter.db " ) ;
const char * filename ;
if ( IS_CAREER_MATCH ( ) )
{
filename = " MissionPacks/BotPackList.db " ;
}
else
{
filename = " BotPackList.db " ;
}
// read in the list of bot profile DBs
int dataLength ;
char * dataPointer = ( char * ) LOAD_FILE_FOR_ME ( ( char * ) filename , & dataLength ) ;
if ( dataPointer = = NULL )
{
TheBotProfiles - > Init ( " BotProfile.db " ) ;
}
else
{
const char * dataFile = SharedParse ( dataPointer ) ;
const char * token ;
while ( dataFile ! = NULL )
{
token = SharedGetToken ( ) ;
char * clone = CloneString ( token ) ;
TheBotProfiles - > Init ( clone ) ;
delete [ ] clone ;
dataFile = SharedParse ( dataFile ) ;
}
FREE_FILE ( dataPointer ) ;
}
// Now that we've parsed all the profiles, we have a list of the voice banks they're using.
// Go back and parse the custom voice speakables.
const BotProfileManager : : VoiceBankList * pVoiceBanks = TheBotProfiles - > GetVoiceBanks ( ) ;
for ( uint32 i = 1 ; i < pVoiceBanks - > size ( ) ; + + i )
{
TheBotPhrases - > Initialize ( ( * pVoiceBanks ) [ i ] , i ) ;
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Invoked when a new round begins
2016-02-04 03:18:26 +03:00
void CCSBotManager : : __MAKE_VHOOK ( RestartRound ) ( )
2015-06-30 12:46:07 +03:00
{
2015-09-16 23:19:21 +03:00
// extend
CBotManager : : RestartRound ( ) ;
SetLooseBomb ( NULL ) ;
m_isBombPlanted = false ;
2016-01-19 14:54:31 +03:00
m_earliestBombPlantTimestamp = gpGlobals - > time + RANDOM_FLOAT ( 10.0f , 30.0f ) ;
2015-09-16 23:19:21 +03:00
m_bombDefuser = NULL ;
2015-12-09 01:39:54 +03:00
IMPL ( m_editCmd ) = EDIT_NONE ;
2015-09-16 23:19:21 +03:00
ResetRadioMessageTimestamps ( ) ;
2016-01-19 14:54:31 +03:00
2015-09-16 23:19:21 +03:00
m_lastSeenEnemyTimestamp = - 9999.9f ;
2016-01-19 14:54:31 +03:00
2015-09-16 23:19:21 +03:00
m_roundStartTimestamp = gpGlobals - > time + CVAR_GET_FLOAT ( " mp_freezetime " ) ;
// randomly decide if defensive team wants to "rush" as a whole
const float defenseRushChance = 33.3f ; // 25.0f;
2016-01-19 14:54:31 +03:00
m_isDefenseRushing = ( RANDOM_FLOAT ( 0.0f , 100.0f ) < = defenseRushChance ) ? true : false ;
2015-09-16 23:19:21 +03:00
TheBotPhrases - > OnRoundRestart ( ) ;
2015-08-02 20:45:57 +03:00
m_isRoundOver = false ;
m_isRespawnStarted = false ;
m_canRespawn = true ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
void UTIL_DrawBox ( Extent * extent , int lifetime , int red , int green , int blue )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
Vector v [ 8 ] ;
v [ 0 ] . x = extent - > lo . x ; v [ 0 ] . y = extent - > lo . y ; v [ 0 ] . z = extent - > lo . z ;
v [ 1 ] . x = extent - > hi . x ; v [ 1 ] . y = extent - > lo . y ; v [ 1 ] . z = extent - > lo . z ;
v [ 2 ] . x = extent - > hi . x ; v [ 2 ] . y = extent - > hi . y ; v [ 2 ] . z = extent - > lo . z ;
v [ 3 ] . x = extent - > lo . x ; v [ 3 ] . y = extent - > hi . y ; v [ 3 ] . z = extent - > lo . z ;
v [ 4 ] . x = extent - > lo . x ; v [ 4 ] . y = extent - > lo . y ; v [ 4 ] . z = extent - > hi . z ;
v [ 5 ] . x = extent - > hi . x ; v [ 5 ] . y = extent - > lo . y ; v [ 5 ] . z = extent - > hi . z ;
v [ 6 ] . x = extent - > hi . x ; v [ 6 ] . y = extent - > hi . y ; v [ 6 ] . z = extent - > hi . z ;
v [ 7 ] . x = extent - > lo . x ; v [ 7 ] . y = extent - > hi . y ; v [ 7 ] . z = extent - > hi . z ;
static int edge [ ] =
{
1 , 2 , 3 , 4 , - 1 ,
5 , 6 , 7 , 8 , - 5 ,
1 , - 5 ,
2 , - 6 ,
3 , - 7 ,
4 , - 8 ,
0 // end iterator
} ;
Vector from , to ;
bool restart = true ;
for ( int i = 0 ; edge [ i ] ! = 0 ; + + i )
{
if ( restart )
{
to = v [ edge [ i ] - 1 ] ;
restart = false ;
continue ;
}
from = to ;
int index = edge [ i ] ;
if ( index < 0 )
{
restart = true ;
index = - index ;
}
to = v [ index - 1 ] ;
UTIL_DrawBeamPoints ( from , to , lifetime , red , green , blue ) ;
UTIL_DrawBeamPoints ( to , from , lifetime , red , green , blue ) ;
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Called each frame
2016-02-04 03:18:26 +03:00
void CCSBotManager : : __MAKE_VHOOK ( StartFrame ) ( )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
// EXTEND
CBotManager : : StartFrame ( ) ;
MonitorBotCVars ( ) ;
2015-06-30 12:46:07 +03:00
2016-01-19 14:54:31 +03:00
// debug zone extent visualization
if ( cv_bot_debug . value = = 5.0f )
{
for ( int z = 0 ; z < m_zoneCount ; + + z )
{
Zone * zone = & m_zone [ z ] ;
UTIL_DrawBox ( & zone - > m_extent , 1 , 255 , 100 , 0 ) ;
}
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return true if the bot can use this weapon
2015-08-20 13:35:01 +03:00
bool CCSBotManager : : IsWeaponUseable ( CBasePlayerItem * item ) const
2015-06-30 12:46:07 +03:00
{
2015-08-20 13:35:01 +03:00
if ( item = = NULL )
{
return false ;
}
2016-01-19 14:54:31 +03:00
if ( item - > m_iId = = WEAPON_C4 )
return true ;
2015-08-20 13:35:01 +03:00
2016-01-19 14:54:31 +03:00
int weaponClass = WeaponIDToWeaponClass ( item - > m_iId ) ;
if ( ( ! AllowShotguns ( ) & & weaponClass = = WEAPONCLASS_SHOTGUN )
| | ( ! AllowMachineGuns ( ) & & weaponClass = = WEAPONCLASS_MACHINEGUN )
| | ( ! AllowRifles ( ) & & weaponClass = = WEAPONCLASS_RIFLE )
# ifndef REGAMEDLL_FIXES
// TODO: already is checked shotguns!
| | ( ! AllowShotguns ( ) & & weaponClass = = WEAPONCLASS_SHOTGUN )
2016-02-23 02:13:52 +03:00
# endif
2016-01-19 14:54:31 +03:00
| | ( ! AllowSnipers ( ) & & weaponClass = = WEAPONCLASS_SNIPERRIFLE )
| | ( ! AllowSubMachineGuns ( ) & & weaponClass = = WEAPONCLASS_SUBMACHINEGUN )
| | ( ! AllowTacticalShield ( ) & & item - > m_iId = = WEAPON_SHIELDGUN )
| | ( ! AllowPistols ( ) & & weaponClass = = WEAPONCLASS_PISTOL )
| | ( ! AllowGrenades ( ) & & weaponClass = = WEAPONCLASS_GRENADE ) )
{
return false ;
2015-08-20 13:35:01 +03:00
}
return true ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return true if this player is on "defense"
bool CCSBotManager : : IsOnDefense ( CBasePlayer * player ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
switch ( GetScenario ( ) )
{
case SCENARIO_DEFUSE_BOMB :
return ( player - > m_iTeam = = CT ) ;
case SCENARIO_RESCUE_HOSTAGES :
return ( player - > m_iTeam = = TERRORIST ) ;
case SCENARIO_ESCORT_VIP :
return ( player - > m_iTeam = = TERRORIST ) ;
}
return false ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return true if this player is on "offense"
bool CCSBotManager : : IsOnOffense ( CBasePlayer * player ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
return ! IsOnDefense ( player ) ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Invoked when a map has just been loaded
2016-02-04 03:18:26 +03:00
void CCSBotManager : : __MAKE_VHOOK ( ServerActivate ) ( )
2015-06-30 12:46:07 +03:00
{
2015-08-02 20:45:57 +03:00
DestroyNavigationMap ( ) ;
2015-12-09 01:39:54 +03:00
IMPL ( m_isMapDataLoaded ) = false ;
2015-06-30 12:46:07 +03:00
2015-08-02 20:45:57 +03:00
m_zoneCount = 0 ;
m_gameScenario = SCENARIO_DEATHMATCH ;
2015-06-30 12:46:07 +03:00
2015-08-02 20:45:57 +03:00
ValidateMapData ( ) ;
RestartRound ( ) ;
2015-06-30 12:46:07 +03:00
2015-12-09 01:39:54 +03:00
IMPL ( m_isLearningMap ) = false ;
IMPL ( m_isAnalysisRequested ) = false ;
2015-08-02 20:45:57 +03:00
m_bServerActive = true ;
AddServerCommands ( ) ;
2015-12-05 22:40:30 +03:00
TheBotPhrases - > OnMapChange ( ) ;
2015-06-30 12:46:07 +03:00
}
2015-08-20 13:35:01 +03:00
void CCSBotManager : : __MAKE_VHOOK ( AddServerCommand ) ( const char * cmd )
2015-06-30 12:46:07 +03:00
{
2015-08-02 20:45:57 +03:00
ADD_SERVER_COMMAND ( ( char * ) cmd , Bot_ServerCommand ) ;
2015-06-30 12:46:07 +03:00
}
2016-02-04 03:18:26 +03:00
void CCSBotManager : : __MAKE_VHOOK ( AddServerCommands ) ( )
2015-06-30 12:46:07 +03:00
{
2015-08-02 20:45:57 +03:00
static bool fFirstTime = true ;
if ( ! fFirstTime )
return ;
fFirstTime = false ;
2016-02-23 02:13:52 +03:00
if ( ! AreBotsAllowed ( ) )
return ;
AddServerCommand ( " bot_about " ) ;
AddServerCommand ( " bot_add " ) ;
AddServerCommand ( " bot_add_t " ) ;
AddServerCommand ( " bot_add_ct " ) ;
AddServerCommand ( " bot_kill " ) ;
AddServerCommand ( " bot_kick " ) ;
AddServerCommand ( " bot_knives_only " ) ;
AddServerCommand ( " bot_pistols_only " ) ;
AddServerCommand ( " bot_snipers_only " ) ;
AddServerCommand ( " bot_all_weapons " ) ;
AddServerCommand ( " entity_dump " ) ;
AddServerCommand ( " bot_nav_delete " ) ;
AddServerCommand ( " bot_nav_split " ) ;
AddServerCommand ( " bot_nav_merge " ) ;
AddServerCommand ( " bot_nav_mark " ) ;
AddServerCommand ( " bot_nav_begin_area " ) ;
AddServerCommand ( " bot_nav_end_area " ) ;
AddServerCommand ( " bot_nav_connect " ) ;
AddServerCommand ( " bot_nav_disconnect " ) ;
AddServerCommand ( " bot_nav_splice " ) ;
AddServerCommand ( " bot_nav_crouch " ) ;
AddServerCommand ( " bot_nav_jump " ) ;
AddServerCommand ( " bot_nav_precise " ) ;
AddServerCommand ( " bot_nav_no_jump " ) ;
AddServerCommand ( " bot_nav_analyze " ) ;
AddServerCommand ( " bot_nav_strip " ) ;
AddServerCommand ( " bot_nav_save " ) ;
AddServerCommand ( " bot_nav_load " ) ;
AddServerCommand ( " bot_nav_use_place " ) ;
AddServerCommand ( " bot_nav_place_floodfill " ) ;
AddServerCommand ( " bot_nav_place_pick " ) ;
AddServerCommand ( " bot_nav_toggle_place_mode " ) ;
AddServerCommand ( " bot_nav_toggle_place_painting " ) ;
AddServerCommand ( " bot_goto_mark " ) ;
AddServerCommand ( " bot_memory_usage " ) ;
AddServerCommand ( " bot_nav_mark_unnamed " ) ;
AddServerCommand ( " bot_nav_warp " ) ;
AddServerCommand ( " bot_nav_corner_select " ) ;
AddServerCommand ( " bot_nav_corner_raise " ) ;
AddServerCommand ( " bot_nav_corner_lower " ) ;
AddServerCommand ( " bot_nav_check_consistency " ) ;
2015-08-02 20:45:57 +03:00
}
2016-02-04 03:18:26 +03:00
void CCSBotManager : : __MAKE_VHOOK ( ServerDeactivate ) ( )
2015-08-02 20:45:57 +03:00
{
m_bServerActive = false ;
}
2015-08-20 13:35:01 +03:00
void CCSBotManager : : __MAKE_VHOOK ( ClientDisconnect ) ( CBasePlayer * pPlayer )
2015-09-16 23:19:21 +03:00
{
2016-01-19 14:54:31 +03:00
if ( pPlayer ! = NULL & & pPlayer - > IsBot ( ) )
{
entvars_t * temp = VARS ( pPlayer - > edict ( ) ) ;
2016-02-23 02:13:52 +03:00
CCSBot * pBot = dynamic_cast < CCSBot * > ( pPlayer ) ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
if ( pBot ! = NULL )
{
pBot - > Disconnect ( ) ;
}
2015-09-16 23:19:21 +03:00
2016-01-19 14:54:31 +03:00
if ( ! FStringNull ( pPlayer - > pev - > classname ) )
{
RemoveEntityHashValue ( pPlayer - > pev , STRING ( pPlayer - > pev - > classname ) , CLASSNAME ) ;
}
2015-09-16 23:19:21 +03:00
2016-01-19 14:54:31 +03:00
FREE_PRIVATE ( pPlayer - > edict ( ) ) ;
2015-09-16 23:19:21 +03:00
2016-03-17 20:44:52 +03:00
CBasePlayer * player = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) temp ) ;
2016-01-19 14:54:31 +03:00
AddEntityHashValue ( player - > pev , STRING ( player - > pev - > classname ) , CLASSNAME ) ;
player - > pev - > flags = FL_DORMANT ;
}
2015-06-30 12:46:07 +03:00
}
2016-02-04 03:18:26 +03:00
void PrintAllEntities ( )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
for ( int i = 1 ; i < gpGlobals - > maxEntities ; + + i )
2015-08-02 20:45:57 +03:00
{
edict_t * edict = INDEXENT ( i ) ;
if ( ! edict | | FStringNull ( edict - > v . classname ) )
continue ;
2015-09-16 23:19:21 +03:00
2015-08-02 20:45:57 +03:00
CONSOLE_ECHO ( " %s \n " , STRING ( edict - > v . classname ) ) ;
}
2015-06-30 12:46:07 +03:00
}
2015-08-20 13:35:01 +03:00
void CCSBotManager : : __MAKE_VHOOK ( ServerCommand ) ( const char * pcmd )
2015-06-30 12:46:07 +03:00
{
2016-02-23 02:13:52 +03:00
if ( ! m_bServerActive | | ! AreBotsAllowed ( ) )
2015-08-02 20:45:57 +03:00
return ;
char buffer [ 400 ] ;
const char * msg = CMD_ARGV ( 1 ) ;
if ( FStrEq ( pcmd , " bot_about " ) )
{
2016-04-05 03:12:05 +03:00
Q_sprintf ( buffer , " \n -------------------------------------------------------------------------- \n The Official Counter-Strike Bot V%d.%02d \n Created by Michael S. Booth \n Web: www.turtlerockstudios.com \\ csbot \n E-mail: csbot@turtlerockstudios.com \n -------------------------------------------------------------------------- \n \n " , BOT_VERSION_MAJOR , BOT_VERSION_MINOR ) ;
2015-08-02 20:45:57 +03:00
CONSOLE_ECHO ( buffer ) ;
HintMessageToAllPlayers ( buffer ) ;
}
else if ( FStrEq ( pcmd , " bot_add " ) )
{
2016-01-19 14:54:31 +03:00
BotAddCommand ( BOT_TEAM_ANY , FROM_CONSOLE ) ;
2015-08-02 20:45:57 +03:00
}
else if ( FStrEq ( pcmd , " bot_add_t " ) )
{
2016-01-19 14:54:31 +03:00
BotAddCommand ( BOT_TEAM_T , FROM_CONSOLE ) ;
2015-08-02 20:45:57 +03:00
}
else if ( FStrEq ( pcmd , " bot_add_ct " ) )
{
2016-01-19 14:54:31 +03:00
BotAddCommand ( BOT_TEAM_CT , FROM_CONSOLE ) ;
2015-08-02 20:45:57 +03:00
}
else if ( FStrEq ( pcmd , " bot_kill " ) )
{
bool killThemAll ;
if ( CMD_ARGC ( ) = = 1 | | FStrEq ( msg , " all " ) )
killThemAll = true ;
else
killThemAll = false ;
2016-01-19 14:54:31 +03:00
for ( int iIndex = 1 ; iIndex < = gpGlobals - > maxClients ; + + iIndex )
2015-08-02 20:45:57 +03:00
{
2016-01-19 14:54:31 +03:00
CBasePlayer * pPlayer = static_cast < CBasePlayer * > ( UTIL_PlayerByIndex ( iIndex ) ) ;
2015-08-02 20:45:57 +03:00
if ( pPlayer = = NULL )
continue ;
if ( FNullEnt ( pPlayer - > pev ) )
continue ;
const char * name = STRING ( pPlayer - > pev - > netname ) ;
if ( FStrEq ( name , " " ) )
continue ;
if ( pPlayer - > IsBot ( ) )
{
if ( killThemAll | | FStrEq ( name , msg ) )
{
pPlayer - > TakeDamage ( pPlayer - > pev , pPlayer - > pev , 9999.9f , DMG_CRUSH ) ;
}
}
}
}
else if ( FStrEq ( pcmd , " bot_kick " ) )
{
bool kickThemAll ;
if ( CMD_ARGC ( ) = = 1 | | FStrEq ( msg , " all " ) )
kickThemAll = true ;
else
kickThemAll = false ;
2016-01-19 14:54:31 +03:00
for ( int iIndex = 1 ; iIndex < = gpGlobals - > maxClients ; + + iIndex )
2015-08-02 20:45:57 +03:00
{
2016-01-19 14:54:31 +03:00
CBasePlayer * pPlayer = static_cast < CBasePlayer * > ( UTIL_PlayerByIndex ( iIndex ) ) ;
2015-08-02 20:45:57 +03:00
if ( pPlayer = = NULL )
continue ;
if ( FNullEnt ( pPlayer - > pev ) )
continue ;
const char * name = STRING ( pPlayer - > pev - > netname ) ;
if ( FStrEq ( name , " " ) )
continue ;
if ( pPlayer - > IsBot ( ) )
{
if ( kickThemAll | | FStrEq ( name , msg ) )
{
2016-01-19 14:54:31 +03:00
// adjust bot quota so kicked bot is not immediately added back in
int newQuota = cv_bot_quota . value - 1 ;
2015-08-02 20:45:57 +03:00
SERVER_COMMAND ( UTIL_VarArgs ( " kick \" %s \" \n " , name ) ) ;
2016-02-23 02:13:52 +03:00
CVAR_SET_FLOAT ( " bot_quota " , clamp ( newQuota , 0 , int ( cv_bot_quota . value ) ) ) ;
2015-08-02 20:45:57 +03:00
}
}
}
if ( kickThemAll | | cv_bot_quota . value < 0.0f )
{
CVAR_SET_FLOAT ( " bot_quota " , 0 ) ;
}
}
else if ( FStrEq ( pcmd , " bot_knives_only " ) )
{
CVAR_SET_FLOAT ( " bot_allow_pistols " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_shotguns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_sub_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_rifles " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_grenades " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_snipers " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_shield " , 0 ) ;
}
else if ( FStrEq ( pcmd , " bot_pistols_only " ) )
{
CVAR_SET_FLOAT ( " bot_allow_pistols " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_shotguns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_sub_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_rifles " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_grenades " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_snipers " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_shield " , 0 ) ;
}
else if ( FStrEq ( pcmd , " bot_snipers_only " ) )
{
CVAR_SET_FLOAT ( " bot_allow_pistols " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_shotguns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_sub_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_rifles " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_machine_guns " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_grenades " , 0 ) ;
CVAR_SET_FLOAT ( " bot_allow_snipers " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_shield " , 0 ) ;
}
else if ( FStrEq ( pcmd , " bot_all_weapons " ) )
{
CVAR_SET_FLOAT ( " bot_allow_pistols " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_shotguns " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_sub_machine_guns " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_rifles " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_machine_guns " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_grenades " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_snipers " , 1 ) ;
CVAR_SET_FLOAT ( " bot_allow_shield " , 1 ) ;
}
else if ( FStrEq ( pcmd , " entity_dump " ) )
{
PrintAllEntities ( ) ;
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_nav_delete " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_DELETE ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_split " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_SPLIT ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_merge " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_MERGE ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_mark " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_MARK ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_begin_area " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_BEGIN_AREA ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_end_area " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_END_AREA ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_connect " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_CONNECT ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_disconnect " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_DISCONNECT ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_splice " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_SPLICE ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_crouch " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_ATTRIB_CROUCH ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_jump " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_ATTRIB_JUMP ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_precise " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_ATTRIB_PRECISE ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_no_jump " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_ATTRIB_NO_JUMP ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_analyze " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_isAnalysisRequested ) = true ;
2015-08-02 20:45:57 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_strip " ) )
{
2016-01-19 14:54:31 +03:00
StripNavigationAreas ( ) ;
2015-08-02 20:45:57 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_save " ) )
{
GET_GAME_DIR ( buffer ) ;
2016-01-27 13:05:04 +03:00
Q_strcat ( buffer , " \\ " ) ;
2015-08-02 20:45:57 +03:00
Q_strcat ( buffer , CBotManager : : GetNavMapFilename ( ) ) ;
2016-01-19 14:54:31 +03:00
if ( SaveNavigationMap ( buffer ) )
2015-08-02 20:45:57 +03:00
CONSOLE_ECHO ( " Navigation map '%s' saved. \n " , buffer ) ;
else
CONSOLE_ECHO ( " ERROR: Cannot save navigation map '%s'. \n " , buffer ) ;
}
else if ( FStrEq ( pcmd , " bot_nav_load " ) )
{
ValidateMapData ( ) ;
}
else if ( FStrEq ( pcmd , " bot_nav_use_place " ) )
{
if ( CMD_ARGC ( ) = = 1 )
{
2016-01-19 14:54:31 +03:00
// no arguments = list all available places
2015-08-02 20:45:57 +03:00
int i = 0 ;
const BotPhraseList * placeList = TheBotPhrases - > GetPlaceList ( ) ;
2016-01-19 14:54:31 +03:00
for ( BotPhraseList : : const_iterator iter = placeList - > begin ( ) ; iter ! = placeList - > end ( ) ; + + iter , + + i )
2015-08-02 20:45:57 +03:00
{
2016-02-23 02:13:52 +03:00
const BotPhrase * phrase = ( * iter ) ;
if ( phrase - > GetID ( ) = = GetNavPlace ( ) )
CONSOLE_ECHO ( " --> %-26s " , phrase - > GetName ( ) ) ;
2015-08-02 20:45:57 +03:00
else
2016-02-23 02:13:52 +03:00
CONSOLE_ECHO ( " %-30s " , phrase - > GetName ( ) ) ;
2015-08-02 20:45:57 +03:00
if ( ! ( i % 3 ) )
CONSOLE_ECHO ( " \n " ) ;
}
CONSOLE_ECHO ( " \n " ) ;
}
else
{
2016-01-19 14:54:31 +03:00
// single argument = set current place
2015-08-02 20:45:57 +03:00
const BotPhraseList * placeList = TheBotPhrases - > GetPlaceList ( ) ;
const BotPhrase * found = NULL ;
bool isAmbiguous = false ;
for ( BotPhraseList : : const_iterator iter = placeList - > begin ( ) ; iter ! = placeList - > end ( ) ; + + iter )
{
2016-02-23 02:13:52 +03:00
const BotPhrase * phrase = ( * iter ) ;
if ( ! Q_strnicmp ( phrase - > GetName ( ) , msg , Q_strlen ( msg ) ) )
2015-08-02 20:45:57 +03:00
{
2016-01-19 14:54:31 +03:00
// check for exact match in case of subsets of other strings
2016-02-23 02:13:52 +03:00
if ( ! Q_strcmp ( phrase - > GetName ( ) , msg ) )
2015-08-02 20:45:57 +03:00
{
2016-02-23 02:13:52 +03:00
found = phrase ;
2016-01-19 14:54:31 +03:00
isAmbiguous = false ;
2015-08-02 20:45:57 +03:00
break ;
}
if ( found ! = NULL )
2016-01-19 14:54:31 +03:00
{
2015-08-02 20:45:57 +03:00
isAmbiguous = true ;
2016-01-19 14:54:31 +03:00
}
2015-08-02 20:45:57 +03:00
else
2016-01-19 14:54:31 +03:00
{
2016-02-23 02:13:52 +03:00
found = phrase ;
2016-01-19 14:54:31 +03:00
}
2015-08-02 20:45:57 +03:00
}
}
if ( isAmbiguous )
{
CONSOLE_ECHO ( " Ambiguous \n " ) ;
}
2016-01-19 14:54:31 +03:00
else
2015-08-02 20:45:57 +03:00
{
CONSOLE_ECHO ( " Current place set to '%s' \n " , found - > GetName ( ) ) ;
2016-02-23 22:54:07 +03:00
SetNavPlace ( found - > GetID ( ) ) ;
2015-08-02 20:45:57 +03:00
}
}
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_nav_toggle_place_mode " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_TOGGLE_PLACE_MODE ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_place_floodfill " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_PLACE_FLOODFILL ;
2015-08-02 20:45:57 +03:00
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_nav_place_pick " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_PLACE_PICK ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_toggle_place_painting " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_TOGGLE_PLACE_PAINTING ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_goto_mark " ) )
2015-08-02 20:45:57 +03:00
{
// tell the first bot we find to go to our marked area
2016-01-19 14:54:31 +03:00
CNavArea * area = GetMarkedArea ( ) ;
2015-08-02 20:45:57 +03:00
if ( area ! = NULL )
{
CBaseEntity * pEntity = NULL ;
while ( ( pEntity = UTIL_FindEntityByClassname ( pEntity , " player " ) ) ! = NULL )
{
if ( ! pEntity - > IsPlayer ( ) )
continue ;
if ( ( pEntity - > pev - > flags & FL_DORMANT ) = = FL_DORMANT )
continue ;
2016-03-17 20:44:52 +03:00
CBasePlayer * playerOrBot = GetClassPtr < CCSPlayer > ( ( CBasePlayer * ) pEntity - > pev ) ;
2015-08-02 20:45:57 +03:00
if ( playerOrBot - > IsBot ( ) )
{
2016-01-19 14:54:31 +03:00
CCSBot * bot = static_cast < CCSBot * > ( playerOrBot ) ;
if ( bot ! = NULL )
{
bot - > MoveTo ( & area - > m_center , FASTEST_ROUTE ) ;
}
break ;
2015-08-02 20:45:57 +03:00
}
}
}
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_memory_usage " ) )
2015-08-02 20:45:57 +03:00
{
CONSOLE_ECHO ( " Memory usage: \n " ) ;
CONSOLE_ECHO ( " %d bytes per bot \b " , sizeof ( CCSBot ) ) ;
CONSOLE_ECHO ( " %d Navigation Areas @ %d bytes each = %d bytes \n " ,
TheNavAreaGrid . GetNavAreaCount ( ) ,
sizeof ( CNavArea ) ,
TheNavAreaGrid . GetNavAreaCount ( ) * sizeof ( CNavArea ) ) ;
CONSOLE_ECHO ( " %d Hiding Spots @ %d bytes each = %d bytes \n " ,
TheHidingSpotList . size ( ) ,
sizeof ( HidingSpot ) ,
sizeof ( HidingSpot ) * TheHidingSpotList . size ( ) ) ;
unsigned int encounterMem = 0 ;
for ( NavAreaList : : iterator iter = TheNavAreaList . begin ( ) ; iter ! = TheNavAreaList . end ( ) ; + + iter )
{
CNavArea * area = ( * iter ) ;
for ( SpotEncounterList : : iterator siter = area - > m_spotEncounterList . begin ( ) ; siter ! = area - > m_spotEncounterList . end ( ) ; + + siter )
{
SpotEncounter se = ( * siter ) ;
encounterMem + = sizeof ( SpotEncounter ) ;
encounterMem + = sizeof ( SpotOrder ) * se . spotList . size ( ) ;
}
}
CONSOLE_ECHO ( " Encounter Spot data = %d bytes \n " , encounterMem ) ;
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_nav_mark_unnamed " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_MARK_UNNAMED ;
2015-08-02 20:45:57 +03:00
}
2015-09-16 23:19:21 +03:00
else if ( FStrEq ( pcmd , " bot_nav_warp " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_WARP_TO_MARK ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_corner_select " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_SELECT_CORNER ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_corner_raise " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_RAISE_CORNER ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_corner_lower " ) )
{
2016-01-19 14:54:31 +03:00
IMPL ( m_editCmd ) = EDIT_LOWER_CORNER ;
2015-09-16 23:19:21 +03:00
}
else if ( FStrEq ( pcmd , " bot_nav_check_consistency " ) )
2015-08-02 20:45:57 +03:00
{
if ( CMD_ARGC ( ) ! = 2 )
{
CONSOLE_ECHO ( " usage: bot_nav_check_consistency <filename> \n " ) ;
return ;
}
2016-01-19 14:54:31 +03:00
SanityCheckNavigationMap ( msg ) ;
2015-08-02 20:45:57 +03:00
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
BOOL CCSBotManager : : __MAKE_VHOOK ( ClientCommand ) ( CBasePlayer * pPlayer , const char * pcmd )
{
# ifndef REGAMEDLL_FIXES
if ( pPlayer & & UTIL_GetLocalPlayer ( ) )
{
UTIL_GetLocalPlayer ( ) ;
}
2016-02-23 02:13:52 +03:00
# endif
2016-01-19 14:54:31 +03:00
return FALSE ;
}
// Process the "bot_add" console command
bool CCSBotManager : : BotAddCommand ( BotProfileTeamType team , bool isFromConsole )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
// dont allow bots to join if the Navigation Area is being generated
if ( IMPL ( m_isLearningMap ) )
return false ;
if ( ! AreBotsAllowed ( ) )
2015-08-02 20:45:57 +03:00
return false ;
const BotProfile * profile = NULL ;
2015-09-16 23:19:21 +03:00
if ( ! isFromConsole | | CMD_ARGC ( ) < 2 )
2015-08-02 20:45:57 +03:00
{
2016-01-19 14:54:31 +03:00
// if team not specified, check cv_bot_join_team cvar for preference
2015-08-02 20:45:57 +03:00
if ( team = = BOT_TEAM_ANY )
{
2015-09-16 23:19:21 +03:00
if ( ! Q_stricmp ( cv_bot_join_team . string , " T " ) )
team = BOT_TEAM_T ;
else if ( ! Q_stricmp ( cv_bot_join_team . string , " CT " ) )
team = BOT_TEAM_CT ;
else
2015-08-02 20:45:57 +03:00
{
TeamName defaultTeam = SelectDefaultTeam ( ) ;
if ( defaultTeam = = TERRORIST )
team = BOT_TEAM_T ;
else if ( defaultTeam = = CT )
team = BOT_TEAM_CT ;
}
}
// try to add a bot by name
profile = TheBotProfiles - > GetRandomProfile ( GetDifficultyLevel ( ) , team ) ;
if ( profile = = NULL )
{
CONSOLE_ECHO ( " All bot profiles at this difficulty level are in use. \n " ) ;
return true ;
}
}
else
{
// in career, ignore humans
bool ignoreHumans = false ;
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) ! = NULL & & CSGameRules ( ) - > IsCareer ( ) )
2015-08-02 20:45:57 +03:00
ignoreHumans = true ;
2015-09-16 23:19:21 +03:00
if ( UTIL_IsNameTaken ( CMD_ARGV ( 1 ) , ignoreHumans ) )
2015-08-02 20:45:57 +03:00
{
CONSOLE_ECHO ( " Error - %s is already in the game. \n " , CMD_ARGV ( 1 ) ) ;
return true ;
}
2015-09-16 23:19:21 +03:00
profile = TheBotProfiles - > GetProfile ( CMD_ARGV ( 1 ) , team ) ;
if ( profile = = NULL )
{
CONSOLE_ECHO ( " Error - no profile for '%s' exists. \n " , CMD_ARGV ( 1 ) ) ;
return true ;
2015-08-02 20:45:57 +03:00
}
}
// create the bot
2016-01-19 14:54:31 +03:00
if ( AddBot ( profile , team ) )
2015-08-02 20:45:57 +03:00
{
if ( isFromConsole )
{
// increase the bot quota to account for manually added bot
CVAR_SET_FLOAT ( " bot_quota " , cv_bot_quota . value + 1 ) ;
}
}
return true ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Keep a minimum quota of bots in the game
2016-02-04 03:18:26 +03:00
void CCSBotManager : : MaintainBotQuota ( )
2015-06-30 12:46:07 +03:00
{
2016-02-23 02:13:52 +03:00
if ( ! AreBotsAllowed ( ) )
return ;
2016-01-19 14:54:31 +03:00
if ( IMPL ( m_isLearningMap ) )
return ;
int totalHumansInGame = UTIL_HumansInGame ( ) ;
int humanPlayersInGame = UTIL_HumansInGame ( IGNORE_SPECTATORS ) ;
// don't add bots until local player has been registered, to make sure he's player ID #1
if ( ! IS_DEDICATED_SERVER ( ) & & totalHumansInGame = = 0 )
return ;
2016-02-23 02:13:52 +03:00
int desiredBotCount = int ( cv_bot_quota . value ) ;
2016-01-19 14:54:31 +03:00
int botsInGame = UTIL_BotsInGame ( ) ;
if ( cv_bot_quota_match . value > 0.0 )
{
2016-02-23 02:13:52 +03:00
desiredBotCount = int ( humanPlayersInGame * cv_bot_quota_match . value ) ;
2016-01-19 14:54:31 +03:00
}
// wait for a player to join, if necessary
if ( cv_bot_join_after_player . value > 0.0 )
{
if ( humanPlayersInGame = = 0 )
desiredBotCount = 0 ;
}
// if bots will auto-vacate, we need to keep one slot open to allow players to join
if ( cv_bot_auto_vacate . value > 0.0 )
desiredBotCount = Q_min ( desiredBotCount , gpGlobals - > maxClients - ( totalHumansInGame + 1 ) ) ;
else
desiredBotCount = Q_min ( desiredBotCount , gpGlobals - > maxClients - totalHumansInGame ) ;
// add bots if necessary
if ( desiredBotCount > botsInGame )
{
// don't try to add a bot if all teams are full
2016-02-23 02:13:52 +03:00
if ( ! CSGameRules ( ) - > TeamFull ( TERRORIST ) | | ! CSGameRules ( ) - > TeamFull ( CT ) )
2016-01-19 14:54:31 +03:00
BotAddCommand ( BOT_TEAM_ANY ) ;
}
else if ( desiredBotCount < botsInGame )
{
// kick a bot to maintain quota
// first remove any unassigned bots
if ( UTIL_KickBotFromTeam ( UNASSIGNED ) )
return ;
TeamName kickTeam ;
// remove from the team that has more players
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) - > m_iNumTerrorist > CSGameRules ( ) - > m_iNumCT )
2016-01-19 14:54:31 +03:00
{
kickTeam = TERRORIST ;
}
2016-02-23 02:13:52 +03:00
else if ( CSGameRules ( ) - > m_iNumTerrorist < CSGameRules ( ) - > m_iNumCT )
2016-01-19 14:54:31 +03:00
{
kickTeam = CT ;
}
// remove from the team that's winning
2016-02-23 02:13:52 +03:00
else if ( CSGameRules ( ) - > m_iNumTerroristWins > CSGameRules ( ) - > m_iNumCTWins )
2016-01-19 14:54:31 +03:00
{
kickTeam = TERRORIST ;
}
2016-02-23 02:13:52 +03:00
else if ( CSGameRules ( ) - > m_iNumCTWins > CSGameRules ( ) - > m_iNumTerroristWins )
2016-01-19 14:54:31 +03:00
{
kickTeam = CT ;
}
else
{
// teams and scores are equal, pick a team at random
kickTeam = ( RANDOM_LONG ( 0 , 1 ) = = 0 ) ? CT : TERRORIST ;
}
// attempt to kick a bot from the given team
if ( UTIL_KickBotFromTeam ( kickTeam ) )
return ;
// if there were no bots on the team, kick a bot from the other team
if ( kickTeam = = TERRORIST )
UTIL_KickBotFromTeam ( CT ) ;
else
UTIL_KickBotFromTeam ( TERRORIST ) ;
}
else
{
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) ! = NULL & & ! CSGameRules ( ) - > IsCareer ( ) )
2016-01-19 14:54:31 +03:00
return ;
bool humansAreCTs = ( Q_strcmp ( humans_join_team . string , " CT " ) = = 0 ) ;
if ( humansAreCTs )
{
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) - > m_iNumCT < = 6 )
2016-01-19 14:54:31 +03:00
return ;
UTIL_KickBotFromTeam ( CT ) ;
}
else
{
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) - > m_iNumTerrorist < = 6 )
2016-01-19 14:54:31 +03:00
return ;
UTIL_KickBotFromTeam ( TERRORIST ) ;
}
CVAR_SET_FLOAT ( " bot_quota " , cv_bot_quota . value - 1.0f ) ;
}
2015-06-30 12:46:07 +03:00
}
2016-02-04 03:18:26 +03:00
void CCSBotManager : : MonitorBotCVars ( )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
if ( cv_bot_nav_edit . value ! = 0.0f )
{
EditNavAreas ( IMPL ( m_editCmd ) ) ;
IMPL ( m_editCmd ) = EDIT_NONE ;
}
if ( gpGlobals - > time > = IMPL ( m_flNextCVarCheck ) )
{
if ( cv_bot_show_danger . value ! = 0.0f )
DrawDanger ( ) ;
MaintainBotQuota ( ) ;
IMPL ( m_flNextCVarCheck ) = gpGlobals - > time + 0.3f ;
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Collect all nav areas that overlap the given zone
class CollectOverlappingAreas
{
public :
CollectOverlappingAreas ( CCSBotManager : : Zone * zone )
{
m_zone = zone ;
zone - > m_areaCount = 0 ;
}
bool operator ( ) ( CNavArea * area )
{
const Extent * areaExtent = area - > GetExtent ( ) ;
if ( areaExtent - > hi . x > = m_zone - > m_extent . lo . x & & areaExtent - > lo . x < = m_zone - > m_extent . hi . x
& & areaExtent - > hi . y > = m_zone - > m_extent . lo . y & & areaExtent - > lo . y < = m_zone - > m_extent . hi . y
& & areaExtent - > hi . z > = m_zone - > m_extent . lo . z & & areaExtent - > lo . z < = m_zone - > m_extent . hi . z )
{
// area overlaps m_zone
m_zone - > m_area [ m_zone - > m_areaCount + + ] = area ;
if ( m_zone - > m_areaCount = = CCSBotManager : : MAX_ZONE_NAV_AREAS )
{
return false ;
}
}
return true ;
}
private :
CCSBotManager : : Zone * m_zone ;
} ;
// Search the map entities to determine the game scenario and define important zones.
2016-02-04 03:18:26 +03:00
void CCSBotManager : : ValidateMapData ( )
2015-06-30 12:46:07 +03:00
{
2016-02-23 02:13:52 +03:00
if ( IMPL ( m_isMapDataLoaded ) | | ! AreBotsAllowed ( ) )
2015-08-02 20:45:57 +03:00
return ;
2015-06-30 12:46:07 +03:00
2015-12-09 01:39:54 +03:00
IMPL ( m_isMapDataLoaded ) = true ;
2015-06-30 12:46:07 +03:00
2015-08-02 20:45:57 +03:00
if ( LoadNavigationMap ( ) )
{
CONSOLE_ECHO ( " Failed to load navigation map. \n " ) ;
return ;
}
CONSOLE_ECHO ( " Navigation map loaded. \n " ) ;
m_zoneCount = 0 ;
m_gameScenario = SCENARIO_DEATHMATCH ;
2015-09-16 23:19:21 +03:00
// Search all entities in the map and set the game type and
2015-08-02 20:45:57 +03:00
// store all zones (bomb target, etc).
CBaseEntity * entity = NULL ;
int i ;
2016-01-19 14:54:31 +03:00
for ( i = 1 ; i < gpGlobals - > maxEntities ; + + i )
2015-08-02 20:45:57 +03:00
{
entity = CBaseEntity : : Instance ( INDEXENT ( i ) ) ;
if ( entity = = NULL )
continue ;
bool found = false ;
bool isLegacy = false ;
if ( FClassnameIs ( entity - > pev , " func_bomb_target " ) )
{
2016-01-19 14:54:31 +03:00
m_gameScenario = SCENARIO_DEFUSE_BOMB ;
2015-09-16 23:19:21 +03:00
found = true ;
2015-08-02 20:45:57 +03:00
isLegacy = false ;
}
else if ( FClassnameIs ( entity - > pev , " info_bomb_target " ) )
{
2016-01-19 14:54:31 +03:00
m_gameScenario = SCENARIO_DEFUSE_BOMB ;
2015-09-16 23:19:21 +03:00
found = true ;
2015-08-02 20:45:57 +03:00
isLegacy = true ;
}
else if ( FClassnameIs ( entity - > pev , " func_hostage_rescue " ) )
{
2016-01-19 14:54:31 +03:00
m_gameScenario = SCENARIO_RESCUE_HOSTAGES ;
2015-09-16 23:19:21 +03:00
found = true ;
2015-08-02 20:45:57 +03:00
isLegacy = false ;
}
else if ( FClassnameIs ( entity - > pev , " info_hostage_rescue " ) )
{
2016-01-19 14:54:31 +03:00
m_gameScenario = SCENARIO_RESCUE_HOSTAGES ;
2015-09-16 23:19:21 +03:00
found = true ;
2015-08-02 20:45:57 +03:00
isLegacy = true ;
}
else if ( FClassnameIs ( entity - > pev , " hostage_entity " ) )
{
2015-09-16 23:19:21 +03:00
// some very old maps (ie: cs_assault) use info_player_start
// as rescue zones, so set the scenario if there are hostages
2015-08-02 20:45:57 +03:00
// in the map
m_gameScenario = SCENARIO_RESCUE_HOSTAGES ;
}
else if ( FClassnameIs ( entity - > pev , " func_vip_safetyzone " ) )
{
2016-01-19 14:54:31 +03:00
m_gameScenario = SCENARIO_ESCORT_VIP ;
2015-09-16 23:19:21 +03:00
found = true ;
2015-08-02 20:45:57 +03:00
isLegacy = false ;
}
2015-09-16 23:19:21 +03:00
if ( found )
2015-08-02 20:45:57 +03:00
{
if ( m_zoneCount < MAX_ZONES )
{
2016-01-19 14:54:31 +03:00
m_zone [ m_zoneCount ] . m_center = ( isLegacy ) ? entity - > pev - > origin : ( entity - > pev - > absmax + entity - > pev - > absmin ) / 2.0f ;
2015-08-02 20:45:57 +03:00
m_zone [ m_zoneCount ] . m_isLegacy = isLegacy ;
m_zone [ m_zoneCount ] . m_index = m_zoneCount ;
2016-01-19 14:54:31 +03:00
m_zone [ m_zoneCount + + ] . m_entity = entity ;
2015-08-02 20:45:57 +03:00
}
else
CONSOLE_ECHO ( " Warning: Too many zones, some will be ignored. \n " ) ;
}
}
2015-09-16 23:19:21 +03:00
// If there are no zones and the scenario is hostage rescue,
2015-08-02 20:45:57 +03:00
// use the info_player_start entities as rescue zones.
if ( m_zoneCount = = 0 & & m_gameScenario = = SCENARIO_RESCUE_HOSTAGES )
{
entity = NULL ;
while ( ( entity = UTIL_FindEntityByClassname ( entity , " info_player_start " ) ) ! = NULL )
{
if ( FNullEnt ( entity - > edict ( ) ) )
break ;
if ( m_zoneCount < MAX_ZONES )
{
m_zone [ m_zoneCount ] . m_center = entity - > pev - > origin ;
m_zone [ m_zoneCount ] . m_isLegacy = true ;
m_zone [ m_zoneCount ] . m_index = m_zoneCount ;
2016-01-19 14:54:31 +03:00
m_zone [ m_zoneCount + + ] . m_entity = entity ;
2015-08-02 20:45:57 +03:00
}
else
CONSOLE_ECHO ( " Warning: Too many zones, some will be ignored. \n " ) ;
}
}
// Collect nav areas that overlap each zone
2016-01-19 14:54:31 +03:00
for ( i = 0 ; i < m_zoneCount ; + + i )
2015-08-02 20:45:57 +03:00
{
Zone * zone = & m_zone [ i ] ;
2015-09-16 23:19:21 +03:00
if ( zone - > m_isLegacy )
2015-08-02 20:45:57 +03:00
{
2015-09-16 23:19:21 +03:00
const float legacyRange = 256.0f ;
zone - > m_extent . lo . x = zone - > m_center . x - legacyRange ;
zone - > m_extent . lo . y = zone - > m_center . y - legacyRange ;
zone - > m_extent . lo . z = zone - > m_center . z - legacyRange ;
zone - > m_extent . hi . x = zone - > m_center . x + legacyRange ;
zone - > m_extent . hi . y = zone - > m_center . y + legacyRange ;
2015-08-02 20:45:57 +03:00
zone - > m_extent . hi . z = zone - > m_center . z + legacyRange ;
}
else
{
zone - > m_extent . lo = zone - > m_entity - > pev - > absmin ;
zone - > m_extent . hi = zone - > m_entity - > pev - > absmax ;
}
2015-09-16 23:19:21 +03:00
// ensure Z overlap
const float zFudge = 50.0f ;
zone - > m_extent . lo . z - = zFudge ;
2015-08-02 20:45:57 +03:00
zone - > m_extent . hi . z + = zFudge ;
// build a list of nav areas that overlap this zone
2016-01-19 14:54:31 +03:00
CollectOverlappingAreas collector ( zone ) ;
ForAllAreas ( collector ) ;
2015-08-02 20:45:57 +03:00
}
2015-06-30 12:46:07 +03:00
}
2016-01-25 20:02:57 +03:00
bool CCSBotManager : : AddBot ( const BotProfile * profile , BotProfileTeamType team )
2015-06-30 12:46:07 +03:00
{
2016-02-23 02:13:52 +03:00
if ( ! AreBotsAllowed ( ) )
2016-01-19 14:54:31 +03:00
return false ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
int nTeamSlot = UNASSIGNED ;
if ( team = = BOT_TEAM_ANY )
{
// if team not specified, check cv_bot_join_team cvar for preference
if ( ! Q_stricmp ( cv_bot_join_team . string , " T " ) )
nTeamSlot = TERRORIST ;
2015-09-16 23:19:21 +03:00
2016-01-19 14:54:31 +03:00
else if ( ! Q_stricmp ( cv_bot_join_team . string , " CT " ) )
nTeamSlot = CT ;
}
else if ( team = = BOT_TEAM_CT )
nTeamSlot = CT ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
else if ( team = = BOT_TEAM_T )
nTeamSlot = TERRORIST ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
if ( nTeamSlot = = UNASSIGNED )
{
nTeamSlot = SelectDefaultTeam ( ) ;
}
2015-08-02 20:45:57 +03:00
2016-02-23 02:13:52 +03:00
if ( nTeamSlot = = UNASSIGNED | | CSGameRules ( ) - > TeamFull ( nTeamSlot ) )
2016-01-19 14:54:31 +03:00
{
CONSOLE_ECHO ( " Could not add bot to the game: Team is full \n " ) ;
return false ;
}
2015-08-02 20:45:57 +03:00
2016-02-23 02:13:52 +03:00
if ( CSGameRules ( ) - > TeamStacked ( nTeamSlot , UNASSIGNED ) )
2016-01-19 14:54:31 +03:00
{
CONSOLE_ECHO ( " Could not add bot to the game: Team is stacked (to disable this check, set mp_limitteams and mp_autoteambalance to zero and restart the round). \n " ) ;
return false ;
}
2015-08-02 20:45:57 +03:00
2016-03-17 20:44:52 +03:00
CCSBot * pBot = CreateBot < CCSBot , CAPI_CSBot > ( profile ) ;
2016-01-19 14:54:31 +03:00
if ( pBot = = NULL )
{
return false ;
}
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
//int nJoinedTeam;
ClientPutInServer ( pBot - > edict ( ) ) ;
SET_CLIENT_KEY_VALUE ( pBot - > entindex ( ) , GET_INFO_BUFFER ( pBot - > edict ( ) ) , " *bot " , " 1 " ) ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
pBot - > m_iMenu = Menu_ChooseTeam ;
pBot - > m_iJoiningState = PICKINGTEAM ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
if ( HandleMenu_ChooseTeam ( pBot , nTeamSlot ) )
{
int skin = profile - > GetSkin ( ) ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
if ( ! skin )
skin = 6 ; // MODEL_GIGN?
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
HandleMenu_ChooseAppearance ( pBot , skin ) ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
if ( IS_DEDICATED_SERVER ( ) )
{
UTIL_DPrintf ( " Added bot %s to server \n " , STRING ( pBot - > pev - > netname ) ) ;
}
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
return true ;
}
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
SERVER_COMMAND ( UTIL_VarArgs ( " kick \" %s \" \n " , STRING ( pBot - > pev - > netname ) ) ) ;
CONSOLE_ECHO ( " Could not add bot to the game. \n " ) ;
2015-08-02 20:45:57 +03:00
2016-01-19 14:54:31 +03:00
return false ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return the zone that contains the given position
const CCSBotManager : : Zone * CCSBotManager : : GetZone ( const Vector * pos ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
for ( int z = 0 ; z < m_zoneCount ; + + z )
{
if ( m_zone [ z ] . m_extent . Contains ( pos ) )
{
return & m_zone [ z ] ;
}
}
return NULL ;
2015-06-30 12:46:07 +03:00
}
2015-12-05 22:40:30 +03:00
// Return the closest zone to the given position
const CCSBotManager : : Zone * CCSBotManager : : GetClosestZone ( const Vector * pos ) const
2015-06-30 12:46:07 +03:00
{
2015-12-05 22:40:30 +03:00
const Zone * close = NULL ;
float closeRangeSq = 1e9 f ;
2016-01-19 14:54:31 +03:00
for ( int z = 0 ; z < m_zoneCount ; + + z )
2015-12-09 01:39:54 +03:00
{
float rangeSq = ( m_zone [ z ] . m_center - ( * pos ) ) . LengthSquared ( ) ;
if ( rangeSq < closeRangeSq )
{
closeRangeSq = rangeSq ;
close = & m_zone [ z ] ;
}
2015-12-05 22:40:30 +03:00
}
return close ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return a random position inside the given zone
const Vector * CCSBotManager : : GetRandomPositionInZone ( const Zone * zone ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
static Vector pos ;
if ( zone = = NULL )
return NULL ;
if ( zone - > m_areaCount = = 0 )
return NULL ;
// pick a random overlapping area
CNavArea * area = GetRandomAreaInZone ( zone ) ;
// pick a location inside both the nav area and the zone
// TODO: Randomize this
if ( zone - > m_isLegacy )
{
// TODO: It is possible that the radius might not overlap this area at all...
area - > GetClosestPointOnArea ( & zone - > m_center , & pos ) ;
}
else
{
const Extent & areaExtent = * area - > GetExtent ( ) ;
Extent overlap ;
overlap . lo . x = Q_max ( areaExtent . lo . x , zone - > m_extent . lo . x ) ;
overlap . lo . y = Q_max ( areaExtent . lo . y , zone - > m_extent . lo . y ) ;
overlap . hi . x = Q_min ( areaExtent . hi . x , zone - > m_extent . hi . x ) ;
overlap . hi . y = Q_min ( areaExtent . hi . y , zone - > m_extent . hi . y ) ;
pos . x = ( overlap . lo . x + overlap . hi . x ) / 2.0f ;
pos . y = ( overlap . lo . y + overlap . hi . y ) / 2.0f ;
pos . z = area - > GetZ ( & pos ) ;
}
return & pos ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return a random area inside the given zone
CNavArea * CCSBotManager : : GetRandomAreaInZone ( const Zone * zone ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
// TODO: improvement is needed
if ( ! zone - > m_areaCount )
return NULL ;
return zone - > m_area [ RANDOM_LONG ( 0 , zone - > m_areaCount - 1 ) ] ;
2015-06-30 12:46:07 +03:00
}
2015-08-20 13:35:01 +03:00
void CCSBotManager : : __MAKE_VHOOK ( OnEvent ) ( GameEventType event , CBaseEntity * entity , CBaseEntity * other )
2015-06-30 12:46:07 +03:00
{
switch ( event )
{
case EVENT_BOMB_PLANTED :
m_isBombPlanted = true ;
m_bombPlantTimestamp = gpGlobals - > time ;
break ;
case EVENT_BOMB_DEFUSING :
m_bombDefuser = ( CBasePlayer * ) entity ;
break ;
case EVENT_BOMB_DEFUSE_ABORTED :
m_bombDefuser = NULL ;
break ;
case EVENT_BOMB_DEFUSED :
m_isBombPlanted = false ;
m_bombDefuser = NULL ;
break ;
case EVENT_TERRORISTS_WIN :
case EVENT_CTS_WIN :
case EVENT_ROUND_DRAW :
m_isRoundOver = true ;
break ;
case EVENT_RADIO_ENEMY_SPOTTED :
m_lastSeenEnemyTimestamp = gpGlobals - > time ;
SetLastSeenEnemyTimestamp ( ) ;
break ;
default :
break ;
}
2015-09-16 23:19:21 +03:00
2015-06-30 12:46:07 +03:00
CBotManager : : OnEvent ( event , entity , other ) ;
}
2016-01-19 14:54:31 +03:00
// Get the time remaining before the planted bomb explodes
2016-02-04 03:18:26 +03:00
float CCSBotManager : : GetBombTimeLeft ( ) const
2015-06-30 12:46:07 +03:00
{
2016-02-23 02:13:52 +03:00
return ( CSGameRules ( ) - > m_iC4Timer - ( gpGlobals - > time - m_bombPlantTimestamp ) ) ;
2015-06-30 12:46:07 +03:00
}
void CCSBotManager : : SetLooseBomb ( CBaseEntity * bomb )
{
2015-09-16 23:19:21 +03:00
m_looseBomb = bomb ;
if ( bomb )
2016-01-19 14:54:31 +03:00
{
2015-09-16 23:19:21 +03:00
m_looseBombArea = TheNavAreaGrid . GetNearestNavArea ( & bomb - > pev - > origin ) ;
2016-01-19 14:54:31 +03:00
}
2015-09-16 23:19:21 +03:00
else
2016-01-19 14:54:31 +03:00
{
2015-06-30 12:46:07 +03:00
m_looseBombArea = NULL ;
2016-01-19 14:54:31 +03:00
}
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return true if player is important to scenario (VIP, bomb carrier, etc)
bool CCSBotManager : : __MAKE_VHOOK ( IsImportantPlayer ) ( CBasePlayer * player ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
switch ( GetScenario ( ) )
{
case SCENARIO_DEFUSE_BOMB :
{
if ( player - > m_iTeam = = TERRORIST & & player - > IsBombGuy ( ) )
return true ;
// TODO: TEAM_CT's defusing the bomb are important
return false ;
}
case SCENARIO_ESCORT_VIP :
{
if ( player - > m_iTeam = = CT & & player - > m_bIsVIP )
return true ;
return false ;
}
case SCENARIO_RESCUE_HOSTAGES :
{
// TODO: TEAM_CT's escorting hostages are important
return false ;
}
}
// everyone is equally important in a deathmatch
return false ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return priority of player (0 = max pri)
unsigned int CCSBotManager : : __MAKE_VHOOK ( GetPlayerPriority ) ( CBasePlayer * player ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
const unsigned int lowestPriority = 0xFFFFFFFF ;
if ( ! player - > IsPlayer ( ) )
return lowestPriority ;
// human players have highest priority
if ( ! player - > IsBot ( ) )
return 0 ;
CCSBot * bot = dynamic_cast < CCSBot * > ( player ) ;
if ( ! bot )
return 0 ;
// bots doing something important for the current scenario have high priority
switch ( GetScenario ( ) )
{
case SCENARIO_DEFUSE_BOMB :
{
// the bomb carrier has high priority
if ( bot - > m_iTeam = = TERRORIST & & bot - > m_bHasC4 )
return 1 ;
break ;
}
case SCENARIO_ESCORT_VIP :
{
// the VIP has high priority
if ( bot - > m_iTeam = = CT & & bot - > m_bIsVIP )
return 1 ;
break ;
}
case SCENARIO_RESCUE_HOSTAGES :
{
// TEAM_CT's rescuing hostages have high priority
if ( bot - > m_iTeam = = CT & & bot - > GetHostageEscortCount ( ) )
return 1 ;
break ;
}
}
// everyone else is ranked by their unique ID (which cannot be zero)
return 1 + bot - > GetID ( ) ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return the last time the given radio message was sent for given team
// 'teamID' can be TEAM_CT or TEAM_TERRORIST
float CCSBotManager : : GetRadioMessageTimestamp ( GameEventType event , int teamID ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
if ( event < = EVENT_START_RADIO_1 | | event > = EVENT_END_RADIO )
return 0.0f ;
int i = ( teamID = = TERRORIST ) ? 0 : 1 ;
return m_radioMsgTimestamp [ event - EVENT_START_RADIO_1 ] [ i ] ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Return the interval since the last time this message was sent
float CCSBotManager : : GetRadioMessageInterval ( GameEventType event , int teamID ) const
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
if ( event < = EVENT_START_RADIO_1 | | event > = EVENT_END_RADIO )
return 99999999.9f ;
int i = ( teamID = = TERRORIST ) ? 0 : 1 ;
return gpGlobals - > time - m_radioMsgTimestamp [ event - EVENT_START_RADIO_1 ] [ i ] ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Set the given radio message timestamp.
// 'teamID' can be TEAM_CT or TEAM_TERRORIST
void CCSBotManager : : SetRadioMessageTimestamp ( GameEventType event , int teamID )
2015-06-30 12:46:07 +03:00
{
2016-01-19 14:54:31 +03:00
if ( event < = EVENT_START_RADIO_1 | | event > = EVENT_END_RADIO )
return ;
int i = ( teamID = = TERRORIST ) ? 0 : 1 ;
m_radioMsgTimestamp [ event - 1 ] [ i ] = gpGlobals - > time ;
2015-06-30 12:46:07 +03:00
}
2016-01-19 14:54:31 +03:00
// Reset all radio message timestamps
2016-02-04 03:18:26 +03:00
void CCSBotManager : : ResetRadioMessageTimestamps ( )
2015-06-30 12:46:07 +03:00
{
2016-02-04 03:18:26 +03:00
for ( int t = 0 ; t < ARRAYSIZE ( m_radioMsgTimestamp [ 0 ] ) ; + + t )
2015-08-02 20:45:57 +03:00
{
2016-02-04 03:18:26 +03:00
for ( int m = 0 ; m < ARRAYSIZE ( m_radioMsgTimestamp ) ; + + m )
2015-08-02 20:45:57 +03:00
{
m_radioMsgTimestamp [ m ] [ t ] = 0.0f ;
}
}
2015-06-30 12:46:07 +03:00
}