730 lines
24 KiB
Plaintext
730 lines
24 KiB
Plaintext
#include common_scripts\utility;
|
|
#include maps\mp\_utility;
|
|
#include maps\mp\bots\_bots;
|
|
#include maps\mp\bots\_bots_ks;
|
|
#include maps\mp\bots\_bots_util;
|
|
#include maps\mp\bots\_bots_strategy;
|
|
#include maps\mp\bots\_bots_personality;
|
|
|
|
bot_fireteam_setup_callbacks()
|
|
{
|
|
|
|
}
|
|
|
|
bot_fireteam_init()
|
|
{
|
|
level.bots_fireteam_num_classes_loaded = [];
|
|
|
|
level thread bot_fireteam_connect_monitor();
|
|
}
|
|
|
|
//========================================================
|
|
// bot_fireteam_connect_monitor
|
|
//========================================================
|
|
bot_fireteam_connect_monitor()
|
|
{
|
|
self notify( "bot_connect_monitor" );
|
|
self endon( "bot_connect_monitor" );
|
|
|
|
level.bots_fireteam_humans = [];
|
|
while(1)
|
|
{
|
|
foreach(player in level.players)
|
|
{
|
|
if ( !IsBot( player ) && !IsDefined(player.processed_for_fireteam) )
|
|
{
|
|
if ( IsDefined(player.team) && (player.team == "allies" || player.team == "axis") )
|
|
{
|
|
// Player is already on a team, so skip right to the bot spawning
|
|
player.processed_for_fireteam = true;
|
|
|
|
level.bots_fireteam_humans[player.team] = player;
|
|
level.bots_fireteam_num_classes_loaded[player.team] = 0;
|
|
|
|
team_limit = bot_get_team_limit();
|
|
|
|
if ( level.bots_fireteam_humans.size == 2 )
|
|
{
|
|
// TEMP - remove the 6 bots that were already spawned on this team to make room for the player's bots
|
|
drop_bots( team_limit-1, player.team );
|
|
}
|
|
|
|
spawn_bots( team_limit-1, player.team, ::bot_fireteam_spawn_callback );
|
|
|
|
if ( level.bots_fireteam_humans.size == 1 )
|
|
{
|
|
num_human_players = 0;
|
|
foreach( client in level.players )
|
|
{
|
|
if ( IsDefined( client ) && !IsBot( client ) )
|
|
num_human_players++;
|
|
}
|
|
if ( num_human_players == 1 )
|
|
{
|
|
// TEMP - spawn 6 bots on the other team for enemies
|
|
spawn_bots( team_limit-1, get_enemy_team( player.team ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wait(0.25);
|
|
}
|
|
}
|
|
|
|
bot_fireteam_spawn_callback()
|
|
{
|
|
// Make sure the fireteam code is called to determine this bot's class, not the personality or default class selection code
|
|
self.override_class_function = ::bot_fireteam_setup_callback_class;
|
|
|
|
// Set fireteam commander to the human player on this team
|
|
self.fireteam_commander = level.bots_fireteam_humans[self.bot_team];
|
|
|
|
// Monitor earning killstreaks and let our commander know
|
|
self thread bot_fireteam_monitor_killstreak_earned();
|
|
}
|
|
|
|
bot_fireteam_setup_callback_class()
|
|
{
|
|
// Set the bot as "callback" class and set up the callback function for when he chooses his loadout
|
|
self.classCallback = ::bot_fireteam_loadout_class_callback;
|
|
return "callback";
|
|
}
|
|
|
|
bot_fireteam_loadout_class_callback()
|
|
{
|
|
if ( IsDefined(self.botLastLoadout) )
|
|
return self.botLastLoadout;
|
|
|
|
//FIXME: Unify this with Squad vs. Squad mode...
|
|
self.class_num = level.bots_fireteam_num_classes_loaded[self.team];
|
|
level.bots_fireteam_num_classes_loaded[self.team] += 1;
|
|
|
|
if ( self.class_num == 5 )
|
|
{
|
|
// Ugly hack - the 6th class is currently not supported because the player only has 5 loadouts unlocked by default
|
|
// Different things happen depending on how you are playing - loadouts return "none", cause script errors, etc.,
|
|
// so better to just pinch it off here and return a random loadout
|
|
// TODO: Fix this correctly
|
|
//return maps\mp\bots\_bots_loadout::bot_loadout_class_callback();
|
|
self.class_num = 0;
|
|
}
|
|
|
|
loadoutValueArray["loadoutPrimary"] = self.fireteam_commander bot_fireteam_cac_getWeapon( self.class_num, 0 );
|
|
loadoutValueArray["loadoutPrimaryAttachment"] = self.fireteam_commander bot_fireteam_cac_getWeaponAttachment( self.class_num, 0 );
|
|
loadoutValueArray["loadoutPrimaryAttachment2"] = self.fireteam_commander bot_fireteam_cac_getWeaponAttachmentTwo( self.class_num, 0 );
|
|
loadoutValueArray["loadoutPrimaryBuff"] = self.fireteam_commander bot_fireteam_cac_getWeaponBuff( self.class_num, 0 );
|
|
loadoutValueArray["loadoutPrimaryCamo"] = self.fireteam_commander bot_fireteam_cac_getWeaponCamo( self.class_num, 0 );
|
|
loadoutValueArray["loadoutPrimaryReticle"] = self.fireteam_commander bot_fireteam_cac_getWeaponReticle( self.class_num, 0 );
|
|
loadoutValueArray["loadoutSecondary"] = self.fireteam_commander bot_fireteam_cac_getWeapon( self.class_num, 1 );
|
|
loadoutValueArray["loadoutSecondaryAttachment"] = self.fireteam_commander bot_fireteam_cac_getWeaponAttachment( self.class_num, 1 );
|
|
loadoutValueArray["loadoutSecondaryAttachment2"] = self.fireteam_commander bot_fireteam_cac_getWeaponAttachmentTwo( self.class_num, 1 );
|
|
loadoutValueArray["loadoutSecondaryBuff"] = self.fireteam_commander bot_fireteam_cac_getWeaponBuff( self.class_num, 1 );
|
|
loadoutValueArray["loadoutSecondaryCamo"] = self.fireteam_commander bot_fireteam_cac_getWeaponCamo( self.class_num, 1 );
|
|
loadoutValueArray["loadoutSecondaryReticle"] = self.fireteam_commander bot_fireteam_cac_getWeaponReticle( self.class_num, 1 );
|
|
loadoutValueArray["loadoutEquipment"] = self.fireteam_commander bot_fireteam_cac_getPrimaryGrenade( self.class_num );
|
|
loadoutValueArray["loadoutOffhand"] = self.fireteam_commander bot_fireteam_cac_getSecondaryGrenade( self.class_num );
|
|
loadoutValueArray["loadoutPerk1"] = self.fireteam_commander bot_fireteam_cac_getPerk( self.class_num, 2 );
|
|
loadoutValueArray["loadoutPerk2"] = self.fireteam_commander bot_fireteam_cac_getPerk( self.class_num, 3 );
|
|
loadoutValueArray["loadoutPerk3"] = self.fireteam_commander bot_fireteam_cac_getPerk( self.class_num, 4 );
|
|
loadoutValueArray["loadoutStreakType"] = self.fireteam_commander bot_fireteam_cac_getPerk( self.class_num, 5 );
|
|
if ( loadoutValueArray["loadoutStreakType"] != "specialty_null" )
|
|
{
|
|
playerData = GetSubStr(loadoutValueArray["loadoutStreakType"],11) + "Streaks"; // "loadoutStreakType" will be streaktype_assault, etc, so remove first 11 chars
|
|
|
|
loadoutValueArray["loadoutStreak1"] = self.fireteam_commander bot_fireteam_cac_getStreak( self.class_num, playerData, 0 );
|
|
if ( loadoutValueArray["loadoutStreak1"] == "none" )
|
|
loadoutValueArray["loadoutStreak1"] = undefined;
|
|
|
|
loadoutValueArray["loadoutStreak2"] = self.fireteam_commander bot_fireteam_cac_getStreak( self.class_num, playerData, 1 );
|
|
if ( loadoutValueArray["loadoutStreak2"] == "none" )
|
|
loadoutValueArray["loadoutStreak2"] = undefined;
|
|
|
|
loadoutValueArray["loadoutStreak3"] = self.fireteam_commander bot_fireteam_cac_getStreak( self.class_num, playerData, 2 );
|
|
if ( loadoutValueArray["loadoutStreak3"] == "none" )
|
|
loadoutValueArray["loadoutStreak3"] = undefined;
|
|
|
|
/#
|
|
bot_fireteam_test_killstreaks(loadoutValueArray, self);
|
|
#/
|
|
}
|
|
|
|
self.botLastLoadout = loadoutValueArray;
|
|
|
|
return loadoutValueArray;
|
|
}
|
|
|
|
/#
|
|
bot_fireteam_test_killstreaks(loadoutValueArray, bot)
|
|
{
|
|
if ( IsDefined(loadoutValueArray["loadoutStreak1"]) )
|
|
bot_killstreak_valid_for_specific_streakType(loadoutValueArray["loadoutStreak1"], loadoutValueArray["loadoutStreakType"], true);
|
|
if ( IsDefined(loadoutValueArray["loadoutStreak2"]) )
|
|
bot_killstreak_valid_for_specific_streakType(loadoutValueArray["loadoutStreak2"], loadoutValueArray["loadoutStreakType"], true);
|
|
if ( IsDefined(loadoutValueArray["loadoutStreak3"]) )
|
|
bot_killstreak_valid_for_specific_streakType(loadoutValueArray["loadoutStreak3"], loadoutValueArray["loadoutStreakType"], true);
|
|
}
|
|
#/
|
|
|
|
bot_fireteam_cac_getWeapon( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "weapon" );
|
|
}
|
|
|
|
bot_fireteam_cac_getWeaponAttachment( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "attachment", 0 );
|
|
}
|
|
|
|
bot_fireteam_cac_getWeaponAttachmentTwo( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "attachment", 1 );
|
|
}
|
|
|
|
bot_fireteam_cac_getWeaponBuff( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "buff" );
|
|
}
|
|
|
|
bot_fireteam_cac_getWeaponCamo( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "camo" );
|
|
}
|
|
|
|
bot_fireteam_cac_getWeaponReticle( classIndex, weaponIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "weaponSetups", weaponIndex, "reticle" );
|
|
}
|
|
|
|
bot_fireteam_cac_getPrimaryGrenade( classIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "perks", 0 );
|
|
}
|
|
|
|
bot_fireteam_cac_getSecondaryGrenade( classIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "perks", 1 );
|
|
}
|
|
|
|
bot_fireteam_cac_getPerk( classIndex, perkIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, "perks", perkIndex );
|
|
}
|
|
|
|
bot_fireteam_cac_getStreak( classIndex, playerData, streakIndex )
|
|
{
|
|
return self getCaCPlayerData( classIndex, playerData, streakIndex );
|
|
}
|
|
|
|
//========================================
|
|
//
|
|
// TACTICS
|
|
//
|
|
//========================================
|
|
|
|
|
|
//---------------------
|
|
// BUDDY SYSTEM
|
|
//---------------------
|
|
|
|
bot_fireteam_buddy_think()
|
|
{
|
|
buddy_range = 250;
|
|
buddy_range_sq = (buddy_range*buddy_range);
|
|
if ( !self bot_is_guarding_player( self.owner ) )
|
|
{
|
|
self bot_guard_player( self.owner, buddy_range );
|
|
}
|
|
|
|
if ( DistanceSquared( self.origin, self.owner.origin ) > buddy_range_sq )
|
|
{
|
|
self BotSetFlag( "force_sprint", true );
|
|
}
|
|
else if ( self.owner IsSprinting() )
|
|
{
|
|
self BotSetFlag( "force_sprint", true );
|
|
}
|
|
else
|
|
{
|
|
self BotSetFlag( "force_sprint", false );
|
|
}
|
|
}
|
|
|
|
bot_fireteam_buddy_search()
|
|
{
|
|
self endon( "buddy_cancel" );
|
|
self endon( "disconnect" );
|
|
|
|
self notify( "buddy_search_start" );
|
|
self endon( "buddy_search_start" );
|
|
|
|
while(1)
|
|
{
|
|
if ( IsAlive( self ) && !IsDefined( self.bot_fireteam_follower ) )
|
|
{//we're alive & not a leader
|
|
if ( IsDefined( self.owner ) )
|
|
{//we have a leader
|
|
if ( self.sessionstate == "playing" )
|
|
{//we're playing
|
|
if ( !self.owner.connected )
|
|
{//my owner disconnected - search for a new one
|
|
self.owner.bot_fireteam_follower = undefined;
|
|
self.owner = undefined;
|
|
}
|
|
else if ( isdefined( level.fireteam_commander[self.team] ) )
|
|
{//we have a player commander
|
|
if ( IsDefined(level.fireteam_commander[self.team].commanding_bot) && level.fireteam_commander[self.team].commanding_bot == self )
|
|
{//the commander took us over, make our leader follow the commander instead
|
|
//clear our leader's follower
|
|
self.owner.bot_fireteam_follower = undefined;
|
|
//make our leader follow the commander
|
|
self.owner.owner = level.fireteam_commander[self.team];
|
|
self.owner.personality_update_function = ::bot_fireteam_buddy_think;
|
|
//clear our leader
|
|
self.owner = undefined;
|
|
}
|
|
else if ( IsDefined(level.fireteam_commander[self.team].commanding_bot) && level.fireteam_commander[self.team].commanding_bot == self.owner )
|
|
{//the commander has taken over our owner, switch to the commander as our owner
|
|
self.owner.bot_fireteam_follower = undefined;
|
|
self.owner = level.fireteam_commander[self.team];
|
|
self.owner.bot_fireteam_follower = self;
|
|
}
|
|
else if ( self.owner == level.fireteam_commander[self.team] && !IsDefined( self.owner.commanding_bot ) )
|
|
{//the commander was our owner and is no longer controlling a bot, switch to the bot they were last controlling
|
|
self.owner.bot_fireteam_follower = undefined;
|
|
if ( IsDefined( self.owner.last_commanded_bot ) )
|
|
{//switch to the bot the commander relinquished control over
|
|
self.owner = self.owner.last_commanded_bot;
|
|
self.owner.bot_fireteam_follower = self;
|
|
}
|
|
else
|
|
{//there is no last bot they were commanding? search for a new one
|
|
self.owner = undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{//we've been sidelined
|
|
if ( isdefined( level.fireteam_commander[self.team] ) )
|
|
{//we have a player commander
|
|
if ( IsDefined(level.fireteam_commander[self.team].commanding_bot) && level.fireteam_commander[self.team].commanding_bot == self )
|
|
{//the commander took us over, make our leader follow the commander instead
|
|
//clear our leader's follower
|
|
self.owner.bot_fireteam_follower = undefined;
|
|
//make our leader follow the commander
|
|
self.owner.owner = level.fireteam_commander[self.team];
|
|
self.owner.personality_update_function = ::bot_fireteam_buddy_think;
|
|
//clear our leader
|
|
self.owner = undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( self.sessionstate == "playing" )
|
|
{
|
|
if ( !IsDefined( self.owner ) )
|
|
{//look for the closest other player/bot
|
|
myAvailableTeam = [];
|
|
foreach( player in level.players )
|
|
{
|
|
if ( player != self && player.team == self.team )
|
|
{//on our team and not us, ourselves
|
|
if ( IsAlive( player ) && player.sessionstate == "playing" && !IsDefined( player.bot_fireteam_follower ) && !IsDefined( player.owner ) )
|
|
{//player/bot is alive, playing and not already a leader and not a follower
|
|
myAvailableTeam[myAvailableTeam.size] = player;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( myAvailableTeam.size > 0 )
|
|
{//there's at least one available, unattached other bot/player
|
|
closestBot = getClosest( self.origin, myAvailableTeam );
|
|
if ( IsDefined( closestBot ) )
|
|
{//get the closest one and follow them
|
|
self.owner = closestBot;
|
|
self.owner.bot_fireteam_follower = self;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( IsDefined( self.owner ) )
|
|
{//have a leader
|
|
//Line( self.origin + (0,0,48), self.owner.origin + (0,0,48), (0,1,0), 1.0, false, 10 );
|
|
//Line( self.origin + (0,0,48), self.origin + (0,0,128), (1,1,1), 1.0, false, 10 );
|
|
//Line( self.owner.origin + (0,0,48), self.owner.origin + (0,0,128), (0,1,1), 1.0, false, 10 );
|
|
self.personality_update_function = ::bot_fireteam_buddy_think;
|
|
}
|
|
else
|
|
{//no leader
|
|
//Line( self.origin + (0,0,48), self.origin + (0,0,128), (1,0,0), 1.0, false, 10 );
|
|
self bot_assign_personality_functions();
|
|
}
|
|
}
|
|
wait(0.5);
|
|
}
|
|
}
|
|
|
|
//---------------------
|
|
// HUNTING PARTY
|
|
//---------------------
|
|
fireteam_tdm_set_hunt_leader( whichTeam )
|
|
{
|
|
//try to use the player if they're in the game
|
|
botsOnTeam = [];
|
|
foreach( player in level.players )
|
|
{
|
|
if ( player.team == whichTeam )
|
|
{
|
|
if ( player.connected && IsAlive( player ) && player.sessionstate == "playing" )
|
|
{
|
|
if ( !IsBot( player ) )
|
|
{
|
|
level.fireteam_hunt_leader[whichTeam] = player;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
botsOnTeam[botsOnTeam.size] = player;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !IsDefined( level.fireteam_hunt_leader[whichTeam] ) )
|
|
{//if no leader yet, use a bot
|
|
if ( botsOnTeam.size > 0 )
|
|
{
|
|
if ( botsOnTeam.size == 1 )
|
|
{
|
|
level.fireteam_hunt_leader[whichTeam] = botsOnTeam[0];
|
|
}
|
|
else
|
|
{
|
|
level.fireteam_hunt_leader[whichTeam] = botsOnTeam[RandomInt(botsOnTeam.size)];
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fireteam_tdm_hunt_end( whichTeam )
|
|
{
|
|
level notify( "hunting_party_end_"+whichTeam );
|
|
level.fireteam_hunt_leader[whichTeam] = undefined;
|
|
level.fireteam_hunt_target_zone[whichTeam] = undefined;
|
|
level.bot_random_path_function[whichTeam] = ::bot_random_path_default;
|
|
}
|
|
|
|
fireteam_tdm_hunt_most_dangerous_zone( leaderZone, whichTeam )
|
|
{
|
|
bestZoneEnemyCount = 0;
|
|
bestZone = undefined;
|
|
bestZonePathSize = -1;
|
|
|
|
if ( level.zoneCount > 0 )
|
|
{//go through all zones, return the closest one with the highest # of predicted enemies
|
|
for( testZone = 0; testZone < level.zoneCount; testZone++ )
|
|
{
|
|
zoneEnemyCount = BotZoneGetCount( testZone, whichTeam, "enemy_predict" );
|
|
if ( zoneEnemyCount < bestZoneEnemyCount )
|
|
{
|
|
continue;
|
|
}
|
|
zonePath = undefined;
|
|
if ( zoneEnemyCount == bestZoneEnemyCount )
|
|
{//same number of enemies - use the closer zone
|
|
zonePath = GetZonePath( leaderZone, testZone );
|
|
if ( !IsDefined( zonePath ) )
|
|
{//no path?
|
|
continue;
|
|
}
|
|
if ( bestZonePathSize >= 0 && zonePath.size > bestZonePathSize )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
bestZoneEnemyCount = zoneEnemyCount;
|
|
bestZone = testZone;
|
|
if ( IsDefined( zonePath ) )
|
|
{
|
|
bestZonePathSize = zonePath.size;
|
|
}
|
|
else
|
|
{
|
|
bestZonePathSize = -1;
|
|
}
|
|
}
|
|
}
|
|
return bestZone;
|
|
}
|
|
|
|
fireteam_tdm_find_hunt_zone( whichTeam )
|
|
{
|
|
level endon( "hunting_party_end_"+whichTeam );
|
|
self endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
if ( level.zoneCount <= 0 )
|
|
return;
|
|
|
|
level.bot_random_path_function[whichTeam] = ::bot_fireteam_hunt_zone_find_node;
|
|
|
|
while(1)
|
|
{
|
|
wait_time = 3;
|
|
if ( !IsDefined( level.fireteam_hunt_leader[whichTeam] ) || IsBot( level.fireteam_hunt_leader[whichTeam] ) || IsDefined( level.fireteam_hunt_leader[whichTeam].commanding_bot ) )
|
|
{
|
|
fireteam_tdm_set_hunt_leader( whichTeam );
|
|
}
|
|
|
|
if ( IsDefined( level.fireteam_hunt_leader[whichTeam] ) )
|
|
{
|
|
leaderZone = GetZoneNearest( level.fireteam_hunt_leader[whichTeam].origin );
|
|
if ( !IsDefined(leaderZone) )
|
|
{
|
|
wait(wait_time);
|
|
continue;
|
|
}
|
|
|
|
if ( !IsBot( level.fireteam_hunt_leader[whichTeam] ) )
|
|
{//just follow the player around
|
|
if ( IsAlive( level.fireteam_hunt_leader[whichTeam] ) && level.fireteam_hunt_leader[whichTeam].sessionstate == "playing" && (!IsDefined(level.fireteam_hunt_leader[whichTeam].deathTime) || level.fireteam_hunt_leader[whichTeam].deathTime+5000 < GetTime()) )
|
|
{//only if the player is alive and didn't die recently
|
|
level.fireteam_hunt_target_zone[whichTeam] = leaderZone;
|
|
level.fireteam_hunt_next_zone_search_time[whichTeam] = GetTime() + 1000;
|
|
wait_time = 0.5;
|
|
}
|
|
else
|
|
{//just hold this position for a while
|
|
wait_time = 1;
|
|
}
|
|
}
|
|
else
|
|
{//try to find the zone with the most enemies
|
|
first_search = false;
|
|
changeZones = false;
|
|
curZone = undefined;
|
|
if ( IsDefined( level.fireteam_hunt_target_zone[whichTeam] ) )
|
|
curZone = level.fireteam_hunt_target_zone[whichTeam];
|
|
else
|
|
{
|
|
first_search = true;
|
|
changeZones = true;
|
|
curZone = leaderZone;
|
|
}
|
|
newZone = undefined;
|
|
|
|
if ( IsDefined( curZone ) )
|
|
{
|
|
// Get nearest zone with the most predicted enemies
|
|
newZone = fireteam_tdm_hunt_most_dangerous_zone( leaderZone, whichTeam );
|
|
|
|
if ( !first_search )
|
|
{//not the first search
|
|
if ( !IsDefined( newZone ) || newZone != curZone )
|
|
{//either no known enemies at all or no known enemies in our target zone, but we found another with enemies
|
|
if ( curZone == leaderZone )
|
|
{//leader has reached the original target zone
|
|
changeZones = true;
|
|
}
|
|
else if ( GetTime() > level.fireteam_hunt_next_zone_search_time[whichTeam] )
|
|
{//enough time has passed to change nodes
|
|
changeZones = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( changeZones )
|
|
{
|
|
if ( !IsDefined( newZone ) )
|
|
{// If we have no idea where enemies are then pick the zone furthest from us
|
|
furthestDist = 0;
|
|
furthestZone = -1;
|
|
for ( z = 0; z < level.zoneCount; z++ )
|
|
{
|
|
dist = Distance2D( GetZoneOrigin( z ), level.fireteam_hunt_leader[whichTeam].origin );
|
|
if ( dist > furthestDist )
|
|
{
|
|
furthestDist = dist;
|
|
furthestZone = z;
|
|
}
|
|
}
|
|
newZone = furthestZone;
|
|
}
|
|
|
|
if ( IsDefined( newZone ) )
|
|
{
|
|
if ( !IsDefined( level.fireteam_hunt_target_zone[whichTeam] ) || level.fireteam_hunt_target_zone[whichTeam] != newZone )
|
|
{//tell all the bots to get new goals
|
|
foreach( player in level.players )
|
|
{
|
|
if ( IsBot( player ) && player.team == whichTeam )
|
|
{
|
|
player BotClearScriptGoal();
|
|
player.fireteam_hunt_goalpos = undefined;
|
|
player thread bot_fireteam_hunt_zone_find_node();
|
|
}
|
|
}
|
|
}
|
|
level.fireteam_hunt_target_zone[whichTeam] = newZone;
|
|
level.fireteam_hunt_next_zone_search_time[whichTeam] = GetTime() + 12000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wait(wait_time);
|
|
}
|
|
}
|
|
|
|
bot_debug_script_goal()
|
|
{
|
|
self notify( "bot_debug_script_goal" );
|
|
|
|
level endon( "hunting_party_end_"+ self.team );
|
|
self endon( "bot_debug_script_goal" );
|
|
|
|
lineHeight = 48;
|
|
while(1)
|
|
{
|
|
if ( self BotHasScriptGoal() )
|
|
{
|
|
goalPos = self BotGetScriptGoal();
|
|
if ( !IsDefined( self.fireteam_hunt_goalpos ) )
|
|
{//we have a goal, but no hunt goal??
|
|
Line( self.origin + (0,0,lineHeight), goalPos + (0,0,lineHeight), (0,1,1), 1.0, false, 1 );
|
|
}
|
|
else if ( self.fireteam_hunt_goalpos != goalPos )
|
|
{//something changed our goal on us! Bastards!
|
|
Line( self.origin + (0,0,lineHeight), goalPos + (0,0,lineHeight), (1,1,1), 1.0, false, 1 );
|
|
Line( self.origin + (0,0,lineHeight), self.fireteam_hunt_goalpos + (0,0,lineHeight), (1,1,0), 1.0, false, 1 );
|
|
}
|
|
else
|
|
{//all is good
|
|
Line( self.origin + (0,0,lineHeight), self.fireteam_hunt_goalpos + (0,0,lineHeight), (0,1,0), 1.0, false, 1 );
|
|
}
|
|
}
|
|
else if ( IsDefined( self.fireteam_hunt_goalpos ) )
|
|
{//something removed our goal on us! Bastards!
|
|
Line( self.origin + (0,0,lineHeight), self.fireteam_hunt_goalpos + (0,0,lineHeight), (1,0,0), 1.0, false, 1 );
|
|
}
|
|
|
|
wait(0.05);
|
|
}
|
|
}
|
|
|
|
//=======================================================
|
|
// bot_fireteam_hunt_zone_find_node
|
|
//=======================================================
|
|
bot_fireteam_hunt_zone_find_node()
|
|
{
|
|
result = false;
|
|
node_to_guard = undefined;
|
|
|
|
if ( IsDefined( level.fireteam_hunt_target_zone[self.team] ) )
|
|
{
|
|
// get set of nodes in the region we want to camp
|
|
nodes_to_select_from = GetZoneNodes( level.fireteam_hunt_target_zone[self.team], 0 );
|
|
|
|
// Choose from only the BEST camp spots from within those nodes
|
|
if ( nodes_to_select_from.size <= 18 )
|
|
{//each zone should have at least 3 nodes per teammate - if not, expand to neighbor zones
|
|
nodes_to_select_from = GetZoneNodes( level.fireteam_hunt_target_zone[self.team], 1 );
|
|
if ( nodes_to_select_from.size <= 18 )
|
|
{//each zone should have at least 3 nodes per teammate - if not, expand to neighbor zones
|
|
nodes_to_select_from = GetZoneNodes( level.fireteam_hunt_target_zone[self.team], 2 );
|
|
if ( nodes_to_select_from.size <= 18 )
|
|
{//each zone should have at least 3 nodes per teammate - if not, expand to neighbor zones
|
|
nodes_to_select_from = GetZoneNodes( level.fireteam_hunt_target_zone[self.team], 3 );
|
|
}
|
|
}
|
|
}
|
|
if ( nodes_to_select_from.size <= 0 )
|
|
{
|
|
return bot_random_path_default();
|
|
}
|
|
|
|
node_to_guard = self BotNodePick( nodes_to_select_from, nodes_to_select_from.size, "node_hide" );
|
|
|
|
tries = 0;
|
|
while(!IsDefined( node_to_guard ) || !self BotNodeAvailable( node_to_guard ) )
|
|
{
|
|
tries++;
|
|
if ( tries >= 10 )
|
|
return bot_random_path_default();
|
|
|
|
node_to_guard = nodes_to_select_from[RandomInt(nodes_to_select_from.size)];
|
|
}
|
|
|
|
goalPos = node_to_guard.origin;
|
|
if ( IsDefined( goalPos ) )
|
|
{
|
|
node_type = "guard";
|
|
|
|
myZone = GetZoneNearest( self.origin );
|
|
if ( IsDefined(myZone) && myZone == level.fireteam_hunt_target_zone[self.team] )
|
|
{//in the zone, free to move around a bit more
|
|
//node_type = "hunt";
|
|
self BotSetFlag( "force_sprint", false );
|
|
}
|
|
else
|
|
{
|
|
self BotSetFlag( "force_sprint", true );
|
|
}
|
|
|
|
result = self BotSetScriptGoal( goalPos, 128, node_type );
|
|
self.fireteam_hunt_goalpos = goalPos;
|
|
//self thread bot_debug_script_goal();
|
|
}
|
|
}
|
|
|
|
if ( !result )
|
|
return bot_random_path_default();
|
|
|
|
return result;
|
|
}
|
|
|
|
bot_fireteam_monitor_killstreak_earned()
|
|
{
|
|
level endon( "game_ended" );
|
|
self endon( "disconnect" );
|
|
|
|
self notify( "bot_fireteam_monitor_killstreak_earned" );
|
|
self endon( "bot_fireteam_monitor_killstreak_earned" );
|
|
|
|
while(1)
|
|
{
|
|
self waittill( "bot_killstreak_earned", splashString, streakVal );
|
|
//In Fireteam mode, notify my commander if I got a killstreak
|
|
if ( bot_is_fireteam_mode() )
|
|
{
|
|
if ( IsDefined( self ) && IsBot( self ) )
|
|
{
|
|
if ( IsDefined( self.fireteam_commander ) )
|
|
{
|
|
commandersBot = undefined;
|
|
if ( IsDefined( self.fireteam_commander.commanding_bot ) )
|
|
{
|
|
commandersBot = self.fireteam_commander.commanding_bot;
|
|
}
|
|
else
|
|
{
|
|
commandersBot = self.fireteam_commander GetSpectatingPlayer();
|
|
}
|
|
|
|
if ( !IsDefined( commandersBot ) || commandersBot != self )
|
|
{
|
|
self.fireteam_commander thread maps\mp\gametypes\_hud_message::playerCardSplashNotify( splashString, self, streakVal );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|