Engine
Class GameInfo

source: c:\runehov\Engine\Classes\GameInfo.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.GameInfo
Direct Known Subclasses:RuneGameInfo

class GameInfo
extends Engine.Info

//============================================================================= // GameInfo. // // default game info is normal single player // //=============================================================================
Variables
 string AdminPassword
           Password to receive bAdmin privileges.
 float AutoAim
           How much autoaiming to do (1 = none, 0 = always).
 Mutator BaseMutator
           Identifying string used for finding LAN servers.
 string BeaconName
           Identifying string used for finding LAN servers.
 string BotMenuType
           Type of bot menu to display.
 int CurrentID
           Identifying string used for finding LAN servers.
 class DMMessageClass
           Identifying string used for finding LAN servers.
 Mutator DamageMutator
           linked list of mutators which affect damage
 class DeathMessageClass
           Identifying string used for finding LAN servers.
 float DebrisPercentage
           Percentage of normal debris spawned
 class DefaultPlayerClass
           Scale applied to game rate.
 string DefaultPlayerName
           Identifying string used for finding LAN servers.
 name DefaultPlayerState
           linked list of mutators which affect damage
 class DefaultShield
           Default shield given to player at start
 class DefaultWeapon
           Default weapon given to player at start.
 int DemoBuild
           Does this gametype log?
 int DemoHasTuts
           Does this gametype log?
 byte Difficulty
           0=easy, 1=medium, 2=hard, 3=very hard.
 string EnteredMessage
           Identifying string used for finding LAN servers.
 string FailedPlaceMessage
           Identifying string used for finding LAN servers.
 string FailedSpawnMessage
           Identifying string used for finding LAN servers.
 string FailedTeamMessage
           Identifying string used for finding LAN servers.
 class GameMenuType
           Type of oldstyle game options menu to display.
 string GameName
           Identifying string used for finding LAN servers.
 string GameOptionsMenuType
           Type of options dropdown to display.
 string GamePassword
           Password to enter game.
 GameReplicationInfo GameReplicationInfo
           linked list of mutators which affect damage
 class GameReplicationInfoClass
           linked list of mutators which affect damage
 float GameSpeed
           Scale applied to game rate.
 string GameUMenuType
           Type of Game dropdown to display.
 class HUDType
           HUD class this game uses.
 string IPPolicies[50]
           Identifying string used for finding LAN servers.
 string LeftMessage
           Identifying string used for finding LAN servers.
 StatLog LocalLog
           linked list of mutators which affect damage
 string LocalLogFileName
           Does this gametype log?
 class MapListType
           Maplist this game uses.
 string MapPrefix
           Prefix characters for names of maps for this game type.
 string MaplistMenuType
           Type of maplist menu to display
 int MaxPlayers
           Identifying string used for finding LAN servers.
 int MaxSpectators
           Maximum number of spectators.
 string MultiplayerUMenuType
           Type of Multiplayer dropdown to display.
 class MutatorClass
           Identifying string used for finding LAN servers.
 string MutatorMenuType
           Type of mutator menu to display
 string NameChangedMessage
           Identifying string used for finding LAN servers.
 int NumPlayers
           Identifying string used for finding LAN servers.
 float ParticlePercentage
           Percentage of nomral particles spawned
 string RulesMenuType
           Type of rules menu to display.
 class ScoreBoardType
           Type of scoreboard this game uses.
 KillGoals, SecretGoals
           Special game goals.
 string ServerLogName
           linked list of mutators which affect damage
 string SettingsMenuType
           Type of settings menu to display.
 string SpecialDamageString
           Identifying string used for finding LAN servers.
 float StartTime
           Scale applied to game rate.
 class StatLogClass
           Does this gametype log?
 string SwitchLevelMessage
           Identifying string used for finding LAN servers.
 class WaterZoneType
           linked list of mutators which affect damage
 StatLog WorldLog
           linked list of mutators which affect damage
 string WorldLogFileName
           Does this gametype log?
 bool bAllowFOV
           Allows FOV changes in net games
 bool bAllowLimbSever
           RUNE: Allow arms to be chopped-off
 bool bAllowShieldDrop
           RUNE: Allow shields to be dropped after death
 bool bAllowWeaponDrop
           RUNE: Allow weapons to be dropped after death
 bool bAlternateMode
           This game is some type of deathmatch (where players can respawn during gameplay)
 bool bAutoPickup
           RUNE: Autopickup inventory items
 bool bBatchLocal
           linked list of mutators which affect damage
 bool bClassicDeathmessages
           Weapon deathmessages if false.
 bool bCoopWeaponMode
           Whether or not weapons stay when picked up.
 bool bDeathMatch
           This game is some type of deathmatch (where players can respawn during gameplay)
 bool bHumansOnly
           Whether non human player models are allowed.
 bool bLocalLog
           linked list of mutators which affect damage
 bool bLoggingGame
           Does this gametype log?
 bool bLowGore
           Whether or not to reduce gore.
 bool bMuteSpectators
           Whether spectators are allowed to speak.
 bool bNoCheating
           Disallows cheating. Hehe.
 bool bNoMonsters
           Whether monsters are allowed in this play mode.
 bool bPauseable
           Whether the level is pauseable.
 bool bRestartLevel
           Whether non human player models are allowed.
 bool bSubtitles
           display subtitles
 bool bTeamGame
           This is a teamgame.
 bool bWorldLog
           linked list of mutators which affect damage


Function Summary
 bool AddBot()
     
//
// Add bot to game.
//
 void AddDefaultInventory(Pawn PlayerPawn)
     
//
// Spawn any default inventory for the player.
//
 void AdminLogin(PlayerPawn P, string Password)
     
//------------------------------------------------------------------------------
// Admin
 void AdminLogout(PlayerPawn P)
 bool AllowShieldDrop()
 bool AllowWeaponDrop()
 bool AllowsBroadcast(Actor broadcaster, int Len)
     
//
// Whether players are allowed to broadcast messages now.
//
 bool AtCapacity(string Options)
 void BroadcastRegularDeathMessage(Pawn Killer, Pawn Other, name damageType)
 bool CanSpectate(Pawn Viewer, Actor ViewTarget)
     
//
// Return whether Viewer is allowed to spectate from the
// point of view of ViewTarget.
//
 void ChangeName(Pawn Other, string S, bool bNameChange)
     
//
// Try to change a player's name.
//	
 bool ChangeTeam(Pawn Other, int N)
     
//
// Return whether a team change is allowed.
//
 bool CheckIPPolicy(string Address)
 string CreatureKillMessage(name damageType, Pawn Other)
     
//
// Generate a killed by creature message.
//
 
simulated
Debug(Canvas canvas, int mode)
 void DiscardInventory(Pawn Other)
     
//
// Discard a player's inventory after he dies.
//
 void EndGame(string Reason)
     
//
// End of game.
//
 NavigationPoint FindPlayerStart(Pawn Player, optional byte, optional string)
     
//
// Return the 'best' player start for this player to start from.
// Re-implement for each game type.
//
 bool ForceAddBot()
 string GetInfo()
     
//------------------------------------------------------------------------------
// Game Querying.
 int GetIntOption(string Options, string ParseString, int CurrentValue)
 void GetKeyValue(string Pair, out string, out string)
     
//
// Break up a key=value pair into its key and value.
//
 string GetNetworkNumber()
 string GetRules()
 int GetServerPort()
     
// Return the server's port number.
 vector GetTeamVectorColor(int num)
 bool GrabOption(out string, out string)
     
//
// Grab the next option from a string.
//
 bool HasOption(string Options, string InKey)
     
//
// See if an option was specified in the options string.
//
 void InitGameReplicationInfo()
     
//------------------------------------------------------------------------------
// Replication
 void InitLogging()
 bool IsRelevant(Actor Other)
     
//
// Return whether an actor should be destroyed in
// this type of game.
//	
 string KillMessage(name damageType, Pawn killer)
     
//
// Default death message.
//
 void Killed(Pawn killer, Pawn Other, name damageType)
     
//-------------------------------------------------------
//
// Killed
//
// Display a death message, called when a pawn is killed
//-------------------------------------------------------
 void LogGameParameters(StatLog StatLog)
     
//------------------------------------------------------------------------------
// Stat Logging.
 void Logout(Pawn Exiting)
     
//
// Pawn exits.
//
 string ParseKillMessage(string KillerName, string VictimName, string WeaponName, string DeathMessage)
     
// %k = Owner's PlayerName (Killer)
// %o = Other's PlayerName (Victim)
// %w = Owner's Weapon ItemName
 string ParseOption(string Options, string InKey)
     
//
// Find an option in the options string and return it.
//
 bool PickupQuery(Pawn Other, Inventory item)
     
//
// Called when pawn has a chance to pick Item up (i.e. when 
// the pawn touches a weapon pickup). Should return true if 
// he wants to pick it up, false if he does not want it.
//
 float PlaySpawnEffect(Inventory Inv)
     
//
// Play an inventory respawn effect.
//
 void PlayTeleportEffect(Actor Incoming, bool bOut, bool bSound)
     
//
// Play a teleporting special effect.
//
 float PlayerJumpZScaling()
     
// Return the player jumpZ scaling for this gametype
 string PlayerKillMessage(name damageType, PlayerReplicationInfo Other)
     
//
// Generate a player killled message.
//
 void PostBeginPlay()
 void PreBeginPlay()
     
//------------------------------------------------------------------------------
// Engine notifications.
 void ProcessServerTravel(string URL, bool bItems)
     
//
// Optional handling of ServerTravel for network games.
//
 void ReduceDamage(out int, out int, name DamageType, Pawn injured, Pawn instigatedBy)
     
//
// Use reduce damage for teamplay modifications, etc.
//
 void RegisterDamageMutator(Mutator M)
 void ResetGame()
 void RestartGame()
     
//
// Restart the game.
//
 bool RestartPlayer(Pawn aPlayer)
     
//
// Restart a player.
//
 void ScoreEvent(name EventName, Actor EventActor, Pawn InstigatedBy)
     
//
// Award a score to an actor.
//
 void ScoreKill(Pawn Killer, Pawn Other)
 void SendPlayer(PlayerPawn aPlayer, string URL)
     
//
// Send a player to a URL.
//
 bool SetEndCams(string Reason)
 void SetGameSpeed(Float T)
     
//
// Set gameplay speed.
//
 bool SetPause(BOOL bPause, PlayerPawn P)
 bool ShouldRespawn(Actor Other)
     
//
// Return whether an item should respawn.
//
 void StartPlayer(PlayerPawn Other)
     
//
// Start a player.
//
 void Timer()



Source Code


00001	//=============================================================================
00002	// GameInfo.
00003	//
00004	// default game info is normal single player
00005	//
00006	//=============================================================================
00007	class GameInfo extends Info
00008		native;
00009	
00010	//-----------------------------------------------------------------------------
00011	// Variables.
00012	
00013	var int ItemGoals, KillGoals, SecretGoals;				// Special game goals.
00014	var byte  Difficulty;									// 0=easy, 1=medium, 2=hard, 3=very hard.
00015	var() config bool   		  bNoMonsters;				// Whether monsters are allowed in this play mode.
00016	var() globalconfig bool		  bMuteSpectators;			// Whether spectators are allowed to speak.
00017	var() config bool			  bHumansOnly;				// Whether non human player models are allowed.
00018	var() bool				      bRestartLevel;	
00019	var() bool				      bPauseable;				// Whether the level is pauseable.
00020	var() config bool			  bCoopWeaponMode;			// Whether or not weapons stay when picked up.
00021	var() config bool			  bClassicDeathmessages;	// Weapon deathmessages if false.
00022	var   globalconfig bool	      bLowGore;					// Whether or not to reduce gore.
00023	var	  bool				      bCanChangeSkin;			// Allow player to change skins in game.
00024	var() bool				      bTeamGame;				// This is a teamgame.
00025	var	  globalconfig bool	      bVeryLowGore;				// Greatly reduces gore.
00026	var() globalconfig bool       bNoCheating;				// Disallows cheating. Hehe.
00027	var() globalconfig bool       bAllowFOV;				// Allows FOV changes in net games
00028	var() bool					  bDeathMatch;				// This game is some type of deathmatch (where players can respawn during gameplay)
00029	var	  bool					  bGameEnded;				// set when game ends
00030	var	  bool					  bOverTime;
00031	var localized bool			  bAlternateMode;
00032	var		bool				  bCanViewOthers;
00033	var() bool					  bAllowWeaponDrop;			// RUNE: Allow weapons to be dropped after death
00034	var() bool					  bAllowShieldDrop;			// RUNE: Allow shields to be dropped after death
00035	var() globalconfig bool		  bAutoPickup;				// RUNE: Autopickup inventory items
00036	
00037	
00038	var() globalconfig float	  AutoAim;					// How much autoaiming to do (1 = none, 0 = always).
00039															// (cosine of max error to correct)
00040	
00041	var() globalconfig float	  GameSpeed;				// Scale applied to game rate.
00042	var   float                   StartTime;
00043	
00044	var() class<playerpawn>       DefaultPlayerClass;
00045	var() class<weapon>           DefaultWeapon;			// Default weapon given to player at start.
00046	var() class<shield>			  DefaultShield;			// Default shield given to player at start
00047	
00048	var() globalconfig int	      MaxSpectators;			// Maximum number of spectators.
00049	var	  int					  NumSpectators;			// Current number of spectators.
00050	
00051	var() private globalconfig string AdminPassword;	    // Password to receive bAdmin privileges.
00052	var() private globalconfig string GamePassword;		    // Password to enter game.
00053	
00054	var() class<scoreboard>		  ScoreBoardType;			// Type of scoreboard this game uses.
00055	var() class<menu>			  GameMenuType;				// Type of oldstyle game options menu to display.
00056	var() string			      BotMenuType;				// Type of bot menu to display.
00057	var() string			      RulesMenuType;			// Type of rules menu to display.
00058	var() string				  SettingsMenuType;			// Type of settings menu to display.
00059	var() string                  MutatorMenuType;			// Type of mutator menu to display
00060	var() string                  MaplistMenuType;			// Type of maplist menu to display
00061	var() string				  GameUMenuType;			// Type of Game dropdown to display.
00062	var() string				  MultiplayerUMenuType;		// Type of Multiplayer dropdown to display.
00063	var() string				  GameOptionsMenuType;		// Type of options dropdown to display.
00064	
00065	var() class<hud>			  HUDType;					// HUD class this game uses.
00066	var() class<MapList>		  MapListType;				// Maplist this game uses.
00067	var() string			      MapPrefix;				// Prefix characters for names of maps for this game type.
00068	var() string			      BeaconName;				// Identifying string used for finding LAN servers.
00069	var() string			      SpecialDamageString;
00070	var localized string	      SwitchLevelMessage;
00071	var	int					      SentText;
00072	var localized string	      DefaultPlayerName;
00073	var localized string	      LeftMessage;
00074	var localized string	      FailedSpawnMessage;
00075	var localized string	      FailedPlaceMessage;
00076	var localized string	      FailedTeamMessage;
00077	var localized string	      NameChangedMessage;
00078	var localized string	      EnteredMessage;
00079	var localized string	      GameName;
00080	var	localized string	      MaxedOutMessage;
00081	var	localized string	      WrongPassword;
00082	var	localized string          NeedPassword;
00083	var	localized string          IPBanned;
00084	
00085	var() globalconfig int		  MaxPlayers; 
00086	var   int					  NumPlayers;
00087	var   int					  CurrentID;
00088	var() globalconfig string     IPPolicies[50];
00089	
00090	// Message classes.
00091	var class<LocalMessage>		  DeathMessageClass;
00092	var class<LocalMessage>		  DMMessageClass;
00093	
00094	// Mutator (for modifying actors as they enter the game)
00095	var class<Mutator> MutatorClass;
00096	var Mutator BaseMutator;
00097	var Mutator DamageMutator;	// linked list of mutators which affect damage
00098	
00099	// Default waterzone entry and exit effects
00100	var class<ZoneInfo> WaterZoneType;
00101	
00102	// What state a player should start in for this game type
00103	var name DefaultPlayerState;
00104	
00105	// ReplicationInfo
00106	var() class<GameReplicationInfo> GameReplicationInfoClass;
00107	var GameReplicationInfo GameReplicationInfo;
00108	
00109	// Server Log
00110	var globalconfig string         ServerLogName;
00111	
00112	// Statistics Logging
00113	var StatLog						LocalLog;
00114	var StatLog						WorldLog;
00115	var globalconfig bool			bLocalLog;
00116	var globalconfig bool			bWorldLog;
00117	var globalconfig bool			bBatchLocal;
00118	var globalconfig bool			bSubtitles;		// display subtitles
00119	var bool						bLoggingGame;			// Does this gametype log?
00120	var string					    LocalLogFileName;
00121	var string					    WorldLogFileName;
00122	var class<StatLog>				StatLogClass;
00123	
00124	// Demo Information
00125	var globalconfig int DemoBuild;
00126	var globalconfig int DemoHasTuts;
00127	
00128	var globalconfig float DebrisPercentage;		// Percentage of normal debris spawned
00129	var globalconfig float ParticlePercentage;		// Percentage of nomral particles spawned
00130	
00131	var() config bool bAllowLimbSever;		//RUNE: Allow arms to be chopped-off
00132	
00133	//------------------------------------------------------------------------------
00134	// Admin
00135	
00136	function AdminLogin( PlayerPawn P, string Password )
00137	{
00138		if (AdminPassword == "")
00139			return;
00140	
00141		if (Password == AdminPassword)
00142		{
00143			P.bAdmin = True;
00144			P.PlayerReplicationInfo.bAdmin = P.bAdmin;
00145			Log("Administrator logged in.");
00146			BroadcastMessage( P.PlayerReplicationInfo.PlayerName@"became a server administrator." );
00147		}
00148	}
00149	
00150	function AdminLogout( PlayerPawn P )
00151	{
00152		if (AdminPassword == "")
00153			return;
00154	
00155		if (P.bAdmin)
00156		{
00157			P.bAdmin = False;
00158			P.PlayerReplicationInfo.bAdmin = P.bAdmin;
00159			Log("Administrator logged out.");
00160			BroadcastMessage( P.PlayerReplicationInfo.PlayerName@"gave up administrator abilities." );
00161		}
00162	}
00163	
00164	//------------------------------------------------------------------------------
00165	// Engine notifications.
00166	
00167	function PreBeginPlay()
00168	{
00169		StartTime = 0;
00170		SetGameSpeed(GameSpeed);
00171		Level.bNoCheating = bNoCheating;
00172		Level.bAllowFOV = bAllowFOV;
00173		
00174		if (GameReplicationInfoClass != None)
00175			GameReplicationInfo = Spawn(GameReplicationInfoClass);
00176		else
00177			GameReplicationInfo = Spawn(class'GameReplicationInfo');
00178		InitGameReplicationInfo();
00179	}
00180	
00181	function PostBeginPlay()
00182	{
00183		local ZoneInfo W;
00184	
00185		if ( bAlternateMode )
00186		{
00187			bLowGore = true;
00188			bVeryLowGore = true;
00189		}
00190	
00191		if ( bVeryLowGore )
00192			bLowGore = true;
00193	
00194		if ( WaterZoneType != None )
00195		{
00196			ForEach AllActors(class'ZoneInfo', W )
00197				if ( W.bWaterZone )
00198				{
00199					if( W.EntryActor == None )
00200						W.EntryActor = WaterZoneType.Default.EntryActor;
00201					if( W.ExitActor == None )
00202						W.ExitActor = WaterZoneType.Default.ExitActor;
00203					if( W.EntrySound == None )
00204						W.EntrySound = WaterZoneType.Default.EntrySound;
00205					if( W.ExitSound == None )
00206						W.ExitSound = WaterZoneType.Default.ExitSound;
00207				}
00208		}
00209	
00210		// Setup local statistics logging.
00211		InitLogging();
00212	
00213		Super.PostBeginPlay();
00214	}
00215	
00216	function InitLogging()
00217	{
00218		local Mutator M;
00219	
00220		if (bLocalLog && bLoggingGame)
00221		{
00222			Log("Initiating local logging...");
00223			LocalLog = spawn(StatLogClass);
00224			LocalLog.bWorld = False;
00225			LocalLog.StartLog();
00226			LocalLog.LogStandardInfo();
00227			LocalLog.LogServerInfo();
00228			LocalLog.LogMapParameters();
00229			for (M = BaseMutator; M != None; M = M.NextMutator)
00230				LocalLog.LogMutator(M);
00231			LogGameParameters(LocalLog);
00232			LocalLogFileName = LocalLog.GetLogFileName();
00233		}
00234	
00235		// Setup world statistics logging.
00236		if ((Level.NetMode != NM_DedicatedServer) && (Level.NetMode != NM_ListenServer))
00237			return;
00238	
00239		if (bWorldLog && bLoggingGame)
00240		{
00241			Log("Initiating world logging...");
00242			WorldLog = spawn(StatLogClass);
00243			WorldLog.bWorld = True;
00244			WorldLog.StartLog();
00245			WorldLog.LogStandardInfo();
00246			WorldLog.LogServerInfo();
00247			WorldLog.LogMapParameters();
00248			WorldLog.InitialCheck(Self);
00249			for (M = BaseMutator; M != None; M = M.NextMutator)
00250				WorldLog.LogMutator(M);
00251			LogGameParameters(WorldLog);
00252			WorldLogFileName = WorldLog.GetLogFileName();
00253		}
00254	}
00255	
00256	function Timer()
00257	{
00258		SentText = 0;
00259	}
00260	
00261	// Called when game shutsdown.
00262	event GameEnding()
00263	{
00264		if (LocalLog != None)
00265		{
00266			LocalLog.LogGameEnd("serverquit");
00267			LocalLog.StopLog();
00268			LocalLog.Destroy();
00269			LocalLog = None;
00270		}
00271	
00272		if (WorldLog != None)
00273		{
00274			WorldLog.LogGameEnd("serverquit");
00275			WorldLog.StopLog();
00276			WorldLog.Destroy();
00277			WorldLog = None;
00278		}
00279	}
00280	
00281	//------------------------------------------------------------------------------
00282	// Replication
00283	
00284	function InitGameReplicationInfo()
00285	{
00286		GameReplicationInfo.bTeamGame = bTeamGame;
00287		GameReplicationInfo.GameName = GameName;
00288		GameReplicationInfo.GameClass = string(Class);
00289		GameReplicationInfo.bClassicDeathmessages = bClassicDeathmessages;
00290	}
00291	
00292	native function string GetNetworkNumber();
00293	
00294	//------------------------------------------------------------------------------
00295	// Game Querying.
00296	
00297	function string GetInfo()
00298	{
00299		local string ResultSet;
00300	
00301		// World logging
00302		if (WorldLog != None)
00303			ResultSet = "\\worldlog\\true";
00304		else
00305			ResultSet = "\\worldlog\\false";
00306	
00307		return ResultSet;
00308	}
00309	
00310	function string GetRules()
00311	{
00312		local string ResultSet;
00313		local Mutator M;
00314		local string NextMutator, NextDesc;
00315		local string EnabledMutators;
00316		local int Num, i;
00317	
00318		ResultSet = "";
00319	
00320		EnabledMutators = "";
00321		for (M = BaseMutator.NextMutator; M != None; M = M.NextMutator)
00322		{
00323			Num = 0;
00324			NextMutator = "";
00325			GetNextIntDesc("Engine.Mutator", 0, NextMutator, NextDesc);
00326			while( (NextMutator != "") && (Num < 50) )
00327			{
00328				if(NextMutator ~= string(M.Class))
00329				{
00330					i = InStr(NextDesc, ",");
00331					if(i != -1)
00332						NextDesc = Left(NextDesc, i);
00333	
00334					if(EnabledMutators != "")
00335						EnabledMutators = EnabledMutators $ ", ";
00336					 EnabledMutators = EnabledMutators $ NextDesc;
00337					 break;
00338				}
00339				
00340				Num++;
00341				GetNextIntDesc("Engine.Mutator", Num, NextMutator, NextDesc);
00342			}
00343		}
00344		if(EnabledMutators != "")
00345			ResultSet = ResultSet $ "\\mutators\\"$EnabledMutators;
00346	
00347		ResultSet = ResultSet $ "\\listenserver\\"$string(Level.NetMode==NM_ListenServer);
00348	
00349		// Add gamespeed
00350		ResultSet = ResultSet $ "\\gamespeed\\"$int(Level.TimeDilation*100)$"%";
00351	
00352		// Add autopickup
00353		ResultSet = ResultSet $ "\\autopickup\\"$string(bAutoPickup);
00354	
00355		return ResultSet;
00356	}
00357	
00358	// Return the server's port number.
00359	function int GetServerPort()
00360	{
00361		local string S;
00362		local int i;
00363	
00364		// Figure out the server's port.
00365		S = Level.GetAddressURL();
00366		i = InStr( S, ":" );
00367		assert(i>=0);
00368		return int(Mid(S,i+1));
00369	}
00370	
00371	function bool SetPause( BOOL bPause, PlayerPawn P )
00372	{
00373		if( bPauseable || P.bAdmin || Level.Netmode==NM_Standalone )
00374		{
00375			if( bPause )
00376				Level.Pauser=P.PlayerReplicationInfo.PlayerName;
00377			else
00378				Level.Pauser="";
00379			return True;
00380		}
00381		else return False;
00382	}
00383	
00384	//------------------------------------------------------------------------------
00385	// Stat Logging.
00386	
00387	function LogGameParameters(StatLog StatLog)
00388	{
00389		if (StatLog == None)
00390			return;
00391	
00392		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameName"$Chr(9)$GameName);
00393		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NoMonsters"$Chr(9)$bNoMonsters);
00394		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"NoMonsters"$Chr(9)$bNoMonsters);
00395		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MuteSpectators"$Chr(9)$bMuteSpectators);
00396		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"HumansOnly"$Chr(9)$bHumansOnly);
00397		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"WeaponsStay"$Chr(9)$bCoopWeaponMode);
00398		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"ClassicDeathmessages"$Chr(9)$bClassicDeathmessages);
00399		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"LowGore"$Chr(9)$bLowGore);
00400		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"VeryLowGore"$Chr(9)$bVeryLowGore);
00401		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"TeamGame"$Chr(9)$bTeamGame);
00402		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameSpeed"$Chr(9)$int(GameSpeed*100));
00403		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MaxSpectators"$Chr(9)$MaxSpectators);
00404		StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MaxPlayers"$Chr(9)$MaxPlayers);
00405	}
00406	
00407	//------------------------------------------------------------------------------
00408	// Game parameters.
00409	
00410	//
00411	// Set gameplay speed.
00412	//
00413	function SetGameSpeed( Float T )
00414	{
00415	//	GameSpeed = FMax(T, 0.1);	// RUNE: Not enforced for debugging
00416		if (T==0) T=0.1;
00417		GameSpeed = FMax(T, 0.001);
00418		Level.TimeDilation = GameSpeed;
00419		SetTimer(Level.TimeDilation, true);
00420	}
00421	
00422	static function ResetGame();
00423	
00424	//
00425	// Called after setting low or high detail mode.
00426	//
00427	event DetailChange()
00428	{
00429		local actor A;
00430		local zoneinfo Z;
00431		local skyzoneinfo S;
00432		if( !Level.bHighDetailMode )
00433		{
00434			foreach AllActors(class'Actor', A)
00435			{
00436				if( A.bHighDetail && !A.bGameRelevant )
00437					A.Destroy();
00438			}
00439		}
00440		foreach AllActors(class'ZoneInfo', Z)
00441			Z.LinkToSkybox();
00442	}
00443	
00444	//
00445	// Return whether an actor should be destroyed in
00446	// this type of game.
00447	//	
00448	function bool IsRelevant( actor Other )
00449	{
00450		local byte bSuperRelevant;
00451	
00452		// let the mutators mutate the actor or choose to remove it
00453		if ( BaseMutator.AlwaysKeep(Other) )
00454			return true;
00455		if ( BaseMutator.IsRelevant(Other, bSuperRelevant) )
00456		{
00457			if ( bSuperRelevant == 1 ) // mutator wants to override any logic in here
00458				return true;
00459		}
00460		else return false;
00461	
00462		if
00463		(	(Difficulty==0 && !Other.bDifficulty0 )
00464		||  (Difficulty==1 && !Other.bDifficulty1 )
00465		||  (Difficulty==2 && !Other.bDifficulty2 )
00466		||  (Difficulty==3 && !Other.bDifficulty3 )
00467		||  (!Other.bSinglePlayer && (Level.NetMode==NM_Standalone) ) 
00468		||  (!Other.bNet && ((Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer)) )
00469		||  (!Other.bNetSpecial  && (Level.NetMode==NM_Client)) )
00470			return False;
00471	
00472		if( bNoMonsters && (Pawn(Other) != None) && !Pawn(Other).bIsPlayer )
00473			return False;
00474	
00475		if( FRand() > Other.OddsOfAppearing )
00476			return False;
00477	
00478	    // Update the level info goal counts.
00479	    if( Other.bIsSecretGoal )
00480	       SecretGoals++;
00481	
00482	    if( Other.bIsItemGoal )
00483	       ItemGoals++;
00484	
00485	    if( Other.bIsKillGoal )
00486	       KillGoals++;
00487	
00488		return True;
00489	}
00490	
00491	//------------------------------------------------------------------------------
00492	// Player start functions
00493	
00494	//
00495	// Grab the next option from a string.
00496	//
00497	function bool GrabOption( out string Options, out string Result )
00498	{
00499		if( Left(Options,1)=="?" )
00500		{
00501			// Get result.
00502			Result = Mid(Options,1);
00503			if( InStr(Result,"?")>=0 )
00504				Result = Left( Result, InStr(Result,"?") );
00505	
00506			// Update options.
00507			Options = Mid(Options,1);
00508			if( InStr(Options,"?")>=0 )
00509				Options = Mid( Options, InStr(Options,"?") );
00510			else
00511				Options = "";
00512	
00513			return true;
00514		}
00515		else return false;
00516	}
00517	
00518	//
00519	// Break up a key=value pair into its key and value.
00520	//
00521	function GetKeyValue( string Pair, out string Key, out string Value )
00522	{
00523		if( InStr(Pair,"=")>=0 )
00524		{
00525			Key   = Left(Pair,InStr(Pair,"="));
00526			Value = Mid(Pair,InStr(Pair,"=")+1);
00527		}
00528		else
00529		{
00530			Key   = Pair;
00531			Value = "";
00532		}
00533	}
00534	
00535	//
00536	// See if an option was specified in the options string.
00537	//
00538	function bool HasOption( string Options, string InKey )
00539	{
00540		local string Pair, Key, Value;
00541		while( GrabOption( Options, Pair ) )
00542		{
00543			GetKeyValue( Pair, Key, Value );
00544			if( Key ~= InKey )
00545				return true;
00546		}
00547		return false;
00548	}
00549	
00550	//
00551	// Find an option in the options string and return it.
00552	//
00553	function string ParseOption( string Options, string InKey )
00554	{
00555		local string Pair, Key, Value;
00556		while( GrabOption( Options, Pair ) )
00557		{
00558			GetKeyValue( Pair, Key, Value );
00559			if( Key ~= InKey )
00560				return Value;
00561		}
00562		return "";
00563	}
00564	
00565	//
00566	// Initialize the game.
00567	//warning: this is called before actors' PreBeginPlay.
00568	//
00569	event InitGame( string Options, out string Error )
00570	{
00571		local string InOpt, LeftOpt;
00572		local int pos;
00573		local class<Mutator> MClass;
00574	
00575		log( "InitGame:" @ Options );
00576		MaxPlayers = Min( 32,GetIntOption( Options, "MaxPlayers", MaxPlayers ));
00577		InOpt = ParseOption( Options, "Difficulty" );
00578		if( InOpt != "" )
00579			Difficulty = int(InOpt);
00580	
00581		InOpt = ParseOption( Options, "AdminPassword");
00582		if( InOpt!="" )
00583			AdminPassword = InOpt;
00584	
00585		InOpt = ParseOption( Options, "GameSpeed");
00586		if( InOpt != "" )
00587		{
00588			log("GameSpeed"@InOpt);
00589			SetGameSpeed(float(InOpt));
00590		}
00591	
00592		BaseMutator = spawn(MutatorClass);
00593		log("Base Mutator is "$BaseMutator);
00594		InOpt = ParseOption( Options, "Mutator");
00595		if ( InOpt != "" )
00596		{
00597			log("Mutators"@InOpt);
00598			while ( InOpt != "" )
00599			{
00600				pos = InStr(InOpt,",");
00601				if ( pos > 0 )
00602				{
00603					LeftOpt = Left(InOpt, pos);
00604					InOpt = Right(InOpt, Len(InOpt) - pos - 1);
00605				}
00606				else
00607				{
00608					LeftOpt = InOpt;
00609					InOpt = "";
00610				}
00611				log("Add mutator "$LeftOpt);
00612				MClass = class<Mutator>(DynamicLoadObject(LeftOpt, class'Class'));	
00613				BaseMutator.AddMutator(Spawn(MClass));
00614			}
00615		}
00616	
00617		InOpt = ParseOption( Options, "GamePassword");
00618		if( InOpt != "" )
00619		{
00620			GamePassWord = InOpt;
00621			log( "GamePassword" @ InOpt );
00622		}
00623	
00624		InOpt = ParseOption( Options, "LocalLog");
00625		if( InOpt ~= "true" )
00626			bLocalLog = True;
00627	
00628		InOpt = ParseOption( Options, "WorldLog");
00629		if( InOpt ~= "true" )
00630			bWorldLog = True;
00631	}
00632	
00633	//
00634	// Return beacon text for serverbeacon.
00635	//
00636	event string GetBeaconText()
00637	{	
00638		return
00639			Level.ComputerName
00640		$	" "
00641		$	Left(Level.Title,24) 
00642		$	" "
00643		$	BeaconName
00644		$	" "
00645		$	NumPlayers
00646		$	"/"
00647		$	MaxPlayers;
00648	}
00649	
00650	//
00651	// Optional handling of ServerTravel for network games.
00652	//
00653	function ProcessServerTravel( string URL, bool bItems )
00654	{
00655		local playerpawn P, LocalPlayer;
00656	
00657		if (LocalLog != None)
00658		{
00659			LocalLog.LogGameEnd("mapchange");
00660			LocalLog.StopLog();
00661			LocalLog.Destroy();
00662			LocalLog = None;
00663		}
00664	
00665		if (WorldLog != None)
00666		{
00667			WorldLog.LogGameEnd("mapchange");
00668			WorldLog.StopLog();
00669			WorldLog.Destroy();
00670			WorldLog = None;
00671		}
00672	
00673		// Notify clients we're switching level and give them time to receive.
00674		// We call PreClientTravel directly on any local PlayerPawns (ie listen server)
00675		log("ProcessServerTravel:"@URL);
00676		foreach AllActors( class'PlayerPawn', P )
00677			if( NetConnection(P.Player)!=None )
00678				P.ClientTravel( URL, TRAVEL_Relative, bItems );
00679			else
00680			{	
00681				LocalPlayer = P;
00682				P.PreClientTravel();
00683			}
00684	
00685		if ( (Level.NetMode == NM_ListenServer) && (LocalPlayer != None) )
00686			Level.NextURL = Level.NextURL$"?Skin="$LocalPlayer.GetDefaultURL("Skin")
00687						 $"?Face="$LocalPlayer.GetDefaultURL("Face")
00688						 $"?Team="$LocalPlayer.GetDefaultURL("Team")
00689						 $"?Name="$LocalPlayer.GetDefaultURL("Name")
00690						 $"?Class="$LocalPlayer.GetDefaultURL("Class");
00691	
00692		// Switch immediately if not networking.
00693		if( Level.NetMode!=NM_DedicatedServer && Level.NetMode!=NM_ListenServer )
00694			Level.NextSwitchCountdown = 0.0;
00695	}
00696	
00697	function bool AtCapacity(string Options)
00698	{
00699		return ( (MaxPlayers>0) && (NumPlayers>=MaxPlayers) );
00700	}
00701	
00702	//
00703	// Accept or reject a player on the server.
00704	// Fails login if you set the Error to a non-empty string.
00705	//
00706	event PreLogin
00707	(
00708		string Options,
00709		string Address,
00710		out string Error,
00711		out string FailCode
00712	)
00713	{
00714		// Do any name or password or name validation here.
00715		local string InPassword;
00716		Error="";
00717		InPassword = ParseOption( Options, "Password" );
00718		if( (Level.NetMode != NM_Standalone) && AtCapacity(Options) )
00719		{
00720			Error=MaxedOutMessage;
00721		}
00722		else if
00723		(	GamePassword!=""
00724		&&	caps(InPassword)!=caps(GamePassword)
00725		&&	(AdminPassword=="" || caps(InPassword)!=caps(AdminPassword)) )
00726		{
00727			if( InPassword == "" )
00728			{
00729				Error = NeedPassword;
00730				FailCode = "NEEDPW";
00731			}
00732			else
00733			{
00734				Error = WrongPassword;
00735				FailCode = "WRONGPW";
00736			}
00737		}
00738	
00739		if(!CheckIPPolicy(Address))
00740			Error = IPBanned;
00741	}
00742	
00743	function bool CheckIPPolicy(string Address)
00744	{
00745		local int i, j, LastMatchingPolicy;
00746		local string Policy, Mask;
00747		local bool bAcceptAddress, bAcceptPolicy;
00748		
00749		// strip port number
00750		j = InStr(Address, ":");
00751		if(j != -1)
00752			Address = Left(Address, j);
00753	
00754		bAcceptAddress = True;
00755		for(i=0; i<50 && IPPolicies[i] != ""; i++)
00756		{
00757			j = InStr(IPPolicies[i], ",");
00758			if(j==-1)
00759				continue;
00760			Policy = Left(IPPolicies[i], j);
00761			Mask = Mid(IPPolicies[i], j+1);
00762			if(Policy ~= "ACCEPT") 
00763				bAcceptPolicy = True;
00764			else
00765			if(Policy ~= "DENY") 
00766				bAcceptPolicy = False;
00767			else
00768				continue;
00769	
00770			j = InStr(Mask, "*");
00771			if(j != -1)
00772			{
00773				if(Left(Mask, j) == Left(Address, j))
00774				{
00775					bAcceptAddress = bAcceptPolicy;
00776					LastMatchingPolicy = i;
00777				}
00778			}
00779			else
00780			{
00781				if(Mask == Address)
00782				{
00783					bAcceptAddress = bAcceptPolicy;
00784					LastMatchingPolicy = i;
00785				}
00786			}
00787		}
00788	
00789		if(!bAcceptAddress)
00790			Log("Denied connection for "$Address$" with IP policy "$IPPolicies[LastMatchingPolicy]);
00791			
00792		return bAcceptAddress;
00793	}
00794	
00795	function int GetIntOption( string Options, string ParseString, int CurrentValue)
00796	{
00797		local string InOpt;
00798	
00799		InOpt = ParseOption( Options, ParseString );
00800		if ( InOpt != "" )
00801		{
00802			log(ParseString@InOpt);
00803			return int(InOpt);
00804		}	
00805		return CurrentValue;
00806	}
00807	
00808	//
00809	// Log a player in.
00810	// Fails login if you set the Error string.
00811	// PreLogin is called before Login, but significant game time may pass before
00812	// Login is called, especially if content is downloaded.
00813	//
00814	event playerpawn Login
00815	(
00816		string Portal,
00817		string Options,
00818		out string Error,
00819		class<playerpawn> SpawnClass
00820	)
00821	{
00822		local NavigationPoint StartSpot;
00823		local PlayerPawn      NewPlayer, TestPlayer;
00824		local Pawn            PawnLink;
00825		local string          InName, InPassword, InSkin, InFace, InChecksum;
00826		local byte            InTeam;
00827	
00828		// Make sure there is capacity. (This might have changed since the PreLogin call).
00829		if ( Level.NetMode != NM_Standalone )
00830		{
00831			if ( ClassIsChildOf(SpawnClass, class'Spectator') )
00832			{
00833				if ( (NumSpectators >= MaxSpectators)
00834					&& ((Level.NetMode != NM_ListenServer) || (NumPlayers > 0)) )
00835				{
00836					Error=MaxedOutMessage;
00837					return None;
00838				}
00839			}		
00840			else if ( (MaxPlayers>0) && (NumPlayers>=MaxPlayers) )
00841			{
00842				Error=MaxedOutMessage;
00843				return None;
00844			}
00845		}
00846	
00847		// Get URL options.
00848		InName     = Left(ParseOption ( Options, "Name"), 20);
00849		InTeam     = GetIntOption( Options, "Team", 255 ); // default to "no team"
00850		InPassword = ParseOption ( Options, "Password" );
00851		InSkin	   = ParseOption ( Options, "Skin"    );
00852		InFace     = ParseOption ( Options, "Face"    );
00853		InChecksum = ParseOption ( Options, "Checksum" );
00854	
00855		log( "Login:" @ InName );
00856		if( InPassword != "" )
00857			log( "Password"@InPassword );
00858		 
00859		// Find a start spot.
00860		StartSpot = FindPlayerStart( None, InTeam, Portal );
00861	
00862		if( StartSpot == None )
00863		{
00864			Error = FailedPlaceMessage;
00865			return None;
00866		}
00867	
00868		// Try to match up to existing unoccupied player in level,
00869		// for savegames and coop level switching.
00870		for( PawnLink=Level.PawnList; PawnLink!=None; PawnLink=PawnLink.NextPawn )
00871		{
00872			TestPlayer = PlayerPawn(PawnLink);
00873			if
00874			(	TestPlayer!=None
00875			&&	TestPlayer.Player==None 
00876			&&  TestPlayer.PlayerReplicationInfo != None
00877			&&  TestPlayer.bIsPlayer
00878			&&	TestPlayer.PlayerReplicationInfo.PlayerName != class'PlayerReplicationInfo'.default.PlayerName
00879			)
00880			{
00881				if
00882				(	(Level.NetMode==NM_Standalone)
00883				||	(TestPlayer.PlayerReplicationInfo.PlayerName~=InName && TestPlayer.Password~=InPassword) )
00884				{
00885					// Found matching unoccupied player, so use this one.
00886					NewPlayer = TestPlayer;
00887					NewPlayer.Tag = 'Player';
00888					break;
00889				}
00890			}
00891		}
00892	
00893		// In not found, spawn a new player.
00894		if( NewPlayer==None )
00895		{
00896			// Make sure this kind of player is allowed.
00897			if ( (bHumansOnly || Level.bHumansOnly) && !SpawnClass.Default.bIsHuman
00898				&& !ClassIsChildOf(SpawnClass, class'Spectator') )
00899				SpawnClass = DefaultPlayerClass;
00900	
00901			NewPlayer = Spawn(SpawnClass,,'Player',StartSpot.Location,StartSpot.Rotation);
00902			if( NewPlayer!=None )
00903			{
00904				NewPlayer.ViewRotation = StartSpot.Rotation;
00905	
00906				// Save the playerstart event for later firing
00907				NewPlayer.StartEvent = StartSpot.Event;
00908	
00909				NewPlayer.bJustSpawned = true;
00910			}
00911		}
00912		else
00913		{
00914			NewPlayer.bJustSpawned = false;
00915		}
00916	
00917		// Handle spawn failure.
00918		if( NewPlayer == None )
00919		{
00920			log("Couldn't spawn player at "$StartSpot);
00921			Error = FailedSpawnMessage;
00922			return None;
00923		}
00924	
00925	//	NewPlayer.static.SetMultiSkin(NewPlayer, InSkin, InFace, InTeam);
00926		NewPlayer.CurrentSkin = int(InSkin);
00927		NewPlayer.static.SetSkinActor(NewPlayer, int(InSkin));
00928	
00929		// Set the player's ID.
00930		NewPlayer.PlayerReplicationInfo.PlayerID = CurrentID++;
00931	
00932		// Init player's information.
00933		NewPlayer.ClientSetRotation(NewPlayer.Rotation);
00934		if( InName=="" )
00935			InName=DefaultPlayerName;
00936		if( Level.NetMode!=NM_Standalone || NewPlayer.PlayerReplicationInfo.PlayerName==DefaultPlayerName )
00937			ChangeName( NewPlayer, InName, false );
00938	
00939		// Change player's team.
00940		if ( !ChangeTeam(newPlayer, InTeam) )
00941		{
00942			Error = FailedTeamMessage;
00943			return None;
00944		}
00945	
00946		if( NewPlayer.IsA('Spectator') && (Level.NetMode == NM_DedicatedServer) )
00947			NumSpectators++;
00948	
00949		// Init player's administrative privileges
00950		NewPlayer.Password = InPassword;
00951		NewPlayer.bAdmin = AdminPassword!="" && caps(InPassword)==caps(AdminPassword);
00952		NewPlayer.PlayerReplicationInfo.bAdmin = NewPlayer.bAdmin;
00953		if( NewPlayer.bAdmin )
00954			log( "Administrator logged in!" );
00955	
00956		// Init player's replication info
00957		NewPlayer.GameReplicationInfo = GameReplicationInfo;
00958	
00959		// If we are a server, broadcast a welcome message.
00960		if( Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer )
00961			BroadcastMessage( NewPlayer.PlayerReplicationInfo.PlayerName$EnteredMessage, false );
00962	
00963		// Teleport-in effect.
00964		StartSpot.PlayTeleportEffect( NewPlayer, true );
00965	
00966		// Log it.
00967		if ( LocalLog != None )
00968			LocalLog.LogPlayerConnect(NewPlayer);
00969		if ( WorldLog != None )
00970			WorldLog.LogPlayerConnect(NewPlayer, InChecksum);
00971	
00972		if ( !NewPlayer.IsA('Spectator') )
00973			NumPlayers++;
00974	
00975	//	newPlayer.FireEvent(StartSpot.Event);
00976			
00977		return newPlayer;
00978	}	
00979	
00980	//
00981	// Called after a successful login. This is the first place
00982	// it is safe to call replicated functions on the PlayerPawn.
00983	//
00984	event PostLogin( playerpawn NewPlayer )
00985	{
00986		local Pawn P;
00987		// Start player's music.
00988		NewPlayer.ClientSetMusic( Level.Song, Level.SongSection, Level.CdTrack, MTRAN_Fade );
00989		if ( Level.NetMode != NM_Standalone )
00990		{
00991			// replicate skins
00992			for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00993				if ( P.bIsPlayer && (P != NewPlayer) )
00994				{
00995					if ( P.bIsMultiSkinned )
00996						NewPlayer.ClientReplicateSkins(P.MultiSkins[0], P.MultiSkins[1], P.MultiSkins[2], P.MultiSkins[3]);
00997					else
00998						NewPlayer.ClientReplicateSkins(P.Skin);	
00999						
01000					if ( (P.PlayerReplicationInfo != None) && P.PlayerReplicationInfo.bWaitingPlayer && P.IsA('PlayerPawn') )
01001					{
01002						if ( NewPlayer.bIsMultiSkinned )
01003							PlayerPawn(P).ClientReplicateSkins(NewPlayer.MultiSkins[0], NewPlayer.MultiSkins[1], NewPlayer.MultiSkins[2], NewPlayer.MultiSkins[3]);
01004						else
01005							PlayerPawn(P).ClientReplicateSkins(NewPlayer.Skin);	
01006					}						
01007				}
01008		}
01009	}
01010	
01011	//
01012	// Add bot to game.
01013	//
01014	function bool AddBot();
01015	function bool ForceAddBot();
01016	
01017	//
01018	// Pawn exits.
01019	//
01020	function Logout( pawn Exiting )
01021	{
01022		local bool bMessage;
01023	
01024		bMessage = true;
01025		if ( Exiting.IsA('PlayerPawn') )
01026	
01027		{
01028			if ( Exiting.IsA('Spectator') )
01029			{
01030				bMessage = false;
01031				if ( Level.NetMode == NM_DedicatedServer )
01032					NumSpectators--;
01033			}
01034			else
01035				NumPlayers--;
01036		}
01037		if( bMessage && (Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer) )
01038			BroadcastMessage( Exiting.PlayerReplicationInfo.PlayerName$LeftMessage, false );
01039	
01040		if ( LocalLog != None )
01041			LocalLog.LogPlayerDisconnect(Exiting);
01042		if ( WorldLog != None )
01043			WorldLog.LogPlayerDisconnect(Exiting);
01044	}
01045	
01046	//
01047	// Examine the passed player's inventory, and accept or discard each item.
01048	// AcceptInventory needs to gracefully handle the case of some inventory
01049	// being accepted but other inventory not being accepted (such as the default
01050	// weapon).  There are several things that can go wrong: The player's selected
01051	// inventory item, active
01052	// weapon, etc. not being accepted, leaving the player weaponless or leaving
01053	// the HUD inventory rendering messed up (AcceptInventory should pick another
01054	// applicable weapon/item as current).
01055	//
01056	event AcceptInventory(pawn PlayerPawn)
01057	{
01058		//default accept all inventory except default weapon (spawned explicitly)
01059	
01060		local inventory inv;
01061	
01062		// Initialize the inventory.
01063		AddDefaultInventory( PlayerPawn );
01064	
01065		log( "All inventory from" @ PlayerPawn.PlayerReplicationInfo.PlayerName @ "is accepted" );
01066	}
01067	
01068	//
01069	// Spawn any default inventory for the player.
01070	//
01071	function AddDefaultInventory( pawn PlayerPawn )
01072	{
01073		local Weapon newWeapon;
01074		local Shield newShield;
01075	
01076		PlayerPawn.JumpZ = PlayerPawn.Default.JumpZ * PlayerJumpZScaling();
01077		 
01078		if( PlayerPawn.IsA('Spectator') )
01079			return;
01080	
01081		// Spawn default weapon.
01082		if (PlayerPawn.Weapon == None)
01083		{
01084			if( (DefaultWeapon!=None && PlayerPawn.FindInventoryType(DefaultWeapon)==None) ||	// Default weapon exists that player doesn't yet have
01085				BaseMutator.MutatedDefaultWeapon()!=None )										// Mutators dictating a default weapon
01086			{
01087				newWeapon = Spawn(BaseMutator.MutatedDefaultWeapon(),,,PlayerPawn.Location);
01088				if( newWeapon != None )
01089				{
01090					newWeapon.bTossedOut = true;
01091					newWeapon.Instigator = PlayerPawn;
01092					newWeapon.BecomeItem();
01093					PlayerPawn.AddInventory(newWeapon);
01094					PlayerPawn.AcquireInventory(newWeapon);
01095					PlayerPawn.Weapon = newWeapon;
01096					newWeapon.GotoState('Active');
01097		//			newWeapon.BringUp();
01098		//			newWeapon.SetSwitchPriority(PlayerPawn);
01099		//			newWeapon.WeaponSet(PlayerPawn);
01100				}
01101			}
01102		}
01103	
01104		// Spawn default shield
01105		if (PlayerPawn.Shield == None)
01106		{
01107			if( (DefaultShield!=None && PlayerPawn.FindInventoryType(DefaultShield)==None) ||
01108				BaseMutator.MutatedDefaultShield()!=None )
01109			{
01110				newShield = Spawn(BaseMutator.MutatedDefaultShield(),,,PlayerPawn.Location);
01111				if( newShield != None )
01112				{
01113					newShield.bTossedOut = true;
01114					newShield.Instigator = PlayerPawn;
01115					newShield.BecomeItem();
01116					PlayerPawn.AddInventory(newShield);
01117					PlayerPawn.AcquireInventory(newShield);
01118					PlayerPawn.Shield = newShield;
01119					newShield.GotoState('Active');
01120				}
01121			}
01122		}
01123	
01124		BaseMutator.ModifyPlayer(PlayerPawn);
01125	}
01126	
01127	
01128	//
01129	// Return the 'best' player start for this player to start from.
01130	// Re-implement for each game type.
01131	//
01132	function NavigationPoint FindPlayerStart( Pawn Player, optional byte InTeam, optional string incomingName )
01133	{
01134		local PlayerStart Dest;
01135		local Teleporter Tel;
01136		if( incomingName!="" )
01137			foreach AllActors( class 'Teleporter', Tel )
01138				if( string(Tel.Tag)~=incomingName )
01139					return Tel;
01140		foreach AllActors( class 'PlayerStart', Dest )
01141			if( Dest.bSinglePlayerStart && Dest.bEnabled )
01142				return Dest;
01143	
01144		// if none, check for any that aren't enabled
01145		log("WARNING: All single player starts were disabled - picking one anyway!");
01146		foreach AllActors( class 'PlayerStart', Dest )
01147			if( Dest.bSinglePlayerStart )
01148				return Dest;
01149		log( "No single player start found" );
01150		return None;
01151	}
01152	
01153	//
01154	// Restart a player.
01155	//
01156	function bool RestartPlayer( pawn aPlayer )	
01157	{
01158		local NavigationPoint startSpot;
01159		local bool foundStart;
01160		local int i;
01161		local actor A;
01162	
01163		if( bRestartLevel && Level.NetMode!=NM_DedicatedServer && Level.NetMode!=NM_ListenServer )
01164			return true;
01165	
01166		startSpot = FindPlayerStart(aPlayer, 255);
01167		if( startSpot == None )
01168		{
01169			log(" Player start not found!!!");
01170			return false;
01171		}
01172			
01173		foundStart = aPlayer.SetLocation(startSpot.Location);
01174		if( foundStart )
01175		{
01176			startSpot.PlayTeleportEffect(aPlayer, true);
01177			aPlayer.SetRotation(startSpot.Rotation);
01178			aPlayer.ViewRotation = aPlayer.Rotation;
01179			aPlayer.Acceleration = vect(0,0,0);
01180			aPlayer.Velocity = vect(0,0,0);
01181			aPlayer.Health = aPlayer.Default.Health;
01182			aPlayer.SetCollision( true, true, true );
01183			aPlayer.bCollideWorld = true;
01184			aPlayer.SetCollisionSize(aPlayer.Default.CollisionRadius, aPlayer.Default.CollisionHeight);
01185			aPlayer.ClientSetLocation( startSpot.Location, startSpot.Rotation );
01186			aPlayer.bHidden = false;
01187			aPlayer.DamageScaling = aPlayer.Default.DamageScaling;
01188			aPlayer.SoundDampening = aPlayer.Default.SoundDampening;
01189	
01190			// Team games require this
01191			if (bTeamGame)
01192				aPlayer.DesiredColorAdjust = GetTeamVectorColor(aPlayer.PlayerReplicationInfo.Team);
01193			else
01194				aPlayer.DesiredColorAdjust = aPlayer.Default.DesiredColorAdjust;
01195	
01196			if (PlayerPawn(aPlayer)!=None)
01197			{
01198				PlayerPawn(aPlayer).DesiredPolyColorAdjust = PlayerPawn(aPlayer).Default.DesiredPolyColorAdjust;
01199				PlayerPawn(aPlayer).PolyColorAdjust = PlayerPawn(aPlayer).Default.PolyColorAdjust;
01200			}
01201	
01202			aPlayer.ReducedDamageType = aPlayer.Default.ReducedDamageType;
01203			aPlayer.ReducedDamagePct = aPlayer.Default.ReducedDamagePct;
01204			aPlayer.Style = aPlayer.Default.Style;
01205			aPlayer.bInvisible = aPlayer.Default.bInvisible;
01206			aPlayer.SpeedScale = SS_Circular;
01207			aPlayer.bLookFocusPlayer = aPlayer.Default.bLookFocusPlayer;
01208			aPlayer.bAlignToFloor = aPlayer.Default.bAlignToFloor;
01209			aPlayer.ColorAdjust = aPlayer.Default.ColorAdjust;
01210			aPlayer.ScaleGlow = aPlayer.Default.ScaleGlow;
01211			aPlayer.Fatness = aPlayer.Default.Fatness;
01212			aPlayer.BlendAnimSequence = aPlayer.Default.BlendAnimSequence;
01213			aPlayer.DesiredFatness = aPlayer.Default.DesiredFatness;
01214			aPlayer.MaxHealth = aPlayer.Default.MaxHealth;
01215			aPlayer.Strength = aPlayer.Default.Strength;
01216			aPlayer.MaxStrength = aPlayer.Default.MaxStrength;
01217			aPlayer.RunePower = aPlayer.Default.RunePower;
01218			aPlayer.MaxPower = aPlayer.Default.MaxPower;
01219			aPlayer.GroundSpeed = aPlayer.Default.GroundSpeed;
01220			aPlayer.SetDefaultPolyGroups();
01221			aPlayer.SetDefaultJointFlags();
01222			for (i=0; i<aPlayer.NumJoints(); i++)
01223			{	// Get rid of all attachments
01224				A = aPlayer.DetachActorFromJoint(i);
01225				if (A!=None)
01226					A.Destroy();
01227			}
01228			for (i=0; i<NUM_BODYPARTS; i++)
01229			{	// Restore body part health
01230				aPlayer.BodyPartHealth[i] = aPlayer.Default.BodyPartHealth[i];
01231			}
01232			// Restore joint flags
01233			aPlayer.SetDefaultJointFlags();
01234			for (i=0; i<16; i++)
01235			{	// Restore polygroup skins/properties
01236				aPlayer.SkelGroupSkins[i] = aPlayer.Default.SkelGroupSkins[i];
01237				aPlayer.SkelGroupFlags[i] = aPlayer.Default.SkelGroupFlags[i];
01238			}
01239			aPlayer.SetSkinActor(aPlayer, aPlayer.CurrentSkin);
01240	
01241			AddDefaultInventory(aPlayer);
01242	
01243			// Reset anim proxy vars
01244			if(PlayerPawn(aPlayer) != None && PlayerPawn(aPlayer).AnimProxy != None)
01245			{
01246				PlayerPawn(aPlayer).AnimProxy.GotoState('Idle');
01247			}
01248		}
01249		else
01250			log(startspot$" Player start not useable!!!");
01251	
01252		return foundStart;
01253	}
01254	
01255	//
01256	// Start a player.
01257	//
01258	function StartPlayer(PlayerPawn Other)
01259	{
01260		if( Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer || !bRestartLevel )
01261			Other.GotoState(Other.PlayerRestartState);
01262		else
01263			Other.ClientTravel( "?restart", TRAVEL_Relative, false );
01264	}
01265	
01266	//------------------------------------------------------------------------------
01267	// Level death message functions.
01268	//------------------------------------------------------------------------------
01269	
01270	//-------------------------------------------------------
01271	//
01272	// Killed
01273	//
01274	// Display a death message, called when a pawn is killed
01275	//-------------------------------------------------------
01276	function Killed( pawn killer, pawn Other, name damageType )
01277	{
01278		local string killed;
01279		local string message;
01280		local string KillerWeaponName;
01281		local string VictimWeaponName;
01282		local string DeathMessage;
01283	
01284		if (Other.bIsPlayer)
01285		{
01286			if ( (Killer == Other) || (Killer == None) )
01287			{
01288				// suicide
01289				if ( LocalLog != None )
01290					LocalLog.LogSuicide(Other, damageType, Killer);
01291				if ( WorldLog != None )
01292					WorldLog.LogSuicide(Other, damageType, Killer);
01293				message = KillMessage(damageType, None);
01294				BroadcastMessage(Other.PlayerReplicationInfo.PlayerName$message, false, 'DeathMessage');
01295			}
01296			else
01297			{
01298				DeathMessage = KillMessage(damageType, Killer);
01299				if (Killer.Weapon != None)
01300					KillerWeaponName = Killer.Weapon.ItemName;
01301				if (Other.Weapon != None)
01302					VictimWeaponName = Other.Weapon.ItemName;
01303				if ( LocalLog != None && Killer.bIsPlayer)
01304					LocalLog.LogKill(
01305							Killer.PlayerReplicationInfo.PlayerID,
01306							Other.PlayerReplicationInfo.PlayerID,
01307							KillerWeaponName,
01308							VictimWeaponName,
01309							damageType
01310					);
01311				if ( WorldLog != None  && Killer.bIsPlayer)
01312					WorldLog.LogKill(
01313							Killer.PlayerReplicationInfo.PlayerID,
01314							Other.PlayerReplicationInfo.PlayerID,
01315							KillerWeaponName,
01316							VictimWeaponName,
01317							damageType
01318					);
01319	
01320				killed = Other.PlayerReplicationInfo.PlayerName;
01321				if ( (DamageType == 'SpecialDamage') && (SpecialDamageString != "") && Killer.bIsPlayer)
01322				{
01323					message = ParseKillMessage(
01324						Killer.PlayerReplicationInfo.PlayerName,
01325						Other.PlayerReplicationInfo.PlayerName,
01326						KillerWeaponName,
01327						SpecialDamageString
01328					);
01329					BroadcastMessage(message, false, 'DeathMessage');
01330				}
01331				else if (Killer.bIsPlayer)
01332				{
01333					message = ParseKillMessage(
01334						Killer.PlayerReplicationInfo.PlayerName,
01335						Other.PlayerReplicationInfo.PlayerName,
01336						KillerWeaponName,
01337						DeathMessage
01338					);
01339					BroadcastMessage(message, false, 'DeathMessage');
01340				}
01341			}
01342		}
01343		ScoreKill(killer, Other);
01344	}
01345	
01346	function BroadcastRegularDeathMessage(pawn Killer, pawn Other, name damageType)
01347	{
01348		BroadcastLocalizedMessage(DeathMessageClass, 0, Killer.PlayerReplicationInfo, Other.PlayerReplicationInfo, Killer.Weapon.Class);
01349	}
01350	
01351	// %k = Owner's PlayerName (Killer)
01352	// %o = Other's PlayerName (Victim)
01353	// %w = Owner's Weapon ItemName
01354	static native function string ParseKillMessage( string KillerName, string VictimName, string WeaponName, string DeathMessage );
01355	
01356	function ScoreKill(pawn Killer, pawn Other)
01357	{
01358		if (Other==None)
01359		{
01360			log("Warning: ScoreKill (OTHER==NONE): Killer="$Killer@"Other="$Other);
01361			return;
01362		}
01363	
01364		Other.DieCount++;
01365		if (Other.bIsPlayer && Other.PlayerReplicationInfo != None)
01366			Other.PlayerReplicationInfo.Deaths +=1;
01367	
01368		if( (killer == Other) || (killer == None) )
01369		{
01370			if (Other.PlayerReplicationInfo != None)
01371				Other.PlayerReplicationInfo.Score -= 1;
01372		}
01373		else if ( killer != None )
01374		{
01375			killer.killCount++;
01376			if ( killer.PlayerReplicationInfo != None )
01377				killer.PlayerReplicationInfo.Score += 1;
01378		}
01379		BaseMutator.ScoreKill(Killer, Other);
01380	}	
01381	
01382	//
01383	// Default death message.
01384	//
01385	static function string KillMessage( name damageType, pawn killer )
01386	{
01387		return " died.";
01388	}
01389	
01390	//-------------------------------------------------------------------------------------
01391	// Level gameplay modification.
01392	
01393	//
01394	// Return whether Viewer is allowed to spectate from the
01395	// point of view of ViewTarget.
01396	//
01397	function bool CanSpectate( pawn Viewer, actor ViewTarget )
01398	{
01399		return true;
01400	}
01401	
01402	function RegisterDamageMutator(Mutator M)
01403	{
01404		M.NextDamageMutator = DamageMutator;
01405		DamageMutator = M;
01406	}
01407	
01408	
01409	//
01410	// Use reduce damage for teamplay modifications, etc.
01411	//
01412	function ReduceDamage( out int BluntDamage, out int SeverDamage, name DamageType, pawn injured, pawn instigatedBy )
01413	{
01414		if (injured.Region.Zone.bNeutralZone)
01415		{	// Sanctuary
01416			BluntDamage = 0;
01417			SeverDamage = 0;
01418		}
01419		else if ( injured.bIsPlayer )
01420		{
01421			switch(Difficulty)
01422			{
01423			case 0:
01424				BluntDamage = BluntDamage * 0.5;
01425				SeverDamage = SeverDamage * 0.5;
01426				break;
01427			case 1:
01428				BluntDamage = BluntDamage;
01429				SeverDamage = SeverDamage;
01430				break;
01431			case 2:
01432				BluntDamage = BluntDamage * 1.5;
01433				SeverDamage = SeverDamage * 1.5;
01434				break;
01435			case 3:
01436				BluntDamage = BluntDamage * 2;
01437				SeverDamage = SeverDamage * 2;
01438				break;
01439			}
01440	
01441			if (injured.ReducedDamageType=='All')
01442			{	// God Mode
01443				BluntDamage = 0;
01444				SeverDamage = 0;
01445			}
01446			else if (injured.ReducedDamageType=='conventional')
01447			{	// Spirit
01448				if (DamageType=='blunt' || DamageType=='thrownweaponblunt' ||
01449					DamageType=='sever' || DamageType=='thrownweaponsever' ||
01450					DamageType=='bluntsever' || DamageType=='thrownweaponbluntsever')
01451				{
01452					BluntDamage = float(BluntDamage) * (1 - injured.ReducedDamagePct);
01453					SeverDamage = float(SeverDamage) * (1 - injured.ReducedDamagePct);
01454				}
01455			}
01456			else if (injured.Inventory != None)
01457			{	//then check if carrying armor
01458				injured.Inventory.ReduceDamage(BluntDamage, SeverDamage, DamageType, injured.Location);
01459			}
01460		}
01461		else if ( (injured.ReducedDamageType == 'All') || 
01462			((injured.ReducedDamageType != '') && (injured.ReducedDamageType == damageType)) )
01463		{	// Reduced damage
01464			BluntDamage = float(BluntDamage) * (1 - injured.ReducedDamagePct);
01465			SeverDamage = float(SeverDamage) * (1 - injured.ReducedDamagePct);
01466		}
01467	}
01468	
01469	//
01470	// Award a score to an actor.
01471	//
01472	function ScoreEvent( name EventName, actor EventActor, pawn InstigatedBy )
01473	{
01474	}
01475	
01476	//
01477	// Return whether an item should respawn.
01478	//
01479	function bool ShouldRespawn( actor Other )
01480	{
01481		if( Level.NetMode == NM_StandAlone )
01482			return false;
01483		return Inventory(Other)!=None && Inventory(Other).ReSpawnTime!=0.0;
01484	}
01485	
01486	//
01487	// Called when pawn has a chance to pick Item up (i.e. when 
01488	// the pawn touches a weapon pickup). Should return true if 
01489	// he wants to pick it up, false if he does not want it.
01490	//
01491	function bool PickupQuery( Pawn Other, Inventory item )
01492	{
01493		if ( !Other.CanPickup(item) )
01494			return false;
01495		
01496		if ( !Other.WantsToPickup(item) )
01497			return false;
01498			
01499		if ( Other.Inventory == None )
01500			return true;
01501		else
01502			return !Other.Inventory.HandlePickupQuery(Item);
01503	}
01504	
01505	function bool AllowWeaponDrop()
01506	{
01507		return (bAllowWeaponDrop && BaseMutator.AllowWeaponDrop());
01508	}
01509	
01510	function bool AllowShieldDrop()
01511	{
01512		return (bAllowShieldDrop && BaseMutator.AllowShieldDrop());
01513	}
01514	
01515	//
01516	// Discard a player's inventory after he dies.
01517	//
01518	function DiscardInventory( Pawn Other )
01519	{
01520		local actor dropped;
01521		local inventory Inv;
01522		local weapon weap;
01523		local float speed;
01524		local inventory next;
01525	
01526		if( Other.DropWhenKilled != None )
01527		{
01528			dropped = Spawn(Other.DropWhenKilled,,,Other.Location);
01529			Inv = Inventory(dropped);
01530			if ( Inv != None )
01531			{ 
01532				Inv.RespawnTime = 0.0; //don't respawn
01533				Inv.BecomePickup();		
01534			}
01535			if ( dropped != None )
01536			{
01537				dropped.RemoteRole = ROLE_DumbProxy;
01538				dropped.SetPhysics(PHYS_Falling);
01539				dropped.bCollideWorld = true;
01540				dropped.Velocity = Other.Velocity + VRand() * 280;
01541			}
01542			if ( Inv != None )
01543				Inv.GotoState('PickUp', 'Dropped');
01544		}
01545	
01546		Other.Weapon = None;
01547		Other.Shield = None;
01548		Other.SelectedItem = None;
01549		for( Inv=Other.Inventory; Inv!=None; Inv = next )
01550		{
01551			next = Inv.Inventory;
01552			Inv.Destroy();
01553		}
01554	}
01555	
01556	// Return the player jumpZ scaling for this gametype
01557	function float PlayerJumpZScaling()
01558	{
01559		return 1.0;
01560	}
01561	
01562	//
01563	// Try to change a player's name.
01564	//	
01565	function ChangeName( Pawn Other, coerce string S, bool bNameChange )
01566	{
01567		if( S == "" )
01568			return;
01569		if (LocalLog != None)
01570			LocalLog.LogNameChange(Other);
01571		if (WorldLog != None)
01572			WorldLog.LogNameChange(Other);
01573		Other.PlayerReplicationInfo.PlayerName = S;
01574		if( bNameChange )
01575			Other.ClientMessage( NameChangedMessage $ Other.PlayerReplicationInfo.PlayerName );
01576	}
01577	
01578	//
01579	// Return whether a team change is allowed.
01580	//
01581	function bool ChangeTeam(Pawn Other, int N)
01582	{
01583		Other.PlayerReplicationInfo.Team = N;
01584		if (LocalLog != None)
01585			LocalLog.LogTeamChange(Other);
01586		if (WorldLog != None)
01587			WorldLog.LogTeamChange(Other);
01588		return true;
01589	}
01590	
01591	//
01592	// Play an inventory respawn effect.
01593	//
01594	function float PlaySpawnEffect( inventory Inv )
01595	{
01596		return 0.3;
01597	}
01598	
01599	//
01600	// Generate a player killled message.
01601	//
01602	static function string PlayerKillMessage( name damageType, PlayerReplicationInfo Other )
01603	{
01604		local string message;
01605	
01606		message = " was killed by ";
01607		return message;
01608	}
01609	
01610	//
01611	// Generate a killed by creature message.
01612	//
01613	static function string CreatureKillMessage( name damageType, pawn Other )
01614	{
01615		return " was killed by a ";
01616	}
01617	
01618	//
01619	// Send a player to a URL.
01620	//
01621	function SendPlayer( PlayerPawn aPlayer, string URL )
01622	{
01623		aPlayer.ClientTravel( URL, TRAVEL_Relative, true );
01624	}
01625	
01626	//
01627	// Play a teleporting special effect.
01628	//
01629	function PlayTeleportEffect( actor Incoming, bool bOut, bool bSound);
01630	
01631	//
01632	// Restart the game.
01633	//
01634	function RestartGame()
01635	{
01636		Level.ServerTravel( "?Restart", false );
01637	}
01638	
01639	//
01640	// Whether players are allowed to broadcast messages now.
01641	//
01642	function bool AllowsBroadcast( actor broadcaster, int Len )
01643	{
01644		SentText += Len;
01645	
01646		return (SentText < 260);
01647	}
01648	
01649	//
01650	// End of game.
01651	//
01652	function EndGame( string Reason )
01653	{
01654		local actor A;
01655	
01656		// don't end game if not really ready
01657		if ( !SetEndCams(Reason) )
01658		{
01659			bOverTime = true;
01660			return;
01661		}
01662		bGameEnded = true;
01663		foreach AllActors(class'Actor', A, 'EndGame')
01664			A.trigger(self, none);
01665	
01666		if (LocalLog != None)
01667		{
01668			LocalLog.LogGameEnd(Reason);
01669			LocalLog.StopLog();
01670			if (bBatchLocal)
01671				LocalLog.ExecuteSilentLogBatcher();
01672			LocalLog.Destroy();
01673			LocalLog = None;
01674		}
01675		if (WorldLog != None)
01676		{
01677			WorldLog.LogGameEnd(Reason);
01678			WorldLog.StopLog();
01679			WorldLog.ExecuteWorldLogBatcher();
01680			WorldLog.Destroy();
01681			WorldLog = None;
01682		}
01683	}
01684	
01685	function bool SetEndCams(string Reason)
01686	{
01687		local pawn aPawn;
01688	
01689		for ( aPawn=Level.PawnList; aPawn!=None; aPawn=aPawn.NextPawn )
01690			if ( aPawn.bIsPlayer )
01691			{
01692				aPawn.GotoState('GameEnded');
01693				aPawn.ClientGameEnded();
01694			}	
01695	
01696		return true;
01697	}
01698	
01699	function vector GetTeamVectorColor(int num)
01700	{
01701		return vect(255,255,255);
01702	}
01703	
01704	simulated function Debug(Canvas canvas, int mode)
01705	{
01706		Super.Debug(canvas, mode);
01707	
01708		Canvas.DrawText("GameInfo:");
01709		Canvas.CurY -= 8;
01710		Canvas.DrawText("  bGameEnded: " $ bGameEnded);
01711		Canvas.CurY -= 8;
01712		Canvas.DrawText("  RuleList:   " $ GetRules());
01713		Canvas.CurY -= 8;
01714		Canvas.DrawText("  bAllowWeaponDrop: " $ bAllowWeaponDrop);
01715		Canvas.CurY -= 8;
01716		Canvas.DrawText("  bAllowShieldDrop: " $ bAllowShieldDrop);
01717		Canvas.CurY -= 8;
01718	
01719	}
01720	
01721	defaultproperties
01722	{
01723	     Difficulty=1
01724	     bRestartLevel=True
01725	     bPauseable=True
01726	     bCanChangeSkin=True
01727	     bCanViewOthers=True
01728	     bAllowWeaponDrop=True
01729	     bAllowShieldDrop=True
01730	     AutoAim=0.930000
01731	     GameSpeed=1.000000
01732	     MaxSpectators=2
01733	     AdminPassword="72777228"
01734	     SwitchLevelMessage="Switching Levels"
01735	     DefaultPlayerName="Player"
01736	     LeftMessage=" left the game."
01737	     FailedSpawnMessage="Failed to spawn player actor"
01738	     FailedPlaceMessage="Could not find starting spot (level might need a 'PlayerStart' actor)"
01739	     FailedTeamMessage="Could not find team for player"
01740	     NameChangedMessage="Name changed to "
01741	     EnteredMessage=" entered the game."
01742	     GameName="Game"
01743	     MaxedOutMessage="Server is already at capacity."
01744	     WrongPassword="The password you entered is incorrect."
01745	     NeedPassword="You need to enter a password to join this game."
01746	     IPBanned="Your IP address has been banned on this server."
01747	     MaxPlayers=16
01748	     IPPolicies(0)="ACCEPT,*"
01749	     DeathMessageClass=Class'Engine.LocalMessage'
01750	     MutatorClass=Class'Engine.Mutator'
01751	     DefaultPlayerState=PlayerWalking
01752	     ServerLogName="server.log"
01753	     bLocalLog=True
01754	     bWorldLog=True
01755	     bSubtitles=True
01756	     StatLogClass=Class'Engine.StatLogFile'
01757	     DebrisPercentage=0.900000
01758	     ParticlePercentage=1.000000
01759	     bAllowLimbSever=True
01760	}

End Source Code