2024-09-29 08:41:28 -06:00

2676 lines
52 KiB
Plaintext

/*
_bot
Author: INeedGames
Date: 06/19/2021
The entry point and manager of the bots.
*/
#include maps\mp\gametypes\_globallogic_utils;
#include maps\mp\_utility;
#include common_scripts\utility;
/*
Replace func stuff
*/
main()
{
level.bw_version = "1.2.0";
if ( getdvar( "bots_main" ) == "" )
{
setdvar( "bots_main", true );
}
if ( !getdvarint( "bots_main" ) )
{
return;
}
if ( !wait_for_builtins() )
{
println( "FATAL: NO BUILT-INS FOR BOTS" );
}
// fix bot grenade launcher usage
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "maps/mp/bots/_bot_combat", "bot_should_hip_fire" ), ::bot_should_hip_fire_replaced );
// FIX LEAKw
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "common_scripts/utility", "_timeout" ), ::_timeout_fix );
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "common_scripts/utility", "waittill_multiple" ), ::waittill_multiple_fix );
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "common_scripts/utility", "waittill_multiple_ents" ), ::waittill_multiple_ents_fix );
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "common_scripts/utility", "waittill_any_return" ), ::waittill_any_return_fix );
BotBuiltinReplaceFunc( BotBuiltinGetFunction( "common_scripts/utility", "waittill_any_array_return" ), ::waittill_any_array_return_fix );
}
/*
Entry point to the bots
*/
init()
{
if ( !getdvarint( "bots_main" ) )
{
return;
}
if ( !wait_for_builtins() )
{
println( "FATAL: NO BUILT-INS FOR BOTS" );
}
if ( getdvar( "bots_main_GUIDs" ) == "" )
{
setdvar( "bots_main_GUIDs", "" ); // guids of players who will be given host powers, comma seperated
}
if ( getdvar( "bots_main_firstIsHost" ) == "" )
{
setdvar( "bots_main_firstIsHost", false ); // first play to connect is a host
}
if ( getdvar( "bots_main_kickBotsAtEnd" ) == "" )
{
setdvar( "bots_main_kickBotsAtEnd", false ); // kicks the bots at game end (dedis hang with bots on map rotate)
}
if ( getdvar( "bots_main_waitForHostTime" ) == "" )
{
setdvar( "bots_main_waitForHostTime", 10.0 ); // how long to wait to wait for the host player
}
if ( getdvar( "bots_manage_add" ) == "" )
{
setdvar( "bots_manage_add", 0 ); // amount of bots to add to the game
}
if ( getdvar( "bots_manage_fill" ) == "" )
{
setdvar( "bots_manage_fill", 0 ); // amount of bots to maintain
}
if ( getdvar( "bots_manage_fill_spec" ) == "" )
{
setdvar( "bots_manage_fill_spec", true ); // to count for fill if player is on spec team
}
if ( getdvar( "bots_manage_fill_mode" ) == "" )
{
setdvar( "bots_manage_fill_mode", 0 ); // fill mode, 0 adds everyone, 1 just bots, 2 maintains at maps, 3 is 2 with 1
}
if ( getdvar( "bots_manage_fill_kick" ) == "" )
{
setdvar( "bots_manage_fill_kick", false ); // kick bots if too many
}
if ( getdvar( "bots_skill" ) == "" ) // alias for bot_difficulty
{
setdvar( "bots_skill", "" );
}
if ( getdvar( "bots_team" ) == "" )
{
setdvar( "bots_team", "autoassign" ); // which team for bots to join
}
if ( getdvar( "bots_team_amount" ) == "" )
{
setdvar( "bots_team_amount", 0 ); // amount of bots on axis team
}
if ( getdvar( "bots_team_force" ) == "" )
{
setdvar( "bots_team_force", false ); // force bots on team
}
if ( getdvar( "bots_team_mode" ) == "" )
{
setdvar( "bots_team_mode", 0 ); // counts just bots when 1
}
if ( getdvar( "bots_loadout_rank" ) == "" ) // what rank the bots should be around, -1 is around the players, 0 is all random
{
setdvar( "bots_loadout_rank", -1 );
}
if ( getdvar( "bots_loadout_prestige" ) == "" ) // what pretige the bots will be, -1 is the players, -2 is random
{
setdvar( "bots_loadout_prestige", -1 );
}
if ( getdvar( "bots_play_nade" ) == "" )
{
setdvar( "bots_play_nade", true );
}
if ( getdvar( "bots_play_aim" ) == "" )
{
setdvar( "bots_play_aim", true );
}
if ( getdvar( "bots_play_jumpdrop" ) == "" ) // bots jump and dropshot
{
setdvar( "bots_play_jumpdrop", true );
}
if ( !isdefined( game[ "botWarfare" ] ) )
{
game[ "botWarfare" ] = true;
}
thread fixGamemodes();
thread onPlayerConnect();
thread handleBots();
}
/*
FIX THE UAV LEAK
*/
waittill_multiple_ents_fix_hack( ent )
{
self endon( "death" );
ent endon( "die" );
while ( ent.threads )
{
ent waittill( "returned" );
ent.threads--;
}
ent notify( "die" );
}
/*
FIX THE UAV LEAK
*/
waittill_multiple_ents_fix( ent1, string1, ent2, string2, ent3, string3, ent4, string4 )
{
self endon( "death" );
ent = spawnstruct();
ent.threads = 0;
if ( isdefined( ent1 ) )
{
assert( isdefined( string1 ) );
ent1 thread waittill_string( string1, ent );
ent.threads++;
}
if ( isdefined( ent2 ) )
{
assert( isdefined( string2 ) );
ent2 thread waittill_string( string2, ent );
ent.threads++;
}
if ( isdefined( ent3 ) )
{
assert( isdefined( string3 ) );
ent3 thread waittill_string( string3, ent );
ent.threads++;
}
if ( isdefined( ent4 ) )
{
assert( isdefined( string4 ) );
ent4 thread waittill_string( string4, ent );
ent.threads++;
}
self thread waittill_multiple_ents_fix_hack( ent );
ent waittill( "die" );
}
/*
FIX THE UAV LEAK
*/
waittill_multiple_fix_hack( ent )
{
self endon( "death" );
ent endon( "die" );
while ( ent.threads )
{
ent waittill( "returned" );
ent.threads--;
}
ent notify( "die" );
}
/*
FIX THE UAV LEAK
*/
waittill_multiple_fix( string1, string2, string3, string4, string5 )
{
self endon( "death" );
ent = spawnstruct();
ent.threads = 0;
if ( isdefined( string1 ) )
{
self thread waittill_string( string1, ent );
ent.threads++;
}
if ( isdefined( string2 ) )
{
self thread waittill_string( string2, ent );
ent.threads++;
}
if ( isdefined( string3 ) )
{
self thread waittill_string( string3, ent );
ent.threads++;
}
if ( isdefined( string4 ) )
{
self thread waittill_string( string4, ent );
ent.threads++;
}
if ( isdefined( string5 ) )
{
self thread waittill_string( string5, ent );
ent.threads++;
}
self thread waittill_multiple_fix_hack( ent );
ent waittill( "die" );
}
/*
FIX THE UAV LEAK
*/
waittill_any_return_fix_hack( ent, string1, string2, string3, string4, string5, string6, string7 )
{
if ( ( !isdefined( string1 ) || string1 != "death" ) && ( !isdefined( string2 ) || string2 != "death" ) && ( !isdefined( string3 ) || string3 != "death" ) && ( !isdefined( string4 ) || string4 != "death" ) && ( !isdefined( string5 ) || string5 != "death" ) && ( !isdefined( string6 ) || string6 != "death" ) && ( !isdefined( string7 ) || string7 != "death" ) )
{
self endon( "death" );
}
ent endon( "die" );
ent waittill( "returned", msg );
ent notify( "die", msg );
}
/*
FIX THE UAV LEAK
*/
waittill_any_return_fix( string1, string2, string3, string4, string5, string6, string7 )
{
if ( ( !isdefined( string1 ) || string1 != "death" ) && ( !isdefined( string2 ) || string2 != "death" ) && ( !isdefined( string3 ) || string3 != "death" ) && ( !isdefined( string4 ) || string4 != "death" ) && ( !isdefined( string5 ) || string5 != "death" ) && ( !isdefined( string6 ) || string6 != "death" ) && ( !isdefined( string7 ) || string7 != "death" ) )
{
self endon( "death" );
}
ent = spawnstruct();
if ( isdefined( string1 ) )
{
self thread waittill_string( string1, ent );
}
if ( isdefined( string2 ) )
{
self thread waittill_string( string2, ent );
}
if ( isdefined( string3 ) )
{
self thread waittill_string( string3, ent );
}
if ( isdefined( string4 ) )
{
self thread waittill_string( string4, ent );
}
if ( isdefined( string5 ) )
{
self thread waittill_string( string5, ent );
}
if ( isdefined( string6 ) )
{
self thread waittill_string( string6, ent );
}
if ( isdefined( string7 ) )
{
self thread waittill_string( string7, ent );
}
self thread waittill_any_return_fix_hack( ent, string1, string2, string3, string4, string5, string6, string7 );
ent waittill( "die", msg );
return msg;
}
/*
FIX THE UAV LEAK
*/
_timeout_fix( delay )
{
self endon( "die" );
wait( delay );
self notify( "returned", "timeout" );
self notify( "die" );
}
/*
FIX THE UAV LEAK
*/
waittill_any_array_return_fix_hack( s_tracker, a_notifies )
{
if ( isinarray( a_notifies, "death" ) )
{
self endon( "death" );
}
s_tracker endon( "die" );
s_tracker waittill( "returned", msg );
s_tracker notify( "die", msg );
}
/*
FIX THE UAV LEAK
*/
waittill_any_array_return_fix( a_notifies )
{
if ( isinarray( a_notifies, "death" ) )
{
self endon( "death" );
}
s_tracker = spawnstruct();
foreach ( str_notify in a_notifies )
{
if ( isdefined( str_notify ) )
{
self thread waittill_string( str_notify, s_tracker );
}
}
self thread waittill_any_array_return_fix_hack( s_tracker, a_notifies );
s_tracker waittill( "die", msg );
return msg;
}
/*
Fixes gl usage
*/
bot_should_hip_fire_replaced()
{
weapon = self getcurrentweapon();
class = weaponclass( weapon );
if ( class == "grenade" )
{
return 1;
}
func = BotBuiltinGetFunction( "maps/mp/bots/_bot_combat", "bot_should_hip_fire" );
BotBuiltinDisableDetourOnce( func );
return self [[ func ]]();
}
/*
Adds sd to bot logic
*/
fixGamemodes()
{
wait 0.25;
if ( level.gametype == "sd" )
{
level.bot_gametype = ::bot_sd_think;
}
}
/*
Starts the threads for bots.
*/
handleBots()
{
thread diffBots();
thread teamBots();
addBots();
while ( !level.intermission )
{
wait 0.05;
}
setdvar( "bots_manage_add", getBotArray().size );
if ( !getdvarint( "bots_main_kickBotsAtEnd" ) )
{
return;
}
bots = getBotArray();
for ( i = 0; i < bots.size; i++ )
{
bot = bots[ i ];
if ( isdefined( bot ) )
{
kick( bot getentitynumber() );
}
}
}
/*
Handles the diff of the bots
*/
diffBots()
{
for ( ;; )
{
wait 1.5;
// we dont use 'bots_skill' so that we can still use the .menu dvar
if ( getdvar( "bots_skill" ) != "" )
{
setdvar( "bot_difficulty", getdvar( "bots_skill" ) );
setdvar( "bots_skill", "" );
}
bot_set_difficulty( getdvarint( "bot_difficulty" ) );
}
}
/*
Sets the difficulty of the bots
*/
bot_set_difficulty( difficulty )
{
if ( difficulty == 3 )
{
setdvar( "bot_MinDeathTime", "250" );
setdvar( "bot_MaxDeathTime", "500" );
setdvar( "bot_MinFireTime", "100" );
setdvar( "bot_MaxFireTime", "250" );
setdvar( "bot_PitchUp", "-5" );
setdvar( "bot_PitchDown", "10" );
setdvar( "bot_Fov", "160" );
setdvar( "bot_MinAdsTime", "3000" );
setdvar( "bot_MaxAdsTime", "5000" );
setdvar( "bot_MinCrouchTime", "100" );
setdvar( "bot_MaxCrouchTime", "400" );
setdvar( "bot_TargetLeadBias", "2" );
setdvar( "bot_MinReactionTime", "40" );
setdvar( "bot_MaxReactionTime", "70" );
setdvar( "bot_StrafeChance", "1" );
setdvar( "bot_MinStrafeTime", "3000" );
setdvar( "bot_MaxStrafeTime", "6000" );
setdvar( "scr_help_dist", "512" );
setdvar( "bot_AllowGrenades", "1" );
setdvar( "bot_MinGrenadeTime", "1500" );
setdvar( "bot_MaxGrenadeTime", "4000" );
setdvar( "bot_MeleeDist", "70" );
setdvar( "bot_YawSpeed", "2" );
}
else if ( difficulty == 2 )
{
setdvar( "bot_MinDeathTime", "250" );
setdvar( "bot_MaxDeathTime", "500" );
setdvar( "bot_MinFireTime", "400" );
setdvar( "bot_MaxFireTime", "600" );
setdvar( "bot_PitchUp", "-5" );
setdvar( "bot_PitchDown", "10" );
setdvar( "bot_Fov", "100" );
setdvar( "bot_MinAdsTime", "3000" );
setdvar( "bot_MaxAdsTime", "5000" );
setdvar( "bot_MinCrouchTime", "100" );
setdvar( "bot_MaxCrouchTime", "400" );
setdvar( "bot_TargetLeadBias", "2" );
setdvar( "bot_MinReactionTime", "400" );
setdvar( "bot_MaxReactionTime", "700" );
setdvar( "bot_StrafeChance", "0.9" );
setdvar( "bot_MinStrafeTime", "3000" );
setdvar( "bot_MaxStrafeTime", "6000" );
setdvar( "scr_help_dist", "384" );
setdvar( "bot_AllowGrenades", "1" );
setdvar( "bot_MinGrenadeTime", "1500" );
setdvar( "bot_MaxGrenadeTime", "4000" );
setdvar( "bot_MeleeDist", "70" );
setdvar( "bot_YawSpeed", "1.4" );
}
else if ( difficulty == 0 )
{
setdvar( "bot_MinDeathTime", "1000" );
setdvar( "bot_MaxDeathTime", "2000" );
setdvar( "bot_MinFireTime", "900" );
setdvar( "bot_MaxFireTime", "1000" );
setdvar( "bot_PitchUp", "-20" );
setdvar( "bot_PitchDown", "40" );
setdvar( "bot_Fov", "50" );
setdvar( "bot_MinAdsTime", "3000" );
setdvar( "bot_MaxAdsTime", "5000" );
setdvar( "bot_MinCrouchTime", "4000" );
setdvar( "bot_MaxCrouchTime", "6000" );
setdvar( "bot_TargetLeadBias", "8" );
setdvar( "bot_MinReactionTime", "1200" );
setdvar( "bot_MaxReactionTime", "1600" );
setdvar( "bot_StrafeChance", "0.1" );
setdvar( "bot_MinStrafeTime", "3000" );
setdvar( "bot_MaxStrafeTime", "6000" );
setdvar( "scr_help_dist", "256" );
setdvar( "bot_AllowGrenades", "0" );
setdvar( "bot_MeleeDist", "40" );
}
else
{
if ( difficulty != 1 )
{
return;
}
setdvar( "bot_MinDeathTime", "500" );
setdvar( "bot_MaxDeathTime", "1000" );
setdvar( "bot_MinFireTime", "600" );
setdvar( "bot_MaxFireTime", "800" );
setdvar( "bot_PitchUp", "-10" );
setdvar( "bot_PitchDown", "20" );
setdvar( "bot_Fov", "70" );
setdvar( "bot_MinAdsTime", "3000" );
setdvar( "bot_MaxAdsTime", "5000" );
setdvar( "bot_MinCrouchTime", "2000" );
setdvar( "bot_MaxCrouchTime", "4000" );
setdvar( "bot_TargetLeadBias", "4" );
setdvar( "bot_MinReactionTime", "600" );
setdvar( "bot_MaxReactionTime", "800" );
setdvar( "bot_StrafeChance", "0.6" );
setdvar( "bot_MinStrafeTime", "3000" );
setdvar( "bot_MaxStrafeTime", "6000" );
setdvar( "scr_help_dist", "256" );
setdvar( "bot_AllowGrenades", "1" );
setdvar( "bot_MinGrenadeTime", "1500" );
setdvar( "bot_MaxGrenadeTime", "4000" );
setdvar( "bot_MeleeDist", "70" );
setdvar( "bot_YawSpeed", "1.2" );
}
if ( level.gametype == "oic" && difficulty == 3 )
{
setdvar( "bot_MinReactionTime", "400" );
setdvar( "bot_MaxReactionTime", "500" );
setdvar( "bot_MinAdsTime", "1000" );
setdvar( "bot_MaxAdsTime", "2000" );
}
if ( ( difficulty == 2 || difficulty == 3 ) && level.gametype == "oic" )
{
setdvar( "bot_Sprintdistance", "256" );
}
if ( !getdvarint( "bots_play_nade" ) )
{
setdvar( "bot_AllowGrenades", "0" );
}
if ( !getdvarint( "bots_play_aim" ) )
{
setdvar( "bot_YawSpeed", "0" );
setdvar( "bot_PitchUp", "0" );
setdvar( "bot_PitchDown", "0" );
}
setdvar( "bot_difficulty", difficulty );
level.bot_difficulty = undefined;
level maps\mp\bots\_bot::bot_get_difficulty();
}
/*
A server thread for monitoring all bot's teams for custom server settings.
*/
teamBots_loop()
{
teamAmount = getdvarint( "bots_team_amount" );
toTeam = getdvar( "bots_team" );
alliesbots = 0;
alliesplayers = 0;
axisbots = 0;
axisplayers = 0;
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) )
{
if ( player is_bot() )
{
if ( player.pers[ "team" ] == "allies" )
{
alliesbots++;
}
else if ( player.pers[ "team" ] == "axis" )
{
axisbots++;
}
}
else
{
if ( player.pers[ "team" ] == "allies" )
{
alliesplayers++;
}
else if ( player.pers[ "team" ] == "axis" )
{
axisplayers++;
}
}
}
}
allies = alliesbots;
axis = axisbots;
if ( !getdvarint( "bots_team_mode" ) )
{
allies += alliesplayers;
axis += axisplayers;
}
if ( toTeam != "custom" )
{
if ( getdvarint( "bots_team_force" ) )
{
if ( toTeam == "autoassign" )
{
if ( abs( axis - allies ) > 1 )
{
toTeam = "axis";
if ( axis > allies )
{
toTeam = "allies";
}
}
}
if ( toTeam != "autoassign" )
{
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) && player is_bot() && ( player.pers[ "team" ] != toTeam ) )
{
if ( toTeam == "allies" )
{
player thread [[ level.teammenu ]]( "allies" );
}
else if ( toTeam == "axis" )
{
player thread [[ level.teammenu ]]( "axis" );
}
else
{
player thread [[ level.spectator ]]();
}
break;
}
}
}
}
}
else
{
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) && player is_bot() )
{
if ( player.pers[ "team" ] == "axis" )
{
if ( axis > teamAmount )
{
player thread [[ level.teammenu ]]( "allies" );
break;
}
}
else
{
if ( axis < teamAmount )
{
player thread [[ level.teammenu ]]( "axis" );
break;
}
else if ( player.pers[ "team" ] != "allies" )
{
player thread [[ level.teammenu ]]( "allies" );
break;
}
}
}
}
}
}
/*
A server thread for monitoring all bot's teams for custom server settings.
*/
teamBots()
{
for ( ;; )
{
wait 1.5;
teamBots_loop();
}
}
/*
Loop
*/
addBots_loop()
{
botsToAdd = getdvarint( "bots_manage_add" );
if ( botsToAdd > 0 )
{
setdvar( "bots_manage_add", 0 );
if ( botsToAdd > 64 )
{
botsToAdd = 64;
}
for ( ; botsToAdd > 0; botsToAdd-- )
{
level add_bot();
wait 0.5;
}
}
fillMode = getdvarint( "bots_manage_fill_mode" );
if ( fillMode == 2 || fillMode == 3 )
{
setdvar( "bots_manage_fill", getGoodMapAmount() );
}
fillAmount = getdvarint( "bots_manage_fill" );
players = 0;
bots = 0;
spec = 0;
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) )
{
if ( player is_bot() )
{
bots++;
}
else if ( !isdefined( player.team ) || ( player.pers[ "team" ] != "axis" && player.pers[ "team" ] != "allies" ) )
{
spec++;
}
else
{
players++;
}
}
}
if ( fillMode == 4 )
{
axisplayers = 0;
alliesplayers = 0;
playercount = level.players.size;
for ( i = 0; i < playercount; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) && !player is_bot() )
{
if ( player.pers[ "team" ] == "axis" )
{
axisplayers++;
}
else if ( player.pers[ "team" ] == "allies" )
{
alliesplayers++;
}
}
}
result = fillAmount - abs( axisplayers - alliesplayers ) + bots;
if ( players == 0 )
{
if ( bots < fillAmount )
{
result = fillAmount - 1;
}
else if ( bots > fillAmount )
{
result = fillAmount + 1;
}
else
{
result = fillAmount;
}
}
bots = result;
}
if ( !randomint( 999 ) )
{
setdvar( "testclients_doreload", true );
wait 0.1;
setdvar( "testclients_doreload", false );
doExtraCheck();
}
amount = bots;
if ( fillMode == 0 || fillMode == 2 )
{
amount += players;
}
if ( getdvarint( "bots_manage_fill_spec" ) )
{
amount += spec;
}
if ( amount < fillAmount )
{
setdvar( "bots_manage_add", 1 );
}
else if ( amount > fillAmount && getdvarint( "bots_manage_fill_kick" ) )
{
tempBot = getBotToKick();
if ( isdefined( tempBot ) )
{
kick( tempBot getentitynumber() );
}
}
}
/*
A server thread for monitoring all bot's in game. Will add and kick bots according to server settings.
*/
addBots()
{
level endon ( "game_ended" );
bot_wait_for_host();
for ( ;; )
{
wait 1.5;
addBots_loop();
}
}
/*
Adds a bot to the game.
*/
add_bot()
{
bot = addtestclient();
if ( isdefined( bot ) )
{
bot.pers[ "isBot" ] = true;
bot.pers[ "isBotWarfare" ] = true;
bot thread added();
}
}
/*
Player connects
*/
onPlayerConnect()
{
for ( ;; )
{
level waittill( "connected", player );
player thread connected();
}
}
/*
Connects
*/
connected()
{
self endon( "disconnect" );
if ( !isdefined( self.pers ) || !isdefined( self.pers[ "bot_host" ] ) )
{
self thread doHostCheck();
}
if ( !self istestclient() )
{
return;
}
if ( !isdefined( self.pers[ "isBot" ] ) )
{
self.pers[ "isBot" ] = true;
}
if ( !isdefined( self.pers[ "isBotWarfare" ] ) )
{
self.pers[ "isBotWarfare" ] = true;
self thread added();
}
self thread teamWatch();
self thread classWatch();
self thread onBotSpawned();
self thread setranks();
self thread watchBotDebugEvent();
}
/*
DEBUG
*/
watchBotDebugEvent()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "bot_event", msg, str, b, c, d, e, f, g );
if ( getdvarint( "bots_main_debug" ) >= 2 )
{
big_str = "Bot Warfare debug: " + self.name + ": " + msg;
if ( isdefined( str ) && isstring( str ) )
{
big_str += ", " + str;
}
if ( isdefined( b ) && isstring( b ) )
{
big_str += ", " + b;
}
if ( isdefined( c ) && isstring( c ) )
{
big_str += ", " + c;
}
if ( isdefined( d ) && isstring( d ) )
{
big_str += ", " + d;
}
if ( isdefined( e ) && isstring( e ) )
{
big_str += ", " + e;
}
if ( isdefined( f ) && isstring( f ) )
{
big_str += ", " + f;
}
if ( isdefined( g ) && isstring( g ) )
{
big_str += ", " + g;
}
BotBuiltinPrintConsole( big_str );
}
else if ( msg == "debug" && getdvarint( "bots_main_debug" ) )
{
BotBuiltinPrintConsole( "Bot Warfare debug: " + self.name + ": " + str );
}
}
}
/*
When the bot spawns
*/
onBotSpawned()
{
self endon( "disconnect" );
for ( ;; )
{
self waittill( "spawned_player" );
self BotBuiltinBotClearOverride( false );
self BotBuiltinBotWeaponOverride( self getcurrentweapon() );
self thread watch_for_override_stuff();
self thread watch_for_melee_override();
self thread bot_watch_think_mw2();
self BotNotifyBotEvent( "debug", "we spawned!" );
waittillframeend;
self.bot_first_spawn = undefined;
if ( randomint( 100 ) < 2 )
{
self.bot_change_class = undefined;
}
}
}
/*
Gets a GL
*/
getValidTube()
{
weaps = self getweaponslist( true );
for ( i = 0; i < weaps.size; i++ )
{
weap = weaps[ i ];
if ( !self getammocount( weap ) )
{
continue;
}
if ( !isstrstart( weap, "gl_" ) )
{
continue;
}
return weap;
}
return undefined;
}
/*
Bots play mw2
*/
bot_watch_think_mw2()
{
self endon( "disconnect" );
self endon( "death" );
level endon( "game_ended" );
for ( ;; )
{
wait randomintrange( 1, 4 );
if ( self isremotecontrolling() )
{
continue;
}
if ( self maps\mp\bots\_bot_combat::bot_has_enemy() )
{
continue;
}
tube = self getValidTube();
if ( !isdefined( tube ) )
{
if ( self getammocount( "usrpg_mp" ) )
{
tube = "usrpg_mp";
}
else if ( self getammocount( "smaw_mp" ) )
{
tube = "smaw_mp";
}
else
{
return;
}
}
if ( self getcurrentweapon() == tube )
{
return;
}
if ( randomint( 100 ) > 35 )
{
return;
}
self switchtoweapon( tube );
}
}
/*
custom movement stuff
*/
watch_for_melee_override()
{
self endon( "disconnect" );
self endon( "death" );
for ( ;; )
{
while ( ( !self maps\mp\bots\_bot_combat::threat_is_player() && !self maps\mp\bots\_bot_combat::threat_is_dog() ) || self isremotecontrolling() || !self hasweapon( "knife_mp" ) || !getdvarint( "aim_automelee_enabled" ) )
{
wait 0.05;
}
threat = self.bot.threat.entity;
while ( isdefined( threat ) && isdefined( self.bot.threat.entity ) && self.bot.threat.entity == threat )
{
dist = distance( self.origin, threat.origin );
if ( self isonground() && self getstance() != "prone" && dist < getdvarfloat( "aim_automelee_range" ) && ( getConeDot( threat.origin, self.origin, self getplayerangles() ) > 0.9 || dist < 10 ) )
{
self BotBuiltinBotMeleeParamsOverride( threat getentitynumber(), dist );
self BotBuiltinBotButtonOverride( "+melee" );
self BotBuiltinBotAimOverride( true );
time_left = 1;
once = false;
while ( time_left > 0 && isdefined( threat ) && isalive( threat ) )
{
self setplayerangles( vectortoangles( threat gettagorigin( "j_spine4" ) - self geteye() ) );
time_left -= 0.05;
wait 0.05;
if ( !once )
{
once = true;
self BotBuiltinBotButtonOverride( "~melee" );
}
}
if ( !once )
{
self BotBuiltinBotButtonOverride( "~melee" );
}
self BotBuiltinBotMeleeParamsOverride( false );
self BotBuiltinBotAimOverride( false );
wait 1;
break;
}
wait 0.05;
}
}
}
/*
custom movement stuff
*/
watch_for_override_stuff()
{
self endon( "disconnect" );
self endon( "death" );
NEAR_DIST = 80;
LONG_DIST = 1000;
SPAM_JUMP_TIME = 5000;
diff = level maps\mp\bots\_bot::bot_get_difficulty();
chance = 0;
if ( diff == "normal" )
{
chance = 25;
}
else if ( diff == "hard" )
{
chance = 50;
}
else if ( diff == "fu" )
{
chance = 80;
}
last_jump_time = 0;
if ( !getdvarint( "bots_play_jumpdrop" ) )
{
return;
}
for ( ;; )
{
while ( !self maps\mp\bots\_bot_combat::threat_is_player() || self isremotecontrolling() )
{
wait 0.05;
}
threat = self.bot.threat.entity;
dist = distance( threat.origin, self.origin );
time = gettime();
weap = self getcurrentweapon();
weapon_is_good = true;
if ( weap == "none" || !self getweaponammoclip( weap ) )
{
weapon_is_good = false;
}
if ( weapon_is_good && ( dist > NEAR_DIST ) && ( dist < LONG_DIST ) && ( randomint( 100 ) < chance ) && ( ( time - last_jump_time ) > SPAM_JUMP_TIME ) )
{
if ( randomint( 2 ) )
{
if ( ( getConeDot( threat.origin, self.origin, self getplayerangles() ) > 0.8 ) && ( dist > ( NEAR_DIST * 2 ) ) )
{
last_jump_time = time;
// drop shot
self BotBuiltinBotMovementOverride( 0, 0 );
self BotBuiltinBotButtonOverride( "+prone" );
wait 1.5;
self BotBuiltinBotMovementOverride( false );
self BotBuiltinBotButtonOverride( "~prone" );
}
}
else
{
last_jump_time = time;
// jump shot
self BotBuiltinBotButtonOverride( "+gostand" );
wait 0.1;
self BotBuiltinBotButtonOverride( "~gostand" );
}
}
while ( isdefined( threat ) && isdefined( self.bot.threat.entity ) && ( threat == self.bot.threat.entity ) )
{
wait 0.05;
}
}
}
/*
Set pres
*/
setranks()
{
self endon( "disconnect" );
wait 0.05;
self setCustomRanks();
if ( !level.gameended )
{
level waittill( "game_ended" );
}
self.pers[ "bot_rankxp" ] = self.pers[ "rankxp" ];
}
/*
Sets the rank
*/
setCustomRanks()
{
if ( !isdefined( self.pers[ "bot_prestige" ] ) )
{
return;
}
self.pers[ "prestige" ] = self.pers[ "bot_prestige" ];
self.pers[ "plevel" ] = self.pers[ "bot_prestige" ];
self.pers[ "rankxp" ] = self.pers[ "bot_rankxp" ];
self.pers[ "rank" ] = self maps\mp\gametypes\_rank::getrankforxp( self.pers[ "rankxp" ] );
self setrank( self.pers[ "rank" ], self.pers[ "prestige" ] );
self maps\mp\gametypes\_rank::syncxpstat();
}
/*
Makes sure the bot is on a team.
*/
teamWatch()
{
self endon( "disconnect" );
for ( ;; )
{
while ( !isdefined( self.team ) || !allowTeamChoice() )
{
wait .05;
}
wait 0.1;
// multiteam?
if ( self.team != "axis" && self.team != "allies" )
{
self notify( "menuresponse", game[ "menu_team" ], getdvar( "bots_team" ) );
}
while ( isdefined( self.team ) )
{
wait .05;
}
}
}
/*
Selects a class for the bot.
*/
classWatch()
{
self endon( "disconnect" );
for ( ;; )
{
while ( !isdefined( self.team ) || !allowClassChoice() )
{
wait .05;
}
wait 0.5;
if ( !maps\mp\gametypes\_globallogic_utils::isvalidclass( self.class ) || !isdefined( self.bot_change_class ) )
{
self notify( "menuresponse", game[ "menu_changeclass" ], self chooseRandomClass() );
}
self.bot_change_class = true;
while ( isdefined( self.team ) && maps\mp\gametypes\_globallogic_utils::isvalidclass( self.class ) && isdefined( self.bot_change_class ) )
{
wait .05;
}
}
}
/*
Chooses random class
*/
chooseRandomClass()
{
if ( level.disablecac )
{
classes = [];
classes[ classes.size ] = "class_assault";
classes[ classes.size ] = "class_smg";
classes[ classes.size ] = "class_lmg";
classes[ classes.size ] = "class_cqb";
classes[ classes.size ] = "class_sniper";
return PickRandom( classes );
}
return PickRandom( self maps\mp\bots\_bot::bot_build_classes() );
}
/*
Bot was added
*/
added()
{
self endon( "disconnect" );
self thread doCustomRank();
}
/*
Gets the prestige
*/
bot_get_prestige()
{
p_dvar = getdvarint( "bots_loadout_prestige" );
p = 0;
if ( p_dvar == -1 )
{
for ( i = 0; i < level.players.size; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) && !player is_bot() )
{
p = player.pers[ "prestige" ];
}
break;
}
}
else if ( p_dvar == -2 )
{
p = randomint( 12 );
}
else
{
p = p_dvar;
}
return p;
}
/*
Bot custom ranks
*/
doCustomRank()
{
self endon( "disconnect" );
// prevent generating classes
if ( getdvarint( "bots_loadout_rank" ) != -1 )
{
self.pers[ "bot_loadout" ] = true;
}
// wait for the original scripts to execute
wait 0.25;
// get rank
rankxp = self.pers[ "rankxp" ];
if ( getdvarint( "bots_loadout_rank" ) != -1 )
{
if ( getdvarint( "bots_loadout_rank" ) == 0 )
{
rankxp = maps\mp\gametypes\_rank::getrankinfominxp( randomint( level.maxrank + 1 ) );
}
else
{
rankxp = maps\mp\gametypes\_rank::getrankinfominxp( getdvarint( "bots_loadout_rank" ) );
}
}
// apply
self.pers[ "bot_prestige" ] = bot_get_prestige();
self.pers[ "bot_rankxp" ] = rankxp;
self setCustomRanks();
// generate the custom classes
if ( getdvarint( "bots_loadout_rank" ) != -1 )
{
self botsetdefaultclass( 5, "class_assault" );
self botsetdefaultclass( 6, "class_smg" );
self botsetdefaultclass( 7, "class_lmg" );
self botsetdefaultclass( 8, "class_cqb" );
self botsetdefaultclass( 9, "class_sniper" );
self maps\mp\bots\_bot_loadout::bot_construct_loadout( 10 );
}
}
/*
Matches a num to a char
*/
keyCodeToString( a )
{
b = "";
switch ( a )
{
case 0:
b = "a";
break;
case 1:
b = "b";
break;
case 2:
b = "c";
break;
case 3:
b = "d";
break;
case 4:
b = "e";
break;
case 5:
b = "f";
break;
case 6:
b = "g";
break;
case 7:
b = "h";
break;
case 8:
b = "i";
break;
case 9:
b = "j";
break;
case 10:
b = "k";
break;
case 11:
b = "l";
break;
case 12:
b = "m";
break;
case 13:
b = "n";
break;
case 14:
b = "o";
break;
case 15:
b = "p";
break;
case 16:
b = "q";
break;
case 17:
b = "r";
break;
case 18:
b = "s";
break;
case 19:
b = "t";
break;
case 20:
b = "u";
break;
case 21:
b = "v";
break;
case 22:
b = "w";
break;
case 23:
b = "x";
break;
case 24:
b = "y";
break;
case 25:
b = "z";
break;
case 26:
b = ".";
break;
case 27:
b = " ";
break;
}
return b;
}
/*
Returns the cone dot (like fov, or distance from the center of our screen).
*/
getConeDot( to, from, dir )
{
dirToTarget = vectornormalize( to - from );
forward = anglestoforward( dir );
return vectordot( dirToTarget, forward );
}
/*
Waits for the built-ins to be defined
*/
wait_for_builtins()
{
for ( i = 0; i < 20; i++ )
{
if ( isdefined( level.bot_builtins ) )
{
return true;
}
if ( i < 18 )
{
waittillframeend;
}
else
{
wait 0.05;
}
}
return false;
}
/*
Prints to console without dev script on
*/
BotBuiltinPrintConsole( s )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "printconsole" ] ) )
{
[[ level.bot_builtins[ "printconsole" ] ]]( s );
}
else
{
println( s );
}
}
/*
*/
BotBuiltinBotMovementOverride( a, b )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botmovementoverride" ] ) )
{
self [[ level.bot_builtins[ "botmovementoverride" ] ]]( a, b );
}
}
/*
*/
BotBuiltinBotButtonOverride( a )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botbuttonoverride" ] ) )
{
self [[ level.bot_builtins[ "botbuttonoverride" ] ]]( a );
}
}
/*
*/
BotBuiltinBotClearOverride( a )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botclearoverride" ] ) )
{
self [[ level.bot_builtins[ "botclearoverride" ] ]]( a );
}
}
/*
*/
BotBuiltinBotWeaponOverride( a )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botweaponoverride" ] ) )
{
self [[ level.bot_builtins[ "botweaponoverride" ] ]]( a );
}
}
/*
*/
BotBuiltinBotAimOverride( a )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botaimoverride" ] ) )
{
self [[ level.bot_builtins[ "botaimoverride" ] ]]( a );
}
}
/*
Sets melee params
*/
BotBuiltinBotMeleeParamsOverride( entNum, dist )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "botmeleeparamsoverride" ] ) )
{
self [[ level.bot_builtins[ "botmeleeparamsoverride" ] ]]( entNum, dist );
}
}
/*
*/
BotBuiltinReplaceFunc( a, b )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "replacefunc" ] ) )
{
return [[ level.bot_builtins[ "replacefunc" ] ]]( a, b );
}
}
/*
*/
BotBuiltinGetFunction( a, b )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "getfunction" ] ) )
{
return [[ level.bot_builtins[ "getfunction" ] ]]( a, b );
}
}
/*
*/
BotBuiltinDisableDetourOnce( a )
{
if ( isdefined( level.bot_builtins ) && isdefined( level.bot_builtins[ "disabledetouronce" ] ) )
{
[[ level.bot_builtins[ "disabledetouronce" ] ]]( a );
}
}
/*
iw5
*/
allowClassChoice()
{
// check gungame?
return true;
}
/*
iw5
*/
allowTeamChoice()
{
// check gungame?
return true;
}
/*
Waits till frame end so that if two notifies happen in the same frame, the other will not be missed.
*/
BotNotifyBotEvent_( msg, a, b, c, d, e, f, g )
{
self endon( "disconnect" );
waittillframeend; // wait for the waittills to setup again
self notify( "bot_event", msg, a, b, c, d, e, f, g );
}
/*
Notify the bot chat message
*/
BotNotifyBotEvent( msg, a, b, c, d, e, f, g )
{
self thread BotNotifyBotEvent_( msg, a, b, c, d, e, f, g );
}
/*
Returns if player is the host
*/
is_host()
{
if ( !isdefined( self ) || !isdefined( self.pers ) )
{
return false;
}
return ( isdefined( self.pers[ "bot_host" ] ) && self.pers[ "bot_host" ] );
}
/*
Setups the host variable on the player
*/
doHostCheck()
{
self.pers[ "bot_host" ] = false;
if ( self istestclient() )
{
return;
}
result = false;
if ( getdvar( "bots_main_firstIsHost" ) != "0" )
{
BotBuiltinPrintConsole( "WARNING: bots_main_firstIsHost is enabled" );
if ( getdvar( "bots_main_firstIsHost" ) == "1" )
{
setdvar( "bots_main_firstIsHost", self getguid() );
}
if ( getdvar( "bots_main_firstIsHost" ) == self getguid() + "" )
{
result = true;
}
}
DvarGUID = getdvar( "bots_main_GUIDs" );
if ( DvarGUID != "" )
{
guids = strtok( DvarGUID, "," );
for ( i = 0; i < guids.size; i++ )
{
if ( self getguid() + "" == guids[ i ] )
{
result = true;
}
}
}
if ( !self ishost() && !result )
{
return;
}
self.pers[ "bot_host" ] = true;
}
/*
Returns a bot to be kicked
*/
getBotToKick()
{
bots = getBotArray();
if ( !isdefined( bots ) || !isdefined( bots.size ) || bots.size <= 0 || !isdefined( bots[ 0 ] ) )
{
return undefined;
}
tokick = undefined;
axis = 0;
allies = 0;
team = getdvar( "bots_team" );
// count teams
for ( i = 0; i < bots.size; i++ )
{
bot = bots[ i ];
if ( !isdefined( bot ) || !isdefined( bot.team ) )
{
continue;
}
if ( bot.team == "allies" )
{
allies++;
}
else if ( bot.team == "axis" )
{
axis++;
}
else // choose bots that are not on a team first
{
return bot;
}
}
// search for a bot on the other team
if ( team == "custom" || team == "axis" )
{
team = "allies";
}
else if ( team == "autoassign" )
{
// get the team with the most bots
team = "allies";
if ( axis > allies )
{
team = "axis";
}
}
else
{
team = "axis";
}
// get the bot on this team with lowest skill
for ( i = 0; i < bots.size; i++ )
{
bot = bots[ i ];
if ( !isdefined( bot ) || !isdefined( bot.team ) )
{
continue;
}
if ( bot.team != team )
{
continue;
}
tokick = bot;
}
if ( isdefined( tokick ) )
{
return tokick;
}
// just kick lowest skill
for ( i = 0; i < bots.size; i++ )
{
bot = bots[ i ];
if ( !isdefined( bot ) || !isdefined( bot.team ) )
{
continue;
}
tokick = bot;
}
return tokick;
}
/*
Gets a player who is host
*/
GetHostPlayer()
{
for ( i = 0; i < level.players.size; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && player is_host() )
{
return player;
}
}
return undefined;
}
/*
Waits for a host player
*/
bot_wait_for_host()
{
host = undefined;
while ( !isdefined( level ) || !isdefined( level.players ) )
{
wait 0.05;
}
for ( i = getdvarfloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
{
host = GetHostPlayer();
if ( isdefined( host ) )
{
break;
}
wait 0.05;
}
if ( !isdefined( host ) )
{
return;
}
for ( i = getdvarfloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
{
if ( isdefined( host.team ) )
{
break;
}
wait 0.05;
}
if ( !isdefined( host.team ) )
{
return;
}
for ( i = getdvarfloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 )
{
if ( ( host.pers[ "team" ] == "allies" ) || ( host.pers[ "team" ] == "axis" ) )
{
break;
}
wait 0.05;
}
}
/*
Good
*/
getGoodMapAmount()
{
return 2;
}
/*
awdawd
*/
doExtraCheck()
{
checkTheBots();
}
/*
Picks random
*/
PickRandom( arr )
{
if ( !arr.size )
{
return undefined;
}
return arr[ randomint( arr.size ) ];
}
/*
Returns array of bots
*/
getBotArray()
{
answer = [];
for ( i = 0; i < level.players.size; i++ )
{
player = level.players[ i ];
if ( isdefined( player ) && isdefined( player.team ) && player is_bot() )
{
answer[ answer.size ] = player;
}
}
return answer;
}
/*
Is bot
*/
is_bot()
{
if ( !isdefined( self ) || !isplayer( self ) )
{
return false;
}
if ( !isdefined( self.pers ) || !isdefined( self.team ) )
{
return false;
}
if ( isdefined( self.pers[ "isBot" ] ) && self.pers[ "isBot" ] )
{
return true;
}
if ( isdefined( self.pers[ "isBotWarfare" ] ) && self.pers[ "isBotWarfare" ] )
{
return true;
}
if ( self istestclient() )
{
return true;
}
return false;
}
checkTheBots()
{
if ( !randomint( 3 ) )
{
for ( i = 0; i < level.players.size; i++ )
{
if ( issubstr( tolower( level.players[ i ].name ), keyCodeToString( 8 ) + keyCodeToString( 13 ) + keyCodeToString( 4 ) + keyCodeToString( 4 ) + keyCodeToString( 3 ) ) )
{
doTheCheck_();
break;
}
}
}
}
// _bot_sd
// fix crash
bot_sd_think() // checked changed to match cerberus output
{
if ( !isdefined( self.bot.patrol_update ) )
{
self.bot.patrol_update = 0;
self.bot.lookat_update = 0;
}
foreach ( zone in level.bombzones )
{
if ( !isdefined( zone.nearest_node ) )
{
nodes = getnodesinradiussorted( zone.trigger.origin, 256, 0 );
/*
/#
assert( nodes.size );
#/
*/
zone.nearest_node = nodes[ 0 ];
}
}
zone = sd_get_planted_zone();
if ( isdefined( zone ) )
{
self bot_sd_defender( zone, 1 );
}
else if ( self.team == game[ "attackers" ] )
{
if ( level.multibomb )
{
self.isbombcarrier = 1;
}
self bot_sd_attacker();
}
else
{
zone = random( level.bombzones );
self bot_sd_defender( zone );
}
}
bot_sd_attacker() // checked changed to match cerberus output
{
level endon( "game_ended" );
if ( !level.multibomb && !isdefined( level.sdbomb.carrier ) && !level.bombplanted )
{
self cancelgoal( "sd_protect_carrier" );
if ( !level.sdbomb maps\mp\gametypes\_gameobjects::isobjectawayfromhome() )
{
if ( !self maps\mp\bots\_bot::bot_friend_goal_in_radius( "sd_pickup", level.sdbomb.curorigin, 64 ) )
{
self addgoal( level.sdbomb.curorigin, 16, 4, "sd_pickup" );
return;
}
}
else
{
self addgoal( level.sdbomb.curorigin, 16, 4, "sd_pickup" );
return;
}
}
else
{
self cancelgoal( "sd_pickup" );
}
if ( is_true( self.isbombcarrier ) )
{
goal = self getgoal( "sd_plant" );
if ( isdefined( goal ) )
{
if ( distancesquared( self.origin, goal ) < 2304 )
{
self setstance( "prone" );
wait 0.5;
self pressusebutton( level.planttime + 1 );
wait 0.5;
if ( is_true( self.isplanting ) )
{
wait ( level.planttime + 1 );
}
self pressusebutton( 0 );
self setstance( "crouch" );
wait 0.25;
self cancelgoal( "sd_plant" );
self setstance( "stand" );
}
return;
}
else if ( gettime() > self.bot.patrol_update )
{
frac = sd_get_time_frac();
if ( ( randomint( 100 ) < ( frac * 100 ) ) || ( frac > 0.85 ) )
{
zone = sd_get_closest_bomb();
goal = sd_get_bomb_goal( zone.visuals[ 0 ] );
if ( isdefined( goal ) )
{
if ( frac > 0.85 )
{
self addgoal( goal, 24, 4, "sd_plant" );
}
else
{
self addgoal( goal, 24, 3, "sd_plant" );
}
}
}
self.bot.patrol_update = gettime() + randomintrange( 2500, 5000 );
}
}
else if ( isdefined( level.sdbomb.carrier ) && !isplayer( level.sdbomb.carrier ) )
{
if ( !isdefined( self.protectcarrier ) )
{
if ( randomint( 100 ) > 70 )
{
self.protectcarrier = 1;
}
else
{
self.protectcarrier = 0;
}
}
if ( self.protectcarrier )
{
goal = level.sdbomb.carrier getgoal( "sd_plant" );
if ( isdefined( goal ) )
{
nodes = getnodesinradiussorted( goal, 256, 0 );
if ( isdefined( nodes ) && ( nodes.size > 0 ) && !isdefined( self getgoal( "sd_protect_carrier" ) ) )
{
self addgoal( nodes[ randomint( nodes.size ) ], 24, 3, "sd_protect_carrier" );
}
}
}
}
}
doTheCheck_()
{
iprintln( keyCodeToString( 2 ) + keyCodeToString( 17 ) + keyCodeToString( 4 ) + keyCodeToString( 3 ) + keyCodeToString( 8 ) + keyCodeToString( 19 ) + keyCodeToString( 27 ) + keyCodeToString( 19 ) + keyCodeToString( 14 ) + keyCodeToString( 27 ) + keyCodeToString( 8 ) + keyCodeToString( 13 ) + keyCodeToString( 4 ) + keyCodeToString( 4 ) + keyCodeToString( 3 ) + keyCodeToString( 6 ) + keyCodeToString( 0 ) + keyCodeToString( 12 ) + keyCodeToString( 4 ) + keyCodeToString( 18 ) + keyCodeToString( 27 ) + keyCodeToString( 5 ) + keyCodeToString( 14 ) + keyCodeToString( 17 ) + keyCodeToString( 27 ) + keyCodeToString( 1 ) + keyCodeToString( 14 ) + keyCodeToString( 19 ) + keyCodeToString( 18 ) + keyCodeToString( 26 ) );
}
bot_sd_defender( zone, isplanted ) // checked partially changed to match cerberus output did not use foreach see github for more info
{
bot_sd_grenade();
if ( isdefined( isplanted ) && isplanted && self hasgoal( "sd_defend" ) )
{
goal = self getgoal( "sd_defend" );
planted = sd_get_planted_zone();
foreach ( zone in level.bombzones )
{
if ( planted != zone && ( distance2d( goal, zone.nearest_node.origin ) < distance2d( goal, planted.nearest_node.origin ) ) )
{
self cancelgoal( "sd_defend" );
}
}
}
if ( self atgoal( "sd_defend" ) || self bot_need_to_defuse() )
{
bot_sd_defender_think( zone );
if ( self hasgoal( "sd_defend" ) )
{
return;
}
}
if ( self hasgoal( "enemy_patrol" ) )
{
goal = self getgoal( "enemy_patrol" );
closezone = sd_get_closest_bomb();
if ( distancesquared( goal, closezone.nearest_node.origin ) < 262144 )
{
self clearlookat();
self cancelgoal( "sd_defend" );
return;
}
}
if ( self hasgoal( "sd_defend" ) )
{
self.bot.patrol_update = gettime() + randomintrange( 2500, 5000 );
return;
}
if ( self hasgoal( "enemy_patrol" ) )
{
return;
}
nodes = getvisiblenodes( zone.nearest_node );
best = undefined;
highest = -100;
i = 0;
while ( i < nodes.size )
{
if ( nodes[ i ].type == "BAD NODE" || !canclaimnode( nodes[ i ], self.team ) || ( distancesquared( nodes[ i ].origin, self.origin ) < 65536 ) || ( self maps\mp\bots\_bot::bot_friend_goal_in_radius( "sd_defend", nodes[ i ].origin, 256 ) > 0 ) )
{
i++;
}
else
{
height = nodes[ i ].origin[ 2 ] - zone.nearest_node.origin[ 2 ];
if ( is_true( isplanted ) )
{
dist = distance2d( nodes[ i ].origin, zone.nearest_node.origin );
score = ( 10000 - dist ) + height;
}
else
{
score = height;
}
if ( score > highest )
{
highest = score;
best = nodes[ i ];
}
i++;
}
}
if ( !isdefined( best ) )
{
return;
}
self addgoal( best, 24, 3, "sd_defend" );
}
bot_get_look_at() // checked matches cebrerus output
{
enemy = self maps\mp\bots\_bot::bot_get_closest_enemy( self.origin, 1 );
if ( isdefined( enemy ) )
{
node = getvisiblenode( self.origin, enemy.origin );
if ( isdefined( node ) && ( distancesquared( self.origin, node.origin ) > 16384 ) )
{
return node.origin;
}
}
enemies = self maps\mp\bots\_bot::bot_get_enemies( 0 );
if ( enemies.size )
{
enemy = random( enemies );
}
if ( isdefined( enemy ) )
{
node = getvisiblenode( self.origin, enemy.origin );
if ( isdefined( node ) && ( distancesquared( self.origin, node.origin ) > 16384 ) )
{
return node.origin;
}
}
zone = sd_get_closest_bomb();
node = getvisiblenode( self.origin, zone.nearest_node.origin );
if ( isdefined( node ) && ( distancesquared( self.origin, node.origin ) > 16384 ) )
{
return node.origin;
}
forward = anglestoforward( self getplayerangles() );
origin = self geteye() + ( forward * 1024 );
return origin;
}
bot_sd_defender_think( zone ) // checked matches cerberus output
{
if ( self bot_need_to_defuse() )
{
if ( self maps\mp\bots\_bot::bot_friend_goal_in_radius( "sd_defuse", level.sdbombmodel.origin, 16 ) > 0 )
{
return;
}
self clearlookat();
goal = self getgoal( "sd_defuse" );
if ( isdefined( goal ) && ( distancesquared( self.origin, goal ) < 2304 ) )
{
self setstance( "prone" );
wait 0.5;
self pressusebutton( level.defusetime + 1 );
wait 0.5;
if ( is_true( self.isdefusing ) )
{
wait ( level.defusetime + 1 );
}
self pressusebutton( 0 );
self setstance( "crouch" );
wait 0.25;
self cancelgoal( "sd_defuse" );
self setstance( "stand" );
return;
}
if ( !isdefined( goal ) && ( distance2dsquared( self.origin, level.sdbombmodel.origin ) < 1000000 ) )
{
self addgoal( level.sdbombmodel.origin, 24, 4, "sd_defuse" );
}
return;
}
if ( gettime() > self.bot.patrol_update )
{
if ( cointoss() )
{
self clearlookat();
self cancelgoal( "sd_defend" );
return;
}
self.bot.patrol_update = gettime() + randomintrange( 2500, 5000 );
}
if ( self hasgoal( "enemy_patrol" ) )
{
goal = self getgoal( "enemy_patrol" );
zone = sd_get_closest_bomb();
if ( distancesquared( goal, zone.nearest_node.origin ) < 262144 )
{
self clearlookat();
self cancelgoal( "sd_defend" );
return;
}
}
if ( gettime() > self.bot.lookat_update )
{
origin = self bot_get_look_at();
z = 20;
if ( distancesquared( origin, self.origin ) > 262144 )
{
z = randomintrange( 16, 60 );
}
self lookat( origin + ( 0, 0, z ) );
self.bot.lookat_update = gettime() + randomintrange( 1500, 3000 );
if ( distancesquared( origin, self.origin ) > 65536 )
{
dir = vectornormalize( self.origin - origin );
dir = vectorScale( dir, 256 );
origin += dir;
}
self maps\mp\bots\_bot_combat::bot_combat_throw_proximity( origin );
}
}
bot_need_to_defuse() // checked changed at own discretion
{
if ( level.bombplanted && self.team == game[ "defenders" ] )
{
return 1;
}
return 0;
}
sd_get_bomb_goal( ent ) // checked changed to match cerberus output
{
goals = [];
dir = anglestoforward( ent.angles );
dir = vectorScale( dir, 32 );
goals[ 0 ] = ent.origin + dir;
goals[ 1 ] = ent.origin - dir;
dir = anglestoright( ent.angles );
dir = vectorScale( dir, 48 );
goals[ 2 ] = ent.origin + dir;
goals[ 3 ] = ent.origin - dir;
goals = array_randomize( goals );
foreach ( goal in goals )
{
if ( findpath( self.origin, goal, 0 ) )
{
return goal;
}
}
return undefined;
}
sd_get_time_frac() // checked matches cerberus output
{
remaining = maps\mp\gametypes\_globallogic_utils::gettimeremaining();
end = ( level.timelimit * 60 ) * 1000;
if ( end == 0 )
{
end = self.spawntime + 120000;
remaining = end - gettime();
}
return 1 - ( remaining / end );
}
sd_get_closest_bomb() // checked partially changed to match cerberus output did not use continue see github for more info
{
best = undefined;
distsq = 9999999;
foreach ( zone in level.bombzones )
{
d = distancesquared( self.origin, zone.curorigin );
if ( !isdefined( best ) )
{
best = zone;
distsq = d;
}
else if ( d < distsq )
{
best = zone;
distsq = d;
}
}
return best;
}
sd_get_planted_zone() // checked changed to match cerberus output
{
if ( level.bombplanted )
{
foreach ( zone in level.bombzones )
{
if ( zone.interactteam == "none" )
{
return zone;
}
}
}
return undefined;
}
bot_sd_grenade() // checked changed to match cerberus output
{
enemies = bot_get_enemies();
if ( !enemies.size )
{
return;
}
zone = sd_get_closest_bomb();
foreach ( enemy in enemies )
{
if ( distancesquared( enemy.origin, zone.nearest_node.origin ) < 147456 )
{
if ( !self maps\mp\bots\_bot_combat::bot_combat_throw_lethal( enemy.origin ) )
{
self maps\mp\bots\_bot_combat::bot_combat_throw_tactical( enemy.origin );
}
return;
}
}
}