Botpack
Class Assault

source: e:\games\UnrealTournament\Botpack\Classes\Assault.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.GameInfo
            |
            +--Botpack.TournamentGameInfo
               |
               +--Botpack.DeathMatchPlus
                  |
                  +--Botpack.TeamGamePlus
                     |
                     +--Botpack.Assault
Direct Known Subclasses:TrainingAS

class Assault
extends Botpack.TeamGamePlus

//============================================================================= // Assault. //=============================================================================
Variables
 Defender, Attacker
 Fort[16], BestFort
 int CurrentDefender
 string DefenderSuccess
 int Defenses
 int Destroyer
 SpectatorCam EndCam
 string GameCode
 float LastIncoming
 Pawn Leader[4]
           current leader of each team (used by bots)
 int NumDefenses
 WinMessage, ObjectivesMessage
 int Part
 float SavedTime
 bool bAssaultWon
 bool bDefenseSet
 bool bFortDown
 bool bTiePartOne
 int numForts


Function Summary
 void AddDefaultInventory(Pawn PlayerPawn)
 byte AssessBotAttitude(Bot aBot, Pawn Other)
 FortStandard AttackFort(Bot aBot, out byte)
 bool AttackOnlyLocalFort(Bot aBot)
 bool BestFortFor(Bot aBot, FortStandard oldFort, FortStandard currentFort)
 void CalcEndStats()
 bool ChangeTeam(Pawn Other, int NewTeam)
 void ElectNewLeaderFor(Bot OldLeader)
 void FallBackTo(name F, int Priority)
 bool FindPathToFortFor(Bot aBot, Actor Dest)
 NavigationPoint FindPlayerStart(Pawn Player, optional byte, optional string)
     
// Defenders always use team 0 labelled starts, attackers use team 1 labelled starts	
 bool FindSpecialAttractionFor(Bot aBot)
 float GameThreatAdd(Bot aBot, Pawn Other)
 bool HandleTieUp(Bot Bumper, Bot Bumpee)
 void InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
 bool IsOnTeam(Pawn Other, int TeamNum)
 void Killed(Pawn killer, Pawn Other, name damageType)
 bool NeverStakeOut(Bot Other)
 void PickAmbushSpotFor(Bot aBot)
 void PlayStartUpMessage(PlayerPawn NewPlayer)
 void PostBeginPlay()
 void RemoveFort(FortStandard F, Pawn instigator)
 void ResetGame()
 void RestartGame()
 bool RestartPlayer(Pawn aPlayer)
 bool SendBotToGoal(Bot aBot)
 void SendStartMessage(PlayerPawn P)
 void SetBotOrders(Bot NewBot)
 Actor SetDefenseFor(Bot aBot)
 bool SetEndCams(string Reason)
 bool SuccessfulGame()
 bool WaitForPoint(Bot aBot)
     
// return true when leader has died/respawned, and bots should wait for him to show back up
// before advancing - and not fallback to the start



Source Code


00001	//=============================================================================
00002	// Assault.
00003	//=============================================================================
00004	class Assault extends TeamGamePlus
00005		config;
00006	
00007	var TeamInfo Defender, Attacker;
00008	var() config int Defenses;
00009	var FortStandard Fort[16], BestFort;
00010	var localized string AttackMessage, DefendMessage, TieMessage, WinMessage, ObjectivesMessage;
00011	var int Destroyer;
00012	var int numForts;
00013	var float LastIncoming;
00014	var SpectatorCam EndCam;
00015	
00016	var config float SavedTime;
00017	var config int NumDefenses;
00018	var config int CurrentDefender;
00019	var config bool bDefenseSet;
00020	var config bool bTiePartOne;
00021	var config string GameCode;
00022	var config int Part;
00023	var bool	bAssaultWon;
00024	var bool	bFortDown;
00025	
00026	var localized string DefenderSuccess;
00027	var Pawn Leader[4];		// current leader of each team (used by bots)
00028		
00029	function PostBeginPlay()
00030	{
00031		local int i, Num;
00032		local FortStandard F;
00033	
00034		Super.PostBeginPlay();
00035	
00036		numForts = 0;
00037		ForEach AllActors(class'FortStandard', F)
00038		{
00039			Fort[numForts] = F;
00040			numForts++;
00041		}
00042	
00043		//randomize fort order (so AI doesn't always attack/defend in same order)
00044		for ( i=0; i<numForts; i++ )
00045			if ( FRand() < 0.5 )
00046			{
00047				F = Fort[numForts-i-1];
00048				Fort[numForts-i-1]= Fort[i];
00049				Fort[i] = F;
00050			}			
00051	
00052		if (GameCode == "")
00053		{
00054			while (i<8) 
00055			{
00056				Num = Rand(123);
00057				if ( ((Num >= 48) && (Num <= 57)) || 
00058					 ((Num >= 65) && (Num <= 91)) ||
00059					((Num >= 97) && (Num <= 123)) ) 
00060				{
00061					GameCode = GameCode$Chr(Num);
00062					i++;
00063				}
00064			}
00065		}
00066		if (WorldLog != None)
00067		{
00068			WorldLog.LogSpecialEvent("assault_timelimit", TimeLimit);
00069			WorldLog.LogSpecialEvent("assault_gamecode", GameCode, Part);
00070		}
00071		if (LocalLog != None)
00072		{
00073			LocalLog.LogSpecialEvent("assault_timelimit", TimeLimit);
00074			LocalLog.LogSpecialEvent("assault_gamecode", GameCode, Part);
00075		}
00076	}
00077	
00078	function AddDefaultInventory( pawn PlayerPawn )
00079	{
00080		bUseTranslocator = false; // never allow translocator in assault
00081		Super.AddDefaultInventory(PlayerPawn);
00082	}	
00083	
00084	function InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
00085	{
00086		Super.InitRatedGame(LadderObj, LadderPlayer);
00087		Defenses = 3;
00088		MaxTeams = 2;
00089		bJumpMatch = false;
00090	}
00091	
00092	static function ResetGame()
00093	{
00094		local int i;
00095	
00096		Default.bDefenseSet = False;
00097		Default.NumDefenses = 0;
00098		Default.CurrentDefender = 0;
00099		Default.SavedTime = 0;
00100		Default.GameCode = "";
00101		Default.Part = 1;
00102		Default.bTiePartOne = false;
00103		StaticSaveConfig();
00104	}
00105	
00106	event InitGame( string Options, out string Error )
00107	{
00108		local FortStandard F;
00109		local name EndCamTag;
00110		
00111		Super.InitGame(Options, Error);
00112	
00113		TimeLimit = 1;
00114		if ( SavedTime > 0 )
00115		{
00116			RemainingTime = SavedTime;
00117			ForEach AllActors(class'FortStandard', F)
00118				if ( F.EndCamTag != '' )
00119					EndCamTag = F.EndCamTag;
00120		}
00121		else
00122		{
00123			ForEach AllActors(class'FortStandard', F)
00124			{
00125				TimeLimit = Max(TimeLimit, F.DefenseTime);
00126				if ( F.EndCamTag != '' )
00127					EndCamTag = F.EndCamTag;
00128			}
00129			
00130			RemainingTime = TimeLimit * 60;
00131		}
00132		if ( EndCamTag != '' )
00133			ForEach AllActors(class'SpectatorCam', EndCam, EndCamTag)
00134				break;
00135		GoalTeamScore = 0;
00136		FragLimit = 0;
00137		bMegaSpeed = false;
00138		bUseTranslocator = false;
00139		bJumpMatch = false;
00140	}
00141	
00142	function FallBackTo(name F, int Priority)
00143	{
00144		local int i;
00145	
00146		for ( i=0; i<numForts; i++ )
00147			if ( Fort[i].tag == F )
00148			{
00149				Fort[i].DefensePriority = Priority;
00150				return;
00151			}
00152	}
00153	
00154	function bool SuccessfulGame()
00155	{
00156		local int i;
00157	
00158		if (RatedPlayer.PlayerReplicationInfo.Team == Attacker.TeamIndex)
00159		{
00160			// If the player is the attacker.
00161			return bAssaultWon;
00162		} else {
00163			// If the player is the defender.
00164			return !bAssaultWon;
00165		}
00166	}
00167	
00168	function bool RestartPlayer( pawn aPlayer )	
00169	{
00170		local Bot B;
00171	
00172		// boost attacker AI a little
00173		B = Bot(aPlayer);
00174		if ( (B != None) && (B.PlayerReplicationInfo.Team != Defender.TeamIndex)
00175			&& (Bot(Leader[B.PlayerReplicationInfo.Team]) != None) ) 
00176		{
00177			if ( bNoviceMode && (Level.Game.Difficulty == 3) )
00178			{
00179				B.bNovice = false;
00180				B.skill = 0;
00181			}
00182			else
00183				B.skill = FClamp(Level.Game.Difficulty + 1, B.skill, 3); 
00184		}
00185		return Super.RestartPlayer(aPlayer);
00186	}
00187	
00188	function RestartGame()
00189	{
00190		local Pawn P;
00191		local int i;
00192	
00193		if ( bDontRestart )
00194			return;
00195	
00196		if ( !bGameEnded || (EndTime > Level.TimeSeconds) ) // still showing end screen
00197			return;
00198	
00199		// If a team has defended and attacked, the game is over
00200		// Or in a rated game if the player failed on attack
00201		if ( bDefenseSet 
00202			|| (bRatedGame && (RatedPlayer.PlayerReplicationInfo.TeamID == Attacker.TeamIndex) && !bAssaultWon) ) 
00203		{
00204			ResetGame();
00205			Super.RestartGame();
00206			return;
00207		}
00208	
00209		bDontRestart = true; // don't restart more than once
00210		bDefenseSet = true;	
00211		if ( Defender.TeamIndex == 1 )
00212			CurrentDefender = 0;
00213		else
00214			CurrentDefender = 1;
00215		Part = 2;
00216		SavedTime  = TimeLimit * 60 - RemainingTime;
00217	
00218		SaveConfig();
00219		Level.ServerTravel( "?Restart", false );
00220	}
00221	
00222	function PlayStartUpMessage(PlayerPawn NewPlayer)
00223	{
00224		if ( NewPlayer.PlayerReplicationInfo.Team > 1 )
00225			return;
00226	
00227		if ( Defender == Teams[NewPlayer.PlayerReplicationInfo.Team] )
00228			StartupMessage = DefendMessage;
00229		else
00230			StartUpMessage = AttackMessage;
00231	
00232		Super.PlayStartupMessage(NewPlayer);
00233	}
00234	
00235	// Defenders always use team 0 labelled starts, attackers use team 1 labelled starts	
00236	function NavigationPoint FindPlayerStart(Pawn Player, optional byte InTeam, optional string incomingName)
00237	{
00238		local Pawn P;
00239		local int i,d;
00240		local byte Team;
00241	
00242		if ( (Player != None) && (Player.PlayerReplicationInfo != None) )
00243			Team = Player.PlayerReplicationInfo.Team;
00244		else
00245			Team = InTeam;
00246	
00247		if ( Team != 255 )
00248		{
00249			if ( Team > 1 )
00250				Team = 0;
00251			if ( Defender == None )
00252			{
00253				if ( bDefenseSet )
00254					d = CurrentDefender;
00255				else if ( Team == 0 )
00256					d = 1;
00257				else 
00258					d = 0;
00259	
00260				Defender = Teams[d];
00261				if ( d == 0 )
00262					Attacker = Teams[1];
00263				else
00264					Attacker = Teams[0];
00265	
00266				for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00267					if ( P.IsA('StationaryPawn') )
00268						StationaryPawn(P).SetTeam(Defender.TeamIndex);
00269	
00270				for (i=0; i<numForts; i++ )
00271				{
00272					if ( d == 0 )
00273						Fort[i].Skin = texture'JFlag11';
00274					else if ( d == 1 )
00275						Fort[i].Skin = texture'JFlag12'; 
00276				}
00277				if (WorldLog != None)
00278				{
00279					WorldLog.LogSpecialEvent("assault_defender", Defender.TeamIndex);
00280					WorldLog.LogSpecialEvent("assault_attacker", Attacker.TeamIndex);
00281				}
00282				if (LocalLog != None)
00283				{
00284					LocalLog.LogSpecialEvent("assault_defender", Defender.TeamIndex);
00285					LocalLog.LogSpecialEvent("assault_attacker", Attacker.TeamIndex);
00286				}
00287			}
00288			if ( Teams[Team] == Defender )
00289				Team = 0;
00290			else
00291				Team = 1;
00292		}
00293	
00294		return Super.FindPlayerStart(None, Team, incomingName);
00295	}
00296	
00297	function SendStartMessage(PlayerPawn P)
00298	{
00299		P.ClearProgressMessages();
00300		P.SetProgressTime(8);
00301		if ( P.PlayerReplicationInfo.Team == Defender.TeamIndex )
00302		{
00303			P.SetProgressMessage(StartMessage, 0);
00304			P.SetProgressMessage(DefendMessage, 1);
00305		} else {
00306			P.SetProgressMessage(StartMessage, 0);
00307			P.SetProgressMessage(AttackMessage, 1);
00308		}
00309		if (RatedPlayer == None)
00310			P.SetProgressMessage(ObjectivesMessage, 2);
00311	}
00312	
00313	function RemoveFort(FortStandard F, Pawn instigator)
00314	{
00315		local int i;
00316		local Pawn P;
00317		local bool bFound;
00318		local NavigationPoint N;
00319		local Bot B;
00320	
00321		bFortDown = true;
00322		if ( instigator.bIsPlayer )
00323			instigator.PlayerReplicationInfo.Score += 10;
00324		if ( F.DestroyedMessage != "" )
00325			BroadcastMessage(F.FortName@F.DestroyedMessage, true, 'CriticalEvent');
00326	
00327		if ( F.bSayDestroyed 
00328			&& (instigator.IsA('Bot') || ((TournamentPlayer(instigator) != None) && TournamentPlayer(instigator).bAutoTaunt)) )
00329			instigator.SendTeamMessage(None, 'OTHER', 16, 15);
00330		else
00331			bFulfilledSpecial = true;
00332					
00333		if ( F.Tag != '' )
00334			for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
00335				if ( N.IsA('Defensepoint') && (DefensePoint(N).FortTag == F.Tag) )
00336				{
00337					if ( N.taken )
00338						for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00339							if ( P.IsA('Bot') && Bot(P).AmbushSpot == N )
00340								Bot(P).AmbushSpot = None;
00341					N.taken = true;
00342				}
00343	
00344		if ( !F.bFinalFort )
00345		{
00346			for ( i=0; i<(numForts - 1); i++ )
00347			{
00348				if ( Fort[i] == F )
00349					bFound = true;
00350				if ( bFound )
00351					Fort[i] = Fort[i+1];
00352			}
00353			Fort[numForts] = None;
00354			numForts--;
00355		}
00356		if ( F.bFinalFort || (numForts == 0) )
00357		{
00358			if ( instigator.bIsPlayer )
00359				instigator.PlayerReplicationInfo.Score += 100;
00360			bAssaultWon = true;
00361			EndGame("Assault succeeded!");
00362		}
00363		else
00364		{
00365			for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00366			{
00367				B = Bot(P);
00368				if ( B != None )
00369				{
00370					if ( (BotReplicationInfo(B.PlayerReplicationInfo).RealOrders == 'Defend') && (B.OrderObject == F) )
00371					{
00372						B.SetOrders(BotReplicationInfo(B.PlayerReplicationInfo).RealOrders, None, true);
00373						B.OrderObject = SetDefenseFor(Bot(P));
00374						BotReplicationInfo(B.PlayerReplicationInfo).OrderObject = B.OrderObject;
00375					}
00376					else
00377						B.Killed(None, F, '');
00378				}
00379			}
00380		}
00381	}
00382	
00383	function Killed(pawn killer, pawn Other, name damageType)
00384	{
00385		Super.Killed(killer, Other, damageType);
00386		if ( (Other == Leader[Other.PlayerReplicationInfo.Team]) && Other.IsA('Bot') )
00387			ElectNewLeaderFor(Bot(Other));
00388	}
00389	
00390	function bool SetEndCams(string Reason)
00391	{
00392		local pawn P;
00393		local PlayerPawn Player;
00394		local int ConquerTime, Minutes, Seconds;
00395		local string TimeResult;
00396		local actor A;
00397		local bool bTieGame;
00398	
00399		GameReplicationInfo.bStopCountDown = true;
00400		EndTime = Level.TimeSeconds + EndCam.FadeOutTime;
00401		if ( bAssaultWon )
00402		{
00403			if ( SavedTime > 0 )
00404	 			ConquerTime = SavedTime - RemainingTime;
00405			else
00406	 			ConquerTime = TimeLimit * 60 - RemainingTime;
00407			Minutes = ConquerTime/60;
00408			if ( Minutes > 0 )
00409				TimeResult = string(Minutes)$":";
00410			else
00411				TimeResult = ":";
00412			Seconds = ConquerTime % 60;
00413			if ( Seconds == 0 )
00414				TimeResult = TimeResult$"00";
00415			else if ( Seconds < 10 )
00416				TimeResult = TimeResult$"0"$Seconds;
00417			else
00418				TimeResult = TimeResult$Seconds;
00419			GameReplicationInfo.GameEndedComments = TeamPrefix@Attacker.TeamName@GameEndedMessage@TimeResult;
00420			if ( bDefenseSet )
00421				GameReplicationInfo.GameEndedComments = GameReplicationInfo.GameEndedComments@WinMessage;
00422			Attacker.Score += 1;
00423			if ( (EndCam != None) && (EndCam.Event != '') )
00424				ForEach AllActors(class'Actor', A, EndCam.Event)
00425					A.Trigger(None, None);
00426		}
00427		else
00428		{
00429			GameReplicationInfo.GameEndedComments = TeamPrefix@Defender.TeamName@DefenderSuccess;
00430			if ( bDefenseSet )
00431			{
00432				bTieGame = bTiePartOne;
00433				if ( bTiePartOne )
00434					GameReplicationInfo.GameEndedComments = GameReplicationInfo.GameEndedComments@TieMessage;
00435				else
00436					GameReplicationInfo.GameEndedComments = GameReplicationInfo.GameEndedComments@WinMessage;
00437			}
00438			else
00439			{
00440				bTiePartOne = true;
00441				GameReplicationInfo.GameEndedComments = GameReplicationInfo.GameEndedComments$"!";
00442			}
00443			Defender.Score += 1;
00444		}
00445	
00446		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00447		{
00448			Player = Playerpawn(P);
00449			if ( Player != None )
00450			{
00451				if ( bAssaultWon )
00452				{
00453					Player.ViewTarget = EndCam;
00454					Player.bBehindView = false;
00455					Player.bFixedCamera = true;
00456					if ( !bTutorialGame && !bTieGame && bDefenseSet )
00457						PlayWinMessage(Player, (Player.PlayerReplicationInfo.Team == Attacker.TeamIndex));
00458				}
00459				else
00460				{
00461					if ( !bTutorialGame && !bTieGame && bDefenseSet)
00462						PlayWinMessage(Player, (Player.PlayerReplicationInfo.Team == Defender.TeamIndex));
00463					Player.bBehindView = true;
00464				}
00465				Player.ClientGameEnded();
00466			}
00467			P.GotoState('GameEnded');
00468		}
00469		CalcEndStats();
00470		return true;
00471	}
00472	
00473	function CalcEndStats()
00474	{
00475		EndStatsClass.Default.TotalGames++;
00476		EndStatsClass.Static.StaticSaveConfig();
00477	}
00478	
00479	function bool BestFortFor(Bot aBot, FortStandard oldFort, FortStandard currentFort)
00480	{
00481		if ( (currentFort.DefensePriority > oldFort.DefensePriority)
00482			|| ((currentFort.DefensePriority == oldFort.DefensePriority)
00483			   && ((currentFort.Defender == None) || (currentFort.Defender == aBot)
00484					|| ((oldFort.Defender != None) && (oldFort.Defender != aBot) && (FRand() < 0.5)))) )
00485		{
00486			if ( oldFort.Defender == aBot )
00487				oldFort.Defender = None;
00488			return true;
00489		}
00490		
00491		return false;
00492	}
00493	
00494	function FortStandard AttackFort(Bot aBot, out byte bMultiSame)
00495	{
00496		local int i;
00497		
00498		BestFort = Fort[0];
00499		bMultiSame = 0;
00500		for ( i=1; i<numForts; i++ )
00501		{
00502			if ( BestFort.DefensePriority < Fort[i].DefensePriority )
00503				BestFort = Fort[i];
00504			else if ( BestFort.DefensePriority == Fort[i].DefensePriority )
00505			{
00506				if ( aBot.LineOfSightTo(Fort[i]) )
00507					BestFort = Fort[i];
00508				bMultiSame = 1;
00509			}
00510		}
00511	
00512		return BestFort;
00513	}
00514	
00515	function Actor SetDefenseFor(Bot aBot)
00516	{
00517		local int i, best;
00518		local FortStandard F;
00519	
00520		if ( aBot.PlayerReplicationInfo.Team != Defender.TeamIndex )
00521		{
00522			aBot.SetOrders('Attack', None);	
00523			return None;
00524		}
00525	
00526		for ( i=0; i<numForts; i++ )
00527			if ( (F == None) || BestFortFor(aBot, F, Fort[i])  )
00528				F = Fort[i];
00529		
00530		if ( F != None )
00531			F.Defender = aBot;
00532		else
00533			aBot.SetOrders('FreeLance', None, true);				
00534		return F;
00535	}
00536	
00537	function bool FindPathToFortFor(Bot aBot, Actor Dest)
00538	{
00539		local FortStandard F;
00540	
00541		if ( Dest == None )
00542		{
00543			aBot.SetOrders('Freelance', None, true);
00544			return false;
00545		}
00546	
00547		F = FortStandard(Dest);
00548		if ( (F != None) && (F.NearestPath != None) )
00549			aBot.MoveTarget = aBot.FindPathToward(F.NearestPath);
00550		else
00551			aBot.MoveTarget = aBot.FindPathToward(Dest);
00552	
00553		if ( aBot.MoveTarget == None )
00554		{
00555			aBot.bStayFreelance = true;
00556			aBot.Orders = 'FreeLance';
00557			if ( aBot.bVerbose )
00558				log(aBot.PlayerReplicationInfo.PlayerName$" freelance because no path to fort "$F$" from "$aBot.Location);
00559			return false;
00560		}
00561		else
00562		{
00563			SetAttractionStateFor(aBot);
00564			return true;
00565		}
00566	}
00567	
00568	function bool SendBotToGoal(Bot aBot)
00569	{
00570		local byte bMultiSame;
00571	
00572		return FindPathToFortFor(aBot, AttackFort(aBot,bMultiSame));
00573	}
00574	
00575	function bool AttackOnlyLocalFort(Bot aBot)
00576	{
00577		local FortStandard F;
00578		local bool bVisible, bPressOn;
00579		local byte bMultiSame;
00580		local float dist;
00581	
00582		F = AttackFort(aBot,bMultiSame);
00583		if ( F != None )
00584		{
00585			bPressOn = ( !Leader[aBot.PlayerReplicationInfo.Team].IsA('PlayerPawn')
00586						|| aBot.Region.Zone.bWaterZone
00587						|| (Leader[aBot.PlayerReplicationInfo.Team].Health <= 0)
00588						|| ((VSize(Leader[aBot.PlayerReplicationInfo.Team].Location - F.Location) < 1500)
00589							&& Leader[aBot.PlayerReplicationInfo.Team].LineOfSightTo(F))
00590						|| ((aBot.Enemy != None) && (Level.TimeSeconds - aBot.LastSeenTime < 1.5)) );
00591	
00592			dist = VSize(aBot.Location - F.Location);
00593			if ( F.bTriggerOnly )
00594			{
00595				if ( (bMultiSame == 1) || ((dist < F.ChargeDist)
00596					&& (aBot.Region.Zone == F.Region.Zone) && (F.bForceRadius || aBot.LineOfSightTo(F))) )
00597				{
00598					if ( aBot.ActorReachable(F) )
00599					{
00600						SetAttractionStateFor(aBot);
00601						aBot.MoveTarget = F;
00602						return true;
00603					}
00604					else if ( !F.bForceRadius && !bPressOn )
00605						return false;
00606					else
00607						return FindPathToFortFor(aBot, F);
00608					}
00609			}
00610			else if ( dist < 2 * F.ChargeDist ) 
00611			{
00612				bVisible = aBot.LineOfSightTo(F);
00613				if ( F.bForceRadius || bVisible || (bPressOn  && ((bMultiSame == 1) || (aBot.Region.Zone == F.Region.Zone))) )
00614				{
00615					aBot.SetEnemy(F);
00616					if ( aBot.Enemy == F )
00617					{
00618						if ( bVisible && (dist < 1200) )
00619						{
00620							aBot.GotoState('RangedAttack');
00621							return true;
00622						}
00623						else
00624							return FindPathToFortFor(aBot, F);
00625					}
00626				}
00627			}
00628		}
00629		if ( FortStandard(aBot.Enemy) != None )
00630		{
00631			aBot.Enemy = aBot.OldEnemy;
00632			aBot.OldEnemy = None;
00633			if ( FortStandard(aBot.Enemy) != None )
00634				aBot.Enemy = None;
00635		}
00636		return false;
00637	}
00638	
00639	function bool FindSpecialAttractionFor(Bot aBot)
00640	{
00641		local Pawn P;
00642		local int num, needed;
00643		local Bot B;
00644		local float dist;
00645	
00646		if ( aBot.LastAttractCheck == Level.TimeSeconds )
00647			return false;
00648		aBot.LastAttractCheck = Level.TimeSeconds;
00649	
00650		if ( aBot.PlayerReplicationInfo.Team != Defender.TeamIndex )
00651		{
00652			if ( !aBot.Weapon.bMeleeWeapon
00653				&& (FortStandard(aBot.Enemy) != None) && (aBot.OldEnemy == None)
00654				&& aBot.LineOfSightTo(aBot.Enemy) )
00655			{
00656				if ( FortStandard(aBot.Enemy).bTriggerOnly )
00657				{
00658					if ( aBot.ActorReachable(aBot.Enemy) )
00659					{
00660						SetAttractionStateFor(aBot);
00661						aBot.MoveTarget = aBot.Enemy;
00662						return true;
00663					}
00664				}
00665				else
00666				{
00667					aBot.GotoState('RangedAttack');
00668					return true;
00669				}
00670			}
00671			else if ( aBot.Orders == 'Hold' ) 
00672				return AttackOnlyLocalFort(aBot);
00673			else if ( (aBot.Orders == 'Follow')	&& ((TimeLimit == 0) || (RemainingTime > 100)) 
00674					&& (!aBot.Region.Zone.IsA('KillingField') || aBot.OrderObject.IsA('PlayerPawn') || (Pawn(aBot.OrderObject).Health <= 0)) )
00675			{
00676				if ( !aBot.CloseToPointMan(Pawn(aBot.OrderObject)) )
00677				{
00678					if ( aBot.OrderObject.IsA('Bot') && ((aBot.Weapon == None) || (aBot.Weapon.AIRating < 0.5)) )
00679						return false;
00680					if ( aBot.ActorReachable(aBot.OrderObject) )
00681						aBot.MoveTarget = aBot.OrderObject;
00682					else
00683						aBot.MoveTarget = aBot.FindPathToward(aBot.OrderObject);
00684					if ( (aBot.MoveTarget != None) && (VSize(aBot.Location - aBot.MoveTarget.Location) > 2 * aBot.CollisionRadius) )
00685					{
00686						SetAttractionStateFor(aBot);
00687						return true;
00688					}
00689				}
00690				return AttackOnlyLocalFort(aBot);
00691			}
00692			else if ( aBot == Leader[aBot.PlayerReplicationInfo.Team] ) // if leader, make sure followers are close
00693			{
00694				if ( aBot.Orders != 'Attack' )
00695					aBot.SetOrders('Attack', None);
00696				if ( (aBot.Weapon == None) || (aBot.Weapon.AIRating < 0.5) )
00697					return false;
00698	
00699				if ( aBot.Region.Zone.bWaterZone || aBot.Region.Zone.IsA('KillingField') || ((TimeLimit > 0) && (RemainingTime < 100)) )
00700					needed = 0;
00701				else
00702				{
00703					needed = Min(2, Teams[aBot.PlayerReplicationInfo.Team].Size - 2 );
00704					for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00705					{
00706						if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == aBot.PlayerReplicationInfo.Team)
00707							&& (P != aBot) )
00708						{
00709							B = Bot(P);
00710							if ( B != None )
00711							{
00712								Dist = VSize(B.Location - aBot.Location);
00713								if ( (Dist < 600) || ((Dist < 1600) && (B.LineOfSightTo(aBot))) )
00714								{
00715									num++;
00716									if ( num == needed )
00717										break;
00718								}
00719							}
00720						}
00721					}
00722				}
00723				aBot.GoalString="Leader has"@num@"vs"@needed;
00724				if ( num < needed )
00725				{
00726					if ( AttackOnlyLocalFort(aBot) )
00727						return true;
00728					if ( aBot.Enemy == None )
00729					{
00730						aBot.CampTime = 1.0;
00731						aBot.bCampOnlyOnce = true;
00732						aBot.GotoState('Roaming', 'Camp');
00733						return true;
00734					}
00735					else if ( !aBot.LineOfSightTo(aBot.Enemy) )
00736					{
00737						aBot.GotoState('StakeOut');
00738						return true;
00739					}
00740					else
00741						return FindPathToFortFor(aBot, BestFort);
00742				}
00743			}
00744		}
00745	
00746		if ( (aBot.Weapon == None) || (aBot.Weapon.AIRating < 0.5) )
00747			return false;
00748	
00749		if ( aBot.PlayerReplicationInfo.Team == Defender.TeamIndex )
00750		{
00751			aBot.GoalString = "Defender of"@aBot.OrderObject;
00752			if ( (aBot.Enemy != None) && (Level.TimeSeconds - LastIncoming > 12) )
00753			{
00754				LastIncoming = Level.TimeSeconds;
00755				aBot.SendTeamMessage(None, 'OTHER', 14, 15); //"Incoming!"
00756			}			
00757			if ( !aBot.bKamikaze && (aBot.Health < 40) )
00758			{
00759				aBot.bKamikaze = ( FRand() < 0.1 );
00760				return false;
00761			}
00762	
00763			if ( (aBot.Enemy != None) && (FRand() < 0.2) )
00764			{
00765				aBot.Orders = 'FreeLance';
00766				aBot.GoalString = "FreeLancer";
00767			}
00768			else if ( (aBot.Enemy == None) && (BotReplicationInfo(aBot.PlayerReplicationInfo).RealOrders == 'Defend') )
00769			{
00770				aBot.Orders = 'Defend';
00771				aBot.GoalString = "Defending";
00772			}
00773			if ( aBot.Orders != 'Defend' )
00774				return false;
00775			else
00776			{
00777				if ( (aBot.Enemy == None) && aBot.FindAmbushSpot() )
00778					return true;
00779	
00780				if ( aBot.AmbushSpot != None )
00781				{
00782					if ( aBot.LineOfSightTo(aBot.AmbushSpot) )
00783						return false;
00784					else if ( aBot.Enemy == None )
00785					{ 
00786						aBot.MoveTarget = aBot.FindPathToward(aBot.Ambushspot);
00787						if ( aBot.MoveTarget != None )
00788						{
00789							SetAttractionStateFor(aBot);
00790							return true;
00791						}
00792					}
00793				}
00794				else if ( aBot.LineOfSightTo(aBot.OrderObject) )
00795					return false;
00796				return FindPathToFortFor(aBot, aBot.OrderObject);
00797			}
00798		}		
00799		else
00800		{
00801			if ( AttackOnlyLocalFort(aBot) )
00802				return true;		
00803	
00804			if ( aBot.Orders == 'Freelance' )
00805			{
00806				if ( BotReplicationInfo(aBot.PlayerReplicationInfo).RealOrders == 'Freelance' )
00807					return false;
00808				if ( (FRand() < 0.1) || ((TimeLimit > 0) && (RemainingTime < 120)) )
00809					aBot.SetOrders(BotReplicationInfo(aBot.PlayerReplicationInfo).RealOrders, BotReplicationInfo(aBot.PlayerReplicationInfo).RealOrderGiver, true);
00810				else
00811					return false;
00812			}
00813	
00814			return FindPathToFortFor(aBot, BestFort);
00815		}
00816	
00817		return false;
00818	}
00819		
00820	function byte AssessBotAttitude(Bot aBot, Pawn Other)
00821	{
00822		local Pawn P;
00823		local int num, needed;
00824		local Bot B;
00825		local float Dist;
00826	
00827		if ( Other.IsA('FortStandard') )
00828		{
00829			if ( aBot.PlayerReplicationInfo.Team == Defender.TeamIndex )
00830				return 3;
00831			else
00832				return 1;
00833		}
00834		else if ( BotReplicationInfo(aBot.PlayerReplicationInfo).RealOrders == 'Attack' ) 
00835		{
00836			if ( (aBot == Leader[aBot.PlayerReplicationInfo.Team])
00837				&& ((Other.Location.Z > aBot.Location.Z + 512) || Other.IsA('TeamCannon')) )
00838			{
00839				// ignore if enough followers to press on
00840				needed = Min(2, Teams[aBot.PlayerReplicationInfo.Team].Size - 2 );
00841				for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00842				{
00843					if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == aBot.PlayerReplicationInfo.Team)
00844						&& (P != aBot) )
00845					{
00846						B = Bot(P);
00847						if ( (B != None)
00848							&& (B.Orders == 'Follow') && (B.OrderObject == aBot) )
00849						{
00850							Dist = VSize(B.Location - aBot.Location);
00851							if ( (Dist < 600) || ((Dist < 1600) && (B.LineOfSightTo(aBot))) )
00852							{
00853								num++;
00854								if ( num == needed )
00855									break;
00856							}
00857						}
00858					}
00859				}
00860				if ( num < needed )
00861					return 1;
00862				else
00863					return 2; //ignore
00864			}
00865			else if ( Other.bIsPlayer && (aBot.PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team) )
00866				return 3;
00867			else 
00868				return 1;
00869		}
00870		else 
00871			return Super.AssessBotAttitude(aBot, Other);
00872	}
00873	 
00874	function float GameThreatAdd(Bot aBot, Pawn Other)
00875	{
00876		if ( Other.IsA('FortStandard') && (aBot.PlayerReplicationInfo.Team != Defender.TeamIndex) )
00877			return 5;
00878		if ( Other.IsA('TeamCannon') || (Other.Location.Z - aBot.Location.Z > 500) )
00879			return -5;
00880	}
00881	
00882	function SetBotOrders(Bot NewBot)
00883	{
00884		local Pawn P, L;
00885		local int num;
00886	
00887		NewBot.BaseAggressiveness += 0.3;
00888		if ( IsOnTeam(NewBot,0) )
00889		{
00890			NewBot.SetOrders('Defend', None, true);
00891			return;
00892		}
00893	
00894		NewBot.SetOrders('Attack', None, true);
00895	
00896		// only follow players, if there are any
00897		For ( P=Level.PawnList; P!=None; P= P.NextPawn )
00898			if ( P.IsA('PlayerPawn') && (P.PlayerReplicationInfo.Team == NewBot.PlayerReplicationInfo.Team)
00899				&& !P.IsA('Spectator') )
00900		{
00901			num++;
00902			if ( (L == None) || (FRand() < 1.0/float(num)) )
00903				L = P;
00904		}
00905		
00906		if ( L != None ) 
00907		{
00908			Leader[NewBot.PlayerReplicationInfo.Team] = L;
00909			NumSupportingPlayer++;
00910			NewBot.SetOrders('Follow',L, true);
00911			return;
00912		}
00913	
00914		if ( NewBot.Orders == 'Defend' )
00915			return;
00916	
00917		// if no player to support, support a bot
00918		if ( Leader[NewBot.PlayerReplicationInfo.Team] == None )
00919		{
00920			// pick NewBot as leader
00921			Leader[NewBot.PlayerReplicationInfo.Team] = NewBot;
00922			NewBot.bLeading = true;
00923			return;
00924		}
00925			
00926		NewBot.SetOrders('Follow',Leader[NewBot.PlayerReplicationInfo.Team],true);
00927	}	
00928	
00929	
00930	function bool IsOnTeam(Pawn Other, int TeamNum)
00931	{
00932		if ( (Other == None) || (Other.PlayerReplicationInfo == None) )
00933			return false;
00934		if ( Defender == Teams[Other.PlayerReplicationInfo.Team] )
00935			return (TeamNum == 0);
00936	
00937		return (TeamNum != 0);
00938	}	
00939	
00940	function PickAmbushSpotFor(Bot aBot)
00941	{
00942		local NavigationPoint N;
00943		local bool bFreeDefense, bFortDefense, bFoundDefense;
00944	
00945		for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
00946			if ( N.IsA('Defensepoint') && !N.taken && IsOnTeam(aBot,DefensePoint(N).team) )
00947			{
00948				if ( aBot.OrderObject != None )
00949				{
00950					bFreeDefense = (DefensePoint(N).FortTag == '');
00951					bFortDefense = !bFreeDefense && (DefensePoint(N).FortTag == aBot.OrderObject.Tag);
00952					if ( !bFoundDefense )
00953					{
00954						if ( bFortDefense )
00955						{
00956							bFoundDefense = true;
00957							aBot.AmbushSpot = AmbushPoint(N);
00958						}
00959						else if ( bFreeDefense && ((aBot.AmbushSpot == None) || (FRand() < 0.4)) )
00960							aBot.AmbushSpot = AmbushPoint(N);
00961					}
00962					else if ( bFortDefense )
00963					{
00964						if ( DefensePoint(N).priority > DefensePoint(aBot.Ambushspot).priority )
00965							aBot.Ambushspot = Ambushpoint(N);
00966						else if ( (DefensePoint(N).priority == DefensePoint(aBot.Ambushspot).priority)
00967							&& (FRand() < 0.4) ) 
00968							aBot.Ambushspot = Ambushpoint(N);
00969					}		
00970				}
00971				else if ( (aBot.AmbushSpot == None)
00972						|| (VSize(aBot.Location - aBot.Ambushspot.Location)
00973							> VSize(aBot.Location - N.Location)) )
00974					aBot.Ambushspot = Ambushpoint(N);
00975			}
00976	}
00977	
00978	// return true when leader has died/respawned, and bots should wait for him to show back up
00979	// before advancing - and not fallback to the start
00980	function bool WaitForPoint(bot aBot)
00981	{
00982		if ( !aBot.Region.Zone.bWaterZone && bFortDown && (Level.TimeSeconds - aBot.PointDied < 12) && aBot.OrderObject.IsA('PlayerPawn') )
00983		{
00984			if ( (Pawn(aBot.OrderObject).Health > 0) && (VSize(aBot.Location - aBot.OrderObject.Location) < 1200) && aBot.LineOfSightTo(aBot.OrderObject) )
00985				aBot.PointDied = -1000;
00986			return (Level.TimeSeconds - aBot.PointDied < 12);
00987		}
00988		return false;
00989	}
00990	
00991	function ElectNewLeaderFor(bot OldLeader)
00992	{
00993		local Pawn P;
00994		local Bot Best;
00995		local float BestDist, Dist;
00996		// leader died, find an appropriate new one
00997		// (closest to old leader)
00998	
00999		BestDist = 1000000;
01000		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
01001		{
01002			if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == OldLeader.PlayerReplicationInfo.Team)
01003				&& (P != OldLeader) && (P.Health > 0)
01004				&& P.IsA('Bot') )
01005			{
01006				Dist = VSize(P.Location - OldLeader.Location);
01007				if ( Dist < BestDist )
01008				{
01009					BestDist = Dist;
01010					Best = Bot(P);
01011				}		
01012			}
01013		}
01014		if ( Best == None ) // keep old leader
01015			return;
01016		OldLeader.SetOrders('Follow', Best);
01017		Best.SetOrders('Attack', None);
01018		Best.GotoState('Attacking');
01019		Leader[OldLeader.PlayerReplicationInfo.Team] = Best;
01020		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
01021			if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == OldLeader.PlayerReplicationInfo.Team)
01022				&& P.IsA('Bot')
01023				&& (BotReplicationInfo(P.PlayerReplicationInfo).RealOrders == 'Follow') )
01024				Bot(P).SetOrders('Follow',Best);
01025	}	 
01026	
01027	function bool HandleTieUp(Bot Bumper, Bot Bumpee)
01028	{
01029		local Pawn P;
01030	
01031		if ( (Bumper == Leader[Bumper.PlayerReplicationInfo.Team])
01032			&& (FRand() < 0.35) 
01033			&& (VSize(Bumpee.Velocity) < 100) )
01034		{
01035			Leader[Bumper.PlayerReplicationInfo.Team] = Bumpee;	
01036			Bumper.SetOrders('Follow', Bumpee);
01037			Bumpee.SetOrders('Attack', None);
01038			Bumpee.GotoState('Attacking');
01039			for ( P=Level.PawnList; P!=None; P=P.NextPawn )
01040				if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == Bumper.PlayerReplicationInfo.Team)
01041					&& P.IsA('Bot')
01042					&& (BotReplicationInfo(P.PlayerReplicationInfo).RealOrders == 'Follow') )
01043					Bot(P).SetOrders('Follow',Bumpee);
01044			return true;
01045		}
01046		return false;
01047	}
01048	
01049		
01050	function bool NeverStakeOut(bot Other)
01051	{
01052		if ( Other.Region.Zone.bWaterZone || Other.Region.Zone.IsA('KillingField') )
01053			return true;
01054		return false;
01055	}
01056	
01057	function bool ChangeTeam(Pawn Other, int NewTeam)
01058	{
01059		local bool bRealBalance, bResult;
01060	
01061		bRealBalance = bPlayersBalanceTeams;
01062		if ( bDefenseSet )
01063			bPlayersBalanceTeams = false;
01064		if ( NewTeam > 1 )
01065			NewTeam = 255;
01066		bResult = Super.ChangeTeam(Other, NewTeam);
01067		bPlayersBalanceTeams = bRealBalance;
01068		return bResult;
01069	}
01070				
01071	
01072	defaultproperties
01073	{
01074	     Defenses=3
01075	     AttackMessage="Take the enemy base!"
01076	     DefendMessage="Defend your base against the enemy!"
01077	     TieMessage="Tie!"
01078	     WinMessage="and wins!"
01079	     ObjectivesMessage="Press F3 for an objectives briefing."
01080	     GameCode="eW4"
01081	     Part=1
01082	     DefenderSuccess="defended the base"
01083	     bSpawnInTeamArea=True
01084	     bScoreTeamKills=False
01085	     MaxAllowedTeams=2
01086	     GoalTeamScore=0.000000
01087	     FragLimit=0
01088	     TimeLimit=10
01089	     StartUpMessage=""
01090	     GameEndedMessage="conquered the base in"
01091	     MaxCommanders=0
01092	     LadderTypeIndex=4
01093	     bCoopWeaponMode=True
01094	     ScoreBoardType=Class'Botpack.AssaultScoreboard'
01095	     RulesMenuType="UTMenu.UTAssaultRulesSC"
01096	     HUDType=Class'Botpack.AssaultHUD'
01097	     MapListType=Class'Botpack.ASMapList'
01098	     MapPrefix="AS"
01099	     BeaconName="ASLT"
01100	     GameName="Assault"
01101	}

End Source Code