#include maps\mp\_utility; #include maps\mp\bots\_bot_utility; /* When the bot gets added into the game. */ added() { self endon( "disconnect" ); self set_diff(); } /* When the bot connects to the game. */ connected() { self endon( "disconnect" ); self.killerlocation = undefined; self.lastkiller = undefined; self.bot_change_class = true; self thread difficulty(); self thread teamWatch(); self thread classWatch(); self thread onBotSpawned(); self thread onSpawned(); } /* The callback for when the bot gets killed. */ onKilled( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration ) { self.killerlocation = undefined; self.lastkiller = undefined; if ( !isdefined( self ) || !isdefined( self.team ) ) return; if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) return; if ( iDamage <= 0 ) return; if ( !isdefined( eAttacker ) || !isdefined( eAttacker.team ) ) return; if ( eAttacker == self ) return; if ( level.teambased && eAttacker.team == self.team ) return; if ( !isdefined( eInflictor ) || eInflictor.classname != "player" ) return; if ( !isalive( eAttacker ) ) return; self.killerlocation = eAttacker.origin; self.lastkiller = eAttacker; } /* The callback for when the bot gets damaged. */ onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) { if ( !isdefined( self ) || !isdefined( self.team ) ) return; if ( !isalive( self ) ) return; if ( sMeansOfDeath == "MOD_FALLING" || sMeansOfDeath == "MOD_SUICIDE" ) return; if ( iDamage <= 0 ) return; if ( !isdefined( eAttacker ) || !isdefined( eAttacker.team ) ) return; if ( eAttacker == self ) return; if ( level.teambased && eAttacker.team == self.team ) return; if ( !isdefined( eInflictor ) || eInflictor.classname != "player" ) return; if ( !isalive( eAttacker ) ) return; self bot_cry_for_help( eAttacker ); self SetAttacker( eAttacker ); } /* When the bot gets attacked, have the bot ask for help from teammates. */ bot_cry_for_help( attacker ) { if ( !level.teambased ) { return; } theTime = gettime(); if ( isdefined( self.help_time ) && theTime - self.help_time < 1000 ) { return; } self.help_time = theTime; for ( i = level.players.size - 1; i >= 0; i-- ) { player = level.players[i]; if ( !player is_bot() ) { continue; } if ( !isdefined( player.team ) ) continue; if ( !player IsPlayerModelOK() ) continue; if ( !isalive( player ) ) { continue; } if ( player == self ) { continue; } if ( player.team != self.team ) { continue; } dist = player.pers["bots"]["skill"]["help_dist"]; dist *= dist; if ( distancesquared( self.origin, player.origin ) > dist ) { continue; } if ( randomint( 100 ) < 50 ) { self SetAttacker( attacker ); if ( randomint( 100 ) > 70 ) { break; } } } } /* Sets the bot difficulty. */ set_diff() { rankVar = getcvarint( "bots_skill" ); switch ( rankVar ) { case 0: self.pers["bots"]["skill"]["base"] = RoundNum( random_normal_distribution( 3.5, 1.75, 1, 7 ) ); break; case 8: break; case 9: self.pers["bots"]["skill"]["base"] = randomintrange( 1, 7 ); self.pers["bots"]["skill"]["aim_time"] = 0.05 * randomintrange( 1, 20 ); self.pers["bots"]["skill"]["init_react_time"] = 50 * randomint( 100 ); self.pers["bots"]["skill"]["reaction_time"] = 50 * randomint( 100 ); self.pers["bots"]["skill"]["no_trace_ads_time"] = 50 * randomint( 100 ); self.pers["bots"]["skill"]["no_trace_look_time"] = 50 * randomint( 100 ); self.pers["bots"]["skill"]["remember_time"] = 50 * randomint( 100 ); self.pers["bots"]["skill"]["fov"] = randomfloatrange( -1, 1 ); randomNum = randomintrange( 500, 25000 ); self.pers["bots"]["skill"]["dist_start"] = randomNum; self.pers["bots"]["skill"]["dist_max"] = randomNum * 2; self.pers["bots"]["skill"]["spawn_time"] = 0.05 * randomint( 20 ); self.pers["bots"]["skill"]["help_dist"] = randomintrange( 500, 25000 ); self.pers["bots"]["skill"]["semi_time"] = randomfloatrange( 0.05, 1 ); self.pers["bots"]["skill"]["shoot_after_time"] = randomfloatrange( 0.05, 1 ); self.pers["bots"]["skill"]["aim_offset_time"] = randomfloatrange( 0.05, 1 ); self.pers["bots"]["skill"]["aim_offset_amount"] = randomfloatrange( 0.05, 1 ); self.pers["bots"]["skill"]["bone_update_interval"] = randomfloatrange( 0.05, 1 ); self.pers["bots"]["skill"]["bones"] = "j_head,j_spine4,j_ankle_ri,j_ankle_le"; self.pers["bots"]["behavior"]["strafe"] = randomint( 100 ); self.pers["bots"]["behavior"]["nade"] = randomint( 100 ); self.pers["bots"]["behavior"]["camp"] = randomint( 100 ); self.pers["bots"]["behavior"]["follow"] = randomint( 100 ); self.pers["bots"]["behavior"]["crouch"] = randomint( 100 ); self.pers["bots"]["behavior"]["switch"] = randomint( 100 ); self.pers["bots"]["behavior"]["class"] = randomint( 100 ); self.pers["bots"]["behavior"]["jump"] = randomint( 100 ); break; default: self.pers["bots"]["skill"]["base"] = rankVar; break; } } /* Updates the bot's difficulty variables. */ difficulty() { self endon( "disconnect" ); for ( ;; ) { if ( getcvarint( "bots_skill" ) != 9 ) { switch ( self.pers["bots"]["skill"]["base"] ) { case 1: self.pers["bots"]["skill"]["aim_time"] = 0.6; self.pers["bots"]["skill"]["init_react_time"] = 1500; self.pers["bots"]["skill"]["reaction_time"] = 1000; self.pers["bots"]["skill"]["no_trace_ads_time"] = 500; self.pers["bots"]["skill"]["no_trace_look_time"] = 600; self.pers["bots"]["skill"]["remember_time"] = 750; self.pers["bots"]["skill"]["fov"] = 0.7; self.pers["bots"]["skill"]["dist_max"] = 2500; self.pers["bots"]["skill"]["dist_start"] = 1000; self.pers["bots"]["skill"]["spawn_time"] = 0.75; self.pers["bots"]["skill"]["help_dist"] = 0; self.pers["bots"]["skill"]["semi_time"] = 0.9; self.pers["bots"]["skill"]["shoot_after_time"] = 1; self.pers["bots"]["skill"]["aim_offset_time"] = 1.5; self.pers["bots"]["skill"]["aim_offset_amount"] = 4; self.pers["bots"]["skill"]["bone_update_interval"] = 2; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_ankle_le,j_ankle_ri"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 0; self.pers["bots"]["behavior"]["nade"] = 10; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 20; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 0; break; case 2: self.pers["bots"]["skill"]["aim_time"] = 0.55; self.pers["bots"]["skill"]["init_react_time"] = 1000; self.pers["bots"]["skill"]["reaction_time"] = 800; self.pers["bots"]["skill"]["no_trace_ads_time"] = 1000; self.pers["bots"]["skill"]["no_trace_look_time"] = 1250; self.pers["bots"]["skill"]["remember_time"] = 1500; self.pers["bots"]["skill"]["fov"] = 0.65; self.pers["bots"]["skill"]["dist_max"] = 3000; self.pers["bots"]["skill"]["dist_start"] = 1500; self.pers["bots"]["skill"]["spawn_time"] = 0.65; self.pers["bots"]["skill"]["help_dist"] = 500; self.pers["bots"]["skill"]["semi_time"] = 0.75; self.pers["bots"]["skill"]["shoot_after_time"] = 0.75; self.pers["bots"]["skill"]["aim_offset_time"] = 1; self.pers["bots"]["skill"]["aim_offset_amount"] = 3; self.pers["bots"]["skill"]["bone_update_interval"] = 1.5; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_ankle_le,j_ankle_ri,j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 10; self.pers["bots"]["behavior"]["nade"] = 15; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 15; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 10; break; case 3: self.pers["bots"]["skill"]["aim_time"] = 0.4; self.pers["bots"]["skill"]["init_react_time"] = 750; self.pers["bots"]["skill"]["reaction_time"] = 500; self.pers["bots"]["skill"]["no_trace_ads_time"] = 1000; self.pers["bots"]["skill"]["no_trace_look_time"] = 1500; self.pers["bots"]["skill"]["remember_time"] = 2000; self.pers["bots"]["skill"]["fov"] = 0.6; self.pers["bots"]["skill"]["dist_max"] = 4000; self.pers["bots"]["skill"]["dist_start"] = 2250; self.pers["bots"]["skill"]["spawn_time"] = 0.5; self.pers["bots"]["skill"]["help_dist"] = 750; self.pers["bots"]["skill"]["semi_time"] = 0.65; self.pers["bots"]["skill"]["shoot_after_time"] = 0.65; self.pers["bots"]["skill"]["aim_offset_time"] = 0.75; self.pers["bots"]["skill"]["aim_offset_amount"] = 2.5; self.pers["bots"]["skill"]["bone_update_interval"] = 1; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_spine4,j_ankle_le,j_ankle_ri,j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 20; self.pers["bots"]["behavior"]["nade"] = 20; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 10; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 25; break; case 4: self.pers["bots"]["skill"]["aim_time"] = 0.3; self.pers["bots"]["skill"]["init_react_time"] = 600; self.pers["bots"]["skill"]["reaction_time"] = 400; self.pers["bots"]["skill"]["no_trace_ads_time"] = 1000; self.pers["bots"]["skill"]["no_trace_look_time"] = 1500; self.pers["bots"]["skill"]["remember_time"] = 3000; self.pers["bots"]["skill"]["fov"] = 0.55; self.pers["bots"]["skill"]["dist_max"] = 5000; self.pers["bots"]["skill"]["dist_start"] = 3350; self.pers["bots"]["skill"]["spawn_time"] = 0.35; self.pers["bots"]["skill"]["help_dist"] = 1000; self.pers["bots"]["skill"]["semi_time"] = 0.5; self.pers["bots"]["skill"]["shoot_after_time"] = 0.5; self.pers["bots"]["skill"]["aim_offset_time"] = 0.5; self.pers["bots"]["skill"]["aim_offset_amount"] = 2; self.pers["bots"]["skill"]["bone_update_interval"] = 0.75; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_spine4,j_ankle_le,j_ankle_ri,j_head,j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 30; self.pers["bots"]["behavior"]["nade"] = 25; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 10; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 35; break; case 5: self.pers["bots"]["skill"]["aim_time"] = 0.25; self.pers["bots"]["skill"]["init_react_time"] = 500; self.pers["bots"]["skill"]["reaction_time"] = 300; self.pers["bots"]["skill"]["no_trace_ads_time"] = 1500; self.pers["bots"]["skill"]["no_trace_look_time"] = 2000; self.pers["bots"]["skill"]["remember_time"] = 4000; self.pers["bots"]["skill"]["fov"] = 0.5; self.pers["bots"]["skill"]["dist_max"] = 7500; self.pers["bots"]["skill"]["dist_start"] = 5000; self.pers["bots"]["skill"]["spawn_time"] = 0.25; self.pers["bots"]["skill"]["help_dist"] = 1500; self.pers["bots"]["skill"]["semi_time"] = 0.4; self.pers["bots"]["skill"]["shoot_after_time"] = 0.35; self.pers["bots"]["skill"]["aim_offset_time"] = 0.35; self.pers["bots"]["skill"]["aim_offset_amount"] = 1.5; self.pers["bots"]["skill"]["bone_update_interval"] = 0.5; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 40; self.pers["bots"]["behavior"]["nade"] = 35; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 10; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 50; break; case 6: self.pers["bots"]["skill"]["aim_time"] = 0.2; self.pers["bots"]["skill"]["init_react_time"] = 250; self.pers["bots"]["skill"]["reaction_time"] = 150; self.pers["bots"]["skill"]["no_trace_ads_time"] = 2000; self.pers["bots"]["skill"]["no_trace_look_time"] = 3000; self.pers["bots"]["skill"]["remember_time"] = 5000; self.pers["bots"]["skill"]["fov"] = 0.45; self.pers["bots"]["skill"]["dist_max"] = 10000; self.pers["bots"]["skill"]["dist_start"] = 7500; self.pers["bots"]["skill"]["spawn_time"] = 0.2; self.pers["bots"]["skill"]["help_dist"] = 2000; self.pers["bots"]["skill"]["semi_time"] = 0.25; self.pers["bots"]["skill"]["shoot_after_time"] = 0.25; self.pers["bots"]["skill"]["aim_offset_time"] = 0.25; self.pers["bots"]["skill"]["aim_offset_amount"] = 1; self.pers["bots"]["skill"]["bone_update_interval"] = 0.25; self.pers["bots"]["skill"]["bones"] = "j_spine4,j_head,j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 50; self.pers["bots"]["behavior"]["nade"] = 45; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 10; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 75; break; case 7: self.pers["bots"]["skill"]["aim_time"] = 0.1; self.pers["bots"]["skill"]["init_react_time"] = 100; self.pers["bots"]["skill"]["reaction_time"] = 50; self.pers["bots"]["skill"]["no_trace_ads_time"] = 2500; self.pers["bots"]["skill"]["no_trace_look_time"] = 4000; self.pers["bots"]["skill"]["remember_time"] = 7500; self.pers["bots"]["skill"]["fov"] = 0.4; self.pers["bots"]["skill"]["dist_max"] = 15000; self.pers["bots"]["skill"]["dist_start"] = 10000; self.pers["bots"]["skill"]["spawn_time"] = 0.05; self.pers["bots"]["skill"]["help_dist"] = 3000; self.pers["bots"]["skill"]["semi_time"] = 0.1; self.pers["bots"]["skill"]["shoot_after_time"] = 0; self.pers["bots"]["skill"]["aim_offset_time"] = 0; self.pers["bots"]["skill"]["aim_offset_amount"] = 0; self.pers["bots"]["skill"]["bone_update_interval"] = 0.05; self.pers["bots"]["skill"]["bones"] = "j_head"; self.pers["bots"]["skill"]["ads_fov_multi"] = 0.5; self.pers["bots"]["skill"]["ads_aimspeed_multi"] = 0.5; self.pers["bots"]["behavior"]["strafe"] = 65; self.pers["bots"]["behavior"]["nade"] = 65; self.pers["bots"]["behavior"]["camp"] = 5; self.pers["bots"]["behavior"]["follow"] = 5; self.pers["bots"]["behavior"]["crouch"] = 5; self.pers["bots"]["behavior"]["switch"] = 2; self.pers["bots"]["behavior"]["class"] = 2; self.pers["bots"]["behavior"]["jump"] = 90; break; } } wait 5; } } /* Makes sure the bot is on a team. */ teamWatch() { self endon( "disconnect" ); for ( ;; ) { while ( !isdefined( self.pers["team"] ) || !allowTeamChoice() ) wait .05; wait 0.1; if ( self.team != "axis" && self.team != "allies" ) self notify( "menuresponse", game["menu_team"], getcvar( "bots_team" ) ); while ( isdefined( self.pers["team"] ) ) wait .05; } } /* Chooses a random class */ chooseRandomClass() { weap = ""; weapons = []; if ( self.team == "axis" ) { weapons[weapons.size] = "mp40_mp"; weapons[weapons.size] = "mp44_mp"; weapons[weapons.size] = "kar98k_mp"; weapons[weapons.size] = "kar98k_sniper_mp"; weapons[weapons.size] = "shotgun_mp"; weapons[weapons.size] = "g43_mp"; } else { if ( game["allies"] == "american" ) { weapons[weapons.size] = "shotgun_mp"; weapons[weapons.size] = "bar_mp"; weapons[weapons.size] = "thompson_mp"; weapons[weapons.size] = "springfield_mp"; weapons[weapons.size] = "m1garand_mp"; weapons[weapons.size] = "m1carbine_mp"; weapons[weapons.size] = "greasegun_mp"; } else if ( game["allies"] == "british" ) { weapons[weapons.size] = "shotgun_mp"; weapons[weapons.size] = "sten_mp"; weapons[weapons.size] = "bren_mp"; weapons[weapons.size] = "enfield_mp"; weapons[weapons.size] = "enfield_scope_mp"; weapons[weapons.size] = "m1garand_mp"; weapons[weapons.size] = "thompson_mp"; } else { weapons[weapons.size] = "shotgun_mp"; weapons[weapons.size] = "ppsh_mp"; weapons[weapons.size] = "mosin_nagant_mp"; weapons[weapons.size] = "mosin_nagant_sniper_mp"; weapons[weapons.size] = "SVT40_mp"; weapons[weapons.size] = "PPS42_mp"; } } weap = weapons[randomint( weapons.size )]; return weap; } /* Selects a class for the bot. */ classWatch() { self endon( "disconnect" ); // cod2 has to wait this long or else theres a crash? wait 3; for ( ;; ) { while ( !isdefined( self.pers["team"] ) || !allowClassChoice() ) wait .05; wait 0.5; if ( !isdefined( self.pers["weapon"] ) || self.pers["weapon"] == "" || !isdefined( self.bot_change_class ) ) self notify( "menuresponse", game["menu_weapon_" + self.team], self chooseRandomClass() ); self.bot_change_class = true; while ( isdefined( self.pers["team"] ) && isdefined( self.pers["weapon"] ) && self.pers["weapon"] != "" && isdefined( self.bot_change_class ) ) wait .05; } } /* When the bot spawns. */ onSpawned() { self endon( "disconnect" ); for ( ;; ) { self waittill( "spawned_player" ); if ( randomint( 100 ) <= self.pers["bots"]["behavior"]["class"] ) self.bot_change_class = undefined; self.bot_lock_goal = false; self.help_time = undefined; self.bot_was_follow_script_update = undefined; } } /* When the bot spawned, after the difficulty wait. Start the logic for the bot. */ onBotSpawned() { self endon( "disconnect" ); level endon( "game_ended" ); for ( ;; ) { self waittill( "bot_spawned" ); self thread start_bot_threads(); } } /* Starts all the bot thinking */ start_bot_threads() { self endon( "disconnect" ); level endon( "game_ended" ); self endon( "death" ); }