Botpack
Class TeamGamePlus

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

class TeamGamePlus
extends Botpack.DeathMatchPlus

//============================================================================= // TeamGamePlus. //=============================================================================
Variables
 name CurrentOrders[4]
           like fraglimit
 float FriendlyFireScale
           scale friendly fire damage by this value
 float GoalTeamScore
           like fraglimit
 int MaxTeamSize
           like fraglimit
 int MaxTeams
           Maximum number of teams allowed in (up to MaxAllowedTeams)
 int PlayerTeamNum
           like fraglimit
 string StartupTeamTralier
           like fraglimit
 TEAM_Green, TEAM_Gold
           like fraglimit
 StartUpTeamMessage, TeamChangeMessage,TeamPrefix
           like fraglimit
 string TeamColor[4]
           like fraglimit
 bool bBalanceTeams
           bots balance teams
 bool bNoTeamChanges
 bool bPlayersBalanceTeams
           players balance teams
 bool bScoreTeamKills
 bool bSpawnInTeamArea


Function Summary
 bool AddBot()
 void AddToTeam(int num, Pawn Other)
 byte AssessBotAttitude(Bot aBot, Pawn Other)
 bool CanSpectate(Pawn Viewer, Actor ViewTarget)
 bool ChangeTeam(Pawn Other, int NewTeam)
 void CheckReady()
 void ClearOrders(Pawn Leaving)
 NavigationPoint FindPlayerStart(Pawn Player, optional byte, optional string)
 bool FindSpecialAttractionFor(Bot aBot)
 byte FindTeamByName(string TeamName)
     
// Find a team given its name
 string GetRules()
     
//------------------------------------------------------------------------------
// Game Querying.
 TeamInfo GetTeam(int TeamNum)
 bool HandleTieUp(Bot Bumper, Bot Bumpee)
 void InitGameReplicationInfo()
 void InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
     
// Set game settings based on ladder information.
// Called when RatedPlayer logs in.
 bool IsOnTeam(Pawn Other, int TeamNum)
 void LogGameParameters(StatLog StatLog)
 void Logout(Pawn Exiting)
 void PickAmbushSpotFor(Bot aBot)
 void PlayStartUpMessage(PlayerPawn NewPlayer)
     
//------------------------------------------------------------------------------
// Player start functions
 void PostBeginPlay()
 byte PriorityObjective(Bot aBot)
 void ReBalance()
     
// rebalance teams after player changes teams or leaves
// find biggest and smallest teams.  If 2 apart, move bot from biggest to smallest
 int ReduceDamage(int Damage, name DamageType, Pawn injured, Pawn instigatedBy)
     
//Use reduce damage for teamplay modifications, etc.
 void ScoreKill(Pawn Killer, Pawn Other)
 bool SendBotToGoal(Bot aBot)
 void SetAttractionStateFor(Bot aBot)
 void SetBotOrders(Bot NewBot)
 Actor SetDefenseFor(Bot aBot)
 bool SetEndCams(string Reason)
 bool SuccessfulGame()
 bool WaitForPoint(Bot aBot)



Source Code


00001	//=============================================================================
00002	// TeamGamePlus.
00003	//=============================================================================
00004	class TeamGamePlus extends DeathMatchPlus
00005		config;
00006	
00007	#exec MESH IMPORT MESH=Flag1M ANIVFILE=MODELS\flag_a.3D DATAFILE=MODELS\flag_d.3D X=0 Y=0 Z=0 ZeroTex=1
00008	#exec MESH ORIGIN MESH=Flag1M X=0 Y=100 Z=0 YAW=128 PITCH=0 ROLL=-64
00009	#exec MESH SEQUENCE MESH=flag1M SEQ=All    STARTFRAME=0  NUMFRAMES=14
00010	#exec MESH SEQUENCE MESH=flag1M SEQ=Wave  STARTFRAME=1  NUMFRAMES=13
00011	#exec TEXTURE IMPORT NAME=JFlag11 FILE=MODELS\flag_red.PCX GROUP=Skins
00012	#exec TEXTURE IMPORT NAME=JFlag12 FILE=MODELS\flag_blue.PCX GROUP=Skins
00013	#exec TEXTURE IMPORT NAME=JFlag13 FILE=MODELS\flag_green.PCX GROUP=Skins
00014	#exec TEXTURE IMPORT NAME=JFlag14 FILE=MODELS\flag_yellow.PCX GROUP=Skins
00015	#exec TEXTURE IMPORT NAME=JFlag15 FILE=MODELS\flag3.PCX GROUP=Skins
00016	#exec MESHMAP SCALE MESHMAP=flag1M X=0.1 Y=0.1 Z=0.2
00017	#exec MESHMAP SETTEXTURE MESHMAP=flag1M NUM=0 TEXTURE=Jflag11
00018		
00019	var()		 bool   bSpawnInTeamArea;
00020	var()		 bool	bScoreTeamKills;
00021	var() config bool	bNoTeamChanges;
00022	var			 int	NumSupportingPlayer; 
00023	var globalconfig	 bool	bBalanceTeams;	// bots balance teams
00024	var globalconfig	 bool	bPlayersBalanceTeams;	// players balance teams
00025	var			 bool	bBalancing;
00026	var() config float  FriendlyFireScale; //scale friendly fire damage by this value
00027	var() config int	MaxTeams; //Maximum number of teams allowed in (up to MaxAllowedTeams)
00028	var			 int	MaxAllowedTeams;
00029	var	TeamInfo Teams[4]; // Red, Blue, Green, Gold
00030	var() config float  GoalTeamScore; //like fraglimit
00031	var() config int	MaxTeamSize;
00032	var  localized string StartUpTeamMessage, TeamChangeMessage,TeamPrefix;
00033	var localized string TeamColor[4];
00034	
00035	var		int			NextBotTeam;
00036	var byte TEAM_Red, TEAM_Blue, TEAM_Green, TEAM_Gold;
00037	var name CurrentOrders[4];
00038	var int PlayerTeamNum;
00039	var localized string StartupTeamTralier;
00040	
00041	function PostBeginPlay()
00042	{
00043		local int i;
00044		for (i=0;i<4;i++)
00045		{
00046			Teams[i] = Spawn(class'TeamInfo');
00047			Teams[i].Size = 0;
00048			Teams[i].Score = 0;
00049			Teams[i].TeamName = TeamColor[i];
00050			Teams[i].TeamIndex = i;
00051			TournamentGameReplicationInfo(GameReplicationInfo).Teams[i] = Teams[i];
00052		}
00053		
00054		Super.PostBeginPlay();
00055	
00056		if ( bRatedGame )
00057		{
00058			FriendlyFireScale = 0;
00059			MaxTeams = 2;
00060		}
00061	}
00062	
00063	event InitGame( string Options, out string Error )
00064	{
00065		Super.InitGame(Options, Error);
00066		MaxTeams = Min(MaxTeams,MaxAllowedTeams);
00067	}
00068	
00069	function InitGameReplicationInfo()
00070	{
00071		Super.InitGameReplicationInfo();
00072	
00073		TournamentGameReplicationInfo(GameReplicationInfo).GoalTeamScore = GoalTeamScore;
00074	}
00075	
00076	// Set game settings based on ladder information.
00077	// Called when RatedPlayer logs in.
00078	function InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
00079	{
00080		local class<RatedMatchInfo> RMI;
00081		local Weapon W;
00082	
00083		GoalTeamScore = LadderObj.CurrentLadder.Default.GoalTeamScore[IDnum];
00084		Super.InitRatedGame(LadderObj, LadderPlayer);	
00085		bCoopWeaponMode = true;
00086		FriendlyFireScale = 0.0;
00087		MaxTeams = 2;
00088		ForEach AllActors(class'Weapon', W)
00089			W.SetWeaponStay();
00090	}
00091	
00092	function CheckReady()
00093	{
00094		if ( (TimeLimit == 0) && (GoalTeamScore == 0) )
00095		{
00096			TimeLimit = 20;
00097			RemainingTime = 60 * TimeLimit;
00098		}
00099	}
00100	
00101	event PostLogin( playerpawn NewPlayer )
00102	{
00103		Super.PostLogin(NewPlayer);
00104	
00105		if ( Level.NetMode != NM_Standalone )
00106			NewPlayer.ClientChangeTeam(NewPlayer.PlayerReplicationInfo.Team);
00107	}
00108	
00109	function LogGameParameters(StatLog StatLog)
00110	{
00111		if (StatLog == None)
00112			return;
00113		
00114		Super.LogGameParameters(StatLog);
00115	
00116		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GoalTeamScore"$Chr(9)$int(GoalTeamScore));
00117		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"FriendlyFireScale"$Chr(9)$FriendlyFireScale);
00118	}
00119	
00120	function bool SetEndCams(string Reason)
00121	{
00122		local TeamInfo BestTeam;
00123		local int i;
00124		local pawn P, Best;
00125		local PlayerPawn player;
00126	
00127		// find individual winner
00128		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00129			if ( P.bIsPlayer && ((Best == None) || (P.PlayerReplicationInfo.Score > Best.PlayerReplicationInfo.Score)) )
00130				Best = P;
00131	
00132		// find winner
00133		BestTeam = Teams[0];
00134		for ( i=1; i<MaxTeams; i++ )
00135			if ( Teams[i].Score > BestTeam.Score )
00136				BestTeam = Teams[i];
00137	
00138		for ( i=0; i<MaxTeams; i++ )
00139			if ( (BestTeam.TeamIndex != i) && (BestTeam.Score == Teams[i].Score) )
00140			{
00141				BroadcastLocalizedMessage( DMMessageClass, 0 );
00142				return false;
00143			}		
00144	
00145		GameReplicationInfo.GameEndedComments = TeamPrefix@BestTeam.TeamName@GameEndedMessage;
00146	
00147		EndTime = Level.TimeSeconds + 3.0;
00148		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00149		{
00150			player = PlayerPawn(P);
00151			if ( Player != None )
00152			{
00153				if (!bTutorialGame)
00154					PlayWinMessage(Player, (Player.PlayerReplicationInfo.Team == BestTeam.TeamIndex));
00155				player.bBehindView = true;
00156				if ( Player == Best )
00157					Player.ViewTarget = None;
00158				else
00159					Player.ViewTarget = Best;
00160				player.ClientGameEnded();
00161			}
00162			P.GotoState('GameEnded');
00163		}
00164		CalcEndStats();
00165		return true;
00166	}
00167	
00168	//------------------------------------------------------------------------------
00169	// Player start functions
00170	
00171	function PlayStartUpMessage(PlayerPawn NewPlayer)
00172	{
00173		local int i;
00174		local color WhiteColor;
00175	
00176		NewPlayer.ClearProgressMessages();
00177	
00178		// GameName
00179		NewPlayer.SetProgressMessage(GameName, i++);
00180		if ( bRequireReady && (Level.NetMode != NM_Standalone) )
00181			NewPlayer.SetProgressMessage(TourneyMessage, i++);
00182		else
00183			NewPlayer.SetProgressMessage(StartUpMessage, i++);
00184	
00185		if ( GoalTeamScore > 0 )
00186			NewPlayer.SetProgressMessage(int(GoalTeamScore)@GameGoal, i++);
00187	
00188		if ( NewPlayer.PlayerReplicationInfo.Team < 4 )
00189		{
00190			NewPlayer.SetProgressColor(class'ChallengeTeamHUD'.Default.TeamColor[NewPlayer.PlayerReplicationInfo.Team], i);
00191			NewPlayer.SetProgressMessage(StartupTeamMessage@Teams[NewPlayer.PlayerReplicationInfo.Team].TeamName$StartupTeamTralier, i++);
00192			WhiteColor.R = 255;
00193			WhiteColor.G = 255;
00194			WhiteColor.B = 255;
00195			NewPlayer.SetProgressColor(WhiteColor, i);
00196			if ( !bRatedGame )
00197				NewPlayer.SetProgressMessage(TeamChangeMessage, i++);
00198		}
00199	
00200		if ( Level.NetMode == NM_Standalone )
00201			NewPlayer.SetProgressMessage(SingleWaitingMessage, i++);
00202	}
00203	
00204	function playerpawn Login
00205	(
00206		string Portal,
00207		string Options,
00208		out string Error,
00209		class<playerpawn> SpawnClass
00210	)
00211	{
00212		local PlayerPawn newPlayer;
00213		local NavigationPoint StartSpot;
00214	
00215		newPlayer = Super.Login(Portal, Options, Error, SpawnClass);
00216		if ( newPlayer == None)
00217			return None;
00218	
00219		if ( bSpawnInTeamArea )
00220		{
00221			StartSpot = FindPlayerStart(NewPlayer,255, Portal);
00222			if ( StartSpot != None )
00223			{
00224				NewPlayer.SetLocation(StartSpot.Location);
00225				NewPlayer.SetRotation(StartSpot.Rotation);
00226				NewPlayer.ViewRotation = StartSpot.Rotation;
00227				NewPlayer.ClientSetRotation(NewPlayer.Rotation);
00228				StartSpot.PlayTeleportEffect( NewPlayer, true );
00229			}
00230		}
00231		PlayerTeamNum = NewPlayer.PlayerReplicationInfo.Team;
00232			
00233		return newPlayer;
00234	}
00235	
00236	function Logout(pawn Exiting)
00237	{
00238		Super.Logout(Exiting);
00239		if ( Exiting.IsA('Spectator') || Exiting.IsA('Commander') )
00240			return;
00241	    Teams[Exiting.PlayerReplicationInfo.Team].Size--;
00242		ClearOrders(Exiting);
00243		if ( !bGameEnded && bBalanceTeams && !bRatedGame )
00244			ReBalance();
00245	}
00246	
00247	// Find a team given its name
00248	function byte FindTeamByName( string TeamName )
00249	{
00250		local byte i;
00251	
00252		for ( i=0; i<MaxTeams; i++ )
00253			if ( Teams[i].TeamName == TeamName )
00254				return i;
00255	
00256		return 255; // No Team
00257	}
00258	
00259	// rebalance teams after player changes teams or leaves
00260	// find biggest and smallest teams.  If 2 apart, move bot from biggest to smallest
00261	
00262	function ReBalance()
00263	{
00264		local int big, small, i, bigsize, smallsize;
00265		local Pawn P, A;
00266		local Bot B;
00267	
00268		if ( bBalancing || (NumBots == 0) )
00269			return;
00270	
00271		big = 0;
00272		small = 0;
00273		bigsize = Teams[0].Size;
00274		smallsize = Teams[0].Size;
00275		for ( i=1; i<MaxTeams; i++ )
00276		{
00277			if ( Teams[i].Size > bigsize )
00278			{
00279				big = i;
00280				bigsize = Teams[i].Size;
00281			}
00282			else if ( Teams[i].Size < smallsize )
00283			{
00284				small = i;
00285				smallsize = Teams[i].Size;
00286			}
00287		}
00288		
00289		bBalancing = true;
00290		while ( bigsize - smallsize > 1 )
00291		{
00292			for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00293				if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == big)
00294					&& P.IsA('Bot') )
00295				{
00296					B = Bot(P);
00297					break;
00298				}
00299			if ( B != None )
00300			{
00301				B.Health = 0;
00302				B.Died( None, 'Suicided', B.Location );
00303				bigsize--;
00304				smallsize++;
00305				ChangeTeam(B, small);
00306			}
00307			else
00308				Break;
00309		}
00310		bBalancing = false;
00311	
00312		// re-assign orders to follower bots with no leaders
00313		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00314			if ( P.bIsPlayer && P.IsA('Bot') && (BotReplicationInfo(P.PlayerReplicationInfo).RealOrders == 'Follow') )
00315			{
00316				A = Pawn(Bot(P).OrderObject);
00317				if ( (A == None) || A.bDeleteMe || !A.bIsPlayer || (A.PlayerReplicationInfo.Team != P.PlayerReplicationInfo.Team) )
00318				{
00319					Bot(P).OrderObject = None;
00320					SetBotOrders(Bot(P));
00321				}
00322			}
00323	
00324	}
00325		
00326	function NavigationPoint FindPlayerStart( Pawn Player, optional byte InTeam, optional string incomingName )
00327	{
00328		local PlayerStart Dest, Candidate[16], Best;
00329		local float Score[16], BestScore, NextDist;
00330		local pawn OtherPlayer;
00331		local int i, num;
00332		local Teleporter Tel;
00333		local NavigationPoint N;
00334		local byte Team;
00335	
00336		if ( bStartMatch && (Player != None) && Player.IsA('TournamentPlayer') 
00337			&& (Level.NetMode == NM_Standalone)
00338			&& (TournamentPlayer(Player).StartSpot != None) )
00339			return TournamentPlayer(Player).StartSpot;
00340	
00341		if ( (Player != None) && (Player.PlayerReplicationInfo != None) )
00342			Team = Player.PlayerReplicationInfo.Team;
00343		else
00344			Team = InTeam;
00345	
00346		if( incomingName!="" )
00347			foreach AllActors( class 'Teleporter', Tel )
00348				if( string(Tel.Tag)~=incomingName )
00349					return Tel;
00350	
00351		if ( Team == 255 )
00352			Team = 0;
00353					
00354		//choose candidates	
00355		for ( N=Level.NavigationPointList; N!=None; N=N.nextNavigationPoint )
00356		{
00357			Dest = PlayerStart(N);
00358			if ( (Dest != None) && Dest.bEnabled
00359				&& (!bSpawnInTeamArea || (Team == Dest.TeamNumber)) )
00360			{
00361				if (num<16)
00362					Candidate[num] = Dest;
00363				else if (Rand(num) < 16)
00364					Candidate[Rand(16)] = Dest;
00365				num++;
00366			}
00367		}
00368	
00369		if (num == 0 )
00370		{
00371			log("Didn't find any player starts in list for team"@Team@"!!!"); 
00372			foreach AllActors( class'PlayerStart', Dest )
00373			{
00374				if (num<16)
00375					Candidate[num] = Dest;
00376				else if (Rand(num) < 16)
00377					Candidate[Rand(16)] = Dest;
00378				num++;
00379			}
00380			if ( num == 0 )
00381				return None;
00382		}
00383	
00384		if (num>16) 
00385			num = 16;
00386		
00387		//assess candidates
00388		for (i=0;i<num;i++)
00389		{
00390			if ( Candidate[i] == LastStartSpot )
00391				Score[i] = -6000.0;
00392			else
00393				Score[i] = 4000 * FRand(); //randomize
00394		}		
00395		
00396		for ( OtherPlayer=Level.PawnList; OtherPlayer!=None; OtherPlayer=OtherPlayer.NextPawn)	
00397			if ( OtherPlayer.bIsPlayer && (OtherPlayer.Health > 0) && !OtherPlayer.IsA('Spectator') )
00398				for (i=0; i<num; i++)
00399					if ( OtherPlayer.Region.Zone == Candidate[i].Region.Zone ) 
00400					{
00401						Score[i] -= 1500;
00402						NextDist = VSize(OtherPlayer.Location - Candidate[i].Location);
00403						if (NextDist < 2 * (CollisionRadius + CollisionHeight))
00404							Score[i] -= 1000000.0;
00405						else if ( (NextDist < 2000) && (OtherPlayer.PlayerReplicationInfo.Team != Team)
00406								&& FastTrace(Candidate[i].Location, OtherPlayer.Location) )
00407							Score[i] -= (10000.0 - NextDist);
00408					}
00409		
00410		BestScore = Score[0];
00411		Best = Candidate[0];
00412		for (i=1; i<num; i++)
00413			if (Score[i] > BestScore)
00414			{
00415				BestScore = Score[i];
00416				Best = Candidate[i];
00417			}
00418		LastStartSpot = Best;
00419					
00420		return Best;
00421	}
00422	
00423	//-------------------------------------------------------------------------------------
00424	// Level gameplay modification
00425	
00426	//Use reduce damage for teamplay modifications, etc.
00427	function int ReduceDamage(int Damage, name DamageType, pawn injured, pawn instigatedBy)
00428	{
00429		Damage = Super.ReduceDamage(Damage, DamageType, injured, instigatedBy);
00430		
00431		if ( instigatedBy == None )
00432			return Damage;
00433	
00434		if ( (instigatedBy != injured) && injured.bIsPlayer && instigatedBy.bIsPlayer 
00435			&& (injured.PlayerReplicationInfo.Team == instigatedBy.PlayerReplicationInfo.Team) )
00436		{
00437			if ( injured.IsA('Bot') )
00438				Bot(Injured).YellAt(instigatedBy);
00439			return (Damage * FriendlyFireScale);
00440		}
00441		else
00442			return Damage;
00443	}
00444	
00445	function ScoreKill(pawn Killer, pawn Other)
00446	{
00447		if ( (Killer == None) || (Killer == Other) || !Other.bIsPlayer || !Killer.bIsPlayer 
00448			|| (Killer.PlayerReplicationInfo.Team != Other.PlayerReplicationInfo.Team) )
00449			Super.ScoreKill(Killer, Other);
00450	
00451		if ( !bScoreTeamKills )
00452			return;
00453		if ( Other.bIsPlayer && ((Killer == None) || Killer.bIsPlayer) )
00454		{
00455			if ( (Killer == Other) || (Killer == None) )
00456				Teams[Other.PlayerReplicationInfo.Team].Score -= 1;
00457			else if ( Killer.PlayerReplicationInfo.Team != Other.PlayerReplicationInfo.Team )
00458				Teams[Killer.PlayerReplicationInfo.Team].Score += 1;
00459			else if ( FriendlyFireScale > 0 )
00460			{
00461				Teams[Other.PlayerReplicationInfo.Team].Score -= 1;
00462				Killer.PlayerReplicationInfo.Score -= 1;
00463			}
00464		}
00465	
00466		if ( (bOverTime || (GoalTeamScore > 0)) && Killer.bIsPlayer
00467			&& (Teams[killer.PlayerReplicationInfo.Team].Score >= GoalTeamScore) )
00468			EndGame("teamscorelimit");
00469	}
00470	
00471	function bool ChangeTeam(Pawn Other, int NewTeam)
00472	{
00473		local int i, Smallest, DesiredTeam;
00474		local pawn APlayer, P;
00475		local teaminfo SmallestTeam;
00476	
00477		if ( bRatedGame && (Other.PlayerReplicationInfo.Team != 255) )
00478			return false;
00479		if ( Other.IsA('Spectator') )
00480		{
00481			Other.PlayerReplicationInfo.Team = 255;
00482			if (LocalLog != None)
00483				LocalLog.LogTeamChange(Other);
00484			if (WorldLog != None)
00485				WorldLog.LogTeamChange(Other);
00486			return true;
00487		}
00488	
00489		// find smallest team
00490		Smallest = 0;
00491		for( i=1; i<MaxTeams; i++ )
00492			if ( Teams[Smallest].Size > Teams[i].Size )
00493				Smallest = i;
00494	
00495		if ( (NewTeam == 255) || (NewTeam >= MaxTeams) )
00496			NewTeam = Smallest;
00497	
00498		if ( bPlayersBalanceTeams && (Level.NetMode != NM_Standalone) )
00499		{
00500			if ( Teams[NewTeam].Size > Teams[Smallest].Size )
00501				NewTeam = Smallest;
00502			if ( NumBots == 1 )
00503			{
00504				// join bot's team if sizes are equal, because he will leave
00505				for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00506					if ( P.IsA('Bot') )
00507						break;
00508				
00509				if ( (P != None) && (P.PlayerReplicationInfo != None) && (P.PlayerReplicationInfo.Team != 255)
00510					&& (Teams[P.PlayerReplicationInfo.Team].Size == Teams[Smallest].Size) )
00511					NewTeam = P.PlayerReplicationInfo.Team;
00512			}
00513		}
00514	
00515		if ( (Other.PlayerReplicationInfo.Team == NewTeam) && bNoTeamChanges )
00516			return false;
00517	
00518		if ( Other.IsA('TournamentPlayer') )
00519			TournamentPlayer(Other).StartSpot = None;
00520	
00521		if ( Other.PlayerReplicationInfo.Team != 255 )
00522		{
00523			ClearOrders(Other);
00524			Teams[Other.PlayerReplicationInfo.Team].Size--;
00525		}
00526	
00527		if ( Teams[NewTeam].Size < MaxTeamSize )
00528		{
00529			AddToTeam(NewTeam, Other);
00530			return true;
00531		}
00532	
00533		if ( Other.PlayerReplicationInfo.Team == 255 )
00534		{
00535			AddToTeam(Smallest, Other);
00536			return true;
00537		}
00538	
00539		return false;
00540	}
00541	
00542	function AddToTeam( int num, Pawn Other )
00543	{
00544		local teaminfo aTeam;
00545		local Pawn P;
00546		local bool bSuccess;
00547		local string SkinName, FaceName;
00548	
00549		if ( Other == None )
00550		{
00551			log("Added none to team!!!");
00552			return;
00553		}
00554	
00555		aTeam = Teams[num];
00556	
00557		aTeam.Size++;
00558		Other.PlayerReplicationInfo.Team = num;
00559		Other.PlayerReplicationInfo.TeamName = aTeam.TeamName;
00560		if (LocalLog != None)
00561			LocalLog.LogTeamChange(Other);
00562		if (WorldLog != None)
00563			WorldLog.LogTeamChange(Other);
00564		bSuccess = false;
00565		if ( Other.IsA('PlayerPawn') )
00566		{
00567			Other.PlayerReplicationInfo.TeamID = 0;
00568			PlayerPawn(Other).ClientChangeTeam(Other.PlayerReplicationInfo.Team);
00569		}
00570		else
00571			Other.PlayerReplicationInfo.TeamID = 1;
00572	
00573		while ( !bSuccess )
00574		{
00575			bSuccess = true;
00576			for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00577	            if ( P.bIsPlayer && (P != Other) 
00578					&& (P.PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team) 
00579					&& (P.PlayerReplicationInfo.TeamId == Other.PlayerReplicationInfo.TeamId) )
00580					bSuccess = false;
00581			if ( !bSuccess )
00582				Other.PlayerReplicationInfo.TeamID++;
00583		}
00584	
00585		BroadcastLocalizedMessage( DMMessageClass, 3, Other.PlayerReplicationInfo, None, aTeam );
00586	
00587		Other.static.GetMultiSkin(Other, SkinName, FaceName);
00588		Other.static.SetMultiSkin(Other, SkinName, FaceName, num);
00589	
00590		if ( bBalanceTeams && !bRatedGame )
00591			ReBalance();
00592	}
00593	
00594	function bool CanSpectate( pawn Viewer, actor ViewTarget )
00595	{
00596		if ( ViewTarget.bIsPawn && (Pawn(ViewTarget).PlayerReplicationInfo != None)
00597			&& Pawn(ViewTarget).PlayerReplicationInfo.bIsSpectator )
00598			return false;
00599		if ( Viewer.PlayerReplicationInfo.bIsSpectator && (Viewer.PlayerReplicationInfo.Team == 255) )
00600			return true;
00601		return ( (Pawn(ViewTarget) != None) && Pawn(ViewTarget).bIsPlayer 
00602			&& (Pawn(ViewTarget).PlayerReplicationInfo.Team == Viewer.PlayerReplicationInfo.Team) );
00603	}
00604	
00605	function TeamInfo GetTeam(int TeamNum )
00606	{
00607		if ( TeamNum < ArrayCount(Teams) )
00608			return Teams[TeamNum];
00609		else return None;
00610	}
00611	
00612	function bool IsOnTeam(Pawn Other, int TeamNum)
00613	{
00614		if ( Other.PlayerReplicationInfo.Team == TeamNum )
00615			return true;
00616	
00617		return false;
00618	}
00619	
00620	function bool AddBot()
00621	{
00622		local bot NewBot;
00623		local NavigationPoint StartSpot, OldStartSpot;
00624		local int DesiredTeam, i, MinSize;
00625	
00626		NewBot = SpawnBot(StartSpot);
00627		if ( NewBot == None )
00628		{
00629			log("Failed to spawn bot");
00630			return false;
00631		}
00632	
00633		if ( bBalanceTeams && !bRatedGame )
00634		{
00635			MinSize = Teams[0].Size;
00636			DesiredTeam = 0;
00637			for ( i=1; i<MaxTeams; i++ )
00638				if ( Teams[i].Size < MinSize )
00639				{
00640					MinSize = Teams[i].Size;
00641					DesiredTeam = i;
00642				}	
00643		}
00644		else
00645			DesiredTeam = NewBot.PlayerReplicationInfo.Team;
00646		NewBot.PlayerReplicationInfo.Team = 255;
00647		if ( (DesiredTeam == 255) || !ChangeTeam(NewBot, DesiredTeam) )
00648		{
00649			ChangeTeam(NewBot, NextBotTeam);
00650			NextBotTeam++;
00651			if ( NextBotTeam >= MaxTeams )
00652				NextBotTeam = 0;
00653		}
00654	
00655		if ( bSpawnInTeamArea )
00656		{
00657			OldStartSpot = StartSpot;
00658			StartSpot = FindPlayerStart(NewBot,255);
00659			if ( StartSpot != None )
00660			{
00661				NewBot.SetLocation(StartSpot.Location);
00662				NewBot.SetRotation(StartSpot.Rotation);
00663				NewBot.ViewRotation = StartSpot.Rotation;
00664				NewBot.SetRotation(NewBot.Rotation);
00665				StartSpot.PlayTeleportEffect( NewBot, true );
00666			}
00667			else
00668				StartSpot = OldStartSpot;
00669		}
00670	
00671		StartSpot.PlayTeleportEffect(NewBot, true);
00672	
00673		SetBotOrders(NewBot);
00674	
00675		// Log it.
00676		if (LocalLog != None)
00677		{
00678			LocalLog.LogPlayerConnect(NewBot);
00679			LocalLog.FlushLog();
00680		}
00681		if (WorldLog != None)
00682		{
00683			WorldLog.LogPlayerConnect(NewBot);
00684			WorldLog.FlushLog();
00685		}
00686	
00687		return true;
00688	}
00689	
00690	function SetBotOrders(Bot NewBot)
00691	{
00692		local Pawn P, L;
00693		local int num, total;
00694	
00695		// only follow players, if there are any
00696		if ( (NumSupportingPlayer == 0)
00697			 || (NumSupportingPlayer < Teams[NewBot.PlayerReplicationInfo.Team].Size/2 - 1) ) 
00698		{
00699			For ( P=Level.PawnList; P!=None; P= P.NextPawn )
00700				if ( P.IsA('PlayerPawn') && (P.PlayerReplicationInfo.Team == NewBot.PlayerReplicationInfo.Team)
00701					&& !P.IsA('Spectator') )
00702			{
00703				num++;
00704				if ( (L == None) || (FRand() < 1.0/float(num)) )
00705					L = P;
00706			}
00707	
00708			if ( L != None )
00709			{
00710				NumSupportingPlayer++;
00711				NewBot.SetOrders('Follow',L,true);
00712				return;
00713			}
00714		}
00715		num = 0;
00716		For ( P=Level.PawnList; P!=None; P= P.NextPawn )
00717			if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == NewBot.PlayerReplicationInfo.Team) )
00718			{
00719				total++;
00720				if ( (P != NewBot) && P.IsA('Bot') && (Bot(P).Orders == 'FreeLance') )
00721				{
00722					num++;
00723					if ( (L == None) || (FRand() < 1/float(num)) )
00724						L = P;
00725				}
00726			}
00727					
00728		if ( (L != None) && (FRand() < float(num)/float(total)) )
00729		{
00730			NewBot.SetOrders('Follow',L,true);
00731			return;
00732		}
00733		NewBot.SetOrders('Freelance', None,true);
00734	}				 
00735	
00736	function byte AssessBotAttitude(Bot aBot, Pawn Other)
00737	{
00738		if ( (Other.bIsPlayer && (aBot.PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team))
00739			|| (Other.IsA('TeamCannon') 
00740				&& (StationaryPawn(Other).SameTeamAs(aBot.PlayerReplicationInfo.Team))) ) 
00741			return 3;
00742		else 
00743			return Super.AssessBotAttitude(aBot, Other);
00744	}
00745	
00746	function Actor SetDefenseFor(Bot aBot)
00747	{
00748		return None;
00749	}
00750	
00751	function bool FindSpecialAttractionFor(Bot aBot)
00752	{
00753		return false;
00754	}
00755	
00756	function SetAttractionStateFor(Bot aBot)
00757	{
00758		if ( aBot.Enemy != None )
00759		{
00760			if ( !aBot.IsInState('FallBack') )
00761			{
00762				aBot.bNoClearSpecial = true;
00763				aBot.TweenToRunning(0.1);
00764				aBot.GotoState('FallBack','SpecialNavig');
00765			}
00766		}
00767		else if ( !aBot.IsInState('Roaming') )
00768		{
00769			aBot.bNoClearSpecial = true;
00770			aBot.TweenToRunning(0.1);
00771			aBot.GotoState('Roaming', 'SpecialNavig');
00772		}
00773	}
00774	
00775	function PickAmbushSpotFor(Bot aBot)
00776	{
00777		local NavigationPoint N;
00778	
00779		for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
00780			if ( N.IsA('Ambushpoint') && !N.taken )
00781			{
00782				if ( aBot.Orders == 'Defend' )
00783				{
00784					if ( N.IsA('DefensePoint') && (DefensePoint(N).team == aBot.PlayerReplicationInfo.team) )
00785					{
00786						if ( (DefensePoint(aBot.Ambushspot) == None)
00787							|| (DefensePoint(N).priority > DefensePoint(aBot.Ambushspot).priority) )
00788							aBot.Ambushspot = Ambushpoint(N);
00789						else if ( (DefensePoint(N).priority == DefensePoint(aBot.Ambushspot).priority)
00790							&& (FRand() < 0.4) ) 
00791							aBot.Ambushspot = Ambushpoint(N);
00792					}		
00793					else if ( (DefensePoint(aBot.AmbushSpot) == None)
00794							&& (VSize(N.Location - aBot.OrderObject.Location) < 1500)
00795							&& FastTrace(aBot.OrderObject.Location, N.Location)
00796							&& ((aBot.Ambushspot == None) || (FRand() < 0.5)) )
00797								aBot.Ambushspot = Ambushpoint(N);
00798				}
00799				else if ( (aBot.AmbushSpot == None)
00800					|| (VSize(aBot.Location - aBot.Ambushspot.Location)
00801						 > VSize(aBot.Location - N.Location)) )
00802					aBot.Ambushspot = Ambushpoint(N);
00803			}
00804	}
00805	
00806	function byte PriorityObjective(Bot aBot)
00807	{
00808		return 0;
00809	}
00810	
00811	function bool SuccessfulGame()
00812	{
00813		local TeamInfo BestTeam;
00814		local int i;
00815		BestTeam = Teams[0];
00816		for ( i=1; i<MaxTeams; i++ )
00817			if ( Teams[i].Score > BestTeam.Score )
00818				BestTeam = Teams[i];
00819	
00820		bFulfilledSpecial = True; // Override and implement if you have a special condition.
00821		if (BestTeam.TeamIndex == RatedPlayer.PlayerReplicationInfo.Team)
00822			return ( bFulfilledSpecial && (BestTeam.Score >= GoalTeamScore) );
00823		else
00824			return false;
00825	}
00826	
00827	function ClearOrders(Pawn Leaving)
00828	{
00829		local Pawn P;
00830	
00831		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00832			if ( P.IsA('Bot') && (Bot(P).OrderObject == Leaving) )
00833				Bot(P).SetOrders('Freelance', None);
00834	}
00835	function bool WaitForPoint(bot aBot)
00836	{
00837		return false;
00838	}
00839	
00840	function bool SendBotToGoal(Bot aBot)
00841	{
00842		return false;
00843	}
00844	
00845	function bool HandleTieUp(Bot Bumper, Bot Bumpee)
00846	{
00847		return false;
00848	}
00849	
00850	//------------------------------------------------------------------------------
00851	// Game Querying.
00852	
00853	function string GetRules()
00854	{
00855		local string ResultSet;
00856		ResultSet = Super(TournamentGameInfo).GetRules();
00857	
00858		ResultSet = ResultSet$"\\timelimit\\"$TimeLimit;
00859		ResultSet = ResultSet$"\\goalteamscore\\"$int(GoalTeamScore);
00860		Resultset = ResultSet$"\\minplayers\\"$MinPlayers;
00861		Resultset = ResultSet$"\\changelevels\\"$bChangeLevels;
00862		ResultSet = ResultSet$"\\maxteams\\"$MaxTeams;
00863		ResultSet = ResultSet$"\\balanceteams\\"$bBalanceTeams;
00864		ResultSet = ResultSet$"\\playersbalanceteams\\"$bPlayersBalanceTeams;
00865		ResultSet = ResultSet$"\\friendlyfire\\"$int(FriendlyFireScale*100)$"%";
00866		Resultset = ResultSet$"\\tournament\\"$bTournament;
00867		if(bMegaSpeed)
00868			Resultset = ResultSet$"\\gamestyle\\Turbo";
00869		else
00870		if(bHardcoreMode)
00871			Resultset = ResultSet$"\\gamestyle\\Hardcore";
00872		else
00873			Resultset = ResultSet$"\\gamestyle\\Classic";
00874	
00875		if(MinPlayers > 0)
00876			Resultset = ResultSet$"\\botskill\\"$class'ChallengeBotInfo'.default.Skills[Difficulty];
00877	
00878		return ResultSet;
00879	}
00880	
00881	defaultproperties
00882	{
00883	     bScoreTeamKills=True
00884	     bBalanceTeams=True
00885	     bPlayersBalanceTeams=True
00886	     MaxTeams=2
00887	     MaxAllowedTeams=4
00888	     GoalTeamScore=30.000000
00889	     MaxTeamSize=16
00890	     StartUpTeamMessage="You are on"
00891	     TeamChangeMessage="Use Options->Player Setup to change teams."
00892	     TeamColor(0)="Red"
00893	     TeamColor(1)="Blue"
00894	     TeamColor(2)="Green"
00895	     TeamColor(3)="Gold"
00896	     TEAM_Blue=1
00897	     TEAM_Green=2
00898	     TEAM_Gold=3
00899	     CurrentOrders(0)=Defend
00900	     CurrentOrders(1)=Defend
00901	     CurrentOrders(2)=Defend
00902	     CurrentOrders(3)=Defend
00903	     StartupTeamTralier="."
00904	     StartUpMessage="Work with your teammates against the other teams."
00905	     MaxCommanders=2
00906	     bCanChangeSkin=False
00907	     bTeamGame=True
00908	     ScoreBoardType=Class'Botpack.TeamScoreBoard'
00909	     RulesMenuType="UTMenu.UTTeamRSClient"
00910	     SettingsMenuType="UTMenu.UTTeamSSClient"
00911	     HUDType=Class'Botpack.ChallengeTeamHUD'
00912	     BeaconName="TTeam"
00913	     GameName="Tournament Team Game"
00914	}

End Source Code