diff --git a/README.md b/README.md index ffc2f26..4f2a897 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Bot Warfare is a GSC mod for the [CoD4x project](https://github.com/callofduty4x It aims to add playable AI to the multiplayer games of CoD4. -You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfare/downloads/cod4x-bot-warfare-latest) and the CoD4x.me post [here](https://cod4x.me/index.php?/forums/topic/3116-release-bot-warfare/). +You can find the ModDB release post [here](https://www.moddb.com/mods/bot-warfare/downloads/cod4x-bot-warfare-latest) and the CoD4x forum post [here](https://cod4x.ovh/index.php?/forums/topic/3116-release-bot-warfare/). ## Important to public dedicated servers The ```bots_main_firstIsHost``` DVAR is enabled by default! @@ -57,15 +57,15 @@ Make sure to disable this DVAR by adding ```set bots_main_firstIsHost 0``` in yo - ... And pretty much everything you expect a Combat Training bot to have ## Installation -Using CoD4x's extended functionality requires to use their Dedicated server, as explained [here](https://cod4x.me/index.php?/forums/topic/2047-add-cod4x-server-gsc-functions-to-the-client/). +Using CoD4x's extended functionality requires to use their Dedicated server, as explained [here](https://cod4x.ovh/index.php?/forums/topic/2047-add-cod4x-server-gsc-functions-to-the-client/). You can easily setup a local LAN dedicated server for you to join and play on. Have a look at [Setting up a CoD4x server](). -0. Make sure that [CoD4x server + client](https://cod4x.me/) is installed, updated and working properly. +0. Make sure that [CoD4x server + client](https://cod4x.ovh/) is installed, updated and working properly. - Download the [latest release](https://github.com/ineedbots/cod4x_bot_warfare/releases) of Bot Warfare. 1. Locate your CoD4x server install folder. 2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder. - - The folder/file structure should follow as '.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc'. + - The folder/file structure should follow as `.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc`. 3. The mod is now installed, now start your server, change the DVARs and start a map. 4. Now start your CoD4x client and connect to your server ('connect 127.0.0.1' in the console most likely) and play! @@ -88,6 +88,7 @@ You can easily setup a local LAN dedicated server for you to join and play on. H | bots_main_menu | Enable the in-game menu for hosts. | true | | bots_main_debug | Enable the in-game waypoint editor. | false | | bots_main_kickBotsAtEnd | Kick the bots at the end of a match. | false | +| bots_main_chat | The rate bots will chat at, set to 0 to disable. | 1.0 | | bots_manage_add | Amount of bots to add to the game, once bots are added, resets back to `0`. | 0 | | bots_manage_fill | Amount of players/bots (look at `bots_manage_fill_mode`) to maintain in the match. | 0 | | bots_manage_fill_mode | `bots_manage_fill` players/bots counting method. | 0 | @@ -121,6 +122,17 @@ You can easily setup a local LAN dedicated server for you to join and play on. H ## Changelog +- v2.1.0 + - Bot chatter system, bots_main_chat + - Greatly reduce script variable usage + - Improved bots mantling and stuck + - Fix some runtime errors + - Bots sprint more + - Improved bots sight on enemies + - Bots do random actions while waiting at an objective + - Improved bots from getting stuck + - Better bot difficulty management, bots_skill_min and bots_skill_max + - v2.0.1 - Reduced bots crouching - Increased bots sprinting diff --git a/main/waypoints b/main/waypoints index 65a344f..c734ac7 160000 --- a/main/waypoints +++ b/main/waypoints @@ -1 +1 @@ -Subproject commit 65a344f95388f6d0f0704f3c4517283670bb2818 +Subproject commit c734ac790d590225e613fa3c2b10f411c29885aa diff --git a/main_shared/maps/mp/bots/_bot.gsc b/main_shared/maps/mp/bots/_bot.gsc index 2b8b1d8..23064a7 100644 --- a/main_shared/maps/mp/bots/_bot.gsc +++ b/main_shared/maps/mp/bots/_bot.gsc @@ -8,7 +8,7 @@ */ init() { - level.bw_VERSION = "2.0.1"; + level.bw_VERSION = "2.1.0"; if ( getDvar( "bots_main" ) == "" ) setDvar( "bots_main", true ); diff --git a/out/Add to root of CoD4x server/main/plugins/httpget.so b/out/Add to root of CoD4x server/main/plugins/httpget.so new file mode 100644 index 0000000..5077dc9 Binary files /dev/null and b/out/Add to root of CoD4x server/main/plugins/httpget.so differ diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot.gsc index 1d49140..23064a7 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot.gsc @@ -8,96 +8,134 @@ */ init() { - level.bw_VERSION = "2.0.1"; + level.bw_VERSION = "2.1.0"; - if(getDvar("bots_main") == "") - setDvar("bots_main", true); + if ( getDvar( "bots_main" ) == "" ) + setDvar( "bots_main", true ); - if (!getDvarInt("bots_main")) + if ( !getDvarInt( "bots_main" ) ) return; thread load_waypoints(); cac_init_patch(); thread hook_callbacks(); - if(getDvar("bots_main_GUIDs") == "") - setDvar("bots_main_GUIDs", "");//guids of players who will be given host powers, comma seperated - if(getDvar("bots_main_firstIsHost") == "") - setDvar("bots_main_firstIsHost", true);//first player to connect is a host - if(getDvar("bots_main_waitForHostTime") == "") - setDvar("bots_main_waitForHostTime", 10.0);//how long to wait to wait for the host player - - if(getDvar("bots_manage_add") == "") - setDvar("bots_manage_add", 0);//amount of bots to add to the game - if(getDvar("bots_manage_fill") == "") - setDvar("bots_manage_fill", 0);//amount of bots to maintain - if(getDvar("bots_manage_fill_spec") == "") - setDvar("bots_manage_fill_spec", true);//to count for fill if player is on spec team - if(getDvar("bots_manage_fill_mode") == "") - setDvar("bots_manage_fill_mode", 0);//fill mode, 0 adds everyone, 1 just bots, 2 maintains at maps, 3 is 2 with 1 - if(getDvar("bots_manage_fill_kick") == "") - setDvar("bots_manage_fill_kick", false);//kick bots if too many - - if(getDvar("bots_team") == "") - setDvar("bots_team", "autoassign");//which team for bots to join - if(getDvar("bots_team_amount") == "") - setDvar("bots_team_amount", 0);//amount of bots on axis team - if(getDvar("bots_team_force") == "") - setDvar("bots_team_force", false);//force bots on team - if(getDvar("bots_team_mode") == "") - setDvar("bots_team_mode", 0);//counts just bots when 1 - - if(getDvar("bots_skill") == "") - setDvar("bots_skill", 0);//0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random - if(getDvar("bots_skill_axis_hard") == "") - setDvar("bots_skill_axis_hard", 0);//amount of hard bots on axis team - if(getDvar("bots_skill_axis_med") == "") - setDvar("bots_skill_axis_med", 0); - if(getDvar("bots_skill_allies_hard") == "") - setDvar("bots_skill_allies_hard", 0); - if(getDvar("bots_skill_allies_med") == "") - setDvar("bots_skill_allies_med", 0); - - if(getDvar("bots_loadout_reasonable") == "")//filter out the bad 'guns' and perks - setDvar("bots_loadout_reasonable", false); - if(getDvar("bots_loadout_allow_op") == "")//allows jug, marty and laststand - setDvar("bots_loadout_allow_op", true); - if(getDvar("bots_loadout_rank") == "")// what rank the bots should be around, -1 is around the players, 0 is all random - setDvar("bots_loadout_rank", -1); - if(getDvar("bots_loadout_prestige") == "")// what pretige the bots will be, -1 is the players, -2 is random - setDvar("bots_loadout_prestige", -1); + if ( getDvar( "bots_main_GUIDs" ) == "" ) + setDvar( "bots_main_GUIDs", "" ); //guids of players who will be given host powers, comma seperated - if(getDvar("bots_play_move") == "")//bots move - setDvar("bots_play_move", true); - if(getDvar("bots_play_knife") == "")//bots knife - setDvar("bots_play_knife", true); - if(getDvar("bots_play_fire") == "")//bots fire - setDvar("bots_play_fire", true); - if(getDvar("bots_play_nade") == "")//bots grenade - setDvar("bots_play_nade", true); - if(getDvar("bots_play_obj") == "")//bots play the obj - setDvar("bots_play_obj", true); - if(getDvar("bots_play_camp") == "")//bots camp and follow - setDvar("bots_play_camp", true); - if(getDvar("bots_play_jumpdrop") == "")//bots jump and dropshot - setDvar("bots_play_jumpdrop", true); - if(getDvar("bots_play_target_other") == "")//bot target non play ents (vehicles) - setDvar("bots_play_target_other", true); - if(getDvar("bots_play_killstreak") == "")//bot use killstreaks - setDvar("bots_play_killstreak", true); - if(getDvar("bots_play_ads") == "")//bot ads - setDvar("bots_play_ads", true); + if ( getDvar( "bots_main_firstIsHost" ) == "" ) + setDvar( "bots_main_firstIsHost", true ); //first player to connect is a host - if(!isDefined(game["botWarfare"])) + if ( getDvar( "bots_main_waitForHostTime" ) == "" ) + setDvar( "bots_main_waitForHostTime", 10.0 ); //how long to wait to wait for the host player + + if ( getDvar( "bots_main_kickBotsAtEnd" ) == "" ) + setDvar( "bots_main_kickBotsAtEnd", false ); //kicks the bots at game end + + if ( getDvar( "bots_manage_add" ) == "" ) + setDvar( "bots_manage_add", 0 ); //amount of bots to add to the game + + if ( getDvar( "bots_manage_fill" ) == "" ) + setDvar( "bots_manage_fill", 0 ); //amount of bots to maintain + + if ( getDvar( "bots_manage_fill_spec" ) == "" ) + setDvar( "bots_manage_fill_spec", true ); //to count for fill if player is on spec team + + if ( getDvar( "bots_manage_fill_mode" ) == "" ) + setDvar( "bots_manage_fill_mode", 0 ); //fill mode, 0 adds everyone, 1 just bots, 2 maintains at maps, 3 is 2 with 1 + + if ( getDvar( "bots_manage_fill_kick" ) == "" ) + setDvar( "bots_manage_fill_kick", false ); //kick bots if too many + + if ( getDvar( "bots_team" ) == "" ) + setDvar( "bots_team", "autoassign" ); //which team for bots to join + + if ( getDvar( "bots_team_amount" ) == "" ) + setDvar( "bots_team_amount", 0 ); //amount of bots on axis team + + if ( getDvar( "bots_team_force" ) == "" ) + setDvar( "bots_team_force", false ); //force bots on team + + if ( getDvar( "bots_team_mode" ) == "" ) + setDvar( "bots_team_mode", 0 ); //counts just bots when 1 + + if ( getDvar( "bots_skill" ) == "" ) + setDvar( "bots_skill", 0 ); //0 is random, 1 is easy 7 is hard, 8 is custom, 9 is completely random + + if ( getDvar( "bots_skill_axis_hard" ) == "" ) + setDvar( "bots_skill_axis_hard", 0 ); //amount of hard bots on axis team + + if ( getDvar( "bots_skill_axis_med" ) == "" ) + setDvar( "bots_skill_axis_med", 0 ); + + if ( getDvar( "bots_skill_allies_hard" ) == "" ) + setDvar( "bots_skill_allies_hard", 0 ); + + if ( getDvar( "bots_skill_allies_med" ) == "" ) + setDvar( "bots_skill_allies_med", 0 ); + + if ( getDvar( "bots_skill_min" ) == "" ) + setDvar( "bots_skill_min", 1 ); + + if ( getDvar( "bots_skill_max" ) == "" ) + setDvar( "bots_skill_max", 7 ); + + if ( getDvar( "bots_loadout_reasonable" ) == "" ) //filter out the bad 'guns' and perks + setDvar( "bots_loadout_reasonable", false ); + + if ( getDvar( "bots_loadout_allow_op" ) == "" ) //allows jug, marty and laststand + setDvar( "bots_loadout_allow_op", true ); + + if ( getDvar( "bots_loadout_rank" ) == "" ) // what rank the bots should be around, -1 is around the players, 0 is all random + setDvar( "bots_loadout_rank", -1 ); + + if ( getDvar( "bots_loadout_prestige" ) == "" ) // what pretige the bots will be, -1 is the players, -2 is random + setDvar( "bots_loadout_prestige", -1 ); + + if ( getDvar( "bots_play_move" ) == "" ) //bots move + setDvar( "bots_play_move", true ); + + if ( getDvar( "bots_play_knife" ) == "" ) //bots knife + setDvar( "bots_play_knife", true ); + + if ( getDvar( "bots_play_fire" ) == "" ) //bots fire + setDvar( "bots_play_fire", true ); + + if ( getDvar( "bots_play_nade" ) == "" ) //bots grenade + setDvar( "bots_play_nade", true ); + + if ( getDvar( "bots_play_obj" ) == "" ) //bots play the obj + setDvar( "bots_play_obj", true ); + + if ( getDvar( "bots_play_camp" ) == "" ) //bots camp and follow + setDvar( "bots_play_camp", true ); + + if ( getDvar( "bots_play_jumpdrop" ) == "" ) //bots jump and dropshot + setDvar( "bots_play_jumpdrop", true ); + + if ( getDvar( "bots_play_target_other" ) == "" ) //bot target non play ents (vehicles) + setDvar( "bots_play_target_other", true ); + + if ( getDvar( "bots_play_killstreak" ) == "" ) //bot use killstreaks + setDvar( "bots_play_killstreak", true ); + + if ( getDvar( "bots_play_ads" ) == "" ) //bot ads + setDvar( "bots_play_ads", true ); + + if ( getDvar( "bots_play_aim" ) == "" ) + setDvar( "bots_play_aim", true ); + + if ( !isDefined( game["botWarfare"] ) ) game["botWarfare"] = true; - + level.defuseObject = undefined; level.bots_smokeList = List(); level.tbl_PerkData[0]["reference_full"] = true; - for(h = 1; h < 6; h++) - for(i = 0; i < 3; i++) - level.default_perk["CLASS_CUSTOM"+h][i] = "specialty_null"; - + + for ( h = 1; h < 6; h++ ) + for ( i = 0; i < 3; i++ ) + level.default_perk["CLASS_CUSTOM" + h][i] = "specialty_null"; + level.bots_minSprintDistance = 315; level.bots_minSprintDistance *= level.bots_minSprintDistance; level.bots_minGrenadeDistance = 256; @@ -113,11 +151,11 @@ init() level.bots_maxShotgunDistance = 500; level.bots_maxShotgunDistance *= level.bots_maxShotgunDistance; level.bots_listenDist = 100; - + level.smokeRadius = 255; level.bots = []; - + level.bots_fullautoguns = []; level.bots_fullautoguns["rpd"] = true; level.bots_fullautoguns["m60e4"] = true; @@ -131,12 +169,12 @@ init() level.bots_fullautoguns["m4"] = true; level.bots_fullautoguns["ak47"] = true; level.bots_fullautoguns["mp44"] = true; - + level thread fixGamemodes(); level thread onUAVAlliesUpdate(); level thread onUAVAxisUpdate(); level thread chopperWatch(); - + level thread onPlayerConnect(); level thread handleBots(); @@ -151,39 +189,52 @@ handleBots() level thread teamBots(); level thread diffBots(); level addBots(); - - while(!level.intermission) + + while ( !level.intermission ) wait 0.05; - - setDvar("bots_manage_add", getBotArray().size); + + setDvar( "bots_manage_add", getBotArray().size ); + + if ( !getDvarInt( "bots_main_kickBotsAtEnd" ) ) + return; + + removeAllTestClients(); } /* The hook callback for when any player becomes damaged. */ -onPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset) +onPlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { - if(self is_bot()) + if ( self is_bot() ) { - self maps\mp\bots\_bot_internal::onDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset); - self maps\mp\bots\_bot_script::onDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset); + self maps\mp\bots\_bot_internal::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); + self maps\mp\bots\_bot_script::onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); } - - self [[level.prevCallbackPlayerDamage]](eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset); + + self [[level.prevCallbackPlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); } /* The hook callback when any player gets killed. */ -onPlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration) +onPlayerKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) { - if(self is_bot()) + if ( self is_bot() ) { - self maps\mp\bots\_bot_internal::onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration); - self maps\mp\bots\_bot_script::onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration); + self maps\mp\bots\_bot_internal::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); + self maps\mp\bots\_bot_script::onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); } - - self [[level.prevCallbackPlayerKilled]](eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration); + + self.lastAttacker = eAttacker; + + if ( isDefined( eAttacker ) ) + { + eAttacker.lastKilledPlayer = self; + eAttacker notify( "killed_enemy" ); + } + + self [[level.prevCallbackPlayerKilled]]( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ); } /* @@ -194,7 +245,7 @@ hook_callbacks() wait 0.05; level.prevCallbackPlayerDamage = level.callbackPlayerDamage; level.callbackPlayerDamage = ::onPlayerDamage; - + level.prevCallbackPlayerKilled = level.callbackPlayerKilled; level.callbackPlayerKilled = ::onPlayerKilled; } @@ -205,26 +256,26 @@ hook_callbacks() fixKoth() { level.radio = undefined; - - for(;;) + + for ( ;; ) { wait 0.05; - - if(!isDefined(level.radioObject)) + + if ( !isDefined( level.radioObject ) ) { continue; } - - for(i = level.radios.size - 1; i >= 0; i--) + + for ( i = level.radios.size - 1; i >= 0; i-- ) { - if(level.radioObject != level.radios[i].gameobject) + if ( level.radioObject != level.radios[i].gameobject ) continue; - + level.radio = level.radios[i]; break; } - - while(isDefined(level.radioObject) && level.radio.gameobject == level.radioObject) + + while ( isDefined( level.radioObject ) && level.radio.gameobject == level.radioObject ) wait 0.05; } } @@ -234,22 +285,23 @@ fixKoth() */ fixGamemodes() { - for(i=0;i<19;i++) + 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; + break; } - - if(isDefined(level.radios) && level.gametype == "koth") + + if ( isDefined( level.radios ) && level.gametype == "koth" ) { level thread fixKoth(); - + break; } - + wait 0.05; } } @@ -259,14 +311,14 @@ fixGamemodes() */ onPlayerConnect() { - for(;;) + for ( ;; ) { - level waittill("connected", player); - + level waittill( "connected", player ); + player thread onGrenadeFire(); player thread onWeaponFired(); player thread doPlayerModelFix(); - + player thread connected(); } } @@ -276,15 +328,15 @@ onPlayerConnect() */ fixPerksAndScriptKick() { - self endon("disconnect"); - - self waittill("spawned"); - + self endon( "disconnect" ); + + self waittill( "spawned" ); + self.pers["isBot"] = undefined; - - if(!level.gameEnded) + + if ( !level.gameEnded ) level waittill ( "game_ended" ); - + self.pers["isBot"] = true; } @@ -293,9 +345,9 @@ fixPerksAndScriptKick() */ onDisconnect() { - self waittill("disconnect"); - - level.bots = array_remove(level.bots, self); + self waittill( "disconnect" ); + + level.bots = array_remove( level.bots, self ); } /* @@ -303,35 +355,55 @@ onDisconnect() */ connected() { - self endon("disconnect"); + self endon( "disconnect" ); - if (!isDefined(self.pers["bot_host"])) + if ( !isDefined( self.pers["bot_host"] ) ) self thread doHostCheck(); - if(!self is_bot()) + if ( !self is_bot() ) return; - if (!isDefined(self.pers["isBot"])) + if ( !isDefined( self.pers["isBot"] ) ) { // fast restart... self.pers["isBot"] = true; } - - if (!isDefined(self.pers["isBotWarfare"])) + + if ( !isDefined( self.pers["isBotWarfare"] ) ) { self.pers["isBotWarfare"] = true; self thread added(); } - + self thread fixPerksAndScriptKick(); - + self thread maps\mp\bots\_bot_internal::connected(); self thread maps\mp\bots\_bot_script::connected(); level.bots[level.bots.size] = self; self thread onDisconnect(); - level notify("bot_connected", self); + level notify( "bot_connected", self ); + + self thread watchBotDebugEvent(); +} + +/* + DEBUG +*/ +watchBotDebugEvent() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "bot_event", msg, str, b, c, d, e, f, g ); + + if ( msg == "debug" && GetDvarInt( "bots_main_debug" ) ) + { + printToConsole( "Bot Warfare debug: " + self.name + ": " + str ); + } + } } /* @@ -339,8 +411,8 @@ connected() */ added() { - self endon("disconnect"); - + self endon( "disconnect" ); + self thread maps\mp\bots\_bot_internal::added(); self thread maps\mp\bots\_bot_script::added(); } @@ -351,15 +423,15 @@ added() add_bot() { name = getABotName(); - + bot = undefined; - if (isDefined(name) && name.size >= 3) - bot = addtestclient(name); + if ( isDefined( name ) && name.size >= 3 ) + bot = addtestclient( name ); else bot = addtestclient(); - if (isdefined(bot)) + if ( isdefined( bot ) ) { bot.pers["isBot"] = true; bot.pers["isBotWarfare"] = true; @@ -367,82 +439,236 @@ add_bot() } } +/* + A server thread for monitoring all bot's difficulty levels for custom server settings. +*/ +diffBots_loop() +{ + var_allies_hard = getDVarInt( "bots_skill_allies_hard" ); + var_allies_med = getDVarInt( "bots_skill_allies_med" ); + var_axis_hard = getDVarInt( "bots_skill_axis_hard" ); + var_axis_med = getDVarInt( "bots_skill_axis_med" ); + var_skill = getDvarInt( "bots_skill" ); + + allies_hard = 0; + allies_med = 0; + axis_hard = 0; + axis_med = 0; + + if ( var_skill == 8 ) + { + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) + { + player = level.players[i]; + + if ( !isDefined( player.pers["team"] ) ) + continue; + + if ( !player is_bot() ) + continue; + + if ( player.pers["team"] == "axis" ) + { + if ( axis_hard < var_axis_hard ) + { + axis_hard++; + player.pers["bots"]["skill"]["base"] = 7; + } + else if ( axis_med < var_axis_med ) + { + axis_med++; + player.pers["bots"]["skill"]["base"] = 4; + } + else + player.pers["bots"]["skill"]["base"] = 1; + } + else if ( player.pers["team"] == "allies" ) + { + if ( allies_hard < var_allies_hard ) + { + allies_hard++; + player.pers["bots"]["skill"]["base"] = 7; + } + else if ( allies_med < var_allies_med ) + { + allies_med++; + player.pers["bots"]["skill"]["base"] = 4; + } + else + player.pers["bots"]["skill"]["base"] = 1; + } + } + } + else if ( var_skill != 0 && var_skill != 9 ) + { + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) + { + player = level.players[i]; + + if ( !player is_bot() ) + continue; + + player.pers["bots"]["skill"]["base"] = var_skill; + } + } + + playercount = level.players.size; + min_diff = GetDvarInt( "bots_skill_min" ); + max_diff = GetDvarInt( "bots_skill_max" ); + + for ( i = 0; i < playercount; i++ ) + { + player = level.players[i]; + + if ( !player is_bot() ) + continue; + + player.pers["bots"]["skill"]["base"] = int( clamp( player.pers["bots"]["skill"]["base"], min_diff, max_diff ) ); + } +} + /* A server thread for monitoring all bot's difficulty levels for custom server settings. */ diffBots() { - for(;;) + for ( ;; ) { wait 1.5; - - var_allies_hard = getDVarInt("bots_skill_allies_hard"); - var_allies_med = getDVarInt("bots_skill_allies_med"); - var_axis_hard = getDVarInt("bots_skill_axis_hard"); - var_axis_med = getDVarInt("bots_skill_axis_med"); - var_skill = getDvarInt("bots_skill"); - - allies_hard = 0; - allies_med = 0; - axis_hard = 0; - axis_med = 0; - - if(var_skill == 8) + + diffBots_loop(); + } +} + +/* + A server thread for monitoring all bot's teams for custom server settings. +*/ +teamBots_loop() +{ + teamAmount = getDvarInt( "bots_team_amount" ); + toTeam = getDvar( "bots_team" ); + + alliesbots = 0; + alliesplayers = 0; + axisbots = 0; + axisplayers = 0; + + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) + { + player = level.players[i]; + + if ( !isDefined( player.pers["team"] ) ) + continue; + + if ( player is_bot() ) { - playercount = level.players.size; - for(i = 0; i < playercount; i++) + if ( player.pers["team"] == "allies" ) + alliesbots++; + else if ( player.pers["team"] == "axis" ) + axisbots++; + } + else + { + if ( player.pers["team"] == "allies" ) + alliesplayers++; + else if ( player.pers["team"] == "axis" ) + axisplayers++; + } + } + + allies = alliesbots; + axis = axisbots; + + if ( !getDvarInt( "bots_team_mode" ) ) + { + allies += alliesplayers; + axis += axisplayers; + } + + if ( toTeam != "custom" ) + { + if ( getDvarInt( "bots_team_force" ) ) + { + if ( toTeam == "autoassign" ) { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == "axis") + if ( abs( axis - allies ) > 1 ) { - if(axis_hard < var_axis_hard) - { - axis_hard++; - player.pers["bots"]["skill"]["base"] = 7; - } - else if(axis_med < var_axis_med) - { - axis_med++; - player.pers["bots"]["skill"]["base"] = 4; - } - else - player.pers["bots"]["skill"]["base"] = 1; + toTeam = "axis"; + + if ( axis > allies ) + toTeam = "allies"; } - else if(player.pers["team"] == "allies") + } + + if ( toTeam != "autoassign" ) + { + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) { - if(allies_hard < var_allies_hard) - { - allies_hard++; - player.pers["bots"]["skill"]["base"] = 7; - } - else if(allies_med < var_allies_med) - { - allies_med++; - player.pers["bots"]["skill"]["base"] = 4; - } + player = level.players[i]; + + if ( !isDefined( player.pers["team"] ) ) + continue; + + if ( !player is_bot() ) + continue; + + if ( player.pers["team"] == toTeam ) + continue; + + if ( toTeam == "allies" ) + player thread [[level.allies]](); + else if ( toTeam == "axis" ) + player thread [[level.axis]](); else - player.pers["bots"]["skill"]["base"] = 1; + player thread [[level.spectator]](); + + break; } } } - else if (var_skill != 0 && var_skill != 9) + } + else + { + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) { - playercount = level.players.size; - for(i = 0; i < playercount; i++) + player = level.players[i]; + + if ( !isDefined( player.pers["team"] ) ) + continue; + + if ( !player is_bot() ) + continue; + + if ( player.pers["team"] == "axis" ) { - player = level.players[i]; - - if(!player is_bot()) - continue; - - player.pers["bots"]["skill"]["base"] = var_skill; + if ( axis > teamAmount ) + { + player thread [[level.allies]](); + break; + } + } + else + { + if ( axis < teamAmount ) + { + player thread [[level.axis]](); + break; + } + else if ( player.pers["team"] != "allies" ) + { + player thread [[level.allies]](); + break; + } } } } @@ -453,127 +679,119 @@ diffBots() */ teamBots() { - for(;;) + for ( ;; ) { wait 1.5; - teamAmount = getDvarInt("bots_team_amount"); - toTeam = getDvar("bots_team"); - - alliesbots = 0; - alliesplayers = 0; - axisbots = 0; + + teamBots_loop(); + } +} + +/* + A server thread for monitoring all bot's in game. Will add and kick bots according to server settings. +*/ +addBots_loop() +{ + botsToAdd = GetDvarInt( "bots_manage_add" ); + + if ( botsToAdd > 0 ) + { + SetDvar( "bots_manage_add", 0 ); + + if ( botsToAdd > 64 ) + botsToAdd = 64; + + for ( ; botsToAdd > 0; botsToAdd-- ) + { + level add_bot(); + wait 0.25; + } + } + + fillMode = getDVarInt( "bots_manage_fill_mode" ); + + if ( fillMode == 2 || fillMode == 3 ) + setDvar( "bots_manage_fill", getGoodMapAmount() ); + + fillAmount = getDvarInt( "bots_manage_fill" ); + + players = 0; + bots = 0; + spec = 0; + + playercount = level.players.size; + + for ( i = 0; i < playercount; i++ ) + { + player = level.players[i]; + + if ( player is_bot() ) + bots++; + else if ( !isDefined( player.pers["team"] ) || ( player.pers["team"] != "axis" && player.pers["team"] != "allies" ) ) + spec++; + else + players++; + } + + if ( !randomInt( 999 ) ) + { + setDvar( "testclients_doreload", true ); + wait 0.1; + setDvar( "testclients_doreload", false ); + doExtraCheck(); + } + + if ( fillMode == 4 ) + { axisplayers = 0; - + alliesplayers = 0; + playercount = level.players.size; - for(i = 0; i < playercount; i++) + + for ( i = 0; i < playercount; i++ ) { player = level.players[i]; - - if(!isDefined(player.pers["team"])) + + if ( player is_bot() ) continue; - - if(player is_bot()) - { - if(player.pers["team"] == "allies") - alliesbots++; - else if(player.pers["team"] == "axis") - axisbots++; - } + + if ( !isDefined( player.pers["team"] ) ) + continue; + + if ( player.pers["team"] == "axis" ) + axisplayers++; + else if ( player.pers["team"] == "allies" ) + alliesplayers++; + } + + result = fillAmount - abs( axisplayers - alliesplayers ) + bots; + + if ( players == 0 ) + { + if ( bots < fillAmount ) + result = fillAmount - 1; + else if ( bots > fillAmount ) + result = fillAmount + 1; else - { - if(player.pers["team"] == "allies") - alliesplayers++; - else if(player.pers["team"] == "axis") - axisplayers++; - } - } - - allies = alliesbots; - axis = axisbots; - - if(!getDvarInt("bots_team_mode")) - { - allies += alliesplayers; - axis += axisplayers; - } - - if(toTeam != "custom") - { - if(getDvarInt("bots_team_force")) - { - if(toTeam == "autoassign") - { - if(abs(axis - allies) > 1) - { - toTeam = "axis"; - if(axis > allies) - toTeam = "allies"; - } - } - - if(toTeam != "autoassign") - { - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == toTeam) - continue; - - if (toTeam == "allies") - player thread [[level.allies]](); - else if (toTeam == "axis") - player thread [[level.axis]](); - else - player thread [[level.spectator]](); - break; - } - } - } - } - else - { - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(!isDefined(player.pers["team"])) - continue; - - if(!player is_bot()) - continue; - - if(player.pers["team"] == "axis") - { - if(axis > teamAmount) - { - player thread [[level.allies]](); - break; - } - } - else - { - if(axis < teamAmount) - { - player thread [[level.axis]](); - break; - } - else if(player.pers["team"] != "allies") - { - player thread [[level.allies]](); - break; - } - } - } + result = fillAmount; } + + bots = result; + } + + amount = bots; + + if ( fillMode == 0 || fillMode == 2 ) + amount += players; + + if ( getDVarInt( "bots_manage_fill_spec" ) ) + amount += spec; + + if ( amount < fillAmount ) + setDvar( "bots_manage_add", 1 ); + else if ( amount > fillAmount && getDvarInt( "bots_manage_fill_kick" ) ) + { + RemoveTestClient(); //cod4x } } @@ -582,111 +800,15 @@ teamBots() */ addBots() { - level endon("game_ended"); + level endon( "game_ended" ); bot_wait_for_host(); - - for(;;) + + for ( ;; ) { wait 1.5; - - botsToAdd = GetDvarInt("bots_manage_add"); - - if(botsToAdd > 0) - { - SetDvar("bots_manage_add", 0); - - if(botsToAdd > 64) - botsToAdd = 64; - - for(; botsToAdd > 0; botsToAdd--) - { - level add_bot(); - wait 0.25; - } - } - - fillMode = getDVarInt("bots_manage_fill_mode"); - - if(fillMode == 2 || fillMode == 3) - setDvar("bots_manage_fill", getGoodMapAmount()); - - fillAmount = getDvarInt("bots_manage_fill"); - - players = 0; - bots = 0; - spec = 0; - - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(player is_bot()) - bots++; - else if(!isDefined(player.pers["team"]) || (player.pers["team"] != "axis" && player.pers["team"] != "allies")) - spec++; - else - players++; - } - if (!randomInt(999)) - { - setDvar("testclients_doreload", true); - wait 0.1; - setDvar("testclients_doreload", false); - doExtraCheck(); - } - - if(fillMode == 4) - { - axisplayers = 0; - alliesplayers = 0; - - playercount = level.players.size; - for(i = 0; i < playercount; i++) - { - player = level.players[i]; - - if(player is_bot()) - continue; - - if(!isDefined(player.pers["team"])) - continue; - - if(player.pers["team"] == "axis") - axisplayers++; - else if(player.pers["team"] == "allies") - alliesplayers++; - } - - result = fillAmount - abs(axisplayers - alliesplayers) + bots; - - if (players == 0) - { - if(bots < fillAmount) - result = fillAmount-1; - else if (bots > fillAmount) - result = fillAmount+1; - else - result = fillAmount; - } - - bots = result; - } - - amount = bots; - if(fillMode == 0 || fillMode == 2) - amount += players; - if(getDVarInt("bots_manage_fill_spec")) - amount += spec; - - if(amount < fillAmount) - setDvar("bots_manage_add", 1); - else if(amount > fillAmount && getDvarInt("bots_manage_fill_kick")) - { - RemoveTestClient(); //cod4x - } + addBots_loop(); } } @@ -695,12 +817,18 @@ addBots() */ onGrenadeFire() { - self endon("disconnect"); - for(;;) + self endon( "disconnect" ); + + for ( ;; ) { self waittill ( "grenade_fire", grenade, weaponName ); + + if ( !isDefined( grenade ) ) + continue; + grenade.name = weaponName; - if(weaponName == "smoke_grenade_mp") + + if ( weaponName == "smoke_grenade_mp" ) grenade thread AddToSmokeList(); } } @@ -714,10 +842,10 @@ AddToSmokeList() grenade.origin = self getOrigin(); grenade.state = "moving"; grenade.grenade = self; - + grenade thread thinkSmoke(); - - level.bots_smokeList ListAdd(grenade); + + level.bots_smokeList ListAdd( grenade ); } /* @@ -725,16 +853,17 @@ AddToSmokeList() */ thinkSmoke() { - while(isDefined(self.grenade)) + while ( isDefined( self.grenade ) ) { self.origin = self.grenade getOrigin(); self.state = "moving"; wait 0.05; } + self.state = "smoking"; wait 11.5; - - level.bots_smokeList ListRemove(self); + + level.bots_smokeList ListRemove( self ); } /* @@ -742,25 +871,26 @@ thinkSmoke() */ chopperWatch() { - for(;;) + for ( ;; ) { - while(!isDefined(level.chopper)) + while ( !isDefined( level.chopper ) ) wait 0.05; chopper = level.chopper; - if (level.teamBased && getDvarInt("doubleHeli")) + if ( level.teamBased && getDvarInt( "doubleHeli" ) ) { chopper = level.chopper["allies"]; - if (!isDefined(chopper)) + + if ( !isDefined( chopper ) ) chopper = level.chopper["axis"]; } level.bot_chopper = true; chopper watchChopper(); level.bot_chopper = false; - - while(isDefined(level.chopper)) + + while ( isDefined( level.chopper ) ) wait 0.05; } } @@ -770,11 +900,11 @@ chopperWatch() */ watchChopper() { - self endon("death"); - self endon("leaving"); - self endon("crashing"); - - level waittill("helicopter gone"); + self endon( "death" ); + self endon( "leaving" ); + self endon( "crashing" ); + + level waittill( "helicopter gone" ); } /* @@ -782,10 +912,10 @@ watchChopper() */ onUAVAxisUpdate() { - for(;;) + for ( ;; ) { level waittill( "radar_timer_kill_axis" ); - level thread doUAVUpdate("axis"); + level thread doUAVUpdate( "axis" ); } } @@ -794,46 +924,47 @@ onUAVAxisUpdate() */ onUAVAlliesUpdate() { - for(;;) + for ( ;; ) { level waittill( "radar_timer_kill_allies" ); - level thread doUAVUpdate("allies"); + level thread doUAVUpdate( "allies" ); } } /* Updates the player's radar so bots can know when they have a uav up, because iw3 script is old. */ -doUAVUpdate(team) +doUAVUpdate( team ) { - level endon("radar_timer_kill_" + team); - + level endon( "radar_timer_kill_" + team ); + playercount = level.players.size; - - for(i = 0; i < playercount; i++) + + for ( i = 0; i < playercount; i++ ) { player = level.players[i]; - - if(!isDefined(player.team)) + + if ( !isDefined( player.team ) ) continue; - - if(player.team == team) + + if ( player.team == team ) { player.bot_radar = true; } } - + wait level.radarViewTime; - + playercount = level.players.size; - for(i = 0; i < playercount; i++) + + for ( i = 0; i < playercount; i++ ) { player = level.players[i]; - - if(!isDefined(player.team)) + + if ( !isDefined( player.team ) ) continue; - - if(player.team == team) + + if ( player.team == team ) { player.bot_radar = false; } @@ -845,8 +976,8 @@ doUAVUpdate(team) */ doPlayerModelFix() { - self endon("disconnect"); - self waittill("spawned_player"); + self endon( "disconnect" ); + self waittill( "spawned_player" ); wait 0.05; self.bot_model_fix = true; } @@ -856,9 +987,10 @@ doPlayerModelFix() */ onWeaponFired() { - self endon("disconnect"); + self endon( "disconnect" ); self.bots_firing = false; - for(;;) + + for ( ;; ) { self waittill( "weapon_fired" ); self thread doFiringThread(); @@ -870,8 +1002,8 @@ onWeaponFired() */ doFiringThread() { - self endon("disconnect"); - self endon("weapon_fired"); + self endon( "disconnect" ); + self endon( "weapon_fired" ); self.bots_firing = true; wait 1; self.bots_firing = false; diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_chat.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_chat.gsc new file mode 100644 index 0000000..bdefe9e --- /dev/null +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_chat.gsc @@ -0,0 +1,2186 @@ +/* + _bot_chat + Author: INeedGames + Date: 05/06/2022 + Does bot chatter. +*/ + +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include maps\mp\bots\_bot_utility; + +/* + Init +*/ +init() +{ + if ( getDvar( "bots_main_chat" ) == "" ) + setDvar( "bots_main_chat", 1.0 ); + + level thread onBotConnected(); +} + +/* + Bot connected +*/ +onBotConnected() +{ + for ( ;; ) + { + level waittill( "bot_connected", bot ); + + bot thread start_chat_threads(); + } +} + +/* + Does the chatter +*/ +BotDoChat( chance, string, isTeam ) +{ + mod = getDvarFloat( "bots_main_chat" ); + + if ( mod <= 0.0 ) + return; + + if ( chance >= 100 || mod >= 100.0 || + ( RandomInt( 100 ) < ( chance * mod ) + 0 ) ) + { + if ( isDefined( isTeam ) && isTeam ) + self sayteam( string ); + else + self sayall( string ); + } +} + +/* + Threads for bots +*/ +start_chat_threads() +{ + self endon( "disconnect" ); + + self thread start_random_chat(); + self thread start_chat_watch(); + self thread start_killed_watch(); + self thread start_death_watch(); + self thread start_endgame_watch(); + + self thread start_startgame_watch(); +} + +/* + death +*/ +start_death_watch() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "death" ); + + self thread bot_chat_death_watch( self.lastAttacker, self.bots_lastKS ); + + self.bots_lastKS = 0; + } +} + +/* + start_endgame_watch +*/ +start_endgame_watch() +{ + self endon( "disconnect" ); + + level waittill ( "game_ended" ); + + self thread endgame_chat(); +} + +/* + Random chatting +*/ +start_random_chat() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + wait 1; + + if ( randomInt( 100 ) < 1 ) + { + if ( randomInt( 100 ) < 1 && isAlive( self ) ) + self thread doQuickMessage(); + } + } +} + +/* + Got a kill +*/ +start_killed_watch() +{ + self endon( "disconnect" ); + + self.bots_lastKS = 0; + + for ( ;; ) + { + self waittill( "killed_enemy" ); + wait 0.05; + + if ( self.bots_lastKS < self.cur_kill_streak ) + { + for ( i = self.bots_lastKS + 1; i <= self.cur_kill_streak; i++ ) + { + self thread bot_chat_streak( i ); + } + } + + self.bots_lastKS = self.cur_kill_streak; + + self thread bot_chat_killed_watch( self.lastKilledPlayer ); + } +} + +/* + Starts things for the bot +*/ +start_chat_watch() +{ + self endon( "disconnect" ); + level endon ( "game_ended" ); + + for ( ;; ) + { + self waittill( "bot_event", msg, a, b, c, d, e, f, g ); + + switch ( msg ) + { + case "killcam": + self thread bot_chat_killcam_watch( a, b, c, d, e, f, g ); + break; + + case "stuck": + self thread bot_chat_stuck_watch( a, b, c, d, e, f, g ); + break; + + case "tube": + self thread bot_chat_tube_watch( a, b, c, d, e, f, g ); + break; + + case "killstreak": + self thread bot_chat_killstreak_watch( a, b, c, d, e, f, g ); + break; + + case "attack_vehicle": + self thread bot_chat_attack_vehicle_watch( a, b, c, d, e, f, g ); + break; + + case "follow_threat": + self thread bot_chat_follow_threat_watch( a, b, c, d, e, f, g ); + break; + + case "camp": + self thread bot_chat_camp_watch( a, b, c, d, e, f, g ); + break; + + case "follow": + self thread bot_chat_follow_watch( a, b, c, d, e, f, g ); + break; + + case "equ": + self thread bot_chat_equ_watch( a, b, c, d, e, f, g ); + break; + + case "nade": + self thread bot_chat_nade_watch( a, b, c, d, e, f, g ); + break; + + case "throwback": + self thread bot_chat_throwback_watch( a, b, c, d, e, f, g ); + break; + + case "rage": + self thread bot_chat_rage_watch( a, b, c, d, e, f, g ); + break; + + case "tbag": + self thread bot_chat_tbag_watch( a, b, c, d, e, f, g ); + break; + + case "revenge": + self thread bot_chat_revenge_watch( a, b, c, d, e, f, g ); + break; + + case "heard_target": + self thread bot_chat_heard_target_watch( a, b, c, d, e, f, g ); + break; + + case "uav_target": + self thread bot_chat_uav_target_watch( a, b, c, d, e, f, g ); + break; + + case "attack_equ": + self thread bot_chat_attack_equ_watch( a, b, c, d, e, f, g ); + break; + + case "dom": + self thread bot_chat_dom_watch( a, b, c, d, e, f, g ); + break; + + case "hq": + self thread bot_chat_hq_watch( a, b, c, d, e, f, g ); + break; + + case "sab": + self thread bot_chat_sab_watch( a, b, c, d, e, f, g ); + break; + + case "sd": + self thread bot_chat_sd_watch( a, b, c, d, e, f, g ); + break; + } + } +} + +/* + start_startgame_watch +*/ +start_startgame_watch() +{ + self endon( "disconnect" ); + + wait( randomint( 5 ) + randomint( 5 ) ); + + switch ( level.gametype ) + { + case "war": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 7, "TEEEEEEEEAM, DEEEEAAAAAATHMAAAAATCH!!" ); + break; + + case 1: + self BotDoChat( 7, "Lets get em guys, wipe the floor with them." ); + break; + + case 2: + self BotDoChat( 7, "Yeeeesss master..." ); + break; + } + + break; + + case "dom": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 7, "Yaaayy!! I LOVE DOMINATION!!!!" ); + break; + + case 1: + self BotDoChat( 7, "Lets cap the flags and them." ); + break; + + case 2: + self BotDoChat( 7, "Yeeeesss master..." ); + break; + } + + break; + + case "sd": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 7, "Ahhhh! I'm scared! No respawning!" ); + break; + + case 1: + self BotDoChat( 7, "Lets get em guys, wipe the floor with them." ); + break; + + case 2: + self BotDoChat( 7, "Yeeeesss master..." ); + break; + } + + break; + + case "sab": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 7, "Soccer/Football! Lets play it!" ); + break; + + case 1: + self BotDoChat( 7, "Who plays sab these days." ); + break; + + case 2: + self BotDoChat( 7, "I do not know what to say." ); + break; + } + + break; + + case "dm": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 7, "DEEEEAAAAAATHMAAAAATCH!!" ); + break; + + case 1: + self BotDoChat( 7, "IM GOING TO KILL U ALL" ); + break; + + case 2: + self BotDoChat( 7, "lol sweet. time to camp." ); + break; + } + + break; + + case "koth": + self BotDoChat( 7, "HQ TIME!" ); + break; + } +} + +/* + Does quick cod4 style message +*/ +doQuickMessage() +{ + self endon( "disconnect" ); + self endon( "death" ); + + if ( !isDefined( self.talking ) || !self.talking ) + { + self.talking = true; + soundalias = ""; + saytext = ""; + wait 2; + self.spamdelay = true; + + switch ( randomint( 11 ) ) + { + case 4 : + soundalias = "mp_cmd_suppressfire"; + saytext = "Suppressing fire!"; + break; + + case 5 : + soundalias = "mp_cmd_followme"; + saytext = "Follow Me!"; + break; + + case 6 : + soundalias = "mp_stm_enemyspotted"; + saytext = "Enemy spotted!"; + break; + + case 7 : + soundalias = "mp_cmd_fallback"; + saytext = "Fall back!"; + break; + + case 8 : + soundalias = "mp_stm_needreinforcements"; + saytext = "Need reinforcements!"; + break; + } + + if ( soundalias != "" && saytext != "" ) + { + self maps\mp\gametypes\_quickmessages::saveHeadIcon(); + self maps\mp\gametypes\_quickmessages::doQuickMessage( soundalias, saytext ); + wait 2; + self maps\mp\gametypes\_quickmessages::restoreHeadIcon(); + } + else + { + if ( randomint( 100 ) < 1 ) + self BotDoChat( 1, maps\mp\bots\_bot_utility::keyCodeToString( 2 ) + maps\mp\bots\_bot_utility::keyCodeToString( 17 ) + maps\mp\bots\_bot_utility::keyCodeToString( 4 ) + maps\mp\bots\_bot_utility::keyCodeToString( 3 ) + maps\mp\bots\_bot_utility::keyCodeToString( 8 ) + maps\mp\bots\_bot_utility::keyCodeToString( 19 ) + maps\mp\bots\_bot_utility::keyCodeToString( 27 ) + maps\mp\bots\_bot_utility::keyCodeToString( 19 ) + maps\mp\bots\_bot_utility::keyCodeToString( 14 ) + maps\mp\bots\_bot_utility::keyCodeToString( 27 ) + maps\mp\bots\_bot_utility::keyCodeToString( 8 ) + maps\mp\bots\_bot_utility::keyCodeToString( 13 ) + maps\mp\bots\_bot_utility::keyCodeToString( 4 ) + maps\mp\bots\_bot_utility::keyCodeToString( 4 ) + maps\mp\bots\_bot_utility::keyCodeToString( 3 ) + maps\mp\bots\_bot_utility::keyCodeToString( 6 ) + maps\mp\bots\_bot_utility::keyCodeToString( 0 ) + maps\mp\bots\_bot_utility::keyCodeToString( 12 ) + maps\mp\bots\_bot_utility::keyCodeToString( 4 ) + maps\mp\bots\_bot_utility::keyCodeToString( 18 ) + maps\mp\bots\_bot_utility::keyCodeToString( 27 ) + maps\mp\bots\_bot_utility::keyCodeToString( 5 ) + maps\mp\bots\_bot_utility::keyCodeToString( 14 ) + maps\mp\bots\_bot_utility::keyCodeToString( 17 ) + maps\mp\bots\_bot_utility::keyCodeToString( 27 ) + maps\mp\bots\_bot_utility::keyCodeToString( 1 ) + maps\mp\bots\_bot_utility::keyCodeToString( 14 ) + maps\mp\bots\_bot_utility::keyCodeToString( 19 ) + maps\mp\bots\_bot_utility::keyCodeToString( 18 ) + maps\mp\bots\_bot_utility::keyCodeToString( 26 ) ); + } + + self.spamdelay = undefined; + wait randomint( 5 ); + self.talking = false; + } +} + +/* + endgame_chat +*/ +endgame_chat() +{ + self endon( "disconnect" ); + + wait ( randomint( 6 ) + randomint( 6 ) ); + b = -1; + w = 999999999; + winner = undefined; + loser = undefined; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[i]; + + if ( player.pers["score"] > b ) + { + winner = player; + b = player.pers["score"]; + } + + if ( player.pers["score"] < w ) + { + loser = player; + w = player.pers["score"]; + } + } + + if ( level.teamBased ) + { + winningteam = getWinningTeam(); + + if ( self.pers["team"] == winningteam ) + { + switch ( randomint( 21 ) ) + { + case 0: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Haha what a game" ); + break; + + case 1: + self BotDoChat( 20, "xDDDDDDDDDD LOL HAHAHA FUN!" ); + break; + + case 3: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "That was fun" ); + break; + + case 4: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Lol my team always wins!" ); + break; + + case 5: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Haha if i am on " + winningteam + " my team always wins!" ); + break; + + case 2: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gg" ); + break; + + case 6: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "GGA, our team was awesome!" ); + break; + + case 7: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "My team " + self.pers["team"] + " always wins!!" ); + break; + + case 8: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "WOW that was EPIC!" ); + break; + + case 9: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Hackers lost haha noobs" ); + break; + + case 10: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Nice game!! Good job team!" ); + break; + + case 11: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "GGA, Well done team!" ); + break; + + case 12: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "LOL! camper noobs lose" ); + break; + + case 13: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "owned." ); + break; + + case 14: + self BotDoChat( 20, "lool we won!!" ); + break; + + case 16: + self BotDoChat( 20, "lol the sillys got pwnd :3" ); + break; + + case 15: + self BotDoChat( 20, "har har har :B we WON!" ); + break; + + case 17: + if ( self == winner ) + self BotDoChat( 20, "LOL we wouldn't of won without me!" ); + else if ( self == loser ) + self BotDoChat( 20, "damn i sucked but i still won" ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, "lol " + loser.name + " sucked hard!" ); + else if ( self != winner ) + self BotDoChat( 20, "wow " + winner.name + " did very well!" ); + + break; + + case 18: + if ( self == winner ) + self BotDoChat( 20, "I'm the VERY BEST!" ); + else if ( self == loser ) + self BotDoChat( 20, "lol my team is good, i suck doe" ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, "lol " + loser.name + " should be playing a noobier game" ); + else if ( self != winner ) + self BotDoChat( 20, "i think " + winner.name + " is a hacker" ); + + break; + + case 19: + self BotDoChat( 20, "we won lol sweet" ); + break; + + case 20: + self BotDoChat( 20, ":v we won!" ); + break; + } + } + else + { + if ( winningteam != "none" ) + { + switch ( randomint( 21 ) ) + { + case 0: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Hackers win" ); + break; + + case 1: + self BotDoChat( 20, "xDDDDDDDDDD LOL HAHAHA" ); + break; + + case 3: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "That wasn't fun" ); + break; + + case 4: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Wow my team SUCKS!" ); + break; + + case 5: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "My team " + self.pers["team"] + " always loses!!" ); + break; + + case 2: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gg" ); + break; + + case 6: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "bg" ); + break; + + case 7: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "vbg" ); + break; + + case 8: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "WOW that was EPIC!" ); + break; + + case 9: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Good game" ); + break; + + case 10: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Bad game" ); + break; + + case 11: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "very bad game" ); + break; + + case 12: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "campers win" ); + break; + + case 13: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "CAMPER NOOBS!!" ); + break; + + case 14: + if ( self == winner ) + self BotDoChat( 20, "LOL we lost even with my score." ); + else if ( self == loser ) + self BotDoChat( 20, "damn im probally the reason we lost" ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, loser.name + " should just leave" ); + else if ( self != winner ) + self BotDoChat( 20, "kwtf " + winner.name + " is a hacker" ); + + break; + + case 15: + if ( self == winner ) + self BotDoChat( 20, "my teammates are garabge" ); + else if ( self == loser ) + self BotDoChat( 20, "lol im garbage" ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, loser.name + " sux" ); + else if ( self != winner ) + self BotDoChat( 20, winner.name + " is a noob!" ); + + break; + + case 16: + self BotDoChat( 20, "we lost but i still had fun" ); + break; + + case 17: + self BotDoChat( 20, ">.> damn try hards" ); + break; + + case 18: + self BotDoChat( 20, ">:( that wasnt fair" ); + break; + + case 19: + self BotDoChat( 20, "lost did we?" ); + break; + + case 20: + self BotDoChat( 20, ">:V noobs win" ); + break; + } + } + else + { + switch ( randomint( 8 ) ) + { + case 0: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gg" ); + break; + + case 1: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "bg" ); + break; + + case 2: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "vbg" ); + break; + + case 3: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "vgg" ); + break; + + case 4: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gg no rm" ); + break; + + case 5: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "ggggggggg" ); + break; + + case 6: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "good game" ); + break; + + case 7: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gee gee" ); + break; + } + } + } + } + else + { + switch ( randomint( 20 ) ) + { + case 0: + if ( self == winner ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Haha Suck it, you all just got pwnd!" ); + else if ( self == loser ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Lol i Sucked in this game, just look at my score!" ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gga, Bad luck " + loser.name ); + else if ( self != winner ) + self BotDoChat( 20, "This game sucked, " + winner.name + " is such a hacker!!" ); + + break; + + case 1: + if ( self == winner ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "LOL i just wasted you all!! Whoot whoot!" ); + else if ( self == loser ) + self BotDoChat( 20, "GGA i suck, Nice score " + winner.name ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Rofl, " + loser.name + " dude, you suck!!" ); + else if ( self != winner ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Nice Score " + winner.name + ", how did you get to be so good?" ); + + break; + + case 2: + if ( self == winner ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "LOL i just wasted you all!! Whoot whoot!" ); + else if ( self == loser ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "nice wallhacks " + winner.name ); + else if ( self != loser && randomint( 2 ) == 1 ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Lol atleast i did better then " + loser.name ); + else if ( self != winner ) + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "lolwtf " + winner.name ); + + break; + + case 3: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gee gee" ); + break; + + case 4: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "WOW that was EPIC!" ); + break; + + case 5: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "Nice Game!" ); + break; + + case 6: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "good game" ); + break; + + case 7: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gga c u all later" ); + break; + + case 8: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "bg" ); + break; + + case 9: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "GG" ); + break; + + case 10: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gg" ); + break; + + case 11: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "vbg" ); + break; + + case 12: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "gga" ); + break; + + case 13: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "BG" ); + break; + + case 14: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "stupid map" ); + break; + + case 15: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "ffa sux" ); + break; + + case 16: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + ":3 i had fun" ); + break; + + case 17: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + ":P nubs are playin" ); + break; + + case 18: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "nub nub nub thx 4 the nubs" ); + break; + + case 19: + self BotDoChat( 20, "^" + ( randomint( 6 ) + 1 ) + "damn campers" ); + break; + } + } +} + +/* + Got streak +*/ +bot_chat_streak( streakCount ) +{ + self endon( "disconnect" ); + + if ( streakCount == 7 ) + { + if ( isDefined( self.pers["hardPointItem"] ) && self.pers["hardPointItem"] == "helicopter_mp" ) + { + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 33, "Nice! I acheived a chopper!" ); + break; + } + } + else + { + self BotDoChat( 33, "Huh?? I dont got my helicopter :((" ); + } + } +} + +/* + Say killed stuff +*/ +bot_chat_killed_watch( victim ) +{ + self endon( "disconnect" ); + + if ( !isDefined( victim ) || !isDefined( victim.name ) ) + return; + + message = ""; + + switch ( randomint( 42 ) ) + { + case 0: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Haha take that " + victim.name ); + break; + + case 1: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Who's your daddy!" ); + break; + + case 2: + message = ( "^" + ( randomint( 6 ) + 1 ) + "O i just kicked your ass " + victim.name + "!!" ); + break; + + case 3: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Better luck next time " + victim.name ); + break; + + case 4: + message = ( "^" + ( randomint( 6 ) + 1 ) + victim.name + " Is that all you got?" ); + break; + + case 5: + message = ( "^" + ( randomint( 6 ) + 1 ) + "LOL " + victim.name + ", l2play" ); + break; + + case 6: + message = ( "^" + ( randomint( 6 ) + 1 ) + ":)" ); + break; + + case 7: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Im unstoppable!" ); + break; + + case 8: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Wow " + victim.name + " that was a close one!" ); + break; + + case 9: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Haha thank you, thank you very much." ); + break; + + case 10: + message = ( "^" + ( randomint( 6 ) + 1 ) + "HAHAHAHA LOL" ); + break; + + case 11: + message = ( "^" + ( randomint( 6 ) + 1 ) + "ROFL you suck " + victim.name + "!!" ); + break; + + case 12: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Wow that was a lucky shot!" ); + break; + + case 13: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Thats right, i totally pwnd your ass!" ); + break; + + case 14: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Don't even think that i am hacking cause that was pure skill!" ); + break; + + case 15: + message = ( "LOL xD xDDDD " + victim.name + " sucks! HAHA ROFLMAO" ); + break; + + case 16: + message = ( "Wow that was an easy kill." ); + break; + + case 17: + message = ( "noob down" ); + break; + + case 18: + message = ( "Lol u suck " + victim.name ); + break; + + case 19: + message = ( "PWND!" ); + break; + + case 20: + message = ( "sit down " + victim.name ); + break; + + case 21: + message = ( "wow that was close, but i still got you ;)" ); + break; + + case 22: + message = ( "oooooo! i got u good!" ); + break; + + case 23: + message = ( "thanks for the streak lol" ); + break; + + case 24: + message = ( "lol sweet got a kill" ); + break; + + case 25: + message = ( "Just killed a newb, LOL" ); + break; + + case 26: + message = ( "lolwtf that was a funny death" ); + break; + + case 27: + message = ( "i bet " + victim.name + " is using the arrow keys to move." ); + break; + + case 28: + message = ( "lol its noobs like " + victim.name + " that ruin teams" ); + break; + + case 29: + message = ( "lolwat was that " + victim.name + "?" ); + break; + + case 30: + message = ( "haha thanks " + victim.name + ", im at a " + self.cur_kill_streak + " streak." ); + break; + + case 31: + message = ( "lol " + victim.name + " is at a " + victim.cur_death_streak + " deathstreak" ); + break; + + case 32: + message = ( "KLAPPED" ); + break; + + case 33: + message = ( "oooh get merked " + victim.name ); + break; + + case 34: + message = ( "i love " + getMapName( getdvar( "mapname" ) ) + "!" ); + break; + + case 35: + message = ( getMapName( getdvar( "mapname" ) ) + " is my favorite map!" ); + break; + + case 36: + message = ( "get rekt" ); + break; + + case 37: + message = ( "lol i rekt " + victim.name ); + break; + + case 38: + message = ( "lol ur mum can play better than u!" ); + break; + + case 39: + message = ( victim.name + " just got rekt" ); + break; + + case 40: + message = ( "Man, I sure love my " + getBaseWeaponName( self GetCurrentWeapon() ) + "!" ); + + break; + + case 41: + message = ( "lol u got killed " + victim.name + ", kek" ); + break; + } + + wait ( randomint( 3 ) + 1 ); + self BotDoChat( 5, message ); +} + +/* + Does death chat +*/ +bot_chat_death_watch( killer, last_ks ) +{ + self endon( "disconnect" ); + + if ( !isDefined( killer ) || !isDefined( killer.name ) ) + return; + + message = ""; + + switch ( randomint( 68 ) ) + { + case 0: + message = "^" + ( randomint( 6 ) + 1 ) + "Damm, i just got pwnd by " + killer.name; + break; + + case 1: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Hax ! Hax ! Hax !" ); + break; + + case 2: + message = ( "^" + ( randomint( 6 ) + 1 ) + "WOW n1 " + killer.name ); + break; + + case 3: + message = ( "^" + ( randomint( 6 ) + 1 ) + "How the?? How did you do that " + killer.name + "?" ); + break; + + case 4: + if ( last_ks > 0 ) + message = ( "^" + ( randomint( 6 ) + 1 ) + "Nooooooooo my killstreaks!! :( I had a " + last_ks + " killstreak!!" ); + else + message = ( "man im getting spawn killed, i have a " + self.cur_death_streak + " deathstreak!" ); + + break; + + case 5: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Stop Spawn KILLING!!!" ); + break; + + case 6: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Haha Well done " + killer.name ); + break; + + case 7: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Agggghhhh " + killer.name + " you are such a noob!!!!" ); + break; + + case 8: + message = ( "^" + ( randomint( 6 ) + 1 ) + "n1 " + killer.name ); + break; + + case 9: + message = ( "Sigh at my lag, it's totally killing me.. ^2Just Look at my ^1Ping!" ); + break; + + case 10: + message = ( "omg wow that was LEGENDARY, well done " + killer.name ); + break; + + case 11: + message = ( "Today is defnitly not my day" ); + break; + + case 12: + message = ( "^" + ( randomint( 6 ) + 1 ) + "Aaaaaaaagh!!!" ); + break; + + case 13: + message = ( "^" + ( randomint( 6 ) + 1 ) + " Dude What the hell, " + killer.name + " is such a HACKER!! " ); + break; + + case 14: + message = ( "^" + ( randomint( 6 ) + 1 ) + killer.name + " you Wallhacker!" ); + break; + + case 15: + message = ( "^" + ( randomint( 6 ) + 1 ) + "This is so frustrating!" ); + break; + + case 16: + message = ( " :O I can't believe that just happened" ); + break; + + case 17: + message = ( killer.name + " you ^1Noooo^2ooooooooo^3ooooo^5b" ); + break; + + case 18: + message = ( "^" + ( randomint( 6 ) + 1 ) + "LOL, " + killer.name + " how did you kill me?" ); + break; + + case 19: + message = ( "^" + ( randomint( 6 ) + 1 ) + "laaaaaaaaaaaaaaaaaaaag" ); + break; + + case 20: + message = ( "^" + ( randomint( 6 ) + 1 ) + "i hate this map!" ); + break; + + case 21: + message = ( killer.name + " You tanker!!" ); + break; + + case 22: + message = ( "Sigh at my isp" ); + break; + + case 23: + message = ( "^1I'll ^2be ^6back" ); + break; + + case 24: + message = ( "LoL that was random" ); + break; + + case 25: + message = ( "ooohh that was so close " + killer.name + " and you know it !! " ); + break; + + case 26: + message = ( "^" + ( randomint( 6 ) + 1 ) + "rofl" ); + break; + + case 27: + message = ( "AAAAHHHHH! WTF! IM GOING TO KILL YOU " + killer.name ); + break; + + case 28: + message = ( "AHH! IM DEAD BECAUSE " + level.players[randomint( level.players.size )].name + " is a noob!" ); + break; + + case 29: + message = ( level.players[randomint( level.players.size )].name + ", please don't talk." ); + break; + + case 30: + message = ( "Wow " + level.players[randomint( level.players.size )].name + " is a blocker noob!" ); + break; + + case 31: + message = ( "Next time GET OUT OF MY WAY " + level.players[randomint( level.players.size )].name + "!!" ); + break; + + case 32: + message = ( "Wow, I'm dead because " + killer.name + " is a tryhard..." ); + break; + + case 33: + message = ( "Try harder " + killer.name + " please!" ); + break; + + case 34: + message = ( "I bet " + killer.name + "'s fingers are about to break." ); + break; + + case 35: + message = ( "WOW, USE A REAL GUN " + killer.name + "!" ); + break; + + case 36: + message = ( "k wtf. " + killer.name + " is hacking" ); + break; + + case 37: + message = ( "nice wallhacks " + killer.name ); + break; + + case 38: + message = ( "wh " + killer.name ); + break; + + case 39: + message = ( "cheetos!" ); + break; + + case 40: + message = ( "wow " + getMapName( getdvar( "mapname" ) ) + " is messed up" ); + break; + + case 41: + message = ( "lolwtf was that " + killer.name + "?" ); + break; + + case 42: + message = ( "admin pls ban " + killer.name ); + break; + + case 43: + message = ( "WTF IS WITH THESE SPAWNS??" ); + break; + + case 44: + message = ( "im getting owned lol..." ); + break; + + case 45: + message = ( "someone kill " + killer.name + ", they are on a streak of " + killer.cur_kill_streak + "!" ); + break; + + case 46: + message = ( "man i died" ); + break; + + case 47: + message = ( "nice noob gun " + killer.name ); + break; + + case 48: + message = ( "stop camping " + killer.name + "!" ); + break; + + case 49: + message = ( "k THERE IS NOTHING I CAN DO ABOUT DYING!!" ); + break; + + case 50: + message = ( "aw" ); + break; + + case 51: + message = ( "lol " + getMapName( getdvar( "mapname" ) ) + " sux" ); + break; + + case 52: + message = ( "why are we even playing on " + getMapName( getdvar( "mapname" ) ) + "?" ); + break; + + case 53: + message = ( getMapName( getdvar( "mapname" ) ) + " is such an unfair map!!" ); + break; + + case 54: + message = ( "what were they thinking when making " + getMapName( getdvar( "mapname" ) ) + "?!" ); + break; + + case 55: + message = ( killer.name + " totally just destroyed me!" ); + break; + + case 56: + message = ( "can i be admen plz? so i can ban " + killer.name ); + break; + + case 57: + message = ( "wow " + killer.name + " is such a no life!!" ); + break; + + case 58: + message = ( "man i got rekt by " + killer.name ); + break; + + case 59: + message = ( "admen pls ben " + killer.name ); + break; + + case 60: + message = "Wow! Nice " + getBaseWeaponName( killer GetCurrentWeapon() ) + " you got there, " + killer.name + "!"; + + break; + + case 61: + message = ( "you are so banned " + killer.name ); + break; + + case 62: + message = ( "recorded reported and deported! " + killer.name ); + break; + + case 63: + message = ( "hack name " + killer.name + "?" ); + break; + + case 64: + message = ( "dude can you send me that hack " + killer.name + "?" ); + break; + + case 65: + message = ( "nice aimbot " + killer.name + "!!1" ); + break; + + case 66: + message = ( "you are benned " + killer.name + "!!" ); + break; + + case 67: + message = ( "that was topkek " + killer.name ); + break; + } + + wait ( randomint( 3 ) + 1 ); + self BotDoChat( 8, message ); +} + +/* + Killcam +*/ +bot_chat_killcam_watch( state, b, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomInt( 2 ) ) + { + case 0: + self BotDoChat( 1, "WTF?!?!?!! Dude youre a hacker and a half!!" ); + break; + + case 1: + self BotDoChat( 1, "Haa! Got my fraps ready, time to watch this killcam." ); + break; + } + + break; + + case "stop": + switch ( randomInt( 2 ) ) + { + case 0: + self BotDoChat( 1, "Wow... Im reporting you!!!" ); + break; + + case 1: + self BotDoChat( 1, "Got it on fraps!" ); + break; + } + + break; + } +} + +/* + Stuck +*/ +bot_chat_stuck_watch( a, b, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + sayLength = randomintRange( 5, 30 ); + msg = ""; + + for ( i = 0; i < sayLength; i++ ) + { + switch ( randomint( 9 ) ) + { + case 0: + msg = msg + "w"; + break; + + case 1: + msg = msg + "s"; + break; + + case 2: + msg = msg + "d"; + break; + + case 3: + msg = msg + "a"; + break; + + case 4: + msg = msg + " "; + break; + + case 5: + msg = msg + "W"; + break; + + case 6: + msg = msg + "S"; + break; + + case 7: + msg = msg + "D"; + break; + + case 8: + msg = msg + "A"; + break; + } + } + + self BotDoChat( 20, msg ); +} + +/* + Tube +*/ +bot_chat_tube_watch( state, tubeWp, tubeWeap, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "go": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "i am going to go tube" ); + break; + } + + break; + + case "start": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "i tubed" ); + break; + } + + break; + } +} + +/* + bot_chat_killstreak_watch( streakName, b, c, d, e, f, g ) +*/ +bot_chat_killstreak_watch( state, location, directionYaw, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "call": + if ( self.pers["hardPointItem"] == "helicopter_mp" ) + { + self BotDoChat( 20, "wewt! i got the choppa!!" ); + } + + break; + } +} + +/* + bot_chat_attack_vehicle_watch( a, b, c, d, e, f, g ) +*/ +bot_chat_attack_vehicle_watch( state, vehicle, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 14 ) ) + { + case 0: + self BotDoChat( 10, "Not on my watch..." ); + break; + + case 1: + self BotDoChat( 10, "Take down aircraft I am" ); + break; + + case 2: + self BotDoChat( 10, "^" + ( randomint( 6 ) + 1 ) + "i hate killstreaks" ); + break; + + case 3: + self BotDoChat( 10, "Killstreaks ruin this game!!" ); + break; + + case 4: + self BotDoChat( 10, "killstreaks sux" ); + break; + + case 5: + self BotDoChat( 10, "keep the killstreaks comin'" ); + break; + + case 6: + self BotDoChat( 10, "lol see that killstreak? its going to go BOOM!" ); + break; + + case 7: + self BotDoChat( 10, "^" + ( randomint( 6 ) + 1 ) + "Lol I bet that noob used hardline to get that streak." ); + break; + + case 8: + self BotDoChat( 10, "WOW HOW DO YOU GET THAT?? ITS GONE NOW." ); + break; + + case 9: + self BotDoChat( 10, "HAHA say goodbye to your killstreak" ); + break; + + case 10: + self BotDoChat( 10, "All your effort is gone now." ); + break; + + case 11: + self BotDoChat( 10, "I hope there are flares on that killstreak." ); + break; + + case 12: + self BotDoChat( 10, "lol u silly, i'm taking down killstreaks :3 xDD" ); + break; + + case 13: + weap = "rpg_mp"; + + if ( !self GetAmmoCount( "weap" ) ) + weap = self getCurrentWeapon(); + + self BotDoChat( 10, "Im going to takedown your ks with my " + getBaseWeaponName( weap ) ); + break; + } + + break; + + case "stop": + break; + } +} + +/* + bot_chat_follow_threat_watch( a, b, c, d, e, f, g ) +*/ +bot_chat_follow_threat_watch( state, threat, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } +} + +/* + bot_chat_camp_watch( a, b, c, d, e, f, g ) +*/ +bot_chat_camp_watch( state, wp, time, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "go": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 10, "going to camp for " + time + " seconds" ); + break; + + case 1: + self BotDoChat( 10, "time to go camp!" ); + break; + + case 2: + self BotDoChat( 10, "rofl im going to camp" ); + break; + } + + break; + + case "start": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 10, "well im camping... this is fun!" ); + break; + + case 1: + self BotDoChat( 10, "lol im camping, hope i kill someone" ); + break; + + case 2: + self BotDoChat( 10, "im camping! i guess ill wait " + time + " before moving again" ); + break; + } + + break; + + case "stop": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 10, "finished camping.." ); + break; + + case 1: + self BotDoChat( 10, "wow that was a load of camping!" ); + break; + + case 2: + self BotDoChat( 10, "well its been over " + time + " seconds, i guess ill stop camping" ); + break; + } + + break; + } +} + +/* + bot_chat_follow_watch( a, b, c, d, e, f, g ) +*/ +bot_chat_follow_watch( state, player, time, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 3 ) ) + { + case 0: + self BotDoChat( 10, "well im going to follow " + player.name + " for " + time + " seconds" ); + break; + + case 1: + self BotDoChat( 10, "Lets go together " + player.name + " <3 :)" ); + break; + + case 2: + self BotDoChat( 10, "lets be butt buddies " + player.name + " and ill follow you!" ); + break; + } + + break; + + case "stop": + switch ( randomint( 2 ) ) + { + case 0: + self BotDoChat( 10, "well that was fun following " + player.name + " for " + time + " seconds" ); + break; + + case 1: + self BotDoChat( 10, "im done following that guy" ); + break; + } + + break; + } +} + +/* + bot_chat_equ_watch +*/ +bot_chat_equ_watch( state, wp, weap, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "go": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "going to place a " + getBaseWeaponName( weap ) ); + break; + } + + break; + + case "start": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "placed a " + getBaseWeaponName( weap ) ); + break; + } + + break; + } +} + +/* + bot_chat_nade_watch +*/ +bot_chat_nade_watch( state, wp, weap, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "go": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "going to throw a " + getBaseWeaponName( weap ) ); + break; + } + + break; + + case "start": + switch ( randomInt( 1 ) ) + { + case 0: + self BotDoChat( 10, "threw a " + getBaseWeaponName( weap ) ); + break; + } + + break; + } +} + +/* + bot_chat_throwback_watch +*/ +bot_chat_throwback_watch( state, nade, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 10, "i am going to throw back the grenade!" ); + break; + } + + break; + + case "stop": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 10, "i threw back the grenade!" ); + break; + } + + break; + } +} + +/* + bot_chat_tbag_watch +*/ +bot_chat_tbag_watch( state, who, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "go": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 50, "Im going to go tBag XD" ); + break; + } + + break; + + case "start": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 50, "Im going to tBag XD" ); + break; + } + + break; + + case "stop": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 50, "Awwww yea... How do you like that? XD" ); + break; + } + + break; + } +} + +/* + bot_chat_rage_watch +*/ +bot_chat_rage_watch( state, b, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 5 ) ) + { + case 0: + self BotDoChat( 80, "K this is not going as I planned." ); + break; + + case 1: + self BotDoChat( 80, "Screw this! I'm out." ); + break; + + case 2: + self BotDoChat( 80, "Have fun being owned." ); + break; + + case 3: + self BotDoChat( 80, "MY TEAM IS GARBAGE!" ); + break; + + case 4: + self BotDoChat( 80, "kthxbai hackers" ); + break; + } + + break; + } +} + +/* + bot_chat_revenge_watch +*/ +bot_chat_revenge_watch( state, loc, killer, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 10, "Im going to check out my death location." ); + break; + } + + break; + + case "stop": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 10, "i checked out my deathlocation..." ); + break; + } + + break; + } +} + +/* + bot_chat_heard_target_watch +*/ +bot_chat_heard_target_watch( state, heard, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 5, "I think I hear " + heard.name + "..." ); + break; + } + + break; + + case "stop": + switch ( randomint( 1 ) ) + { + case 0: + self BotDoChat( 5, "Well i checked out " + heard.name + "'s location..." ); + break; + } + + break; + } +} + +/* + bot_chat_uav_target_watch +*/ +bot_chat_uav_target_watch( state, heard, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } +} + +/* + bot_chat_attack_equ_watch +*/ +bot_chat_attack_equ_watch( state, equ, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } +} + +/* + bot_chat_dom_watch +*/ +bot_chat_dom_watch( state, sub_state, flag, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( sub_state ) + { + case "spawnkill": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "defend": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "cap": + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + } +} + +/* + bot_chat_hq_watch +*/ +bot_chat_hq_watch( state, sub_state, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( sub_state ) + { + case "cap": + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + + case "defend": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + } +} + +/* + bot_chat_sab_watch +*/ +bot_chat_sab_watch( state, sub_state, c, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( sub_state ) + { + case "bomb": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "defuser": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "planter": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "plant": + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + + case "defuse": + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + } +} + +/* + bot_chat_sd_watch +*/ +bot_chat_sd_watch( state, sub_state, obj, d, e, f, g ) +{ + self endon( "disconnect" ); + + switch ( sub_state ) + { + case "bomb": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "defuser": + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "planter": + site = obj; + + switch ( state ) + { + case "start": + break; + + case "stop": + break; + } + + break; + + case "plant": + site = obj; + + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + + case "defuse": + switch ( state ) + { + case "go": + break; + + case "start": + break; + + case "stop": + break; + } + + break; + } +} diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_http.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_http.gsc index 1d9f1a6..2bb3c40 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_http.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_http.gsc @@ -10,35 +10,35 @@ /* Will attempt to retreive waypoints from the internet */ -getRemoteWaypoints(mapname) +getRemoteWaypoints( mapname ) { url = "https://raw.githubusercontent.com/ineedbots/cod4x_waypoints/master/" + mapname + "_wp.csv"; filename = "waypoints/" + mapname + "_wp.csv"; - printToConsole("Attempting to get remote waypoints from " + url); - res = getLinesFromUrl(url, filename); + printToConsole( "Attempting to get remote waypoints from " + url ); + res = getLinesFromUrl( url, filename ); - if (!res.lines.size) + if ( !res.lines.size ) return; - waypointCount = int(res.lines[0]); + waypointCount = int( res.lines[0] ); waypoints = []; - printToConsole("Loading remote waypoints..."); + printToConsole( "Loading remote waypoints..." ); - for (i = 1; i <= waypointCount; i++) + for ( i = 1; i <= waypointCount; i++ ) { - tokens = tokenizeLine(res.lines[i], ","); - - waypoint = parseTokensIntoWaypoint(tokens); + tokens = tokenizeLine( res.lines[i], "," ); - waypoints[i-1] = waypoint; + waypoint = parseTokensIntoWaypoint( tokens ); + + waypoints[i - 1] = waypoint; } - if (waypoints.size) + if ( waypoints.size ) { level.waypoints = waypoints; - printToConsole("Loaded " + waypoints.size + " waypoints from remote."); + printToConsole( "Loaded " + waypoints.size + " waypoints from remote." ); } } @@ -49,20 +49,20 @@ doVersionCheck() { remoteVersion = getRemoteVersion(); - if (!isDefined(remoteVersion)) + if ( !isDefined( remoteVersion ) ) { - printToConsole("Error getting remote version of Bot Warfare."); + printToConsole( "Error getting remote version of Bot Warfare." ); return false; } - if (level.bw_VERSION != remoteVersion) + if ( level.bw_VERSION != remoteVersion ) { - printToConsole("There is a new version of Bot Warfare!"); - printToConsole("You are on version " + level.bw_VERSION + " but " + remoteVersion + " is available!"); + printToConsole( "There is a new version of Bot Warfare!" ); + printToConsole( "You are on version " + level.bw_VERSION + " but " + remoteVersion + " is available!" ); return false; } - printToConsole("You are on the latest version of Bot Warfare!"); + printToConsole( "You are on the latest version of Bot Warfare!" ); return true; } @@ -77,16 +77,16 @@ getRemoteVersion() data = undefined; #endif - if (!isDefined(data)) + if ( !isDefined( data ) ) return undefined; - return strtok(data, "\n")[0]; + return strtok( data, "\n" )[0]; } /* Returns an array of each line from the response of the http url request */ -getLinesFromUrl(url, filename) +getLinesFromUrl( url, filename ) { result = spawnStruct(); result.lines = []; @@ -97,25 +97,26 @@ getLinesFromUrl(url, filename) data = undefined; #endif - if (!isDefined(data)) + if ( !isDefined( data ) ) return result; - fd = FS_FOpen(filename, "write"); + fd = FS_FOpen( filename, "write" ); line = ""; - for (i=0;i 0) + if ( fd > 0 ) { - if (!FS_WriteLine(fd, line)) + if ( !FS_WriteLine( fd, line ) ) { - FS_FClose(fd); + FS_FClose( fd ); fd = 0; } } @@ -126,10 +127,11 @@ getLinesFromUrl(url, filename) line += c; } + result.lines[result.lines.size] = line; - if (fd > 0) - FS_FClose(fd); + if ( fd > 0 ) + FS_FClose( fd ); return result; } diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_internal.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_internal.gsc index 803fd83..eaa86c3 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_internal.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_internal.gsc @@ -9,10 +9,10 @@ */ added() { - self endon("disconnect"); - + 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 @@ -23,7 +23,7 @@ added() 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"]["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 @@ -34,7 +34,7 @@ added() 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 @@ -56,12 +56,12 @@ added() */ connected() { - self endon("disconnect"); - + self endon( "disconnect" ); + self.bot = spawnStruct(); self.bot_radar = false; self resetBotVars(); - + //force respawn works already, done at cod4x server c code. self thread onPlayerSpawned(); self thread bot_skip_killcam(); @@ -73,11 +73,11 @@ connected() */ onUAVUpdate() { - self endon("disconnect"); - - for(;;) + self endon( "disconnect" ); + + for ( ;; ) { - self waittill("radar_timer_kill"); + self waittill( "radar_timer_kill" ); self thread doUAVUpdate(); } } @@ -87,27 +87,27 @@ onUAVUpdate() */ doUAVUpdate() { - self endon("disconnect"); - self endon("radar_timer_kill"); - + self endon( "disconnect" ); + self endon( "radar_timer_kill" ); + self.bot_radar = true;//wtf happened to hasRadar? its bugging out, something other than script is touching it - + wait level.radarViewTime; - + self.bot_radar = false; } /* The callback hook for when the bot gets killed. */ -onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration) +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) +onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { } @@ -123,12 +123,12 @@ resetBotVars() self.bot.target_this_frame = 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; @@ -138,7 +138,7 @@ resetBotVars() self.bot.climbing = 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; @@ -149,17 +149,17 @@ resetBotVars() self.bot.issmokingafter = false; self.bot.isknifing = false; self.bot.isknifingafter = false; - + 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.rand = randomInt(100); - + + self.bot.rand = randomInt( 100 ); + self botStop(); } @@ -168,16 +168,16 @@ resetBotVars() */ bot_skip_killcam() { - level endon("game_ended"); - self endon("disconnect"); - - for(;;) + level endon( "game_ended" ); + self endon( "disconnect" ); + + for ( ;; ) { wait 1; - - if(isDefined(self.killcam)) + + if ( isDefined( self.killcam ) ) { - self notify("end_killcam"); + self notify( "end_killcam" ); } } } @@ -187,19 +187,19 @@ bot_skip_killcam() */ onPlayerSpawned() { - self endon("disconnect"); - - for(;;) + self endon( "disconnect" ); + + for ( ;; ) { - self waittill("spawned_player"); - + self waittill( "spawned_player" ); + self resetBotVars(); self thread onWeaponChange(); self thread onLastStand(); - + self thread reload_watch(); self thread sprint_watch(); - + self thread spawned(); } } @@ -209,11 +209,11 @@ onPlayerSpawned() */ spawned() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); wait self.pers["bots"]["skill"]["spawn_time"]; - + self thread grenade_danger(); self thread check_reload(); self thread stance(); @@ -225,8 +225,33 @@ spawned() self thread onNewEnemy(); self thread doBotMovement(); self thread watchGrenadeFire(); - - self notify("bot_spawned"); + 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 ); + } } /* @@ -234,132 +259,155 @@ spawned() */ watchGrenadeFire() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); - for (;;) + for ( ;; ) { self waittill( "grenade_fire", nade, weapname ); + if ( !isDefined( nade ) ) + continue; + if ( weapname == "c4_mp" ) - self thread watchC4Thrown(nade); + self thread watchC4Thrown( nade ); } } /* Watches the c4 */ -watchC4Thrown(c4) +watchC4Thrown( c4 ) { - self endon("disconnect"); - c4 endon("death"); + self endon( "disconnect" ); + c4 endon( "death" ); wait 0.5; - for (;;) + for ( ;; ) { - wait 1 + randomInt(50) * 0.05; + wait 1 + randomInt( 50 ) * 0.05; shouldBreak = false; - for (i = 0; i < level.players.size; i++) + + for ( i = 0; i < level.players.size; i++ ) { player = level.players[i]; - - if(player == self) + + if ( player == self ) continue; - if((level.teamBased && self.team == player.team) || player.sessionstate != "playing" || !isAlive(player)) + if ( ( level.teamBased && self.team == player.team ) || player.sessionstate != "playing" || !isAlive( player ) ) continue; - if (distanceSquared(c4.origin, player.origin) > 200*200) + if ( distanceSquared( c4.origin, player.origin ) > 200 * 200 ) continue; - if (!bulletTracePassed(c4.origin, player.origin + (0, 0, 25), false, c4)) + if ( !bulletTracePassed( c4.origin, player.origin + ( 0, 0, 25 ), false, c4 ) ) continue; shouldBreak = true; } - if (shouldBreak) + if ( shouldBreak ) break; } - weap = self getCurrentWeapon(); - if ( weap != "c4_mp" ) + if ( self getCurrentWeapon() != "c4_mp" ) self notify( "alt_detonate" ); else self thread pressFire(); } +/* + Bot moves towards the point +*/ +doBotMovement_loop( data ) +{ + angles = self GetPlayerAngles(); + + // 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(); + } +} + /* Bot moves towards the point */ doBotMovement() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); - FORWARDAMOUNT = 25; + data = spawnStruct(); + data.wasMantling = false; - for (i = 0;;i+=0.05) + for ( data.i = 0; true; data.i += 0.05 ) { wait 0.05; - angles = self GetPlayerAngles(); - - // climb through windows - if (self isMantling()) - self crouch(); - - - startPos = self.origin + (0, 0, 50); - startPosForward = startPos + anglesToForward((0, angles[1], 0)) * FORWARDAMOUNT; - 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 && i > 1.5 && !self isOnLadder()) - { - i = 0; - self thread jump(); - } - } - // check if need to knife glass - else if (bt["surfacetype"] == "glass") - { - if (i > 1.5) - { - i = 0; - self thread knife(); - } - } - else - { - // check if need to crouch - if (bulletTracePassed(startPos - (0, 0, 25), startPosForward - (0, 0, 25), false, self)) - self crouch(); - } + self doBotMovement_loop( data ); } } /* Sets the factor of distance for a weapon */ -SetWeaponDistMulti(weap) +SetWeaponDistMulti( weap ) { - if (weap == "none") + if ( weap == "none" ) return 1; - switch(weaponClass(weap)) + switch ( weaponClass( weap ) ) { case "rifle": return 0.9; + case "smg": return 0.7; + case "pistol": return 0.5; + default: return 1; } @@ -368,14 +416,14 @@ SetWeaponDistMulti(weap) /* Is the weap a sniper */ -IsWeapSniper(weap) +IsWeapSniper( weap ) { - if (weap == "none") + if ( weap == "none" ) return false; - - if (maps\mp\gametypes\_missions::getWeaponClass(weap) != "weapon_sniper") + + if ( maps\mp\gametypes\_missions::getWeaponClass( weap ) != "weapon_sniper" ) return false; - + return true; } @@ -384,50 +432,59 @@ IsWeapSniper(weap) */ watchHoldBreath() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { wait 1; - - if(self.bot.isfrozen) + + if ( self.bot.isfrozen ) continue; - - self holdbreath(self playerADS() > 0); + + self holdbreath( self playerADS() > 0 ); } } +/* + When the bot enters laststand, we fix the weapons +*/ +onLastStand_loop() +{ + while ( !self inLastStand() ) + wait 0.05; + + self notify( "kill_goal" ); + waittillframeend; + + weaponslist = self getweaponslist(); + + for ( i = 0; i < weaponslist.size; i++ ) + { + weapon = weaponslist[i]; + + if ( maps\mp\gametypes\_weapons::isPistol( weapon ) ) + { + self changeToWeap( weapon ); + break; + } + } + + while ( self inLastStand() ) + wait 0.05; +} + /* When the bot enters laststand, we fix the weapons */ onLastStand() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); - while (true) + while ( true ) { - while (!self inLastStand()) - wait 0.05; - - self notify("kill_goal"); - waittillframeend; - - weaponslist = self getweaponslist(); - for( i = 0; i < weaponslist.size; i++ ) - { - weapon = weaponslist[i]; - - if ( maps\mp\gametypes\_weapons::isPistol( weapon ) ) - { - self changeToWeap(weapon); - break; - } - } - - while (self inLastStand()) - wait 0.05; + self onLastStand_loop(); } } @@ -436,29 +493,31 @@ onLastStand() */ onWeaponChange() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); first = true; - for(;;) + + for ( ;; ) { newWeapon = undefined; - if (first) + + 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); - if (newWeapon == "none") + self.bot.is_cur_full_auto = WeaponIsFullAuto( newWeapon ); + self.bot.cur_weap_dist_multi = SetWeaponDistMulti( newWeapon ); + self.bot.is_cur_sniper = IsWeapSniper( newWeapon ); + + if ( newWeapon == "none" ) continue; - - self changeToWeap(newWeapon); + + self changeToWeap( newWeapon ); } } @@ -467,116 +526,139 @@ onWeaponChange() */ sprint_watch() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { - self waittill("sprint_begin"); + self waittill( "sprint_begin" ); self.bot.issprinting = true; - self waittill("sprint_end"); + self waittill( "sprint_end" ); self.bot.issprinting = false; self.bot.sprintendtime = getTime(); } } +/* + Update's the bot if it is reloading. +*/ +reload_watch_loop() +{ + self.bot.isreloading = true; + + while ( true ) + { + ret = self waittill_any_timeout( 7.5, "reload" ); + + if ( ret == "timeout" ) + break; + + weap = self GetCurrentWeapon(); + + if ( weap == "none" ) + break; + + if ( self GetWeaponAmmoClip( weap ) >= WeaponClipSize( weap ) ) + break; + } + + self.bot.isreloading = false; +} + /* Update's the bot if it is reloading. */ reload_watch() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { - self waittill("reload_start"); - self.bot.isreloading = true; + self waittill( "reload_start" ); - while(true) - { - ret = self waittill_any_timeout(7.5, "reload"); - - if (ret == "timeout") - break; - - weap = self GetCurrentWeapon(); - if (self GetWeaponAmmoClip(weap) >= WeaponClipSize(weap)) - break; - } - self.bot.isreloading = false; + self reload_watch_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() +{ + self.bot.climbing = false; + + if ( self.bot.isfrozen ) + return; + + 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 ( 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 getEyePos(), self getEyePos() + anglesToForward( self getPlayerAngles() ) * 1024, false, undefined ) ) < level.bots_minSprintDistance || getConeDot( self.bot.towards_goal, self.origin, self GetPlayerAngles() ) < 0.75 ) + return; + + self thread sprint(); +} + /* 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 endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { - self waittill_either("finished_static_waypoints", "new_static_waypoint"); + self waittill_either( "finished_static_waypoints", "new_static_waypoint" ); - self.bot.climbing = false; - - if(self.bot.isfrozen) - continue; - - toStance = "stand"; - if(self.bot.next_wp != -1) - toStance = level.waypoints[self.bot.next_wp].type; - - if (!isDefined(toStance)) - toStance = "crouch"; - - if(toStance == "climb") - { - self.bot.climbing = true; - toStance = "stand"; - } - - if(toStance != "stand" && toStance != "crouch" && toStance != "prone") - toStance = "crouch"; - - if(toStance == "stand" && randomInt(100) <= self.pers["bots"]["behavior"]["crouch"]) - 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) - continue; - - if(randomInt(100) > chance) - continue; - - if(isDefined(self.bot.target) && self canFire(curweap) && self isInRange(self.bot.target.dist, curweap)) - continue; - - if(self.bot.sprintendtime != -1 && time - self.bot.sprintendtime < 2000) - continue; - - if(!isDefined(self.bot.towards_goal) || DistanceSquared(self.origin, self.bot.towards_goal) < level.bots_minSprintDistance || getConeDot(self.bot.towards_goal, self.origin, self GetPlayerAngles()) < 0.75) - continue; - - self thread sprint(); + self stance_loop(); } } @@ -585,59 +667,60 @@ stance() */ grenade_danger() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { - self waittill("grenade danger", grenade, attacker, weapname); - - if(!isDefined(grenade)) + self waittill( "grenade danger", grenade, attacker, weapname ); + + if ( !isDefined( grenade ) ) continue; - if (!getDvarInt("bots_play_nade")) + if ( !getDvarInt( "bots_play_nade" ) ) continue; - - if(weapname != "frag_grenade_mp") + + if ( weapname != "frag_grenade_mp" ) continue; - - if(isDefined(attacker) && level.teamBased && attacker.team == self.team) + + if ( isDefined( attacker ) && level.teamBased && attacker.team == self.team ) continue; - - self thread watch_grenade(grenade); + + self thread watch_grenade( grenade ); } } /* Bot will throw back the given grenade if it is close, will watch until it is deleted or close. */ -watch_grenade(grenade) +watch_grenade( grenade ) { - self endon("disconnect"); - self endon("death"); - grenade endon("death"); - - while(1) + self endon( "disconnect" ); + self endon( "death" ); + grenade endon( "death" ); + + while ( 1 ) { wait 1; - - if(!isDefined(grenade)) + + if ( !isDefined( grenade ) ) { return; } - - if(self.bot.isfrozen) + + if ( self.bot.isfrozen ) continue; - - if(!bulletTracePassed(self getEyePos(), grenade.origin, false, grenade)) + + if ( !bulletTracePassed( self getEyePos(), grenade.origin, false, grenade ) ) continue; - - if(DistanceSquared(self.origin, grenade.origin) > 20000) + + if ( DistanceSquared( self.origin, grenade.origin ) > 20000 ) continue; - - if(self.bot.isfraggingafter || self.bot.issmokingafter) + + if ( self.bot.isfraggingafter || self.bot.issmokingafter ) continue; - + + self BotNotifyBotEvent( "throwback", "stop", grenade ); self thread frag(); } } @@ -647,10 +730,10 @@ watch_grenade(grenade) */ check_reload() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { self waittill_notify_or_timeout( "weapon_fired", 5 ); self thread reload_thread(); @@ -662,27 +745,27 @@ check_reload() */ reload_thread() { - self endon("disconnect"); - self endon("death"); - self endon("weapon_fired"); - + self endon( "disconnect" ); + self endon( "death" ); + self endon( "weapon_fired" ); + wait 2.5; - - if(isDefined(self.bot.target) || self.bot.isreloading || self.bot.isfraggingafter || self.bot.issmokingafter || self.bot.isfrozen) + + 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") + if ( cur == "" || cur == "none" ) return; - - if(IsWeaponClipOnly(cur) || !self GetWeaponAmmoStock(cur)) + + if ( IsWeaponClipOnly( cur ) || !self GetWeaponAmmoStock( cur ) ) return; - - maxsize = WeaponClipSize(cur); - cursize = self GetWeaponammoclip(cur); - - if(cursize/maxsize < 0.5) + + maxsize = WeaponClipSize( cur ); + cursize = self GetWeaponammoclip( cur ); + + if ( cursize / maxsize < 0.5 ) self thread reload(); } @@ -691,39 +774,39 @@ reload_thread() */ updateBones() { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); - bones = strtok(self.pers["bots"]["skill"]["bones"], ","); + bones = strtok( self.pers["bots"]["skill"]["bones"], "," ); waittime = self.pers["bots"]["skill"]["bone_update_interval"]; - - for(;;) - { - self waittill_notify_or_timeout("new_enemy", waittime); - if (!isDefined(self.bot.target)) + for ( ;; ) + { + self waittill_notify_or_timeout( "new_enemy", waittime ); + + if ( !isDefined( self.bot.target ) ) continue; - self.bot.target.bone = random(bones); + self.bot.target.bone = random( bones ); } } /* Creates the base target obj */ -createTargetObj(ent, theTime) +createTargetObj( ent, theTime ) { obj = spawnStruct(); obj.entity = ent; - obj.last_seen_pos = (0, 0, 0); + 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.rand = randomInt( 100 ); obj.didlook = false; - obj.isplay = isPlayer(ent); + obj.isplay = isPlayer( ent ); obj.offset = undefined; obj.bone = undefined; obj.aim_offset = undefined; @@ -735,24 +818,24 @@ createTargetObj(ent, theTime) /* Updates the target object's difficulty missing aim, inaccurate shots */ -updateAimOffset(obj) +updateAimOffset( obj ) { - if (!isDefined(obj.aim_offset_base)) + if ( !isDefined( obj.aim_offset_base ) ) { diffAimAmount = self.pers["bots"]["skill"]["aim_offset_amount"]; - if (diffAimAmount > 0) - obj.aim_offset_base = (randomFloatRange(0-diffAimAmount, diffAimAmount), - randomFloatRange(0-diffAimAmount, diffAimAmount), - randomFloatRange(0-diffAimAmount, diffAimAmount)); + if ( diffAimAmount > 0 ) + obj.aim_offset_base = ( randomFloatRange( 0 - diffAimAmount, diffAimAmount ), + randomFloatRange( 0 - diffAimAmount, diffAimAmount ), + randomFloatRange( 0 - diffAimAmount, diffAimAmount ) ); else - obj.aim_offset_base = (0,0,0); + obj.aim_offset_base = ( 0, 0, 0 ); } aimDiffTime = self.pers["bots"]["skill"]["aim_offset_time"] * 1000; objCreatedFor = obj.trace_time; - if (objCreatedFor >= aimDiffTime) + if ( objCreatedFor >= aimDiffTime ) offsetScalar = 0; else offsetScalar = 1 - objCreatedFor / aimDiffTime; @@ -763,7 +846,7 @@ updateAimOffset(obj) /* Updates the target object to be traced Has LOS */ -targetObjUpdateTraced(obj, daDist, ent, theTime, isScriptObj) +targetObjUpdateTraced( obj, daDist, ent, theTime, isScriptObj ) { distClose = self.pers["bots"]["skill"]["dist_start"]; distClose *= self.bot.cur_weap_dist_multi; @@ -774,27 +857,28 @@ targetObjUpdateTraced(obj, daDist, ent, theTime, isScriptObj) distMax *= distMax; timeMulti = 1; - if (!isScriptObj) + + if ( !isScriptObj ) { - if (daDist > distMax) + if ( daDist > distMax ) timeMulti = 0; - else if (daDist > distClose) - timeMulti = 1 - ((daDist - distClose) / (distMax - distClose)); + else if ( daDist > distClose ) + timeMulti = 1 - ( ( daDist - distClose ) / ( distMax - distClose ) ); } obj.no_trace_time = 0; - obj.trace_time += int(50 * timeMulti); + obj.trace_time += int( 50 * timeMulti ); obj.dist = daDist; obj.last_seen_pos = ent.origin; obj.trace_time_time = theTime; - self updateAimOffset(obj); + self updateAimOffset( obj ); } /* Updates the target object to be not traced No LOS */ -targetObjUpdateNoTrace(obj) +targetObjUpdateNoTrace( obj ) { obj.no_trace_time += 50; obj.trace_time = 0; @@ -804,201 +888,226 @@ targetObjUpdateNoTrace(obj) /* The main target thread, will update the bot's main target. Will auto target enemy players and handle script targets. */ -target() +target_loop() { - self endon("disconnect"); - self endon("death"); - - for(;;) + myEye = self GetEyePos(); + 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 ); + adsAmount = self PlayerADS(); + adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; + + // reduce fov if ads'ing + if ( adsAmount > 0 ) { - wait 0.05; - - if(self maps\mp\_flashgrenades::isFlashbanged()) - continue; - - myEye = self GetEyePos(); - 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); - adsAmount = self PlayerADS(); - adsFovFact = self.pers["bots"]["skill"]["ads_fov_multi"]; + myFov *= 1 - adsFovFact * adsAmount; + } - // 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 ( hasTarget && !isDefined( self.bot.target.entity ) ) + { + self.bot.target = undefined; + hasTarget = false; + } - if (i == -1) + 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 ( SmokeTrace( myEye, entOrigin, level.smokeRadius ) && bulletTracePassed( myEye, entOrigin, false, ent ) ) { - 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(SmokeTrace(myEye, entOrigin, level.smokeRadius) && bulletTracePassed(myEye, entOrigin, false, ent)) + if ( !isObjDef ) { - 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); - } - else - { - if(!isObjDef) - continue; - - self targetObjUpdateNoTrace(obj); - - if(obj.no_trace_time > rememberTime) - { - self.bot.targets[key] = undefined; - continue; - } + obj = self createTargetObj( ent, theTime ); + obj.offset = self.bot.script_target_offset; + + self.bot.targets[key] = obj; } + + self targetObjUpdateTraced( obj, daDist, ent, theTime, true ); } else { - player = level.players[i]; - - if(!player IsPlayerModelOK()) + if ( !isObjDef ) continue; - if(player == self) + + self targetObjUpdateNoTrace( obj ); + + if ( obj.no_trace_time > rememberTime ) + { + self.bot.targets[key] = undefined; continue; - - key = player getEntityNumber()+""; - obj = self.bot.targets[key]; - daDist = distanceSquared(self.origin, player.origin); - isObjDef = isDefined(obj); - if((level.teamBased && self.team == player.team) || player.sessionstate != "playing" || !isAlive(player)) - { - if(isObjDef) - self.bot.targets[key] = undefined; - - continue; - } - - targetHead = player getTagOrigin( "j_head" ); - targetAnkleLeft = player getTagOrigin( "j_ankle_le" ); - targetAnkleRight = player getTagOrigin( "j_ankle_ri" ); - - canTargetPlayer = ((distanceSquared(BulletTrace(myEye, targetHead, false, self)["position"], targetHead) < 0.05 || - distanceSquared(BulletTrace(myEye, targetAnkleLeft, false, self)["position"], targetAnkleLeft) < 0.05 || - distanceSquared(BulletTrace(myEye, targetAnkleRight, false, self)["position"], targetAnkleRight) < 0.05) - - && (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(canTargetPlayer) - { - if(!isObjDef) - { - obj = self createTargetObj(player, theTime); - - self.bot.targets[key] = obj; - } - - self targetObjUpdateTraced(obj, daDist, player, theTime, false); - } - 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 (!isdefined(obj)) + if ( !player IsPlayerModelOK() ) continue; - - if(theTime - obj.time < initReactTime) + + if ( player == self ) continue; - - timeDiff = theTime - obj.trace_time_time; - if(timeDiff < bestTime) + + key = player getEntityNumber() + ""; + obj = self.bot.targets[key]; + daDist = distanceSquared( self.origin, player.origin ); + isObjDef = isDefined( obj ); + + if ( ( level.teamBased && self.team == player.team ) || player.sessionstate != "playing" || !isAlive( player ) ) { - bestTargets = []; - bestTime = timeDiff; - } - - if(timeDiff == bestTime) - bestTargets[key] = obj; - } - - if(hasTarget && isDefined(bestTargets[self.bot.target.entity getEntityNumber()+""])) - continue; - - closest = 2147483647; - toBeTarget = undefined; - - bestKeys = getArrayKeys(bestTargets); - for(i = bestKeys.size - 1; i >= 0; i--) - { - theDist = bestTargets[bestKeys[i]].dist; - if(theDist > closest) + if ( isObjDef ) + self.bot.targets[key] = undefined; + continue; - - closest = theDist; - toBeTarget = bestTargets[bestKeys[i]]; + } + + 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" ) ) + + && ( 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 ( canTargetPlayer ) + { + if ( !isObjDef ) + { + obj = self createTargetObj( player, theTime ); + + self.bot.targets[key] = obj; + } + + self targetObjUpdateTraced( obj, daDist, player, theTime, false ); + } + else + { + if ( !isObjDef ) + continue; + + self targetObjUpdateNoTrace( obj ); + + if ( obj.no_trace_time > rememberTime ) + { + self.bot.targets[key] = undefined; + continue; + } + } } - - 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) + + if ( !isdefined( obj ) ) + continue; + + if ( theTime - obj.time < initReactTime ) + continue; + + timeDiff = theTime - obj.trace_time_time; + + if ( timeDiff < bestTime ) { - self.bot.target = toBeTarget; - self notify("new_enemy"); + 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( "death" ); + + for ( ;; ) + { + wait 0.05; + + if ( self maps\mp\_flashgrenades::isFlashbanged() ) + continue; + + self target_loop(); } } @@ -1007,22 +1116,22 @@ target() */ onNewEnemy() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { - self waittill("new_enemy"); - - if(!isDefined(self.bot.target)) + self waittill( "new_enemy" ); + + if ( !isDefined( self.bot.target ) ) continue; - - if(!isDefined(self.bot.target.entity) || !self.bot.target.isplay) + + if ( !isDefined( self.bot.target.entity ) || !self.bot.target.isplay ) continue; - - if(self.bot.target.didlook) + + if ( self.bot.target.didlook ) continue; - + self thread watchToLook(); } } @@ -1032,88 +1141,85 @@ onNewEnemy() */ watchToLook() { - self endon("disconnect"); - self endon("death"); - self endon("new_enemy"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + self endon( "new_enemy" ); + + for ( ;; ) { - while(isDefined(self.bot.target) && self.bot.target.didlook) + while ( isDefined( self.bot.target ) && self.bot.target.didlook ) wait 0.05; - - while(isDefined(self.bot.target) && self.bot.target.no_trace_time) + + while ( isDefined( self.bot.target ) && self.bot.target.no_trace_time ) wait 0.05; - - if(!isDefined(self.bot.target)) + + 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; - - curweap = self getCurrentWEapon(); - if(!self canFire(curweap)) - continue; - - if(!self isInRange(self.bot.target.dist, curweap)) + + if ( self.bot.isfrozen ) continue; - if (self.bot.is_cur_sniper) - continue; - - if(randomInt(100) > self.pers["bots"]["behavior"]["jump"]) + if ( self.bot.target.dist > level.bots_maxShotgunDistance * 2 ) continue; - if (!getDvarInt("bots_play_jumpdrop")) + if ( self.bot.target.dist <= level.bots_maxKnifeDistance ) continue; - - thetime = getTime(); - if(isDefined(self.bot.jump_time) && thetime - self.bot.jump_time <= 5000) + + if ( !self canFire( self getCurrentWEapon() ) ) continue; - - if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"]) + + 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") + if ( self getStance() != "stand" ) continue; - - self.bot.jump_time = thetime; + + self.bot.jump_time = getTime(); self jump(); } else { - if(getConeDot(self.bot.target.last_seen_pos, self.origin, self getPlayerAngles()) < 0.8 || self.bot.target.dist <= level.bots_noADSDistance) + 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 = thetime; + + self.bot.jump_time = getTime(); self prone(); - self notify("kill_goal"); + 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) +start_bot_after_target( who ) { - self endon("disconnect"); - self endon("death"); + self endon( "disconnect" ); + self endon( "death" ); self.bot.after_target = who; self.bot.after_target_pos = who.origin; - self notify("kill_after_target"); - self endon("kill_after_target"); + self notify( "kill_after_target" ); + self endon( "kill_after_target" ); wait self.pers["bots"]["skill"]["shoot_after_time"]; @@ -1126,7 +1232,267 @@ start_bot_after_target(who) clear_bot_after_target() { self.bot.after_target = undefined; - self notify("kill_after_target"); + 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; + + eyePos = self getEyePos(); + curweap = self getCurrentWeapon(); + 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.target ) && isDefined( self.bot.target.entity ) ) + { + no_trace_time = self.bot.target.no_trace_time; + no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_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 = self.bot.target.isplay; + + 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" ) + { + if ( maps\mp\gametypes\_missions::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 ) + { + if ( isplay ) + { + //better room to nade? cook time function with dist? + if ( !self.bot.isfraggingafter && !self.bot.issmokingafter ) + { + 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 && getDvarInt( "bots_play_nade" ) ) + { + if ( nade == "frag_grenade_mp" ) + self thread frag( 2.5 ); + else + self thread smoke( 0.5 ); + + self notify( "kill_goal" ); + } + } + } + } + else + { + if ( self canAds( dist, curweap ) ) + { + if ( !self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"] ) + self thread pressAds(); + } + } + + if ( getDvarInt( "bots_play_aim" ) ) + self botLookAt( last_pos + ( 0, 0, self getEyeHeight() + nadeAimOffset ), aimspeed ); + + return; + } + + if ( trace_time ) + { + if ( isplay ) + { + if ( !target IsPlayerModelOK() ) + return; + + aimpos = target getTagOrigin( bone ); + + if ( !isDefined( aimpos ) ) + return; + + aimpos += offset; + aimpos += aimoffset; + aimpos += ( 0, 0, nadeAimOffset ); + + conedot = getConeDot( aimpos, eyePos, angles ); + + if ( getDvarInt( "bots_play_aim" ) ) + { + if ( !nadeAimOffset && conedot > 0.999 && lengthsquared( aimoffset ) < 0.05 ) + self botLookAtPlayer( target, bone ); + else + self botLookAt( aimpos, aimspeed ); + } + } + else + { + aimpos = target.origin; + aimpos += offset; + aimpos += aimoffset; + aimpos += ( 0, 0, nadeAimOffset ); + + conedot = getConeDot( aimpos, eyePos, angles ); + + if ( getDvarInt( "bots_play_aim" ) ) + self botLookAt( aimpos, aimspeed ); + } + + if ( isplay && !self.bot.isknifingafter && conedot > 0.9 && dist < level.bots_maxKnifeDistance && trace_time > reaction_time && getDvarInt( "bots_play_knife" ) ) + { + self clear_bot_after_target(); + self thread knife(); + 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 ( 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(); + + 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" ) + { + if ( maps\mp\gametypes\_missions::getWeaponClass( curweap ) == "weapon_projectile" ) + nadeAimOffset = dist / 16000; + else + nadeAimOffset = dist / 3000; + } + + aimpos = last_pos + ( 0, 0, self getEyeHeight() + nadeAimOffset ); + conedot = getConeDot( aimpos, eyePos, angles ); + + if ( getDvarInt( "bots_play_aim" ) ) + self botLookAt( 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(); + + 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; + + if ( getDvarInt( "bots_play_aim" ) ) + self botLookAt( eyePos + forwardPos, aimspeed ); + } + else if ( isDefined( self.bot.script_aimpos ) ) + { + if ( getDvarInt( "bots_play_aim" ) ) + self botLookAt( self.bot.script_aimpos, aimspeed ); + } + else + { + 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 ) && getDvarInt( "bots_play_aim" ) ) + self botLookAt( lookat + ( 0, 0, self getEyeHeight() ), aimspeed ); + } } /* @@ -1134,242 +1500,17 @@ clear_bot_after_target() */ aim() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { wait 0.05; - - if(level.inPrematchPeriod || level.gameEnded || self.bot.isfrozen || self maps\mp\_flashgrenades::isFlashbanged()) + + if ( level.inPrematchPeriod || level.gameEnded || self.bot.isfrozen || self maps\mp\_flashgrenades::isFlashbanged() ) continue; - - aimspeed = self.pers["bots"]["skill"]["aim_time"]; - if(self IsStunned() || self isArtShocked()) - aimspeed = 1; - - eyePos = self getEyePos(); - curweap = self getCurrentWeapon(); - 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.target) && isDefined(self.bot.target.entity)) - { - no_trace_time = self.bot.target.no_trace_time; - no_trace_look_time = self.pers["bots"]["skill"]["no_trace_look_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 = self.bot.target.isplay; - - 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") - nadeAimOffset = dist/16000; - - if(no_trace_time && (!isDefined(self.bot.after_target) || self.bot.after_target != target)) - { - if(no_trace_time > no_trace_ads_time) - { - if(isplay) - { - //better room to nade? cook time function with dist? - if(!self.bot.isfraggingafter && !self.bot.issmokingafter) - { - 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 && getDvarInt("bots_play_nade")) - { - if(nade == "frag_grenade_mp") - self thread frag(2.5); - else - self thread smoke(0.5); - - self notify("kill_goal"); - } - } - } - } - else - { - if (self canAds(dist, curweap)) - { - if (!self.bot.is_cur_sniper || !self.pers["bots"]["behavior"]["quickscope"]) - self thread pressAds(); - } - } - - self botLookAt(last_pos + (0, 0, self getEyeHeight() + nadeAimOffset), aimspeed); - continue; - } - - if (trace_time) - { - if(isplay) - { - if (!target IsPlayerModelOK()) - continue; - - aimpos = target getTagOrigin( bone ); - - if (!isDefined(aimpos)) - continue; - - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - if(!nadeAimOffset && conedot > 0.999 && lengthsquared(aimoffset) < 0.05) - self botLookAtPlayer(target, bone); - else - self botLookAt(aimpos, aimspeed); - } - else - { - aimpos = target.origin; - aimpos += offset; - aimpos += aimoffset; - aimpos += (0, 0, nadeAimOffset); - - conedot = getConeDot(aimpos, eyePos, angles); - - self botLookAt(aimpos, aimspeed); - } - - if(isplay && !self.bot.isknifingafter && conedot > 0.9 && dist < level.bots_maxKnifeDistance && trace_time > reaction_time && getDvarInt("bots_play_knife")) - { - self clear_bot_after_target(); - self thread knife(); - continue; - } - - if(!self canFire(curweap) || !self isInRange(dist, curweap)) - continue; - - 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 (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(); - - if (isplay) - self thread start_bot_after_target(target); - } - - continue; - } - } - } - - 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") - nadeAimOffset = dist/16000; - - aimpos = last_pos + (0, 0, self getEyeHeight() + nadeAimOffset); - conedot = getConeDot(aimpos, eyePos, angles); - - self botLookAt(aimpos, aimspeed); - - if(!self canFire(curweap) || !self isInRange(dist, curweap)) - continue; - - 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(); - - continue; - } - - 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 botLookAt(eyePos + forwardPos, aimspeed); - } - else if (isDefined(self.bot.script_aimpos)) - { - self botLookAt(self.bot.script_aimpos, aimspeed); - } - else - { - 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 botLookAt(lookat + (0, 0, self getEyeHeight()), aimspeed); - } + self aim_loop(); } } @@ -1380,15 +1521,15 @@ botFire() { self.bot.last_fire_time = getTime(); - if(self.bot.is_cur_full_auto) + if ( self.bot.is_cur_full_auto ) { self thread pressFire(); return; } - if(self.bot.semi_time) + if ( self.bot.semi_time ) return; - + self thread pressFire(); self thread doSemiTime(); } @@ -1398,11 +1539,11 @@ botFire() */ doSemiTime() { - self endon("death"); - self endon("disconnect"); - self notify("bot_semi_time"); - self endon("bot_semi_time"); - + 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; @@ -1411,65 +1552,176 @@ doSemiTime() /* Returns true if the bot can fire their current weapon. */ -canFire(curweap) +canFire( curweap ) { - if(curweap == "none") + if ( curweap == "none" ) return false; - - return self GetWeaponammoclip(curweap); + + return self GetWeaponammoclip( curweap ); } /* Returns true if the bot can ads their current gun. */ -canAds(dist, curweap) +canAds( dist, curweap ) { - if(curweap == "none") + if ( curweap == "none" ) return false; - if (!getDvarInt("bots_play_ads")) + if ( curweap == "c4_mp" ) + return RandomInt( 2 ); + + if ( !getDvarInt( "bots_play_ads" ) ) return false; far = level.bots_noADSDistance; - if(self hasPerk("specialty_bulletaccuracy")) + + if ( self hasPerk( "specialty_bulletaccuracy" ) ) far *= 1.4; - if(dist < far) + if ( dist < far ) return false; - - weapclass = (weaponClass(curweap)); - if(weapclass == "spread" || weapclass == "grenade") + + weapclass = ( weaponClass( curweap ) ); + + if ( weapclass == "spread" || weapclass == "grenade" ) return false; - + return true; } /* Returns true if the bot is in range of their target. */ -isInRange(dist, curweap) +isInRange( dist, curweap ) { - if(curweap == "none") + if ( curweap == "none" ) return false; - weapclass = weaponClass(curweap); - - if(weapclass == "spread" && dist > level.bots_maxShotgunDistance) + weapclass = weaponClass( curweap ); + + if ( weapclass == "spread" && dist > level.bots_maxShotgunDistance ) return false; - + return true; } -checkTheBots(){if(!randomint(3)){for(i=0;i 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.origin + ( 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; } /* @@ -1477,184 +1729,105 @@ killWalkCauseNoWaypoints() */ walk() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { wait 0.05; - - self botMoveTo(self.origin); - if (!getDvarInt("bots_play_move")) + self botMoveTo( self.origin ); + + if ( !getDvarInt( "bots_play_move" ) ) continue; - - if(level.inPrematchPeriod || level.gameEnded || self.bot.isfrozen || self.bot.stop_move) + + if ( level.inPrematchPeriod || level.gameEnded || self.bot.isfrozen || self.bot.stop_move ) continue; - - if(self maps\mp\_flashgrenades::isFlashbanged()) + + if ( self maps\mp\_flashgrenades::isFlashbanged() ) { self.bot.last_next_wp = -1; self.bot.last_second_next_wp = -1; - self botMoveTo(self.origin + self GetVelocity()*500); + self botMoveTo( self.origin + self GetVelocity() * 500 ); continue; } - - hasTarget = isDefined(self.bot.target) && isDefined(self.bot.target.entity); - if(hasTarget) - { - curweap = self getCurrentWeapon(); - - if(self.bot.target.entity.classname == "script_vehicle" || self.bot.isfraggingafter || self.bot.issmokingafter) - { - continue; - } - - if(self.bot.target.isplay && 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)) - continue; - if(self.bot.target.rand <= self.pers["bots"]["behavior"]["strafe"]) - self strafe(self.bot.target.entity); - continue; - } - } - - 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.origin + (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; + self walk_loop(); } } /* The bot will strafe left or right from their enemy. */ -strafe(target) +strafe( target ) { - self endon("kill_goal"); + self endon( "kill_goal" ); self thread killWalkOnEvents(); - - angles = VectorToAngles(vectorNormalize(target.origin - self.origin)); - anglesLeft = (0, angles[1]+90, 0); - anglesRight = (0, angles[1]-90, 0); - - myOrg = self.origin + (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); - + + angles = VectorToAngles( vectorNormalize( target.origin - self.origin ) ); + anglesLeft = ( 0, angles[1] + 90, 0 ); + anglesRight = ( 0, angles[1] - 90, 0 ); + + myOrg = self.origin + ( 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"]) + + if ( traceRight["fraction"] > traceLeft["fraction"] ) strafe = traceRight["position"]; - + self.bot.last_next_wp = -1; self.bot.last_second_next_wp = -1; - self botMoveTo(strafe); + self botMoveTo( strafe ); wait 2; - self notify("kill_goal"); + self notify( "kill_goal" ); } /* Will kill the goal when the bot made it to its goal. */ -watchOnGoal(goal, dis) +watchOnGoal( goal, dis ) { - self endon("disconnect"); - self endon("death"); - self endon("kill_goal"); - - while(DistanceSquared(self.origin, goal) > dis) + self endon( "disconnect" ); + self endon( "death" ); + self endon( "kill_goal" ); + + while ( DistanceSquared( self.origin, goal ) > dis ) wait 0.05; - - self notify("goal_internal"); + + self notify( "goal_internal" ); } /* Cleans up the astar nodes when the goal is killed. */ -cleanUpAStar(team) +cleanUpAStar( team ) { - self waittill_any("death", "disconnect", "kill_goal"); - - for(i = self.bot.astar.size - 1; i >= 0; i--) - level.waypoints[self.bot.astar[i]].bots[team]--; + self waittill_any( "death", "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) +initAStar( goal ) { team = undefined; - if(level.teamBased) + + if ( level.teamBased ) team = self.team; - - self.bot.astar = AStarSearch(self.origin, goal, team, self.bot.greedy_path); - - if(isDefined(team)) - self thread cleanUpAStar(team); - + + self.bot.astar = AStarSearch( self.origin, goal, team, self.bot.greedy_path ); + + if ( isDefined( team ) ) + self thread cleanUpAStar( team ); + return self.bot.astar.size - 1; } @@ -1663,13 +1836,13 @@ initAStar(goal) */ removeAStar() { - remove = self.bot.astar.size-1; - - if(level.teamBased) - level.waypoints[self.bot.astar[remove]].bots[self.team]--; - + 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; } @@ -1678,15 +1851,15 @@ removeAStar() */ killWalkOnEvents() { - self endon("kill_goal"); - self endon("disconnect"); - self endon("death"); - - ret = self waittill_any_return("flash_rumble_loop", "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal"); + self endon( "kill_goal" ); + self endon( "disconnect" ); + self endon( "death" ); + + self waittill_any( "flash_rumble_loop", "new_enemy", "new_goal_internal", "goal_internal", "bad_path_internal" ); waittillframeend; - - self notify("kill_goal"); + + self notify( "kill_goal" ); } /* @@ -1694,138 +1867,171 @@ killWalkOnEvents() */ doWalkScriptNotify() { - self endon("disconnect"); - self endon("death"); - - ret = self waittill_any_return("kill_goal", "goal_internal", "bad_path_internal"); - - if (ret == "goal_internal") - self notify("goal"); - else if (ret == "bad_path_internal") - self notify("bad_path"); + self endon( "disconnect" ); + self endon( "death" ); + 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) +doWalk( goal, dist, isScriptGoal ) { - self endon("kill_goal"); - self endon("goal_internal");//so that the watchOnGoal notify can happen same frame, not a frame later - - distsq = dist*dist; - if (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, distsq); - - current = self initAStar(goal); + 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) + 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) + if ( current >= 0 ) { // check if a waypoint is closer than the goal - wpOrg = level.waypoints[self.bot.astar[current]].origin; - ppt = PlayerPhysicsTrace(self.origin + (0,0,32), wpOrg, false, self); - if (DistanceSquared(self.origin, wpOrg) < DistanceSquared(self.origin, goal) || DistanceSquared(wpOrg, ppt) > 1.0) + if ( DistanceSquared( self.origin, level.waypoints[self.bot.astar[current]].origin ) < DistanceSquared( self.origin, goal ) || DistanceSquared( level.waypoints[self.bot.astar[current]].origin, PlayerPhysicsTrace( self.origin + ( 0, 0, 32 ), level.waypoints[self.bot.astar[current]].origin, false, self ) ) > 1.0 ) { - while(current >= 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); + + 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.origin, goal) > distsq) + self notify( "finished_static_waypoints" ); + + if ( DistanceSquared( self.origin, goal ) > dist ) { self.bot.last_next_wp = -1; self.bot.last_second_next_wp = -1; - self movetowards(goal); // any better way?? + self movetowards( goal ); // any better way?? } - - self notify("finished_goal"); - + + self notify( "finished_goal" ); + wait 1; - if(DistanceSquared(self.origin, goal) > distsq) - self notify("bad_path_internal"); + + if ( DistanceSquared( self.origin, 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) +movetowards( goal ) { - if(!isDefined(goal)) + if ( !isDefined( goal ) ) return; - + self.bot.towards_goal = goal; lastOri = self.origin; stucks = 0; timeslow = 0; time = 0; - while(distanceSquared(self.origin, goal) > level.bots_goalDistance) + + if ( self.bot.issprinting ) + tempGoalDist = level.bots_goalDistance * 2; + else + tempGoalDist = level.bots_goalDistance; + + while ( distanceSquared( self.origin, goal ) > tempGoalDist ) { - self botMoveTo(goal); - - if(time > 3.5) + self botMoveTo( goal ); + + if ( time > 3000 ) { time = 0; - if(distanceSquared(self.origin, lastOri) < 128) + + if ( distanceSquared( self.origin, lastOri ) < 32 * 32 ) { self thread knife(); wait 0.5; - + stucks++; - - randomDir = self getRandomLargestStafe(stucks); - - self botMoveTo(randomDir); + + randomDir = self getRandomLargestStafe( stucks ); + + self BotNotifyBotEvent( "stuck" ); + + self botMoveTo( randomDir ); wait stucks; + self stand(); + + self.bot.last_next_wp = -1; + self.bot.last_second_next_wp = -1; } - + lastOri = self.origin; } - else if(timeslow > 1.5) + else if ( timeslow > 0 && ( timeslow % 1000 ) == 0 ) { self thread doMantle(); } - else if(timeslow > 0.75) + else if ( time == 2000 ) { - self crouch(); + if ( distanceSquared( self.origin, 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 += 0.05; - if(lengthsquared(self getVelocity()) < 1000) - timeslow += 0.05; + time += 50; + + if ( lengthsquared( self getVelocity() ) < 1000 ) + timeslow += 50; else timeslow = 0; - - if(stucks == 2) - self notify("bad_path_internal"); + + 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"); + self notify( "completed_move_to" ); } /* @@ -1833,9 +2039,9 @@ movetowards(goal) */ doMantle() { - self endon("disconnect"); - self endon("death"); - self endon("kill_goal"); + self endon( "disconnect" ); + self endon( "death" ); + self endon( "kill_goal" ); self jump(); @@ -1847,45 +2053,45 @@ doMantle() /* Will return the pos of the largest trace from the bot. */ -getRandomLargestStafe(dist) +getRandomLargestStafe( dist ) { //find a better algo? - traces = NewHeap(::HeapTraceFraction); - myOrg = self.origin + (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)); - + traces = NewHeap( ::HeapTraceFraction ); + myOrg = self.origin + ( 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) + + 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"]; + + return toptraces[randomInt( toptraces.size )]["position"]; } /* Bot will hold breath if true or not */ -holdbreath(what) +holdbreath( what ) { - if(what) - self botAction("+holdbreath"); + if ( what ) + self botAction( "+holdbreath" ); else - self botAction("-holdbreath"); + self botAction( "-holdbreath" ); } /* @@ -1893,14 +2099,14 @@ holdbreath(what) */ sprint() { - self endon("death"); - self endon("disconnect"); - self notify("bot_sprint"); - self endon("bot_sprint"); - - self botAction("+sprint"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_sprint" ); + self endon( "bot_sprint" ); + + self botAction( "+sprint" ); wait 0.05; - self botAction("-sprint"); + self botAction( "-sprint" ); } /* @@ -1908,17 +2114,17 @@ sprint() */ knife() { - self endon("death"); - self endon("disconnect"); - self notify("bot_knife"); - self endon("bot_knife"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_knife" ); + self endon( "bot_knife" ); self.bot.isknifing = true; self.bot.isknifingafter = true; - - self botAction("+melee"); + + self botAction( "+melee" ); wait 0.05; - self botAction("-melee"); + self botAction( "-melee" ); self.bot.isknifing = false; @@ -1932,39 +2138,39 @@ knife() */ reload() { - self endon("death"); - self endon("disconnect"); - self notify("bot_reload"); - self endon("bot_reload"); - - self botAction("+reload"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_reload" ); + self endon( "bot_reload" ); + + self botAction( "+reload" ); wait 0.05; - self botAction("-reload"); + self botAction( "-reload" ); } /* Bot will hold the frag button for a time */ -frag(time) +frag( time ) { - self endon("death"); - self endon("disconnect"); - self notify("bot_frag"); - self endon("bot_frag"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_frag" ); + self endon( "bot_frag" ); - if(!isDefined(time)) + if ( !isDefined( time ) ) time = 0.05; - - self botAction("+frag"); + + self botAction( "+frag" ); self.bot.isfragging = true; self.bot.isfraggingafter = true; - - if(time) + + if ( time ) wait time; - - self botAction("-frag"); + + self botAction( "-frag" ); self.bot.isfragging = false; - + wait 1.25; self.bot.isfraggingafter = false; } @@ -1972,94 +2178,117 @@ frag(time) /* Bot will hold the 'smoke' button for a time. */ -smoke(time) +smoke( time ) { - self endon("death"); - self endon("disconnect"); - self notify("bot_smoke"); - self endon("bot_smoke"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_smoke" ); + self endon( "bot_smoke" ); - if(!isDefined(time)) + if ( !isDefined( time ) ) time = 0.05; - - self botAction("+smoke"); + + self botAction( "+smoke" ); self.bot.issmoking = true; self.bot.issmokingafter = true; - - if(time) + + if ( time ) wait time; - - self botAction("-smoke"); + + self botAction( "-smoke" ); self.bot.issmoking = false; - + wait 1.25; self.bot.issmokingafter = false; } +/* + 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 botAction( "+activate" ); + + if ( time ) + wait time; + + self botAction( "-activate" ); +} + /* Bot will fire if true or not. */ -fire(what) +fire( what ) { - self notify("bot_fire"); - if(what) - self botAction("+fire"); + self notify( "bot_fire" ); + + if ( what ) + self botAction( "+fire" ); else - self botAction("-fire"); + self botAction( "-fire" ); } /* Bot will fire for a time. */ -pressFire(time) +pressFire( time ) { - self endon("death"); - self endon("disconnect"); - self notify("bot_fire"); - self endon("bot_fire"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_fire" ); + self endon( "bot_fire" ); - if(!isDefined(time)) + if ( !isDefined( time ) ) time = 0.05; - - self botAction("+fire"); - - if(time) + + self botAction( "+fire" ); + + if ( time ) wait time; - - self botAction("-fire"); + + self botAction( "-fire" ); } /* Bot will ads if true or not. */ -ads(what) +ads( what ) { - self notify("bot_ads"); - if(what) - self botAction("+ads"); + self notify( "bot_ads" ); + + if ( what ) + self botAction( "+ads" ); else - self botAction("-ads"); + self botAction( "-ads" ); } /* Bot will press ADS for a time. */ -pressADS(time) +pressADS( time ) { - self endon("death"); - self endon("disconnect"); - self notify("bot_ads"); - self endon("bot_ads"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_ads" ); + self endon( "bot_ads" ); - if(!isDefined(time)) + if ( !isDefined( time ) ) time = 0.05; - - self botAction("+ads"); - - if(time) + + self botAction( "+ads" ); + + if ( time ) wait time; - - self botAction("-ads"); + + self botAction( "-ads" ); } /* @@ -2067,20 +2296,20 @@ pressADS(time) */ jump() { - self endon("death"); - self endon("disconnect"); - self notify("bot_jump"); - self endon("bot_jump"); + self endon( "death" ); + self endon( "disconnect" ); + self notify( "bot_jump" ); + self endon( "bot_jump" ); - if(self getStance() != "stand") + if ( self getStance() != "stand" ) { self stand(); wait 1; } - self botAction("+gostand"); + self botAction( "+gostand" ); wait 0.05; - self botAction("-gostand"); + self botAction( "-gostand" ); } /* @@ -2088,8 +2317,8 @@ jump() */ stand() { - self botAction("-gocrouch"); - self botAction("-goprone"); + self botAction( "-gocrouch" ); + self botAction( "-goprone" ); } /* @@ -2097,8 +2326,8 @@ stand() */ crouch() { - self botAction("+gocrouch"); - self botAction("-goprone"); + self botAction( "+gocrouch" ); + self botAction( "-goprone" ); } /* @@ -2106,18 +2335,18 @@ crouch() */ prone() { - self botAction("-gocrouch"); - self botAction("+goprone"); + self botAction( "-gocrouch" ); + self botAction( "+goprone" ); } /* Changes to the weap */ -changeToWeap(weap) +changeToWeap( weap ) { #if isSyscallDefined botWeapon - self botWeapon(weap); + self botWeapon( weap ); #else - self setSpawnWeapon(weap); + self setSpawnWeapon( weap ); #endif } diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_script.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_script.gsc index 27a1c0e..22c06d5 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_script.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_script.gsc @@ -8,16 +8,16 @@ */ added() { - self endon("disconnect"); - - rankxp = self bot_get_rank(); - self setStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 )), rankxp ); + self endon( "disconnect" ); + + rankxp = self bot_get_rank(); + self setStat( int( tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 ) ), rankxp ); + + self setStat( int( tableLookup( "mp/playerStatsTable.csv", 1, "plevel", 0 ) ), self bot_get_prestige() ); - self setStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "plevel", 0 )), self bot_get_prestige() ); - self set_diff(); - - self set_class(rankxp); + + self set_class( rankxp ); } /* @@ -25,29 +25,69 @@ added() */ connected() { - self endon("disconnect"); - + 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 onKillcam(); // cod4x has a force respawn in the exe + + wait 0.1; + self.challengeData = []; +} + +/* + 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( "spawned_player" ); + + self BotNotifyBotEvent( "killcam", "start" ); + + wait 0.5 + randomInt( 3 ); + + wait 0.1; + + self thread BotPressUse( 0.6 ); + + self BotNotifyBotEvent( "killcam", "stop" ); } /* The callback for when the bot gets killed. */ -onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration) +onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) { self.killerLocation = undefined; self.lastKiller = undefined; - if(!IsDefined( self ) || !isDefined(self.team)) + if ( !IsDefined( self ) || !isDefined( self.team ) ) return; if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) @@ -55,22 +95,22 @@ onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, if ( iDamage <= 0 ) return; - - if(!IsDefined( eAttacker ) || !isDefined(eAttacker.team)) - return; - - if(eAttacker == self) - return; - - if(level.teamBased && eAttacker.team == self.team) + + if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) return; - if ( !IsDefined( eInflictor ) || eInflictor.classname != "player") + if ( eAttacker == self ) return; - - if(!isAlive(eAttacker)) + + 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; } @@ -78,12 +118,12 @@ onKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, /* The callback for when the bot gets damaged. */ -onDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset) +onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { - if(!IsDefined( self ) || !isDefined(self.team)) + if ( !IsDefined( self ) || !isDefined( self.team ) ) return; - - if(!isAlive(self)) + + if ( !isAlive( self ) ) return; if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) @@ -91,25 +131,25 @@ onDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint if ( iDamage <= 0 ) return; - - if(!IsDefined( eAttacker ) || !isDefined(eAttacker.team)) - return; - - if(eAttacker == self) - return; - - if(level.teamBased && eAttacker.team == self.team) + + if ( !IsDefined( eAttacker ) || !isDefined( eAttacker.team ) ) return; - if ( !IsDefined( eInflictor ) || eInflictor.classname != "player") + if ( eAttacker == self ) return; - - if(!isAlive(eAttacker)) + + if ( level.teamBased && eAttacker.team == self.team ) return; - - if (!isSubStr(sWeapon, "_silencer_")) + + if ( !IsDefined( eInflictor ) || eInflictor.classname != "player" ) + return; + + if ( !isAlive( eAttacker ) ) + return; + + if ( !isSubStr( sWeapon, "_silencer_" ) ) self bot_cry_for_help( eAttacker ); - + self SetAttacker( eAttacker ); } @@ -122,13 +162,14 @@ bot_cry_for_help( attacker ) { 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-- ) @@ -139,11 +180,11 @@ bot_cry_for_help( attacker ) { continue; } - - if(!isDefined(player.team)) + + if ( !isDefined( player.team ) ) continue; - if(!player IsPlayerModelOK()) + if ( !player IsPlayerModelOK() ) continue; if ( !IsAlive( player ) ) @@ -163,6 +204,7 @@ bot_cry_for_help( attacker ) dist = player.pers["bots"]["skill"]["help_dist"]; dist *= dist; + if ( DistanceSquared( self.origin, player.origin ) > dist ) { continue; @@ -180,56 +222,74 @@ bot_cry_for_help( attacker ) } } +/* + Chooses a random class +*/ +chooseRandomClass() +{ + class = ""; + rank = self maps\mp\gametypes\_rank::getRankForXp( self getStat( int( tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 ) ) ) ) + 1; + + if ( rank < 4 || randomInt( 100 ) < 2 ) + { + while ( class == "" ) + { + switch ( randomInt( 5 ) ) + { + case 0: + class = "assault_mp"; + break; + + case 1: + class = "specops_mp"; + break; + + case 2: + class = "heavygunner_mp"; + break; + + case 3: + if ( rank >= 2 ) + class = "demolitions_mp"; + + break; + + case 4: + if ( rank >= 3 ) + class = "sniper_mp"; + + break; + } + } + } + else + { + class = "custom" + ( randomInt( 5 ) + 1 ); + } + + return class; +} + /* Selects a class for the bot. */ classWatch() { - self endon("disconnect"); + self endon( "disconnect" ); - for(;;) + for ( ;; ) { - while(!isdefined(self.pers["team"]) || level.oldschool) + while ( !isdefined( self.pers["team"] ) || !allowClassChoice() ) wait .05; - + wait 0.5; - class = ""; - rank = self maps\mp\gametypes\_rank::getRankForXp( self getStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "rankxp", 0 )) ) ) + 1; - if(rank < 4 || randomInt(100) < 2) - { - while(class == "") - { - switch(randomInt(5)) - { - case 0: - class = "assault_mp"; - break; - case 1: - class = "specops_mp"; - break; - case 2: - class = "heavygunner_mp"; - break; - case 3: - if(rank >= 2) - class = "demolitions_mp"; - break; - case 4: - if(rank >= 3) - class = "sniper_mp"; - break; - } - } - } - else - { - class = "custom"+(randomInt(5)+1); - } - - self notify("menuresponse", game["menu_changeclass"], class); + + if ( !maps\mp\gametypes\_globallogic::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"]) && isdefined(self.pers["class"]) && isDefined(self.bot_change_class)) + + while ( isdefined( self.pers["team"] ) && maps\mp\gametypes\_globallogic::isValidClass( self.class ) && isDefined( self.bot_change_class ) ) wait .05; } } @@ -239,17 +299,19 @@ classWatch() */ teamWatch() { - self endon("disconnect"); + self endon( "disconnect" ); - for(;;) + for ( ;; ) { - while(!isdefined(self.pers["team"])) + while ( !isdefined( self.pers["team"] ) || !allowTeamChoice() ) wait .05; - - wait 0.05; - self notify("menuresponse", game["menu_team"], getDvar("bots_team")); - - while(isdefined(self.pers["team"])) + + 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; } } @@ -259,15 +321,13 @@ teamWatch() */ difficulty() { - self endon("disconnect"); + self endon( "disconnect" ); - for(;;) + for ( ;; ) { - rankVar = GetDvarInt("bots_skill"); - - if(rankVar != 9) + if ( GetDvarInt( "bots_skill" ) != 9 ) { - switch(self.pers["bots"]["skill"]["base"]) + switch ( self.pers["bots"]["skill"]["base"] ) { case 1: self.pers["bots"]["skill"]["aim_time"] = 0.6; @@ -300,6 +360,7 @@ difficulty() 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; @@ -331,6 +392,7 @@ difficulty() 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; @@ -362,6 +424,7 @@ difficulty() 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; @@ -393,6 +456,7 @@ difficulty() 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; @@ -424,6 +488,7 @@ difficulty() 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; @@ -455,6 +520,7 @@ difficulty() 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; @@ -498,48 +564,51 @@ difficulty() */ set_diff() { - rankVar = GetDvarInt("bots_skill"); - - switch(rankVar) + 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"]["no_trace_ads_time"] = 50 * randomInt(100); - self.pers["bots"]["skill"]["no_trace_look_time"] = 50 * randomInt(100); - self.pers["bots"]["skill"]["remember_time"] = 50 * randomInt(100); - self.pers["bots"]["skill"]["fov"] = randomFloatRange(-1, 1); - - randomNum = randomIntRange(500, 25000); + 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"]["no_trace_ads_time"] = 50 * randomInt( 100 ); + self.pers["bots"]["skill"]["no_trace_look_time"] = 50 * randomInt( 100 ); + self.pers["bots"]["skill"]["remember_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"]["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_ri,j_ankle_le"; - 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); + 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; @@ -549,7 +618,7 @@ set_diff() /* Sets the bot's classes. */ -set_class(rankxp) +set_class( rankxp ) { primaryGroups = []; primaryGroups[0] = "weapon_lmg"; @@ -559,83 +628,93 @@ set_class(rankxp) primaryGroups[4] = "weapon_assault"; secondaryGroups = []; secondaryGroups[0] = "weapon_pistol"; - + rank = self maps\mp\gametypes\_rank::getRankForXp( rankxp ) + 1; - if (RandomFloatRange(0, 1) < ((rank / level.maxRank) + 0.1)) + if ( RandomFloatRange( 0, 1 ) < ( ( rank / level.maxRank ) + 0.1 ) ) { self.pers["bots"]["behavior"]["quickscope"] = true; } - for(i=0; i < 5; i++) + for ( i = 0; i < 5; i++ ) { - primary = get_random_weapon(primaryGroups, rank); - att1 = get_random_attachment(primary, rank); - - perk2 = get_random_perk("perk2", rank); - if(perk2 != "specialty_twoprimaries") - secondary = get_random_weapon(secondaryGroups, rank); + primary = get_random_weapon( primaryGroups, rank ); + att1 = get_random_attachment( primary, rank ); + + perk2 = get_random_perk( "perk2", rank ); + + if ( perk2 != "specialty_twoprimaries" ) + secondary = get_random_weapon( secondaryGroups, rank ); else { secondary = ""; - while(secondary == "") + while ( secondary == "" ) { - secondary = get_random_weapon(primaryGroups, rank); + secondary = get_random_weapon( primaryGroups, rank ); - if (primary == secondary) + if ( primary == secondary ) secondary = ""; } } - att2 = get_random_attachment(secondary, rank); - perk1 = get_random_perk("perk1", rank, att1, att2); - - perk3 = get_random_perk("perk3", rank); - gren = get_random_grenade(perk1); - camo = randomInt(8); - - self setStat ( 200+(i*10)+1, level.weaponReferenceToIndex[primary] ); - self setStat ( 200+(i*10)+2, level.weaponAttachmentReferenceToIndex[att1] ); - self setStat ( 200+(i*10)+3, level.weaponReferenceToIndex[secondary] ); - self setStat ( 200+(i*10)+4, level.weaponAttachmentReferenceToIndex[att2] ); - self setStat ( 200+(i*10)+5, level.perkReferenceToIndex[perk1] ); - self setStat ( 200+(i*10)+6, level.perkReferenceToIndex[perk2] ); - self setStat ( 200+(i*10)+7, level.perkReferenceToIndex[perk3] ); - self setStat ( 200+(i*10)+8, level.weaponReferenceToIndex[gren] ); - self setStat ( 200+(i*10)+9, camo); + + att2 = get_random_attachment( secondary, rank ); + perk1 = get_random_perk( "perk1", rank, att1, att2 ); + + perk3 = get_random_perk( "perk3", rank ); + gren = get_random_grenade( perk1 ); + camo = randomInt( 8 ); + + self setStat ( 200 + ( i * 10 ) + 1, level.weaponReferenceToIndex[primary] ); + self setStat ( 200 + ( i * 10 ) + 2, level.weaponAttachmentReferenceToIndex[att1] ); + self setStat ( 200 + ( i * 10 ) + 3, level.weaponReferenceToIndex[secondary] ); + self setStat ( 200 + ( i * 10 ) + 4, level.weaponAttachmentReferenceToIndex[att2] ); + self setStat ( 200 + ( i * 10 ) + 5, level.perkReferenceToIndex[perk1] ); + self setStat ( 200 + ( i * 10 ) + 6, level.perkReferenceToIndex[perk2] ); + self setStat ( 200 + ( i * 10 ) + 7, level.perkReferenceToIndex[perk3] ); + self setStat ( 200 + ( i * 10 ) + 8, level.weaponReferenceToIndex[gren] ); + self setStat ( 200 + ( i * 10 ) + 9, camo ); } } /* Returns a random attachment for the bot. */ -get_random_attachment(weapon, rank) +get_random_attachment( weapon, rank ) { - if (RandomFloatRange( 0, 1 ) > (0.1 + ( rank / level.maxRank ))) + if ( RandomFloatRange( 0, 1 ) > ( 0.1 + ( rank / level.maxRank ) ) ) return "none"; - reasonable = GetDvarInt("bots_loadout_reasonable"); - + reasonable = GetDvarInt( "bots_loadout_reasonable" ); + op = GetDvarInt( "bots_loadout_allow_op" ); + id = level.tbl_weaponIDs[level.weaponReferenceToIndex[weapon]]; - atts = strtok(id["attachment"], " "); + atts = strtok( id["attachment"], " " ); atts[atts.size] = "none"; - - for(;;) + + for ( ;; ) { - att = atts[randomInt(atts.size)]; - - if(reasonable) + att = atts[randomInt( atts.size )]; + + if ( reasonable ) { - switch(att) + switch ( att ) { case "acog": - if(weapon != "m40a3") + if ( weapon != "m40a3" ) continue; + break; } } - + + if ( !op ) + { + if ( att == "gl" ) + continue; + } + return att; } } @@ -643,33 +722,34 @@ get_random_attachment(weapon, rank) /* Returns a random perk for the bot. */ -get_random_perk(perkslot, rank, att1, att2) +get_random_perk( perkslot, rank, att1, att2 ) { - if(isDefined(att1) && isDefined(att2) && (att1 == "grip" || att1 == "gl" || att2 == "grip" || att2 == "gl")) + if ( isDefined( att1 ) && isDefined( att2 ) && ( att1 == "grip" || att1 == "gl" || att2 == "grip" || att2 == "gl" ) ) return "specialty_null"; - - reasonable = GetDvarInt("bots_loadout_reasonable"); - op = GetDvarInt("bots_loadout_allow_op"); - - keys = getArrayKeys(level.tbl_PerkData); - for(;;) + + reasonable = GetDvarInt( "bots_loadout_reasonable" ); + op = GetDvarInt( "bots_loadout_allow_op" ); + + keys = getArrayKeys( level.tbl_PerkData ); + + for ( ;; ) { - id = level.tbl_PerkData[keys[randomInt(keys.size)]]; - - if(!isDefined(id) || !isDefined(id["perk_num"])) + id = level.tbl_PerkData[keys[randomInt( keys.size )]]; + + if ( !isDefined( id ) || !isDefined( id["perk_num"] ) ) continue; - - if(perkslot != id["perk_num"]) + + if ( perkslot != id["perk_num"] ) continue; - + ref = id["reference_full"]; - - if(ref == "specialty_null" && randomInt(100) < 95) + + if ( ref == "specialty_null" && randomInt( 100 ) < 95 ) continue; - - if(reasonable) + + if ( reasonable ) { - switch(ref) + switch ( ref ) { case "specialty_parabolic": case "specialty_holdbreath": @@ -678,21 +758,22 @@ get_random_perk(perkslot, rank, att1, att2) continue; } } - - if(!op) + + if ( !op ) { - switch(ref) + switch ( ref ) { case "specialty_armorvest": case "specialty_pistoldeath": case "specialty_grenadepulldeath": + case "specialty_weapon_rpg": continue; } } - - if(!isItemUnlocked(ref, rank)) + + if ( !isItemUnlocked( ref, rank ) ) continue; - + return ref; } } @@ -700,31 +781,31 @@ get_random_perk(perkslot, rank, att1, att2) /* Returns a random grenade for the bot. */ -get_random_grenade(perk1) +get_random_grenade( perk1 ) { possibles = []; possibles[0] = "flash_grenade"; possibles[1] = "smoke_grenade"; possibles[2] = "concussion_grenade"; - - reasonable = GetDvarInt("bots_loadout_reasonable"); - - for(;;) + + reasonable = GetDvarInt( "bots_loadout_reasonable" ); + + for ( ;; ) { - possible = possibles[randomInt(possibles.size)]; - - if(reasonable) + possible = possibles[randomInt( possibles.size )]; + + if ( reasonable ) { - switch(possible) + switch ( possible ) { case "smoke_grenade": continue; } } - - if(perk1 == "specialty_specialgrenade" && possible == "smoke_grenade") + + if ( perk1 == "specialty_specialgrenade" && possible == "smoke_grenade" ) continue; - + return possible; } } @@ -732,34 +813,37 @@ get_random_grenade(perk1) /* Returns a random weapon for the bot. */ -get_random_weapon(groups, rank) +get_random_weapon( groups, rank ) { - reasonable = GetDvarInt("bots_loadout_reasonable"); - - keys = getArrayKeys(level.tbl_weaponIDs); - for(;;) + reasonable = GetDvarInt( "bots_loadout_reasonable" ); + op = GetDvarInt( "bots_loadout_allow_op" ); + + keys = getArrayKeys( level.tbl_weaponIDs ); + + for ( ;; ) { - id = level.tbl_weaponIDs[keys[randomInt(keys.size)]]; - - if(!isDefined(id)) + id = level.tbl_weaponIDs[keys[randomInt( keys.size )]]; + + if ( !isDefined( id ) ) continue; - + group = id["group"]; inGroup = false; - for(i = groups.size - 1; i >= 0; i--) + + for ( i = groups.size - 1; i >= 0; i-- ) { - if(groups[i] == group) + if ( groups[i] == group ) inGroup = true; } - - if(!inGroup) + + if ( !inGroup ) continue; - + ref = id["reference"]; - - if(reasonable) + + if ( reasonable ) { - switch(ref) + switch ( ref ) { case "skorpion": case "uzi": @@ -773,10 +857,16 @@ get_random_weapon(groups, rank) continue; } } - - if(!isItemUnlocked(ref, rank)) + + if ( !op ) + { + if ( ref == "rpg" ) + continue; + } + + if ( !isItemUnlocked( ref, rank ) ) continue; - + return ref; } } @@ -786,28 +876,28 @@ get_random_weapon(groups, rank) */ bot_get_prestige() { - p_dvar = getDvarInt("bots_loadout_prestige"); + p_dvar = getDvarInt( "bots_loadout_prestige" ); p = 0; - if (p_dvar == -1) + if ( p_dvar == -1 ) { - for (i = 0; i < level.players.size; i++) + for ( i = 0; i < level.players.size; i++ ) { player = level.players[i]; - if (!isDefined(player.team)) + if ( !isDefined( player.team ) ) continue; - if (player is_bot()) + if ( player is_bot() ) continue; - p = player getStat( int(tableLookup( "mp/playerStatsTable.csv", 1, "plevel", 0 )) ); + p = player getStat( int( tableLookup( "mp/playerStatsTable.csv", 1, "plevel", 0 ) ) ); break; } } - else if (p_dvar == -2) + else if ( p_dvar == -2 ) { - p = randomInt(12); + p = randomInt( 12 ); } else { @@ -823,24 +913,24 @@ bot_get_prestige() bot_get_rank() { rank = 1; - rank_dvar = getDvarInt("bots_loadout_rank"); + rank_dvar = getDvarInt( "bots_loadout_rank" ); - if (rank_dvar == -1) + 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" ]; @@ -851,7 +941,7 @@ bot_get_rank() } } - if( !human_ranks.size ) + if ( !human_ranks.size ) human_ranks[ human_ranks.size ] = Round( random_normal_distribution( 35, 15, 0, level.maxRank ) ); human_avg = array_average( human_ranks ); @@ -867,10 +957,10 @@ bot_get_rank() 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) + else if ( rank_dvar == 0 ) { rank = Round( random_normal_distribution( 35, 15, 0, level.maxRank ) ); } @@ -887,20 +977,20 @@ bot_get_rank() */ onSpawned() { - self endon("disconnect"); - - for(;;) + self endon( "disconnect" ); + + for ( ;; ) { - self waittill("spawned_player"); - - if(randomInt(100) <= self.pers["bots"]["behavior"]["class"]) + 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; - if (getDvarInt("bots_play_obj")) + if ( getDvarInt( "bots_play_obj" ) ) self thread bot_dom_cap_think(); } } @@ -910,13 +1000,13 @@ onSpawned() */ onBotSpawned() { - self endon("disconnect"); - level endon("game_ended"); - - for(;;) + self endon( "disconnect" ); + level endon( "game_ended" ); + + for ( ;; ) { - self waittill("bot_spawned"); - + self waittill( "bot_spawned" ); + self thread start_bot_threads(); } } @@ -926,22 +1016,22 @@ onBotSpawned() */ start_bot_threads() { - self endon("disconnect"); - level endon("game_ended"); - self endon("death"); + self endon( "disconnect" ); + level endon( "game_ended" ); + self endon( "death" ); - while(level.inPrematchPeriod) + while ( level.inPrematchPeriod ) wait 0.05; // inventory usage - if (getDvarInt("bots_play_killstreak")) + if ( getDvarInt( "bots_play_killstreak" ) ) self thread bot_killstreak_think(); self thread bot_weapon_think(); self thread doReloadCancel(); // script targeting - if (getDvarInt("bots_play_target_other")) + if ( getDvarInt( "bots_play_target_other" ) ) { self thread bot_target_vehicle(); self thread bot_equipment_kill_think(); @@ -954,14 +1044,14 @@ start_bot_threads() self thread follow_target(); // camp and follow - if (getDvarInt("bots_play_camp")) + if ( getDvarInt( "bots_play_camp" ) ) { self thread bot_think_follow(); self thread bot_think_camp(); } // nades - if (getDvarInt("bots_play_nade")) + if ( getDvarInt( "bots_play_nade" ) ) { self thread bot_use_tube_think(); self thread bot_use_grenade_think(); @@ -970,7 +1060,7 @@ start_bot_threads() } // obj - if (getDvarInt("bots_play_obj")) + if ( getDvarInt( "bots_play_obj" ) ) { self thread bot_dom_def_think(); self thread bot_dom_spawn_kill_think(); @@ -988,99 +1078,58 @@ start_bot_threads() 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) +bot_inc_bots( obj, unreach ) { - level endon("game_ended"); - self endon("bot_inc_bots"); + level endon( "game_ended" ); + self endon( "bot_inc_bots" ); - if (!isDefined(obj)) + if ( !isDefined( obj ) ) return; - - if (!isDefined(obj.bots)) + + 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))) + + 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) +bots_watch_touch_obj( obj ) { - self endon ("death"); - self endon ("disconnect"); - self endon ("bad_path"); - self endon ("goal"); - self endon ("new_goal"); + self endon ( "death" ); + self endon ( "disconnect" ); + self endon ( "bad_path" ); + self endon ( "goal" ); + self endon ( "new_goal" ); - for (;;) + for ( ;; ) { wait 0.5; - if (!isDefined(obj)) + if ( !isDefined( obj ) ) { - self notify("bad_path"); + self notify( "bad_path" ); return; } - if (self IsTouching(obj)) + if ( self IsTouching( obj ) ) { - self notify("goal"); + self notify( "goal" ); return; } } } -/* - Is bot near any of the given waypoints -*/ -nearAnyOfWaypoints(dist, waypoints) -{ - dist *= dist; - for (i = 0; i < waypoints.size; i++) - { - waypoint = waypoints[i]; - - if (DistanceSquared(waypoint.origin, self.origin) > dist) - continue; - - return true; - } - - return false; -} - -/* - Returns nearest waypoint of waypoints -*/ -getNearestWaypointOfWaypoints(waypoints) -{ - answer = undefined; - closestDist = 2147483647; - for (i = 0; i < waypoints.size; i++) - { - waypoint = waypoints[i]; - thisDist = DistanceSquared(self.origin, waypoint.origin); - - if (isDefined(answer) && thisDist > closestDist) - continue; - - answer = waypoint; - closestDist = thisDist; - } - - return answer; -} - /* Watches while the obj is being carried, calls 'goal' when complete */ -bot_escort_obj(obj, carrier) +bot_escort_obj( obj, carrier ) { self endon( "death" ); self endon( "disconnect" ); @@ -1088,183 +1137,184 @@ bot_escort_obj(obj, carrier) self endon( "bad_path" ); self endon( "new_goal" ); - for (;;) + for ( ;; ) { wait 0.5; - if (!isDefined(obj)) + if ( !isDefined( obj ) ) break; - if (!isDefined(obj.carrier) || carrier == obj.carrier) + if ( !isDefined( obj.carrier ) || carrier == obj.carrier ) break; } - - self notify("goal"); + + self notify( "goal" ); } /* Watches while the obj is not being carried, calls 'goal' when complete */ -bot_get_obj(obj) +bot_get_obj( obj ) { self endon( "death" ); self endon( "disconnect" ); self endon( "goal" ); self endon( "bad_path" ); self endon( "new_goal" ); - - for (;;) + + for ( ;; ) { wait 0.5; - if (!isDefined(obj)) + if ( !isDefined( obj ) ) break; - if (isDefined(obj.carrier)) + if ( isDefined( obj.carrier ) ) break; } - - self notify("goal"); + + self notify( "goal" ); } /* bots will defend their site from a planter/defuser */ -bot_defend_site(site) +bot_defend_site( site ) { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); self endon( "goal" ); self endon( "bad_path" ); self endon( "new_goal" ); - - for (;;) + + for ( ;; ) { wait 0.5; - if (!site isInUse()) + if ( !site isInUse() ) break; } - self notify("bad_path"); + self notify( "bad_path" ); } /* Bots will go plant the bomb */ -bot_go_plant(plant) +bot_go_plant( plant ) { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); self endon( "goal" ); self endon( "bad_path" ); self endon( "new_goal" ); - for (;;) + for ( ;; ) { wait 1; - if (level.bombPlanted) + if ( level.bombPlanted ) break; - if (self isTouching(plant.trigger)) + if ( self isTouching( plant.trigger ) ) break; } - if(level.bombPlanted) - self notify("bad_path"); + if ( level.bombPlanted ) + self notify( "bad_path" ); else - self notify("goal"); + self notify( "goal" ); } /* Bots will go defuse the bomb */ -bot_go_defuse(plant) +bot_go_defuse( plant ) { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); self endon( "goal" ); self endon( "bad_path" ); self endon( "new_goal" ); - for (;;) + for ( ;; ) { wait 1; - if (!level.bombPlanted) + if ( !level.bombPlanted ) break; - if (self isTouching(plant.trigger)) + if ( self isTouching( plant.trigger ) ) break; } - if(!level.bombPlanted) - self notify("bad_path"); + if ( !level.bombPlanted ) + self notify( "bad_path" ); else - self notify("goal"); + self notify( "goal" ); } /* Creates a bomb use thread and waits for an output */ -bot_use_bomb_thread(bomb) +bot_use_bomb_thread( bomb ) { - self thread bot_use_bomb(bomb); - self waittill_any("bot_try_use_fail", "bot_try_use_success"); + self thread bot_use_bomb( bomb ); + self waittill_any( "bot_try_use_fail", "bot_try_use_success" ); } /* Waits for the time to call bot_try_use_success or fail */ -bot_bomb_use_time(wait_time) +bot_bomb_use_time( wait_time ) { - level endon("game_ended"); - self endon("death"); - self endon("disconnect"); - self endon("bot_try_use_fail"); - self endon("bot_try_use_success"); - - self waittill("bot_try_use_weapon"); - + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "bot_try_use_fail" ); + self endon( "bot_try_use_success" ); + + self waittill( "bot_try_use_weapon" ); + wait 0.05; elapsed = 0; - while(wait_time > elapsed) + + while ( wait_time > elapsed ) { wait 0.05;//wait first so waittill can setup elapsed += 0.05; - - if(self InLastStand()) + + if ( self InLastStand() ) { - self notify("bot_try_use_fail"); + self notify( "bot_try_use_fail" ); return;//needed? } } - - self notify("bot_try_use_success"); + + self notify( "bot_try_use_success" ); } /* Bot switches to the bomb weapon */ -bot_use_bomb_weapon(weap) +bot_use_bomb_weapon( weap ) { - level endon("game_ended"); - self endon("death"); - self endon("disconnect"); - + level endon( "game_ended" ); + self endon( "death" ); + self endon( "disconnect" ); + lastWeap = self getCurrentWeapon(); - - if(self getCurrentWeapon() != weap) + + if ( self getCurrentWeapon() != weap ) { self GiveWeapon( weap ); - if (!self ChangeToWeapon(weap)) + if ( !self ChangeToWeapon( weap ) ) { - self notify("bot_try_use_fail"); + self notify( "bot_try_use_fail" ); return; } } @@ -1272,50 +1322,50 @@ bot_use_bomb_weapon(weap) { wait 0.05;//allow a waittill to setup as the notify may happen on the same frame } - - self notify("bot_try_use_weapon"); - ret = self waittill_any_return("bot_try_use_fail", "bot_try_use_success"); - - if(lastWeap != "none") - self thread ChangeToWeapon(lastWeap); + + self notify( "bot_try_use_weapon" ); + ret = self waittill_any_return( "bot_try_use_fail", "bot_try_use_success" ); + + if ( lastWeap != "none" ) + self thread ChangeToWeapon( lastWeap ); else - self takeWeapon(weap); + self takeWeapon( weap ); } /* Bot tries to use the bomb site */ -bot_use_bomb(bomb) +bot_use_bomb( bomb ) { - level endon("game_ended"); + level endon( "game_ended" ); bomb.inUse = true; - + myteam = self.team; - - self BotFreezeControls(true); - - bomb [[bomb.onBeginUse]](self); - + + self BotFreezeControls( true ); + + bomb [[bomb.onBeginUse]]( self ); + self clientClaimTrigger( bomb.trigger ); self.claimTrigger = bomb.trigger; - - self thread bot_bomb_use_time(bomb.useTime / 1000); - self thread bot_use_bomb_weapon(bomb.useWeapon); - - result = self waittill_any_return("death", "disconnect", "bot_try_use_fail", "bot_try_use_success"); - - if (isDefined(self)) + + self thread bot_bomb_use_time( bomb.useTime / 1000 ); + self thread bot_use_bomb_weapon( bomb.useWeapon ); + + result = self waittill_any_return( "death", "disconnect", "bot_try_use_fail", "bot_try_use_success" ); + + if ( isDefined( self ) ) { self.claimTrigger = undefined; - self BotFreezeControls(false); + self BotFreezeControls( false ); } - bomb [[bomb.onEndUse]](myteam, self, (result == "bot_try_use_success")); + bomb [[bomb.onEndUse]]( myteam, self, ( result == "bot_try_use_success" ) ); bomb.trigger releaseClaimedTrigger(); - - if(result == "bot_try_use_success") - bomb [[bomb.onUse]](self); + + if ( result == "bot_try_use_success" ) + bomb [[bomb.onUse]]( self ); bomb.inUse = false; } @@ -1325,14 +1375,14 @@ bot_use_bomb(bomb) */ fire_current_weapon() { - self endon("death"); - self endon("disconnect"); - self endon("weapon_change"); - self endon("stop_firing_weapon"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "stop_firing_weapon" ); - for (;;) + for ( ;; ) { - self thread BotPressAttack(0.05); + self thread BotPressAttack( 0.05 ); wait 0.1; } } @@ -1342,14 +1392,14 @@ fire_current_weapon() */ fire_c4() { - self endon("death"); - self endon("disconnect"); - self endon("weapon_change"); - self endon("stop_firing_weapon"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "weapon_change" ); + self endon( "stop_firing_weapon" ); - for (;;) + for ( ;; ) { - self thread BotPressAds(0.05); + self thread BotPressAds( 0.05 ); wait 0.1; } } @@ -1357,65 +1407,65 @@ fire_c4() /* Changes to the weap */ -changeToWeapon(weap) +changeToWeapon( weap ) { - self endon("disconnect"); - self endon("death"); - level endon("game_ended"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - if (!self HasWeapon(weap)) + if ( !self HasWeapon( weap ) ) return false; - if (self GetCurrentWeapon() == weap) + self BotChangeToWeapon( weap ); + + if ( self GetCurrentWeapon() == weap ) return true; - self BotChangeToWeapon(weap); + self waittill_any_timeout( 5, "weapon_change" ); - self waittill_any_timeout(5, "weapon_change"); - - return (self GetCurrentWeapon() == weap); + return ( self GetCurrentWeapon() == weap ); } /* Bots throw the grenade */ -botThrowGrenade(nade, time) +botThrowGrenade( nade, time ) { - self endon("disconnect"); - self endon("death"); - level endon("game_ended"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - if (!self GetAmmoCount(nade)) + if ( !self GetAmmoCount( nade ) ) return false; - if (nade != "frag_grenade_mp") - self thread BotPressSmoke(time); + if ( nade != "frag_grenade_mp" ) + self thread BotPressSmoke( time ); else - self thread BotPressFrag(time); + self thread BotPressFrag( time ); - ret = self waittill_any_timeout(5, "grenade_fire"); + ret = self waittill_any_timeout( 5, "grenade_fire" ); - return (ret == "grenade_fire"); + return ( ret == "grenade_fire" ); } /* Gets the object thats the closest in the array */ -bot_array_nearest_curorigin(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)) + + 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; } /* Clears goal when events death */ -stop_go_target_on_death(tar) +stop_go_target_on_death( tar ) { self endon( "death" ); self endon( "disconnect" ); @@ -1423,11 +1473,43 @@ stop_go_target_on_death(tar) self endon( "bad_path" ); self endon( "goal" ); - tar waittill_either("death", "disconnect"); + tar waittill_either( "death", "disconnect" ); self ClearScriptGoal(); } +/* + Bot logic for bot determining to camp. +*/ +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. */ @@ -1435,102 +1517,123 @@ bot_think_camp() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + for ( ;; ) { - wait randomintrange(4,7); - + wait randomintrange( 4, 7 ); + if ( self HasScriptGoal() || self.bot_lock_goal || self HasScriptAimPos() ) continue; - - if(randomInt(100) > self.pers["bots"]["behavior"]["camp"]) + + if ( randomInt( 100 ) > self.pers["bots"]["behavior"]["camp"] ) continue; - campSpots = []; - distSq = 1024*1024; - for (i = 0; i < level.waypointsCamp.size; i++) - { - if (DistanceSquared(self.origin, level.waypointsCamp[i].origin) > distSq) - continue; - - campSpots[campSpots.size] = level.waypointsCamp[i]; - } - campSpot = random(campSpots); - - if (!isDefined(campSpot)) - continue; - - self SetScriptGoal(campSpot.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - self thread killCampAfterTime(randomIntRange(10,20)); - self CampAtSpot(campSpot.origin, campSpot.origin + AnglesToForward(campSpot.angles) * 2048); + self bot_think_camp_loop(); } } /* Kills the camping thread when time */ -killCampAfterTime(time) +killCampAfterTime( time ) { - self endon("death"); - self endon("disconnect"); - self endon("kill_camp_bot"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_camp_bot" ); wait time + 0.05; self ClearScriptGoal(); self ClearScriptAimPos(); - self notify("kill_camp_bot"); + self notify( "kill_camp_bot" ); } /* Kills the camping thread when ent gone */ -killCampAfterEntGone(ent) +killCampAfterEntGone( ent ) { - self endon("death"); - self endon("disconnect"); - self endon("kill_camp_bot"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_camp_bot" ); - for (;;) + for ( ;; ) { wait 0.05; - if (!isDefined(ent)) + if ( !isDefined( ent ) ) break; } self ClearScriptGoal(); self ClearScriptAimPos(); - self notify("kill_camp_bot"); + self notify( "kill_camp_bot" ); } /* Camps at the spot */ -CampAtSpot(origin, anglePos) +CampAtSpot( origin, anglePos ) { - self endon("kill_camp_bot"); + self endon( "kill_camp_bot" ); - self SetScriptGoal(origin, 64); - if (isDefined(anglePos)) + self SetScriptGoal( origin, 64 ); + + if ( isDefined( anglePos ) ) { - self SetScriptAimPos(anglePos); + self SetScriptAimPos( anglePos ); } - self waittill("new_goal"); + self waittill( "new_goal" ); self ClearScriptAimPos(); - self notify("kill_camp_bot"); + self notify( "kill_camp_bot" ); +} + +/* + Bot logic for bot determining to follow another player. +*/ +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 IsPlayerModelOK() ) + continue; + + if ( player == self ) + continue; + + if ( !isAlive( player ) ) + continue; + + if ( player.team != self.team ) + continue; + + if ( DistanceSquared( player.origin, self.origin ) > distSq ) + continue; + + follows[follows.size] = player; + } + + toFollow = random( follows ); + + 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 ); } /* @@ -1540,50 +1643,21 @@ bot_think_follow() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + for ( ;; ) { - wait randomIntRange(3,5); - + 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) + + if ( randomInt( 100 ) > self.pers["bots"]["behavior"]["follow"] ) continue; - 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 IsPlayerModelOK()) - continue; - - if (player == self) - continue; - - if(!isAlive(player)) - continue; - - if (player.team != self.team) - continue; - - if (DistanceSquared(player.origin, self.origin) > distSq) - continue; - - follows[follows.size] = player; - } - toFollow = random(follows); - - if (!isDefined(toFollow)) + if ( !level.teamBased ) continue; - self thread killFollowAfterTime(randomIntRange(10,20)); - self followPlayer(toFollow); + self bot_think_follow_loop(); } } @@ -1592,72 +1666,182 @@ bot_think_follow() */ watchForFollowNewGoal() { - self endon("death"); - self endon("disconnect"); - self endon("kill_follow_bot"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_follow_bot" ); - for (;;) + for ( ;; ) { - self waittill("new_goal"); + self waittill( "new_goal" ); - if (!isDefined(self.bot_was_follow_script_update)) + if ( !isDefined( self.bot_was_follow_script_update ) ) break; } self ClearScriptAimPos(); - self notify("kill_follow_bot"); + self notify( "kill_follow_bot" ); } /* Kills follow when time */ -killFollowAfterTime(time) +killFollowAfterTime( time ) { - self endon("death"); - self endon("disconnect"); - self endon("kill_follow_bot"); + self endon( "death" ); + self endon( "disconnect" ); + self endon( "kill_follow_bot" ); wait time; self ClearScriptGoal(); self ClearScriptAimPos(); - self notify("kill_follow_bot"); + self notify( "kill_follow_bot" ); } /* Determine bot to follow a player */ -followPlayer(who) +followPlayer( who ) { - self endon("kill_follow_bot"); + self endon( "kill_follow_bot" ); self thread watchForFollowNewGoal(); - for (;;) + for ( ;; ) { wait 0.05; - if (!isDefined(who) || !isAlive(who)) + if ( !isDefined( who ) || !isAlive( who ) ) break; - self SetScriptAimPos(who.origin + (0, 0, 42)); + self SetScriptAimPos( who.origin + ( 0, 0, 42 ) ); myGoal = self GetScriptGoal(); - if (isDefined(myGoal) && DistanceSquared(myGoal, who.origin) < 64*64) + if ( isDefined( myGoal ) && DistanceSquared( myGoal, who.origin ) < 64 * 64 ) continue; - + self.bot_was_follow_script_update = true; - self SetScriptGoal(who.origin, 32); + self SetScriptGoal( who.origin, 32 ); waittillframeend; self.bot_was_follow_script_update = undefined; - self waittill_either("goal", "bad_path"); + self waittill_either( "goal", "bad_path" ); } self ClearScriptGoal(); self ClearScriptAimPos(); - self notify("kill_follow_bot"); + self notify( "kill_follow_bot" ); +} + +/* + Bots thinking of using a noobtube +*/ +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 HasScriptAimPos() ) + return; + + if ( self BotIsFrozen() ) + return; + + if ( self IsBotFragging() || self IsBotSmoking() ) + return; + + if ( self isDefusing() || self isPlanting() ) + return; + + if ( self InLastStand() ) + 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 ); } /* @@ -1665,362 +1849,303 @@ followPlayer(who) */ bot_use_tube_think() { - self endon("disconnect"); - self endon("death"); - level endon("game_ended"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; - for (;;) + for ( ;; ) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(3, 7); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - tube = self getValidTube(); - if (!isDefined(tube)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if (self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self InLastStand()) - continue; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, level.waypointsTube)) - { - tubeWps = []; - distSq = 1024*1024; - for (i = 0; i < level.waypointsTube.size; i++) - { - if (DistanceSquared(self.origin, level.waypointsTube[i].origin) > distSq) - continue; - - tubeWps[tubeWps.size] = level.waypointsTube[i]; - } - tubeWp = random(tubeWps); - - 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) - continue; - - if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) - continue; - - if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) - continue; - - loc += (0, 0, dist/16000); - } - else - { - self SetScriptGoal(tubeWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - tubeWp = self getNearestWaypointOfWaypoints(level.waypointsTube); - loc = tubeWp.origin + AnglesToForward(tubeWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - 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); + self bot_use_tube_think_loop( data ); } } +/* + Bots thinking of using claymores +*/ +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( "c4_mp" ) ) + nade = "c4_mp"; + + if ( !isDefined( nade ) ) + return; + + if ( self HasThreat() || self HasScriptAimPos() ) + return; + + if ( self BotIsFrozen() ) + return; + + if ( self IsBotFragging() || self IsBotSmoking() ) + return; + + if ( self isDefusing() || self isPlanting() ) + return; + + if ( self inLastStand() ) + return; + + curWeap = self GetCurrentWeapon(); + + if ( curWeap == "none" || !isWeaponDroppable( curWeap ) ) + curWeap = self.lastDroppableWeapon; + + 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; + + if ( self changeToWeapon( nade ) ) + { + if ( nade != "c4_mp" ) + self thread fire_current_weapon(); + else + self thread fire_c4(); + + self waittill_any_timeout( 5, "grenade_fire", "weapon_change" ); + self notify( "stop_firing_weapon" ); + } + + self thread changeToWeapon( curWeap ); + self ClearScriptAimPos(); + self BotStopMoving( false ); +} + /* Bots thinking of using claymores */ bot_use_equipment_think() { - self endon("disconnect"); - self endon("death"); - level endon("game_ended"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; - for (;;) + for ( ;; ) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(2, 4); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - nade = undefined; - if (self GetAmmoCount("claymore_mp")) - nade = "claymore_mp"; - if (self GetAmmoCount("c4_mp")) - nade = "c4_mp"; - - if (!isDefined(nade)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self inLastStand()) - continue; - - curWeap = self GetCurrentWeapon(); - if (curWeap == "none" || !isWeaponDroppable(curWeap)) - curWeap = self.lastDroppableWeapon; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, level.waypointsClay)) - { - clayWps = []; - distSq = 1024*1024; - for (i = 0; i < level.waypointsClay.size; i++) - { - if (DistanceSquared(self.origin, level.waypointsClay[i].origin) > distSq) - continue; - - clayWps[clayWps.size] = level.waypointsClay[i]; - } - clayWp = random(clayWps); - - if (!isDefined(clayWp) || self HasScriptGoal() || self.bot_lock_goal) - { - myEye = self GetEye(); - loc = myEye + AnglesToForward(self GetPlayerAngles()) * 256; - - if (!bulletTracePassed(myEye, loc, false, self)) - continue; - } - else - { - self SetScriptGoal(clayWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - clayWp = self getNearestWaypointOfWaypoints(level.waypointsClay); - loc = clayWp.origin + AnglesToForward(clayWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - self SetScriptAimPos(loc); - self BotStopMoving(true); - wait 1; - - if (self changeToWeapon(nade)) - { - if (nade != "c4_mp") - self thread fire_current_weapon(); - else - self thread fire_c4(); - self waittill_any_timeout(5, "grenade_fire", "weapon_change"); - self notify("stop_firing_weapon"); - } - - self thread changeToWeapon(curWeap); - self ClearScriptAimPos(); - self BotStopMoving(false); + self bot_use_equipment_think_loop( data ); } } +/* + Bots thinking of using grenades +*/ +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 HasScriptAimPos() ) + return; + + if ( self BotIsFrozen() ) + return; + + if ( self IsBotFragging() || self IsBotSmoking() ) + return; + + if ( self isDefusing() || self isPlanting() ) + return; + + if ( self inLastStand() ) + 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"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - doFastContinue = false; + data = spawnStruct(); + data.doFastContinue = false; - for (;;) + for ( ;; ) { - if (doFastContinue) - doFastContinue = false; - else - { - wait randomintRange(4, 7); - - chance = self.pers["bots"]["behavior"]["nade"] / 2; - if (chance > 20) - chance = 20; - - if (randomInt(100) > chance) - continue; - } - - nade = self getValidGrenade(); - if (!isDefined(nade)) - continue; - - if (self HasThreat() || self HasScriptAimPos()) - continue; - - if(self BotIsFrozen()) - continue; - - if(self IsBotFragging() || self IsBotSmoking()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self inLastStand()) - continue; - - loc = undefined; - - if (!self nearAnyOfWaypoints(128, level.waypointsGren)) - { - nadeWps = []; - distSq = 1024*1024; - for (i = 0; i < level.waypointsGren.size; i++) - { - if (DistanceSquared(self.origin, level.waypointsGren[i].origin) > distSq) - continue; - - nadeWps[nadeWps.size] = level.waypointsGren[i]; - } - nadeWp = random(nadeWps); - - 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) - continue; - - if (!bulletTracePassed(self.origin + (0, 0, 5), self.origin + (0, 0, 2048), false, self)) - continue; - - if (!bulletTracePassed(loc + (0, 0, 5), loc + (0, 0, 2048), false, self)) - continue; - - loc += (0, 0, dist/3000); - } - else - { - self SetScriptGoal(nadeWp.origin, 16); - - ret = self waittill_any_return("new_goal", "goal", "bad_path"); - - if (ret != "new_goal") - self ClearScriptGoal(); - - if (ret != "goal") - continue; - - doFastContinue = true; - continue; - } - } - else - { - nadeWp = self getNearestWaypointOfWaypoints(level.waypointsGren); - loc = nadeWp.origin + AnglesToForward(nadeWp.angles) * 2048; - } - - if (!isDefined(loc)) - continue; - - 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); + self bot_use_grenade_think_loop( data ); } } +/* + Goes to the target's location if it had one +*/ +follow_target_loop() +{ + threat = self GetThreat(); + + if ( !isPlayer( threat ) ) + return; + + if ( randomInt( 100 ) > self.pers["bots"]["behavior"]["follow"] * 5 ) + return; + + 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 ); +} + /* Goes to the target's location if it had one */ @@ -2028,99 +2153,105 @@ follow_target() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + 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 thread stop_go_target_on_death(threat); - - self SetScriptGoal(threat.origin, 64); - if (self waittill_any_return("new_goal", "goal", "bad_path") != "new_goal") - self ClearScriptGoal(); + self follow_target_loop(); } } +/* + Bot logic for detecting nearby players. +*/ +bot_listen_to_steps_loop() +{ + dist = level.bots_listenDist; + + if ( self hasPerk( "specialty_parabolic" ) ) + dist *= 1.4; + + dist *= dist; + + heard = undefined; + + for ( i = level.players.size - 1 ; i >= 0; i-- ) + { + player = level.players[i]; + + if ( !player IsPlayerModelOK() ) + continue; + + if ( player == self ) + continue; + + if ( level.teamBased && self.team == player.team ) + continue; + + if ( player.sessionstate != "playing" ) + continue; + + if ( !isAlive( player ) ) + continue; + + if ( player hasPerk( "specialty_quieter" ) ) + continue; + + if ( lengthsquared( player getVelocity() ) < 20000 ) + continue; + + if ( distanceSquared( player.origin, self.origin ) > dist ) + continue; + + heard = player; + break; + } + + if ( !IsDefined( heard ) ) + return; + + self BotNotifyBotEvent( "heard_target", "start", heard ); + + if ( bulletTracePassed( self getEyePos(), 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 ); +} + /* Bot logic for detecting nearby players. */ bot_listen_to_steps() { - self endon("disconnect"); - self endon("death"); - - for(;;) + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) { wait 1; - - if(self.pers["bots"]["skill"]["base"] < 3) - continue; - - dist = level.bots_listenDist; - if(self hasPerk("specialty_parabolic")) - dist *= 1.4; - - dist *= dist; - - heard = undefined; - for(i = level.players.size-1 ; i >= 0; i--) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if(player == self) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isAlive(player)) - continue; - if(player hasPerk("specialty_quieter")) - continue; - - if(lengthsquared( player getVelocity() ) < 20000) - continue; - - if(distanceSquared(player.origin, self.origin) > dist) - continue; - - heard = player; - break; - } - - if(!IsDefined(heard)) - continue; - - if(bulletTracePassed(self getEyePos(), heard getTagOrigin( "j_spineupper" ), false, heard)) - { - self setAttacker(heard); - continue; - } - if(self HasScriptGoal() || self.bot_lock_goal) + if ( self.pers["bots"]["skill"]["base"] < 3 ) continue; - - self SetScriptGoal( heard.origin, 64 ); - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); + self bot_listen_to_steps_loop(); } } @@ -2131,236 +2262,382 @@ bot_revenge_think() { self endon( "death" ); self endon( "disconnect" ); - - if(self.pers["bots"]["skill"]["base"] <= 1) + + if ( self.pers["bots"]["skill"]["base"] <= 1 ) return; - if (isDefined(self.lastKiller) && isAlive(self.lastKiller)) + if ( isDefined( self.lastKiller ) && isAlive( self.lastKiller ) ) { - if(bulletTracePassed(self getEyePos(), self.lastKiller getTagOrigin( "j_spineupper" ), false, self.lastKiller)) + if ( bulletTracePassed( self getEyePos(), self.lastKiller getTagOrigin( "j_spineupper" ), false, self.lastKiller ) ) { - self setAttacker(self.lastKiller); + self setAttacker( self.lastKiller ); } } - - if(!isDefined(self.killerLocation)) + + if ( !isDefined( self.killerLocation ) ) return; loc = self.killerLocation; - - for(;;) + + for ( ;; ) { wait( RandomIntRange( 1, 5 ) ); - - if(self HasScriptGoal() || self.bot_lock_goal) + + 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") + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) self ClearScriptGoal(); + + self BotNotifyBotEvent( "revenge", "stop", loc, self.lastKiller ); } } +/* + Reload cancels +*/ +doReloadCancel_loop() +{ + ret = self waittill_any_return( "reload", "weapon_change" ); + + if ( self BotIsFrozen() ) + return; + + if ( self isDefusing() || self isPlanting() ) + return; + + if ( self InLastStand() ) + return; + + curWeap = self GetCurrentWeapon(); + + if ( !maps\mp\gametypes\_weapons::isSideArm( curWeap ) && !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::isSideArm( weapon ) && !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"); + self endon( "disconnect" ); + self endon( "death" ); - for (;;) + for ( ;; ) { - ret = self waittill_any_return("reload", "weapon_change"); - - if(self BotIsFrozen()) - continue; - - if(self isDefusing() || self isPlanting()) - continue; - - if (self InLastStand()) - continue; - - curWeap = self GetCurrentWeapon(); - - if (!maps\mp\gametypes\_weapons::isSideArm( curWeap ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( curWeap )) - continue; - - if (ret == "reload") - { - // check single reloads - if (self GetWeaponAmmoClip(curWeap) < WeaponClipSize(curWeap)) - continue; - } - - // check difficulty - if (self.pers["bots"]["skill"]["base"] <= 3) - continue; - - // 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::isSideArm( weapon ) && !maps\mp\gametypes\_weapons::isPrimaryWeapon( weapon )) - continue; - - if(curWeap == weapon || weapon == "none" || weapon == "") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - // do the cancel - wait 0.1; - self BotChangeToWeapon(weap); - wait 0.25; - self BotChangeToWeapon(curWeap); - wait 2; + self doReloadCancel_loop(); } } +/* + Bot logic for switching weapons. +*/ +bot_weapon_think_loop( data ) +{ + self waittill_any_timeout( randomIntRange( 2, 4 ), "bot_force_check_switch" ); + + if ( self BotIsFrozen() ) + return; + + if ( self isDefusing() || self isPlanting() || self InLastStand() ) + return; + + hasTarget = self hasThreat(); + curWeap = self GetCurrentWeapon(); + + if ( hasTarget ) + { + threat = self getThreat(); + + if ( threat.classname == "script_vehicle" && self getAmmoCount( "rpg_mp" ) ) + { + if ( curWeap != "rpg_mp" ) + self thread ChangeToWeapon( "rpg_mp" ); + + return; + } + } + + if ( data.first ) + { + data.first = false; + + if ( randomInt( 100 ) > self.pers["bots"]["behavior"]["initswitch"] ) + return; + } + else + { + if ( curWeap != "none" && self getAmmoCount( curWeap ) ) + { + if ( randomInt( 100 ) > self.pers["bots"]["behavior"]["switch"] ) + return; + + if ( hasTarget ) + return; + } + } + + weaponslist = self getweaponslist(); + weap = ""; + + while ( weaponslist.size ) + { + weapon = weaponslist[randomInt( weaponslist.size )]; + weaponslist = array_remove( weaponslist, weapon ); + + if ( !self getAmmoCount( weapon ) ) + continue; + + if ( maps\mp\gametypes\_weapons::isHackWeapon( weapon ) ) + continue; + + if ( maps\mp\gametypes\_weapons::isGrenade( weapon ) ) + continue; + + if ( curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "" ) + continue; + + weap = weapon; + break; + } + + if ( weap == "" ) + return; + + self thread ChangeToWeapon( weap ); +} + /* Bot logic for switching weapons. */ bot_weapon_think() { - self endon("death"); - self endon("disconnect"); - level endon("game_ended"); + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); - first = true; - - for(;;) + data = spawnStruct(); + data.first = true; + + for ( ;; ) { - self waittill_any_timeout(randomIntRange(2, 4), "bot_force_check_switch"); - - if(self BotIsFrozen()) - continue; - - if(self isDefusing() || self isPlanting() || self InLastStand()) - continue; - - hasTarget = self hasThreat(); - curWeap = self GetCurrentWeapon(); - - if(hasTarget) - { - threat = self getThreat(); - - if(threat.classname == "script_vehicle" && self getAmmoCount("rpg_mp")) - { - if (curWeap != "rpg_mp") - self thread ChangeToWeapon("rpg_mp"); - continue; - } - } - - if (first) - { - first = false; - - if(randomInt(100) > self.pers["bots"]["behavior"]["initswitch"]) - continue; - } - else - { - if(curWeap != "none" && self getAmmoCount(curWeap)) - { - if(randomInt(100) > self.pers["bots"]["behavior"]["switch"]) - continue; - - if(hasTarget) - continue; - } - } - - weaponslist = self getweaponslist(); - weap = ""; - while(weaponslist.size) - { - weapon = weaponslist[randomInt(weaponslist.size)]; - weaponslist = array_remove(weaponslist, weapon); - - if(!self getAmmoCount(weapon)) - continue; - - if (maps\mp\gametypes\_weapons::isHackWeapon( weapon )) - continue; - - if (maps\mp\gametypes\_weapons::isGrenade( weapon )) - continue; - - if(curWeap == weapon || weapon == "c4_mp" || weapon == "none" || weapon == "claymore_mp" || weapon == "") - continue; - - weap = weapon; - break; - } - - if(weap == "") - continue; - - self thread ChangeToWeapon(weap); + self bot_weapon_think_loop( data ); } } +/* + Bots play mw2 +*/ +bot_watch_think_mw2_loop() +{ + tube = self getValidTube(); + + if ( !isDefined( tube ) ) + { + if ( self GetAmmoCount( "rpg_mp" ) ) + tube = "rpg_mp"; + else + return; + } + + if ( self GetCurrentWeapon() == tube ) + return; + + chance = self.pers["bots"]["behavior"]["nade"]; + + if ( randomInt( 100 ) > chance ) + return; + + self thread ChangeToWeapon( tube ); +} + /* Bots play mw2 */ bot_watch_think_mw2() { - self endon("disconnect"); - self endon("death"); - level endon("game_ended"); + self endon( "disconnect" ); + self endon( "death" ); + level endon( "game_ended" ); - for (;;) + for ( ;; ) { - wait randomIntRange(1, 4); + wait randomIntRange( 1, 4 ); - if(self BotIsFrozen()) - continue; - - if(self isDefusing() || self isPlanting()) + if ( self BotIsFrozen() ) continue; - if (self InLastStand()) + if ( self isDefusing() || self isPlanting() ) continue; - if (self HasThreat()) + if ( self InLastStand() ) continue; - tube = self getValidTube(); - if (!isDefined(tube)) + if ( self HasThreat() ) + continue; + + self bot_watch_think_mw2_loop(); + } +} + +/* + Bot logic for killstreaks. +*/ +bot_killstreak_think_loop() +{ + curWeap = self GetCurrentWeapon(); + + if ( curWeap == "none" || !isWeaponDroppable( curWeap ) ) + curWeap = self.lastDroppableWeapon; + + targetPos = undefined; + + switch ( self.pers["hardPointItem"] ) + { + case "radar_mp": + if ( self.bot_radar && self.pers["bots"]["skill"]["base"] > 3 ) + return; + + break; + + case "helicopter_mp": + chopper = level.chopper; + + if ( isDefined( chopper ) && level.teamBased && getDvarInt( "doubleHeli" ) ) + chopper = level.chopper[self.team]; + + if ( isDefined( chopper ) ) + return; + + if ( isDefined( level.mannedchopper ) ) + return; + + break; + + case "airstrike_mp": + if ( isDefined( level.airstrikeInProgress ) ) + return; + + players = []; + + for ( i = level.players.size - 1; i >= 0; i-- ) + { + player = level.players[i]; + + if ( !player IsPlayerModelOK() ) + continue; + + if ( player == self ) + continue; + + if ( !isDefined( player.team ) ) + continue; + + if ( level.teamBased && self.team == player.team ) + continue; + + if ( player.sessionstate != "playing" ) + continue; + + if ( !isAlive( player ) ) + continue; + + if ( player hasPerk( "specialty_gpsjammer" ) ) + continue; + + if ( !bulletTracePassed( player.origin, player.origin + ( 0, 0, 512 ), false, player ) && self.pers["bots"]["skill"]["base"] > 3 ) + continue; + + players[players.size] = player; + } + + target = random( players ); + + if ( isDefined( target ) ) + targetPos = 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 ) + targetPos = self.origin + ( randomIntRange( -512, 512 ), randomIntRange( -512, 512 ), 0 ); + + break; + + default: + return; + } + + isAirstrikePos = isDefined( targetPos ); + + if ( self.pers["hardPointItem"] == "airstrike_mp" && !isAirstrikePos ) + return; + + self BotNotifyBotEvent( "killstreak", "call", targetPos ); + + self BotStopMoving( true ); + + if ( self changeToWeapon( self.pers["hardPointItem"] ) ) + { + wait 1; + + if ( isAirstrikePos && !isDefined( level.airstrikeInProgress ) ) { - if (self GetAmmoCount("rpg_mp")) - tube = "rpg_mp"; - else - continue; + self BotFreezeControls( true ); + + self notify( "confirm_location", targetPos ); + wait 1; + + self BotFreezeControls( false ); } - if (self GetCurrentWeapon() == tube) - continue; - - chance = self.pers["bots"]["behavior"]["nade"]; - - if (randomInt(100) > chance) - continue; - - self ChangeToWeapon(tube); + self thread changeToWeapon( curWeap ); } + + self BotStopMoving( false ); } /* @@ -2368,118 +2645,89 @@ bot_watch_think_mw2() */ bot_killstreak_think() { - self endon("death"); - self endon("disconnect"); - level endon("game_ended"); - - for(;;) + self endon( "death" ); + self endon( "disconnect" ); + level endon( "game_ended" ); + + for ( ;; ) { - wait randomIntRange(1, 3); - - if(self BotIsFrozen()) - continue; - - if(!isDefined(self.pers["hardPointItem"])) - continue; - - if(self HasThreat()) - continue; - - if(self isDefusing() || self isPlanting() || self InLastStand()) + wait randomIntRange( 1, 3 ); + + if ( self BotIsFrozen() ) continue; - curWeap = self GetCurrentWeapon(); - if (curWeap == "none" || !isWeaponDroppable(curWeap)) - curWeap = self.lastDroppableWeapon; - - targetPos = undefined; - switch(self.pers["hardPointItem"]) + if ( !isDefined( self.pers["hardPointItem"] ) ) + continue; + + if ( self HasThreat() ) + continue; + + if ( self isDefusing() || self isPlanting() || self InLastStand() ) + continue; + + self bot_killstreak_think_loop(); + } +} + +/* + Bot logic for UAV detection here. Checks for UAV and players who are shooting. +*/ +bot_uav_think_loop() +{ + 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 IsPlayerModelOK() ) + continue; + + if ( player == self ) + continue; + + if ( !isDefined( player.team ) ) + continue; + + if ( player.sessionstate != "playing" ) + continue; + + if ( level.teambased && player.team == self.team ) + continue; + + if ( !isAlive( player ) ) + continue; + + distFromPlayer = DistanceSquared( self.origin, player.origin ); + + if ( distFromPlayer > dist ) + continue; + + if ( ( !isSubStr( player getCurrentWeapon(), "_silencer_" ) && player.bots_firing ) || ( self.bot_radar && !player hasPerk( "specialty_gpsjammer" ) ) ) { - case "radar_mp": - if(self.bot_radar && self.pers["bots"]["skill"]["base"] > 3) - continue; - break; - - case "helicopter_mp": - chopper = level.chopper; + self BotNotifyBotEvent( "uav_target", "start", player ); - if (isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) - chopper = level.chopper[self.team]; + distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; - if (isDefined(chopper)) - continue; - - if (isDefined( level.mannedchopper )) - continue; - - break; - - case "airstrike_mp": - if(isDefined( level.airstrikeInProgress )) - continue; - - players = []; - for(i = level.players.size - 1; i >= 0; i--) - { - player = level.players[i]; - - if(!player IsPlayerModelOK()) - continue; - - if(player == self) - continue; - if(!isDefined(player.team)) - continue; - if(level.teamBased && self.team == player.team) - continue; - if(player.sessionstate != "playing") - continue; - if(!isAlive(player)) - continue; - if(player hasPerk("specialty_gpsjammer")) - continue; - if(!bulletTracePassed(player.origin, player.origin+(0,0,512), false, player) && self.pers["bots"]["skill"]["base"] > 3) - continue; - - players[players.size] = player; - } - - target = random(players); - - if(isDefined(target)) - targetPos = 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) - targetPos = self.origin + (randomIntRange(-512, 512), randomIntRange(-512, 512), 0); - break; - - default: - continue; - } - - isAirstrikePos = isDefined(targetPos); - if(self.pers["hardPointItem"] == "airstrike_mp" && !isAirstrikePos) - continue; - - self BotStopMoving(true); - - if (self changeToWeapon(self.pers["hardPointItem"])) - { - wait 1; - - if (isAirstrikePos && !isDefined( level.airstrikeInProgress )) + if ( distFromPlayer < distSq && bulletTracePassed( self getEyePos(), player getTagOrigin( "j_spineupper" ), false, player ) ) { - self BotFreezeControls(true); - - self notify( "confirm_location", targetPos ); - wait 1; - - self BotFreezeControls(false); + self SetAttacker( player ); } - self thread changeToWeapon(curWeap); - } + if ( !self HasScriptGoal() && !self.bot_lock_goal ) + { + self SetScriptGoal( player.origin, 128 ); + self thread stop_go_target_on_death( player ); - self BotStopMoving(false); + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) + self ClearScriptGoal(); + + self BotNotifyBotEvent( "uav_target", "stop", player ); + } + + break; + } } } @@ -2490,68 +2738,58 @@ bot_uav_think() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + for ( ;; ) { wait 0.75; - - if(self.pers["bots"]["skill"]["base"] <= 1) + + if ( self.pers["bots"]["skill"]["base"] <= 1 ) continue; - - if( level.hardcoreMode && !self.bot_radar ) + + if ( level.hardcoreMode && !self.bot_radar ) continue; - - 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 IsPlayerModelOK()) - continue; - - if(player == self) - continue; - - if(!isDefined(player.team)) - continue; - - if(player.sessionstate != "playing") - continue; - - if(level.teambased && player.team == self.team) - continue; - - if(!isAlive(player)) - continue; - - distFromPlayer = DistanceSquared(self.origin, player.origin); - if(distFromPlayer > dist) - continue; - - if((!isSubStr(player getCurrentWeapon(), "_silencer_") && player.bots_firing) || (self.bot_radar && !player hasPerk("specialty_gpsjammer"))) - { - distSq = self.pers["bots"]["skill"]["help_dist"] * self.pers["bots"]["skill"]["help_dist"]; - if (distFromPlayer < distSq && bulletTracePassed(self getEyePos(), player getTagOrigin( "j_spineupper" ), false, player)) - { - self SetAttacker(player); - } - - if (!self HasScriptGoal() && !self.bot_lock_goal) - { - self thread stop_go_target_on_death(player); - self SetScriptGoal( player.origin, 128 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } - break; - } - } + self bot_uav_think_loop(); } } +/* + Bot logic for detecting the chopper as an enemy. +*/ +bot_target_vehicle_loop() +{ + chopper = level.chopper; + + if ( isDefined( chopper ) && level.teamBased && getDvarInt( "doubleHeli" ) ) + { + chopper = level.chopper[ level.otherTeam[self.team] ]; + } + + if ( !isdefined( chopper ) ) + return; + + if ( !isDefined( level.bot_chopper ) || !level.bot_chopper ) //must be crashing or leaving + return; + + if ( isDefined( chopper.owner ) && chopper.owner == self ) + return; + + if ( chopper.team == self.team && level.teamBased ) + return; + + if ( !bulletTracePassed( self getEyePos(), chopper.origin + ( 0, 0, -5 ), false, chopper ) ) + return; + + self BotNotifyBotEvent( "attack_vehicle", "start", chopper ); + + self SetScriptEnemy( chopper, ( 0, 0, -5 ) ); + self bot_attack_vehicle( chopper ); + self ClearScriptEnemy(); + self notify( "bot_force_check_switch" ); + + self BotNotifyBotEvent( "attack_vehicle", "stop", chopper ); +} + /* Bot logic for detecting the chopper as an enemy. */ @@ -2559,63 +2797,38 @@ bot_target_vehicle() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + for ( ;; ) { wait( RandomIntRange( 2, 4 ) ); - if(self.pers["bots"]["skill"]["base"] <= 1) - continue; - - if(self HasScriptEnemy()) - continue; - - if(!self getAmmoCount("rpg_mp") && self BotGetRandom() < 90) + if ( self.pers["bots"]["skill"]["base"] <= 1 ) continue; - chopper = level.chopper; + if ( self HasScriptEnemy() ) + continue; - if(isDefined(chopper) && level.teamBased && getDvarInt("doubleHeli")) - { - chopper = level.chopper[ level.otherTeam[self.team] ]; - } + if ( !self getAmmoCount( "rpg_mp" ) && self BotGetRandom() < 90 ) + continue; - if (!isdefined(chopper)) - continue; - - if(!isDefined(level.bot_chopper) || !level.bot_chopper)//must be crashing or leaving - continue; - - if(isDefined(chopper.owner) && chopper.owner == self) - continue; - - if(chopper.team == self.team && level.teamBased) - continue; - - if(!bulletTracePassed( self getEyePos(), chopper.origin + (0, 0, -5), false, chopper )) - continue; - - self SetScriptEnemy( chopper, (0, 0, -5) ); - self bot_attack_vehicle(chopper); - self ClearScriptEnemy(); - self notify("bot_force_check_switch"); + self bot_target_vehicle_loop(); } } /* Bot logic for how long to keep targeting chopper. */ -bot_attack_vehicle(chopper) +bot_attack_vehicle( chopper ) { chopper endon( "death" ); chopper endon( "crashing" ); chopper endon( "leaving" ); - + wait_time = RandomIntRange( 7, 10 ); for ( i = 0; i < wait_time; i++ ) { - self notify("bot_force_check_switch"); + self notify( "bot_force_check_switch" ); wait( 1 ); if ( !IsDefined( chopper ) ) @@ -2625,6 +2838,62 @@ bot_attack_vehicle(chopper) } } +/* + Bot logic for targeting equipment. +*/ +bot_equipment_kill_think_loop() +{ + grenades = GetEntArray( "grenade", "classname" ); + myEye = self getEyePos(); + myAngles = self getPlayerAngles(); + target = undefined; + hasDetectExp = self hasPerk( "specialty_detectexplosive" ); + + for ( i = grenades.size - 1; i >= 0; i-- ) + { + item = grenades[i]; + + if ( !isDefined( item ) ) + continue; + + if ( !IsDefined( item.name ) ) + { + continue; + } + + if ( IsDefined( item.owner ) && ( ( level.teamBased && item.owner.team == self.team ) || item.owner == self ) ) + { + continue; + } + + if ( item.name != "c4_mp" && item.name != "claymore_mp" ) + continue; + + if ( !hasDetectExp && !bulletTracePassed( myEye, item.origin + ( 0, 0, 0 ), false, item ) ) + continue; + + if ( getConeDot( item.origin, self.origin, myAngles ) < 0.6 ) + continue; + + if ( DistanceSquared( item.origin, self.origin ) < 512 * 512 ) + { + target = item; + break; + } + } + + if ( isDefined( target ) ) + { + self BotNotifyBotEvent( "attack_equ", "start", target ); + + self SetScriptEnemy( target, ( 0, 0, 0 ) ); + self bot_equipment_attack( target ); + self ClearScriptEnemy(); + + self BotNotifyBotEvent( "attack_equ", "stop", target ); + } +} + /* Bot logic for targeting equipment. */ @@ -2632,72 +2901,28 @@ bot_equipment_kill_think() { self endon( "death" ); self endon( "disconnect" ); - - for(;;) + + for ( ;; ) { wait( RandomIntRange( 1, 3 ) ); - - if(self HasScriptEnemy()) + + if ( self HasScriptEnemy() ) continue; - if(self.pers["bots"]["skill"]["base"] <= 1) + if ( self.pers["bots"]["skill"]["base"] <= 1 ) continue; - - grenades = GetEntArray( "grenade", "classname" ); - myEye = self getEyePos(); - myAngles = self getPlayerAngles(); - target = undefined; - hasDetectExp = self hasPerk("specialty_detectexplosive"); - for ( i = grenades.size - 1; i >= 0; i-- ) - { - item = grenades[i]; - - if (!isDefined(item)) - continue; - - if ( !IsDefined( item.name ) ) - { - continue; - } - - if ( IsDefined( item.owner ) && ((level.teamBased && item.owner.team == self.team) || item.owner == self) ) - { - continue; - } - - if (item.name != "c4_mp" && item.name != "claymore_mp") - continue; - - if(!hasDetectExp && !bulletTracePassed(myEye, item.origin+(0, 0, 0), false, item)) - continue; - - if(getConeDot(item.origin, self.origin, myAngles) < 0.6) - continue; - - if ( DistanceSquared( item.origin, self.origin ) < 512 * 512 ) - { - target = item; - break; - } - } - - if(isDefined(target)) - { - self SetScriptEnemy( target, (0, 0, 0) ); - self bot_equipment_attack(target); - self ClearScriptEnemy(); - } + self bot_equipment_kill_think_loop(); } } /* How long to keep targeting the equipment. */ -bot_equipment_attack(equ) +bot_equipment_attack( equ ) { - equ endon("death"); - + equ endon( "death" ); + wait_time = RandomIntRange( 7, 10 ); for ( i = 0; i < wait_time; i++ ) @@ -2711,6 +2936,181 @@ bot_equipment_attack(equ) } } +/* + 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" ); + + equ = undefined; + + if ( self GetAmmoCount( "claymore_mp" ) ) + equ = "claymore_mp"; + + if ( self GetAmmoCount( "c4_mp" ) ) + equ = "c4_mp"; + + if ( !isDefined( equ ) ) + return; + + curWeap = self GetCurrentWeapon(); + + if ( self changeToWeapon( equ ) ) + { + if ( equ != "c4_mp" ) + self thread fire_current_weapon(); + else + self thread fire_c4(); + + self waittill_any_timeout( 5, "grenade_fire", "weapon_change" ); + self notify( "stop_firing_weapon" ); + } + + self thread changeToWeapon( curWeap ); +} + +/* + 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 GetEyeHeight() ); + + 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 */ @@ -2722,55 +3122,24 @@ bot_dom_spawn_kill_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 10, 20 ) ); - + if ( randomint( 100 ) < 20 ) continue; - - if ( self HasScriptGoal() || self.bot_lock_goal) - continue; - - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - if ( myFlagCount == level.flags.size ) + if ( self HasScriptGoal() || self.bot_lock_goal ) continue; - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if (myFlagCount <= otherFlagCount || otherFlagCount != 1) - continue; - - flag = undefined; - for ( i = 0; i < level.flags.size; i++ ) - { - if ( level.flags[i] maps\mp\gametypes\dom::getFlagTeam() == myTeam ) - continue; - } - - if(!isDefined(flag)) - continue; - - if(DistanceSquared(self.origin, flag.origin) < 2048*2048) - continue; - - 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 bot_dom_spawn_kill_think_loop(); } } /* Calls 'bad_path' when the flag count changes */ -bot_dom_watch_flags(count, myTeam) +bot_dom_watch_flags( count, myTeam ) { self endon( "death" ); self endon( "disconnect" ); @@ -2778,15 +3147,51 @@ bot_dom_watch_flags(count, myTeam) self endon( "bad_path" ); self endon( "new_goal" ); - for (;;) + for ( ;; ) { wait 0.5; - if (maps\mp\gametypes\dom::getTeamFlagCount( myTeam ) != count) + if ( maps\mp\gametypes\dom::getTeamFlagCount( myTeam ) != count ) break; } - - self notify("bad_path"); + + 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 ); } /* @@ -2800,67 +3205,144 @@ bot_dom_def_think() if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - for ( ;; ) { wait( randomintrange( 1, 3 ) ); - + if ( randomint( 100 ) < 35 ) continue; - + if ( self HasScriptGoal() || self.bot_lock_goal ) continue; - - 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) ) - continue; - 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 bot_dom_def_think_loop(); } } /* Watches while the flag is under capture */ -bot_dom_watch_for_flashing(flag, myTeam) +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 (;;) + + for ( ;; ) { wait 0.5; - if (!isDefined(flag)) + if ( !isDefined( flag ) ) break; - if (flag maps\mp\gametypes\dom::getFlagTeam() != myTeam || !flag.useObj.objPoints[myTeam].isFlashing) + if ( flag maps\mp\gametypes\dom::getFlagTeam() != myTeam || !flag.useObj.objPoints[myTeam].isFlashing ) break; } - - self notify("bad_path"); + + 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; } /* @@ -2870,139 +3352,163 @@ bot_dom_cap_think() { self endon( "death" ); self endon( "disconnect" ); - + if ( level.gametype != "dom" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 12 ) ); - + if ( self.bot_lock_goal ) { continue; } - if ( !isDefined(level.flags) || level.flags.size == 0 ) + if ( !isDefined( level.flags ) || level.flags.size == 0 ) continue; - myFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( myTeam ); - - if ( myFlagCount == level.flags.size ) - continue; - - otherFlagCount = maps\mp\gametypes\dom::getTeamFlagCount( otherTeam ); - - if (game["teamScores"][myteam] >= game["teamScores"][otherTeam]) - { - if ( myFlagCount < otherFlagCount ) - { - if ( randomint( 100 ) < 15 ) - continue; - } - else if ( myFlagCount == otherFlagCount ) - { - if ( randomint( 100 ) < 35 ) - continue; - } - else if ( myFlagCount > otherFlagCount ) - { - if ( randomint( 100 ) < 95 ) - continue; - } - } - - 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) ) - continue; - - 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; - continue; - } - - 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 ClearScriptGoal(); - - self.bot_lock_goal = false; + 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) +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 (;;) + + for ( ;; ) { - wait randomintrange(2,4); + wait randomintrange( 2, 4 ); - if (!isDefined(flag)) + if ( !isDefined( flag ) ) break; - if (flag maps\mp\gametypes\dom::getFlagTeam() == myTeam) + if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) break; - if (self isTouching(flag)) + if ( self isTouching( flag ) ) break; } - - if (flag maps\mp\gametypes\dom::getFlagTeam() == myTeam) - self notify("bad_path"); + + if ( flag maps\mp\gametypes\dom::getFlagTeam() == myTeam ) + self notify( "bad_path" ); else - self notify("goal"); + 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(); + } } /* @@ -3016,116 +3522,29 @@ bot_hq() if ( level.gametype != "koth" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); - + if ( self.bot_lock_goal ) { continue; } - - if(!isDefined(level.radio)) + + if ( !isDefined( level.radio ) ) continue; - - if(!isDefined(level.radio.gameobject)) + + if ( !isDefined( level.radio.gameobject ) ) continue; - - 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()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - //capture it - - 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; - continue; - } - - if(!self isTouching(gameobj.trigger) || level.radio != radio) - { - self.bot_lock_goal = false; - continue; - } - - 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 ClearScriptGoal(); - self.bot_lock_goal = false; - } - else//we own it - { - if(gameobj.objPoints[myteam].isFlashing)//underattack - { - 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; - continue; - } - - if(self HasScriptGoal()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - } + self bot_hq_loop(); } } /* Waits until not touching the trigger and it is the current radio. */ -bot_hq_go_cap(obj, radio) +bot_hq_go_cap( obj, radio ) { self endon( "death" ); self endon( "disconnect" ); @@ -3133,54 +3552,315 @@ bot_hq_go_cap(obj, radio) self endon( "bad_path" ); self endon( "new_goal" ); - for (;;) + for ( ;; ) { - wait randomintrange(2,4); + wait randomintrange( 2, 4 ); - if (!isDefined(obj)) + if ( !isDefined( obj ) ) break; - if (self isTouching(obj.trigger)) + if ( self isTouching( obj.trigger ) ) break; - if (level.radio != radio) + if ( level.radio != radio ) break; } - - if(level.radio != radio) - self notify("bad_path"); + + if ( level.radio != radio ) + self notify( "bad_path" ); else - self notify("goal"); + self notify( "goal" ); } /* Waits while the radio is under attack. */ -bot_hq_watch_flashing(obj, radio) +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 (;;) + for ( ;; ) { wait 0.5; - if (!isDefined(obj)) + if ( !isDefined( obj ) ) break; - if (!obj.objPoints[myteam].isFlashing) + if ( !obj.objPoints[myteam].isFlashing ) break; - if (level.radio != radio) + if ( level.radio != radio ) break; } - - self notify("bad_path"); + + 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\_globallogic::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 = maps\mp\gametypes\_globallogic::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_use_bomb_thread( site ); + wait 1; + + 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_gpsjammer" ) ) + 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_use_bomb_thread( site ); + wait 1; + 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; + } } /* @@ -3190,251 +3870,192 @@ bot_sab() { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); if ( level.gametype != "sab" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - for ( ;; ) { wait( randomintrange( 3, 5 ) ); - + if ( self.bot_lock_goal ) { continue; } - - if(!isDefined(level.sabBomb)) - continue; - - if(!isDefined(level.bombZones) || !level.bombZones.size) + + if ( !isDefined( level.sabBomb ) ) continue; - if (self IsPlanting() || self isDefusing()) + if ( !isDefined( level.bombZones ) || !level.bombZones.size ) continue; - - bomb = level.sabBomb; - bombteam = bomb.ownerTeam; - carrier = bomb.carrier; - timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - - // the bomb is ours, we are on the offence - if(bombteam == myTeam) + + 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\_globallogic::getTimeRemaining() / 1000; + + if ( timeleft >= 90 ) + return; + + // check for a bomb carrier, and camp the bomb + if ( !level.multiBomb && isDefined( level.sdBomb ) ) { - 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.bot_lock_goal = true; - self SetScriptGoal( origin, 64 ); + 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 thread bot_defend_site(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - self.bot_lock_goal = false; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self.bot_lock_goal = true; self SetScriptGoal( origin, 256 ); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") + + 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; - continue; + + return; } - - // we are not the carrier - if(!self isBombCarrier()) - { - // lets escort the bomb carrier - if(self HasScriptGoal()) - continue; - - origin = carrier.origin; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - 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(); - continue; - } - - // we are the carrier of the bomb, lets check if we need to plant - timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; - - if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) - continue; - - 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; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(site); - wait 1; - - self ClearScriptGoal(); - self.bot_lock_goal = false; } - else if(bombteam == otherTeam) // the bomb is theirs, we are on the defense + + // pick a site to protect + if ( !isDefined( level.bombZones ) || !level.bombZones.size ) + return; + + sites = []; + + for ( i = 0; i < level.bombZones.size; i++ ) { - 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()) - continue; - - if(carrier hasPerk( "specialty_gpsjammer" )) - continue; - - 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(); - continue; - } - - //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.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; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - { - wait 4; - self notify("bot_inc_bots"); site.bots--; - continue; - } - - 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; - continue; - } - - // 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()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse(site); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // lets 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; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(site); - wait 1; - self ClearScriptGoal(); - - self.bot_lock_goal = false; + sites[sites.size] = level.bombZones[i]; } - else // we need to go get the bomb! + + 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 { - origin = ( bomb.curorigin[0], bomb.curorigin[1], bomb.curorigin[2]+5 ); - + self BotNotifyBotEvent( "sd", "start", "planter", site ); + 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 thread bot_defend_site( site ); + + if ( self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal" ) self ClearScriptGoal(); - + self.bot_lock_goal = false; - continue; + + 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_use_bomb_thread( defuse ); + wait 1; + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "defuse" ); } /* @@ -3444,171 +4065,226 @@ bot_sd_defenders() { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); if ( level.gametype != "sd" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - if(myTeam == game["attackers"]) + if ( self.team == game["attackers"] ) return; - rand = self BotGetRandom(); + data = spawnStruct(); + data.rand = self BotGetRandom(); for ( ;; ) { wait( randomintrange( 3, 5 ) ); - + if ( self.bot_lock_goal ) { continue; } - if (self IsPlanting() || self isDefusing()) + if ( self IsPlanting() || self isDefusing() ) continue; - - // bomb not planted, lets protect our sites - if(!level.bombPlanted) - { - timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - - if(timeleft >= 90) - continue; - - // 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()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_get_obj(bomb); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - } - - // pick a site to protect - if(!isDefined(level.bombZones) || !level.bombZones.size) - continue; - - sites = []; - for(i = 0; i < level.bombZones.size; i++) - { - sites[sites.size] = level.bombZones[i]; - } - - if(!sites.size) - continue; - - if (rand > 50) - site = self bot_array_nearest_curorigin(sites); - else - site = random(sites); - - if(!isDefined(site)) - continue; - - origin = ( site.curorigin[0]+50, site.curorigin[1]+50, site.curorigin[2]+5 ); - - if(site isInUse())//somebody is planting - { - 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; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - 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; - continue; - } - - // bomb is planted, we need to defuse - if(!isDefined(level.defuseObject)) - continue; - - 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()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - self thread bot_go_defuse(defuse); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // lets 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; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(defuse); - wait 1; - self ClearScriptGoal(); - self.bot_lock_goal = false; + 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.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\_globallogic::getTimeRemaining() / 1000; + timepassed = maps\mp\gametypes\_globallogic::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_use_bomb_thread( plant ); + wait 1; + + self ClearScriptGoal(); + self.bot_lock_goal = false; + + self BotNotifyBotEvent( "sd", "stop", "plant", plant ); +} + /* Bots play sd attackers */ @@ -3616,187 +4292,20 @@ bot_sd_attackers() { self endon( "death" ); self endon( "disconnect" ); - level endon("game_ended"); + level endon( "game_ended" ); if ( level.gametype != "sd" ) return; - myTeam = self.pers[ "team" ]; - otherTeam = getOtherTeam( myTeam ); - - if(myTeam != game["attackers"]) + if ( self.team != game["attackers"] ) return; - rand = self BotGetRandom(); - - first = true; + data = spawnStruct(); + data.rand = self BotGetRandom(); + data.first = true; for ( ;; ) { - if(first) - first = false; - else - wait( randomintrange( 3, 5 ) ); - - if ( self.bot_lock_goal ) - { - continue; - } - - //bomb planted - if(level.bombPlanted) - { - if(!isDefined(level.defuseObject)) - continue; - - site = level.defuseObject; - - origin = ( site.curorigin[0], site.curorigin[1], site.curorigin[2]+5 ); - - if(site IsInUse())//somebody is defusing - { - 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; - continue; - } - - //else hang around the site - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - 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; - continue; - } - - timeleft = maps\mp\gametypes\_globallogic::getTimeRemaining()/1000; - timepassed = maps\mp\gametypes\_globallogic::getTimePassed()/1000; - - //dont have a bomb - if(!self IsBombCarrier() && !level.multiBomb) - { - if(!isDefined(level.sdBomb)) - continue; - - bomb = level.sdBomb; - carrier = level.sdBomb.carrier; - - //bomb is picked up - if(isDefined(carrier)) - { - //escort the bomb carrier - if(self HasScriptGoal()) - continue; - - origin = carrier.origin; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - 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(); - continue; - } - - 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()) - continue; - - if(DistanceSquared(origin, self.origin) <= 1024*1024) - continue; - - self SetScriptGoal( origin, 256 ); - - self thread bot_get_obj(bomb); - - if (self waittill_any_return( "goal", "bad_path", "new_goal" ) != "new_goal") - self ClearScriptGoal(); - continue; - } - - // go get the 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; - continue; - } - - // check if to plant - if(timepassed < 120 && timeleft >= 90 && randomInt(100) < 98) - continue; - - if(!isDefined(level.bombZones) || !level.bombZones.size) - continue; - - sites = []; - for(i = 0; i < level.bombZones.size; i++) - { - sites[sites.size] = level.bombZones[i]; - } - - if(!sites.size) - continue; - - if(rand > 50) - plant = self bot_array_nearest_curorigin(sites); - else - plant = random(sites); - - if(!isDefined(plant)) - continue; - - origin = ( plant.curorigin[0]+50, plant.curorigin[1]+50, plant.curorigin[2]+5 ); - - 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; - continue; - } - - self SetScriptGoal( self.origin, 64 ); - - self bot_use_bomb_thread(plant); - wait 1; - - self ClearScriptGoal(); - self.bot_lock_goal = false; + self bot_sd_attackers_loop( data ); } } diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_utility.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_utility.gsc index c16c195..e85c995 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_utility.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_bot_utility.gsc @@ -7,7 +7,7 @@ */ is_host() { - return (isDefined(self.pers["bot_host"]) && self.pers["bot_host"]); + return ( isDefined( self.pers["bot_host"] ) && self.pers["bot_host"] ); } /* @@ -17,36 +17,38 @@ doHostCheck() { self.pers["bot_host"] = false; - if (self is_bot()) + if ( self is_bot() ) return; result = false; - if (getDvar("bots_main_firstIsHost") != "0") + + if ( getDvar( "bots_main_firstIsHost" ) != "0" ) { - printToConsole("WARNING: bots_main_firstIsHost is enabled"); - - if (getDvar("bots_main_firstIsHost") == "1") + printToConsole( "WARNING: bots_main_firstIsHost is enabled" ); + + if ( getDvar( "bots_main_firstIsHost" ) == "1" ) { - setDvar("bots_main_firstIsHost", self getguid()); + setDvar( "bots_main_firstIsHost", self getguid() ); } - if (getDvar("bots_main_firstIsHost") == self getguid()+"") + if ( getDvar( "bots_main_firstIsHost" ) == self getguid() + "" ) result = true; } - DvarGUID = getDvar("bots_main_GUIDs"); - if (DvarGUID != "") - { - guids = strtok(DvarGUID, ","); + DvarGUID = getDvar( "bots_main_GUIDs" ); - for (i = 0; i < guids.size; i++) + if ( DvarGUID != "" ) + { + guids = strtok( DvarGUID, "," ); + + for ( i = 0; i < guids.size; i++ ) { - if(self getguid()+"" == guids[i]) + if ( self getguid() + "" == guids[i] ) result = true; } } - - if (!result) + + if ( !result ) return; self.pers["bot_host"] = true; @@ -60,44 +62,73 @@ is_bot() return self.isbot; } +/* + Set the bot's stance +*/ +BotSetStance( stance ) +{ + switch ( stance ) + { + case "stand": + self maps\mp\bots\_bot_internal::stand(); + break; + + case "crouch": + self maps\mp\bots\_bot_internal::crouch(); + break; + + case "prone": + self maps\mp\bots\_bot_internal::prone(); + break; + } +} + /* Bot changes to the weap */ -BotChangeToWeapon(weap) +BotChangeToWeapon( weap ) { - self maps\mp\bots\_bot_internal::changeToWeap(weap); + self maps\mp\bots\_bot_internal::changeToWeap( weap ); } /* Bot presses the button for time. */ -BotPressAttack(time) +BotPressAttack( time ) { - self maps\mp\bots\_bot_internal::pressFire(time); + self maps\mp\bots\_bot_internal::pressFire( time ); } /* Bot presses the ads button for time. */ -BotPressADS(time) +BotPressADS( time ) { - self maps\mp\bots\_bot_internal::pressADS(time); + self maps\mp\bots\_bot_internal::pressADS( time ); +} + +/* + Bot presses the use button for time. +*/ +BotPressUse( time ) +{ + self maps\mp\bots\_bot_internal::use( time ); } /* Bot presses the frag button for time. */ -BotPressFrag(time) +BotPressFrag( time ) { - self maps\mp\bots\_bot_internal::frag(time); + self maps\mp\bots\_bot_internal::frag( time ); } /* Bot presses the smoke button for time. */ -BotPressSmoke(time) +BotPressSmoke( time ) { - self maps\mp\bots\_bot_internal::smoke(time); + self maps\mp\bots\_bot_internal::smoke( time ); } /* @@ -113,7 +144,7 @@ BotGetRandom() */ BotGetTargetRandom() { - if (!isDefined(self.bot.target)) + if ( !isDefined( self.bot.target ) ) return undefined; return self.bot.target.rand; @@ -164,17 +195,18 @@ IsBotKnifing() */ IsPlayerModelOK() { - return (isDefined(self.bot_model_fix)); + return ( isDefined( self.bot_model_fix ) ); } /* Freezes the bot's controls. */ -BotFreezeControls(what) +BotFreezeControls( what ) { self.bot.isfrozen = what; - if(what) - self notify("kill_goal"); + + if ( what ) + self notify( "kill_goal" ); } /* @@ -188,12 +220,20 @@ BotIsFrozen() /* Bot will stop moving */ -BotStopMoving(what) +BotStopMoving( what ) { self.bot.stop_move = what; - if(what) - self notify("kill_goal"); + if ( what ) + self notify( "kill_goal" ); +} + +/* + Notify the bot chat message +*/ +BotNotifyBotEvent( msg, a, b, c, d, e, f, g ) +{ + self notify( "bot_event", msg, a, b, c, d, e, f, g ); } /* @@ -202,7 +242,7 @@ BotStopMoving(what) */ HasScriptGoal() { - return (isDefined(self GetScriptGoal())); + return ( isDefined( self GetScriptGoal() ) ); } /* @@ -216,15 +256,16 @@ GetScriptGoal() /* Sets the bot's goal, will acheive it when dist away from it. */ -SetScriptGoal(goal, dist) +SetScriptGoal( goal, dist ) { - if (!isDefined(dist)) + if ( !isDefined( dist ) ) dist = 16; + self.bot.script_goal = goal; self.bot.script_goal_dist = dist; waittillframeend; - self notify("new_goal_internal"); - self notify("new_goal"); + self notify( "new_goal_internal" ); + self notify( "new_goal" ); } /* @@ -232,13 +273,13 @@ SetScriptGoal(goal, dist) */ ClearScriptGoal() { - self SetScriptGoal(undefined, 0); + self SetScriptGoal( undefined, 0 ); } /* Sets the aim position of the bot */ -SetScriptAimPos(pos) +SetScriptAimPos( pos ) { self.bot.script_aimpos = pos; } @@ -248,7 +289,7 @@ SetScriptAimPos(pos) */ ClearScriptAimPos() { - self SetScriptAimPos(undefined); + self SetScriptAimPos( undefined ); } /* @@ -264,13 +305,13 @@ GetScriptAimPos() */ HasScriptAimPos() { - return isDefined(self GetScriptAimPos()); + return isDefined( self GetScriptAimPos() ); } /* Sets the bot's target to be this ent. */ -SetAttacker(att) +SetAttacker( att ) { self.bot.target_this_frame = att; } @@ -278,7 +319,7 @@ SetAttacker(att) /* Sets the script enemy for a bot. */ -SetScriptEnemy(enemy, offset) +SetScriptEnemy( enemy, offset ) { self.bot.script_target = enemy; self.bot.script_target_offset = offset; @@ -289,7 +330,7 @@ SetScriptEnemy(enemy, offset) */ ClearScriptEnemy() { - self SetScriptEnemy(undefined, undefined); + self SetScriptEnemy( undefined, undefined ); } /* @@ -297,9 +338,9 @@ ClearScriptEnemy() */ GetThreat() { - if(!isdefined(self.bot.target)) + if ( !isdefined( self.bot.target ) ) return undefined; - + return self.bot.target.entity; } @@ -308,7 +349,7 @@ GetThreat() */ HasScriptEnemy() { - return (isDefined(self.bot.script_target)); + return ( isDefined( self.bot.script_target ) ); } /* @@ -316,7 +357,7 @@ HasScriptEnemy() */ HasThreat() { - return (isDefined(self GetThreat())); + return ( isDefined( self GetThreat() ) ); } /* @@ -324,7 +365,7 @@ HasThreat() */ IsDefusing() { - return (isDefined(self.isDefusing) && self.isDefusing); + return ( isDefined( self.isDefusing ) && self.isDefusing ); } /* @@ -332,7 +373,7 @@ IsDefusing() */ isPlanting() { - return (isDefined(self.isPlanting) && self.isPlanting); + return ( isDefined( self.isPlanting ) && self.isPlanting ); } /* @@ -340,7 +381,7 @@ isPlanting() */ inLastStand() { - return (isDefined(self.lastStand) && self.lastStand); + return ( isDefined( self.lastStand ) && self.lastStand ); } /* @@ -348,7 +389,7 @@ inLastStand() */ isBombCarrier() { - return (isDefined(self.isBombCarrier) && self.isBombCarrier); + return ( isDefined( self.isBombCarrier ) && self.isBombCarrier ); } /* @@ -356,7 +397,7 @@ isBombCarrier() */ isInUse() { - return (isDefined(self.inUse) && self.inUse); + return ( isDefined( self.inUse ) && self.inUse ); } /* @@ -364,15 +405,15 @@ isInUse() */ IsStunned() { - return (isdefined(self.concussionEndTime) && self.concussionEndTime > gettime()); + return ( isdefined( self.concussionEndTime ) && self.concussionEndTime > gettime() ); } /* - Returns if we are beingArtilleryShellshocked + Returns if we are beingArtilleryShellshocked */ isArtShocked() { - return (isDefined(self.beingArtilleryShellshocked) && self.beingArtilleryShellshocked); + return ( isDefined( self.beingArtilleryShellshocked ) && self.beingArtilleryShellshocked ); } /* @@ -382,14 +423,14 @@ getValidTube() { weaps = self getweaponslist(); - for (i = 0; i < weaps.size; i++) + for ( i = 0; i < weaps.size; i++ ) { weap = weaps[i]; - if(!self getAmmoCount(weap)) + if ( !self getAmmoCount( weap ) ) continue; - if (isSubStr(weap, "gl_") && !isSubStr(weap, "_gl_")) + if ( isSubStr( weap, "gl_" ) && !isSubStr( weap, "_gl_" ) ) return weap; } @@ -406,31 +447,54 @@ getValidGrenade() grenadeTypes[grenadeTypes.size] = "smoke_grenade_mp"; grenadeTypes[grenadeTypes.size] = "flash_grenade_mp"; grenadeTypes[grenadeTypes.size] = "concussion_grenade_mp"; - + possibles = []; - - for(i = 0; i < grenadeTypes.size; i++) + + for ( i = 0; i < grenadeTypes.size; i++ ) { if ( !self hasWeapon( grenadeTypes[i] ) ) continue; - + if ( !self getAmmoCount( grenadeTypes[i] ) ) continue; - + possibles[possibles.size] = grenadeTypes[i]; } - - return random(possibles); + + return random( possibles ); +} + +/* + CoD4 meme +*/ +getWinningTeam() +{ + if ( maps\mp\gametypes\_globallogic::getGameScore( "allies" ) == maps\mp\gametypes\_globallogic::getGameScore( "axis" ) ) + winner = "tie"; + else if ( maps\mp\gametypes\_globallogic::getGameScore( "allies" ) > maps\mp\gametypes\_globallogic::getGameScore( "axis" ) ) + winner = "allies"; + else + winner = "axis"; + + return winner; +} + +/* + CoD4 +*/ +getBaseWeaponName( weap ) +{ + return strtok( weap, "_" )[0]; } /* Returns if the given weapon is full auto. */ -WeaponIsFullAuto(weap) +WeaponIsFullAuto( weap ) { - weaptoks = strtok(weap, "_"); - - return isDefined(weaptoks[0]) && isString(weaptoks[0]) && isdefined(level.bots_fullautoguns[weaptoks[0]]); + weaptoks = strtok( weap, "_" ); + + return isDefined( weaptoks[0] ) && isString( weaptoks[0] ) && isdefined( level.bots_fullautoguns[weaptoks[0]] ); } /* @@ -439,7 +503,7 @@ WeaponIsFullAuto(weap) GetEyeHeight() { myEye = self GetEyePos(); - + return myEye[2] - self.origin[2]; } @@ -448,16 +512,53 @@ GetEyeHeight() */ GetEyePos() { - return self getTagOrigin("tag_eye"); + return self getTagOrigin( "tag_eye" ); +} + +/* + helper +*/ +waittill_either_return_( str1, str2 ) +{ + self endon( str1 ); + self waittill( str2 ); + return true; +} + +/* + Returns which string gets notified first +*/ +waittill_either_return( str1, str2 ) +{ + if ( !isDefined( self waittill_either_return_( str1, str2 ) ) ) + return str1; + + return str2; } /* Waits until either of the nots. */ -waittill_either(not, not1) +waittill_either( not, not1 ) { - self endon(not); - self waittill(not1); + self endon( not ); + self waittill( not1 ); +} + +/* + iw5 +*/ +allowClassChoice() +{ + return true; +} + +/* + iw5 +*/ +allowTeamChoice() +{ + return true; } /* @@ -466,10 +567,10 @@ waittill_either(not, not1) waittill_any_timeout( timeOut, string1, string2, string3, string4, string5 ) { if ( ( !isdefined( string1 ) || string1 != "death" ) && - ( !isdefined( string2 ) || string2 != "death" ) && - ( !isdefined( string3 ) || string3 != "death" ) && - ( !isdefined( string4 ) || string4 != "death" ) && - ( !isdefined( string5 ) || string5 != "death" ) ) + ( !isdefined( string2 ) || string2 != "death" ) && + ( !isdefined( string3 ) || string3 != "death" ) && + ( !isdefined( string4 ) || string4 != "death" ) && + ( !isdefined( string5 ) || string5 != "death" ) ) self endon( "death" ); ent = spawnstruct(); @@ -510,108 +611,157 @@ _timeout( delay ) /* Returns if we have the create a class object unlocked. */ -isItemUnlocked(what, lvl) +isItemUnlocked( what, lvl ) { - switch(what) + switch ( what ) { case "ak47": return true; + case "ak74u": - return (lvl >= 28); + return ( lvl >= 28 ); + case "barrett": - return (lvl >= 49); + return ( lvl >= 49 ); + case "dragunov": - return (lvl >= 22); + return ( lvl >= 22 ); + case "g3": - return (lvl >= 25); + return ( lvl >= 25 ); + case "g36c": - return (lvl >= 37); + return ( lvl >= 37 ); + case "m1014": - return (lvl >= 31); + return ( lvl >= 31 ); + case "m14": - return (lvl >= 46); + return ( lvl >= 46 ); + case "m16": return true; + case "m21": - return (lvl >= 7); + return ( lvl >= 7 ); + case "m4": - return (lvl >= 10); + return ( lvl >= 10 ); + case "m40a3": return true; + case "m60e4": - return (lvl >= 19); + return ( lvl >= 19 ); + case "mp44": - return (lvl >= 52); + return ( lvl >= 52 ); + case "mp5": return true; + case "p90": - return (lvl >= 40); + return ( lvl >= 40 ); + case "rpd": return true; + case "saw": return true; + case "skorpion": return true; + case "uzi": - return (lvl >= 13); + return ( lvl >= 13 ); + case "winchester1200": return true; + case "remington700": - return (lvl >= 34); + return ( lvl >= 34 ); + case "beretta": return true; + case "colt45": - return (lvl >= 16); + return ( lvl >= 16 ); + case "deserteagle": - return (lvl >= 43); + return ( lvl >= 43 ); + case "deserteaglegold": - return (lvl >= 55); + return ( lvl >= 55 ); + case "usp": return true; + case "specialty_bulletdamage": return true; + case "specialty_armorvest": return true; + case "specialty_fastreload": - return (lvl >= 20); + return ( lvl >= 20 ); + case "specialty_rof": - return (lvl >= 29); + return ( lvl >= 29 ); + case "specialty_twoprimaries": - return (lvl >= 38); + return ( lvl >= 38 ); + case "specialty_gpsjammer": - return (lvl >= 11); + return ( lvl >= 11 ); + case "specialty_explosivedamage": return true; + case "specialty_longersprint": return true; + case "specialty_bulletaccuracy": return true; + case "specialty_pistoldeath": - return (lvl >= 8); + return ( lvl >= 8 ); + case "specialty_grenadepulldeath": - return (lvl >= 17); + return ( lvl >= 17 ); + case "specialty_bulletpenetration": return true; + case "specialty_holdbreath": - return (lvl >= 26); + return ( lvl >= 26 ); + case "specialty_quieter": - return (lvl >= 44); + return ( lvl >= 44 ); + case "specialty_parabolic": - return (lvl >= 35); + return ( lvl >= 35 ); + case "specialty_specialgrenade": return true; + case "specialty_weapon_rpg": return true; + case "specialty_weapon_claymore": - return (lvl >= 23); + return ( lvl >= 23 ); + case "specialty_fraggrenade": - return (lvl >= 41); + return ( lvl >= 41 ); + case "specialty_extraammo": - return (lvl >= 32); + return ( lvl >= 32 ); + case "specialty_detectexplosive": - return (lvl >= 14); + return ( lvl >= 14 ); + case "specialty_weapon_c4": return true; + default: return true; } @@ -620,21 +770,22 @@ isItemUnlocked(what, lvl) /* If the weapon is allowed to be dropped */ -isWeaponDroppable(weap) +isWeaponDroppable( weap ) { - return (maps\mp\gametypes\_weapons::mayDropWeapon(weap)); + return ( maps\mp\gametypes\_weapons::mayDropWeapon( weap ) ); } /* Selects a random element from the array. */ -Random(arr) +Random( arr ) { size = arr.size; - if(!size) + + if ( !size ) return undefined; - - return arr[randomInt(size)]; + + return arr[randomInt( size )]; } /* @@ -643,10 +794,11 @@ Random(arr) array_remove( ents, remover ) { newents = []; - for(i = 0; i < ents.size; i++) + + for ( i = 0; i < ents.size; i++ ) { index = ents[i]; - + if ( index != remover ) newents[ newents.size ] = index; } @@ -657,9 +809,9 @@ array_remove( ents, remover ) /* Waits until not or tim. */ -waittill_notify_or_timeout(not, tim) +waittill_notify_or_timeout( not, tim ) { - self endon(not); + self endon( not ); wait tim; } @@ -668,11 +820,11 @@ waittill_notify_or_timeout(not, tim) */ GetHostPlayer() { - for (i = 0; i < level.players.size; i++) + for ( i = 0; i < level.players.size; i++ ) { player = level.players[i]; - if (!player is_host()) + if ( !player is_host() ) continue; return player; @@ -682,44 +834,44 @@ GetHostPlayer() } /* - Waits for a host player + Waits for a host player */ bot_wait_for_host() { host = undefined; - while (!isDefined(level) || !isDefined(level.players)) + while ( !isDefined( level ) || !isDefined( level.players ) ) wait 0.05; - - for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05) + + for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 ) { host = GetHostPlayer(); - - if(isDefined(host)) + + if ( isDefined( host ) ) break; - - wait 0.05; - } - - if(!isDefined(host)) - return; - - for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05) - { - if(IsDefined( host.pers[ "team" ] )) - break; - + wait 0.05; } - if(!IsDefined( host.pers[ "team" ] )) + if ( !isDefined( host ) ) return; - - for(i = getDvarFloat("bots_main_waitForHostTime"); i > 0; i -= 0.05) + + for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 ) { - if(host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis") + if ( IsDefined( host.pers[ "team" ] ) ) break; - + + wait 0.05; + } + + if ( !IsDefined( host.pers[ "team" ] ) ) + return; + + for ( i = getDvarFloat( "bots_main_waitForHostTime" ); i > 0; i -= 0.05 ) + { + if ( host.pers[ "team" ] == "allies" || host.pers[ "team" ] == "axis" ) + break; + wait 0.05; } } @@ -728,46 +880,47 @@ bot_wait_for_host() Pezbot's line sphere intersection. http://paulbourke.net/geometry/circlesphere/raysphere.c */ -RaySphereIntersect(start, end, spherePos, radius) +RaySphereIntersect( start, end, spherePos, radius ) { // check if the start or end points are in the sphere r2 = radius * radius; - if (DistanceSquared(start, spherePos) < r2) + + if ( DistanceSquared( start, spherePos ) < r2 ) return true; - if (DistanceSquared(end, spherePos) < r2) + if ( DistanceSquared( end, spherePos ) < r2 ) return true; // check if the line made by start and end intersect the sphere dp = end - start; a = dp[0] * dp[0] + dp[1] * dp[1] + dp[2] * dp[2]; - b = 2 * (dp[0] * (start[0] - spherePos[0]) + dp[1] * (start[1] - spherePos[1]) + dp[2] * (start[2] - spherePos[2])); + b = 2 * ( dp[0] * ( start[0] - spherePos[0] ) + dp[1] * ( start[1] - spherePos[1] ) + dp[2] * ( start[2] - spherePos[2] ) ); c = spherePos[0] * spherePos[0] + spherePos[1] * spherePos[1] + spherePos[2] * spherePos[2]; c += start[0] * start[0] + start[1] * start[1] + start[2] * start[2]; - c -= 2.0 * (spherePos[0] * start[0] + spherePos[1] * start[1] + spherePos[2] * start[2]); + c -= 2.0 * ( spherePos[0] * start[0] + spherePos[1] * start[1] + spherePos[2] * start[2] ); c -= radius * radius; bb4ac = b * b - 4.0 * a * c; - if (abs(a) < 0.0001 || bb4ac < 0) + if ( abs( a ) < 0.0001 || bb4ac < 0 ) return false; - mu1 = (0-b + sqrt(bb4ac)) / (2 * a); + mu1 = ( 0 - b + sqrt( bb4ac ) ) / ( 2 * a ); //mu2 = (0-b - sqrt(bb4ac)) / (2 * a); // intersection points of the sphere ip1 = start + mu1 * dp; //ip2 = start + mu2 * dp; - myDist = DistanceSquared(start, end); + myDist = DistanceSquared( start, end ); // check if both intersection points far - if (DistanceSquared(start, ip1) > myDist/* && DistanceSquared(start, ip2) > myDist*/) + if ( DistanceSquared( start, ip1 ) > myDist/* && DistanceSquared(start, ip2) > myDist*/ ) return false; - dpAngles = VectorToAngles(dp); + dpAngles = VectorToAngles( dp ); // check if the point is behind us - if (getConeDot(ip1, start, dpAngles) < 0/* || getConeDot(ip2, start, dpAngles) < 0*/) + if ( getConeDot( ip1, start, dpAngles ) < 0/* || getConeDot(ip2, start, dpAngles) < 0*/ ) return false; return true; @@ -776,55 +929,55 @@ RaySphereIntersect(start, end, spherePos, radius) /* Returns if a smoke grenade would intersect start to end line. */ -SmokeTrace(start, end, rad) +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]; - - if(nade.state != "smoking") + + if ( nade.state != "smoking" ) continue; - - if(!RaySphereIntersect(start, end, nade.origin, rad)) + + if ( !RaySphereIntersect( start, end, nade.origin, rad ) ) continue; - + return false; } - + return true; } /* Returns the cone dot (like fov, or distance from the center of our screen). 1.0 = directly looking at, 0.0 = completely right angle, -1.0, completely 180 */ -getConeDot(to, from, dir) +getConeDot( to, from, dir ) { - dirToTarget = VectorNormalize(to-from); - forward = AnglesToForward(dir); - return vectordot(dirToTarget, forward); + dirToTarget = VectorNormalize( to - from ); + forward = AnglesToForward( dir ); + return vectordot( dirToTarget, forward ); } /* Returns the distance squared in a 2d space */ -DistanceSquared2D(to, from) +DistanceSquared2D( to, from ) { - to = (to[0], to[1], 0); - from = (from[0], from[1], 0); - - return DistanceSquared(to, from); + to = ( to[0], to[1], 0 ); + from = ( from[0], from[1], 0 ); + + return DistanceSquared( to, from ); } /* Rounds to the nearest whole number. */ -Round(x) +Round( x ) { - y = int(x); - - if(abs(x) - abs(y) > 0.5) + y = int( x ); + + if ( abs( x ) - abs( y ) > 0.5 ) { - if(x < 0) + if ( x < 0 ) return y - 1; else return y + 1; @@ -834,54 +987,149 @@ Round(x) } /* - Rounds up the given value. + clamps angle between -180 and 180 */ -RoundUp( floatVal ) +AngleClamp180( angle ) { - i = int( floatVal ); - if ( i != floatVal ) - return i + 1; - else - return i; + angleFrac = angle / 360.0; + angle = ( angleFrac - floor( angleFrac ) ) * 360.0; + + if ( angle > 180.0 ) + return angle - 360.0; + + return angle; +} + +/* + Clamps between value +*/ +Clamp( a, minv, maxv ) +{ + return max( min( a, maxv ), minv ); } /* Matches a num to a char */ -keyCodeToString(a) +keyCodeToString( a ) { - b=""; - switch(a) + b = ""; + + switch ( a ) { - case 0: b= "a"; break; - case 1: b= "b"; break; - case 2: b= "c"; break; - case 3: b= "d"; break; - case 4: b= "e"; break; - case 5: b= "f"; break; - case 6: b= "g"; break; - case 7: b= "h"; break; - case 8: b= "i"; break; - case 9: b= "j"; break; - case 10: b= "k"; break; - case 11: b= "l"; break; - case 12: b= "m"; break; - case 13: b= "n"; break; - case 14: b= "o"; break; - case 15: b= "p"; break; - case 16: b= "q"; break; - case 17: b= "r"; break; - case 18: b= "s"; break; - case 19: b= "t"; break; - case 20: b= "u"; break; - case 21: b= "v"; break; - case 22: b= "w"; break; - case 23: b= "x"; break; - case 24: b= "y"; break; - case 25: b= "z"; break; - case 26: b= "."; break; - case 27: b= " "; break; + case 0: + b = "a"; + break; + + case 1: + b = "b"; + break; + + case 2: + b = "c"; + break; + + case 3: + b = "d"; + break; + + case 4: + b = "e"; + break; + + case 5: + b = "f"; + break; + + case 6: + b = "g"; + break; + + case 7: + b = "h"; + break; + + case 8: + b = "i"; + break; + + case 9: + b = "j"; + break; + + case 10: + b = "k"; + break; + + case 11: + b = "l"; + break; + + case 12: + b = "m"; + break; + + case 13: + b = "n"; + break; + + case 14: + b = "o"; + break; + + case 15: + b = "p"; + break; + + case 16: + b = "q"; + break; + + case 17: + b = "r"; + break; + + case 18: + b = "s"; + break; + + case 19: + b = "t"; + break; + + case 20: + b = "u"; + break; + + case 21: + b = "v"; + break; + + case 22: + b = "w"; + break; + + case 23: + b = "x"; + break; + + case 24: + b = "y"; + break; + + case 25: + b = "z"; + break; + + case 26: + b = "."; + break; + + case 27: + b = " "; + break; } + return b; } @@ -891,42 +1139,47 @@ keyCodeToString(a) cac_init_patch() { // oldschool mode does not create these, we need those tho. - if(!isDefined(level.tbl_weaponIDs)) + if ( !isDefined( level.tbl_weaponIDs ) ) { level.tbl_weaponIDs = []; - for( i=0; i<150; i++ ) + + for ( i = 0; i < 150; i++ ) { reference_s = tableLookup( "mp/statsTable.csv", 0, i, 4 ); - if( reference_s != "" ) - { + + if ( reference_s != "" ) + { level.tbl_weaponIDs[i]["reference"] = reference_s; level.tbl_weaponIDs[i]["group"] = tablelookup( "mp/statstable.csv", 0, i, 2 ); level.tbl_weaponIDs[i]["count"] = int( tablelookup( "mp/statstable.csv", 0, i, 5 ) ); - level.tbl_weaponIDs[i]["attachment"] = tablelookup( "mp/statstable.csv", 0, i, 8 ); + level.tbl_weaponIDs[i]["attachment"] = tablelookup( "mp/statstable.csv", 0, i, 8 ); } else continue; } } - - if(!isDefined(level.tbl_WeaponAttachment)) + + if ( !isDefined( level.tbl_WeaponAttachment ) ) { level.tbl_WeaponAttachment = []; - for( i=0; i<8; i++ ) + + for ( i = 0; i < 8; i++ ) { level.tbl_WeaponAttachment[i]["bitmask"] = int( tableLookup( "mp/attachmentTable.csv", 9, i, 10 ) ); level.tbl_WeaponAttachment[i]["reference"] = tableLookup( "mp/attachmentTable.csv", 9, i, 4 ); } } - - if(!isDefined(level.tbl_PerkData)) + + if ( !isDefined( level.tbl_PerkData ) ) { level.tbl_PerkData = []; + // generating perk data vars collected form statsTable.csv - for( i=150; i<194; i++ ) + for ( i = 150; i < 194; i++ ) { reference_s = tableLookup( "mp/statsTable.csv", 0, i, 4 ); - if( reference_s != "" ) + + if ( reference_s != "" ) { level.tbl_PerkData[i]["reference"] = reference_s; level.tbl_PerkData[i]["reference_full"] = tableLookup( "mp/statsTable.csv", 0, i, 6 ); @@ -943,45 +1196,85 @@ cac_init_patch() level.perkReferenceToIndex = []; level.weaponReferenceToIndex = []; level.weaponAttachmentReferenceToIndex = []; - - for( i=0; i<150; i++ ) + + for ( i = 0; i < 150; i++ ) { - if(!isDefined(level.tbl_weaponIDs[i]) || !isDefined(level.tbl_weaponIDs[i]["reference"])) + if ( !isDefined( level.tbl_weaponIDs[i] ) || !isDefined( level.tbl_weaponIDs[i]["reference"] ) ) continue; - + level.weaponReferenceToIndex[level.tbl_weaponIDs[i]["reference"]] = i; } - - for( i=0; i<8; i++ ) + + for ( i = 0; i < 8; i++ ) { - if(!isDefined(level.tbl_WeaponAttachment[i]) || !isDefined(level.tbl_WeaponAttachment[i]["reference"])) + if ( !isDefined( level.tbl_WeaponAttachment[i] ) || !isDefined( level.tbl_WeaponAttachment[i]["reference"] ) ) continue; - + level.weaponAttachmentReferenceToIndex[level.tbl_WeaponAttachment[i]["reference"]] = i; } - - for( i=150; i<194; i++ ) + + for ( i = 150; i < 194; i++ ) { - if(!isDefined(level.tbl_PerkData[i]) || !isDefined(level.tbl_PerkData[i]["reference_full"])) + if ( !isDefined( level.tbl_PerkData[i] ) || !isDefined( level.tbl_PerkData[i]["reference_full"] ) ) continue; - + level.perkReferenceToIndex[ level.tbl_PerkData[i]["reference_full"] ] = i; } } +/* + Parse frontlines type waypoints +*/ +FrontLinesWaypoints() +{ + waypoints = []; + + for ( i = 0;; i++ ) + { + dvar_answer = getDvar( "flwp_" + i ); + + if ( dvar_answer == "" || dvar_answer == "eof" ) + break; + + toks = strtok( dvar_answer, "," ); + + waypoint = spawnStruct(); + wp_num = int( toks[0] ); + x = float( toks[1] ); + y = float( toks[2] ); + z = float( toks[3] ); + waypoint.origin = ( x, y, z ); + + waypoint.type = toks[4]; + waypoint.children = []; + + num_children = int( toks[5] ); + + for ( h = 0; h < num_children; h++ ) + { + waypoint.children[waypoint.children.size] = int( toks[6 + h] ); + } + + waypoints[wp_num] = waypoint; + } + + return waypoints; +} + /* Tokenizes a string (strtok has limits...) (only one char tok) */ -tokenizeLine(line, tok) +tokenizeLine( line, tok ) { tokens = []; token = ""; - for (i = 0; i < line.size; i++) + + for ( i = 0; i < line.size; i++ ) { c = line[i]; - if (c == tok) + if ( c == tok ) { tokens[tokens.size] = token; token = ""; @@ -990,6 +1283,7 @@ tokenizeLine(line, tok) token += c; } + tokens[tokens.size] = token; return tokens; @@ -998,29 +1292,30 @@ tokenizeLine(line, tok) /* Parses tokens into a waypoint obj */ -parseTokensIntoWaypoint(tokens) +parseTokensIntoWaypoint( tokens ) { waypoint = spawnStruct(); orgStr = tokens[0]; - orgToks = strtok(orgStr, " "); - waypoint.origin = (float(orgToks[0]), float(orgToks[1]), float(orgToks[2])); + orgToks = strtok( orgStr, " " ); + waypoint.origin = ( float( orgToks[0] ), float( orgToks[1] ), float( orgToks[2] ) ); childStr = tokens[1]; - childToks = strtok(childStr, " "); - waypoint.childCount = childToks.size; + childToks = strtok( childStr, " " ); waypoint.children = []; - for( j=0; j dist ) + continue; + + return true; + } + + return false; +} + +/* + Returns the waypoints that are near +*/ +waypointsNear( waypoints, dist ) +{ + dist *= dist; + + answer = []; + + for ( i = 0; i < waypoints.size; i++ ) + { + wp = level.waypoints[waypoints[i]]; + + if ( DistanceSquared( wp.origin, self.origin ) > dist ) + continue; + + answer[answer.size] = waypoints[i]; + } + + return answer; +} + +/* + Returns nearest waypoint of waypoints +*/ +getNearestWaypointOfWaypoints( waypoints ) +{ + answer = undefined; + closestDist = 2147483647; + + for ( i = 0; i < waypoints.size; i++ ) + { + waypoint = level.waypoints[waypoints[i]]; + thisDist = DistanceSquared( self.origin, waypoint.origin ); + + if ( isDefined( answer ) && thisDist > closestDist ) + continue; + + answer = waypoints[i]; + closestDist = thisDist; + } + + return answer; +} + +/* + Returns all waypoints of type +*/ +getWaypointsOfType( type ) +{ + answer = []; + + for ( i = 0; i < level.waypointCount; i++ ) + { + wp = level.waypoints[i]; + + if ( type == "camp" ) + { + if ( wp.type != "crouch" ) + continue; + + if ( wp.children.size != 1 ) + continue; + } + else if ( type != wp.type ) + continue; + + answer[answer.size] = i; + } + + return answer; +} + +/* + Returns the waypoint for index +*/ +getWaypointForIndex( i ) +{ + if ( !isDefined( i ) ) + return undefined; + + return level.waypoints[i]; } /* @@ -1260,7 +1670,7 @@ load_waypoints() */ getGoodMapAmount() { - switch(getDvar("mapname")) + switch ( getDvar( "mapname" ) ) { case "mp_crash": case "mp_crash_snow": @@ -1277,82 +1687,102 @@ getGoodMapAmount() case "mp_backlot": case "mp_convoy": case "mp_bloc": - if(level.teamBased) + if ( level.teamBased ) return 14; else return 9; - + case "mp_vacant": case "mp_showdown": case "mp_citystreets": case "mp_bog": - if(level.teamBased) + if ( level.teamBased ) return 12; else return 8; - + case "mp_killhouse": case "mp_shipment": - if(level.teamBased) + if ( level.teamBased ) return 8; else return 4; } - + return 2; } /* Returns the friendly user name for a given map's codename */ -getMapName(map) +getMapName( map ) { - switch(map) + switch ( map ) { case "mp_convoy": return "Ambush"; + case "mp_backlot": return "Backlot"; + case "mp_bloc": return "Bloc"; + case "mp_bog": return "Bog"; + case "mp_countdown": return "Countdown"; + case "mp_crash": return "Crash"; + case "mp_crash_snow": return "Winter Crash"; + case "mp_crossfire": return "Crossfire"; + case "mp_citystreets": return "District"; + case "mp_farm": return "Downpour"; + case "mp_overgrown": return "Overgrown"; + case "mp_pipeline": return "Pipeline"; + case "mp_shipment": return "Shipment"; + case "mp_showdown": return "Showdown"; + case "mp_strike": return "Strike"; + case "mp_vacant": return "Vacant"; + case "mp_cargoship": return "Wetwork"; + case "mp_broadcast": return "Broadcast"; + case "mp_creek": return "Creek"; + case "mp_carentan": return "Chinatown"; + case "mp_killhouse": return "Killhouse"; } - + return map; } @@ -1371,16 +1801,17 @@ getBotArray() { result = []; playercount = level.players.size; - for(i = 0; i < playercount; i++) + + for ( i = 0; i < playercount; i++ ) { player = level.players[i]; - - if(!player is_bot()) + + if ( !player is_bot() ) continue; - + result[result.size] = player; } - + return result; } @@ -1390,64 +1821,68 @@ getBotArray() WaypointsToKDTree() { kdTree = KDTree(); - - kdTree _WaypointsToKDTree(level.waypoints, 0); - + + kdTree _WaypointsToKDTree( level.waypoints, 0 ); + return kdTree; } /* Recurive function. We construct a balanced KD tree by sorting the waypoints using heap sort. */ -_WaypointsToKDTree(waypoints, dem) +_WaypointsToKDTree( waypoints, dem ) { - if(!waypoints.size) + if ( !waypoints.size ) return; callbacksort = undefined; - - switch(dem) + + switch ( dem ) { case 0: callbacksort = ::HeapSortCoordX; - break; + break; + case 1: callbacksort = ::HeapSortCoordY; - break; + break; + case 2: callbacksort = ::HeapSortCoordZ; - break; + break; } - - heap = NewHeap(callbacksort); - - for(i = 0; i < waypoints.size; i++) + + heap = NewHeap( callbacksort ); + + for ( i = 0; i < waypoints.size; i++ ) { - heap HeapInsert(waypoints[i]); + heap HeapInsert( waypoints[i] ); } - + sorted = []; - while(heap.data.size) + + while ( heap.data.size ) { sorted[sorted.size] = heap.data[0]; heap HeapRemove(); } - - median = int(sorted.size/2);//use divide and conq - + + median = int( sorted.size / 2 ); //use divide and conq + left = []; right = []; - for(i = 0; i < sorted.size; i++) - if(i < median) + + for ( i = 0; i < sorted.size; i++ ) + if ( i < median ) right[right.size] = sorted[i]; - else if(i > median) + else if ( i > median ) left[left.size] = sorted[i]; - - self KDTreeInsert(sorted[median]); - - _WaypointsToKDTree(left, (dem+1)%3); - - _WaypointsToKDTree(right, (dem+1)%3); + + self KDTreeInsert( sorted[median] ); + + _WaypointsToKDTree( left, ( dem + 1 ) % 3 ); + + _WaypointsToKDTree( right, ( dem + 1 ) % 3 ); } /* @@ -1458,26 +1893,26 @@ List() list = spawnStruct(); list.count = 0; list.data = []; - + return list; } /* Adds a new thing to the list. */ -ListAdd(thing) +ListAdd( thing ) { self.data[self.count] = thing; - + self.count++; } /* Adds to the start of the list. */ -ListAddFirst(thing) +ListAddFirst( thing ) { - for (i = self.count - 1; i >= 0; i--) + for ( i = self.count - 1; i >= 0; i-- ) { self.data[i + 1] = self.data[i]; } @@ -1489,18 +1924,18 @@ ListAddFirst(thing) /* Removes the thing from the list. */ -ListRemove(thing) +ListRemove( thing ) { for ( i = 0; i < self.count; i++ ) { if ( self.data[i] == thing ) { - while ( i < self.count-1 ) + while ( i < self.count - 1 ) { - self.data[i] = self.data[i+1]; + self.data[i] = self.data[i + 1]; i++; } - + self.data[i] = undefined; self.count--; break; @@ -1516,24 +1951,24 @@ KDTree() kdTree = spawnStruct(); kdTree.root = undefined; kdTree.count = 0; - + return kdTree; } /* Called on a KDTree. Will insert the object into the KDTree. */ -KDTreeInsert(data)//as long as what you insert has a .origin attru, it will work. +KDTreeInsert( data ) //as long as what you insert has a .origin attru, it will work. { - self.root = self _KDTreeInsert(self.root, data, 0, -2147483647, -2147483647, -2147483647, 2147483647, 2147483647, 2147483647); + self.root = self _KDTreeInsert( self.root, data, 0, -2147483647, -2147483647, -2147483647, 2147483647, 2147483647, 2147483647 ); } /* Recurive function that insert the object into the KDTree. */ -_KDTreeInsert(node, data, dem, x0, y0, z0, x1, y1, z1) +_KDTreeInsert( node, data, dem, x0, y0, z0, x1, y1, z1 ) { - if(!isDefined(node)) + if ( !isDefined( node ) ) { r = spawnStruct(); r.data = data; @@ -1545,116 +1980,122 @@ _KDTreeInsert(node, data, dem, x0, y0, z0, x1, y1, z1) r.y1 = y1; r.z0 = z0; r.z1 = z1; - + self.count++; - + return r; } - - switch(dem) + + switch ( dem ) { case 0: - if(data.origin[0] < node.data.origin[0]) - node.left = self _KDTreeInsert(node.left, data, 1, x0, y0, z0, node.data.origin[0], y1, z1); + if ( data.origin[0] < node.data.origin[0] ) + node.left = self _KDTreeInsert( node.left, data, 1, x0, y0, z0, node.data.origin[0], y1, z1 ); else - node.right = self _KDTreeInsert(node.right, data, 1, node.data.origin[0], y0, z0, x1, y1, z1); - break; + node.right = self _KDTreeInsert( node.right, data, 1, node.data.origin[0], y0, z0, x1, y1, z1 ); + + break; + case 1: - if(data.origin[1] < node.data.origin[1]) - node.left = self _KDTreeInsert(node.left, data, 2, x0, y0, z0, x1, node.data.origin[1], z1); + if ( data.origin[1] < node.data.origin[1] ) + node.left = self _KDTreeInsert( node.left, data, 2, x0, y0, z0, x1, node.data.origin[1], z1 ); else - node.right = self _KDTreeInsert(node.right, data, 2, x0, node.data.origin[1], z0, x1, y1, z1); - break; + node.right = self _KDTreeInsert( node.right, data, 2, x0, node.data.origin[1], z0, x1, y1, z1 ); + + break; + case 2: - if(data.origin[2] < node.data.origin[2]) - node.left = self _KDTreeInsert(node.left, data, 0, x0, y0, z0, x1, y1, node.data.origin[2]); + if ( data.origin[2] < node.data.origin[2] ) + node.left = self _KDTreeInsert( node.left, data, 0, x0, y0, z0, x1, y1, node.data.origin[2] ); else - node.right = self _KDTreeInsert(node.right, data, 0, x0, y0, node.data.origin[2], x1, y1, z1); - break; + node.right = self _KDTreeInsert( node.right, data, 0, x0, y0, node.data.origin[2], x1, y1, z1 ); + + break; } - + return node; } /* Called on a KDTree, will return the nearest object to the given origin. */ -KDTreeNearest(origin) +KDTreeNearest( origin ) { - if(!isDefined(self.root)) + if ( !isDefined( self.root ) ) return undefined; - - return self _KDTreeNearest(self.root, origin, self.root.data, DistanceSquared(self.root.data.origin, origin), 0); + + return self _KDTreeNearest( self.root, origin, self.root.data, DistanceSquared( self.root.data.origin, origin ), 0 ); } /* Recurive function that will retrieve the closest object to the query. */ -_KDTreeNearest(node, point, closest, closestdist, dem) +_KDTreeNearest( node, point, closest, closestdist, dem ) { - if(!isDefined(node)) + if ( !isDefined( node ) ) { return closest; } - - thisDis = DistanceSquared(node.data.origin, point); - - if(thisDis < closestdist) + + thisDis = DistanceSquared( node.data.origin, point ); + + if ( thisDis < closestdist ) { closestdist = thisDis; closest = node.data; } - - if(node RectDistanceSquared(point) < closestdist) + + if ( node RectDistanceSquared( point ) < closestdist ) { near = node.left; far = node.right; - if(point[dem] > node.data.origin[dem]) + + if ( point[dem] > node.data.origin[dem] ) { near = node.right; far = node.left; } - - closest = self _KDTreeNearest(near, point, closest, closestdist, (dem+1)%3); - - closest = self _KDTreeNearest(far, point, closest, DistanceSquared(closest.origin, point), (dem+1)%3); + + closest = self _KDTreeNearest( near, point, closest, closestdist, ( dem + 1 ) % 3 ); + + closest = self _KDTreeNearest( far, point, closest, DistanceSquared( closest.origin, point ), ( dem + 1 ) % 3 ); } - + return closest; } /* Called on a rectangle, returns the distance from origin to the rectangle. */ -RectDistanceSquared(origin) +RectDistanceSquared( origin ) { dx = 0; dy = 0; dz = 0; - - if(origin[0] < self.x0) + + if ( origin[0] < self.x0 ) dx = origin[0] - self.x0; - else if(origin[0] > self.x1) + else if ( origin[0] > self.x1 ) dx = origin[0] - self.x1; - - if(origin[1] < self.y0) + + if ( origin[1] < self.y0 ) dy = origin[1] - self.y0; - else if(origin[1] > self.y1) + else if ( origin[1] > self.y1 ) dy = origin[1] - self.y1; - - if(origin[2] < self.z0) + + if ( origin[2] < self.z0 ) dz = origin[2] - self.z0; - else if(origin[2] > self.z1) + else if ( origin[2] > self.z1 ) dz = origin[2] - self.z1; - - return dx*dx + dy*dy + dz*dz; + + return dx * dx + dy * dy + dz * dz; } /* A heap invarient comparitor, used for objects, objects with a higher X coord will be first in the heap. */ -HeapSortCoordX(item, item2) +HeapSortCoordX( item, item2 ) { return item.origin[0] > item2.origin[0]; } @@ -1662,7 +2103,7 @@ HeapSortCoordX(item, item2) /* A heap invarient comparitor, used for objects, objects with a higher Y coord will be first in the heap. */ -HeapSortCoordY(item, item2) +HeapSortCoordY( item, item2 ) { return item.origin[1] > item2.origin[1]; } @@ -1670,7 +2111,7 @@ HeapSortCoordY(item, item2) /* A heap invarient comparitor, used for objects, objects with a higher Z coord will be first in the heap. */ -HeapSortCoordZ(item, item2) +HeapSortCoordZ( item, item2 ) { return item.origin[2] > item2.origin[2]; } @@ -1678,7 +2119,7 @@ HeapSortCoordZ(item, item2) /* A heap invarient comparitor, used for numbers, numbers with the highest number will be first in the heap. */ -Heap(item, item2) +Heap( item, item2 ) { return item > item2; } @@ -1686,7 +2127,7 @@ Heap(item, item2) /* A heap invarient comparitor, used for numbers, numbers with the lowest number will be first in the heap. */ -ReverseHeap(item, item2) +ReverseHeap( item, item2 ) { return item < item2; } @@ -1694,7 +2135,7 @@ ReverseHeap(item, item2) /* A heap invarient comparitor, used for traces. Wanting the trace with the largest length first in the heap. */ -HeapTraceFraction(item, item2) +HeapTraceFraction( item, item2 ) { return item["fraction"] > item2["fraction"]; } @@ -1702,53 +2143,53 @@ HeapTraceFraction(item, item2) /* Returns a new heap. */ -NewHeap(compare) +NewHeap( compare ) { heap_node = spawnStruct(); heap_node.data = []; heap_node.compare = compare; - + return heap_node; } /* Inserts the item into the heap. Called on a heap. */ -HeapInsert(item) +HeapInsert( item ) { insert = self.data.size; self.data[insert] = item; - - current = insert+1; - - while(current > 1) + + current = insert + 1; + + while ( current > 1 ) { last = current; - current = int(current/2); - - if(![[self.compare]](item, self.data[current-1])) + current = int( current / 2 ); + + if ( ![[self.compare]]( item, self.data[current - 1] ) ) break; - - self.data[last-1] = self.data[current-1]; - self.data[current-1] = item; + + self.data[last - 1] = self.data[current - 1]; + self.data[current - 1] = item; } } /* Helper function to determine what is the next child of the bst. */ -_HeapNextChild(node, hsize) +_HeapNextChild( node, hsize ) { left = node * 2; right = left + 1; - - if(left > hsize) + + if ( left > hsize ) return -1; - - if(right > hsize) + + if ( right > hsize ) return left; - - if([[self.compare]](self.data[left-1], self.data[right-1])) + + if ( [[self.compare]]( self.data[left - 1], self.data[right - 1] ) ) return left; else return right; @@ -1760,223 +2201,279 @@ _HeapNextChild(node, hsize) HeapRemove() { remove = self.data.size; - - if(!remove) + + if ( !remove ) return remove; - - move = self.data[remove-1]; + + move = self.data[remove - 1]; self.data[0] = move; - self.data[remove-1] = undefined; + self.data[remove - 1] = undefined; remove--; - - if(!remove) + + if ( !remove ) return remove; - + last = 1; - next = self _HeapNextChild(1, remove); - - while(next != -1) + next = self _HeapNextChild( 1, remove ); + + while ( next != -1 ) { - if([[self.compare]](move, self.data[next-1])) + if ( [[self.compare]]( move, self.data[next - 1] ) ) break; - - self.data[last-1] = self.data[next-1]; - self.data[next-1] = move; - + + self.data[last - 1] = self.data[next - 1]; + self.data[next - 1] = move; + last = next; - next = self _HeapNextChild(next, remove); + next = self _HeapNextChild( next, remove ); } - + return remove; } /* A heap invarient comparitor, used for the astar's nodes, wanting the node with the lowest f to be first in the heap. */ -ReverseHeapAStar(item, item2) +ReverseHeapAStar( item, item2 ) { return item.f < item2.f; } +/* + Removes the waypoint usage +*/ +RemoveWaypointUsage( wp, team ) +{ + if ( !isDefined( level.waypointUsage ) ) + return; + + if ( !isDefined( level.waypointUsage[team][wp + ""] ) ) + return; + + level.waypointUsage[team][wp + ""]--; + + if ( level.waypointUsage[team][wp + ""] <= 0 ) + level.waypointUsage[team][wp + ""] = undefined; +} + /* Will linearly search for the nearest waypoint to pos that has a direct line of sight. */ -GetNearestWaypointWithSight(pos) +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)) + if ( !bulletTracePassed( pos + ( 0, 0, 15 ), level.waypoints[i].origin + ( 0, 0, 15 ), false, undefined ) ) continue; - - curdis = DistanceSquared(level.waypoints[i].origin, pos); - if(curdis > dist) + + curdis = DistanceSquared( level.waypoints[i].origin, pos ); + + if ( curdis > dist ) continue; - + dist = curdis; - candidate = level.waypoints[i]; + candidate = i; } - + + return candidate; +} + +/* + Will linearly search for the nearest waypoint +*/ +GetNearestWaypoint( pos ) +{ + candidate = undefined; + dist = 2147483647; + + for ( i = 0; i < level.waypointCount; i++ ) + { + curdis = DistanceSquared( level.waypoints[i].origin, pos ); + + if ( curdis > dist ) + continue; + + dist = curdis; + candidate = i; + } + return candidate; } /* Modified Pezbot astar search. This makes use of sets for quick look up and a heap for a priority queue instead of simple lists which require to linearly search for elements everytime. - Also makes use of the KD tree to search for the nearest node to the goal. We only use the closest node from the KD tree if it has a direct line of sight, else we will have to linearly search for one that we have a line of sight on. It is also modified to make paths with bots already on more expensive and will try a less congested path first. Thus spliting up the bots onto more paths instead of just one (the smallest). */ -AStarSearch(start, goal, team, greedy_path) +AStarSearch( start, goal, team, greedy_path ) { - open = NewHeap(::ReverseHeapAStar);//heap + open = NewHeap( ::ReverseHeapAStar ); //heap openset = [];//set for quick lookup - closed = [];//set for quick lookup - - startwp = level.waypointsKDTree KDTreeNearest(start);//balanced kdtree, for nns - if(!isDefined(startwp)) + + + startWp = getNearestWaypoint( start ); + + if ( !isDefined( startWp ) ) return []; + _startwp = undefined; - if(!bulletTracePassed(start + (0, 0, 15), startwp.origin + (0, 0, 15), false, undefined)) - _startwp = GetNearestWaypointWithSight(start); - if(isDefined(_startwp)) - startwp = _startwp; - startwp = startwp.index; - - goalwp = level.waypointsKDTree KDTreeNearest(goal); - if(!isDefined(goalwp)) + + if ( !bulletTracePassed( start + ( 0, 0, 15 ), level.waypoints[startWp].origin + ( 0, 0, 15 ), false, undefined ) ) + _startwp = GetNearestWaypointWithSight( start ); + + if ( isDefined( _startwp ) ) + startWp = _startwp; + + + goalWp = getNearestWaypoint( goal ); + + if ( !isDefined( goalWp ) ) return []; - _goalwp = undefined; - if(!bulletTracePassed(goal + (0, 0, 15), goalwp.origin + (0, 0, 15), false, undefined)) - _goalwp = GetNearestWaypointWithSight(goal); - if(isDefined(_goalwp)) - goalwp = _goalwp; - goalwp = goalwp.index; - - goalorg = level.waypoints[goalWp].origin; - + + _goalWp = undefined; + + if ( !bulletTracePassed( goal + ( 0, 0, 15 ), level.waypoints[goalWp].origin + ( 0, 0, 15 ), false, undefined ) ) + _goalwp = GetNearestWaypointWithSight( goal ); + + if ( isDefined( _goalwp ) ) + goalWp = _goalwp; + + node = spawnStruct(); node.g = 0; //path dist so far - node.h = DistanceSquared(level.waypoints[startWp].origin, goalorg); //herustic, distance to goal for path finding - //node.f = node.h + node.g; // combine path dist and heru, use reverse heap to sort the priority queue by this attru - node.f = node.h; - node.index = startwp; + node.h = DistanceSquared( level.waypoints[startWp].origin, level.waypoints[goalWp].origin ); //herustic, distance to goal for path finding + node.f = node.h + node.g; // combine path dist and heru, use reverse heap to sort the priority queue by this attru + node.index = startWp; node.parent = undefined; //we are start, so we have no parent - + //push node onto queue - openset[node.index] = node; - open HeapInsert(node); - + openset[node.index + ""] = node; + open HeapInsert( node ); + //while the queue is not empty - while(open.data.size) + while ( open.data.size ) { //pop bestnode from queue bestNode = open.data[0]; open HeapRemove(); - openset[bestNode.index] = undefined; - + openset[bestNode.index + ""] = undefined; + wp = level.waypoints[bestNode.index]; + //check if we made it to the goal - if(bestNode.index == goalwp) + if ( bestNode.index == goalWp ) { path = []; - - while(isDefined(bestNode)) + + while ( isDefined( bestNode ) ) { - if(isdefined(team)) - level.waypoints[bestNode.index].bots[team]++; - + if ( isdefined( team ) && isDefined( level.waypointUsage ) ) + { + if ( !isDefined( level.waypointUsage[team][bestNode.index + ""] ) ) + level.waypointUsage[team][bestNode.index + ""] = 0; + + level.waypointUsage[team][bestNode.index + ""]++; + } + //construct path path[path.size] = bestNode.index; - + bestNode = bestNode.parent; } - + return path; } - - nodeorg = level.waypoints[bestNode.index].origin; - childcount = level.waypoints[bestNode.index].childCount; + //for each child of bestnode - for(i = 0; i < childcount; i++) + for ( i = wp.children.size - 1; i >= 0; i-- ) { - child = level.waypoints[bestNode.index].children[i]; - childorg = level.waypoints[child].origin; - childtype = level.waypoints[child].type; - + child = wp.children[i]; + childWp = level.waypoints[child]; + penalty = 1; - if(!greedy_path && isdefined(team)) + + if ( !greedy_path && isdefined( team ) && isDefined( level.waypointUsage ) ) { - temppen = level.waypoints[child].bots[team];//consider how many bots are taking this path - if(temppen > 1) + temppen = 1; + + if ( isDefined( level.waypointUsage[team][child + ""] ) ) + temppen = level.waypointUsage[team][child + ""]; //consider how many bots are taking this path + + if ( temppen > 1 ) penalty = temppen; } // have certain types of nodes more expensive - if (childtype == "climb" || childtype == "prone") + if ( childWp.type == "climb" || childWp.type == "prone" ) penalty += 4; - + //calc the total path we have took - newg = bestNode.g + DistanceSquared(nodeorg, childorg)*penalty;//bots on same team's path are more expensive - + newg = bestNode.g + DistanceSquared( wp.origin, childWp.origin ) * penalty; //bots on same team's path are more expensive + //check if this child is in open or close with a g value less than newg - inopen = isDefined(openset[child]); - if(inopen && openset[child].g <= newg) + inopen = isDefined( openset[child + ""] ); + + if ( inopen && openset[child + ""].g <= newg ) continue; - - inclosed = isDefined(closed[child]); - if(inclosed && closed[child].g <= newg) + + inclosed = isDefined( closed[child + ""] ); + + if ( inclosed && closed[child + ""].g <= newg ) continue; - - if(inopen) - node = openset[child]; - else if(inclosed) - node = closed[child]; + + node = undefined; + + if ( inopen ) + node = openset[child + ""]; + else if ( inclosed ) + node = closed[child + ""]; else node = spawnStruct(); - + node.parent = bestNode; node.g = newg; - node.h = DistanceSquared(childorg, goalorg); + node.h = DistanceSquared( childWp.origin, level.waypoints[goalWp].origin ); node.f = node.g + node.h; node.index = child; - + //check if in closed, remove it - if(inclosed) - closed[child] = undefined; - + if ( inclosed ) + closed[child + ""] = undefined; + //check if not in open, add it - if(!inopen) + if ( !inopen ) { - open HeapInsert(node); - openset[child] = node; + open HeapInsert( node ); + openset[child + ""] = node; } } - + //done with children, push onto closed - closed[bestNode.index] = bestNode; + closed[bestNode.index + ""] = bestNode; } - + return []; } /* Returns the natural log of x using harmonic series. */ -Log(x) +Log( x ) { - /*if (!isDefined(level.log_cache)) + /* if (!isDefined(level.log_cache)) level.log_cache = []; - - key = x + ""; - - if (isDefined(level.log_cache[key])) + + key = x + ""; + + if (isDefined(level.log_cache[key])) return level.log_cache[key];*/ //thanks Bob__ at stackoverflow old_sum = 0.0; - xmlxpl = (x - 1) / (x + 1); + xmlxpl = ( x - 1 ) / ( x + 1 ); xmlxpl_2 = xmlxpl * xmlxpl; denom = 1.0; frac = xmlxpl; @@ -1989,9 +2486,9 @@ Log(x) frac *= xmlxpl_2; sum += frac / denom; } - + answer = 2.0 * sum; - + //level.log_cache[key] = answer; return answer; } @@ -2001,24 +2498,29 @@ Log(x) */ array_combine( array1, array2 ) { - if( !array1.size ) + if ( !array1.size ) { - return array2; + return array2; } + array3 = []; keys = GetArrayKeys( array1 ); - for( i = 0;i < keys.size;i++ ) + + for ( i = 0; i < keys.size; i++ ) { key = keys[ i ]; - array3[ array3.size ] = array1[ key ]; - } + array3[ array3.size ] = array1[ key ]; + } + keys = GetArrayKeys( array2 ); - for( i = 0;i < keys.size;i++ ) + + for ( i = 0; i < keys.size; i++ ) { key = keys[ i ]; array3[ array3.size ] = array2[ key ]; } - return array3; + + return array3; } /* @@ -2030,10 +2532,12 @@ array_average( array ) assert( IsArray( array ) ); assert( array.size > 0 ); total = 0; + for ( i = 0; i < array.size; i++ ) { total += array[i]; } + return ( total / array.size ); } @@ -2046,15 +2550,19 @@ array_std_deviation( array, mean ) assert( IsArray( array ) ); assert( array.size > 0 ); tmp = []; + for ( i = 0; i < array.size; i++ ) { tmp[i] = ( array[i] - mean ) * ( array[i] - mean ); } + total = 0; + for ( i = 0; i < tmp.size; i++ ) { total = total + tmp[i]; } + return Sqrt( total / array.size ); } @@ -2068,25 +2576,29 @@ random_normal_distribution( mean, std_deviation, lower_bound, upper_bound ) x2 = 0; w = 1; y1 = 0; + while ( w >= 1 ) { x1 = 2 * RandomFloatRange( 0, 1 ) - 1; x2 = 2 * RandomFloatRange( 0, 1 ) - 1; w = x1 * x1 + x2 * x2; } + w = Sqrt( ( -2.0 * Log( w ) ) / w ); y1 = x1 * w; number = mean + y1 * std_deviation; + if ( IsDefined( lower_bound ) && number < lower_bound ) { number = lower_bound; } + if ( IsDefined( upper_bound ) && number > upper_bound ) { number = upper_bound; } - - return( number ); + + return ( number ); } /* @@ -2099,20 +2611,22 @@ onUsePlantObjectFix( player ) { level thread bombPlantedFix( self, player ); player logString( "bomb planted: " + self.label ); - + // disable all bomb zones except this one for ( index = 0; index < level.bombZones.size; index++ ) { if ( level.bombZones[index] == self ) continue; - + level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject(); } - + player playSound( "mp_bomb_plant" ); player notify ( "bomb_planted" ); + if ( !level.hardcoreMode ) iPrintLn( &"MP_EXPLOSIVES_PLANTED_BY", player ); + maps\mp\gametypes\_globallogic::leaderDialog( "bomb_planted" ); maps\mp\gametypes\_globallogic::givePlayerScore( "plant", player ); @@ -2127,14 +2641,14 @@ bombPlantedFix( destroyedObj, player ) { maps\mp\gametypes\_globallogic::pauseTimer(); level.bombPlanted = true; - + destroyedObj.visuals[0] thread maps\mp\gametypes\_globallogic::playTickingSound(); level.tickingObject = destroyedObj.visuals[0]; level.timeLimitOverride = true; - setGameEndTime( int( gettime() + (level.bombTimer * 1000) ) ); + setGameEndTime( int( gettime() + ( level.bombTimer * 1000 ) ) ); setDvar( "ui_bomb_timer", 1 ); - + if ( !level.multiBomb ) { level.sdBomb maps\mp\gametypes\_gameobjects::allowCarry( "none" ); @@ -2144,39 +2658,40 @@ bombPlantedFix( destroyedObj, player ) } else { - + for ( index = 0; index < level.players.size; index++ ) { if ( isDefined( level.players[index].carryIcon ) ) level.players[index].carryIcon destroyElem(); } - trace = bulletTrace( player.origin + (0,0,20), player.origin - (0,0,2000), false, player ); - + trace = bulletTrace( player.origin + ( 0, 0, 20 ), player.origin - ( 0, 0, 2000 ), false, player ); + tempAngle = randomfloat( 360 ); - forward = (cos( tempAngle ), sin( tempAngle ), 0); + forward = ( cos( tempAngle ), sin( tempAngle ), 0 ); forward = vectornormalize( forward - vector_scale( trace["normal"], vectordot( forward, trace["normal"] ) ) ); dropAngles = vectortoangles( forward ); - + level.sdBombModel = spawn( "script_model", trace["position"] ); level.sdBombModel.angles = dropAngles; level.sdBombModel setModel( "prop_suitcase_bomb" ); } + destroyedObj maps\mp\gametypes\_gameobjects::allowUse( "none" ); destroyedObj maps\mp\gametypes\_gameobjects::setVisibleTeam( "none" ); /* - destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined ); - destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined ); - destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined ); - destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined ); + destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "friendly", undefined ); + destroyedObj maps\mp\gametypes\_gameobjects::set2DIcon( "enemy", undefined ); + destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "friendly", undefined ); + destroyedObj maps\mp\gametypes\_gameobjects::set3DIcon( "enemy", undefined ); */ label = destroyedObj maps\mp\gametypes\_gameobjects::getLabel(); - + // create a new object to defuse with. trigger = destroyedObj.bombDefuseTrig; trigger.origin = level.sdBombModel.origin; visuals = []; - defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, (0,0,32) ); + defuseObject = maps\mp\gametypes\_gameobjects::createUseObject( game["defenders"], trigger, visuals, ( 0, 0, 32 ) ); defuseObject maps\mp\gametypes\_gameobjects::allowUse( "friendly" ); defuseObject maps\mp\gametypes\_gameobjects::setUseTime( level.defuseTime ); defuseObject maps\mp\gametypes\_gameobjects::setUseText( &"MP_DEFUSING_EXPLOSIVE" ); @@ -2191,43 +2706,44 @@ bombPlantedFix( destroyedObj, player ) defuseObject.onEndUse = maps\mp\gametypes\sd::onEndUse; defuseObject.onUse = maps\mp\gametypes\sd::onUseDefuseObject; defuseObject.useWeapon = "briefcase_bomb_defuse_mp"; - + level.defuseObject = defuseObject; - + maps\mp\gametypes\sd::BombTimerWait(); setDvar( "ui_bomb_timer", 0 ); - + destroyedObj.visuals[0] maps\mp\gametypes\_globallogic::stopTickingSound(); - + if ( level.gameEnded || level.bombDefused ) return; - + level.bombExploded = true; - + explosionOrigin = level.sdBombModel.origin; level.sdBombModel hide(); - + if ( isdefined( player ) ) destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20, player ); else destroyedObj.visuals[0] radiusDamage( explosionOrigin, 512, 200, 20 ); - - rot = randomfloat(360); - explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + (0,0,50), (0,0,1), (cos(rot),sin(rot),0) ); + + rot = randomfloat( 360 ); + explosionEffect = spawnFx( level._effect["bombexplosion"], explosionOrigin + ( 0, 0, 50 ), ( 0, 0, 1 ), ( cos( rot ), sin( rot ), 0 ) ); triggerFx( explosionEffect ); - + thread maps\mp\gametypes\sd::playSoundinSpace( "exp_suitcase_bomb_main", explosionOrigin ); - + if ( isDefined( destroyedObj.exploderIndex ) ) exploder( destroyedObj.exploderIndex ); - + for ( index = 0; index < level.bombZones.size; index++ ) level.bombZones[index] maps\mp\gametypes\_gameobjects::disableObject(); + defuseObject maps\mp\gametypes\_gameobjects::disableObject(); - + setGameEndTime( 0 ); - + wait 3; - + maps\mp\gametypes\sd::sd_endGame( game["attackers"], game["strings"]["target_destroyed"] ); } diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_menu.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_menu.gsc index b92f8f9..770b9e1 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_menu.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_menu.gsc @@ -12,10 +12,10 @@ init() { - if (getDvar("bots_main_menu") == "") - setDvar("bots_main_menu", true); + if ( getDvar( "bots_main_menu" ) == "" ) + setDvar( "bots_main_menu", true ); - if (!getDvarInt("bots_main_menu")) + if ( !getDvarInt( "bots_main_menu" ) ) return; thread watchPlayers(); @@ -23,21 +23,21 @@ init() watchPlayers() { - for (;;) + for ( ;; ) { wait 1; - if (!getDvarInt("bots_main_menu")) + if ( !getDvarInt( "bots_main_menu" ) ) return; - for (i = level.players.size - 1; i >= 0; i--) + for ( i = level.players.size - 1; i >= 0; i-- ) { player = level.players[i]; - if (!player is_host()) + if ( !player is_host() ) continue; - if (isDefined(player.menuInit) && player.menuInit) + if ( isDefined( player.menuInit ) && player.menuInit ) continue; player thread init_menu(); @@ -48,55 +48,55 @@ watchPlayers() 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 watchDisconnect(); - + self thread doGreetings(); } kill_menu() { - self notify("bots_kill_menu"); + self notify( "bots_kill_menu" ); self.menuInit = undefined; } watchDisconnect() { - self waittill_either("disconnect", "bots_kill_menu"); - - if(self.menuOpen) + 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])) + 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])) + + 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 ) && isDefined( self.Menu["X"] ) ) { - if(isDefined(self.Menu["X"]["Shader"])) + if ( isDefined( self.Menu["X"]["Shader"] ) ) self.Menu["X"]["Shader"] destroy(); - - if(isDefined(self.Menu["X"]["Scroller"])) + + if ( isDefined( self.Menu["X"]["Scroller"] ) ) self.Menu["X"]["Scroller"] destroy(); } - if (isDefined(self.menuVersionHud)) + if ( isDefined( self.menuVersionHud ) ) self.menuVersionHud destroy(); } } @@ -106,42 +106,44 @@ doGreetings() self endon ( "disconnect" ); self endon ( "bots_kill_menu" ); wait 1; - self iPrintln("Welcome to Bot Warfare "+self.name+"!"); + self iPrintln( "Welcome to Bot Warfare " + self.name + "!" ); wait 5; - self iPrintln("Press [{+frag}] + [{+smoke}] to open menu!"); + self iPrintln( "Press [{+frag}] + [{+smoke}] to open menu!" ); } watchPlayerOpenMenu() { self endon ( "disconnect" ); self endon ( "bots_kill_menu" ); - - for(;;) + + for ( ;; ) { - while(!self FragButtonPressed() || !self SecondaryOffhandButtonPressed()) + while ( !self FragButtonPressed() || !self SecondaryOffhandButtonPressed() ) wait 0.05; - - if(!self.menuOpen) + + if ( !self.menuOpen ) { self playLocalSound( "mouse_click" ); - self thread OpenSub(self.SubMenu); + self thread OpenSub( self.SubMenu ); } else { self playLocalSound( "mouse_click" ); - if(self.SubMenu != "Main") + + if ( self.SubMenu != "Main" ) self ExitSub(); else { self ExitMenu(); - if(level.inPrematchPeriod || level.gameEnded) - self freezeControls(true); + + if ( level.inPrematchPeriod || level.gameEnded ) + self freezeControls( true ); else - self freezecontrols(false); + self freezecontrols( false ); } } - - while(self FragButtonPressed() && self SecondaryOffhandButtonPressed()) + + while ( self FragButtonPressed() && self SecondaryOffhandButtonPressed() ) wait 0.05; } } @@ -150,22 +152,23 @@ MenuSelect() { self endon ( "disconnect" ); self endon ( "bots_kill_menu" ); - - for(;;) + + for ( ;; ) { - while(!self MeleeButtonPressed()) + while ( !self MeleeButtonPressed() ) wait 0.05; - - if(self.MenuOpen) + + 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"]]); + + 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"]]); + 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"]] ); } - - while(self MeleeButtonPressed()) + + while ( self MeleeButtonPressed() ) wait 0.05; } } @@ -175,36 +178,36 @@ LeftMenu() self endon ( "disconnect" ); self endon ( "bots_kill_menu" ); - for(;;) + for ( ;; ) { - while(!self AttackButtonPressed()) + while ( !self AttackButtonPressed() ) wait 0.05; - - if(self.MenuOpen) + + if ( self.MenuOpen ) { - self playLocalSound("mouse_over"); - - if(self.SubMenu == "Main") + self playLocalSound( "mouse_over" ); + + if ( self.SubMenu == "Main" ) { self.Curs["Main"]["X"]--; - if(self.Curs["Main"]["X"] < 0) - self.Curs["Main"]["X"] = self.Option["Name"][self.SubMenu].size -1; + if ( self.Curs["Main"]["X"] < 0 ) + self.Curs["Main"]["X"] = self.Option["Name"][self.SubMenu].size - 1; - self CursMove("X"); + self CursMove( "X" ); } else { self.Curs[self.SubMenu]["Y"]--; - if(self.Curs[self.SubMenu]["Y"] < 0) - self.Curs[self.SubMenu]["Y"] = self.Option["Name"][self.SubMenu].size -1; + if ( self.Curs[self.SubMenu]["Y"] < 0 ) + self.Curs[self.SubMenu]["Y"] = self.Option["Name"][self.SubMenu].size - 1; - self CursMove("Y"); + self CursMove( "Y" ); } } - - while(self AttackButtonPressed()) + + while ( self AttackButtonPressed() ) wait 0.05; } } @@ -214,242 +217,249 @@ RightMenu() self endon ( "disconnect" ); self endon ( "bots_kill_menu" ); - for(;;) + for ( ;; ) { - while(!self AdsButtonPressed()) + while ( !self AdsButtonPressed() ) wait 0.05; - - if(self.MenuOpen) + + if ( self.MenuOpen ) { - self playLocalSound("mouse_over"); - - if(self.SubMenu == "Main") + self playLocalSound( "mouse_over" ); + + if ( self.SubMenu == "Main" ) { self.Curs["Main"]["X"]++; - if(self.Curs["Main"]["X"] > self.Option["Name"][self.SubMenu].size -1) + if ( self.Curs["Main"]["X"] > self.Option["Name"][self.SubMenu].size - 1 ) self.Curs["Main"]["X"] = 0; - self CursMove("X"); + self CursMove( "X" ); } else { self.Curs[self.SubMenu]["Y"]++; - if(self.Curs[self.SubMenu]["Y"] > self.Option["Name"][self.SubMenu].size -1) + if ( self.Curs[self.SubMenu]["Y"] > self.Option["Name"][self.SubMenu].size - 1 ) self.Curs[self.SubMenu]["Y"] = 0; - self CursMove("Y"); + self CursMove( "Y" ); } } - - while(self AdsButtonPressed()) + + while ( self AdsButtonPressed() ) wait 0.05; } } -OpenSub(menu, menu2) +OpenSub( menu, menu2 ) { - if(menu != "Main" && (!isDefined(self.Menu[menu]) || !!isDefined(self.Menu[menu]["FirstOpen"]))) + 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 ( self.SubMenu == "Main" ) { - if(isDefined(self.MenuText)) - for(i = 0; i < self.MenuText.size; i++) - if(isDefined(self.MenuText[i])) + 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 ) && isDefined( self.Menu["X"] ) ) { - if(isDefined(self.Menu["X"]["Shader"])) + if ( isDefined( self.Menu["X"]["Shader"] ) ) self.Menu["X"]["Shader"] destroy(); - - if(isDefined(self.Menu["X"]["Scroller"])) + + if ( isDefined( self.Menu["X"]["Scroller"] ) ) self.Menu["X"]["Scroller"] destroy(); } - if (isDefined(self.menuVersionHud)) + if ( isDefined( self.menuVersionHud ) ) self.menuVersionHud destroy(); - - for(i=0 ; i < self.Option["Name"][self.SubMenu].size ; i++) + + 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.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) + + 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] 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"); + 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"]["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.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.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])) + 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++) + + 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] = 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"); + + self CursMove( "Y" ); } } -CursMove(direction) +CursMove( direction ) { - self notify("scrolled"); - if(self.SubMenu == "Main") + 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)) + + if ( isDefined( self.MenuText ) ) { - for(i = 0; i < self.MenuText.size; i++) + for ( i = 0; i < self.MenuText.size; i++ ) { - if(isDefined(self.MenuText[i])) + if ( isDefined( self.MenuText[i] ) ) { self.MenuText[i].fontscale = 1.5; - self.MenuText[i].color = (1,1,1); + self.MenuText[i].color = ( 1, 1, 1 ); self.MenuText[i].glowAlpha = 0; } } } - - self thread ShowOptionOn(direction); + + self thread ShowOptionOn( direction ); } else { - if(isDefined(self.MenuTextY)) + if ( isDefined( self.MenuTextY ) ) { - for(i = 0; i < self.MenuTextY.size; i++) + for ( i = 0; i < self.MenuTextY.size; i++ ) { - if(isDefined(self.MenuTextY[i])) + if ( isDefined( self.MenuTextY[i] ) ) { self.MenuTextY[i].fontscale = 1.5; - self.MenuTextY[i].color = (1,1,1); + self.MenuTextY[i].color = ( 1, 1, 1 ); self.MenuTextY[i].glowAlpha = 0; } } } - - if(isDefined(self.MenuText)) + + if ( isDefined( self.MenuText ) ) { - for(i = 0; i < self.MenuText.size; i++) + for ( i = 0; i < self.MenuText.size; i++ ) { - if(isDefined(self.MenuText[i])) + if ( isDefined( self.MenuText[i] ) ) { self.MenuText[i].fontscale = 1.5; - self.MenuText[i].color = (1,1,1); + self.MenuText[i].color = ( 1, 1, 1 ); self.MenuText[i].glowAlpha = 0; } } } - - self thread ShowOptionOn(direction); + + self thread ShowOptionOn( direction ); } } -ShowOptionOn(variable) +ShowOptionOn( variable ) { - self endon("scrolled"); - self endon("disconnect"); - self endon("exit"); - self endon("bots_kill_menu"); - - for(time=0;;time+=0.05) + 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) && !level.inPrematchPeriod && !level.gameEnded) - self freezecontrols(false); + if ( !self isOnGround() && isAlive( self ) && !level.inPrematchPeriod && !level.gameEnded ) + self freezecontrols( false ); else - self freezecontrols(true); - - self setClientDvar( "r_blur", "5" ); + self freezecontrols( true ); + + self setClientDvar( "r_blur", "5" ); self setClientDvar( "sc_blur", "4" ); self addOptions(); - - if(self.SubMenu == "Main") + + if ( self.SubMenu == "Main" ) { - if(isDefined(self.Curs[self.SubMenu][variable]) && isDefined(self.MenuText) && isDefined(self.MenuText[self.Curs[self.SubMenu][variable]])) + 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); + 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)) + + if ( isDefined( self.MenuText ) ) { - for(i = 0; i < self.Option["Name"][self.SubMenu].size; i++) + 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]); + 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]])) + 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); + 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)) + + if ( isDefined( self.MenuTextY ) ) { - for(i = 0; i < self.Option["Name"][self.SubMenu].size; i++) + 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]); + 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) +AddMenu( menu, num, text, function, arg1, arg2 ) { self.Option["Name"][menu][num] = text; self.Option["Function"][menu][num] = function; @@ -457,56 +467,56 @@ AddMenu(menu, num, text, function, arg1, arg2) self.Option["Arg2"][menu][num] = arg2; } -AddBack(menu, back) +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])) + 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"); + + if ( self.SubMenu == "Main" ) + self CursMove( "X" ); else - self CursMove("Y"); + self CursMove( "Y" ); } ExitMenu() { - if(isDefined(self.MenuText)) - for(i = 0; i < self.MenuText.size; i++) - if(isDefined(self.MenuText[i])) + 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 ) && isDefined( self.Menu["X"] ) ) { - if(isDefined(self.Menu["X"]["Shader"])) + if ( isDefined( self.Menu["X"]["Shader"] ) ) self.Menu["X"]["Shader"] destroy(); - - if(isDefined(self.Menu["X"]["Scroller"])) + + if ( isDefined( self.Menu["X"]["Scroller"] ) ) self.Menu["X"]["Scroller"] destroy(); } - if (isDefined(self.menuVersionHud)) + if ( isDefined( self.menuVersionHud ) ) self.menuVersionHud destroy(); - + self.MenuOpen = false; - self notify("exit"); - + self notify( "exit" ); + self setClientDvar( "r_blur", "0" ); self setClientDvar( "sc_blur", "2" ); } -initHudElem(txt, xl, yl) +initHudElem( txt, xl, yl ) { hud = NewClientHudElem( self ); - hud setText(txt); + hud setText( txt ); hud.alignX = "center"; hud.alignY = "bottom"; hud.horzAlign = "center"; @@ -521,11 +531,11 @@ initHudElem(txt, xl, yl) 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) +createRectangle( align, relative, x, y, width, height, color, sort, alpha, shader ) { barElemBG = newClientHudElem( self ); barElemBG.elemType = "bar_"; @@ -540,479 +550,582 @@ createRectangle(align,relative,x,y,width,height,color,sort,alpha,shader) barElemBG.color = color; barElemBG.alpha = alpha; barElemBG setParent( level.uiParent ); - barElemBG setShader( shader, width , height ); + barElemBG setShader( shader, width, height ); barElemBG.hidden = false; - barElemBG setPoint(align, relative, x, y); + barElemBG setPoint( align, relative, x, y ); return barElemBG; } AddOptions() { - self AddMenu("Main", 0, "Manage bots", ::OpenSub, "man_bots", ""); - self AddBack("man_bots", "Main"); - + 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) + _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) + + 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; + break; + case 1: _temp = "just bots"; - break; + break; + case 2: _temp = "everyone, adjust to map"; - break; + break; + case 3: _temp = "just bots, adjust to map"; - break; + break; + case 4: _temp = "bots used as team balance"; - break; + break; + default: _temp = "out of range"; - break; + 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) + + 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( "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) + 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) + + 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) + + 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; + break; + case 1: _temp = "too easy"; - break; + break; + case 2: _temp = "easy"; - break; + break; + case 3: _temp = "easy-medium"; - break; + break; + case 4: _temp = "medium"; - break; + break; + case 5: _temp = "hard"; - break; + break; + case 6: _temp = "very hard"; - break; + break; + case 7: _temp = "hardest"; - break; + break; + case 8: _temp = "custom"; - break; + break; + case 9: _temp = "complete random"; - break; + break; + default: _temp = "out of range"; - break; + 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( "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"); + self AddMenu( "Main", 2, "Bot settings", ::OpenSub, "set1", "" ); + self AddBack( "set1", "Main" ); - _tempDvar = getDvarInt("bots_loadout_reasonable"); - if(_tempDvar) + _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) + 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) + 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) + 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) + 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) + 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_obj"); - if(_tempDvar) + self AddMenu( "set1", 5, "Bots can nade: " + _temp, ::bot_func, "nade", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_obj" ); + + if ( _tempDvar ) _temp = "true"; else _temp = "false"; - self AddMenu("set1", 6, "Bots play the objective: "+_temp, ::bot_func, "obj", _tempDvar); - _tempDvar = getDvarInt("bots_play_camp"); - if(_tempDvar) + self AddMenu( "set1", 6, "Bots play the objective: " + _temp, ::bot_func, "obj", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_camp" ); + + if ( _tempDvar ) _temp = "true"; else _temp = "false"; - self AddMenu("set1", 7, "Bots can camp: "+_temp, ::bot_func, "camp", _tempDvar); - _tempDvar = getDvarInt("bots_play_jumpdrop"); - if(_tempDvar) + self AddMenu( "set1", 7, "Bots can camp: " + _temp, ::bot_func, "camp", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_jumpdrop" ); + + if ( _tempDvar ) _temp = "true"; else _temp = "false"; - self AddMenu("set1", 8, "Bots can jump and dropshot: "+_temp, ::bot_func, "jump", _tempDvar); - _tempDvar = getDvarInt("bots_play_target_other"); - if(_tempDvar) + self AddMenu( "set1", 8, "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", 9, "Bots can target other script objects: "+_temp, ::bot_func, "targetother", _tempDvar); - _tempDvar = getDvarInt("bots_play_killstreak"); - if(_tempDvar) + self AddMenu( "set1", 9, "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", 10, "Bots can use killstreaks: "+_temp, ::bot_func, "killstreak", _tempDvar); - _tempDvar = getDvarInt("bots_play_ads"); - if(_tempDvar) + self AddMenu( "set1", 10, "Bots can use killstreaks: " + _temp, ::bot_func, "killstreak", _tempDvar ); + + _tempDvar = getDvarInt( "bots_play_ads" ); + + if ( _tempDvar ) _temp = "true"; else _temp = "false"; - self AddMenu("set1", 11, "Bots can ads: "+_temp, ::bot_func, "ads", _tempDvar); + + self AddMenu( "set1", 11, "Bots can ads: " + _temp, ::bot_func, "ads", _tempDvar ); } -bot_func(a, b) +bot_func( a, b ) { - switch (a) + switch ( a ) { case "reasonable": - setDvar("bots_loadout_reasonable", !b); - self iPrintln("Bots using reasonable setups: " + !b); - break; + 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; + 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; + setDvar( "bots_play_move", !b ); + self iPrintln( "Bots move: " + !b ); + break; + case "knife": - setDvar("bots_play_knife", !b); - self iPrintln("Bots knife: " + !b); - break; + setDvar( "bots_play_knife", !b ); + self iPrintln( "Bots knife: " + !b ); + break; + case "fire": - setDvar("bots_play_fire", !b); - self iPrintln("Bots fire: " + !b); - break; + setDvar( "bots_play_fire", !b ); + self iPrintln( "Bots fire: " + !b ); + break; + case "nade": - setDvar("bots_play_nade", !b); - self iPrintln("Bots nade: " + !b); - break; + setDvar( "bots_play_nade", !b ); + self iPrintln( "Bots nade: " + !b ); + break; + case "obj": - setDvar("bots_play_obj", !b); - self iPrintln("Bots play the obj: " + !b); - break; + 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; + setDvar( "bots_play_camp", !b ); + self iPrintln( "Bots camp: " + !b ); + break; + case "jump": - setDvar("bots_play_jumpdrop", !b); - self iPrintln("Bots jump: " + !b); - break; + 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; + 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; + 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; + setDvar( "bots_play_ads", !b ); + self iPrintln( "Bots ads: " + !b ); + break; } } -bot_teams(a, b) +bot_teams( a, b ) { - switch(a) + switch ( a ) { case "team": - switch(b) + switch ( b ) { case "autoassign": - setdvar("bots_team", "allies"); - self iPrintlnBold("Changed bot team to allies."); - break; + 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; + 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; + 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; + setdvar( "bots_team", "autoassign" ); + self iPrintlnBold( "Changed bot team to autoassign." ); + break; } - break; + + break; + case "teamup": - setdvar("bots_team_amount", b+1); - self iPrintln((b+1)+" bot(s) will try to be on axis team."); - break; + 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; + 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; + 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; + setDvar( "bots_team_mode", !b ); + self iPrintln( "Only count bots on team: " + !b ); + break; + case "skill": - switch(b) + switch ( b ) { case 0: - self iPrintlnBold("Changed bot skill to easy."); - setDvar("bots_skill", 1); - break; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + self iPrintlnBold( "Changed bot skill to random. Takes effect at restart." ); + setDvar( "bots_skill", 0 ); + break; } - break; + + break; + case "axishardup": - setdvar("bots_skill_axis_hard", (b+1)); - self iPrintln(((b+1))+" hard bots will be on axis team."); - break; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + setdvar( "bots_skill_allies_med", ( b - 1 ) ); + self iPrintln( ( ( b - 1 ) ) + " med bots will be on allies team." ); + break; } } -man_bots(a, b) +man_bots( a, b ) { - switch(a) + switch ( a ) { case "add": - setdvar("bots_manage_add", b); - if(b == 1) + setdvar( "bots_manage_add", b ); + + if ( b == 1 ) { - self iPrintln("Adding "+b+" bot."); + self iPrintln( "Adding " + b + " bot." ); } else { - self iPrintln("Adding "+b+" bots."); + self iPrintln( "Adding " + b + " bots." ); } - break; + + break; + case "kick": - for (i = 0; i < b; i++) + for ( i = 0; i < b; i++ ) { RemoveTestClient(); wait 0.25; } - break; + + break; + case "autokick": - setDvar("bots_manage_fill_kick", !b); - self iPrintln("Kicking bots when bots_fill is exceeded: " + !b); - break; + setDvar( "bots_manage_fill_kick", !b ); + self iPrintln( "Kicking bots when bots_fill is exceeded: " + !b ); + break; + case "fillmode": - switch(b) + switch ( b ) { case 0: - setdvar("bots_manage_fill_mode", 1); - self iPrintln("bot_fill will now count only bots."); - break; + 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; + 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; + 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; + 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; + setdvar( "bots_manage_fill_mode", 0 ); + self iPrintln( "bot_fill will now count everyone." ); + break; } - break; + + break; + case "fillup": - setdvar("bots_manage_fill", b+1); - self iPrintln("Increased to maintain "+(b+1)+" bot(s)."); - break; + 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; + 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; + setDvar( "bots_manage_fill_spec", !b ); + self iPrintln( "Count players on spectator for bots_fill: " + !b ); + break; } } diff --git a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_wp_editor.gsc b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_wp_editor.gsc index 4b3bc9e..e4dedf8 100644 --- a/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_wp_editor.gsc +++ b/out/Add to root of CoD4x server/main_shared/maps/mp/bots/_wp_editor.gsc @@ -1,649 +1,648 @@ -/* - _wp_editor - Author: INeedGames - Date: 09/26/2020 - The ingame waypoint editor. -*/ - -#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_debug") == "") - setDvar("bots_main_debug", 0); - - if(!getDVarint("bots_main_debug")) - return; - - if(!getDVarint("developer")) - { - setdvar("developer_script", 1); - setdvar("developer", 1); - - setdvar("sv_mapRotation", "map "+getDvar("mapname")); - exitLevel(false); - } - - setDvar("bots_main", 0); - setdvar("bots_main_menu", 0); - setdvar("bots_manage_fill_mode", 0); - setdvar("bots_manage_fill", 0); - setdvar("bots_manage_add", 0); - setdvar("bots_manage_fill_kick", 1); - setDvar("bots_manage_fill_spec", 1); - - if (getDvar("bots_main_debug_distance") == "") - setDvar("bots_main_debug_distance", 512.0); - - if (getDvar("bots_main_debug_cone") == "") - setDvar("bots_main_debug_cone", 0.65); - - if (getDvar("bots_main_debug_minDist") == "") - setDvar("bots_main_debug_minDist", 32.0); - - if (getDvar("bots_main_debug_drawThrough") == "") - setDvar("bots_main_debug_drawThrough", false); - - if(getDvar("bots_main_debug_commandWait") == "") - setDvar("bots_main_debug_commandWait", 0.5); - - if(getDvar("bots_main_debug_framerate") == "") - setDvar("bots_main_debug_framerate", 58); - - if(getDvar("bots_main_debug_lineDuration") == "") - setDvar("bots_main_debug_lineDuration", 3); - - if(getDvar("bots_main_debug_printDuration") == "") - setDvar("bots_main_debug_printDuration", 3); - - if(getDvar("bots_main_debug_debugRate") == "") - setDvar("bots_main_debug_debugRate", 0.5); - - setDvar("player_sustainAmmo", 1); - - level.waypoints = []; - level.waypointCount = 0; - - level waittill( "connected", player); - - player thread onPlayerSpawned(); -} - -onPlayerSpawned() -{ - self endon("disconnect"); - for(;;) - { - self waittill("spawned_player"); - self thread beginDebug(); - } -} - -beginDebug() -{ - self endon("disconnect"); - self endon("death"); - - level.wpToLink = -1; - level.autoLink = false; - self.closest = -1; - self.command = undefined; - - self clearPerks(); - self takeAllWeapons(); - self.specialty = []; - self giveWeapon("m16_gl_mp"); - self SetActionSlot( 3, "altMode" ); - self giveWeapon("frag_grenade_mp"); - self freezecontrols(false); - - self thread debug(); - self thread addWaypoints(); - self thread linkWaypoints(); - self thread deleteWaypoints(); - self thread watchSaveWaypointsCommand(); - self thread sayExtras(); - - self thread textScroll("^1SecondaryOffhand - ^2Add Waypoint; ^3MeleeButton - ^4Link Waypoint; ^5FragButton - ^6Delete Waypoint; ^7UseButton + AttackButton - ^8Save"); -} - -sayExtras() -{ - self endon("disconnect"); - self endon("death"); - self iprintln("Making a crouch waypoint with only one link..."); - self iprintln("Makes a camping waypoint."); -} - -debug() -{ - self endon("disconnect"); - self endon("death"); - - self setClientDvar("com_maxfps", getDvarInt("bots_main_debug_framerate")); - - for(;;) - { - wait getDvarFloat("bots_main_debug_debugRate"); - - if(isDefined(self.command)) - continue; - - closest = -1; - myEye = self getTagOrigin( "j_head" ); - myAngles = self GetPlayerAngles(); - - for(i = 0; i < level.waypointCount; i++) - { - if(closest == -1 || closer(self.origin, level.waypoints[i].origin, level.waypoints[closest].origin)) - closest = i; - - wpOrg = level.waypoints[i].origin + (0, 0, 25); - - if(distance(level.waypoints[i].origin, self.origin) < getDvarFloat("bots_main_debug_distance") && (bulletTracePassed(myEye, wpOrg, false, self) || getDVarint("bots_main_debug_drawThrough"))) - { - for(h = 0; h < level.waypoints[i].childCount; h++) - line(wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + (0, 0, 25), (1,0,1), 1, 1, getDvarInt("bots_main_debug_lineDuration")); - - if(getConeDot(wpOrg, myEye, myAngles) > getDvarFloat("bots_main_debug_cone")) - print3d(wpOrg, i, (1,0,0), 2, 1, 6); - - if (isDefined(level.waypoints[i].angles) && level.waypoints[i].type != "stand") - line(wpOrg, wpOrg + AnglesToForward(level.waypoints[i].angles) * 64, (1,1,1), 1, 1, getDvarInt("bots_main_debug_lineDuration")); - } - } - - self.closest = closest; - - if(closest != -1) - { - stringChildren = ""; - for(i = 0; i < level.waypoints[closest].childCount; i++) - { - if(i != 0) - stringChildren = stringChildren + "," + level.waypoints[closest].children[i]; - else - stringChildren = stringChildren + level.waypoints[closest].children[i]; - } - print3d(level.waypoints[closest].origin + (0, 0, 35), stringChildren, (0,1,0), 2, 1, getDvarInt("bots_main_debug_printDuration")); - - print3d(level.waypoints[closest].origin + (0, 0, 15), level.waypoints[closest].type, (0,1,0), 2, 1, getDvarInt("bots_main_debug_printDuration")); - } - } -} - -AddWaypoints() -{ - self endon("disconnect"); - self endon("death"); - for(;;) - { - while(!self SecondaryOffhandButtonPressed() || isDefined(self.command)) - wait 0.05; - - pos = self getOrigin(); - self.command = true; - - self iprintln("Adding a waypoint..."); - self iprintln("ADS - climb; Attack + Use - tube"); - self iprintln("Attack - grenade; Use - claymore"); - self iprintln("Else(wait) - your stance"); - - wait getDvarFloat("bots_main_debug_commandWait"); - - self addWaypoint(pos); - - self.command = undefined; - - while(self SecondaryOffhandButtonPressed()) - wait 0.05; - } -} - -linkWaypoints() -{ - self endon("disconnect"); - self endon("death"); - for(;;) - { - while(!self MeleeButtonPressed() || isDefined(self.command)) - wait 0.05; - - self.command = true; - - self iprintln("ADS - Unlink; Else(wait) - Link"); - - wait getDvarFloat("bots_main_debug_commandWait"); - - if(!self adsButtonPressed()) - self LinkWaypoint(self.closest); - else - self UnLinkWaypoint(self.closest); - - self.command = undefined; - - while(self MeleeButtonPressed()) - wait 0.05; - } -} - -deleteWaypoints() -{ - self endon("disconnect"); - self endon("death"); - for(;;) - { - while(!self fragButtonPressed() || isDefined(self.command)) - wait 0.05; - - self.command = true; - - self iprintln("Attack - DeleteAll; ADS - Load"); - self iprintln("Else(wait) - Delete"); - - wait getDvarFloat("bots_main_debug_commandWait"); - - if(self attackButtonPressed()) - self deleteAllWaypoints(); - else if(self adsButtonPressed()) - self LoadWaypoints(); - else - self DeleteWaypoint(self.closest); - - self.command = undefined; - - while(self fragButtonPressed()) - wait 0.05; - } -} - -watchSaveWaypointsCommand() -{ - self endon("death"); - self endon("disconnect"); - - for(;;) - { - while(!self useButtonPressed() || !self attackButtonPressed() || isDefined(self.command)) - wait 0.05; - - self.command = true; - - self iprintln("ADS - Autolink; Else(wait) - Save"); - - wait getDvarFloat("bots_main_debug_commandWait"); - - if(!self adsButtonPressed()) - { - self checkForWarnings(); - wait 1; - - logprint("***********ABiliTy's WPDump**************\n\n"); - logprint("\n\n\n\n"); - mpnm=getMapName(getdvar("mapname")); - logprint("\n\n"+mpnm+"()\n{\n/*"); - logprint("*/waypoints = [];\n/*"); - for(i = 0; i < level.waypointCount; i++) - { - logprint("*/waypoints["+i+"] = spawnstruct();\n/*"); - logprint("*/waypoints["+i+"].origin = "+level.waypoints[i].origin+";\n/*"); - logprint("*/waypoints["+i+"].type = \""+level.waypoints[i].type+"\";\n/*"); - logprint("*/waypoints["+i+"].childCount = "+level.waypoints[i].childCount+";\n/*"); - for(c = 0; c < level.waypoints[i].childCount; c++) - { - logprint("*/waypoints["+i+"].children["+c+"] = "+level.waypoints[i].children[c]+";\n/*"); - } - if(isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) - logprint("*/waypoints["+i+"].angles = "+level.waypoints[i].angles+";\n/*"); - } - logprint("*/return waypoints;\n}\n\n\n\n"); - - filename = "waypoints/" + getdvar("mapname") + "_wp.csv"; - fd = FS_FOpen(filename, "write"); - - PrintLn("********* Start Bot Warfare WPDump *********"); - PrintLn(level.waypointCount); - - if (fd > 0) - { - if (!FS_WriteLine(fd, level.waypointCount+"")) - { - FS_FClose(fd); - fd = 0; - } - } - for(i = 0; i < level.waypointCount; i++) - { - str = ""; - wp = level.waypoints[i]; - - str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ","; - - for(h = 0; h < wp.childCount; h++) - { - str += wp.children[h]; - - if (h < wp.childCount - 1) - str += " "; - } - str += "," + wp.type + ","; - - if (isDefined(wp.angles)) - str += wp.angles[0] + " " + wp.angles[1] + " " + wp.angles[2] + ","; - else - str += ","; - - str += ","; - - PrintLn(str); - - if (fd > 0) - { - if (!FS_WriteLine(fd, str)) - { - FS_FClose(fd); - fd = 0; - } - } - } - PrintLn("\n\n\n\n\n\n"); - - self iprintln("Saved!!! to " + filename); - - if (fd > 0) - FS_FClose(fd); - } - else - { - if(level.autoLink) - { - self iPrintlnBold("Auto link disabled"); - level.autoLink = false; - level.wpToLink = -1; - } - else - { - self iPrintlnBold("Auto link enabled"); - level.autoLink = true; - level.wpToLink = self.closest; - } - } - - self.command = undefined; - - while(self useButtonPressed() && self attackButtonPressed()) - wait 0.05; - } -} - -LoadWaypoints() -{ - self DeleteAllWaypoints(); - self iPrintlnBold("Loading WPS..."); - load_waypoints(); - - wait 1; - - self checkForWarnings(); -} - -checkForWarnings() -{ - if(level.waypointCount <= 0) - self iprintln("WARNING: waypointCount is "+level.waypointCount); - - if(level.waypointCount != level.waypoints.size) - self iprintln("WARNING: waypointCount is not "+level.waypoints.size); - - for(i = 0; i < level.waypointCount; i++) - { - if(!isDefined(level.waypoints[i])) - { - self iprintln("WARNING: waypoint "+i+" is undefined"); - continue; - } - - if(level.waypoints[i].childCount <= 0) - self iprintln("WARNING: waypoint "+i+" childCount is "+level.waypoints[i].childCount); - else - { - if (!isDefined(level.waypoints[i].children) || !isDefined(level.waypoints[i].children.size)) - { - self iprintln("WARNING: waypoint "+i+" children is not defined"); - } - else - { - if(level.waypoints[i].childCount != level.waypoints[i].children.size) - self iprintln("WARNING: waypoint "+i+" childCount is not "+level.waypoints[i].children.size); - - for (h = 0; h < level.waypoints[i].childCount; h++) - { - child = level.waypoints[i].children[h]; - - if(!isDefined(level.waypoints[child])) - self iprintln("WARNING: waypoint "+i+" child "+child+" is undefined"); - else if(child == i) - self iprintln("WARNING: waypoint "+i+" child "+child+" is itself"); - } - } - } - - if(!isDefined(level.waypoints[i].type)) - { - self iprintln("WARNING: waypoint "+i+" type is undefined"); - continue; - } - - if(!isDefined(level.waypoints[i].angles) && (level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || (level.waypoints[i].type == "crouch" && level.waypoints[i].childCount == 1) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade")) - self iprintln("WARNING: waypoint "+i+" angles is undefined"); - } -} - -DeleteAllWaypoints() -{ - level.waypoints = []; - level.waypointCount = 0; - level.waypointsKDTree = WaypointsToKDTree(); - - level.waypointsCamp = []; - level.waypointsTube = []; - level.waypointsGren = []; - level.waypointsClay = []; - - self iprintln("DelAllWps"); -} - -DeleteWaypoint(nwp) -{ - if(nwp == -1 || distance(self.origin, level.waypoints[nwp].origin) > getDvarFloat("bots_main_debug_minDist")) - { - self iprintln("No close enough waypoint to delete."); - return; - } - - level.wpToLink = -1; - - for(i = 0; i < level.waypoints[nwp].childCount; i++) - { - child = level.waypoints[nwp].children[i]; - - level.waypoints[child].children = array_remove(level.waypoints[child].children, nwp); - - level.waypoints[child].childCount = level.waypoints[child].children.size; - } - - for(i = 0; i < level.waypointCount; i++) - { - for(h = 0; h < level.waypoints[i].childCount; h++) - { - if(level.waypoints[i].children[h] > nwp) - level.waypoints[i].children[h]--; - } - } - - for ( entry = 0; entry < level.waypointCount; entry++ ) - { - if ( entry == nwp ) - { - while ( entry < level.waypointCount-1 ) - { - level.waypoints[entry] = level.waypoints[entry+1]; - entry++; - } - level.waypoints[entry] = undefined; - break; - } - } - level.waypointCount--; - - self iprintln("DelWp "+nwp); -} - -addWaypoint(pos) -{ - level.waypoints[level.waypointCount] = spawnstruct(); - - level.waypoints[level.waypointCount].origin = pos; - - if(self AdsButtonPressed()) - level.waypoints[level.waypointCount].type = "climb"; - else if(self AttackButtonPressed() && self UseButtonPressed()) - level.waypoints[level.waypointCount].type = "tube"; - else if(self AttackButtonPressed()) - level.waypoints[level.waypointCount].type = "grenade"; - else if(self UseButtonPressed()) - level.waypoints[level.waypointCount].type = "claymore"; - else - level.waypoints[level.waypointCount].type = self getStance(); - - level.waypoints[level.waypointCount].angles = self getPlayerAngles(); - - level.waypoints[level.waypointCount].children = []; - level.waypoints[level.waypointCount].childCount = 0; - - self iprintln(level.waypoints[level.waypointCount].type + " Waypoint "+ level.waypointCount +" Added at "+pos); - - if(level.autoLink) - { - if(level.wpToLink == -1) - level.wpToLink = level.waypointCount - 1; - - level.waypointCount++; - self LinkWaypoint(level.waypointCount - 1); - } - else - { - level.waypointCount++; - } -} - -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; - return; - } - - if(level.wpToLink == -1 || nwp == level.wpToLink) - { - 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].childCount = level.waypoints[nwp].children.size; - level.waypoints[level.wpToLink].childCount = level.waypoints[level.wpToLink].children.size; - - 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; - return; - } - - if(level.wpToLink == -1 || nwp == level.wpToLink) - { - level.wpToLink = nwp; - self iprintln("Waypoint Link Started "+nwp); - return; - } - - weGood = true; - for(i = 0; i < level.waypoints[level.wpToLink].childCount; i++) - { - if(level.waypoints[level.wpToLink].children[i] == nwp) - { - weGood = false; - break; - } - } - if(weGood) - { - for(i = 0; i < level.waypoints[nwp].childCount; i++) - { - if(level.waypoints[nwp].children[i] == level.wpToLink) - { - weGood = false; - break; - } - } - } - - if (!weGood ) - { - self iprintln("Waypoint Link Cancelled "+nwp+" and "+level.wpToLink+" already linked."); - level.wpToLink = -1; - return; - } - - level.waypoints[level.wpToLink].children[level.waypoints[level.wpToLink].childcount] = nwp; - level.waypoints[level.wpToLink].childcount++; - level.waypoints[nwp].children[level.waypoints[nwp].childcount] = level.wpToLink; - level.waypoints[nwp].childcount++; - - self iprintln("Waypoint " + nwp + " Linked to " + level.wpToLink); - level.wpToLink = -1; -} - -destroyOnDeath(hud) -{ - hud endon("death"); - self waittill_either("death","disconnect"); - hud destroy(); -} - -textScroll(string) -{ - self endon("death"); - self endon("disconnect"); - //thanks ActionScript - - back = createBar((0,0,0), 1000, 30); - back setPoint("CENTER", undefined, 0, 220); - self thread destroyOnDeath(back); - - text = createFontString("default", 1.5); - text setText(string); - self thread destroyOnDeath(text); - - for (;;) - { - text setPoint("CENTER", undefined, 1200, 220); - text setPoint("CENTER", undefined, -1200, 220, 20); - wait 20; - } -} +/* + _wp_editor + Author: INeedGames + Date: 09/26/2020 + The ingame waypoint editor. +*/ + +#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_debug" ) == "" ) + setDvar( "bots_main_debug", 0 ); + + if ( !getDVarint( "bots_main_debug" ) ) + return; + + if ( !getDVarint( "developer" ) ) + { + setdvar( "developer_script", 1 ); + setdvar( "developer", 1 ); + + setdvar( "sv_mapRotation", "map " + getDvar( "mapname" ) ); + exitLevel( false ); + } + + setDvar( "bots_main", 0 ); + setdvar( "bots_main_menu", 0 ); + setdvar( "bots_manage_fill_mode", 0 ); + setdvar( "bots_manage_fill", 0 ); + setdvar( "bots_manage_add", 0 ); + setdvar( "bots_manage_fill_kick", 1 ); + setDvar( "bots_manage_fill_spec", 1 ); + + if ( getDvar( "bots_main_debug_distance" ) == "" ) + setDvar( "bots_main_debug_distance", 512.0 ); + + if ( getDvar( "bots_main_debug_cone" ) == "" ) + setDvar( "bots_main_debug_cone", 0.65 ); + + if ( getDvar( "bots_main_debug_minDist" ) == "" ) + setDvar( "bots_main_debug_minDist", 32.0 ); + + if ( getDvar( "bots_main_debug_drawThrough" ) == "" ) + setDvar( "bots_main_debug_drawThrough", false ); + + if ( getDvar( "bots_main_debug_commandWait" ) == "" ) + setDvar( "bots_main_debug_commandWait", 0.5 ); + + if ( getDvar( "bots_main_debug_framerate" ) == "" ) + setDvar( "bots_main_debug_framerate", 58 ); + + if ( getDvar( "bots_main_debug_lineDuration" ) == "" ) + setDvar( "bots_main_debug_lineDuration", 3 ); + + if ( getDvar( "bots_main_debug_printDuration" ) == "" ) + setDvar( "bots_main_debug_printDuration", 3 ); + + if ( getDvar( "bots_main_debug_debugRate" ) == "" ) + setDvar( "bots_main_debug_debugRate", 0.5 ); + + setDvar( "player_sustainAmmo", 1 ); + + level.waypoints = []; + level.waypointCount = 0; + + level waittill( "connected", player ); + + player thread onPlayerSpawned(); +} + +onPlayerSpawned() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + self waittill( "spawned_player" ); + self thread beginDebug(); + } +} + +beginDebug() +{ + self endon( "disconnect" ); + self endon( "death" ); + + level.wpToLink = -1; + level.autoLink = false; + self.closest = -1; + self.command = undefined; + + self clearPerks(); + self takeAllWeapons(); + self.specialty = []; + self giveWeapon( "m16_gl_mp" ); + self SetActionSlot( 3, "altMode" ); + self giveWeapon( "frag_grenade_mp" ); + self freezecontrols( false ); + + self thread debug(); + self thread addWaypoints(); + self thread linkWaypoints(); + self thread deleteWaypoints(); + self thread watchSaveWaypointsCommand(); + self thread sayExtras(); + + self thread textScroll( "^1SecondaryOffhand - ^2Add Waypoint; ^3MeleeButton - ^4Link Waypoint; ^5FragButton - ^6Delete Waypoint; ^7UseButton + AttackButton - ^8Save" ); +} + +sayExtras() +{ + self endon( "disconnect" ); + self endon( "death" ); + self iprintln( "Making a crouch waypoint with only one link..." ); + self iprintln( "Makes a camping waypoint." ); +} + +debug() +{ + self endon( "disconnect" ); + self endon( "death" ); + + self setClientDvar( "com_maxfps", getDvarInt( "bots_main_debug_framerate" ) ); + + for ( ;; ) + { + wait getDvarFloat( "bots_main_debug_debugRate" ); + + if ( isDefined( self.command ) ) + continue; + + closest = -1; + myEye = self getTagOrigin( "j_head" ); + myAngles = self GetPlayerAngles(); + + for ( i = 0; i < level.waypointCount; i++ ) + { + if ( closest == -1 || closer( self.origin, level.waypoints[i].origin, level.waypoints[closest].origin ) ) + closest = i; + + wpOrg = level.waypoints[i].origin + ( 0, 0, 25 ); + + if ( distance( level.waypoints[i].origin, self.origin ) < getDvarFloat( "bots_main_debug_distance" ) && ( bulletTracePassed( myEye, wpOrg, false, self ) || getDVarint( "bots_main_debug_drawThrough" ) ) ) + { + for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- ) + line( wpOrg, level.waypoints[level.waypoints[i].children[h]].origin + ( 0, 0, 25 ), ( 1, 0, 1 ), 1, 1, getDvarInt( "bots_main_debug_lineDuration" ) ); + + if ( getConeDot( wpOrg, myEye, myAngles ) > getDvarFloat( "bots_main_debug_cone" ) ) + print3d( wpOrg, i, ( 1, 0, 0 ), 2, 1, 6 ); + + if ( isDefined( level.waypoints[i].angles ) && level.waypoints[i].type != "stand" ) + line( wpOrg, wpOrg + AnglesToForward( level.waypoints[i].angles ) * 64, ( 1, 1, 1 ), 1, 1, getDvarInt( "bots_main_debug_lineDuration" ) ); + } + } + + self.closest = closest; + + if ( closest != -1 ) + { + stringChildren = ""; + + for ( i = 0; i < level.waypoints[closest].children.size; i++ ) + { + if ( i != 0 ) + stringChildren = stringChildren + "," + level.waypoints[closest].children[i]; + else + stringChildren = stringChildren + level.waypoints[closest].children[i]; + } + + print3d( level.waypoints[closest].origin + ( 0, 0, 35 ), stringChildren, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) ); + + print3d( level.waypoints[closest].origin + ( 0, 0, 15 ), level.waypoints[closest].type, ( 0, 1, 0 ), 2, 1, getDvarInt( "bots_main_debug_printDuration" ) ); + } + } +} + +AddWaypoints() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + while ( !self SecondaryOffhandButtonPressed() || isDefined( self.command ) ) + wait 0.05; + + pos = self getOrigin(); + self.command = true; + + self iprintln( "Adding a waypoint..." ); + self iprintln( "ADS - climb; Attack + Use - tube" ); + self iprintln( "Attack - grenade; Use - claymore" ); + self iprintln( "Else(wait) - your stance" ); + + wait getDvarFloat( "bots_main_debug_commandWait" ); + + self addWaypoint( pos ); + + self.command = undefined; + + while ( self SecondaryOffhandButtonPressed() ) + wait 0.05; + } +} + +linkWaypoints() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + while ( !self MeleeButtonPressed() || isDefined( self.command ) ) + wait 0.05; + + self.command = true; + + self iprintln( "ADS - Unlink; Else(wait) - Link" ); + + wait getDvarFloat( "bots_main_debug_commandWait" ); + + if ( !self adsButtonPressed() ) + self LinkWaypoint( self.closest ); + else + self UnLinkWaypoint( self.closest ); + + self.command = undefined; + + while ( self MeleeButtonPressed() ) + wait 0.05; + } +} + +deleteWaypoints() +{ + self endon( "disconnect" ); + self endon( "death" ); + + for ( ;; ) + { + while ( !self fragButtonPressed() || isDefined( self.command ) ) + wait 0.05; + + self.command = true; + + self iprintln( "Attack - DeleteAll; ADS - Load" ); + self iprintln( "Else(wait) - Delete" ); + + wait getDvarFloat( "bots_main_debug_commandWait" ); + + if ( self attackButtonPressed() ) + self deleteAllWaypoints(); + else if ( self adsButtonPressed() ) + self LoadWaypoints(); + else + self DeleteWaypoint( self.closest ); + + self.command = undefined; + + while ( self fragButtonPressed() ) + wait 0.05; + } +} + +watchSaveWaypointsCommand() +{ + self endon( "death" ); + self endon( "disconnect" ); + + for ( ;; ) + { + while ( !self useButtonPressed() || !self attackButtonPressed() || isDefined( self.command ) ) + wait 0.05; + + self.command = true; + + self iprintln( "ADS - Autolink; Else(wait) - Save" ); + + wait getDvarFloat( "bots_main_debug_commandWait" ); + + if ( !self adsButtonPressed() ) + { + self checkForWarnings(); + wait 1; + + logprint( "***********ABiliTy's WPDump**************\n\n" ); + logprint( "\n\n\n\n" ); + mpnm = getMapName( getdvar( "mapname" ) ); + logprint( "\n\n" + mpnm + "()\n{\n/*" ); + logprint( "*/waypoints = [];\n/*" ); + + for ( i = 0; i < level.waypointCount; i++ ) + { + logprint( "*/waypoints[" + i + "] = spawnstruct();\n/*" ); + logprint( "*/waypoints[" + i + "].origin = " + level.waypoints[i].origin + ";\n/*" ); + logprint( "*/waypoints[" + i + "].type = \"" + level.waypoints[i].type + "\";\n/*" ); + + for ( c = 0; c < level.waypoints[i].children.size; c++ ) + { + logprint( "*/waypoints[" + i + "].children[" + c + "] = " + level.waypoints[i].children[c] + ";\n/*" ); + } + + if ( isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) ) + logprint( "*/waypoints[" + i + "].angles = " + level.waypoints[i].angles + ";\n/*" ); + } + + logprint( "*/return waypoints;\n}\n\n\n\n" ); + + filename = "waypoints/" + getdvar( "mapname" ) + "_wp.csv"; + fd = FS_FOpen( filename, "write" ); + + PrintLn( "********* Start Bot Warfare WPDump *********" ); + PrintLn( level.waypointCount ); + + if ( fd > 0 ) + { + if ( !FS_WriteLine( fd, level.waypointCount + "" ) ) + { + FS_FClose( fd ); + fd = 0; + } + } + + for ( i = 0; i < level.waypointCount; i++ ) + { + str = ""; + wp = level.waypoints[i]; + + str += wp.origin[0] + " " + wp.origin[1] + " " + wp.origin[2] + ","; + + for ( h = 0; h < wp.children.size; h++ ) + { + str += wp.children[h]; + + if ( h < wp.children.size - 1 ) + str += " "; + } + + str += "," + wp.type + ","; + + if ( isDefined( wp.angles ) ) + str += wp.angles[0] + " " + wp.angles[1] + " " + wp.angles[2] + ","; + else + str += ","; + + str += ","; + + PrintLn( str ); + + if ( fd > 0 ) + { + if ( !FS_WriteLine( fd, str ) ) + { + FS_FClose( fd ); + fd = 0; + } + } + } + + PrintLn( "\n\n\n\n\n\n" ); + + self iprintln( "Saved!!! to " + filename ); + + if ( fd > 0 ) + FS_FClose( fd ); + } + else + { + if ( level.autoLink ) + { + self iPrintlnBold( "Auto link disabled" ); + level.autoLink = false; + level.wpToLink = -1; + } + else + { + self iPrintlnBold( "Auto link enabled" ); + level.autoLink = true; + level.wpToLink = self.closest; + } + } + + self.command = undefined; + + while ( self useButtonPressed() && self attackButtonPressed() ) + wait 0.05; + } +} + +LoadWaypoints() +{ + self DeleteAllWaypoints(); + self iPrintlnBold( "Loading WPS..." ); + load_waypoints(); + + wait 1; + + self checkForWarnings(); +} + +checkForWarnings() +{ + if ( level.waypointCount <= 0 ) + self iprintln( "WARNING: waypointCount is " + level.waypointCount ); + + if ( level.waypointCount != level.waypoints.size ) + self iprintln( "WARNING: waypointCount is not " + level.waypoints.size ); + + for ( i = 0; i < level.waypointCount; i++ ) + { + if ( !isDefined( level.waypoints[i] ) ) + { + self iprintln( "WARNING: waypoint " + i + " is undefined" ); + continue; + } + + if ( level.waypoints[i].children.size <= 0 ) + self iprintln( "WARNING: waypoint " + i + " childCount is " + level.waypoints[i].children.size ); + else + { + if ( !isDefined( level.waypoints[i].children ) || !isDefined( level.waypoints[i].children.size ) ) + { + self iprintln( "WARNING: waypoint " + i + " children is not defined" ); + } + else + { + for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- ) + { + child = level.waypoints[i].children[h]; + + if ( !isDefined( level.waypoints[child] ) ) + self iprintln( "WARNING: waypoint " + i + " child " + child + " is undefined" ); + else if ( child == i ) + self iprintln( "WARNING: waypoint " + i + " child " + child + " is itself" ); + } + } + } + + if ( !isDefined( level.waypoints[i].type ) ) + { + self iprintln( "WARNING: waypoint " + i + " type is undefined" ); + continue; + } + + if ( !isDefined( level.waypoints[i].angles ) && ( level.waypoints[i].type == "claymore" || level.waypoints[i].type == "tube" || ( level.waypoints[i].type == "crouch" && level.waypoints[i].children.size == 1 ) || level.waypoints[i].type == "climb" || level.waypoints[i].type == "grenade" ) ) + self iprintln( "WARNING: waypoint " + i + " angles is undefined" ); + } +} + +DeleteAllWaypoints() +{ + level.waypoints = []; + level.waypointCount = 0; + + self iprintln( "DelAllWps" ); +} + +DeleteWaypoint( nwp ) +{ + if ( nwp == -1 || distance( self.origin, level.waypoints[nwp].origin ) > getDvarFloat( "bots_main_debug_minDist" ) ) + { + self iprintln( "No close enough waypoint to delete." ); + return; + } + + level.wpToLink = -1; + + for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- ) + { + child = level.waypoints[nwp].children[i]; + + level.waypoints[child].children = array_remove( level.waypoints[child].children, nwp ); + } + + for ( i = 0; i < level.waypointCount; i++ ) + { + for ( h = level.waypoints[i].children.size - 1; h >= 0; h-- ) + { + if ( level.waypoints[i].children[h] > nwp ) + level.waypoints[i].children[h]--; + } + } + + for ( entry = 0; entry < level.waypointCount; entry++ ) + { + if ( entry == nwp ) + { + while ( entry < level.waypointCount - 1 ) + { + level.waypoints[entry] = level.waypoints[entry + 1]; + entry++; + } + + level.waypoints[entry] = undefined; + break; + } + } + + level.waypointCount--; + + self iprintln( "DelWp " + nwp ); +} + +addWaypoint( pos ) +{ + level.waypoints[level.waypointCount] = spawnstruct(); + + level.waypoints[level.waypointCount].origin = pos; + + if ( self AdsButtonPressed() ) + level.waypoints[level.waypointCount].type = "climb"; + else if ( self AttackButtonPressed() && self UseButtonPressed() ) + level.waypoints[level.waypointCount].type = "tube"; + else if ( self AttackButtonPressed() ) + level.waypoints[level.waypointCount].type = "grenade"; + else if ( self UseButtonPressed() ) + level.waypoints[level.waypointCount].type = "claymore"; + else + level.waypoints[level.waypointCount].type = self getStance(); + + level.waypoints[level.waypointCount].angles = self getPlayerAngles(); + + level.waypoints[level.waypointCount].children = []; + + self iprintln( level.waypoints[level.waypointCount].type + " Waypoint " + level.waypointCount + " Added at " + pos ); + + if ( level.autoLink ) + { + if ( level.wpToLink == -1 ) + level.wpToLink = level.waypointCount - 1; + + level.waypointCount++; + self LinkWaypoint( level.waypointCount - 1 ); + } + else + { + level.waypointCount++; + } +} + +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; + return; + } + + if ( level.wpToLink == -1 || nwp == level.wpToLink ) + { + 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 ); + + 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; + return; + } + + if ( level.wpToLink == -1 || nwp == level.wpToLink ) + { + level.wpToLink = nwp; + self iprintln( "Waypoint Link Started " + nwp ); + return; + } + + weGood = true; + + for ( i = level.waypoints[level.wpToLink].children.size - 1; i >= 0; i-- ) + { + if ( level.waypoints[level.wpToLink].children[i] == nwp ) + { + weGood = false; + break; + } + } + + if ( weGood ) + { + for ( i = level.waypoints[nwp].children.size - 1; i >= 0; i-- ) + { + if ( level.waypoints[nwp].children[i] == level.wpToLink ) + { + weGood = false; + break; + } + } + } + + if ( !weGood ) + { + 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; + + self iprintln( "Waypoint " + nwp + " Linked to " + level.wpToLink ); + level.wpToLink = -1; +} + +destroyOnDeath( hud ) +{ + hud endon( "death" ); + self waittill_either( "death", "disconnect" ); + hud destroy(); +} + +textScroll( string ) +{ + self endon( "death" ); + self endon( "disconnect" ); + //thanks ActionScript + + back = createBar( ( 0, 0, 0 ), 1000, 30 ); + back setPoint( "CENTER", undefined, 0, 220 ); + self thread destroyOnDeath( back ); + + text = createFontString( "default", 1.5 ); + text setText( string ); + self thread destroyOnDeath( text ); + + for ( ;; ) + { + text setPoint( "CENTER", undefined, 1200, 220 ); + text setPoint( "CENTER", undefined, -1200, 220, 20 ); + wait 20; + } +} diff --git a/out/readme.txt b/out/readme.txt index 6bde1ce..86ac30f 100644 --- a/out/readme.txt +++ b/out/readme.txt @@ -1,4 +1,4 @@ -# CoD4x Bot Warfare +# CoD4x Bot Warfare v2.1.0 Bot Warfare is a GSC mod for the CoD4x project. It aims to add playable AI to the multiplayer games of CoD4. @@ -12,7 +12,7 @@ Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your s ## Installation 0. Make sure that CoD4x server + client is installed, updated and working properly. - - Go to https://cod4x.me/ and download the Windows Server zip file. Move the contents of 'cod4x-windows-server' into your CoD4 game folder. + - Go to https://cod4x.ovh/ and download the Windows Server zip file. Move the contents of 'cod4x-windows-server' into your CoD4 game folder. 1. Locate your CoD4x server install folder. 2. Move the files/folders found in 'Add to root of CoD4x server' from the Bot Warfare release archive you downloaded to the root of your CoD4x server folder. - The folder/file structure should follow as '.CoD4x server folder\main_shared\maps\mp\bots\_bot.gsc'. @@ -30,6 +30,17 @@ Make sure to disable this DVAR by adding 'set bots_main_firstIsHost 0' in your s - Pressing the menu button again closes menus. ## Changelog +- v2.1.0 + - Bot chatter system, bots_main_chat + - Greatly reduce script variable usage + - Improved bots mantling and stuck + - Fix some runtime errors + - Bots sprint more + - Improved bots sight on enemies + - Bots do random actions while waiting at an objective + - Improved bots from getting stuck + - Better bot difficulty management, bots_skill_min and bots_skill_max + - v2.0.1 - Reduced bots crouching - Increased bots sprinting diff --git a/out/ss.jpg b/out/ss.jpg new file mode 100644 index 0000000..98cd01d Binary files /dev/null and b/out/ss.jpg differ diff --git a/out/ss.png b/out/ss.png deleted file mode 100644 index 58e2b96..0000000 Binary files a/out/ss.png and /dev/null differ