#include maps/mp/gametypes/_dev; #include maps/mp/killstreaks/_killstreakrules; #include maps/mp/killstreaks/_killstreaks; #include maps/mp/bots/_bot_conf; #include maps/mp/bots/_bot_hq; #include maps/mp/bots/_bot_koth; #include maps/mp/bots/_bot_dom; #include maps/mp/bots/_bot_dem; #include maps/mp/bots/_bot_ctf; #include maps/mp/bots/_bot; #include maps/mp/killstreaks/_radar; #include maps/mp/teams/_teams; #include maps/mp/gametypes/_weapons; #include maps/mp/gametypes/_rank; #include maps/mp/bots/_bot_combat; #include maps/mp/bots/_bot_loadout; #include maps/mp/_utility; #include common_scripts/utility; init() //checked matches cerberus output { //begin debug code level.custom_bot_loaded = 1; maps/mp/gametypes/_clientids::init(); if ( !isDefined( level.debugLogging_bot ) ) { level.debugLogging_bot = 0; } //end debug code /* /# level thread bot_system_devgui_think(); #/ */ level thread maps/mp/bots/_bot_loadout::init(); if ( !bot_gametype_allowed() ) { return; } /* if ( level.rankedmatch && !is_bot_ranked_match() ) { return; } */ /* bot_friends = getDvarInt( "bot_friends" ); bot_enemies = getDvarInt( "bot_enemies" ); if ( bot_friends <= 0 && bot_enemies <= 0 ) { return; } */ //bot_wait_for_host(); bot_set_difficulty(); /* if ( is_bot_comp_stomp() ) { team = bot_choose_comp_stomp_team(); level thread bot_comp_stomp_think( team ); } else if ( is_bot_ranked_match() ) { level thread bot_ranked_think(); } else { */ level thread bot_local_think(); //} } spawn_bot( team ) //checked matches cerberus output { bot = addtestclient(); if ( isDefined( bot ) ) { bot.pers[ "isBot" ] = 1; if ( team != "autoassign" ) { bot.pers[ "team" ] = team; } bot thread bot_spawn_think( team ); return 1; } return 0; } getenemyteamwithlowestplayercount( player_team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { counts = []; foreach ( team in level.teams ) { counts[ team ] = 0; } i = 0; players = get_players(); while ( i < players.size ) { if ( !isDefined( players[ i ].team ) ) { i++; continue; } if ( !isDefined( counts[ players[ i ].team ] ) ) { i++; continue; } counts[ players[ i ].team ]++; i++; } count = 999999; enemy_team = player_team; foreach ( team in level.teams ) { if ( team == player_team ) { } else if ( team == "spectator" ) { } else if ( counts[ team ] < count ) { enemy_team = team; count = counts[ team ]; } } return enemy_team; } getenemyteamwithgreatestbotcount( player_team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { counts = []; foreach ( team in level.teams ) { counts[ team ] = 0; } i = 0; players = get_players(); while ( i < players.size ) { if ( !isDefined( players[ i ].team ) ) { i++; continue; } if ( !isDefined( counts[ players[ i ].team ] ) ) { i++; continue; } if ( !players[ i ] maps/mp/_utility::is_bot() ) { i++; continue; } counts[ players[ i ].team ]++; i++; } count = -1; enemy_team = undefined; foreach ( team in level.teams ) { if ( team == player_team ) { } else if ( team == "spectator" ) { } else if ( counts[ team ] > count ) { enemy_team = team; count = counts[ team ]; } } return enemy_team; } bot_wait_for_host() //checked does not match cerberus output did not change { host = gethostplayerforbots(); while ( !isDefined( host ) ) { wait 0.25; host = gethostplayerforbots(); } if ( level.prematchperiod > 0 && level.inprematchperiod == 1 ) { wait 1; } } bot_count_humans( team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { players = get_players(); count = 0; i = 0; while ( i < players.size ) { if ( players[ i ] maps/mp/_utility::is_bot() ) { i++; continue; } if ( isDefined( team ) ) { if ( getassignedteam( players[ i ] ) == team ) { count++; } i++; continue; } count++; i++; } return count; } bot_count_bots( team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { players = get_players(); count = 0; i = 0; while ( i < players.size ) { if ( !players[ i ] maps/mp/_utility::is_bot() ) { i++; continue; } if ( isDefined( team ) ) { if ( isDefined( players[ i ].team ) && players[ i ].team == team ) { count++; } i++; continue; } count++; i++; } return count; } bot_count_enemy_bots( friend_team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { if ( !level.teambased ) { return bot_count_bots(); } enemies = 0; foreach ( team in level.teams ) { if ( team == friend_team ) { } else { enemies += bot_count_bots( team ); } } return enemies; } bot_choose_comp_stomp_team() //checked matches cerberus output { host = gethostplayerforbots(); /* /# assert( isDefined( host ) ); #/ */ teamkeys = getarraykeys( level.teams ); /* /# assert( teamkeys.size == 2 ); #/ */ enemy_team = host.pers[ "team" ]; /* /# if ( isDefined( enemy_team ) ) { assert( enemy_team != "spectator" ); } #/ */ return getotherteam( enemy_team ); } bot_comp_stomp_think( team ) //checked partially changed to match cerberus output { for ( ;; ) { humans = bot_count_humans(); bots = bot_count_bots(); if ( humans == bots ) { } else if ( bots < humans ) { spawn_bot( team ); } if ( bots > humans ) { bot_comp_stomp_remove( team ); } wait 1; } wait 3; } bot_comp_stomp_remove( team ) //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { players = get_players(); bots = []; remove = undefined; i = 0; while ( i < players.size ) { if ( !isDefined( players[ i ].team ) ) { i++; continue; } if ( players[ i ] maps/mp/_utility::is_bot() ) { if ( level.teambased ) { if ( players[ i ].team == team ) { bots[ bots.size ] = players[ i ]; } i++; continue; } bots[ bots.size ] = players[ i ]; } i++; } if ( !bots.size ) { return; } foreach ( bot in bots ) { if ( !bot maps/mp/bots/_bot_combat::bot_has_enemy() ) { remove = bot; break; } } if ( !isDefined( remove ) ) { remove = random( bots ); } remove botleavegame(); } bot_ranked_remove() //checked changed to match cerberus output { if ( !level.teambased ) { bot_comp_stomp_remove(); return; } high = -1; highest_team = undefined; foreach ( team in level.teams ) { count = countplayers( team ); if ( count > high ) { high = count; highest_team = team; } } bot_comp_stomp_remove( highest_team ); } bot_ranked_count( team ) //checked changed to match cerberus output { count = countplayers( team ); if ( count < 6 ) { spawn_bot( team ); return 1; } else if ( count > 6 ) { bot_comp_stomp_remove( team ); return 1; } return 0; } bot_ranked_think() //checked partially changed to match cerberus output //changed at own discretion { level endon( "game_ended" ); wait 5; for ( ;; ) { wait 1; teams = []; teams[ 0 ] = "axis"; teams[ 1 ] = "allies"; if ( cointoss() ) { teams[ 0 ] = "allies"; teams[ 1 ] = "axis"; } if ( !bot_ranked_count( teams[ 0 ] ) && !bot_ranked_count( teams[ 1 ] ) ) { break; //not in cerberus output but leaving here anyway= } } for ( ;; ) { level waittill_any( "connected", "disconnect" ); wait 5; while ( isDefined( level.hostmigrationtimer ) ) { wait 1; } } } bot_local_friends( expected_friends, max, host_team ) //checked matches cerberus output { if ( level.teambased ) { players = get_players(); friends = bot_count_bots( host_team ); if ( friends < expected_friends && players.size < max ) { spawn_bot( host_team ); return 1; } if ( friends > expected_friends ) { bot_comp_stomp_remove( host_team ); return 1; } } return 0; } bot_local_enemies( expected_enemies, max, host_team ) //checked matches cerberus output { enemies = bot_count_enemy_bots( host_team ); players = get_players(); if ( enemies < expected_enemies && players.size < max ) { team = getenemyteamwithlowestplayercount( host_team ); spawn_bot( team ); return 1; } if ( enemies > expected_enemies ) { team = getenemyteamwithgreatestbotcount( host_team ); if ( isDefined( team ) ) { bot_comp_stomp_remove( team ); } return 1; } return 0; } bot_local_think() //checked changed at own discretion { wait 5; host = gethostplayerforbots(); /* /# assert( isDefined( host ) ); #/ */ host_team = host.team; if ( !isDefined( host_team ) || host_team == "spectator" ) { host_team = "allies"; } //bot_expected_friends = getDvarInt( "bot_friends" ); //bot_expected_enemies = getDvarInt( "bot_enemies" ); bot_expected_friends = 1; bot_expected_enemies = 1; if ( islocalgame() ) { } else { } max_players = 18; for ( ;; ) { if ( bot_local_friends( bot_expected_friends, max_players, host_team ) ) { wait 0.5; continue; } if ( bot_local_enemies( bot_expected_enemies, max_players, host_team ) ) { wait 0.5; continue; } wait 3; } } is_bot_ranked_match() //checked changed at own discretion { bot_enemies = getDvarInt( "bot_enemies" ); isdedicatedbotsoak = getDvarInt( "sv_botsoak" ); //dvar taken from bo3 no guarantees it works if ( level.rankedmatch && bot_enemies && isdedicatedbotsoak == 0 ) { return 1; } return 0; } is_bot_comp_stomp() //checked changed at own discretion { if ( is_bot_ranked_match() && !getDvarInt( "party_autoteams" ) ) { return 1; } return 0; } bot_spawn_think( team ) //checked changed to match cerberus output { self endon( "disconnect" ); while ( !isDefined( self.pers[ "bot_loadout" ] ) ) { wait 0.1; } while ( !isDefined( self.team ) ) { wait 0.05; } if ( level.teambased ) { self notify( "menuresponse", game["menu_team"], team ); wait 0.5; } self notify( "joined_team" ); bot_classes = bot_build_classes(); self notify( "menuresponse", "changeclass", random(bot_classes) ); } bot_build_classes() //checked matches cerberus output { bot_classes = []; if ( !self isitemlocked( maps/mp/gametypes/_rank::getitemindex( "feature_cac" ) ) ) { bot_classes[ bot_classes.size ] = "custom0"; bot_classes[ bot_classes.size ] = "custom1"; bot_classes[ bot_classes.size ] = "custom2"; bot_classes[ bot_classes.size ] = "custom3"; bot_classes[ bot_classes.size ] = "custom4"; if ( randomint( 100 ) < 10 ) { bot_classes[ bot_classes.size ] = "class_smg"; bot_classes[ bot_classes.size ] = "class_cqb"; bot_classes[ bot_classes.size ] = "class_assault"; bot_classes[ bot_classes.size ] = "class_lmg"; bot_classes[ bot_classes.size ] = "class_sniper"; } } else { bot_classes[ bot_classes.size ] = "class_smg"; bot_classes[ bot_classes.size ] = "class_cqb"; bot_classes[ bot_classes.size ] = "class_assault"; bot_classes[ bot_classes.size ] = "class_lmg"; bot_classes[ bot_classes.size ] = "class_sniper"; } return bot_classes; } bot_choose_class() //checked partially changed to match cerberus output did not use foreach with continue to prevent infinite loop due to continue { bot_classes = bot_build_classes(); if ( !self maps/mp/bots/_bot_combat::threat_requires_rocket( self.bot.attacker ) || self maps/mp/bots/_bot_combat::threat_is_qrdrone( self.bot.attacker ) && !maps/mp/bots/_bot_combat::threat_is_warthog( self.bot.attacker ) ) { if ( randomint( 100 ) < 75 ) { bot_classes[ bot_classes.size ] = "class_smg"; bot_classes[ bot_classes.size ] = "class_cqb"; bot_classes[ bot_classes.size ] = "class_assault"; bot_classes[ bot_classes.size ] = "class_lmg"; bot_classes[ bot_classes.size ] = "class_sniper"; } i = 0; while ( i < bot_classes.size ) { sidearm = self getloadoutweapon( i, "secondary" ); if ( sidearm == "fhj18_mp" ) { self notify( "menuresponse", "changeclass", bot_classes[ i ] ); i++; continue; } if ( sidearm == "smaw_mp" ) { bot_classes[ bot_classes.size ] = bot_classes[ i ]; bot_classes[ bot_classes.size ] = bot_classes[ i ]; bot_classes[ bot_classes.size ] = bot_classes[ i ]; } i++; } } else if ( maps/mp/bots/_bot_combat::threat_requires_rocket( self.bot.attacker ) || maps/mp/bots/_bot_combat::threat_is_warthog( self.bot.attacker ) ) { for ( i = 0; i < bot_classes.size; i++ ) { perks = self getloadoutperks( i ); foreach ( perk in perks ) { if ( perk == "specialty_nottargetedbyairsupport" ) { bot_classes[ bot_classes.size ] = bot_classes[ i ]; bot_classes[ bot_classes.size ] = bot_classes[ i ]; bot_classes[ bot_classes.size ] = bot_classes[ i ]; } } } } self notify( "menuresponse", "changeclass", random(bot_classes) ); } bot_spawn() //checked matches cerberus output { self endon( "disconnect" ); /* /# weapon = undefined; if ( getDvarInt( "scr_botsHasPlayerWeapon" ) != 0 ) { player = gethostplayer(); weapon = player getcurrentweapon(); } if ( getDvar( "devgui_bot_weapon" ) != "" ) { weapon = getDvar( "devgui_bot_weapon" ); } if ( isDefined( weapon ) ) { self maps/mp/gametypes/_weapons::detach_all_weapons(); self takeallweapons(); self giveweapon( weapon ); self switchtoweapon( weapon ); self setspawnweapon( weapon ); self maps/mp/teams/_teams::set_player_model( self.team, weapon ); #/ } */ self bot_spawn_init(); if ( isDefined( self.bot_first_spawn ) ) { self bot_choose_class(); } self.bot_first_spawn = 1; self thread bot_main(); /* /# self thread bot_devgui_think(); #/ */ } bot_spawn_init() //checked matches cerberus output { time = getTime(); if ( !isDefined( self.bot ) ) { self.bot = spawnstruct(); self.bot.threat = spawnstruct(); } self.bot.glass_origin = undefined; self.bot.ignore_entity = []; self.bot.previous_origin = self.origin; self.bot.time_ads = 0; self.bot.update_c4 = time + randomintrange( 1000, 3000 ); self.bot.update_crate = time + randomintrange( 1000, 3000 ); self.bot.update_crouch = time + randomintrange( 1000, 3000 ); self.bot.update_failsafe = time + randomintrange( 1000, 3000 ); self.bot.update_idle_lookat = time + randomintrange( 1000, 3000 ); self.bot.update_killstreak = time + randomintrange( 1000, 3000 ); self.bot.update_lookat = time + randomintrange( 1000, 3000 ); self.bot.update_objective = time + randomintrange( 1000, 3000 ); self.bot.update_objective_patrol = time + randomintrange( 1000, 3000 ); self.bot.update_patrol = time + randomintrange( 1000, 3000 ); self.bot.update_toss = time + randomintrange( 1000, 3000 ); self.bot.update_launcher = time + randomintrange( 1000, 3000 ); self.bot.update_weapon = time + randomintrange( 1000, 3000 ); difficulty = bot_get_difficulty(); switch( difficulty ) { case "easy": self.bot.think_interval = 0.5; self.bot.fov = 0.4226; break; case "normal": self.bot.think_interval = 0.25; self.bot.fov = 0.0872; break; case "hard": self.bot.think_interval = 0.2; self.bot.fov = -0.1736; break; case "fu": self.bot.think_interval = 0.1; self.bot.fov = -0.9396; break; default: self.bot.think_interval = 0.25; self.bot.fov = 0.0872; break; } self.bot.threat.entity = undefined; self.bot.threat.position = ( 0, 0, 0 ); self.bot.threat.time_first_sight = 0; self.bot.threat.time_recent_sight = 0; self.bot.threat.time_aim_interval = 0; self.bot.threat.time_aim_correct = 0; self.bot.threat.update_riotshield = 0; } bot_wakeup_think() { self endon( "death" ); self endon( "disconnect" ); level endon( "game_ended" ); for ( ;; ) { wait self.bot.think_interval; self notify( "wakeup" ); } } bot_damage_think() //checked changed to match cerberus output { self notify( "bot_damage_think" ); self endon( "bot_damage_think" ); self endon( "disconnect" ); level endon( "game_ended" ); for ( ;; ) { self waittill( "damage", damage, attacker, direction, point, mod, unused1, unused2, unused3, weapon, flags, inflictor ); if ( attacker.classname == "worldspawn" ) { continue; } else if ( isDefined( weapon ) ) { if ( weapon == "proximity_grenade_mp" || weapon == "proximity_grenade_aoe_mp" ) { continue; } if ( weapon == "claymore_mp" ) { continue; } if ( weapon == "satchel_charge_mp" ) { continue; } if ( weapon == "bouncingbetty_mp" ) { continue; } } if ( isDefined( inflictor ) ) { switch( inflictor.classname ) { case "auto_turret": case "script_vehicle": attacker = inflictor; break; } } if ( isDefined( attacker.viewlockedentity ) ) { attacker = attacker.viewlockedentity; } if ( maps/mp/bots/_bot_combat::threat_requires_rocket( attacker ) || maps/mp/bots/_bot_combat::threat_is_warthog( attacker ) ) { level thread bot_killstreak_dangerous_think( self.origin, self.team, attacker ); } self.bot.attacker = attacker; self notify( "wakeup", damage, attacker, direction ); } } bot_killcam_think() //checked matches cerberus output { self notify( "bot_killcam_think" ); self endon( "bot_killcam_think" ); self endon( "disconnect" ); level endon( "game_ended" ); wait_time = 0.5; if ( level.playerrespawndelay ) { wait_time = level.playerrespawndelay + 1.5; } if ( !level.killcam ) { self waittill( "death" ); } else { self waittill( "begin_killcam" ); } wait wait_time; for ( ;; ) { self pressusebutton( 0.1 ); wait 0.5; } } bot_glass_think() //checked matches cerberus output { self endon( "death" ); self endon( "disconnect" ); level endon( "game_ended" ); for ( ;; ) { self waittill( "glass", origin ); self.bot.glass_origin = origin; self notify( "wakeup" ); } } bot_main() //checked matches cerberus output { self endon( "death" ); self endon( "disconnect" ); level endon( "game_ended" ); if ( level.inprematchperiod ) { level waittill( "prematch_over" ); self.bot.update_failsafe = getTime() + randomintrange( 1000, 3000 ); } self thread bot_wakeup_think(); self thread bot_damage_think(); self thread bot_killcam_think(); self thread bot_glass_think(); for ( ;; ) { self waittill( "wakeup", damage, attacker, direction ); if ( self isremotecontrolling() ) { continue; } else { self maps/mp/bots/_bot_combat::bot_combat_think( damage, attacker, direction ); self bot_update_glass(); self bot_update_patrol(); self bot_update_lookat(); self bot_update_killstreak(); self bot_update_wander(); self bot_update_c4(); self bot_update_launcher(); self bot_update_weapon(); if ( cointoss() ) { self bot_update_toss_flash(); self bot_update_toss_frag(); } else { self bot_update_toss_frag(); self bot_update_toss_flash(); } self [[ level.bot_gametype ]](); } } } bot_failsafe_node_valid( nearest, node ) //checked changed to match cerberus output { if ( isDefined( node.script_noteworthy ) ) { return 0; } if ( ( node.origin[ 2 ] - self.origin[ 2 ] ) > 18 ) { return 0; } if ( nearest == node ) { return 0; } if ( !nodesvisible( nearest, node ) ) { return 0; } if ( self bot_friend_in_radius( node.origin, 32 ) ) { return 0; } if ( isDefined( level.spawn_all ) && level.spawn_all.size > 0 ) { spawns = arraysort( level.spawn_all, node.origin ); } else if ( isDefined( level.spawnpoints ) && level.spawnpoints.size > 0 ) { spawns = arraysort( level.spawnpoints, node.origin ); } else if ( isDefined( level.spawn_start ) && level.spawn_start.size > 0 ) { spawns = arraycombine( level.spawn_start[ "allies" ], level.spawn_start[ "axis" ], 1, 0 ); spawns = arraysort( spawns, node.origin ); } else { return 0; } goal = bot_nearest_node( spawns[ 0 ].origin ); if ( isDefined( goal ) && findpath( node.origin, goal.origin, undefined, 0, 1 ) ) { return 1; } return 0; } bot_get_mantle_start() //checked changed at own discretion { dist = self getlookaheaddist(); dir = self getlookaheaddir(); if ( dist > 0 && isDefined( dir ) ) { forward = anglesToForward( self.angles ); if ( vectordot( dir, forward ) < 0 ) { dir = vectorScale( dir, dist ); origin = self.origin + dir; nodes = getnodesinradius( origin, 16, 0, 16, "Begin" ); //if ( nodes.size && nodes[ 0 ].spawnflags & 8388608 ) if ( nodes.size && nodes[ 0 ].spawnflags ) { return nodes[ 0 ]; } } } return undefined; } bot_is_traversing() //checked changed at own discretion { if ( !self isonground() && !self ismantling() && !self isonladder() ) { return 1; } return 0; } bot_update_failsafe() //checked partially changed to match cerberus output //did not change while loop to foreach to prevent infinite continue loop bug { time = getTime(); if ( ( time - self.spawntime ) < 7500 ) { return; } if ( bot_is_traversing() ) { wait 0.25; node = bot_get_mantle_start(); if ( isDefined( node ) ) { end = getnode( node.target, "targetname" ); self clearlookat(); self botsetfailsafenode( end ); self wait_endon( 1, "goal" ); self botsetfailsafenode(); return; } } if ( time < self.bot.update_failsafe ) { return; } if ( !self ismantling() || self isonladder() && !self isonground() ) { wait randomfloatrange( 0.1, 0.25 ); return; } if ( !self atgoal() && distance2dsquared( self.bot.previous_origin, self.origin ) < 256 ) { nodes = getnodesinradius( self.origin, 512, 0 ); nodes = array_randomize( nodes ); nearest = bot_nearest_node( self.origin ); failsafe = 0; if ( isDefined( nearest ) ) { i = 0; while ( i < nodes.size ) { if ( !bot_failsafe_node_valid( nearest, nodes[ i ] ) ) { i++; continue; } else { self botsetfailsafenode( nodes[ i ] ); wait 0.5; self.bot.update_idle_lookat = 0; self bot_update_lookat(); self cancelgoal( "enemy_patrol" ); self wait_endon( 4, "goal" ); self botsetfailsafenode(); self bot_update_lookat(); failsafe = 1; break; } i++; } } else if ( !failsafe && nodes.size ) { node = random( nodes ); self botsetfailsafenode( node ); wait 0.5; self.bot.update_idle_lookat = 0; self bot_update_lookat(); self cancelgoal( "enemy_patrol" ); self wait_endon( 4, "goal" ); self botsetfailsafenode(); self bot_update_lookat(); } } self.bot.update_failsafe = getTime() + 3500; self.bot.previous_origin = self.origin; } bot_update_crouch() //checked changed to match cerberus output { time = getTime(); if ( time < self.bot.update_crouch ) { return; } if ( self atgoal() ) { return; } if ( self ismantling() || self isonladder() && !self isonground() ) { return; } dist = self getlookaheaddist(); if ( dist > 0 ) { dir = self getlookaheaddir(); /* /# assert( isDefined( dir ) ); #/ */ dir = vectorScale( dir, dist ); start = self.origin + vectorScale( ( 0, 0, 1 ), 70 ); end = start + dir; if ( dist >= 256 ) { self.bot.update_crouch = time + 1500; } if ( self getstance() == "stand" ) { trace = worldtrace( start, end ); if ( trace[ "fraction" ] < 1 ) { self setstance( "crouch" ); self.bot.update_crouch = time + 2500; } } else if ( self getstance() == "crouch" ) { trace = worldtrace( start, end ); if ( trace[ "fraction" ] >= 1 ) { self setstance( "stand" ); } } } } bot_update_glass() //checked matches cerberus output { if ( isDefined( self.bot.glass_origin ) ) { forward = anglesToForward( self.angles ); dir = vectornormalize( self.bot.glass_origin - self.origin ); dot = vectordot( forward, dir ); if ( dot > 0 ) { self lookat( self.bot.glass_origin ); wait_time = 0.5 * ( 1 - dot ); wait_time = clamp( wait_time, 0.05, 0.5 ); wait wait_time; self pressmelee(); wait 0.25; self clearlookat(); self.bot.glass_origin = undefined; } } } bot_has_radar() //checked changed at own discretion { if ( ( maps/mp/killstreaks/_radar::teamhasspyplane( self.team ) || maps/mp/killstreaks/_radar::teamhassatellite( self.team ) ) && level.teambased ) { return 1; } if ( isDefined( self.hasspyplane ) && self.hasspyplane || isDefined( self.hassatellite ) && self.hassatellite) { return 1; } return 0; } bot_get_enemies( on_radar ) //checked partially changed to match cerberus output //did not change while loop to for loop to prevent infinite continue bug { if ( !isDefined( on_radar ) ) { on_radar = 0; } enemies = self getenemies( 1 ); /* /# for ( i = 0; i < enemies.size; i++ ) { if ( enemies[ i ] isinmovemode( "ufo", "noclip" ) ) { arrayremoveindex( enemies, i ); i--; } #/ } */ if ( on_radar && !self bot_has_radar() ) { i = 0; while ( i < enemies.size ) { if ( !isDefined( enemies[ i ].lastfiretime ) ) { arrayremoveindex( enemies, i ); i--; i++; continue; } if ( ( getTime() - enemies[ i ].lastfiretime ) > 2000 ) { arrayremoveindex( enemies, i ); i--; i++; continue; } i++; } } return enemies; } bot_get_friends() //checked changed to match cerberus output { friends = self getfriendlies( 1 ); /* /# for ( i = 0; i < friends.size; i++ ) { if ( friends[ i ] isinmovemode( "ufo", "noclip" ) ) { arrayremoveindex( friends, i ); i--; } #/ } */ return friends; } bot_friend_goal_in_radius( goal_name, origin, radius ) //checked changed to match cerberus output { count = 0; friends = bot_get_friends(); foreach ( friend in friends ) { if ( friend maps/mp/_utility::is_bot() ) { goal = friend getgoal( goal_name ); if ( isDefined( goal ) && distancesquared( origin, goal ) < radius * radius ) { count++; } } } return count; } bot_friend_in_radius( origin, radius ) //checked changed to match cerberus output { friends = bot_get_friends(); foreach ( friend in friends ) { if ( distancesquared( friend.origin, origin ) < ( radius * radius ) ) { return 1; } } return 0; } bot_get_closest_enemy( origin, on_radar ) //checked matches cerberus output { enemies = self bot_get_enemies( on_radar ); enemies = arraysort( enemies, origin ); if ( enemies.size ) { return enemies[ 0 ]; } return undefined; } bot_update_wander() //checked changed to match cerberus output { goal = self getgoal( "wander" ); if ( isDefined( goal ) ) { if ( distancesquared( goal, self.origin ) > 65536 ) { return; } } if ( isDefined( level.spawn_all ) && level.spawn_all.size > 0 ) { spawns = arraysort( level.spawn_all, self.origin ); } if ( isDefined( level.spawnpoints ) && level.spawnpoints.size > 0 ) { spawns = arraysort( level.spawnpoints, self.origin ); } if ( isDefined( level.spawn_start ) && level.spawn_start.size > 0 ) { spawns = arraycombine( level.spawn_start[ "allies" ], level.spawn_start[ "axis" ], 1, 0 ); spawns = arraysort( spawns, self.origin ); } else { return; } far = int( spawns.size / 2 ); far = randomintrange( far, spawns.size ); goal = bot_nearest_node( spawns[ far ].origin ); if ( !isDefined( goal ) ) { return; } self addgoal( goal, 24, 1, "wander" ); } bot_get_look_at() //checked matches cerberus 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 ) > 1024 ) { 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 ) > 1024 ) { return node.origin; } } spawn = self getgoal( "wander" ); if ( isDefined( spawn ) ) { node = getvisiblenode( self.origin, spawn ); } if ( isDefined( node ) && distancesquared( self.origin, node.origin ) > 1024 ) { return node.origin; } return undefined; } bot_update_lookat() //checked changed to match cerberus output { path = 0; if ( isDefined( self getlookaheaddir() ) ) { path = 1; } if ( !path && getTime() > self.bot.update_idle_lookat ) { origin = bot_get_look_at(); if ( !isDefined( origin ) ) { return; } self lookat( origin + vectorScale( ( 0, 0, 1 ), 16 ) ); self.bot.update_idle_lookat = getTime() + randomintrange( 1500, 3000 ); } else if ( path && self.bot.update_idle_lookat > 0 ) { self clearlookat(); self.bot.update_idle_lookat = 0; } } bot_update_patrol() //checked matches cerberus output { closest = bot_get_closest_enemy( self.origin, 1 ); if ( isDefined( closest ) && distancesquared( self.origin, closest.origin ) < 262144 ) { goal = self getgoal( "enemy_patrol" ); if ( isDefined( goal ) && distancesquared( goal, closest.origin ) > 16384 ) { self cancelgoal( "enemy_patrol" ); self.bot.update_patrol = 0; } } if ( getTime() < self.bot.update_patrol ) { return; } self maps/mp/bots/_bot_combat::bot_patrol_near_enemy(); self.bot.update_patrol = getTime() + randomintrange( 5000, 10000 ); } bot_update_toss_flash() //checked matches cerberus output { if ( bot_get_difficulty() == "easy" ) { return; } time = getTime(); if ( ( time - self.spawntime ) < 7500 ) { return; } if ( time < self.bot.update_toss ) { return; } self.bot.update_toss = time + 1500; if ( self getweaponammostock( "sensor_grenade_mp" ) <= 0 && self getweaponammostock( "proximity_grenade_mp" ) <= 0 && self getweaponammostock( "trophy_system_mp" ) <= 0 ) { return; } enemy = self maps/mp/bots/_bot::bot_get_closest_enemy( self.origin, 1 ); node = undefined; if ( isDefined( enemy ) ) { node = getvisiblenode( self.origin, enemy.origin ); } if ( isDefined( node ) && distancesquared( self.origin, node.origin ) < 65536 ) { self lookat( node.origin ); wait 0.75; self pressattackbutton( 2 ); self.bot.update_toss = time + 20000; self clearlookat(); } } bot_update_toss_frag() //checked matches cerberus output { if ( bot_get_difficulty() == "easy" ) { return; } time = getTime(); if ( ( time - self.spawntime ) < 7500 ) { return; } if ( time < self.bot.update_toss ) { return; } self.bot.update_toss = time + 1500; if ( self getweaponammostock( "bouncingbetty_mp" ) <= 0 && self getweaponammostock( "claymore_mp" ) <= 0 && self getweaponammostock( "satchel_charge_mp" ) <= 0 ) { return; } enemy = self maps/mp/bots/_bot::bot_get_closest_enemy( self.origin, 1 ); node = undefined; if ( isDefined( enemy ) ) { node = getvisiblenode( self.origin, enemy.origin ); } if ( isDefined( node ) && distancesquared( self.origin, node.origin ) < 65536 ) { self lookat( node.origin ); wait 0.75; self pressattackbutton( 1 ); self.bot.update_toss = time + 20000; self clearlookat(); } } bot_set_rank() //checked partially changed to match cerberus output //did not change while loop to for loop to prevent infinite loop due to continue { players = get_players(); ranks = []; bot_ranks = []; human_ranks = []; i = 0; while ( i < players.size ) { if ( players[ i ] == self ) { i++; continue; } if ( isDefined( players[ i ].pers[ "rank" ] ) ) { if ( players[ i ] maps/mp/_utility::is_bot() ) { bot_ranks[ bot_ranks.size ] = players[ i ].pers[ "rank" ]; i++; continue; } human_ranks[ human_ranks.size ] = players[ i ].pers[ "rank" ]; } i++; } if ( !human_ranks.size ) { human_ranks[ human_ranks.size ] = 10; } human_avg = array_average( human_ranks ); while ( ( bot_ranks.size + human_ranks.size ) < 5 ) { r = human_avg + randomintrange( -5, 5 ); rank = clamp( r, 0, level.maxrank ); human_ranks[ human_ranks.size ] = rank; } ranks = arraycombine( human_ranks, bot_ranks, 1, 0 ); avg = array_average( ranks ); s = array_std_deviation( ranks, avg ); rank = int( random_normal_distribution( avg, s, 0, level.maxrank ) ); self.pers[ "rank" ] = rank; self.pers[ "rankxp" ] = maps/mp/gametypes/_rank::getrankinfominxp( rank ); self setrank( rank ); self maps/mp/gametypes/_rank::syncxpstat(); } bot_gametype_allowed() //checked matches cerberus output { level.bot_gametype = ::gametype_void; switch( level.gametype ) { case "dm": case "tdm": return 1; case "ctf": level.bot_gametype = maps/mp/bots/_bot_ctf::bot_ctf_think; return 1; case "dem": level.bot_gametype = maps/mp/bots/_bot_dem::bot_dem_think; return 1; case "dom": level.bot_gametype = maps/mp/bots/_bot_dom::bot_dom_think; return 1; case "koth": level.bot_gametype = maps/mp/bots/_bot_koth::bot_koth_think; return 1; case "hq": level.bot_gametype = maps/mp/bots/_bot_hq::bot_hq_think; return 1; case "conf": level.bot_gametype = maps/mp/bots/_bot_conf::bot_conf_think; return 1; } return 0; } bot_get_difficulty() //checked matches cerberus output { level.bot_difficulty = "normal"; difficulty = getdvarintdefault( "bot_difficulty", 1 ); if ( difficulty == 0 ) { level.bot_difficulty = "easy"; } else if ( difficulty == 1 ) { level.bot_difficulty = "normal"; } else if ( difficulty == 2 ) { level.bot_difficulty = "hard"; } else if ( difficulty == 3 ) { level.bot_difficulty = "fu"; } return level.bot_difficulty; } bot_set_difficulty() //checked changed to match cerberus output { difficulty = bot_get_difficulty(); if ( difficulty == "fu" ) { 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 == "hard" ) { 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 == "easy" ) { 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 { 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 == "fu" ) { setdvar( "bot_MinReactionTime", "400" ); setdvar( "bot_MaxReactionTime", "500" ); setdvar( "bot_MinAdsTime", "1000" ); setdvar( "bot_MaxAdsTime", "2000" ); } if ( ( difficulty == "hard" || difficulty == "fu" ) && level.gametype == "oic" ) { setdvar( "bot_SprintDistance", "256" ); } } bot_update_c4() { if ( !isDefined( self.weaponobjectwatcherarray ) ) { return; } time = getTime(); if ( time < self.bot.update_c4 ) { return; } self.bot.update_c4 = time + randomintrange( 1000, 2000 ); radius = getweaponexplosionradius( "satchel_charge_mp" ); foreach ( watcher in self.weaponobjectwatcherarray ) { if ( watcher.name == "satchel_charge" ) { break; } } if ( watcher.objectarray.size ) { i = 0; while ( i < watcherArray.objectarray.size ) { if ( !isDefined( watcher.objectarray[ i ] ) ) { i++; continue; } enemy = bot_get_closest_enemy( watcher.objectarray[ i ].origin, 0 ); if ( !isDefined( enemy ) ) { return; } if ( distancesquared( enemy.origin, watcher.objectarray[ i ].origin ) < radius * radius ) { self pressattackbutton( 1 ); return; } i++; } } } bot_update_launcher() //checked partially changed to match cerberus output //continues in foreach bad see github for more info { time = getTime(); if ( time < self.bot.update_launcher ) { return; } self.bot.update_launcher = time + randomintrange( 5000, 10000 ); if ( !self maps/mp/bots/_bot_combat::bot_has_launcher() ) { return; } enemies = self getthreats( -1 ); i = 0; while ( i < enemies.size ) { if ( !target_istarget( enemies[ i ] ) ) { i++; continue; } if ( maps/mp/bots/_bot_combat::threat_is_warthog( enemies[ i ] ) ) { i++; continue; } if ( !maps/mp/bots/_bot_combat::threat_requires_rocket( enemies[ i ] ) ) { i++; continue; } origin = self getplayercamerapos(); angles = vectorToAngles( enemies[ i ].origin - origin ); if ( angles[ 0 ] < 290 ) { i++; continue; } if ( self botsighttracepassed( enemies[ i ] ) ) { self maps/mp/bots/_bot_combat::bot_lookat_entity( enemies[ i ] ); return; } i++; } } bot_update_weapon() { time = getTime(); if ( time < self.bot.update_weapon ) { return; } self.bot.update_weapon = time + randomintrange( 5000, 7500 ); weapon = self getcurrentweapon(); ammo = self getweaponammoclip( weapon ) + self getweaponammostock( weapon ); if ( weapon == "none" ) { return; } if ( self maps/mp/bots/_bot_combat::bot_can_reload() ) { frac = 0.5; if ( maps/mp/bots/_bot_combat::bot_has_lmg() ) { frac = 0.25; } frac += randomfloatrange( -0.1, 0.1 ); if ( maps/mp/bots/_bot_combat::bot_weapon_ammo_frac() < frac ) { self pressusebutton( 0.1 ); return; } } if ( ammo && !self maps/mp/bots/_bot_combat::bot_has_pistol() && !self maps/mp/bots/_bot_combat::bot_using_launcher() ) { return; } primaries = self getweaponslistprimaries(); foreach ( primary in primaries ) { if ( primary == "knife_held_mp" ) { i++; continue; } if ( ( self getweaponammoclip( primary ) || self getweaponammostock( primary ) ) && primary != weapon ) { self switchtoweapon( primary ); return; } i++; } } bot_update_crate() //checked partially changed to match cerberus output continue in foreach bad see github for more info { time = getTime(); if ( time < self.bot.update_crate ) { return; } self.bot.update_crate = time + randomintrange( 1000, 3000 ); self cancelgoal( "care package" ); radius = getDvarFloat( "player_useRadius" ); crates = getentarray( "care_package", "script_noteworthy" ); i = 0; while ( i < crates.size ) { if ( distancesquared( self.origin, crates[ i ].origin ) < radius * radius ) { if ( isDefined( crates[ i ].hacker ) ) { if ( crates[ i ].hacker == self ) { i++; continue; } if ( crates[ i ].hacker.team == self.team ) { i++; continue; } } if ( crates[ i ].owner == self ) { time = ( level.crateownerusetime / 1000 ) + 0.5; } else { time = ( level.cratenonownerusetime / 1000 ) + 0.5; } self setstance( "crouch" ); self addgoal( self.origin, 24, 4, "care package" ); self pressusebutton( time ); wait time; self setstance( "stand" ); self cancelgoal( "care package" ); self.bot.update_crate = getTime() + randomintrange( 1000, 3000 ); return; } i++; } if ( self getweaponammostock( "pda_hack_mp" ) ) { i = 0; while ( i < crates.size ) { if ( !isDefined( crates[ i ].friendlyobjid ) ) { i++; continue; } if ( isDefined( crates[ i ].hacker ) ) { if ( crates[ i ].hacker == self ) { i++; continue; } else if ( crates[ i ].hacker.team == self.team ) { i++; continue; } } if ( self botsighttracepassed( crates[ i ] ) ) { self lookat( crates[ i ].origin ); self addgoal( self.origin, 24, 4, "care package" ); wait 0.75; start = getTime(); if ( !isDefined( crates[ i ].owner ) ) { self cancelgoal( "care package" ); return; } if ( crates[ i ].owner == self ) { end = level.crateownerusetime + 1000; i++; continue; } end = level.cratenonownerusetime + 1000; while ( getTime() < start + end ) { self pressattackbutton( 2 ); wait 0.05; } self.bot.update_crate = getTime() + randomintrange( 1000, 3000 ); self cancelgoal( "care package" ); return; } i++; } } } bot_update_killstreak() //checked partially changed to match cerberus output see info about continues on the github { if ( !level.loadoutkillstreaksenabled ) { return; } time = getTime(); if ( time < self.bot.update_killstreak ) { return; } if ( self isweaponviewonlylinked() ) { return; } /* /# if ( !getDvarInt( "scr_botsAllowKillstreaks" ) ) { return; #/ } */ self.bot.update_killstreak = time + randomintrange( 1000, 3000 ); weapons = self getweaponslist(); ks_weapon = undefined; inventoryweapon = self getinventoryweapon(); i = 0; while ( i < weapons.size ) { if ( self getweaponammoclip( weapons[ i ] ) <= 0 && !isDefined( inventoryweapon ) || weapons[ i ] != inventoryweapon ) { i++; continue; } if ( iskillstreakweapon( weapons[ i ] ) ) { killstreak = maps/mp/killstreaks/_killstreaks::getkillstreakforweapon( weapons[ i ] ); if ( self maps/mp/killstreaks/_killstreakrules::iskillstreakallowed( killstreak, self.team ) ) { ks_weapon = weapons[ i ]; break; } } i++; } if ( !isDefined( ks_weapon ) ) { return; } killstreak = maps/mp/killstreaks/_killstreaks::getkillstreakforweapon( ks_weapon ); killstreak_ref = maps/mp/killstreaks/_killstreaks::getkillstreakmenuname( killstreak ); if ( !isDefined( killstreak_ref ) ) { return; } switch( killstreak_ref ) { case "killstreak_helicopter_comlink": bot_killstreak_location( 1, weapon ); break; case "killstreak_planemortar": bot_killstreak_location( 3, weapon ); break; case "killstreak_ai_tank_drop": case "killstreak_missile_drone": case "killstreak_supply_drop": self bot_use_supply_drop( weapon ); break; case "killstreak_auto_turret": case "killstreak_microwave_turret": case "killstreak_tow_turret": self bot_turret_location( weapon ); break; case "killstreak_helicopter_player_gunner": case "killstreak_qrdrone": case "killstreak_rcbomb": case "killstreak_remote_mortar": return; case "killstreak_remote_missile": if ( ( time - self.spawntime ) < 6000 ) { self switchtoweapon( weapons[ i ] ); self waittill( "weapon_change_complete" ); wait 1.5; self pressattackbutton(); } return; default: self switchtoweapon( weapons[ i ] ); break; } } bot_get_vehicle_entity() //checked changed to match cerberus output { if ( self isremotecontrolling() ) { if ( isDefined( self.rcbomb ) ) { return self.rcbomb; } else if ( isDefined( self.qrdrone ) ) { return self.qrdrone; } } return undefined; } bot_rccar_think() //checked partially changed to match cerberus output check the github for info on continues { self endon( "disconnect" ); self endon( "rcbomb_done" ); self endon( "weapon_object_destroyed" ); level endon( "game_ended" ); wait 2; self thread bot_rccar_kill(); for ( ;; ) { wait 0.5; ent = self bot_get_vehicle_entity(); if ( !isDefined( ent ) ) { return; } players = get_players(); i = 0; while ( i < players.size ) { player = players[ i ]; if ( player == self ) { i++; continue; } if ( !isalive( player ) ) { i++; continue; } if ( level.teambased && player.team == self.team ) { i++; continue; } /* /# if ( player isinmovemode( "ufo", "noclip" ) ) { i++; continue; #/ } */ if ( bot_get_difficulty() == "easy" ) { if ( distancesquared( ent.origin, player.origin ) < 262144 ) { self pressattackbutton(); } i++; continue; } if ( distancesquared( ent.origin, player.origin ) < 40000 ) { self pressattackbutton(); } i++; } } } bot_rccar_kill() //checked matches cerberus output { self endon( "disconnect" ); self endon( "rcbomb_done" ); self endon( "weapon_object_destroyed" ); level endon( "game_ended" ); og_origin = self.origin; for ( ;; ) { wait 1; ent = bot_get_vehicle_entity(); if ( !isDefined( ent ) ) { return; } if ( distancesquared( og_origin, ent.origin ) < 256 ) { wait 2; if ( !isDefined( ent ) ) { return; } if ( distancesquared( og_origin, ent.origin ) < 256 ) { self pressattackbutton(); } } og_origin = ent.origin; } } bot_turret_location( weapon ) //checked matches cerberus output { enemy = bot_get_closest_enemy( self.origin ); if ( !isDefined( enemy ) ) { return; } forward = anglesToForward( self getplayerangles() ); forward = vectornormalize( forward ); delta = enemy.origin - self.origin; delta = vectornormalize( delta ); dot = vectordot( forward, delta ); if ( dot < 0.707 ) { return; } node = getvisiblenode( self.origin, enemy.origin ); if ( !isDefined( node ) ) { return; } if ( distancesquared( self.origin, node.origin ) < 262144 ) { return; } delta = node.origin - self.origin; delta = vectornormalize( delta ); dot = vectordot( forward, delta ); if ( dot < 0.707 ) { return; } self thread weapon_switch_failsafe(); self switchtoweapon( weapon ); self waittill( "weapon_change_complete" ); self freeze_player_controls( 1 ); wait 1; self freeze_player_controls( 0 ); bot_use_item( weapon ); self switchtoweapon( self.lastnonkillstreakweapon ); } bot_use_supply_drop( weapon ) //checked changed to match cerberus output { if ( weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp" ) { if ( ( getTime() - self.spawntime ) > 5000 ) { return; } } yaw = ( 0, self.angles[ 1 ], 0 ); dir = anglesToForward( yaw ); dir = vectornormalize( dir ); drop_point = self.origin + vectorScale( dir, 384 ); end = drop_point + vectorScale( ( 0, 0, 0 ), 2048 ); if ( !sighttracepassed( drop_point, end, 0, undefined ) ) { return; } if ( !sighttracepassed( self.origin, end, 0, undefined ) ) { return; } end = drop_point - vectorScale( ( 0, 0, 1 ), 32 ); if ( bullettracepassed( drop_point, end, 0, undefined ) ) { return; } self addgoal( self.origin, 24, 4, "killstreak" ); if ( weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp" ) { self lookat( drop_point + vectorScale( ( 0, 0, 1 ), 384 ) ); } else { self lookat( drop_point ); } wait 0.5; if ( self getcurrentweapon() != weapon ) { self thread weapon_switch_failsafe(); self switchtoweapon( weapon ); self waittill( "weapon_change_complete" ); } bot_use_item( weapon ); self switchtoweapon( self.lastnonkillstreakweapon ); self clearlookat(); self cancelgoal( "killstreak" ); } bot_use_item( weapon ) { self pressattackbutton(); wait 0.5; for ( i = 0; i < 10; i++ ) { if ( self getcurrentweapon() == weapon || self getcurrentweapon() == "none" ) { self pressattackbutton(); } else { return; } wait 0.5; } } bot_killstreak_location( num, weapon ) //checked changed to match cerberus output { enemies = bot_get_enemies(); if ( !enemies.size ) { return; } if ( !self switchtoweapon( weapon ) ) { return; } self waittill( "weapon_change" ); self freeze_player_controls( 1 ); wait_time = 1; while ( !isDefined( self.selectinglocation ) || self.selectinglocation == 0 ) { wait 0.05; wait_time -= 0.05; if ( wait_time <= 0 ) { self freeze_player_controls( 0 ); self switchtoweapon( self.lastnonkillstreakweapon ); return; } } wait 2; for ( i = 0; i < num; i++ ) { enemies = bot_get_enemies(); if ( enemies.size ) { enemy = random( enemies ); self notify( "confirm_location" ); } wait 0.25; } self freeze_player_controls( 0 ); } bot_killstreak_dangerous_think( origin, team, attacker ) //checked changed to match cerberus output { if ( !level.teambased ) { return; } nodes = getnodesinradius( origin + vectorScale( ( 0, 0, 1 ), 384 ), 384, 0 ); foreach ( node in nodes ) { if ( node isdangerous( team ) ) { return; } } foreach ( node in nodes ) { node setdangerous( team, 1 ); } attacker wait_endon( 25, "death" ); foreach ( node in nodes ) { node setdangerous( team, 0 ); } } weapon_switch_failsafe() //checked changed to match cerberus output { self endon( "death" ); self endon( "disconnect" ); self endon( "weapon_change_complete" ); wait 10; self notify( "weapon_change_complete" ); } bot_dive_to_prone( exit_stance ) //checked changed to match cerberus output { self pressdtpbutton(); event = self waittill_any_timeout( 0.25, "dtp_start" ); if ( event == "dtp_start" ) { self waittill( "dtp_end" ); self setstance( "prone" ); wait 0.35; self setstance( exit_stance ); } } gametype_void() //checked changed to match cerberus output { } bot_debug_star( origin, seconds, color ) //didn't check dev call { /* /# if ( !isDefined( seconds ) ) { seconds = 1; } if ( !isDefined( color ) ) { color = ( 0, 0, 0 ); } frames = int( 20 * seconds ); debugstar( origin, frames, color ); #/ */ } bot_debug_circle( origin, radius, seconds, color ) //didn't check dev call { /* /# if ( !isDefined( seconds ) ) { seconds = 1; } if ( !isDefined( color ) ) { color = ( 0, 0, 0 ); } frames = int( 20 * seconds ); circle( origin, radius, color, 0, 1, frames ); #/ */ } bot_debug_box( origin, mins, maxs, yaw, seconds, color ) //didn't check dev call { /* /# if ( !isDefined( yaw ) ) { yaw = 0; } if ( !isDefined( seconds ) ) { seconds = 1; } if ( !isDefined( color ) ) { color = ( 0, 0, 0 ); } frames = int( 20 * seconds ); box( origin, mins, maxs, yaw, color, 1, 0, frames ); #/ */ } bot_devgui_think()//didn't check dev call { /* /# self endon( "death" ); self endon( "disconnect" ); setdvar( "devgui_bot", "" ); setdvar( "scr_bot_follow", "0" ); for ( ;; ) { wait 1; reset = 1; switch( getDvar( "devgui_bot" ) ) { case "crosshair": if ( getDvarInt( "scr_bot_follow" ) != 0 ) { iprintln( "Bot following enabled" ); self thread bot_crosshair_follow(); } else { iprintln( "Bot following disabled" ); self notify( "crosshair_follow_off" ); setdvar( "bot_AllowMovement", "0" ); } break; case "laststand": setdvar( "scr_forcelaststand", "1" ); self setperk( "specialty_pistoldeath" ); self setperk( "specialty_finalstand" ); self dodamage( self.health, self.origin ); break; case "": default: reset = 0; break; } if ( reset ) { setdvar( "devgui_bot", "" ); } #/ } */ } bot_system_devgui_think() //didn't check dev call { /* /# setdvar( "devgui_bot", "" ); setdvar( "devgui_bot_weapon", "" ); for ( ;; ) { wait 1; reset = 1; switch( getDvar( "devgui_bot" ) ) { case "spawn_friendly": player = gethostplayer(); team = player.team; devgui_bot_spawn( team ); break; case "spawn_enemy": player = gethostplayer(); team = getenemyteamwithlowestplayercount( player.team ); devgui_bot_spawn( team ); break; case "loadout": case "player_weapon": players = get_players(); _a2692 = players; _k2692 = getFirstArrayKey( _a2692 ); while ( isDefined( _k2692 ) ) { player = _a2692[ _k2692 ]; if ( !player maps/mp/_utility::is_bot() ) { } else { host = gethostplayer(); weapon = host getcurrentweapon(); player maps/mp/gametypes/_weapons::detach_all_weapons(); player takeallweapons(); player giveweapon( weapon ); player switchtoweapon( weapon ); player setspawnweapon( weapon ); player maps/mp/teams/_teams::set_player_model( player.team, weapon ); } _k2692 = getNextArrayKey( _a2692, _k2692 ); } case "routes": devgui_debug_route(); break; case "": default: reset = 0; break; } if ( reset ) { setdvar( "devgui_bot", "" ); } #/ } } */ } bot_crosshair_follow() //didn't check dev call { /* /# self notify( "crosshair_follow_off" ); self endon( "death" ); self endon( "disconnect" ); self endon( "crosshair_follow_off" ); for ( ;; ) { wait 1; setdvar( "bot_AllowMovement", "1" ); setdvar( "bot_IgnoreHumans", "1" ); setdvar( "bot_ForceStand", "1" ); player = gethostplayerforbots(); direction = player getplayerangles(); direction_vec = anglesToForward( direction ); eye = player geteye(); scale = 8000; direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale ); trace = bullettrace( eye, eye + direction_vec, 0, undefined ); origin = trace[ "position" ] + ( 0, 0, 0 ); if ( distancesquared( self.origin, origin ) > 16384 ) { } #/ } */ } bot_debug_patrol( node1, node2 ) //didn't check dev call { /* /# self endon( "death" ); self endon( "debug_patrol" ); for ( ;; ) { self addgoal( node1, 24, 4, "debug_route" ); self waittill( "debug_route", result ); if ( result == "failed" ) { self cancelgoal( "debug_route" ); wait 5; } self addgoal( node2, 24, 4, "debug_route" ); self waittill( "debug_route", result ); if ( result == "failed" ) { self cancelgoal( "debug_route" ); wait 5; } #/ } */ } devgui_debug_route() //didn't check dev call { /* /# iprintln( "Choose nodes with 'A' or press 'B' to cancel" ); nodes = maps/mp/gametypes/_dev::dev_get_node_pair(); if ( !isDefined( nodes ) ) { iprintln( "Route Debug Cancelled" ); return; } iprintln( "Sending bots to chosen nodes" ); players = get_players(); _a2804 = players; _k2804 = getFirstArrayKey( _a2804 ); while ( isDefined( _k2804 ) ) { player = _a2804[ _k2804 ]; if ( !player maps/mp/_utility::is_bot() ) { } else { player notify( "debug_patrol" ); player thread bot_debug_patrol( nodes[ 0 ], nodes[ 1 ] ); } _k2804 = getNextArrayKey( _a2804, _k2804 ); #/ } */ } devgui_bot_spawn( team ) //didn't check dev call { /* /# player = gethostplayer(); direction = player getplayerangles(); direction_vec = anglesToForward( direction ); eye = player geteye(); scale = 8000; direction_vec = ( direction_vec[ 0 ] * scale, direction_vec[ 1 ] * scale, direction_vec[ 2 ] * scale ); trace = bullettrace( eye, eye + direction_vec, 0, undefined ); direction_vec = player.origin - trace[ "position" ]; direction = vectorToAngles( direction_vec ); bot = addtestclient(); if ( !isDefined( bot ) ) { println( "Could not add test client" ); return; } bot.pers[ "isBot" ] = 1; bot thread bot_spawn_think( team ); yaw = direction[ 1 ]; bot thread devgui_bot_spawn_think( trace[ "position" ], yaw ); #/ */ } devgui_bot_spawn_think( origin, yaw ) //didn't check dev call { /* /# self endon( "disconnect" ); for ( ;; ) { self waittill( "spawned_player" ); self setorigin( origin ); angles = ( 0, yaw, 0 ); self setplayerangles( angles ); #/ } */ }