Advertisement
Guest User

_bot.gsc

a guest
Mar 16th, 2013
355
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 62.43 KB | None | 0 0
  1. #include common_scripts\utility;
  2. #include maps\mp\_utility;
  3.  
  4. init()
  5. {
  6.     level.bot_offline = false;
  7.     level.bot_weapon_ids = [];
  8.    
  9.     bot_spawner_Once();
  10.  
  11.  
  12.     // bots have already been spawned (happens on round changes)
  13.     if ( IsDefined( game[ "bots_spawned" ] ) )
  14.     {
  15.         return;
  16.     }
  17.  
  18.     if ( level.bot_offline )
  19.     {
  20.         humans = GetDvarInt( #"splitscreen_playerCount" );
  21.         bot_friends = GetDvarInt( #"splitscreen_botFriends" );
  22.         bot_enemies = GetDvarInt( #"splitscreen_botEnemies" );
  23.         bot_difficulty = GetDvar( #"splitscreen_botDifficulty" );
  24.     }
  25.     else
  26.     {
  27.         if( level.console )
  28.             humans = GetDvarInt( #"party_playerCount" );
  29.         else
  30.             humans = 1;
  31.         bot_friends = GetDvarInt( #"bot_friends" );
  32.         bot_enemies = GetDvarInt( #"bot_enemies" );
  33.         bot_difficulty = GetDvar( #"bot_difficulty" );
  34.     }
  35.  
  36.     // all humans playing
  37.     if ( humans >= bot_friends + bot_enemies )
  38.     {
  39.         return;
  40.     }
  41.  
  42.     level.autoassign = ::basic_training_auto_assign;
  43.     level thread bot_kick_think();
  44.    
  45.     // calculate the number of friendly bots
  46.     if ( level.teambased )
  47.     {
  48.         bot_num_friendly = bot_friends - humans;
  49.         bot_num_friendly = clamp( bot_num_friendly, 0, bot_num_friendly );
  50.     }
  51.     else
  52.     {
  53.         bot_num_friendly = 0;
  54.     }
  55.  
  56.     // calculate the number of enemy bots
  57.     if ( level.teambased )
  58.     {
  59.         human_enemies = humans - bot_friends;
  60.         human_enemies = clamp( human_enemies, 0, human_enemies );
  61.  
  62.         bot_num_enemy = bot_enemies - human_enemies;
  63.     }
  64.     else
  65.     {
  66.         bot_num_enemy = bot_enemies - humans + 1; /* + 1 for the host */
  67.     }
  68.  
  69.     // sanity check
  70.     if ( bot_num_enemy + bot_num_friendly <= 0 )
  71.     {
  72.         return;
  73.     }
  74.    
  75.     bot_wait_for_host();
  76.     player = GetHostPlayer();
  77.        
  78.     /#
  79.         SetDvar( "sv_botsAllowMovement", "1" );
  80.         SetDvar( "sv_botsPressAttackBtn", "1" );
  81.         SetDvar( "sv_botsPressMeleeBtn", "1" );
  82.         SetDvar( "sv_botsIgnoreHumans", "0" );
  83.         SetDvar( "scr_botsHasPlayerWeapon", "0" );
  84.         SetDvar( "scr_botsGrenadesOnly", "0" );
  85.         SetDvar( "scr_botsSpecialGrenadesOnly", "0" );
  86.     #/
  87.  
  88.     if ( bot_difficulty == "" )
  89.     {
  90.         bot_difficulty = "normal";
  91.     }
  92.  
  93.     bot_set_difficulty( bot_difficulty );
  94.     team = player.pers[ "team" ];
  95.     game[ "bots_spawned" ] = 1;
  96.  
  97.     // spawn the enemies first
  98.     spawned_bots = 0;
  99.  
  100.     equipment_weights = array( 0, 1, 1, 2, 2, 2, 2, 3, 3, 4 );
  101.     can_use_equipment = random( equipment_weights );
  102.  
  103.     while ( spawned_bots < bot_num_enemy )
  104.     {
  105.         wait( 0.25 );
  106.         bot = AddTestClient();
  107.  
  108.         if ( !IsDefined( bot ) )
  109.         {
  110.             continue;
  111.         }
  112.                    
  113.         spawned_bots++;
  114.         bot.pers[ "isBot" ] = true;
  115.         bot.equipment_enabled = false;
  116.  
  117.         if ( can_use_equipment > 0 )
  118.         {
  119.             bot.equipment_enabled = true;
  120.             can_use_equipment--;
  121.         }
  122.  
  123.         bot thread bot_spawn_think( getOtherTeam( team ) );
  124.     }
  125.  
  126.     // friendlies
  127.     spawned_bots = 0;
  128.     can_use_equipment = random( equipment_weights );
  129.  
  130.     while ( spawned_bots < bot_num_friendly )
  131.     {
  132.         wait( 0.25 );
  133.         bot = AddTestClient();
  134.  
  135.         if ( !IsDefined( bot ) )
  136.         {
  137.             continue;
  138.         }
  139.                    
  140.         spawned_bots++;
  141.         bot.pers[ "isBot" ] = true;
  142.         bot.equipment_enabled = false;
  143.  
  144.         if ( can_use_equipment > 0 )
  145.         {
  146.             bot.equipment_enabled = true;
  147.             can_use_equipment--;
  148.         }
  149.  
  150.         bot thread bot_spawn_think( team );
  151.     }
  152. }
  153.  
  154. basic_training_auto_assign()
  155. {
  156.     host = GetHostPlayer();
  157.  
  158.     if ( host == self )
  159.     {
  160.         self maps\mp\gametypes\_globallogic_ui::menuAutoAssign();
  161.         return;
  162.     }
  163.  
  164.     if ( self is_bot() )
  165.     {
  166.         if ( !level.teambased )
  167.         {
  168.             self maps\mp\gametypes\_globallogic_ui::menuAutoAssign();
  169.         }
  170.         return;
  171.     }
  172.  
  173.     bot_wait_for_host();
  174.     host = GetHostPlayer();
  175.     host_team = host.pers[ "team" ];
  176.  
  177.     player_counts = self maps\mp\gametypes\_teams::CountPlayers();
  178.  
  179.     if ( level.bot_offline )
  180.     {
  181.         friends = GetDvarInt( #"splitscreen_botFriends" ) - player_counts[ host_team ];
  182.     }
  183.     else
  184.     {
  185.         friends = GetDvarInt( #"bot_friends" ) - player_counts[ host_team ];
  186.     }
  187.  
  188.     if ( friends > 0 )
  189.     {
  190.         assignment = host_team;
  191.     }
  192.     else
  193.     {
  194.         assignment = getOtherTeam( host_team );
  195.     }
  196.  
  197.     // remainder of this function is taken directly from _globallogic_ui::menuAutoAssign()
  198.     self.pers["team"] = assignment;
  199.     self.team = assignment;
  200.     self.pers["class"] = undefined;
  201.     self.class = undefined;
  202.     self.pers["weapon"] = undefined;
  203.     self.pers["savedmodel"] = undefined;
  204.  
  205.     self maps\mp\gametypes\_globallogic_ui::updateObjectiveText();
  206.  
  207.     if ( level.teamBased )
  208.         self.sessionteam = assignment;
  209.     else
  210.     {
  211.         self.sessionteam = "none";
  212.         self.ffateam = assignment;
  213.     }
  214.    
  215.     if ( !isAlive( self ) )
  216.         self.statusicon = "hud_status_dead";
  217.    
  218.     self notify("joined_team");
  219.     level notify( "joined_team" );
  220.     self notify("end_respawn");
  221.    
  222.     if( isPregameGameStarted() )
  223.     {
  224.         pclass = self GetPregameClass();
  225.         if( IsDefined( pclass ) )
  226.         {
  227.             self closeMenu();
  228.             self closeInGameMenu();
  229.            
  230.             self.selectedClass = true;
  231.             self [[level.class]](pclass);
  232.             return;
  233.         }
  234.     }
  235.  
  236.     self maps\mp\gametypes\_globallogic_ui::beginClassChoice();
  237.     self setclientdvar( "g_scriptMainMenu", game[ "menu_class_" + self.pers["team"] ] );
  238. }
  239.  
  240. bot_wait_for_host()
  241. {
  242.     host = GetHostPlayer();
  243.        
  244.     while ( !IsDefined( host ) )
  245.     {
  246.         wait( 0.05 );
  247.         host = GetHostPlayer();
  248.     }
  249.  
  250.     while ( !IsDefined( host.pers[ "team" ] ) )
  251.     {
  252.         wait( 0.05 );
  253.     }
  254.    
  255.     while ( host.pers[ "team" ] != "allies" && host.pers[ "team" ] != "axis" )
  256.     {
  257.         wait( 0.05 );
  258.     }
  259. }
  260.  
  261. bot_spawn_think( team )
  262. {
  263.     self endon( "disconnect" );
  264.  
  265.     while( !IsDefined( self.pers["team"] ) )
  266.     {
  267.         wait .05;
  268.     }
  269.  
  270.     if ( level.teambased )
  271.     {
  272.         self notify( "menuresponse", game["menu_team"], team );
  273.         wait 0.5;
  274.     }
  275.  
  276.     self bot_set_rank();
  277.  
  278.     while( 1 )
  279.     {
  280.         self notify( "menuresponse", "changeclass", "smg_mp" );
  281.         self waittill( "spawned_player" );
  282.         wait ( 0.10 );
  283.     }
  284. }
  285.  
  286. bot_kick_think()
  287. {
  288.     for ( ;; )
  289.     {
  290.         level waittill( "bot_kicked", team );
  291.         level thread bot_reconnect_bot( team );
  292.     }
  293. }
  294.  
  295. bot_reconnect_bot( team )
  296. {
  297.     wait( RandomIntRange( 3, 15 ) );
  298.  
  299.     bot = AddTestClient();
  300.  
  301.     if ( !IsDefined( bot ) )
  302.     {
  303.         return;
  304.     }
  305.                    
  306.     bot.pers[ "isBot" ] = true;
  307.     bot.equipment_enabled = false;
  308.  
  309.     if ( cointoss() )
  310.     {
  311.         bot.equipment_enabled = true;
  312.     }
  313.  
  314.     bot thread bot_spawn_think( team );
  315. }
  316.  
  317. bot_set_rank()
  318. {
  319.     players = get_players();
  320.  
  321.     ranks = [];
  322.     bot_ranks = [];
  323.     human_ranks = [];
  324.  
  325.     if ( !IsDefined( self.bot ) )
  326.     {
  327.         self.bot = [];
  328.     }
  329.    
  330.     for ( i = 0; i < players.size; i++ )
  331.     {
  332.         if ( players[i] == self )
  333.             continue;
  334.        
  335.         if ( players[i] is_bot() && IsDefined( players[i].bot ) && IsDefined( players[i].bot[ "rank" ] ) )
  336.         {
  337.             bot_ranks[ bot_ranks.size ] = players[i].bot[ "rank" ];
  338.         }
  339.         else if ( !players[i] is_bot() && !players[i] isdemoclient() && IsDefined( players[i].pers[ "rank" ] ) )
  340.         {
  341.             human_ranks[ human_ranks.size ] = players[i].pers[ "rank" ];
  342.         }
  343.     }
  344.  
  345.     if( !human_ranks.size )
  346.         human_ranks[ human_ranks.size ] = 10;
  347.  
  348.     human_avg = array_average( human_ranks );
  349.  
  350.     while ( bot_ranks.size + human_ranks.size < 5 )
  351.     {
  352.         // add some random ranks for better random number distribution
  353.         rank = human_avg + RandomIntRange( -10, 10 );
  354.         human_ranks[ human_ranks.size ] = rank;
  355.     }
  356.  
  357.     ranks = array_combine( human_ranks, bot_ranks );
  358.  
  359.     avg = array_average( ranks );
  360.     s = array_std_deviation( ranks, avg );
  361.    
  362.     rank = Int( random_normal_distribution( avg, s, 0, level.maxRank ) );
  363.  
  364.     self setRank( rank );
  365.     self.bot[ "rank" ] = rank;
  366.     self.pers[ "rank" ] = rank;
  367.  
  368.     self.pers[ "rankxp" ] = maps\mp\gametypes\_rank::getRankInfoMinXP( rank );
  369.  
  370.     if ( self.kills == 1 )
  371.     {
  372.         self.kills = 0;
  373.         self.pers[ "bot_perk" ] = true;
  374.     }
  375.     else
  376.     {
  377.         self.pers[ "bot_perk" ] = false;
  378.     }
  379. }
  380.  
  381. bot_set_difficulty( difficulty )
  382. {
  383.     if ( difficulty == "fu" )
  384.     {
  385.         SetDvar( "sv_botMinDeathTime",      "250" );
  386.         SetDvar( "sv_botMaxDeathTime",      "500" );
  387.         SetDvar( "sv_botMinFireTime",       "100" );
  388.         SetDvar( "sv_botMaxFireTime",       "300" );
  389.         SetDvar( "sv_botYawSpeed",          "14" );
  390.         SetDvar( "sv_botYawSpeedAds",       "14" );
  391.         SetDvar( "sv_botPitchUp",           "-5" );
  392.         SetDvar( "sv_botPitchDown",         "10" );
  393.         SetDvar( "sv_botFov",               "160" );
  394.         SetDvar( "sv_botMinAdsTime",        "3000" );
  395.         SetDvar( "sv_botMaxAdsTime",        "5000" );
  396.         SetDvar( "sv_botMinCrouchTime",     "100" );
  397.         SetDvar( "sv_botMaxCrouchTime",     "400" );
  398.         SetDvar( "sv_botTargetLeadBias",    "2" );
  399.         SetDvar( "sv_botMinReactionTime",   "30" );
  400.         SetDvar( "sv_botMaxReactionTime",   "100" );
  401.         SetDvar( "sv_botStrafeChance",      "1" );
  402.         SetDvar( "sv_botMinStrafeTime",     "3000" );
  403.         SetDvar( "sv_botMaxStrafeTime",     "6000" );
  404.         SetDvar( "scr_help_dist",           "512" );
  405.         SetDvar( "sv_botAllowGrenades",     "1" );
  406.         SetDvar( "sv_botMinGrenadeTime",    "1500" );
  407.         SetDvar( "sv_botMaxGrenadeTime",    "4000" );
  408.         SetDvar( "sv_botSprintDistance",    "512"   );
  409.         SetDvar( "sv_botMeleeDist",         "80" );
  410.     }
  411.     else if ( difficulty == "hard" )
  412.     {
  413.         SetDvar( "sv_botMinDeathTime",      "250" );
  414.         SetDvar( "sv_botMaxDeathTime",      "500" );
  415.         SetDvar( "sv_botMinFireTime",       "400" );
  416.         SetDvar( "sv_botMaxFireTime",       "600" );
  417.         SetDvar( "sv_botYawSpeed",          "8" );
  418.         SetDvar( "sv_botYawSpeedAds",       "10" );
  419.         SetDvar( "sv_botPitchUp",           "-5" );
  420.         SetDvar( "sv_botPitchDown",         "10" );
  421.         SetDvar( "sv_botFov",               "100" );
  422.         SetDvar( "sv_botMinAdsTime",        "3000" );
  423.         SetDvar( "sv_botMaxAdsTime",        "5000" );
  424.         SetDvar( "sv_botMinCrouchTime",     "100" );
  425.         SetDvar( "sv_botMaxCrouchTime",     "400" );
  426.         SetDvar( "sv_botTargetLeadBias",    "2" );
  427.         SetDvar( "sv_botMinReactionTime",   "400" );
  428.         SetDvar( "sv_botMaxReactionTime",   "700" );
  429.         SetDvar( "sv_botStrafeChance",      "0.9" );
  430.         SetDvar( "sv_botMinStrafeTime",     "3000" );
  431.         SetDvar( "sv_botMaxStrafeTime",     "6000" );
  432.         SetDvar( "scr_help_dist",           "384" );
  433.         SetDvar( "sv_botAllowGrenades",     "1" );
  434.         SetDvar( "sv_botMinGrenadeTime",    "1500" );
  435.         SetDvar( "sv_botMaxGrenadeTime",    "4000" );
  436.         SetDvar( "sv_botSprintDistance",    "512"   );
  437.         SetDvar( "sv_botMeleeDist",         "80" );
  438.     }
  439.     else if ( difficulty == "easy" )
  440.     {
  441.         SetDvar( "sv_botMinDeathTime",      "1000" );
  442.         SetDvar( "sv_botMaxDeathTime",      "2000" );
  443.         SetDvar( "sv_botMinFireTime",       "900" );
  444.         SetDvar( "sv_botMaxFireTime",       "1000" );
  445.         SetDvar( "sv_botYawSpeed",          "2" );
  446.         SetDvar( "sv_botYawSpeedAds",       "2.5" );
  447.         SetDvar( "sv_botPitchUp",           "-20" );
  448.         SetDvar( "sv_botPitchDown",         "40" );
  449.         SetDvar( "sv_botFov",               "50" );
  450.         SetDvar( "sv_botMinAdsTime",        "3000" );
  451.         SetDvar( "sv_botMaxAdsTime",        "5000" );
  452.         SetDvar( "sv_botMinCrouchTime",     "4000" );
  453.         SetDvar( "sv_botMaxCrouchTime",     "6000" );
  454.         SetDvar( "sv_botTargetLeadBias",    "8" );
  455.         SetDvar( "sv_botMinReactionTime",   "1200" );
  456.         SetDvar( "sv_botMaxReactionTime",   "1600" );
  457.         SetDvar( "sv_botStrafeChance",      "0.1" );
  458.         SetDvar( "sv_botMinStrafeTime",     "3000" );
  459.         SetDvar( "sv_botMaxStrafeTime",     "6000" );
  460.         SetDvar( "scr_help_dist",           "256" );
  461.         SetDvar( "sv_botAllowGrenades",     "0" );
  462.         SetDvar( "sv_botSprintDistance",    "1024"  );
  463.         SetDvar( "sv_botMeleeDist",         "40" );
  464.     }
  465.     else // 'normal' difficulty
  466.     {
  467.         SetDvar( "sv_botMinDeathTime",      "500" );
  468.         SetDvar( "sv_botMaxDeathTime",      "1000" );
  469.         SetDvar( "sv_botMinFireTime",       "600" );
  470.         SetDvar( "sv_botMaxFireTime",       "800" );
  471.         SetDvar( "sv_botYawSpeed",          "4" );
  472.         SetDvar( "sv_botYawSpeedAds",       "5" );
  473.         SetDvar( "sv_botPitchUp",           "-10" );
  474.         SetDvar( "sv_botPitchDown",         "20" );
  475.         SetDvar( "sv_botFov",               "70" );
  476.         SetDvar( "sv_botMinAdsTime",        "3000" );
  477.         SetDvar( "sv_botMaxAdsTime",        "5000" );
  478.         SetDvar( "sv_botMinCrouchTime",     "2000" );
  479.         SetDvar( "sv_botMaxCrouchTime",     "4000" );
  480.         SetDvar( "sv_botTargetLeadBias",    "4" );
  481.         SetDvar( "sv_botMinReactionTime",   "800" );
  482.         SetDvar( "sv_botMaxReactionTime",   "1200" );
  483.         SetDvar( "sv_botStrafeChance",      "0.6" );
  484.         SetDvar( "sv_botMinStrafeTime",     "3000" );
  485.         SetDvar( "sv_botMaxStrafeTime",     "6000" );
  486.         SetDvar( "scr_help_dist",           "256" );
  487.         SetDvar( "sv_botAllowGrenades",     "1" );
  488.         SetDvar( "sv_botMinGrenadeTime",    "1500" );
  489.         SetDvar( "sv_botMaxGrenadeTime",    "4000" );
  490.         SetDvar( "sv_botSprintDistance",    "512"   );
  491.         SetDvar( "sv_botMeleeDist",         "80" );
  492.     }
  493.  
  494.     if ( level.gameType == "oic" && difficulty == "fu" )
  495.     {
  496.         SetDvar( "sv_botMinReactionTime",       "400" );
  497.         SetDvar( "sv_botMaxReactionTime",       "500" );
  498.         SetDvar( "sv_botMinAdsTime",        "1000" );
  499.         SetDvar( "sv_botMaxAdsTime",        "2000" );
  500.     }
  501.  
  502.     if ( level.gameType == "oic" && ( difficulty == "hard" || difficulty == "fu" ) )
  503.     {
  504.         SetDvar( "sv_botSprintDistance",    "256" );
  505.     }
  506. }
  507.  
  508. bot_give_loadout()
  509. {
  510.     if ( !IsDefined( self.bot ) )
  511.     {
  512.         self.bot = [];
  513.     }
  514.  
  515.     if ( !IsDefined( self.equipment_enabled ) )
  516.     {
  517.         self.equipment_enabled = false;
  518.     }
  519.  
  520. /#
  521.     if ( bot_should_clone_loadout() )
  522.     {
  523.         self bot_clone_loadout( level.dev_cac_player );
  524.         return;
  525.     }
  526.  
  527.     if ( GetDvar( "scr_help_dist" ) == "" )
  528.     {
  529.         SetDvar( "scr_help_dist", "256" );
  530.     }
  531. #/
  532.  
  533.     if ( !IsDefined( self.bot[ "rank" ] ) )
  534.     {
  535.         self bot_set_rank();
  536.     }
  537.  
  538.     self bot_get_cod_points();
  539.    
  540.     playerRenderOptions = self calcPlayerOptions( randomint(5), randomint(5) );
  541.     self SetPlayerRenderOptions( int( playerRenderOptions ) );
  542.    
  543.     // calcWeaponOptions ( <camo> <lens> <reticle> <tag> <emblem> )
  544.     weaponOptions = self calcWeaponOptions( randomint(5), 0, 0, 0, 0 );
  545.     equipment = undefined;
  546.  
  547.     if ( GetDvarInt( #"scr_botsHasPlayerWeapon" ) )
  548.     {
  549.         player = maps\mp\_utility::get_players()[0];
  550.  
  551.         weapon = player GetCurrentWeapon();
  552.         reference = bot_weapon_reference_from_weapon( weapon );
  553.  
  554.         self.bot[ "primary" ] = weapon;
  555.         self GiveWeapon( weapon );
  556.         self GiveStartAmmo( weapon );
  557.  
  558.         primarygrenade = player getcurrentoffhand();
  559.         self.bot[ "primarygrenade" ] = primarygrenade;
  560.         self GiveWeapon( primarygrenade );
  561.         self GiveStartAmmo( primarygrenade );
  562.         self SwitchToOffhand( self.bot[ "primarygrenade" ] );
  563.  
  564.         player_class = player.pers["class"];
  565.         if( isSubstr( player_class, "CLASS_CUSTOM" ) || isSubstr(player_class, "CLASS_PRESTIGE") )
  566.         {
  567.             specialgrenade = player.custom_class[player.class_num]["specialgrenades"];
  568.         }
  569.         else
  570.         {
  571.             specialgrenade = level.classGrenades[player_class]["secondary"]["type"];
  572.         }
  573.         self.bot[ "specialgrenade" ] = specialgrenade;
  574.         self GiveWeapon( specialgrenade );
  575.         self GiveStartAmmo( specialgrenade );
  576.         self SetOffhandSecondaryClass( self.bot[ "specialgrenade" ] );
  577.  
  578.         if ( self.equipment_enabled && ( self.bot[ "rank" ] > 3 || level.bot_offline ) )
  579.         {
  580.             equipment = self bot_give_random_weapon( "equipment", 0 );
  581.         }
  582.     }
  583.     else
  584.     {
  585.         reference = self bot_give_random_weapon( "primary", int( weaponOptions ) );
  586.         self bot_give_random_weapon( "secondary", 0 );
  587.  
  588.         self bot_give_random_weapon( "primarygrenade", 0 );
  589.         self SwitchToOffhand( self.bot[ "primarygrenade" ] );
  590.  
  591.         self bot_give_random_weapon( "specialgrenade", 0 );
  592.         self SetOffhandSecondaryClass( self.bot[ "specialgrenade" ] );
  593.  
  594.         if ( self.equipment_enabled && ( self.bot[ "rank" ] > 3 || level.bot_offline ) )
  595.         {
  596.             equipment = self bot_give_random_weapon( "equipment", 0 );
  597.         }
  598.     }
  599.  
  600.     self bot_giveKillStreaks();
  601.  
  602.     self.pers[ "primaryWeapon" ] = reference;
  603.     if ( GetDvarInt( #"sv_botsForceFragOnly" ) )
  604.     {
  605.         self TakeWeapon( self.bot[ "primary" ] );
  606.        
  607.         if ( IsDefined(self.bot[ "secondary" ] ) )
  608.         {
  609.             self TakeWeapon( self.bot[ "secondary" ] );
  610.         }
  611.        
  612.         self TakeWeapon( self.bot[ "specialgrenade" ] );
  613.     }
  614.     else if ( GetDvarInt( #"sv_botsForceSpecialOnly" ) )
  615.     {
  616.         self TakeWeapon( self.bot[ "primary" ] );
  617.        
  618.         if ( IsDefined(self.bot[ "secondary" ] ) )
  619.         {
  620.             self TakeWeapon( self.bot[ "secondary" ] );
  621.         }
  622.        
  623.         self TakeWeapon( self.bot[ "primarygrenade" ] );
  624.     }
  625.     else
  626.     {
  627.         self SetSpawnWeapon( self.bot[ "primary" ] );
  628.     }
  629.  
  630.  
  631.     self ClearPerks();
  632.     self bot_give_random_armor();
  633.     if ( GetDvarInt( #"scr_game_perks" ) != 0 )
  634.     {
  635.         //self bot_give_random_perk( "specialty1" );
  636.         self bot_give_random_perk( "specialty2" );
  637.         self bot_give_random_perk( "specialty3" );
  638.     }
  639.  
  640.     self thread bot_revive_think();
  641.     self thread bot_crate_think();
  642.     self thread bot_crate_touch_think();
  643.     self thread bot_turret_think();
  644.     self thread bot_killstreak_think();
  645.     self thread bot_dogs_think();
  646.     self thread bot_vehicle_think();
  647.     self thread bot_wager_think();
  648.     self thread bot_equipment_think( equipment );
  649.     self thread bot_equipment_kill_think();
  650.     self thread bot_radiation_think();
  651.  
  652. /#
  653.     self thread bot_devgui_think();
  654. #/
  655. }
  656.  
  657. bot_giveKillstreaks()
  658. {
  659.     if ( !isDefined( self.killstreak ) || !isDefined( self.killstreak[ 0 ] ) || !isDefined( self.killstreak[ 1 ] ) || !isDefined( self.killstreak[ 2 ] ) )
  660.     {
  661.         bot_setKillstreaks();
  662.     }
  663.    
  664.     assert( isDefined( self.killstreak[ 0 ] ) && isDefined( self.killstreak[ 1 ] ) && isDefined( self.killstreak[ 2 ] ) );
  665. }
  666.    
  667.  
  668. bot_setKillstreaks()
  669. {
  670.     self.killstreak = [];
  671.  
  672.     allowed_killstreaks = [];
  673.  
  674.     allowed_killstreaks[ 0 ] = "killstreak_spyplane";
  675.     allowed_killstreaks[ 1 ] = "killstreak_supply_drop";
  676.     allowed_killstreaks[ 2 ] = "killstreak_helicopter_comlink";
  677.  
  678.     if ( self.bot[ "rank" ] >= 9 || level.bot_offline )
  679.     {
  680.         allowed_killstreaks[ 3 ] = "killstreak_auto_turret_drop";
  681.         allowed_killstreaks[ 4 ] = "killstreak_tow_turret_drop";
  682.         allowed_killstreaks[ 5 ] = "killstreak_napalm";
  683.         allowed_killstreaks[ 6 ] = "killstreak_counteruav";
  684.         allowed_killstreaks[ 7 ] = "killstreak_mortar";
  685.         allowed_killstreaks[ 8 ] = "killstreak_spyplane_direction";
  686.         allowed_killstreaks[ 9 ] = "killstreak_airstrike";
  687.         allowed_killstreaks[ 10 ] = "killstreak_dogs";
  688.         allowed_killstreaks[ 11 ] = "killstreak_rcbomb";
  689.     }
  690.  
  691.     used_levels = [];
  692.    
  693.     for ( i = 0; i < 3; i++ )
  694.     {
  695.         killstreak = random( allowed_killstreaks );
  696.         allowed_killstreaks = array_remove( allowed_killstreaks, killstreak );
  697.  
  698.         ks_level = maps\mp\gametypes\_hardpoints::GetKillstreakLevel( i, killstreak );
  699.  
  700.         if ( bot_killstreak_level_is_used( ks_level, used_levels ) )
  701.         {
  702.             i--;
  703.             continue;
  704.         }
  705.  
  706.         used_levels[ used_levels.size ] = ks_level;
  707.         self.killstreak[ i ] = killstreak;
  708.     }
  709. }
  710.  
  711. bot_killstreak_level_is_used( ks_level, used_levels )
  712. {
  713.     for ( used = 0; used < used_levels.size; used++ )
  714.     {
  715.         if ( ks_level == used_levels[ used ] )
  716.         {
  717.             return true;
  718.         }
  719.     }
  720.  
  721.     return false;
  722. }
  723.  
  724. bot_give_random_weapon( slot, weaponOptions )
  725. {
  726.     pixbeginevent( "bot_give_random_weapon" );
  727.     rank = self.bot[ "rank" ];
  728.  
  729.     if ( level.bot_offline )
  730.     {
  731.         rank = level.maxRank;
  732.     }
  733.  
  734.     if ( !IsDefined( level.bot_weapon_ids[ slot ] ) )
  735.     {
  736.         level.bot_weapon_ids[ slot ] = [];
  737.  
  738.         keys = GetArrayKeys( level.tbl_weaponIDs );
  739.  
  740.         for ( i = 0; i < keys.size; i++ )
  741.         {
  742.             key = keys[i];
  743.             id = level.tbl_weaponIDs[ key ];
  744.  
  745.             if ( id[ "reference" ] == "weapon_null" )
  746.                 continue;
  747.  
  748.             if ( id[ "cost" ] == "-1" )
  749.                 continue;
  750.  
  751.             if ( id[ "slot" ] == slot )
  752.             {
  753.                 level.bot_weapon_ids[ slot ][ level.bot_weapon_ids[ slot ].size ] = id;
  754.             }
  755.         }
  756.     }
  757.  
  758.     for ( tries = 0; ; tries++ )
  759.     {
  760.         id = random( level.bot_weapon_ids[ slot ] );
  761.  
  762.         if ( id[ "classified" ] != 0 )
  763.         {
  764.             if ( !bot_weapon_classified_unlocked( id, rank ) )
  765.             {
  766.                 continue;
  767.             }
  768.         }
  769.  
  770.         if ( id[ "reference" ] == "hatchet" && RandomInt( 100 ) > 20 )
  771.         {
  772.             continue;
  773.         }
  774.  
  775.         if ( id[ "reference" ] == "willy_pete" && RandomInt( 100 ) > 20 )
  776.         {
  777.             continue;
  778.         }
  779.  
  780.         if ( id[ "reference" ] == "nightingale" && RandomInt( 100 ) > 20 )
  781.         {
  782.             continue;
  783.         }
  784.  
  785.         if ( id[ "reference" ] == "claymore" && GetDvar( #"bot_difficulty" ) == "easy" )
  786.         {
  787.             continue;
  788.         }
  789.  
  790.         if ( id[ "reference" ] == "scrambler" && GetDvar( #"bot_difficulty" ) == "easy" )
  791.         {
  792.             continue;
  793.         }
  794.  
  795.         // dual-wield weapon
  796.         if ( id[ "unlock_level" ] == "" )
  797.         {
  798.             if ( !bot_weapon_dual_wield_unlocked( id[ "reference" ], rank ) )
  799.             {
  800.                 continue;
  801.             }
  802.         }
  803.  
  804.         unlock = Int( id[ "unlock_level" ] );
  805.  
  806.         if ( unlock > 3 && unlock > rank )
  807.             continue;
  808.  
  809.         if ( slot == "equipment" )
  810.         {
  811.             if ( tries >= level.bot_weapon_ids[ slot ].size )
  812.             {
  813.                 pixendevent();
  814.                 return undefined;
  815.             }
  816.  
  817.             if ( !maps\mp\gametypes\_class::isEquipmentAllowed( id[ "reference" ] + "_mp" ) )
  818.                 continue;
  819.        
  820.             if ( id[ "reference" ] == "satchel_charge" )
  821.                 continue;
  822.            
  823.             cost = Int( id[ "cost" ] );
  824.  
  825.             if ( cost > self.bot[ "cod_points" ] )
  826.                 continue;
  827.  
  828.             self.bot[ "cod_points" ] = self.bot[ "cod_points" ] - cost;
  829.         }
  830.  
  831.         if ( id[ "unlock_level" ] != "" && id[ "attachment" ] != "" && RandomFloatRange( 0, 1 ) < ( rank / level.maxRank ) )
  832.         {
  833.             base_weapon = bot_give_random_attachment( id[ "reference" ], id[ "attachment" ] );
  834.         }
  835.         else
  836.         {
  837.             base_weapon = id[ "reference" ];
  838.         }
  839.  
  840.         weapon = base_weapon + "_mp";
  841.  
  842.         self.bot[ slot ] = weapon;
  843.         self GiveWeapon( weapon, 0, weaponOptions );
  844.         self GiveStartAmmo( weapon );
  845.         pixendevent();
  846.         return base_weapon;
  847.     }
  848.  
  849.     pixendevent();
  850. }
  851.  
  852. bot_weapon_dual_wield_unlocked( dw_weapon, rank )
  853. {
  854.     if ( RandomInt( 100 ) > 20 )
  855.     {
  856.         return false;
  857.     }
  858.    
  859.     base_weapon = StrTok( dw_weapon, "dw" );
  860.  
  861.     if ( !IsDefined( base_weapon ) || base_weapon.size == 0 )
  862.     {
  863.         return false;
  864.     }
  865.  
  866.     base_weapon = base_weapon[0];
  867.  
  868.     if ( !IsDefined( base_weapon ) || base_weapon == "" )
  869.     {
  870.         return false;
  871.     }
  872.  
  873.     unlock = 999;
  874.    
  875.     for ( i = 0; i < level.tbl_weaponIDs.size; i++ )
  876.     {
  877.         id = level.tbl_weaponIDs[i];
  878.  
  879.         if ( !IsDefined( id ) )
  880.         {
  881.             continue;
  882.         }
  883.  
  884.         if ( base_weapon == id[ "reference" ] )
  885.         {
  886.             if ( id[ "classified" ] != 0 )
  887.             {
  888.                 if ( !bot_weapon_classified_unlocked( id, rank ) )
  889.                 {
  890.                     return false;
  891.                 }
  892.             }
  893.            
  894.             unlock = Int( id[ "unlock_level" ] );
  895.             break;
  896.         }
  897.     }
  898.  
  899.     return ( unlock <= rank );
  900. }
  901.  
  902. bot_weapon_classified_unlocked( id, rank )
  903. {
  904.     unlock = 999;
  905.  
  906.     // to do: get this from a data source
  907.  
  908.     switch( id[ "group" ] )
  909.     {
  910.         case "weapon_pistol":
  911.             unlock = 17;
  912.             break;
  913.         case "weapon_smg":
  914.             unlock = 40;
  915.             break;
  916.         case "weapon_assault":
  917.             unlock = 43;
  918.             break;
  919.         case "weapon_lmg":
  920.             unlock = 20;
  921.             break;
  922.         case "weapon_sniper":
  923.             unlock = 26;
  924.             break;
  925.         case "weapon_cqb":
  926.             unlock = 23;
  927.             break;
  928.     }
  929.  
  930.     return ( unlock <= rank );
  931. }
  932.  
  933. bot_give_random_attachment( weapon, attachments )
  934. {
  935.     /*
  936.     cost = 500; // TODO: get this from data some day
  937.  
  938.     if ( cost > self.bot[ "cod_points" ] )
  939.     {
  940.         return ( weapon );
  941.     }
  942.  
  943.     self.bot[ "cod_points" ] = self.bot[ "cod_points" ] - cost;
  944.     */
  945.    
  946.     attachments = StrTok( attachments, " " );
  947.     attachments = array_remove( attachments, "dw" ); // dw weapon madness in the statstable
  948.  
  949.     if ( attachments.size <= 0 )
  950.     {
  951.         return ( weapon );
  952.     }
  953.  
  954.     attachment = random( attachments );
  955.  
  956.     if ( attachment == "" )
  957.     {
  958.         return ( weapon );
  959.     }
  960.  
  961.     return ( weapon + "_" + attachment );
  962. }
  963.  
  964. bot_give_random_armor()
  965. {
  966.     if ( self bot_has_perk( "specialty_noname" ) )
  967.     {
  968.         self.cac_body_type = "hardened_mp";
  969.        
  970.         playerRenderOptions = self calcPlayerOptions( 0, 0 );
  971.         self SetPlayerRenderOptions( int( playerRenderOptions ) );
  972.  
  973.         self.bot[ "cod_points" ] = 500000;
  974.     }
  975.     else
  976.     {
  977.         keys = GetArrayKeys( level.cac_functions[ "set_body_model" ] );
  978.         self.cac_body_type = random( keys );
  979.  
  980.         if ( game[ "cac_faction_allies" ] == "cub_rebels" && self.pers[ "team" ] == "allies" )
  981.         {
  982.             while ( self.cac_body_type == "hardened_mp" )
  983.             {
  984.                 self.cac_body_type = random( keys );
  985.             }
  986.         }
  987.     }
  988.  
  989.     self.cac_head_type = self maps\mp\gametypes\_armor::get_default_head();
  990.     self.cac_hat_type = "none";
  991.  
  992.     self maps\mp\gametypes\_armor::set_player_model();
  993.     self bot_give_body_perk();
  994. }
  995.  
  996. bot_give_random_perk( slot )
  997. {
  998.     for ( ;; )
  999.     {
  1000.         id = random( level.allowedPerks[0] );
  1001.         id = level.tbl_PerkData[ id ];
  1002.  
  1003.         if ( id[ "reference" ] == "specialty_null" )
  1004.             continue;
  1005.  
  1006.         if ( id[ "slot" ] != slot )
  1007.             continue;
  1008.  
  1009.         cost = Int( id[ "cost" ] );
  1010.  
  1011.         if ( cost > self.bot[ "cod_points" ] )
  1012.             continue;
  1013.  
  1014.         self.bot[ "cod_points" ] = self.bot[ "cod_points" ] - cost;
  1015.  
  1016.         self.bot[ slot ] = id[ "reference_full" ];
  1017.         perks = StrTok( id[ "reference" ], "|" );
  1018.        
  1019.         for ( i = 0; i < perks.size; i++ )
  1020.         {
  1021.             self SetPerk( perks[i] );
  1022.         }
  1023.  
  1024.         return;
  1025.     }
  1026. }
  1027.  
  1028. bot_give_body_perk()
  1029. {
  1030.     reference_full = "";
  1031.     pro_cost = 3000; // to do: get this from a data source someday
  1032.  
  1033.     switch( self.cac_body_type )
  1034.     {
  1035.         case "camo_mp":
  1036.             reference_full = "perk_ghost";
  1037.             break;
  1038.  
  1039.         case "hardened_mp":
  1040.             reference_full = "perk_hardline";
  1041.             break;
  1042.  
  1043.         case "ordnance_disposal_mp":
  1044.             reference_full = "perk_flak_jacket";
  1045.             break;
  1046.  
  1047.         case "utility_mp":
  1048.             reference_full = "perk_scavenger";
  1049.             break;
  1050.  
  1051.         case "standard_mp":
  1052.         default:
  1053.             reference_full = "perk_lightweight";
  1054.             break;
  1055.     }
  1056.  
  1057.     if ( self.bot[ "cod_points" ] >= pro_cost )
  1058.     {
  1059.         self.bot[ "cod_points" ] = self.bot[ "cod_points" ] - pro_cost;
  1060.         reference_full = reference_full + "_pro";
  1061.     }
  1062.  
  1063.     id = bot_perk_from_reference_full( reference_full );
  1064.  
  1065.     if ( !IsDefined( id ) )
  1066.     {
  1067.         return;
  1068.     }
  1069.  
  1070.     self.bot[ "specialty1" ] = id[ "reference_full" ];
  1071.     perks = StrTok( id[ "reference" ], "|" );
  1072.  
  1073.     for ( i = 0; i < perks.size; i++ )
  1074.     {
  1075.         self SetPerk( perks[i] );
  1076.     }
  1077. }
  1078.  
  1079. bot_perk_from_reference_full( reference_full )
  1080. {
  1081.     keys = GetArrayKeys( level.tbl_PerkData );
  1082.  
  1083.     // start from the beginning of the array since our perk is most likely near the start
  1084.     for ( i = keys.size - 1; i >= 0; i-- )
  1085.     {
  1086.         key = keys[i];
  1087.  
  1088.         if ( level.tbl_PerkData[ key ][ "reference_full" ] == reference_full )
  1089.         {
  1090.             return level.tbl_PerkData[ key ];
  1091.         }
  1092.     }
  1093.  
  1094.     return undefined;
  1095. }
  1096.  
  1097. bot_weapon_reference_from_weapon( weapon )
  1098. {
  1099.     toks = StrTok( weapon, "_" );
  1100.     reference = toks[0];
  1101.  
  1102.     for ( i = 1; i < toks.size - 1; i++ )
  1103.     {
  1104.         reference = reference + "_" + toks[i];
  1105.     }
  1106.  
  1107.     return reference;
  1108. }
  1109.  
  1110. /#
  1111. bot_should_clone_loadout()
  1112. {
  1113.     return ( maps\mp\gametypes\_dev_class::dev_cac_player_valid() && level.dev_cac_player is_bot() );
  1114. }
  1115. #/
  1116.  
  1117. bot_get_cod_points()
  1118. {
  1119.     if ( level.bot_offline )
  1120.     {
  1121.         self.bot[ "cod_points" ] = 999999;
  1122.         return;
  1123.     }
  1124.    
  1125.     players = get_players();
  1126.     total_points = [];
  1127.  
  1128.     for ( i = 0; i < players.size; i++ )
  1129.     {
  1130.         if ( players[i] is_bot() )
  1131.         {
  1132.             continue;
  1133.         }
  1134.  
  1135.         total_points[ total_points.size ] = players[i].pers["currencyspent"] + players[i].pers["codpoints"];
  1136.     }
  1137.    
  1138.     if( !total_points.size )
  1139.         total_points[ total_points.size ] = 10000;
  1140.  
  1141.     point_average = array_average( total_points );
  1142.     self.bot[ "cod_points" ] = Int( point_average * RandomFloatRange( 0.6, 0.8 ) );
  1143. }
  1144.  
  1145. bot_clone_loadout( player )
  1146. {
  1147.     // primary
  1148.     self.bot[ "primary" ] = player.bot[ "primary" ];
  1149.     self GiveWeapon( self.bot[ "primary" ] );
  1150.     self GiveStartAmmo( self.bot[ "primary" ] );
  1151.     self SetSpawnWeapon( self.bot[ "primary" ] );
  1152.  
  1153.     reference = bot_weapon_reference_from_weapon( self.bot[ "primary" ] );
  1154.     self.pers[ "primaryWeapon" ] = reference;
  1155.  
  1156.     // secondary
  1157.     self.bot[ "secondary" ] = player.bot[ "secondary" ];
  1158.     self GiveWeapon( self.bot[ "secondary" ] );
  1159.     self GiveStartAmmo( self.bot[ "secondary" ] );
  1160.  
  1161.     // grenades
  1162.     self.bot[ "primarygrenade" ] = player.bot[ "primarygrenade" ];
  1163.     self GiveWeapon( self.bot[ "primarygrenade" ] );
  1164.     self GiveStartAmmo( self.bot[ "primarygrenade" ] );
  1165.     self SwitchToOffhand( self.bot[ "primarygrenade" ] );
  1166.  
  1167.     self.bot[ "specialgrenade" ] = player.bot[ "specialgrenade" ];
  1168.     self GiveWeapon( self.bot[ "specialgrenade" ] );
  1169.     self GiveStartAmmo( self.bot[ "specialgrenade" ] );
  1170.     self SetOffhandSecondaryClass( self.bot[ "specialgrenade" ] );
  1171.  
  1172.     // armor
  1173.     self.cac_faction = player.cac_faction;
  1174.     self.cac_body_type = player.cac_body_type;
  1175.     self.cac_head_type = player.cac_head_type;
  1176.     self.cac_hat_type = player.cac_hat_type;
  1177.     self maps\mp\gametypes\_armor::set_player_model();
  1178. }
  1179.  
  1180. // returns true if the bot not engaged and doesn't have a script goal, false otherwise
  1181. bot_is_idle()
  1182. {
  1183.     if ( !IsDefined( self ) )
  1184.     {
  1185.         return false;
  1186.     }
  1187.  
  1188.     if ( !IsAlive( self ) )
  1189.     {
  1190.         return false;
  1191.     }
  1192.  
  1193.     if ( !self is_bot() )
  1194.     {
  1195.         return false;
  1196.     }
  1197.  
  1198.     if ( IsDefined( self.laststand ) && self.laststand == true )
  1199.     {
  1200.         return false;
  1201.     }
  1202.  
  1203.     if ( self HasScriptGoal() )
  1204.     {
  1205.         return false;
  1206.     }
  1207.  
  1208.     if ( IsDefined( self GetThreat() ) )
  1209.     {
  1210.         return false;
  1211.     }
  1212.  
  1213.     return true;
  1214. }
  1215.  
  1216. bot_damage_callback( eAttacker, iDamage, sMeansOfDeath, sWeapon, eInflictor, sHitLoc )
  1217. {
  1218.     if ( !IsDefined( self ) || !IsAlive( self ) )
  1219.     {
  1220.         return;
  1221.     }
  1222.    
  1223.     if ( !self is_bot() )
  1224.     {
  1225.         return;
  1226.     }
  1227.  
  1228.     if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" )
  1229.     {
  1230.         return;
  1231.     }
  1232.  
  1233.     if ( iDamage <= 0 )
  1234.     {
  1235.         return;
  1236.     }
  1237.  
  1238.     if ( !IsDefined( eInflictor ) && !IsDefined( eAttacker ) )
  1239.     {
  1240.         return;
  1241.     }
  1242.  
  1243.     if ( !IsDefined( eInflictor ) )
  1244.     {
  1245.         eInflictor = eAttacker;
  1246.     }
  1247.  
  1248.     if ( eInflictor.classname == "script_vehicle" )
  1249.     {
  1250.         // ignore vehicle entities (rc bomb, choppers)
  1251.         return;
  1252.     }
  1253.  
  1254.     if ( IsDefined( eInflictor.classname ) && eInflictor.classname == "auto_turret" )
  1255.     {
  1256.         eAttacker = eInflictor;
  1257.     }
  1258.  
  1259.     if ( IsDefined( eAttacker ) )
  1260.     {
  1261.         if ( level.teamBased && IsDefined( eAttacker.team ) )
  1262.         {
  1263.             if ( level.hardcoreMode && eAttacker.team == self.team )
  1264.             {
  1265.                 if ( cointoss() && iDamage > 5 )
  1266.                 {
  1267.                 }
  1268.                 else
  1269.                 {
  1270.                     return;
  1271.                 }
  1272.             }
  1273.             else if ( eAttacker.team == self.team )
  1274.             {
  1275.                 return;
  1276.             }
  1277.         }
  1278.  
  1279.         self bot_cry_for_help( eAttacker );
  1280.         self SetAttacker( eAttacker );
  1281.     }
  1282. }
  1283.  
  1284. bot_cry_for_help( attacker )
  1285. {
  1286.     if ( !level.teamBased )
  1287.     {
  1288.         return;
  1289.     }
  1290.  
  1291.     if ( level.teamBased && IsDefined( attacker.team ) )
  1292.     {
  1293.         if ( attacker.team == self.team )
  1294.         {
  1295.             return;
  1296.         }
  1297.     }
  1298.    
  1299.     if ( IsDefined( self.help_time ) && GetTime() - self.help_time < 1000 )
  1300.     {
  1301.         return;
  1302.     }
  1303.    
  1304.     self.help_time = GetTime();
  1305.  
  1306.     players = get_players();
  1307.     dist = GetDvarInt( #"scr_help_dist" );
  1308.  
  1309.     for ( i = 0; i < players.size; i++ )
  1310.     {
  1311.         player = players[i];
  1312.  
  1313.         if ( !player is_bot() )
  1314.         {
  1315.             continue;
  1316.         }
  1317.  
  1318.         if ( !IsAlive( player ) )
  1319.         {
  1320.             continue;
  1321.         }
  1322.  
  1323.         if ( player == self )
  1324.         {
  1325.             continue;
  1326.         }
  1327.  
  1328.         if ( player.team != self.team )
  1329.         {
  1330.             continue;
  1331.         }
  1332.  
  1333.         if ( DistanceSquared( self.origin, player.origin ) > dist * dist )
  1334.         {
  1335.             continue;
  1336.         }
  1337.  
  1338.         if ( RandomInt( 100 ) < 50 )
  1339.         {
  1340.             player thread bot_find_attacker( attacker );
  1341.  
  1342.             if ( RandomInt( 100 ) > 70 )
  1343.             {
  1344.                 break;
  1345.             }
  1346.         }
  1347.     }
  1348. }
  1349.  
  1350. bot_find_attacker( attacker )
  1351. {
  1352.     self endon( "death" );
  1353.     self endon( "disconnect" );
  1354.  
  1355.     if ( !IsDefined( attacker ) || !IsAlive( attacker ) )
  1356.     {
  1357.         return;
  1358.     }
  1359.  
  1360.     if ( attacker.classname == "auto_turret" )
  1361.     {
  1362.         self SetScriptEnemy( attacker );
  1363.         self thread turret_path_monitor( attacker );
  1364.         return;
  1365.     }
  1366.  
  1367.     dir = VectorNormalize( attacker.origin - self.origin );
  1368.     dir = vector_scale( dir, 128 );
  1369.  
  1370.     goal = self.origin + dir;
  1371.     goal = ( goal[0], goal[1], self.origin[2] + 50 );
  1372.  
  1373.     //DebugStar( goal, 100, ( 1, 0, 0 ) );
  1374.  
  1375.     self SetScriptGoal( goal, 128 );
  1376.  
  1377.     wait( 1 );
  1378.  
  1379.     self ClearScriptGoal();
  1380. }
  1381.  
  1382. bot_revive_think()
  1383. {
  1384.     self endon( "death" );
  1385.     self endon( "disconnect" );
  1386.     level endon ( "game_ended" );
  1387.  
  1388.     if ( self bot_has_perk( "specialty_noname" ) )
  1389.     {
  1390.         self SetPerk( "specialty_killstreak" );
  1391.         self SetPerk( "specialty_fastreload" );
  1392.         self SetPerk( "specialty_fastads" );
  1393.         self SetPerk( "specialty_gpsjammer" );
  1394.     }
  1395.  
  1396.     if ( !level.teamBased )
  1397.     {
  1398.         return;
  1399.     }
  1400.  
  1401.     for ( ;; )
  1402.     {
  1403.         wait( randomintrange( 3, 5 ) );
  1404.  
  1405.         players = get_players();
  1406.  
  1407.         for ( i = 0; i < players.size; i++ )
  1408.         {
  1409.             player = players[i];
  1410.  
  1411.             if ( player == self )
  1412.             {
  1413.                 continue;
  1414.             }
  1415.  
  1416.             if ( !IsAlive( player ) )
  1417.             {
  1418.                 continue;
  1419.             }
  1420.  
  1421.             if ( player.team != self.team )
  1422.             {
  1423.                 continue;
  1424.             }
  1425.  
  1426.             if ( !IsDefined( player.revivetrigger ) )
  1427.             {
  1428.                 player.bots = 0;
  1429.                 continue;
  1430.             }
  1431.  
  1432.             if ( !IsDefined( player.bots ) )
  1433.             {
  1434.                 player.bots = 0;
  1435.             }
  1436.  
  1437.             if ( player.bots >= 1 )
  1438.             {
  1439.                 continue;
  1440.             }
  1441.  
  1442.             if ( DistanceSquared( self.origin, player.origin ) < 2048 * 2048 )
  1443.             {
  1444.                 self SetScriptGoal( player.origin, 32 );
  1445.                 player.bots++;
  1446.                 self waittill_any( "goal", "bad_path" );
  1447.  
  1448.                 if ( IsDefined( player ) && IsDefined( player.revivetrigger ) && self IsTouching( player.revivetrigger ) )
  1449.                 {
  1450.                     self PressUseButton( GetDvarInt( #"revive_time_taken" ) + 1 );
  1451.                     wait( GetDvarInt( #"revive_time_taken" ) + 1.5 );
  1452.                 }
  1453.  
  1454.                 self ClearScriptGoal();
  1455.                 break;
  1456.             }
  1457.         }
  1458.     }
  1459. }
  1460.  
  1461. bot_crate_think()
  1462. {
  1463.     self endon( "death" );
  1464.     self endon( "disconnect" );
  1465.     level endon ( "game_ended" );
  1466.  
  1467.     myteam = self.pers[ "team" ];
  1468.  
  1469.     for ( ;; )
  1470.     {
  1471.         self wait_endon( randomintrange( 3, 5 ), "my_crate_landed" );
  1472.  
  1473.         if ( !self bot_is_idle() )
  1474.         {
  1475.             continue;
  1476.         }
  1477.  
  1478.         crates = GetEntArray( "care_package", "script_noteworthy" );
  1479.  
  1480.         if ( crates.size == 0 )
  1481.         {
  1482.             continue;
  1483.         }
  1484.  
  1485.         crate = random( crates );
  1486.  
  1487.         if ( IsDefined( crate.droppingToGround ) )
  1488.         {
  1489.             continue;
  1490.         }
  1491.  
  1492.         if ( !IsDefined( crate.bots ) )
  1493.         {
  1494.             crate.bots = 0;
  1495.         }
  1496.  
  1497.         if ( crate.bots >= 1 )
  1498.         {
  1499.             continue;
  1500.         }
  1501.  
  1502.         if ( level.teambased && IsDefined( crate.owner ) && crate.owner != self )
  1503.         {
  1504.             if ( myteam == crate.owner.team )
  1505.             {
  1506.                 if ( RandomInt( 100 ) > 30 )
  1507.                 {
  1508.                     continue;
  1509.                 }
  1510.             }
  1511.         }
  1512.  
  1513.         if ( DistanceSquared( self.origin, crate.origin ) > 2048 * 2048 )
  1514.         {
  1515.             if ( !IsDefined( crate.owner ) )
  1516.             {
  1517.                 continue;
  1518.             }
  1519.            
  1520.             if ( crate.owner != self )
  1521.             {
  1522.                 continue;
  1523.             }
  1524.         }
  1525.  
  1526.         origin = ( crate.origin[0], crate.origin[1], crate.origin[2] + 12 );
  1527.  
  1528.         self SetScriptGoal( origin, 100 );
  1529.         crate.bots++;
  1530.         self thread crate_path_monitor( crate );
  1531.         self thread crate_touch_monitor( crate );
  1532.         crate thread crate_death_monitor( self );
  1533.  
  1534.         path = self waittill_any_return( "goal", "bad_path" );
  1535.  
  1536.         if ( path == "bad_path" )
  1537.         {
  1538.             if ( IsDefined( crate ) )
  1539.             {
  1540.                 crate.bots--;
  1541.             }
  1542.  
  1543.             self ClearScriptGoal();
  1544.             continue;
  1545.         }
  1546.  
  1547.         self SetScriptGoal( self.origin, 100 );
  1548.  
  1549.         if ( crate.owner == self )
  1550.         {
  1551.             self PressUseButton( level.crateOwnerUseTime / 1000 + 0.5 );
  1552.             wait( level.crateOwnerUseTime / 1000 + 0.5 );
  1553.         }
  1554.         else
  1555.         {
  1556.             self PressUseButton( level.crateNonOwnerUseTime / 1000 + 1 );
  1557.             wait( level.crateNonOwnerUseTime / 1000 + 1.5 );
  1558.         }
  1559.  
  1560.         self ClearScriptGoal();
  1561.     }
  1562. }
  1563.  
  1564. crate_death_monitor( bot )
  1565. {
  1566.     self endon( "death" );
  1567.  
  1568.     bot waittill( "death" );
  1569.     self.bots--;
  1570. }
  1571.  
  1572. crate_path_monitor( crate )
  1573. {
  1574.     self endon( "death" );
  1575.     self endon( "disconnect" );
  1576.     self endon( "bad_path" );
  1577.     self endon( "goal" );
  1578.  
  1579.     crate waittill( "death" );
  1580.     self notify( "bad_path" );
  1581. }
  1582.  
  1583. crate_touch_monitor( crate )
  1584. {
  1585.     self endon( "death" );
  1586.     self endon( "disconnect" );
  1587.     self endon( "bad_path" );
  1588.     self endon( "goal" );
  1589.  
  1590.     radius = GetDvarFloat( #"player_useRadius" );
  1591.  
  1592.     for ( ;; )
  1593.     {
  1594.         wait( 0.5 );
  1595.  
  1596.         if ( DistanceSquared( self.origin, crate.origin ) < radius * radius )
  1597.         {
  1598.             self notify( "goal" );
  1599.             return;
  1600.         }
  1601.     }
  1602. }
  1603.  
  1604. // ensure bots don't get stuck on crates for too long
  1605. bot_crate_touch_think()
  1606. {
  1607.     self endon( "death" );
  1608.     self endon( "disconnect" );
  1609.  
  1610.     radius = GetDvarFloat( #"player_useRadius" );
  1611.  
  1612.     for ( ;; )
  1613.     {
  1614.         wait( 3 );
  1615.  
  1616.         if ( IsDefined( self GetThreat() ) )
  1617.         {
  1618.             continue;
  1619.         }
  1620.  
  1621.         if ( self UseButtonPressed() )
  1622.         {
  1623.             continue;
  1624.         }
  1625.  
  1626.         crates = GetEntArray( "care_package", "script_noteworthy" );
  1627.  
  1628.         for ( i = 0; i < crates.size; i++ )
  1629.         {
  1630.             crate = crates[i];
  1631.  
  1632.             if ( DistanceSquared( self.origin, crate.origin ) < radius * radius )
  1633.             {
  1634.                 if ( crate.owner == self )
  1635.                 {
  1636.                     self PressUseButton( level.crateOwnerUseTime / 1000 + 0.5 );
  1637.                 }
  1638.                 else
  1639.                 {
  1640.                     self PressUseButton( level.crateNonOwnerUseTime / 1000 + 0.5 );
  1641.                 }
  1642.             }
  1643.         }
  1644.     }
  1645. }
  1646.  
  1647. bot_turret_think()
  1648. {
  1649.     self endon( "death" );
  1650.     self endon( "disconnect" );
  1651.     level endon ( "game_ended" );
  1652.  
  1653.     myteam = self.pers[ "team" ];
  1654.  
  1655.     if ( GetDvar( #"bot_difficulty" ) == "easy" )
  1656.     {
  1657.         return;
  1658.     }
  1659.  
  1660.     for ( ;; )
  1661.     {
  1662.         wait( 1 );
  1663.  
  1664.         turrets = GetEntArray( "auto_turret", "classname" );
  1665.  
  1666.         if ( turrets.size == 0 || IsDefined( self GetThreat() ) )
  1667.         {
  1668.             wait( randomintrange( 3, 5 ) );
  1669.             continue;
  1670.         }
  1671.  
  1672.         turret = Random( turrets );
  1673.  
  1674.         if ( turret.carried )
  1675.         {
  1676.             continue;
  1677.         }
  1678.  
  1679.         if ( turret.damageTaken >= turret.health )
  1680.         {
  1681.             continue;
  1682.         }
  1683.  
  1684.         if ( level.teambased && turret.team == myteam )
  1685.         {
  1686.             continue;
  1687.         }
  1688.  
  1689.         if ( IsDefined( turret.owner ) && turret.owner == self )
  1690.         {
  1691.             continue;
  1692.         }
  1693.  
  1694.         if ( !IsDefined( turret.bots ) )
  1695.         {
  1696.             turret.bots = 0;
  1697.         }
  1698.  
  1699.         if ( turret.bots >= 2 )
  1700.         {
  1701.             continue;
  1702.         }
  1703.  
  1704.         forward = AnglesToForward( turret.angles );
  1705.         forward = VectorNormalize( forward );
  1706.  
  1707.         delta = self.origin - turret.origin;
  1708.         delta = VectorNormalize( delta );
  1709.        
  1710.         dot = VectorDot( forward, delta );
  1711.         facing = true;
  1712.  
  1713.         if ( dot < 0.342 ) // cos 70 degrees
  1714.         {
  1715.             facing = false;
  1716.         }
  1717.  
  1718.         if ( turret.turrettype == "tow" )
  1719.         {
  1720.             facing = false;
  1721.         }
  1722.  
  1723.         if ( turret maps\mp\gametypes\_weaponobjects::isStunned() )
  1724.         {
  1725.             facing = false;
  1726.         }
  1727.  
  1728.         if ( facing && !BulletTracePassed( self.origin + ( 0, 0, 30 ), turret.origin + ( 0, 0, 15 ), false, turret ) )
  1729.         {
  1730.             continue;
  1731.         }
  1732.  
  1733.         turret.bots++;
  1734.         turret thread turret_death_monitor( self );
  1735.  
  1736.         if ( self HasPerk( "specialty_disarmexplosive" ) && !facing )
  1737.         {
  1738.             self thread turret_path_monitor( turret );
  1739.             self SetScriptGoal( turret.origin, 32 );
  1740.  
  1741.             path = self waittill_any_return( "goal", "bad_path" );
  1742.  
  1743.             if ( path == "goal" )
  1744.             {
  1745.                 hackTime = GetDvarFloat( #"perk_disarmExplosiveTime" );
  1746.                 self PressUseButton( hackTime + 0.5 );
  1747.                 wait( hackTime + 0.5 );
  1748.                 self ClearScriptGoal();
  1749.                 continue;
  1750.             }
  1751.         }
  1752.         else if ( !facing )
  1753.         {
  1754.             self thread turret_path_monitor( turret );
  1755.             self SetScriptGoal( turret.origin, 64 );
  1756.             self waittill_any_return( "goal", "bad_path" );
  1757.             self ClearScriptGoal();
  1758.         }
  1759.  
  1760.         if ( !IsDefined( turret ) )
  1761.         {
  1762.             continue;
  1763.         }
  1764.  
  1765.         if ( turret.carried )
  1766.         {
  1767.             continue;
  1768.         }
  1769.  
  1770.         if ( turret.damageTaken >= turret.health )
  1771.         {
  1772.             continue;
  1773.         }
  1774.  
  1775.         self SetScriptEnemy( turret );
  1776.         turret waittill_any( "turret_carried", "turret_deactivated", "death" );
  1777.         self ClearScriptEnemy();
  1778.     }
  1779. }
  1780.  
  1781. bot_killstreak_think()
  1782. {
  1783.     self endon( "death" );
  1784.     self endon( "disconnect" );
  1785.     level endon ( "game_ended" );
  1786.  
  1787.     myteam = self.pers[ "team" ];
  1788.  
  1789.     wait( 1 );
  1790.  
  1791.     for ( ;; )
  1792.     {
  1793.         wait( RandomIntRange( 3, 5 ) );
  1794.  
  1795.         if ( self IsRemoteControlling() )
  1796.         {
  1797.             continue;
  1798.         }
  1799.  
  1800.         weapon = self maps\mp\gametypes\_hardpoints::getTopKillstreak();
  1801.        
  1802.         if ( !IsDefined( weapon ) || weapon == "none" )
  1803.         {
  1804.             continue;
  1805.         }
  1806.  
  1807.         killstreak = maps\mp\gametypes\_hardpoints::getKillStreakMenuName( weapon );
  1808.  
  1809.         if ( !IsDefined( killstreak ) )
  1810.         {
  1811.             continue;
  1812.         }
  1813.  
  1814.         id = self maps\mp\gametypes\_hardpoints::getTopKillstreakUniqueId();
  1815.  
  1816.         if ( !self maps\mp\_killstreakrules::isKillstreakAllowed( weapon, myteam ) )
  1817.         {
  1818.             wait( 5 );
  1819.             continue;
  1820.         }
  1821.  
  1822.         switch( killstreak )
  1823.         {
  1824.             case "killstreak_helicopter_comlink":
  1825.             case "killstreak_napalm":
  1826.             case "killstreak_airstrike":
  1827.                 bot_killstreak_location( 1, weapon );
  1828.                 break;
  1829.  
  1830.             case "killstreak_mortar":
  1831.                 bot_killstreak_location( 3, weapon );
  1832.                 break;
  1833.            
  1834.             case "killstreak_auto_turret_drop":
  1835.             case "killstreak_tow_turret_drop":
  1836.                 self bot_use_supply_drop( weapon );
  1837.                 break;
  1838.  
  1839.             case "killstreak_supply_drop":
  1840.                 self bot_use_supply_drop( "supplydrop_mp" );
  1841.                 break;
  1842.  
  1843.             case "killstreak_auto_turret":
  1844.             case "killstreak_tow_turret":
  1845.                 self bot_turret_location( weapon );
  1846.                 break;
  1847.  
  1848.             //case "killstreak_rcbomb":
  1849.             case "killstreak_helicopter_gunner":
  1850.             case "killstreak_helicopter_player_firstperson":
  1851.                 self maps\mp\gametypes\_hardpoints::removeUsedKillstreak( weapon, id );
  1852.                 break;
  1853.  
  1854.             case "killstreak_rcbomb":
  1855.                 if ( IsDefined( self GetThreat() ) )
  1856.                 {
  1857.                     continue;
  1858.                 }
  1859.  
  1860.                 if ( self GetLookaheadDist() < 128 )
  1861.                 {
  1862.                     continue;
  1863.                 }
  1864.  
  1865.                 dir = self GetLookaheadDir();
  1866.  
  1867.                 if ( !IsDefined( dir ) )
  1868.                 {
  1869.                     continue;
  1870.                 }
  1871.  
  1872.                 dir = VectorToAngles( dir );
  1873.  
  1874.                 if ( abs( dir[1] - self.angles[1] ) > 5 )
  1875.                 {
  1876.                     continue;
  1877.                 }
  1878.  
  1879.                 self SwitchToWeapon( weapon );
  1880.                 self thread bot_rccar_think();
  1881.                 break;
  1882.  
  1883.             case "killstreak_spyplane":
  1884.             case "killstreak_counteruav":
  1885.             case "killstreak_dogs":
  1886.             case "killstreak_spyplane_direction":
  1887.             default:
  1888.                 self SwitchToWeapon( weapon );
  1889.                 self waittill( "weapon_change" );
  1890.                 break;
  1891.         }
  1892.  
  1893.         // crazy fail-safe
  1894.         wait( 0.05 );
  1895.         if ( self GetCurrentWeapon() == weapon )
  1896.         {
  1897.             self SwitchToWeapon( self.lastNonKillstreakWeapon );
  1898.         }
  1899.     }
  1900. }
  1901.  
  1902. bot_rccar_think()
  1903. {
  1904.     self endon( "disconnect" );
  1905.     self endon( "rcbomb_done" );
  1906.     self endon( "weapon_object_destroyed" );
  1907.     level endon ( "game_ended" );
  1908.  
  1909.     wait( 2 );
  1910.  
  1911.     self thread bot_rccar_kill();
  1912.  
  1913.     for ( ;; )
  1914.     {
  1915.         wait( 0.5 );
  1916.  
  1917.         if ( !IsDefined( self.rcbomb ) )
  1918.         {
  1919.             return;
  1920.         }
  1921.  
  1922.         players = get_players();
  1923.  
  1924.         for ( i = 0; i < players.size; i++ )
  1925.         {
  1926.             player = players[i];
  1927.  
  1928.             if ( player == self )
  1929.             {
  1930.                 continue;
  1931.             }
  1932.  
  1933.             if ( !IsAlive( player ) )
  1934.             {
  1935.                 continue;
  1936.             }
  1937.  
  1938.             if ( level.teamBased && player.team == self.team )
  1939.             {
  1940.                 continue;
  1941.             }
  1942.  
  1943.             if ( GetDvar( #"bot_difficulty" ) == "easy" )
  1944.             {
  1945.                 if ( DistanceSquared( self.rcbomb.origin, player.origin ) < 512 * 512 )
  1946.                 {
  1947.                     self PressAttackButton();
  1948.                 }
  1949.             }
  1950.             else if ( DistanceSquared( self.rcbomb.origin, player.origin ) < 200 * 200 )
  1951.             {
  1952.                 self PressAttackButton();
  1953.             }
  1954.         }
  1955.     }
  1956. }
  1957.  
  1958. // failsafe for stuck cars
  1959. bot_rccar_kill()
  1960. {
  1961.     self endon( "disconnect" );
  1962.     self endon( "rcbomb_done" );
  1963.     self endon( "weapon_object_destroyed" );
  1964.     level endon ( "game_ended" );
  1965.  
  1966.     og_origin = self.origin;
  1967.  
  1968.     for ( ;; )
  1969.     {
  1970.         wait( 1 );
  1971.  
  1972.         if ( !IsDefined( self.rcbomb ) )
  1973.         {
  1974.             return;
  1975.         }
  1976.  
  1977.         if ( DistanceSquared( og_origin, self.rcbomb.origin ) < 16 * 16 )
  1978.         {
  1979.             wait( 2 );
  1980.  
  1981.             if ( !IsDefined( self.rcbomb ) )
  1982.             {
  1983.                 return;
  1984.             }
  1985.  
  1986.             if ( DistanceSquared( og_origin, self.rcbomb.origin ) < 16 * 16 )
  1987.             {
  1988.                 self PressAttackButton();
  1989.             }
  1990.         }
  1991.  
  1992.         og_origin = self.rcbomb.origin;
  1993.     }
  1994. }
  1995.  
  1996. bot_turret_location( weapon )
  1997. {
  1998.     for ( ;; )
  1999.     {
  2000.         wait( 0.5 );
  2001.  
  2002.         if ( !self bot_is_idle() )
  2003.         {
  2004.             continue;
  2005.         }
  2006.  
  2007.         if ( GetDvar( #"bot_difficulty" ) == "easy" )
  2008.         {
  2009.             if ( self GetLookaheadDist() < 256 )
  2010.             {
  2011.                 continue;
  2012.             }
  2013.         }
  2014.         else if ( self GetLookaheadDist() < 256 )
  2015.         {
  2016.             continue;
  2017.         }
  2018.  
  2019.         dir = self GetLookaheadDir();
  2020.  
  2021.         if ( !IsDefined( dir ) )
  2022.         {
  2023.             continue;
  2024.         }
  2025.  
  2026.         dir = VectorToAngles( dir );
  2027.  
  2028.         if ( abs( dir[1] - self.angles[1] ) > 5 )
  2029.         {
  2030.             continue;
  2031.         }
  2032.  
  2033.         yaw = ( 0, self.angles[1], 0 );
  2034.         dir = AnglesToForward( yaw );
  2035.         dir = VectorNormalize( dir );
  2036.  
  2037.         goal = self.origin + vector_scale( dir, 32 );
  2038.  
  2039.         if ( weapon == "autoturret_mp" && GetDvar( #"bot_difficulty" ) != "easy" )
  2040.         {
  2041.             eye = self.origin + ( 0, 0, 60 );
  2042.             goal = eye + vector_scale( dir, 1024 );
  2043.  
  2044.             if ( !SightTracePassed( self.origin, goal, false, undefined ) )
  2045.             {
  2046.                 continue;
  2047.             }
  2048.         }
  2049.  
  2050.         if ( weapon == "auto_tow_mp" )
  2051.         {
  2052.             end = goal + ( 0, 0, 2048 );
  2053.        
  2054.             if ( !SightTracePassed( goal, end, false, undefined ) )
  2055.             {
  2056.                 continue;
  2057.             }
  2058.         }
  2059.  
  2060.         self thread weapon_switch_failsafe();
  2061.         self SwitchToWeapon( weapon );
  2062.         self waittill( "weapon_change_complete" );
  2063.         self freeze_player_controls( true );
  2064.  
  2065.         wait( 1 );
  2066.         self freeze_player_controls( false );
  2067.         bot_use_item( weapon );
  2068.         self SwitchToWeapon( self.lastNonKillstreakWeapon );
  2069.         return;
  2070.     }
  2071. }
  2072.  
  2073. bot_use_supply_drop( weapon )
  2074. {
  2075.     wait_time = 1;
  2076.  
  2077.     for ( ;; )
  2078.     {
  2079.         wait( wait_time );
  2080.         wait_time = 1;
  2081.  
  2082.         if ( !self HasWeapon( weapon ) )
  2083.         {
  2084.             return;
  2085.         }
  2086.  
  2087.         if ( !self bot_is_idle() )
  2088.         {
  2089.             continue;
  2090.         }
  2091.  
  2092.         if ( self GetLookaheadDist() < 96 )
  2093.         {
  2094.             continue;
  2095.         }
  2096.  
  2097.         view_angles = self GetPlayerAngles();
  2098.  
  2099.         if ( view_angles[0] < 7 )
  2100.         {
  2101.             continue;
  2102.         }
  2103.  
  2104.         dir = self GetLookaheadDir();
  2105.  
  2106.         if ( !IsDefined( dir ) )
  2107.         {
  2108.             continue;
  2109.         }
  2110.  
  2111.         dir = VectorToAngles( dir );
  2112.  
  2113.         if ( abs( dir[1] - self.angles[1] ) > 2 )
  2114.         {
  2115.             continue;
  2116.         }
  2117.  
  2118.         yaw = ( 0, self.angles[1], 0 );
  2119.         dir = AnglesToForward( yaw );
  2120.  
  2121.         dir = VectorNormalize( dir );
  2122.         drop_point = self.origin + vector_scale( dir, 384 );
  2123.         //DebugStar( drop_point, 500, ( 1, 0, 0 ) );
  2124.  
  2125.         end = drop_point + ( 0, 0, 2048 );
  2126.         //DebugStar( end, 500, ( 1, 0, 0 ) );
  2127.  
  2128.         if ( !SightTracePassed( drop_point, end, false, undefined ) )
  2129.         {
  2130.             continue;
  2131.         }
  2132.  
  2133.         if ( !SightTracePassed( self.origin, end, false, undefined ) )
  2134.         {
  2135.             continue;
  2136.         }
  2137.  
  2138.         // is this point in mid-air?
  2139.         end = drop_point - ( 0, 0, 32 );
  2140.         //DebugStar( end, 500, ( 1, 0, 0 ) );
  2141.         if ( BulletTracePassed( drop_point, end, false, undefined ) )
  2142.         {
  2143.             wait_time = 0.1;
  2144.             continue;
  2145.         }
  2146.  
  2147.         goal = self.origin + vector_scale( dir, 64 );
  2148.         //DebugStar( goal, 500, ( 0, 1, 0 ) );
  2149.  
  2150.         self SetScriptGoal( goal, 128 );
  2151.         self waittill_any( "goal", "bad_path" );
  2152.  
  2153.         if ( self GetCurrentWeapon() != weapon )
  2154.         {
  2155.             self thread weapon_switch_failsafe();
  2156.             self SwitchToWeapon( weapon );
  2157.             self waittill( "weapon_change_complete" );
  2158.         }
  2159.  
  2160.         bot_use_item( weapon );
  2161.         self SwitchToWeapon( self.lastNonKillstreakWeapon );
  2162.  
  2163.         self wait_endon( RandomIntRange( 10, 15 ), "bot_crate_landed" );
  2164.         self ClearScriptGoal();
  2165.  
  2166.         self notify( "my_crate_landed" );
  2167.  
  2168.         return;
  2169.     }
  2170. }
  2171.  
  2172. bot_killstreak_location( num, weapon )
  2173. {
  2174.     self SwitchToWeapon( weapon );
  2175.     self waittill( "weapon_change" );
  2176.     self freeze_player_controls( true );
  2177.  
  2178.     wait_time = 1;
  2179.     while ( !IsDefined( self.selectingLocation ) || self.selectingLocation == false )
  2180.     {
  2181.         wait( 0.05 );
  2182.         wait_time -= 0.05;
  2183.  
  2184.         if ( wait_time <= 0 )
  2185.         {
  2186.             self freeze_player_controls( false );
  2187.             self SwitchToWeapon( self.lastNonKillstreakWeapon );
  2188.             return;
  2189.         }
  2190.     }
  2191.  
  2192.     wait( 2 );
  2193.     myteam = self.pers[ "team" ];
  2194.  
  2195.     for ( i = 0; i < num; i++ )
  2196.     {
  2197.         wait( 0.05 );
  2198.         player = Random( get_players() );
  2199.  
  2200.         if ( player.sessionstate != "playing" )
  2201.         {
  2202.             i--;
  2203.             continue;
  2204.         }
  2205.  
  2206.         if ( player == self )
  2207.         {
  2208.             i--;
  2209.             continue;
  2210.         }
  2211.  
  2212.         if ( level.teambased )
  2213.         {
  2214.             if ( myteam == player.team )
  2215.             {
  2216.                 i--;
  2217.                 continue;
  2218.             }
  2219.         }
  2220.  
  2221.         x = RandomIntRange( -512, 512 );
  2222.         y = RandomIntRange( -512, 512 );
  2223.  
  2224.         origin = player.origin;
  2225.         origin = origin + ( x, y, 0 );
  2226.         yaw = RandomIntRange( 0, 360 );
  2227.  
  2228.         wait( 0.25 );
  2229.         self notify( "confirm_location", origin, yaw );
  2230.     }
  2231.  
  2232.     self freeze_player_controls( false );
  2233. }
  2234.  
  2235. bot_dogs_think()
  2236. {
  2237.     self endon( "death" );
  2238.     self endon( "disconnect" );
  2239.     level endon ( "game_ended" );
  2240.  
  2241.     myteam = self.pers[ "team" ];
  2242.  
  2243.     if ( level.no_dogs )
  2244.     {
  2245.         return;
  2246.     }
  2247.  
  2248.     for ( ;; )
  2249.     {
  2250.         wait( 1 );
  2251.  
  2252.         if ( !IsDefined( level.dogs ) || level.dogs.size <= 0 )
  2253.         {
  2254.             level waittill( "called_in_the_dogs" );
  2255.         }
  2256.  
  2257.         for ( i = 0; i < level.dogs.size; i++ )
  2258.         {
  2259.             dog = level.dogs[i];
  2260.  
  2261.             if ( !IsDefined( dog ) )
  2262.             {
  2263.                 continue;
  2264.             }
  2265.  
  2266.             if ( !IsAlive( dog ) )
  2267.             {
  2268.                 continue;
  2269.             }
  2270.  
  2271.             if ( level.teamBased )
  2272.             {
  2273.                 if ( dog.aiteam == myteam )
  2274.                 {
  2275.                     continue;
  2276.                 }
  2277.             }
  2278.  
  2279.             if ( dog.script_owner == self )
  2280.             {
  2281.                 continue;
  2282.             }
  2283.  
  2284.             if ( DistanceSquared( self.origin, dog.origin ) < ( 1024 * 1024 ) )
  2285.             {
  2286.                 self SetScriptEnemy( dog );
  2287.                 break;
  2288.             }
  2289.         }
  2290.     }
  2291. }
  2292.  
  2293. bot_vehicle_think()
  2294. {
  2295.     self endon( "death" );
  2296.     self endon( "disconnect" );
  2297.     level endon ( "game_ended" );
  2298.  
  2299.     if ( GetDvar( #"bot_difficulty" ) == "easy" )
  2300.     {
  2301.         return;
  2302.     }
  2303.  
  2304.     myteam = self.pers[ "team" ];
  2305.  
  2306.     for ( ;; )
  2307.     {
  2308.         wait( 1 );
  2309.  
  2310.         airborne_enemies = GetEntArray( "script_vehicle", "classname" );
  2311.  
  2312.         if ( !IsDefined( airborne_enemies ) || airborne_enemies.size <= 0 )
  2313.         {
  2314.             wait( RandomIntRange( 3, 5 ) );
  2315.             continue;
  2316.         }
  2317.  
  2318.         if ( !self bot_is_idle() )
  2319.         {
  2320.             continue;
  2321.         }
  2322.  
  2323.         for ( i = 0; i < airborne_enemies.size; i++ )
  2324.         {
  2325.             enemy = airborne_enemies[i];
  2326.  
  2327.             if ( !IsDefined( enemy ) )
  2328.             {
  2329.                 continue;
  2330.             }
  2331.  
  2332.             if ( !IsAlive( enemy ) )
  2333.             {
  2334.                 continue;
  2335.             }
  2336.  
  2337.             if ( level.teamBased )
  2338.             {
  2339.                 if ( enemy.team == myteam )
  2340.                 {
  2341.                     continue;
  2342.                 }
  2343.             }
  2344.  
  2345.             if ( enemy.owner == self )
  2346.             {
  2347.                 continue;
  2348.             }
  2349.  
  2350.             if ( !IsDefined( enemy.targetname ) || enemy.targetname != "rcbomb" )
  2351.             {
  2352.                 if ( !self bot_vehicle_weapon() )
  2353.                 {
  2354.                     continue;
  2355.                 }
  2356.             }
  2357.  
  2358.             if ( !BulletTracePassed( self.origin, enemy.origin, false, enemy ) )
  2359.             {
  2360.                 continue;
  2361.             }
  2362.  
  2363.             self SetScriptEnemy( enemy );
  2364.             self bot_vehicle_attack( enemy );
  2365.             self ClearScriptEnemy();
  2366.             break;
  2367.         }
  2368.     }
  2369. }
  2370.  
  2371. bot_vehicle_attack( enemy )
  2372. {
  2373.     wait_time = RandomIntRange( 7, 10 );
  2374.  
  2375.     for ( i = 0; i < wait_time; i++ )
  2376.     {
  2377.         wait( 1 );
  2378.  
  2379.         if ( !IsDefined( enemy ) )
  2380.         {
  2381.             return;
  2382.         }
  2383.  
  2384.         if ( !IsAlive( enemy ) )
  2385.         {
  2386.             return;
  2387.         }
  2388.  
  2389.         if ( !IsDefined( enemy.targetname ) || enemy.targetname != "rcbomb" )
  2390.         {
  2391.             if ( !self bot_vehicle_weapon() )
  2392.             {
  2393.                 return;
  2394.             }
  2395.         }
  2396.  
  2397.         if ( !BulletTracePassed( self.origin, enemy.origin, false, enemy ) )
  2398.         {
  2399.             return;
  2400.         }
  2401.     }
  2402. }
  2403.  
  2404. bot_vehicle_weapon()
  2405. {
  2406.     weapons = [];
  2407.     weapons[0] = "m72_law_mp";
  2408.     weapons[1] = "strela_mp";
  2409.     weapons[2] = "m202_flash_mp";
  2410.     weapons[3] = "minigun_mp";
  2411.     weapons[4] = "rpg_mp";
  2412.  
  2413.     for ( i = 0; i < weapons.size; i++ )
  2414.     {
  2415.         if ( self HasWeapon( weapons[i] ) && self bot_vehicle_weapon_ammo( weapons[i] ) > 0 )
  2416.         {
  2417.             return true;
  2418.         }
  2419.     }
  2420.  
  2421.     return false;
  2422. }
  2423.  
  2424. bot_vehicle_weapon_ammo( weapon )
  2425. {
  2426.     return ( self GetWeaponAmmoClip( weapon ) + self GetWeaponAmmoStock( weapon ) );
  2427. }
  2428.  
  2429. turret_path_monitor( turret )
  2430. {
  2431.     self endon( "death" );
  2432.     self endon( "disconnect" );
  2433.     self endon( "bad_path" );
  2434.     //self endon( "goal" );
  2435.  
  2436.     turret waittill_any( "death", "hacked", "turret_deactivated" );
  2437.  
  2438.     self ClearScriptGoal();
  2439.     self ClearScriptEnemy();
  2440. }
  2441.  
  2442. turret_death_monitor( bot )
  2443. {
  2444.     self endon( "death" );
  2445.  
  2446.     bot waittill( "death" );
  2447.     self.bots--;
  2448. }
  2449.  
  2450. bot_wager_think()
  2451. {
  2452.     self endon( "death" );
  2453.     self endon( "disconnect" );
  2454.     level endon ( "game_ended" );
  2455.  
  2456.     if ( !level.wagerMatch )
  2457.     {
  2458.         return;
  2459.     }
  2460.  
  2461.     for ( ;; )
  2462.     {
  2463.         wait( RandomIntRange( 3, 5 ) );
  2464.  
  2465.         if ( IsDefined( self.hasSpyplane ) && self.hasSpyplane == true )
  2466.         {
  2467.             players = get_players();
  2468.             players = array_randomize( players );
  2469.             player = undefined;
  2470.        
  2471.             for ( i = 0; i < players.size; i++ )
  2472.             {
  2473.                 if ( !IsDefined( players[i] ) || !IsAlive( players[i] ) )
  2474.                 {
  2475.                     continue;
  2476.                 }
  2477.  
  2478.                 if ( players[i] == self )
  2479.                 {
  2480.                     continue;
  2481.                 }
  2482.  
  2483.                 if ( players[i].sessionstate != "playing" )
  2484.                 {
  2485.                     continue;
  2486.                 }
  2487.  
  2488.                 player = players[i];
  2489.                 break;
  2490.             }
  2491.  
  2492.             if ( IsDefined( player ) )
  2493.             {
  2494.                 self SetScriptGoal( player.origin, 64 );
  2495.                 self waittill_any( "goal", "bad_path" );
  2496.                 self ClearScriptGoal();
  2497.             }
  2498.         }
  2499.     }
  2500. }
  2501.  
  2502. bot_use_item( weapon )
  2503. {
  2504.     self PressAttackButton();
  2505.     wait( 0.5 );
  2506.  
  2507.     for ( i = 0; i < 5; i++ )
  2508.     {
  2509.         if ( self GetCurrentWeapon() == weapon || self GetCurrentWeapon() == "none" )
  2510.         {
  2511.             self PressAttackButton();
  2512.         }
  2513.  
  2514.         wait( 0.25 );
  2515.     }
  2516. }
  2517.  
  2518. bot_equipment_think( weapon )
  2519. {
  2520.     self endon( "death" );
  2521.     self endon( "disconnect" );
  2522.     level endon ( "game_ended" );
  2523.  
  2524.     if ( !IsDefined( weapon ) )
  2525.     {
  2526.         return;
  2527.     }
  2528.  
  2529.     weapon = weapon + "_mp";
  2530.  
  2531.     for ( ;; )
  2532.     {
  2533.         wait( RandomIntRange( 1, 3 ) );
  2534.  
  2535.         if ( !self HasWeapon( weapon ) )
  2536.         {
  2537.             return;
  2538.         }
  2539.  
  2540.         if ( !self bot_is_idle() )
  2541.         {
  2542.             continue;
  2543.         }
  2544.  
  2545.         if ( self._is_sprinting )
  2546.         {
  2547.             continue;
  2548.         }
  2549.  
  2550.         if ( weapon == "camera_spike_mp" )
  2551.         {
  2552.             if ( self GetLookaheadDist() < 384 )
  2553.             {
  2554.                 continue;
  2555.             }
  2556.  
  2557.             view_angles = self GetPlayerAngles();
  2558.  
  2559.             if ( view_angles[0] < -5 )
  2560.             {
  2561.                 continue;
  2562.             }
  2563.         }
  2564.         else
  2565.         {
  2566.             if ( self GetLookaheadDist() > 64 )
  2567.             {
  2568.                 continue;
  2569.             }
  2570.         }
  2571.  
  2572.         dir = self GetLookaheadDir();
  2573.  
  2574.         if ( !IsDefined( dir ) )
  2575.         {
  2576.             continue;
  2577.         }
  2578.  
  2579.         dir = VectorToAngles( dir );
  2580.  
  2581.         if ( abs( dir[1] - self.angles[1] ) > 5 )
  2582.         {
  2583.             continue;
  2584.         }
  2585.  
  2586.         dir = VectorNormalize( AnglesToForward( self.angles ) );
  2587.         dir = vector_scale( dir, 32 );
  2588.         goal = self.origin + dir;
  2589.  
  2590.         self SetScriptGoal( goal, 128 );
  2591.         self waittill_any( "goal", "bad_path" );
  2592.  
  2593.         if ( equipment_nearby( self.origin ) )
  2594.         {
  2595.             self ClearScriptGoal();
  2596.             continue;
  2597.         }
  2598.  
  2599.         if ( self GetCurrentWeapon() != weapon )
  2600.         {
  2601.             self thread weapon_switch_failsafe();
  2602.             self SwitchToWeapon( weapon );
  2603.             self waittill( "weapon_change_complete" );
  2604.         }
  2605.         else
  2606.         {
  2607.             self ClearScriptGoal();
  2608.             continue;
  2609.         }
  2610.  
  2611.         self bot_use_item( weapon );
  2612.         self ClearScriptGoal();
  2613.         return;
  2614.     }
  2615. }
  2616.  
  2617. bot_equipment_kill_think()
  2618. {
  2619.     self endon( "death" );
  2620.     self endon( "disconnect" );
  2621.     level endon ( "game_ended" );
  2622.  
  2623.     if ( GetDvar( #"bot_difficulty" ) == "easy" )
  2624.     {
  2625.         return;
  2626.     }
  2627.  
  2628.     myteam = self.pers[ "team" ];
  2629.  
  2630.     for ( ;; )
  2631.     {
  2632.         if ( self HasPerk( "specialty_showenemyequipment" ) )
  2633.         {
  2634.             wait( RandomIntRange( 2, 5 ) );
  2635.         }
  2636.         else
  2637.         {
  2638.             wait( RandomIntRange( 5, 7 ) );
  2639.         }
  2640.  
  2641.         if ( !self bot_is_idle() )
  2642.         {
  2643.             continue;
  2644.         }
  2645.  
  2646.         grenades = GetEntArray( "grenade", "classname" );
  2647.         target = undefined;
  2648.  
  2649.         for ( i = 0; i < grenades.size; i++ )
  2650.         {
  2651.             item = grenades[i];
  2652.  
  2653.             if ( !IsDefined( item.name ) )
  2654.             {
  2655.                 continue;
  2656.             }
  2657.  
  2658.             if ( !IsDefined( item.owner ) )
  2659.             {
  2660.                 continue;
  2661.             }
  2662.  
  2663.             if ( level.teamBased && item.owner.team == myteam )
  2664.             {
  2665.                 continue;
  2666.             }
  2667.  
  2668.             if ( item.owner == self )
  2669.             {
  2670.                 continue;
  2671.             }
  2672.  
  2673.             if ( !IsWeaponEquipment( item.name ) )
  2674.             {
  2675.                 continue;
  2676.             }
  2677.  
  2678.             if ( self HasPerk( "specialty_showenemyequipment" ) && DistanceSquared( item.origin, self.origin ) < 512 * 512 )
  2679.             {
  2680.                 target = item;
  2681.                 break;
  2682.             }
  2683.  
  2684.             if ( DistanceSquared( item.origin, self.origin ) < 256 * 256 )
  2685.             {
  2686.                 target = item;
  2687.                 break;
  2688.             }
  2689.         }
  2690.  
  2691.         if ( IsDefined( target ) )
  2692.         {
  2693.             if ( self HasPerk( "specialty_disarmexplosive" ) && target.name != "claymore_mp" )
  2694.             {
  2695.                 self SetScriptGoal( target.origin, 32 );
  2696.                 path = self waittill_any_return( "goal", "bad_path" );
  2697.  
  2698.                 if ( path == "goal" )
  2699.                 {
  2700.                     hackTime = GetDvarFloat( #"perk_disarmExplosiveTime" );
  2701.                     self PressUseButton( hackTime + 0.5 );
  2702.                     wait( hackTime + 0.5 );
  2703.                     self ClearScriptGoal();
  2704.                     continue;
  2705.                 }
  2706.             }
  2707.  
  2708.             self SetScriptEnemy( target );
  2709.             wait( RandomIntRange( 7, 10 ) );
  2710.             self ClearScriptEnemy();
  2711.         }
  2712.     }
  2713. }
  2714.  
  2715. equipment_nearby( origin )
  2716. {
  2717.     grenades = GetEntArray( "grenade", "classname" );
  2718.  
  2719.     for ( i = 0; i < grenades.size; i++ )
  2720.     {
  2721.         item = grenades[i];
  2722.  
  2723.         if ( !IsDefined( item.name ) )
  2724.         {
  2725.             continue;
  2726.         }
  2727.  
  2728.         if ( !IsWeaponEquipment( item.name ) )
  2729.         {
  2730.             continue;
  2731.         }
  2732.  
  2733.         if ( DistanceSquared( item.origin, origin ) < 128 * 128 )
  2734.         {
  2735.             return true;
  2736.         }
  2737.     }
  2738.  
  2739.     return false;
  2740. }
  2741.  
  2742. weapon_switch_failsafe()
  2743. {
  2744.     self endon( "death" );
  2745.     self endon( "disconnect" );
  2746.     self endon( "weapon_change_complete" );
  2747.  
  2748.     wait( 10 );
  2749.  
  2750.     self ClearScriptGoal();
  2751.     self notify( "weapon_change_complete" );
  2752. }
  2753.  
  2754. bot_has_perk( perk )
  2755. {
  2756.     return ( game[ "cac_faction_allies" ] == "cub_rebels" && self.team == "allies" && self.pers[ "bot_perk" ] );
  2757. }
  2758.  
  2759. bot_radiation_think()
  2760. {
  2761.     self endon( "death" );
  2762.     self endon( "disconnect" );
  2763.  
  2764.     if ( level.script != "mp_radiation" )
  2765.     {
  2766.         return;
  2767.     }
  2768.  
  2769.     if ( level.wagerMatch )
  2770.     {
  2771.         return;
  2772.     }
  2773.  
  2774.     origins = [];
  2775.     origins[0] = ( 813, 5, 267 );
  2776.     origins[1] = ( -811, 30, 363 );
  2777.  
  2778.     for ( ;; )
  2779.     {
  2780.         wait( RandomIntRange( 5, 10 ) );
  2781.  
  2782.         origin = random( origins );
  2783.  
  2784.         if ( DistanceSquared( self.origin, origin ) < 256 * 256 )
  2785.         {
  2786.             self SetScriptGoal( origin, 32 );
  2787.  
  2788.             event = self waittill_any_return( "goal", "bad_path" );
  2789.  
  2790.             if ( event == "goal" )
  2791.             {
  2792.                 self PressUseButton( 3 );
  2793.                 wait( 3 );
  2794.                 self ClearScriptGoal();
  2795.                 wait( RandomIntRange( 5, 10 ) );
  2796.             }
  2797.         }
  2798.     }
  2799. }
  2800.  
  2801. /#
  2802.  
  2803. bot_devgui_think()
  2804. {
  2805.     self endon( "death" );
  2806.     self endon( "disconnect" );
  2807.  
  2808.     SetDvar( "devgui_bot", "" );
  2809.     SetDvar( "scr_bot_follow", "0" );
  2810.  
  2811.     for ( ;; )
  2812.     {
  2813.         wait( 1 );
  2814.  
  2815.         reset = true;
  2816.         switch( GetDvar( #"devgui_bot" ) )
  2817.         {
  2818.         case "":
  2819.             reset = false;
  2820.             break;
  2821.  
  2822.         case "crosshair":
  2823.             if ( GetDvarInt( #"scr_bot_follow" ) != 0 )
  2824.             {
  2825.                 iprintln( "Bot following enabled" );
  2826.                 self thread bot_crosshair_follow();
  2827.             }
  2828.             else
  2829.             {
  2830.                 iprintln( "Bot following disabled" );
  2831.                 self notify( "crosshair_follow_off" );
  2832.                 SetDvar( "sv_botsAllowMovement", "0" );
  2833.                 self ClearScriptGoal();
  2834.             }
  2835.             break;
  2836.  
  2837.         case "laststand":
  2838.             SetDvar( "scr_forcelaststand", "1" );
  2839.            
  2840.             self SetPerk( "specialty_pistoldeath" );
  2841.             self SetPerk( "specialty_finalstand" );
  2842.             self DoDamage( self.health, self.origin );
  2843.             break;
  2844.  
  2845.         default:
  2846.             break;
  2847.         }
  2848.  
  2849.         if ( reset )
  2850.         {
  2851.             SetDvar( "devgui_bot", "" );
  2852.         }
  2853.     }
  2854. }
  2855.  
  2856. bot_crosshair_follow()
  2857. {
  2858.     self notify( "crosshair_follow_off" );
  2859.     self endon( "death" );
  2860.     self endon( "disconnect" );
  2861.     self endon( "crosshair_follow_off" );
  2862.    
  2863.     for ( ;; )
  2864.     {
  2865.         wait( 1 );
  2866.         SetDvar( "sv_botsAllowMovement", "1" );
  2867.         SetDvar( "sv_botsIgnoreHumans", "1" );
  2868.         SetDvar( "sv_botsForceStand", "1" );
  2869.    
  2870.         // Trace to where the player is looking
  2871.         player = GetHostPlayer();
  2872.         direction = player GetPlayerAngles();
  2873.         direction_vec = AnglesToForward( direction );
  2874.         eye = player GetEye();
  2875.  
  2876.         scale = 8000;
  2877.         direction_vec = ( direction_vec[0] * scale, direction_vec[1] * scale, direction_vec[2] * scale );
  2878.         trace = bullettrace( eye, eye + direction_vec, 0, undefined );
  2879.  
  2880.         origin = trace[ "position" ] + ( 0, 0, 0 );
  2881.  
  2882.         if ( DistanceSquared( self.origin, origin ) > 128 * 128 )
  2883.         {
  2884.             self ClearScriptGoal();
  2885.             self SetScriptGoal( origin, 32 );
  2886.         }
  2887.     }
  2888. }
  2889.  
  2890. #/
  2891.  
  2892. bot_spawner_Once()
  2893. {
  2894.     if ( !GetDvarInt( #"scr_bots_managed_spawn" ) )
  2895.     {
  2896.         SetDvar( "scr_bots_managed_spawn", 0 );
  2897.     }
  2898.    
  2899.     if ( !GetDvarInt( #"scr_bots_managed_all" ) )
  2900.     {
  2901.         SetDvar( "scr_bots_managed_all", 0 );
  2902.     }
  2903.    
  2904.     if ( !GetDvarInt( #"scr_bots_managed_axis" ) )
  2905.     {
  2906.         SetDvar( "scr_bots_managed_axis", 0 );
  2907.     }
  2908.    
  2909.     if ( !GetDvarInt( #"scr_bots_managed_allies" ) )
  2910.     {
  2911.         SetDvar( "scr_bots_managed_allies", 0 );
  2912.     }
  2913.    
  2914.     if ( GetDvar( #"scr_bot_difficulty" ) == "" )
  2915.     {
  2916.         SetDvar( "scr_bot_difficulty", "normal" );
  2917.     }
  2918.    
  2919.     bot_set_difficulty( GetDvar( #"scr_bot_difficulty" ) );
  2920.    
  2921. /#
  2922.         SetDvar( "sv_botsAllowMovement", "1" );
  2923.         SetDvar( "sv_botsPressAttackBtn", "1" );
  2924.         SetDvar( "sv_botsPressMeleeBtn", "1" );
  2925.         SetDvar( "sv_botsIgnoreHumans", "0" );
  2926.         SetDvar( "scr_botsHasPlayerWeapon", "0" );
  2927.         SetDvar( "scr_botsGrenadesOnly", "0" );
  2928.         SetDvar( "scr_botsSpecialGrenadesOnly", "0" );
  2929. #/
  2930.    
  2931.     level thread bot_spawner_think();
  2932. }
  2933.  
  2934. bot_spawner_think()
  2935. {
  2936.     level endon ( "game_ended" );
  2937.    
  2938.     wait( 0.5 );   
  2939.  
  2940.     for( ;; )
  2941.     {      
  2942.         wait 10.0;
  2943.        
  2944.         if ( game["state"] == "postgame" )
  2945.             return;
  2946.            
  2947.         if( !GetDvarInt( #"scr_bots_managed_spawn" ) )
  2948.             continue;
  2949.            
  2950.         humans = 0;
  2951.  
  2952.         players = level.players;           
  2953.         for ( i = 0; i < players.size; i++ )
  2954.         {
  2955.             player = players[i];
  2956.            
  2957.             if( player is_bot() || player isdemoclient() )
  2958.                 continue;
  2959.            
  2960.             humans++;
  2961.             break;
  2962.         }
  2963.        
  2964. /#
  2965.         PrintLn("Updating bots count per team\n");
  2966. #/
  2967.         countAllies = 0;
  2968.         countAxis = 0;
  2969.        
  2970.         if( IsDefined( level.botsCount["axis"] ) )
  2971.             countAxis = level.botsCount["axis"];
  2972.    
  2973.         if( IsDefined( level.botsCount["allies"] ) )           
  2974.             countAllies = level.botsCount["allies"];
  2975.            
  2976.         num = GetDvarInt( #"scr_bots_managed_all" );
  2977.    
  2978.         if ( num > 0 )
  2979.         {
  2980.             axis_num = Ceil( num / 2 );
  2981.             allies_num = Floor( num / 2 );
  2982.         }
  2983.         else
  2984.         {
  2985.             axis_num = GetDvarInt( #"scr_bots_managed_axis" );
  2986.             allies_num = GetDvarInt( #"scr_bots_managed_allies" );
  2987.         }
  2988.        
  2989.         if( !humans )
  2990.         {
  2991.             // kick all bots if no humans left
  2992.             players = level.players;
  2993.             for ( i = 0; i < players.size; i++ )
  2994.             {
  2995.                 player = players[i];
  2996.                
  2997.                 if( !IsDefined( player.pers[ "isBot" ] ) )
  2998.                     continue;
  2999.                
  3000.                 kick( player getEntityNumber() );
  3001.                 wait(0.25);
  3002.             }
  3003.            
  3004.             // don't spawn any more bots
  3005.             continue;
  3006.         }
  3007.        
  3008.         // got humans so add or remove bots as needed
  3009.         // positive = add ---- negative = kick
  3010.         differenceAxis = axis_num - countAxis;
  3011.         differenceAllies = allies_num - countAllies;
  3012.        
  3013.         if( differenceAxis == 0 && differenceAllies == 0 )
  3014.         {
  3015.             continue;
  3016.         }
  3017.        
  3018.        
  3019.         if( differenceAxis < 0 )
  3020.         {
  3021. /#
  3022.         PrintLn("Updating bots kick axis: " + differenceAxis );
  3023. #/         
  3024.             players = level.players;
  3025.             for ( i = 0; i < players.size; i++ )
  3026.             {
  3027.                 if( differenceAxis >= 0 )
  3028.                     break;
  3029.    
  3030.                 player = players[i];
  3031.                
  3032.                 if( !IsDefined( player.pers[ "isBot" ] ) )
  3033.                     continue;
  3034.                
  3035.                 if( "axis" == player.team )
  3036.                 {
  3037.                     kick( player getEntityNumber() );
  3038.                     differenceAxis = differenceAxis + 1;
  3039.                     wait(0.25);
  3040.                 }
  3041.             }   // for ( i = 0; i < players.size; i++ )            
  3042.         }
  3043.         else // if( differenceAxis < 0 )
  3044.         {
  3045. /#
  3046.             PrintLn("Updating bots add axis: " + differenceAxis );
  3047. #/         
  3048.             for( ; differenceAxis > 0; differenceAxis = differenceAxis - 1 )
  3049.             {
  3050.                 wait( 0.25 );
  3051.                 bot = AddTestClient();
  3052.        
  3053.                 if ( !IsDefined( bot ) )
  3054.                 {
  3055.                     continue;
  3056.                 }
  3057.                            
  3058.                 bot.pers[ "isBot" ] = true;
  3059.                 bot.equipment_enabled = false;
  3060.                 bot thread bot_spawn_think( "axis" );
  3061.             } // while ( spawned_bots < differenceAxis )
  3062.         } // else // if( differenceAxis < 0 )
  3063.        
  3064.         if( differenceAllies < 0 )
  3065.         {
  3066. /#
  3067.             PrintLn("Updating bots kick allies: " + differenceAllies );
  3068. #/ 
  3069.             players = level.players;
  3070.             for ( i = 0; i < players.size; i++ )
  3071.             {
  3072.                 if( differenceAllies >= 0 )
  3073.                     break;
  3074.    
  3075.                 player = players[i];
  3076.                
  3077.                 if( !IsDefined( player.pers[ "isBot" ] ) )
  3078.                     continue;
  3079.                
  3080.                 if( "allies" == player.team )
  3081.                 {
  3082.                     kick( player getEntityNumber() );
  3083.                     differenceAllies = differenceAllies + 1;
  3084.                     wait(0.25);
  3085.                 }              
  3086.             } // for ( i = 0; i < players.size; i++ )
  3087.         }
  3088.         else // if( differenceAllies < 0 )
  3089.         {
  3090. /#
  3091.             PrintLn("Updating bots add allies: " + differenceAllies );
  3092. #/         
  3093.             for( ; differenceAllies > 0; differenceAllies = differenceAllies - 1 )
  3094.             {
  3095.                 wait( 0.25 );
  3096.                 bot = AddTestClient();
  3097.        
  3098.                 if ( !IsDefined( bot ) )
  3099.                 {
  3100.                     continue;
  3101.                 }
  3102.                            
  3103.                 bot.pers[ "isBot" ] = true;
  3104.                 bot.equipment_enabled = false;
  3105.                 bot thread bot_spawn_think( "allies" );
  3106.             }   // while ( spawned_bots < differenceAllies )       
  3107.         } // else // if( differenceAllies < 0 )
  3108.     } // for( ;; )
  3109. }
  3110.  
  3111. /#
  3112. devgui_bot_spawn( team )
  3113. {
  3114.     player = GetHostPlayer();
  3115.  
  3116.     // Trace to where the player is looking
  3117.     direction = player GetPlayerAngles();
  3118.     direction_vec = AnglesToForward( direction );
  3119.     eye = player GetEye();
  3120.  
  3121.     scale = 8000;
  3122.     direction_vec = ( direction_vec[0] * scale, direction_vec[1] * scale, direction_vec[2] * scale );
  3123.     trace = bullettrace( eye, eye + direction_vec, 0, undefined );
  3124.  
  3125.     direction_vec = player.origin - trace["position"];
  3126.     direction = VectorToAngles( direction_vec );
  3127.    
  3128.     bot = AddTestClient();
  3129.  
  3130.     if ( !IsDefined( bot ) )
  3131.     {
  3132.         println( "Could not add test client" );
  3133.         return;
  3134.     }
  3135.            
  3136.     bot.pers["isBot"] = true;
  3137.     bot.equipment_enabled = false;
  3138.     bot thread bot_spawn_think( team );
  3139.  
  3140.     yaw = direction[1];
  3141.     bot thread devgui_bot_spawn_think( trace[ "position" ], yaw );
  3142. }
  3143.  
  3144. devgui_bot_spawn_think( origin, yaw )
  3145. {
  3146.     self endon( "disconnect" );
  3147.  
  3148.     for ( ;; )
  3149.     {
  3150.         self waittill( "spawned_player" );
  3151.         self SetOrigin( origin );
  3152.  
  3153.         angles = ( 0, yaw, 0 );
  3154.         self SetPlayerAngles( angles );
  3155.     }
  3156. }
  3157. #/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement