Botpack
Class DeathMatchPlus

source: e:\games\UnrealTournament\Botpack\Classes\DeathMatchPlus.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.GameInfo
            |
            +--Botpack.TournamentGameInfo
               |
               +--Botpack.DeathMatchPlus
Direct Known Subclasses:ChallengeDMP, ChallengeIntro, LastManStanding, TDarkMatch, TeamGamePlus, TrainingDM, MyGame

class DeathMatchPlus
extends Botpack.TournamentGameInfo

//============================================================================= // DeathMatchPlus. //=============================================================================
Variables
 float AirControl
           bots fill in to guarantee this level in net game
 PlayerRating, AvgOpponentRating
           time to wait for players in netgames w/ bNetReady (typically team games)
 class BotConfigType
           time to wait for players in netgames w/ bNetReady (typically team games)
 string CountDownMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 float EndTime
           time to wait for players in netgames w/ bNetReady (typically team games)
 int FragLimit
           bots fill in to guarantee this level in net game
 string GameEndedMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 int IDnum
           time to wait for players in netgames w/ bNetReady (typically team games)
 int InitialBots
           time to wait for players in netgames w/ bNetReady (typically team games)
 int LadderTypeIndex
           time to wait for players in netgames w/ bNetReady (typically team games)
 NavigationPoint LastStartSpot
           time to wait for players in netgames w/ bNetReady (typically team games)
 float LastTauntTime
           time to wait for players in netgames w/ bNetReady (typically team games)
 WinCount, LoseCount
           time to wait for players in netgames w/ bNetReady (typically team games)
 int MaxCommanders
           time to wait for players in netgames w/ bNetReady (typically team games)
 int MinPlayers
           bots fill in to guarantee this level in net game
 int NetWait
           time to wait for players in netgames w/ bNetReady (typically team games)
 string NotReadyMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 int NumBots
           time to wait for players in netgames w/ bNetReady (typically team games)
 int NumCommanders
           time to wait for players in netgames w/ bNetReady (typically team games)
 NoNameChange, OvertimeMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 LadderInventory RatedGameLadderObj
           time to wait for players in netgames w/ bNetReady (typically team games)
 RatedMatchInfo RatedMatchConfig
           time to wait for players in netgames w/ bNetReady (typically team games)
 PlayerPawn RatedPlayer
           time to wait for players in netgames w/ bNetReady (typically team games)
 string ReadyMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 int RestartWait
           time to wait for players in netgames w/ bNetReady (typically team games)
 string SingleWaitingMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 CountDown, StartCount
           time to wait for players in netgames w/ bNetReady (typically team games)
 string StartMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 string StartUpMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 int TimeLimit
           time limit in minutes
 string TourneyMessage
           time to wait for players in netgames w/ bNetReady (typically team games)
 string WaitingMessage1
           time to wait for players in netgames w/ bNetReady (typically team games)
 string WaitingMessage2
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bAltScoring
           time limit in minutes
 bool bChallengeMode
           time limit in minutes
 bool bChangeLevels
           time limit in minutes
 bool bForceRespawn
           time limit in minutes
 bool bFulfilledSpecial
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bHardCoreMode
           time limit in minutes
 bool bJumpMatch
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bMegaSpeed
           time limit in minutes
 bool bMultiWeaponStay
           time limit in minutes
 bool bNetReady
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bNoviceMode
           time limit in minutes
 bool bRatedTranslocator
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bRequireReady
           time limit in minutes
 bool bStartMatch
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bThreePlus
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bTournament
           time limit in minutes
 bool bTutorialGame
           time to wait for players in netgames w/ bNetReady (typically team games)
 bool bUseTranslocator
           time to wait for players in netgames w/ bNetReady (typically team games)
 string gamegoal
           time to wait for players in netgames w/ bNetReady (typically team games)


Function Summary
 void AcceptInventory(Pawn PlayerPawn)
     
/* AcceptInventory()
Examine the passed player's inventory, and accept or discard each item
* AcceptInventory needs to gracefully handle the case of some inventory
being accepted but other inventory not being accepted (such as the default
weapon).  There are several things that can go wrong: A weapon's
AmmoType not being accepted but the weapon being accepted -- the weapon
should be killed off. Or the player's selected inventory item, active
weapon, etc. not being accepted, leaving the player weaponless or leaving
the HUD inventory rendering messed up (AcceptInventory should pick another
applicable weapon/item as current).
*/
 bool AddBot()
 void AddDefaultInventory(Pawn PlayerPawn)
 bool AllowTranslocation(Pawn Other, vector Dest)
     
// AllowTranslocation - return true if Other can teleport to Dest
 byte AssessBotAttitude(Bot aBot, Pawn Other)
 bool CanSpectate(Pawn Viewer, Actor ViewTarget)
 bool CanTranslocate(Bot aBot)
 void ChangeName(Pawn Other, string S, bool bNameChange)
 void CheckReady()
 bool CheckThisTranslocator(Bot aBot, TranslocatorTarget T)
 void EndSpree(Pawn Killer, Pawn Other)
 NavigationPoint FindPlayerStart(Pawn Player, optional byte, optional string)
     
/* FindPlayerStart()
returns the 'best' player start for this player to start from.
Re-implement for each game type
*/
 bool ForceAddBot()
 float GameThreatAdd(Bot aBot, Pawn Other)
 string GetRules()
     
//------------------------------------------------------------------------------
// Game Querying.
 void GiveWeapon(Pawn PlayerPawn, string aClassName)
 void InitGameReplicationInfo()
 void InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
     
// Set game settings based on ladder information.
// Called when RatedPlayer logs in.
 void Killed(Pawn killer, Pawn Other, name damageType)
     
// Monitor killed messages for fraglimit
 void LogGameParameters(StatLog StatLog)
 void Logout(Pawn Exiting)
 void ModifyBehaviour(Bot NewBot)
 bool NeedPlayers()
 bool NeverStakeOut(Bot Other)
 void NotifySpree(Pawn Other, int num)
 bool OneOnOne()
 void PickAmbushSpotFor(Bot aBot)
 void PlayStartUpMessage(PlayerPawn NewPlayer)
 void PlayTeleportEffect(Actor Incoming, bool bOut, bool bSound)
 void PlayWinMessage(PlayerPawn Player, bool bWinner)
 float PlayerJumpZScaling()
 void PostBeginPlay()
 void PreCacheReferences()
 void RateVs(Pawn Other, Pawn Killer)
 int ReduceDamage(int Damage, name DamageType, Pawn injured, Pawn instigatedBy)
 void RestartGame()
 bool RestartPlayer(Pawn aPlayer)
 void ScoreKill(Pawn Killer, Pawn Other)
 void SendStartMessage(PlayerPawn P)
 bool SetEndCams(string Reason)
 void SetGameSpeed(Float T)
     
//
// Set gameplay speed.
//
 bool ShouldRespawn(Actor Other)
 void Skip()
     
// Commented out for release version.
 void SkipAll()
 Bot SpawnBot(out NavigationPoint)
 Bot SpawnRatedBot(out NavigationPoint)
 float SpawnWait(Bot B)
 void StartMatch()
 bool SuccessfulGame()
 void Timer()
 bool TooManyBots()



Source Code


00001	//=============================================================================
00002	// DeathMatchPlus.
00003	//=============================================================================
00004	class DeathMatchPlus extends TournamentGameInfo
00005		config;
00006	
00007	// Sounds
00008	#exec OBJ LOAD FILE=..\Sounds\Announcer.uax
00009	
00010	var() globalconfig int  MinPlayers;		// bots fill in to guarantee this level in net game 
00011	var() globalconfig float AirControl; 
00012	var() config int	FragLimit; 
00013	var() config int	TimeLimit; // time limit in minutes
00014	var() globalconfig bool bChangeLevels;
00015	var() globalconfig bool bHardCoreMode;
00016	var   bool			    bChallengeMode;
00017	var() globalconfig bool bMegaSpeed;
00018	var() globalconfig bool	bAltScoring;
00019	var() config bool	bMultiWeaponStay;
00020	var() config bool	bForceRespawn;
00021	var		bool	bAlwaysForceRespawn;
00022	var		bool	bDontRestart;
00023	var		bool	bAlreadyChanged;
00024	var		bool	bFirstBlood;
00025	
00026	var() globalconfig bool bTournament;
00027	var  bool bRequireReady;
00028	var() bool bNoviceMode;
00029	var() globalconfig int NetWait; // time to wait for players in netgames w/ bNetReady (typically team games)
00030	var() globalconfig int RestartWait;
00031	var config bool bUseTranslocator;
00032	var bool bJumpMatch;
00033	var bool bThreePlus;
00034	var bool bFulfilledSpecial;
00035	var bool	bNetReady;
00036	var bool bRatedTranslocator;
00037	var bool bStartMatch;
00038	
00039	var	int RemainingTime, ElapsedTime;
00040	var int CountDown, StartCount;
00041	var localized string StartUpMessage;
00042	var localized string TourneyMessage;
00043	var localized string WaitingMessage1;
00044	var localized string WaitingMessage2;
00045	var localized string ReadyMessage;
00046	var localized string NotReadyMessage;
00047	var localized string CountDownMessage;
00048	var localized string StartMessage;
00049	var localized string GameEndedMessage;
00050	var localized string SingleWaitingMessage;
00051	var localized string gamegoal;
00052	
00053	var float LastTauntTime;
00054	var NavigationPoint LastStartSpot;
00055	var() config int	MaxCommanders;
00056	var int   NumCommanders;
00057	
00058	var bool bTutorialGame;
00059	
00060	// Bot related info
00061	var   int				NumBots;
00062	var	  int				RemainingBots;
00063	var	  int				LastTaunt[4];
00064	var() globalconfig int	InitialBots;
00065	var	ChallengeBotInfo	BotConfig;
00066	var localized string	NoNameChange, OvertimeMessage;
00067	var class<ChallengeBotInfo>		BotConfigType;
00068	
00069	// Player rating variables for single player rated games
00070	var float PlayerRating, AvgOpponentRating;
00071	var int NumOpp, WinCount, LoseCount;
00072	var PlayerPawn RatedPlayer;
00073	var int IDnum;
00074	var RatedMatchInfo RatedMatchConfig;
00075	var float EndTime;
00076	var int LadderTypeIndex;
00077	
00078	var LadderInventory RatedGameLadderObj;
00079	
00080	function PostBeginPlay()
00081	{
00082		local string NextPlayerClass;
00083		local int i;
00084	
00085		if ( bAlternateMode )
00086		{
00087			bVeryLowGore = true;
00088			bLowGore = true;
00089		}
00090		BotConfig = spawn(BotConfigType);
00091		if ( Level.NetMode == NM_Standalone )
00092			RemainingBots = InitialBots;
00093		else
00094			RemainingBots = 0;
00095		Super.PostBeginPlay();
00096		GameReplicationInfo.RemainingTime = RemainingTime;
00097	}
00098	
00099	function PreCacheReferences()
00100	{
00101		//never called - here to force precaching of meshes
00102		spawn(class'TMale1');
00103		spawn(class'TMale2');
00104		spawn(class'TFemale1');
00105		spawn(class'TFemale2');
00106		spawn(class'ImpactHammer');
00107		spawn(class'Translocator');
00108		spawn(class'Enforcer');
00109		spawn(class'UT_Biorifle');
00110		spawn(class'ShockRifle');
00111		spawn(class'PulseGun');
00112		spawn(class'Ripper');
00113		spawn(class'Minigun2');
00114		spawn(class'UT_FlakCannon');
00115		spawn(class'UT_Eightball');
00116		spawn(class'SniperRifle');
00117	}
00118	
00119	function CheckReady()
00120	{
00121		if ( (FragLimit == 0) && (TimeLimit == 0) )
00122		{
00123			TimeLimit = 20;
00124			RemainingTime = 60 * TimeLimit;
00125		}
00126	}
00127	
00128	//
00129	// Set gameplay speed.
00130	//
00131	function SetGameSpeed( Float T )
00132	{
00133		GameSpeed = FMax(T, 0.1);
00134		if ( bHardCoreMode )
00135		{
00136			if ( bChallengeMode )
00137				Level.TimeDilation = 1.25 * GameSpeed;
00138			else
00139				Level.TimeDilation = 1.1 * GameSpeed;
00140		}
00141		else
00142			Level.TimeDilation = GameSpeed;
00143		SaveConfig();
00144		SetTimer(Level.TimeDilation, true);
00145	}
00146	
00147	function PlayTeleportEffect( actor Incoming, bool bOut, bool bSound)
00148	{
00149	 	local UTTeleportEffect PTE;
00150	
00151		if ( bRequireReady && (Countdown > 0) )
00152			return;
00153	
00154		if ( Incoming.bIsPawn && (Incoming.Mesh != None) )
00155		{
00156			if ( bSound )
00157			{
00158	 			PTE = Spawn(class'UTTeleportEffect',Incoming,, Incoming.Location, Incoming.Rotation);
00159	 			PTE.Initialize(Pawn(Incoming), bOut);
00160				PTE.PlaySound(sound'Resp2A',, 10.0);
00161			}
00162		}
00163	}
00164	
00165	// Parse options for this game...
00166	event InitGame( string Options, out string Error )
00167	{
00168		local string InOpt;
00169	
00170		Super.InitGame(Options, Error);
00171	
00172		RemainingTime = 60 * TimeLimit;
00173		SetGameSpeed(GameSpeed);
00174		FragLimit = GetIntOption( Options, "FragLimit", FragLimit );
00175		TimeLimit = GetIntOption( Options, "TimeLimit", TimeLimit );
00176		MaxCommanders = GetIntOption( Options, "MaxCommanders", MaxCommanders );
00177	
00178		InOpt = ParseOption( Options, "CoopWeaponMode");
00179		if ( InOpt != "" )
00180		{
00181			log("CoopWeaponMode: "$bool(InOpt));
00182			bCoopWeaponMode = bool(InOpt);
00183		}
00184	
00185		IDnum = -1;
00186		IDnum = GetIntOption( Options, "Tournament", IDnum );
00187		if ( IDnum > 0 )
00188		{
00189			bRatedGame = true;
00190			TimeLimit = 0;
00191			RemainingTime = 0;
00192		}
00193		if ( bTournament ) 
00194		{
00195			bRequireReady = true;
00196			CheckReady();
00197		}
00198		if ( Level.NetMode == NM_StandAlone )
00199		{
00200			bRequireReady = true;
00201			CountDown = 1;
00202		}
00203		if ( !bRequireReady && (Level.NetMode != NM_Standalone) )
00204		{
00205			bRequireReady = true;
00206			bNetReady = true;
00207		}
00208	}
00209	
00210	// Set game settings based on ladder information.
00211	// Called when RatedPlayer logs in.
00212	function InitRatedGame(LadderInventory LadderObj, PlayerPawn LadderPlayer)
00213	{
00214		local class<RatedMatchInfo> RMI;
00215		local Weapon W;
00216	
00217		FragLimit = LadderObj.CurrentLadder.Default.FragLimits[IDnum];
00218		RatedGameLadderObj = LadderObj;
00219		if (LadderObj.CurrentLadder.Default.TimeLimits[IDnum] > 0)
00220			TimeLimit = LadderObj.CurrentLadder.Default.TimeLimits[IDnum];
00221		bJumpMatch = false;
00222		bHardCoreMode = true;
00223		bRequireReady = true;
00224		bMegaSpeed = false;
00225		CountDown = 1;
00226		bRatedGame = true;
00227		bCoopWeaponMode = false;
00228		bUseTranslocator = bRatedTranslocator;
00229		ForEach AllActors(class'Weapon', W)
00230			W.bWeaponStay = false;
00231	
00232		RatedPlayer = LadderPlayer; 
00233	
00234		// Set up RatedBotConfig for this game
00235		BotConfig.bAdjustSkill = false;
00236		RMI = LadderObj.CurrentLadder.Static.GetMatchConfigType(IDnum);
00237		RatedMatchConfig = spawn(RMI);
00238		RemainingBots = RatedMatchConfig.NumBots; 
00239		Difficulty = LadderObj.TournamentDifficulty + RatedMatchConfig.ModifiedDifficulty;
00240		if ( Difficulty >= 4 )
00241		{
00242			bNoviceMode = false;
00243			Difficulty = Difficulty - 4;
00244		}
00245		else
00246		{
00247			if ( Difficulty > 3 )
00248			{
00249				Difficulty = 3;
00250				bThreePlus = true;
00251			}
00252			bNoviceMode = true;
00253		}
00254	
00255		// Update GRI
00256		InitGameReplicationInfo();
00257	
00258		// Update Logged Info
00259		if (bLocalLog && bLoggingGame)
00260		{
00261			LogGameParameters(LocalLog);
00262		}
00263		if (bWorldLog && bLoggingGame)
00264		{
00265			LogGameParameters(WorldLog);
00266		}
00267	
00268		PlayStartupMessage(LadderPlayer);
00269		LadderPlayer.SetProgressTime(6);
00270	}
00271	
00272	/* AcceptInventory()
00273	Examine the passed player's inventory, and accept or discard each item
00274	* AcceptInventory needs to gracefully handle the case of some inventory
00275	being accepted but other inventory not being accepted (such as the default
00276	weapon).  There are several things that can go wrong: A weapon's
00277	AmmoType not being accepted but the weapon being accepted -- the weapon
00278	should be killed off. Or the player's selected inventory item, active
00279	weapon, etc. not being accepted, leaving the player weaponless or leaving
00280	the HUD inventory rendering messed up (AcceptInventory should pick another
00281	applicable weapon/item as current).
00282	*/
00283	function AcceptInventory(pawn PlayerPawn)
00284	{
00285		local inventory Inv;
00286		local LadderInventory LadderObj;
00287	
00288		// DeathMatchPlus accepts LadderInventory
00289		for( Inv=PlayerPawn.Inventory; Inv!=None; Inv=Inv.Inventory )
00290		{
00291			if (Inv.IsA('LadderInventory'))
00292			{
00293				LadderObj = LadderInventory(Inv);
00294			} 
00295			else 	
00296				Inv.Destroy();
00297		}
00298		PlayerPawn.Weapon = None;
00299		PlayerPawn.SelectedItem = None;
00300		AddDefaultInventory( PlayerPawn );
00301	}
00302	
00303	function bool SetEndCams(string Reason)
00304	{
00305		local pawn P, Best;
00306		local PlayerPawn Player;
00307	
00308		// find individual winner
00309		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00310			if ( P.bIsPlayer && !P.IsA('Spectator') && ((Best == None) || (P.PlayerReplicationInfo.Score > Best.PlayerReplicationInfo.Score)) )
00311				Best = P;
00312	
00313		// check for tie
00314		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00315			if ( P.bIsPlayer && (Best != P) && (P.PlayerReplicationInfo.Score == Best.PlayerReplicationInfo.Score) )
00316			{
00317				BroadcastLocalizedMessage( DMMessageClass, 0 );
00318				return false;
00319			}		
00320	
00321		EndTime = Level.TimeSeconds + 3.0;
00322		GameReplicationInfo.GameEndedComments = Best.PlayerReplicationInfo.PlayerName@GameEndedMessage;
00323		log( "Game ended at "$EndTime);
00324		for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00325		{
00326			Player = PlayerPawn(P);
00327			if ( Player != None )
00328			{
00329				if (!bTutorialGame)
00330					PlayWinMessage(Player, (Player == Best));
00331				Player.bBehindView = true;
00332				if ( Player == Best )
00333					Player.ViewTarget = None;
00334				else
00335					Player.ViewTarget = Best;
00336				Player.ClientGameEnded();
00337			}
00338			P.GotoState('GameEnded');
00339		}
00340		CalcEndStats();
00341		return true;
00342	}
00343	
00344	function PlayWinMessage(PlayerPawn Player, bool bWinner)
00345	{
00346		if ( Player.IsA('TournamentPlayer') )
00347			TournamentPlayer(Player).PlayWinMessage(bWinner);
00348	}
00349	
00350	function NotifySpree(Pawn Other, int num)
00351	{
00352		local Pawn P;
00353	
00354		if ( num == 5 )
00355			num = 0;
00356		else if ( num == 10 )
00357			num = 1;
00358		else if ( num == 15 )
00359			num = 2;
00360		else if ( num == 20 )
00361			num = 3;
00362		else if ( num == 25 )
00363			num = 4;
00364		else
00365			return;
00366	
00367		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00368			if ( P.IsA('TournamentPlayer') )
00369				P.ReceiveLocalizedMessage( class'KillingSpreeMessage', Num, Other.PlayerReplicationInfo );
00370	}
00371	
00372	function EndSpree(Pawn Killer, Pawn Other)
00373	{
00374		local Pawn P;
00375	
00376		if ( !Other.bIsPlayer )
00377			return;
00378		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00379			if ( P.IsA('TournamentPlayer') )
00380			{
00381				if ( (Killer == None) || !Killer.bIsPlayer )
00382					TournamentPlayer(P).EndSpree(None, Other.PlayerReplicationInfo);
00383				else
00384					TournamentPlayer(P).EndSpree(Killer.PlayerReplicationInfo, Other.PlayerReplicationInfo);
00385			}
00386	}
00387	
00388	function ScoreKill(pawn Killer, pawn Other)
00389	{
00390		Super.ScoreKill(Killer, Other);
00391	
00392		if ( bAltScoring && (Killer != Other) && (killer != None) )
00393			Other.PlayerReplicationInfo.Score -= 1;
00394	}
00395	
00396	// Monitor killed messages for fraglimit
00397	function Killed(pawn killer, pawn Other, name damageType)
00398	{
00399		local int NextTaunt, i;
00400		local bool bAutoTaunt, bEndOverTime;
00401		local Pawn P, Best;
00402	
00403		if ( (damageType == 'Decapitated') && (Killer != Other) && (Killer != None) )
00404		{
00405			if (Level.Game.LocalLog != None)
00406				Level.Game.LocalLog.LogSpecialEvent("headshot", Killer.PlayerReplicationInfo.PlayerID, Other.PlayerReplicationInfo.PlayerID);
00407			if (Level.Game.WorldLog != None)
00408				Level.Game.WorldLog.LogSpecialEvent("headshot", Killer.PlayerReplicationInfo.PlayerID, Other.PlayerReplicationInfo.PlayerID);
00409			Killer.ReceiveLocalizedMessage( class'DecapitationMessage' );
00410		}
00411	
00412		Super.Killed(killer, Other, damageType);
00413	
00414		if ( Other.Spree > 4 )
00415			EndSpree(Killer, Other); 
00416		Other.Spree = 0;
00417	
00418		if ( !bTeamGame )
00419		{
00420			if ( bOverTime )
00421			{
00422				bEndOverTime = true;
00423				//check for clear winner now
00424				// find individual winner
00425				for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00426					if ( P.bIsPlayer && ((Best == None) || (P.PlayerReplicationInfo.Score > Best.PlayerReplicationInfo.Score)) )
00427						Best = P;
00428	
00429				// check for tie
00430				for ( P=Level.PawnList; P!=None; P=P.nextPawn )
00431					if ( P.bIsPlayer && (Best != P) && (P.PlayerReplicationInfo.Score == Best.PlayerReplicationInfo.Score) )
00432						bEndOverTime = false;
00433	
00434				if ( bEndOverTime )
00435				{
00436					if ( (FragLimit > 0) && (Best.PlayerReplicationInfo.Score >= FragLimit) )
00437						EndGame("fraglimit");
00438					else
00439						EndGame("timelimit");
00440				}
00441			}
00442			else if ( (FragLimit > 0) && (killer != None) && (killer.PlayerReplicationInfo != None)
00443					&& (killer.PlayerReplicationInfo.Score >= FragLimit) )
00444				EndGame("fraglimit");
00445		}
00446		
00447		if ( (killer == None) || (Other == None) )
00448			return;
00449		if ( !bFirstBlood )
00450			if ( Killer.bIsPlayer && (Killer != Other) )
00451				if (!Self.IsA('TrainingDM'))
00452				{
00453					bFirstBlood = True;
00454					BroadcastLocalizedMessage( class'FirstBloodMessage', 0, Killer.PlayerReplicationInfo );
00455				}
00456	
00457		if ( BotConfig.bAdjustSkill && (killer.IsA('PlayerPawn') || Other.IsA('PlayerPawn')) )
00458		{
00459			if ( killer.IsA('Bot') )
00460				BotConfig.AdjustSkill(Bot(killer),true);
00461			if ( Other.IsA('Bot') )
00462				BotConfig.AdjustSkill(Bot(Other),false);
00463		}
00464			
00465		if ( Other.bIsPlayer && (Killer != None) && Killer.bIsPlayer && (Killer != Other) 
00466			&& (!bTeamGame || (Other.PlayerReplicationInfo.Team != Killer.PlayerReplicationInfo.Team)) )
00467		{
00468			Killer.Spree++;
00469			if ( Killer.Spree > 4 )
00470				NotifySpree(Killer, Killer.Spree);
00471		} 
00472	
00473		bAutoTaunt = ((TournamentPlayer(Killer) != None) && TournamentPlayer(Killer).bAutoTaunt);
00474		if ( ((Bot(Killer) != None) || bAutoTaunt)
00475			&& (Killer != Other) && (DamageType != 'gibbed') && (Killer.Health > 0)
00476			&& (Level.TimeSeconds - LastTauntTime > 3) )
00477		{
00478			LastTauntTime = Level.TimeSeconds;
00479			NextTaunt = Rand(class<ChallengeVoicePack>(Killer.PlayerReplicationInfo.VoiceType).Default.NumTaunts);
00480			for ( i=0; i<4; i++ )
00481			{
00482				if ( NextTaunt == LastTaunt[i] )
00483					NextTaunt = Rand(class<ChallengeVoicePack>(Killer.PlayerReplicationInfo.VoiceType).Default.NumTaunts);
00484				if ( i > 0 )
00485					LastTaunt[i-1] = LastTaunt[i];
00486			}	
00487			LastTaunt[3] = NextTaunt;
00488	 		killer.SendGlobalMessage(None, 'AUTOTAUNT', NextTaunt, 5);
00489		}
00490		if ( bRatedGame )
00491			RateVs(Other, Killer);
00492	}
00493	
00494	event playerpawn Login
00495	(
00496		string Portal,
00497		string Options,
00498		out string Error,
00499		class<playerpawn> SpawnClass
00500	)
00501	{
00502		local playerpawn NewPlayer;
00503	
00504		if ( (Level.NetMode != NM_Standalone) && (NumCommanders >= MaxCommanders) && ClassIsChildOf(SpawnClass, class'Commander') )
00505		{
00506			Error="Max commanders "$MaxCommanders$" exceeded";
00507			return None;
00508		}
00509	
00510		NewPlayer = Super.Login(Portal, Options, Error, SpawnClass);
00511	
00512		if ( NewPlayer != None )
00513		{
00514			if ( bRatedGame )
00515				NewPlayer.AirControl = 0.35;
00516			else
00517				NewPlayer.AirControl = AirControl;
00518			if ( Left(NewPlayer.PlayerReplicationInfo.PlayerName, 6) == DefaultPlayerName )
00519			{
00520				if (Level.Game.WorldLog != None)
00521					Level.Game.WorldLog.LogSpecialEvent("forced_name_change", NewPlayer.PlayerReplicationInfo.PlayerName, NewPlayer.PlayerReplicationInfo.PlayerID, DefaultPlayerName$NumPlayers);
00522				ChangeName( NewPlayer, (DefaultPlayerName$NumPlayers), false );
00523			}
00524			NewPlayer.bAutoActivate = true;
00525			if ( (bGameEnded || (bRequireReady && (CountDown > 0))) && !NewPlayer.IsA('Spectator') )
00526				NewPlayer.PlayerRestartState = 'PlayerWaiting';
00527			else
00528				NewPlayer.PlayerRestartState = NewPlayer.Default.PlayerRestartState;
00529	
00530			if ( NewPlayer.IsA('TournamentPlayer') )
00531			{
00532				TournamentPlayer(NewPlayer).StartSpot = LastStartSpot;
00533				if ( NewPlayer.IsA('Commander') )
00534					NumCommanders++;
00535			}
00536		}
00537		return NewPlayer;
00538	}
00539	
00540	event PostLogin( playerpawn NewPlayer )
00541	{
00542		Super.PostLogin(NewPlayer);
00543		if ( Level.NetMode == NM_Standalone )
00544		{
00545			while ( (RemainingBots > 0) && AddBot() )
00546				RemainingBots--;
00547		}
00548		else
00549			RemainingBots = 0;
00550	
00551		if ( !bRatedGame )
00552		{
00553			PlayStartUpMessage(NewPlayer);
00554			NewPlayer.SetProgressTime(6);
00555		}
00556	}
00557	
00558	function int ReduceDamage(int Damage, name DamageType, pawn injured, pawn instigatedBy)
00559	{
00560		if (injured.Region.Zone.bNeutralZone)
00561			return 0;
00562	
00563		if ( instigatedBy == None)
00564			return Damage;
00565	
00566		if ( bHardCoreMode )
00567			Damage *= 1.5;
00568		if ( bNoviceMode && !bThreePlus )
00569		{
00570			if ( instigatedBy.bIsPlayer && (injured == instigatedby) && (Level.NetMode == NM_Standalone) )
00571				Damage *= 0.5;
00572	
00573			//skill level modification
00574			if ( instigatedBy.IsA('Bot') && injured.IsA('PlayerPawn') )
00575			{
00576				if ( ((instigatedBy.Weapon != None) && instigatedBy.Weapon.bMeleeWeapon) 
00577					|| ((injured.Weapon != None) && injured.Weapon.bMeleeWeapon && (VSize(injured.location - instigatedBy.Location) < 600)) )
00578					Damage = Damage * (0.76 + 0.08 * instigatedBy.skill);
00579				else
00580					Damage = Damage * (0.25 + 0.15 * instigatedBy.skill);
00581			}
00582		}
00583		return (Damage * instigatedBy.DamageScaling);
00584	}
00585	
00586	function StartMatch()
00587	{	
00588		local Pawn P;
00589		local TimedTrigger T;
00590	
00591		if (LocalLog != None)
00592			LocalLog.LogGameStart();
00593		if (WorldLog != None)
00594			WorldLog.LogGameStart();
00595	
00596		ForEach AllActors(class'TimedTrigger', T)
00597			T.SetTimer(T.DelaySeconds, T.bRepeating);
00598		if ( Level.NetMode != NM_Standalone )
00599			RemainingBots = 0;
00600		GameReplicationInfo.RemainingMinute = RemainingTime;
00601		bStartMatch = true;
00602	
00603		// start players first (in their current startspots)
00604		for ( P = Level.PawnList; P!=None; P=P.nextPawn )
00605			if ( P.bIsPlayer && P.IsA('PlayerPawn') )
00606			{
00607				if ( bGameEnded ) return; // telefrag ended the game with ridiculous frag limit
00608				else if ( !P.IsA('Spectator')  )
00609				{
00610					P.PlayerRestartState = P.Default.PlayerRestartState;
00611					P.GotoState(P.Default.PlayerRestartState);
00612					if ( !P.IsA('Commander') )
00613						RestartPlayer(P);
00614				}
00615				SendStartMessage(PlayerPawn(P));
00616			}
00617	
00618	
00619		for ( P = Level.PawnList; P!=None; P=P.nextPawn )
00620			if ( P.bIsPlayer && !P.IsA('PlayerPawn') )
00621			{
00622				P.RestartPlayer();
00623				if ( P.IsA('Bot') )
00624					Bot(P).StartMatch();
00625			}
00626		bStartMatch = false;
00627	}
00628	
00629	
00630	function Timer()
00631	{
00632		local Pawn P;
00633		local bool bReady;
00634		local int M;
00635	
00636		Super.Timer();
00637	
00638		if ( bNetReady )
00639		{
00640			if ( NumPlayers > 0 )
00641				ElapsedTime++;
00642			else
00643				ElapsedTime = 0;
00644			if ( ElapsedTime > NetWait )
00645			{
00646				if ( (NumPlayers + NumBots < 4) && NeedPlayers() )
00647					AddBot();
00648				else if ( (NumPlayers + NumBots > 1) || ((NumPlayers > 0) && (ElapsedTime > 2 * NetWait)) )
00649					bNetReady = false;
00650			}
00651	
00652			if ( bNetReady )
00653			{
00654				for (P=Level.PawnList; P!=None; P=P.NextPawn )
00655					if ( P.IsA('PlayerPawn') )
00656						PlayerPawn(P).SetProgressTime(2);
00657				return;
00658			}
00659			else
00660			{
00661				while ( NeedPlayers() )
00662					AddBot();
00663				bRequireReady = false;
00664				StartMatch();
00665			}
00666		}
00667	
00668		if ( bRequireReady && (CountDown > 0) )
00669		{
00670			while ( (RemainingBots > 0) && AddBot() )
00671				RemainingBots--;
00672			for (P=Level.PawnList; P!=None; P=P.NextPawn )
00673				if ( P.IsA('PlayerPawn') )
00674					PlayerPawn(P).SetProgressTime(2);
00675			if ( ((NumPlayers == MaxPlayers) || (Level.NetMode == NM_Standalone)) 
00676					&& (RemainingBots <= 0) )
00677			{	
00678				bReady = true;
00679				for (P=Level.PawnList; P!=None; P=P.NextPawn )
00680					if ( P.IsA('PlayerPawn') && !P.IsA('Spectator')
00681						&& !PlayerPawn(P).bReadyToPlay )
00682						bReady = false;
00683				
00684				if ( bReady )
00685				{	
00686					StartCount = 30;
00687					CountDown--;
00688					if ( CountDown <= 0 )
00689						StartMatch();
00690					else
00691					{
00692						for ( P = Level.PawnList; P!=None; P=P.nextPawn )
00693							if ( P.IsA('PlayerPawn') )
00694							{
00695								PlayerPawn(P).ClearProgressMessages();
00696								if ( (CountDown < 11) && P.IsA('TournamentPlayer') )
00697									TournamentPlayer(P).TimeMessage(CountDown);
00698								else
00699									PlayerPawn(P).SetProgressMessage(CountDown$CountDownMessage, 0);
00700							}
00701					}
00702				}
00703				else if ( StartCount > 8 ) 
00704				{
00705					for ( P = Level.PawnList; P!=None; P=P.nextPawn )
00706						if ( P.IsA('PlayerPawn') )
00707						{
00708							PlayerPawn(P).ClearProgressMessages();
00709							PlayerPawn(P).SetProgressTime(2);
00710							PlayerPawn(P).SetProgressMessage(WaitingMessage1, 0);
00711							PlayerPawn(P).SetProgressMessage(WaitingMessage2, 1);
00712							if ( PlayerPawn(P).bReadyToPlay )
00713								PlayerPawn(P).SetProgressMessage(ReadyMessage, 2);
00714							else
00715								PlayerPawn(P).SetProgressMessage(NotReadyMessage, 2);
00716						}
00717				}
00718				else
00719				{
00720					StartCount++;
00721					if ( Level.NetMode != NM_Standalone )
00722						StartCount = 30;
00723				}
00724			}
00725			else
00726			{
00727				for ( P = Level.PawnList; P!=None; P=P.nextPawn )
00728					if ( P.IsA('PlayerPawn') )
00729						PlayStartupMessage(PlayerPawn(P));
00730			}
00731		}	
00732		else
00733		{
00734			if ( bAlwaysForceRespawn || (bForceRespawn && (Level.NetMode != NM_Standalone)) )
00735				For ( P=Level.PawnList; P!=None; P=P.NextPawn )
00736				{
00737					if ( P.IsInState('Dying') && P.IsA('PlayerPawn') && P.bHidden )
00738						PlayerPawn(P).ServerReStartPlayer();
00739				}
00740			if ( Level.NetMode != NM_Standalone )
00741			{
00742				if ( NeedPlayers() )
00743					AddBot();
00744			}
00745			else
00746				while ( (RemainingBots > 0) && AddBot() )
00747					RemainingBots--;
00748			if ( bGameEnded )
00749			{
00750				if ( Level.TimeSeconds > EndTime + RestartWait )
00751					RestartGame();
00752			}
00753			else if ( !bOverTime && (TimeLimit > 0) )
00754			{
00755				GameReplicationInfo.bStopCountDown = false;
00756				RemainingTime--;
00757				GameReplicationInfo.RemainingTime = RemainingTime;
00758				if ( RemainingTime % 60 == 0 )
00759					GameReplicationInfo.RemainingMinute = RemainingTime;
00760				if ( RemainingTime <= 0 )
00761					EndGame("timelimit");
00762			}
00763			else
00764			{
00765				ElapsedTime++;
00766				GameReplicationInfo.ElapsedTime = ElapsedTime;
00767			}
00768		}
00769	}
00770	
00771	function bool TooManyBots()
00772	{
00773		return (NumBots + NumPlayers > MinPlayers);
00774	}
00775	
00776	function bool RestartPlayer( pawn aPlayer )	
00777	{
00778		local Bot B;
00779		local bool bResult;
00780	
00781		aPlayer.DamageScaling = aPlayer.Default.DamageScaling;
00782		B = Bot(aPlayer);
00783		if ( (B != None) 
00784			&& (Level.NetMode != NM_Standalone) 
00785			&& TooManyBots() )
00786		{
00787			aPlayer.Destroy();
00788			return false;
00789		}
00790		bResult = Super.RestartPlayer(aPlayer);
00791		if ( aPlayer.IsA('TournamentPlayer') )
00792			TournamentPlayer(aPlayer).StartSpot = LastStartSpot;
00793		return bResult;
00794	}
00795	
00796	function SendStartMessage(PlayerPawn P)
00797	{
00798		P.ClearProgressMessages();
00799		P.SetProgressMessage(StartMessage, 0);
00800	}
00801	
00802	function Bot SpawnBot(out NavigationPoint StartSpot)
00803	{
00804		local bot NewBot;
00805		local int BotN;
00806		local Pawn P;
00807	
00808		if ( bRatedGame )
00809			return SpawnRatedBot(StartSpot);
00810	
00811		Difficulty = BotConfig.Difficulty;
00812	
00813		if ( Difficulty >= 4 )
00814		{
00815			bNoviceMode = false;
00816			Difficulty = Difficulty - 4;
00817		}
00818		else
00819		{
00820			if ( Difficulty > 3 )
00821			{
00822				Difficulty = 3;
00823				bThreePlus = true;
00824			}
00825			bNoviceMode = true;
00826		}
00827		BotN = BotConfig.ChooseBotInfo();
00828		
00829		// Find a start spot.
00830		StartSpot = FindPlayerStart(None, 255);
00831		if( StartSpot == None )
00832		{
00833			log("Could not find starting spot for Bot");
00834			return None;
00835		}
00836	
00837		// Try to spawn the bot.
00838		NewBot = Spawn(BotConfig.CHGetBotClass(BotN),,,StartSpot.Location,StartSpot.Rotation);
00839	
00840		if ( NewBot == None )
00841			log("Couldn't spawn player at "$StartSpot);
00842	
00843		if ( (bHumansOnly || Level.bHumansOnly) && !NewBot.bIsHuman )
00844		{
00845			log("can't add non-human bot to this game");
00846			NewBot.Destroy();
00847			NewBot = None;
00848		}
00849	
00850		if ( NewBot == None )
00851			NewBot = Spawn(BotConfig.CHGetBotClass(0),,,StartSpot.Location,StartSpot.Rotation);
00852	
00853		if ( NewBot != None )
00854		{
00855			// Set the player's ID.
00856			NewBot.PlayerReplicationInfo.PlayerID = CurrentID++;
00857	
00858			NewBot.PlayerReplicationInfo.Team = BotConfig.GetBotTeam(BotN);
00859			BotConfig.CHIndividualize(NewBot, BotN, NumBots);
00860			NewBot.ViewRotation = StartSpot.Rotation;
00861			// broadcast a welcome message.
00862			BroadcastMessage( NewBot.PlayerReplicationInfo.PlayerName$EnteredMessage, false );
00863	
00864			ModifyBehaviour(NewBot);
00865			AddDefaultInventory( NewBot );
00866			NumBots++;
00867			if ( bRequireReady && (CountDown > 0) )
00868				NewBot.GotoState('Dying', 'WaitingForStart');
00869			NewBot.AirControl = AirControl;
00870	
00871			if ( (Level.NetMode != NM_Standalone) && (bNetReady || bRequireReady) )
00872			{
00873				// replicate skins
00874				for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00875					if ( P.bIsPlayer && (P.PlayerReplicationInfo != None) && P.PlayerReplicationInfo.bWaitingPlayer && P.IsA('PlayerPawn') )
00876					{
00877						if ( NewBot.bIsMultiSkinned )
00878							PlayerPawn(P).ClientReplicateSkins(NewBot.MultiSkins[0], NewBot.MultiSkins[1], NewBot.MultiSkins[2], NewBot.MultiSkins[3]);
00879						else
00880							PlayerPawn(P).ClientReplicateSkins(NewBot.Skin);	
00881					}						
00882			}
00883		}
00884	
00885		return NewBot;
00886	}
00887	
00888	
00889	function Bot SpawnRatedBot(out NavigationPoint StartSpot)
00890	{
00891		local bot NewBot;
00892		local int BotN;
00893		local bool bEnemy;
00894	
00895		if (RemainingBots > RatedMatchConfig.NumAllies)
00896			bEnemy = True;
00897	
00898		BotN = RatedMatchConfig.ChooseBotInfo(bTeamGame, bEnemy);
00899		
00900		// Find a start spot.
00901		StartSpot = FindPlayerStart(None, 255);
00902		if( StartSpot == None )
00903		{
00904			log("Could not find starting spot for Bot");
00905			return None;
00906		}
00907	
00908		// Try to spawn the bot.
00909		NewBot = Spawn(RatedMatchConfig.GetBotClass(BotN, bTeamGame, bEnemy, RatedPlayer),,,StartSpot.Location,StartSpot.Rotation);
00910		if ( NewBot == None )
00911			log("Couldn't spawn player at "$StartSpot);
00912	
00913		if ( NewBot != None )
00914		{
00915			// Set the player's ID.
00916			NewBot.PlayerReplicationInfo.PlayerID = CurrentID++;
00917		
00918			RatedMatchConfig.Individualize(NewBot, BotN, NumBots, bTeamGame, bEnemy);
00919			NewBot.ViewRotation = StartSpot.Rotation;
00920			// broadcast a welcome message.
00921			BroadcastMessage( NewBot.PlayerReplicationInfo.PlayerName$EnteredMessage, false );
00922	
00923			ModifyBehaviour(NewBot);
00924			AddDefaultInventory( NewBot );
00925			NumBots++;
00926			if ( bRequireReady && (CountDown > 0) )
00927				NewBot.GotoState('Dying', 'WaitingForStart');
00928			NewBot.AirControl = 0.35;
00929		}
00930	
00931		return NewBot;
00932	}
00933	
00934	function bool ForceAddBot()
00935	{
00936		// add bot during gameplay
00937		if ( Level.NetMode != NM_Standalone )
00938			MinPlayers = Max(MinPlayers+1, NumPlayers + NumBots + 1);
00939		AddBot();
00940	}
00941			
00942	function bool AddBot()
00943	{
00944		local bot NewBot;
00945		local NavigationPoint StartSpot;
00946	
00947		NewBot = SpawnBot(StartSpot);
00948		if ( NewBot == None )
00949		{
00950			log("Failed to spawn bot.");
00951			return false;
00952		}
00953	
00954		StartSpot.PlayTeleportEffect(NewBot, true);
00955	
00956		NewBot.PlayerReplicationInfo.bIsABot = True;
00957	
00958		// Log it.
00959		if (LocalLog != None)
00960		{
00961			LocalLog.LogPlayerConnect(NewBot);
00962			LocalLog.FlushLog();
00963		}
00964		if (WorldLog != None)
00965		{
00966			WorldLog.LogPlayerConnect(NewBot);
00967			WorldLog.FlushLog();
00968		}
00969	
00970		return true;
00971	}
00972	
00973	function ModifyBehaviour(Bot NewBot);
00974	
00975	function PlayStartUpMessage(PlayerPawn NewPlayer)
00976	{
00977		local int i;
00978	
00979		NewPlayer.ClearProgressMessages();
00980	
00981		// Game Name
00982		NewPlayer.SetProgressMessage(GameName, i++);
00983	
00984		// Optional FragLimit
00985		if ( fraglimit > 0 )
00986			NewPlayer.SetProgressMessage(FragLimit@GameGoal, i++);
00987	
00988		if ( Level.NetMode == NM_Standalone )
00989			NewPlayer.SetProgressMessage(SingleWaitingMessage, i++);
00990		else if ( bRequireReady )
00991			NewPlayer.SetProgressMessage(TourneyMessage, i++);
00992	}
00993	
00994	function float PlayerJumpZScaling()
00995	{
00996		if ( bJumpMatch )
00997			return 3;
00998		else if ( bMegaSpeed )
00999			return 1.2;
01000		else if ( bHardCoreMode )
01001			return 1.1;
01002		else
01003			return 1.0;
01004	}
01005	
01006	function AddDefaultInventory( pawn PlayerPawn )
01007	{
01008		local Weapon NewWeapon;
01009		local Bot B;
01010	
01011		if ( PlayerPawn.IsA('Spectator') || (bRequireReady && (CountDown > 0)) )
01012			return;
01013	
01014		// Spawn Automag
01015		GiveWeapon(PlayerPawn, "Botpack.Enforcer");
01016	
01017		Super.AddDefaultInventory(PlayerPawn);
01018	
01019		if ( bUseTranslocator && (!bRatedGame || bRatedTranslocator) )
01020		{
01021			// Spawn Translocator.
01022			if( PlayerPawn.FindInventoryType(class'Translocator')==None )
01023			{
01024				newWeapon = Spawn(class'Translocator');
01025				if( newWeapon != None )
01026				{
01027					newWeapon.Instigator = PlayerPawn;
01028					newWeapon.BecomeItem();
01029					PlayerPawn.AddInventory(newWeapon);
01030					newWeapon.GiveAmmo(PlayerPawn);
01031					newWeapon.SetSwitchPriority(PlayerPawn);
01032					newWeapon.WeaponSet(PlayerPawn);
01033				}
01034			}
01035		}
01036	
01037		B = Bot(PlayerPawn);
01038		if ( B != None )
01039			B.bHasImpactHammer = (B.FindInventoryType(class'ImpactHammer') != None);
01040	}	
01041	
01042	function GiveWeapon(Pawn PlayerPawn, string aClassName )
01043	{
01044		local class<Weapon> WeaponClass;
01045		local Weapon NewWeapon;
01046	
01047		WeaponClass = class<Weapon>(DynamicLoadObject(aClassName, class'Class'));
01048	
01049		if( PlayerPawn.FindInventoryType(WeaponClass) != None )
01050			return;
01051		newWeapon = Spawn(WeaponClass);
01052		if( newWeapon != None )
01053		{
01054			newWeapon.RespawnTime = 0.0;
01055			newWeapon.GiveTo(PlayerPawn);
01056			newWeapon.bHeldItem = true;
01057			newWeapon.GiveAmmo(PlayerPawn);
01058			newWeapon.SetSwitchPriority(PlayerPawn);
01059			newWeapon.WeaponSet(PlayerPawn);
01060			newWeapon.AmbientGlow = 0;
01061			if ( PlayerPawn.IsA('PlayerPawn') )
01062				newWeapon.SetHand(PlayerPawn(PlayerPawn).Handedness);
01063			else
01064				newWeapon.GotoState('Idle');
01065			PlayerPawn.Weapon.GotoState('DownWeapon');
01066			PlayerPawn.PendingWeapon = None;
01067			PlayerPawn.Weapon = newWeapon;
01068		}
01069	}
01070		
01071	function byte AssessBotAttitude(Bot aBot, Pawn Other)
01072	{
01073		local float skillmod;
01074	
01075		if ( bNoviceMode )
01076			skillmod = 0.3;
01077		else
01078			skillmod = 0.2 - aBot.skill * 0.06;
01079		if ( aBot.bKamikaze )
01080			return 1;
01081		else if ( Other.IsA('TeamCannon') 
01082			|| (aBot.RelativeStrength(Other) > aBot.Aggressiveness + skillmod) )
01083			return 0;
01084		else
01085			return 1;
01086	}
01087	
01088	function float GameThreatAdd(Bot aBot, Pawn Other)
01089	{
01090		return 0;
01091	}
01092	
01093	// AllowTranslocation - return true if Other can teleport to Dest
01094	function bool AllowTranslocation(Pawn Other, vector Dest )
01095	{
01096		return true;
01097	}
01098	
01099	function bool CanTranslocate(Bot aBot)
01100	{
01101		if ( !bUseTranslocator || (bRatedGame && !bRatedTranslocator) )
01102			return false;
01103		return ( (aBot.MyTranslocator != None) && (aBot.MyTranslocator.TTarget == None) );
01104	} 
01105	
01106	function PickAmbushSpotFor(Bot aBot)
01107	{
01108		local NavigationPoint N;
01109	
01110		for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
01111			if ( N.IsA('Ambushpoint') && !N.taken 
01112				&& ((aBot.AmbushSpot == None)
01113					|| (VSize(aBot.Location - aBot.Ambushspot.Location)
01114						 > VSize(aBot.Location - N.Location))) )
01115					aBot.Ambushspot = Ambushpoint(N);
01116	}
01117	
01118	function RateVs(Pawn Other, Pawn Killer)
01119	{
01120		local int numopp, Win;
01121		local float oppRating, K, We;
01122		Local PlayerPawn P;
01123		Local Bot B;
01124	
01125		if ( Killer.IsA('PlayerPawn') )
01126		{
01127			P = PlayerPawn(Killer);
01128			B = Bot(Other);
01129			Win = 1;
01130			WinCount++;
01131		}
01132		else if ( Other.IsA('PlayerPawn') )
01133		{
01134			LoseCount++;
01135			P = PlayerPawn(Other);
01136			B = Bot(Killer);
01137		}
01138		else
01139			return;
01140	
01141		if ( B == None )
01142			oppRating = PlayerRating - 400;
01143		else
01144			oppRating = FMin(B.GetRating(), PlayerRating + 400);
01145	
01146		numopp++;
01147		AvgOpponentRating = (AvgOpponentRating * (numopp - 1) + oppRating)/numopp;  	
01148		if ( numopp < 20 )
01149		{
01150			PlayerRating = AvgOpponentRating + 400 * (WinCount - LoseCount)/numopp;			
01151		}
01152		else
01153		{
01154			if ( oppRating < PlayerRating - 400 )
01155				return;
01156			
01157			if ( PlayerRating < 2100 )
01158				K = 32;
01159			else if ( PlayerRating < 2400 )
01160				K = 24;
01161			else 
01162				K = 16; 
01163	
01164			We = 1/(10^((PlayerRating - opprating)/400) + 1);
01165			PlayerRating = PlayerRating + K * (Win - We);
01166	
01167			/* FOLLOWING NOT DONE - do at end of level FIXME
01168			Pre-tournament Rating Post-tournament Rating   
01169			0-2099  2100-2399 Ra = 2100 + (Rn-2100) x 0.75  
01170			2100-2399 0-2099  Ra = 2100 + (Rn-2100) x 1.33  
01171			2100-2399 2400-3000 Ra = 2400 + (Rn-2400) x 0.66  
01172			2400-3000  2100-2399  Ra = 2400 + (Rn-2400) x 1.50 
01173			*/
01174		}
01175	}
01176	
01177	function bool SuccessfulGame()
01178	{
01179		local Pawn P;
01180	
01181		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
01182			if ( P.bIsPlayer && (P != RatedPlayer) )
01183				if ( P.PlayerReplicationInfo.Score >= RatedPlayer.PlayerReplicationInfo.Score )
01184					return false;
01185	
01186		return true;
01187	}
01188	
01189	
01190	// Commented out for release version.
01191	function Skip()
01192	{
01193		if (bRatedGame)
01194		{
01195			RatedGameLadderObj.LastMatchType = LadderTypeIndex;
01196			RatedGameLadderObj.PendingChange = LadderTypeIndex;
01197			if (IDnum < RatedGameLadderObj.CurrentLadder.Default.Matches-1)
01198				RatedGameLadderObj.PendingPosition = IDnum+1;
01199			RatedGameLadderObj.PendingRank = RatedGameLadderObj.CurrentLadder.Default.RankedGame[IDnum];
01200	
01201			RatedPlayer.ClientTravel("UT-Logo-Map.unr"$"?Game=Botpack.LadderTransition", TRAVEL_Absolute, True);
01202			return;
01203		}
01204	}
01205	
01206	function SkipAll()
01207	{
01208		if (bRatedGame)
01209		{
01210			RatedGameLadderObj.DMPosition = class'LadderDMGOTY'.Default.Matches - 1;
01211			RatedGameLadderObj.DMRank = 6;
01212			RatedGameLadderObj.DOMPosition = class'LadderDOM'.Default.Matches - 1;
01213			RatedGameLadderObj.DOMRank = 6;
01214			RatedGameLadderObj.CTFPosition = class'LadderCTFGOTY'.Default.Matches - 1;
01215			RatedGameLadderObj.CTFRank = 6;
01216			RatedGameLadderObj.ASPosition = class'LadderAS'.Default.Matches - 1;
01217			RatedGameLadderObj.ASRank = 6;
01218			RatedGameLadderObj.ChalPosition = class'LadderChal'.Default.Matches - 1;
01219			RatedGameLadderObj.ChalRank = 6;
01220	
01221			RatedGameLadderObj.LastMatchType = LadderTypeIndex;
01222			RatedGameLadderObj.PendingChange = LadderTypeIndex;
01223			RatedGameLadderObj.PendingPosition = 0;
01224			RatedGameLadderObj.PendingRank = 0;
01225	
01226			RatedPlayer.ClientTravel("UT-Logo-Map.unr"$"?Game=Botpack.LadderTransition", TRAVEL_Absolute, True);
01227			return;
01228		}
01229	}
01230	
01231	function bool CanSpectate( pawn Viewer, actor ViewTarget )
01232	{
01233		if ( ViewTarget.bIsPawn && (Pawn(ViewTarget).PlayerReplicationInfo != None)
01234			&& Pawn(ViewTarget).PlayerReplicationInfo.bIsSpectator )
01235			return false;
01236		return ( (!bRatedGame && (Level.NetMode == NM_Standalone)) || Viewer.PlayerReplicationInfo.bIsSpectator );
01237	}
01238	
01239	function bool ShouldRespawn(Actor Other)
01240	{
01241		return ( (Inventory(Other) != None) && (Inventory(Other).ReSpawnTime!=0.0) );
01242	}
01243	
01244	function ChangeName(Pawn Other, string S, bool bNameChange)
01245	{
01246		local pawn APlayer;
01247	
01248		if ( S == "" )
01249			return;
01250	
01251		if (Other.PlayerReplicationInfo.PlayerName~=S)
01252			return;
01253		
01254		APlayer = Level.PawnList;
01255		
01256		While ( APlayer != None )
01257		{	
01258			if ( APlayer.bIsPlayer && (APlayer.PlayerReplicationInfo.PlayerName~=S) )
01259			{
01260				Other.ClientMessage(S$NoNameChange);
01261				return;
01262			}
01263			APlayer = APlayer.NextPawn;
01264		}
01265	
01266		Other.PlayerReplicationInfo.OldName = Other.PlayerReplicationInfo.PlayerName;
01267		Other.PlayerReplicationInfo.PlayerName = S;
01268		if ( bNameChange )
01269			BroadcastLocalizedMessage( DMMessageClass, 2, Other.PlayerReplicationInfo );			
01270	
01271		if (LocalLog != None)
01272			LocalLog.LogNameChange(Other);
01273		if (WorldLog != None)
01274			WorldLog.LogNameChange(Other);
01275	}
01276	
01277	/* FindPlayerStart()
01278	returns the 'best' player start for this player to start from.
01279	Re-implement for each game type
01280	*/
01281	function NavigationPoint FindPlayerStart(Pawn Player, optional byte InTeam, optional string incomingName)
01282	{
01283		local PlayerStart Dest, Candidate[16], Best;
01284		local float Score[16], BestScore, NextDist;
01285		local pawn OtherPlayer;
01286		local int i, num;
01287		local Teleporter Tel;
01288		local NavigationPoint N, LastPlayerStartSpot;
01289	
01290		if ( bStartMatch && (Player != None) && Player.IsA('TournamentPlayer') 
01291			&& (Level.NetMode == NM_Standalone)
01292			&& (TournamentPlayer(Player).StartSpot != None) )
01293			return TournamentPlayer(Player).StartSpot;
01294	
01295		if( incomingName!="" )
01296			foreach AllActors( class 'Teleporter', Tel )
01297				if( string(Tel.Tag)~=incomingName )
01298					return Tel;
01299	
01300		//choose candidates	
01301		for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
01302		{
01303			Dest = PlayerStart(N);
01304			if ( (Dest != None) && Dest.bEnabled && !Dest.Region.Zone.bWaterZone )
01305			{
01306				if (num<16)
01307					Candidate[num] = Dest;
01308				else if (Rand(num) < 16)
01309					Candidate[Rand(16)] = Dest;
01310				num++;
01311			}
01312		}
01313	
01314		if (num == 0 )
01315			foreach AllActors( class 'PlayerStart', Dest )
01316			{
01317				if (num<16)
01318					Candidate[num] = Dest;
01319				else if (Rand(num) < 16)
01320					Candidate[Rand(16)] = Dest;
01321				num++;
01322			}
01323	
01324		if (num>16) num = 16;
01325		else if (num == 0)
01326			return None;
01327	
01328		if ( (Player != None) && Player.IsA('TournamentPlayer') 
01329			&& (TournamentPlayer(Player).StartSpot != None) )
01330			LastPlayerStartSpot = TournamentPlayer(Player).StartSpot;
01331	
01332		//assess candidates
01333		for (i=0;i<num;i++)
01334		{
01335			if ( (Candidate[i] == LastStartSpot) || (Candidate[i] == LastPlayerStartSpot) )
01336				Score[i] = -10000.0;
01337			else
01338				Score[i] = 3000 * FRand(); //randomize
01339		}		
01340		for ( OtherPlayer=Level.PawnList; OtherPlayer!=None; OtherPlayer=OtherPlayer.NextPawn)	
01341			if ( OtherPlayer.bIsPlayer && (OtherPlayer.Health > 0) && !OtherPlayer.IsA('Spectator') )
01342				for ( i=0; i<num; i++ )
01343				{
01344					if ( OtherPlayer.Region.Zone == Candidate[i].Region.Zone )
01345					{
01346						Score[i] -= 1500;
01347						NextDist = VSize(OtherPlayer.Location - Candidate[i].Location);
01348						if ( NextDist < OtherPlayer.CollisionRadius + OtherPlayer.CollisionHeight )
01349							Score[i] -= 1000000.0;
01350						else if ( (NextDist < 2000) && FastTrace(Candidate[i].Location, OtherPlayer.Location) )
01351							Score[i] -= (10000.0 - NextDist);
01352					}
01353					else if ( NumPlayers + NumBots == 2 )
01354					{
01355						Score[i] += 2 * VSize(OtherPlayer.Location - Candidate[i].Location);
01356						if ( FastTrace(Candidate[i].Location, OtherPlayer.Location) )
01357							Score[i] -= 10000;
01358					}
01359				}
01360		
01361		BestScore = Score[0];
01362		Best = Candidate[0];
01363		for (i=1;i<num;i++)
01364			if (Score[i] > BestScore)
01365			{
01366				BestScore = Score[i];
01367				Best = Candidate[i];
01368			}
01369	
01370		LastStartSpot = Best;
01371		return Best;
01372	}
01373	
01374	function Logout(pawn Exiting)
01375	{
01376		Super.Logout(Exiting);
01377		if ( Exiting.IsA('Bot') )
01378			NumBots--;
01379		if ( Exiting.IsA('Commander') )
01380			NumCommanders--;
01381		if ( (Level.NetMode != NM_Standalone) && NeedPlayers() && !AddBot() )
01382			RemainingBots++;
01383	}
01384	
01385	function bool NeedPlayers()
01386	{
01387		return (!bGameEnded && (NumPlayers + NumBots < MinPlayers));
01388	}
01389	
01390	function RestartGame()
01391	{
01392		local string NextMap;
01393		local MapList myList;
01394	
01395		// multipurpose don't restart variable
01396		if ( bDontRestart )
01397			return;
01398	
01399		if ( EndTime > Level.TimeSeconds ) // still showing end screen
01400			return;
01401	
01402		// Evaluate a rated game.
01403		if ( bRatedGame )
01404		{
01405			// Clear out the advancement fields.
01406			RatedGameLadderObj.PendingPosition = 0;
01407			RatedGameLadderObj.PendingRank = 0;
01408			RatedGameLadderObj.PendingChange = 0;
01409	
01410			// Setup advancement.
01411			RatedGameLadderObj.LastMatchType = LadderTypeIndex;
01412			if ( SuccessfulGame() )
01413			{
01414				RatedGameLadderObj.PendingChange = LadderTypeIndex;
01415				if (IDnum < RatedGameLadderObj.CurrentLadder.Default.Matches-1)
01416					RatedGameLadderObj.PendingPosition = IDnum+1;	// We are advancing to the next match.
01417				RatedGameLadderObj.PendingRank = RatedGameLadderObj.CurrentLadder.Default.RankedGame[IDnum];
01418			}
01419	
01420			RatedPlayer.Health = RatedPlayer.Default.Health;
01421			RatedPlayer.ClientTravel("UT-Logo-Map.unr"$"?Game=Botpack.LadderTransition", TRAVEL_Absolute, True);
01422			return;
01423		}
01424	
01425		// these server travels should all be relative to the current URL
01426		if ( bChangeLevels && !bAlreadyChanged && (MapListType != None) )
01427		{
01428			// open a the nextmap actor for this game type and get the next map
01429			bAlreadyChanged = true;
01430			myList = spawn(MapListType);
01431			NextMap = myList.GetNextMap();
01432			myList.Destroy();
01433			if ( NextMap == "" )
01434				NextMap = GetMapName(MapPrefix, NextMap,1);
01435	
01436			if ( NextMap != "" )
01437			{
01438				Level.ServerTravel(NextMap, false);
01439				return;
01440			}
01441		}
01442	
01443		Level.ServerTravel("?Restart" , false);
01444	}
01445	
01446	function LogGameParameters(StatLog StatLog)
01447	{
01448		local bool bTemp;
01449	
01450		if (StatLog == None)
01451			return;
01452	
01453		// hack to make sure weapon stay logging is correct for multiplayer games
01454		bTemp = bCoopWeaponMode;
01455		if ( Level.Netmode != NM_Standalone )
01456			bCoopWeaponMode = bMultiWeaponStay;	
01457		Super.LogGameParameters(StatLog);
01458		bCoopWeaponMode = bTemp;
01459	
01460		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"FragLimit"$Chr(9)$FragLimit);
01461		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"TimeLimit"$Chr(9)$TimeLimit);
01462		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MultiPlayerBots"$Chr(9)$(MinPlayers > 0));
01463		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"HardCore"$Chr(9)$bHardCoreMode);
01464		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MegaSpeed"$Chr(9)$bMegaSpeed);
01465		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"AirControl"$Chr(9)$AirControl);
01466		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"JumpMatch"$Chr(9)$bJumpMatch);
01467		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"UseTranslocator"$Chr(9)$bUseTranslocator);
01468		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"TournamentMode"$Chr(9)$bTournament);
01469		if (Level.NetMode == NM_DedicatedServer)
01470			StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NetMode"$Chr(9)$"DedicatedServer");
01471		else if (Level.NetMode == NM_ListenServer)
01472			StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NetMode"$Chr(9)$"ListenServer");
01473		else if (Level.NetMode == NM_Standalone)
01474		{
01475			if (bRatedGame)
01476				StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NetMode"$Chr(9)$"SinglePlayer");
01477			else
01478				StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NetMode"$Chr(9)$"PracticeMatch");
01479		}
01480	}
01481	
01482	//------------------------------------------------------------------------------
01483	// Game Querying.
01484	
01485	function string GetRules()
01486	{
01487		local string ResultSet;
01488		ResultSet = Super.GetRules();
01489	
01490		ResultSet = ResultSet$"\\timelimit\\"$TimeLimit;
01491		ResultSet = ResultSet$"\\fraglimit\\"$FragLimit;
01492		Resultset = ResultSet$"\\minplayers\\"$MinPlayers;
01493		Resultset = ResultSet$"\\changelevels\\"$bChangeLevels;
01494		Resultset = ResultSet$"\\tournament\\"$bTournament;
01495		if(bMegaSpeed)
01496			Resultset = ResultSet$"\\gamestyle\\Turbo";
01497		else
01498		if(bHardcoreMode)
01499			Resultset = ResultSet$"\\gamestyle\\Hardcore";
01500		else
01501			Resultset = ResultSet$"\\gamestyle\\Classic";
01502	
01503		if(MinPlayers > 0)
01504			Resultset = ResultSet$"\\botskill\\"$class'ChallengeBotInfo'.default.Skills[Difficulty];
01505	
01506		return ResultSet;
01507	}
01508	
01509	function InitGameReplicationInfo()
01510	{
01511		Super.InitGameReplicationInfo();
01512	
01513		TournamentGameReplicationInfo(GameReplicationInfo).FragLimit = FragLimit;
01514		TournamentGameReplicationInfo(GameReplicationInfo).TimeLimit = TimeLimit;
01515	}
01516	
01517	function bool CheckThisTranslocator(Bot aBot, TranslocatorTarget T)
01518	{
01519		return false;
01520	}
01521	
01522	function bool OneOnOne()
01523	{
01524		return ( NumPlayers + NumBots == 2 );
01525	}
01526	
01527	function float SpawnWait(bot B)
01528	{
01529		if ( bRatedGame && bNoviceMode && !bTeamGame && (Difficulty <= 2) 
01530			&& (NumBots > 1)
01531			&& (B.PlayerReplicationInfo.Score > RatedPlayer.PlayerReplicationInfo.Score) )
01532			return ( 7 + NumBots * FRand() );
01533		return ( NumBots * FRand() );
01534	}
01535		
01536	function bool NeverStakeOut(bot Other)
01537	{
01538		return false;
01539	}
01540	
01541	defaultproperties
01542	{
01543	     MinPlayers=6
01544	     AirControl=0.350000
01545	     FragLimit=30
01546	     bChangeLevels=True
01547	     bHardCoreMode=True
01548	     bMultiWeaponStay=True
01549	     NetWait=10
01550	     RestartWait=15
01551	     CountDown=10
01552	     TourneyMessage="Waiting for other players."
01553	     WaitingMessage1="Waiting for ready signals."
01554	     WaitingMessage2="(Use your fire button to toggle ready!)"
01555	     ReadyMessage="You are READY!"
01556	     NotReadyMessage="You are NOT READY!"
01557	     CountDownMessage=" seconds until play starts!"
01558	     StartMessage="The match has begun!"
01559	     GameEndedMessage="wins the match!"
01560	     SingleWaitingMessage="Press Fire to start."
01561	     gamegoal="frags wins the match."
01562	     InitialBots=5
01563	     NoNameChange=" is already in use."
01564	     OvertimeMessage="Score tied at the end of regulation. Sudden Death Overtime!!!"
01565	     BotConfigType=Class'Botpack.ChallengeBotInfo'
01566	     LadderTypeIndex=1
01567	     bRestartLevel=False
01568	     bPauseable=False
01569	     bDeathMatch=True
01570	     ScoreBoardType=Class'Botpack.TournamentScoreBoard'
01571	     BotMenuType="UTMenu.UTBotConfigSClient"
01572	     RulesMenuType="UTMenu.UTRulesSClient"
01573	     SettingsMenuType="UTMenu.UTSettingsSClient"
01574	     GameUMenuType="UTMenu.UTGameMenu"
01575	     MultiplayerUMenuType="UTMenu.UTMultiplayerMenu"
01576	     GameOptionsMenuType="UTMenu.UTOptionsMenu"
01577	     HUDType=Class'Botpack.ChallengeHUD'
01578	     MapListType=Class'Botpack.TDMmaplist'
01579	     MapPrefix="DM"
01580	     BeaconName="DM"
01581	     GameName="Tournament DeathMatch"
01582	     DeathMessageClass=Class'Botpack.DeathMessagePlus'
01583	     DMMessageClass=Class'Botpack.DeathMatchMessage'
01584	     MutatorClass=Class'Botpack.DMMutator'
01585	     GameReplicationInfoClass=Class'Botpack.TournamentGameReplicationInfo'
01586	     bLoggingGame=True
01587	}

End Source Code