#include maps\mp\_utility; #include maps\mp\bots\_bot_utility; /* Initiates the whole bot scripts. */ init() { level.bw_version = "2.2.0 PR 1"; if ( getcvar( "bots_main" ) == "" ) { setcvar( "bots_main", true ); } if ( !getcvarint( "bots_main" ) ) { return; } if ( !wait_for_builtins() ) { println( "FATAL: NO BUILT-INS FOR BOTS" ); } thread load_waypoints(); thread hook_callbacks(); if ( getcvar( "bots_main_GUIDs" ) == "" ) { setcvar( "bots_main_GUIDs", "" ); // guids of players who will be given host powers, comma seperated } if ( getcvar( "bots_main_firstIsHost" ) == "" ) { setcvar( "bots_main_firstIsHost", true ); // first player to connect is a host } if ( getcvar( "bots_main_waitForHostTime" ) == "" ) { setcvar( "bots_main_waitForHostTime", 10.0 ); // how long to wait to wait for the host player } if ( getcvar( "bots_main_kickBotsAtEnd" ) == "" ) { setcvar( "bots_main_kickBotsAtEnd", false ); // kicks the bots at game end } if ( getcvar( "bots_manage_add" ) == "" ) { setcvar( "bots_manage_add", 0 ); // amount of bots to add to the game } if ( getcvar( "bots_manage_fill" ) == "" ) { setcvar( "bots_manage_fill", 0 ); // amount of bots to maintain } if ( getcvar( "bots_manage_fill_spec" ) == "" ) { setcvar( "bots_manage_fill_spec", true ); // to count for fill if player is on spec team } if ( getcvar( "bots_manage_fill_mode" ) == "" ) { setcvar( "bots_manage_fill_mode", 0 ); // fill mode, 0 adds everyone, 1 just bots, 2 maintains at maps, 3 is 2 with 1 } if ( getcvar( "bots_manage_fill_kick" ) == "" ) { setcvar( "bots_manage_fill_kick", false ); // kick bots if too many } if ( getcvar( "bots_team" ) == "" ) { setcvar( "bots_team", "autoassign" ); // which team for bots to join } if ( getcvar( "bots_team_amount" ) == "" ) { setcvar( "bots_team_amount", 0 ); // amount of bots on axis team } if ( getcvar( "bots_team_force" ) == "" ) { setcvar( "bots_team_force", false ); // force bots on team } if ( getcvar( "bots_team_mode" ) == "" ) { setcvar( "bots_team_mode", 0 ); // counts just bots when 1 } if ( getcvar( "bots_skill" ) == "" ) { setcvar( "bots_skill", 0 ); // 0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random } if ( getcvar( "bots_skill_axis_hard" ) == "" ) { setcvar( "bots_skill_axis_hard", 0 ); // amount of hard bots on axis team } if ( getcvar( "bots_skill_axis_med" ) == "" ) { setcvar( "bots_skill_axis_med", 0 ); } if ( getcvar( "bots_skill_allies_hard" ) == "" ) { setcvar( "bots_skill_allies_hard", 0 ); } if ( getcvar( "bots_skill_allies_med" ) == "" ) { setcvar( "bots_skill_allies_med", 0 ); } if ( getcvar( "bots_skill_min" ) == "" ) { setcvar( "bots_skill_min", 1 ); } if ( getcvar( "bots_skill_max" ) == "" ) { setcvar( "bots_skill_max", 7 ); } if ( getcvar( "bots_loadout_rank" ) == "" ) // what rank the bots should be around, -1 is around the players, 0 is all random { setcvar( "bots_loadout_rank", -1 ); } if ( getcvar( "bots_play_move" ) == "" ) // bots move { setcvar( "bots_play_move", true ); } if ( getcvar( "bots_play_knife" ) == "" ) // bots knife { setcvar( "bots_play_knife", true ); } if ( getcvar( "bots_play_fire" ) == "" ) // bots fire { setcvar( "bots_play_fire", true ); } if ( getcvar( "bots_play_nade" ) == "" ) // bots grenade { setcvar( "bots_play_nade", true ); } if ( getcvar( "bots_play_obj" ) == "" ) // bots play the obj { setcvar( "bots_play_obj", true ); } if ( getcvar( "bots_play_camp" ) == "" ) // bots camp and follow { setcvar( "bots_play_camp", true ); } if ( getcvar( "bots_play_jumpdrop" ) == "" ) // bots jump and dropshot { setcvar( "bots_play_jumpdrop", true ); } if ( getcvar( "bots_play_ads" ) == "" ) // bot ads { setcvar( "bots_play_ads", true ); } if ( getcvar( "bots_play_aim" ) == "" ) { setcvar( "bots_play_aim", true ); } if ( !isdefined( game[ "botWarfare" ] ) ) { game[ "botWarfare" ] = true; game[ "botWarfareInitTime" ] = gettime(); } level.bot_inittime = gettime(); level.defuseobject = undefined; level.bots_smokelist = List(); level.bots_mingrenadedistance = 256; level.bots_mingrenadedistance *= level.bots_mingrenadedistance; level.bots_maxgrenadedistance = 1024; level.bots_maxgrenadedistance *= level.bots_maxgrenadedistance; level.bots_maxknifedistance = 80; level.bots_maxknifedistance *= level.bots_maxknifedistance; level.bots_goaldistance = 27.5; level.bots_goaldistance *= level.bots_goaldistance; level.bots_noadsdistance = 200; level.bots_noadsdistance *= level.bots_noadsdistance; level.bots_maxshotgundistance = 500; level.bots_maxshotgundistance *= level.bots_maxshotgundistance; level.bots_listendist = 100; level.smokeradius = 255; level.bots = []; level.players = []; level.bots_fullautoguns = []; level.bots_fullautoguns[ "greasegun" ] = true; level.bots_fullautoguns[ "thompson" ] = true; level.bots_fullautoguns[ "bar" ] = true; level.bots_fullautoguns[ "pps42" ] = true; level.bots_fullautoguns[ "sten" ] = true; level.bots_fullautoguns[ "bren" ] = true; level.bots_fullautoguns[ "mp44" ] = true; level.bots_fullautoguns[ "ppsh" ] = true; level.bots_fullautoguns[ "mp40" ] = true; level.bots_weapon_clip_sizes = []; level.bots_weapon_clip_sizes[ "m1carbine_mp" ] = 15; level.bots_weapon_clip_sizes[ "m1garand_mp" ] = 8; level.bots_weapon_clip_sizes[ "bar_mp" ] = 20; level.bots_weapon_clip_sizes[ "shotgun_mp" ] = 6; level.bots_weapon_clip_sizes[ "thompson_mp" ] = 20; level.bots_weapon_clip_sizes[ "springfield_mp" ] = 5; level.bots_weapon_clip_sizes[ "sten_mp" ] = 32; level.bots_weapon_clip_sizes[ "enfield_mp" ] = 10; level.bots_weapon_clip_sizes[ "bren_mp" ] = 30; level.bots_weapon_clip_sizes[ "enfield_scope_mp" ] = 10; level.bots_weapon_clip_sizes[ "svt40_mp" ] = 10; level.bots_weapon_clip_sizes[ "pps42_mp" ] = 35; level.bots_weapon_clip_sizes[ "ppsh_mp" ] = 71; level.bots_weapon_clip_sizes[ "g43_mp" ] = 10; level.bots_weapon_clip_sizes[ "mosin_nagant_mp" ] = 5; level.bots_weapon_clip_sizes[ "mosin_nagant_sniper_mp" ] = 5; level.bots_weapon_clip_sizes[ "mp40_mp" ] = 32; level.bots_weapon_clip_sizes[ "kar98k_mp" ] = 5; level.bots_weapon_clip_sizes[ "kar98k_sniper_mp" ] = 5; level.bots_weapon_clip_sizes[ "mp44_mp" ] = 30; level.bots_weapon_clip_sizes[ "colt_mp" ] = 7; level.bots_weapon_clip_sizes[ "webley_mp" ] = 6; level.bots_weapon_clip_sizes[ "luger_mp" ] = 8; level.bots_weapon_clip_sizes[ "tt30_mp" ] = 8; level.bots_weapon_clip_sizes[ "greasegun_mp" ] = 32; level.bots_weapon_class_names = []; level.bots_weapon_class_names[ "m1carbine_mp" ] = "rifle"; level.bots_weapon_class_names[ "m1garand_mp" ] = "rifle"; level.bots_weapon_class_names[ "bar_mp" ] = "lmg"; level.bots_weapon_class_names[ "shotgun_mp" ] = "spread"; level.bots_weapon_class_names[ "thompson_mp" ] = "smg"; level.bots_weapon_class_names[ "springfield_mp" ] = "sniper"; level.bots_weapon_class_names[ "sten_mp" ] = "smg"; level.bots_weapon_class_names[ "enfield_mp" ] = "sniper"; level.bots_weapon_class_names[ "bren_mp" ] = "lmg"; level.bots_weapon_class_names[ "enfield_scope_mp" ] = "sniper"; level.bots_weapon_class_names[ "svt40_mp" ] = "rifle"; level.bots_weapon_class_names[ "pps42_mp" ] = "smg"; level.bots_weapon_class_names[ "ppsh_mp" ] = "smg"; level.bots_weapon_class_names[ "g43_mp" ] = "rifle"; level.bots_weapon_class_names[ "mosin_nagant_mp" ] = "sniper"; level.bots_weapon_class_names[ "mosin_nagant_sniper_mp" ] = "sniper"; level.bots_weapon_class_names[ "mp40_mp" ] = "smg"; level.bots_weapon_class_names[ "kar98k_mp" ] = "sniper"; level.bots_weapon_class_names[ "kar98k_sniper_mp" ] = "sniper"; level.bots_weapon_class_names[ "mp44_mp" ] = "rifle"; level.bots_weapon_class_names[ "colt_mp" ] = "pistol"; level.bots_weapon_class_names[ "webley_mp" ] = "pistol"; level.bots_weapon_class_names[ "luger_mp" ] = "pistol"; level.bots_weapon_class_names[ "tt30_mp" ] = "pistol"; level.bots_weapon_class_names[ "greasegun_mp" ] = "smg"; level thread fixGamemodes(); level thread onPlayerConnect(); level thread handleBots(); level thread watchNades(); level thread watchGameEnded(); level.teambased = true; if ( getcvar( "g_gametype" ) == "dm" ) { level.teambased = false; } } /* Starts the threads for bots. */ handleBots() { level thread teamBots(); level thread diffBots(); level addBots(); while ( !level.mapended ) { wait 0.05; } setcvar( "bots_manage_add", getBotArray().size ); if ( !getcvarint( "bots_main_kickBotsAtEnd" ) ) { return; } bots = getBotArray(); for ( i = 0; i < bots.size; i++ ) { kick( bots[ i ] getentitynumber() ); } } /* The hook callback for when any player becomes damaged. */ onPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { if ( self is_bot() ) { self maps\mp\bots\_bot_internal::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); self maps\mp\bots\_bot_script::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); } self [[ level.prevcallbackplayerdamage ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); } /* The hook callback when any player gets killed. */ onPlayerKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) { if ( self is_bot() ) { self maps\mp\bots\_bot_internal::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); self maps\mp\bots\_bot_script::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); } self [[ level.prevcallbackplayerkilled ]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); } /* Starts the callbacks. */ hook_callbacks() { wait 0.05; level.prevcallbackplayerdamage = level.callbackplayerdamage; level.callbackplayerdamage = ::onPlayerDamage; level.prevcallbackplayerkilled = level.callbackplayerkilled; level.callbackplayerkilled = ::onPlayerKilled; } /* Fixes gamemodes when level starts. */ fixGamemodes() { for ( i = 0; i < 19; i++ ) { wait 0.05; } } /* Thread when any player connects. Starts the threads needed. */ onPlayerConnect() { for ( ;; ) { level waittill( "connected", player ); player thread onWeaponFired(); player thread connected(); player thread onDeath(); player thread watchWeapons(); player thread watchVelocity(); player thread watchVars(); player thread doPlayerModelFix(); } } /* Fixes a weird iw3 bug when for a frame the player doesn't have any bones when they first spawn in. */ doPlayerModelFix() { self endon( "disconnect" ); self waittill( "spawned_player" ); wait 0.05; self.bot_model_fix = true; } /* CoD2 */ watchWeapons() { self endon( "disconnect" ); for ( ;; ) { weap = self getcurrentweapon(); self thread watchAmmoUsage( weap ); while ( weap == self getcurrentweapon() ) { wait 0.05; } self notify( "weapon_change", self getcurrentweapon() ); } } /* CoD2 */ watchAmmoUsage( weap ) { self endon( "disconnect" ); self endon( "weapon_change" ); slot = self getWeaponSlot( weap ); for ( ;; ) { aCount = self getweaponslotclipammo( slot ); while ( aCount == self getweaponslotclipammo( slot ) ) { wait 0.05; } if ( self getweaponslotclipammo( slot ) < aCount ) { self notify( "weapon_fired" ); } else { self notify( "reload" ); } } } /* CoD2 */ watchVars() { self endon( "disconnect" ); for ( ;; ) { self.team = self.pers[ "team" ]; wait 0.05; } } /* CoD2 */ watchVelocity() { self endon( "disconnect" ); lastOrigin = self.origin; for ( ;; ) { wait 0.05; self.velocity = vector_scale( self.origin - lastOrigin, 20 ); lastOrigin = self.origin; } } /* Kills the tags for a player */ killTags() { if ( isdefined( self.tags ) ) { for ( i = 0; i < self.tags.size; i++ ) { self.tags[ i ] delete (); } self.tags = undefined; self.tagmap = undefined; } } /* death */ onDeath() { self endon( "disconnect" ); for ( ;; ) { self waittill( "death" ); self killTags(); } } /* When a bot disconnects. */ onDisconnectPlayer() { name = self.name; self waittill( "disconnect" ); self killTags(); level.players = array_remove( level.players, self ); waittillframeend; for ( i = 0; i < level.bots.size; i++ ) { bot = level.bots[ i ]; bot BotNotifyBotEvent( "connection", "disconnected", self, name ); } } /* When a bot disconnects. */ onDisconnect() { self waittill( "disconnect" ); level.bots = array_remove( level.bots, self ); } /* Called when a player connects. */ connected() { self endon( "disconnect" ); level.players[ level.players.size ] = self; for ( i = 0; i < level.bots.size; i++ ) { bot = level.bots[ i ]; bot BotNotifyBotEvent( "connection", "connected", self, self.name ); } self thread onDisconnectPlayer(); if ( !isdefined( self.pers[ "bot_host" ] ) ) { self thread doHostCheck(); } if ( !self is_bot() ) { return; } if ( !isdefined( self.pers[ "isBot" ] ) ) { // fast restart... self.pers[ "isBot" ] = true; } if ( !isdefined( self.pers[ "isBotWarfare" ] ) ) { self.pers[ "isBotWarfare" ] = true; self thread added(); } self thread maps\mp\bots\_bot_internal::connected(); self thread maps\mp\bots\_bot_script::connected(); level.bots[ level.bots.size ] = self; self thread onDisconnect(); level notify( "bot_connected", self ); self thread watchBotDebugEvent(); } /* DEBUG */ watchBotDebugEvent() { self endon( "disconnect" ); for ( ;; ) { self waittill( "bot_event", msg, str, b, c, d, e, f, g ); if ( getcvarint( "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" && getcvarint( "bots_main_debug" ) ) { BotBuiltinPrintConsole( "Bot Warfare debug: " + self.name + ": " + str ); } } } /* When a bot gets added into the game. */ added() { self endon( "disconnect" ); self thread maps\mp\bots\_bot_internal::added(); self thread maps\mp\bots\_bot_script::added(); } /* Adds a bot to the game. */ add_bot() { bot = addtestclient(); if ( isdefined( bot ) ) { bot.pers[ "isBot" ] = true; bot.pers[ "isBotWarfare" ] = true; bot thread added(); } } /* A server thread for monitoring all bot's difficulty levels for custom server settings. */ diffBots_loop() { var_allies_hard = getcvarint( "bots_skill_allies_hard" ); var_allies_med = getcvarint( "bots_skill_allies_med" ); var_axis_hard = getcvarint( "bots_skill_axis_hard" ); var_axis_med = getcvarint( "bots_skill_axis_med" ); var_skill = getcvarint( "bots_skill" ); allies_hard = 0; allies_med = 0; axis_hard = 0; axis_med = 0; if ( var_skill == 8 ) { playercount = level.players.size; for ( i = 0; i < playercount; i++ ) { player = level.players[ i ]; if ( !isdefined( player.pers[ "team" ] ) ) { continue; } if ( !player is_bot() ) { continue; } if ( player.pers[ "team" ] == "axis" ) { if ( axis_hard < var_axis_hard ) { axis_hard++; player.pers[ "bots" ] [ "skill" ][ "base" ] = 7; } else if ( axis_med < var_axis_med ) { axis_med++; player.pers[ "bots" ][ "skill" ][ "base" ] = 4; } else { player.pers[ "bots" ][ "skill" ][ "base" ] = 1; } } else if ( player.pers[ "team" ] == "allies" ) { if ( allies_hard < var_allies_hard ) { allies_hard++; player.pers[ "bots" ][ "skill" ][ "base" ] = 7; } else if ( allies_med < var_allies_med ) { allies_med++; player.pers[ "bots" ][ "skill" ][ "base" ] = 4; } else { player.pers[ "bots" ][ "skill" ][ "base" ] = 1; } } } } else if ( var_skill != 0 && var_skill != 9 ) { playercount = level.players.size; for ( i = 0; i < playercount; i++ ) { player = level.players[ i ]; if ( !player is_bot() ) { continue; } player.pers[ "bots" ][ "skill" ][ "base" ] = var_skill; } } playercount = level.players.size; min_diff = getcvarint( "bots_skill_min" ); max_diff = getcvarint( "bots_skill_max" ); for ( i = 0; i < playercount; i++ ) { player = level.players[ i ]; if ( !player is_bot() ) { continue; } player.pers[ "bots" ][ "skill" ][ "base" ] = int( clamp( player.pers[ "bots" ][ "skill" ][ "base" ], min_diff, max_diff ) ); } } /* A server thread for monitoring all bot's difficulty levels for custom server settings. */ diffBots() { for ( ;; ) { wait 1.5; diffBots_loop(); } } /* A server thread for monitoring all bot's teams for custom server settings. */ teamBots_loop() { teamAmount = getcvarint( "bots_team_amount" ); toTeam = getcvar( "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.pers[ "team" ] ) ) { continue; } 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 ( !getcvarint( "bots_team_mode" ) ) { allies += alliesplayers; axis += axisplayers; } if ( toTeam != "custom" ) { if ( getcvarint( "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.pers[ "team" ] ) ) { continue; } if ( !player is_bot() ) { continue; } if ( player.pers[ "team" ] == toTeam ) { continue; } if ( toTeam == "allies" ) { player thread [[ level.allies ]](); } else if ( toTeam == "axis" ) { player thread [[ level.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.pers[ "team" ] ) ) { continue; } if ( !player is_bot() ) { continue; } if ( player.pers[ "team" ] == "axis" ) { if ( axis > teamAmount ) { player thread [[ level.allies ]](); break; } } else { if ( axis < teamAmount ) { player thread [[ level.axis ]](); break; } else if ( player.pers[ "team" ] != "allies" ) { player thread [[ level.allies ]](); break; } } } } } /* A server thread for monitoring all bot's teams for custom server settings. */ teamBots() { for ( ;; ) { wait 1.5; teamBots_loop(); } } /* A server thread for monitoring all bot's in game. Will add and kick bots according to server settings. */ addBots_loop() { botsToAdd = getcvarint( "bots_manage_add" ); if ( botsToAdd > 0 ) { setcvar( "bots_manage_add", 0 ); if ( botsToAdd > 64 ) { botsToAdd = 64; } for ( ; botsToAdd > 0; botsToAdd-- ) { level add_bot(); wait 0.25; } } fillMode = getcvarint( "bots_manage_fill_mode" ); if ( fillMode == 2 || fillMode == 3 ) { setcvar( "bots_manage_fill", getGoodMapAmount() ); } fillAmount = getcvarint( "bots_manage_fill" ); players = 0; bots = 0; spec = 0; playercount = level.players.size; for ( i = 0; i < playercount; i++ ) { player = level.players[ i ]; if ( player is_bot() ) { bots++; } else if ( !isdefined( player.pers[ "team" ] ) || ( player.pers[ "team" ] != "axis" && player.pers[ "team" ] != "allies" ) ) { spec++; } else { players++; } } if ( !randomint( 999 ) ) { setcvar( "testclients_doreload", true ); wait 0.1; setcvar( "testclients_doreload", false ); doExtraCheck(); } if ( fillMode == 4 ) { axisplayers = 0; alliesplayers = 0; playercount = level.players.size; for ( i = 0; i < playercount; i++ ) { player = level.players[ i ]; if ( player is_bot() ) { continue; } if ( !isdefined( player.pers[ "team" ] ) ) { continue; } 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; } amount = bots; if ( fillMode == 0 || fillMode == 2 ) { amount += players; } if ( getcvarint( "bots_manage_fill_spec" ) ) { amount += spec; } if ( amount < fillAmount ) { setcvar( "bots_manage_add", 1 ); } else if ( amount > fillAmount && getcvarint( "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(); } } /* A thread for ALL players when they fire. */ onWeaponFired() { self endon( "disconnect" ); self.bots_firing = false; for ( ;; ) { self waittill( "weapon_fired" ); self thread doFiringThread(); } } /* Lets bot's know that the player is firing. */ doFiringThread() { self endon( "disconnect" ); self endon( "weapon_fired" ); self.bots_firing = true; wait 1; self.bots_firing = false; } /* Launches the smoke */ launchSmoke( org ) { nade = spawnstruct(); nade.origin = org; level.bots_smokelist ListAdd( nade ); wait 11.5; level.bots_smokelist ListRemove( nade ); } /* Deletes smoke grenades when they explode */ watchNade() { self endon( "death" ); lastOrigin = self.origin; creationTime = gettime(); timeSlow = 0; wait 0.05; while ( isdefined( self ) ) { velocity = vector_scale( self.origin - lastOrigin, 20 ); lastOrigin = self.origin; if ( gettime() - creationTime > 4000 ) { if ( lengthsquared( velocity ) <= 0.05 ) { timeSlow += 0.05; } else { timeSlow = 0; } } if ( timeSlow > 1 ) { thread launchSmoke( lastOrigin ); self delete (); } wait 0.05; } } /* Watches nades */ watchNades_loop() { nades = getentarray( "grenade", "classname" ); for ( i = 0; i < nades.size; i++ ) { nade = nades[ i ]; if ( !isdefined( nade ) ) { continue; } if ( isdefined( nade.bot_audit ) ) { continue; } nade.bot_audit = true; nade thread watchNade(); } } /* Watches nades */ watchNades() { for ( ;; ) { wait 0.05; watchNades_loop(); } } /* Watches the game to end */ watchGameEnded() { level.gameended = false; for ( ;; ) { wait 0.05; if ( isdefined( level.roundended ) ) { if ( level.roundended ) { break; } } else if ( isdefined( level.mapended ) ) { if ( level.mapended ) { break; } } } level.gameended = true; level notify( "game_ended" ); }