2019-09-23 00:09:58 +03:00
/*
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* In addition , as a special exception , the author gives permission to
* link the code of this program with the Half - Life Game Engine ( " HL
* Engine " ) and Modified Game Libraries ( " MODs " ) developed by Valve,
* L . L . C ( " Valve " ) . You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve . If you modify this file , you may extend this exception
* to your version of the file , but you are not obligated to do so . If
* you do not wish to do so , delete this exception statement from your
* version .
*
*/
# include "precompiled.h"
bool HasDefaultPistol ( CCSBot * me )
{
CBasePlayerWeapon * pSecondary = static_cast < CBasePlayerWeapon * > ( me - > m_rgpPlayerItems [ PISTOL_SLOT ] ) ;
if ( ! pSecondary )
return false ;
if ( me - > m_iTeam = = TERRORIST & & pSecondary - > m_iId = = WEAPON_GLOCK18 )
return true ;
if ( me - > m_iTeam = = CT & & pSecondary - > m_iId = = WEAPON_USP )
return true ;
return false ;
}
// Buy weapons, armor, etc.
void BuyState : : OnEnter ( CCSBot * me )
{
m_retries = 0 ;
m_prefRetries = 0 ;
m_prefIndex = 0 ;
m_doneBuying = false ;
m_isInitialDelay = true ;
// this will force us to stop holding live grenade
me - > EquipBestWeapon ( ) ;
m_buyDefuseKit = false ;
m_buyShield = false ;
if ( me - > m_iTeam = = CT )
{
if ( TheCSBots ( ) - > GetScenario ( ) = = CCSBotManager : : SCENARIO_DEFUSE_BOMB )
{
// CT's sometimes buy defuse kits in the bomb scenario (except in career mode, where the player should defuse)
if ( ! CSGameRules ( ) - > IsCareer ( ) )
{
const float buyDefuseKitChance = 50.0f ; // 100.0f * (me->GetProfile()->GetSkill() + 0.2f);
if ( RANDOM_FLOAT ( 0.0f , 100.0f ) < buyDefuseKitChance )
{
m_buyDefuseKit = true ;
}
}
}
// determine if we want a tactical shield
if ( ! me - > m_bHasPrimary & & TheCSBots ( ) - > AllowTacticalShield ( ) )
{
if ( me - > m_iAccount > 2500 )
{
if ( me - > m_iAccount < 4000 )
m_buyShield = ( RANDOM_FLOAT ( 0 , 100.0f ) < 33.3f ) ? true : false ;
else
m_buyShield = ( RANDOM_FLOAT ( 0 , 100.0f ) < 10.0f ) ? true : false ;
}
}
}
if ( TheCSBots ( ) - > AllowGrenades ( ) )
{
m_buyGrenade = ( RANDOM_FLOAT ( 0.0f , 100.0f ) < 33.3f ) ? true : false ;
}
else
{
m_buyGrenade = false ;
}
m_buyPistol = false ;
if ( TheCSBots ( ) - > AllowPistols ( ) )
{
CBasePlayerWeapon * pSecondary = static_cast < CBasePlayerWeapon * > ( me - > m_rgpPlayerItems [ PISTOL_SLOT ] ) ;
// check if we have a pistol
if ( pSecondary )
{
// if we have our default pistol, think about buying a different one
if ( HasDefaultPistol ( me ) )
{
// if everything other than pistols is disallowed, buy a pistol
if ( ! TheCSBots ( ) - > AllowShotguns ( )
& & ! TheCSBots ( ) - > AllowSubMachineGuns ( )
& & ! TheCSBots ( ) - > AllowRifles ( )
& & ! TheCSBots ( ) - > AllowMachineGuns ( )
& & ! TheCSBots ( ) - > AllowTacticalShield ( )
& & ! TheCSBots ( ) - > AllowSnipers ( ) )
{
m_buyPistol = ( RANDOM_FLOAT ( 0 , 100 ) < 75.0f ) ;
}
else if ( me - > m_iAccount < 1000 )
{
// if we're low on cash, buy a pistol
m_buyPistol = ( RANDOM_FLOAT ( 0 , 100 ) < 75.0f ) ;
}
else
{
m_buyPistol = ( RANDOM_FLOAT ( 0 , 100 ) < 33.3f ) ;
}
}
}
else
{
// we dont have a pistol - buy one
m_buyPistol = true ;
}
}
}
enum WeaponType
{
PISTOL ,
SHOTGUN ,
SUB_MACHINE_GUN ,
RIFLE ,
MACHINE_GUN ,
SNIPER_RIFLE ,
GRENADE ,
NUM_WEAPON_TYPES ,
} ;
struct BuyInfo
{
WeaponType type ;
bool preferred ; // more challenging bots prefer these weapons
char * buyAlias ; // the buy alias for this equipment
} ;
// These tables MUST be kept in sync with the CT and T buy aliases
BuyInfo primaryWeaponBuyInfoCT [ MAX_BUY_WEAPON_PRIMARY ] =
{
{ SHOTGUN , false , " m3 " } , // WEAPON_M3
{ SHOTGUN , false , " xm1014 " } , // WEAPON_XM1014
{ SUB_MACHINE_GUN , false , " tmp " } , // WEAPON_TMP
{ SUB_MACHINE_GUN , false , " mp5 " } , // WEAPON_MP5N
{ SUB_MACHINE_GUN , false , " ump45 " } , // WEAPON_UMP45
{ SUB_MACHINE_GUN , false , " p90 " } , // WEAPON_P90
{ RIFLE , true , " famas " } , // WEAPON_FAMAS
{ SNIPER_RIFLE , false , " scout " } , // WEAPON_SCOUT
{ RIFLE , true , " m4a1 " } , // WEAPON_M4A1
{ RIFLE , false , " aug " } , // WEAPON_AUG
{ SNIPER_RIFLE , true , " sg550 " } , // WEAPON_SG550
{ SNIPER_RIFLE , true , " awp " } , // WEAPON_AWP
{ MACHINE_GUN , false , " m249 " } , // WEAPON_M249
} ;
BuyInfo secondaryWeaponBuyInfoCT [ MAX_BUY_WEAPON_SECONDARY ] =
{
// { PISTOL, false, "glock" },
// { PISTOL, false, "usp" },
{ PISTOL , true , " p228 " } ,
{ PISTOL , true , " deagle " } ,
{ PISTOL , true , " fn57 " } ,
} ;
BuyInfo primaryWeaponBuyInfoT [ MAX_BUY_WEAPON_PRIMARY ] =
{
{ SHOTGUN , false , " m3 " } , // WEAPON_M3
{ SHOTGUN , false , " xm1014 " } , // WEAPON_XM1014
{ SUB_MACHINE_GUN , false , " mac10 " } , // WEAPON_MAC10
{ SUB_MACHINE_GUN , false , " mp5 " } , // WEAPON_MP5N
{ SUB_MACHINE_GUN , false , " ump45 " } , // WEAPON_UMP45
{ SUB_MACHINE_GUN , false , " p90 " } , // WEAPON_P90
{ RIFLE , true , " galil " } , // WEAPON_GALIL
{ RIFLE , true , " ak47 " } , // WEAPON_AK47
{ SNIPER_RIFLE , false , " scout " } , // WEAPON_SCOUT
{ RIFLE , true , " sg552 " } , // WEAPON_SG552
{ SNIPER_RIFLE , true , " awp " } , // WEAPON_AWP
{ SNIPER_RIFLE , true , " g3sg1 " } , // WEAPON_G3SG1
{ MACHINE_GUN , false , " m249 " } , // WEAPON_M249
} ;
BuyInfo secondaryWeaponBuyInfoT [ MAX_BUY_WEAPON_SECONDARY ] =
{
// { PISTOL, false, "glock" },
// { PISTOL, false, "usp" },
{ PISTOL , true , " p228 " } ,
{ PISTOL , true , " deagle " } ,
{ PISTOL , true , " elites " } ,
} ;
// Given a weapon alias, return the kind of weapon it is
inline WeaponType GetWeaponType ( const char * alias )
{
int i ;
for ( i = 0 ; i < MAX_BUY_WEAPON_PRIMARY ; i + + )
{
if ( ! Q_stricmp ( alias , primaryWeaponBuyInfoCT [ i ] . buyAlias ) )
return primaryWeaponBuyInfoCT [ i ] . type ;
if ( ! Q_stricmp ( alias , primaryWeaponBuyInfoT [ i ] . buyAlias ) )
return primaryWeaponBuyInfoT [ i ] . type ;
}
for ( i = 0 ; i < MAX_BUY_WEAPON_SECONDARY ; i + + )
{
if ( ! Q_stricmp ( alias , secondaryWeaponBuyInfoCT [ i ] . buyAlias ) )
return secondaryWeaponBuyInfoCT [ i ] . type ;
if ( ! Q_stricmp ( alias , secondaryWeaponBuyInfoT [ i ] . buyAlias ) )
return secondaryWeaponBuyInfoT [ i ] . type ;
}
return NUM_WEAPON_TYPES ;
}
void BuyState : : OnUpdate ( CCSBot * me )
{
// wait for a Navigation Mesh
if ( ! TheNavAreaList . size ( ) )
return ;
// apparently we cant buy things in the first few seconds, so wait a bit
if ( m_isInitialDelay )
{
const float waitToBuyTime = 2.0f ; // 0.25f;
if ( gpGlobals - > time - me - > GetStateTimestamp ( ) < waitToBuyTime )
return ;
m_isInitialDelay = false ;
}
// if we're done buying and still in the freeze period, wait
if ( m_doneBuying )
{
if ( CSGameRules ( ) - > IsMultiplayer ( ) & & CSGameRules ( ) - > IsFreezePeriod ( ) )
{
# ifdef REGAMEDLL_FIXES
// make sure we're locked and loaded
me - > EquipBestWeapon ( MUST_EQUIP ) ;
me - > Reload ( ) ;
me - > ResetStuckMonitor ( ) ;
# endif
return ;
}
me - > Idle ( ) ;
# ifdef REGAMEDLL_FIXES
return ;
# endif
}
// is the bot spawned outside of a buy zone?
if ( ! ( me - > m_signals . GetState ( ) & SIGNAL_BUY ) )
{
m_doneBuying = true ;
UTIL_DPrintf ( " %s bot spawned outside of a buy zone (%d, %d, %d) \n " , ( me - > m_iTeam = = CT ) ? " CT " : " Terrorist " , int ( me - > pev - > origin . x ) , int ( me - > pev - > origin . y ) , int ( me - > pev - > origin . z ) ) ;
return ;
}
// try to buy some weapons
const float buyInterval = 0.2f ; // 0.02f
if ( gpGlobals - > time - me - > GetStateTimestamp ( ) > buyInterval )
{
me - > m_stateTimestamp = gpGlobals - > time ;
bool isPreferredAllDisallowed = true ;
// try to buy our preferred weapons first
if ( m_prefIndex < me - > GetProfile ( ) - > GetWeaponPreferenceCount ( ) )
{
// need to retry because sometimes first buy fails??
const int maxPrefRetries = 2 ;
if ( m_prefRetries > = maxPrefRetries )
{
// try to buy next preferred weapon
m_prefIndex + + ;
m_prefRetries = 0 ;
return ;
}
int weaponPreference = me - > GetProfile ( ) - > GetWeaponPreference ( m_prefIndex ) ;
// don't buy it again if we still have one from last round
CBasePlayerWeapon * pCurrentWeapon = me - > GetActiveWeapon ( ) ;
if ( pCurrentWeapon & & pCurrentWeapon - > m_iId = = weaponPreference )
{
// done with buying preferred weapon
m_prefIndex = 9999 ;
return ;
}
if ( me - > HasShield ( ) & & weaponPreference = = WEAPON_SHIELDGUN )
{
// done with buying preferred weapon
m_prefIndex = 9999 ;
return ;
}
const char * buyAlias = nullptr ;
if ( weaponPreference = = WEAPON_SHIELDGUN )
{
if ( TheCSBots ( ) - > AllowTacticalShield ( ) )
buyAlias = " shield " ;
}
else
{
buyAlias = WeaponIDToAlias ( weaponPreference ) ;
WeaponType type = GetWeaponType ( buyAlias ) ;
switch ( type )
{
case PISTOL :
if ( ! TheCSBots ( ) - > AllowPistols ( ) )
buyAlias = nullptr ;
break ;
case SHOTGUN :
if ( ! TheCSBots ( ) - > AllowShotguns ( ) )
buyAlias = nullptr ;
break ;
case SUB_MACHINE_GUN :
if ( ! TheCSBots ( ) - > AllowSubMachineGuns ( ) )
buyAlias = nullptr ;
break ;
case RIFLE :
if ( ! TheCSBots ( ) - > AllowRifles ( ) )
buyAlias = nullptr ;
break ;
case MACHINE_GUN :
if ( ! TheCSBots ( ) - > AllowMachineGuns ( ) )
buyAlias = nullptr ;
break ;
case SNIPER_RIFLE :
if ( ! TheCSBots ( ) - > AllowSnipers ( ) )
buyAlias = nullptr ;
break ;
}
}
if ( buyAlias )
{
me - > ClientCommand ( buyAlias ) ;
me - > PrintIfWatched ( " Tried to buy preferred weapon %s. \n " , buyAlias ) ;
isPreferredAllDisallowed = false ;
}
m_prefRetries + + ;
// bail out so we dont waste money on other equipment
// unless everything we prefer has been disallowed, then buy at random
if ( isPreferredAllDisallowed = = false )
return ;
}
// if we have no preferred primary weapon (or everything we want is disallowed), buy at random
if ( ! me - > m_bHasPrimary & & ( isPreferredAllDisallowed | | ! me - > GetProfile ( ) - > HasPrimaryPreference ( ) ) )
{
if ( m_buyShield )
{
// buy a shield
me - > ClientCommand ( " shield " ) ;
me - > PrintIfWatched ( " Tried to buy a shield. \n " ) ;
}
else
{
// build list of allowable weapons to buy
BuyInfo * masterPrimary = ( me - > m_iTeam = = TERRORIST ) ? primaryWeaponBuyInfoT : primaryWeaponBuyInfoCT ;
BuyInfo * stockPrimary [ MAX_BUY_WEAPON_PRIMARY ] ;
int stockPrimaryCount = 0 ;
// dont choose sniper rifles as often
const float sniperRifleChance = 50.0f ;
bool wantSniper = ( RANDOM_FLOAT ( 0 , 100 ) < sniperRifleChance ) ? true : false ;
for ( int i = 0 ; i < MAX_BUY_WEAPON_PRIMARY ; i + + )
{
if ( ( masterPrimary [ i ] . type = = SHOTGUN & & TheCSBots ( ) - > AllowShotguns ( ) )
| | ( masterPrimary [ i ] . type = = SUB_MACHINE_GUN & & TheCSBots ( ) - > AllowSubMachineGuns ( ) )
| | ( masterPrimary [ i ] . type = = RIFLE & & TheCSBots ( ) - > AllowRifles ( ) )
| | ( masterPrimary [ i ] . type = = SNIPER_RIFLE & & TheCSBots ( ) - > AllowSnipers ( ) & & wantSniper )
| | ( masterPrimary [ i ] . type = = MACHINE_GUN & & TheCSBots ( ) - > AllowMachineGuns ( ) ) )
{
stockPrimary [ stockPrimaryCount + + ] = & masterPrimary [ i ] ;
}
}
if ( stockPrimaryCount )
{
// buy primary weapon if we don't have one
int which ;
// on hard difficulty levels, bots try to buy preferred weapons on the first pass
if ( m_retries = = 0 & & TheCSBots ( ) - > GetDifficultyLevel ( ) > = BOT_HARD )
{
// count up available preferred weapons
int prefCount = 0 ;
for ( which = 0 ; which < stockPrimaryCount ; which + + )
{
if ( stockPrimary [ which ] - > preferred )
prefCount + + ;
}
if ( prefCount )
{
int whichPref = RANDOM_LONG ( 0 , prefCount - 1 ) ;
for ( which = 0 ; which < stockPrimaryCount ; which + + )
{
if ( stockPrimary [ which ] - > preferred & & whichPref - - = = 0 )
break ;
}
}
else
{
// no preferred weapons available, just pick randomly
which = RANDOM_LONG ( 0 , stockPrimaryCount - 1 ) ;
}
}
else
{
which = RANDOM_LONG ( 0 , stockPrimaryCount - 1 ) ;
}
me - > ClientCommand ( stockPrimary [ which ] - > buyAlias ) ;
me - > PrintIfWatched ( " Tried to buy %s. \n " , stockPrimary [ which ] - > buyAlias ) ;
}
}
}
// If we now have a weapon, or have tried for too long, we're done
if ( me - > m_bHasPrimary | | m_retries + + > 5 )
{
// primary ammo
if ( me - > m_bHasPrimary )
{
me - > ClientCommand ( " primammo " ) ;
}
// buy armor last, to make sure we bought a weapon first
me - > ClientCommand ( " vesthelm " ) ;
me - > ClientCommand ( " vest " ) ;
// pistols - if we have no preferred pistol, buy at random
if ( TheCSBots ( ) - > AllowPistols ( ) & & ! me - > GetProfile ( ) - > HasPistolPreference ( ) )
{
if ( m_buyPistol )
{
int which = RANDOM_LONG ( 0 , MAX_BUY_WEAPON_SECONDARY - 1 ) ;
if ( me - > m_iTeam = = TERRORIST )
me - > ClientCommand ( secondaryWeaponBuyInfoT [ which ] . buyAlias ) ;
else
me - > ClientCommand ( secondaryWeaponBuyInfoCT [ which ] . buyAlias ) ;
// only buy one pistol
m_buyPistol = false ;
}
me - > ClientCommand ( " secammo " ) ;
}
// buy a grenade if we wish, and we don't already have one
if ( m_buyGrenade & & ! me - > HasGrenade ( ) )
{
if ( UTIL_IsTeamAllBots ( me - > m_iTeam ) )
{
// only allow Flashbangs if everyone on the team is a bot (dont want to blind our friendly humans)
float rnd = RANDOM_FLOAT ( 0 , 100 ) ;
if ( rnd < 10.0f )
{
// smoke grenade
me - > ClientCommand ( " sgren " ) ;
}
else if ( rnd < 35.0f )
{
// flashbang
me - > ClientCommand ( " flash " ) ;
}
else
{
// he grenade
me - > ClientCommand ( " hegren " ) ;
}
}
else
{
if ( RANDOM_FLOAT ( 0 , 100 ) < 10.0f )
{
// smoke grenade
me - > ClientCommand ( " sgren " ) ;
}
else
{
// he grenade
me - > ClientCommand ( " hegren " ) ;
}
}
}
if ( m_buyDefuseKit )
{
me - > ClientCommand ( " defuser " ) ;
}
m_doneBuying = true ;
}
}
}
void BuyState : : OnExit ( CCSBot * me )
{
me - > ResetStuckMonitor ( ) ;
me - > EquipBestWeapon ( ) ;
}