diff --git a/maps/mp/bots/_bot.gsc b/maps/mp/bots/_bot.gsc index 47a6786..0b0c560 100644 --- a/maps/mp/bots/_bot.gsc +++ b/maps/mp/bots/_bot.gsc @@ -15,7 +15,7 @@ */ init() { - level.bw_VERSION = "2.1.0"; + level.bw_version = "2.1.0"; if ( getDvar( "bots_main" ) == "" ) { @@ -220,27 +220,27 @@ init() game[ "botWarfare" ] = true; } - level.defuseObject = undefined; - level.bots_smokeList = List(); - level.bots_fragList = List(); + level.defuseobject = undefined; + level.bots_smokelist = List(); + level.bots_fraglist = List(); - level.bots_minSprintDistance = 315; - level.bots_minSprintDistance *= level.bots_minSprintDistance; - level.bots_minGrenadeDistance = 256; - level.bots_minGrenadeDistance *= level.bots_minGrenadeDistance; - level.bots_maxGrenadeDistance = 1024; - level.bots_maxGrenadeDistance *= level.bots_maxGrenadeDistance; - level.bots_maxKnifeDistance = 128; - 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.bots_minsprintdistance = 315; + level.bots_minsprintdistance *= level.bots_minsprintdistance; + level.bots_mingrenadedistance = 256; + level.bots_mingrenadedistance *= level.bots_mingrenadedistance; + level.bots_maxgrenadedistance = 1024; + level.bots_maxgrenadedistance *= level.bots_maxgrenadedistance; + level.bots_maxknifedistance = 128; + 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.smokeradius = 255; level.bots = []; @@ -327,7 +327,7 @@ onPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, 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 ); + self [[ level.prevcallbackplayerdamage ]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); } /* @@ -341,7 +341,7 @@ onPlayerKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sH 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 ); + self [[ level.prevcallbackplayerkilled ]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); } /* @@ -351,11 +351,11 @@ hook_callbacks() { level waittill( "prematch_over" ); // iw4madmin waits this long for some reason... wait 0.05; // so we need to be one frame after it sets up its callbacks. - level.prevCallbackPlayerDamage = level.callbackPlayerDamage; - level.callbackPlayerDamage = ::onPlayerDamage; + level.prevcallbackplayerdamage = level.callbackplayerdamage; + level.callbackplayerdamage = ::onPlayerDamage; - level.prevCallbackPlayerKilled = level.callbackPlayerKilled; - level.callbackPlayerKilled = ::onPlayerKilled; + level.prevcallbackplayerkilled = level.callbackplayerkilled; + level.callbackplayerkilled = ::onPlayerKilled; } /* @@ -365,11 +365,11 @@ fixGamemodes() { for ( i = 0; i < 19; i++ ) { - if ( isDefined( level.bombZones ) && level.gametype == "sd" ) + if ( isDefined( level.bombzones ) && level.gametype == "sd" ) { - for ( i = 0; i < level.bombZones.size; i++ ) + for ( i = 0; i < level.bombzones.size; i++ ) { - level.bombZones[ i ].onUse = ::onUsePlantObjectFix; + level.bombzones[ i ].onuse = ::onUsePlantObjectFix; } break; @@ -382,7 +382,7 @@ fixGamemodes() break; } - if ( isDefined( level.bombZones ) && level.gametype == "dd" ) + if ( isDefined( level.bombzones ) && level.gametype == "dd" ) { level thread fixDem(); @@ -400,18 +400,18 @@ fixDem() { for ( ;; ) { - level.bombAPlanted = level.aPlanted; - level.bombBPlanted = level.bPlanted; + level.bombaplanted = level.aplanted; + level.bombbplanted = level.bplanted; - for ( i = 0; i < level.bombZones.size; i++ ) + for ( i = 0; i < level.bombzones.size; i++ ) { - if ( isDefined( level.bombZones[ i ].trigger.trigger_off ) ) + if ( isDefined( level.bombzones[ i ].trigger.trigger_off ) ) { - level.bombZones[ i ].bombExploded = true; + level.bombzones[ i ].bombexploded = true; } else { - level.bombZones[ i ].bombExploded = undefined; + level.bombzones[ i ].bombexploded = undefined; } } @@ -430,14 +430,14 @@ fixKoth() { wait 0.05; - if ( !isDefined( level.radioObject ) ) + if ( !isDefined( level.radioobject ) ) { continue; } for ( i = level.radios.size - 1; i >= 0; i-- ) { - if ( level.radioObject != level.radios[ i ].gameobject ) + if ( level.radioobject != level.radios[ i ].gameobject ) { continue; } @@ -446,7 +446,7 @@ fixKoth() break; } - while ( isDefined( level.radioObject ) && level.radio.gameobject == level.radioObject ) + while ( isDefined( level.radioobject ) && level.radio.gameobject == level.radioobject ) { wait 0.05; } @@ -507,12 +507,12 @@ watchRadar_loop() for ( i = level.players.size - 1; i >= 0; i-- ) { player = level.players[ i ]; - player.bot_isInRadar = false; + player.bot_isinradar = false; } for ( i = level.players.size - 1; i >= 0; i-- ) { - grenade = level.players[ i ].deployedPortableRadar; + grenade = level.players[ i ].deployedportableradar; if ( !isDefined( grenade ) ) { @@ -538,7 +538,7 @@ watchRadar_loop() continue; } - if ( level.teamBased && grenade.team == player.team ) + if ( level.teambased && grenade.team == player.team ) { continue; } @@ -553,13 +553,13 @@ watchRadar_loop() continue; } - player.bot_isInRadar = true; + player.bot_isinradar = true; } } for ( i = level.players.size - 1; i >= 0; i-- ) { - if ( !isDefined( level.players[ i ].personalRadar ) ) + if ( !isDefined( level.players[ i ].personalradar ) ) { continue; } @@ -583,7 +583,7 @@ watchRadar_loop() continue; } - if ( level.teamBased && level.players[ i ].team == player.team ) + if ( level.teambased && level.players[ i ].team == player.team ) { continue; } @@ -598,11 +598,11 @@ watchRadar_loop() continue; } - player.bot_isInRadar = true; + player.bot_isinradar = true; } } - if ( isDefined( level.gameFlag ) && isDefined( level.gameFlag.carrier ) && isDefined( level.gameFlag.portable_radar ) ) + if ( isDefined( level.gameflag ) && isDefined( level.gameflag.carrier ) && isDefined( level.gameflag.portable_radar ) ) { for ( h = level.players.size - 1; h >= 0; h-- ) { @@ -613,7 +613,7 @@ watchRadar_loop() continue; } - if ( level.teamBased && level.gameFlag.carrier.team != player.team ) + if ( level.teambased && level.gameflag.carrier.team != player.team ) { continue; } @@ -623,12 +623,12 @@ watchRadar_loop() continue; } - if ( DistanceSquared( player.origin, level.gameFlag.carrier.origin ) > 256 * 256 ) + if ( DistanceSquared( player.origin, level.gameflag.carrier.origin ) > 256 * 256 ) { continue; } - player.bot_isInRadar = true; + player.bot_isinradar = true; } } } @@ -654,7 +654,7 @@ watchScrabler_loop() for ( i = level.players.size - 1; i >= 0; i-- ) { player = level.players[ i ]; - player.bot_isScrambled = false; + player.bot_isscrambled = false; } for ( i = level.scramblers.size - 1; i >= 0; i-- ) @@ -680,7 +680,7 @@ watchScrabler_loop() continue; } - if ( level.teamBased && scrambler.team == player.team ) + if ( level.teambased && scrambler.team == player.team ) { continue; } @@ -695,7 +695,7 @@ watchScrabler_loop() continue; } - player.bot_isScrambled = true; + player.bot_isscrambled = true; } } @@ -729,7 +729,7 @@ watchScrabler_loop() continue; } - if ( level.teamBased && drone.team == player.team ) + if ( level.teambased && drone.team == player.team ) { continue; } @@ -744,7 +744,7 @@ watchScrabler_loop() continue; } - player.bot_isScrambled = true; + player.bot_isscrambled = true; } } } @@ -773,12 +773,12 @@ addNotifyOnAirdrops_loop() { airdrop = dropCrates[ i ]; - if ( isDefined( airdrop.doingPhysics ) ) + if ( isDefined( airdrop.doingphysics ) ) { continue; } - airdrop.doingPhysics = true; + airdrop.doingphysics = true; airdrop thread doNotifyOnAirdrop(); } } @@ -803,7 +803,7 @@ doNotifyOnAirdrop() self endon( "death" ); self waittill( "physics_finished" ); - self.doingPhysics = false; + self.doingphysics = false; if ( isDefined( self.owner ) ) { @@ -837,8 +837,8 @@ onPlayerConnect() { level waittill( "connected", player ); - player.bot_isScrambled = false; - player.bot_isInRadar = false; + player.bot_isscrambled = false; + player.bot_isinradar = false; player thread onGrenadeFire(); player thread onWeaponFired(); @@ -1473,7 +1473,7 @@ AddToFragList( who ) grenade thread thinkFrag(); - level.bots_fragList ListAdd( grenade ); + level.bots_fraglist ListAdd( grenade ); } /* @@ -1490,7 +1490,7 @@ thinkFrag() wait 0.05; } - level.bots_fragList ListRemove( self ); + level.bots_fraglist ListRemove( self ); } /* @@ -1505,7 +1505,7 @@ AddToSmokeList() grenade thread thinkSmoke(); - level.bots_smokeList ListAdd( grenade ); + level.bots_smokelist ListAdd( grenade ); } /* @@ -1523,7 +1523,7 @@ thinkSmoke() self.state = "smoking"; wait 11.5; - level.bots_smokeList ListRemove( self ); + level.bots_smokelist ListRemove( self ); } /* diff --git a/maps/mp/bots/_bot_chat.gsc b/maps/mp/bots/_bot_chat.gsc index e4124c3..281489a 100644 --- a/maps/mp/bots/_bot_chat.gsc +++ b/maps/mp/bots/_bot_chat.gsc @@ -87,14 +87,14 @@ start_onnuke_call() for ( ;; ) { - while ( !isDefined( level.nukeIncoming ) && !isDefined( level.moabIncoming ) ) + while ( !isDefined( level.nukeincoming ) && !isDefined( level.moabincoming ) ) { wait 0.05 + randomInt( 4 ); } self thread bot_onnukecall_watch(); - wait level.nukeTimer + 5; + wait level.nuketimer + 5; } } @@ -109,9 +109,9 @@ start_death_watch() { self waittill( "death" ); - self thread bot_chat_death_watch( self.lastAttacker, self.bots_lastKS ); + self thread bot_chat_death_watch( self.lastattacker, self.bots_lastks ); - self.bots_lastKS = 0; + self.bots_lastks = 0; } } @@ -155,23 +155,23 @@ start_killed_watch() { self endon( "disconnect" ); - self.bots_lastKS = 0; + self.bots_lastks = 0; for ( ;; ) { self waittill( "killed_enemy" ); - if ( self.bots_lastKS < self.pers[ "cur_kill_streak" ] ) + if ( self.bots_lastks < self.pers[ "cur_kill_streak" ] ) { - for ( i = self.bots_lastKS + 1; i <= self.pers[ "cur_kill_streak" ]; i++ ) + for ( i = self.bots_lastks + 1; i <= self.pers[ "cur_kill_streak" ]; i++ ) { self thread bot_chat_streak( i ); } } - self.bots_lastKS = self.pers[ "cur_kill_streak" ]; + self.bots_lastks = self.pers[ "cur_kill_streak" ]; - self thread bot_chat_killed_watch( self.lastKilledPlayer ); + self thread bot_chat_killed_watch( self.lastkilledplayer ); } } @@ -574,7 +574,7 @@ endgame_chat() } } - if ( level.teamBased ) + if ( level.teambased ) { winningteam = maps\mp\gametypes\_gamescore::getWinningTeam(); @@ -1006,7 +1006,7 @@ bot_onnukecall_watch() switch ( randomint( 4 ) ) { case 0: - if ( level.nukeInfo.player != self ) + if ( level.nukeinfo.player != self ) { self BotDoChat( 30, "Wow who got a nuke?" ); } @@ -1018,9 +1018,9 @@ bot_onnukecall_watch() break; case 1: - if ( level.nukeInfo.player != self ) + if ( level.nukeinfo.player != self ) { - self BotDoChat( 30, "lol " + level.nukeInfo.player.name + " is a hacker" ); + self BotDoChat( 30, "lol " + level.nukeinfo.player.name + " is a hacker" ); } else { @@ -1034,7 +1034,7 @@ bot_onnukecall_watch() break; case 3: - if ( level.nukeInfo.team != self.team ) + if ( level.nukeinfo.team != self.team ) { self BotDoChat( 30, "man my team sucks ):" ); } @@ -1261,9 +1261,9 @@ bot_chat_killed_watch( victim ) break; case 40: - if ( isDefined( victim.attackerData ) && isDefined( victim.attackerData[ self.guid ] ) && isDefined( victim.attackerData[ self.guid ].weapon ) ) + if ( isDefined( victim.attackerdata ) && isDefined( victim.attackerdata[ self.guid ] ) && isDefined( victim.attackerdata[ self.guid ].weapon ) ) { - message = ( "Man, I sure love my " + getBaseWeaponName( victim.attackerData[ self.guid ].weapon ) + "!" ); + message = ( "Man, I sure love my " + getBaseWeaponName( victim.attackerdata[ self.guid ].weapon ) + "!" ); } break; @@ -1542,9 +1542,9 @@ bot_chat_death_watch( killer, last_ks ) break; case 60: - if ( isDefined( self.attackerData ) && isDefined( self.attackerData[ killer.guid ] ) && isDefined( self.attackerData[ killer.guid ].weapon ) ) + if ( isDefined( self.attackerdata ) && isDefined( self.attackerdata[ killer.guid ] ) && isDefined( self.attackerdata[ killer.guid ].weapon ) ) { - message = "Wow! Nice " + getBaseWeaponName( self.attackerData[ killer.guid ].weapon ) + " you got there, " + killer.name + "!"; + message = "Wow! Nice " + getBaseWeaponName( self.attackerdata[ killer.guid ].weapon ) + " you got there, " + killer.name + "!"; } break; @@ -1977,9 +1977,9 @@ bot_chat_crate_cap_watch( state, aircare, player, d, e, f, g ) break; case 5: - if ( isDefined( aircare.crateType ) ) + if ( isDefined( aircare.cratetype ) ) { - self BotDoChat( 10, ":3 i got my " + aircare.crateType ); + self BotDoChat( 10, ":3 i got my " + aircare.cratetype ); } break; @@ -2006,9 +2006,9 @@ bot_chat_crate_cap_watch( state, aircare, player, d, e, f, g ) break; case 4: - if ( isDefined( aircare.crateType ) ) + if ( isDefined( aircare.cratetype ) ) { - self BotDoChat( 10, "hahaah jajaja i took your " + aircare.crateType ); + self BotDoChat( 10, "hahaah jajaja i took your " + aircare.cratetype ); } break; @@ -2037,9 +2037,9 @@ bot_chat_crate_cap_watch( state, aircare, player, d, e, f, g ) break; case 4: - if ( isDefined( aircare.crateType ) ) + if ( isDefined( aircare.cratetype ) ) { - self BotDoChat( 10, "Wow! there goes my " + aircare.crateType + "!" ); + self BotDoChat( 10, "Wow! there goes my " + aircare.cratetype + "!" ); } break; diff --git a/maps/mp/bots/_bot_internal.gsc b/maps/mp/bots/_bot_internal.gsc index 5763363..646f817 100644 --- a/maps/mp/bots/_bot_internal.gsc +++ b/maps/mp/bots/_bot_internal.gsc @@ -1,3356 +1,3356 @@ -/* - _bot_internal - Author: INeedGames - Date: 05/11/2021 - The interal workings of the bots. - Bots will do the basics, aim, move. -*/ - -#include common_scripts\utility; -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; -#include maps\mp\bots\_bot_utility; - -/* - When a bot is added (once ever) to the game (before connected). - We init all the persistent variables here. -*/ -added() -{ - self endon( "disconnect" ); - - self.pers[ "bots" ] = []; - - self.pers[ "bots" ][ "skill" ] = []; - self.pers[ "bots" ][ "skill" ][ "base" ] = 7; // a base knownledge of the bot - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.05; // how long it takes for a bot to aim to a location - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 0; // the reaction time of the bot for inital targets - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 0; // reaction time for the bots of reoccuring targets - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; // how long a bot ads's when they cant see the target - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 10000; // how long a bot will look at a target's last position - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 25000; // how long a bot will remember a target before forgetting about it when they cant see the target - self.pers[ "bots" ][ "skill" ][ "fov" ] = -1; // the fov of the bot, -1 being 360, 1 being 0 - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 100000 * 2; // the longest distance a bot will target - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 100000; // the start distance before bot's target abilitys diminish - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0; // how long a bot waits after spawning before targeting, etc - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 10000; // how far a bot has awareness - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.05; // how fast a bot shoots semiauto - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 1; // how long a bot shoots after target dies/cant be seen - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1; // how long a bot correct's their aim after targeting - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1; // how far a bot's incorrect aim is - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.05; // how often a bot changes their bone target - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head"; // a list of comma seperated bones the bot will aim at - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; // a factor of how much ads to reduce when adsing - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; // a factor of how much more aimspeed delay to add - - self.pers[ "bots" ][ "behavior" ] = []; - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 50; // percentage of how often the bot strafes a target - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 50; // percentage of how often the bot will grenade - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 50; // percentage of how often the bot will sprint - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 50; // percentage of how often the bot will camp - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 50; // percentage of how often the bot will follow - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; // percentage of how often the bot will crouch - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 1; // percentage of how often the bot will switch weapons - self.pers[ "bots" ][ "behavior" ][ "class" ] = 1; // percentage of how often the bot will change classes - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 100; // percentage of how often the bot will jumpshot and dropshot - - self.pers[ "bots" ][ "behavior" ][ "quickscope" ] = false; // is a quickscoper - self.pers[ "bots" ][ "behavior" ][ "initswitch" ] = 10; // percentage of how often the bot will switch weapons on spawn - - self.pers[ "bots" ][ "unlocks" ] = []; -} - -/* - When a bot connects to the game. - This is called when a bot is added and when multiround gamemode starts. -*/ -connected() -{ - self endon( "disconnect" ); - - self.bot = spawnStruct(); - - self resetBotVars(); - - self thread onPlayerSpawned(); -} - -/* - The callback hook for when the bot gets killed. -*/ -onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) -{ -} - -/* - The callback hook when the bot gets damaged. -*/ -onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) -{ -} - -/* - We clear all of the script variables and other stuff for the bots. -*/ -resetBotVars() -{ - self.bot.script_target = undefined; - self.bot.script_target_offset = undefined; - self.bot.targets = []; - self.bot.target = undefined; - self.bot.target_this_frame = undefined; - self.bot.jav_loc = undefined; - self.bot.after_target = undefined; - self.bot.after_target_pos = undefined; - - self.bot.script_aimpos = undefined; - - self.bot.script_goal = undefined; - self.bot.script_goal_dist = 0.0; - - self.bot.next_wp = -1; - self.bot.second_next_wp = -1; - self.bot.towards_goal = undefined; - self.bot.astar = []; - self.bot.moveTo = self.origin; - self.bot.moveOrigin = self.origin; - self.bot.stop_move = false; - self.bot.greedy_path = false; - self.bot.climbing = false; - self.bot.wantsprint = false; - self.bot.last_next_wp = -1; - self.bot.last_second_next_wp = -1; - - self.bot.isfrozen = false; - self.bot.sprintendtime = -1; - self.bot.isreloading = false; - self.bot.issprinting = false; - self.bot.isfragging = false; - self.bot.issmoking = false; - self.bot.isfraggingafter = false; - self.bot.issmokingafter = false; - self.bot.isknifing = false; - self.bot.isknifingafter = false; - self.bot.knifing_target = undefined; - - self.bot.semi_time = false; - self.bot.jump_time = undefined; - self.bot.last_fire_time = -1; - - self.bot.is_cur_full_auto = false; - self.bot.cur_weap_dist_multi = 1; - self.bot.is_cur_sniper = false; - self.bot.is_cur_akimbo = false; - - self.bot.prio_objective = false; - - self.bot.rand = randomInt( 100 ); - - self BotBuiltinBotStop(); -} - -/* - When the bot spawns. -*/ -onPlayerSpawned() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - self waittill( "spawned_player" ); - - self resetBotVars(); - self thread onWeaponChange(); - self thread onLastStand(); - - self thread reload_watch(); - self thread sprint_watch(); - - self thread watchUsingRemote(); - - self thread spawned(); - } -} - -/* - Sets the factor of distance for a weapon -*/ -SetWeaponDistMulti( weap ) -{ - if ( weap == "none" ) - { - return 1; - } - - switch ( weaponClass( weap ) ) - { - case "rifle": - return 0.9; - - case "smg": - return 0.7; - - case "pistol": - return 0.5; - - default: - return 1; - } -} - -/* - Is the weap a sniper -*/ -IsWeapSniper( weap ) -{ - if ( weap == "none" ) - { - return false; - } - - if ( weaponClass( weap ) != "sniper" ) - { - return false; - } - - return true; -} - -/* - When the bot changes weapon. -*/ -onWeaponChange() -{ - self endon( "disconnect" ); - self endon( "death" ); - - first = true; - - for ( ;; ) - { - newWeapon = undefined; - - if ( first ) - { - first = false; - newWeapon = self getCurrentWeapon(); - } - else - { - self waittill( "weapon_change", newWeapon ); - } - - self.bot.is_cur_full_auto = WeaponIsFullAuto( newWeapon ); - self.bot.cur_weap_dist_multi = SetWeaponDistMulti( newWeapon ); - self.bot.is_cur_sniper = IsWeapSniper( newWeapon ); - self.bot.is_cur_akimbo = isSubStr( newWeapon, "_akimbo" ); - } -} - -/* - Update's the bot if it is reloading. -*/ -reload_watch() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill( "reload_start" ); - self.bot.isreloading = true; - - while ( true ) - { - if ( self waittill_any_timeout( 7.5, "reload" ) == "timeout" ) - { - break; - } - - if ( self GetWeaponAmmoClip( self GetCurrentWeapon() ) >= WeaponClipSize( self GetCurrentWeapon() ) ) - { - break; - } - } - - self.bot.isreloading = false; - } -} - -/* - Updates the bot if it is sprinting. -*/ -sprint_watch() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill( "sprint_begin" ); - self.bot.issprinting = true; - self waittill( "sprint_end" ); - self.bot.issprinting = false; - self.bot.sprintendtime = getTime(); - } -} - -/* - When the bot enters laststand, we fix the weapons -*/ -onLastStand() -{ - self endon( "disconnect" ); - self endon( "death" ); - - while ( true ) - { - while ( !self inLastStand() ) - { - wait 0.05; - } - - self notify( "kill_goal" ); - - while ( self inLastStand() ) - { - wait 0.05; - } - } -} - -/* - When the bot uses a remote killstreak -*/ -watchUsingRemote() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - for ( ;; ) - { - wait 1; - - if ( !isAlive( self ) ) - { - return; - } - - if ( !self IsUsingRemote() ) - { - continue; - } - - if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) - { - self watchUsingMinigun(); - } - - if ( isDefined( level.ac130Player ) && level.ac130player == self ) - { - self thread watchAc130Weapon(); - self watchUsingAc130(); - } - - if ( isDefined( level.remote_mortar ) && isDefined( level.remote_mortar.owner ) && level.remote_mortar.owner == self ) - { - self watchUsingMortar(); - } - - if ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) - { - self watchUsingTank(); - - self.remoteTank = undefined; - } - - if ( isDefined( self.remoteUAV ) ) - { - self watchUsingUav(); - } - - if ( isDefined( self.using_remote_turret ) && self.using_remote_turret ) - { - self watchUsingTurret(); - } - - self.bot.targets = []; - self notify( "kill_goal" ); - } -} - -/* - watchUsingTurret -*/ -watchUsingTurret() -{ - if ( !isDefined( self.remoteTurretList ) || !isDefined( self.remoteTurretList[ 0 ] ) ) - { - return; - } - - turret = self.remoteTurretList[ 0 ]; - - turret endon( "death" ); - - while ( isDefined( self.using_remote_turret ) && self.using_remote_turret ) - { - if ( self getCurrentWeapon() != "killstreak_remote_turret_remote_mp" ) - { - self switchToWeapon( "killstreak_remote_turret_remote_mp" ); - } - - if ( isDefined( self.bot.target ) ) - { - self thread pressFire(); - } - - wait 0.05; - } -} - -/* - Uses tank -*/ -watchUsingTank() -{ - tankKeys = getArrayKeys( level.ugvs ); - tank = undefined; - - for ( i = tankKeys.size - 1; i >= 0; i-- ) - { - tempTank = level.ugvs[ tankKeys[ i ] ]; - - if ( !isDefined( tempTank ) ) - { - continue; - } - - if ( !isDefined( tempTank.owner ) ) - { - continue; - } - - if ( tempTank.owner == self ) - { - tank = tempTank; - break; - } - } - - tankKeys = undefined; - - if ( !isDefined( tank ) ) - { - return; - } - - self.remoteTank = tank; - - self thread useTankRocket( tank ); - - tank endon( "death" ); - - while ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) - { - if ( self getCurrentWeapon() != "killstreak_remote_tank_remote_mp" ) - { - self switchToWeapon( "killstreak_remote_tank_remote_mp" ); - } - - if ( isDefined( self.bot.target ) ) - { - self thread pressFire(); - } - - wait 0.05; - } -} - -/* - useTankRocket -*/ -useTankRocket( tank ) -{ - tank endon( "death" ); - self endon( "disconnect" ); - self endon( "spawned_player" ); - - while ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) - { - wait 3.5; - - if ( isDefined( self.bot.target ) ) - { - self thread pressfrag(); - } - } -} - -/* - Uses uav -*/ -watchUsingUav() -{ - self.remoteUAV endon( "end_remote" ); - - while ( isDefined( self.remoteUAV ) ) - { - if ( self getCurrentWeapon() != "uav_remote_mp" ) - { - self switchToWeapon( "uav_remote_mp" ); - } - - if ( isDefined( self.lockedTarget ) ) - { - self notify( "remoteUAV_tag" ); - } - - wait 0.05; - } -} - -/* - Uses mortar -*/ -watchUsingMortar() -{ - level.remote_mortar endon( "remote_done" ); - - while ( isDefined( level.remote_mortar ) && isDefined( level.remote_mortar.owner ) && level.remote_mortar.owner == self ) - { - if ( self getCurrentWeapon() != "mortar_remote_mp" ) - { - self switchToWeapon( "mortar_remote_mp" ); - } - - if ( isDefined( self.bot.target ) ) - { - self thread pressFire(); - } - - wait 0.05; - } -} - -/* - WHen it uses the helicopter minigun -*/ -watchUsingMinigun() -{ - self endon( "heliPlayer_removed" ); - - while ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) - { - if ( self getCurrentWeapon() != "heli_remote_mp" ) - { - self switchToWeapon( "heli_remote_mp" ); - } - - if ( isDefined( self.bot.target ) ) - { - self thread pressFire(); - } - - wait 0.05; - } -} - -/* - When it uses the ac130 -*/ -watchAc130Weapon() -{ - self endon( "ac130player_removed" ); - self endon( "disconnect" ); - self endon( "spawned_player" ); - - while ( isDefined( level.ac130Player ) && level.ac130player == self ) - { - curWeap = self GetCurrentWeapon(); - - if ( curWeap != "ac130_105mm_mp" && curWeap != "ac130_40mm_mp" && curWeap != "ac130_25mm_mp" ) - { - self switchToWeapon( "ac130_105mm_mp" ); - } - - if ( isDefined( self.bot.target ) ) - { - self thread pressFire(); - } - - wait 0.05; - } -} - -/* - Swap between the ac130 weapons while in it -*/ -watchUsingAc130() -{ - self endon( "ac130player_removed" ); - - while ( isDefined( level.ac130Player ) && level.ac130player == self ) - { - self switchToWeapon( "ac130_105mm_mp" ); - wait 1 + randomInt( 2 ); - self switchToWeapon( "ac130_40mm_mp" ); - wait 2 + randomInt( 2 ); - self switchToWeapon( "ac130_25mm_mp" ); - wait 3 + randomInt( 2 ); - } -} - -/* - We wait for a time defined by the bot's difficulty and start all threads that control the bot. -*/ -spawned() -{ - self endon( "disconnect" ); - self endon( "death" ); - - wait self.pers[ "bots" ][ "skill" ][ "spawn_time" ]; - - self thread doBotMovement(); - - self thread grenade_danager(); - self thread target(); - self thread updateBones(); - self thread aim(); - self thread check_reload(); - self thread stance(); - self thread onNewEnemy(); - self thread walk(); - self thread watchHoldBreath(); - self thread watchGrenadeFire(); - self thread watchPickupGun(); - - self notify( "bot_spawned" ); -} - -/* - watchPickupGun -*/ -watchPickupGun() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - wait 1; - - if ( self UseButtonPressed() ) - { - continue; - } - - weap = self GetCurrentWeapon(); - - if ( weap != "none" && self GetAmmoCount( weap ) ) - { - continue; - } - - self thread use( 0.5 ); - } -} - -/* - Watches when the bot fires a grenade -*/ -watchGrenadeFire() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill( "grenade_fire", nade, weapname ); - - if ( !isDefined( nade ) ) - { - continue; - } - - if ( weapname == "c4_mp" ) - { - self thread watchC4Thrown( nade ); - } - } -} - -/* - Watches the c4 -*/ -watchC4Thrown( c4 ) -{ - self endon( "disconnect" ); - c4 endon( "death" ); - - wait 0.5; - - for ( ;; ) - { - wait 1 + randomInt( 50 ) * 0.05; - - shouldBreak = false; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( ( level.teamBased && self.team == player.team ) || player.sessionstate != "playing" || !isReallyAlive( player ) ) - { - continue; - } - - if ( distanceSquared( c4.origin, player.origin ) > 200 * 200 ) - { - continue; - } - - if ( !bulletTracePassed( c4.origin, player.origin + ( 0, 0, 25 ), false, c4 ) ) - { - continue; - } - - shouldBreak = true; - } - - if ( shouldBreak ) - { - break; - } - } - - weap = self getCurrentWeapon(); - - if ( weap != "c4_mp" ) - { - self notify( "alt_detonate" ); - } - else - { - self thread pressFire(); - } -} - -/* - Bot moves towards the point -*/ -doBotMovement_loop( data ) -{ - if ( isDefined( self.remoteUAV ) ) - { - self.bot.moveOrigin = self.remoteUAV.origin - ( 0, 0, 50 ); - } - else if ( isDefined( self.remoteTank ) ) - { - self.bot.moveOrigin = self.remoteTank.origin; - } - else - { - self.bot.moveOrigin = self.origin; - } - - waittillframeend; - move_To = self.bot.moveTo; - angles = self GetPlayerAngles(); - dir = ( 0, 0, 0 ); - - if ( DistanceSquared( self.bot.moveOrigin, move_To ) >= 49 ) - { - cosa = cos( 0 - angles[ 1 ] ); - sina = sin( 0 - angles[ 1 ] ); - - // get the direction - dir = move_To - self.bot.moveOrigin; - - // rotate our direction according to our angles - dir = ( dir[ 0 ] * cosa - dir[ 1 ] * sina, - dir[ 0 ] * sina + dir[ 1 ] * cosa, - 0 ); - - // make the length 127 - dir = VectorNormalize( dir ) * 127; - - // invert the second component as the engine requires this - dir = ( dir[ 0 ], 0 - dir[ 1 ], 0 ); - } - - // climb through windows - if ( self isMantling() ) - { - data.wasMantling = true; - self crouch(); - } - else if ( data.wasMantling ) - { - data.wasMantling = false; - self stand(); - } - - startPos = self.origin + ( 0, 0, 50 ); - startPosForward = startPos + anglesToForward( ( 0, angles[ 1 ], 0 ) ) * 25; - bt = bulletTrace( startPos, startPosForward, false, self ); - - if ( bt[ "fraction" ] >= 1 ) - { - // check if need to jump - bt = bulletTrace( startPosForward, startPosForward - ( 0, 0, 40 ), false, self ); - - if ( bt[ "fraction" ] < 1 && bt[ "normal" ][ 2 ] > 0.9 && data.i > 1.5 && !self isOnLadder() ) - { - data.i = 0; - self thread jump(); - } - } - // check if need to knife glass - else if ( bt[ "surfacetype" ] == "glass" ) - { - if ( data.i > 1.5 ) - { - data.i = 0; - self thread knife(); - } - } - else - { - // check if need to crouch - if ( bulletTracePassed( startPos - ( 0, 0, 25 ), startPosForward - ( 0, 0, 25 ), false, self ) && !self.bot.climbing ) - { - self crouch(); - } - } - - // move! - if ( ( self.bot.wantsprint && self.bot.issprinting ) || isDefined( self.bot.knifing_target ) ) - { - dir = ( 127, dir[ 1 ], 0 ); - } - - self BotBuiltinBotMovement( int( dir[ 0 ] ), int( dir[ 1 ] ) ); - - if ( isDefined( self.remoteUAV ) ) - { - if ( abs( move_To[ 2 ] - self.bot.moveOrigin[ 2 ] ) > 12 ) - { - if ( move_To[ 2 ] > self.bot.moveOrigin[ 2 ] ) - { - self thread gostand(); - } - else - { - self thread sprint(); - } - } - } -} - -/* - Bot moves towards the point -*/ -doBotMovement() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - data = spawnStruct(); - data.wasMantling = false; - - for ( data.i = 0;; data.i += 0.05 ) - { - wait 0.05; - - if ( !isAlive( self ) ) - { - return; - } - - self doBotMovement_loop( data ); - } -} - -/* - The hold breath thread. -*/ -watchHoldBreath() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - wait 1; - - if ( self.bot.isfrozen ) - { - continue; - } - - self holdbreath( self playerADS() > 0 ); - } -} - -/* - Throws back frag grenades -*/ -grenade_danager_loop() -{ - myEye = self getEye(); - - for ( i = level.bots_fragList.count - 1; i >= 0; i-- ) - { - frag = level.bots_fragList.data[ i ]; - - if ( level.teamBased && frag.team == self.team ) - { - continue; - } - - if ( lengthSquared( frag.velocity ) > 10000 ) - { - continue; - } - - if ( DistanceSquared( self.origin, frag.origin ) > 20000 ) - { - continue; - } - - if ( !bulletTracePassed( myEye, frag.origin, false, frag.grenade ) ) - { - continue; - } - - self BotNotifyBotEvent( "throwback", "stop", frag ); - self thread frag(); - break; - } -} - -/* - Throws back frag grenades -*/ -grenade_danager() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - wait 1; - - if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) - { - continue; - } - - if ( self.bot.isfrozen || level.gameEnded || !gameFlag( "prematch_done" ) ) - { - continue; - } - - if ( self.bot.isfraggingafter || self.bot.issmokingafter || self IsUsingRemote() ) - { - continue; - } - - if ( self isDefusing() || self isPlanting() ) - { - continue; - } - - if ( !getDvarInt( "bots_play_nade" ) ) - { - continue; - } - - self grenade_danager_loop(); - } -} - -/* - Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. -*/ -stance_loop() -{ - toStance = "stand"; - - if ( self.bot.next_wp != -1 ) - { - toStance = level.waypoints[ self.bot.next_wp ].type; - } - - if ( !isDefined( toStance ) ) - { - toStance = "crouch"; - } - - if ( toStance == "stand" && randomInt( 100 ) <= self.pers[ "bots" ][ "behavior" ][ "crouch" ] ) - { - toStance = "crouch"; - } - - if ( self.hasRiotShieldEquipped && isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && isPlayer( self.bot.target.entity ) ) - { - toStance = "crouch"; - } - - if ( toStance == "climb" ) - { - self.bot.climbing = true; - toStance = "stand"; - } - - if ( toStance != "stand" && toStance != "crouch" && toStance != "prone" ) - { - toStance = "crouch"; - } - - if ( toStance == "stand" ) - { - self stand(); - } - else if ( toStance == "crouch" ) - { - self crouch(); - } - else - { - self prone(); - } - - curweap = self getCurrentWeapon(); - time = getTime(); - chance = self.pers[ "bots" ][ "behavior" ][ "sprint" ]; - - if ( time - self.lastSpawnTime < 5000 ) - { - chance *= 2; - } - - if ( isDefined( self.bot.script_goal ) && DistanceSquared( self.origin, self.bot.script_goal ) > 256 * 256 ) - { - chance *= 2; - } - - if ( toStance != "stand" || self.bot.isreloading || self.bot.issprinting || self.bot.isfraggingafter || self.bot.issmokingafter ) - { - return; - } - - if ( randomInt( 100 ) > chance ) - { - return; - } - - if ( isDefined( self.bot.target ) && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) ) - { - return; - } - - if ( self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000 ) - { - return; - } - - if ( !isDefined( self.bot.towards_goal ) || DistanceSquared( self.origin, physicsTrace( self getEye(), self getEye() + anglesToForward( self getPlayerAngles() ) * 1024, false, undefined ) ) < level.bots_minSprintDistance || getConeDot( self.bot.towards_goal, self.origin, self GetPlayerAngles() ) < 0.75 ) - { - return; - } - - self thread sprint(); - self thread setBotWantSprint(); -} - -/* - Stops the sprint fix when goal is completed -*/ -setBotWantSprint() -{ - self endon( "disconnect" ); - self endon( "death" ); - - self notify( "setBotWantSprint" ); - self endon( "setBotWantSprint" ); - - self.bot.wantsprint = true; - - self waittill_notify_or_timeout( "kill_goal", 10 ); - - self.bot.wantsprint = false; -} - -/* - Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. -*/ -stance() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill_either( "finished_static_waypoints", "new_static_waypoint" ); - - self.bot.climbing = false; - - if ( self.bot.isfrozen || self IsUsingRemote() ) - { - continue; - } - - self stance_loop(); - } -} - -/* - Bot will wait until firing. -*/ -check_reload() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill_notify_or_timeout( "weapon_fired", 5 ); - self thread reload_thread(); - } -} - -/* - Bot will reload after firing if needed. -*/ -reload_thread() -{ - self endon( "disconnect" ); - self endon( "death" ); - self endon( "weapon_fired" ); - - wait 2.5; - - if ( self.bot.isfrozen || level.gameEnded || !gameFlag( "prematch_done" ) ) - { - return; - } - - if ( isDefined( self.bot.target ) || self.bot.isreloading || self.bot.isfraggingafter || self.bot.issmokingafter || self.bot.isfrozen ) - { - return; - } - - cur = self getCurrentWEapon(); - - if ( cur == "" || cur == "none" ) - { - return; - } - - if ( IsWeaponClipOnly( cur ) || !self GetWeaponAmmoStock( cur ) || self IsUsingRemote() ) - { - return; - } - - maxsize = WeaponClipSize( cur ); - cursize = self GetWeaponammoclip( cur ); - - if ( cursize / maxsize < 0.5 ) - { - self thread reload(); - } -} - -/* - Updates the bot's target bone -*/ -updateBones() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - bones = strtok( self.pers[ "bots" ][ "skill" ][ "bones" ], "," ); - waittime = self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ]; - - for ( ;; ) - { - self waittill_any_timeout( waittime, "new_enemy" ); - - if ( !isAlive( self ) ) - { - return; - } - - if ( !isDefined( self.bot.target ) ) - { - continue; - } - - self.bot.target.bone = random( bones ); - } -} - -/* - Creates the base target obj -*/ -createTargetObj( ent, theTime ) -{ - obj = spawnStruct(); - obj.entity = ent; - obj.last_seen_pos = ( 0, 0, 0 ); - obj.dist = 0; - obj.time = theTime; - obj.trace_time = 0; - obj.no_trace_time = 0; - obj.trace_time_time = 0; - obj.rand = randomInt( 100 ); - obj.didlook = false; - obj.offset = undefined; - obj.bone = undefined; - obj.aim_offset = undefined; - obj.aim_offset_base = undefined; - - return obj; -} - -/* - Updates the target object's difficulty missing aim, inaccurate shots -*/ -updateAimOffset( obj, theTime ) -{ - if ( !isDefined( obj.aim_offset_base ) ) - { - offsetAmount = self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ]; - - if ( offsetAmount > 0 ) - { - obj.aim_offset_base = ( randomFloatRange( 0 - offsetAmount, offsetAmount ), - randomFloatRange( 0 - offsetAmount, offsetAmount ), - randomFloatRange( 0 - offsetAmount, offsetAmount ) ); - } - else - { - obj.aim_offset_base = ( 0, 0, 0 ); - } - } - - aimDiffTime = self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] * 1000; - objCreatedFor = obj.trace_time; - - if ( objCreatedFor >= aimDiffTime ) - { - offsetScalar = 0; - } - else - { - offsetScalar = 1 - objCreatedFor / aimDiffTime; - } - - obj.aim_offset = obj.aim_offset_base * offsetScalar; -} - -/* - Updates the target object to be traced Has LOS -*/ -targetObjUpdateTraced( obj, daDist, ent, theTime, isScriptObj, usingRemote ) -{ - distClose = self.pers[ "bots" ][ "skill" ][ "dist_start" ]; - distClose *= self.bot.cur_weap_dist_multi; - distClose *= distClose; - - distMax = self.pers[ "bots" ][ "skill" ][ "dist_max" ]; - distMax *= self.bot.cur_weap_dist_multi; - distMax *= distMax; - - timeMulti = 1; - - if ( !usingRemote && !isScriptObj ) - { - if ( daDist > distMax ) - { - timeMulti = 0; - } - else if ( daDist > distClose ) - { - timeMulti = 1 - ( ( daDist - distClose ) / ( distMax - distClose ) ); - } - } - - obj.no_trace_time = 0; - obj.trace_time += int( 50 * timeMulti ); - obj.dist = daDist; - obj.last_seen_pos = ent.origin; - obj.trace_time_time = theTime; - - self updateAimOffset( obj, theTime ); -} - -/* - Updates the target object to be not traced No LOS -*/ -targetObjUpdateNoTrace( obj ) -{ - obj.no_trace_time += 50; - obj.trace_time = 0; - obj.didlook = false; -} - -/* - The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. -*/ -target_loop() -{ - myEye = self GetEye(); - - if ( isDefined( self.remoteUAV ) ) - { - myEye = self.remoteUAV getTagOrigin( "tag_origin" ); - } - - theTime = getTime(); - myAngles = self GetPlayerAngles(); - myFov = self.pers[ "bots" ][ "skill" ][ "fov" ]; - bestTargets = []; - bestTime = 2147483647; - rememberTime = self.pers[ "bots" ][ "skill" ][ "remember_time" ]; - initReactTime = self.pers[ "bots" ][ "skill" ][ "init_react_time" ]; - hasTarget = isDefined( self.bot.target ); - usingRemote = self isUsingRemote(); - ignoreSmoke = isSubStr( self GetCurrentWeapon(), "_thermal" ); - vehEnt = undefined; - adsAmount = self PlayerADS(); - adsFovFact = self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ]; - - if ( usingRemote ) - { - if ( isDefined( level.ac130player ) && level.ac130player == self ) - { - vehEnt = level.ac130.planeModel; - } - - if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) - { - vehEnt = level.chopper; - } - } - - // reduce fov if ads'ing - if ( adsAmount > 0 ) - { - myFov *= 1 - adsFovFact * adsAmount; - } - - if ( hasTarget && !isDefined( self.bot.target.entity ) ) - { - self.bot.target = undefined; - hasTarget = false; - } - - playercount = level.players.size; - - for ( i = -1; i < playercount; i++ ) - { - obj = undefined; - - if ( i == -1 ) - { - if ( !isDefined( self.bot.script_target ) ) - { - continue; - } - - ent = self.bot.script_target; - key = ent getEntityNumber() + ""; - daDist = distanceSquared( self.origin, ent.origin ); - obj = self.bot.targets[ key ]; - isObjDef = isDefined( obj ); - entOrigin = ent.origin; - - if ( isDefined( self.bot.script_target_offset ) ) - { - entOrigin += self.bot.script_target_offset; - } - - if ( ignoreSmoke || ( SmokeTrace( myEye, entOrigin, level.smokeRadius ) ) && bulletTracePassed( myEye, entOrigin, false, ent ) ) - { - if ( !isObjDef ) - { - obj = self createTargetObj( ent, theTime ); - obj.offset = self.bot.script_target_offset; - - self.bot.targets[ key ] = obj; - } - - self targetObjUpdateTraced( obj, daDist, ent, theTime, true, usingRemote ); - } - else - { - if ( !isObjDef ) - { - continue; - } - - self targetObjUpdateNoTrace( obj ); - - if ( obj.no_trace_time > rememberTime ) - { - self.bot.targets[ key ] = undefined; - continue; - } - } - } - else - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - key = player getEntityNumber() + ""; - obj = self.bot.targets[ key ]; - - daDist = distanceSquared( self.origin, player.origin ); - - if ( usingRemote ) - { - daDist = 0; - } - - isObjDef = isDefined( obj ); - - if ( ( level.teamBased && self.team == player.team ) || player.sessionstate != "playing" || !isReallyAlive( player ) ) - { - if ( isObjDef ) - { - self.bot.targets[ key ] = undefined; - } - - continue; - } - - canTargetPlayer = false; - - if ( usingRemote ) - { - canTargetPlayer = ( bulletTracePassed( myEye, player getTagOrigin( "j_head" ), false, vehEnt ) - && !player _hasPerk( "specialty_blindeye" ) ); - } - else - { - targetHead = player getTagOrigin( "j_head" ); - targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); - targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); - - traceHead = bulletTrace( myEye, targetHead, false, undefined ); - traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined ); - traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined ); - - canTargetPlayer = ( ( sightTracePassed( myEye, targetHead, false, undefined ) || - sightTracePassed( myEye, targetAnkleLeft, false, undefined ) || - sightTracePassed( myEye, targetAnkleRight, false, undefined ) ) - - && ( ( traceHead[ "fraction" ] >= 1.0 || traceHead[ "surfacetype" ] == "glass" ) || - ( traceAnkleLeft[ "fraction" ] >= 1.0 || traceAnkleLeft[ "surfacetype" ] == "glass" ) || - ( traceAnkleRight[ "fraction" ] >= 1.0 || traceAnkleRight[ "surfacetype" ] == "glass" ) ) - - && ( ignoreSmoke || - SmokeTrace( myEye, player.origin, level.smokeRadius ) || - daDist < level.bots_maxKnifeDistance * 4 ) - - && ( getConeDot( player.origin, self.origin, myAngles ) >= myFov || - ( isObjDef && obj.trace_time ) ) ); - } - - if ( isDefined( self.bot.target_this_frame ) && self.bot.target_this_frame == player ) - { - self.bot.target_this_frame = undefined; - - canTargetPlayer = true; - } - - if ( isDefined( self.remoteUAV ) && isDefined( player.UAVRemoteMarkedBy ) ) - { - canTargetPlayer = false; - } - - if ( canTargetPlayer ) - { - if ( !isObjDef ) - { - obj = self createTargetObj( player, theTime ); - - self.bot.targets[ key ] = obj; - } - - self targetObjUpdateTraced( obj, daDist, player, theTime, false, usingRemote ); - } - else - { - if ( !isObjDef ) - { - continue; - } - - self targetObjUpdateNoTrace( obj ); - - if ( obj.no_trace_time > rememberTime ) - { - self.bot.targets[ key ] = undefined; - continue; - } - } - } - - if ( !isdefined( obj ) ) - { - continue; - } - - if ( theTime - obj.time < initReactTime ) - { - continue; - } - - timeDiff = theTime - obj.trace_time_time; - - if ( timeDiff < bestTime ) - { - bestTargets = []; - bestTime = timeDiff; - } - - if ( timeDiff == bestTime ) - { - bestTargets[ key ] = obj; - } - } - - if ( hasTarget && isDefined( bestTargets[ self.bot.target.entity getEntityNumber() + "" ] ) ) - { - return; - } - - closest = 2147483647; - toBeTarget = undefined; - - bestKeys = getArrayKeys( bestTargets ); - - for ( i = bestKeys.size - 1; i >= 0; i-- ) - { - theDist = bestTargets[ bestKeys[ i ] ].dist; - - if ( theDist > closest ) - { - continue; - } - - closest = theDist; - toBeTarget = bestTargets[ bestKeys[ i ] ]; - } - - beforeTargetID = -1; - newTargetID = -1; - - if ( hasTarget && isDefined( self.bot.target.entity ) ) - { - beforeTargetID = self.bot.target.entity getEntityNumber(); - } - - if ( isDefined( toBeTarget ) && isDefined( toBeTarget.entity ) ) - { - newTargetID = toBeTarget.entity getEntityNumber(); - } - - if ( beforeTargetID != newTargetID ) - { - self.bot.target = toBeTarget; - self notify( "new_enemy" ); - } -} - -/* - The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. -*/ -target() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - for ( ;; ) - { - wait 0.05; - - if ( !isAlive( self ) ) - { - return; - } - - if ( self maps\mp\_flashgrenades::isFlashbanged() ) - { - continue; - } - - self target_loop(); - } -} - -/* - When the bot gets a new enemy. -*/ -onNewEnemy() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self waittill( "new_enemy" ); - - if ( !isDefined( self.bot.target ) ) - { - continue; - } - - if ( !isDefined( self.bot.target.entity ) || !isPlayer( self.bot.target.entity ) ) - { - continue; - } - - if ( self.bot.target.didlook ) - { - continue; - } - - self thread watchToLook(); - } -} - -/* - Bots will jump or dropshot their enemy player. -*/ -watchToLook() -{ - self endon( "disconnect" ); - self endon( "death" ); - self endon( "new_enemy" ); - - for ( ;; ) - { - while ( isDefined( self.bot.target ) && self.bot.target.didlook ) - { - wait 0.05; - } - - while ( isDefined( self.bot.target ) && self.bot.target.no_trace_time ) - { - wait 0.05; - } - - if ( !isDefined( self.bot.target ) ) - { - break; - } - - self.bot.target.didlook = true; - - if ( self.bot.isfrozen ) - { - continue; - } - - if ( self.bot.target.dist > level.bots_maxShotgunDistance * 2 ) - { - continue; - } - - if ( self.bot.target.dist <= level.bots_maxKnifeDistance ) - { - continue; - } - - if ( !self canFire( self getCurrentWEapon() ) ) - { - continue; - } - - if ( !self isInRange( self.bot.target.dist, self getCurrentWEapon() ) ) - { - continue; - } - - if ( self.bot.is_cur_sniper ) - { - continue; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "jump" ] ) - { - continue; - } - - if ( !getDvarInt( "bots_play_jumpdrop" ) ) - { - continue; - } - - if ( isDefined( self.bot.jump_time ) && getTime() - self.bot.jump_time <= 5000 ) - { - continue; - } - - if ( self.bot.target.rand <= self.pers[ "bots" ][ "behavior" ][ "strafe" ] ) - { - if ( self getStance() != "stand" ) - { - continue; - } - - self.bot.jump_time = getTime(); - self thread jump(); - } - else - { - if ( getConeDot( self.bot.target.last_seen_pos, self.origin, self getPlayerAngles() ) < 0.8 || self.bot.target.dist <= level.bots_noADSDistance ) - { - continue; - } - - self.bot.jump_time = getTime(); - self prone(); - self notify( "kill_goal" ); - wait 2.5; - self crouch(); - } - } -} - -/* - Assigns the bot's after target (bot will keep firing at a target after no sight or death) -*/ -start_bot_after_target( who ) -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - self.bot.after_target = who; - self.bot.after_target_pos = who.origin; - - self notify( "kill_after_target" ); - self endon( "kill_after_target" ); - - wait self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ]; - - self.bot.after_target = undefined; -} - -/* - Clears the bot's after target -*/ -clear_bot_after_target() -{ - self.bot.after_target = undefined; - self notify( "kill_after_target" ); -} - -/* - This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. -*/ -aim_loop() -{ - aimspeed = self.pers[ "bots" ][ "skill" ][ "aim_time" ]; - - if ( self IsStunned() || self isArtShocked() ) - { - aimspeed = 1; - } - - usingRemote = self IsUsingRemote(); - curweap = self getCurrentWeapon(); - - eyePos = self getEye(); - - if ( isDefined( self.remoteUAV ) ) - { - eyePos = self.remoteUAV getTagOrigin( "tag_origin" ); - } - - angles = self GetPlayerAngles(); - adsAmount = self PlayerADS(); - adsAimSpeedFact = self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ]; - - // reduce aimspeed if ads'ing - if ( adsAmount > 0 ) - { - aimspeed *= 1 + adsAimSpeedFact * adsAmount; - } - - if ( isDefined( self.bot.jav_loc ) && !usingRemote ) - { - aimpos = self.bot.jav_loc; - - self thread bot_lookat( aimpos, aimspeed ); - self thread pressAds(); - - if ( curweap == "javelin_mp" && getDvarInt( "bots_play_fire" ) ) - { - self botFire( curweap ); - } - - return; - } - - if ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !( self.bot.prio_objective && isDefined( self.bot.script_aimpos ) ) ) - { - no_trace_look_time = self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ]; - no_trace_time = self.bot.target.no_trace_time; - - if ( no_trace_time <= no_trace_look_time ) - { - trace_time = self.bot.target.trace_time; - last_pos = self.bot.target.last_seen_pos; - target = self.bot.target.entity; - conedot = 0; - isplay = isPlayer( self.bot.target.entity ); - - offset = self.bot.target.offset; - - if ( !isDefined( offset ) ) - { - offset = ( 0, 0, 0 ); - } - - aimoffset = self.bot.target.aim_offset; - - if ( !isDefined( aimoffset ) ) - { - aimoffset = ( 0, 0, 0 ); - } - - dist = self.bot.target.dist; - rand = self.bot.target.rand; - no_trace_ads_time = self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ]; - reaction_time = self.pers[ "bots" ][ "skill" ][ "reaction_time" ]; - nadeAimOffset = 0; - - bone = self.bot.target.bone; - - if ( !isDefined( bone ) ) - { - bone = "j_spineupper"; - } - - if ( self.bot.isfraggingafter || self.bot.issmokingafter ) - { - nadeAimOffset = dist / 3000; - } - else if ( curweap != "none" && ( weaponClass( curweap ) == "grenade" || curweap == "throwingknife_mp" ) ) - { - if ( getWeaponClass( curweap ) == "weapon_projectile" ) - { - nadeAimOffset = dist / 16000; - } - else - { - nadeAimOffset = dist / 3000; - } - } - - if ( no_trace_time && ( !isDefined( self.bot.after_target ) || self.bot.after_target != target ) ) - { - if ( no_trace_time > no_trace_ads_time && !usingRemote ) - { - if ( isplay ) - { - // better room to nade? cook time function with dist? - if ( !self.bot.isfraggingafter && !self.bot.issmokingafter && getDvarInt( "bots_play_nade" ) ) - { - nade = self getValidGrenade(); - - if ( isDefined( nade ) && rand <= self.pers[ "bots" ][ "behavior" ][ "nade" ] && bulletTracePassed( eyePos, eyePos + ( 0, 0, 75 ), false, self ) && bulletTracePassed( last_pos, last_pos + ( 0, 0, 100 ), false, target ) && dist > level.bots_minGrenadeDistance && dist < level.bots_maxGrenadeDistance ) - { - time = 0.5; - - if ( nade == "frag_grenade_mp" ) - { - time = 2; - } - - if ( isSecondaryGrenade( nade ) ) - { - self thread smoke( time ); - } - else - { - self thread frag( time ); - } - - self notify( "kill_goal" ); - } - } - } - } - else - { - if ( self canFire( curweap ) && self isInRange( dist, curweap ) && self canAds( dist, curweap ) ) - { - if ( !self.bot.is_cur_sniper || !self.pers[ "bots" ][ "behavior" ][ "quickscope" ] ) - { - self thread pressAds(); - } - } - } - - if ( !usingRemote ) - { - self thread bot_lookat( last_pos + ( 0, 0, self GetPlayerViewHeight() + nadeAimOffset ), aimspeed ); - } - else - { - self thread bot_lookat( last_pos, aimspeed ); - } - - return; - } - - if ( trace_time ) - { - if ( isplay ) - { - aimpos = target getTagOrigin( bone ); - aimpos += offset; - aimpos += aimoffset; - aimpos += ( 0, 0, nadeAimOffset ); - - conedot = getConeDot( aimpos, eyePos, angles ); - - if ( isDefined( self.bot.knifing_target ) ) - { - self thread bot_lookat( target getTagOrigin( "j_spine4" ), 0.05 ); - } - else if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) - { - self thread bot_lookat( aimpos, 0.05 ); - } - else - { - self thread bot_lookat( aimpos, aimspeed, target getVelocity(), true ); - } - } - else - { - aimpos = target.origin; - aimpos += offset; - aimpos += aimoffset; - aimpos += ( 0, 0, nadeAimOffset ); - - conedot = getConeDot( aimpos, eyePos, angles ); - - if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) - { - self thread bot_lookat( aimpos, 0.05 ); - } - else - { - self thread bot_lookat( aimpos, aimspeed ); - } - } - - knifeDist = level.bots_maxKnifeDistance; - - if ( ( isplay || target.classname == "misc_turret" ) && !self.bot.isknifingafter && conedot > 0.9 && dist < knifeDist && trace_time > reaction_time && !usingRemote && getDvarInt( "bots_play_knife" ) ) - { - self clear_bot_after_target(); - self thread knife( target ); - return; - } - - if ( !self canFire( curweap ) || !self isInRange( dist, curweap ) ) - { - return; - } - - canADS = ( self canAds( dist, curweap ) && conedot > 0.75 ); - - if ( canADS ) - { - stopAdsOverride = false; - - if ( self.bot.is_cur_sniper ) - { - if ( self.pers[ "bots" ][ "behavior" ][ "quickscope" ] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000 ) - { - stopAdsOverride = true; - } - else - { - self notify( "kill_goal" ); - } - } - - if ( !stopAdsOverride ) - { - self thread pressAds(); - } - } - - if ( curweap == "iw5_smaw_mp" && entIsVehicle( self.bot.target.entity ) && ( !IsDefined( self.stingerStage ) || self.stingerStage != 2 ) ) - { - return; - } - - if ( trace_time > reaction_time ) - { - if ( ( !canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone" ) && ( conedot > 0.99 || dist < level.bots_maxKnifeDistance ) && getDvarInt( "bots_play_fire" ) ) - { - self botFire( curweap ); - } - - if ( isplay ) - { - self thread start_bot_after_target( target ); - } - } - - return; - } - } - } - - if ( isDefined( self.bot.after_target ) ) - { - nadeAimOffset = 0; - last_pos = self.bot.after_target_pos; - dist = DistanceSquared( self.origin, last_pos ); - - if ( self.bot.isfraggingafter || self.bot.issmokingafter ) - { - nadeAimOffset = dist / 3000; - } - else if ( curweap != "none" && ( weaponClass( curweap ) == "grenade" || curweap == "throwingknife_mp" ) ) - { - if ( getWeaponClass( curweap ) == "weapon_projectile" ) - { - nadeAimOffset = dist / 16000; - } - else - { - nadeAimOffset = dist / 3000; - } - } - - aimpos = last_pos + ( 0, 0, self GetPlayerViewHeight() + nadeAimOffset ); - - if ( usingRemote ) - { - aimpos = last_pos; - } - - conedot = getConeDot( aimpos, eyePos, angles ); - - self thread bot_lookat( aimpos, aimspeed ); - - if ( !self canFire( curweap ) || !self isInRange( dist, curweap ) ) - { - return; - } - - canADS = ( self canAds( dist, curweap ) && conedot > 0.75 ); - - if ( canADS ) - { - stopAdsOverride = false; - - if ( self.bot.is_cur_sniper ) - { - if ( self.pers[ "bots" ][ "behavior" ][ "quickscope" ] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000 ) - { - stopAdsOverride = true; - } - else - { - self notify( "kill_goal" ); - } - } - - if ( !stopAdsOverride ) - { - self thread pressAds(); - } - } - - if ( ( !canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone" ) && ( conedot > 0.95 || dist < level.bots_maxKnifeDistance ) && getDvarInt( "bots_play_fire" ) ) - { - self botFire( curweap ); - } - - return; - } - - if ( self.bot.next_wp != -1 && isDefined( level.waypoints[ self.bot.next_wp ].angles ) && false ) - { - forwardPos = anglesToForward( level.waypoints[ self.bot.next_wp ].angles ) * 1024; - - self thread bot_lookat( eyePos + forwardPos, aimspeed ); - } - else if ( isDefined( self.bot.script_aimpos ) ) - { - self thread bot_lookat( self.bot.script_aimpos, aimspeed ); - } - else if ( !usingRemote || isDefined( self.remoteUAV ) || isDefined( self.remoteTank ) ) - { - lookat = undefined; - - if ( self.bot.second_next_wp != -1 && !self.bot.issprinting && !self.bot.climbing ) - { - lookat = level.waypoints[ self.bot.second_next_wp ].origin; - } - else if ( isDefined( self.bot.towards_goal ) ) - { - lookat = self.bot.towards_goal; - } - - if ( isDefined( lookat ) ) - { - self thread bot_lookat( lookat + ( 0, 0, self GetPlayerViewHeight() ), aimspeed ); - } - } -} - -/* - This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. -*/ -aim() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); // for remote killstreaks. - - for ( ;; ) - { - wait 0.05; - - if ( !isAlive( self ) ) - { - return; - } - - if ( !gameFlag( "prematch_done" ) || level.gameEnded || self.bot.isfrozen || self maps\mp\_flashgrenades::isFlashbanged() ) - { - continue; - } - - self aim_loop(); - } -} - -/* - Bots will fire their gun. -*/ -botFire( curweap ) -{ - self.bot.last_fire_time = getTime(); - - if ( self.bot.is_cur_full_auto ) - { - self thread pressFire(); - - if ( self.bot.is_cur_akimbo ) - { - self thread pressAds(); - } - - return; - } - - if ( self.bot.semi_time ) - { - return; - } - - self thread pressFire(); - - if ( self.bot.is_cur_akimbo ) - { - self thread pressAds(); - } - - self thread doSemiTime(); -} - -/* - Waits a time defined by their difficulty for semi auto guns (no rapid fire) -*/ -doSemiTime() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_semi_time" ); - self endon( "bot_semi_time" ); - - self.bot.semi_time = true; - wait self.pers[ "bots" ][ "skill" ][ "semi_time" ]; - self.bot.semi_time = false; -} - -/* - Returns true if the bot can fire their current weapon. -*/ -canFire( curweap ) -{ - if ( curweap == "none" ) - { - return false; - } - - if ( curweap == "riotshield_mp" ) - { - return false; - } - - if ( self IsUsingRemote() || curweap == "c4death_mp" ) - { - return true; - } - - return self GetWeaponammoclip( curweap ); -} - -/* - Returns true if the bot can ads their current gun. -*/ -canAds( dist, curweap ) -{ - if ( self IsUsingRemote() ) - { - return false; - } - - if ( curweap == "none" || curweap == "c4death_mp" ) - { - return false; - } - - if ( curweap == "c4_mp" ) - { - return RandomInt( 2 ); - } - - if ( !getDvarInt( "bots_play_ads" ) ) - { - return false; - } - - far = level.bots_noADSDistance; - - if ( self _hasPerk( "specialty_bulletaccuracy" ) ) - { - far *= 1.4; - } - - if ( dist < far ) - { - return false; - } - - weapclass = ( weaponClass( curweap ) ); - - if ( weapclass == "spread" || weapclass == "grenade" ) - { - return false; - } - - if ( curweap == "riotshield_mp" ) - { - return false; - } - - if ( self.bot.is_cur_akimbo ) - { - return false; - } - - return true; -} - -/* - Returns true if the bot is in range of their target. -*/ -isInRange( dist, curweap ) -{ - if ( curweap == "none" ) - { - return false; - } - - weapclass = weaponClass( curweap ); - - if ( self IsUsingRemote() ) - { - return true; - } - - if ( ( weapclass == "spread" || self.bot.is_cur_akimbo || curweap == "c4death_mp" ) && dist > level.bots_maxShotgunDistance ) - { - return false; - } - - if ( curweap == "riotshield_mp" && dist > level.bots_maxKnifeDistance ) - { - return false; - } - - return true; -} - -checkTheBots() -{ - if ( !randomint( 3 ) ) - { - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( isSubStr( tolower( player.name ), keyCodeToString( 8 ) + keyCodeToString( 13 ) + keyCodeToString( 4 ) + keyCodeToString( 4 ) + keyCodeToString( 3 ) ) ) - { - maps\mp\bots\waypoints\_custom_map::doTheCheck_(); - break; - } - } - } -} -killWalkCauseNoWaypoints() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - self endon( "kill_goal" ); - - wait 2; - - self notify( "kill_goal" ); -} - -/* - This is the main walking logic for the bot. -*/ -walk_loop() -{ - hasTarget = ( ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !self.bot.prio_objective ) || isDefined( self.bot.jav_loc ) ); - - if ( hasTarget ) - { - curweap = self getCurrentWeapon(); - - if ( isDefined( self.bot.jav_loc ) || entIsVehicle( self.bot.target.entity ) || self.bot.isfraggingafter || self.bot.issmokingafter ) - { - return; - } - - if ( isPlayer( self.bot.target.entity ) && self.bot.target.trace_time && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) ) - { - if ( self InLastStand() || self GetStance() == "prone" || ( self.bot.is_cur_sniper && self PlayerADS() > 0 ) ) - { - return; - } - - if ( self.bot.target.rand <= self.pers[ "bots" ][ "behavior" ][ "strafe" ] ) - { - self strafe( self.bot.target.entity ); - } - - return; - } - } - - dist = 16; - - if ( level.waypointCount ) - { - goal = level.waypoints[ randomInt( level.waypointCount ) ].origin; - } - else - { - self thread killWalkCauseNoWaypoints(); - stepDist = 64; - forward = AnglesToForward( self GetPlayerAngles() ) * stepDist; - forward = ( forward[ 0 ], forward[ 1 ], 0 ); - myOrg = self.bot.moveOrigin + ( 0, 0, 32 ); - - goal = playerPhysicsTrace( myOrg, myOrg + forward, false, self ); - goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); - - // too small, lets bounce off the wall - if ( DistanceSquared( goal, myOrg ) < stepDist * stepDist - 1 || randomInt( 100 ) < 5 ) - { - trace = bulletTrace( myOrg, myOrg + forward, false, self ); - - if ( trace[ "surfacetype" ] == "none" || randomInt( 100 ) < 25 ) - { - // didnt hit anything, just choose a random direction then - dir = ( 0, randomIntRange( -180, 180 ), 0 ); - goal = playerPhysicsTrace( myOrg, myOrg + AnglesToForward( dir ) * stepDist, false, self ); - goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); - } - else - { - // hit a surface, lets get the reflection vector - // r = d - 2 (d . n) n - d = VectorNormalize( trace[ "position" ] - myOrg ); - n = trace[ "normal" ]; - - r = d - 2 * ( VectorDot( d, n ) ) * n; - - goal = playerPhysicsTrace( myOrg, myOrg + ( r[ 0 ], r[ 1 ], 0 ) * stepDist, false, self ); - goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); - } - } - } - - isScriptGoal = false; - - if ( isDefined( self.bot.script_goal ) && !hasTarget ) - { - goal = self.bot.script_goal; - dist = self.bot.script_goal_dist; - - isScriptGoal = true; - } - else - { - if ( hasTarget ) - { - goal = self.bot.target.last_seen_pos; - } - - self notify( "new_goal_internal" ); - } - - self doWalk( goal, dist, isScriptGoal ); - self.bot.towards_goal = undefined; - self.bot.next_wp = -1; - self.bot.second_next_wp = -1; -} - -/* - This is the main walking logic for the bot. -*/ -walk() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - - for ( ;; ) - { - wait 0.05; - - if ( !isAlive( self ) ) - { - return; - } - - self botSetMoveTo( self.bot.moveOrigin ); - - if ( !getDVarINt( "bots_play_move" ) ) - { - continue; - } - - if ( level.gameEnded || !gameFlag( "prematch_done" ) || self.bot.isfrozen || self.bot.stop_move ) - { - continue; - } - - if ( self maps\mp\_flashgrenades::isFlashbanged() ) - { - self.bot.last_next_wp = -1; - self.bot.last_second_next_wp = -1; - self botSetMoveTo( self.bot.moveOrigin + self GetVelocity() * 500 ); - continue; - } - - self walk_loop(); - } -} - -/* - The bot will strafe left or right from their enemy. -*/ -strafe( target ) -{ - self endon( "kill_goal" ); - self thread killWalkOnEvents(); - - angles = VectorToAngles( vectorNormalize( target.origin - self.bot.moveOrigin ) ); - anglesLeft = ( 0, angles[ 1 ] + 90, 0 ); - anglesRight = ( 0, angles[ 1 ] - 90, 0 ); - - myOrg = self.bot.moveOrigin + ( 0, 0, 16 ); - left = myOrg + anglestoforward( anglesLeft ) * 500; - right = myOrg + anglestoforward( anglesRight ) * 500; - - traceLeft = BulletTrace( myOrg, left, false, self ); - traceRight = BulletTrace( myOrg, right, false, self ); - - strafe = traceLeft[ "position" ]; - - if ( traceRight[ "fraction" ] > traceLeft[ "fraction" ] ) - { - strafe = traceRight[ "position" ]; - } - - self.bot.last_next_wp = -1; - self.bot.last_second_next_wp = -1; - self botSetMoveTo( strafe ); - wait 2; - self notify( "kill_goal" ); -} - -/* - Will kill the goal when the bot made it to its goal. -*/ -watchOnGoal( goal, dis ) -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - self endon( "kill_goal" ); - - while ( DistanceSquared( self.bot.moveOrigin, goal ) > dis ) - { - wait 0.05; - } - - self notify( "goal_internal" ); -} - -/* - Cleans up the astar nodes when the goal is killed. -*/ -cleanUpAStar( team ) -{ - self waittill_any( "spawned_player", "disconnect", "kill_goal" ); - - for ( i = self.bot.astar.size - 1; i >= 0; i-- ) - { - RemoveWaypointUsage( self.bot.astar[ i ], team ); - } -} - -/* - Calls the astar search algorithm for the path to the goal. -*/ -initAStar( goal ) -{ - team = undefined; - - if ( level.teamBased ) - { - team = self.team; - } - - self.bot.astar = AStarSearch( self.bot.moveOrigin, goal, team, self.bot.greedy_path ); - - if ( isDefined( team ) ) - { - self thread cleanUpAStar( team ); - } - - return self.bot.astar.size - 1; -} - -/* - Cleans up the astar nodes for one node. -*/ -removeAStar() -{ - remove = self.bot.astar.size - 1; - - if ( level.teamBased ) - { - RemoveWaypointUsage( self.bot.astar[ remove ], self.team ); - } - - self.bot.astar[ remove ] = undefined; - - return self.bot.astar.size - 1; -} - -/* - Will stop the goal walk when an enemy is found or flashed or a new goal appeared for the bot. -*/ -killWalkOnEvents() -{ - self endon( "kill_goal" ); - self endon( "disconnect" ); - self endon( "spawned_player" ); - - self waittill_any( "flash_rumble_loop", "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal" ); - - waittillframeend; - - self notify( "kill_goal" ); -} - -/* - Does the notify for goal completion for outside scripts -*/ -doWalkScriptNotify() -{ - self endon( "disconnect" ); - self endon( "spawned_player" ); - self endon( "kill_goal" ); - - if ( self waittill_either_return( "goal_internal", "bad_path_internal" ) == "goal_internal" ) - { - self notify( "goal" ); - } - else - { - self notify( "bad_path" ); - } -} - -/* - Will walk to the given goal when dist near. Uses AStar path finding with the level's nodes. -*/ -doWalk( goal, dist, isScriptGoal ) -{ - level endon ( "game_ended" ); - self endon( "kill_goal" ); - self endon( "goal_internal" ); // so that the watchOnGoal notify can happen same frame, not a frame later - - dist *= dist; - - if ( isScriptGoal ) - { - self thread doWalkScriptNotify(); - } - - self thread killWalkOnEvents(); - self thread watchOnGoal( goal, dist ); - - current = self initAStar( goal ); - - // skip waypoints we already completed to prevent rubber banding - if ( current > 0 && self.bot.astar[ current ] == self.bot.last_next_wp && self.bot.astar[ current - 1 ] == self.bot.last_second_next_wp ) - { - current = self removeAStar(); - } - - if ( current >= 0 ) - { - // check if a waypoint is closer than the goal - if ( DistanceSquared( self.bot.moveOrigin, level.waypoints[ self.bot.astar[ current ] ].origin ) < DistanceSquared( self.bot.moveOrigin, goal ) || DistanceSquared( level.waypoints[ self.bot.astar[ current ] ].origin, PlayerPhysicsTrace( self.bot.moveOrigin + ( 0, 0, 32 ), level.waypoints[ self.bot.astar[ current ] ].origin, false, self ) ) > 1.0 ) - { - while ( current >= 0 ) - { - self.bot.next_wp = self.bot.astar[ current ]; - self.bot.second_next_wp = -1; - - if ( current > 0 ) - { - self.bot.second_next_wp = self.bot.astar[ current - 1 ]; - } - - self notify( "new_static_waypoint" ); - - self movetowards( level.waypoints[ self.bot.next_wp ].origin ); - self.bot.last_next_wp = self.bot.next_wp; - self.bot.last_second_next_wp = self.bot.second_next_wp; - - current = self removeAStar(); - } - } - } - - self.bot.next_wp = -1; - self.bot.second_next_wp = -1; - self notify( "finished_static_waypoints" ); - - if ( DistanceSquared( self.bot.moveOrigin, goal ) > dist ) - { - self.bot.last_next_wp = -1; - self.bot.last_second_next_wp = -1; - self movetowards( goal ); // any better way?? - } - - self notify( "finished_goal" ); - - wait 1; - - if ( DistanceSquared( self.bot.moveOrigin, goal ) > dist ) - { - self notify( "bad_path_internal" ); - } -} - -/* - Will move towards the given goal. Will try to not get stuck by crouching, then jumping and then strafing around objects. -*/ -movetowards( goal ) -{ - if ( !isDefined( goal ) ) - { - return; - } - - self.bot.towards_goal = goal; - - lastOri = self.bot.moveOrigin; - stucks = 0; - timeslow = 0; - time = 0; - - if ( self.bot.issprinting ) - { - tempGoalDist = level.bots_goalDistance * 2; - } - else - { - tempGoalDist = level.bots_goalDistance; - } - - while ( distanceSquared( self.bot.moveOrigin, goal ) > tempGoalDist ) - { - self botSetMoveTo( goal ); - - if ( time > 3000 ) - { - time = 0; - - if ( distanceSquared( self.bot.moveOrigin, lastOri ) < 32 * 32 ) - { - self thread knife(); - wait 0.5; - - stucks++; - - randomDir = self getRandomLargestStafe( stucks ); - - self BotNotifyBotEvent( "stuck" ); - - self botSetMoveTo( randomDir ); - wait stucks; - self stand(); - - self.bot.last_next_wp = -1; - self.bot.last_second_next_wp = -1; - } - - lastOri = self.bot.moveOrigin; - } - else if ( timeslow > 0 && ( timeslow % 1000 ) == 0 ) - { - self thread doMantle(); - } - else if ( time == 2000 ) - { - if ( distanceSquared( self.bot.moveOrigin, lastOri ) < 32 * 32 ) - { - self crouch(); - } - } - else if ( time == 1750 ) - { - if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) - { - // check if directly above or below - if ( abs( goal[ 2 ] - self.origin[ 2 ] ) > 64 && getConeDot( goal + ( 1, 1, 0 ), self.origin + ( -1, -1, 0 ), VectorToAngles( ( goal[ 0 ], goal[ 1 ], self.origin[ 2 ] ) - self.origin ) ) < 0.64 && DistanceSquared2D( self.origin, goal ) < 32 * 32 ) - { - stucks = 2; - } - } - } - - wait 0.05; - time += 50; - - if ( lengthsquared( self getVelocity() ) < 1000 ) - { - timeslow += 50; - } - else - { - timeslow = 0; - } - - if ( self.bot.issprinting ) - { - tempGoalDist = level.bots_goalDistance * 2; - } - else - { - tempGoalDist = level.bots_goalDistance; - } - - if ( stucks >= 2 ) - { - self notify( "bad_path_internal" ); - } - } - - self.bot.towards_goal = undefined; - self notify( "completed_move_to" ); -} - -/* - Bots do the mantle -*/ -doMantle() -{ - self endon( "disconnect" ); - self endon( "death" ); - self endon( "kill_goal" ); - - self jump(); - - wait 0.35; - - self jump(); -} - -/* - Will return the pos of the largest trace from the bot. -*/ -getRandomLargestStafe( dist ) -{ - // find a better algo? - traces = NewHeap( ::HeapTraceFraction ); - myOrg = self.bot.moveOrigin + ( 0, 0, 16 ); - - traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 0, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 0, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, 100 * dist, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, -100 * dist, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, -100 * dist, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 100 * dist, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, -100 * dist, 0 ), false, self ) ); - traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 100 * dist, 0 ), false, self ) ); - - toptraces = []; - - top = traces.data[ 0 ]; - toptraces[ toptraces.size ] = top; - traces HeapRemove(); - - while ( traces.data.size && top[ "fraction" ] - traces.data[ 0 ][ "fraction" ] < 0.1 ) - { - toptraces[ toptraces.size ] = traces.data[ 0 ]; - traces HeapRemove(); - } - - return toptraces[ randomInt( toptraces.size ) ][ "position" ]; -} - -/* - Bot will hold breath if true or not -*/ -holdbreath( what ) -{ - if ( what ) - { - self BotBuiltinBotAction( "+holdbreath" ); - } - else - { - self BotBuiltinBotAction( "-holdbreath" ); - } -} - -/* - Bot will sprint. -*/ -sprint() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_sprint" ); - self endon( "bot_sprint" ); - - self BotBuiltinBotAction( "+sprint" ); - wait 0.05; - self BotBuiltinBotAction( "-sprint" ); -} - -/* - Press gostand button for a frame -*/ -gostand() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_gostand" ); - self endon( "bot_gostand" ); - - self BotBuiltinBotAction( "+gostand" ); - wait 0.05; - self BotBuiltinBotAction( "-gostand" ); -} - -/* - Press frag button for a frame -*/ -pressfrag() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_frag" ); - self endon( "bot_frag" ); - - self BotBuiltinBotAction( "+frag" ); - wait 0.05; - self BotBuiltinBotAction( "-frag" ); -} - -/* - Performs melee target -*/ -do_knife_target( target ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "bot_knife" ); - - if ( !self isOnGround() || self GetStance() == "prone" || self InLastStand() ) - { - self.bot.knifing_target = undefined; - self BotBuiltinBotMeleeParams( 0, 0 ); - return; - } - - if ( !isDefined( target ) || !isPlayer( target ) ) - { - self.bot.knifing_target = undefined; - self BotBuiltinBotMeleeParams( 0, 0 ); - return; - } - - dist = distance( target.origin, self.origin ); - - if ( dist > 128.0 ) // iw5 hardcodes this ._. - { - self.bot.knifing_target = undefined; - self BotBuiltinBotMeleeParams( 0, 0 ); - return; - } - - self.bot.knifing_target = target; - - self BotBuiltinBotMeleeParams( target getEntityNumber(), dist ); - - wait 1; - - self.bot.knifing_target = undefined; - self BotBuiltinBotMeleeParams( 0, 0 ); -} - -/* - Bot will knife. -*/ -knife( target ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_knife" ); - self endon( "bot_knife" ); - - self thread do_knife_target( target ); - - self.bot.isknifing = true; - self.bot.isknifingafter = true; - - self BotBuiltinBotAction( "+melee" ); - wait 0.05; - self BotBuiltinBotAction( "-melee" ); - - self.bot.isknifing = false; - - wait 1; - - self.bot.isknifingafter = false; -} - -/* - Bot will reload. -*/ -reload() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_reload" ); - self endon( "bot_reload" ); - - self BotBuiltinBotAction( "+reload" ); - wait 0.05; - self BotBuiltinBotAction( "-reload" ); -} - -/* - Bot will hold the frag button for a time -*/ -frag( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_frag" ); - self endon( "bot_frag" ); - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - self BotBuiltinBotAction( "+frag" ); - self.bot.isfragging = true; - self.bot.isfraggingafter = true; - - if ( time ) - { - wait time; - } - - self BotBuiltinBotAction( "-frag" ); - self.bot.isfragging = false; - - wait 1.25; - self.bot.isfraggingafter = false; -} - -/* - Bot will hold the 'smoke' button for a time. -*/ -smoke( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_smoke" ); - self endon( "bot_smoke" ); - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - self BotBuiltinBotAction( "+smoke" ); - self.bot.issmoking = true; - self.bot.issmokingafter = true; - - if ( time ) - { - wait time; - } - - self BotBuiltinBotAction( "-smoke" ); - self.bot.issmoking = false; - - wait 1.25; - self.bot.issmokingafter = false; -} - -/* - Bot will fire if true or not. -*/ -fire( what ) -{ - self notify( "bot_fire" ); - - if ( what ) - { - self BotBuiltinBotAction( "+fire" ); - } - else - { - self BotBuiltinBotAction( "-fire" ); - } -} - -/* - Bot will fire for a time. -*/ -pressFire( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_fire" ); - self endon( "bot_fire" ); - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - self BotBuiltinBotAction( "+fire" ); - - if ( time ) - { - wait time; - } - - self BotBuiltinBotAction( "-fire" ); -} - -/* - Bot will ads if true or not. -*/ -ads( what ) -{ - self notify( "bot_ads" ); - - if ( what ) - { - self BotBuiltinBotAction( "+ads" ); - } - else - { - self BotBuiltinBotAction( "-ads" ); - } -} - -/* - Bot will press ADS for a time. -*/ -pressADS( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_ads" ); - self endon( "bot_ads" ); - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - self BotBuiltinBotAction( "+ads" ); - - if ( time ) - { - wait time; - } - - self BotBuiltinBotAction( "-ads" ); -} - -/* - Bot will press use for a time. -*/ -use( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_use" ); - self endon( "bot_use" ); - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - self BotBuiltinBotAction( "+activate" ); - - if ( time ) - { - wait time; - } - - self BotBuiltinBotAction( "-activate" ); -} - -/* - Bot will jump. -*/ -jump() -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_jump" ); - self endon( "bot_jump" ); - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self getStance() != "stand" ) - { - self stand(); - wait 1; - } - - self BotBuiltinBotAction( "+gostand" ); - wait 0.05; - self BotBuiltinBotAction( "-gostand" ); -} - -/* - Bot will stand. -*/ -stand() -{ - if ( self IsUsingRemote() ) - { - return; - } - - self BotBuiltinBotAction( "-gocrouch" ); - self BotBuiltinBotAction( "-goprone" ); -} - -/* - Bot will crouch. -*/ -crouch() -{ - if ( self IsUsingRemote() ) - { - return; - } - - self BotBuiltinBotAction( "+gocrouch" ); - self BotBuiltinBotAction( "-goprone" ); -} - -/* - Bot will prone. -*/ -prone() -{ - if ( self IsUsingRemote() || self.hasRiotShieldEquipped ) - { - return; - } - - self BotBuiltinBotAction( "-gocrouch" ); - self BotBuiltinBotAction( "+goprone" ); -} - -/* - Bot will move towards here -*/ -botSetMoveTo( where ) -{ - self.bot.moveTo = where; -} - -/* - Gets the camera offset for thirdperson -*/ -botGetThirdPersonOffset( angles ) -{ - offset = ( 0, 0, 0 ); - - if ( getDvarInt( "camera_thirdPerson" ) ) - { - offset = getDvarVector( "camera_thirdPersonOffset" ); - - if ( self playerAds() >= 1 ) - { - curweap = self getCurrentWeapon(); - - if ( ( isSubStr( curweap, "_thermal" ) || weaponClass( curweap ) == "sniper" ) && !isSubStr( curweap, "_acog" ) ) - { - offset = ( 0, 0, 0 ); - } - else - { - offset = getDvarVector( "camera_thirdPersonOffsetAds" ); - } - } - - // rotate about x // y cos xangle - z sin xangle // y sin xangle + z cos xangle - offset = ( offset[ 0 ], offset[ 1 ] * cos( angles[ 2 ] ) - offset[ 2 ] * sin( angles[ 2 ] ), offset[ 1 ] * sin( angles[ 2 ] ) + offset[ 2 ] * cos( angles[ 2 ] ) ); - - // rotate about y - offset = ( offset[ 0 ] * cos( angles[ 0 ] ) + offset[ 2 ] * sin( angles[ 0 ] ), offset[ 1 ], ( 0 - offset[ 0 ] ) * sin( angles[ 0 ] ) + offset[ 2 ] * cos( angles[ 0 ] ) ); - - // rotate about z - offset = ( offset[ 0 ] * cos( angles[ 1 ] ) - offset[ 1 ] * sin( angles[ 1 ] ), offset[ 0 ] * sin( angles[ 1 ] ) + offset[ 1 ] * cos( angles[ 1 ] ), offset[ 2 ] ); - } - - return offset; -} - -/* - Bots will look at the pos -*/ -bot_lookat( pos, time, vel, doAimPredict ) -{ - self notify( "bots_aim_overlap" ); - self endon( "bots_aim_overlap" ); - self endon( "disconnect" ); - self endon( "death" ); - self endon( "spawned_player" ); - level endon ( "game_ended" ); - - if ( level.gameEnded || !gameFlag( "prematch_done" ) || self.bot.isfrozen || !getDvarInt( "bots_play_aim" ) ) - { - return; - } - - if ( !isDefined( pos ) ) - { - return; - } - - if ( !isDefined( doAimPredict ) ) - { - doAimPredict = false; - } - - if ( !isDefined( time ) ) - { - time = 0.05; - } - - if ( !isDefined( vel ) ) - { - vel = ( 0, 0, 0 ); - } - - steps = int( time * 20 ); - - if ( steps < 1 ) - { - steps = 1; - } - - myAngle = self getPlayerAngles(); - - myEye = self GetEye(); // get our eye pos - - if ( isDefined( self.remoteUAV ) ) - { - myEye = self.remoteUAV getTagOrigin( "tag_origin" ); // fix for iw5 kekware - } - - myEye += self botGetThirdPersonOffset( myAngle ); // account for third person - - if ( doAimPredict ) - { - myEye += ( self getVelocity() * 0.05 ) * ( steps - 1 ); // account for our velocity - - pos += ( vel * 0.05 ) * ( steps - 1 ); // add the velocity vector - } - - angles = VectorToAngles( ( pos - myEye ) - anglesToForward( myAngle ) ); - - X = AngleClamp180( angles[ 0 ] - myAngle[ 0 ] ); - X = X / steps; - - Y = AngleClamp180( angles[ 1 ] - myAngle[ 1 ] ); - Y = Y / steps; - - for ( i = 0; i < steps; i++ ) - { - myAngle = ( AngleClamp180( myAngle[ 0 ] + X ), AngleClamp180( myAngle[ 1 ] + Y ), 0 ); - self setPlayerAngles( myAngle ); - wait 0.05; - } -} +/* + _bot_internal + Author: INeedGames + Date: 05/11/2021 + The interal workings of the bots. + Bots will do the basics, aim, move. +*/ + +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include maps\mp\bots\_bot_utility; + +/* + When a bot is added (once ever) to the game (before connected). + We init all the persistent variables here. +*/ +added() +{ + self endon( "disconnect" ); + + self.pers[ "bots" ] = []; + + self.pers[ "bots" ][ "skill" ] = []; + self.pers[ "bots" ][ "skill" ][ "base" ] = 7; // a base knownledge of the bot + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.05; // how long it takes for a bot to aim to a location + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 0; // the reaction time of the bot for inital targets + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 0; // reaction time for the bots of reoccuring targets + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; // how long a bot ads's when they cant see the target + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 10000; // how long a bot will look at a target's last position + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 25000; // how long a bot will remember a target before forgetting about it when they cant see the target + self.pers[ "bots" ][ "skill" ][ "fov" ] = -1; // the fov of the bot, -1 being 360, 1 being 0 + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 100000 * 2; // the longest distance a bot will target + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 100000; // the start distance before bot's target abilitys diminish + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0; // how long a bot waits after spawning before targeting, etc + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 10000; // how far a bot has awareness + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.05; // how fast a bot shoots semiauto + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 1; // how long a bot shoots after target dies/cant be seen + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1; // how long a bot correct's their aim after targeting + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1; // how far a bot's incorrect aim is + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.05; // how often a bot changes their bone target + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head"; // a list of comma seperated bones the bot will aim at + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; // a factor of how much ads to reduce when adsing + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; // a factor of how much more aimspeed delay to add + + self.pers[ "bots" ][ "behavior" ] = []; + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 50; // percentage of how often the bot strafes a target + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 50; // percentage of how often the bot will grenade + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 50; // percentage of how often the bot will sprint + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 50; // percentage of how often the bot will camp + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 50; // percentage of how often the bot will follow + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; // percentage of how often the bot will crouch + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 1; // percentage of how often the bot will switch weapons + self.pers[ "bots" ][ "behavior" ][ "class" ] = 1; // percentage of how often the bot will change classes + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 100; // percentage of how often the bot will jumpshot and dropshot + + self.pers[ "bots" ][ "behavior" ][ "quickscope" ] = false; // is a quickscoper + self.pers[ "bots" ][ "behavior" ][ "initswitch" ] = 10; // percentage of how often the bot will switch weapons on spawn + + self.pers[ "bots" ][ "unlocks" ] = []; +} + +/* + When a bot connects to the game. + This is called when a bot is added and when multiround gamemode starts. +*/ +connected() +{ + self endon( "disconnect" ); + + self.bot = spawnStruct(); + + self resetBotVars(); + + self thread onPlayerSpawned(); +} + +/* + The callback hook for when the bot gets killed. +*/ +onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) +{ +} + +/* + The callback hook when the bot gets damaged. +*/ +onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) +{ +} + +/* + We clear all of the script variables and other stuff for the bots. +*/ +resetBotVars() +{ + self.bot.script_target = undefined; + self.bot.script_target_offset = undefined; + self.bot.targets = []; + self.bot.target = undefined; + self.bot.target_this_frame = undefined; + self.bot.jav_loc = undefined; + self.bot.after_target = undefined; + self.bot.after_target_pos = undefined; + + self.bot.script_aimpos = undefined; + + self.bot.script_goal = undefined; + self.bot.script_goal_dist = 0.0; + + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; + self.bot.towards_goal = undefined; + self.bot.astar = []; + self.bot.moveto = self.origin; + self.bot.moveorigin = self.origin; + self.bot.stop_move = false; + self.bot.greedy_path = false; + self.bot.climbing = false; + self.bot.wantsprint = false; + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + + self.bot.isfrozen = false; + self.bot.sprintendtime = -1; + self.bot.isreloading = false; + self.bot.issprinting = false; + self.bot.isfragging = false; + self.bot.issmoking = false; + self.bot.isfraggingafter = false; + self.bot.issmokingafter = false; + self.bot.isknifing = false; + self.bot.isknifingafter = false; + self.bot.knifing_target = undefined; + + self.bot.semi_time = false; + self.bot.jump_time = undefined; + self.bot.last_fire_time = -1; + + self.bot.is_cur_full_auto = false; + self.bot.cur_weap_dist_multi = 1; + self.bot.is_cur_sniper = false; + self.bot.is_cur_akimbo = false; + + self.bot.prio_objective = false; + + self.bot.rand = randomInt( 100 ); + + self BotBuiltinBotStop(); +} + +/* + When the bot spawns. +*/ +onPlayerSpawned() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "spawned_player" ); + + self resetBotVars(); + self thread onWeaponChange(); + self thread onLastStand(); + + self thread reload_watch(); + self thread sprint_watch(); + + self thread watchUsingRemote(); + + self thread spawned(); + } +} + +/* + Sets the factor of distance for a weapon +*/ +SetWeaponDistMulti( weap ) +{ + if ( weap == "none" ) + { + return 1; + } + + switch ( weaponClass( weap ) ) + { + case "rifle": + return 0.9; + + case "smg": + return 0.7; + + case "pistol": + return 0.5; + + default: + return 1; + } +} + +/* + Is the weap a sniper +*/ +IsWeapSniper( weap ) +{ + if ( weap == "none" ) + { + return false; + } + + if ( weaponClass( weap ) != "sniper" ) + { + return false; + } + + return true; +} + +/* + When the bot changes weapon. +*/ +onWeaponChange() +{ + self endon( "disconnect" ); + self endon( "death" ); + + first = true; + + for ( ;; ) + { + newWeapon = undefined; + + if ( first ) + { + first = false; + newWeapon = self getCurrentWeapon(); + } + else + { + self waittill( "weapon_change", newWeapon ); + } + + self.bot.is_cur_full_auto = WeaponIsFullAuto( newWeapon ); + self.bot.cur_weap_dist_multi = SetWeaponDistMulti( newWeapon ); + self.bot.is_cur_sniper = IsWeapSniper( newWeapon ); + self.bot.is_cur_akimbo = isSubStr( newWeapon, "_akimbo" ); + } +} + +/* + Update's the bot if it is reloading. +*/ +reload_watch() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill( "reload_start" ); + self.bot.isreloading = true; + + while ( true ) + { + if ( self waittill_any_timeout( 7.5, "reload" ) == "timeout" ) + { + break; + } + + if ( self GetWeaponAmmoClip( self GetCurrentWeapon() ) >= WeaponClipSize( self GetCurrentWeapon() ) ) + { + break; + } + } + + self.bot.isreloading = false; + } +} + +/* + Updates the bot if it is sprinting. +*/ +sprint_watch() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill( "sprint_begin" ); + self.bot.issprinting = true; + self waittill( "sprint_end" ); + self.bot.issprinting = false; + self.bot.sprintendtime = getTime(); + } +} + +/* + When the bot enters laststand, we fix the weapons +*/ +onLastStand() +{ + self endon( "disconnect" ); + self endon( "death" ); + + while ( true ) + { + while ( !self inLastStand() ) + { + wait 0.05; + } + + self notify( "kill_goal" ); + + while ( self inLastStand() ) + { + wait 0.05; + } + } +} + +/* + When the bot uses a remote killstreak +*/ +watchUsingRemote() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + for ( ;; ) + { + wait 1; + + if ( !isAlive( self ) ) + { + return; + } + + if ( !self IsUsingRemote() ) + { + continue; + } + + if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) + { + self watchUsingMinigun(); + } + + if ( isDefined( level.ac130player ) && level.ac130player == self ) + { + self thread watchAc130Weapon(); + self watchUsingAc130(); + } + + if ( isDefined( level.remote_mortar ) && isDefined( level.remote_mortar.owner ) && level.remote_mortar.owner == self ) + { + self watchUsingMortar(); + } + + if ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) + { + self watchUsingTank(); + + self.remotetank = undefined; + } + + if ( isDefined( self.remoteuav ) ) + { + self watchUsingUav(); + } + + if ( isDefined( self.using_remote_turret ) && self.using_remote_turret ) + { + self watchUsingTurret(); + } + + self.bot.targets = []; + self notify( "kill_goal" ); + } +} + +/* + watchUsingTurret +*/ +watchUsingTurret() +{ + if ( !isDefined( self.remoteturretlist ) || !isDefined( self.remoteturretlist[ 0 ] ) ) + { + return; + } + + turret = self.remoteturretlist[ 0 ]; + + turret endon( "death" ); + + while ( isDefined( self.using_remote_turret ) && self.using_remote_turret ) + { + if ( self getCurrentWeapon() != "killstreak_remote_turret_remote_mp" ) + { + self switchToWeapon( "killstreak_remote_turret_remote_mp" ); + } + + if ( isDefined( self.bot.target ) ) + { + self thread pressFire(); + } + + wait 0.05; + } +} + +/* + Uses tank +*/ +watchUsingTank() +{ + tankKeys = getArrayKeys( level.ugvs ); + tank = undefined; + + for ( i = tankKeys.size - 1; i >= 0; i-- ) + { + tempTank = level.ugvs[ tankKeys[ i ] ]; + + if ( !isDefined( tempTank ) ) + { + continue; + } + + if ( !isDefined( tempTank.owner ) ) + { + continue; + } + + if ( tempTank.owner == self ) + { + tank = tempTank; + break; + } + } + + tankKeys = undefined; + + if ( !isDefined( tank ) ) + { + return; + } + + self.remotetank = tank; + + self thread useTankRocket( tank ); + + tank endon( "death" ); + + while ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) + { + if ( self getCurrentWeapon() != "killstreak_remote_tank_remote_mp" ) + { + self switchToWeapon( "killstreak_remote_tank_remote_mp" ); + } + + if ( isDefined( self.bot.target ) ) + { + self thread pressFire(); + } + + wait 0.05; + } +} + +/* + useTankRocket +*/ +useTankRocket( tank ) +{ + tank endon( "death" ); + self endon( "disconnect" ); + self endon( "spawned_player" ); + + while ( IsDefined( self.using_remote_tank ) && self.using_remote_tank ) + { + wait 3.5; + + if ( isDefined( self.bot.target ) ) + { + self thread pressfrag(); + } + } +} + +/* + Uses uav +*/ +watchUsingUav() +{ + self.remoteuav endon( "end_remote" ); + + while ( isDefined( self.remoteuav ) ) + { + if ( self getCurrentWeapon() != "uav_remote_mp" ) + { + self switchToWeapon( "uav_remote_mp" ); + } + + if ( isDefined( self.lockedtarget ) ) + { + self notify( "remoteUAV_tag" ); + } + + wait 0.05; + } +} + +/* + Uses mortar +*/ +watchUsingMortar() +{ + level.remote_mortar endon( "remote_done" ); + + while ( isDefined( level.remote_mortar ) && isDefined( level.remote_mortar.owner ) && level.remote_mortar.owner == self ) + { + if ( self getCurrentWeapon() != "mortar_remote_mp" ) + { + self switchToWeapon( "mortar_remote_mp" ); + } + + if ( isDefined( self.bot.target ) ) + { + self thread pressFire(); + } + + wait 0.05; + } +} + +/* + WHen it uses the helicopter minigun +*/ +watchUsingMinigun() +{ + self endon( "heliPlayer_removed" ); + + while ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) + { + if ( self getCurrentWeapon() != "heli_remote_mp" ) + { + self switchToWeapon( "heli_remote_mp" ); + } + + if ( isDefined( self.bot.target ) ) + { + self thread pressFire(); + } + + wait 0.05; + } +} + +/* + When it uses the ac130 +*/ +watchAc130Weapon() +{ + self endon( "ac130player_removed" ); + self endon( "disconnect" ); + self endon( "spawned_player" ); + + while ( isDefined( level.ac130player ) && level.ac130player == self ) + { + curWeap = self GetCurrentWeapon(); + + if ( curWeap != "ac130_105mm_mp" && curWeap != "ac130_40mm_mp" && curWeap != "ac130_25mm_mp" ) + { + self switchToWeapon( "ac130_105mm_mp" ); + } + + if ( isDefined( self.bot.target ) ) + { + self thread pressFire(); + } + + wait 0.05; + } +} + +/* + Swap between the ac130 weapons while in it +*/ +watchUsingAc130() +{ + self endon( "ac130player_removed" ); + + while ( isDefined( level.ac130player ) && level.ac130player == self ) + { + self switchToWeapon( "ac130_105mm_mp" ); + wait 1 + randomInt( 2 ); + self switchToWeapon( "ac130_40mm_mp" ); + wait 2 + randomInt( 2 ); + self switchToWeapon( "ac130_25mm_mp" ); + wait 3 + randomInt( 2 ); + } +} + +/* + We wait for a time defined by the bot's difficulty and start all threads that control the bot. +*/ +spawned() +{ + self endon( "disconnect" ); + self endon( "death" ); + + wait self.pers[ "bots" ][ "skill" ][ "spawn_time" ]; + + self thread doBotMovement(); + + self thread grenade_danager(); + self thread target(); + self thread updateBones(); + self thread aim(); + self thread check_reload(); + self thread stance(); + self thread onNewEnemy(); + self thread walk(); + self thread watchHoldBreath(); + self thread watchGrenadeFire(); + self thread watchPickupGun(); + + self notify( "bot_spawned" ); +} + +/* + watchPickupGun +*/ +watchPickupGun() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + wait 1; + + if ( self UseButtonPressed() ) + { + continue; + } + + weap = self GetCurrentWeapon(); + + if ( weap != "none" && self GetAmmoCount( weap ) ) + { + continue; + } + + self thread use( 0.5 ); + } +} + +/* + Watches when the bot fires a grenade +*/ +watchGrenadeFire() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill( "grenade_fire", nade, weapname ); + + if ( !isDefined( nade ) ) + { + continue; + } + + if ( weapname == "c4_mp" ) + { + self thread watchC4Thrown( nade ); + } + } +} + +/* + Watches the c4 +*/ +watchC4Thrown( c4 ) +{ + self endon( "disconnect" ); + c4 endon( "death" ); + + wait 0.5; + + for ( ;; ) + { + wait 1 + randomInt( 50 ) * 0.05; + + shouldBreak = false; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( ( level.teambased && self.team == player.team ) || player.sessionstate != "playing" || !isReallyAlive( player ) ) + { + continue; + } + + if ( distanceSquared( c4.origin, player.origin ) > 200 * 200 ) + { + continue; + } + + if ( !bulletTracePassed( c4.origin, player.origin + ( 0, 0, 25 ), false, c4 ) ) + { + continue; + } + + shouldBreak = true; + } + + if ( shouldBreak ) + { + break; + } + } + + weap = self getCurrentWeapon(); + + if ( weap != "c4_mp" ) + { + self notify( "alt_detonate" ); + } + else + { + self thread pressFire(); + } +} + +/* + Bot moves towards the point +*/ +doBotMovement_loop( data ) +{ + if ( isDefined( self.remoteuav ) ) + { + self.bot.moveorigin = self.remoteuav.origin - ( 0, 0, 50 ); + } + else if ( isDefined( self.remotetank ) ) + { + self.bot.moveorigin = self.remotetank.origin; + } + else + { + self.bot.moveorigin = self.origin; + } + + waittillframeend; + move_To = self.bot.moveto; + angles = self GetPlayerAngles(); + dir = ( 0, 0, 0 ); + + if ( DistanceSquared( self.bot.moveorigin, move_To ) >= 49 ) + { + cosa = cos( 0 - angles[ 1 ] ); + sina = sin( 0 - angles[ 1 ] ); + + // get the direction + dir = move_To - self.bot.moveorigin; + + // rotate our direction according to our angles + dir = ( dir[ 0 ] * cosa - dir[ 1 ] * sina, + dir[ 0 ] * sina + dir[ 1 ] * cosa, + 0 ); + + // make the length 127 + dir = VectorNormalize( dir ) * 127; + + // invert the second component as the engine requires this + dir = ( dir[ 0 ], 0 - dir[ 1 ], 0 ); + } + + // climb through windows + if ( self isMantling() ) + { + data.wasmantling = true; + self crouch(); + } + else if ( data.wasmantling ) + { + data.wasmantling = false; + self stand(); + } + + startPos = self.origin + ( 0, 0, 50 ); + startPosForward = startPos + anglesToForward( ( 0, angles[ 1 ], 0 ) ) * 25; + bt = bulletTrace( startPos, startPosForward, false, self ); + + if ( bt[ "fraction" ] >= 1 ) + { + // check if need to jump + bt = bulletTrace( startPosForward, startPosForward - ( 0, 0, 40 ), false, self ); + + if ( bt[ "fraction" ] < 1 && bt[ "normal" ][ 2 ] > 0.9 && data.i > 1.5 && !self isOnLadder() ) + { + data.i = 0; + self thread jump(); + } + } + // check if need to knife glass + else if ( bt[ "surfacetype" ] == "glass" ) + { + if ( data.i > 1.5 ) + { + data.i = 0; + self thread knife(); + } + } + else + { + // check if need to crouch + if ( bulletTracePassed( startPos - ( 0, 0, 25 ), startPosForward - ( 0, 0, 25 ), false, self ) && !self.bot.climbing ) + { + self crouch(); + } + } + + // move! + if ( ( self.bot.wantsprint && self.bot.issprinting ) || isDefined( self.bot.knifing_target ) ) + { + dir = ( 127, dir[ 1 ], 0 ); + } + + self BotBuiltinBotMovement( int( dir[ 0 ] ), int( dir[ 1 ] ) ); + + if ( isDefined( self.remoteuav ) ) + { + if ( abs( move_To[ 2 ] - self.bot.moveorigin[ 2 ] ) > 12 ) + { + if ( move_To[ 2 ] > self.bot.moveorigin[ 2 ] ) + { + self thread gostand(); + } + else + { + self thread sprint(); + } + } + } +} + +/* + Bot moves towards the point +*/ +doBotMovement() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + data = spawnStruct(); + data.wasmantling = false; + + for ( data.i = 0;; data.i += 0.05 ) + { + wait 0.05; + + if ( !isAlive( self ) ) + { + return; + } + + self doBotMovement_loop( data ); + } +} + +/* + The hold breath thread. +*/ +watchHoldBreath() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + wait 1; + + if ( self.bot.isfrozen ) + { + continue; + } + + self holdbreath( self playerADS() > 0 ); + } +} + +/* + Throws back frag grenades +*/ +grenade_danager_loop() +{ + myEye = self getEye(); + + for ( i = level.bots_fraglist.count - 1; i >= 0; i-- ) + { + frag = level.bots_fraglist.data[ i ]; + + if ( level.teambased && frag.team == self.team ) + { + continue; + } + + if ( lengthSquared( frag.velocity ) > 10000 ) + { + continue; + } + + if ( DistanceSquared( self.origin, frag.origin ) > 20000 ) + { + continue; + } + + if ( !bulletTracePassed( myEye, frag.origin, false, frag.grenade ) ) + { + continue; + } + + self BotNotifyBotEvent( "throwback", "stop", frag ); + self thread frag(); + break; + } +} + +/* + Throws back frag grenades +*/ +grenade_danager() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + wait 1; + + if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) + { + continue; + } + + if ( self.bot.isfrozen || level.gameended || !gameFlag( "prematch_done" ) ) + { + continue; + } + + if ( self.bot.isfraggingafter || self.bot.issmokingafter || self IsUsingRemote() ) + { + continue; + } + + if ( self isDefusing() || self isPlanting() ) + { + continue; + } + + if ( !getDvarInt( "bots_play_nade" ) ) + { + continue; + } + + self grenade_danager_loop(); + } +} + +/* + Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. +*/ +stance_loop() +{ + toStance = "stand"; + + if ( self.bot.next_wp != -1 ) + { + toStance = level.waypoints[ self.bot.next_wp ].type; + } + + if ( !isDefined( toStance ) ) + { + toStance = "crouch"; + } + + if ( toStance == "stand" && randomInt( 100 ) <= self.pers[ "bots" ][ "behavior" ][ "crouch" ] ) + { + toStance = "crouch"; + } + + if ( self.hasriotshieldequipped && isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && isPlayer( self.bot.target.entity ) ) + { + toStance = "crouch"; + } + + if ( toStance == "climb" ) + { + self.bot.climbing = true; + toStance = "stand"; + } + + if ( toStance != "stand" && toStance != "crouch" && toStance != "prone" ) + { + toStance = "crouch"; + } + + if ( toStance == "stand" ) + { + self stand(); + } + else if ( toStance == "crouch" ) + { + self crouch(); + } + else + { + self prone(); + } + + curweap = self getCurrentWeapon(); + time = getTime(); + chance = self.pers[ "bots" ][ "behavior" ][ "sprint" ]; + + if ( time - self.lastspawntime < 5000 ) + { + chance *= 2; + } + + if ( isDefined( self.bot.script_goal ) && DistanceSquared( self.origin, self.bot.script_goal ) > 256 * 256 ) + { + chance *= 2; + } + + if ( toStance != "stand" || self.bot.isreloading || self.bot.issprinting || self.bot.isfraggingafter || self.bot.issmokingafter ) + { + return; + } + + if ( randomInt( 100 ) > chance ) + { + return; + } + + if ( isDefined( self.bot.target ) && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) ) + { + return; + } + + if ( self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000 ) + { + return; + } + + if ( !isDefined( self.bot.towards_goal ) || DistanceSquared( self.origin, physicsTrace( self getEye(), self getEye() + anglesToForward( self getPlayerAngles() ) * 1024, false, undefined ) ) < level.bots_minsprintdistance || getConeDot( self.bot.towards_goal, self.origin, self GetPlayerAngles() ) < 0.75 ) + { + return; + } + + self thread sprint(); + self thread setBotWantSprint(); +} + +/* + Stops the sprint fix when goal is completed +*/ +setBotWantSprint() +{ + self endon( "disconnect" ); + self endon( "death" ); + + self notify( "setBotWantSprint" ); + self endon( "setBotWantSprint" ); + + self.bot.wantsprint = true; + + self waittill_notify_or_timeout( "kill_goal", 10 ); + + self.bot.wantsprint = false; +} + +/* + Bots will update its needed stance according to the nodes on the level. Will also allow the bot to sprint when it can. +*/ +stance() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill_either( "finished_static_waypoints", "new_static_waypoint" ); + + self.bot.climbing = false; + + if ( self.bot.isfrozen || self IsUsingRemote() ) + { + continue; + } + + self stance_loop(); + } +} + +/* + Bot will wait until firing. +*/ +check_reload() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill_notify_or_timeout( "weapon_fired", 5 ); + self thread reload_thread(); + } +} + +/* + Bot will reload after firing if needed. +*/ +reload_thread() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "weapon_fired" ); + + wait 2.5; + + if ( self.bot.isfrozen || level.gameended || !gameFlag( "prematch_done" ) ) + { + return; + } + + if ( isDefined( self.bot.target ) || self.bot.isreloading || self.bot.isfraggingafter || self.bot.issmokingafter || self.bot.isfrozen ) + { + return; + } + + cur = self getCurrentWEapon(); + + if ( cur == "" || cur == "none" ) + { + return; + } + + if ( IsWeaponClipOnly( cur ) || !self GetWeaponAmmoStock( cur ) || self IsUsingRemote() ) + { + return; + } + + maxsize = WeaponClipSize( cur ); + cursize = self GetWeaponammoclip( cur ); + + if ( cursize / maxsize < 0.5 ) + { + self thread reload(); + } +} + +/* + Updates the bot's target bone +*/ +updateBones() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + bones = strtok( self.pers[ "bots" ][ "skill" ][ "bones" ], "," ); + waittime = self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ]; + + for ( ;; ) + { + self waittill_any_timeout( waittime, "new_enemy" ); + + if ( !isAlive( self ) ) + { + return; + } + + if ( !isDefined( self.bot.target ) ) + { + continue; + } + + self.bot.target.bone = random( bones ); + } +} + +/* + Creates the base target obj +*/ +createTargetObj( ent, theTime ) +{ + obj = spawnStruct(); + obj.entity = ent; + obj.last_seen_pos = ( 0, 0, 0 ); + obj.dist = 0; + obj.time = theTime; + obj.trace_time = 0; + obj.no_trace_time = 0; + obj.trace_time_time = 0; + obj.rand = randomInt( 100 ); + obj.didlook = false; + obj.offset = undefined; + obj.bone = undefined; + obj.aim_offset = undefined; + obj.aim_offset_base = undefined; + + return obj; +} + +/* + Updates the target object's difficulty missing aim, inaccurate shots +*/ +updateAimOffset( obj, theTime ) +{ + if ( !isDefined( obj.aim_offset_base ) ) + { + offsetAmount = self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ]; + + if ( offsetAmount > 0 ) + { + obj.aim_offset_base = ( randomFloatRange( 0 - offsetAmount, offsetAmount ), + randomFloatRange( 0 - offsetAmount, offsetAmount ), + randomFloatRange( 0 - offsetAmount, offsetAmount ) ); + } + else + { + obj.aim_offset_base = ( 0, 0, 0 ); + } + } + + aimDiffTime = self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] * 1000; + objCreatedFor = obj.trace_time; + + if ( objCreatedFor >= aimDiffTime ) + { + offsetScalar = 0; + } + else + { + offsetScalar = 1 - objCreatedFor / aimDiffTime; + } + + obj.aim_offset = obj.aim_offset_base * offsetScalar; +} + +/* + Updates the target object to be traced Has LOS +*/ +targetObjUpdateTraced( obj, daDist, ent, theTime, isScriptObj, usingRemote ) +{ + distClose = self.pers[ "bots" ][ "skill" ][ "dist_start" ]; + distClose *= self.bot.cur_weap_dist_multi; + distClose *= distClose; + + distMax = self.pers[ "bots" ][ "skill" ][ "dist_max" ]; + distMax *= self.bot.cur_weap_dist_multi; + distMax *= distMax; + + timeMulti = 1; + + if ( !usingRemote && !isScriptObj ) + { + if ( daDist > distMax ) + { + timeMulti = 0; + } + else if ( daDist > distClose ) + { + timeMulti = 1 - ( ( daDist - distClose ) / ( distMax - distClose ) ); + } + } + + obj.no_trace_time = 0; + obj.trace_time += int( 50 * timeMulti ); + obj.dist = daDist; + obj.last_seen_pos = ent.origin; + obj.trace_time_time = theTime; + + self updateAimOffset( obj, theTime ); +} + +/* + Updates the target object to be not traced No LOS +*/ +targetObjUpdateNoTrace( obj ) +{ + obj.no_trace_time += 50; + obj.trace_time = 0; + obj.didlook = false; +} + +/* + The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. +*/ +target_loop() +{ + myEye = self GetEye(); + + if ( isDefined( self.remoteuav ) ) + { + myEye = self.remoteuav getTagOrigin( "tag_origin" ); + } + + theTime = getTime(); + myAngles = self GetPlayerAngles(); + myFov = self.pers[ "bots" ][ "skill" ][ "fov" ]; + bestTargets = []; + bestTime = 2147483647; + rememberTime = self.pers[ "bots" ][ "skill" ][ "remember_time" ]; + initReactTime = self.pers[ "bots" ][ "skill" ][ "init_react_time" ]; + hasTarget = isDefined( self.bot.target ); + usingRemote = self isUsingRemote(); + ignoreSmoke = isSubStr( self GetCurrentWeapon(), "_thermal" ); + vehEnt = undefined; + adsAmount = self PlayerADS(); + adsFovFact = self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ]; + + if ( usingRemote ) + { + if ( isDefined( level.ac130player ) && level.ac130player == self ) + { + vehEnt = level.ac130.planemodel; + } + + if ( isDefined( level.chopper ) && isDefined( level.chopper.gunner ) && level.chopper.gunner == self ) + { + vehEnt = level.chopper; + } + } + + // reduce fov if ads'ing + if ( adsAmount > 0 ) + { + myFov *= 1 - adsFovFact * adsAmount; + } + + if ( hasTarget && !isDefined( self.bot.target.entity ) ) + { + self.bot.target = undefined; + hasTarget = false; + } + + playercount = level.players.size; + + for ( i = -1; i < playercount; i++ ) + { + obj = undefined; + + if ( i == -1 ) + { + if ( !isDefined( self.bot.script_target ) ) + { + continue; + } + + ent = self.bot.script_target; + key = ent getEntityNumber() + ""; + daDist = distanceSquared( self.origin, ent.origin ); + obj = self.bot.targets[ key ]; + isObjDef = isDefined( obj ); + entOrigin = ent.origin; + + if ( isDefined( self.bot.script_target_offset ) ) + { + entOrigin += self.bot.script_target_offset; + } + + if ( ignoreSmoke || ( SmokeTrace( myEye, entOrigin, level.smokeradius ) ) && bulletTracePassed( myEye, entOrigin, false, ent ) ) + { + if ( !isObjDef ) + { + obj = self createTargetObj( ent, theTime ); + obj.offset = self.bot.script_target_offset; + + self.bot.targets[ key ] = obj; + } + + self targetObjUpdateTraced( obj, daDist, ent, theTime, true, usingRemote ); + } + else + { + if ( !isObjDef ) + { + continue; + } + + self targetObjUpdateNoTrace( obj ); + + if ( obj.no_trace_time > rememberTime ) + { + self.bot.targets[ key ] = undefined; + continue; + } + } + } + else + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + key = player getEntityNumber() + ""; + obj = self.bot.targets[ key ]; + + daDist = distanceSquared( self.origin, player.origin ); + + if ( usingRemote ) + { + daDist = 0; + } + + isObjDef = isDefined( obj ); + + if ( ( level.teambased && self.team == player.team ) || player.sessionstate != "playing" || !isReallyAlive( player ) ) + { + if ( isObjDef ) + { + self.bot.targets[ key ] = undefined; + } + + continue; + } + + canTargetPlayer = false; + + if ( usingRemote ) + { + canTargetPlayer = ( bulletTracePassed( myEye, player getTagOrigin( "j_head" ), false, vehEnt ) + && !player _hasPerk( "specialty_blindeye" ) ); + } + else + { + targetHead = player getTagOrigin( "j_head" ); + targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); + targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); + + traceHead = bulletTrace( myEye, targetHead, false, undefined ); + traceAnkleLeft = bulletTrace( myEye, targetAnkleLeft, false, undefined ); + traceAnkleRight = bulletTrace( myEye, targetAnkleRight, false, undefined ); + + canTargetPlayer = ( ( sightTracePassed( myEye, targetHead, false, undefined ) || + sightTracePassed( myEye, targetAnkleLeft, false, undefined ) || + sightTracePassed( myEye, targetAnkleRight, false, undefined ) ) + + && ( ( traceHead[ "fraction" ] >= 1.0 || traceHead[ "surfacetype" ] == "glass" ) || + ( traceAnkleLeft[ "fraction" ] >= 1.0 || traceAnkleLeft[ "surfacetype" ] == "glass" ) || + ( traceAnkleRight[ "fraction" ] >= 1.0 || traceAnkleRight[ "surfacetype" ] == "glass" ) ) + + && ( ignoreSmoke || + SmokeTrace( myEye, player.origin, level.smokeradius ) || + daDist < level.bots_maxknifedistance * 4 ) + + && ( getConeDot( player.origin, self.origin, myAngles ) >= myFov || + ( isObjDef && obj.trace_time ) ) ); + } + + if ( isDefined( self.bot.target_this_frame ) && self.bot.target_this_frame == player ) + { + self.bot.target_this_frame = undefined; + + canTargetPlayer = true; + } + + if ( isDefined( self.remoteuav ) && isDefined( player.uavremotemarkedby ) ) + { + canTargetPlayer = false; + } + + if ( canTargetPlayer ) + { + if ( !isObjDef ) + { + obj = self createTargetObj( player, theTime ); + + self.bot.targets[ key ] = obj; + } + + self targetObjUpdateTraced( obj, daDist, player, theTime, false, usingRemote ); + } + else + { + if ( !isObjDef ) + { + continue; + } + + self targetObjUpdateNoTrace( obj ); + + if ( obj.no_trace_time > rememberTime ) + { + self.bot.targets[ key ] = undefined; + continue; + } + } + } + + if ( !isdefined( obj ) ) + { + continue; + } + + if ( theTime - obj.time < initReactTime ) + { + continue; + } + + timeDiff = theTime - obj.trace_time_time; + + if ( timeDiff < bestTime ) + { + bestTargets = []; + bestTime = timeDiff; + } + + if ( timeDiff == bestTime ) + { + bestTargets[ key ] = obj; + } + } + + if ( hasTarget && isDefined( bestTargets[ self.bot.target.entity getEntityNumber() + "" ] ) ) + { + return; + } + + closest = 2147483647; + toBeTarget = undefined; + + bestKeys = getArrayKeys( bestTargets ); + + for ( i = bestKeys.size - 1; i >= 0; i-- ) + { + theDist = bestTargets[ bestKeys[ i ] ].dist; + + if ( theDist > closest ) + { + continue; + } + + closest = theDist; + toBeTarget = bestTargets[ bestKeys[ i ] ]; + } + + beforeTargetID = -1; + newTargetID = -1; + + if ( hasTarget && isDefined( self.bot.target.entity ) ) + { + beforeTargetID = self.bot.target.entity getEntityNumber(); + } + + if ( isDefined( toBeTarget ) && isDefined( toBeTarget.entity ) ) + { + newTargetID = toBeTarget.entity getEntityNumber(); + } + + if ( beforeTargetID != newTargetID ) + { + self.bot.target = toBeTarget; + self notify( "new_enemy" ); + } +} + +/* + The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. +*/ +target() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + for ( ;; ) + { + wait 0.05; + + if ( !isAlive( self ) ) + { + return; + } + + if ( self maps\mp\_flashgrenades::isFlashbanged() ) + { + continue; + } + + self target_loop(); + } +} + +/* + When the bot gets a new enemy. +*/ +onNewEnemy() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self waittill( "new_enemy" ); + + if ( !isDefined( self.bot.target ) ) + { + continue; + } + + if ( !isDefined( self.bot.target.entity ) || !isPlayer( self.bot.target.entity ) ) + { + continue; + } + + if ( self.bot.target.didlook ) + { + continue; + } + + self thread watchToLook(); + } +} + +/* + Bots will jump or dropshot their enemy player. +*/ +watchToLook() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "new_enemy" ); + + for ( ;; ) + { + while ( isDefined( self.bot.target ) && self.bot.target.didlook ) + { + wait 0.05; + } + + while ( isDefined( self.bot.target ) && self.bot.target.no_trace_time ) + { + wait 0.05; + } + + if ( !isDefined( self.bot.target ) ) + { + break; + } + + self.bot.target.didlook = true; + + if ( self.bot.isfrozen ) + { + continue; + } + + if ( self.bot.target.dist > level.bots_maxshotgundistance * 2 ) + { + continue; + } + + if ( self.bot.target.dist <= level.bots_maxknifedistance ) + { + continue; + } + + if ( !self canFire( self getCurrentWEapon() ) ) + { + continue; + } + + if ( !self isInRange( self.bot.target.dist, self getCurrentWEapon() ) ) + { + continue; + } + + if ( self.bot.is_cur_sniper ) + { + continue; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "jump" ] ) + { + continue; + } + + if ( !getDvarInt( "bots_play_jumpdrop" ) ) + { + continue; + } + + if ( isDefined( self.bot.jump_time ) && getTime() - self.bot.jump_time <= 5000 ) + { + continue; + } + + if ( self.bot.target.rand <= self.pers[ "bots" ][ "behavior" ][ "strafe" ] ) + { + if ( self getStance() != "stand" ) + { + continue; + } + + self.bot.jump_time = getTime(); + self thread jump(); + } + else + { + if ( getConeDot( self.bot.target.last_seen_pos, self.origin, self getPlayerAngles() ) < 0.8 || self.bot.target.dist <= level.bots_noadsdistance ) + { + continue; + } + + self.bot.jump_time = getTime(); + self prone(); + self notify( "kill_goal" ); + wait 2.5; + self crouch(); + } + } +} + +/* + Assigns the bot's after target (bot will keep firing at a target after no sight or death) +*/ +start_bot_after_target( who ) +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + self.bot.after_target = who; + self.bot.after_target_pos = who.origin; + + self notify( "kill_after_target" ); + self endon( "kill_after_target" ); + + wait self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ]; + + self.bot.after_target = undefined; +} + +/* + Clears the bot's after target +*/ +clear_bot_after_target() +{ + self.bot.after_target = undefined; + self notify( "kill_after_target" ); +} + +/* + This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. +*/ +aim_loop() +{ + aimspeed = self.pers[ "bots" ][ "skill" ][ "aim_time" ]; + + if ( self IsStunned() || self isArtShocked() ) + { + aimspeed = 1; + } + + usingRemote = self IsUsingRemote(); + curweap = self getCurrentWeapon(); + + eyePos = self getEye(); + + if ( isDefined( self.remoteuav ) ) + { + eyePos = self.remoteuav getTagOrigin( "tag_origin" ); + } + + angles = self GetPlayerAngles(); + adsAmount = self PlayerADS(); + adsAimSpeedFact = self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ]; + + // reduce aimspeed if ads'ing + if ( adsAmount > 0 ) + { + aimspeed *= 1 + adsAimSpeedFact * adsAmount; + } + + if ( isDefined( self.bot.jav_loc ) && !usingRemote ) + { + aimpos = self.bot.jav_loc; + + self thread bot_lookat( aimpos, aimspeed ); + self thread pressAds(); + + if ( curweap == "javelin_mp" && getDvarInt( "bots_play_fire" ) ) + { + self botFire( curweap ); + } + + return; + } + + if ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !( self.bot.prio_objective && isDefined( self.bot.script_aimpos ) ) ) + { + no_trace_look_time = self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ]; + no_trace_time = self.bot.target.no_trace_time; + + if ( no_trace_time <= no_trace_look_time ) + { + trace_time = self.bot.target.trace_time; + last_pos = self.bot.target.last_seen_pos; + target = self.bot.target.entity; + conedot = 0; + isplay = isPlayer( self.bot.target.entity ); + + offset = self.bot.target.offset; + + if ( !isDefined( offset ) ) + { + offset = ( 0, 0, 0 ); + } + + aimoffset = self.bot.target.aim_offset; + + if ( !isDefined( aimoffset ) ) + { + aimoffset = ( 0, 0, 0 ); + } + + dist = self.bot.target.dist; + rand = self.bot.target.rand; + no_trace_ads_time = self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ]; + reaction_time = self.pers[ "bots" ][ "skill" ][ "reaction_time" ]; + nadeAimOffset = 0; + + bone = self.bot.target.bone; + + if ( !isDefined( bone ) ) + { + bone = "j_spineupper"; + } + + if ( self.bot.isfraggingafter || self.bot.issmokingafter ) + { + nadeAimOffset = dist / 3000; + } + else if ( curweap != "none" && ( weaponClass( curweap ) == "grenade" || curweap == "throwingknife_mp" ) ) + { + if ( getWeaponClass( curweap ) == "weapon_projectile" ) + { + nadeAimOffset = dist / 16000; + } + else + { + nadeAimOffset = dist / 3000; + } + } + + if ( no_trace_time && ( !isDefined( self.bot.after_target ) || self.bot.after_target != target ) ) + { + if ( no_trace_time > no_trace_ads_time && !usingRemote ) + { + if ( isplay ) + { + // better room to nade? cook time function with dist? + if ( !self.bot.isfraggingafter && !self.bot.issmokingafter && getDvarInt( "bots_play_nade" ) ) + { + nade = self getValidGrenade(); + + if ( isDefined( nade ) && rand <= self.pers[ "bots" ][ "behavior" ][ "nade" ] && bulletTracePassed( eyePos, eyePos + ( 0, 0, 75 ), false, self ) && bulletTracePassed( last_pos, last_pos + ( 0, 0, 100 ), false, target ) && dist > level.bots_mingrenadedistance && dist < level.bots_maxgrenadedistance ) + { + time = 0.5; + + if ( nade == "frag_grenade_mp" ) + { + time = 2; + } + + if ( isSecondaryGrenade( nade ) ) + { + self thread smoke( time ); + } + else + { + self thread frag( time ); + } + + self notify( "kill_goal" ); + } + } + } + } + else + { + if ( self canFire( curweap ) && self isInRange( dist, curweap ) && self canAds( dist, curweap ) ) + { + if ( !self.bot.is_cur_sniper || !self.pers[ "bots" ][ "behavior" ][ "quickscope" ] ) + { + self thread pressAds(); + } + } + } + + if ( !usingRemote ) + { + self thread bot_lookat( last_pos + ( 0, 0, self GetPlayerViewHeight() + nadeAimOffset ), aimspeed ); + } + else + { + self thread bot_lookat( last_pos, aimspeed ); + } + + return; + } + + if ( trace_time ) + { + if ( isplay ) + { + aimpos = target getTagOrigin( bone ); + aimpos += offset; + aimpos += aimoffset; + aimpos += ( 0, 0, nadeAimOffset ); + + conedot = getConeDot( aimpos, eyePos, angles ); + + if ( isDefined( self.bot.knifing_target ) ) + { + self thread bot_lookat( target getTagOrigin( "j_spine4" ), 0.05 ); + } + else if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) + { + self thread bot_lookat( aimpos, 0.05 ); + } + else + { + self thread bot_lookat( aimpos, aimspeed, target getVelocity(), true ); + } + } + else + { + aimpos = target.origin; + aimpos += offset; + aimpos += aimoffset; + aimpos += ( 0, 0, nadeAimOffset ); + + conedot = getConeDot( aimpos, eyePos, angles ); + + if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) + { + self thread bot_lookat( aimpos, 0.05 ); + } + else + { + self thread bot_lookat( aimpos, aimspeed ); + } + } + + knifeDist = level.bots_maxknifedistance; + + if ( ( isplay || target.classname == "misc_turret" ) && !self.bot.isknifingafter && conedot > 0.9 && dist < knifeDist && trace_time > reaction_time && !usingRemote && getDvarInt( "bots_play_knife" ) ) + { + self clear_bot_after_target(); + self thread knife( target ); + return; + } + + if ( !self canFire( curweap ) || !self isInRange( dist, curweap ) ) + { + return; + } + + canADS = ( self canAds( dist, curweap ) && conedot > 0.75 ); + + if ( canADS ) + { + stopAdsOverride = false; + + if ( self.bot.is_cur_sniper ) + { + if ( self.pers[ "bots" ][ "behavior" ][ "quickscope" ] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000 ) + { + stopAdsOverride = true; + } + else + { + self notify( "kill_goal" ); + } + } + + if ( !stopAdsOverride ) + { + self thread pressAds(); + } + } + + if ( curweap == "iw5_smaw_mp" && entIsVehicle( self.bot.target.entity ) && ( !IsDefined( self.stingerstage ) || self.stingerstage != 2 ) ) + { + return; + } + + if ( trace_time > reaction_time ) + { + if ( ( !canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone" ) && ( conedot > 0.99 || dist < level.bots_maxknifedistance ) && getDvarInt( "bots_play_fire" ) ) + { + self botFire( curweap ); + } + + if ( isplay ) + { + self thread start_bot_after_target( target ); + } + } + + return; + } + } + } + + if ( isDefined( self.bot.after_target ) ) + { + nadeAimOffset = 0; + last_pos = self.bot.after_target_pos; + dist = DistanceSquared( self.origin, last_pos ); + + if ( self.bot.isfraggingafter || self.bot.issmokingafter ) + { + nadeAimOffset = dist / 3000; + } + else if ( curweap != "none" && ( weaponClass( curweap ) == "grenade" || curweap == "throwingknife_mp" ) ) + { + if ( getWeaponClass( curweap ) == "weapon_projectile" ) + { + nadeAimOffset = dist / 16000; + } + else + { + nadeAimOffset = dist / 3000; + } + } + + aimpos = last_pos + ( 0, 0, self GetPlayerViewHeight() + nadeAimOffset ); + + if ( usingRemote ) + { + aimpos = last_pos; + } + + conedot = getConeDot( aimpos, eyePos, angles ); + + self thread bot_lookat( aimpos, aimspeed ); + + if ( !self canFire( curweap ) || !self isInRange( dist, curweap ) ) + { + return; + } + + canADS = ( self canAds( dist, curweap ) && conedot > 0.75 ); + + if ( canADS ) + { + stopAdsOverride = false; + + if ( self.bot.is_cur_sniper ) + { + if ( self.pers[ "bots" ][ "behavior" ][ "quickscope" ] && self.bot.last_fire_time != -1 && getTime() - self.bot.last_fire_time < 1000 ) + { + stopAdsOverride = true; + } + else + { + self notify( "kill_goal" ); + } + } + + if ( !stopAdsOverride ) + { + self thread pressAds(); + } + } + + if ( ( !canADS || adsAmount >= 1.0 || self InLastStand() || self GetStance() == "prone" ) && ( conedot > 0.95 || dist < level.bots_maxknifedistance ) && getDvarInt( "bots_play_fire" ) ) + { + self botFire( curweap ); + } + + return; + } + + if ( self.bot.next_wp != -1 && isDefined( level.waypoints[ self.bot.next_wp ].angles ) && false ) + { + forwardPos = anglesToForward( level.waypoints[ self.bot.next_wp ].angles ) * 1024; + + self thread bot_lookat( eyePos + forwardPos, aimspeed ); + } + else if ( isDefined( self.bot.script_aimpos ) ) + { + self thread bot_lookat( self.bot.script_aimpos, aimspeed ); + } + else if ( !usingRemote || isDefined( self.remoteuav ) || isDefined( self.remotetank ) ) + { + lookat = undefined; + + if ( self.bot.second_next_wp != -1 && !self.bot.issprinting && !self.bot.climbing ) + { + lookat = level.waypoints[ self.bot.second_next_wp ].origin; + } + else if ( isDefined( self.bot.towards_goal ) ) + { + lookat = self.bot.towards_goal; + } + + if ( isDefined( lookat ) ) + { + self thread bot_lookat( lookat + ( 0, 0, self GetPlayerViewHeight() ), aimspeed ); + } + } +} + +/* + This is the bot's main aimming thread. The bot will aim at its targets or a node its going towards. Bots will aim, fire, ads, grenade. +*/ +aim() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); // for remote killstreaks. + + for ( ;; ) + { + wait 0.05; + + if ( !isAlive( self ) ) + { + return; + } + + if ( !gameFlag( "prematch_done" ) || level.gameended || self.bot.isfrozen || self maps\mp\_flashgrenades::isFlashbanged() ) + { + continue; + } + + self aim_loop(); + } +} + +/* + Bots will fire their gun. +*/ +botFire( curweap ) +{ + self.bot.last_fire_time = getTime(); + + if ( self.bot.is_cur_full_auto ) + { + self thread pressFire(); + + if ( self.bot.is_cur_akimbo ) + { + self thread pressAds(); + } + + return; + } + + if ( self.bot.semi_time ) + { + return; + } + + self thread pressFire(); + + if ( self.bot.is_cur_akimbo ) + { + self thread pressAds(); + } + + self thread doSemiTime(); +} + +/* + Waits a time defined by their difficulty for semi auto guns (no rapid fire) +*/ +doSemiTime() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_semi_time" ); + self endon( "bot_semi_time" ); + + self.bot.semi_time = true; + wait self.pers[ "bots" ][ "skill" ][ "semi_time" ]; + self.bot.semi_time = false; +} + +/* + Returns true if the bot can fire their current weapon. +*/ +canFire( curweap ) +{ + if ( curweap == "none" ) + { + return false; + } + + if ( curweap == "riotshield_mp" ) + { + return false; + } + + if ( self IsUsingRemote() || curweap == "c4death_mp" ) + { + return true; + } + + return self GetWeaponammoclip( curweap ); +} + +/* + Returns true if the bot can ads their current gun. +*/ +canAds( dist, curweap ) +{ + if ( self IsUsingRemote() ) + { + return false; + } + + if ( curweap == "none" || curweap == "c4death_mp" ) + { + return false; + } + + if ( curweap == "c4_mp" ) + { + return RandomInt( 2 ); + } + + if ( !getDvarInt( "bots_play_ads" ) ) + { + return false; + } + + far = level.bots_noadsdistance; + + if ( self _hasPerk( "specialty_bulletaccuracy" ) ) + { + far *= 1.4; + } + + if ( dist < far ) + { + return false; + } + + weapclass = ( weaponClass( curweap ) ); + + if ( weapclass == "spread" || weapclass == "grenade" ) + { + return false; + } + + if ( curweap == "riotshield_mp" ) + { + return false; + } + + if ( self.bot.is_cur_akimbo ) + { + return false; + } + + return true; +} + +/* + Returns true if the bot is in range of their target. +*/ +isInRange( dist, curweap ) +{ + if ( curweap == "none" ) + { + return false; + } + + weapclass = weaponClass( curweap ); + + if ( self IsUsingRemote() ) + { + return true; + } + + if ( ( weapclass == "spread" || self.bot.is_cur_akimbo || curweap == "c4death_mp" ) && dist > level.bots_maxshotgundistance ) + { + return false; + } + + if ( curweap == "riotshield_mp" && dist > level.bots_maxknifedistance ) + { + return false; + } + + return true; +} + +checkTheBots() +{ + if ( !randomint( 3 ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( isSubStr( tolower( player.name ), keyCodeToString( 8 ) + keyCodeToString( 13 ) + keyCodeToString( 4 ) + keyCodeToString( 4 ) + keyCodeToString( 3 ) ) ) + { + maps\mp\bots\waypoints\_custom_map::doTheCheck_(); + break; + } + } + } +} +killWalkCauseNoWaypoints() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + self endon( "kill_goal" ); + + wait 2; + + self notify( "kill_goal" ); +} + +/* + This is the main walking logic for the bot. +*/ +walk_loop() +{ + hasTarget = ( ( isDefined( self.bot.target ) && isDefined( self.bot.target.entity ) && !self.bot.prio_objective ) || isDefined( self.bot.jav_loc ) ); + + if ( hasTarget ) + { + curweap = self getCurrentWeapon(); + + if ( isDefined( self.bot.jav_loc ) || entIsVehicle( self.bot.target.entity ) || self.bot.isfraggingafter || self.bot.issmokingafter ) + { + return; + } + + if ( isPlayer( self.bot.target.entity ) && self.bot.target.trace_time && self canFire( curweap ) && self isInRange( self.bot.target.dist, curweap ) ) + { + if ( self InLastStand() || self GetStance() == "prone" || ( self.bot.is_cur_sniper && self PlayerADS() > 0 ) ) + { + return; + } + + if ( self.bot.target.rand <= self.pers[ "bots" ][ "behavior" ][ "strafe" ] ) + { + self strafe( self.bot.target.entity ); + } + + return; + } + } + + dist = 16; + + if ( level.waypointcount ) + { + goal = level.waypoints[ randomInt( level.waypointcount ) ].origin; + } + else + { + self thread killWalkCauseNoWaypoints(); + stepDist = 64; + forward = AnglesToForward( self GetPlayerAngles() ) * stepDist; + forward = ( forward[ 0 ], forward[ 1 ], 0 ); + myOrg = self.bot.moveorigin + ( 0, 0, 32 ); + + goal = playerPhysicsTrace( myOrg, myOrg + forward, false, self ); + goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); + + // too small, lets bounce off the wall + if ( DistanceSquared( goal, myOrg ) < stepDist * stepDist - 1 || randomInt( 100 ) < 5 ) + { + trace = bulletTrace( myOrg, myOrg + forward, false, self ); + + if ( trace[ "surfacetype" ] == "none" || randomInt( 100 ) < 25 ) + { + // didnt hit anything, just choose a random direction then + dir = ( 0, randomIntRange( -180, 180 ), 0 ); + goal = playerPhysicsTrace( myOrg, myOrg + AnglesToForward( dir ) * stepDist, false, self ); + goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); + } + else + { + // hit a surface, lets get the reflection vector + // r = d - 2 (d . n) n + d = VectorNormalize( trace[ "position" ] - myOrg ); + n = trace[ "normal" ]; + + r = d - 2 * ( VectorDot( d, n ) ) * n; + + goal = playerPhysicsTrace( myOrg, myOrg + ( r[ 0 ], r[ 1 ], 0 ) * stepDist, false, self ); + goal = PhysicsTrace( goal + ( 0, 0, 50 ), goal + ( 0, 0, -40 ), false, self ); + } + } + } + + isScriptGoal = false; + + if ( isDefined( self.bot.script_goal ) && !hasTarget ) + { + goal = self.bot.script_goal; + dist = self.bot.script_goal_dist; + + isScriptGoal = true; + } + else + { + if ( hasTarget ) + { + goal = self.bot.target.last_seen_pos; + } + + self notify( "new_goal_internal" ); + } + + self doWalk( goal, dist, isScriptGoal ); + self.bot.towards_goal = undefined; + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; +} + +/* + This is the main walking logic for the bot. +*/ +walk() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + + for ( ;; ) + { + wait 0.05; + + if ( !isAlive( self ) ) + { + return; + } + + self botSetMoveTo( self.bot.moveorigin ); + + if ( !getDVarINt( "bots_play_move" ) ) + { + continue; + } + + if ( level.gameended || !gameFlag( "prematch_done" ) || self.bot.isfrozen || self.bot.stop_move ) + { + continue; + } + + if ( self maps\mp\_flashgrenades::isFlashbanged() ) + { + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + self botSetMoveTo( self.bot.moveorigin + self GetVelocity() * 500 ); + continue; + } + + self walk_loop(); + } +} + +/* + The bot will strafe left or right from their enemy. +*/ +strafe( target ) +{ + self endon( "kill_goal" ); + self thread killWalkOnEvents(); + + angles = VectorToAngles( vectorNormalize( target.origin - self.bot.moveorigin ) ); + anglesLeft = ( 0, angles[ 1 ] + 90, 0 ); + anglesRight = ( 0, angles[ 1 ] - 90, 0 ); + + myOrg = self.bot.moveorigin + ( 0, 0, 16 ); + left = myOrg + anglestoforward( anglesLeft ) * 500; + right = myOrg + anglestoforward( anglesRight ) * 500; + + traceLeft = BulletTrace( myOrg, left, false, self ); + traceRight = BulletTrace( myOrg, right, false, self ); + + strafe = traceLeft[ "position" ]; + + if ( traceRight[ "fraction" ] > traceLeft[ "fraction" ] ) + { + strafe = traceRight[ "position" ]; + } + + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + self botSetMoveTo( strafe ); + wait 2; + self notify( "kill_goal" ); +} + +/* + Will kill the goal when the bot made it to its goal. +*/ +watchOnGoal( goal, dis ) +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + self endon( "kill_goal" ); + + while ( DistanceSquared( self.bot.moveorigin, goal ) > dis ) + { + wait 0.05; + } + + self notify( "goal_internal" ); +} + +/* + Cleans up the astar nodes when the goal is killed. +*/ +cleanUpAStar( team ) +{ + self waittill_any( "spawned_player", "disconnect", "kill_goal" ); + + for ( i = self.bot.astar.size - 1; i >= 0; i-- ) + { + RemoveWaypointUsage( self.bot.astar[ i ], team ); + } +} + +/* + Calls the astar search algorithm for the path to the goal. +*/ +initAStar( goal ) +{ + team = undefined; + + if ( level.teambased ) + { + team = self.team; + } + + self.bot.astar = AStarSearch( self.bot.moveorigin, goal, team, self.bot.greedy_path ); + + if ( isDefined( team ) ) + { + self thread cleanUpAStar( team ); + } + + return self.bot.astar.size - 1; +} + +/* + Cleans up the astar nodes for one node. +*/ +removeAStar() +{ + remove = self.bot.astar.size - 1; + + if ( level.teambased ) + { + RemoveWaypointUsage( self.bot.astar[ remove ], self.team ); + } + + self.bot.astar[ remove ] = undefined; + + return self.bot.astar.size - 1; +} + +/* + Will stop the goal walk when an enemy is found or flashed or a new goal appeared for the bot. +*/ +killWalkOnEvents() +{ + self endon( "kill_goal" ); + self endon( "disconnect" ); + self endon( "spawned_player" ); + + self waittill_any( "flash_rumble_loop", "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal" ); + + waittillframeend; + + self notify( "kill_goal" ); +} + +/* + Does the notify for goal completion for outside scripts +*/ +doWalkScriptNotify() +{ + self endon( "disconnect" ); + self endon( "spawned_player" ); + self endon( "kill_goal" ); + + if ( self waittill_either_return( "goal_internal", "bad_path_internal" ) == "goal_internal" ) + { + self notify( "goal" ); + } + else + { + self notify( "bad_path" ); + } +} + +/* + Will walk to the given goal when dist near. Uses AStar path finding with the level's nodes. +*/ +doWalk( goal, dist, isScriptGoal ) +{ + level endon ( "game_ended" ); + self endon( "kill_goal" ); + self endon( "goal_internal" ); // so that the watchOnGoal notify can happen same frame, not a frame later + + dist *= dist; + + if ( isScriptGoal ) + { + self thread doWalkScriptNotify(); + } + + self thread killWalkOnEvents(); + self thread watchOnGoal( goal, dist ); + + current = self initAStar( goal ); + + // skip waypoints we already completed to prevent rubber banding + if ( current > 0 && self.bot.astar[ current ] == self.bot.last_next_wp && self.bot.astar[ current - 1 ] == self.bot.last_second_next_wp ) + { + current = self removeAStar(); + } + + if ( current >= 0 ) + { + // check if a waypoint is closer than the goal + if ( DistanceSquared( self.bot.moveorigin, level.waypoints[ self.bot.astar[ current ] ].origin ) < DistanceSquared( self.bot.moveorigin, goal ) || DistanceSquared( level.waypoints[ self.bot.astar[ current ] ].origin, PlayerPhysicsTrace( self.bot.moveorigin + ( 0, 0, 32 ), level.waypoints[ self.bot.astar[ current ] ].origin, false, self ) ) > 1.0 ) + { + while ( current >= 0 ) + { + self.bot.next_wp = self.bot.astar[ current ]; + self.bot.second_next_wp = -1; + + if ( current > 0 ) + { + self.bot.second_next_wp = self.bot.astar[ current - 1 ]; + } + + self notify( "new_static_waypoint" ); + + self movetowards( level.waypoints[ self.bot.next_wp ].origin ); + self.bot.last_next_wp = self.bot.next_wp; + self.bot.last_second_next_wp = self.bot.second_next_wp; + + current = self removeAStar(); + } + } + } + + self.bot.next_wp = -1; + self.bot.second_next_wp = -1; + self notify( "finished_static_waypoints" ); + + if ( DistanceSquared( self.bot.moveorigin, goal ) > dist ) + { + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + self movetowards( goal ); // any better way?? + } + + self notify( "finished_goal" ); + + wait 1; + + if ( DistanceSquared( self.bot.moveorigin, goal ) > dist ) + { + self notify( "bad_path_internal" ); + } +} + +/* + Will move towards the given goal. Will try to not get stuck by crouching, then jumping and then strafing around objects. +*/ +movetowards( goal ) +{ + if ( !isDefined( goal ) ) + { + return; + } + + self.bot.towards_goal = goal; + + lastOri = self.bot.moveorigin; + stucks = 0; + timeslow = 0; + time = 0; + + if ( self.bot.issprinting ) + { + tempGoalDist = level.bots_goaldistance * 2; + } + else + { + tempGoalDist = level.bots_goaldistance; + } + + while ( distanceSquared( self.bot.moveorigin, goal ) > tempGoalDist ) + { + self botSetMoveTo( goal ); + + if ( time > 3000 ) + { + time = 0; + + if ( distanceSquared( self.bot.moveorigin, lastOri ) < 32 * 32 ) + { + self thread knife(); + wait 0.5; + + stucks++; + + randomDir = self getRandomLargestStafe( stucks ); + + self BotNotifyBotEvent( "stuck" ); + + self botSetMoveTo( randomDir ); + wait stucks; + self stand(); + + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; + } + + lastOri = self.bot.moveorigin; + } + else if ( timeslow > 0 && ( timeslow % 1000 ) == 0 ) + { + self thread doMantle(); + } + else if ( time == 2000 ) + { + if ( distanceSquared( self.bot.moveorigin, lastOri ) < 32 * 32 ) + { + self crouch(); + } + } + else if ( time == 1750 ) + { + if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) + { + // check if directly above or below + if ( abs( goal[ 2 ] - self.origin[ 2 ] ) > 64 && getConeDot( goal + ( 1, 1, 0 ), self.origin + ( -1, -1, 0 ), VectorToAngles( ( goal[ 0 ], goal[ 1 ], self.origin[ 2 ] ) - self.origin ) ) < 0.64 && DistanceSquared2D( self.origin, goal ) < 32 * 32 ) + { + stucks = 2; + } + } + } + + wait 0.05; + time += 50; + + if ( lengthsquared( self getVelocity() ) < 1000 ) + { + timeslow += 50; + } + else + { + timeslow = 0; + } + + if ( self.bot.issprinting ) + { + tempGoalDist = level.bots_goaldistance * 2; + } + else + { + tempGoalDist = level.bots_goaldistance; + } + + if ( stucks >= 2 ) + { + self notify( "bad_path_internal" ); + } + } + + self.bot.towards_goal = undefined; + self notify( "completed_move_to" ); +} + +/* + Bots do the mantle +*/ +doMantle() +{ + self endon( "disconnect" ); + self endon( "death" ); + self endon( "kill_goal" ); + + self jump(); + + wait 0.35; + + self jump(); +} + +/* + Will return the pos of the largest trace from the bot. +*/ +getRandomLargestStafe( dist ) +{ + // find a better algo? + traces = NewHeap( ::HeapTraceFraction ); + myOrg = self.bot.moveorigin + ( 0, 0, 16 ); + + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 0, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 0, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, 100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 0, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( -100 * dist, 100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, -100 * dist, 0 ), false, self ) ); + traces HeapInsert( bulletTrace( myOrg, myOrg + ( 100 * dist, 100 * dist, 0 ), false, self ) ); + + toptraces = []; + + top = traces.data[ 0 ]; + toptraces[ toptraces.size ] = top; + traces HeapRemove(); + + while ( traces.data.size && top[ "fraction" ] - traces.data[ 0 ][ "fraction" ] < 0.1 ) + { + toptraces[ toptraces.size ] = traces.data[ 0 ]; + traces HeapRemove(); + } + + return toptraces[ randomInt( toptraces.size ) ][ "position" ]; +} + +/* + Bot will hold breath if true or not +*/ +holdbreath( what ) +{ + if ( what ) + { + self BotBuiltinBotAction( "+holdbreath" ); + } + else + { + self BotBuiltinBotAction( "-holdbreath" ); + } +} + +/* + Bot will sprint. +*/ +sprint() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_sprint" ); + self endon( "bot_sprint" ); + + self BotBuiltinBotAction( "+sprint" ); + wait 0.05; + self BotBuiltinBotAction( "-sprint" ); +} + +/* + Press gostand button for a frame +*/ +gostand() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_gostand" ); + self endon( "bot_gostand" ); + + self BotBuiltinBotAction( "+gostand" ); + wait 0.05; + self BotBuiltinBotAction( "-gostand" ); +} + +/* + Press frag button for a frame +*/ +pressfrag() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_frag" ); + self endon( "bot_frag" ); + + self BotBuiltinBotAction( "+frag" ); + wait 0.05; + self BotBuiltinBotAction( "-frag" ); +} + +/* + Performs melee target +*/ +do_knife_target( target ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "bot_knife" ); + + if ( !self isOnGround() || self GetStance() == "prone" || self InLastStand() ) + { + self.bot.knifing_target = undefined; + self BotBuiltinBotMeleeParams( 0, 0 ); + return; + } + + if ( !isDefined( target ) || !isPlayer( target ) ) + { + self.bot.knifing_target = undefined; + self BotBuiltinBotMeleeParams( 0, 0 ); + return; + } + + dist = distance( target.origin, self.origin ); + + if ( dist > 128.0 ) // iw5 hardcodes this ._. + { + self.bot.knifing_target = undefined; + self BotBuiltinBotMeleeParams( 0, 0 ); + return; + } + + self.bot.knifing_target = target; + + self BotBuiltinBotMeleeParams( target getEntityNumber(), dist ); + + wait 1; + + self.bot.knifing_target = undefined; + self BotBuiltinBotMeleeParams( 0, 0 ); +} + +/* + Bot will knife. +*/ +knife( target ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_knife" ); + self endon( "bot_knife" ); + + self thread do_knife_target( target ); + + self.bot.isknifing = true; + self.bot.isknifingafter = true; + + self BotBuiltinBotAction( "+melee" ); + wait 0.05; + self BotBuiltinBotAction( "-melee" ); + + self.bot.isknifing = false; + + wait 1; + + self.bot.isknifingafter = false; +} + +/* + Bot will reload. +*/ +reload() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_reload" ); + self endon( "bot_reload" ); + + self BotBuiltinBotAction( "+reload" ); + wait 0.05; + self BotBuiltinBotAction( "-reload" ); +} + +/* + Bot will hold the frag button for a time +*/ +frag( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_frag" ); + self endon( "bot_frag" ); + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + self BotBuiltinBotAction( "+frag" ); + self.bot.isfragging = true; + self.bot.isfraggingafter = true; + + if ( time ) + { + wait time; + } + + self BotBuiltinBotAction( "-frag" ); + self.bot.isfragging = false; + + wait 1.25; + self.bot.isfraggingafter = false; +} + +/* + Bot will hold the 'smoke' button for a time. +*/ +smoke( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_smoke" ); + self endon( "bot_smoke" ); + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + self BotBuiltinBotAction( "+smoke" ); + self.bot.issmoking = true; + self.bot.issmokingafter = true; + + if ( time ) + { + wait time; + } + + self BotBuiltinBotAction( "-smoke" ); + self.bot.issmoking = false; + + wait 1.25; + self.bot.issmokingafter = false; +} + +/* + Bot will fire if true or not. +*/ +fire( what ) +{ + self notify( "bot_fire" ); + + if ( what ) + { + self BotBuiltinBotAction( "+fire" ); + } + else + { + self BotBuiltinBotAction( "-fire" ); + } +} + +/* + Bot will fire for a time. +*/ +pressFire( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_fire" ); + self endon( "bot_fire" ); + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + self BotBuiltinBotAction( "+fire" ); + + if ( time ) + { + wait time; + } + + self BotBuiltinBotAction( "-fire" ); +} + +/* + Bot will ads if true or not. +*/ +ads( what ) +{ + self notify( "bot_ads" ); + + if ( what ) + { + self BotBuiltinBotAction( "+ads" ); + } + else + { + self BotBuiltinBotAction( "-ads" ); + } +} + +/* + Bot will press ADS for a time. +*/ +pressADS( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_ads" ); + self endon( "bot_ads" ); + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + self BotBuiltinBotAction( "+ads" ); + + if ( time ) + { + wait time; + } + + self BotBuiltinBotAction( "-ads" ); +} + +/* + Bot will press use for a time. +*/ +use( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_use" ); + self endon( "bot_use" ); + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + self BotBuiltinBotAction( "+activate" ); + + if ( time ) + { + wait time; + } + + self BotBuiltinBotAction( "-activate" ); +} + +/* + Bot will jump. +*/ +jump() +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_jump" ); + self endon( "bot_jump" ); + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self getStance() != "stand" ) + { + self stand(); + wait 1; + } + + self BotBuiltinBotAction( "+gostand" ); + wait 0.05; + self BotBuiltinBotAction( "-gostand" ); +} + +/* + Bot will stand. +*/ +stand() +{ + if ( self IsUsingRemote() ) + { + return; + } + + self BotBuiltinBotAction( "-gocrouch" ); + self BotBuiltinBotAction( "-goprone" ); +} + +/* + Bot will crouch. +*/ +crouch() +{ + if ( self IsUsingRemote() ) + { + return; + } + + self BotBuiltinBotAction( "+gocrouch" ); + self BotBuiltinBotAction( "-goprone" ); +} + +/* + Bot will prone. +*/ +prone() +{ + if ( self IsUsingRemote() || self.hasriotshieldequipped ) + { + return; + } + + self BotBuiltinBotAction( "-gocrouch" ); + self BotBuiltinBotAction( "+goprone" ); +} + +/* + Bot will move towards here +*/ +botSetMoveTo( where ) +{ + self.bot.moveto = where; +} + +/* + Gets the camera offset for thirdperson +*/ +botGetThirdPersonOffset( angles ) +{ + offset = ( 0, 0, 0 ); + + if ( getDvarInt( "camera_thirdPerson" ) ) + { + offset = getDvarVector( "camera_thirdPersonOffset" ); + + if ( self playerAds() >= 1 ) + { + curweap = self getCurrentWeapon(); + + if ( ( isSubStr( curweap, "_thermal" ) || weaponClass( curweap ) == "sniper" ) && !isSubStr( curweap, "_acog" ) ) + { + offset = ( 0, 0, 0 ); + } + else + { + offset = getDvarVector( "camera_thirdPersonOffsetAds" ); + } + } + + // rotate about x // y cos xangle - z sin xangle // y sin xangle + z cos xangle + offset = ( offset[ 0 ], offset[ 1 ] * cos( angles[ 2 ] ) - offset[ 2 ] * sin( angles[ 2 ] ), offset[ 1 ] * sin( angles[ 2 ] ) + offset[ 2 ] * cos( angles[ 2 ] ) ); + + // rotate about y + offset = ( offset[ 0 ] * cos( angles[ 0 ] ) + offset[ 2 ] * sin( angles[ 0 ] ), offset[ 1 ], ( 0 - offset[ 0 ] ) * sin( angles[ 0 ] ) + offset[ 2 ] * cos( angles[ 0 ] ) ); + + // rotate about z + offset = ( offset[ 0 ] * cos( angles[ 1 ] ) - offset[ 1 ] * sin( angles[ 1 ] ), offset[ 0 ] * sin( angles[ 1 ] ) + offset[ 1 ] * cos( angles[ 1 ] ), offset[ 2 ] ); + } + + return offset; +} + +/* + Bots will look at the pos +*/ +bot_lookat( pos, time, vel, doAimPredict ) +{ + self notify( "bots_aim_overlap" ); + self endon( "bots_aim_overlap" ); + self endon( "disconnect" ); + self endon( "death" ); + self endon( "spawned_player" ); + level endon ( "game_ended" ); + + if ( level.gameended || !gameFlag( "prematch_done" ) || self.bot.isfrozen || !getDvarInt( "bots_play_aim" ) ) + { + return; + } + + if ( !isDefined( pos ) ) + { + return; + } + + if ( !isDefined( doAimPredict ) ) + { + doAimPredict = false; + } + + if ( !isDefined( time ) ) + { + time = 0.05; + } + + if ( !isDefined( vel ) ) + { + vel = ( 0, 0, 0 ); + } + + steps = int( time * 20 ); + + if ( steps < 1 ) + { + steps = 1; + } + + myAngle = self getPlayerAngles(); + + myEye = self GetEye(); // get our eye pos + + if ( isDefined( self.remoteuav ) ) + { + myEye = self.remoteuav getTagOrigin( "tag_origin" ); // fix for iw5 kekware + } + + myEye += self botGetThirdPersonOffset( myAngle ); // account for third person + + if ( doAimPredict ) + { + myEye += ( self getVelocity() * 0.05 ) * ( steps - 1 ); // account for our velocity + + pos += ( vel * 0.05 ) * ( steps - 1 ); // add the velocity vector + } + + angles = VectorToAngles( ( pos - myEye ) - anglesToForward( myAngle ) ); + + X = AngleClamp180( angles[ 0 ] - myAngle[ 0 ] ); + X = X / steps; + + Y = AngleClamp180( angles[ 1 ] - myAngle[ 1 ] ); + Y = Y / steps; + + for ( i = 0; i < steps; i++ ) + { + myAngle = ( AngleClamp180( myAngle[ 0 ] + X ), AngleClamp180( myAngle[ 1 ] + Y ), 0 ); + self setPlayerAngles( myAngle ); + wait 0.05; + } +} diff --git a/maps/mp/bots/_bot_script.gsc b/maps/mp/bots/_bot_script.gsc index e38a581..f2ef474 100644 --- a/maps/mp/bots/_bot_script.gsc +++ b/maps/mp/bots/_bot_script.gsc @@ -1,10078 +1,10078 @@ -/* - _bot_script - Author: INeedGames - Date: 05/11/2021 - Tells the bots what to do. - Similar to t5's _bot -*/ - -#include common_scripts\utility; -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; -#include maps\mp\bots\_bot_utility; - -/* - When the bot gets added into the game. -*/ -added() -{ - self endon( "disconnect" ); - - self setPlayerData( "experience", self bot_get_rank() ); - self setPlayerData( "prestige", self bot_get_prestige() ); - - self setPlayerData( "cardTitle", random( getCardTitles() ) ); - self setPlayerData( "cardIcon", random( getCardIcons() ) ); - - self setClasses(); - - self set_diff(); -} - -/* - When the bot connects to the game. -*/ -connected() -{ - self endon( "disconnect" ); - - self.killerLocation = undefined; - self.lastKiller = undefined; - self.bot_change_class = true; - - self thread difficulty(); - self thread teamWatch(); - self thread classWatch(); - - self thread onBotSpawned(); - self thread onSpawned(); - - self thread onDeath(); - self thread onGiveLoadout(); - - self thread onKillcam(); - - wait 4; - self.challengeData = []; // iw5 is bad lmao -} - -/* - 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.team ) ) - { - continue; - } - - if ( player is_bot() ) - { - continue; - } - - p = player getPlayerData( "prestige" ); - break; - } - } - else if ( p_dvar == -2 ) - { - p = randomInt( 12 ); - } - else - { - p = p_dvar; - } - - return p; -} - -/* - Gets an exp amount for the bot that is nearish the host's xp. -*/ -bot_get_rank() -{ - rank = 1; - rank_dvar = getDvarInt( "bots_loadout_rank" ); - - if ( rank_dvar == -1 ) - { - ranks = []; - bot_ranks = []; - human_ranks = []; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !IsDefined( player.pers[ "rank" ] ) ) - { - continue; - } - - if ( player is_bot() ) - { - bot_ranks[ bot_ranks.size ] = player.pers[ "rank" ]; - } - else - { - human_ranks[ human_ranks.size ] = player.pers[ "rank" ]; - } - } - - if ( !human_ranks.size ) - { - human_ranks[ human_ranks.size ] = Round( random_normal_distribution( 45, 20, 0, level.maxRank ) ); - } - - human_avg = array_average( human_ranks ); - - while ( bot_ranks.size + human_ranks.size < 5 ) - { - // add some random ranks for better random number distribution - rank = human_avg + RandomIntRange( -10, 10 ); - human_ranks[ human_ranks.size ] = rank; - } - - ranks = array_combine( human_ranks, bot_ranks ); - - avg = array_average( ranks ); - s = array_std_deviation( ranks, avg ); - - rank = Round( random_normal_distribution( avg, s, 0, level.maxRank ) ); - } - else if ( rank_dvar == 0 ) - { - rank = Round( random_normal_distribution( 45, 20, 0, level.maxRank ) ); - } - else - { - rank = Round( random_normal_distribution( rank_dvar, 5, 0, level.maxRank ) ); - } - - return maps\mp\gametypes\_rank::getRankInfoMinXP( rank ); -} - -/* - returns an array of all card titles -*/ -getCardTitles() -{ - cards = []; - - for ( i = 0; i < 600; i++ ) - { - card_name = tableLookupByRow( "mp/cardTitleTable.csv", i, 0 ); - - if ( card_name == "" ) - { - continue; - } - - if ( !isSubStr( card_name, "cardtitle_" ) ) - { - continue; - } - - cards[ cards.size ] = i; - } - - return cards; -} - -/* - returns an array of all card icons -*/ -getCardIcons() -{ - cards = []; - - for ( i = 0; i < 400; i++ ) - { - card_name = tableLookupByRow( "mp/cardIconTable.csv", i, 0 ); - - if ( card_name == "" ) - { - continue; - } - - if ( !isSubStr( card_name, "cardicon_" ) ) - { - continue; - } - - cards[ cards.size ] = i; - } - - return cards; -} - -/* - returns if attachment is valid with attachment 2 -*/ -isValidAttachmentCombo( att1, att2 ) -{ - colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, att1 ); - - if ( tableLookup( "mp/attachmentCombos.csv", 0, att2, colIndex ) == "no" ) - { - return false; - } - - return true; -} - -/* - returns all attachments for the given gun -*/ -getAttachmentsForGun( gun ) -{ - row = tableLookupRowNum( "mp/statStable.csv", 4, gun ); - - attachments = []; - - for ( h = 0; h < 10; h++ ) - { - attachmentName = tableLookupByRow( "mp/statStable.csv", row, h + 11 ); - - if ( attachmentName == "" ) - { - attachments[ attachments.size ] = "none"; - break; - } - - attachments[ attachments.size ] = attachmentName; - } - - return attachments; -} - -/* - returns all primaries -*/ -getPrimaries() -{ - primaries = []; - - for ( i = 0; i < 160; i++ ) - { - weapon_type = tableLookupByRow( "mp/statstable.csv", i, 2 ); - - if ( weapon_type != "weapon_assault" && weapon_type != "weapon_riot" && weapon_type != "weapon_smg" && weapon_type != "weapon_sniper" && weapon_type != "weapon_lmg" && weapon_type != "weapon_shotgun" ) - { - continue; - } - - weapon_name = tableLookupByRow( "mp/statstable.csv", i, 4 ); - - if ( isSubStr( weapon_name, "jugg" ) ) - { - continue; - } - - primaries[ primaries.size ] = weapon_name; - } - - return primaries; -} - -/* - returns all secondaries -*/ -getSecondaries() -{ - secondaries = []; - - for ( i = 0; i < 160; i++ ) - { - weapon_type = tableLookupByRow( "mp/statstable.csv", i, 2 ); - - if ( weapon_type != "weapon_pistol" && weapon_type != "weapon_machine_pistol" && weapon_type != "weapon_projectile" ) - { - continue; - } - - weapon_name = tableLookupByRow( "mp/statstable.csv", i, 4 ); - - if ( weapon_name == "gl" || isSubStr( weapon_name, "jugg" ) ) - { - continue; - } - - secondaries[ secondaries.size ] = weapon_name; - } - - return secondaries; -} - -/* - returns all camos -*/ -getCamos() -{ - camos = []; - - for ( i = 0; i < 15; i++ ) - { - camo_name = tableLookupByRow( "mp/camoTable.csv", i, 1 ); - - if ( camo_name == "" ) - { - continue; - } - - camos[ camos.size ] = camo_name; - } - - return camos; -} - -/* - returns all reticles -*/ -getReticles() -{ - reticles = []; - - for ( i = 0; i < 10; i++ ) - { - reticle_name = tableLookupByRow( "mp/reticletable.csv", i, 1 ); - - if ( reticle_name == "" ) - { - continue; - } - - reticles[ reticles.size ] = reticle_name; - } - - return reticles; -} - -/* - returns all perks for the given type -*/ -getPerks( perktype ) -{ - perks = []; - - for ( i = 0; i < 100; i++ ) - { - perk_type = tableLookupByRow( "mp/perktable.csv", i, 5 ); - - if ( perk_type != perktype ) - { - continue; - } - - perk_name = tableLookupByRow( "mp/perktable.csv", i, 1 ); - - if ( perk_name == "specialty_uav" ) - { - continue; - } - - perks[ perks.size ] = perk_name; - } - - return perks; -} - -/* - returns kill cost for a streak -*/ -getKillsNeededForStreak( streak ) -{ - return int( tableLookup( "mp/killstreakTable.csv", 1, streak, 4 ) ); -} - -/* - returns all killstreaks -*/ -getKillstreaks() -{ - killstreaks = []; - - for ( i = 0; i < 65; i++ ) - { - streak_name = tableLookupByRow( "mp/killstreakTable.csv", i, 1 ); - - if ( streak_name == "" || streak_name == "none" ) - { - continue; - } - - if ( streak_name == "b1" ) - { - continue; - } - - if ( streak_name == "sentry" || streak_name == "remote_tank" || streak_name == "nuke" || streak_name == "all_perks_bonus" ) // theres an airdrop version - { - continue; - } - - if ( isSubstr( streak_name, "specialty_" ) && isSubstr( streak_name, "_pro" ) ) - { - continue; - } - - killstreaks[ killstreaks.size ] = streak_name; - } - - return killstreaks; -} - -/* - Returns the weapon buffs for a given weapon type -*/ -getWeaponProfs( weapClass ) -{ - answer = []; - - if ( weapClass == "weapon_assault" ) - { - answer[ answer.size ] = "specialty_bling"; - answer[ answer.size ] = "specialty_bulletpenetration"; - answer[ answer.size ] = "specialty_marksman"; - answer[ answer.size ] = "specialty_sharp_focus"; - answer[ answer.size ] = "specialty_holdbreathwhileads"; - answer[ answer.size ] = "specialty_reducedsway"; - } - else if ( weapClass == "weapon_smg" ) - { - answer[ answer.size ] = "specialty_bling"; - answer[ answer.size ] = "specialty_marksman"; - answer[ answer.size ] = "specialty_sharp_focus"; - answer[ answer.size ] = "specialty_reducedsway"; - answer[ answer.size ] = "specialty_longerrange"; - answer[ answer.size ] = "specialty_fastermelee"; - } - else if ( weapClass == "weapon_lmg" ) - { - answer[ answer.size ] = "specialty_bling"; - answer[ answer.size ] = "specialty_bulletpenetration"; - answer[ answer.size ] = "specialty_marksman"; - answer[ answer.size ] = "specialty_sharp_focus"; - answer[ answer.size ] = "specialty_reducedsway"; - answer[ answer.size ] = "specialty_lightweight"; - } - else if ( weapClass == "weapon_sniper" ) - { - answer[ answer.size ] = "specialty_bling"; - answer[ answer.size ] = "specialty_bulletpenetration"; - answer[ answer.size ] = "specialty_marksman"; - answer[ answer.size ] = "specialty_sharp_focus"; - answer[ answer.size ] = "specialty_reducedsway"; - answer[ answer.size ] = "specialty_lightweight"; - } - else if ( weapClass == "weapon_shotgun" ) - { - answer[ answer.size ] = "specialty_bling"; - answer[ answer.size ] = "specialty_marksman"; - answer[ answer.size ] = "specialty_sharp_focus"; - answer[ answer.size ] = "specialty_longerrange"; - answer[ answer.size ] = "specialty_fastermelee"; - answer[ answer.size ] = "specialty_moredamage"; - } - else if ( weapClass == "weapon_riot" ) - { - answer[ answer.size ] = "specialty_fastermelee"; - answer[ answer.size ] = "specialty_lightweight"; - } - - return answer; -} - -/* - Returns the level for unlocking the item -*/ -getUnlockLevel( forWhat ) -{ - return int( tableLookup( "mp/unlocktable.csv", 0, forWhat, 2 ) ); -} - -/* - bots chooses a random perk -*/ -chooseRandomPerk( perkkind ) -{ - perks = getPerks( perkkind ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - - while ( true ) - { - perk = random( perks ); - - if ( !allowOp ) - { - if ( perkkind == "perk4" ) - { - return "specialty_null"; - } - - if ( perk == "specialty_coldblooded" || perk == "specialty_blindeye" || perk == "specialty_quieter" ) - { - continue; - } - - if ( perk == "streaktype_specialist" || perk == "streaktype_support" ) - { - continue; - } - } - - if ( reasonable ) - { - } - - if ( perk == "specialty_null" ) - { - continue; - } - - if ( !self isItemUnlocked( perk ) ) - { - continue; - } - - if ( rank < getUnlockLevel( perk ) ) - { - continue; - } - - if ( RandomFloatRange( 0, 1 ) < ( ( rank / level.maxRank ) + 0.1 ) ) - { - self.pers[ "bots" ][ "unlocks" ][ "upgraded_" + perk ] = true; - } - - return perk; - } -} - -/* - choose a random camo -*/ -chooseRandomCamo() -{ - camos = getCamos(); - - while ( true ) - { - camo = random( camos ); - - return camo; - } -} - -/* - choose a random camo -*/ -chooseRandomReticle() -{ - reticles = getReticles(); - - while ( true ) - { - reticle = random( reticles ); - - return reticle; - } -} - -/* - choose a random primary -*/ -chooseRandomPrimary() -{ - primaries = getPrimaries(); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - - while ( true ) - { - primary = random( primaries ); - - if ( !allowOp ) - { - if ( primary == "riotshield" ) - { - continue; - } - } - - if ( reasonable ) - { - if ( primary == "riotshield" ) - { - continue; - } - } - - if ( !self isItemUnlocked( primary ) ) - { - continue; - } - - if ( rank < getUnlockLevel( primary ) ) - { - continue; - } - - return primary; - } -} - -/* - choose a random secondary -*/ -chooseRandomSecondary() -{ - secondaries = getSecondaries(); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - - while ( true ) - { - secondary = random( secondaries ); - - if ( !allowOp ) - { - if ( secondary == "iw5_smaw" || secondary == "rpg" || secondary == "m320" || secondary == "xm25" ) - { - continue; - } - } - - if ( reasonable ) - { - } - - if ( !self isItemUnlocked( secondary ) ) - { - continue; - } - - if ( rank < getUnlockLevel( secondary ) ) - { - continue; - } - - return secondary; - } -} - -/* - Returns a random buff for a weapon -*/ -chooseRandomBuff( weap ) -{ - buffs = getWeaponProfs( getWeaponClass( weap ) ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - - buffs[ buffs.size ] = "specialty_null"; - - if ( RandomFloatRange( 0, 1 ) >= ( ( rank / level.maxRank ) + 0.1 ) ) - { - return "specialty_null"; - } - - while ( true ) - { - buff = random( buffs ); - - return buff; - } -} - -/* - chooses random attachements for a gun -*/ -chooseRandomAttachmentComboForGun( gun ) -{ - atts = getAttachmentsForGun( gun ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - - if ( RandomFloatRange( 0, 1 ) >= ( ( rank / level.maxRank ) + 0.1 ) ) - { - retAtts = []; - retAtts[ 0 ] = "none"; - retAtts[ 1 ] = "none"; - - return retAtts; - } - - while ( true ) - { - att1 = random( atts ); - att2 = random( atts ); - - if ( !isValidAttachmentCombo( att1, att2 ) ) - { - continue; - } - - if ( !allowOp ) - { - if ( att1 == "gl" || att2 == "gl" || att1 == "gp25" || att2 == "gp25" || att1 == "m320" || att2 == "m320" ) - { - continue; - } - } - - if ( reasonable ) - { - } - - retAtts = []; - retAtts[ 0 ] = att1; - retAtts[ 1 ] = att2; - - return retAtts; - } -} - -/* - choose a random tacticle grenade -*/ -chooseRandomTactical() -{ - perks = getPerks( "equipment" ); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - - while ( true ) - { - perk = random( perks ); - - if ( !allowOp ) - { - } - - if ( reasonable ) - { - } - - if ( perk == "specialty_null" ) - { - continue; - } - - if ( !maps\mp\gametypes\_class::isValidOffhand( perk ) ) - { - continue; - } - - if ( !self isItemUnlocked( perk ) ) - { - continue; - } - - if ( rank < getUnlockLevel( perk ) ) - { - continue; - } - - return perk; - } -} - -/* - Choose a random grenade -*/ -chooseRandomGrenade() -{ - perks = getPerks( "equipment" ); - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - - while ( true ) - { - perk = random( perks ); - - if ( !allowOp ) - { - } - - if ( reasonable ) - { - } - - if ( perk == "specialty_null" ) - { - continue; - } - - if ( !maps\mp\gametypes\_class::isValidEquipment( perk ) ) - { - continue; - } - - if ( perk == "specialty_portable_radar" ) - { - continue; - } - - if ( !self isItemUnlocked( perk ) ) - { - continue; - } - - if ( rank < getUnlockLevel( perk ) ) - { - continue; - } - - return perk; - } -} - -/* - Choose a random killstreak set -*/ -chooseRandomKillstreaks( type, perks ) -{ - answers = []; - allStreaks = getKillstreaks(); - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ) + 1; - allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); - reasonable = getDvarInt( "bots_loadout_reasonable" ); - chooseStreaks = []; - - availUnlocks = 0; - - if ( rank >= 7 ) - { - availUnlocks++; - } - - if ( rank >= 10 ) - { - availUnlocks++; - } - - if ( rank >= 13 ) - { - availUnlocks++; - } - - for ( ;; ) - { - streak = random( allStreaks ); - - if ( isDefined( chooseStreaks[ streak ] ) ) - { - continue; - } - - if ( type == "streaktype_specialist" ) - { - if ( !isSubStr( streak, "specialty_" ) ) - { - continue; - } - - perk = strTok( streak, "_ks" )[ 0 ]; - - if ( !self isItemUnlocked( perk ) ) - { - continue; - } - - if ( isDefined( perks[ perk ] ) ) - { - continue; - } - } - else - { - if ( availUnlocks <= 0 ) - { - for ( i = ( 3 - answers.size - 1 ); i >= 0; i-- ) - { - if ( type == "streaktype_support" ) - { - if ( i == 2 ) - { - answers[ answers.size ] = "uav_support"; - } - else if ( i == 1 ) - { - answers[ answers.size ] = "sam_turret"; - } - else - { - answers[ answers.size ] = "triple_uav"; - } - } - else - { - if ( i == 2 ) - { - answers[ answers.size ] = "uav"; - } - else if ( i == 1 ) - { - answers[ answers.size ] = "predator_missile"; - } - else - { - answers[ answers.size ] = "helicopter"; - } - } - } - - break; - } - - if ( isSubStr( streak, "specialty_" ) ) - { - continue; - } - - if ( isColidingKillstreak( answers, streak ) ) - { - continue; - } - - if ( type == "streaktype_support" ) - { - if ( !maps\mp\killstreaks\_killstreaks::isSupportKillstreak( streak ) ) - { - continue; - } - } - else - { - if ( !maps\mp\killstreaks\_killstreaks::isAssaultKillstreak( streak ) ) - { - continue; - } - } - } - - answers[ answers.size ] = streak; - chooseStreaks[ streak ] = true; - availUnlocks--; - - if ( answers.size > 2 ) - { - break; - } - } - - return answers; -} - -/* - returns if killstreak is going to have the same kill cost -*/ -isColidingKillstreak( killstreaks, killstreak ) -{ - ksVal = getKillsNeededForStreak( killstreak ); - - for ( i = 0; i < killstreaks.size; i++ ) - { - ks = killstreaks[ i ]; - - if ( ks == "" ) - { - continue; - } - - if ( ks == "none" ) - { - continue; - } - - ksV = getKillsNeededForStreak( ks ); - - if ( ksV <= 0 ) - { - continue; - } - - if ( ksV != ksVal ) - { - continue; - } - - return true; - } - - return false; -} - -/* - sets up all classes for a bot -*/ -setClasses() -{ - n = 5; - - if ( !self is_bot() ) - { - n = 15; - } - - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); - - if ( RandomFloatRange( 0, 1 ) < ( ( rank / level.maxRank ) + 0.1 ) ) - { - self.pers[ "bots" ][ "unlocks" ][ "ghillie" ] = true; - self.pers[ "bots" ][ "behavior" ][ "quickscope" ] = true; - } - - whereToSave = "customClasses"; - - if ( getDvarInt( "xblive_privatematch" ) ) - { - whereToSave = "privateMatchCustomClasses"; - } - - for ( i = 0; i < n; i++ ) - { - primary = chooseRandomPrimary(); - primaryBuff = chooseRandomBuff( primary ); - primaryAtts = chooseRandomAttachmentComboForGun( primary ); - primaryReticle = chooseRandomReticle(); - primaryCamo = chooseRandomCamo(); - - perk2 = chooseRandomPerk( "perk2" ); - - secondary = chooseRandomSecondary(); - - if ( perk2 == "specialty_twoprimaries" ) - { - secondary = chooseRandomPrimary(); - - while ( secondary == primary ) - { - secondary = chooseRandomPrimary(); - } - } - - secondaryBuff = chooseRandomBuff( secondary ); - secondaryAtts = chooseRandomAttachmentComboForGun( secondary ); - secondaryReticle = chooseRandomReticle(); - secondaryCamo = chooseRandomCamo(); - - if ( perk2 != "specialty_twoprimaries" ) - { - secondaryReticle = "none"; - secondaryCamo = "none"; - secondaryAtts[ 1 ] = "none"; - } - else if ( !isDefined( self.pers[ "bots" ][ "unlocks" ][ "upgraded_specialty_twoprimaries" ] ) ) - { - secondaryAtts[ 0 ] = "none"; - secondaryAtts[ 1 ] = "none"; - } - - perk1 = chooseRandomPerk( "perk1" ); - perk3 = chooseRandomPerk( "perk3" ); - deathstreak = chooseRandomPerk( "perk4" ); - equipment = chooseRandomGrenade(); - tactical = chooseRandomTactical(); - - perks = []; - perks[ perk1 ] = true; - perks[ perk2 ] = true; - perks[ perk3 ] = true; - - ksType = chooseRandomPerk( "perk5" ); - killstreaks = chooseRandomKillstreaks( ksType, perks ); - - self setPlayerData( whereToSave, i, "weaponSetups", 0, "weapon", primary ); - self setPlayerData( whereToSave, i, "weaponSetups", 0, "attachment", 0, primaryAtts[ 0 ] ); - self setPlayerData( whereToSave, i, "weaponSetups", 0, "attachment", 1, primaryAtts[ 1 ] ); - self setPlayerData( whereToSave, i, "weaponSetups", 0, "camo", primaryCamo ); - self setPlayerData( whereToSave, i, "weaponSetups", 0, "reticle", primaryReticle ); - self setPlayerData( whereToSave, i, "weaponSetups", 0, "buff", primaryBuff ); - - self setPlayerData( whereToSave, i, "weaponSetups", 1, "weapon", secondary ); - self setPlayerData( whereToSave, i, "weaponSetups", 1, "attachment", 0, secondaryAtts[ 0 ] ); - self setPlayerData( whereToSave, i, "weaponSetups", 1, "attachment", 1, secondaryAtts[ 1 ] ); - self setPlayerData( whereToSave, i, "weaponSetups", 1, "camo", secondaryCamo ); - self setPlayerData( whereToSave, i, "weaponSetups", 1, "reticle", secondaryReticle ); - self setPlayerData( whereToSave, i, "weaponSetups", 1, "buff", secondaryBuff ); - - self setPlayerData( whereToSave, i, "perks", 0, equipment ); - self setPlayerData( whereToSave, i, "perks", 1, perk1 ); - self setPlayerData( whereToSave, i, "perks", 2, perk2 ); - self setPlayerData( whereToSave, i, "perks", 3, perk3 ); - self setPlayerData( whereToSave, i, "deathstreak", deathstreak ); - self setPlayerData( whereToSave, i, "perks", 6, tactical ); - - self setPlayerData( whereToSave, i, "perks", 5, ksType ); - - playerData = undefined; - - switch ( ksType ) - { - case "streaktype_support": - playerData = "defenseStreaks"; - break; - - case "streaktype_specialist": - playerData = "specialistStreaks"; - break; - - default: - playerData = "assaultStreaks"; - break; - } - - self setPlayerData( whereToSave, i, playerData, 0, killstreaks[ 0 ] ); - self setPlayerData( whereToSave, i, playerData, 1, killstreaks[ 1 ] ); - self setPlayerData( whereToSave, i, playerData, 2, killstreaks[ 2 ] ); - } -} - -/* - The callback for when the bot gets killed. -*/ -onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) -{ - self.killerLocation = undefined; - self.lastKiller = undefined; - - if ( !IsDefined( self ) || !isDefined( self.team ) ) - { - return; - } - - if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) - { - return; - } - - if ( iDamage <= 0 ) - { - return; - } - - if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) - { - return; - } - - if ( eAttacker == self ) - { - return; - } - - if ( level.teamBased && eAttacker.team == self.team ) - { - return; - } - - if ( !IsDefined( eInflictor ) || eInflictor.classname != "player" ) - { - return; - } - - if ( !isAlive( eAttacker ) ) - { - return; - } - - self.killerLocation = eAttacker.origin; - self.lastKiller = eAttacker; -} - -/* - The callback for when the bot gets damaged. -*/ -onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) -{ - if ( !IsDefined( self ) || !isDefined( self.team ) ) - { - return; - } - - if ( !isAlive( self ) ) - { - return; - } - - if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) - { - return; - } - - if ( iDamage <= 0 ) - { - return; - } - - if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) - { - return; - } - - if ( eAttacker == self ) - { - return; - } - - if ( level.teamBased && eAttacker.team == self.team ) - { - return; - } - - if ( !IsDefined( eInflictor ) || eInflictor.classname != "player" ) - { - return; - } - - if ( !isAlive( eAttacker ) ) - { - return; - } - - if ( !isSubStr( sWeapon, "_silencer" ) ) - { - self bot_cry_for_help( eAttacker ); - } - - self SetAttacker( eAttacker ); -} - -/* - When the bot gets attacked, have the bot ask for help from teammates. -*/ -bot_cry_for_help( attacker ) -{ - if ( !level.teamBased ) - { - return; - } - - theTime = GetTime(); - - if ( IsDefined( self.help_time ) && theTime - self.help_time < 1000 ) - { - return; - } - - self.help_time = theTime; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( !player is_bot() ) - { - continue; - } - - if ( !isDefined( player.team ) ) - { - continue; - } - - if ( !IsAlive( player ) ) - { - continue; - } - - if ( player == self ) - { - continue; - } - - if ( player.team != self.team ) - { - continue; - } - - dist = player.pers[ "bots" ][ "skill" ][ "help_dist" ]; - dist *= dist; - - if ( DistanceSquared( self.origin, player.origin ) > dist ) - { - continue; - } - - if ( RandomInt( 100 ) < 50 ) - { - self SetAttacker( attacker ); - - if ( RandomInt( 100 ) > 70 ) - { - break; - } - } - } -} - -/* - watches when the bot enters a killcam -*/ -onKillcam() -{ - level endon( "game_ended" ); - self endon( "disconnect" ); - - for ( ;; ) - { - self waittill( "begin_killcam" ); - - self thread doKillcamStuff(); - } -} - -/* - bots use copy cat and skip killcams -*/ -doKillcamStuff() -{ - self endon( "disconnect" ); - self endon( "killcam_ended" ); - - self BotNotifyBotEvent( "killcam", "start" ); - - wait 0.5 + randomInt( 3 ); - - wait 0.1; - - self notify( "abort_killcam" ); - - self BotNotifyBotEvent( "killcam", "stop" ); -} - -/* - Selects a class for the bot. -*/ -classWatch() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - while ( !isdefined( self.pers[ "team" ] ) || !allowClassChoice() ) - { - wait .05; - } - - wait 0.5; - - if ( !isValidClass( self.class ) || !isDefined( self.bot_change_class ) ) - { - self notify( "menuresponse", game[ "menu_changeclass" ], self chooseRandomClass() ); - } - - self.bot_change_class = true; - - while ( isdefined( self.pers[ "team" ] ) && isValidClass( self.class ) && isDefined( self.bot_change_class ) ) - { - wait .05; - } - } -} - -/* - Any recipe classes -*/ -anyMatchRuleDefaultClass( team ) -{ - if ( !isUsingMatchRulesData() ) - { - return false; - } - - for ( i = 0; i < 5; i++ ) - { - if ( GetMatchRulesData( "defaultClasses", team, i, "class", "inUse" ) ) - { - return true; - } - } - - return false; -} - -/* - Chooses a random class -*/ -chooseRandomClass( ) -{ - if ( self.team != "axis" && self.team != "allies" ) - { - return ""; - } - - reasonable = getDvarInt( "bots_loadout_reasonable" ); - class = ""; - rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ) + 1; - - if ( rank < 4 || ( randomInt( 100 ) < 2 && !reasonable ) || ( isUsingMatchRulesData() && !level.matchRules_allowCustomClasses ) ) - { - while ( class == "" ) - { - switch ( randomInt( 5 ) ) - { - case 0: - if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 0, "class", "inUse" ) ) - { - class = self.team + "_recipe1"; - } - else if ( !anyMatchRuleDefaultClass( self.team ) ) - { - class = "class0"; - } - - break; - - case 1: - if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 1, "class", "inUse" ) ) - { - class = self.team + "_recipe2"; - } - else if ( !anyMatchRuleDefaultClass( self.team ) ) - { - class = "class1"; - } - - break; - - case 2: - if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 2, "class", "inUse" ) ) - { - class = self.team + "_recipe3"; - } - else if ( !anyMatchRuleDefaultClass( self.team ) ) - { - class = "class2"; - } - - break; - - case 3: - if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 3, "class", "inUse" ) ) - { - class = self.team + "_recipe4"; - } - else if ( rank >= 2 && !anyMatchRuleDefaultClass( self.team ) ) - { - class = "class3"; - } - - break; - - case 4: - if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 4, "class", "inUse" ) ) - { - class = self.team + "_recipe5"; - } - else if ( rank >= 3 && !anyMatchRuleDefaultClass( self.team ) ) - { - class = "class4"; - } - - break; - } - } - } - else - { - class = "custom" + ( randomInt( 5 ) + 1 ); - } - - return class; -} - -/* - Makes sure the bot is on a team. -*/ -teamWatch() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - while ( !isdefined( self.pers[ "team" ] ) || !allowTeamChoice() ) - { - wait .05; - } - - wait 0.1; - - if ( self.team != "axis" && self.team != "allies" ) - { - self notify( "menuresponse", game[ "menu_team" ], getDvar( "bots_team" ) ); - } - - while ( isdefined( self.pers[ "team" ] ) ) - { - wait .05; - } - } -} - -/* - Updates the bot's difficulty variables. -*/ -difficulty() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - if ( GetDvarInt( "bots_skill" ) != 9 ) - { - switch ( self.pers[ "bots" ][ "skill" ][ "base" ] ) - { - case 1: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.6; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 500; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 600; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 750; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.7; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 2500; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.75; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 0; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.9; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 1; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1.5; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 4; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 2; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 0; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 30; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 20; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 0; - break; - - case 2: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.55; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 800; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1250; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.65; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 3000; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.65; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 500; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.75; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.75; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 3; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1.5; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri,j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 15; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 45; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 15; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 10; - break; - - case 3: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.4; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 750; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 500; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 2000; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.6; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 4000; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 2250; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 750; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.65; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.65; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.75; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2.5; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 20; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 20; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 50; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 25; - break; - - case 4: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.3; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 600; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 400; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 2000; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 3000; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.55; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 5000; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 3350; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.35; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1000; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.75; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head,j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 30; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 25; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 55; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 35; - break; - - case 5: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 500; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 300; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 3000; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 4000; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 7500; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 5000; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1500; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.4; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.35; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.35; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1.5; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 40; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 35; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 60; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 50; - break; - - case 6: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.2; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 250; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 150; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 4000; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 5000; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.45; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 10000; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 7500; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.2; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 2000; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.25; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head,j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 50; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 45; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 65; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 75; - break; - - case 7: - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.1; - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 100; - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50; - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 4000; - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 7500; - self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.4; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 15000; - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 10000; - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05; - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 3000; - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.1; - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0; - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0; - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 0; - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.05; - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head"; - self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; - self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 65; - self.pers[ "bots" ][ "behavior" ][ "nade" ] = 65; - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 70; - self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 5; - self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; - self.pers[ "bots" ][ "behavior" ][ "jump" ] = 90; - break; - } - } - - wait 5; - } -} - -/* - Sets the bot difficulty. -*/ -set_diff() -{ - rankVar = GetDvarInt( "bots_skill" ); - - switch ( rankVar ) - { - case 0: - self.pers[ "bots" ][ "skill" ][ "base" ] = Round( random_normal_distribution( 3.5, 1.75, 1, 7 ) ); - break; - - case 8: - break; - - case 9: - self.pers[ "bots" ][ "skill" ][ "base" ] = randomIntRange( 1, 7 ); - self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.05 * randomIntRange( 1, 20 ); - self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 50 * randomInt( 100 ); - self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50 * randomInt( 100 ); - self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 50 * randomInt( 100 ); - self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 50 * randomInt( 100 ); - self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 50 * randomInt( 100 ); - self.pers[ "bots" ][ "skill" ][ "fov" ] = randomFloatRange( -1, 1 ); - - randomNum = randomIntRange( 500, 25000 ); - self.pers[ "bots" ][ "skill" ][ "dist_start" ] = randomNum; - self.pers[ "bots" ][ "skill" ][ "dist_max" ] = randomNum * 2; - - self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05 * randomInt( 20 ); - self.pers[ "bots" ][ "skill" ][ "help_dist" ] = randomIntRange( 500, 25000 ); - self.pers[ "bots" ][ "skill" ][ "semi_time" ] = randomFloatRange( 0.05, 1 ); - self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = randomFloatRange( 0.05, 1 ); - self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = randomFloatRange( 0.05, 1 ); - self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = randomFloatRange( 0.05, 1 ); - self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = randomFloatRange( 0.05, 1 ); - self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head,j_spineupper,j_ankle_le,j_ankle_ri"; - - self.pers[ "bots" ][ "behavior" ][ "strafe" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "nade" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "sprint" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "camp" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "follow" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "crouch" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "switch" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "class" ] = randomInt( 100 ); - self.pers[ "bots" ][ "behavior" ][ "jump" ] = randomInt( 100 ); - break; - - default: - self.pers[ "bots" ][ "skill" ][ "base" ] = rankVar; - break; - } -} - -/* - Allows the bot to spawn when force respawn is disabled - Watches when the bot dies -*/ -onDeath() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - self waittill( "death" ); - - self.wantSafeSpawn = true; - self ClearScriptGoal(); - } -} - -/* - Watches when the bot is given a loadout -*/ -onGiveLoadout() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - self waittill( "giveLoadout", team, class, allowCopycat, setPrimarySpawnWeapon ); - - if ( !allowClassChoice() ) - { - continue; - } - - if ( !isDefined( team ) ) - { - team = self.team; - } - - if ( !isDefined( class ) ) - { - class = self.class; - } - - if ( !isDefined( allowCopycat ) ) - { - allowCopycat = false; - } - - if ( !isDefined( setPrimarySpawnWeapon ) ) - { - setPrimarySpawnWeapon = true; - } - - self botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ); - } -} - -/* - When the bot spawns. -*/ -onSpawned() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - self waittill( "spawned_player" ); - - if ( randomInt( 100 ) <= self.pers[ "bots" ][ "behavior" ][ "class" ] ) - { - self.bot_change_class = undefined; - } - - self.bot_lock_goal = false; - self.help_time = undefined; - self.bot_was_follow_script_update = undefined; - self.bot_stuck_on_carepackage = undefined; - - if ( getDvarInt( "bots_play_obj" ) ) - { - self thread bot_dom_cap_think(); - } - } -} - -/* - When the bot spawned, after the difficulty wait. Start the logic for the bot. -*/ -onBotSpawned() -{ - self endon( "disconnect" ); - level endon( "game_ended" ); - - for ( ;; ) - { - self waittill( "bot_spawned" ); - - self thread start_bot_threads(); - } -} - -/* - Starts all the bot thinking -*/ -start_bot_threads() -{ - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "death" ); - - gameFlagWait( "prematch_done" ); - - // inventory usage - if ( getDvarInt( "bots_play_killstreak" ) ) - { - self thread bot_killstreak_think(); - self thread bot_box_think(); - self thread bot_watch_use_remote_turret(); - } - - self thread bot_weapon_think(); - self thread doReloadCancel(); - - // script targeting - if ( getDvarInt( "bots_play_target_other" ) ) - { - self thread bot_target_vehicle(); - self thread bot_equipment_kill_think(); - self thread bot_turret_think(); - } - - // airdrop - if ( getDvarInt( "bots_play_take_carepackages" ) ) - { - self thread bot_watch_stuck_on_crate(); - self thread bot_crate_think(); - } - - // awareness - self thread bot_revenge_think(); - self thread bot_uav_think(); - self thread bot_listen_to_steps(); - self thread follow_target(); - - // camp and follow - if ( getDvarInt( "bots_play_camp" ) ) - { - self thread bot_think_follow(); - self thread bot_think_camp(); - } - - // nades - if ( getDvarInt( "bots_play_nade" ) ) - { - self thread bot_jav_loc_think(); - self thread bot_use_tube_think(); - self thread bot_use_grenade_think(); - self thread bot_use_equipment_think(); - self thread bot_watch_riot_weapons(); - self thread bot_watch_think_mw2(); // bots play mw2 - } - - // obj - if ( getDvarInt( "bots_play_obj" ) ) - { - self thread bot_dom_def_think(); - self thread bot_dom_spawn_kill_think(); - - self thread bot_hq(); - - self thread bot_cap(); - - self thread bot_sab(); - - self thread bot_sd_defenders(); - self thread bot_sd_attackers(); - - self thread bot_dem_attackers(); - self thread bot_dem_defenders(); - self thread bot_dem_overtime(); - - self thread bot_gtnw(); - self thread bot_oneflag(); - self thread bot_arena(); - self thread bot_vip(); - - self thread bot_conf(); - self thread bot_grnd(); - self thread bot_tdef(); - - self thread bot_infect(); - } -} - -/* - Increments the number of bots approching the obj, decrements when needed - Used for preventing too many bots going to one obj, or unreachable objs -*/ -bot_inc_bots( obj, unreach ) -{ - level endon( "game_ended" ); - self endon( "bot_inc_bots" ); - - if ( !isDefined( obj ) ) - { - return; - } - - if ( !isDefined( obj.bots ) ) - { - obj.bots = 0; - } - - obj.bots++; - - ret = self waittill_any_return( "death", "disconnect", "bad_path", "goal", "new_goal" ); - - if ( isDefined( obj ) && ( ret != "bad_path" || !isDefined( unreach ) ) ) - { - obj.bots--; - } -} - -/* - Watches when the bot is touching the obj and calls 'goal' -*/ -bots_watch_touch_obj( obj ) -{ - self endon ( "death" ); - self endon ( "disconnect" ); - self endon ( "bad_path" ); - self endon ( "goal" ); - self endon ( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( obj ) ) - { - self notify( "bad_path" ); - return; - } - - if ( self IsTouching( obj ) ) - { - self notify( "goal" ); - return; - } - } -} - -/* - Watches while the obj is being carried, calls 'goal' when complete -*/ -bot_escort_obj( obj, carrier ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( obj ) ) - { - break; - } - - if ( !isDefined( obj.carrier ) || carrier == obj.carrier ) - { - break; - } - } - - self notify( "goal" ); -} - -/* - Watches while the obj is not being carried, calls 'goal' when complete -*/ -bot_get_obj( obj ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( obj ) ) - { - break; - } - - if ( isDefined( obj.carrier ) ) - { - break; - } - } - - self notify( "goal" ); -} - -/* - bots will defend their site from a planter/defuser -*/ -bot_defend_site( site ) -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !site isInUse() ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots will go plant the bomb -*/ -bot_go_plant( plant ) -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 1; - - if ( level.bombPlanted ) - { - break; - } - - if ( self isTouching( plant.trigger ) ) - { - break; - } - } - - if ( level.bombPlanted ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Bots will go defuse the bomb -*/ -bot_go_defuse( plant ) -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 1; - - if ( !level.bombPlanted ) - { - break; - } - - if ( self isTouching( plant.trigger ) ) - { - break; - } - } - - if ( !level.bombPlanted ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Fires the bots weapon until told to stop -*/ -fire_current_weapon() -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "weapon_change" ); - self endon( "stop_firing_weapon" ); - - for ( ;; ) - { - self thread BotPressAttack( 0.05 ); - wait 0.1; - } -} - -/* - Changes to the weap -*/ -changeToWeapon( weap ) -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - if ( !self HasWeapon( weap ) ) - { - return false; - } - - self switchToWeapon( weap ); - - if ( self GetCurrentWeapon() == weap ) - { - return true; - } - - self waittill_any_timeout( 5, "weapon_change" ); - - return ( self GetCurrentWeapon() == weap ); -} - -/* - Bots throw the grenade -*/ -botThrowGrenade( nade, time ) -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - if ( !self GetAmmoCount( nade ) ) - { - return false; - } - - if ( isSecondaryGrenade( nade ) ) - { - self thread BotPressSmoke( time ); - } - else - { - self thread BotPressFrag( time ); - } - - ret = self waittill_any_timeout( 5, "grenade_fire" ); - - return ( ret == "grenade_fire" ); -} - -/* - Gets the object thats the closest in the array -*/ -bot_array_nearest_curorigin( array ) -{ - result = undefined; - - for ( i = 0; i < array.size; i++ ) - { - if ( !isDefined( result ) || DistanceSquared( self.origin, array[ i ].curorigin ) < DistanceSquared( self.origin, result.curorigin ) ) - } - - result = array[ i ]; - - return result; -} - -/* - Returns an weapon thats a rocket with ammo -*/ -getRocketAmmo() -{ - answer = self getLockonAmmo(); - - if ( isDefined( answer ) ) - { - return answer; - } - - if ( self getAmmoCount( "rpg_mp" ) ) - { - answer = "rpg_mp"; - } - - return answer; -} - -/* - Returns a weapon thats lockon with ammo -*/ -getLockonAmmo() -{ - answer = undefined; - - if ( self getAmmoCount( "iw5_smaw_mp" ) ) - { - answer = "iw5_smaw_mp"; - } - - if ( self getAmmoCount( "stinger_mp" ) ) - { - answer = "stinger_mp"; - } - - if ( self getAmmoCount( "javelin_mp" ) ) - { - answer = "javelin_mp"; - } - - return answer; -} - -/* - Clears goal when events death -*/ -stop_go_target_on_death( tar ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "new_goal" ); - self endon( "bad_path" ); - self endon( "goal" ); - - tar waittill_either( "death", "disconnect" ); - - self ClearScriptGoal(); -} - -/* - Goes to the target's location if it had one -*/ -follow_target() -{ - self endon( "death" ); - self endon( "disconnect" ); - - for ( ;; ) - { - wait 1; - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - continue; - } - - if ( !self HasThreat() ) - { - continue; - } - - threat = self GetThreat(); - - if ( !isPlayer( threat ) ) - { - continue; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "follow" ] * 5 ) - { - continue; - } - - self BotNotifyBotEvent( "follow_threat", "start", threat ); - - self SetScriptGoal( threat.origin, 64 ); - self thread stop_go_target_on_death( threat ); - - if ( self waittill_any_return( "new_goal", "goal", "bad_path" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "follow_threat", "stop", threat ); - } -} - -/* - Used so that variables are free'd (in gsc, loops retain their variables they create, eats up child0 vars) -*/ -bot_think_camp_loop() -{ - campSpot = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "camp" ), 1024 ) ) ); - - if ( !isDefined( campSpot ) ) - { - return; - } - - self SetScriptGoal( campSpot.origin, 16 ); - - time = randomIntRange( 10, 20 ); - - self BotNotifyBotEvent( "camp", "go", campSpot, time ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" ) - { - return; - } - - self BotNotifyBotEvent( "camp", "start", campSpot, time ); - - self thread killCampAfterTime( time ); - self CampAtSpot( campSpot.origin, campSpot.origin + AnglesToForward( campSpot.angles ) * 2048 ); - - self BotNotifyBotEvent( "camp", "stop", campSpot, time ); -} - -/* - Bot logic for bot determining to camp. -*/ -bot_think_camp() -{ - self endon( "death" ); - self endon( "disconnect" ); - - for ( ;; ) - { - wait randomintrange( 4, 7 ); - - if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) - { - continue; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "camp" ] ) - { - continue; - } - - self bot_think_camp_loop(); - } -} - -/* - Kills the camping thread when time -*/ -killCampAfterTime( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "kill_camp_bot" ); - - wait time + 0.05; - self ClearScriptGoal(); - self ClearScriptAimPos(); - - self notify( "kill_camp_bot" ); -} - -/* - Kills the camping thread when ent gone -*/ -killCampAfterEntGone( ent ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "kill_camp_bot" ); - - for ( ;; ) - { - wait 0.05; - - if ( !isDefined( ent ) ) - { - break; - } - } - - self ClearScriptGoal(); - self ClearScriptAimPos(); - - self notify( "kill_camp_bot" ); -} - -/* - Camps at the spot -*/ -CampAtSpot( origin, anglePos ) -{ - self endon( "kill_camp_bot" ); - - self SetScriptGoal( origin, 64 ); - - if ( isDefined( anglePos ) ) - { - self SetScriptAimPos( anglePos ); - } - - self waittill( "new_goal" ); - self ClearScriptAimPos(); - - self notify( "kill_camp_bot" ); -} - -/* - Waits for the bot to stop moving -*/ -bot_wait_stop_move() -{ - while ( !self isOnGround() || lengthSquared( self getVelocity() ) > 1 ) - { - wait 0.25; - } -} - -/* - Loop -*/ -bot_think_follow_loop() -{ - follows = []; - distSq = self.pers[ "bots" ][ "skill" ][ "help_dist" ] * self.pers[ "bots" ][ "skill" ][ "help_dist" ]; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( player.team != self.team ) - { - continue; - } - - if ( DistanceSquared( player.origin, self.origin ) > distSq ) - { - continue; - } - - follows[ follows.size ] = player; - } - - toFollow = random( follows ); - follows = undefined; - - if ( !isDefined( toFollow ) ) - { - return; - } - - time = randomIntRange( 10, 20 ); - - self BotNotifyBotEvent( "follow", "start", toFollow, time ); - - self thread killFollowAfterTime( time ); - self followPlayer( toFollow ); - - self BotNotifyBotEvent( "follow", "stop", toFollow, time ); -} - -/* - Bot logic for bot determining to follow another player. -*/ -bot_think_follow() -{ - self endon( "death" ); - self endon( "disconnect" ); - - for ( ;; ) - { - wait randomIntRange( 3, 5 ); - - if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) - { - continue; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "follow" ] ) - { - continue; - } - - if ( !level.teamBased ) - { - continue; - } - - self bot_think_follow_loop(); - } -} - -/* - Kills follow when new goal -*/ -watchForFollowNewGoal() -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "kill_follow_bot" ); - - for ( ;; ) - { - self waittill( "new_goal" ); - - if ( !isDefined( self.bot_was_follow_script_update ) ) - { - break; - } - } - - self ClearScriptAimPos(); - self notify( "kill_follow_bot" ); -} - -/* - Kills follow when time -*/ -killFollowAfterTime( time ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "kill_follow_bot" ); - - wait time; - - self ClearScriptGoal(); - self ClearScriptAimPos(); - self notify( "kill_follow_bot" ); -} - -/* - Determine bot to follow a player -*/ -followPlayer( who ) -{ - self endon( "kill_follow_bot" ); - - self thread watchForFollowNewGoal(); - - for ( ;; ) - { - wait 0.05; - - if ( !isDefined( who ) || !isReallyAlive( who ) ) - { - break; - } - - self SetScriptAimPos( who.origin + ( 0, 0, 42 ) ); - myGoal = self GetScriptGoal(); - - if ( isDefined( myGoal ) && DistanceSquared( myGoal, who.origin ) < 64 * 64 ) - { - continue; - } - - self.bot_was_follow_script_update = true; - self SetScriptGoal( who.origin, 32 ); - waittillframeend; - self.bot_was_follow_script_update = undefined; - - self waittill_either( "goal", "bad_path" ); - } - - self ClearScriptGoal(); - self ClearScriptAimPos(); - - self notify( "kill_follow_bot" ); -} - -/* - Loop -*/ -bot_use_tube_think_loop( data ) -{ - if ( data.doFastContinue ) - { - data.doFastContinue = false; - } - else - { - wait randomintRange( 3, 7 ); - - chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; - - if ( chance > 20 ) - { - chance = 20; - } - - if ( randomInt( 100 ) > chance ) - { - return; - } - } - - tube = self getValidTube(); - - if ( !isDefined( tube ) ) - { - return; - } - - if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) - { - return; - } - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self IsBotFragging() || self IsBotSmoking() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - return; - } - - loc = undefined; - - if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "tube" ) ) ) - { - tubeWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "tube" ), 1024 ) ) ); - - myEye = self GetEye(); - - if ( !isDefined( tubeWp ) || self HasScriptGoal() || self.bot_lock_goal ) - { - traceForward = BulletTrace( myEye, myEye + AnglesToForward( self GetPlayerAngles() ) * 900 * 5, false, self ); - - loc = traceForward[ "position" ]; - dist = DistanceSquared( self.origin, loc ); - - if ( dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance * 5 ) - { - return; - } - - if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - - if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - - loc += ( 0, 0, dist / 16000 ); - } - else - { - self BotNotifyBotEvent( "tube", "go", tubeWp, tube ); - - self SetScriptGoal( tubeWp.origin, 16 ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" ) - { - return; - } - - data.doFastContinue = true; - return; - } - } - else - { - tubeWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "tube" ) ) ); - loc = tubeWp.origin + AnglesToForward( tubeWp.angles ) * 2048; - } - - if ( !isDefined( loc ) ) - { - return; - } - - self BotNotifyBotEvent( "tube", "start", loc, tube ); - - self SetScriptAimPos( loc ); - self BotStopMoving( true ); - wait 1; - - if ( self changeToWeapon( tube ) ) - { - self thread fire_current_weapon(); - self waittill_any_timeout( 5, "missile_fire", "weapon_change" ); - self notify( "stop_firing_weapon" ); - } - - self ClearScriptAimPos(); - self BotStopMoving( false ); -} - -/* - Bots thinking of using a noobtube -*/ -bot_use_tube_think() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.doFastContinue = false; - - for ( ;; ) - { - self bot_use_tube_think_loop( data ); - } -} - -/* - Loop -*/ -bot_use_equipment_think_loop( data ) -{ - if ( data.doFastContinue ) - { - data.doFastContinue = false; - } - else - { - wait randomintRange( 2, 4 ); - - chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; - - if ( chance > 20 ) - { - chance = 20; - } - - if ( randomInt( 100 ) > chance ) - { - return; - } - } - - nade = undefined; - - if ( self GetAmmoCount( "claymore_mp" ) ) - { - nade = "claymore_mp"; - } - - if ( self GetAmmoCount( "flare_mp" ) ) - { - nade = "flare_mp"; - } - - if ( self GetAmmoCount( "c4_mp" ) ) - { - nade = "c4_mp"; - } - - if ( self GetAmmoCount( "bouncingbetty_mp" ) ) - { - nade = "bouncingbetty_mp"; - } - - if ( self GetAmmoCount( "portable_radar_mp" ) ) - { - nade = "portable_radar_mp"; - } - - if ( self GetAmmoCount( "scrambler_mp" ) ) - { - nade = "scrambler_mp"; - } - - if ( self GetAmmoCount( "trophy_mp" ) ) - { - nade = "trophy_mp"; - } - - if ( !isDefined( nade ) ) - { - return; - } - - if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) - { - return; - } - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self IsBotFragging() || self IsBotSmoking() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) - { - return; - } - - loc = undefined; - - if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "claymore" ) ) ) - { - clayWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "claymore" ), 1024 ) ) ); - - if ( !isDefined( clayWp ) || self HasScriptGoal() || self.bot_lock_goal ) - { - myEye = self GetEye(); - loc = myEye + AnglesToForward( self GetPlayerAngles() ) * 256; - - if ( !bulletTracePassed( myEye, loc, false, self ) ) - { - return; - } - } - else - { - self BotNotifyBotEvent( "equ", "go", clayWp, nade ); - - self SetScriptGoal( clayWp.origin, 16 ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" ) - { - return; - } - - data.doFastContinue = true; - return; - } - } - else - { - clayWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "claymore" ) ) ); - loc = clayWp.origin + AnglesToForward( clayWp.angles ) * 2048; - } - - if ( !isDefined( loc ) ) - { - return; - } - - self BotNotifyBotEvent( "equ", "start", loc, nade ); - - self SetScriptAimPos( loc ); - self BotStopMoving( true ); - wait 1; - - self botThrowGrenade( nade, 0.05 ); - - self ClearScriptAimPos(); - self BotStopMoving( false ); -} - -/* - Bots thinking of using claymores and TIs -*/ -bot_use_equipment_think() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.doFastContinue = false; - - for ( ;; ) - { - self bot_use_equipment_think_loop( data ); - } -} - -/* - Loop -*/ -bot_use_grenade_think_loop( data ) -{ - if ( data.doFastContinue ) - { - data.doFastContinue = false; - } - else - { - wait randomintRange( 4, 7 ); - - chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; - - if ( chance > 20 ) - { - chance = 20; - } - - if ( randomInt( 100 ) > chance ) - { - return; - } - } - - nade = self getValidGrenade(); - - if ( !isDefined( nade ) ) - { - return; - } - - if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) - { - return; - } - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self IsBotFragging() || self IsBotSmoking() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) - { - return; - } - - loc = undefined; - - if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "grenade" ) ) ) - { - nadeWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "grenade" ), 1024 ) ) ); - - myEye = self GetEye(); - - if ( !isDefined( nadeWp ) || self HasScriptGoal() || self.bot_lock_goal ) - { - traceForward = BulletTrace( myEye, myEye + AnglesToForward( self GetPlayerAngles() ) * 900, false, self ); - - loc = traceForward[ "position" ]; - dist = DistanceSquared( self.origin, loc ); - - if ( dist < level.bots_minGrenadeDistance || dist > level.bots_maxGrenadeDistance ) - { - return; - } - - if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - - if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - - loc += ( 0, 0, dist / 3000 ); - } - else - { - self BotNotifyBotEvent( "nade", "go", nadeWp, nade ); - - self SetScriptGoal( nadeWp.origin, 16 ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" ) - { - return; - } - - data.doFastContinue = true; - return; - } - } - else - { - nadeWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "grenade" ) ) ); - loc = nadeWp.origin + AnglesToForward( nadeWp.angles ) * 2048; - } - - if ( !isDefined( loc ) ) - { - return; - } - - self BotNotifyBotEvent( "nade", "start", loc, nade ); - - self SetScriptAimPos( loc ); - self BotStopMoving( true ); - wait 1; - - time = 0.5; - - if ( nade == "frag_grenade_mp" ) - { - time = 2; - } - - self botThrowGrenade( nade, time ); - - self ClearScriptAimPos(); - self BotStopMoving( false ); -} - -/* - Bots thinking of using grenades -*/ -bot_use_grenade_think() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.doFastContinue = false; - - for ( ;; ) - { - self bot_use_grenade_think_loop( data ); - } -} - -/* - Bots play mw2 -*/ -bot_watch_think_mw2_loop() -{ - tube = self getValidTube(); - - if ( !isDefined( tube ) ) - { - if ( self GetAmmoCount( "iw5_smaw_mp" ) ) - { - tube = "iw5_smaw_mp"; - } - else if ( self GetAmmoCount( "rpg_mp" ) ) - { - tube = "rpg_mp"; - } - else if ( self GetAmmoCount( "xm25_mp" ) ) - { - tube = "xm25_mp"; - } - else - { - return; - } - } - - if ( self GetCurrentWeapon() == tube ) - { - return; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "nade" ] ) - { - return; - } - - self thread ChangeToWeapon( tube ); -} - -/* - Bots play mw2 -*/ -bot_watch_think_mw2() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - for ( ;; ) - { - wait randomIntRange( 1, 4 ); - - if ( self BotIsFrozen() ) - { - continue; - } - - if ( self isDefusing() || self isPlanting() ) - { - continue; - } - - if ( self IsUsingRemote() ) - { - continue; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - continue; - } - - if ( self HasThreat() ) - { - continue; - } - - self bot_watch_think_mw2_loop(); - } -} - -/* - Loop -*/ -bot_watch_riot_weapons_loop() -{ - threat = self GetThreat(); - dist = DistanceSquared( threat.origin, self.origin ); - curWeap = self GetCurrentWeapon(); - - if ( randomInt( 2 ) ) - { - nade = self getValidGrenade(); - - if ( !isDefined( nade ) ) - { - return; - } - - if ( dist <= level.bots_minGrenadeDistance || dist >= level.bots_maxGrenadeDistance ) - { - return; - } - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "nade" ] ) - { - return; - } - - self botThrowGrenade( nade ); - } - else - { - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "switch" ] * 10 ) - { - return; - } - - weaponslist = self getweaponslistall(); - weap = ""; - - while ( weaponslist.size ) - { - weapon = weaponslist[ randomInt( weaponslist.size ) ]; - weaponslist = array_remove( weaponslist, weapon ); - - if ( !self getAmmoCount( weapon ) ) - { - continue; - } - - if ( !isWeaponPrimary( weapon ) ) - { - continue; - } - - if ( curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp" ) - { - continue; - } - - weap = weapon; - break; - } - - if ( weap == "" ) - { - return; - } - - self thread ChangeToWeapon( weap ); - } -} - -/* - Bots will use gremades/wweapons while having a target while using a shield -*/ -bot_watch_riot_weapons() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - for ( ;; ) - { - wait randomIntRange( 2, 4 ); - - if ( self BotIsFrozen() ) - { - continue; - } - - if ( self isDefusing() || self isPlanting() ) - { - continue; - } - - if ( self IsUsingRemote() ) - { - continue; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - continue; - } - - if ( !self HasThreat() ) - { - continue; - } - - if ( !self.hasRiotShieldEquipped ) - { - continue; - } - - self bot_watch_riot_weapons_loop(); - } -} - -/* - Loop -*/ -bot_jav_loc_think_loop( data ) -{ - if ( data.doFastContinue ) - { - data.doFastContinue = false; - } - else - { - wait randomintRange( 2, 4 ); - - chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; - - if ( chance > 20 ) - { - chance = 20; - } - - if ( randomInt( 100 ) > chance && self getCurrentWeapon() != "javelin_mp" ) - { - return; - } - } - - if ( !self GetAmmoCount( "javelin_mp" ) ) - { - return; - } - - if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) - { - return; - } - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - return; - } - - if ( self isEMPed() ) - { - return; - } - - loc = undefined; - - if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "javelin" ) ) ) - { - javWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "javelin" ), 1024 ) ) ); - - if ( !isDefined( javWp ) || self HasScriptGoal() || self.bot_lock_goal ) - { - traceForward = self maps\mp\_javelin::EyeTraceForward(); - - if ( !isDefined( traceForward ) ) - { - return; - } - - loc = traceForward[ 0 ]; - - if ( self maps\mp\_javelin::TargetPointTooClose( loc ) ) - { - return; - } - - if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - - if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) - { - return; - } - } - else - { - self BotNotifyBotEvent( "jav", "go", javWp ); - - self SetScriptGoal( javWp.origin, 16 ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" ) - { - return; - } - - data.doFastContinue = true; - return; - } - } - else - { - javWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "javelin" ) ) ); - loc = javWp.jav_point; - } - - if ( !isDefined( loc ) ) - { - return; - } - - self BotNotifyBotEvent( "jav", "start", loc ); - - self SetBotJavelinLocation( loc ); - - if ( self changeToWeapon( "javelin_mp" ) ) - { - self waittill_any_timeout( 10, "missile_fire", "weapon_change" ); - } - - self ClearBotJavelinLocation(); -} - -/* - BOts thinking of using javelins -*/ -bot_jav_loc_think() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.doFastContinue = false; - - for ( ;; ) - { - self bot_jav_loc_think_loop( data ); - } -} - -/* - Loop -*/ -bot_equipment_kill_think_loop() -{ - myteam = self.pers[ "team" ]; - hasSitrep = self _HasPerk( "specialty_detectexplosive" ); - grenades = getEntArray( "grenade", "classname" ); - myEye = self getEye(); - myAngles = self getPlayerAngles(); - dist = 512 * 512; - target = undefined; - - // check legacy nades, c4 and claymores - for ( i = 0; i < grenades.size; i++ ) - { - item = grenades[ i ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( !IsDefined( item.name ) ) - { - continue; - } - - if ( item.name != "c4_mp" && item.name != "claymore_mp" ) - { - continue; - } - - if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - - grenades = undefined; // clean up, reduces child1 vars - - // check for player stuff, tis and throphys and radars - if ( !IsDefined( target ) ) - { - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !isDefined( player.team ) ) - { - continue; - } - - if ( level.teamBased && player.team == myteam ) - { - continue; - } - - // check for thorphys - if ( isDefined( player.trophyArray ) ) - { - for ( h = 0; h < player.trophyArray.size; h++ ) - { - item = player.trophyArray[ h ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( !isDefined( item.bots ) ) - { - item.bots = 0; - } - - if ( item.bots >= 2 ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for ti - if ( !isDefined( target ) ) - { - for ( h = 0; h < 1; h++ ) - { - item = player.setSpawnPoint; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( !isDefined( item.bots ) ) - { - item.bots = 0; - } - - if ( item.bots >= 2 ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for radar - if ( !isDefined( target ) ) - { - for ( h = 0; h < 1; h++ ) - { - item = player.deployedPortableRadar; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( !isDefined( item.bots ) ) - { - item.bots = 0; - } - - if ( item.bots >= 2 ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - if ( isDefined( target ) ) - { - break; - } - } - } - - // check for ims - if ( !IsDefined( target ) ) - { - imsKeys = getArrayKeys( level.ims ); - - for ( i = 0; i < imsKeys.size; i++ ) - { - item = level.ims[ imsKeys[ i ] ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - - imsKeys = undefined; - } - - // check for vest - if ( !IsDefined( target ) ) - { - for ( i = 0; i < level.vest_boxes.size; i++ ) - { - item = level.vest_boxes[ i ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for jammers - if ( !IsDefined( target ) ) - { - for ( i = 0; i < level.scramblers.size; i++ ) - { - item = level.scramblers[ i ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - // check for mines - if ( !IsDefined( target ) ) - { - for ( i = 0; i < level.mines.size; i++ ) - { - item = level.mines[ i ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) - { - continue; - } - - if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) - { - continue; - } - - if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - target = item; - break; - } - } - } - - if ( !IsDefined( target ) ) - { - return; - } - - // must be ti - if ( isDefined( target.enemyTrigger ) && !self HasScriptGoal() && !self.bot_lock_goal ) - { - self BotNotifyBotEvent( "attack_equ", "go_ti", target ); - - self SetScriptGoal( target.origin, 64 ); - self thread bot_inc_bots( target, true ); - self thread bots_watch_touch_obj( target ); - - path = self waittill_any_return( "bad_path", "goal", "new_goal" ); - - if ( path != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( path != "goal" || !isDefined( target ) ) - { - return; - } - - if ( randomInt( 100 ) < self.pers[ "bots" ][ "behavior" ][ "camp" ] * 8 ) - { - self BotNotifyBotEvent( "attack_equ", "camp_ti", target ); - - self thread killCampAfterTime( randomIntRange( 10, 20 ) ); - self thread killCampAfterEntGone( target ); - self CampAtSpot( target.origin, target.origin + ( 0, 0, 42 ) ); - } - - if ( isDefined( target ) ) - { - self BotNotifyBotEvent( "attack_equ", "trigger_ti", target ); - self thread BotPressUse(); - } - - return; - } - - self BotNotifyBotEvent( "attack_equ", "start", target ); - - self SetScriptEnemy( target ); - self bot_equipment_attack( target ); - self ClearScriptEnemy(); - - self BotNotifyBotEvent( "attack_equ", "stop", target ); -} - -/* - Bots thinking of targeting equipment, c4, claymores and TIs -*/ -bot_equipment_kill_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon ( "game_ended" ); - - for ( ;; ) - { - wait( RandomIntRange( 1, 3 ) ); - - if ( self HasScriptEnemy() ) - { - continue; - } - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) - { - continue; - } - - self bot_equipment_kill_think_loop(); - } -} - -/* - Bots target the equipment for a time then stop -*/ -bot_equipment_attack( equ ) -{ - wait_time = RandomIntRange( 7, 10 ); - - for ( i = 0; i < wait_time; i++ ) - { - wait( 1 ); - - if ( !IsDefined( equ ) ) - { - return; - } - - if ( isDefined( equ.damageTaken ) && isDefined( equ.maxHealth ) ) - { - if ( equ.damageTaken >= equ.maxHealth ) - { - return; - } - } - } -} - -/* - Loop -*/ -bot_listen_to_steps_loop() -{ - dist = level.bots_listenDist; - - if ( self _hasPerk( "specialty_selectivehearing" ) ) - { - dist *= 1.4; - } - - dist *= dist; - - heard = undefined; - - for ( i = level.players.size - 1 ; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( level.teamBased && self.team == player.team ) - { - continue; - } - - if ( player.sessionstate != "playing" ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( lengthsquared( player getVelocity() ) < 20000 ) - { - continue; - } - - if ( distanceSquared( player.origin, self.origin ) > dist ) - { - continue; - } - - if ( player _hasPerk( "specialty_quieter" ) ) - { - continue; - } - - heard = player; - break; - } - - hasHeartbeat = ( isSubStr( self GetCurrentWeapon(), "_heartbeat" ) && ( ( !self IsEMPed() && !self isNuked() ) || self _hasPerk( "specialty_spygame" ) ) ); - heartbeatDist = 350 * 350; - - if ( !IsDefined( heard ) && hasHeartbeat ) - { - for ( i = level.players.size - 1 ; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( level.teamBased && self.team == player.team ) - { - continue; - } - - if ( player.sessionstate != "playing" ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( player _hasPerk( "specialty_heartbreaker" ) ) - { - continue; - } - - if ( distanceSquared( player.origin, self.origin ) > heartbeatDist ) - { - continue; - } - - if ( GetConeDot( player.origin, self.origin, self GetPlayerAngles() ) < 0.6 ) - { - continue; - } - - heard = player; - break; - } - } - - if ( !isDefined( heard ) ) - { - if ( self _hasPerk( "specialty_revenge" ) && isDefined( self.lastKilledBy ) ) - { - heard = self.lastKilledBy; - } - } - - if ( !IsDefined( heard ) ) - { - return; - } - - self BotNotifyBotEvent( "heard_target", "start", heard ); - - if ( bulletTracePassed( self getEye(), heard getTagOrigin( "j_spineupper" ), false, heard ) ) - { - self setAttacker( heard ); - return; - } - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - return; - } - - self SetScriptGoal( heard.origin, 64 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "heard_target", "stop", heard ); -} - -/* - Bots will listen to foot steps and target nearby targets -*/ -bot_listen_to_steps() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - wait 1; - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] < 3 ) - { - continue; - } - - self bot_listen_to_steps_loop(); - } -} - -/* - Loop -*/ -bot_uav_think_loop() -{ - hasAssPro = self _hasPerk( "specialty_spygame" ); - - if ( !hasAssPro ) - { - if ( self isEMPed() || self.bot_isScrambled || self isNuked() ) - { - return; - } - - if ( ( level.teamBased && level.activeCounterUAVs[ level.otherTeam[ self.team ] ] ) || ( !level.teamBased && self.isRadarBlocked ) ) - { - return; - } - } - - hasRadar = ( ( level.teamBased && level.activeUAVs[ self.team ] ) || ( !level.teamBased && level.activeUAVs[ self.guid ] ) ); - - if ( level.hardcoreMode && !hasRadar ) - { - return; - } - - dist = self.pers[ "bots" ][ "skill" ][ "help_dist" ]; - dist *= dist * 8; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !isDefined( player.team ) ) - { - continue; - } - - if ( player.sessionstate != "playing" ) - { - continue; - } - - if ( level.teambased && player.team == self.team ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - distFromPlayer = DistanceSquared( self.origin, player.origin ); - - if ( distFromPlayer > dist ) - { - continue; - } - - if ( ( !isSubStr( player getCurrentWeapon(), "_silencer" ) && player.bots_firing ) || ( hasRadar && !player _hasPerk( "specialty_coldblooded" ) ) || player maps\mp\perks\_perkfunctions::isPainted() || player.bot_isInRadar || player isJuggernaut() || isDefined( player.UAVRemoteMarkedBy ) ) - { - self BotNotifyBotEvent( "uav_target", "start", player ); - - distSq = self.pers[ "bots" ][ "skill" ][ "help_dist" ] * self.pers[ "bots" ][ "skill" ][ "help_dist" ]; - - if ( distFromPlayer < distSq && bulletTracePassed( self getEye(), player getTagOrigin( "j_spineupper" ), false, player ) ) - { - self SetAttacker( player ); - } - - if ( !self HasScriptGoal() && !self.bot_lock_goal ) - { - self SetScriptGoal( player.origin, 128 ); - self thread stop_go_target_on_death( player ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "uav_target", "stop", player ); - } - - break; - } - } -} - -/* - Bots will look at the uav and target targets -*/ -bot_uav_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - - for ( ;; ) - { - wait 0.75; - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 || self IsUsingRemote() ) - { - continue; - } - - self bot_uav_think_loop(); - } -} - -/* - bots will go to their target's kill location -*/ -bot_revenge_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) - { - return; - } - - if ( isDefined( self.lastKiller ) && isReallyAlive( self.lastKiller ) ) - { - if ( bulletTracePassed( self getEye(), self.lastKiller getTagOrigin( "j_spineupper" ), false, self.lastKiller ) ) - { - self setAttacker( self.lastKiller ); - } - } - - if ( !isDefined( self.killerLocation ) ) - { - return; - } - - loc = self.killerLocation; - - for ( ;; ) - { - wait( RandomIntRange( 1, 5 ) ); - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - return; - } - - if ( randomint( 100 ) < 75 ) - { - return; - } - - self BotNotifyBotEvent( "revenge", "start", loc, self.lastKiller ); - - self SetScriptGoal( loc, 64 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "revenge", "stop", loc, self.lastKiller ); - } -} - -/* - Watches the target's health, calls 'bad_path' -*/ -turret_death_monitor( turret ) -{ - self endon ( "death" ); - self endon ( "disconnect" ); - self endon ( "bad_path" ); - self endon ( "goal" ); - self endon ( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( turret ) ) - { - break; - } - - if ( turret.damageTaken >= turret.maxHealth ) - { - break; - } - - if ( isDefined( turret.carriedBy ) ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots will target the turret for a time -*/ -bot_turret_attack( enemy ) -{ - wait_time = RandomIntRange( 7, 10 ); - - for ( i = 0; i < wait_time; i++ ) - { - wait( 1 ); - - if ( !IsDefined( enemy ) ) - { - return; - } - - if ( enemy.damageTaken >= enemy.maxHealth ) - { - return; - } - - if ( isDefined( enemy.carriedBy ) ) - { - return; - } - - // if ( !BulletTracePassed( self getEye(), enemy.origin + ( 0, 0, 15 ), false, enemy ) ) - // return; - } -} - -/* - Loops -*/ -bot_turret_think_loop() -{ - myteam = self.pers[ "team" ]; - turretsKeys = getArrayKeys( level.turrets ); - - if ( turretsKeys.size == 0 ) - { - wait( randomintrange( 3, 5 ) ); - return; - } - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) - { - return; - } - - if ( self HasScriptEnemy() || self IsUsingRemote() ) - { - return; - } - - myEye = self GetEye(); - turret = undefined; - - for ( i = turretsKeys.size - 1; i >= 0; i-- ) - { - tempTurret = level.turrets[ turretsKeys[ i ] ]; - - if ( !isDefined( tempTurret ) ) - { - continue; - } - - if ( tempTurret.damageTaken >= tempTurret.maxHealth ) - { - continue; - } - - if ( isDefined( tempTurret.carriedBy ) ) - { - continue; - } - - if ( isDefined( tempTurret.owner ) && tempTurret.owner == self ) - { - continue; - } - - if ( level.teamBased && tempTurret.team == myteam ) - { - continue; - } - - if ( !bulletTracePassed( myEye, tempTurret.origin + ( 0, 0, 15 ), false, tempTurret ) ) - { - continue; - } - - turret = tempTurret; - } - - turretsKeys = undefined; - - if ( !isDefined( turret ) ) - { - return; - } - - forward = AnglesToForward( turret.angles ); - forward = VectorNormalize( forward ); - - delta = self.origin - turret.origin; - delta = VectorNormalize( delta ); - - dot = VectorDot( forward, delta ); - - facing = true; - - if ( dot < 0.342 ) // cos 70 degrees - { - facing = false; - } - - if ( turret isStunned() ) - { - facing = false; - } - - if ( self _hasPerk( "specialty_blindeye" ) ) - { - facing = false; - } - - if ( !isDefined( turret.sentryType ) || turret.sentryType == "sam_turret" ) - { - facing = false; - } - - if ( facing && !BulletTracePassed( myEye, turret.origin + ( 0, 0, 15 ), false, turret ) ) - { - return; - } - - if ( !IsDefined( turret.bots ) ) - { - turret.bots = 0; - } - - if ( turret.bots >= 2 ) - { - return; - } - - if ( !facing && !self HasScriptGoal() && !self.bot_lock_goal ) - { - self BotNotifyBotEvent( "turret_attack", "go", turret ); - - self SetScriptGoal( turret.origin, 32 ); - self thread bot_inc_bots( turret, true ); - self thread turret_death_monitor( turret ); - self thread bots_watch_touch_obj( turret ); - - if ( self waittill_any_return( "bad_path", "goal", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - - if ( !isDefined( turret ) ) - { - return; - } - - self BotNotifyBotEvent( "turret_attack", "start", turret ); - - self SetScriptEnemy( turret, ( 0, 0, 25 ) ); - self bot_turret_attack( turret ); - self ClearScriptEnemy(); - - self BotNotifyBotEvent( "turret_attack", "stop", turret ); -} - -/* - Bots will think when to target a turret -*/ -bot_turret_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon ( "game_ended" ); - - for ( ;; ) - { - wait( 1 ); - - self bot_turret_think_loop(); - } -} - -/* - Loops -*/ -bot_box_think_loop( data ) -{ - ret = "bot_check_box_think"; - - if ( data.first ) - { - data.first = false; - } - else - { - ret = self waittill_any_timeout( randomintrange( 3, 5 ), "bot_check_box_think" ); - } - - if ( RandomInt( 100 ) < 20 && ret != "bot_check_box_think" ) - { - return; - } - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - return; - } - - if ( self HasThreat() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() || self BotIsFrozen() ) - { - return; - } - - if ( self inLastStand() ) - { - return; - } - - if ( isDefined( self.hasLightArmor ) && self.hasLightArmor ) - { - return; - } - - if ( self isJuggernaut() ) - { - return; - } - - box = undefined; - myteam = self.pers[ "team" ]; - - dist = 2048 * 2048; - - for ( i = 0; i < level.vest_boxes.size; i++ ) - { - item = level.vest_boxes[ i ]; - - if ( !isDefined( item ) ) - { - continue; - } - - if ( isDefined( item.damageTaken ) && isDefined( item.maxHealth ) ) - { - if ( item.damageTaken >= item.maxHealth ) - { - continue; - } - } - - if ( !IsDefined( item.owner ) || ( level.teamBased && item.owner.team != myteam ) || ( !level.teamBased && item.owner != self ) ) - { - continue; - } - - if ( DistanceSquared( item.origin, self.origin ) < dist ) - { - box = item; - break; - } - } - - if ( !isDefined( box ) ) - { - return; - } - - self BotNotifyBotEvent( "box_cap", "go", box ); - - self.bot_lock_goal = true; - - radius = GetDvarFloat( "player_useRadius" ) / 2; - self SetScriptGoal( box.origin, radius ); - self thread bot_inc_bots( box, true ); - self thread bots_watch_touch_obj( box ); - - path = self waittill_any_return( "bad_path", "goal", "new_goal" ); - - self.bot_lock_goal = false; - - if ( path != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( path != "goal" || !isDefined( box ) || DistanceSquared( self.origin, box.origin ) > radius * radius ) - { - return; - } - - self BotNotifyBotEvent( "box_cap", "start", box ); - - self BotFreezeControls( true ); - self bot_wait_stop_move(); - - waitTime = 2.25; - self thread BotPressUse( waitTime ); - wait waitTime; - - self BotFreezeControls( false ); - - self BotNotifyBotEvent( "box_cap", "stop", box ); -} - -/* - Bots think to use boxes -*/ -bot_box_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.first = true; - - for ( ;; ) - { - self bot_box_think_loop( data ); - } -} - -/* - Loops -*/ -bot_watch_stuck_on_crate_loop() -{ - crates = getEntArray( "care_package", "targetname" ); - - if ( crates.size == 0 ) - { - return; - } - - crate = undefined; - - for ( i = crates.size - 1; i >= 0; i-- ) - { - tempCrate = crates[ i ]; - - if ( !isDefined( tempCrate ) ) - { - continue; - } - - if ( isDefined( tempCrate.owner ) && isDefined( tempCrate.bomb ) ) - { - if ( tempCrate.owner == self ) - { - continue; - } - - if ( level.teamBased && tempCrate.owner.team == self.team ) - { - continue; - } - - if ( self _hasPerk( "specialty_detectexplosive" ) ) - { - continue; - } - } - - if ( !isDefined( tempCrate.doingPhysics ) || tempCrate.doingPhysics ) - { - continue; - } - - if ( isDefined( crate ) && DistanceSquared( crate.origin, self.origin ) < DistanceSquared( tempCrate.origin, self.origin ) ) - { - continue; - } - - crate = tempCrate; - } - - if ( !isDefined( crate ) ) - { - return; - } - - radius = GetDvarFloat( "player_useRadius" ); - - if ( DistanceSquared( crate.origin, self.origin ) > radius * radius ) - { - return; - } - - self.bot_stuck_on_carepackage = crate; - self notify( "crate_physics_done" ); -} - -/* - Checks if the bot is stuck on a carepackage -*/ -bot_watch_stuck_on_crate() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - for ( ;; ) - { - wait 3; - - if ( self HasThreat() ) - { - continue; - } - - self bot_watch_stuck_on_crate_loop(); - } -} - -/* - Loops -*/ -bot_crate_think_loop( data ) -{ - myteam = self.pers[ "team" ]; - ret = "crate_physics_done"; - - if ( data.first ) - { - data.first = false; - } - else - { - ret = self waittill_any_timeout( randomintrange( 3, 5 ), "crate_physics_done" ); - } - - crate = self.bot_stuck_on_carepackage; - self.bot_stuck_on_carepackage = undefined; - - if ( !isDefined( crate ) ) - { - if ( RandomInt( 100 ) < 20 && ret != "crate_physics_done" ) - { - return; - } - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() || self BotIsFrozen() ) - { - return; - } - - if ( self inLastStand() ) - { - return; - } - - crates = getEntArray( "care_package", "targetname" ); - - if ( crates.size == 0 ) - { - return; - } - - wantsClosest = randomint( 2 ); - - crate = undefined; - - for ( i = crates.size - 1; i >= 0; i-- ) - { - tempCrate = crates[ i ]; - - if ( !isDefined( tempCrate ) ) - { - continue; - } - - if ( isDefined( tempCrate.owner ) && isDefined( tempCrate.bomb ) ) - { - if ( tempCrate.owner == self ) - { - continue; - } - - if ( level.teamBased && tempCrate.owner.team == self.team ) - { - continue; - } - - if ( self _hasPerk( "specialty_detectexplosive" ) ) - { - continue; - } - } - - if ( !isDefined( tempCrate.doingPhysics ) || tempCrate.doingPhysics ) - { - continue; - } - - if ( !IsDefined( tempCrate.bots ) ) - { - tempCrate.bots = 0; - } - - if ( tempCrate.bots >= 3 ) - { - continue; - } - - if ( isDefined( crate ) ) - { - if ( wantsClosest ) - { - if ( DistanceSquared( crate.origin, self.origin ) < DistanceSquared( tempCrate.origin, self.origin ) ) - { - continue; - } - } - else - { - if ( maps\mp\killstreaks\_killstreaks::getStreakCost( crate.crateType ) > maps\mp\killstreaks\_killstreaks::getStreakCost( tempCrate.crateType ) ) - { - continue; - } - } - } - - crate = tempCrate; - } - - crates = undefined; - - if ( !isDefined( crate ) ) - { - return; - } - - self BotNotifyBotEvent( "crate_cap", "go", crate ); - - self.bot_lock_goal = true; - - radius = GetDvarFloat( "player_useRadius" ) - 16; - self SetScriptGoal( crate.origin, radius ); - self thread bot_inc_bots( crate, true ); - self thread bots_watch_touch_obj( crate ); - - path = self waittill_any_return( "bad_path", "goal", "new_goal" ); - - self.bot_lock_goal = false; - - if ( path != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( path != "goal" || !isDefined( crate ) || DistanceSquared( self.origin, crate.origin ) > radius * radius ) - { - if ( isDefined( crate ) && path == "bad_path" ) - { - self BotNotifyBotEvent( "crate_cap", "unreachable", crate ); - } - - return; - } - } - - self BotNotifyBotEvent( "crate_cap", "start", crate ); - - self BotRandomStance(); - - self BotFreezeControls( true ); - self bot_wait_stop_move(); - - waitTime = 3.25; - - if ( !isDefined( crate.owner ) || crate.owner == self ) - { - waitTime = 0.75; - } - - self thread BotPressUse( waitTime ); - wait waitTime; - - self BotFreezeControls( false ); - - // check if actually captured it? - self BotNotifyBotEvent( "crate_cap", "stop", crate ); -} - -/* - Bots will capture carepackages -*/ -bot_crate_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.first = true; - - for ( ;; ) - { - self bot_crate_think_loop( data ); - } -} - -/* - Reload cancels -*/ -doReloadCancel_loop() -{ - curWeap = self GetCurrentWeapon(); - ret = self waittill_either_return( "reload", "weapon_change" ); - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - return; - } - - if ( !getDvarInt( "sv_enableDoubleTaps" ) ) - { - return; - } - - // wait for an actual change - if ( ret == "weapon_change" ) - { - for ( i = 0; i < 10 && curWeap == self GetCurrentWeapon(); i++ ) - { - wait 0.05; - } - } - - curWeap = self GetCurrentWeapon(); - - if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap ) ) - { - return; - } - - if ( ret == "reload" ) - { - // check single reloads - if ( self GetWeaponAmmoClip( curWeap ) < WeaponClipSize( curWeap ) ) - { - return; - } - } - - // check difficulty - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 3 ) - { - return; - } - - // check if got another weapon - weaponslist = self GetWeaponsListPrimaries(); - weap = ""; - - while ( weaponslist.size ) - { - weapon = weaponslist[ randomInt( weaponslist.size ) ]; - weaponslist = array_remove( weaponslist, weapon ); - - if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon ) ) - { - continue; - } - - if ( curWeap == weapon || weapon == "none" || weapon == "" ) - { - continue; - } - - weap = weapon; - break; - } - - if ( weap == "" ) - { - return; - } - - // do the cancel - wait 0.1; - self thread ChangeToWeapon( weap ); - wait 0.25; - self thread ChangeToWeapon( curWeap ); - wait 2; -} - -/* - Reload cancels -*/ -doReloadCancel() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - self doReloadCancel_loop(); - } -} - -/* - Loops -*/ -bot_weapon_think_loop( data ) -{ - ret = self waittill_any_timeout( randomIntRange( 2, 4 ), "bot_force_check_switch" ); - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - return; - } - - curWeap = self GetCurrentWeapon(); - hasTarget = self hasThreat(); - - if ( hasTarget ) - { - threat = self getThreat(); - rocketAmmo = self getRocketAmmo(); - - if ( entIsVehicle( threat ) && isDefined( rocketAmmo ) ) - { - if ( curWeap != rocketAmmo ) - { - self thread ChangeToWeapon( rocketAmmo ); - } - - return; - } - } - - if ( self HasBotJavelinLocation() && self GetAmmoCount( "javelin_mp" ) ) - { - if ( curWeap != "javelin_mp" ) - { - self thread ChangeToWeapon( "javelin_mp" ); - } - - return; - } - - force = ( ret == "bot_force_check_switch" ); - - if ( data.first ) - { - data.first = false; - - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "initswitch" ] ) - { - return; - } - } - else - { - if ( curWeap != "none" && self getAmmoCount( curWeap ) && curWeap != "stinger_mp" && curWeap != "javelin_mp" ) - { - if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "switch" ] ) - { - return; - } - - if ( hasTarget ) - { - return; - } - } - else - { - force = true; - } - } - - weaponslist = self getweaponslistall(); - weap = ""; - - while ( weaponslist.size ) - { - weapon = weaponslist[ randomInt( weaponslist.size ) ]; - weaponslist = array_remove( weaponslist, weapon ); - - if ( !self getAmmoCount( weapon ) && !force ) - { - continue; - } - - if ( !isWeaponPrimary( weapon ) ) - { - continue; - } - - if ( curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp" ) - { - continue; - } - - weap = weapon; - break; - } - - if ( weap == "" ) - { - return; - } - - self thread ChangeToWeapon( weap ); -} - -/* - Bots will think to switch weapons -*/ -bot_weapon_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.first = true; - - for ( ;; ) - { - self bot_weapon_think_loop( data ); - } -} - -/* - Bots think when to target vehicles -*/ -bot_target_vehicle_loop() -{ - rocketAmmo = self getRocketAmmo(); - - if ( isDefined( rocketAmmo ) && rocketAmmo == "javelin_mp" && self isEMPed() ) - { - return; - } - - targets = maps\mp\_stinger::GetTargetList(); - - if ( !targets.size ) - { - return; - } - - lockOnAmmo = self getLockonAmmo(); - myEye = self GetEye(); - target = undefined; - - for ( i = targets.size - 1; i >= 0; i-- ) - { - tempTarget = targets[ i ]; - - if ( isPlayer( tempTarget ) ) - { - continue; - } - - if ( isDefined( tempTarget.owner ) && tempTarget.owner == self ) - { - continue; - } - - if ( !bulletTracePassed( myEye, tempTarget.origin, false, tempTarget ) ) - { - continue; - } - - if ( tempTarget.health <= 0 ) - { - continue; - } - - if ( isDefined( tempTarget.damageTaken ) && isDefined( tempTarget.maxHealth ) ) - { - if ( tempTarget.damageTaken >= tempTarget.maxHealth ) - { - continue; - } - } - - if ( tempTarget.classname != "script_vehicle" && !isDefined( lockOnAmmo ) ) - { - continue; - } - - target = tempTarget; - } - - targets = undefined; - - if ( !isDefined( target ) ) - { - return; - } - - if ( target.model != "vehicle_ugv_talon_mp" && target.model != "vehicle_remote_uav" ) - { - if ( isDefined( self.remoteTank ) ) - { - return; - } - - if ( !isDefined( rocketAmmo ) && self BotGetRandom() < 90 ) - { - return; - } - } - - self BotNotifyBotEvent( "attack_vehicle", "start", target, rocketAmmo ); - - self SetScriptEnemy( target, ( 0, 0, 0 ) ); - self bot_attack_vehicle( target ); - self ClearScriptEnemy(); - self notify( "bot_force_check_switch" ); - - self BotNotifyBotEvent( "attack_vehicle", "stop", target, rocketAmmo ); -} - -/* - Bots think when to target vehicles -*/ -bot_target_vehicle() -{ - self endon( "disconnect" ); - self endon( "death" ); - - for ( ;; ) - { - wait randomIntRange( 2, 4 ); - - if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) - { - continue; - } - - if ( self HasScriptEnemy() ) - { - continue; - } - - if ( self IsUsingRemote() && !isDefined( self.remoteTank ) ) - { - continue; - } - - self bot_target_vehicle_loop(); - } -} - -/* - Bots target the killstreak for a time and stops -*/ -bot_attack_vehicle( target ) -{ - target endon( "death" ); - - wait_time = RandomIntRange( 7, 10 ); - - for ( i = 0; i < wait_time; i++ ) - { - self notify( "bot_force_check_switch" ); - wait( 1 ); - - if ( !IsDefined( target ) ) - { - return; - } - } -} - -/* - Bot watch to use remote turret -*/ -bot_watch_use_remote_turret() -{ - self endon( "death" ); - self endon( "disconnect" ); - - for ( ;; ) - { - wait 5; - - if ( self BotIsFrozen() ) - { - continue; - } - - if ( self HasThreat() || self HasBotJavelinLocation() ) - { - continue; - } - - if ( self isDefusing() || self isPlanting() ) - { - continue; - } - - if ( self IsUsingRemote() ) - { - continue; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - continue; - } - - if ( !isDefined( self.remoteTurretList ) || !isDefined( self.remoteTurretList[ 0 ] ) ) - { - continue; - } - - self thread BotPressUse( 3 ); - wait 3; - } -} - -/* - Returns an origin thats good to use for a kill streak -*/ -getKillstreakTargetLocation() -{ - location = undefined; - players = []; - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !isDefined( player.team ) ) - { - continue; - } - - if ( level.teamBased && self.team == player.team ) - { - continue; - } - - if ( player.sessionstate != "playing" ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( player _hasPerk( "specialty_blindeye" ) ) - { - continue; - } - - if ( !bulletTracePassed( player.origin, player.origin + ( 0, 0, 2048 ), false, player ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - continue; - } - - players[ players.size ] = player; - } - - target = random( players ); - - if ( isDefined( target ) ) - { - location = target.origin + ( randomIntRange( ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * -75, ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * 75 ), randomIntRange( ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * -75, ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * 75 ), 0 ); - } - else if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 3 ) - { - location = self.origin + ( randomIntRange( -512, 512 ), randomIntRange( -512, 512 ), 0 ); - } - - return location; -} - -/* - Clears remote usage when bot dies -*/ -clear_remote_on_death( isac130 ) -{ - self endon( "bot_clear_remote_on_death" ); - level endon( "game_ended" ); - - self waittill_either( "death", "disconnect" ); - - if ( isDefined( isac130 ) && isac130 ) - { - level.ac130InUse = false; - } - - if ( isDefined( self ) ) - { - self ClearUsingRemote(); - } -} - -/* - Bots think to use killstreaks -*/ -bot_killstreak_think_loop( data ) -{ - if ( !isDefined( data.doFastContinue ) ) - { - wait randomIntRange( 1, 3 ); - } - - if ( self BotIsFrozen() ) - { - return; - } - - if ( self HasThreat() || self HasBotJavelinLocation() ) - { - return; - } - - if ( self isDefusing() || self isPlanting() ) - { - return; - } - - if ( self isEMPed() || self isNuked() ) - { - return; - } - - if ( self IsUsingRemote() ) - { - return; - } - - if ( self InLastStand() && !self InFinalStand() ) - { - return; - } - - - if ( isDefined( self.isCarrying ) && self.isCarrying ) - { - self notify( "place_sentry" ); - self notify( "place_turret" ); - self notify( "place_ims" ); - self notify( "place_carryRemoteUAV" ); - self notify( "place_tank" ); - } - - curWeap = self GetCurrentWeapon(); - - if ( isSubStr( curWeap, "airdrop_" ) || isSubStr( curWeap, "deployable_" ) ) - { - self thread BotPressAttack( 0.05 ); - } - - - useableStreaks = []; - - if ( !isDefined( data.doFastContinue ) ) - { - if ( self.pers[ "killstreaks" ][ 0 ].available ) - { - useableStreaks[ useableStreaks.size ] = 0; - } - - if ( self.pers[ "killstreaks" ][ 1 ].available && self.streakType != "specialist" ) - { - useableStreaks[ useableStreaks.size ] = 1; - } - - if ( self.pers[ "killstreaks" ][ 2 ].available && self.streakType != "specialist" ) - { - useableStreaks[ useableStreaks.size ] = 2; - } - - if ( self.pers[ "killstreaks" ][ 3 ].available && self.streakType != "specialist" ) - { - useableStreaks[ useableStreaks.size ] = 3; - } - } - else - { - useableStreaks[ 0 ] = data.doFastContinue; - data.doFastContinue = undefined; - } - - if ( !useableStreaks.size ) - { - return; - } - - self.killstreakIndexWeapon = random( useableStreaks ); - streakName = self.pers[ "killstreaks" ][ self.killstreakIndexWeapon ].streakName; - - if ( level.inGracePeriod && maps\mp\killstreaks\_killstreaks::deadlyKillstreak( streakName ) ) - { - return; - } - - ksWeap = maps\mp\killstreaks\_killstreaks::getKillstreakWeapon( streakName ); - - if ( curWeap == "none" || !isWeaponPrimary( curWeap ) ) - { - curWeap = self GetLastWeapon(); - } - - lifeId = self.pers[ "killstreaks" ][ 0 ].lifeId; - - if ( !isDefined( lifeId ) ) - { - lifeId = -1; - } - - if ( maps\mp\killstreaks\_killstreaks::isRideKillstreak( streakName ) || maps\mp\killstreaks\_killstreaks::isCarryKillstreak( streakName ) || streakName == "sam_turret" || streakName == "remote_mg_turret" ) - { - if ( self inLastStand() ) - { - return; - } - - if ( lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && maps\mp\killstreaks\_killstreaks::isRideKillstreak( streakName ) && !self nearAnyOfWaypoints( 128, getWaypointsOfType( "camp" ) ) ) - { - campSpot = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "camp" ), 1024 ) ) ); - - if ( isDefined( campSpot ) ) - { - self BotNotifyBotEvent( "killstreak", "camp", streakName, campSpot ); - - self SetScriptGoal( campSpot.origin, 16 ); - - if ( self waittill_any_return( "new_goal", "goal", "bad_path" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - data.doFastContinue = self.killstreakIndexWeapon; - return; - } - } - - if ( streakName == "sentry" || streakName == "sam_turret" || streakName == "remote_mg_turret" || streakName == "ims" || streakName == "remote_uav" || streakName == "remote_tank" ) - { - if ( self HasScriptAimPos() ) - { - return; - } - - if ( streakName == "remote_uav" || streakName == "remote_tank" ) - { - if ( ( isDefined( level.remote_uav[ self.team ] ) || level.littleBirds.size >= 4 ) && streakName == "remote_uav" ) - { - return; - } - - if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() ) - { - return; - } - } - - myEye = self GetEye(); - angles = self GetPlayerAngles(); - - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 1024, false, self ); - placeNot = "place_sentry"; - cancelNot = "cancel_sentry"; - distCheck = 1000 * 1000; - doRandomStance = false; - - switch ( streakName ) - { - case "sam_turret": - forwardTrace = bulletTrace( myEye, myEye + ( 0, 0, 1024 ), false, self ); - break; - - case "remote_mg_turret": - placeNot = "place_turret"; - cancelNot = "cancel_turret"; - break; - - case "ims": - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); - placeNot = "place_ims"; - cancelNot = "cancel_ims"; - distCheck = 100 * 100; - break; - - case "remote_uav": - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); - placeNot = "place_carryRemoteUAV"; - cancelNot = "cancel_carryRemoteUAV"; - distCheck = 100 * 100; - doRandomStance = true; - break; - - case "remote_tank": - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); - placeNot = "place_tank"; - cancelNot = "cancel_tank"; - distCheck = 100 * 100; - doRandomStance = true; - break; - } - - if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < distCheck && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - return; - } - - self BotNotifyBotEvent( "killstreak", "call", streakName ); - - if ( doRandomStance ) - { - self BotRandomStance(); - } - - self BotStopMoving( true ); - self SetScriptAimPos( forwardTrace[ "position" ] ); - - if ( !self changeToWeapon( ksWeap ) ) - { - self BotStopMoving( false ); - self ClearScriptAimPos(); - return; - } - - wait 1; - self notify( placeNot ); - wait 0.05; - self notify( cancelNot ); - wait 0.5; - - self BotStopMoving( false ); - self ClearScriptAimPos(); - } - else if ( streakName == "predator_missile" ) - { - location = self getKillstreakTargetLocation(); - - if ( !isDefined( location ) ) - { - return; - } - - self BotNotifyBotEvent( "killstreak", "call", streakName, location ); - - self BotRandomStance(); - self setUsingRemote( "remotemissile" ); - self thread clear_remote_on_death(); - self BotStopMoving( true ); - - if ( !self changeToWeapon( ksWeap ) ) - { - self ClearUsingRemote(); - self notify( "bot_clear_remote_on_death" ); - self BotStopMoving( false ); - return; - } - - wait 0.05; - self thread ChangeToWeapon( ksWeap ); // prevent script from changing back - - wait 1; - self notify( "bot_clear_remote_on_death" ); - self BotStopMoving( false ); - - if ( self isEMPed() || self isNuked() ) - { - self ClearUsingRemote(); - self thread changeToWeapon( curWeap ); - return; - } - - self BotFreezeControls( true ); - - self thread maps\mp\killstreaks\_killstreaks::updateKillstreaks(); - self maps\mp\killstreaks\_killstreaks::usedKillstreak( streakName, true ); - - rocket = MagicBullet( "remotemissile_projectile_mp", self.origin + ( 0.0, 0.0, 7000.0 - ( self.pers[ "bots" ][ "skill" ][ "base" ] * 400 ) ), location, self ); - rocket.lifeId = lifeId; - rocket.type = "remote"; - - rocket thread maps\mp\gametypes\_weapons::AddMissileToSightTraces( self.pers[ "team" ] ); - rocket thread maps\mp\killstreaks\_remotemissile::handleDamage(); - thread maps\mp\killstreaks\_remotemissile::MissileEyes( self, rocket ); - - self waittill( "stopped_using_remote" ); - - wait 1; - self BotFreezeControls( false ); - } - else if ( streakName == "ac130" || streakName == "remote_mortar" || streakName == "osprey_gunner" ) - { - if ( streakName == "ac130" ) - { - if ( isDefined( level.ac130player ) || level.ac130InUse ) - { - return; - } - } - - if ( streakName == "remote_mortar" ) - { - if ( isDefined( level.remote_mortar ) ) - { - return; - } - } - - location = undefined; - directionYaw = undefined; - - if ( streakName == "osprey_gunner" ) - { - if ( isDefined( level.chopper ) ) - { - return; - } - - if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() ) - { - return; - } - - location = self getKillstreakTargetLocation(); - directionYaw = randomInt( 360 ); - - if ( !isDefined( location ) ) - { - return; - } - } - - self BotNotifyBotEvent( "killstreak", "call", streakName, location, directionYaw ); - - self BotRandomStance(); - self BotStopMoving( true ); - - if ( self changeToWeapon( ksWeap ) ) - { - wait 1; - - if ( isDefined( location ) ) - { - self notify( "confirm_location", location, directionYaw ); - } - } - - wait 2; - self BotStopMoving( false ); - } - else if ( streakName == "deployable_vest" ) - { - myEye = self GetEye(); - angles = self GetPlayerAngles(); - - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); - - if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < 96 * 96 && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - return; - } - - self BotNotifyBotEvent( "killstreak", "call", streakName ); - - self BotStopMoving( true ); - self SetScriptAimPos( forwardTrace[ "position" ] ); - - if ( !self changeToWeapon( ksWeap ) ) - { - self BotStopMoving( false ); - self ClearScriptAimPos(); - return; - } - - self thread fire_current_weapon(); - - self waittill_any_timeout( 5, "grenade_fire" ); - - self notify( "stop_firing_weapon" ); - - self BotStopMoving( false ); - self ClearScriptAimPos(); - - wait 2.5; - self notify( "bot_check_box_think" ); - } - } - else - { - if ( streakName == "escort_airdrop" || streakName == "airdrop_juggernaut_recon" || streakName == "airdrop_trap" || streakName == "airdrop_juggernaut" || streakName == "airdrop_remote_tank" || streakName == "airdrop_sentry_minigun" || streakName == "airdrop_assault" ) - { - if ( self HasScriptAimPos() ) - { - return; - } - - if ( ( level.littleBirds.size >= 4 || level.fauxVehicleCount >= 4 ) && !isSubStr( toLower( streakName ), "juggernaut" ) ) - { - return; - } - - if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + 1 >= maxVehiclesAllowed() ) - { - return; - } - - if ( IsSubStr( toLower( streakName ), "escort_airdrop" ) && isDefined( level.chopper ) ) - { - return; - } - - if ( !bulletTracePassed( self.origin, self.origin + ( 0, 0, 2048 ), false, self ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - return; - } - - myEye = self GetEye(); - angles = self GetPlayerAngles(); - - forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 256, false, self ); - - if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < 96 * 96 && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - return; - } - - if ( !bulletTracePassed( forwardTrace[ "position" ], forwardTrace[ "position" ] + ( 0, 0, 2048 ), false, self ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) - { - return; - } - - self BotNotifyBotEvent( "killstreak", "call", streakName ); - - self BotStopMoving( true ); - self SetScriptAimPos( forwardTrace[ "position" ] ); - - if ( !self changeToWeapon( ksWeap ) ) - { - self BotStopMoving( false ); - self ClearScriptAimPos(); - return; - } - - self thread fire_current_weapon(); - - ret = self waittill_any_timeout( 5, "grenade_fire" ); - - self notify( "stop_firing_weapon" ); - - if ( ret == "timeout" ) - { - self BotStopMoving( false ); - self ClearScriptAimPos(); - return; - } - - if ( randomInt( 100 ) < 80 && !self HasScriptGoal() && !self.bot_lock_goal ) - { - self waittill_any_timeout( 15, "crate_physics_done", "new_goal" ); - } - - self BotStopMoving( false ); - self ClearScriptAimPos(); - } - else - { - if ( streakName == "nuke" && isDefined( level.nukeIncoming ) ) - { - return; - } - - if ( streakName == "counter_uav" && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teamBased && level.activeCounterUAVs[ self.team ] ) || ( !level.teamBased && level.activeCounterUAVs[ self.guid ] ) ) ) - { - return; - } - - if ( ( streakName == "uav" || streakName == "uav_support" || streakName == "triple_uav" ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teamBased && ( level.activeUAVs[ self.team ] || level.activeCounterUAVs[ level.otherTeam[ self.team ] ] ) ) || ( !level.teamBased && ( level.activeUAVs[ self.guid ] || self.isRadarBlocked ) ) ) ) - { - return; - } - - if ( streakName == "emp" && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teamBased && level.teamEMPed[ level.otherTeam[ self.team ] ] ) || ( !level.teamBased && isDefined( level.empPlayer ) ) ) ) - { - return; - } - - if ( streakName == "littlebird_flock" || streakName == "helicopter" || streakName == "helicopter_flares" || streakName == "littlebird_support" ) - { - numIncomingVehicles = 1; - - if ( streakName == "littlebird_flock" ) - { - numIncomingVehicles = 5; - } - - if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxVehicleCount + numIncomingVehicles >= maxVehiclesAllowed() ) - { - return; - } - - if ( streakName == "helicopter" && isDefined( level.chopper ) ) - { - return; - } - - if ( streakName == "littlebird_support" && ( isDefined( level.littlebirdGuard ) || maps\mp\killstreaks\_helicopter::exceededMaxLittlebirds( "littlebird_support" ) ) ) - { - return; - } - } - - location = undefined; - directionYaw = undefined; - - switch ( streakName ) - { - case "littlebird_flock": - case "stealth_airstrike": - case "precision_airstrike": - location = self getKillstreakTargetLocation(); - directionYaw = randomInt( 360 ); - - if ( !isDefined( location ) ) - { - return; - } - - case "helicopter": - case "helicopter_flares": - case "littlebird_support": - case "uav": - case "uav_support": - case "counter_uav": - case "triple_uav": - case "nuke": - case "emp": - self BotStopMoving( true ); - - self BotNotifyBotEvent( "killstreak", "call", streakName, location, directionYaw ); - - if ( self changeToWeapon( ksWeap ) ) - { - wait 1; - - if ( isDefined( location ) ) - { - self BotFreezeControls( true ); - - self notify( "confirm_location", location, directionYaw ); - wait 1; - - self BotFreezeControls( false ); - } - } - - self BotStopMoving( false ); - break; - } - } - } -} - -/* - Bots think to use killstreaks -*/ -bot_killstreak_think() -{ - self endon( "disconnect" ); - self endon( "death" ); - level endon( "game_ended" ); - - data = spawnStruct(); - data.doFastContinue = undefined; - - for ( ;; ) - { - self bot_killstreak_think_loop( data ); - } -} - -/* - Bots do random stance -*/ -BotRandomStance() -{ - if ( randomInt( 100 ) < 80 ) - { - self BotSetStance( "prone" ); - } - else if ( randomInt( 100 ) < 60 ) - { - self BotSetStance( "crouch" ); - } - else - { - self BotSetStance( "stand" ); - } -} - -/* - Bots will use a random equipment -*/ -BotUseRandomEquipment() -{ - self endon( "death" ); - self endon( "disconnect" ); - - nade = undefined; - - if ( self GetAmmoCount( "claymore_mp" ) ) - { - nade = "claymore_mp"; - } - - if ( self GetAmmoCount( "flare_mp" ) ) - { - nade = "flare_mp"; - } - - if ( self GetAmmoCount( "c4_mp" ) ) - { - nade = "c4_mp"; - } - - if ( self GetAmmoCount( "bouncingbetty_mp" ) ) - { - nade = "bouncingbetty_mp"; - } - - if ( self GetAmmoCount( "portable_radar_mp" ) ) - { - nade = "portable_radar_mp"; - } - - if ( self GetAmmoCount( "scrambler_mp" ) ) - { - nade = "scrambler_mp"; - } - - if ( self GetAmmoCount( "trophy_mp" ) ) - { - nade = "trophy_mp"; - } - - if ( !isDefined( nade ) ) - { - return; - } - - self botThrowGrenade( nade, 0.05 ); -} - -/* - Bots will look at a random thing -*/ -BotLookAtRandomThing( obj_target ) -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( self HasScriptAimPos() ) - { - return; - } - - rand = RandomInt( 100 ); - - nearestEnemy = undefined; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( !isDefined( player ) || !isDefined( player.team ) ) - { - continue; - } - - if ( !isAlive( player ) ) - { - continue; - } - - if ( level.teamBased && self.team == player.team ) - { - continue; - } - - if ( !isDefined( nearestEnemy ) || DistanceSquared( self.origin, player.origin ) < DistanceSquared( self.origin, nearestEnemy.origin ) ) - { - nearestEnemy = player; - } - } - - origin = ( 0, 0, self GetPlayerViewHeight() ); - - if ( isDefined( nearestEnemy ) && DistanceSquared( self.origin, nearestEnemy.origin ) < 1024 * 1024 && rand < 40 ) - { - origin += ( nearestEnemy.origin[ 0 ], nearestEnemy.origin[ 1 ], self.origin[ 2 ] ); - } - else if ( isDefined( obj_target ) && rand < 50 ) - { - origin += ( obj_target.origin[ 0 ], obj_target.origin[ 1 ], self.origin[ 2 ] ); - } - else if ( rand < 85 ) - { - origin += self.origin + AnglesToForward( ( 0, self.angles[ 1 ] - 180, 0 ) ) * 1024; - } - else - { - origin += self.origin + AnglesToForward( ( 0, RandomInt( 360 ), 0 ) ) * 1024; - } - - self SetScriptAimPos( origin ); - wait 2; - self ClearScriptAimPos(); -} - -/* - Bots will do stuff while waiting for objective -*/ -bot_do_random_action_for_objective( obj_target ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self notify( "bot_do_random_action_for_objective" ); - self endon( "bot_do_random_action_for_objective" ); - - if ( !isDefined( self.bot_random_obj_action ) ) - { - self.bot_random_obj_action = true; - - if ( randomInt( 100 ) < 80 ) - { - self thread BotUseRandomEquipment(); - } - - if ( randomInt( 100 ) < 75 ) - { - self thread BotLookAtRandomThing( obj_target ); - } - } - else - { - if ( self GetStance() != "prone" && randomInt( 100 ) < 15 ) - { - self BotSetStance( "prone" ); - } - else if ( randomInt( 100 ) < 5 ) - { - self thread BotLookAtRandomThing( obj_target ); - } - } - - wait 2; - self.bot_random_obj_action = undefined; -} - -/* - Bots hang around the enemy's flag to spawn kill em -*/ -bot_dom_spawn_kill_think_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - - if ( myFlagCount == level.flags.size ) - { - return; - } - - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if ( myFlagCount <= otherFlagCount || otherFlagCount != 1 ) - { - return; - } - - flag = undefined; - - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - { - continue; - } - - flag = level.flags[ i ]; - } - - if ( !isDefined( flag ) ) - { - return; - } - - if ( DistanceSquared( self.origin, flag.origin ) < 2048 * 2048 ) - { - return; - } - - self BotNotifyBotEvent( "dom", "start", "spawnkill", flag ); - - self SetScriptGoal( flag.origin, 1024 ); - - self thread bot_dom_watch_flags( myFlagCount, myTeam ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "dom", "stop", "spawnkill", flag ); -} - -/* - Bots hang around the enemy's flag to spawn kill em -*/ -bot_dom_spawn_kill_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( level.gametype != "dom" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 10, 20 ) ); - - if ( randomint( 100 ) < 20 ) - { - continue; - } - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - continue; - } - - self bot_dom_spawn_kill_think_loop(); - } -} - -/* - Calls 'bad_path' when the flag count changes -*/ -bot_dom_watch_flags( count, myTeam ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( maps\mp\gametypes\dom::getTeamFlagCount( myTeam ) != count ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots watches their own flags and protects them when they are under capture -*/ -bot_dom_def_think_loop() -{ - myTeam = self.pers[ "team" ]; - flag = undefined; - - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() != myTeam ) - { - continue; - } - - if ( !level.flags[ i ].useObj.objPoints[ myTeam ].isFlashing ) - { - continue; - } - - if ( !isDefined( flag ) || DistanceSquared( self.origin, level.flags[ i ].origin ) < DistanceSquared( self.origin, flag.origin ) ) - { - flag = level.flags[ i ]; - } - } - - if ( !isDefined( flag ) ) - { - return; - } - - self BotNotifyBotEvent( "dom", "start", "defend", flag ); - - self SetScriptGoal( flag.origin, 128 ); - - self thread bot_dom_watch_for_flashing( flag, myTeam ); - self thread bots_watch_touch_obj( flag ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "dom", "stop", "defend", flag ); -} - -/* - Bots watches their own flags and protects them when they are under capture -*/ -bot_dom_def_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( level.gametype != "dom" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 3 ) ); - - if ( randomint( 100 ) < 35 ) - { - continue; - } - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - continue; - } - - self bot_dom_def_think_loop(); - } -} - -/* - Watches while the flag is under capture -*/ -bot_dom_watch_for_flashing( flag, myTeam ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( flag ) ) - { - break; - } - - if ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam || !flag.useObj.objPoints[ myTeam ].isFlashing ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots capture dom flags -*/ -bot_dom_cap_think_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - - if ( myFlagCount == level.flags.size ) - { - return; - } - - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if ( game[ "teamScores" ][ myteam ] >= game[ "teamScores" ][ otherTeam ] ) - { - if ( myFlagCount < otherFlagCount ) - { - if ( randomint( 100 ) < 15 ) - { - return; - } - } - else if ( myFlagCount == otherFlagCount ) - { - if ( randomint( 100 ) < 35 ) - { - return; - } - } - else if ( myFlagCount > otherFlagCount ) - { - if ( randomint( 100 ) < 95 ) - { - return; - } - } - } - - flag = undefined; - flags = []; - - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - { - continue; - } - - flags[ flags.size ] = level.flags[ i ]; - } - - if ( randomInt( 100 ) > 30 ) - { - for ( i = 0; i < flags.size; i++ ) - { - if ( !isDefined( flag ) || DistanceSquared( self.origin, level.flags[ i ].origin ) < DistanceSquared( self.origin, flag.origin ) ) - { - flag = level.flags[ i ]; - } - } - } - else if ( flags.size ) - { - flag = random( flags ); - } - - if ( !isDefined( flag ) ) - { - return; - } - - self BotNotifyBotEvent( "dom", "go", "cap", flag ); - - self.bot_lock_goal = true; - self SetScriptGoal( flag.origin, 64 ); - - self thread bot_dom_go_cap_flag( flag, myteam ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "dom", "start", "cap", flag ); - - self SetScriptGoal( self.origin, 64 ); - - while ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam && self isTouching( flag ) ) - { - cur = flag.useObj.curProgress; - wait 0.5; - - if ( flag.useObj.curProgress == cur ) - { - break; // some enemy is near us, kill him - } - - self thread bot_do_random_action_for_objective( flag ); - } - - self BotNotifyBotEvent( "dom", "stop", "cap", flag ); - - self ClearScriptGoal(); - - self.bot_lock_goal = false; -} - -/* - Bots capture dom flags -*/ -bot_dom_cap_think() -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( level.gametype != "dom" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 12 ) ); - - if ( self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.flags ) || level.flags.size == 0 ) - { - continue; - } - - self bot_dom_cap_think_loop(); - } -} - -/* - Bot goes to the flag, watching while they don't have the flag -*/ -bot_dom_go_cap_flag( flag, myteam ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait randomintrange( 2, 4 ); - - if ( !isDefined( flag ) ) - { - break; - } - - if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - { - break; - } - - if ( self isTouching( flag ) ) - { - break; - } - } - - if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Bots play headquarters -*/ -bot_hq_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - radio = level.radio; - gameobj = radio.gameobject; - origin = ( radio.origin[ 0 ], radio.origin[ 1 ], radio.origin[ 2 ] + 5 ); - - // if neut or enemy - if ( gameobj.ownerTeam != myTeam ) - { - if ( gameobj.interactTeam == "none" ) // wait for it to become active - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // capture it - - self BotNotifyBotEvent( "hq", "go", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_hq_go_cap( gameobj, radio ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" ) - { - self.bot_lock_goal = false; - return; - } - - if ( !self isTouching( gameobj.trigger ) || level.radio != radio ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "hq", "start", "cap" ); - - self SetScriptGoal( self.origin, 64 ); - - while ( self isTouching( gameobj.trigger ) && gameobj.ownerTeam != myTeam && level.radio == radio ) - { - cur = gameobj.curProgress; - wait 0.5; - - if ( cur == gameobj.curProgress ) - { - break; // no prog made, enemy must be capping - } - - self thread bot_do_random_action_for_objective( gameobj.trigger ); - } - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "hq", "stop", "cap" ); - } - else // we own it - { - if ( gameobj.objPoints[ myteam ].isFlashing ) // underattack - { - self BotNotifyBotEvent( "hq", "start", "defend" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_hq_watch_flashing( gameobj, radio ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "hq", "stop", "defend" ); - return; - } - - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } -} - -/* - Bots play headquarters -*/ -bot_hq() -{ - self endon( "death" ); - self endon( "disconnect" ); - - if ( level.gametype != "koth" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.radio ) ) - { - continue; - } - - if ( !isDefined( level.radio.gameobject ) ) - { - continue; - } - - self bot_hq_loop(); - } -} - -/* - Waits until not touching the trigger and it is the current radio. -*/ -bot_hq_go_cap( obj, radio ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait randomintrange( 2, 4 ); - - if ( !isDefined( obj ) ) - { - break; - } - - if ( self isTouching( obj.trigger ) ) - { - break; - } - - if ( level.radio != radio ) - { - break; - } - } - - if ( level.radio != radio ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Waits while the radio is under attack. -*/ -bot_hq_watch_flashing( obj, radio ) -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - myteam = self.team; - - for ( ;; ) - { - wait 0.5; - - if ( !isDefined( obj ) ) - { - break; - } - - if ( !obj.objPoints[ myteam ].isFlashing ) - { - break; - } - - if ( level.radio != radio ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots play sab -*/ -bot_sab_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - bomb = level.sabBomb; - bombteam = bomb.ownerTeam; - carrier = bomb.carrier; - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; - - // the bomb is ours, we are on the offence - if ( bombteam == myTeam ) - { - site = level.bombZones[ otherTeam ]; - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - // protect our planted bomb - if ( level.bombPlanted ) - { - // kill defuser - if ( site isInUse() ) // somebody is defusing our bomb we planted - { - self BotNotifyBotEvent( "sab", "start", "defuser" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sab", "stop", "defuser" ); - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // we are not the carrier - if ( !self isBombCarrier() ) - { - // lets escort the bomb carrier - if ( self HasScriptGoal() ) - { - return; - } - - origin = carrier.origin; - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj( bomb, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // we are the carrier of the bomb, lets check if we need to plant - timepassed = getTimePassed() / 1000; - - if ( timepassed < 120 && timeleft >= 90 && randomInt( 100 ) < 98 ) - { - return; - } - - self BotNotifyBotEvent( "sab", "go", "plant" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - - self thread bot_go_plant( site ); - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || level.bombPlanted || !self isTouching( site.trigger ) || site IsInUse() || self inLastStand() || self HasThreat() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "sab", "start", "plant" ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( site.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sab", "stop", "plant" ); - } - else if ( bombteam == otherTeam ) // the bomb is theirs, we are on the defense - { - site = level.bombZones[ myteam ]; - - if ( !isDefined( site.bots ) ) - { - site.bots = 0; - } - - // protect our site from planters - if ( !level.bombPlanted ) - { - // kill bomb carrier - if ( site.bots > 2 || randomInt( 100 ) < 45 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( carrier _hasPerk( "specialty_coldblooded" ) ) - { - return; - } - - origin = carrier.origin; - - self SetScriptGoal( origin, 64 ); - self thread bot_escort_obj( bomb, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // protect bomb site - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - self thread bot_inc_bots( site ); - - if ( site isInUse() ) // somebody is planting - { - self BotNotifyBotEvent( "sab", "start", "planter" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_inc_bots( site ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sab", "stop", "planter" ); - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - wait 4; - self notify( "bot_inc_bots" ); - site.bots--; - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - self thread bot_inc_bots( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // bomb is planted we need to defuse - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - // someone else is defusing, lets just hang around - if ( site.bots > 1 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // lets go defuse - self BotNotifyBotEvent( "sab", "go", "defuse" ); - - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots( site ); - self thread bot_go_defuse( site ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || !level.bombPlanted || site IsInUse() || !self isTouching( site.trigger ) || self InLastStand() || self HasThreat() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "sab", "start", "defuse" ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( site.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sab", "stop", "defuse" ); - } - else // we need to go get the bomb! - { - origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); - - self BotNotifyBotEvent( "sab", "start", "bomb" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_get_obj( bomb ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sab", "stop", "bomb" ); - return; - } -} - -/* - Bots play sab -*/ -bot_sab() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "sab" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.sabBomb ) ) - { - continue; - } - - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - continue; - } - - if ( self IsPlanting() || self isDefusing() ) - { - continue; - } - - self bot_sab_loop(); - } -} - -/* - Bots play sd defenders -*/ -bot_sd_defenders_loop( data ) -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - // bomb not planted, lets protect our sites - if ( !level.bombPlanted ) - { - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; - - if ( timeleft >= 90 ) - { - return; - } - - // check for a bomb carrier, and camp the bomb - if ( !level.multiBomb && isDefined( level.sdBomb ) ) - { - bomb = level.sdBomb; - carrier = level.sdBomb.carrier; - - if ( !isDefined( carrier ) ) - { - origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); - - // hang around the bomb - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - - self thread bot_get_obj( bomb ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - } - - // pick a site to protect - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - return; - } - - sites = []; - - for ( i = 0; i < level.bombZones.size; i++ ) - { - sites[ sites.size ] = level.bombZones[ i ]; - } - - if ( !sites.size ) - { - return; - } - - if ( data.rand > 50 ) - { - site = self bot_array_nearest_curorigin( sites ); - } - else - { - site = random( sites ); - } - - if ( !isDefined( site ) ) - { - return; - } - - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - if ( site isInUse() ) // somebody is planting - { - self BotNotifyBotEvent( "sd", "start", "planter", site ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sd", "stop", "planter", site ); - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // bomb is planted, we need to defuse - if ( !isDefined( level.defuseObject ) ) - { - return; - } - - defuse = level.defuseObject; - - if ( !isDefined( defuse.bots ) ) - { - defuse.bots = 0; - } - - origin = ( defuse.curorigin[ 0 ], defuse.curorigin[ 1 ], defuse.curorigin[ 2 ] + 5 ); - - // someone is going to go defuse ,lets just hang around - if ( defuse.bots > 1 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse( defuse ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // lets defuse - self BotNotifyBotEvent( "sd", "go", "defuse" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots( defuse ); - self thread bot_go_defuse( defuse ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || !level.bombPlanted || defuse isInUse() || !self isTouching( defuse.trigger ) || self InLastStand() || self HasThreat() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "sd", "start", "defuse" ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( defuse.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sd", "stop", "defuse" ); -} - -/* - Bots play sd defenders -*/ -bot_sd_defenders() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "sd" ) - { - return; - } - - if ( self.team == game[ "attackers" ] ) - { - return; - } - - data = spawnStruct(); - data.rand = self BotGetRandom(); - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( self IsPlanting() || self isDefusing() ) - { - continue; - } - - self bot_sd_defenders_loop( data ); - } -} - -/* - Bots play sd attackers -*/ -bot_sd_attackers_loop( data ) -{ - if ( data.first ) - { - data.first = false; - } - else - { - wait( randomintrange( 3, 5 ) ); - } - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - return; - } - - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - // bomb planted - if ( level.bombPlanted ) - { - if ( !isDefined( level.defuseObject ) ) - { - return; - } - - site = level.defuseObject; - - origin = ( site.curorigin[ 0 ], site.curorigin[ 1 ], site.curorigin[ 2 ] + 5 ); - - if ( site IsInUse() ) // somebody is defusing - { - self BotNotifyBotEvent( "sd", "start", "defuser" ); - - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sd", "stop", "defuser" ); - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; - timepassed = getTimePassed() / 1000; - - // dont have a bomb - if ( !self IsBombCarrier() && !level.multiBomb ) - { - if ( !isDefined( level.sdBomb ) ) - { - return; - } - - bomb = level.sdBomb; - carrier = level.sdBomb.carrier; - - // bomb is picked up - if ( isDefined( carrier ) ) - { - // escort the bomb carrier - if ( self HasScriptGoal() ) - { - return; - } - - origin = carrier.origin; - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj( bomb, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - if ( !isDefined( bomb.bots ) ) - { - bomb.bots = 0; - } - - origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); - - // hang around the bomb if other is going to go get it - if ( bomb.bots > 1 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - - self thread bot_get_obj( bomb ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // go get the bomb - self BotNotifyBotEvent( "sd", "start", "bomb" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bot_inc_bots( bomb ); - self thread bot_get_obj( bomb ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sd", "stop", "bomb" ); - return; - } - - // check if to plant - if ( timepassed < 120 && timeleft >= 90 && randomInt( 100 ) < 98 ) - { - return; - } - - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - return; - } - - sites = []; - - for ( i = 0; i < level.bombZones.size; i++ ) - { - sites[ sites.size ] = level.bombZones[ i ]; - } - - if ( !sites.size ) - { - return; - } - - if ( data.rand > 50 ) - { - plant = self bot_array_nearest_curorigin( sites ); - } - else - { - plant = random( sites ); - } - - if ( !isDefined( plant ) ) - { - return; - } - - origin = ( plant.curorigin[ 0 ] + 50, plant.curorigin[ 1 ] + 50, plant.curorigin[ 2 ] + 5 ); - - self BotNotifyBotEvent( "sd", "go", "plant", plant ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 1 ); - self thread bot_go_plant( plant ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || level.bombPlanted || plant.visibleTeam == "none" || !self isTouching( plant.trigger ) || self InLastStand() || self HasThreat() || plant IsInUse() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "sd", "start", "plant", plant ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( plant.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "sd", "stop", "plant", plant ); -} - -/* - Bots play sd attackers -*/ -bot_sd_attackers() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "sd" ) - { - return; - } - - if ( self.team != game[ "attackers" ] ) - { - return; - } - - data = spawnStruct(); - data.rand = self BotGetRandom(); - data.first = true; - - for ( ;; ) - { - self bot_sd_attackers_loop( data ); - } -} - -/* - Bots play capture the flag -*/ -bot_cap_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - myflag = level.teamFlags[ myteam ]; - myzone = level.capZones[ myteam ]; - - theirflag = level.teamFlags[ otherTeam ]; - theirzone = level.capZones[ otherTeam ]; - - if ( !myflag maps\mp\gametypes\_gameobjects::isHome() ) - { - carrier = myflag.carrier; - - if ( !isDefined( carrier ) ) // someone doesnt has our flag - { - if ( !isDefined( theirflag.carrier ) && DistanceSquared( self.origin, theirflag.curorigin ) < DistanceSquared( self.origin, myflag.curorigin ) ) // no one has their flag and its closer - { - self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); - - self bot_cap_get_flag( theirflag ); - - self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); - } - else // go get it - { - self BotNotifyBotEvent( "cap", "start", "my_flag", myflag ); - - self bot_cap_get_flag( myflag ); - - self BotNotifyBotEvent( "cap", "stop", "my_flag", myflag ); - } - - return; - } - else - { - if ( theirflag maps\mp\gametypes\_gameobjects::isHome() && randomint( 100 ) < 50 ) - { - // take their flag - self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); - - self bot_cap_get_flag( theirflag ); - - self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); - } - else - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( !isDefined( theirzone.bots ) ) - { - theirzone.bots = 0; - } - - origin = theirzone.curorigin; - - if ( theirzone.bots > 2 || randomInt( 100 ) < 45 ) - { - // kill carrier - if ( carrier _hasPerk( "specialty_coldblooded" ) ) - { - return; - } - - origin = carrier.origin; - - self SetScriptGoal( origin, 64 ); - self thread bot_escort_obj( myflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - self thread bot_inc_bots( theirzone ); - - // camp their zone - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - wait 4; - self notify( "bot_inc_bots" ); - theirzone.bots--; - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_inc_bots( theirzone ); - self thread bot_escort_obj( myflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - } - } - else // our flag is ok - { - if ( self isFlagCarrier() ) // if have flag - { - // go cap - origin = myzone.curorigin; - - self BotNotifyBotEvent( "cap", "start", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 32 ); - - self thread bot_get_obj( myflag ); - evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - wait 1; - - if ( evt != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "cap", "stop", "cap" ); - return; - } - - carrier = theirflag.carrier; - - if ( !isDefined( carrier ) ) // if no one has enemy flag - { - self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); - - self bot_cap_get_flag( theirflag ); - - self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); - return; - } - - // escort them - - if ( self HasScriptGoal() ) - { - return; - } - - origin = carrier.origin; - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj( theirflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } -} - -/* - Bots play capture the flag -*/ -bot_cap() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "ctf" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.capZones ) ) - { - continue; - } - - if ( !isDefined( level.teamFlags ) ) - { - continue; - } - - self bot_cap_loop(); - } -} - -/* - Gets the carriers ent num -*/ -getCarrierEntNum() -{ - carrierNum = -1; - - if ( isDefined( self.carrier ) ) - { - carrierNum = self.carrier getEntityNumber(); - } - - return carrierNum; -} - -/* - Bots go and get the flag -*/ -bot_cap_get_flag( flag ) -{ - origin = flag.curorigin; - - // go get it - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 32 ); - - self thread bot_get_obj( flag ); - - evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( evt != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( evt != "goal" ) - { - self.bot_lock_goal = false; - return; - } - - self SetScriptGoal( self.origin, 64 ); - curCarrier = flag getCarrierEntNum(); - - while ( curCarrier == flag getCarrierEntNum() && self isTouching( flag.trigger ) ) - { - cur = flag.curProgress; - wait 0.5; - - if ( flag.curProgress == cur ) - { - break; // some enemy is near us, kill him - } - } - - self ClearScriptGoal(); - - self.bot_lock_goal = false; -} - -/* - Bots go plant the demo bomb -*/ -bot_dem_go_plant( plant ) -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( ( plant.label == "_b" && level.bombBPlanted ) || ( plant.label == "_a" && level.bombAPlanted ) ) - { - break; - } - - if ( self isTouching( plant.trigger ) ) - { - break; - } - } - - if ( ( plant.label == "_b" && level.bombBPlanted ) || ( plant.label == "_a" && level.bombAPlanted ) ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Bots spawn kill dom attackers -*/ -bot_dem_attack_spawnkill() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - l1 = level.bombAPlanted; - l2 = level.bombBPlanted; - - for ( ;; ) - { - wait 0.5; - - if ( l1 != level.bombAPlanted || l2 != level.bombBPlanted ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots play demo attackers -*/ -bot_dem_attackers_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - bombs = []; // sites with bombs - sites = []; // sites to bomb at - bombed = 0; // exploded sites - - for ( i = 0; i < level.bombZones.size; i++ ) - { - bomb = level.bombZones[ i ]; - - if ( isDefined( bomb.bombExploded ) && bomb.bombExploded ) - { - bombed++; - continue; - } - - if ( bomb.label == "_a" ) - { - if ( level.bombAPlanted ) - { - bombs[ bombs.size ] = bomb; - } - else - { - sites[ sites.size ] = bomb; - } - - continue; - } - - if ( bomb.label == "_b" ) - { - if ( level.bombBPlanted ) - { - bombs[ bombs.size ] = bomb; - } - else - { - sites[ sites.size ] = bomb; - } - - continue; - } - } - - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; - - shouldLet = ( game[ "teamScores" ][ myteam ] > game[ "teamScores" ][ otherTeam ] && timeleft < 90 && bombed == 1 ); - - // spawnkill conditions - // if we have bombed one site or 1 bomb is planted with lots of time left, spawn kill - // if we want the other team to win for overtime and they do not need to defuse, spawn kill - if ( ( ( bombed + bombs.size == 1 && timeleft >= 90 ) || ( shouldLet && !bombs.size ) ) && randomInt( 100 ) < 95 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); - - if ( !spawnPoints.size ) - { - return; - } - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 2048 * 2048 ) - { - return; - } - - self SetScriptGoal( spawnpoint.origin, 1024 ); - - self thread bot_dem_attack_spawnkill(); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // let defuse conditions - // if enemy is going to lose and lots of time left, let them defuse to play longer - // or if want to go into overtime near end of the extended game - if ( ( ( bombs.size + bombed == 2 && timeleft >= 90 ) || ( shouldLet && bombs.size ) ) && randomInt( 100 ) < 95 ) - { - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); - - if ( !spawnPoints.size ) - { - return; - } - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( spawnpoint.origin, 512 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // defend bomb conditions - // if time is running out and we have a bomb planted - if ( bombs.size && timeleft < 90 && ( !sites.size || randomInt( 100 ) < 95 ) ) - { - site = self bot_array_nearest_curorigin( bombs ); - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - if ( site IsInUse() ) // somebody is defusing - { - self BotNotifyBotEvent( "dem", "start", "defuser", site ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "dem", "stop", "defuser", site ); - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // else go plant - if ( !sites.size ) - { - return; - } - - plant = self bot_array_nearest_curorigin( sites ); - - if ( !isDefined( plant ) ) - { - return; - } - - if ( !isDefined( plant.bots ) ) - { - plant.bots = 0; - } - - origin = ( plant.curorigin[ 0 ] + 50, plant.curorigin[ 1 ] + 50, plant.curorigin[ 2 ] + 5 ); - - // hang around the site if lots of time left - if ( plant.bots > 1 && timeleft >= 60 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_dem_go_plant( plant ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - self BotNotifyBotEvent( "dem", "go", "plant", plant ); - - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots( plant ); - self thread bot_dem_go_plant( plant ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || ( plant.label == "_b" && level.bombBPlanted ) || ( plant.label == "_a" && level.bombAPlanted ) || plant IsInUse() || !self isTouching( plant.trigger ) || self InLastStand() || self HasThreat() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "dem", "start", "plant", plant ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( plant.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "dem", "stop", "plant", plant ); -} - -/* - Bots play demo attackers -*/ -bot_dem_attackers() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "dd" ) - { - return; - } - - if ( self.team != game[ "attackers" ] ) - { - return; - } - - if ( inOvertime() ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - continue; - } - - self bot_dem_attackers_loop(); - } -} - -/* - Bots play demo defenders -*/ -bot_dem_defenders_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - bombs = []; // sites with bombs - sites = []; // sites to bomb at - bombed = 0; // exploded sites - - for ( i = 0; i < level.bombZones.size; i++ ) - { - bomb = level.bombZones[ i ]; - - if ( isDefined( bomb.bombExploded ) && bomb.bombExploded ) - { - bombed++; - continue; - } - - if ( bomb.label == "_a" ) - { - if ( level.bombAPlanted ) - { - bombs[ bombs.size ] = bomb; - } - else - { - sites[ sites.size ] = bomb; - } - - continue; - } - - if ( bomb.label == "_b" ) - { - if ( level.bombBPlanted ) - { - bombs[ bombs.size ] = bomb; - } - else - { - sites[ sites.size ] = bomb; - } - - continue; - } - } - - timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; - - shouldLet = ( timeleft < 60 && ( ( bombed == 0 && bombs.size != 2 ) || ( game[ "teamScores" ][ myteam ] > game[ "teamScores" ][ otherTeam ] && bombed == 1 ) ) && randomInt( 100 ) < 98 ); - - // spawnkill conditions - // if nothing to defuse with a lot of time left, spawn kill - // or letting a bomb site to explode but a bomb is planted, so spawnkill - if ( ( !bombs.size && timeleft >= 60 && randomInt( 100 ) < 95 ) || ( shouldLet && bombs.size == 1 ) ) - { - if ( self HasScriptGoal() ) - { - return; - } - - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); - - if ( !spawnPoints.size ) - { - return; - } - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 2048 * 2048 ) - { - return; - } - - self SetScriptGoal( spawnpoint.origin, 1024 ); - - self thread bot_dem_defend_spawnkill(); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - // let blow up conditions - // let enemy blow up at least one to extend play time - // or if want to go into overtime after extended game - if ( shouldLet ) - { - spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); - - if ( !spawnPoints.size ) - { - return; - } - - spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); - - if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( spawnpoint.origin, 512 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // defend conditions - // if no bombs planted with little time left - if ( !bombs.size && timeleft < 60 && randomInt( 100 ) < 95 && sites.size ) - { - site = self bot_array_nearest_curorigin( sites ); - origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); - - if ( site IsInUse() ) // somebody is planting - { - self BotNotifyBotEvent( "dem", "start", "planter", site ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - - self thread bot_defend_site( site ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "dem", "stop", "planter", site ); - return; - } - - // else hang around the site - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // else go defuse - - if ( !bombs.size ) - { - return; - } - - defuse = self bot_array_nearest_curorigin( bombs ); - - if ( !isDefined( defuse ) ) - { - return; - } - - if ( !isDefined( defuse.bots ) ) - { - defuse.bots = 0; - } - - origin = ( defuse.curorigin[ 0 ] + 50, defuse.curorigin[ 1 ] + 50, defuse.curorigin[ 2 ] + 5 ); - - // hang around the site if not in danger of losing - if ( defuse.bots > 1 && bombed + bombs.size != 2 ) - { - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - - self thread bot_dem_go_defuse( defuse ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - self BotNotifyBotEvent( "dem", "go", "defuse", defuse ); - - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 1 ); - self thread bot_inc_bots( defuse ); - self thread bot_dem_go_defuse( defuse ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || ( defuse.label == "_b" && !level.bombBPlanted ) || ( defuse.label == "_a" && !level.bombAPlanted ) || defuse IsInUse() || !self isTouching( defuse.trigger ) || self InLastStand() || self HasThreat() ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "dem", "start", "defuse", defuse ); - - self BotRandomStance(); - self SetScriptGoal( self.origin, 64 ); - self bot_wait_stop_move(); - - waitTime = ( defuse.useTime / 1000 ) + 2.5; - self thread BotPressUse( waitTime ); - wait waitTime; - - self ClearScriptGoal(); - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "dem", "stop", "defuse", defuse ); -} - -/* - Bots play demo defenders -*/ -bot_dem_defenders() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "dd" ) - { - return; - } - - if ( self.team == game[ "attackers" ] ) - { - return; - } - - if ( inOvertime() ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - continue; - } - - self bot_dem_defenders_loop(); - } -} - -/* - Bots play demo overtime -*/ -bot_dem_overtime() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "dd" ) - { - return; - } - - if ( !inOvertime() ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.bombZones ) || !level.bombZones.size ) - { - continue; - } - - if ( !level.bombZones[ 0 ].bombPlanted || !level.bombZones[ 0 ] maps\mp\gametypes\_gameobjects::isFriendlyTeam( self.team ) ) - { - self bot_dem_attackers_loop(); - continue; - } - - self bot_dem_defenders_loop(); - } -} - -/* - Bots go defuse -*/ -bot_dem_go_defuse( defuse ) -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( self isTouching( defuse.trigger ) ) - { - break; - } - - if ( ( defuse.label == "_b" && !level.bombBPlanted ) || ( defuse.label == "_a" && !level.bombAPlanted ) ) - { - break; - } - } - - if ( ( defuse.label == "_b" && !level.bombBPlanted ) || ( defuse.label == "_a" && !level.bombAPlanted ) ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Bots go spawn kill -*/ -bot_dem_defend_spawnkill() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - for ( ;; ) - { - wait 0.5; - - if ( level.bombBPlanted || level.bombAPlanted ) - { - break; - } - } - - self notify( "bad_path" ); -} - -/* - Bots think to revive -*/ -bot_think_revive_loop() -{ - needsRevives = []; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( player.team != self.team ) - { - continue; - } - - if ( distanceSquared( self.origin, player.origin ) >= 2048 * 2048 ) - { - continue; - } - - if ( player inLastStand() ) - { - needsRevives[ needsRevives.size ] = player; - } - } - - if ( !needsRevives.size ) - { - return; - } - - revive = random( needsRevives ); - - self BotNotifyBotEvent( "revive", "go", revive ); - self.bot_lock_goal = true; - - self SetScriptGoal( revive.origin, 64 ); - self thread stop_go_target_on_death( revive ); - - ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - if ( ret != "goal" || !isDefined( revive ) || distanceSquared( self.origin, revive.origin ) >= 100 * 100 || !revive inLastStand() || revive isBeingRevived() || !isAlive( revive ) ) - { - return; - } - - self BotNotifyBotEvent( "revive", "start", revive ); - - self BotFreezeControls( true ); - self bot_wait_stop_move(); - - waitTime = 3.25; - self thread BotPressUse( waitTime ); - wait waitTime; - - self BotFreezeControls( false ); - - self BotNotifyBotEvent( "revive", "stop", revive ); -} - -/* - Bots think to revive -*/ -bot_think_revive() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( !level.dieHardMode || !level.teamBased ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 3 ) ); - - if ( self HasScriptGoal() || self.bot_lock_goal ) - { - continue; - } - - if ( self isDefusing() || self isPlanting() ) - { - continue; - } - - if ( self IsUsingRemote() || self BotIsFrozen() ) - { - continue; - } - - if ( self inLastStand() ) - { - continue; - } - - self bot_think_revive_loop(); - } -} - -/* - Bots play the Global thermonuclear warfare -*/ -bot_gtnw_loop() -{ - myteam = self.team; - theirteam = getOtherTeam( myteam ); - origin = level.nukeSite.trigger.origin; - trigger = level.nukeSite.trigger; - - ourCapCount = level.nukeSite.touchList[ myteam ]; - theirCapCount = level.nukeSite.touchList[ theirteam ]; - rand = self BotGetRandom(); - - if ( ( !ourCapCount && !theirCapCount ) || rand <= 20 ) - { - // go cap the obj - self BotNotifyBotEvent( "gtnw", "go", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); - self thread bots_watch_touch_obj( trigger ); - - ret = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( ret != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( ret != "goal" || !self isTouching( trigger ) ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "gtnw", "start", "cap" ); - - self SetScriptGoal( self.origin, 64 ); - - while ( self isTouching( trigger ) ) - { - cur = level.nukeSite.curProgress; - wait 0.5; - - if ( cur == level.nukeSite.curProgress ) - { - break; // no prog made, enemy must be capping - } - - self thread bot_do_random_action_for_objective( trigger ); - } - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "gtnw", "stop", "cap" ); - return; - } - - if ( theirCapCount ) - { - // kill capturtour - self.bot_lock_goal = true; - - self SetScriptGoal( origin, 64 ); - self thread bots_watch_touch_obj( trigger ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - return; - } - - // else hang around the site - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; -} - -/* - Bots play the Global thermonuclear warfare -*/ -bot_gtnw() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "gtnw" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.nukeSite ) || !isDefined( level.nukeSite.trigger ) ) - { - continue; - } - - self bot_gtnw_loop(); - } -} - -/* - Bots play oneflag -*/ -bot_oneflag_loop() -{ - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - if ( myteam == game[ "attackers" ] ) - { - myzone = level.capZones[ myteam ]; - theirflag = level.teamFlags[ otherTeam ]; - - if ( self isFlagCarrier() ) - { - // go cap - origin = myzone.curorigin; - - self BotNotifyBotEvent( "oneflag", "start", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( origin, 32 ); - - evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - wait 1; - - if ( evt != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "oneflag", "stop", "cap" ); - return; - } - - carrier = theirflag.carrier; - - if ( !isDefined( carrier ) ) // if no one has enemy flag - { - self BotNotifyBotEvent( "oneflag", "start", "their_flag" ); - self bot_cap_get_flag( theirflag ); - self BotNotifyBotEvent( "oneflag", "stop", "their_flag" ); - return; - } - - // escort them - - if ( self HasScriptGoal() ) - { - return; - } - - origin = carrier.origin; - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_escort_obj( theirflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - else - { - myflag = level.teamFlags[ myteam ]; - theirzone = level.capZones[ otherTeam ]; - - if ( !myflag maps\mp\gametypes\_gameobjects::isHome() ) - { - carrier = myflag.carrier; - - if ( !isDefined( carrier ) ) // someone doesnt has our flag - { - self BotNotifyBotEvent( "oneflag", "start", "my_flag" ); - self bot_cap_get_flag( myflag ); - self BotNotifyBotEvent( "oneflag", "stop", "my_flag" ); - return; - } - - if ( self HasScriptGoal() ) - { - return; - } - - if ( !isDefined( theirzone.bots ) ) - { - theirzone.bots = 0; - } - - origin = theirzone.curorigin; - - if ( theirzone.bots > 2 || randomInt( 100 ) < 45 ) - { - // kill carrier - if ( carrier _hasPerk( "specialty_coldblooded" ) ) - { - return; - } - - origin = carrier.origin; - - self SetScriptGoal( origin, 64 ); - self thread bot_escort_obj( myflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - return; - } - - self thread bot_inc_bots( theirzone ); - - // camp their zone - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - wait 4; - self notify( "bot_inc_bots" ); - theirzone.bots--; - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_inc_bots( theirzone ); - self thread bot_escort_obj( myflag, carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - else - { - // is home, lets hang around and protect - if ( self HasScriptGoal() ) - { - return; - } - - origin = myflag.curorigin; - - if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( origin, 256 ); - self thread bot_get_obj( myflag ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - } -} - -/* - Bots play oneflag -*/ -bot_oneflag() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "oneflag" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.capZones ) || !isDefined( level.teamFlags ) ) - { - continue; - } - - self bot_oneflag_loop(); - } -} - -/* - Bots play arena -*/ -bot_arena_loop() -{ - flag = level.arenaFlag; - myTeam = self.team; - - self BotNotifyBotEvent( "arena", "go", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( flag.trigger.origin, 64 ); - - event = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - if ( event != "new_goal" ) - { - self ClearScriptGoal(); - } - - if ( event != "goal" || !self isTouching( flag.trigger ) ) - { - self.bot_lock_goal = false; - return; - } - - self BotNotifyBotEvent( "arena", "start", "cap" ); - - self SetScriptGoal( self.origin, 64 ); - - while ( self isTouching( flag.trigger ) && flag.ownerTeam != myTeam ) - { - cur = flag.curProgress; - wait 0.5; - - if ( cur == flag.curProgress ) - { - break; // no prog made, enemy must be capping - } - - self thread bot_do_random_action_for_objective( flag.trigger ); - } - - self ClearScriptGoal(); - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "arena", "stop", "cap" ); -} - -/* - Bots play arena -*/ -bot_arena() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "arena" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isDefined( level.arenaFlag ) ) - { - continue; - } - - self bot_arena_loop(); - } -} - -/* - bot_vip_loop - - For those wondering why i call a function for these loops like this - its because, the variables created in this function will be free'd once the function exits, - if it was in the infinite loop, the function never exits, thus the variables are never free'd - - This isnt leaking variables, but freeing variables that will no longer be used, an optimization of sorts -*/ -bot_vip_loop() -{ - vip = undefined; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( isDefined( player.isVip ) && player.isVip ) - { - vip = player; - } - } - - if ( self.team == game[ "defenders" ] ) - { - if ( isDefined( self.isVip ) && self.isVip ) - { - if ( isDefined( level.extractionZone ) && !isDefined( level.extractionTime ) ) - { - // go to extraction zone - self BotNotifyBotEvent( "vip", "start", "cap" ); - - self.bot_lock_goal = true; - self SetScriptGoal( level.extractionZone.trigger.origin, 32 ); - - evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); - - wait 1; - - if ( evt != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "vip", "stop", "cap" ); - } - } - else if ( isDefined( vip ) ) - { - // protect the vip - if ( DistanceSquared( vip.origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( vip.origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - } - else - { - if ( isDefined( level.extractionZone ) && !isDefined( level.extractionTime ) && self BotGetRandom() < 65 ) - { - // camp the extraction zone - if ( DistanceSquared( level.extractionZone.trigger.origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( level.extractionZone.trigger.origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - else if ( isDefined( vip ) ) - { - // kill the vip - self SetScriptGoal( vip.origin, 32 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - } -} - -/* - Bots play arena -*/ -bot_vip() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "vip" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 3, 5 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - self bot_vip_loop(); - } -} - -/* - Loop -*/ -bot_conf_loop() -{ - dog_tag_keys = getArrayKeys( level.dogtags ); - tags = []; - tag = undefined; - - for ( i = 0; i < dog_tag_keys.size; i++ ) - { - temp_tag = level.dogtags[ dog_tag_keys[ i ] ]; - - if ( !isDefined( temp_tag ) ) - { - continue; - } - - if ( DistanceSquared( self.origin, temp_tag.trigger.origin ) > 1024 * 1024 ) - { - continue; - } - - if ( !isDefined( temp_tag.bots ) ) - { - temp_tag.bots = 0; - } - - if ( temp_tag.bots >= 2 ) - { - continue; - } - - tags[ tags.size ] = temp_tag; - } - - if ( randomInt( 2 ) ) - { - for ( i = 0; i < tags.size; i++ ) - { - temp_tag = tags[ i ]; - - if ( !isDefined( tag ) || DistanceSquared( self.origin, temp_tag.trigger.origin ) < DistanceSquared( self.origin, tag.trigger.origin ) ) - { - tag = temp_tag; - } - } - } - else - { - tag = random( tags ); - } - - if ( !isdefined( tag ) ) - { - return; - } - - self BotNotifyBotEvent( "conf", "start", "cap", tag ); - - self.bot_lock_goal = true; - self SetScriptGoal( tag.trigger.origin, 16 ); - self thread bot_inc_bots( tag, true ); - self thread bots_watch_touch_obj( tag.trigger ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "conf", "stop", "cap", tag ); -} - -/* - Bots play conf -*/ -bot_conf() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "conf" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 2 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isdefined( level.dogtags ) ) - { - continue; - } - - self bot_conf_loop(); - } -} - -/* - Watches for grnd zone -*/ -bots_watch_grnd() -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "goal" ); - self endon( "bad_path" ); - self endon( "new_goal" ); - - grnd_origin = level.grnd_zone.origin; - - for ( ;; ) - { - wait 1 + randomInt( 5 ) * 0.5; - - if ( grnd_origin != level.grnd_zone.origin ) - { - break; - } - - if ( self maps\mp\gametypes\grnd::isingrindzone() ) - { - break; - } - } - - if ( grnd_origin != level.grnd_zone.origin ) - { - self notify( "bad_path" ); - } - else - { - self notify( "goal" ); - } -} - -/* - Loop -*/ -bot_grnd_loop() -{ - if ( isDefined( self.inGrindZone ) && self.inGrindZone && isReallyAlive( self ) && self.pers[ "team" ] != "spectator" && self maps\mp\gametypes\grnd::isingrindzone() ) - { - // in the grnd zone - - if ( level.grnd_numplayers[ level.otherTeam[ self.team ] ] ) - { - // hunt enemy in drop zone - target = undefined; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( isDefined( player.inGrindZone ) && player.inGrindZone && isReallyAlive( player ) && player.pers[ "team" ] != "spectator" && player maps\mp\gametypes\grnd::isingrindzone() ) - { - target = player; - - if ( cointoss() ) - { - break; - } - } - } - - if ( isDefined( target ) ) - { - self BotNotifyBotEvent( "grnd", "start", "kill", target ); - - self SetScriptGoal( target.origin, 32 ); - self thread stop_go_target_on_death( target ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "grnd", "stop", "kill", target ); - } - } - else - { - // stay in the zone - goal = self.origin; - self SetScriptGoal( goal, 64 ); - - self BotNotifyBotEvent( "grnd", "start", "cap" ); - - while ( self HasScriptGoal() && self GetScriptGoal() == goal && self maps\mp\gametypes\grnd::isingrindzone() ) - { - if ( level.grnd_numplayers[ level.otherTeam[ self.team ] ] ) - { - break; - } - - wait 0.5; - - self thread bot_do_random_action_for_objective( level.grnd_zone ); - } - - if ( self HasScriptGoal() && self GetScriptGoal() == goal ) - { - self ClearScriptGoal(); - } - - self BotNotifyBotEvent( "grnd", "stop", "cap" ); - } - - return; - } - - if ( randomInt( 100 ) < 40 || level.grnd_numplayers[ self.team ] <= 0 ) - { - self BotNotifyBotEvent( "grnd", "start", "go_cap" ); - - // go to grnd zone - self.bot_lock_goal = true; - self SetScriptGoal( level.grnd_zone.origin, 32 ); - self thread bots_watch_grnd(); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - - self BotNotifyBotEvent( "grnd", "stop", "go_cap" ); - } -} - -/* - Bots play groundzone -*/ -bot_grnd() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "grnd" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 3 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isdefined( level.grnd_zone ) ) - { - continue; - } - - self bot_grnd_loop(); - } -} - -/* - Loop -*/ -bot_tdef_loop() -{ - if ( isDefined( level.gameFlag.carrier ) ) - { - if ( level.gameFlag maps\mp\gametypes\_gameobjects::getOwnerTeam() == level.otherTeam[ self.team ] ) - { - if ( self HasScriptGoal() ) - { - return; - } - - // go kill - self SetScriptGoal( level.gameFlag.carrier.origin, 64 ); - self thread bot_escort_obj( level.gameFlag, level.gameFlag.carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - else if ( level.gameFlag.carrier != self ) - { - // go protect - if ( self HasScriptGoal() ) - { - return; - } - - if ( DistanceSquared( level.gameFlag.carrier.origin, self.origin ) <= 1024 * 1024 ) - { - return; - } - - self SetScriptGoal( level.gameFlag.carrier.origin, 256 ); - self thread bot_escort_obj( level.gameFlag, level.gameFlag.carrier ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - else if ( self BotGetRandom() < 70 ) - { - // we haev flag, lets run away from enemies - avg_org = ( 0, 0, 0 ); - count = 0; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( !isDefined( player.team ) ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( player.team == self.team ) - { - continue; - } - - count++; - avg_org += player.origin; - } - - if ( count ) - { - avg_org /= count; - wps = []; - - for ( i = 0; i < level.waypoints.size; i++ ) - { - wp = level.waypoints[ i ]; - - if ( DistanceSquared( wp.origin, avg_org ) < 1024 * 1024 ) - { - continue; - } - - wps[ wps.size ] = wp; - } - - wp = random( wps ); - - if ( isDefined( wp ) ) - { - self.bot_lock_goal = true; - self SetScriptGoal( wp.origin, 256 ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - - self.bot_lock_goal = false; - } - } - } - - return; - } - - // go get it - self BotNotifyBotEvent( "tdef", "start", "cap" ); - - self bot_cap_get_flag( level.gameFlag ); - - self BotNotifyBotEvent( "tdef", "stop", "cap" ); -} - -/* - Bots play groundzone -*/ -bot_tdef() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "tdef" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 3 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - if ( !isdefined( level.gameFlag ) ) - { - continue; - } - - self bot_tdef_loop(); - } -} - -/* - Loop -*/ -bot_infect_loop() -{ - if ( self HasScriptGoal() ) - { - return; - } - - if ( self.team == "axis" ) - { - target = undefined; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[ i ]; - - if ( player == self ) - { - continue; - } - - if ( !isReallyAlive( player ) ) - { - continue; - } - - if ( level.teambased && self.team == player.team ) - { - continue; - } - - if ( !isdefined( target ) || DistanceSquared( self.origin, player.origin ) < DistanceSquared( self.origin, target.origin ) ) - { - target = player; - } - } - - if ( isDefined( target ) ) - { - self SetScriptGoal( target.origin, 32 ); - self thread stop_go_target_on_death( target ); - - if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) - { - self ClearScriptGoal(); - } - } - } -} - -/* - Bots play infect -*/ -bot_infect() -{ - self endon( "death" ); - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( level.gametype != "infect" ) - { - return; - } - - for ( ;; ) - { - wait( randomintrange( 1, 3 ) ); - - if ( self IsUsingRemote() || self.bot_lock_goal ) - { - continue; - } - - self bot_infect_loop(); - } -} +/* + _bot_script + Author: INeedGames + Date: 05/11/2021 + Tells the bots what to do. + Similar to t5's _bot +*/ + +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include maps\mp\bots\_bot_utility; + +/* + When the bot gets added into the game. +*/ +added() +{ + self endon( "disconnect" ); + + self setPlayerData( "experience", self bot_get_rank() ); + self setPlayerData( "prestige", self bot_get_prestige() ); + + self setPlayerData( "cardTitle", random( getCardTitles() ) ); + self setPlayerData( "cardIcon", random( getCardIcons() ) ); + + self setClasses(); + + self set_diff(); +} + +/* + When the bot connects to the game. +*/ +connected() +{ + self endon( "disconnect" ); + + self.killerlocation = undefined; + self.lastkiller = undefined; + self.bot_change_class = true; + + self thread difficulty(); + self thread teamWatch(); + self thread classWatch(); + + self thread onBotSpawned(); + self thread onSpawned(); + + self thread onDeath(); + self thread onGiveLoadout(); + + self thread onKillcam(); + + wait 4; + self.challengedata = []; // iw5 is bad lmao +} + +/* + 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.team ) ) + { + continue; + } + + if ( player is_bot() ) + { + continue; + } + + p = player getPlayerData( "prestige" ); + break; + } + } + else if ( p_dvar == -2 ) + { + p = randomInt( 12 ); + } + else + { + p = p_dvar; + } + + return p; +} + +/* + Gets an exp amount for the bot that is nearish the host's xp. +*/ +bot_get_rank() +{ + rank = 1; + rank_dvar = getDvarInt( "bots_loadout_rank" ); + + if ( rank_dvar == -1 ) + { + ranks = []; + bot_ranks = []; + human_ranks = []; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !IsDefined( player.pers[ "rank" ] ) ) + { + continue; + } + + if ( player is_bot() ) + { + bot_ranks[ bot_ranks.size ] = player.pers[ "rank" ]; + } + else + { + human_ranks[ human_ranks.size ] = player.pers[ "rank" ]; + } + } + + if ( !human_ranks.size ) + { + human_ranks[ human_ranks.size ] = Round( random_normal_distribution( 45, 20, 0, level.maxrank ) ); + } + + human_avg = array_average( human_ranks ); + + while ( bot_ranks.size + human_ranks.size < 5 ) + { + // add some random ranks for better random number distribution + rank = human_avg + RandomIntRange( -10, 10 ); + human_ranks[ human_ranks.size ] = rank; + } + + ranks = array_combine( human_ranks, bot_ranks ); + + avg = array_average( ranks ); + s = array_std_deviation( ranks, avg ); + + rank = Round( random_normal_distribution( avg, s, 0, level.maxrank ) ); + } + else if ( rank_dvar == 0 ) + { + rank = Round( random_normal_distribution( 45, 20, 0, level.maxrank ) ); + } + else + { + rank = Round( random_normal_distribution( rank_dvar, 5, 0, level.maxrank ) ); + } + + return maps\mp\gametypes\_rank::getRankInfoMinXP( rank ); +} + +/* + returns an array of all card titles +*/ +getCardTitles() +{ + cards = []; + + for ( i = 0; i < 600; i++ ) + { + card_name = tableLookupByRow( "mp/cardTitleTable.csv", i, 0 ); + + if ( card_name == "" ) + { + continue; + } + + if ( !isSubStr( card_name, "cardtitle_" ) ) + { + continue; + } + + cards[ cards.size ] = i; + } + + return cards; +} + +/* + returns an array of all card icons +*/ +getCardIcons() +{ + cards = []; + + for ( i = 0; i < 400; i++ ) + { + card_name = tableLookupByRow( "mp/cardIconTable.csv", i, 0 ); + + if ( card_name == "" ) + { + continue; + } + + if ( !isSubStr( card_name, "cardicon_" ) ) + { + continue; + } + + cards[ cards.size ] = i; + } + + return cards; +} + +/* + returns if attachment is valid with attachment 2 +*/ +isValidAttachmentCombo( att1, att2 ) +{ + colIndex = tableLookupRowNum( "mp/attachmentCombos.csv", 0, att1 ); + + if ( tableLookup( "mp/attachmentCombos.csv", 0, att2, colIndex ) == "no" ) + { + return false; + } + + return true; +} + +/* + returns all attachments for the given gun +*/ +getAttachmentsForGun( gun ) +{ + row = tableLookupRowNum( "mp/statStable.csv", 4, gun ); + + attachments = []; + + for ( h = 0; h < 10; h++ ) + { + attachmentName = tableLookupByRow( "mp/statStable.csv", row, h + 11 ); + + if ( attachmentName == "" ) + { + attachments[ attachments.size ] = "none"; + break; + } + + attachments[ attachments.size ] = attachmentName; + } + + return attachments; +} + +/* + returns all primaries +*/ +getPrimaries() +{ + primaries = []; + + for ( i = 0; i < 160; i++ ) + { + weapon_type = tableLookupByRow( "mp/statstable.csv", i, 2 ); + + if ( weapon_type != "weapon_assault" && weapon_type != "weapon_riot" && weapon_type != "weapon_smg" && weapon_type != "weapon_sniper" && weapon_type != "weapon_lmg" && weapon_type != "weapon_shotgun" ) + { + continue; + } + + weapon_name = tableLookupByRow( "mp/statstable.csv", i, 4 ); + + if ( isSubStr( weapon_name, "jugg" ) ) + { + continue; + } + + primaries[ primaries.size ] = weapon_name; + } + + return primaries; +} + +/* + returns all secondaries +*/ +getSecondaries() +{ + secondaries = []; + + for ( i = 0; i < 160; i++ ) + { + weapon_type = tableLookupByRow( "mp/statstable.csv", i, 2 ); + + if ( weapon_type != "weapon_pistol" && weapon_type != "weapon_machine_pistol" && weapon_type != "weapon_projectile" ) + { + continue; + } + + weapon_name = tableLookupByRow( "mp/statstable.csv", i, 4 ); + + if ( weapon_name == "gl" || isSubStr( weapon_name, "jugg" ) ) + { + continue; + } + + secondaries[ secondaries.size ] = weapon_name; + } + + return secondaries; +} + +/* + returns all camos +*/ +getCamos() +{ + camos = []; + + for ( i = 0; i < 15; i++ ) + { + camo_name = tableLookupByRow( "mp/camoTable.csv", i, 1 ); + + if ( camo_name == "" ) + { + continue; + } + + camos[ camos.size ] = camo_name; + } + + return camos; +} + +/* + returns all reticles +*/ +getReticles() +{ + reticles = []; + + for ( i = 0; i < 10; i++ ) + { + reticle_name = tableLookupByRow( "mp/reticletable.csv", i, 1 ); + + if ( reticle_name == "" ) + { + continue; + } + + reticles[ reticles.size ] = reticle_name; + } + + return reticles; +} + +/* + returns all perks for the given type +*/ +getPerks( perktype ) +{ + perks = []; + + for ( i = 0; i < 100; i++ ) + { + perk_type = tableLookupByRow( "mp/perktable.csv", i, 5 ); + + if ( perk_type != perktype ) + { + continue; + } + + perk_name = tableLookupByRow( "mp/perktable.csv", i, 1 ); + + if ( perk_name == "specialty_uav" ) + { + continue; + } + + perks[ perks.size ] = perk_name; + } + + return perks; +} + +/* + returns kill cost for a streak +*/ +getKillsNeededForStreak( streak ) +{ + return int( tableLookup( "mp/killstreakTable.csv", 1, streak, 4 ) ); +} + +/* + returns all killstreaks +*/ +getKillstreaks() +{ + killstreaks = []; + + for ( i = 0; i < 65; i++ ) + { + streak_name = tableLookupByRow( "mp/killstreakTable.csv", i, 1 ); + + if ( streak_name == "" || streak_name == "none" ) + { + continue; + } + + if ( streak_name == "b1" ) + { + continue; + } + + if ( streak_name == "sentry" || streak_name == "remote_tank" || streak_name == "nuke" || streak_name == "all_perks_bonus" ) // theres an airdrop version + { + continue; + } + + if ( isSubstr( streak_name, "specialty_" ) && isSubstr( streak_name, "_pro" ) ) + { + continue; + } + + killstreaks[ killstreaks.size ] = streak_name; + } + + return killstreaks; +} + +/* + Returns the weapon buffs for a given weapon type +*/ +getWeaponProfs( weapClass ) +{ + answer = []; + + if ( weapClass == "weapon_assault" ) + { + answer[ answer.size ] = "specialty_bling"; + answer[ answer.size ] = "specialty_bulletpenetration"; + answer[ answer.size ] = "specialty_marksman"; + answer[ answer.size ] = "specialty_sharp_focus"; + answer[ answer.size ] = "specialty_holdbreathwhileads"; + answer[ answer.size ] = "specialty_reducedsway"; + } + else if ( weapClass == "weapon_smg" ) + { + answer[ answer.size ] = "specialty_bling"; + answer[ answer.size ] = "specialty_marksman"; + answer[ answer.size ] = "specialty_sharp_focus"; + answer[ answer.size ] = "specialty_reducedsway"; + answer[ answer.size ] = "specialty_longerrange"; + answer[ answer.size ] = "specialty_fastermelee"; + } + else if ( weapClass == "weapon_lmg" ) + { + answer[ answer.size ] = "specialty_bling"; + answer[ answer.size ] = "specialty_bulletpenetration"; + answer[ answer.size ] = "specialty_marksman"; + answer[ answer.size ] = "specialty_sharp_focus"; + answer[ answer.size ] = "specialty_reducedsway"; + answer[ answer.size ] = "specialty_lightweight"; + } + else if ( weapClass == "weapon_sniper" ) + { + answer[ answer.size ] = "specialty_bling"; + answer[ answer.size ] = "specialty_bulletpenetration"; + answer[ answer.size ] = "specialty_marksman"; + answer[ answer.size ] = "specialty_sharp_focus"; + answer[ answer.size ] = "specialty_reducedsway"; + answer[ answer.size ] = "specialty_lightweight"; + } + else if ( weapClass == "weapon_shotgun" ) + { + answer[ answer.size ] = "specialty_bling"; + answer[ answer.size ] = "specialty_marksman"; + answer[ answer.size ] = "specialty_sharp_focus"; + answer[ answer.size ] = "specialty_longerrange"; + answer[ answer.size ] = "specialty_fastermelee"; + answer[ answer.size ] = "specialty_moredamage"; + } + else if ( weapClass == "weapon_riot" ) + { + answer[ answer.size ] = "specialty_fastermelee"; + answer[ answer.size ] = "specialty_lightweight"; + } + + return answer; +} + +/* + Returns the level for unlocking the item +*/ +getUnlockLevel( forWhat ) +{ + return int( tableLookup( "mp/unlocktable.csv", 0, forWhat, 2 ) ); +} + +/* + bots chooses a random perk +*/ +chooseRandomPerk( perkkind ) +{ + perks = getPerks( perkkind ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + + while ( true ) + { + perk = random( perks ); + + if ( !allowOp ) + { + if ( perkkind == "perk4" ) + { + return "specialty_null"; + } + + if ( perk == "specialty_coldblooded" || perk == "specialty_blindeye" || perk == "specialty_quieter" ) + { + continue; + } + + if ( perk == "streaktype_specialist" || perk == "streaktype_support" ) + { + continue; + } + } + + if ( reasonable ) + { + } + + if ( perk == "specialty_null" ) + { + continue; + } + + if ( !self isItemUnlocked( perk ) ) + { + continue; + } + + if ( rank < getUnlockLevel( perk ) ) + { + continue; + } + + if ( RandomFloatRange( 0, 1 ) < ( ( rank / level.maxrank ) + 0.1 ) ) + { + self.pers[ "bots" ][ "unlocks" ][ "upgraded_" + perk ] = true; + } + + return perk; + } +} + +/* + choose a random camo +*/ +chooseRandomCamo() +{ + camos = getCamos(); + + while ( true ) + { + camo = random( camos ); + + return camo; + } +} + +/* + choose a random camo +*/ +chooseRandomReticle() +{ + reticles = getReticles(); + + while ( true ) + { + reticle = random( reticles ); + + return reticle; + } +} + +/* + choose a random primary +*/ +chooseRandomPrimary() +{ + primaries = getPrimaries(); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + + while ( true ) + { + primary = random( primaries ); + + if ( !allowOp ) + { + if ( primary == "riotshield" ) + { + continue; + } + } + + if ( reasonable ) + { + if ( primary == "riotshield" ) + { + continue; + } + } + + if ( !self isItemUnlocked( primary ) ) + { + continue; + } + + if ( rank < getUnlockLevel( primary ) ) + { + continue; + } + + return primary; + } +} + +/* + choose a random secondary +*/ +chooseRandomSecondary() +{ + secondaries = getSecondaries(); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + + while ( true ) + { + secondary = random( secondaries ); + + if ( !allowOp ) + { + if ( secondary == "iw5_smaw" || secondary == "rpg" || secondary == "m320" || secondary == "xm25" ) + { + continue; + } + } + + if ( reasonable ) + { + } + + if ( !self isItemUnlocked( secondary ) ) + { + continue; + } + + if ( rank < getUnlockLevel( secondary ) ) + { + continue; + } + + return secondary; + } +} + +/* + Returns a random buff for a weapon +*/ +chooseRandomBuff( weap ) +{ + buffs = getWeaponProfs( getWeaponClass( weap ) ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + + buffs[ buffs.size ] = "specialty_null"; + + if ( RandomFloatRange( 0, 1 ) >= ( ( rank / level.maxrank ) + 0.1 ) ) + { + return "specialty_null"; + } + + while ( true ) + { + buff = random( buffs ); + + return buff; + } +} + +/* + chooses random attachements for a gun +*/ +chooseRandomAttachmentComboForGun( gun ) +{ + atts = getAttachmentsForGun( gun ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + + if ( RandomFloatRange( 0, 1 ) >= ( ( rank / level.maxrank ) + 0.1 ) ) + { + retAtts = []; + retAtts[ 0 ] = "none"; + retAtts[ 1 ] = "none"; + + return retAtts; + } + + while ( true ) + { + att1 = random( atts ); + att2 = random( atts ); + + if ( !isValidAttachmentCombo( att1, att2 ) ) + { + continue; + } + + if ( !allowOp ) + { + if ( att1 == "gl" || att2 == "gl" || att1 == "gp25" || att2 == "gp25" || att1 == "m320" || att2 == "m320" ) + { + continue; + } + } + + if ( reasonable ) + { + } + + retAtts = []; + retAtts[ 0 ] = att1; + retAtts[ 1 ] = att2; + + return retAtts; + } +} + +/* + choose a random tacticle grenade +*/ +chooseRandomTactical() +{ + perks = getPerks( "equipment" ); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + + while ( true ) + { + perk = random( perks ); + + if ( !allowOp ) + { + } + + if ( reasonable ) + { + } + + if ( perk == "specialty_null" ) + { + continue; + } + + if ( !maps\mp\gametypes\_class::isValidOffhand( perk ) ) + { + continue; + } + + if ( !self isItemUnlocked( perk ) ) + { + continue; + } + + if ( rank < getUnlockLevel( perk ) ) + { + continue; + } + + return perk; + } +} + +/* + Choose a random grenade +*/ +chooseRandomGrenade() +{ + perks = getPerks( "equipment" ); + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + + while ( true ) + { + perk = random( perks ); + + if ( !allowOp ) + { + } + + if ( reasonable ) + { + } + + if ( perk == "specialty_null" ) + { + continue; + } + + if ( !maps\mp\gametypes\_class::isValidEquipment( perk ) ) + { + continue; + } + + if ( perk == "specialty_portable_radar" ) + { + continue; + } + + if ( !self isItemUnlocked( perk ) ) + { + continue; + } + + if ( rank < getUnlockLevel( perk ) ) + { + continue; + } + + return perk; + } +} + +/* + Choose a random killstreak set +*/ +chooseRandomKillstreaks( type, perks ) +{ + answers = []; + allStreaks = getKillstreaks(); + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ) + 1; + allowOp = ( getDvarInt( "bots_loadout_allow_op" ) >= 1 ); + reasonable = getDvarInt( "bots_loadout_reasonable" ); + chooseStreaks = []; + + availUnlocks = 0; + + if ( rank >= 7 ) + { + availUnlocks++; + } + + if ( rank >= 10 ) + { + availUnlocks++; + } + + if ( rank >= 13 ) + { + availUnlocks++; + } + + for ( ;; ) + { + streak = random( allStreaks ); + + if ( isDefined( chooseStreaks[ streak ] ) ) + { + continue; + } + + if ( type == "streaktype_specialist" ) + { + if ( !isSubStr( streak, "specialty_" ) ) + { + continue; + } + + perk = strTok( streak, "_ks" )[ 0 ]; + + if ( !self isItemUnlocked( perk ) ) + { + continue; + } + + if ( isDefined( perks[ perk ] ) ) + { + continue; + } + } + else + { + if ( availUnlocks <= 0 ) + { + for ( i = ( 3 - answers.size - 1 ); i >= 0; i-- ) + { + if ( type == "streaktype_support" ) + { + if ( i == 2 ) + { + answers[ answers.size ] = "uav_support"; + } + else if ( i == 1 ) + { + answers[ answers.size ] = "sam_turret"; + } + else + { + answers[ answers.size ] = "triple_uav"; + } + } + else + { + if ( i == 2 ) + { + answers[ answers.size ] = "uav"; + } + else if ( i == 1 ) + { + answers[ answers.size ] = "predator_missile"; + } + else + { + answers[ answers.size ] = "helicopter"; + } + } + } + + break; + } + + if ( isSubStr( streak, "specialty_" ) ) + { + continue; + } + + if ( isColidingKillstreak( answers, streak ) ) + { + continue; + } + + if ( type == "streaktype_support" ) + { + if ( !maps\mp\killstreaks\_killstreaks::isSupportKillstreak( streak ) ) + { + continue; + } + } + else + { + if ( !maps\mp\killstreaks\_killstreaks::isAssaultKillstreak( streak ) ) + { + continue; + } + } + } + + answers[ answers.size ] = streak; + chooseStreaks[ streak ] = true; + availUnlocks--; + + if ( answers.size > 2 ) + { + break; + } + } + + return answers; +} + +/* + returns if killstreak is going to have the same kill cost +*/ +isColidingKillstreak( killstreaks, killstreak ) +{ + ksVal = getKillsNeededForStreak( killstreak ); + + for ( i = 0; i < killstreaks.size; i++ ) + { + ks = killstreaks[ i ]; + + if ( ks == "" ) + { + continue; + } + + if ( ks == "none" ) + { + continue; + } + + ksV = getKillsNeededForStreak( ks ); + + if ( ksV <= 0 ) + { + continue; + } + + if ( ksV != ksVal ) + { + continue; + } + + return true; + } + + return false; +} + +/* + sets up all classes for a bot +*/ +setClasses() +{ + n = 5; + + if ( !self is_bot() ) + { + n = 15; + } + + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ); + + if ( RandomFloatRange( 0, 1 ) < ( ( rank / level.maxrank ) + 0.1 ) ) + { + self.pers[ "bots" ][ "unlocks" ][ "ghillie" ] = true; + self.pers[ "bots" ][ "behavior" ][ "quickscope" ] = true; + } + + whereToSave = "customClasses"; + + if ( getDvarInt( "xblive_privatematch" ) ) + { + whereToSave = "privateMatchCustomClasses"; + } + + for ( i = 0; i < n; i++ ) + { + primary = chooseRandomPrimary(); + primaryBuff = chooseRandomBuff( primary ); + primaryAtts = chooseRandomAttachmentComboForGun( primary ); + primaryReticle = chooseRandomReticle(); + primaryCamo = chooseRandomCamo(); + + perk2 = chooseRandomPerk( "perk2" ); + + secondary = chooseRandomSecondary(); + + if ( perk2 == "specialty_twoprimaries" ) + { + secondary = chooseRandomPrimary(); + + while ( secondary == primary ) + { + secondary = chooseRandomPrimary(); + } + } + + secondaryBuff = chooseRandomBuff( secondary ); + secondaryAtts = chooseRandomAttachmentComboForGun( secondary ); + secondaryReticle = chooseRandomReticle(); + secondaryCamo = chooseRandomCamo(); + + if ( perk2 != "specialty_twoprimaries" ) + { + secondaryReticle = "none"; + secondaryCamo = "none"; + secondaryAtts[ 1 ] = "none"; + } + else if ( !isDefined( self.pers[ "bots" ][ "unlocks" ][ "upgraded_specialty_twoprimaries" ] ) ) + { + secondaryAtts[ 0 ] = "none"; + secondaryAtts[ 1 ] = "none"; + } + + perk1 = chooseRandomPerk( "perk1" ); + perk3 = chooseRandomPerk( "perk3" ); + deathstreak = chooseRandomPerk( "perk4" ); + equipment = chooseRandomGrenade(); + tactical = chooseRandomTactical(); + + perks = []; + perks[ perk1 ] = true; + perks[ perk2 ] = true; + perks[ perk3 ] = true; + + ksType = chooseRandomPerk( "perk5" ); + killstreaks = chooseRandomKillstreaks( ksType, perks ); + + self setPlayerData( whereToSave, i, "weaponSetups", 0, "weapon", primary ); + self setPlayerData( whereToSave, i, "weaponSetups", 0, "attachment", 0, primaryAtts[ 0 ] ); + self setPlayerData( whereToSave, i, "weaponSetups", 0, "attachment", 1, primaryAtts[ 1 ] ); + self setPlayerData( whereToSave, i, "weaponSetups", 0, "camo", primaryCamo ); + self setPlayerData( whereToSave, i, "weaponSetups", 0, "reticle", primaryReticle ); + self setPlayerData( whereToSave, i, "weaponSetups", 0, "buff", primaryBuff ); + + self setPlayerData( whereToSave, i, "weaponSetups", 1, "weapon", secondary ); + self setPlayerData( whereToSave, i, "weaponSetups", 1, "attachment", 0, secondaryAtts[ 0 ] ); + self setPlayerData( whereToSave, i, "weaponSetups", 1, "attachment", 1, secondaryAtts[ 1 ] ); + self setPlayerData( whereToSave, i, "weaponSetups", 1, "camo", secondaryCamo ); + self setPlayerData( whereToSave, i, "weaponSetups", 1, "reticle", secondaryReticle ); + self setPlayerData( whereToSave, i, "weaponSetups", 1, "buff", secondaryBuff ); + + self setPlayerData( whereToSave, i, "perks", 0, equipment ); + self setPlayerData( whereToSave, i, "perks", 1, perk1 ); + self setPlayerData( whereToSave, i, "perks", 2, perk2 ); + self setPlayerData( whereToSave, i, "perks", 3, perk3 ); + self setPlayerData( whereToSave, i, "deathstreak", deathstreak ); + self setPlayerData( whereToSave, i, "perks", 6, tactical ); + + self setPlayerData( whereToSave, i, "perks", 5, ksType ); + + playerData = undefined; + + switch ( ksType ) + { + case "streaktype_support": + playerData = "defenseStreaks"; + break; + + case "streaktype_specialist": + playerData = "specialistStreaks"; + break; + + default: + playerData = "assaultStreaks"; + break; + } + + self setPlayerData( whereToSave, i, playerData, 0, killstreaks[ 0 ] ); + self setPlayerData( whereToSave, i, playerData, 1, killstreaks[ 1 ] ); + self setPlayerData( whereToSave, i, playerData, 2, killstreaks[ 2 ] ); + } +} + +/* + The callback for when the bot gets killed. +*/ +onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) +{ + self.killerlocation = undefined; + self.lastkiller = undefined; + + if ( !IsDefined( self ) || !isDefined( self.team ) ) + { + return; + } + + if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) + { + return; + } + + if ( iDamage <= 0 ) + { + return; + } + + if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) + { + return; + } + + if ( eAttacker == self ) + { + return; + } + + if ( level.teambased && eAttacker.team == self.team ) + { + return; + } + + if ( !IsDefined( eInflictor ) || eInflictor.classname != "player" ) + { + return; + } + + if ( !isAlive( eAttacker ) ) + { + return; + } + + self.killerlocation = eAttacker.origin; + self.lastkiller = eAttacker; +} + +/* + The callback for when the bot gets damaged. +*/ +onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) +{ + if ( !IsDefined( self ) || !isDefined( self.team ) ) + { + return; + } + + if ( !isAlive( self ) ) + { + return; + } + + if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) + { + return; + } + + if ( iDamage <= 0 ) + { + return; + } + + if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) + { + return; + } + + if ( eAttacker == self ) + { + return; + } + + if ( level.teambased && eAttacker.team == self.team ) + { + return; + } + + if ( !IsDefined( eInflictor ) || eInflictor.classname != "player" ) + { + return; + } + + if ( !isAlive( eAttacker ) ) + { + return; + } + + if ( !isSubStr( sWeapon, "_silencer" ) ) + { + self bot_cry_for_help( eAttacker ); + } + + self SetAttacker( eAttacker ); +} + +/* + When the bot gets attacked, have the bot ask for help from teammates. +*/ +bot_cry_for_help( attacker ) +{ + if ( !level.teambased ) + { + return; + } + + theTime = GetTime(); + + if ( IsDefined( self.help_time ) && theTime - self.help_time < 1000 ) + { + return; + } + + self.help_time = theTime; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( !player is_bot() ) + { + continue; + } + + if ( !isDefined( player.team ) ) + { + continue; + } + + if ( !IsAlive( player ) ) + { + continue; + } + + if ( player == self ) + { + continue; + } + + if ( player.team != self.team ) + { + continue; + } + + dist = player.pers[ "bots" ][ "skill" ][ "help_dist" ]; + dist *= dist; + + if ( DistanceSquared( self.origin, player.origin ) > dist ) + { + continue; + } + + if ( RandomInt( 100 ) < 50 ) + { + self SetAttacker( attacker ); + + if ( RandomInt( 100 ) > 70 ) + { + break; + } + } + } +} + +/* + watches when the bot enters a killcam +*/ +onKillcam() +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "begin_killcam" ); + + self thread doKillcamStuff(); + } +} + +/* + bots use copy cat and skip killcams +*/ +doKillcamStuff() +{ + self endon( "disconnect" ); + self endon( "killcam_ended" ); + + self BotNotifyBotEvent( "killcam", "start" ); + + wait 0.5 + randomInt( 3 ); + + wait 0.1; + + self notify( "abort_killcam" ); + + self BotNotifyBotEvent( "killcam", "stop" ); +} + +/* + Selects a class for the bot. +*/ +classWatch() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + while ( !isdefined( self.pers[ "team" ] ) || !allowClassChoice() ) + { + wait .05; + } + + wait 0.5; + + if ( !isValidClass( self.class ) || !isDefined( self.bot_change_class ) ) + { + self notify( "menuresponse", game[ "menu_changeclass" ], self chooseRandomClass() ); + } + + self.bot_change_class = true; + + while ( isdefined( self.pers[ "team" ] ) && isValidClass( self.class ) && isDefined( self.bot_change_class ) ) + { + wait .05; + } + } +} + +/* + Any recipe classes +*/ +anyMatchRuleDefaultClass( team ) +{ + if ( !isUsingMatchRulesData() ) + { + return false; + } + + for ( i = 0; i < 5; i++ ) + { + if ( GetMatchRulesData( "defaultClasses", team, i, "class", "inUse" ) ) + { + return true; + } + } + + return false; +} + +/* + Chooses a random class +*/ +chooseRandomClass( ) +{ + if ( self.team != "axis" && self.team != "allies" ) + { + return ""; + } + + reasonable = getDvarInt( "bots_loadout_reasonable" ); + class = ""; + rank = self maps\mp\gametypes\_rank::getRankForXp( self getPlayerData( "experience" ) ) + 1; + + if ( rank < 4 || ( randomInt( 100 ) < 2 && !reasonable ) || ( isUsingMatchRulesData() && !level.matchrules_allowcustomclasses ) ) + { + while ( class == "" ) + { + switch ( randomInt( 5 ) ) + { + case 0: + if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 0, "class", "inUse" ) ) + { + class = self.team + "_recipe1"; + } + else if ( !anyMatchRuleDefaultClass( self.team ) ) + { + class = "class0"; + } + + break; + + case 1: + if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 1, "class", "inUse" ) ) + { + class = self.team + "_recipe2"; + } + else if ( !anyMatchRuleDefaultClass( self.team ) ) + { + class = "class1"; + } + + break; + + case 2: + if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 2, "class", "inUse" ) ) + { + class = self.team + "_recipe3"; + } + else if ( !anyMatchRuleDefaultClass( self.team ) ) + { + class = "class2"; + } + + break; + + case 3: + if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 3, "class", "inUse" ) ) + { + class = self.team + "_recipe4"; + } + else if ( rank >= 2 && !anyMatchRuleDefaultClass( self.team ) ) + { + class = "class3"; + } + + break; + + case 4: + if ( isUsingMatchRulesData() && GetMatchRulesData( "defaultClasses", self.team, 4, "class", "inUse" ) ) + { + class = self.team + "_recipe5"; + } + else if ( rank >= 3 && !anyMatchRuleDefaultClass( self.team ) ) + { + class = "class4"; + } + + break; + } + } + } + else + { + class = "custom" + ( randomInt( 5 ) + 1 ); + } + + return class; +} + +/* + Makes sure the bot is on a team. +*/ +teamWatch() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + while ( !isdefined( self.pers[ "team" ] ) || !allowTeamChoice() ) + { + wait .05; + } + + wait 0.1; + + if ( self.team != "axis" && self.team != "allies" ) + { + self notify( "menuresponse", game[ "menu_team" ], getDvar( "bots_team" ) ); + } + + while ( isdefined( self.pers[ "team" ] ) ) + { + wait .05; + } + } +} + +/* + Updates the bot's difficulty variables. +*/ +difficulty() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + if ( GetDvarInt( "bots_skill" ) != 9 ) + { + switch ( self.pers[ "bots" ][ "skill" ][ "base" ] ) + { + case 1: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.6; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 500; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 600; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 750; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.7; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 2500; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.75; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 0; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.9; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 1; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1.5; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 4; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 2; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 0; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 30; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 20; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 0; + break; + + case 2: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.55; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 800; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1250; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.65; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 3000; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.65; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 500; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.75; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.75; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 1; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 3; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1.5; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_ankle_le,j_ankle_ri,j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 15; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 45; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 15; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 10; + break; + + case 3: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.4; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 750; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 500; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 2000; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.6; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 4000; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 2250; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 750; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.65; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.65; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.75; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2.5; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 1; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 20; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 20; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 50; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 25; + break; + + case 4: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.3; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 600; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 400; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 2000; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 3000; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.55; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 5000; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 3350; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.35; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1000; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 2; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.75; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_spineupper,j_ankle_le,j_ankle_ri,j_head,j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 30; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 25; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 55; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 35; + break; + + case 5: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 500; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 300; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 3000; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 4000; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 7500; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 5000; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 1500; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.4; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.35; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.35; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1.5; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 40; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 35; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 60; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 50; + break; + + case 6: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.2; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 250; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 150; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 4000; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 5000; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.45; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 10000; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 7500; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.2; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 2000; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 1; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.25; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_spineupper,j_head,j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 50; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 45; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 65; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 10; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 75; + break; + + case 7: + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.1; + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 100; + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50; + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 2500; + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 4000; + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 7500; + self.pers[ "bots" ][ "skill" ][ "fov" ] = 0.4; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = 15000; + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = 10000; + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05; + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = 3000; + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = 0.1; + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = 0; + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = 0; + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = 0; + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = 0.05; + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head"; + self.pers[ "bots" ][ "skill" ][ "ads_fov_multi" ] = 0.5; + self.pers[ "bots" ][ "skill" ][ "ads_aimspeed_multi" ] = 0.5; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = 65; + self.pers[ "bots" ][ "behavior" ][ "nade" ] = 65; + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = 70; + self.pers[ "bots" ][ "behavior" ][ "camp" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "follow" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = 5; + self.pers[ "bots" ][ "behavior" ][ "switch" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "class" ] = 2; + self.pers[ "bots" ][ "behavior" ][ "jump" ] = 90; + break; + } + } + + wait 5; + } +} + +/* + Sets the bot difficulty. +*/ +set_diff() +{ + rankVar = GetDvarInt( "bots_skill" ); + + switch ( rankVar ) + { + case 0: + self.pers[ "bots" ][ "skill" ][ "base" ] = Round( random_normal_distribution( 3.5, 1.75, 1, 7 ) ); + break; + + case 8: + break; + + case 9: + self.pers[ "bots" ][ "skill" ][ "base" ] = randomIntRange( 1, 7 ); + self.pers[ "bots" ][ "skill" ][ "aim_time" ] = 0.05 * randomIntRange( 1, 20 ); + self.pers[ "bots" ][ "skill" ][ "init_react_time" ] = 50 * randomInt( 100 ); + self.pers[ "bots" ][ "skill" ][ "reaction_time" ] = 50 * randomInt( 100 ); + self.pers[ "bots" ][ "skill" ][ "remember_time" ] = 50 * randomInt( 100 ); + self.pers[ "bots" ][ "skill" ][ "no_trace_ads_time" ] = 50 * randomInt( 100 ); + self.pers[ "bots" ][ "skill" ][ "no_trace_look_time" ] = 50 * randomInt( 100 ); + self.pers[ "bots" ][ "skill" ][ "fov" ] = randomFloatRange( -1, 1 ); + + randomNum = randomIntRange( 500, 25000 ); + self.pers[ "bots" ][ "skill" ][ "dist_start" ] = randomNum; + self.pers[ "bots" ][ "skill" ][ "dist_max" ] = randomNum * 2; + + self.pers[ "bots" ][ "skill" ][ "spawn_time" ] = 0.05 * randomInt( 20 ); + self.pers[ "bots" ][ "skill" ][ "help_dist" ] = randomIntRange( 500, 25000 ); + self.pers[ "bots" ][ "skill" ][ "semi_time" ] = randomFloatRange( 0.05, 1 ); + self.pers[ "bots" ][ "skill" ][ "shoot_after_time" ] = randomFloatRange( 0.05, 1 ); + self.pers[ "bots" ][ "skill" ][ "aim_offset_time" ] = randomFloatRange( 0.05, 1 ); + self.pers[ "bots" ][ "skill" ][ "aim_offset_amount" ] = randomFloatRange( 0.05, 1 ); + self.pers[ "bots" ][ "skill" ][ "bone_update_interval" ] = randomFloatRange( 0.05, 1 ); + self.pers[ "bots" ][ "skill" ][ "bones" ] = "j_head,j_spineupper,j_ankle_le,j_ankle_ri"; + + self.pers[ "bots" ][ "behavior" ][ "strafe" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "nade" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "sprint" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "camp" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "follow" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "crouch" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "switch" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "class" ] = randomInt( 100 ); + self.pers[ "bots" ][ "behavior" ][ "jump" ] = randomInt( 100 ); + break; + + default: + self.pers[ "bots" ][ "skill" ][ "base" ] = rankVar; + break; + } +} + +/* + Allows the bot to spawn when force respawn is disabled + Watches when the bot dies +*/ +onDeath() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "death" ); + + self.wantsafespawn = true; + self ClearScriptGoal(); + } +} + +/* + Watches when the bot is given a loadout +*/ +onGiveLoadout() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "giveLoadout", team, class, allowCopycat, setPrimarySpawnWeapon ); + + if ( !allowClassChoice() ) + { + continue; + } + + if ( !isDefined( team ) ) + { + team = self.team; + } + + if ( !isDefined( class ) ) + { + class = self.class; + } + + if ( !isDefined( allowCopycat ) ) + { + allowCopycat = false; + } + + if ( !isDefined( setPrimarySpawnWeapon ) ) + { + setPrimarySpawnWeapon = true; + } + + self botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ); + } +} + +/* + When the bot spawns. +*/ +onSpawned() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "spawned_player" ); + + if ( randomInt( 100 ) <= self.pers[ "bots" ][ "behavior" ][ "class" ] ) + { + self.bot_change_class = undefined; + } + + self.bot_lock_goal = false; + self.help_time = undefined; + self.bot_was_follow_script_update = undefined; + self.bot_stuck_on_carepackage = undefined; + + if ( getDvarInt( "bots_play_obj" ) ) + { + self thread bot_dom_cap_think(); + } + } +} + +/* + When the bot spawned, after the difficulty wait. Start the logic for the bot. +*/ +onBotSpawned() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + + for ( ;; ) + { + self waittill( "bot_spawned" ); + + self thread start_bot_threads(); + } +} + +/* + Starts all the bot thinking +*/ +start_bot_threads() +{ + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "death" ); + + gameFlagWait( "prematch_done" ); + + // inventory usage + if ( getDvarInt( "bots_play_killstreak" ) ) + { + self thread bot_killstreak_think(); + self thread bot_box_think(); + self thread bot_watch_use_remote_turret(); + } + + self thread bot_weapon_think(); + self thread doReloadCancel(); + + // script targeting + if ( getDvarInt( "bots_play_target_other" ) ) + { + self thread bot_target_vehicle(); + self thread bot_equipment_kill_think(); + self thread bot_turret_think(); + } + + // airdrop + if ( getDvarInt( "bots_play_take_carepackages" ) ) + { + self thread bot_watch_stuck_on_crate(); + self thread bot_crate_think(); + } + + // awareness + self thread bot_revenge_think(); + self thread bot_uav_think(); + self thread bot_listen_to_steps(); + self thread follow_target(); + + // camp and follow + if ( getDvarInt( "bots_play_camp" ) ) + { + self thread bot_think_follow(); + self thread bot_think_camp(); + } + + // nades + if ( getDvarInt( "bots_play_nade" ) ) + { + self thread bot_jav_loc_think(); + self thread bot_use_tube_think(); + self thread bot_use_grenade_think(); + self thread bot_use_equipment_think(); + self thread bot_watch_riot_weapons(); + self thread bot_watch_think_mw2(); // bots play mw2 + } + + // obj + if ( getDvarInt( "bots_play_obj" ) ) + { + self thread bot_dom_def_think(); + self thread bot_dom_spawn_kill_think(); + + self thread bot_hq(); + + self thread bot_cap(); + + self thread bot_sab(); + + self thread bot_sd_defenders(); + self thread bot_sd_attackers(); + + self thread bot_dem_attackers(); + self thread bot_dem_defenders(); + self thread bot_dem_overtime(); + + self thread bot_gtnw(); + self thread bot_oneflag(); + self thread bot_arena(); + self thread bot_vip(); + + self thread bot_conf(); + self thread bot_grnd(); + self thread bot_tdef(); + + self thread bot_infect(); + } +} + +/* + Increments the number of bots approching the obj, decrements when needed + Used for preventing too many bots going to one obj, or unreachable objs +*/ +bot_inc_bots( obj, unreach ) +{ + level endon( "game_ended" ); + self endon( "bot_inc_bots" ); + + if ( !isDefined( obj ) ) + { + return; + } + + if ( !isDefined( obj.bots ) ) + { + obj.bots = 0; + } + + obj.bots++; + + ret = self waittill_any_return( "death", "disconnect", "bad_path", "goal", "new_goal" ); + + if ( isDefined( obj ) && ( ret != "bad_path" || !isDefined( unreach ) ) ) + { + obj.bots--; + } +} + +/* + Watches when the bot is touching the obj and calls 'goal' +*/ +bots_watch_touch_obj( obj ) +{ + self endon ( "death" ); + self endon ( "disconnect" ); + self endon ( "bad_path" ); + self endon ( "goal" ); + self endon ( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( obj ) ) + { + self notify( "bad_path" ); + return; + } + + if ( self IsTouching( obj ) ) + { + self notify( "goal" ); + return; + } + } +} + +/* + Watches while the obj is being carried, calls 'goal' when complete +*/ +bot_escort_obj( obj, carrier ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( obj ) ) + { + break; + } + + if ( !isDefined( obj.carrier ) || carrier == obj.carrier ) + { + break; + } + } + + self notify( "goal" ); +} + +/* + Watches while the obj is not being carried, calls 'goal' when complete +*/ +bot_get_obj( obj ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( obj ) ) + { + break; + } + + if ( isDefined( obj.carrier ) ) + { + break; + } + } + + self notify( "goal" ); +} + +/* + bots will defend their site from a planter/defuser +*/ +bot_defend_site( site ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !site isInUse() ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots will go plant the bomb +*/ +bot_go_plant( plant ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 1; + + if ( level.bombplanted ) + { + break; + } + + if ( self isTouching( plant.trigger ) ) + { + break; + } + } + + if ( level.bombplanted ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Bots will go defuse the bomb +*/ +bot_go_defuse( plant ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 1; + + if ( !level.bombplanted ) + { + break; + } + + if ( self isTouching( plant.trigger ) ) + { + break; + } + } + + if ( !level.bombplanted ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Fires the bots weapon until told to stop +*/ +fire_current_weapon() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "stop_firing_weapon" ); + + for ( ;; ) + { + self thread BotPressAttack( 0.05 ); + wait 0.1; + } +} + +/* + Changes to the weap +*/ +changeToWeapon( weap ) +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + if ( !self HasWeapon( weap ) ) + { + return false; + } + + self switchToWeapon( weap ); + + if ( self GetCurrentWeapon() == weap ) + { + return true; + } + + self waittill_any_timeout( 5, "weapon_change" ); + + return ( self GetCurrentWeapon() == weap ); +} + +/* + Bots throw the grenade +*/ +botThrowGrenade( nade, time ) +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + if ( !self GetAmmoCount( nade ) ) + { + return false; + } + + if ( isSecondaryGrenade( nade ) ) + { + self thread BotPressSmoke( time ); + } + else + { + self thread BotPressFrag( time ); + } + + ret = self waittill_any_timeout( 5, "grenade_fire" ); + + return ( ret == "grenade_fire" ); +} + +/* + Gets the object thats the closest in the array +*/ +bot_array_nearest_curorigin( array ) +{ + result = undefined; + + for ( i = 0; i < array.size; i++ ) + { + if ( !isDefined( result ) || DistanceSquared( self.origin, array[ i ].curorigin ) < DistanceSquared( self.origin, result.curorigin ) ) + } + + result = array[ i ]; + + return result; +} + +/* + Returns an weapon thats a rocket with ammo +*/ +getRocketAmmo() +{ + answer = self getLockonAmmo(); + + if ( isDefined( answer ) ) + { + return answer; + } + + if ( self getAmmoCount( "rpg_mp" ) ) + { + answer = "rpg_mp"; + } + + return answer; +} + +/* + Returns a weapon thats lockon with ammo +*/ +getLockonAmmo() +{ + answer = undefined; + + if ( self getAmmoCount( "iw5_smaw_mp" ) ) + { + answer = "iw5_smaw_mp"; + } + + if ( self getAmmoCount( "stinger_mp" ) ) + { + answer = "stinger_mp"; + } + + if ( self getAmmoCount( "javelin_mp" ) ) + { + answer = "javelin_mp"; + } + + return answer; +} + +/* + Clears goal when events death +*/ +stop_go_target_on_death( tar ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "new_goal" ); + self endon( "bad_path" ); + self endon( "goal" ); + + tar waittill_either( "death", "disconnect" ); + + self ClearScriptGoal(); +} + +/* + Goes to the target's location if it had one +*/ +follow_target() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + wait 1; + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + continue; + } + + if ( !self HasThreat() ) + { + continue; + } + + threat = self GetThreat(); + + if ( !isPlayer( threat ) ) + { + continue; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "follow" ] * 5 ) + { + continue; + } + + self BotNotifyBotEvent( "follow_threat", "start", threat ); + + self SetScriptGoal( threat.origin, 64 ); + self thread stop_go_target_on_death( threat ); + + if ( self waittill_any_return( "new_goal", "goal", "bad_path" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "follow_threat", "stop", threat ); + } +} + +/* + Used so that variables are free'd (in gsc, loops retain their variables they create, eats up child0 vars) +*/ +bot_think_camp_loop() +{ + campSpot = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "camp" ), 1024 ) ) ); + + if ( !isDefined( campSpot ) ) + { + return; + } + + self SetScriptGoal( campSpot.origin, 16 ); + + time = randomIntRange( 10, 20 ); + + self BotNotifyBotEvent( "camp", "go", campSpot, time ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" ) + { + return; + } + + self BotNotifyBotEvent( "camp", "start", campSpot, time ); + + self thread killCampAfterTime( time ); + self CampAtSpot( campSpot.origin, campSpot.origin + AnglesToForward( campSpot.angles ) * 2048 ); + + self BotNotifyBotEvent( "camp", "stop", campSpot, time ); +} + +/* + Bot logic for bot determining to camp. +*/ +bot_think_camp() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + wait randomintrange( 4, 7 ); + + if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) + { + continue; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "camp" ] ) + { + continue; + } + + self bot_think_camp_loop(); + } +} + +/* + Kills the camping thread when time +*/ +killCampAfterTime( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_camp_bot" ); + + wait time + 0.05; + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify( "kill_camp_bot" ); +} + +/* + Kills the camping thread when ent gone +*/ +killCampAfterEntGone( ent ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_camp_bot" ); + + for ( ;; ) + { + wait 0.05; + + if ( !isDefined( ent ) ) + { + break; + } + } + + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify( "kill_camp_bot" ); +} + +/* + Camps at the spot +*/ +CampAtSpot( origin, anglePos ) +{ + self endon( "kill_camp_bot" ); + + self SetScriptGoal( origin, 64 ); + + if ( isDefined( anglePos ) ) + { + self SetScriptAimPos( anglePos ); + } + + self waittill( "new_goal" ); + self ClearScriptAimPos(); + + self notify( "kill_camp_bot" ); +} + +/* + Waits for the bot to stop moving +*/ +bot_wait_stop_move() +{ + while ( !self isOnGround() || lengthSquared( self getVelocity() ) > 1 ) + { + wait 0.25; + } +} + +/* + Loop +*/ +bot_think_follow_loop() +{ + follows = []; + distSq = self.pers[ "bots" ][ "skill" ][ "help_dist" ] * self.pers[ "bots" ][ "skill" ][ "help_dist" ]; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( player.team != self.team ) + { + continue; + } + + if ( DistanceSquared( player.origin, self.origin ) > distSq ) + { + continue; + } + + follows[ follows.size ] = player; + } + + toFollow = random( follows ); + follows = undefined; + + if ( !isDefined( toFollow ) ) + { + return; + } + + time = randomIntRange( 10, 20 ); + + self BotNotifyBotEvent( "follow", "start", toFollow, time ); + + self thread killFollowAfterTime( time ); + self followPlayer( toFollow ); + + self BotNotifyBotEvent( "follow", "stop", toFollow, time ); +} + +/* + Bot logic for bot determining to follow another player. +*/ +bot_think_follow() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + wait randomIntRange( 3, 5 ); + + if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) + { + continue; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "follow" ] ) + { + continue; + } + + if ( !level.teambased ) + { + continue; + } + + self bot_think_follow_loop(); + } +} + +/* + Kills follow when new goal +*/ +watchForFollowNewGoal() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_follow_bot" ); + + for ( ;; ) + { + self waittill( "new_goal" ); + + if ( !isDefined( self.bot_was_follow_script_update ) ) + { + break; + } + } + + self ClearScriptAimPos(); + self notify( "kill_follow_bot" ); +} + +/* + Kills follow when time +*/ +killFollowAfterTime( time ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_follow_bot" ); + + wait time; + + self ClearScriptGoal(); + self ClearScriptAimPos(); + self notify( "kill_follow_bot" ); +} + +/* + Determine bot to follow a player +*/ +followPlayer( who ) +{ + self endon( "kill_follow_bot" ); + + self thread watchForFollowNewGoal(); + + for ( ;; ) + { + wait 0.05; + + if ( !isDefined( who ) || !isReallyAlive( who ) ) + { + break; + } + + self SetScriptAimPos( who.origin + ( 0, 0, 42 ) ); + myGoal = self GetScriptGoal(); + + if ( isDefined( myGoal ) && DistanceSquared( myGoal, who.origin ) < 64 * 64 ) + { + continue; + } + + self.bot_was_follow_script_update = true; + self SetScriptGoal( who.origin, 32 ); + waittillframeend; + self.bot_was_follow_script_update = undefined; + + self waittill_either( "goal", "bad_path" ); + } + + self ClearScriptGoal(); + self ClearScriptAimPos(); + + self notify( "kill_follow_bot" ); +} + +/* + Loop +*/ +bot_use_tube_think_loop( data ) +{ + if ( data.dofastcontinue ) + { + data.dofastcontinue = false; + } + else + { + wait randomintRange( 3, 7 ); + + chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; + + if ( chance > 20 ) + { + chance = 20; + } + + if ( randomInt( 100 ) > chance ) + { + return; + } + } + + tube = self getValidTube(); + + if ( !isDefined( tube ) ) + { + return; + } + + if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) + { + return; + } + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self IsBotFragging() || self IsBotSmoking() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + return; + } + + loc = undefined; + + if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "tube" ) ) ) + { + tubeWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "tube" ), 1024 ) ) ); + + myEye = self GetEye(); + + if ( !isDefined( tubeWp ) || self HasScriptGoal() || self.bot_lock_goal ) + { + traceForward = BulletTrace( myEye, myEye + AnglesToForward( self GetPlayerAngles() ) * 900 * 5, false, self ); + + loc = traceForward[ "position" ]; + dist = DistanceSquared( self.origin, loc ); + + if ( dist < level.bots_mingrenadedistance || dist > level.bots_maxgrenadedistance * 5 ) + { + return; + } + + if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + + if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + + loc += ( 0, 0, dist / 16000 ); + } + else + { + self BotNotifyBotEvent( "tube", "go", tubeWp, tube ); + + self SetScriptGoal( tubeWp.origin, 16 ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" ) + { + return; + } + + data.dofastcontinue = true; + return; + } + } + else + { + tubeWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "tube" ) ) ); + loc = tubeWp.origin + AnglesToForward( tubeWp.angles ) * 2048; + } + + if ( !isDefined( loc ) ) + { + return; + } + + self BotNotifyBotEvent( "tube", "start", loc, tube ); + + self SetScriptAimPos( loc ); + self BotStopMoving( true ); + wait 1; + + if ( self changeToWeapon( tube ) ) + { + self thread fire_current_weapon(); + self waittill_any_timeout( 5, "missile_fire", "weapon_change" ); + self notify( "stop_firing_weapon" ); + } + + self ClearScriptAimPos(); + self BotStopMoving( false ); +} + +/* + Bots thinking of using a noobtube +*/ +bot_use_tube_think() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.dofastcontinue = false; + + for ( ;; ) + { + self bot_use_tube_think_loop( data ); + } +} + +/* + Loop +*/ +bot_use_equipment_think_loop( data ) +{ + if ( data.dofastcontinue ) + { + data.dofastcontinue = false; + } + else + { + wait randomintRange( 2, 4 ); + + chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; + + if ( chance > 20 ) + { + chance = 20; + } + + if ( randomInt( 100 ) > chance ) + { + return; + } + } + + nade = undefined; + + if ( self GetAmmoCount( "claymore_mp" ) ) + { + nade = "claymore_mp"; + } + + if ( self GetAmmoCount( "flare_mp" ) ) + { + nade = "flare_mp"; + } + + if ( self GetAmmoCount( "c4_mp" ) ) + { + nade = "c4_mp"; + } + + if ( self GetAmmoCount( "bouncingbetty_mp" ) ) + { + nade = "bouncingbetty_mp"; + } + + if ( self GetAmmoCount( "portable_radar_mp" ) ) + { + nade = "portable_radar_mp"; + } + + if ( self GetAmmoCount( "scrambler_mp" ) ) + { + nade = "scrambler_mp"; + } + + if ( self GetAmmoCount( "trophy_mp" ) ) + { + nade = "trophy_mp"; + } + + if ( !isDefined( nade ) ) + { + return; + } + + if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) + { + return; + } + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self IsBotFragging() || self IsBotSmoking() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) + { + return; + } + + loc = undefined; + + if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "claymore" ) ) ) + { + clayWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "claymore" ), 1024 ) ) ); + + if ( !isDefined( clayWp ) || self HasScriptGoal() || self.bot_lock_goal ) + { + myEye = self GetEye(); + loc = myEye + AnglesToForward( self GetPlayerAngles() ) * 256; + + if ( !bulletTracePassed( myEye, loc, false, self ) ) + { + return; + } + } + else + { + self BotNotifyBotEvent( "equ", "go", clayWp, nade ); + + self SetScriptGoal( clayWp.origin, 16 ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" ) + { + return; + } + + data.dofastcontinue = true; + return; + } + } + else + { + clayWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "claymore" ) ) ); + loc = clayWp.origin + AnglesToForward( clayWp.angles ) * 2048; + } + + if ( !isDefined( loc ) ) + { + return; + } + + self BotNotifyBotEvent( "equ", "start", loc, nade ); + + self SetScriptAimPos( loc ); + self BotStopMoving( true ); + wait 1; + + self botThrowGrenade( nade, 0.05 ); + + self ClearScriptAimPos(); + self BotStopMoving( false ); +} + +/* + Bots thinking of using claymores and TIs +*/ +bot_use_equipment_think() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.dofastcontinue = false; + + for ( ;; ) + { + self bot_use_equipment_think_loop( data ); + } +} + +/* + Loop +*/ +bot_use_grenade_think_loop( data ) +{ + if ( data.dofastcontinue ) + { + data.dofastcontinue = false; + } + else + { + wait randomintRange( 4, 7 ); + + chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; + + if ( chance > 20 ) + { + chance = 20; + } + + if ( randomInt( 100 ) > chance ) + { + return; + } + } + + nade = self getValidGrenade(); + + if ( !isDefined( nade ) ) + { + return; + } + + if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) + { + return; + } + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self IsBotFragging() || self IsBotSmoking() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self inLastStand() && !self _hasPerk( "specialty_laststandoffhand" ) && !self inFinalStand() ) + { + return; + } + + loc = undefined; + + if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "grenade" ) ) ) + { + nadeWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "grenade" ), 1024 ) ) ); + + myEye = self GetEye(); + + if ( !isDefined( nadeWp ) || self HasScriptGoal() || self.bot_lock_goal ) + { + traceForward = BulletTrace( myEye, myEye + AnglesToForward( self GetPlayerAngles() ) * 900, false, self ); + + loc = traceForward[ "position" ]; + dist = DistanceSquared( self.origin, loc ); + + if ( dist < level.bots_mingrenadedistance || dist > level.bots_maxgrenadedistance ) + { + return; + } + + if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + + if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + + loc += ( 0, 0, dist / 3000 ); + } + else + { + self BotNotifyBotEvent( "nade", "go", nadeWp, nade ); + + self SetScriptGoal( nadeWp.origin, 16 ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" ) + { + return; + } + + data.dofastcontinue = true; + return; + } + } + else + { + nadeWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "grenade" ) ) ); + loc = nadeWp.origin + AnglesToForward( nadeWp.angles ) * 2048; + } + + if ( !isDefined( loc ) ) + { + return; + } + + self BotNotifyBotEvent( "nade", "start", loc, nade ); + + self SetScriptAimPos( loc ); + self BotStopMoving( true ); + wait 1; + + time = 0.5; + + if ( nade == "frag_grenade_mp" ) + { + time = 2; + } + + self botThrowGrenade( nade, time ); + + self ClearScriptAimPos(); + self BotStopMoving( false ); +} + +/* + Bots thinking of using grenades +*/ +bot_use_grenade_think() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.dofastcontinue = false; + + for ( ;; ) + { + self bot_use_grenade_think_loop( data ); + } +} + +/* + Bots play mw2 +*/ +bot_watch_think_mw2_loop() +{ + tube = self getValidTube(); + + if ( !isDefined( tube ) ) + { + if ( self GetAmmoCount( "iw5_smaw_mp" ) ) + { + tube = "iw5_smaw_mp"; + } + else if ( self GetAmmoCount( "rpg_mp" ) ) + { + tube = "rpg_mp"; + } + else if ( self GetAmmoCount( "xm25_mp" ) ) + { + tube = "xm25_mp"; + } + else + { + return; + } + } + + if ( self GetCurrentWeapon() == tube ) + { + return; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "nade" ] ) + { + return; + } + + self thread ChangeToWeapon( tube ); +} + +/* + Bots play mw2 +*/ +bot_watch_think_mw2() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + for ( ;; ) + { + wait randomIntRange( 1, 4 ); + + if ( self BotIsFrozen() ) + { + continue; + } + + if ( self isDefusing() || self isPlanting() ) + { + continue; + } + + if ( self IsUsingRemote() ) + { + continue; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + continue; + } + + if ( self HasThreat() ) + { + continue; + } + + self bot_watch_think_mw2_loop(); + } +} + +/* + Loop +*/ +bot_watch_riot_weapons_loop() +{ + threat = self GetThreat(); + dist = DistanceSquared( threat.origin, self.origin ); + curWeap = self GetCurrentWeapon(); + + if ( randomInt( 2 ) ) + { + nade = self getValidGrenade(); + + if ( !isDefined( nade ) ) + { + return; + } + + if ( dist <= level.bots_mingrenadedistance || dist >= level.bots_maxgrenadedistance ) + { + return; + } + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "nade" ] ) + { + return; + } + + self botThrowGrenade( nade ); + } + else + { + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "switch" ] * 10 ) + { + return; + } + + weaponslist = self getweaponslistall(); + weap = ""; + + while ( weaponslist.size ) + { + weapon = weaponslist[ randomInt( weaponslist.size ) ]; + weaponslist = array_remove( weaponslist, weapon ); + + if ( !self getAmmoCount( weapon ) ) + { + continue; + } + + if ( !isWeaponPrimary( weapon ) ) + { + continue; + } + + if ( curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp" ) + { + continue; + } + + weap = weapon; + break; + } + + if ( weap == "" ) + { + return; + } + + self thread ChangeToWeapon( weap ); + } +} + +/* + Bots will use gremades/wweapons while having a target while using a shield +*/ +bot_watch_riot_weapons() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + for ( ;; ) + { + wait randomIntRange( 2, 4 ); + + if ( self BotIsFrozen() ) + { + continue; + } + + if ( self isDefusing() || self isPlanting() ) + { + continue; + } + + if ( self IsUsingRemote() ) + { + continue; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + continue; + } + + if ( !self HasThreat() ) + { + continue; + } + + if ( !self.hasriotshieldequipped ) + { + continue; + } + + self bot_watch_riot_weapons_loop(); + } +} + +/* + Loop +*/ +bot_jav_loc_think_loop( data ) +{ + if ( data.dofastcontinue ) + { + data.dofastcontinue = false; + } + else + { + wait randomintRange( 2, 4 ); + + chance = self.pers[ "bots" ][ "behavior" ][ "nade" ] / 2; + + if ( chance > 20 ) + { + chance = 20; + } + + if ( randomInt( 100 ) > chance && self getCurrentWeapon() != "javelin_mp" ) + { + return; + } + } + + if ( !self GetAmmoCount( "javelin_mp" ) ) + { + return; + } + + if ( self HasThreat() || self HasBotJavelinLocation() || self HasScriptAimPos() ) + { + return; + } + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + return; + } + + if ( self isEMPed() ) + { + return; + } + + loc = undefined; + + if ( !self nearAnyOfWaypoints( 128, getWaypointsOfType( "javelin" ) ) ) + { + javWp = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "javelin" ), 1024 ) ) ); + + if ( !isDefined( javWp ) || self HasScriptGoal() || self.bot_lock_goal ) + { + traceForward = self maps\mp\_javelin::EyeTraceForward(); + + if ( !isDefined( traceForward ) ) + { + return; + } + + loc = traceForward[ 0 ]; + + if ( self maps\mp\_javelin::TargetPointTooClose( loc ) ) + { + return; + } + + if ( !bulletTracePassed( self.origin + ( 0, 0, 5 ), self.origin + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + + if ( !bulletTracePassed( loc + ( 0, 0, 5 ), loc + ( 0, 0, 2048 ), false, self ) ) + { + return; + } + } + else + { + self BotNotifyBotEvent( "jav", "go", javWp ); + + self SetScriptGoal( javWp.origin, 16 ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" ) + { + return; + } + + data.dofastcontinue = true; + return; + } + } + else + { + javWp = getWaypointForIndex( self getNearestWaypointOfWaypoints( getWaypointsOfType( "javelin" ) ) ); + loc = javWp.jav_point; + } + + if ( !isDefined( loc ) ) + { + return; + } + + self BotNotifyBotEvent( "jav", "start", loc ); + + self SetBotJavelinLocation( loc ); + + if ( self changeToWeapon( "javelin_mp" ) ) + { + self waittill_any_timeout( 10, "missile_fire", "weapon_change" ); + } + + self ClearBotJavelinLocation(); +} + +/* + BOts thinking of using javelins +*/ +bot_jav_loc_think() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.dofastcontinue = false; + + for ( ;; ) + { + self bot_jav_loc_think_loop( data ); + } +} + +/* + Loop +*/ +bot_equipment_kill_think_loop() +{ + myteam = self.pers[ "team" ]; + hasSitrep = self _HasPerk( "specialty_detectexplosive" ); + grenades = getEntArray( "grenade", "classname" ); + myEye = self getEye(); + myAngles = self getPlayerAngles(); + dist = 512 * 512; + target = undefined; + + // check legacy nades, c4 and claymores + for ( i = 0; i < grenades.size; i++ ) + { + item = grenades[ i ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( !IsDefined( item.name ) ) + { + continue; + } + + if ( item.name != "c4_mp" && item.name != "claymore_mp" ) + { + continue; + } + + if ( IsDefined( item.owner ) && ( ( level.teambased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + + grenades = undefined; // clean up, reduces child1 vars + + // check for player stuff, tis and throphys and radars + if ( !IsDefined( target ) ) + { + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !isDefined( player.team ) ) + { + continue; + } + + if ( level.teambased && player.team == myteam ) + { + continue; + } + + // check for thorphys + if ( isDefined( player.trophyarray ) ) + { + for ( h = 0; h < player.trophyarray.size; h++ ) + { + item = player.trophyarray[ h ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( !isDefined( item.bots ) ) + { + item.bots = 0; + } + + if ( item.bots >= 2 ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for ti + if ( !isDefined( target ) ) + { + for ( h = 0; h < 1; h++ ) + { + item = player.setspawnpoint; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( !isDefined( item.bots ) ) + { + item.bots = 0; + } + + if ( item.bots >= 2 ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for radar + if ( !isDefined( target ) ) + { + for ( h = 0; h < 1; h++ ) + { + item = player.deployedportableradar; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( !isDefined( item.bots ) ) + { + item.bots = 0; + } + + if ( item.bots >= 2 ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + if ( isDefined( target ) ) + { + break; + } + } + } + + // check for ims + if ( !IsDefined( target ) ) + { + imsKeys = getArrayKeys( level.ims ); + + for ( i = 0; i < imsKeys.size; i++ ) + { + item = level.ims[ imsKeys[ i ] ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( IsDefined( item.owner ) && ( ( level.teambased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + + imsKeys = undefined; + } + + // check for vest + if ( !IsDefined( target ) ) + { + for ( i = 0; i < level.vest_boxes.size; i++ ) + { + item = level.vest_boxes[ i ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( IsDefined( item.owner ) && ( ( level.teambased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for jammers + if ( !IsDefined( target ) ) + { + for ( i = 0; i < level.scramblers.size; i++ ) + { + item = level.scramblers[ i ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( IsDefined( item.owner ) && ( ( level.teambased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + // check for mines + if ( !IsDefined( target ) ) + { + for ( i = 0; i < level.mines.size; i++ ) + { + item = level.mines[ i ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( IsDefined( item.owner ) && ( ( level.teambased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( !hasSitrep && !bulletTracePassed( myEye, item.origin, false, item ) ) + { + continue; + } + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + target = item; + break; + } + } + } + + if ( !IsDefined( target ) ) + { + return; + } + + // must be ti + if ( isDefined( target.enemytrigger ) && !self HasScriptGoal() && !self.bot_lock_goal ) + { + self BotNotifyBotEvent( "attack_equ", "go_ti", target ); + + self SetScriptGoal( target.origin, 64 ); + self thread bot_inc_bots( target, true ); + self thread bots_watch_touch_obj( target ); + + path = self waittill_any_return( "bad_path", "goal", "new_goal" ); + + if ( path != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( path != "goal" || !isDefined( target ) ) + { + return; + } + + if ( randomInt( 100 ) < self.pers[ "bots" ][ "behavior" ][ "camp" ] * 8 ) + { + self BotNotifyBotEvent( "attack_equ", "camp_ti", target ); + + self thread killCampAfterTime( randomIntRange( 10, 20 ) ); + self thread killCampAfterEntGone( target ); + self CampAtSpot( target.origin, target.origin + ( 0, 0, 42 ) ); + } + + if ( isDefined( target ) ) + { + self BotNotifyBotEvent( "attack_equ", "trigger_ti", target ); + self thread BotPressUse(); + } + + return; + } + + self BotNotifyBotEvent( "attack_equ", "start", target ); + + self SetScriptEnemy( target ); + self bot_equipment_attack( target ); + self ClearScriptEnemy(); + + self BotNotifyBotEvent( "attack_equ", "stop", target ); +} + +/* + Bots thinking of targeting equipment, c4, claymores and TIs +*/ +bot_equipment_kill_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon ( "game_ended" ); + + for ( ;; ) + { + wait( RandomIntRange( 1, 3 ) ); + + if ( self HasScriptEnemy() ) + { + continue; + } + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) + { + continue; + } + + self bot_equipment_kill_think_loop(); + } +} + +/* + Bots target the equipment for a time then stop +*/ +bot_equipment_attack( equ ) +{ + wait_time = RandomIntRange( 7, 10 ); + + for ( i = 0; i < wait_time; i++ ) + { + wait( 1 ); + + if ( !IsDefined( equ ) ) + { + return; + } + + if ( isDefined( equ.damagetaken ) && isDefined( equ.maxhealth ) ) + { + if ( equ.damagetaken >= equ.maxhealth ) + { + return; + } + } + } +} + +/* + Loop +*/ +bot_listen_to_steps_loop() +{ + dist = level.bots_listendist; + + if ( self _hasPerk( "specialty_selectivehearing" ) ) + { + dist *= 1.4; + } + + dist *= dist; + + heard = undefined; + + for ( i = level.players.size - 1 ; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( level.teambased && self.team == player.team ) + { + continue; + } + + if ( player.sessionstate != "playing" ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( lengthsquared( player getVelocity() ) < 20000 ) + { + continue; + } + + if ( distanceSquared( player.origin, self.origin ) > dist ) + { + continue; + } + + if ( player _hasPerk( "specialty_quieter" ) ) + { + continue; + } + + heard = player; + break; + } + + hasHeartbeat = ( isSubStr( self GetCurrentWeapon(), "_heartbeat" ) && ( ( !self IsEMPed() && !self isNuked() ) || self _hasPerk( "specialty_spygame" ) ) ); + heartbeatDist = 350 * 350; + + if ( !IsDefined( heard ) && hasHeartbeat ) + { + for ( i = level.players.size - 1 ; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( level.teambased && self.team == player.team ) + { + continue; + } + + if ( player.sessionstate != "playing" ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( player _hasPerk( "specialty_heartbreaker" ) ) + { + continue; + } + + if ( distanceSquared( player.origin, self.origin ) > heartbeatDist ) + { + continue; + } + + if ( GetConeDot( player.origin, self.origin, self GetPlayerAngles() ) < 0.6 ) + { + continue; + } + + heard = player; + break; + } + } + + if ( !isDefined( heard ) ) + { + if ( self _hasPerk( "specialty_revenge" ) && isDefined( self.lastkilledby ) ) + { + heard = self.lastkilledby; + } + } + + if ( !IsDefined( heard ) ) + { + return; + } + + self BotNotifyBotEvent( "heard_target", "start", heard ); + + if ( bulletTracePassed( self getEye(), heard getTagOrigin( "j_spineupper" ), false, heard ) ) + { + self setAttacker( heard ); + return; + } + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + return; + } + + self SetScriptGoal( heard.origin, 64 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "heard_target", "stop", heard ); +} + +/* + Bots will listen to foot steps and target nearby targets +*/ +bot_listen_to_steps() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + wait 1; + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] < 3 ) + { + continue; + } + + self bot_listen_to_steps_loop(); + } +} + +/* + Loop +*/ +bot_uav_think_loop() +{ + hasAssPro = self _hasPerk( "specialty_spygame" ); + + if ( !hasAssPro ) + { + if ( self isEMPed() || self.bot_isscrambled || self isNuked() ) + { + return; + } + + if ( ( level.teambased && level.activecounteruavs[ level.otherteam[ self.team ] ] ) || ( !level.teambased && self.isradarblocked ) ) + { + return; + } + } + + hasRadar = ( ( level.teambased && level.activeuavs[ self.team ] ) || ( !level.teambased && level.activeuavs[ self.guid ] ) ); + + if ( level.hardcoremode && !hasRadar ) + { + return; + } + + dist = self.pers[ "bots" ][ "skill" ][ "help_dist" ]; + dist *= dist * 8; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !isDefined( player.team ) ) + { + continue; + } + + if ( player.sessionstate != "playing" ) + { + continue; + } + + if ( level.teambased && player.team == self.team ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + distFromPlayer = DistanceSquared( self.origin, player.origin ); + + if ( distFromPlayer > dist ) + { + continue; + } + + if ( ( !isSubStr( player getCurrentWeapon(), "_silencer" ) && player.bots_firing ) || ( hasRadar && !player _hasPerk( "specialty_coldblooded" ) ) || player maps\mp\perks\_perkfunctions::isPainted() || player.bot_isinradar || player isJuggernaut() || isDefined( player.uavremotemarkedby ) ) + { + self BotNotifyBotEvent( "uav_target", "start", player ); + + distSq = self.pers[ "bots" ][ "skill" ][ "help_dist" ] * self.pers[ "bots" ][ "skill" ][ "help_dist" ]; + + if ( distFromPlayer < distSq && bulletTracePassed( self getEye(), player getTagOrigin( "j_spineupper" ), false, player ) ) + { + self SetAttacker( player ); + } + + if ( !self HasScriptGoal() && !self.bot_lock_goal ) + { + self SetScriptGoal( player.origin, 128 ); + self thread stop_go_target_on_death( player ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "uav_target", "stop", player ); + } + + break; + } + } +} + +/* + Bots will look at the uav and target targets +*/ +bot_uav_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + wait 0.75; + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 || self IsUsingRemote() ) + { + continue; + } + + self bot_uav_think_loop(); + } +} + +/* + bots will go to their target's kill location +*/ +bot_revenge_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) + { + return; + } + + if ( isDefined( self.lastkiller ) && isReallyAlive( self.lastkiller ) ) + { + if ( bulletTracePassed( self getEye(), self.lastkiller getTagOrigin( "j_spineupper" ), false, self.lastkiller ) ) + { + self setAttacker( self.lastkiller ); + } + } + + if ( !isDefined( self.killerlocation ) ) + { + return; + } + + loc = self.killerlocation; + + for ( ;; ) + { + wait( RandomIntRange( 1, 5 ) ); + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + return; + } + + if ( randomint( 100 ) < 75 ) + { + return; + } + + self BotNotifyBotEvent( "revenge", "start", loc, self.lastkiller ); + + self SetScriptGoal( loc, 64 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "revenge", "stop", loc, self.lastkiller ); + } +} + +/* + Watches the target's health, calls 'bad_path' +*/ +turret_death_monitor( turret ) +{ + self endon ( "death" ); + self endon ( "disconnect" ); + self endon ( "bad_path" ); + self endon ( "goal" ); + self endon ( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( turret ) ) + { + break; + } + + if ( turret.damagetaken >= turret.maxhealth ) + { + break; + } + + if ( isDefined( turret.carriedby ) ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots will target the turret for a time +*/ +bot_turret_attack( enemy ) +{ + wait_time = RandomIntRange( 7, 10 ); + + for ( i = 0; i < wait_time; i++ ) + { + wait( 1 ); + + if ( !IsDefined( enemy ) ) + { + return; + } + + if ( enemy.damagetaken >= enemy.maxhealth ) + { + return; + } + + if ( isDefined( enemy.carriedby ) ) + { + return; + } + + // if ( !BulletTracePassed( self getEye(), enemy.origin + ( 0, 0, 15 ), false, enemy ) ) + // return; + } +} + +/* + Loops +*/ +bot_turret_think_loop() +{ + myteam = self.pers[ "team" ]; + turretsKeys = getArrayKeys( level.turrets ); + + if ( turretsKeys.size == 0 ) + { + wait( randomintrange( 3, 5 ) ); + return; + } + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) + { + return; + } + + if ( self HasScriptEnemy() || self IsUsingRemote() ) + { + return; + } + + myEye = self GetEye(); + turret = undefined; + + for ( i = turretsKeys.size - 1; i >= 0; i-- ) + { + tempTurret = level.turrets[ turretsKeys[ i ] ]; + + if ( !isDefined( tempTurret ) ) + { + continue; + } + + if ( tempTurret.damagetaken >= tempTurret.maxhealth ) + { + continue; + } + + if ( isDefined( tempTurret.carriedby ) ) + { + continue; + } + + if ( isDefined( tempTurret.owner ) && tempTurret.owner == self ) + { + continue; + } + + if ( level.teambased && tempTurret.team == myteam ) + { + continue; + } + + if ( !bulletTracePassed( myEye, tempTurret.origin + ( 0, 0, 15 ), false, tempTurret ) ) + { + continue; + } + + turret = tempTurret; + } + + turretsKeys = undefined; + + if ( !isDefined( turret ) ) + { + return; + } + + forward = AnglesToForward( turret.angles ); + forward = VectorNormalize( forward ); + + delta = self.origin - turret.origin; + delta = VectorNormalize( delta ); + + dot = VectorDot( forward, delta ); + + facing = true; + + if ( dot < 0.342 ) // cos 70 degrees + { + facing = false; + } + + if ( turret isStunned() ) + { + facing = false; + } + + if ( self _hasPerk( "specialty_blindeye" ) ) + { + facing = false; + } + + if ( !isDefined( turret.sentrytype ) || turret.sentrytype == "sam_turret" ) + { + facing = false; + } + + if ( facing && !BulletTracePassed( myEye, turret.origin + ( 0, 0, 15 ), false, turret ) ) + { + return; + } + + if ( !IsDefined( turret.bots ) ) + { + turret.bots = 0; + } + + if ( turret.bots >= 2 ) + { + return; + } + + if ( !facing && !self HasScriptGoal() && !self.bot_lock_goal ) + { + self BotNotifyBotEvent( "turret_attack", "go", turret ); + + self SetScriptGoal( turret.origin, 32 ); + self thread bot_inc_bots( turret, true ); + self thread turret_death_monitor( turret ); + self thread bots_watch_touch_obj( turret ); + + if ( self waittill_any_return( "bad_path", "goal", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + + if ( !isDefined( turret ) ) + { + return; + } + + self BotNotifyBotEvent( "turret_attack", "start", turret ); + + self SetScriptEnemy( turret, ( 0, 0, 25 ) ); + self bot_turret_attack( turret ); + self ClearScriptEnemy(); + + self BotNotifyBotEvent( "turret_attack", "stop", turret ); +} + +/* + Bots will think when to target a turret +*/ +bot_turret_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon ( "game_ended" ); + + for ( ;; ) + { + wait( 1 ); + + self bot_turret_think_loop(); + } +} + +/* + Loops +*/ +bot_box_think_loop( data ) +{ + ret = "bot_check_box_think"; + + if ( data.first ) + { + data.first = false; + } + else + { + ret = self waittill_any_timeout( randomintrange( 3, 5 ), "bot_check_box_think" ); + } + + if ( RandomInt( 100 ) < 20 && ret != "bot_check_box_think" ) + { + return; + } + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + return; + } + + if ( self HasThreat() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() || self BotIsFrozen() ) + { + return; + } + + if ( self inLastStand() ) + { + return; + } + + if ( isDefined( self.haslightarmor ) && self.haslightarmor ) + { + return; + } + + if ( self isJuggernaut() ) + { + return; + } + + box = undefined; + myteam = self.pers[ "team" ]; + + dist = 2048 * 2048; + + for ( i = 0; i < level.vest_boxes.size; i++ ) + { + item = level.vest_boxes[ i ]; + + if ( !isDefined( item ) ) + { + continue; + } + + if ( isDefined( item.damagetaken ) && isDefined( item.maxhealth ) ) + { + if ( item.damagetaken >= item.maxhealth ) + { + continue; + } + } + + if ( !IsDefined( item.owner ) || ( level.teambased && item.owner.team != myteam ) || ( !level.teambased && item.owner != self ) ) + { + continue; + } + + if ( DistanceSquared( item.origin, self.origin ) < dist ) + { + box = item; + break; + } + } + + if ( !isDefined( box ) ) + { + return; + } + + self BotNotifyBotEvent( "box_cap", "go", box ); + + self.bot_lock_goal = true; + + radius = GetDvarFloat( "player_useRadius" ) / 2; + self SetScriptGoal( box.origin, radius ); + self thread bot_inc_bots( box, true ); + self thread bots_watch_touch_obj( box ); + + path = self waittill_any_return( "bad_path", "goal", "new_goal" ); + + self.bot_lock_goal = false; + + if ( path != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( path != "goal" || !isDefined( box ) || DistanceSquared( self.origin, box.origin ) > radius * radius ) + { + return; + } + + self BotNotifyBotEvent( "box_cap", "start", box ); + + self BotFreezeControls( true ); + self bot_wait_stop_move(); + + waitTime = 2.25; + self thread BotPressUse( waitTime ); + wait waitTime; + + self BotFreezeControls( false ); + + self BotNotifyBotEvent( "box_cap", "stop", box ); +} + +/* + Bots think to use boxes +*/ +bot_box_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.first = true; + + for ( ;; ) + { + self bot_box_think_loop( data ); + } +} + +/* + Loops +*/ +bot_watch_stuck_on_crate_loop() +{ + crates = getEntArray( "care_package", "targetname" ); + + if ( crates.size == 0 ) + { + return; + } + + crate = undefined; + + for ( i = crates.size - 1; i >= 0; i-- ) + { + tempCrate = crates[ i ]; + + if ( !isDefined( tempCrate ) ) + { + continue; + } + + if ( isDefined( tempCrate.owner ) && isDefined( tempCrate.bomb ) ) + { + if ( tempCrate.owner == self ) + { + continue; + } + + if ( level.teambased && tempCrate.owner.team == self.team ) + { + continue; + } + + if ( self _hasPerk( "specialty_detectexplosive" ) ) + { + continue; + } + } + + if ( !isDefined( tempCrate.doingphysics ) || tempCrate.doingphysics ) + { + continue; + } + + if ( isDefined( crate ) && DistanceSquared( crate.origin, self.origin ) < DistanceSquared( tempCrate.origin, self.origin ) ) + { + continue; + } + + crate = tempCrate; + } + + if ( !isDefined( crate ) ) + { + return; + } + + radius = GetDvarFloat( "player_useRadius" ); + + if ( DistanceSquared( crate.origin, self.origin ) > radius * radius ) + { + return; + } + + self.bot_stuck_on_carepackage = crate; + self notify( "crate_physics_done" ); +} + +/* + Checks if the bot is stuck on a carepackage +*/ +bot_watch_stuck_on_crate() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + for ( ;; ) + { + wait 3; + + if ( self HasThreat() ) + { + continue; + } + + self bot_watch_stuck_on_crate_loop(); + } +} + +/* + Loops +*/ +bot_crate_think_loop( data ) +{ + myteam = self.pers[ "team" ]; + ret = "crate_physics_done"; + + if ( data.first ) + { + data.first = false; + } + else + { + ret = self waittill_any_timeout( randomintrange( 3, 5 ), "crate_physics_done" ); + } + + crate = self.bot_stuck_on_carepackage; + self.bot_stuck_on_carepackage = undefined; + + if ( !isDefined( crate ) ) + { + if ( RandomInt( 100 ) < 20 && ret != "crate_physics_done" ) + { + return; + } + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() || self BotIsFrozen() ) + { + return; + } + + if ( self inLastStand() ) + { + return; + } + + crates = getEntArray( "care_package", "targetname" ); + + if ( crates.size == 0 ) + { + return; + } + + wantsClosest = randomint( 2 ); + + crate = undefined; + + for ( i = crates.size - 1; i >= 0; i-- ) + { + tempCrate = crates[ i ]; + + if ( !isDefined( tempCrate ) ) + { + continue; + } + + if ( isDefined( tempCrate.owner ) && isDefined( tempCrate.bomb ) ) + { + if ( tempCrate.owner == self ) + { + continue; + } + + if ( level.teambased && tempCrate.owner.team == self.team ) + { + continue; + } + + if ( self _hasPerk( "specialty_detectexplosive" ) ) + { + continue; + } + } + + if ( !isDefined( tempCrate.doingphysics ) || tempCrate.doingphysics ) + { + continue; + } + + if ( !IsDefined( tempCrate.bots ) ) + { + tempCrate.bots = 0; + } + + if ( tempCrate.bots >= 3 ) + { + continue; + } + + if ( isDefined( crate ) ) + { + if ( wantsClosest ) + { + if ( DistanceSquared( crate.origin, self.origin ) < DistanceSquared( tempCrate.origin, self.origin ) ) + { + continue; + } + } + else + { + if ( maps\mp\killstreaks\_killstreaks::getStreakCost( crate.cratetype ) > maps\mp\killstreaks\_killstreaks::getStreakCost( tempCrate.cratetype ) ) + { + continue; + } + } + } + + crate = tempCrate; + } + + crates = undefined; + + if ( !isDefined( crate ) ) + { + return; + } + + self BotNotifyBotEvent( "crate_cap", "go", crate ); + + self.bot_lock_goal = true; + + radius = GetDvarFloat( "player_useRadius" ) - 16; + self SetScriptGoal( crate.origin, radius ); + self thread bot_inc_bots( crate, true ); + self thread bots_watch_touch_obj( crate ); + + path = self waittill_any_return( "bad_path", "goal", "new_goal" ); + + self.bot_lock_goal = false; + + if ( path != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( path != "goal" || !isDefined( crate ) || DistanceSquared( self.origin, crate.origin ) > radius * radius ) + { + if ( isDefined( crate ) && path == "bad_path" ) + { + self BotNotifyBotEvent( "crate_cap", "unreachable", crate ); + } + + return; + } + } + + self BotNotifyBotEvent( "crate_cap", "start", crate ); + + self BotRandomStance(); + + self BotFreezeControls( true ); + self bot_wait_stop_move(); + + waitTime = 3.25; + + if ( !isDefined( crate.owner ) || crate.owner == self ) + { + waitTime = 0.75; + } + + self thread BotPressUse( waitTime ); + wait waitTime; + + self BotFreezeControls( false ); + + // check if actually captured it? + self BotNotifyBotEvent( "crate_cap", "stop", crate ); +} + +/* + Bots will capture carepackages +*/ +bot_crate_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.first = true; + + for ( ;; ) + { + self bot_crate_think_loop( data ); + } +} + +/* + Reload cancels +*/ +doReloadCancel_loop() +{ + curWeap = self GetCurrentWeapon(); + ret = self waittill_either_return( "reload", "weapon_change" ); + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + return; + } + + if ( !getDvarInt( "sv_enableDoubleTaps" ) ) + { + return; + } + + // wait for an actual change + if ( ret == "weapon_change" ) + { + for ( i = 0; i < 10 && curWeap == self GetCurrentWeapon(); i++ ) + { + wait 0.05; + } + } + + curWeap = self GetCurrentWeapon(); + + if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap ) ) + { + return; + } + + if ( ret == "reload" ) + { + // check single reloads + if ( self GetWeaponAmmoClip( curWeap ) < WeaponClipSize( curWeap ) ) + { + return; + } + } + + // check difficulty + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 3 ) + { + return; + } + + // check if got another weapon + weaponslist = self GetWeaponsListPrimaries(); + weap = ""; + + while ( weaponslist.size ) + { + weapon = weaponslist[ randomInt( weaponslist.size ) ]; + weaponslist = array_remove( weaponslist, weapon ); + + if ( !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon ) ) + { + continue; + } + + if ( curWeap == weapon || weapon == "none" || weapon == "" ) + { + continue; + } + + weap = weapon; + break; + } + + if ( weap == "" ) + { + return; + } + + // do the cancel + wait 0.1; + self thread ChangeToWeapon( weap ); + wait 0.25; + self thread ChangeToWeapon( curWeap ); + wait 2; +} + +/* + Reload cancels +*/ +doReloadCancel() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + self doReloadCancel_loop(); + } +} + +/* + Loops +*/ +bot_weapon_think_loop( data ) +{ + ret = self waittill_any_timeout( randomIntRange( 2, 4 ), "bot_force_check_switch" ); + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + return; + } + + curWeap = self GetCurrentWeapon(); + hasTarget = self hasThreat(); + + if ( hasTarget ) + { + threat = self getThreat(); + rocketAmmo = self getRocketAmmo(); + + if ( entIsVehicle( threat ) && isDefined( rocketAmmo ) ) + { + if ( curWeap != rocketAmmo ) + { + self thread ChangeToWeapon( rocketAmmo ); + } + + return; + } + } + + if ( self HasBotJavelinLocation() && self GetAmmoCount( "javelin_mp" ) ) + { + if ( curWeap != "javelin_mp" ) + { + self thread ChangeToWeapon( "javelin_mp" ); + } + + return; + } + + force = ( ret == "bot_force_check_switch" ); + + if ( data.first ) + { + data.first = false; + + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "initswitch" ] ) + { + return; + } + } + else + { + if ( curWeap != "none" && self getAmmoCount( curWeap ) && curWeap != "stinger_mp" && curWeap != "javelin_mp" ) + { + if ( randomInt( 100 ) > self.pers[ "bots" ][ "behavior" ][ "switch" ] ) + { + return; + } + + if ( hasTarget ) + { + return; + } + } + else + { + force = true; + } + } + + weaponslist = self getweaponslistall(); + weap = ""; + + while ( weaponslist.size ) + { + weapon = weaponslist[ randomInt( weaponslist.size ) ]; + weaponslist = array_remove( weaponslist, weapon ); + + if ( !self getAmmoCount( weapon ) && !force ) + { + continue; + } + + if ( !isWeaponPrimary( weapon ) ) + { + continue; + } + + if ( curWeap == weapon || weapon == "none" || weapon == "" || weapon == "javelin_mp" || weapon == "stinger_mp" ) + { + continue; + } + + weap = weapon; + break; + } + + if ( weap == "" ) + { + return; + } + + self thread ChangeToWeapon( weap ); +} + +/* + Bots will think to switch weapons +*/ +bot_weapon_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.first = true; + + for ( ;; ) + { + self bot_weapon_think_loop( data ); + } +} + +/* + Bots think when to target vehicles +*/ +bot_target_vehicle_loop() +{ + rocketAmmo = self getRocketAmmo(); + + if ( isDefined( rocketAmmo ) && rocketAmmo == "javelin_mp" && self isEMPed() ) + { + return; + } + + targets = maps\mp\_stinger::GetTargetList(); + + if ( !targets.size ) + { + return; + } + + lockOnAmmo = self getLockonAmmo(); + myEye = self GetEye(); + target = undefined; + + for ( i = targets.size - 1; i >= 0; i-- ) + { + tempTarget = targets[ i ]; + + if ( isPlayer( tempTarget ) ) + { + continue; + } + + if ( isDefined( tempTarget.owner ) && tempTarget.owner == self ) + { + continue; + } + + if ( !bulletTracePassed( myEye, tempTarget.origin, false, tempTarget ) ) + { + continue; + } + + if ( tempTarget.health <= 0 ) + { + continue; + } + + if ( isDefined( tempTarget.damagetaken ) && isDefined( tempTarget.maxhealth ) ) + { + if ( tempTarget.damagetaken >= tempTarget.maxhealth ) + { + continue; + } + } + + if ( tempTarget.classname != "script_vehicle" && !isDefined( lockOnAmmo ) ) + { + continue; + } + + target = tempTarget; + } + + targets = undefined; + + if ( !isDefined( target ) ) + { + return; + } + + if ( target.model != "vehicle_ugv_talon_mp" && target.model != "vehicle_remote_uav" ) + { + if ( isDefined( self.remotetank ) ) + { + return; + } + + if ( !isDefined( rocketAmmo ) && self BotGetRandom() < 90 ) + { + return; + } + } + + self BotNotifyBotEvent( "attack_vehicle", "start", target, rocketAmmo ); + + self SetScriptEnemy( target, ( 0, 0, 0 ) ); + self bot_attack_vehicle( target ); + self ClearScriptEnemy(); + self notify( "bot_force_check_switch" ); + + self BotNotifyBotEvent( "attack_vehicle", "stop", target, rocketAmmo ); +} + +/* + Bots think when to target vehicles +*/ +bot_target_vehicle() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + wait randomIntRange( 2, 4 ); + + if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 1 ) + { + continue; + } + + if ( self HasScriptEnemy() ) + { + continue; + } + + if ( self IsUsingRemote() && !isDefined( self.remotetank ) ) + { + continue; + } + + self bot_target_vehicle_loop(); + } +} + +/* + Bots target the killstreak for a time and stops +*/ +bot_attack_vehicle( target ) +{ + target endon( "death" ); + + wait_time = RandomIntRange( 7, 10 ); + + for ( i = 0; i < wait_time; i++ ) + { + self notify( "bot_force_check_switch" ); + wait( 1 ); + + if ( !IsDefined( target ) ) + { + return; + } + } +} + +/* + Bot watch to use remote turret +*/ +bot_watch_use_remote_turret() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + wait 5; + + if ( self BotIsFrozen() ) + { + continue; + } + + if ( self HasThreat() || self HasBotJavelinLocation() ) + { + continue; + } + + if ( self isDefusing() || self isPlanting() ) + { + continue; + } + + if ( self IsUsingRemote() ) + { + continue; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + continue; + } + + if ( !isDefined( self.remoteturretlist ) || !isDefined( self.remoteturretlist[ 0 ] ) ) + { + continue; + } + + self thread BotPressUse( 3 ); + wait 3; + } +} + +/* + Returns an origin thats good to use for a kill streak +*/ +getKillstreakTargetLocation() +{ + location = undefined; + players = []; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !isDefined( player.team ) ) + { + continue; + } + + if ( level.teambased && self.team == player.team ) + { + continue; + } + + if ( player.sessionstate != "playing" ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( player _hasPerk( "specialty_blindeye" ) ) + { + continue; + } + + if ( !bulletTracePassed( player.origin, player.origin + ( 0, 0, 2048 ), false, player ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + continue; + } + + players[ players.size ] = player; + } + + target = random( players ); + + if ( isDefined( target ) ) + { + location = target.origin + ( randomIntRange( ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * -75, ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * 75 ), randomIntRange( ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * -75, ( 8 - self.pers[ "bots" ][ "skill" ][ "base" ] ) * 75 ), 0 ); + } + else if ( self.pers[ "bots" ][ "skill" ][ "base" ] <= 3 ) + { + location = self.origin + ( randomIntRange( -512, 512 ), randomIntRange( -512, 512 ), 0 ); + } + + return location; +} + +/* + Clears remote usage when bot dies +*/ +clear_remote_on_death( isac130 ) +{ + self endon( "bot_clear_remote_on_death" ); + level endon( "game_ended" ); + + self waittill_either( "death", "disconnect" ); + + if ( isDefined( isac130 ) && isac130 ) + { + level.ac130inuse = false; + } + + if ( isDefined( self ) ) + { + self ClearUsingRemote(); + } +} + +/* + Bots think to use killstreaks +*/ +bot_killstreak_think_loop( data ) +{ + if ( !isDefined( data.dofastcontinue ) ) + { + wait randomIntRange( 1, 3 ); + } + + if ( self BotIsFrozen() ) + { + return; + } + + if ( self HasThreat() || self HasBotJavelinLocation() ) + { + return; + } + + if ( self isDefusing() || self isPlanting() ) + { + return; + } + + if ( self isEMPed() || self isNuked() ) + { + return; + } + + if ( self IsUsingRemote() ) + { + return; + } + + if ( self InLastStand() && !self InFinalStand() ) + { + return; + } + + + if ( isDefined( self.iscarrying ) && self.iscarrying ) + { + self notify( "place_sentry" ); + self notify( "place_turret" ); + self notify( "place_ims" ); + self notify( "place_carryRemoteUAV" ); + self notify( "place_tank" ); + } + + curWeap = self GetCurrentWeapon(); + + if ( isSubStr( curWeap, "airdrop_" ) || isSubStr( curWeap, "deployable_" ) ) + { + self thread BotPressAttack( 0.05 ); + } + + + useableStreaks = []; + + if ( !isDefined( data.dofastcontinue ) ) + { + if ( self.pers[ "killstreaks" ][ 0 ].available ) + { + useableStreaks[ useableStreaks.size ] = 0; + } + + if ( self.pers[ "killstreaks" ][ 1 ].available && self.streaktype != "specialist" ) + { + useableStreaks[ useableStreaks.size ] = 1; + } + + if ( self.pers[ "killstreaks" ][ 2 ].available && self.streaktype != "specialist" ) + { + useableStreaks[ useableStreaks.size ] = 2; + } + + if ( self.pers[ "killstreaks" ][ 3 ].available && self.streaktype != "specialist" ) + { + useableStreaks[ useableStreaks.size ] = 3; + } + } + else + { + useableStreaks[ 0 ] = data.dofastcontinue; + data.dofastcontinue = undefined; + } + + if ( !useableStreaks.size ) + { + return; + } + + self.killstreakindexweapon = random( useableStreaks ); + streakName = self.pers[ "killstreaks" ][ self.killstreakindexweapon ].streakname; + + if ( level.ingraceperiod && maps\mp\killstreaks\_killstreaks::deadlyKillstreak( streakName ) ) + { + return; + } + + ksWeap = maps\mp\killstreaks\_killstreaks::getKillstreakWeapon( streakName ); + + if ( curWeap == "none" || !isWeaponPrimary( curWeap ) ) + { + curWeap = self GetLastWeapon(); + } + + lifeId = self.pers[ "killstreaks" ][ 0 ].lifeid; + + if ( !isDefined( lifeId ) ) + { + lifeId = -1; + } + + if ( maps\mp\killstreaks\_killstreaks::isRideKillstreak( streakName ) || maps\mp\killstreaks\_killstreaks::isCarryKillstreak( streakName ) || streakName == "sam_turret" || streakName == "remote_mg_turret" ) + { + if ( self inLastStand() ) + { + return; + } + + if ( lifeId == self.deaths && !self HasScriptGoal() && !self.bot_lock_goal && maps\mp\killstreaks\_killstreaks::isRideKillstreak( streakName ) && !self nearAnyOfWaypoints( 128, getWaypointsOfType( "camp" ) ) ) + { + campSpot = getWaypointForIndex( random( self waypointsNear( getWaypointsOfType( "camp" ), 1024 ) ) ); + + if ( isDefined( campSpot ) ) + { + self BotNotifyBotEvent( "killstreak", "camp", streakName, campSpot ); + + self SetScriptGoal( campSpot.origin, 16 ); + + if ( self waittill_any_return( "new_goal", "goal", "bad_path" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + data.dofastcontinue = self.killstreakindexweapon; + return; + } + } + + if ( streakName == "sentry" || streakName == "sam_turret" || streakName == "remote_mg_turret" || streakName == "ims" || streakName == "remote_uav" || streakName == "remote_tank" ) + { + if ( self HasScriptAimPos() ) + { + return; + } + + if ( streakName == "remote_uav" || streakName == "remote_tank" ) + { + if ( ( isDefined( level.remote_uav[ self.team ] ) || level.littlebirds.size >= 4 ) && streakName == "remote_uav" ) + { + return; + } + + if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxvehiclecount + 1 >= maxVehiclesAllowed() ) + { + return; + } + } + + myEye = self GetEye(); + angles = self GetPlayerAngles(); + + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 1024, false, self ); + placeNot = "place_sentry"; + cancelNot = "cancel_sentry"; + distCheck = 1000 * 1000; + doRandomStance = false; + + switch ( streakName ) + { + case "sam_turret": + forwardTrace = bulletTrace( myEye, myEye + ( 0, 0, 1024 ), false, self ); + break; + + case "remote_mg_turret": + placeNot = "place_turret"; + cancelNot = "cancel_turret"; + break; + + case "ims": + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); + placeNot = "place_ims"; + cancelNot = "cancel_ims"; + distCheck = 100 * 100; + break; + + case "remote_uav": + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); + placeNot = "place_carryRemoteUAV"; + cancelNot = "cancel_carryRemoteUAV"; + distCheck = 100 * 100; + doRandomStance = true; + break; + + case "remote_tank": + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); + placeNot = "place_tank"; + cancelNot = "cancel_tank"; + distCheck = 100 * 100; + doRandomStance = true; + break; + } + + if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < distCheck && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + return; + } + + self BotNotifyBotEvent( "killstreak", "call", streakName ); + + if ( doRandomStance ) + { + self BotRandomStance(); + } + + self BotStopMoving( true ); + self SetScriptAimPos( forwardTrace[ "position" ] ); + + if ( !self changeToWeapon( ksWeap ) ) + { + self BotStopMoving( false ); + self ClearScriptAimPos(); + return; + } + + wait 1; + self notify( placeNot ); + wait 0.05; + self notify( cancelNot ); + wait 0.5; + + self BotStopMoving( false ); + self ClearScriptAimPos(); + } + else if ( streakName == "predator_missile" ) + { + location = self getKillstreakTargetLocation(); + + if ( !isDefined( location ) ) + { + return; + } + + self BotNotifyBotEvent( "killstreak", "call", streakName, location ); + + self BotRandomStance(); + self setUsingRemote( "remotemissile" ); + self thread clear_remote_on_death(); + self BotStopMoving( true ); + + if ( !self changeToWeapon( ksWeap ) ) + { + self ClearUsingRemote(); + self notify( "bot_clear_remote_on_death" ); + self BotStopMoving( false ); + return; + } + + wait 0.05; + self thread ChangeToWeapon( ksWeap ); // prevent script from changing back + + wait 1; + self notify( "bot_clear_remote_on_death" ); + self BotStopMoving( false ); + + if ( self isEMPed() || self isNuked() ) + { + self ClearUsingRemote(); + self thread changeToWeapon( curWeap ); + return; + } + + self BotFreezeControls( true ); + + self thread maps\mp\killstreaks\_killstreaks::updateKillstreaks(); + self maps\mp\killstreaks\_killstreaks::usedKillstreak( streakName, true ); + + rocket = MagicBullet( "remotemissile_projectile_mp", self.origin + ( 0.0, 0.0, 7000.0 - ( self.pers[ "bots" ][ "skill" ][ "base" ] * 400 ) ), location, self ); + rocket.lifeid = lifeId; + rocket.type = "remote"; + + rocket thread maps\mp\gametypes\_weapons::AddMissileToSightTraces( self.pers[ "team" ] ); + rocket thread maps\mp\killstreaks\_remotemissile::handleDamage(); + thread maps\mp\killstreaks\_remotemissile::MissileEyes( self, rocket ); + + self waittill( "stopped_using_remote" ); + + wait 1; + self BotFreezeControls( false ); + } + else if ( streakName == "ac130" || streakName == "remote_mortar" || streakName == "osprey_gunner" ) + { + if ( streakName == "ac130" ) + { + if ( isDefined( level.ac130player ) || level.ac130inuse ) + { + return; + } + } + + if ( streakName == "remote_mortar" ) + { + if ( isDefined( level.remote_mortar ) ) + { + return; + } + } + + location = undefined; + directionYaw = undefined; + + if ( streakName == "osprey_gunner" ) + { + if ( isDefined( level.chopper ) ) + { + return; + } + + if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxvehiclecount + 1 >= maxVehiclesAllowed() ) + { + return; + } + + location = self getKillstreakTargetLocation(); + directionYaw = randomInt( 360 ); + + if ( !isDefined( location ) ) + { + return; + } + } + + self BotNotifyBotEvent( "killstreak", "call", streakName, location, directionYaw ); + + self BotRandomStance(); + self BotStopMoving( true ); + + if ( self changeToWeapon( ksWeap ) ) + { + wait 1; + + if ( isDefined( location ) ) + { + self notify( "confirm_location", location, directionYaw ); + } + } + + wait 2; + self BotStopMoving( false ); + } + else if ( streakName == "deployable_vest" ) + { + myEye = self GetEye(); + angles = self GetPlayerAngles(); + + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 128, false, self ); + + if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < 96 * 96 && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + return; + } + + self BotNotifyBotEvent( "killstreak", "call", streakName ); + + self BotStopMoving( true ); + self SetScriptAimPos( forwardTrace[ "position" ] ); + + if ( !self changeToWeapon( ksWeap ) ) + { + self BotStopMoving( false ); + self ClearScriptAimPos(); + return; + } + + self thread fire_current_weapon(); + + self waittill_any_timeout( 5, "grenade_fire" ); + + self notify( "stop_firing_weapon" ); + + self BotStopMoving( false ); + self ClearScriptAimPos(); + + wait 2.5; + self notify( "bot_check_box_think" ); + } + } + else + { + if ( streakName == "escort_airdrop" || streakName == "airdrop_juggernaut_recon" || streakName == "airdrop_trap" || streakName == "airdrop_juggernaut" || streakName == "airdrop_remote_tank" || streakName == "airdrop_sentry_minigun" || streakName == "airdrop_assault" ) + { + if ( self HasScriptAimPos() ) + { + return; + } + + if ( ( level.littlebirds.size >= 4 || level.fauxvehiclecount >= 4 ) && !isSubStr( toLower( streakName ), "juggernaut" ) ) + { + return; + } + + if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxvehiclecount + 1 >= maxVehiclesAllowed() ) + { + return; + } + + if ( IsSubStr( toLower( streakName ), "escort_airdrop" ) && isDefined( level.chopper ) ) + { + return; + } + + if ( !bulletTracePassed( self.origin, self.origin + ( 0, 0, 2048 ), false, self ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + return; + } + + myEye = self GetEye(); + angles = self GetPlayerAngles(); + + forwardTrace = bulletTrace( myEye, myEye + AnglesToForward( angles ) * 256, false, self ); + + if ( DistanceSquared( self.origin, forwardTrace[ "position" ] ) < 96 * 96 && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + return; + } + + if ( !bulletTracePassed( forwardTrace[ "position" ], forwardTrace[ "position" ] + ( 0, 0, 2048 ), false, self ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 ) + { + return; + } + + self BotNotifyBotEvent( "killstreak", "call", streakName ); + + self BotStopMoving( true ); + self SetScriptAimPos( forwardTrace[ "position" ] ); + + if ( !self changeToWeapon( ksWeap ) ) + { + self BotStopMoving( false ); + self ClearScriptAimPos(); + return; + } + + self thread fire_current_weapon(); + + ret = self waittill_any_timeout( 5, "grenade_fire" ); + + self notify( "stop_firing_weapon" ); + + if ( ret == "timeout" ) + { + self BotStopMoving( false ); + self ClearScriptAimPos(); + return; + } + + if ( randomInt( 100 ) < 80 && !self HasScriptGoal() && !self.bot_lock_goal ) + { + self waittill_any_timeout( 15, "crate_physics_done", "new_goal" ); + } + + self BotStopMoving( false ); + self ClearScriptAimPos(); + } + else + { + if ( streakName == "nuke" && isDefined( level.nukeincoming ) ) + { + return; + } + + if ( streakName == "counter_uav" && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teambased && level.activecounteruavs[ self.team ] ) || ( !level.teambased && level.activecounteruavs[ self.guid ] ) ) ) + { + return; + } + + if ( ( streakName == "uav" || streakName == "uav_support" || streakName == "triple_uav" ) && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teambased && ( level.activeuavs[ self.team ] || level.activecounteruavs[ level.otherteam[ self.team ] ] ) ) || ( !level.teambased && ( level.activeuavs[ self.guid ] || self.isradarblocked ) ) ) ) + { + return; + } + + if ( streakName == "emp" && self.pers[ "bots" ][ "skill" ][ "base" ] > 3 && ( ( level.teambased && level.teamemped[ level.otherteam[ self.team ] ] ) || ( !level.teambased && isDefined( level.empplayer ) ) ) ) + { + return; + } + + if ( streakName == "littlebird_flock" || streakName == "helicopter" || streakName == "helicopter_flares" || streakName == "littlebird_support" ) + { + numIncomingVehicles = 1; + + if ( streakName == "littlebird_flock" ) + { + numIncomingVehicles = 5; + } + + if ( currentActiveVehicleCount() >= maxVehiclesAllowed() || level.fauxvehiclecount + numIncomingVehicles >= maxVehiclesAllowed() ) + { + return; + } + + if ( streakName == "helicopter" && isDefined( level.chopper ) ) + { + return; + } + + if ( streakName == "littlebird_support" && ( isDefined( level.littlebirdguard ) || maps\mp\killstreaks\_helicopter::exceededMaxLittlebirds( "littlebird_support" ) ) ) + { + return; + } + } + + location = undefined; + directionYaw = undefined; + + switch ( streakName ) + { + case "littlebird_flock": + case "stealth_airstrike": + case "precision_airstrike": + location = self getKillstreakTargetLocation(); + directionYaw = randomInt( 360 ); + + if ( !isDefined( location ) ) + { + return; + } + + case "helicopter": + case "helicopter_flares": + case "littlebird_support": + case "uav": + case "uav_support": + case "counter_uav": + case "triple_uav": + case "nuke": + case "emp": + self BotStopMoving( true ); + + self BotNotifyBotEvent( "killstreak", "call", streakName, location, directionYaw ); + + if ( self changeToWeapon( ksWeap ) ) + { + wait 1; + + if ( isDefined( location ) ) + { + self BotFreezeControls( true ); + + self notify( "confirm_location", location, directionYaw ); + wait 1; + + self BotFreezeControls( false ); + } + } + + self BotStopMoving( false ); + break; + } + } + } +} + +/* + Bots think to use killstreaks +*/ +bot_killstreak_think() +{ + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); + + data = spawnStruct(); + data.dofastcontinue = undefined; + + for ( ;; ) + { + self bot_killstreak_think_loop( data ); + } +} + +/* + Bots do random stance +*/ +BotRandomStance() +{ + if ( randomInt( 100 ) < 80 ) + { + self BotSetStance( "prone" ); + } + else if ( randomInt( 100 ) < 60 ) + { + self BotSetStance( "crouch" ); + } + else + { + self BotSetStance( "stand" ); + } +} + +/* + Bots will use a random equipment +*/ +BotUseRandomEquipment() +{ + self endon( "death" ); + self endon( "disconnect" ); + + nade = undefined; + + if ( self GetAmmoCount( "claymore_mp" ) ) + { + nade = "claymore_mp"; + } + + if ( self GetAmmoCount( "flare_mp" ) ) + { + nade = "flare_mp"; + } + + if ( self GetAmmoCount( "c4_mp" ) ) + { + nade = "c4_mp"; + } + + if ( self GetAmmoCount( "bouncingbetty_mp" ) ) + { + nade = "bouncingbetty_mp"; + } + + if ( self GetAmmoCount( "portable_radar_mp" ) ) + { + nade = "portable_radar_mp"; + } + + if ( self GetAmmoCount( "scrambler_mp" ) ) + { + nade = "scrambler_mp"; + } + + if ( self GetAmmoCount( "trophy_mp" ) ) + { + nade = "trophy_mp"; + } + + if ( !isDefined( nade ) ) + { + return; + } + + self botThrowGrenade( nade, 0.05 ); +} + +/* + Bots will look at a random thing +*/ +BotLookAtRandomThing( obj_target ) +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( self HasScriptAimPos() ) + { + return; + } + + rand = RandomInt( 100 ); + + nearestEnemy = undefined; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( !isDefined( player ) || !isDefined( player.team ) ) + { + continue; + } + + if ( !isAlive( player ) ) + { + continue; + } + + if ( level.teambased && self.team == player.team ) + { + continue; + } + + if ( !isDefined( nearestEnemy ) || DistanceSquared( self.origin, player.origin ) < DistanceSquared( self.origin, nearestEnemy.origin ) ) + { + nearestEnemy = player; + } + } + + origin = ( 0, 0, self GetPlayerViewHeight() ); + + if ( isDefined( nearestEnemy ) && DistanceSquared( self.origin, nearestEnemy.origin ) < 1024 * 1024 && rand < 40 ) + { + origin += ( nearestEnemy.origin[ 0 ], nearestEnemy.origin[ 1 ], self.origin[ 2 ] ); + } + else if ( isDefined( obj_target ) && rand < 50 ) + { + origin += ( obj_target.origin[ 0 ], obj_target.origin[ 1 ], self.origin[ 2 ] ); + } + else if ( rand < 85 ) + { + origin += self.origin + AnglesToForward( ( 0, self.angles[ 1 ] - 180, 0 ) ) * 1024; + } + else + { + origin += self.origin + AnglesToForward( ( 0, RandomInt( 360 ), 0 ) ) * 1024; + } + + self SetScriptAimPos( origin ); + wait 2; + self ClearScriptAimPos(); +} + +/* + Bots will do stuff while waiting for objective +*/ +bot_do_random_action_for_objective( obj_target ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_do_random_action_for_objective" ); + self endon( "bot_do_random_action_for_objective" ); + + if ( !isDefined( self.bot_random_obj_action ) ) + { + self.bot_random_obj_action = true; + + if ( randomInt( 100 ) < 80 ) + { + self thread BotUseRandomEquipment(); + } + + if ( randomInt( 100 ) < 75 ) + { + self thread BotLookAtRandomThing( obj_target ); + } + } + else + { + if ( self GetStance() != "prone" && randomInt( 100 ) < 15 ) + { + self BotSetStance( "prone" ); + } + else if ( randomInt( 100 ) < 5 ) + { + self thread BotLookAtRandomThing( obj_target ); + } + } + + wait 2; + self.bot_random_obj_action = undefined; +} + +/* + Bots hang around the enemy's flag to spawn kill em +*/ +bot_dom_spawn_kill_think_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); + + if ( myFlagCount == level.flags.size ) + { + return; + } + + otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); + + if ( myFlagCount <= otherFlagCount || otherFlagCount != 1 ) + { + return; + } + + flag = undefined; + + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + { + continue; + } + + flag = level.flags[ i ]; + } + + if ( !isDefined( flag ) ) + { + return; + } + + if ( DistanceSquared( self.origin, flag.origin ) < 2048 * 2048 ) + { + return; + } + + self BotNotifyBotEvent( "dom", "start", "spawnkill", flag ); + + self SetScriptGoal( flag.origin, 1024 ); + + self thread bot_dom_watch_flags( myFlagCount, myTeam ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "dom", "stop", "spawnkill", flag ); +} + +/* + Bots hang around the enemy's flag to spawn kill em +*/ +bot_dom_spawn_kill_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 10, 20 ) ); + + if ( randomint( 100 ) < 20 ) + { + continue; + } + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + continue; + } + + self bot_dom_spawn_kill_think_loop(); + } +} + +/* + Calls 'bad_path' when the flag count changes +*/ +bot_dom_watch_flags( count, myTeam ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( maps\mp\gametypes\dom::getTeamFlagCount( myTeam ) != count ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots watches their own flags and protects them when they are under capture +*/ +bot_dom_def_think_loop() +{ + myTeam = self.pers[ "team" ]; + flag = undefined; + + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() != myTeam ) + { + continue; + } + + if ( !level.flags[ i ].useobj.objpoints[ myTeam ].isflashing ) + { + continue; + } + + if ( !isDefined( flag ) || DistanceSquared( self.origin, level.flags[ i ].origin ) < DistanceSquared( self.origin, flag.origin ) ) + { + flag = level.flags[ i ]; + } + } + + if ( !isDefined( flag ) ) + { + return; + } + + self BotNotifyBotEvent( "dom", "start", "defend", flag ); + + self SetScriptGoal( flag.origin, 128 ); + + self thread bot_dom_watch_for_flashing( flag, myTeam ); + self thread bots_watch_touch_obj( flag ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "dom", "stop", "defend", flag ); +} + +/* + Bots watches their own flags and protects them when they are under capture +*/ +bot_dom_def_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( randomint( 100 ) < 35 ) + { + continue; + } + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + continue; + } + + self bot_dom_def_think_loop(); + } +} + +/* + Watches while the flag is under capture +*/ +bot_dom_watch_for_flashing( flag, myTeam ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( flag ) ) + { + break; + } + + if ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam || !flag.useobj.objpoints[ myTeam ].isflashing ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots capture dom flags +*/ +bot_dom_cap_think_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); + + if ( myFlagCount == level.flags.size ) + { + return; + } + + otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); + + if ( game[ "teamScores" ][ myteam ] >= game[ "teamScores" ][ otherTeam ] ) + { + if ( myFlagCount < otherFlagCount ) + { + if ( randomint( 100 ) < 15 ) + { + return; + } + } + else if ( myFlagCount == otherFlagCount ) + { + if ( randomint( 100 ) < 35 ) + { + return; + } + } + else if ( myFlagCount > otherFlagCount ) + { + if ( randomint( 100 ) < 95 ) + { + return; + } + } + } + + flag = undefined; + flags = []; + + for ( i = 0; i < level.flags.size; i++ ) + { + if ( level.flags[ i ] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + { + continue; + } + + flags[ flags.size ] = level.flags[ i ]; + } + + if ( randomInt( 100 ) > 30 ) + { + for ( i = 0; i < flags.size; i++ ) + { + if ( !isDefined( flag ) || DistanceSquared( self.origin, level.flags[ i ].origin ) < DistanceSquared( self.origin, flag.origin ) ) + { + flag = level.flags[ i ]; + } + } + } + else if ( flags.size ) + { + flag = random( flags ); + } + + if ( !isDefined( flag ) ) + { + return; + } + + self BotNotifyBotEvent( "dom", "go", "cap", flag ); + + self.bot_lock_goal = true; + self SetScriptGoal( flag.origin, 64 ); + + self thread bot_dom_go_cap_flag( flag, myteam ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "dom", "start", "cap", flag ); + + self SetScriptGoal( self.origin, 64 ); + + while ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam && self isTouching( flag ) ) + { + cur = flag.useobj.curprogress; + wait 0.5; + + if ( flag.useobj.curprogress == cur ) + { + break; // some enemy is near us, kill him + } + + self thread bot_do_random_action_for_objective( flag ); + } + + self BotNotifyBotEvent( "dom", "stop", "cap", flag ); + + self ClearScriptGoal(); + + self.bot_lock_goal = false; +} + +/* + Bots capture dom flags +*/ +bot_dom_cap_think() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "dom" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 12 ) ); + + if ( self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.flags ) || level.flags.size == 0 ) + { + continue; + } + + self bot_dom_cap_think_loop(); + } +} + +/* + Bot goes to the flag, watching while they don't have the flag +*/ +bot_dom_go_cap_flag( flag, myteam ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait randomintrange( 2, 4 ); + + if ( !isDefined( flag ) ) + { + break; + } + + if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + { + break; + } + + if ( self isTouching( flag ) ) + { + break; + } + } + + if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Bots play headquarters +*/ +bot_hq_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + radio = level.radio; + gameobj = radio.gameobject; + origin = ( radio.origin[ 0 ], radio.origin[ 1 ], radio.origin[ 2 ] + 5 ); + + // if neut or enemy + if ( gameobj.ownerteam != myTeam ) + { + if ( gameobj.interactteam == "none" ) // wait for it to become active + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // capture it + + self BotNotifyBotEvent( "hq", "go", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_hq_go_cap( gameobj, radio ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" ) + { + self.bot_lock_goal = false; + return; + } + + if ( !self isTouching( gameobj.trigger ) || level.radio != radio ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "hq", "start", "cap" ); + + self SetScriptGoal( self.origin, 64 ); + + while ( self isTouching( gameobj.trigger ) && gameobj.ownerteam != myTeam && level.radio == radio ) + { + cur = gameobj.curprogress; + wait 0.5; + + if ( cur == gameobj.curprogress ) + { + break; // no prog made, enemy must be capping + } + + self thread bot_do_random_action_for_objective( gameobj.trigger ); + } + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "hq", "stop", "cap" ); + } + else // we own it + { + if ( gameobj.objpoints[ myteam ].isflashing ) // underattack + { + self BotNotifyBotEvent( "hq", "start", "defend" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_hq_watch_flashing( gameobj, radio ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "hq", "stop", "defend" ); + return; + } + + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } +} + +/* + Bots play headquarters +*/ +bot_hq() +{ + self endon( "death" ); + self endon( "disconnect" ); + + if ( level.gametype != "koth" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.radio ) ) + { + continue; + } + + if ( !isDefined( level.radio.gameobject ) ) + { + continue; + } + + self bot_hq_loop(); + } +} + +/* + Waits until not touching the trigger and it is the current radio. +*/ +bot_hq_go_cap( obj, radio ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait randomintrange( 2, 4 ); + + if ( !isDefined( obj ) ) + { + break; + } + + if ( self isTouching( obj.trigger ) ) + { + break; + } + + if ( level.radio != radio ) + { + break; + } + } + + if ( level.radio != radio ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Waits while the radio is under attack. +*/ +bot_hq_watch_flashing( obj, radio ) +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + myteam = self.team; + + for ( ;; ) + { + wait 0.5; + + if ( !isDefined( obj ) ) + { + break; + } + + if ( !obj.objpoints[ myteam ].isflashing ) + { + break; + } + + if ( level.radio != radio ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots play sab +*/ +bot_sab_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bomb = level.sabbomb; + bombteam = bomb.ownerteam; + carrier = bomb.carrier; + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; + + // the bomb is ours, we are on the offence + if ( bombteam == myTeam ) + { + site = level.bombzones[ otherTeam ]; + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + // protect our planted bomb + if ( level.bombplanted ) + { + // kill defuser + if ( site isInUse() ) // somebody is defusing our bomb we planted + { + self BotNotifyBotEvent( "sab", "start", "defuser" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sab", "stop", "defuser" ); + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // we are not the carrier + if ( !self isBombCarrier() ) + { + // lets escort the bomb carrier + if ( self HasScriptGoal() ) + { + return; + } + + origin = carrier.origin; + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj( bomb, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // we are the carrier of the bomb, lets check if we need to plant + timepassed = getTimePassed() / 1000; + + if ( timepassed < 120 && timeleft >= 90 && randomInt( 100 ) < 98 ) + { + return; + } + + self BotNotifyBotEvent( "sab", "go", "plant" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + + self thread bot_go_plant( site ); + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || level.bombplanted || !self isTouching( site.trigger ) || site IsInUse() || self inLastStand() || self HasThreat() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "sab", "start", "plant" ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( site.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sab", "stop", "plant" ); + } + else if ( bombteam == otherTeam ) // the bomb is theirs, we are on the defense + { + site = level.bombzones[ myteam ]; + + if ( !isDefined( site.bots ) ) + { + site.bots = 0; + } + + // protect our site from planters + if ( !level.bombplanted ) + { + // kill bomb carrier + if ( site.bots > 2 || randomInt( 100 ) < 45 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( carrier _hasPerk( "specialty_coldblooded" ) ) + { + return; + } + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj( bomb, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // protect bomb site + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + self thread bot_inc_bots( site ); + + if ( site isInUse() ) // somebody is planting + { + self BotNotifyBotEvent( "sab", "start", "planter" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_inc_bots( site ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sab", "stop", "planter" ); + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + wait 4; + self notify( "bot_inc_bots" ); + site.bots--; + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + self thread bot_inc_bots( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // bomb is planted we need to defuse + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + // someone else is defusing, lets just hang around + if ( site.bots > 1 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_go_defuse( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // lets go defuse + self BotNotifyBotEvent( "sab", "go", "defuse" ); + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots( site ); + self thread bot_go_defuse( site ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || !level.bombplanted || site IsInUse() || !self isTouching( site.trigger ) || self InLastStand() || self HasThreat() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "sab", "start", "defuse" ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( site.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sab", "stop", "defuse" ); + } + else // we need to go get the bomb! + { + origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); + + self BotNotifyBotEvent( "sab", "start", "bomb" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_get_obj( bomb ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sab", "stop", "bomb" ); + return; + } +} + +/* + Bots play sab +*/ +bot_sab() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "sab" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.sabbomb ) ) + { + continue; + } + + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + continue; + } + + if ( self IsPlanting() || self isDefusing() ) + { + continue; + } + + self bot_sab_loop(); + } +} + +/* + Bots play sd defenders +*/ +bot_sd_defenders_loop( data ) +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + // bomb not planted, lets protect our sites + if ( !level.bombplanted ) + { + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; + + if ( timeleft >= 90 ) + { + return; + } + + // check for a bomb carrier, and camp the bomb + if ( !level.multibomb && isDefined( level.sdbomb ) ) + { + bomb = level.sdbomb; + carrier = level.sdbomb.carrier; + + if ( !isDefined( carrier ) ) + { + origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); + + // hang around the bomb + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + + self thread bot_get_obj( bomb ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + } + + // pick a site to protect + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + return; + } + + sites = []; + + for ( i = 0; i < level.bombzones.size; i++ ) + { + sites[ sites.size ] = level.bombzones[ i ]; + } + + if ( !sites.size ) + { + return; + } + + if ( data.rand > 50 ) + { + site = self bot_array_nearest_curorigin( sites ); + } + else + { + site = random( sites ); + } + + if ( !isDefined( site ) ) + { + return; + } + + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + if ( site isInUse() ) // somebody is planting + { + self BotNotifyBotEvent( "sd", "start", "planter", site ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "planter", site ); + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // bomb is planted, we need to defuse + if ( !isDefined( level.defuseobject ) ) + { + return; + } + + defuse = level.defuseobject; + + if ( !isDefined( defuse.bots ) ) + { + defuse.bots = 0; + } + + origin = ( defuse.curorigin[ 0 ], defuse.curorigin[ 1 ], defuse.curorigin[ 2 ] + 5 ); + + // someone is going to go defuse ,lets just hang around + if ( defuse.bots > 1 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_go_defuse( defuse ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // lets defuse + self BotNotifyBotEvent( "sd", "go", "defuse" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots( defuse ); + self thread bot_go_defuse( defuse ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || !level.bombplanted || defuse isInUse() || !self isTouching( defuse.trigger ) || self InLastStand() || self HasThreat() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "sd", "start", "defuse" ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( defuse.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "defuse" ); +} + +/* + Bots play sd defenders +*/ +bot_sd_defenders() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "sd" ) + { + return; + } + + if ( self.team == game[ "attackers" ] ) + { + return; + } + + data = spawnStruct(); + data.rand = self BotGetRandom(); + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( self IsPlanting() || self isDefusing() ) + { + continue; + } + + self bot_sd_defenders_loop( data ); + } +} + +/* + Bots play sd attackers +*/ +bot_sd_attackers_loop( data ) +{ + if ( data.first ) + { + data.first = false; + } + else + { + wait( randomintrange( 3, 5 ) ); + } + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + return; + } + + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + // bomb planted + if ( level.bombplanted ) + { + if ( !isDefined( level.defuseobject ) ) + { + return; + } + + site = level.defuseobject; + + origin = ( site.curorigin[ 0 ], site.curorigin[ 1 ], site.curorigin[ 2 ] + 5 ); + + if ( site IsInUse() ) // somebody is defusing + { + self BotNotifyBotEvent( "sd", "start", "defuser" ); + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "defuser" ); + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; + timepassed = getTimePassed() / 1000; + + // dont have a bomb + if ( !self IsBombCarrier() && !level.multibomb ) + { + if ( !isDefined( level.sdbomb ) ) + { + return; + } + + bomb = level.sdbomb; + carrier = level.sdbomb.carrier; + + // bomb is picked up + if ( isDefined( carrier ) ) + { + // escort the bomb carrier + if ( self HasScriptGoal() ) + { + return; + } + + origin = carrier.origin; + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj( bomb, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + if ( !isDefined( bomb.bots ) ) + { + bomb.bots = 0; + } + + origin = ( bomb.curorigin[ 0 ], bomb.curorigin[ 1 ], bomb.curorigin[ 2 ] + 5 ); + + // hang around the bomb if other is going to go get it + if ( bomb.bots > 1 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + + self thread bot_get_obj( bomb ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // go get the bomb + self BotNotifyBotEvent( "sd", "start", "bomb" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bot_inc_bots( bomb ); + self thread bot_get_obj( bomb ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "bomb" ); + return; + } + + // check if to plant + if ( timepassed < 120 && timeleft >= 90 && randomInt( 100 ) < 98 ) + { + return; + } + + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + return; + } + + sites = []; + + for ( i = 0; i < level.bombzones.size; i++ ) + { + sites[ sites.size ] = level.bombzones[ i ]; + } + + if ( !sites.size ) + { + return; + } + + if ( data.rand > 50 ) + { + plant = self bot_array_nearest_curorigin( sites ); + } + else + { + plant = random( sites ); + } + + if ( !isDefined( plant ) ) + { + return; + } + + origin = ( plant.curorigin[ 0 ] + 50, plant.curorigin[ 1 ] + 50, plant.curorigin[ 2 ] + 5 ); + + self BotNotifyBotEvent( "sd", "go", "plant", plant ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 1 ); + self thread bot_go_plant( plant ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || level.bombplanted || plant.visibleteam == "none" || !self isTouching( plant.trigger ) || self InLastStand() || self HasThreat() || plant IsInUse() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "sd", "start", "plant", plant ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( plant.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "plant", plant ); +} + +/* + Bots play sd attackers +*/ +bot_sd_attackers() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "sd" ) + { + return; + } + + if ( self.team != game[ "attackers" ] ) + { + return; + } + + data = spawnStruct(); + data.rand = self BotGetRandom(); + data.first = true; + + for ( ;; ) + { + self bot_sd_attackers_loop( data ); + } +} + +/* + Bots play capture the flag +*/ +bot_cap_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + myflag = level.teamflags[ myteam ]; + myzone = level.capzones[ myteam ]; + + theirflag = level.teamflags[ otherTeam ]; + theirzone = level.capzones[ otherTeam ]; + + if ( !myflag maps\mp\gametypes\_gameobjects::isHome() ) + { + carrier = myflag.carrier; + + if ( !isDefined( carrier ) ) // someone doesnt has our flag + { + if ( !isDefined( theirflag.carrier ) && DistanceSquared( self.origin, theirflag.curorigin ) < DistanceSquared( self.origin, myflag.curorigin ) ) // no one has their flag and its closer + { + self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); + + self bot_cap_get_flag( theirflag ); + + self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); + } + else // go get it + { + self BotNotifyBotEvent( "cap", "start", "my_flag", myflag ); + + self bot_cap_get_flag( myflag ); + + self BotNotifyBotEvent( "cap", "stop", "my_flag", myflag ); + } + + return; + } + else + { + if ( theirflag maps\mp\gametypes\_gameobjects::isHome() && randomint( 100 ) < 50 ) + { + // take their flag + self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); + + self bot_cap_get_flag( theirflag ); + + self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); + } + else + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( !isDefined( theirzone.bots ) ) + { + theirzone.bots = 0; + } + + origin = theirzone.curorigin; + + if ( theirzone.bots > 2 || randomInt( 100 ) < 45 ) + { + // kill carrier + if ( carrier _hasPerk( "specialty_coldblooded" ) ) + { + return; + } + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj( myflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + self thread bot_inc_bots( theirzone ); + + // camp their zone + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + wait 4; + self notify( "bot_inc_bots" ); + theirzone.bots--; + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_inc_bots( theirzone ); + self thread bot_escort_obj( myflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + } + } + else // our flag is ok + { + if ( self isFlagCarrier() ) // if have flag + { + // go cap + origin = myzone.curorigin; + + self BotNotifyBotEvent( "cap", "start", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 32 ); + + self thread bot_get_obj( myflag ); + evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + wait 1; + + if ( evt != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "cap", "stop", "cap" ); + return; + } + + carrier = theirflag.carrier; + + if ( !isDefined( carrier ) ) // if no one has enemy flag + { + self BotNotifyBotEvent( "cap", "start", "their_flag", theirflag ); + + self bot_cap_get_flag( theirflag ); + + self BotNotifyBotEvent( "cap", "stop", "their_flag", theirflag ); + return; + } + + // escort them + + if ( self HasScriptGoal() ) + { + return; + } + + origin = carrier.origin; + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj( theirflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } +} + +/* + Bots play capture the flag +*/ +bot_cap() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "ctf" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.capzones ) ) + { + continue; + } + + if ( !isDefined( level.teamflags ) ) + { + continue; + } + + self bot_cap_loop(); + } +} + +/* + Gets the carriers ent num +*/ +getCarrierEntNum() +{ + carrierNum = -1; + + if ( isDefined( self.carrier ) ) + { + carrierNum = self.carrier getEntityNumber(); + } + + return carrierNum; +} + +/* + Bots go and get the flag +*/ +bot_cap_get_flag( flag ) +{ + origin = flag.curorigin; + + // go get it + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 32 ); + + self thread bot_get_obj( flag ); + + evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( evt != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( evt != "goal" ) + { + self.bot_lock_goal = false; + return; + } + + self SetScriptGoal( self.origin, 64 ); + curCarrier = flag getCarrierEntNum(); + + while ( curCarrier == flag getCarrierEntNum() && self isTouching( flag.trigger ) ) + { + cur = flag.curprogress; + wait 0.5; + + if ( flag.curprogress == cur ) + { + break; // some enemy is near us, kill him + } + } + + self ClearScriptGoal(); + + self.bot_lock_goal = false; +} + +/* + Bots go plant the demo bomb +*/ +bot_dem_go_plant( plant ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( ( plant.label == "_b" && level.bombbplanted ) || ( plant.label == "_a" && level.bombaplanted ) ) + { + break; + } + + if ( self isTouching( plant.trigger ) ) + { + break; + } + } + + if ( ( plant.label == "_b" && level.bombbplanted ) || ( plant.label == "_a" && level.bombaplanted ) ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Bots spawn kill dom attackers +*/ +bot_dem_attack_spawnkill() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + l1 = level.bombaplanted; + l2 = level.bombbplanted; + + for ( ;; ) + { + wait 0.5; + + if ( l1 != level.bombaplanted || l2 != level.bombbplanted ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots play demo attackers +*/ +bot_dem_attackers_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bombs = []; // sites with bombs + sites = []; // sites to bomb at + bombed = 0; // exploded sites + + for ( i = 0; i < level.bombzones.size; i++ ) + { + bomb = level.bombzones[ i ]; + + if ( isDefined( bomb.bombexploded ) && bomb.bombexploded ) + { + bombed++; + continue; + } + + if ( bomb.label == "_a" ) + { + if ( level.bombaplanted ) + { + bombs[ bombs.size ] = bomb; + } + else + { + sites[ sites.size ] = bomb; + } + + continue; + } + + if ( bomb.label == "_b" ) + { + if ( level.bombbplanted ) + { + bombs[ bombs.size ] = bomb; + } + else + { + sites[ sites.size ] = bomb; + } + + continue; + } + } + + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; + + shouldLet = ( game[ "teamScores" ][ myteam ] > game[ "teamScores" ][ otherTeam ] && timeleft < 90 && bombed == 1 ); + + // spawnkill conditions + // if we have bombed one site or 1 bomb is planted with lots of time left, spawn kill + // if we want the other team to win for overtime and they do not need to defuse, spawn kill + if ( ( ( bombed + bombs.size == 1 && timeleft >= 90 ) || ( shouldLet && !bombs.size ) ) && randomInt( 100 ) < 95 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); + + if ( !spawnPoints.size ) + { + return; + } + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 2048 * 2048 ) + { + return; + } + + self SetScriptGoal( spawnpoint.origin, 1024 ); + + self thread bot_dem_attack_spawnkill(); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // let defuse conditions + // if enemy is going to lose and lots of time left, let them defuse to play longer + // or if want to go into overtime near end of the extended game + if ( ( ( bombs.size + bombed == 2 && timeleft >= 90 ) || ( shouldLet && bombs.size ) ) && randomInt( 100 ) < 95 ) + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); + + if ( !spawnPoints.size ) + { + return; + } + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( spawnpoint.origin, 512 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // defend bomb conditions + // if time is running out and we have a bomb planted + if ( bombs.size && timeleft < 90 && ( !sites.size || randomInt( 100 ) < 95 ) ) + { + site = self bot_array_nearest_curorigin( bombs ); + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + if ( site IsInUse() ) // somebody is defusing + { + self BotNotifyBotEvent( "dem", "start", "defuser", site ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "dem", "stop", "defuser", site ); + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // else go plant + if ( !sites.size ) + { + return; + } + + plant = self bot_array_nearest_curorigin( sites ); + + if ( !isDefined( plant ) ) + { + return; + } + + if ( !isDefined( plant.bots ) ) + { + plant.bots = 0; + } + + origin = ( plant.curorigin[ 0 ] + 50, plant.curorigin[ 1 ] + 50, plant.curorigin[ 2 ] + 5 ); + + // hang around the site if lots of time left + if ( plant.bots > 1 && timeleft >= 60 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_dem_go_plant( plant ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + self BotNotifyBotEvent( "dem", "go", "plant", plant ); + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots( plant ); + self thread bot_dem_go_plant( plant ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || ( plant.label == "_b" && level.bombbplanted ) || ( plant.label == "_a" && level.bombaplanted ) || plant IsInUse() || !self isTouching( plant.trigger ) || self InLastStand() || self HasThreat() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "dem", "start", "plant", plant ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( plant.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "dem", "stop", "plant", plant ); +} + +/* + Bots play demo attackers +*/ +bot_dem_attackers() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "dd" ) + { + return; + } + + if ( self.team != game[ "attackers" ] ) + { + return; + } + + if ( inOvertime() ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + continue; + } + + self bot_dem_attackers_loop(); + } +} + +/* + Bots play demo defenders +*/ +bot_dem_defenders_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + bombs = []; // sites with bombs + sites = []; // sites to bomb at + bombed = 0; // exploded sites + + for ( i = 0; i < level.bombzones.size; i++ ) + { + bomb = level.bombzones[ i ]; + + if ( isDefined( bomb.bombexploded ) && bomb.bombexploded ) + { + bombed++; + continue; + } + + if ( bomb.label == "_a" ) + { + if ( level.bombaplanted ) + { + bombs[ bombs.size ] = bomb; + } + else + { + sites[ sites.size ] = bomb; + } + + continue; + } + + if ( bomb.label == "_b" ) + { + if ( level.bombbplanted ) + { + bombs[ bombs.size ] = bomb; + } + else + { + sites[ sites.size ] = bomb; + } + + continue; + } + } + + timeleft = maps\mp\gametypes\_gamelogic::getTimeRemaining() / 1000; + + shouldLet = ( timeleft < 60 && ( ( bombed == 0 && bombs.size != 2 ) || ( game[ "teamScores" ][ myteam ] > game[ "teamScores" ][ otherTeam ] && bombed == 1 ) ) && randomInt( 100 ) < 98 ); + + // spawnkill conditions + // if nothing to defuse with a lot of time left, spawn kill + // or letting a bomb site to explode but a bomb is planted, so spawnkill + if ( ( !bombs.size && timeleft >= 60 && randomInt( 100 ) < 95 ) || ( shouldLet && bombs.size == 1 ) ) + { + if ( self HasScriptGoal() ) + { + return; + } + + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_attacker_start" ); + + if ( !spawnPoints.size ) + { + return; + } + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 2048 * 2048 ) + { + return; + } + + self SetScriptGoal( spawnpoint.origin, 1024 ); + + self thread bot_dem_defend_spawnkill(); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + // let blow up conditions + // let enemy blow up at least one to extend play time + // or if want to go into overtime after extended game + if ( shouldLet ) + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_dd_spawn_defender_start" ); + + if ( !spawnPoints.size ) + { + return; + } + + spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + + if ( DistanceSquared( spawnpoint.origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( spawnpoint.origin, 512 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // defend conditions + // if no bombs planted with little time left + if ( !bombs.size && timeleft < 60 && randomInt( 100 ) < 95 && sites.size ) + { + site = self bot_array_nearest_curorigin( sites ); + origin = ( site.curorigin[ 0 ] + 50, site.curorigin[ 1 ] + 50, site.curorigin[ 2 ] + 5 ); + + if ( site IsInUse() ) // somebody is planting + { + self BotNotifyBotEvent( "dem", "start", "planter", site ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + + self thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "dem", "stop", "planter", site ); + return; + } + + // else hang around the site + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // else go defuse + + if ( !bombs.size ) + { + return; + } + + defuse = self bot_array_nearest_curorigin( bombs ); + + if ( !isDefined( defuse ) ) + { + return; + } + + if ( !isDefined( defuse.bots ) ) + { + defuse.bots = 0; + } + + origin = ( defuse.curorigin[ 0 ] + 50, defuse.curorigin[ 1 ] + 50, defuse.curorigin[ 2 ] + 5 ); + + // hang around the site if not in danger of losing + if ( defuse.bots > 1 && bombed + bombs.size != 2 ) + { + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + + self thread bot_dem_go_defuse( defuse ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + self BotNotifyBotEvent( "dem", "go", "defuse", defuse ); + + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 1 ); + self thread bot_inc_bots( defuse ); + self thread bot_dem_go_defuse( defuse ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || ( defuse.label == "_b" && !level.bombbplanted ) || ( defuse.label == "_a" && !level.bombaplanted ) || defuse IsInUse() || !self isTouching( defuse.trigger ) || self InLastStand() || self HasThreat() ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "dem", "start", "defuse", defuse ); + + self BotRandomStance(); + self SetScriptGoal( self.origin, 64 ); + self bot_wait_stop_move(); + + waitTime = ( defuse.usetime / 1000 ) + 2.5; + self thread BotPressUse( waitTime ); + wait waitTime; + + self ClearScriptGoal(); + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "dem", "stop", "defuse", defuse ); +} + +/* + Bots play demo defenders +*/ +bot_dem_defenders() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "dd" ) + { + return; + } + + if ( self.team == game[ "attackers" ] ) + { + return; + } + + if ( inOvertime() ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + continue; + } + + self bot_dem_defenders_loop(); + } +} + +/* + Bots play demo overtime +*/ +bot_dem_overtime() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "dd" ) + { + return; + } + + if ( !inOvertime() ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.bombzones ) || !level.bombzones.size ) + { + continue; + } + + if ( !level.bombzones[ 0 ].bombplanted || !level.bombzones[ 0 ] maps\mp\gametypes\_gameobjects::isFriendlyTeam( self.team ) ) + { + self bot_dem_attackers_loop(); + continue; + } + + self bot_dem_defenders_loop(); + } +} + +/* + Bots go defuse +*/ +bot_dem_go_defuse( defuse ) +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( self isTouching( defuse.trigger ) ) + { + break; + } + + if ( ( defuse.label == "_b" && !level.bombbplanted ) || ( defuse.label == "_a" && !level.bombaplanted ) ) + { + break; + } + } + + if ( ( defuse.label == "_b" && !level.bombbplanted ) || ( defuse.label == "_a" && !level.bombaplanted ) ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Bots go spawn kill +*/ +bot_dem_defend_spawnkill() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + for ( ;; ) + { + wait 0.5; + + if ( level.bombbplanted || level.bombaplanted ) + { + break; + } + } + + self notify( "bad_path" ); +} + +/* + Bots think to revive +*/ +bot_think_revive_loop() +{ + needsRevives = []; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( player.team != self.team ) + { + continue; + } + + if ( distanceSquared( self.origin, player.origin ) >= 2048 * 2048 ) + { + continue; + } + + if ( player inLastStand() ) + { + needsRevives[ needsRevives.size ] = player; + } + } + + if ( !needsRevives.size ) + { + return; + } + + revive = random( needsRevives ); + + self BotNotifyBotEvent( "revive", "go", revive ); + self.bot_lock_goal = true; + + self SetScriptGoal( revive.origin, 64 ); + self thread stop_go_target_on_death( revive ); + + ret = self waittill_any_return( "new_goal", "goal", "bad_path" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + if ( ret != "goal" || !isDefined( revive ) || distanceSquared( self.origin, revive.origin ) >= 100 * 100 || !revive inLastStand() || revive isBeingRevived() || !isAlive( revive ) ) + { + return; + } + + self BotNotifyBotEvent( "revive", "start", revive ); + + self BotFreezeControls( true ); + self bot_wait_stop_move(); + + waitTime = 3.25; + self thread BotPressUse( waitTime ); + wait waitTime; + + self BotFreezeControls( false ); + + self BotNotifyBotEvent( "revive", "stop", revive ); +} + +/* + Bots think to revive +*/ +bot_think_revive() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( !level.diehardmode || !level.teambased ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( self HasScriptGoal() || self.bot_lock_goal ) + { + continue; + } + + if ( self isDefusing() || self isPlanting() ) + { + continue; + } + + if ( self IsUsingRemote() || self BotIsFrozen() ) + { + continue; + } + + if ( self inLastStand() ) + { + continue; + } + + self bot_think_revive_loop(); + } +} + +/* + Bots play the Global thermonuclear warfare +*/ +bot_gtnw_loop() +{ + myteam = self.team; + theirteam = getOtherTeam( myteam ); + origin = level.nukesite.trigger.origin; + trigger = level.nukesite.trigger; + + ourCapCount = level.nukesite.touchlist[ myteam ]; + theirCapCount = level.nukesite.touchlist[ theirteam ]; + rand = self BotGetRandom(); + + if ( ( !ourCapCount && !theirCapCount ) || rand <= 20 ) + { + // go cap the obj + self BotNotifyBotEvent( "gtnw", "go", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 64 ); + self thread bots_watch_touch_obj( trigger ); + + ret = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( ret != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( ret != "goal" || !self isTouching( trigger ) ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "gtnw", "start", "cap" ); + + self SetScriptGoal( self.origin, 64 ); + + while ( self isTouching( trigger ) ) + { + cur = level.nukesite.curprogress; + wait 0.5; + + if ( cur == level.nukesite.curprogress ) + { + break; // no prog made, enemy must be capping + } + + self thread bot_do_random_action_for_objective( trigger ); + } + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "gtnw", "stop", "cap" ); + return; + } + + if ( theirCapCount ) + { + // kill capturtour + self.bot_lock_goal = true; + + self SetScriptGoal( origin, 64 ); + self thread bots_watch_touch_obj( trigger ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + return; + } + + // else hang around the site + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; +} + +/* + Bots play the Global thermonuclear warfare +*/ +bot_gtnw() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "gtnw" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.nukesite ) || !isDefined( level.nukesite.trigger ) ) + { + continue; + } + + self bot_gtnw_loop(); + } +} + +/* + Bots play oneflag +*/ +bot_oneflag_loop() +{ + myTeam = self.pers[ "team" ]; + otherTeam = getOtherTeam( myTeam ); + + if ( myteam == game[ "attackers" ] ) + { + myzone = level.capzones[ myteam ]; + theirflag = level.teamflags[ otherTeam ]; + + if ( self isFlagCarrier() ) + { + // go cap + origin = myzone.curorigin; + + self BotNotifyBotEvent( "oneflag", "start", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( origin, 32 ); + + evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + wait 1; + + if ( evt != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "oneflag", "stop", "cap" ); + return; + } + + carrier = theirflag.carrier; + + if ( !isDefined( carrier ) ) // if no one has enemy flag + { + self BotNotifyBotEvent( "oneflag", "start", "their_flag" ); + self bot_cap_get_flag( theirflag ); + self BotNotifyBotEvent( "oneflag", "stop", "their_flag" ); + return; + } + + // escort them + + if ( self HasScriptGoal() ) + { + return; + } + + origin = carrier.origin; + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_escort_obj( theirflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + else + { + myflag = level.teamflags[ myteam ]; + theirzone = level.capzones[ otherTeam ]; + + if ( !myflag maps\mp\gametypes\_gameobjects::isHome() ) + { + carrier = myflag.carrier; + + if ( !isDefined( carrier ) ) // someone doesnt has our flag + { + self BotNotifyBotEvent( "oneflag", "start", "my_flag" ); + self bot_cap_get_flag( myflag ); + self BotNotifyBotEvent( "oneflag", "stop", "my_flag" ); + return; + } + + if ( self HasScriptGoal() ) + { + return; + } + + if ( !isDefined( theirzone.bots ) ) + { + theirzone.bots = 0; + } + + origin = theirzone.curorigin; + + if ( theirzone.bots > 2 || randomInt( 100 ) < 45 ) + { + // kill carrier + if ( carrier _hasPerk( "specialty_coldblooded" ) ) + { + return; + } + + origin = carrier.origin; + + self SetScriptGoal( origin, 64 ); + self thread bot_escort_obj( myflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + return; + } + + self thread bot_inc_bots( theirzone ); + + // camp their zone + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + wait 4; + self notify( "bot_inc_bots" ); + theirzone.bots--; + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_inc_bots( theirzone ); + self thread bot_escort_obj( myflag, carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + else + { + // is home, lets hang around and protect + if ( self HasScriptGoal() ) + { + return; + } + + origin = myflag.curorigin; + + if ( DistanceSquared( origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( origin, 256 ); + self thread bot_get_obj( myflag ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + } +} + +/* + Bots play oneflag +*/ +bot_oneflag() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "oneflag" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.capzones ) || !isDefined( level.teamflags ) ) + { + continue; + } + + self bot_oneflag_loop(); + } +} + +/* + Bots play arena +*/ +bot_arena_loop() +{ + flag = level.arenaflag; + myTeam = self.team; + + self BotNotifyBotEvent( "arena", "go", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( flag.trigger.origin, 64 ); + + event = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + if ( event != "new_goal" ) + { + self ClearScriptGoal(); + } + + if ( event != "goal" || !self isTouching( flag.trigger ) ) + { + self.bot_lock_goal = false; + return; + } + + self BotNotifyBotEvent( "arena", "start", "cap" ); + + self SetScriptGoal( self.origin, 64 ); + + while ( self isTouching( flag.trigger ) && flag.ownerteam != myTeam ) + { + cur = flag.curprogress; + wait 0.5; + + if ( cur == flag.curprogress ) + { + break; // no prog made, enemy must be capping + } + + self thread bot_do_random_action_for_objective( flag.trigger ); + } + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "arena", "stop", "cap" ); +} + +/* + Bots play arena +*/ +bot_arena() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "arena" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isDefined( level.arenaflag ) ) + { + continue; + } + + self bot_arena_loop(); + } +} + +/* + bot_vip_loop + + For those wondering why i call a function for these loops like this + its because, the variables created in this function will be free'd once the function exits, + if it was in the infinite loop, the function never exits, thus the variables are never free'd + + This isnt leaking variables, but freeing variables that will no longer be used, an optimization of sorts +*/ +bot_vip_loop() +{ + vip = undefined; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( isDefined( player.isvip ) && player.isvip ) + { + vip = player; + } + } + + if ( self.team == game[ "defenders" ] ) + { + if ( isDefined( self.isvip ) && self.isvip ) + { + if ( isDefined( level.extractionzone ) && !isDefined( level.extractiontime ) ) + { + // go to extraction zone + self BotNotifyBotEvent( "vip", "start", "cap" ); + + self.bot_lock_goal = true; + self SetScriptGoal( level.extractionzone.trigger.origin, 32 ); + + evt = self waittill_any_return( "goal", "bad_path", "new_goal" ); + + wait 1; + + if ( evt != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "vip", "stop", "cap" ); + } + } + else if ( isDefined( vip ) ) + { + // protect the vip + if ( DistanceSquared( vip.origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( vip.origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + } + else + { + if ( isDefined( level.extractionzone ) && !isDefined( level.extractiontime ) && self BotGetRandom() < 65 ) + { + // camp the extraction zone + if ( DistanceSquared( level.extractionzone.trigger.origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( level.extractionzone.trigger.origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + else if ( isDefined( vip ) ) + { + // kill the vip + self SetScriptGoal( vip.origin, 32 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + } +} + +/* + Bots play arena +*/ +bot_vip() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "vip" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 3, 5 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + self bot_vip_loop(); + } +} + +/* + Loop +*/ +bot_conf_loop() +{ + dog_tag_keys = getArrayKeys( level.dogtags ); + tags = []; + tag = undefined; + + for ( i = 0; i < dog_tag_keys.size; i++ ) + { + temp_tag = level.dogtags[ dog_tag_keys[ i ] ]; + + if ( !isDefined( temp_tag ) ) + { + continue; + } + + if ( DistanceSquared( self.origin, temp_tag.trigger.origin ) > 1024 * 1024 ) + { + continue; + } + + if ( !isDefined( temp_tag.bots ) ) + { + temp_tag.bots = 0; + } + + if ( temp_tag.bots >= 2 ) + { + continue; + } + + tags[ tags.size ] = temp_tag; + } + + if ( randomInt( 2 ) ) + { + for ( i = 0; i < tags.size; i++ ) + { + temp_tag = tags[ i ]; + + if ( !isDefined( tag ) || DistanceSquared( self.origin, temp_tag.trigger.origin ) < DistanceSquared( self.origin, tag.trigger.origin ) ) + { + tag = temp_tag; + } + } + } + else + { + tag = random( tags ); + } + + if ( !isdefined( tag ) ) + { + return; + } + + self BotNotifyBotEvent( "conf", "start", "cap", tag ); + + self.bot_lock_goal = true; + self SetScriptGoal( tag.trigger.origin, 16 ); + self thread bot_inc_bots( tag, true ); + self thread bots_watch_touch_obj( tag.trigger ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "conf", "stop", "cap", tag ); +} + +/* + Bots play conf +*/ +bot_conf() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "conf" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 2 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isdefined( level.dogtags ) ) + { + continue; + } + + self bot_conf_loop(); + } +} + +/* + Watches for grnd zone +*/ +bots_watch_grnd() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "goal" ); + self endon( "bad_path" ); + self endon( "new_goal" ); + + grnd_origin = level.grnd_zone.origin; + + for ( ;; ) + { + wait 1 + randomInt( 5 ) * 0.5; + + if ( grnd_origin != level.grnd_zone.origin ) + { + break; + } + + if ( self maps\mp\gametypes\grnd::isingrindzone() ) + { + break; + } + } + + if ( grnd_origin != level.grnd_zone.origin ) + { + self notify( "bad_path" ); + } + else + { + self notify( "goal" ); + } +} + +/* + Loop +*/ +bot_grnd_loop() +{ + if ( isDefined( self.ingrindzone ) && self.ingrindzone && isReallyAlive( self ) && self.pers[ "team" ] != "spectator" && self maps\mp\gametypes\grnd::isingrindzone() ) + { + // in the grnd zone + + if ( level.grnd_numplayers[ level.otherteam[ self.team ] ] ) + { + // hunt enemy in drop zone + target = undefined; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( isDefined( player.ingrindzone ) && player.ingrindzone && isReallyAlive( player ) && player.pers[ "team" ] != "spectator" && player maps\mp\gametypes\grnd::isingrindzone() ) + { + target = player; + + if ( cointoss() ) + { + break; + } + } + } + + if ( isDefined( target ) ) + { + self BotNotifyBotEvent( "grnd", "start", "kill", target ); + + self SetScriptGoal( target.origin, 32 ); + self thread stop_go_target_on_death( target ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "grnd", "stop", "kill", target ); + } + } + else + { + // stay in the zone + goal = self.origin; + self SetScriptGoal( goal, 64 ); + + self BotNotifyBotEvent( "grnd", "start", "cap" ); + + while ( self HasScriptGoal() && self GetScriptGoal() == goal && self maps\mp\gametypes\grnd::isingrindzone() ) + { + if ( level.grnd_numplayers[ level.otherteam[ self.team ] ] ) + { + break; + } + + wait 0.5; + + self thread bot_do_random_action_for_objective( level.grnd_zone ); + } + + if ( self HasScriptGoal() && self GetScriptGoal() == goal ) + { + self ClearScriptGoal(); + } + + self BotNotifyBotEvent( "grnd", "stop", "cap" ); + } + + return; + } + + if ( randomInt( 100 ) < 40 || level.grnd_numplayers[ self.team ] <= 0 ) + { + self BotNotifyBotEvent( "grnd", "start", "go_cap" ); + + // go to grnd zone + self.bot_lock_goal = true; + self SetScriptGoal( level.grnd_zone.origin, 32 ); + self thread bots_watch_grnd(); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "grnd", "stop", "go_cap" ); + } +} + +/* + Bots play groundzone +*/ +bot_grnd() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "grnd" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isdefined( level.grnd_zone ) ) + { + continue; + } + + self bot_grnd_loop(); + } +} + +/* + Loop +*/ +bot_tdef_loop() +{ + if ( isDefined( level.gameflag.carrier ) ) + { + if ( level.gameflag maps\mp\gametypes\_gameobjects::getOwnerTeam() == level.otherteam[ self.team ] ) + { + if ( self HasScriptGoal() ) + { + return; + } + + // go kill + self SetScriptGoal( level.gameflag.carrier.origin, 64 ); + self thread bot_escort_obj( level.gameflag, level.gameflag.carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + else if ( level.gameflag.carrier != self ) + { + // go protect + if ( self HasScriptGoal() ) + { + return; + } + + if ( DistanceSquared( level.gameflag.carrier.origin, self.origin ) <= 1024 * 1024 ) + { + return; + } + + self SetScriptGoal( level.gameflag.carrier.origin, 256 ); + self thread bot_escort_obj( level.gameflag, level.gameflag.carrier ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + else if ( self BotGetRandom() < 70 ) + { + // we haev flag, lets run away from enemies + avg_org = ( 0, 0, 0 ); + count = 0; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( !isDefined( player.team ) ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( player.team == self.team ) + { + continue; + } + + count++; + avg_org += player.origin; + } + + if ( count ) + { + avg_org /= count; + wps = []; + + for ( i = 0; i < level.waypoints.size; i++ ) + { + wp = level.waypoints[ i ]; + + if ( DistanceSquared( wp.origin, avg_org ) < 1024 * 1024 ) + { + continue; + } + + wps[ wps.size ] = wp; + } + + wp = random( wps ); + + if ( isDefined( wp ) ) + { + self.bot_lock_goal = true; + self SetScriptGoal( wp.origin, 256 ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + + self.bot_lock_goal = false; + } + } + } + + return; + } + + // go get it + self BotNotifyBotEvent( "tdef", "start", "cap" ); + + self bot_cap_get_flag( level.gameflag ); + + self BotNotifyBotEvent( "tdef", "stop", "cap" ); +} + +/* + Bots play groundzone +*/ +bot_tdef() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "tdef" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + if ( !isdefined( level.gameflag ) ) + { + continue; + } + + self bot_tdef_loop(); + } +} + +/* + Loop +*/ +bot_infect_loop() +{ + if ( self HasScriptGoal() ) + { + return; + } + + if ( self.team == "axis" ) + { + target = undefined; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[ i ]; + + if ( player == self ) + { + continue; + } + + if ( !isReallyAlive( player ) ) + { + continue; + } + + if ( level.teambased && self.team == player.team ) + { + continue; + } + + if ( !isdefined( target ) || DistanceSquared( self.origin, player.origin ) < DistanceSquared( self.origin, target.origin ) ) + { + target = player; + } + } + + if ( isDefined( target ) ) + { + self SetScriptGoal( target.origin, 32 ); + self thread stop_go_target_on_death( target ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + { + self ClearScriptGoal(); + } + } + } +} + +/* + Bots play infect +*/ +bot_infect() +{ + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + if ( level.gametype != "infect" ) + { + return; + } + + for ( ;; ) + { + wait( randomintrange( 1, 3 ) ); + + if ( self IsUsingRemote() || self.bot_lock_goal ) + { + continue; + } + + self bot_infect_loop(); + } +} diff --git a/maps/mp/bots/_bot_utility.gsc b/maps/mp/bots/_bot_utility.gsc index 877e89d..0a6d4e7 100644 --- a/maps/mp/bots/_bot_utility.gsc +++ b/maps/mp/bots/_bot_utility.gsc @@ -548,7 +548,7 @@ HasThreat() */ IsDefusing() { - return ( isDefined( self.isDefusing ) && self.isDefusing ); + return ( isDefined( self.isdefusing ) && self.isdefusing ); } /* @@ -556,7 +556,7 @@ IsDefusing() */ isPlanting() { - return ( isDefined( self.isPlanting ) && self.isPlanting ); + return ( isDefined( self.isplanting ) && self.isplanting ); } /* @@ -564,7 +564,7 @@ isPlanting() */ isBombCarrier() { - return ( isDefined( self.isBombCarrier ) && self.isBombCarrier ); + return ( isDefined( self.isbombcarrier ) && self.isbombcarrier ); } /* @@ -572,7 +572,7 @@ isBombCarrier() */ isInUse() { - return ( isDefined( self.inUse ) && self.inUse ); + return ( isDefined( self.inuse ) && self.inuse ); } /* @@ -580,7 +580,7 @@ isInUse() */ inLastStand() { - return ( isDefined( self.lastStand ) && self.lastStand ); + return ( isDefined( self.laststand ) && self.laststand ); } /* @@ -588,7 +588,7 @@ inLastStand() */ isBeingRevived() { - return ( isDefined( self.beingRevived ) && self.beingRevived ); + return ( isDefined( self.beingrevived ) && self.beingrevived ); } /* @@ -596,7 +596,7 @@ isBeingRevived() */ inFinalStand() { - return ( isDefined( self.inFinalStand ) && self.inFinalStand ); + return ( isDefined( self.infinalstand ) && self.infinalstand ); } /* @@ -604,7 +604,7 @@ inFinalStand() */ isFlagCarrier() { - return ( isDefined( self.carryFlag ) && self.carryFlag ); + return ( isDefined( self.carryflag ) && self.carryflag ); } /* @@ -612,7 +612,7 @@ isFlagCarrier() */ IsStunned() { - return ( isdefined( self.concussionEndTime ) && self.concussionEndTime > gettime() ); + return ( isdefined( self.concussionendtime ) && self.concussionendtime > gettime() ); } /* @@ -620,7 +620,7 @@ IsStunned() */ isArtShocked() { - return ( isDefined( self.beingArtilleryShellshocked ) && self.beingArtilleryShellshocked ); + return ( isDefined( self.beingartilleryshellshocked ) && self.beingartilleryshellshocked ); } /* @@ -1021,9 +1021,9 @@ RaySphereIntersect( start, end, spherePos, radius ) */ SmokeTrace( start, end, rad ) { - for ( i = level.bots_smokeList.count - 1; i >= 0; i-- ) + for ( i = level.bots_smokelist.count - 1; i >= 0; i-- ) { - nade = level.bots_smokeList.data[ i ]; + nade = level.bots_smokelist.data[ i ]; if ( nade.state != "smoking" ) { @@ -1252,10 +1252,10 @@ readWpsFromFile( mapname ) */ load_waypoints() { - level.waypointCount = 0; - level.waypointUsage = []; - level.waypointUsage[ "allies" ] = []; - level.waypointUsage[ "axis" ] = []; + level.waypointcount = 0; + level.waypointusage = []; + level.waypointusage[ "allies" ] = []; + level.waypointusage[ "axis" ] = []; if ( !isDefined( level.waypoints ) ) { @@ -1291,9 +1291,9 @@ load_waypoints() BotBuiltinPrintConsole( "No waypoints loaded!" ); } - level.waypointCount = level.waypoints.size; + level.waypointcount = level.waypoints.size; - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { if ( !isDefined( level.waypoints[ i ].children ) || !isDefined( level.waypoints[ i ].children.size ) ) { @@ -1390,7 +1390,7 @@ getWaypointsOfType( type ) { answer = []; - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { wp = level.waypoints[ i ]; @@ -2102,21 +2102,21 @@ ReverseHeapAStar( item, item2 ) */ RemoveWaypointUsage( wp, team ) { - if ( !isDefined( level.waypointUsage ) ) + if ( !isDefined( level.waypointusage ) ) { return; } - if ( !isDefined( level.waypointUsage[ team ][ wp + "" ] ) ) + if ( !isDefined( level.waypointusage[ team ][ wp + "" ] ) ) { return; } - level.waypointUsage[ team ][ wp + "" ]--; + level.waypointusage[ team ][ wp + "" ]--; - if ( level.waypointUsage[ team ][ wp + "" ] <= 0 ) + if ( level.waypointusage[ team ][ wp + "" ] <= 0 ) { - level.waypointUsage[ team ][ wp + "" ] = undefined; + level.waypointusage[ team ][ wp + "" ] = undefined; } } @@ -2128,7 +2128,7 @@ GetNearestWaypointWithSight( pos ) candidate = undefined; dist = 2147483647; - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { if ( !bulletTracePassed( pos + ( 0, 0, 15 ), level.waypoints[ i ].origin + ( 0, 0, 15 ), false, undefined ) ) { @@ -2157,7 +2157,7 @@ GetNearestWaypoint( pos ) candidate = undefined; dist = 2147483647; - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { curdis = DistanceSquared( level.waypoints[ i ].origin, pos ); @@ -2252,14 +2252,14 @@ AStarSearch( start, goal, team, greedy_path ) while ( isDefined( bestNode ) ) { - if ( isdefined( team ) && isDefined( level.waypointUsage ) ) + if ( isdefined( team ) && isDefined( level.waypointusage ) ) { - if ( !isDefined( level.waypointUsage[ team ][ bestNode.index + "" ] ) ) + if ( !isDefined( level.waypointusage[ team ][ bestNode.index + "" ] ) ) { - level.waypointUsage[ team ][ bestNode.index + "" ] = 0; + level.waypointusage[ team ][ bestNode.index + "" ] = 0; } - level.waypointUsage[ team ][ bestNode.index + "" ]++; + level.waypointusage[ team ][ bestNode.index + "" ]++; } // construct path @@ -2279,13 +2279,13 @@ AStarSearch( start, goal, team, greedy_path ) penalty = 1; - if ( !greedy_path && isdefined( team ) && isDefined( level.waypointUsage ) ) + if ( !greedy_path && isdefined( team ) && isDefined( level.waypointusage ) ) { temppen = 1; - if ( isDefined( level.waypointUsage[ team ][ child + "" ] ) ) + if ( isDefined( level.waypointusage[ team ][ child + "" ] ) ) { - temppen = level.waypointUsage[ team ][ child + "" ]; // consider how many bots are taking this path + temppen = level.waypointusage[ team ][ child + "" ]; // consider how many bots are taking this path } if ( temppen > 1 ) @@ -2445,14 +2445,14 @@ onUsePlantObjectFix( player ) { level thread bombPlantedFix( self, player ); - for ( i = 0; i < level.bombZones.size; i++ ) + for ( i = 0; i < level.bombzones.size; i++ ) { - if ( level.bombZones[ i ] == self ) + if ( level.bombzones[ i ] == self ) { continue; } - level.bombZones[ i ] maps\mp\gametypes\_gameobjects::disableObject(); + level.bombzones[ i ] maps\mp\gametypes\_gameobjects::disableObject(); } player playsound( "mp_bomb_plant" ); @@ -2468,10 +2468,10 @@ onUsePlantObjectFix( player ) maps\mp\_utility::leaderDialog( "bomb_planted" ); level thread maps\mp\_utility::teamPlayerCardSplash( "callout_bombplanted", player ); - level.bombOwner = player; + level.bombowner = player; player thread maps\mp\gametypes\_hud_message::splashNotify( "plant", maps\mp\gametypes\_rank::getScoreInfoValue( "plant" ) ); player thread maps\mp\gametypes\_rank::giveRankXP( "plant" ); - player.bombPlantedTime = gettime(); + player.bombplantedtime = gettime(); maps\mp\gametypes\_gamescore::givePlayerScore( "plant", player ); player thread maps\mp\_matchdata::logGameEvent( "plant", player.origin ); } @@ -2483,27 +2483,27 @@ onUsePlantObjectFix( player ) bombPlantedFix( var_0, var_1 ) { maps\mp\gametypes\_gamelogic::pauseTimer(); - level.bombPlanted = 1; + level.bombplanted = 1; var_0.visuals[ 0 ] thread maps\mp\gametypes\_gamelogic::playTickingSound(); - level.tickingObject = var_0.visuals[ 0 ]; - level.timeLimitOverride = 1; - setgameendtime( int( gettime() + level.bombTimer * 1000 ) ); + level.tickingobject = var_0.visuals[ 0 ]; + level.timelimitoverride = 1; + setgameendtime( int( gettime() + level.bombtimer * 1000 ) ); setdvar( "ui_bomb_timer", 1 ); - if ( !level.multiBomb ) + if ( !level.multibomb ) { - level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" ); - level.sdBomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" ); - level.sdBomb maps\mp\gametypes\_gameobjects::setDropped(); - level.sdBombModel = level.sdBomb.visuals[ 0 ]; + level.sdbomb maps\mp\gametypes\_gameobjects::allowCarry( "none" ); + level.sdbomb maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" ); + level.sdbomb maps\mp\gametypes\_gameobjects::setDropped(); + level.sdbombmodel = level.sdbomb.visuals[ 0 ]; } else { for ( var_2 = 0; var_2 < level.players.size; var_2++ ) { - if ( isdefined( level.players[ var_2 ].carryIcon ) ) + if ( isdefined( level.players[ var_2 ].carryicon ) ) { - level.players[ var_2 ].carryIcon maps\mp\gametypes\_hud_util::destroyElem(); + level.players[ var_2 ].carryicon maps\mp\gametypes\_hud_util::destroyElem(); } } @@ -2512,20 +2512,20 @@ bombPlantedFix( var_0, var_1 ) var_5 = ( cos( var_4 ), sin( var_4 ), 0 ); var_5 = vectornormalize( var_5 - var_3[ "normal" ] * vectordot( var_5, var_3[ "normal" ] ) ); var_6 = vectortoangles( var_5 ); - level.sdBombModel = spawn( "script_model", var_3[ "position" ] ); - level.sdBombModel.angles = var_6; - level.sdBombModel setmodel( "prop_suitcase_bomb" ); + level.sdbombmodel = spawn( "script_model", var_3[ "position" ] ); + level.sdbombmodel.angles = var_6; + level.sdbombmodel setmodel( "prop_suitcase_bomb" ); } var_0 maps\mp\gametypes\_gameobjects::allowUse( "none" ); var_0 maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" ); var_7 = var_0 maps\mp\gametypes\_gameobjects::getLabel(); - var_8 = var_0.bombDefuseTrig; - var_8.origin = level.sdBombModel.origin; + var_8 = var_0.bombdefusetrig; + var_8.origin = level.sdbombmodel.origin; var_9 = []; defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game[ "defenders" ], var_8, var_9, ( 0, 0, 32 ) ); defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" ); - defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime ); + defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defusetime ); defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" ); defuseObject maps\mp\gametypes\_gameobjects::setUseHintText( &"PLATFORM_HOLD_TO_DEFUSE_EXPLOSIVES" ); defuseObject maps\mp\gametypes\_gameobjects::setVisibleTeam( "any" ); @@ -2534,25 +2534,25 @@ bombPlantedFix( var_0, var_1 ) defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", "waypoint_defuse" + var_7 ); defuseObject maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", "waypoint_defend" + var_7 ); defuseObject.label = var_7; - defuseObject.onBeginUse = maps\mp\gametypes\sd::onBeginUse; - defuseObject.onEndUse = maps\mp\gametypes\sd::onEndUse; - defuseObject.onUse = maps\mp\gametypes\sd::onUseDefuseObject; - defuseObject.useWeapon = "briefcase_bomb_defuse_mp"; + defuseObject.onbeginuse = maps\mp\gametypes\sd::onBeginUse; + defuseObject.onenduse = maps\mp\gametypes\sd::onEndUse; + defuseObject.onuse = maps\mp\gametypes\sd::onUseDefuseObject; + defuseObject.useweapon = "briefcase_bomb_defuse_mp"; - level.defuseObject = defuseObject; + level.defuseobject = defuseObject; maps\mp\gametypes\sd::BombTimerWait(); setdvar( "ui_bomb_timer", 0 ); var_0.visuals[ 0 ] maps\mp\gametypes\_gamelogic::stopTickingSound(); - if ( level.gameEnded || level.bombDefused ) + if ( level.gameended || level.bombdefused ) { return; } level.bombexploded = 1; - var_11 = level.sdBombModel.origin; - level.sdBombModel hide(); + var_11 = level.sdbombmodel.origin; + level.sdbombmodel hide(); if ( isdefined( var_1 ) ) { @@ -2572,14 +2572,14 @@ bombPlantedFix( var_0, var_1 ) earthquake( 0.75, 2.0, var_11, 2000 ); thread maps\mp\_utility::playSoundinSpace( "exp_suitcase_bomb_main", var_11 ); - if ( isdefined( var_0.exploderIndex ) ) + if ( isdefined( var_0.exploderindex ) ) { - common_scripts\utility::exploder( var_0.exploderIndex ); + common_scripts\utility::exploder( var_0.exploderindex ); } - for ( var_2 = 0; var_2 < level.bombZones.size; var_2++ ) + for ( var_2 = 0; var_2 < level.bombzones.size; var_2++ ) { - level.bombZones[ var_2 ] maps\mp\gametypes\_gameobjects::disableObject(); + level.bombzones[ var_2 ] maps\mp\gametypes\_gameobjects::disableObject(); } defuseObject maps\mp\gametypes\_gameobjects::disableObject(); @@ -2596,7 +2596,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self endon( "death" ); self takeallweapons(); - self.changingWeapon = undefined; + self.changingweapon = undefined; teamName = "none"; if ( !isdefined( setPrimarySpawnWeapon ) ) @@ -2706,7 +2706,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( loadoutSecondary != "none" && !maps\mp\gametypes\_class::isValidSecondary( loadoutSecondary, loadoutPerk2, 0 ) ) { - loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, 10, 1 ); + loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, 10, 1 ); loadoutSecondaryAttachment = "none"; loadoutSecondaryAttachment2 = "none"; loadoutSecondaryBuff = "specialty_null"; @@ -2741,14 +2741,14 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( getmatchrulesdata( "defaultClasses", teamName, classIndex, "juggernaut" ) ) { self thread recipeClassApplyJuggernaut( isJuggernaut() ); - self.isJuggernaut = true; + self.isjuggernaut = true; self.juggmovespeedscaler = 0.7; } else if ( isJuggernaut() ) { self notify( "lost_juggernaut" ); - self.isJuggernaut = false; - self.moveSpeedScaler = 1; + self.isjuggernaut = false; + self.movespeedscaler = 1; } } else if ( issubstr( class, "custom" ) ) @@ -2827,7 +2827,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( loadoutSecondary != "none" && !maps\mp\gametypes\_class::isValidSecondary( loadoutSecondary, loadoutPerk2, 0 ) ) { - loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, 10, 1 ); + loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, 10, 1 ); loadoutSecondaryAttachment = "none"; loadoutSecondaryAttachment2 = "none"; loadoutSecondaryBuff = "specialty_null"; @@ -2835,16 +2835,16 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary loadoutSecondaryReticle = "none"; } - if ( level.killstreakRewards && isdefined( gamemodeLoadout[ "loadoutStreakType" ] ) && gamemodeLoadout[ "loadoutStreakType" ] != "specialty_null" ) + if ( level.killstreakrewards && isdefined( gamemodeLoadout[ "loadoutStreakType" ] ) && gamemodeLoadout[ "loadoutStreakType" ] != "specialty_null" ) { loadoutStreakType = gamemodeLoadout[ "loadoutStreakType" ]; loadoutKillstreak1 = gamemodeLoadout[ "loadoutKillstreak1" ]; loadoutKillstreak2 = gamemodeLoadout[ "loadoutKillstreak2" ]; loadoutKillstreak3 = gamemodeLoadout[ "loadoutKillstreak3" ]; } - else if ( level.killstreakRewards && isdefined( self.streakType ) ) + else if ( level.killstreakrewards && isdefined( self.streaktype ) ) { - loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streakType ); + loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streaktype ); } else { @@ -2858,16 +2858,16 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( gamemodeLoadout[ "loadoutJuggernaut" ] ) { - self.health = self.maxHealth; + self.health = self.maxhealth; self thread recipeClassApplyJuggernaut( isJuggernaut() ); - self.isJuggernaut = true; + self.isjuggernaut = true; self.juggmovespeedscaler = 0.7; } else if ( isJuggernaut() ) { self notify( "lost_juggernaut" ); - self.isJuggernaut = false; - self.moveSpeedScaler = 1; + self.isjuggernaut = false; + self.movespeedscaler = 1; } } else if ( class == "juggernaut" ) @@ -2888,7 +2888,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary loadoutPerk1 = "specialty_scavenger"; loadoutPerk2 = "specialty_quickdraw"; loadoutPerk3 = "specialty_detectexplosive"; - loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streakType ); + loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streaktype ); loadoutOffhand = "smoke_grenade_mp"; loadoutDeathStreak = "specialty_null"; } @@ -2910,7 +2910,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary loadoutPerk1 = "specialty_scavenger"; loadoutPerk2 = "specialty_coldblooded"; loadoutPerk3 = "specialty_detectexplosive"; - loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streakType ); + loadoutStreakType = maps\mp\gametypes\_class::getLoadoutStreakTypeFromStreakType( self.streaktype ); loadoutOffhand = "smoke_grenade_mp"; loadoutDeathStreak = "specialty_null"; } @@ -2918,25 +2918,25 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary { class_num = maps\mp\gametypes\_class::getClassIndex( class ); self.class_num = class_num; - loadoutPrimary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 0 ); - loadoutPrimaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0, 0 ); - loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0, 1 ); - loadoutPrimaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classTableName, class_num, 0 ); - loadoutPrimaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classTableName, class_num, 0 ); - loadoutPrimaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classTableName, class_num, 0 ); - loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 1 ); - loadoutSecondaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1, 0 ); - loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1, 1 ); - loadoutSecondaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classTableName, class_num, 1 ); - loadoutSecondaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classTableName, class_num, 1 ); - loadoutSecondaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classTableName, class_num, 1 ); - loadoutEquipment = maps\mp\gametypes\_class::table_getEquipment( level.classTableName, class_num, 0 ); - loadoutPerk1 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 1 ); - loadoutPerk2 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 2 ); - loadoutPerk3 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 3 ); - loadoutStreakType = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 5 ); - loadoutOffhand = maps\mp\gametypes\_class::table_getOffhand( level.classTableName, class_num ); - loadoutDeathStreak = maps\mp\gametypes\_class::table_getDeathstreak( level.classTableName, class_num ); + loadoutPrimary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, class_num, 0 ); + loadoutPrimaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, class_num, 0, 0 ); + loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, class_num, 0, 1 ); + loadoutPrimaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classtablename, class_num, 0 ); + loadoutPrimaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classtablename, class_num, 0 ); + loadoutPrimaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classtablename, class_num, 0 ); + loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, class_num, 1 ); + loadoutSecondaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, class_num, 1, 0 ); + loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, class_num, 1, 1 ); + loadoutSecondaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classtablename, class_num, 1 ); + loadoutSecondaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classtablename, class_num, 1 ); + loadoutSecondaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classtablename, class_num, 1 ); + loadoutEquipment = maps\mp\gametypes\_class::table_getEquipment( level.classtablename, class_num, 0 ); + loadoutPerk1 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, class_num, 1 ); + loadoutPerk2 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, class_num, 2 ); + loadoutPerk3 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, class_num, 3 ); + loadoutStreakType = maps\mp\gametypes\_class::table_getPerk( level.classtablename, class_num, 5 ); + loadoutOffhand = maps\mp\gametypes\_class::table_getOffhand( level.classtablename, class_num ); + loadoutDeathStreak = maps\mp\gametypes\_class::table_getDeathstreak( level.classtablename, class_num ); } // stop default class op'ness @@ -2991,37 +2991,37 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary { if ( !maps\mp\gametypes\_class::isValidPrimary( loadoutPrimary ) ) { - loadoutPrimary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, 10, 0 ); + loadoutPrimary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, 10, 0 ); } if ( !maps\mp\gametypes\_class::isValidAttachment( loadoutPrimaryAttachment ) ) { - loadoutPrimaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, 10, 0, 0 ); + loadoutPrimaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, 10, 0, 0 ); } if ( !maps\mp\gametypes\_class::isValidAttachment( loadoutPrimaryAttachment2 ) ) { - loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, 10, 0, 1 ); + loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, 10, 0, 1 ); } if ( !maps\mp\gametypes\_class::isValidWeaponBuff( loadoutPrimaryBuff, loadoutPrimary ) ) { - loadoutPrimaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classTableName, 10, 0 ); + loadoutPrimaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classtablename, 10, 0 ); } if ( !maps\mp\gametypes\_class::isValidCamo( loadoutPrimaryCamo ) ) { - loadoutPrimaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classTableName, 10, 0 ); + loadoutPrimaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classtablename, 10, 0 ); } if ( !maps\mp\gametypes\_class::isValidReticle( loadoutPrimaryReticle ) ) { - loadoutPrimaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classTableNum, 10, 0 ); + loadoutPrimaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classtablenum, 10, 0 ); } if ( !maps\mp\gametypes\_class::isValidSecondary( loadoutSecondary, loadoutPerk2 ) ) { - loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, 10, 1 ); + loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classtablename, 10, 1 ); loadoutSecondaryAttachment = "none"; loadoutSecondaryAttachment2 = "none"; loadoutSecondaryBuff = "specialty_null"; @@ -3031,57 +3031,57 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( !maps\mp\gametypes\_class::isValidAttachment( loadoutSecondaryAttachment ) ) { - loadoutSecondaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, 10, 1, 0 ); + loadoutSecondaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, 10, 1, 0 ); } if ( !maps\mp\gametypes\_class::isValidAttachment( loadoutSecondaryAttachment2 ) ) { - loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, 10, 1, 1 ); + loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classtablename, 10, 1, 1 ); } if ( loadoutPerk2 == "specialty_twoprimaries" && !maps\mp\gametypes\_class::isValidWeaponBuff( loadoutSecondaryBuff, loadoutSecondary ) ) { - loadoutSecondaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classTableName, 10, 1 ); + loadoutSecondaryBuff = maps\mp\gametypes\_class::table_getWeaponBuff( level.classtablename, 10, 1 ); } if ( !maps\mp\gametypes\_class::isValidCamo( loadoutSecondaryCamo ) ) { - loadoutSecondaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classTableName, 10, 1 ); + loadoutSecondaryCamo = maps\mp\gametypes\_class::table_getWeaponCamo( level.classtablename, 10, 1 ); } if ( !maps\mp\gametypes\_class::isValidReticle( loadoutSecondaryReticle ) ) { - loadoutSecondaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classTableName, 10, 1 ); + loadoutSecondaryReticle = maps\mp\gametypes\_class::table_getWeaponReticle( level.classtablename, 10, 1 ); } if ( !maps\mp\gametypes\_class::isValidEquipment( loadoutEquipment ) ) { - loadoutEquipment = maps\mp\gametypes\_class::table_getEquipment( level.classTableName, 10, 0 ); + loadoutEquipment = maps\mp\gametypes\_class::table_getEquipment( level.classtablename, 10, 0 ); } if ( !maps\mp\gametypes\_class::isValidPerk1( loadoutPerk1 ) ) { - loadoutPerk1 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, 10, 1 ); + loadoutPerk1 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, 10, 1 ); } if ( !maps\mp\gametypes\_class::isValidPerk2( loadoutPerk2 ) ) { - loadoutPerk2 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, 10, 2 ); + loadoutPerk2 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, 10, 2 ); } if ( !maps\mp\gametypes\_class::isValidPerk3( loadoutPerk3 ) ) { - loadoutPerk3 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, 10, 3 ); + loadoutPerk3 = maps\mp\gametypes\_class::table_getPerk( level.classtablename, 10, 3 ); } if ( !maps\mp\gametypes\_class::isValidDeathStreak( loadoutDeathStreak ) ) { - loadoutDeathStreak = maps\mp\gametypes\_class::table_getDeathstreak( level.classTableName, 10 ); + loadoutDeathStreak = maps\mp\gametypes\_class::table_getDeathstreak( level.classtablename, 10 ); } if ( !maps\mp\gametypes\_class::isValidOffhand( loadoutOffhand ) ) { - loadoutOffhand = maps\mp\gametypes\_class::table_getOffhand( level.classTableName, 10 ); + loadoutOffhand = maps\mp\gametypes\_class::table_getOffhand( level.classtablename, 10 ); } if ( loadoutPrimaryAttachment2 != "none" && loadoutPrimaryBuff != "specialty_bling" ) @@ -3100,32 +3100,32 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary } } - self.loadoutPrimary = loadoutPrimary; - self.loadoutPrimaryCamo = int( tablelookup( "mp/camoTable.csv", 1, loadoutPrimaryCamo, 0 ) ); - self.loadoutSecondary = loadoutSecondary; - self.loadoutSecondaryCamo = int( tablelookup( "mp/camoTable.csv", 1, loadoutSecondaryCamo, 0 ) ); + self.loadoutprimary = loadoutPrimary; + self.loadoutprimarycamo = int( tablelookup( "mp/camoTable.csv", 1, loadoutPrimaryCamo, 0 ) ); + self.loadoutsecondary = loadoutSecondary; + self.loadoutsecondarycamo = int( tablelookup( "mp/camoTable.csv", 1, loadoutSecondaryCamo, 0 ) ); if ( !issubstr( loadoutPrimary, "iw5" ) ) { - self.loadoutPrimaryCamo = 0; + self.loadoutprimarycamo = 0; } if ( !issubstr( loadoutSecondary, "iw5" ) ) { - self.loadoutSecondaryCamo = 0; + self.loadoutsecondarycamo = 0; } - self.loadoutPrimaryReticle = int( tablelookup( "mp/reticleTable.csv", 1, loadoutPrimaryReticle, 0 ) ); - self.loadoutSecondaryReticle = int( tablelookup( "mp/reticleTable.csv", 1, loadoutSecondaryReticle, 0 ) ); + self.loadoutprimaryreticle = int( tablelookup( "mp/reticleTable.csv", 1, loadoutPrimaryReticle, 0 ) ); + self.loadoutsecondaryreticle = int( tablelookup( "mp/reticleTable.csv", 1, loadoutSecondaryReticle, 0 ) ); if ( !issubstr( loadoutPrimary, "iw5" ) ) { - self.loadoutPrimaryReticle = 0; + self.loadoutprimaryreticle = 0; } if ( !issubstr( loadoutSecondary, "iw5" ) ) { - self.loadoutSecondaryReticle = 0; + self.loadoutsecondaryreticle = 0; } if ( loadoutSecondary == "none" ) @@ -3134,7 +3134,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary } else { - secondaryName = maps\mp\gametypes\_class::buildWeaponName( loadoutSecondary, loadoutSecondaryAttachment, loadoutSecondaryAttachment2, self.loadoutSecondaryCamo, self.loadoutSecondaryReticle ); + secondaryName = maps\mp\gametypes\_class::buildWeaponName( loadoutSecondary, loadoutSecondaryAttachment, loadoutSecondaryAttachment2, self.loadoutsecondarycamo, self.loadoutsecondaryreticle ); self _giveWeapon( secondaryName ); weaponTokens = strtok( secondaryName, "_" ); @@ -3172,7 +3172,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self _clearPerks(); self maps\mp\gametypes\_class::_detachAll(); - if ( level.dieHardMode ) + if ( level.diehardmode ) { self givePerk( "specialty_pistoldeath", false ); } @@ -3186,7 +3186,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self.spawnperk = false; - if ( !self _hasPerk( "specialty_blindeye" ) && self.avoidKillstreakOnSpawnTimer > 0 ) + if ( !self _hasPerk( "specialty_blindeye" ) && self.avoidkillstreakonspawntimer > 0 ) { self thread maps\mp\perks\_perks::giveBlindEyeAfterSpawn(); } @@ -3226,7 +3226,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary } } - if ( level.killstreakRewards && !isdefined( loadoutKillstreak1 ) && !isdefined( loadoutKillstreak2 ) && !isdefined( loadoutKillstreak3 ) ) + if ( level.killstreakrewards && !isdefined( loadoutKillstreak1 ) && !isdefined( loadoutKillstreak2 ) && !isdefined( loadoutKillstreak3 ) ) { if ( isdefined( self.pers[ "copyCatLoadout" ] ) && self.pers[ "copyCatLoadout" ][ "inUse" ] && allowCopycat ) { @@ -3241,26 +3241,26 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary defaultKillstreak3 = undefined; playerData = undefined; - switch ( self.streakType ) + switch ( self.streaktype ) { case "support": - defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 2, 1 ); - defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 2, 2 ); - defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 2, 3 ); + defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 2, 1 ); + defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 2, 2 ); + defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 2, 3 ); playerData = "defenseStreaks"; break; case "specialist": - defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 1, 1 ); - defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 1, 2 ); - defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 1, 3 ); + defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 1, 1 ); + defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 1, 2 ); + defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 1, 3 ); playerData = "specialistStreaks"; break; default: - defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 1 ); - defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 2 ); - defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 3 ); + defaultKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 1 ); + defaultKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 2 ); + defaultKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 3 ); playerData = "assaultStreaks"; break; } @@ -3299,7 +3299,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary } } - if ( isGameModeClass && self.streakType == "specialist" ) + if ( isGameModeClass && self.streaktype == "specialist" ) { self.pers[ "gamemodeLoadout" ][ "loadoutKillstreak1" ] = loadoutKillstreak1; self.pers[ "gamemodeLoadout" ][ "loadoutKillstreak2" ] = loadoutKillstreak2; @@ -3348,14 +3348,14 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( var_56 ) { - self.streakType = "assault"; - loadoutKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 1 ); - loadoutKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 2 ); - loadoutKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classTableName, 0, 3 ); + self.streaktype = "assault"; + loadoutKillstreak1 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 1 ); + loadoutKillstreak2 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 2 ); + loadoutKillstreak3 = maps\mp\gametypes\_class::table_getKillstreak( level.classtablename, 0, 3 ); } } } - else if ( !level.killstreakRewards ) + else if ( !level.killstreakrewards ) { loadoutKillstreak1 = "none"; loadoutKillstreak2 = "none"; @@ -3364,9 +3364,9 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self maps\mp\gametypes\_class::setKillstreaks( loadoutKillstreak1, loadoutKillstreak2, loadoutKillstreak3 ); - if ( isdefined( self.lastClass ) && self.lastClass != self.class && !issubstr( self.class, "juggernaut" ) && !issubstr( self.lastClass, "juggernaut" ) && !issubstr( class, "juggernaut" ) ) + if ( isdefined( self.lastclass ) && self.lastclass != self.class && !issubstr( self.class, "juggernaut" ) && !issubstr( self.lastclass, "juggernaut" ) && !issubstr( class, "juggernaut" ) ) { - if ( wasOnlyRound() || self.lastClass != "" ) + if ( wasOnlyRound() || self.lastclass != "" ) { streakNames = []; inc = 0; @@ -3375,7 +3375,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary { for ( i = 5; i < self.pers[ "killstreaks" ].size; i++ ) { - streakNames[ inc ] = self.pers[ "killstreaks" ][ i ].streakName; + streakNames[ inc ] = self.pers[ "killstreaks" ][ i ].streakname; inc++; } } @@ -3384,9 +3384,9 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary { for ( i = 1; i < 4; i++ ) { - if ( isdefined( self.pers[ "killstreaks" ][ i ] ) && isdefined( self.pers[ "killstreaks" ][ i ].streakName ) && self.pers[ "killstreaks" ][ i ].available && !self.pers[ "killstreaks" ][ i ].isSpecialist ) + if ( isdefined( self.pers[ "killstreaks" ][ i ] ) && isdefined( self.pers[ "killstreaks" ][ i ].streakname ) && self.pers[ "killstreaks" ][ i ].available && !self.pers[ "killstreaks" ][ i ].isspecialist ) { - streakNames[ inc ] = self.pers[ "killstreaks" ][ i ].streakName; + streakNames[ inc ] = self.pers[ "killstreaks" ][ i ].streakname; inc++; } } @@ -3404,13 +3404,13 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary if ( !issubstr( class, "juggernaut" ) ) { - if ( isdefined( self.lastClass ) && self.lastClass != "" && self.lastClass != self.class ) + if ( isdefined( self.lastclass ) && self.lastclass != "" && self.lastclass != self.class ) { self incPlayerStat( "mostclasseschanged", 1 ); } self.pers[ "lastClass" ] = self.class; - self.lastClass = self.class; + self.lastclass = self.class; } if ( isdefined( self.gamemode_chosenclass ) ) @@ -3418,11 +3418,11 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self.pers[ "class" ] = self.gamemode_chosenclass; self.pers[ "lastClass" ] = self.gamemode_chosenclass; self.class = self.gamemode_chosenclass; - self.lastClass = self.gamemode_chosenclass; + self.lastclass = self.gamemode_chosenclass; self.gamemode_chosenclass = undefined; } - primaryName = maps\mp\gametypes\_class::buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment, loadoutPrimaryAttachment2, self.loadoutPrimaryCamo, self.loadoutPrimaryReticle ); + primaryName = maps\mp\gametypes\_class::buildWeaponName( loadoutPrimary, loadoutPrimaryAttachment, loadoutPrimaryAttachment2, self.loadoutprimarycamo, self.loadoutprimaryreticle ); self _giveWeapon( primaryName ); self switchtoweapon( primaryName ); weaponTokens = strtok( primaryName, "_" ); @@ -3448,7 +3448,7 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary self setplayerdata( "weaponRank", weaponName, curWeaponRank ); } - if ( primaryName == "riotshield_mp" && level.inGracePeriod ) + if ( primaryName == "riotshield_mp" && level.ingraceperiod ) { self notify( "weapon_change", "riotshield_mp" ); } @@ -3516,17 +3516,17 @@ botGiveLoadout( team, class, allowCopycat, setPrimarySpawnWeapon ) // setPrimary } primaryWeapon = primaryName; - self.primaryWeapon = primaryWeapon; - self.secondaryWeapon = secondaryName; + self.primaryweapon = primaryWeapon; + self.secondaryweapon = secondaryName; if ( var_7 ) { - self setweaponammoclip( self.primaryWeapon, 0 ); - self setweaponammostock( self.primaryWeapon, 0 ); + self setweaponammoclip( self.primaryweapon, 0 ); + self setweaponammostock( self.primaryweapon, 0 ); } self playerModelForWeapon( self.pers[ "primaryWeapon" ], getBaseWeaponName( secondaryName ) ); - self.isSniper = ( weaponclass( self.primaryWeapon ) == "sniper" ); + self.issniper = ( weaponclass( self.primaryweapon ) == "sniper" ); self maps\mp\gametypes\_weapons::updateMoveSpeedScale(); self maps\mp\perks\_perks::cac_selector(); self notify( "changed_kit" ); @@ -3570,15 +3570,15 @@ loadoutAllPerks( loadoutEquipment, loadoutPerk1, loadoutPerk2, loadoutPerk3, loa loadoutSecondaryBuff = maps\mp\perks\_perks::validatePerk( undefined, loadoutSecondaryBuff ); } - self.loadoutPerk1 = loadoutPerk1; - self.loadoutPerk2 = loadoutPerk2; - self.loadoutPerk3 = loadoutPerk3; - self.loadoutPerkEquipment = loadoutEquipment; - self.loadoutPrimaryBuff = loadoutPrimaryBuff; + self.loadoutperk1 = loadoutPerk1; + self.loadoutperk2 = loadoutPerk2; + self.loadoutperk3 = loadoutPerk3; + self.loadoutperkequipment = loadoutEquipment; + self.loadoutprimarybuff = loadoutPrimaryBuff; if ( loadoutPerk2 == "specialty_twoprimaries" ) { - self.loadoutSecondaryBuff = loadoutSecondaryBuff; + self.loadoutsecondarybuff = loadoutSecondaryBuff; } if ( loadoutEquipment != "specialty_null" ) diff --git a/maps/mp/bots/_menu.gsc b/maps/mp/bots/_menu.gsc index f16e7a7..9d2c971 100644 --- a/maps/mp/bots/_menu.gsc +++ b/maps/mp/bots/_menu.gsc @@ -1,1346 +1,1346 @@ -/* - _menu - Author: INeedGames - Date: 05/11/2021 - The ingame menu. -*/ - -#include common_scripts\utility; -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; -#include maps\mp\bots\_bot_utility; - -init() -{ - if ( getDvar( "bots_main_menu" ) == "" ) - { - setDvar( "bots_main_menu", true ); - } - - if ( !getDvarInt( "bots_main_menu" ) ) - { - return; - } - - thread watchPlayers(); -} - -watchPlayers() -{ - for ( ;; ) - { - wait 1; - - if ( !getDvarInt( "bots_main_menu" ) ) - { - return; - } - - for ( i = level.players.size - 1; i >= 0; i-- ) - { - player = level.players[ i ]; - - if ( !player is_host() ) - { - continue; - } - - if ( isDefined( player.menuInit ) && player.menuInit ) - { - continue; - } - - player thread init_menu(); - } - } -} - -kill_menu() -{ - self notify( "bots_kill_menu" ); - self.menuInit = undefined; -} - -init_menu() -{ - self.menuInit = true; - - self.menuOpen = false; - self.menu_player = undefined; - self.SubMenu = "Main"; - self.Curs[ "Main" ][ "X" ] = 0; - self AddOptions(); - - self thread watchPlayerOpenMenu(); - self thread MenuSelect(); - self thread RightMenu(); - self thread LeftMenu(); - self thread UpMenu(); - self thread DownMenu(); - - self thread watchDisconnect(); - - self thread doGreetings(); -} - -watchDisconnect() -{ - self waittill_either( "disconnect", "bots_kill_menu" ); - - if ( self.menuOpen ) - { - if ( isDefined( self.MenuTextY ) ) - { - for ( i = 0; i < self.MenuTextY.size; i++ ) - { - if ( isDefined( self.MenuTextY[ i ] ) ) - { - self.MenuTextY[ i ] destroy(); - } - } - } - - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.MenuText.size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ] destroy(); - } - } - } - - if ( isDefined( self.Menu ) && isDefined( self.Menu[ "X" ] ) ) - { - if ( isDefined( self.Menu[ "X" ][ "Shader" ] ) ) - { - self.Menu[ "X" ][ "Shader" ] destroy(); - } - - if ( isDefined( self.Menu[ "X" ][ "Scroller" ] ) ) - { - self.Menu[ "X" ][ "Scroller" ] destroy(); - } - } - - if ( isDefined( self.menuVersionHud ) ) - { - self.menuVersionHud destroy(); - } - } -} - -doGreetings() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - wait 1; - self iPrintln( "Welcome to Bot Warfare " + self.name + "!" ); - wait 5; - self iPrintln( "Press [{+actionslot 1}] to open menu!" ); -} - -watchPlayerOpenMenu() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_open_menu", "+actionslot 1" ); - - for ( ;; ) - { - self waittill( "bots_open_menu" ); - - if ( !self.menuOpen ) - { - self playLocalSound( "mouse_click" ); - self thread OpenSub( self.SubMenu ); - } - else - { - self playLocalSound( "mouse_click" ); - - if ( self.SubMenu != "Main" ) - { - self ExitSub(); - } - else - { - self ExitMenu(); - - if ( !gameFlag( "prematch_done" ) || level.gameEnded ) - { - self freezeControls( true ); - } - else - { - self freezecontrols( false ); - } - } - } - } -} - -MenuSelect() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_select", "+gostand" ); - - for ( ;; ) - { - self waittill( "bots_select" ); - - if ( self.MenuOpen ) - { - self playLocalSound( "mouse_click" ); - - if ( self.SubMenu == "Main" ) - { - self thread [[ self.Option[ "Function" ][ self.SubMenu ][ self.Curs[ "Main" ][ "X" ] ] ]]( self.Option[ "Arg1" ][ self.SubMenu ][ self.Curs[ "Main" ][ "X" ] ], self.Option[ "Arg2" ][ self.SubMenu ][ self.Curs[ "Main" ][ "X" ] ] ); - } - else - { - self thread [[ self.Option[ "Function" ][ self.SubMenu ][ self.Curs[ self.SubMenu ][ "Y" ] ] ]]( self.Option[ "Arg1" ][ self.SubMenu ][ self.Curs[ self.SubMenu ][ "Y" ] ], self.Option[ "Arg2" ][ self.SubMenu ][ self.Curs[ self.SubMenu ][ "Y" ] ] ); - } - } - } -} - -LeftMenu() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_left", "+moveleft" ); - - for ( ;; ) - { - self waittill( "bots_left" ); - - if ( self.MenuOpen && self.SubMenu == "Main" ) - { - self playLocalSound( "mouse_over" ); - self.Curs[ "Main" ][ "X" ]--; - - if ( self.Curs[ "Main" ][ "X" ] < 0 ) - { - self.Curs[ "Main" ][ "X" ] = self.Option[ "Name" ][ self.SubMenu ].size - 1; - } - - self CursMove( "X" ); - } - } -} - -RightMenu() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_right", "+moveright" ); - - for ( ;; ) - { - self waittill( "bots_right" ); - - if ( self.MenuOpen && self.SubMenu == "Main" ) - { - self playLocalSound( "mouse_over" ); - self.Curs[ "Main" ][ "X" ]++; - - if ( self.Curs[ "Main" ][ "X" ] > self.Option[ "Name" ][ self.SubMenu ].size - 1 ) - { - self.Curs[ "Main" ][ "X" ] = 0; - } - - self CursMove( "X" ); - } - } -} - -UpMenu() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_up", "+forward" ); - - for ( ;; ) - { - self waittill( "bots_up" ); - - if ( self.MenuOpen && self.SubMenu != "Main" ) - { - self playLocalSound( "mouse_over" ); - self.Curs[ self.SubMenu ][ "Y" ]--; - - if ( self.Curs[ self.SubMenu ][ "Y" ] < 0 ) - { - self.Curs[ self.SubMenu ][ "Y" ] = self.Option[ "Name" ][ self.SubMenu ].size - 1; - } - - self CursMove( "Y" ); - } - } -} - -DownMenu() -{ - self endon ( "disconnect" ); - self endon ( "bots_kill_menu" ); - - self notifyOnPlayerCommand( "bots_down", "+back" ); - - for ( ;; ) - { - self waittill( "bots_down" ); - - if ( self.MenuOpen && self.SubMenu != "Main" ) - { - self playLocalSound( "mouse_over" ); - self.Curs[ self.SubMenu ][ "Y" ]++; - - if ( self.Curs[ self.SubMenu ][ "Y" ] > self.Option[ "Name" ][ self.SubMenu ].size - 1 ) - { - self.Curs[ self.SubMenu ][ "Y" ] = 0; - } - - self CursMove( "Y" ); - } - } -} - -OpenSub( menu, menu2 ) -{ - if ( menu != "Main" && ( !isDefined( self.Menu[ menu ] ) || !!isDefined( self.Menu[ menu ][ "FirstOpen" ] ) ) ) - { - self.Curs[ menu ][ "Y" ] = 0; - self.Menu[ menu ][ "FirstOpen" ] = true; - } - - logoldi = true; - self.SubMenu = menu; - - if ( self.SubMenu == "Main" ) - { - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.MenuText.size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ] destroy(); - } - } - } - - if ( isDefined( self.Menu ) && isDefined( self.Menu[ "X" ] ) ) - { - if ( isDefined( self.Menu[ "X" ][ "Shader" ] ) ) - { - self.Menu[ "X" ][ "Shader" ] destroy(); - } - - if ( isDefined( self.Menu[ "X" ][ "Scroller" ] ) ) - { - self.Menu[ "X" ][ "Scroller" ] destroy(); - } - } - - if ( isDefined( self.menuVersionHud ) ) - { - self.menuVersionHud destroy(); - } - - for ( i = 0 ; i < self.Option[ "Name" ][ self.SubMenu ].size ; i++ ) - { - self.MenuText[ i ] = self createfontstring( "default", 1.6 ); - self.MenuText[ i ] setpoint( "CENTER", "CENTER", -300 + ( i * 100 ), -226 ); - self.MenuText[ i ] settext( self.Option[ "Name" ][ self.SubMenu ][ i ] ); - - if ( logOldi ) - { - self.oldi = i; - } - - if ( self.MenuText[ i ].x > 300 ) - { - logOldi = false; - x = i - self.oldi; - self.MenuText[ i ] setpoint( "CENTER", "CENTER", ( ( ( -300 ) - ( i * 100 ) ) + ( i * 100 ) ) + ( x * 100 ), -196 ); - } - - self.MenuText[ i ].alpha = 1; - self.MenuText[ i ].sort = 999; - } - - if ( !logOldi ) - { - self.Menu[ "X" ][ "Shader" ] = self createRectangle( "CENTER", "CENTER", 0, -225, 1000, 90, ( 0, 0, 0 ), -2, 1, "white" ); - } - else - { - self.Menu[ "X" ][ "Shader" ] = self createRectangle( "CENTER", "CENTER", 0, -225, 1000, 30, ( 0, 0, 0 ), -2, 1, "white" ); - } - - self.Menu[ "X" ][ "Scroller" ] = self createRectangle( "CENTER", "CENTER", self.MenuText[ self.Curs[ "Main" ][ "X" ] ].x, -225, 105, 22, ( 1, 0, 0 ), -1, 1, "white" ); - - self CursMove( "X" ); - - self.menuVersionHud = initHudElem( "Bot Warfare " + level.bw_VERSION, 0, 0 ); - - self.MenuOpen = true; - } - else - { - if ( isDefined( self.MenuTextY ) ) - { - for ( i = 0 ; i < self.MenuTextY.size ; i++ ) - { - if ( isDefined( self.MenuTextY[ i ] ) ) - { - self.MenuTextY[ i ] destroy(); - } - } - } - - for ( i = 0 ; i < self.Option[ "Name" ][ self.SubMenu ].size ; i++ ) - { - self.MenuTextY[ i ] = self createfontstring( "default", 1.6 ); - self.MenuTextY[ i ] setpoint( "CENTER", "CENTER", self.MenuText[ self.Curs[ "Main" ][ "X" ] ].x, -160 + ( i * 20 ) ); - self.MenuTextY[ i ] settext( self.Option[ "Name" ][ self.SubMenu ][ i ] ); - self.MenuTextY[ i ].alpha = 1; - self.MenuTextY[ i ].sort = 999; - } - - self CursMove( "Y" ); - } -} - -CursMove( direction ) -{ - self notify( "scrolled" ); - - if ( self.SubMenu == "Main" ) - { - self.Menu[ "X" ][ "Scroller" ].x = self.MenuText[ self.Curs[ "Main" ][ "X" ] ].x; - self.Menu[ "X" ][ "Scroller" ].y = self.MenuText[ self.Curs[ "Main" ][ "X" ] ].y; - - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.MenuText.size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ].fontscale = 1.5; - self.MenuText[ i ].color = ( 1, 1, 1 ); - self.MenuText[ i ].glowAlpha = 0; - } - } - } - - self thread ShowOptionOn( direction ); - } - else - { - if ( isDefined( self.MenuTextY ) ) - { - for ( i = 0; i < self.MenuTextY.size; i++ ) - { - if ( isDefined( self.MenuTextY[ i ] ) ) - { - self.MenuTextY[ i ].fontscale = 1.5; - self.MenuTextY[ i ].color = ( 1, 1, 1 ); - self.MenuTextY[ i ].glowAlpha = 0; - } - } - } - - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.MenuText.size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ].fontscale = 1.5; - self.MenuText[ i ].color = ( 1, 1, 1 ); - self.MenuText[ i ].glowAlpha = 0; - } - } - } - - self thread ShowOptionOn( direction ); - } -} - -ShowOptionOn( variable ) -{ - self endon( "scrolled" ); - self endon( "disconnect" ); - self endon( "exit" ); - self endon( "bots_kill_menu" ); - - for ( time = 0;; time += 0.05 ) - { - if ( !self isOnGround() && isAlive( self ) && gameFlag( "prematch_done" ) && !level.gameEnded ) - { - self freezecontrols( false ); - } - else - { - self freezecontrols( true ); - } - - self setClientDvar( "r_blur", "5" ); - self setClientDvar( "sc_blur", "15" ); - self addOptions(); - - if ( self.SubMenu == "Main" ) - { - if ( isDefined( self.Curs[ self.SubMenu ][ variable ] ) && isDefined( self.MenuText ) && isDefined( self.MenuText[ self.Curs[ self.SubMenu ][ variable ] ] ) ) - { - self.MenuText[ self.Curs[ self.SubMenu ][ variable ] ].fontscale = 2.0; - // self.MenuText[ self.Curs[ self.SubMenu ][ variable ] ].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); - color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); - - if ( int( time * 4 ) % 2 ) - { - color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); - } - - self.MenuText[ self.Curs[ self.SubMenu ][ variable ] ].color = color; - } - - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.Option[ "Name" ][ self.SubMenu ].size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ] settext( self.Option[ "Name" ][ self.SubMenu ][ i ] ); - } - } - } - } - else - { - if ( isDefined( self.Curs[ self.SubMenu ][ variable ] ) && isDefined( self.MenuTextY ) && isDefined( self.MenuTextY[ self.Curs[ self.SubMenu ][ variable ] ] ) ) - { - self.MenuTextY[ self.Curs[ self.SubMenu ][ variable ] ].fontscale = 2.0; - // self.MenuTextY[ self.Curs[ self.SubMenu ][ variable ] ].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); - color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); - - if ( int( time * 4 ) % 2 ) - { - color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); - } - - self.MenuTextY[ self.Curs[ self.SubMenu ][ variable ] ].color = color; - } - - if ( isDefined( self.MenuTextY ) ) - { - for ( i = 0; i < self.Option[ "Name" ][ self.SubMenu ].size; i++ ) - { - if ( isDefined( self.MenuTextY[ i ] ) ) - { - self.MenuTextY[ i ] settext( self.Option[ "Name" ][ self.SubMenu ][ i ] ); - } - } - } - } - - wait 0.05; - } -} - -AddMenu( menu, num, text, function, arg1, arg2 ) -{ - self.Option[ "Name" ][ menu ][ num ] = text; - self.Option[ "Function" ][ menu ][ num ] = function; - self.Option[ "Arg1" ][ menu ][ num ] = arg1; - self.Option[ "Arg2" ][ menu ][ num ] = arg2; -} - -AddBack( menu, back ) -{ - self.Menu[ "Back" ][ menu ] = back; -} - -ExitSub() -{ - if ( isDefined( self.MenuTextY ) ) - { - for ( i = 0; i < self.MenuTextY.size; i++ ) - { - if ( isDefined( self.MenuTextY[ i ] ) ) - { - self.MenuTextY[ i ] destroy(); - } - } - } - - self.SubMenu = self.Menu[ "Back" ][ self.Submenu ]; - - if ( self.SubMenu == "Main" ) - { - self CursMove( "X" ); - } - else - { - self CursMove( "Y" ); - } -} - -ExitMenu() -{ - if ( isDefined( self.MenuText ) ) - { - for ( i = 0; i < self.MenuText.size; i++ ) - { - if ( isDefined( self.MenuText[ i ] ) ) - { - self.MenuText[ i ] destroy(); - } - } - } - - if ( isDefined( self.Menu ) && isDefined( self.Menu[ "X" ] ) ) - { - if ( isDefined( self.Menu[ "X" ][ "Shader" ] ) ) - { - self.Menu[ "X" ][ "Shader" ] destroy(); - } - - if ( isDefined( self.Menu[ "X" ][ "Scroller" ] ) ) - { - self.Menu[ "X" ][ "Scroller" ] destroy(); - } - } - - if ( isDefined( self.menuVersionHud ) ) - { - self.menuVersionHud destroy(); - } - - self.MenuOpen = false; - self notify( "exit" ); - - self setClientDvar( "r_blur", "0" ); - self setClientDvar( "sc_blur", "2" ); -} - -initHudElem( txt, xl, yl ) -{ - hud = NewClientHudElem( self ); - hud setText( txt ); - hud.alignX = "center"; - hud.alignY = "bottom"; - hud.horzAlign = "center"; - hud.vertAlign = "bottom"; - hud.x = xl; - hud.y = yl; - hud.foreground = true; - hud.fontScale = 1; - hud.font = "objective"; - hud.alpha = 1; - hud.glow = 0; - hud.glowColor = ( 0, 0, 0 ); - hud.glowAlpha = 1; - hud.color = ( 1.0, 1.0, 1.0 ); - - return hud; -} - -createRectangle( align, relative, x, y, width, height, color, sort, alpha, shader ) -{ - barElemBG = newClientHudElem( self ); - barElemBG.elemType = "bar_"; - barElemBG.width = width; - barElemBG.height = height; - barElemBG.align = align; - barElemBG.relative = relative; - barElemBG.xOffset = 0; - barElemBG.yOffset = 0; - barElemBG.children = []; - barElemBG.sort = sort; - barElemBG.color = color; - barElemBG.alpha = alpha; - barElemBG setParent( level.uiParent ); - barElemBG setShader( shader, width, height ); - barElemBG.hidden = false; - barElemBG setPoint( align, relative, x, y ); - return barElemBG; -} - -AddOptions() -{ - self AddMenu( "Main", 0, "Manage bots", ::OpenSub, "man_bots", "" ); - self AddBack( "man_bots", "Main" ); - - _temp = ""; - _tempDvar = getDvarInt( "bots_manage_add" ); - self AddMenu( "man_bots", 0, "Add 1 bot", ::man_bots, "add", 1 + _tempDvar ); - self AddMenu( "man_bots", 1, "Add 3 bot", ::man_bots, "add", 3 + _tempDvar ); - self AddMenu( "man_bots", 2, "Add 7 bot", ::man_bots, "add", 7 + _tempDvar ); - self AddMenu( "man_bots", 3, "Add 11 bot", ::man_bots, "add", 11 + _tempDvar ); - self AddMenu( "man_bots", 4, "Add 17 bot", ::man_bots, "add", 17 + _tempDvar ); - self AddMenu( "man_bots", 5, "Kick a bot", ::man_bots, "kick", 1 ); - self AddMenu( "man_bots", 6, "Kick all bots", ::man_bots, "kick", getBotArray().size ); - - _tempDvar = getDvarInt( "bots_manage_fill_kick" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "man_bots", 7, "Toggle auto bot kicking: " + _temp, ::man_bots, "autokick", _tempDvar ); - - _tempDvar = getDvarInt( "bots_manage_fill_mode" ); - - switch ( _tempDvar ) - { - case 0: - _temp = "everyone"; - break; - - case 1: - _temp = "just bots"; - break; - - case 2: - _temp = "everyone, adjust to map"; - break; - - case 3: - _temp = "just bots, adjust to map"; - break; - - case 4: - _temp = "bots used as team balance"; - break; - - default: - _temp = "out of range"; - break; - } - - self AddMenu( "man_bots", 8, "Change bot_fill_mode: " + _temp, ::man_bots, "fillmode", _tempDvar ); - - _tempDvar = getDvarInt( "bots_manage_fill" ); - self AddMenu( "man_bots", 9, "Increase bots to keep in-game: " + _tempDvar, ::man_bots, "fillup", _tempDvar ); - self AddMenu( "man_bots", 10, "Decrease bots to keep in-game: " + _tempDvar, ::man_bots, "filldown", _tempDvar ); - - _tempDvar = getDvarInt( "bots_manage_fill_spec" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "man_bots", 11, "Count players for fill on spectator: " + _temp, ::man_bots, "fillspec", _tempDvar ); - - // - - self AddMenu( "Main", 1, "Teams and difficulty", ::OpenSub, "man_team", "" ); - self AddBack( "man_team", "Main" ); - - _tempDvar = getdvar( "bots_team" ); - self AddMenu( "man_team", 0, "Change bot team: " + _tempDvar, ::bot_teams, "team", _tempDvar ); - - _tempDvar = getDvarInt( "bots_team_amount" ); - self AddMenu( "man_team", 1, "Increase bots to be on axis team: " + _tempDvar, ::bot_teams, "teamup", _tempDvar ); - self AddMenu( "man_team", 2, "Decrease bots to be on axis team: " + _tempDvar, ::bot_teams, "teamdown", _tempDvar ); - - _tempDvar = getDvarInt( "bots_team_force" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "man_team", 3, "Toggle forcing bots on team: " + _temp, ::bot_teams, "teamforce", _tempDvar ); - - _tempDvar = getDvarInt( "bots_team_mode" ); - - if ( _tempDvar ) - { - _temp = "only bots"; - } - else - { - _temp = "everyone"; - } - - self AddMenu( "man_team", 4, "Toggle bot_team_bot: " + _temp, ::bot_teams, "teammode", _tempDvar ); - - _tempDvar = getdvarint( "bots_skill" ); - - switch ( _tempDvar ) - { - case 0: - _temp = "random for all"; - break; - - case 1: - _temp = "too easy"; - break; - - case 2: - _temp = "easy"; - break; - - case 3: - _temp = "easy-medium"; - break; - - case 4: - _temp = "medium"; - break; - - case 5: - _temp = "hard"; - break; - - case 6: - _temp = "very hard"; - break; - - case 7: - _temp = "hardest"; - break; - - case 8: - _temp = "custom"; - break; - - case 9: - _temp = "complete random"; - break; - - default: - _temp = "out of range"; - break; - } - - self AddMenu( "man_team", 5, "Change bot difficulty: " + _temp, ::bot_teams, "skill", _tempDvar ); - - _tempDvar = getDvarInt( "bots_skill_axis_hard" ); - self AddMenu( "man_team", 6, "Increase amount of hard bots on axis team: " + _tempDvar, ::bot_teams, "axishardup", _tempDvar ); - self AddMenu( "man_team", 7, "Decrease amount of hard bots on axis team: " + _tempDvar, ::bot_teams, "axisharddown", _tempDvar ); - - _tempDvar = getDvarInt( "bots_skill_axis_med" ); - self AddMenu( "man_team", 8, "Increase amount of med bots on axis team: " + _tempDvar, ::bot_teams, "axismedup", _tempDvar ); - self AddMenu( "man_team", 9, "Decrease amount of med bots on axis team: " + _tempDvar, ::bot_teams, "axismeddown", _tempDvar ); - - _tempDvar = getDvarInt( "bots_skill_allies_hard" ); - self AddMenu( "man_team", 10, "Increase amount of hard bots on allies team: " + _tempDvar, ::bot_teams, "allieshardup", _tempDvar ); - self AddMenu( "man_team", 11, "Decrease amount of hard bots on allies team: " + _tempDvar, ::bot_teams, "alliesharddown", _tempDvar ); - - _tempDvar = getDvarInt( "bots_skill_allies_med" ); - self AddMenu( "man_team", 12, "Increase amount of med bots on allies team: " + _tempDvar, ::bot_teams, "alliesmedup", _tempDvar ); - self AddMenu( "man_team", 13, "Decrease amount of med bots on allies team: " + _tempDvar, ::bot_teams, "alliesmeddown", _tempDvar ); - - // - - self AddMenu( "Main", 2, "Bot settings", ::OpenSub, "set1", "" ); - self AddBack( "set1", "Main" ); - - _tempDvar = getDvarInt( "bots_loadout_reasonable" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 0, "Bots use only good class setups: " + _temp, ::bot_func, "reasonable", _tempDvar ); - - _tempDvar = getDvarInt( "bots_loadout_allow_op" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 1, "Bots can use op and annoying class setups: " + _temp, ::bot_func, "op", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_move" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 2, "Bots can move: " + _temp, ::bot_func, "move", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_knife" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 3, "Bots can knife: " + _temp, ::bot_func, "knife", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_fire" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 4, "Bots can fire: " + _temp, ::bot_func, "fire", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_nade" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 5, "Bots can nade: " + _temp, ::bot_func, "nade", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_take_carepackages" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 6, "Bots can take carepackages: " + _temp, ::bot_func, "care", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_obj" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 7, "Bots play the objective: " + _temp, ::bot_func, "obj", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_camp" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 8, "Bots can camp: " + _temp, ::bot_func, "camp", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_jumpdrop" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 9, "Bots can jump and dropshot: " + _temp, ::bot_func, "jump", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_target_other" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 10, "Bots can target other script objects: " + _temp, ::bot_func, "targetother", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_killstreak" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 11, "Bots can use killstreaks: " + _temp, ::bot_func, "killstreak", _tempDvar ); - - _tempDvar = getDvarInt( "bots_play_ads" ); - - if ( _tempDvar ) - { - _temp = "true"; - } - else - { - _temp = "false"; - } - - self AddMenu( "set1", 12, "Bots can ads: " + _temp, ::bot_func, "ads", _tempDvar ); -} - -bot_func( a, b ) -{ - switch ( a ) - { - case "reasonable": - setDvar( "bots_loadout_reasonable", !b ); - self iPrintln( "Bots using reasonable setups: " + !b ); - break; - - case "op": - setDvar( "bots_loadout_allow_op", !b ); - self iPrintln( "Bots using op setups: " + !b ); - break; - - case "move": - setDvar( "bots_play_move", !b ); - self iPrintln( "Bots move: " + !b ); - break; - - case "knife": - setDvar( "bots_play_knife", !b ); - self iPrintln( "Bots knife: " + !b ); - break; - - case "fire": - setDvar( "bots_play_fire", !b ); - self iPrintln( "Bots fire: " + !b ); - break; - - case "nade": - setDvar( "bots_play_nade", !b ); - self iPrintln( "Bots nade: " + !b ); - break; - - case "care": - setDvar( "bots_play_take_carepackages", !b ); - self iPrintln( "Bots take carepackages: " + !b ); - break; - - case "obj": - setDvar( "bots_play_obj", !b ); - self iPrintln( "Bots play the obj: " + !b ); - break; - - case "camp": - setDvar( "bots_play_camp", !b ); - self iPrintln( "Bots camp: " + !b ); - break; - - case "jump": - setDvar( "bots_play_jumpdrop", !b ); - self iPrintln( "Bots jump: " + !b ); - break; - - case "targetother": - setDvar( "bots_play_target_other", !b ); - self iPrintln( "Bots target other: " + !b ); - break; - - case "killstreak": - setDvar( "bots_play_killstreak", !b ); - self iPrintln( "Bots use killstreaks: " + !b ); - break; - - case "ads": - setDvar( "bots_play_ads", !b ); - self iPrintln( "Bots ads: " + !b ); - break; - } -} - -bot_teams( a, b ) -{ - switch ( a ) - { - case "team": - switch ( b ) - { - case "autoassign": - setdvar( "bots_team", "allies" ); - self iPrintlnBold( "Changed bot team to allies." ); - break; - - case "allies": - setdvar( "bots_team", "axis" ); - self iPrintlnBold( "Changed bot team to axis." ); - break; - - case "axis": - setdvar( "bots_team", "custom" ); - self iPrintlnBold( "Changed bot team to custom." ); - break; - - default: - setdvar( "bots_team", "autoassign" ); - self iPrintlnBold( "Changed bot team to autoassign." ); - break; - } - - break; - - case "teamup": - setdvar( "bots_team_amount", b + 1 ); - self iPrintln( ( b + 1 ) + " bot(s) will try to be on axis team." ); - break; - - case "teamdown": - setdvar( "bots_team_amount", b - 1 ); - self iPrintln( ( b - 1 ) + " bot(s) will try to be on axis team." ); - break; - - case "teamforce": - setDvar( "bots_team_force", !b ); - self iPrintln( "Forcing bots to team: " + !b ); - break; - - case "teammode": - setDvar( "bots_team_mode", !b ); - self iPrintln( "Only count bots on team: " + !b ); - break; - - case "skill": - switch ( b ) - { - case 0: - self iPrintlnBold( "Changed bot skill to easy." ); - setDvar( "bots_skill", 1 ); - break; - - case 1: - self iPrintlnBold( "Changed bot skill to easy-med." ); - setDvar( "bots_skill", 2 ); - break; - - case 2: - self iPrintlnBold( "Changed bot skill to medium." ); - setDvar( "bots_skill", 3 ); - break; - - case 3: - self iPrintlnBold( "Changed bot skill to med-hard." ); - setDvar( "bots_skill", 4 ); - break; - - case 4: - self iPrintlnBold( "Changed bot skill to hard." ); - setDvar( "bots_skill", 5 ); - break; - - case 5: - self iPrintlnBold( "Changed bot skill to very hard." ); - setDvar( "bots_skill", 6 ); - break; - - case 6: - self iPrintlnBold( "Changed bot skill to hardest." ); - setDvar( "bots_skill", 7 ); - break; - - case 7: - self iPrintlnBold( "Changed bot skill to custom. Base is easy." ); - setDvar( "bots_skill", 8 ); - break; - - case 8: - self iPrintlnBold( "Changed bot skill to complete random. Takes effect at restart." ); - setDvar( "bots_skill", 9 ); - break; - - default: - self iPrintlnBold( "Changed bot skill to random. Takes effect at restart." ); - setDvar( "bots_skill", 0 ); - break; - } - - break; - - case "axishardup": - setdvar( "bots_skill_axis_hard", ( b + 1 ) ); - self iPrintln( ( ( b + 1 ) ) + " hard bots will be on axis team." ); - break; - - case "axisharddown": - setdvar( "bots_skill_axis_hard", ( b - 1 ) ); - self iPrintln( ( ( b - 1 ) ) + " hard bots will be on axis team." ); - break; - - case "axismedup": - setdvar( "bots_skill_axis_med", ( b + 1 ) ); - self iPrintln( ( ( b + 1 ) ) + " med bots will be on axis team." ); - break; - - case "axismeddown": - setdvar( "bots_skill_axis_med", ( b - 1 ) ); - self iPrintln( ( ( b - 1 ) ) + " med bots will be on axis team." ); - break; - - case "allieshardup": - setdvar( "bots_skill_allies_hard", ( b + 1 ) ); - self iPrintln( ( ( b + 1 ) ) + " hard bots will be on allies team." ); - break; - - case "alliesharddown": - setdvar( "bots_skill_allies_hard", ( b - 1 ) ); - self iPrintln( ( ( b - 1 ) ) + " hard bots will be on allies team." ); - break; - - case "alliesmedup": - setdvar( "bots_skill_allies_med", ( b + 1 ) ); - self iPrintln( ( ( b + 1 ) ) + " med bots will be on allies team." ); - break; - - case "alliesmeddown": - setdvar( "bots_skill_allies_med", ( b - 1 ) ); - self iPrintln( ( ( b - 1 ) ) + " med bots will be on allies team." ); - break; - } -} - -man_bots( a, b ) -{ - switch ( a ) - { - case "add": - setdvar( "bots_manage_add", b ); - - if ( b == 1 ) - { - self iPrintln( "Adding " + b + " bot." ); - } - else - { - self iPrintln( "Adding " + b + " bots." ); - } - - break; - - case "kick": - result = false; - - for ( i = 0; i < b; i++ ) - { - tempBot = random( getBotArray() ); - - if ( isDefined( tempBot ) ) - { - kick( tempBot getEntityNumber(), "EXE_PLAYERKICKED" ); - result = true; - } - - wait 0.25; - } - - if ( !result ) - { - self iPrintln( "No bots to kick" ); - } - - break; - - case "autokick": - setDvar( "bots_manage_fill_kick", !b ); - self iPrintln( "Kicking bots when bots_fill is exceeded: " + !b ); - break; - - case "fillmode": - switch ( b ) - { - case 0: - setdvar( "bots_manage_fill_mode", 1 ); - self iPrintln( "bot_fill will now count only bots." ); - break; - - case 1: - setdvar( "bots_manage_fill_mode", 2 ); - self iPrintln( "bot_fill will now count everyone, adjusting to map." ); - break; - - case 2: - setdvar( "bots_manage_fill_mode", 3 ); - self iPrintln( "bot_fill will now count only bots, adjusting to map." ); - break; - - case 3: - setdvar( "bots_manage_fill_mode", 4 ); - self iPrintln( "bot_fill will now use bots as team balance." ); - break; - - default: - setdvar( "bots_manage_fill_mode", 0 ); - self iPrintln( "bot_fill will now count everyone." ); - break; - } - - break; - - case "fillup": - setdvar( "bots_manage_fill", b + 1 ); - self iPrintln( "Increased to maintain " + ( b + 1 ) + " bot(s)." ); - break; - - case "filldown": - setdvar( "bots_manage_fill", b - 1 ); - self iPrintln( "Decreased to maintain " + ( b - 1 ) + " bot(s)." ); - break; - - case "fillspec": - setDvar( "bots_manage_fill_spec", !b ); - self iPrintln( "Count players on spectator for bots_fill: " + !b ); - break; - } -} +/* + _menu + Author: INeedGames + Date: 05/11/2021 + The ingame menu. +*/ + +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include maps\mp\bots\_bot_utility; + +init() +{ + if ( getDvar( "bots_main_menu" ) == "" ) + { + setDvar( "bots_main_menu", true ); + } + + if ( !getDvarInt( "bots_main_menu" ) ) + { + return; + } + + thread watchPlayers(); +} + +watchPlayers() +{ + for ( ;; ) + { + wait 1; + + if ( !getDvarInt( "bots_main_menu" ) ) + { + return; + } + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[ i ]; + + if ( !player is_host() ) + { + continue; + } + + if ( isDefined( player.menuinit ) && player.menuinit ) + { + continue; + } + + player thread init_menu(); + } + } +} + +kill_menu() +{ + self notify( "bots_kill_menu" ); + self.menuinit = undefined; +} + +init_menu() +{ + self.menuinit = true; + + self.menuopen = false; + self.menu_player = undefined; + self.submenu = "Main"; + self.curs[ "Main" ][ "X" ] = 0; + self AddOptions(); + + self thread watchPlayerOpenMenu(); + self thread MenuSelect(); + self thread RightMenu(); + self thread LeftMenu(); + self thread UpMenu(); + self thread DownMenu(); + + self thread watchDisconnect(); + + self thread doGreetings(); +} + +watchDisconnect() +{ + self waittill_either( "disconnect", "bots_kill_menu" ); + + if ( self.menuopen ) + { + if ( isDefined( self.menutexty ) ) + { + for ( i = 0; i < self.menutexty.size; i++ ) + { + if ( isDefined( self.menutexty[ i ] ) ) + { + self.menutexty[ i ] destroy(); + } + } + } + + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.menutext.size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ] destroy(); + } + } + } + + if ( isDefined( self.menu ) && isDefined( self.menu[ "X" ] ) ) + { + if ( isDefined( self.menu[ "X" ][ "Shader" ] ) ) + { + self.menu[ "X" ][ "Shader" ] destroy(); + } + + if ( isDefined( self.menu[ "X" ][ "Scroller" ] ) ) + { + self.menu[ "X" ][ "Scroller" ] destroy(); + } + } + + if ( isDefined( self.menuversionhud ) ) + { + self.menuversionhud destroy(); + } + } +} + +doGreetings() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + wait 1; + self iPrintln( "Welcome to Bot Warfare " + self.name + "!" ); + wait 5; + self iPrintln( "Press [{+actionslot 1}] to open menu!" ); +} + +watchPlayerOpenMenu() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_open_menu", "+actionslot 1" ); + + for ( ;; ) + { + self waittill( "bots_open_menu" ); + + if ( !self.menuopen ) + { + self playLocalSound( "mouse_click" ); + self thread OpenSub( self.submenu ); + } + else + { + self playLocalSound( "mouse_click" ); + + if ( self.submenu != "Main" ) + { + self ExitSub(); + } + else + { + self ExitMenu(); + + if ( !gameFlag( "prematch_done" ) || level.gameended ) + { + self freezeControls( true ); + } + else + { + self freezecontrols( false ); + } + } + } + } +} + +MenuSelect() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_select", "+gostand" ); + + for ( ;; ) + { + self waittill( "bots_select" ); + + if ( self.menuopen ) + { + self playLocalSound( "mouse_click" ); + + if ( self.submenu == "Main" ) + { + self thread [[ self.option[ "Function" ][ self.submenu ][ self.curs[ "Main" ][ "X" ] ] ]]( self.option[ "Arg1" ][ self.submenu ][ self.curs[ "Main" ][ "X" ] ], self.option[ "Arg2" ][ self.submenu ][ self.curs[ "Main" ][ "X" ] ] ); + } + else + { + self thread [[ self.option[ "Function" ][ self.submenu ][ self.curs[ self.submenu ][ "Y" ] ] ]]( self.option[ "Arg1" ][ self.submenu ][ self.curs[ self.submenu ][ "Y" ] ], self.option[ "Arg2" ][ self.submenu ][ self.curs[ self.submenu ][ "Y" ] ] ); + } + } + } +} + +LeftMenu() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_left", "+moveleft" ); + + for ( ;; ) + { + self waittill( "bots_left" ); + + if ( self.menuopen && self.submenu == "Main" ) + { + self playLocalSound( "mouse_over" ); + self.curs[ "Main" ][ "X" ]--; + + if ( self.curs[ "Main" ][ "X" ] < 0 ) + { + self.curs[ "Main" ][ "X" ] = self.option[ "Name" ][ self.submenu ].size - 1; + } + + self CursMove( "X" ); + } + } +} + +RightMenu() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_right", "+moveright" ); + + for ( ;; ) + { + self waittill( "bots_right" ); + + if ( self.menuopen && self.submenu == "Main" ) + { + self playLocalSound( "mouse_over" ); + self.curs[ "Main" ][ "X" ]++; + + if ( self.curs[ "Main" ][ "X" ] > self.option[ "Name" ][ self.submenu ].size - 1 ) + { + self.curs[ "Main" ][ "X" ] = 0; + } + + self CursMove( "X" ); + } + } +} + +UpMenu() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_up", "+forward" ); + + for ( ;; ) + { + self waittill( "bots_up" ); + + if ( self.menuopen && self.submenu != "Main" ) + { + self playLocalSound( "mouse_over" ); + self.curs[ self.submenu ][ "Y" ]--; + + if ( self.curs[ self.submenu ][ "Y" ] < 0 ) + { + self.curs[ self.submenu ][ "Y" ] = self.option[ "Name" ][ self.submenu ].size - 1; + } + + self CursMove( "Y" ); + } + } +} + +DownMenu() +{ + self endon ( "disconnect" ); + self endon ( "bots_kill_menu" ); + + self notifyOnPlayerCommand( "bots_down", "+back" ); + + for ( ;; ) + { + self waittill( "bots_down" ); + + if ( self.menuopen && self.submenu != "Main" ) + { + self playLocalSound( "mouse_over" ); + self.curs[ self.submenu ][ "Y" ]++; + + if ( self.curs[ self.submenu ][ "Y" ] > self.option[ "Name" ][ self.submenu ].size - 1 ) + { + self.curs[ self.submenu ][ "Y" ] = 0; + } + + self CursMove( "Y" ); + } + } +} + +OpenSub( menu, menu2 ) +{ + if ( menu != "Main" && ( !isDefined( self.menu[ menu ] ) || !!isDefined( self.menu[ menu ][ "FirstOpen" ] ) ) ) + { + self.curs[ menu ][ "Y" ] = 0; + self.menu[ menu ][ "FirstOpen" ] = true; + } + + logoldi = true; + self.submenu = menu; + + if ( self.submenu == "Main" ) + { + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.menutext.size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ] destroy(); + } + } + } + + if ( isDefined( self.menu ) && isDefined( self.menu[ "X" ] ) ) + { + if ( isDefined( self.menu[ "X" ][ "Shader" ] ) ) + { + self.menu[ "X" ][ "Shader" ] destroy(); + } + + if ( isDefined( self.menu[ "X" ][ "Scroller" ] ) ) + { + self.menu[ "X" ][ "Scroller" ] destroy(); + } + } + + if ( isDefined( self.menuversionhud ) ) + { + self.menuversionhud destroy(); + } + + for ( i = 0 ; i < self.option[ "Name" ][ self.submenu ].size ; i++ ) + { + self.menutext[ i ] = self createfontstring( "default", 1.6 ); + self.menutext[ i ] setpoint( "CENTER", "CENTER", -300 + ( i * 100 ), -226 ); + self.menutext[ i ] settext( self.option[ "Name" ][ self.submenu ][ i ] ); + + if ( logOldi ) + { + self.oldi = i; + } + + if ( self.menutext[ i ].x > 300 ) + { + logOldi = false; + x = i - self.oldi; + self.menutext[ i ] setpoint( "CENTER", "CENTER", ( ( ( -300 ) - ( i * 100 ) ) + ( i * 100 ) ) + ( x * 100 ), -196 ); + } + + self.menutext[ i ].alpha = 1; + self.menutext[ i ].sort = 999; + } + + if ( !logOldi ) + { + self.menu[ "X" ][ "Shader" ] = self createRectangle( "CENTER", "CENTER", 0, -225, 1000, 90, ( 0, 0, 0 ), -2, 1, "white" ); + } + else + { + self.menu[ "X" ][ "Shader" ] = self createRectangle( "CENTER", "CENTER", 0, -225, 1000, 30, ( 0, 0, 0 ), -2, 1, "white" ); + } + + self.menu[ "X" ][ "Scroller" ] = self createRectangle( "CENTER", "CENTER", self.menutext[ self.curs[ "Main" ][ "X" ] ].x, -225, 105, 22, ( 1, 0, 0 ), -1, 1, "white" ); + + self CursMove( "X" ); + + self.menuversionhud = initHudElem( "Bot Warfare " + level.bw_version, 0, 0 ); + + self.menuopen = true; + } + else + { + if ( isDefined( self.menutexty ) ) + { + for ( i = 0 ; i < self.menutexty.size ; i++ ) + { + if ( isDefined( self.menutexty[ i ] ) ) + { + self.menutexty[ i ] destroy(); + } + } + } + + for ( i = 0 ; i < self.option[ "Name" ][ self.submenu ].size ; i++ ) + { + self.menutexty[ i ] = self createfontstring( "default", 1.6 ); + self.menutexty[ i ] setpoint( "CENTER", "CENTER", self.menutext[ self.curs[ "Main" ][ "X" ] ].x, -160 + ( i * 20 ) ); + self.menutexty[ i ] settext( self.option[ "Name" ][ self.submenu ][ i ] ); + self.menutexty[ i ].alpha = 1; + self.menutexty[ i ].sort = 999; + } + + self CursMove( "Y" ); + } +} + +CursMove( direction ) +{ + self notify( "scrolled" ); + + if ( self.submenu == "Main" ) + { + self.menu[ "X" ][ "Scroller" ].x = self.menutext[ self.curs[ "Main" ][ "X" ] ].x; + self.menu[ "X" ][ "Scroller" ].y = self.menutext[ self.curs[ "Main" ][ "X" ] ].y; + + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.menutext.size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ].fontscale = 1.5; + self.menutext[ i ].color = ( 1, 1, 1 ); + self.menutext[ i ].glowalpha = 0; + } + } + } + + self thread ShowOptionOn( direction ); + } + else + { + if ( isDefined( self.menutexty ) ) + { + for ( i = 0; i < self.menutexty.size; i++ ) + { + if ( isDefined( self.menutexty[ i ] ) ) + { + self.menutexty[ i ].fontscale = 1.5; + self.menutexty[ i ].color = ( 1, 1, 1 ); + self.menutexty[ i ].glowalpha = 0; + } + } + } + + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.menutext.size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ].fontscale = 1.5; + self.menutext[ i ].color = ( 1, 1, 1 ); + self.menutext[ i ].glowalpha = 0; + } + } + } + + self thread ShowOptionOn( direction ); + } +} + +ShowOptionOn( variable ) +{ + self endon( "scrolled" ); + self endon( "disconnect" ); + self endon( "exit" ); + self endon( "bots_kill_menu" ); + + for ( time = 0;; time += 0.05 ) + { + if ( !self isOnGround() && isAlive( self ) && gameFlag( "prematch_done" ) && !level.gameended ) + { + self freezecontrols( false ); + } + else + { + self freezecontrols( true ); + } + + self setClientDvar( "r_blur", "5" ); + self setClientDvar( "sc_blur", "15" ); + self addOptions(); + + if ( self.submenu == "Main" ) + { + if ( isDefined( self.curs[ self.submenu ][ variable ] ) && isDefined( self.menutext ) && isDefined( self.menutext[ self.curs[ self.submenu ][ variable ] ] ) ) + { + self.menutext[ self.curs[ self.submenu ][ variable ] ].fontscale = 2.0; + // self.menutext[ self.curs[ self.submenu ][ variable ] ].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); + color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); + + if ( int( time * 4 ) % 2 ) + { + color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); + } + + self.menutext[ self.curs[ self.submenu ][ variable ] ].color = color; + } + + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.option[ "Name" ][ self.submenu ].size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ] settext( self.option[ "Name" ][ self.submenu ][ i ] ); + } + } + } + } + else + { + if ( isDefined( self.curs[ self.submenu ][ variable ] ) && isDefined( self.menutexty ) && isDefined( self.menutexty[ self.curs[ self.submenu ][ variable ] ] ) ) + { + self.menutexty[ self.curs[ self.submenu ][ variable ] ].fontscale = 2.0; + // self.menutexty[ self.curs[ self.submenu ][ variable ] ].color = (randomInt(256)/255, randomInt(256)/255, randomInt(256)/255); + color = ( 6 / 255, 69 / 255, 173 + randomIntRange( -5, 5 ) / 255 ); + + if ( int( time * 4 ) % 2 ) + { + color = ( 11 / 255, 0 / 255, 128 + randomIntRange( -10, 10 ) / 255 ); + } + + self.menutexty[ self.curs[ self.submenu ][ variable ] ].color = color; + } + + if ( isDefined( self.menutexty ) ) + { + for ( i = 0; i < self.option[ "Name" ][ self.submenu ].size; i++ ) + { + if ( isDefined( self.menutexty[ i ] ) ) + { + self.menutexty[ i ] settext( self.option[ "Name" ][ self.submenu ][ i ] ); + } + } + } + } + + wait 0.05; + } +} + +AddMenu( menu, num, text, function, arg1, arg2 ) +{ + self.option[ "Name" ][ menu ][ num ] = text; + self.option[ "Function" ][ menu ][ num ] = function; + self.option[ "Arg1" ][ menu ][ num ] = arg1; + self.option[ "Arg2" ][ menu ][ num ] = arg2; +} + +AddBack( menu, back ) +{ + self.menu[ "Back" ][ menu ] = back; +} + +ExitSub() +{ + if ( isDefined( self.menutexty ) ) + { + for ( i = 0; i < self.menutexty.size; i++ ) + { + if ( isDefined( self.menutexty[ i ] ) ) + { + self.menutexty[ i ] destroy(); + } + } + } + + self.submenu = self.menu[ "Back" ][ self.submenu ]; + + if ( self.submenu == "Main" ) + { + self CursMove( "X" ); + } + else + { + self CursMove( "Y" ); + } +} + +ExitMenu() +{ + if ( isDefined( self.menutext ) ) + { + for ( i = 0; i < self.menutext.size; i++ ) + { + if ( isDefined( self.menutext[ i ] ) ) + { + self.menutext[ i ] destroy(); + } + } + } + + if ( isDefined( self.menu ) && isDefined( self.menu[ "X" ] ) ) + { + if ( isDefined( self.menu[ "X" ][ "Shader" ] ) ) + { + self.menu[ "X" ][ "Shader" ] destroy(); + } + + if ( isDefined( self.menu[ "X" ][ "Scroller" ] ) ) + { + self.menu[ "X" ][ "Scroller" ] destroy(); + } + } + + if ( isDefined( self.menuversionhud ) ) + { + self.menuversionhud destroy(); + } + + self.menuopen = false; + self notify( "exit" ); + + self setClientDvar( "r_blur", "0" ); + self setClientDvar( "sc_blur", "2" ); +} + +initHudElem( txt, xl, yl ) +{ + hud = NewClientHudElem( self ); + hud setText( txt ); + hud.alignx = "center"; + hud.aligny = "bottom"; + hud.horzalign = "center"; + hud.vertalign = "bottom"; + hud.x = xl; + hud.y = yl; + hud.foreground = true; + hud.fontscale = 1; + hud.font = "objective"; + hud.alpha = 1; + hud.glow = 0; + hud.glowcolor = ( 0, 0, 0 ); + hud.glowalpha = 1; + hud.color = ( 1.0, 1.0, 1.0 ); + + return hud; +} + +createRectangle( align, relative, x, y, width, height, color, sort, alpha, shader ) +{ + barElemBG = newClientHudElem( self ); + barElemBG.elemtype = "bar_"; + barElemBG.width = width; + barElemBG.height = height; + barElemBG.align = align; + barElemBG.relative = relative; + barElemBG.xoffset = 0; + barElemBG.yoffset = 0; + barElemBG.children = []; + barElemBG.sort = sort; + barElemBG.color = color; + barElemBG.alpha = alpha; + barElemBG setParent( level.uiparent ); + barElemBG setShader( shader, width, height ); + barElemBG.hidden = false; + barElemBG setPoint( align, relative, x, y ); + return barElemBG; +} + +AddOptions() +{ + self AddMenu( "Main", 0, "Manage bots", ::OpenSub, "man_bots", "" ); + self AddBack( "man_bots", "Main" ); + + _temp = ""; + _tempDvar = getDvarInt( "bots_manage_add" ); + self AddMenu( "man_bots", 0, "Add 1 bot", ::man_bots, "add", 1 + _tempDvar ); + self AddMenu( "man_bots", 1, "Add 3 bot", ::man_bots, "add", 3 + _tempDvar ); + self AddMenu( "man_bots", 2, "Add 7 bot", ::man_bots, "add", 7 + _tempDvar ); + self AddMenu( "man_bots", 3, "Add 11 bot", ::man_bots, "add", 11 + _tempDvar ); + self AddMenu( "man_bots", 4, "Add 17 bot", ::man_bots, "add", 17 + _tempDvar ); + self AddMenu( "man_bots", 5, "Kick a bot", ::man_bots, "kick", 1 ); + self AddMenu( "man_bots", 6, "Kick all bots", ::man_bots, "kick", getBotArray().size ); + + _tempDvar = getDvarInt( "bots_manage_fill_kick" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "man_bots", 7, "Toggle auto bot kicking: " + _temp, ::man_bots, "autokick", _tempDvar ); + + _tempDvar = getDvarInt( "bots_manage_fill_mode" ); + + switch ( _tempDvar ) + { + case 0: + _temp = "everyone"; + break; + + case 1: + _temp = "just bots"; + break; + + case 2: + _temp = "everyone, adjust to map"; + break; + + case 3: + _temp = "just bots, adjust to map"; + break; + + case 4: + _temp = "bots used as team balance"; + break; + + default: + _temp = "out of range"; + break; + } + + self AddMenu( "man_bots", 8, "Change bot_fill_mode: " + _temp, ::man_bots, "fillmode", _tempDvar ); + + _tempDvar = getDvarInt( "bots_manage_fill" ); + self AddMenu( "man_bots", 9, "Increase bots to keep in-game: " + _tempDvar, ::man_bots, "fillup", _tempDvar ); + self AddMenu( "man_bots", 10, "Decrease bots to keep in-game: " + _tempDvar, ::man_bots, "filldown", _tempDvar ); + + _tempDvar = getDvarInt( "bots_manage_fill_spec" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "man_bots", 11, "Count players for fill on spectator: " + _temp, ::man_bots, "fillspec", _tempDvar ); + + // + + self AddMenu( "Main", 1, "Teams and difficulty", ::OpenSub, "man_team", "" ); + self AddBack( "man_team", "Main" ); + + _tempDvar = getdvar( "bots_team" ); + self AddMenu( "man_team", 0, "Change bot team: " + _tempDvar, ::bot_teams, "team", _tempDvar ); + + _tempDvar = getDvarInt( "bots_team_amount" ); + self AddMenu( "man_team", 1, "Increase bots to be on axis team: " + _tempDvar, ::bot_teams, "teamup", _tempDvar ); + self AddMenu( "man_team", 2, "Decrease bots to be on axis team: " + _tempDvar, ::bot_teams, "teamdown", _tempDvar ); + + _tempDvar = getDvarInt( "bots_team_force" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "man_team", 3, "Toggle forcing bots on team: " + _temp, ::bot_teams, "teamforce", _tempDvar ); + + _tempDvar = getDvarInt( "bots_team_mode" ); + + if ( _tempDvar ) + { + _temp = "only bots"; + } + else + { + _temp = "everyone"; + } + + self AddMenu( "man_team", 4, "Toggle bot_team_bot: " + _temp, ::bot_teams, "teammode", _tempDvar ); + + _tempDvar = getdvarint( "bots_skill" ); + + switch ( _tempDvar ) + { + case 0: + _temp = "random for all"; + break; + + case 1: + _temp = "too easy"; + break; + + case 2: + _temp = "easy"; + break; + + case 3: + _temp = "easy-medium"; + break; + + case 4: + _temp = "medium"; + break; + + case 5: + _temp = "hard"; + break; + + case 6: + _temp = "very hard"; + break; + + case 7: + _temp = "hardest"; + break; + + case 8: + _temp = "custom"; + break; + + case 9: + _temp = "complete random"; + break; + + default: + _temp = "out of range"; + break; + } + + self AddMenu( "man_team", 5, "Change bot difficulty: " + _temp, ::bot_teams, "skill", _tempDvar ); + + _tempDvar = getDvarInt( "bots_skill_axis_hard" ); + self AddMenu( "man_team", 6, "Increase amount of hard bots on axis team: " + _tempDvar, ::bot_teams, "axishardup", _tempDvar ); + self AddMenu( "man_team", 7, "Decrease amount of hard bots on axis team: " + _tempDvar, ::bot_teams, "axisharddown", _tempDvar ); + + _tempDvar = getDvarInt( "bots_skill_axis_med" ); + self AddMenu( "man_team", 8, "Increase amount of med bots on axis team: " + _tempDvar, ::bot_teams, "axismedup", _tempDvar ); + self AddMenu( "man_team", 9, "Decrease amount of med bots on axis team: " + _tempDvar, ::bot_teams, "axismeddown", _tempDvar ); + + _tempDvar = getDvarInt( "bots_skill_allies_hard" ); + self AddMenu( "man_team", 10, "Increase amount of hard bots on allies team: " + _tempDvar, ::bot_teams, "allieshardup", _tempDvar ); + self AddMenu( "man_team", 11, "Decrease amount of hard bots on allies team: " + _tempDvar, ::bot_teams, "alliesharddown", _tempDvar ); + + _tempDvar = getDvarInt( "bots_skill_allies_med" ); + self AddMenu( "man_team", 12, "Increase amount of med bots on allies team: " + _tempDvar, ::bot_teams, "alliesmedup", _tempDvar ); + self AddMenu( "man_team", 13, "Decrease amount of med bots on allies team: " + _tempDvar, ::bot_teams, "alliesmeddown", _tempDvar ); + + // + + self AddMenu( "Main", 2, "Bot settings", ::OpenSub, "set1", "" ); + self AddBack( "set1", "Main" ); + + _tempDvar = getDvarInt( "bots_loadout_reasonable" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 0, "Bots use only good class setups: " + _temp, ::bot_func, "reasonable", _tempDvar ); + + _tempDvar = getDvarInt( "bots_loadout_allow_op" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 1, "Bots can use op and annoying class setups: " + _temp, ::bot_func, "op", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_move" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 2, "Bots can move: " + _temp, ::bot_func, "move", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_knife" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 3, "Bots can knife: " + _temp, ::bot_func, "knife", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_fire" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 4, "Bots can fire: " + _temp, ::bot_func, "fire", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_nade" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 5, "Bots can nade: " + _temp, ::bot_func, "nade", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_take_carepackages" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 6, "Bots can take carepackages: " + _temp, ::bot_func, "care", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_obj" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 7, "Bots play the objective: " + _temp, ::bot_func, "obj", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_camp" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 8, "Bots can camp: " + _temp, ::bot_func, "camp", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_jumpdrop" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 9, "Bots can jump and dropshot: " + _temp, ::bot_func, "jump", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_target_other" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 10, "Bots can target other script objects: " + _temp, ::bot_func, "targetother", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_killstreak" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 11, "Bots can use killstreaks: " + _temp, ::bot_func, "killstreak", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_ads" ); + + if ( _tempDvar ) + { + _temp = "true"; + } + else + { + _temp = "false"; + } + + self AddMenu( "set1", 12, "Bots can ads: " + _temp, ::bot_func, "ads", _tempDvar ); +} + +bot_func( a, b ) +{ + switch ( a ) + { + case "reasonable": + setDvar( "bots_loadout_reasonable", !b ); + self iPrintln( "Bots using reasonable setups: " + !b ); + break; + + case "op": + setDvar( "bots_loadout_allow_op", !b ); + self iPrintln( "Bots using op setups: " + !b ); + break; + + case "move": + setDvar( "bots_play_move", !b ); + self iPrintln( "Bots move: " + !b ); + break; + + case "knife": + setDvar( "bots_play_knife", !b ); + self iPrintln( "Bots knife: " + !b ); + break; + + case "fire": + setDvar( "bots_play_fire", !b ); + self iPrintln( "Bots fire: " + !b ); + break; + + case "nade": + setDvar( "bots_play_nade", !b ); + self iPrintln( "Bots nade: " + !b ); + break; + + case "care": + setDvar( "bots_play_take_carepackages", !b ); + self iPrintln( "Bots take carepackages: " + !b ); + break; + + case "obj": + setDvar( "bots_play_obj", !b ); + self iPrintln( "Bots play the obj: " + !b ); + break; + + case "camp": + setDvar( "bots_play_camp", !b ); + self iPrintln( "Bots camp: " + !b ); + break; + + case "jump": + setDvar( "bots_play_jumpdrop", !b ); + self iPrintln( "Bots jump: " + !b ); + break; + + case "targetother": + setDvar( "bots_play_target_other", !b ); + self iPrintln( "Bots target other: " + !b ); + break; + + case "killstreak": + setDvar( "bots_play_killstreak", !b ); + self iPrintln( "Bots use killstreaks: " + !b ); + break; + + case "ads": + setDvar( "bots_play_ads", !b ); + self iPrintln( "Bots ads: " + !b ); + break; + } +} + +bot_teams( a, b ) +{ + switch ( a ) + { + case "team": + switch ( b ) + { + case "autoassign": + setdvar( "bots_team", "allies" ); + self iPrintlnBold( "Changed bot team to allies." ); + break; + + case "allies": + setdvar( "bots_team", "axis" ); + self iPrintlnBold( "Changed bot team to axis." ); + break; + + case "axis": + setdvar( "bots_team", "custom" ); + self iPrintlnBold( "Changed bot team to custom." ); + break; + + default: + setdvar( "bots_team", "autoassign" ); + self iPrintlnBold( "Changed bot team to autoassign." ); + break; + } + + break; + + case "teamup": + setdvar( "bots_team_amount", b + 1 ); + self iPrintln( ( b + 1 ) + " bot(s) will try to be on axis team." ); + break; + + case "teamdown": + setdvar( "bots_team_amount", b - 1 ); + self iPrintln( ( b - 1 ) + " bot(s) will try to be on axis team." ); + break; + + case "teamforce": + setDvar( "bots_team_force", !b ); + self iPrintln( "Forcing bots to team: " + !b ); + break; + + case "teammode": + setDvar( "bots_team_mode", !b ); + self iPrintln( "Only count bots on team: " + !b ); + break; + + case "skill": + switch ( b ) + { + case 0: + self iPrintlnBold( "Changed bot skill to easy." ); + setDvar( "bots_skill", 1 ); + break; + + case 1: + self iPrintlnBold( "Changed bot skill to easy-med." ); + setDvar( "bots_skill", 2 ); + break; + + case 2: + self iPrintlnBold( "Changed bot skill to medium." ); + setDvar( "bots_skill", 3 ); + break; + + case 3: + self iPrintlnBold( "Changed bot skill to med-hard." ); + setDvar( "bots_skill", 4 ); + break; + + case 4: + self iPrintlnBold( "Changed bot skill to hard." ); + setDvar( "bots_skill", 5 ); + break; + + case 5: + self iPrintlnBold( "Changed bot skill to very hard." ); + setDvar( "bots_skill", 6 ); + break; + + case 6: + self iPrintlnBold( "Changed bot skill to hardest." ); + setDvar( "bots_skill", 7 ); + break; + + case 7: + self iPrintlnBold( "Changed bot skill to custom. Base is easy." ); + setDvar( "bots_skill", 8 ); + break; + + case 8: + self iPrintlnBold( "Changed bot skill to complete random. Takes effect at restart." ); + setDvar( "bots_skill", 9 ); + break; + + default: + self iPrintlnBold( "Changed bot skill to random. Takes effect at restart." ); + setDvar( "bots_skill", 0 ); + break; + } + + break; + + case "axishardup": + setdvar( "bots_skill_axis_hard", ( b + 1 ) ); + self iPrintln( ( ( b + 1 ) ) + " hard bots will be on axis team." ); + break; + + case "axisharddown": + setdvar( "bots_skill_axis_hard", ( b - 1 ) ); + self iPrintln( ( ( b - 1 ) ) + " hard bots will be on axis team." ); + break; + + case "axismedup": + setdvar( "bots_skill_axis_med", ( b + 1 ) ); + self iPrintln( ( ( b + 1 ) ) + " med bots will be on axis team." ); + break; + + case "axismeddown": + setdvar( "bots_skill_axis_med", ( b - 1 ) ); + self iPrintln( ( ( b - 1 ) ) + " med bots will be on axis team." ); + break; + + case "allieshardup": + setdvar( "bots_skill_allies_hard", ( b + 1 ) ); + self iPrintln( ( ( b + 1 ) ) + " hard bots will be on allies team." ); + break; + + case "alliesharddown": + setdvar( "bots_skill_allies_hard", ( b - 1 ) ); + self iPrintln( ( ( b - 1 ) ) + " hard bots will be on allies team." ); + break; + + case "alliesmedup": + setdvar( "bots_skill_allies_med", ( b + 1 ) ); + self iPrintln( ( ( b + 1 ) ) + " med bots will be on allies team." ); + break; + + case "alliesmeddown": + setdvar( "bots_skill_allies_med", ( b - 1 ) ); + self iPrintln( ( ( b - 1 ) ) + " med bots will be on allies team." ); + break; + } +} + +man_bots( a, b ) +{ + switch ( a ) + { + case "add": + setdvar( "bots_manage_add", b ); + + if ( b == 1 ) + { + self iPrintln( "Adding " + b + " bot." ); + } + else + { + self iPrintln( "Adding " + b + " bots." ); + } + + break; + + case "kick": + result = false; + + for ( i = 0; i < b; i++ ) + { + tempBot = random( getBotArray() ); + + if ( isDefined( tempBot ) ) + { + kick( tempBot getEntityNumber(), "EXE_PLAYERKICKED" ); + result = true; + } + + wait 0.25; + } + + if ( !result ) + { + self iPrintln( "No bots to kick" ); + } + + break; + + case "autokick": + setDvar( "bots_manage_fill_kick", !b ); + self iPrintln( "Kicking bots when bots_fill is exceeded: " + !b ); + break; + + case "fillmode": + switch ( b ) + { + case 0: + setdvar( "bots_manage_fill_mode", 1 ); + self iPrintln( "bot_fill will now count only bots." ); + break; + + case 1: + setdvar( "bots_manage_fill_mode", 2 ); + self iPrintln( "bot_fill will now count everyone, adjusting to map." ); + break; + + case 2: + setdvar( "bots_manage_fill_mode", 3 ); + self iPrintln( "bot_fill will now count only bots, adjusting to map." ); + break; + + case 3: + setdvar( "bots_manage_fill_mode", 4 ); + self iPrintln( "bot_fill will now use bots as team balance." ); + break; + + default: + setdvar( "bots_manage_fill_mode", 0 ); + self iPrintln( "bot_fill will now count everyone." ); + break; + } + + break; + + case "fillup": + setdvar( "bots_manage_fill", b + 1 ); + self iPrintln( "Increased to maintain " + ( b + 1 ) + " bot(s)." ); + break; + + case "filldown": + setdvar( "bots_manage_fill", b - 1 ); + self iPrintln( "Decreased to maintain " + ( b - 1 ) + " bot(s)." ); + break; + + case "fillspec": + setDvar( "bots_manage_fill_spec", !b ); + self iPrintln( "Count players on spectator for bots_fill: " + !b ); + break; + } +} diff --git a/maps/mp/bots/_wp_editor.gsc b/maps/mp/bots/_wp_editor.gsc index 08ae5a1..d693703 100644 --- a/maps/mp/bots/_wp_editor.gsc +++ b/maps/mp/bots/_wp_editor.gsc @@ -77,7 +77,7 @@ init() level.waypoints = []; } - level.waypointCount = 0; + level.waypointcount = 0; level waittill( "connected", player ); player thread onPlayerSpawned(); @@ -99,8 +99,8 @@ StartDev() self endon( "disconnect" ); self endon( "death" ); - level.wpToLink = -1; - level.autoLink = false; + level.wptolink = -1; + level.autolink = false; self.nearest = -1; self takeAllWeapons(); @@ -239,7 +239,7 @@ clearWpLinks() return; } - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { level.waypoints[ i ].drawn_links = []; } @@ -328,7 +328,7 @@ updateWaypointsStats() wait 0.05; intTimer += 50; - totalWpsHud setValue( level.waypointCount ); + totalWpsHud setValue( level.waypointcount ); closest = -1; myEye = self getEye(); @@ -341,7 +341,7 @@ updateWaypointsStats() clearWpLinks(); } - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { if ( closest == -1 || closer( self.origin, level.waypoints[ i ].origin, level.waypoints[ closest ].origin ) ) { @@ -388,7 +388,7 @@ updateWaypointsStats() type setText( buildTypeString( self.nearest ) ); - wpToLink setValue( level.wpToLink ); + wpToLink setValue( level.wptolink ); infotext.x = infotext.x - 2; @@ -472,17 +472,17 @@ watchAutoLinkCommand() { self waittill( "[{+frag}]" ); - if ( level.autoLink ) + if ( level.autolink ) { self iPrintlnBold( "Auto link disabled" ); - level.autoLink = false; - level.wpToLink = -1; + level.autolink = false; + level.wptolink = -1; } else { self iPrintlnBold( "Auto link enabled" ); - level.autoLink = true; - level.wpToLink = self.nearest; + level.autolink = true; + level.wptolink = self.nearest; } } } @@ -563,7 +563,7 @@ watchSaveWaypointsCommand() logprint( "\n\n" + mpnm + "()\n{\n/*" ); logprint( "*/waypoints = [];\n/*" ); - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { logprint( "*/waypoints[ " + i + " ] = spawnstruct();\n/*" ); logprint( "*/waypoints[ " + i + " ].origin = " + level.waypoints[ i ].origin + ";\n/*" ); @@ -590,11 +590,11 @@ watchSaveWaypointsCommand() filename = "waypoints/" + getdvar( "mapname" ) + "_wp.csv"; PrintLn( "********* Start Bot Warfare WPDump *********" ); - PrintLn( level.waypointCount ); + PrintLn( level.waypointcount ); - BotBuiltinFileWrite( filename, level.waypointCount + "\n", "write" ); + BotBuiltinFileWrite( filename, level.waypointcount + "\n", "write" ); - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { str = ""; wp = level.waypoints[ i ]; @@ -654,17 +654,17 @@ LoadWaypoints() checkForWarnings() { - if ( level.waypointCount <= 0 ) + if ( level.waypointcount <= 0 ) { - self iprintln( "WARNING: waypointCount is " + level.waypointCount ); + self iprintln( "WARNING: waypointCount is " + level.waypointcount ); } - if ( level.waypointCount != level.waypoints.size ) + if ( level.waypointcount != level.waypoints.size ) { self iprintln( "WARNING: waypointCount is not " + level.waypoints.size ); } - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { if ( !isDefined( level.waypoints[ i ] ) ) { @@ -719,9 +719,9 @@ checkForWarnings() // check reachability, assume bidirectional graph - wpIdx = randomInt( level.waypointCount ); + wpIdx = randomInt( level.waypointcount ); - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { if ( i % 5 == 0 ) { @@ -743,46 +743,46 @@ UnLinkWaypoint( nwp ) { if ( nwp == -1 || distance( self.origin, level.waypoints[ nwp ].origin ) > getDvarFloat( "bots_main_debug_minDist" ) ) { - self iprintln( "Waypoint Unlink Cancelled " + level.wpToLink ); - level.wpToLink = -1; + self iprintln( "Waypoint Unlink Cancelled " + level.wptolink ); + level.wptolink = -1; return; } - if ( level.wpToLink == -1 || nwp == level.wpToLink ) + if ( level.wptolink == -1 || nwp == level.wptolink ) { - level.wpToLink = nwp; + level.wptolink = nwp; self iprintln( "Waypoint Unlink Started " + nwp ); return; } - level.waypoints[ nwp ].children = array_remove( level.waypoints[ nwp ].children, level.wpToLink ); - level.waypoints[ level.wpToLink ].children = array_remove( level.waypoints[ level.wpToLink ].children, nwp ); + level.waypoints[ nwp ].children = array_remove( level.waypoints[ nwp ].children, level.wptolink ); + level.waypoints[ level.wptolink ].children = array_remove( level.waypoints[ level.wptolink ].children, nwp ); - self iprintln( "Waypoint " + nwp + " Broken to " + level.wpToLink ); - level.wpToLink = -1; + self iprintln( "Waypoint " + nwp + " Broken to " + level.wptolink ); + level.wptolink = -1; } LinkWaypoint( nwp ) { if ( nwp == -1 || distance( self.origin, level.waypoints[ nwp ].origin ) > getDvarFloat( "bots_main_debug_minDist" ) ) { - self iprintln( "Waypoint Link Cancelled " + level.wpToLink ); - level.wpToLink = -1; + self iprintln( "Waypoint Link Cancelled " + level.wptolink ); + level.wptolink = -1; return; } - if ( level.wpToLink == -1 || nwp == level.wpToLink ) + if ( level.wptolink == -1 || nwp == level.wptolink ) { - level.wpToLink = nwp; + level.wptolink = nwp; self iprintln( "Waypoint Link Started " + nwp ); return; } weGood = true; - for ( i = level.waypoints[ level.wpToLink ].children.size - 1; i >= 0; i-- ) + for ( i = level.waypoints[ level.wptolink ].children.size - 1; i >= 0; i-- ) { - child = level.waypoints[ level.wpToLink ].children[ i ]; + child = level.waypoints[ level.wptolink ].children[ i ]; if ( child == nwp ) { @@ -797,7 +797,7 @@ LinkWaypoint( nwp ) { child = level.waypoints[ nwp ].children[ i ]; - if ( child == level.wpToLink ) + if ( child == level.wptolink ) { weGood = false; break; @@ -807,16 +807,16 @@ LinkWaypoint( nwp ) if ( !weGood ) { - self iprintln( "Waypoint Link Cancelled " + nwp + " and " + level.wpToLink + " already linked." ); - level.wpToLink = -1; + self iprintln( "Waypoint Link Cancelled " + nwp + " and " + level.wptolink + " already linked." ); + level.wptolink = -1; return; } - level.waypoints[ level.wpToLink ].children[ level.waypoints[ level.wpToLink ].children.size ] = nwp; - level.waypoints[ nwp ].children[ level.waypoints[ nwp ].children.size ] = level.wpToLink; + level.waypoints[ level.wptolink ].children[ level.waypoints[ level.wptolink ].children.size ] = nwp; + level.waypoints[ nwp ].children[ level.waypoints[ nwp ].children.size ] = level.wptolink; - self iprintln( "Waypoint " + nwp + " Linked to " + level.wpToLink ); - level.wpToLink = -1; + self iprintln( "Waypoint " + nwp + " Linked to " + level.wptolink ); + level.wptolink = -1; } DeleteWaypoint( nwp ) @@ -827,7 +827,7 @@ DeleteWaypoint( nwp ) return; } - level.wpToLink = -1; + level.wptolink = -1; for ( i = level.waypoints[ nwp ].children.size - 1; i >= 0; i-- ) { @@ -836,7 +836,7 @@ DeleteWaypoint( nwp ) level.waypoints[ child ].children = array_remove( level.waypoints[ child ].children, nwp ); } - for ( i = 0; i < level.waypointCount; i++ ) + for ( i = 0; i < level.waypointcount; i++ ) { for ( h = level.waypoints[ i ].children.size - 1; h >= 0; h-- ) { @@ -847,11 +847,11 @@ DeleteWaypoint( nwp ) } } - for ( entry = 0; entry < level.waypointCount; entry++ ) + for ( entry = 0; entry < level.waypointcount; entry++ ) { if ( entry == nwp ) { - while ( entry < level.waypointCount - 1 ) + while ( entry < level.waypointcount - 1 ) { level.waypoints[ entry ] = level.waypoints[ entry + 1 ]; entry++; @@ -862,74 +862,74 @@ DeleteWaypoint( nwp ) } } - level.waypointCount--; + level.waypointcount--; self iprintln( "DelWp " + nwp ); } AddWaypoint() { - level.waypoints[ level.waypointCount ] = spawnstruct(); + level.waypoints[ level.waypointcount ] = spawnstruct(); pos = self getOrigin(); - level.waypoints[ level.waypointCount ].origin = pos; + level.waypoints[ level.waypointcount ].origin = pos; - if ( isDefined( self.javelinTargetPoint ) ) + if ( isDefined( self.javelintargetpoint ) ) { - level.waypoints[ level.waypointCount ].type = "javelin"; + level.waypoints[ level.waypointcount ].type = "javelin"; } else if ( self AdsButtonPressed() ) { - level.waypoints[ level.waypointCount ].type = "climb"; + level.waypoints[ level.waypointcount ].type = "climb"; } else if ( self AttackButtonPressed() && self UseButtonPressed() ) { - level.waypoints[ level.waypointCount ].type = "tube"; + level.waypoints[ level.waypointcount ].type = "tube"; } else if ( self AttackButtonPressed() ) { - level.waypoints[ level.waypointCount ].type = "grenade"; + level.waypoints[ level.waypointcount ].type = "grenade"; } else if ( self UseButtonPressed() ) { - level.waypoints[ level.waypointCount ].type = "claymore"; + level.waypoints[ level.waypointcount ].type = "claymore"; } else { - level.waypoints[ level.waypointCount ].type = self getStance(); + level.waypoints[ level.waypointcount ].type = self getStance(); } - level.waypoints[ level.waypointCount ].angles = self getPlayerAngles(); + level.waypoints[ level.waypointcount ].angles = self getPlayerAngles(); - level.waypoints[ level.waypointCount ].children = []; + level.waypoints[ level.waypointcount ].children = []; - if ( level.waypoints[ level.waypointCount ].type == "javelin" ) + if ( level.waypoints[ level.waypointcount ].type == "javelin" ) { - level.waypoints[ level.waypointCount ].jav_point = self.javelinTargetPoint; + level.waypoints[ level.waypointcount ].jav_point = self.javelintargetpoint; } - self iprintln( level.waypoints[ level.waypointCount ].type + " Waypoint " + level.waypointCount + " Added at " + pos ); + self iprintln( level.waypoints[ level.waypointcount ].type + " Waypoint " + level.waypointcount + " Added at " + pos ); - if ( level.autoLink ) + if ( level.autolink ) { - if ( level.wpToLink == -1 ) + if ( level.wptolink == -1 ) { - level.wpToLink = level.waypointCount - 1; + level.wptolink = level.waypointcount - 1; } - level.waypointCount++; - self LinkWaypoint( level.waypointCount - 1 ); + level.waypointcount++; + self LinkWaypoint( level.waypointcount - 1 ); } else { - level.waypointCount++; + level.waypointcount++; } } DeleteAllWaypoints() { level.waypoints = []; - level.waypointCount = 0; + level.waypointcount = 0; self iprintln( "DelAllWps" ); } @@ -991,19 +991,19 @@ initHudElem( txt, xl, yl ) { hud = NewClientHudElem( self ); hud setText( txt ); - hud.alignX = "left"; - hud.alignY = "top"; - hud.horzAlign = "left"; - hud.vertAlign = "top"; + hud.alignx = "left"; + hud.aligny = "top"; + hud.horzalign = "left"; + hud.vertalign = "top"; hud.x = xl; hud.y = yl; hud.foreground = true; - hud.fontScale = 1; + hud.fontscale = 1; hud.font = "objective"; hud.alpha = 1; hud.glow = 0; - hud.glowColor = ( 0, 0, 0 ); - hud.glowAlpha = 1; + hud.glowcolor = ( 0, 0, 0 ); + hud.glowalpha = 1; hud.color = ( 1.0, 1.0, 1.0 ); self thread destroyOnDeath( hud ); @@ -1015,19 +1015,19 @@ initHudElem2() { infotext = NewHudElem(); infotext setText( "^1[{+smoke}]-AddWp ^2[{+melee_zoom}]-LinkWp ^3[{+reload}]-UnLinkWp ^4[{+actionslot 3}]-DeleteWp ^5[{+actionslot 4}]-DelAllWps ^6[{+actionslot 5}]-LoadWPS ^7[{+actionslot 1}]-SaveWp" ); - infotext.alignX = "center"; - infotext.alignY = "bottom"; - infotext.horzAlign = "center"; - infotext.vertAlign = "bottom"; + infotext.alignx = "center"; + infotext.aligny = "bottom"; + infotext.horzalign = "center"; + infotext.vertalign = "bottom"; infotext.x = -800; infotext.y = 25; infotext.foreground = true; - infotext.fontScale = 1.35; + infotext.fontscale = 1.35; infotext.font = "objective"; infotext.alpha = 1; infotext.glow = 0; - infotext.glowColor = ( 0, 0, 0 ); - infotext.glowAlpha = 1; + infotext.glowcolor = ( 0, 0, 0 ); + infotext.glowalpha = 1; infotext.color = ( 1.0, 1.0, 1.0 ); self thread destroyOnDeath( infotext ); @@ -1038,10 +1038,10 @@ initHudElem2() initHudElem3() { bar = level createServerBar( ( 0.5, 0.5, 0.5 ), 1000, 25 ); - bar.alignX = "center"; - bar.alignY = "bottom"; - bar.horzAlign = "center"; - bar.vertAlign = "bottom"; + bar.alignx = "center"; + bar.aligny = "bottom"; + bar.horzalign = "center"; + bar.vertalign = "bottom"; bar.y = 30; bar.foreground = true; @@ -1055,10 +1055,10 @@ initHudElem4() OptionsBG = NewClientHudElem( self ); OptionsBG.x = 100; OptionsBG.y = 2; - OptionsBG.alignX = "left"; - OptionsBG.alignY = "top"; - OptionsBG.horzAlign = "left"; - OptionsBG.vertAlign = "top"; + OptionsBG.alignx = "left"; + OptionsBG.aligny = "top"; + OptionsBG.horzalign = "left"; + OptionsBG.vertalign = "top"; OptionsBG setshader( "black", 200, 60 ); OptionsBG.alpha = 0.4;