Engine
Class GameInfo

source: C:\XIII\Engine\Classes\GameInfo.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Info
         |
         +--Engine.GameInfo
Direct Known Subclasses:XIIIGameInfo

class GameInfo
extends Engine.Info

//============================================================================= // GameInfo. // // The GameInfo defines the game being played: the game rules, scoring, what actors // are allowed to exist in this game type, and who may enter the game. While the // GameInfo class is the public interface, much of this functionality is delegated // to several classes to allow easy modification of specific game components. These // classes include GameInfo, AccessControl, Mutator, BroadcastHandler, and GameRules. // A GameInfo actor is instantiated when the level is initialized for gameplay (in // C++ UGameEngine::LoadMap() ). The class of this GameInfo actor is determined by // (in order) either the DefaultGameType if specified in the LevelInfo, or the // DefaultGame entry in the game's .ini file (in the Engine.Engine section), unless // its a network game in which case the DefaultServerGame entry is used. // //=============================================================================
Variables
 AccessControl AccessControl
           AccessControl controls whether players can enter and/or become admins
 string AccessControlClass
           linked list of Mutators (for modifying actors as they enter the game)
 array AlarmList
           idem
 array AttackPointList
           idem
 Mutator BaseMutator
           linked list of Mutators (for modifying actors as they enter the game)
 array BaseSoldierList
           to avoid foreach repeated calls in BaseSoldiers
 string BeaconName
           Identifying string used for finding LAN servers.
 BroadcastHandler BroadcastHandler
           handles message (text and localized) broadcasts
 string BroadcastHandlerClass
           linked list of modifier classes which affect game rules
 int CurrentID
           set the PlayerID of each player to different using CurrentID++
 class DeathMessageClass
           Class for sending Death messages.
 string DefaultPlayerClassName
           Default player Pawn class
 string DefaultPlayerName
           Default player name
 byte DetailLevel
           0=Low, 1=Normal, 2=High
 byte Difficulty
           0=easy, 1=medium, 2=hard, 3=very hard.
 float DummyStuff1
           default player controller class name
 int DummyStuff2
           default player controller class name
 class GameMessageClass
           Class for sending GameType specific messages.
 string GameName
           Name of the game type
 GameReplicationInfo GameReplicationInfo
           default player controller class name
 class GameReplicationInfoClass
           default player controller class name
 GameRules GameRulesModifiers
           linked list of modifier classes which affect game rules
 float GameSpeed
           Scale applied to game rate.
 Keypoint GenAlerte
           idem
 int GoreLevel
           0=Normal, increasing values=less gore
 array GrenadeTargetList
           idem
 string HUDType
           HUD class this game uses.
 string MapPrefix
           Prefix characters for names of maps for this game type.
 int MaxPlayers
           Maximum number of players
 int MaxSpectators
           Maximum number of spectators.
 string MutatorClass
           Base mutator class to use for the game
 int NumBots
           number of non-human players (AI controlled but participating as a player)
 int NumPlayers
           number of human players
 int NumSpectators
           Current number of spectators.
 array PatrolPointList
           idem
 class PlayerControllerClass
           type of player controller to spawn for players logging in
 string PlayerControllerClassName
           default player controller class name
 array SafePointList
           idem
 string ScoreBoardType
           ScoreBoard class this game uses.
 StatLog StatLog
           default player controller class name
 class StatLogClass
           default player controller class name
 int StatPlayerStart[8]
           idem
 bool bAlternateMode
           Alternate mode Gore -> Peace&Love
 bool bCanViewOthers
           to avoid cheat ViewClass in multi ;)
 bool bCoopWeaponMode
           Whether or not weapons stay when picked up.
 bool bDelayedStart
           When logging, a player is sent to PlayerWaiting instead of being restarted
 bool bGameEnded
           set when game ends
 bool bInventorySetUp
           Used by Saving/Loading (AcceptInventory)
 bool bLocalLog
           Not every logged player is ready, wait for all of them to have PlayerReplicationInfo.bReadyToPlay = true
 bool bLoggingGame
           Does this gametype log?
 bool bOverTime
           Game should be ended but wait for Tie to resolve.
 bool bPauseable
           Whether the game is pauseable.
 bool bRestartLevel
           Level should be restarted when player dies
 bool bTeamGame
           This is a team game.
 bool bWaitingToStartMatch
           Not every logged player is ready, wait for all of them to have PlayerReplicationInfo.bReadyToPlay = true
 bool bWorldLog
           Not every logged player is ready, wait for all of them to have PlayerReplicationInfo.bReadyToPlay = true


Function Summary
 void AddDefaultInventory(Pawn PlayerPawn)
     
//
// Spawn any default inventory for the player.
//
 bool AtCapacity(bool bSpectator)
 void BroadcastTeam(Controller Sender, string Msg, optional name)
 bool CanSpectate(PlayerController Viewer, Actor ViewTarget)
     
//
// Return whether Viewer is allowed to spectate from the
// point of view of ViewTarget.
//
 void ChangeName(Controller Other, string S, bool bNameChange)
     
/* Try to change a player's name.
*/
 bool ChangeTeam(Controller Other, int N)
     
/* Return whether a team change is allowed.
*/
 bool CheckEndGame(PlayerReplicationInfo Winner, string Reason)
     
//==========================================================================
 void CheckScore(PlayerReplicationInfo Scorer)
     
/* CheckScore()
see if this score means the game ends
*/
 void DiscardInventory(Pawn Other)
     
/* Discard a player's inventory after he dies.
*/
 void EndGame(PlayerReplicationInfo Winner, string Reason)
     
/* End of game.
*/
 void EndLogging(string Reason)
 NavigationPoint FindPlayerStart(Controller Player, optional byte, optional string)
     
/* Return the 'best' player start for this player to start from.
 */
 string GetDefaultPlayerClassName(Controller C)
 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.
 bool GrabOption(out string, out string)
     
//
// Grab the next option from a string.
//
 void InitGameReplicationInfo()
     
//------------------------------------------------------------------------------
// Replication
 void InitLists()
     
//_____________________________________________________________________________
 void InitLogging()
     
/* InitLogging()
Set up statistics logging
*/
 bool IsOnTeam(Controller Other, int TeamNum)
 void Kick(string S)
 void KickBan(string S)
 void LogGameParameters()
     
//------------------------------------------------------------------------------
// Stat Logging.
 void Logout(Controller Exiting)
     
//
// Player exits.
//
 void NotifyKilled(Controller Killer, Controller Killed, Pawn KilledPawn)
 string ParseKillMessage(string KillerName, string VictimName, string DeathMessage)
     
// %k = Owner's PlayerName (Killer)
// %o = Other's PlayerName (Victim)
// %w = Owner's Weapon ItemName
 string ParseOption(string Options, string InKey)
     
/* ParseOption()
 Find an option in the options string and return it.
*/
 byte PickTeam(byte Current)
     
/* Return a picked team number if none was specified
*/
 bool PickupQuery(Pawn Other, Pickup 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(Pickup P)
     
/* Play an inventory respawn effect.
*/
 void PlayTeleportEffect(Actor Incoming, bool bOut, bool bSound)
     
/* Play a teleporting special effect.
*/
 void ProcessServerTravel(string URL, bool bItems)
     
/* ProcessServerTravel()
 Optional handling of ServerTravel for network games.
*/
 float RatePlayerStart(NavigationPoint N, byte Team, Controller Player)
     
/* Rate whether player should choose this NavigationPoint as its start
default implementation is for single player game
*/
 void Reset()
     
/* Reset()
reset actor to initial state - used when restarting level without reloading.
*/
 void RestartGame()
     
/* Restart the game.
*/
 void RestartPlayer(Controller aPlayer)
     
//
// Restart a player.
//
 void ScoreKill(Controller Killer, Controller Other)
 void ScoreObjective(PlayerReplicationInfo Scorer, Int Score)
 void SendPlayer(PlayerController aPlayer, string URL)
     
/* Send a player to a URL.
*/
 void SendStartMessage(PlayerController P)
 void SetGameSpeed(Float T)
     
//
// Set gameplay speed.
//
 bool SetPause(BOOL bPause, PlayerController P)
 void SetPlayerDefaults(Pawn PlayerPawn)
     
/* SetPlayerDefaults()
 first make sure pawn properties are back to default, then give mutators an opportunity
 to modify them
*/
 bool ShouldRespawn(Pickup Other)
     
//
// Return whether an item should respawn.
//
 void StartMatch()
     
/* StartMatch()
Start the game - inform all actors that the match is starting, and spawn player pawns
*/



Source Code


00001	//=============================================================================
00002	// GameInfo.
00003	//
00004	// The GameInfo defines the game being played: the game rules, scoring, what actors
00005	// are allowed to exist in this game type, and who may enter the game.  While the
00006	// GameInfo class is the public interface, much of this functionality is delegated
00007	// to several classes to allow easy modification of specific game components.  These
00008	// classes include GameInfo, AccessControl, Mutator, BroadcastHandler, and GameRules.
00009	// A GameInfo actor is instantiated when the level is initialized for gameplay (in
00010	// C++ UGameEngine::LoadMap() ).  The class of this GameInfo actor is determined by
00011	// (in order) either the DefaultGameType if specified in the LevelInfo, or the
00012	// DefaultGame entry in the game's .ini file (in the Engine.Engine section), unless
00013	// its a network game in which case the DefaultServerGame entry is used.
00014	//
00015	//=============================================================================
00016	class GameInfo extends Info
00017	  config(user)
00018	  native;
00019	
00020	//____________________________________________________________________________
00021	// Variables.
00022	var globalconfig byte Difficulty; // 0=easy, 1=medium, 2=hard, 3=very hard.
00023	var globalconfig byte DetailLevel;// 0=Low, 1=Normal, 2=High
00024	
00025	// Group bools
00026	var bool bRestartLevel;           // Level should be restarted when player dies
00027	var bool bPauseable;              // Whether the game is pauseable.
00028	var bool bCoopWeaponMode;  // Whether or not weapons stay when picked up.
00029	var bool bTeamGame;               // This is a team game.
00030	var bool bGameEnded;              // set when game ends
00031	var bool bOverTime;               // Game should be ended but wait for Tie to resolve.
00032	var globalconfig bool bAlternateMode;// Alternate mode Gore -> Peace&Love
00033	var bool bCanViewOthers;          // to avoid cheat ViewClass in multi ;)
00034	var bool bDelayedStart;           // When logging, a player is sent to PlayerWaiting instead of being restarted
00035	var bool bWaitingToStartMatch;    // Not every logged player is ready, wait for all of them to have PlayerReplicationInfo.bReadyToPlay = true
00036	// Statistics Logging
00037	var globalconfig bool bLocalLog;
00038	var globalconfig bool bWorldLog;
00039	var bool bLoggingGame;            // Does this gametype log?
00040	var bool bInventorySetUp;         // Used by Saving/Loading (AcceptInventory)
00041	
00042	var globalconfig int GoreLevel;   // 0=Normal, increasing values=less gore
00043	var float GameSpeed;              // Scale applied to game rate.
00044	var string DefaultPlayerClassName;// Default player Pawn class
00045	// user interface
00046	var string ScoreBoardType;        // ScoreBoard class this game uses.
00047	var string HUDType;               // HUD class this game uses.
00048	var string MapPrefix;             // Prefix characters for names of maps for this game type.
00049	var string BeaconName;            // Identifying string used for finding LAN servers.
00050	
00051	var int MaxSpectators;            // Maximum number of spectators.
00052	var int NumSpectators;            // Current number of spectators.
00053	var int MaxPlayers;               // Maximum number of players
00054	var int NumPlayers;               // number of human players
00055	var int NumBots;                  // number of non-human players (AI controlled but participating as a player)
00056	var int CurrentID;                // set the PlayerID of each player to different using CurrentID++
00057	var localized string DefaultPlayerName;   // Default player name
00058	var localized string GameName;    // Name of the game type
00059	
00060	// Message classes.
00061	var class<LocalMessage> DeathMessageClass;  // Class for sending Death messages.
00062	var class<GameMessage> GameMessageClass;    // Class for sending GameType specific messages.
00063	
00064	// GameInfo components
00065	var string MutatorClass;          // Base mutator class to use for the game
00066	var Mutator BaseMutator;          // linked list of Mutators (for modifying actors as they enter the game)
00067	
00068	var string AccessControlClass;
00069	var AccessControl AccessControl;  // AccessControl controls whether players can enter and/or become admins
00070	var GameRules GameRulesModifiers; // linked list of modifier classes which affect game rules
00071	var string BroadcastHandlerClass;
00072	var BroadcastHandler BroadcastHandler;    // handles message (text and localized) broadcasts
00073	
00074	var class<PlayerController> PlayerControllerClass;    // type of player controller to spawn for players logging in
00075	var string PlayerControllerClassName;                 // default player controller class name
00076	
00077	// ReplicationInfo
00078	var() class<GameReplicationInfo> GameReplicationInfoClass;
00079	var GameReplicationInfo GameReplicationInfo;
00080	
00081	var float DummyStuff1;
00082	var int DummyStuff2;
00083	
00084	// Statistics Logging
00085	var StatLog StatLog;
00086	var class<StatLog> StatLogClass;
00087	
00088	//actor's lists
00089	var keypoint GenAlerte;                       // idem
00090	var array<Pawn> BaseSoldierList;          // to avoid foreach repeated calls in BaseSoldiers
00091	var array<Triggers> AlarmList;            // idem
00092	var array<Keypoint> GrenadeTargetList;        // idem
00093	var array<NavigationPoint> SafePointList;     // idem
00094	var array<NavigationPoint> AttackPointList;   // idem
00095	var array<NavigationPoint> PatrolPointList;   // idem
00096	var int StatPlayerStart[8];
00097	
00098	//____________________________________________________________________________
00099	// Engine notifications.
00100	
00101	event PreBeginPlay()
00102	{
00103	  SetGameSpeed(GameSpeed);
00104	  GameReplicationInfo = Spawn(GameReplicationInfoClass);
00105	  InitGameReplicationInfo();
00106	}
00107	
00108	event PostBeginPlay()
00109	{
00110	//  if ( bAlternateMode )
00111	//    GoreLevel = 2;
00112	  InitLogging();
00113	  InitLists();
00114	  Super.PostBeginPlay();
00115	}
00116	
00117	//_____________________________________________________________________________
00118	function InitLists()
00119	{
00120	    local Pawn P;
00121	    local Triggers T;
00122	    local Keypoint K;
00123	    local Navigationpoint N;
00124	
00125	    foreach dynamicactors(class'Pawn', P)
00126	//    foreach ActorInIterationCategory(1, 1, P)
00127	    {
00128	      if ( (P != none) && P.IsA('BaseSoldier') && !P.IsA('Cine2') ) // Have to do this because Basesoldier unknown (in later package)
00129	      {
00130	        BaseSoldierList.Length = BaseSoldierList.Length + 1;
00131	        BaseSoldierList[BaseSoldierList.Length - 1] = P;
00132	      }
00133	    }
00134	    foreach dynamicactors(class'Triggers', T)
00135	//    foreach ActorInIterationCategory(2, 2, P)
00136	    {
00137	      if ( (T != none) && T.IsA('TriggerAlarme') )
00138	      {
00139	        AlarmList.Length = AlarmList.Length + 1;
00140	        AlarmList[AlarmList.Length - 1] = T;
00141	      }
00142	    }
00143	    foreach Allactors(class'keypoint', K)
00144	//    foreach ActorInIterationCategory(3, 3, P)
00145	    {
00146	      if ( K != none )
00147	      {
00148	        if ( K.IsA('GrenadeTarget') )
00149	        {
00150	          GrenadeTargetList.Length = GrenadeTargetList.Length + 1;
00151	          GrenadeTargetList[GrenadeTargetList.Length - 1] = K;
00152	        }
00153	        else if ( K.IsA('GenAlerte') )
00154	        {
00155	          GenAlerte = K;
00156	        }
00157	      }
00158	    }
00159	    foreach Allactors(class'Navigationpoint', N)
00160	//    foreach ActorInIterationCategory(4, 6, P)
00161	    {
00162	      if ( N != none )
00163	      {
00164	        if ( N.IsA('SafePoint') )
00165	        {
00166	          SafePointList.Length = SafePointList.Length + 1;
00167	          SafePointList[SafePointList.Length - 1] = N;
00168	        }
00169	        else if ( N.IsA('AttackPoint') )
00170	        {
00171	          AttackPointList.Length = AttackPointList.Length + 1;
00172	          AttackPointList[AttackPointList.Length - 1] = N;
00173	        }
00174	        else if ( N.IsA('PatrolPoint') )
00175	        {
00176	          PatrolPointList.Length = PatrolPointList.Length + 1;
00177	          PatrolPointList[PatrolPointList.Length - 1] = N;
00178	        }
00179	      }
00180	    }
00181	}
00182	/* Reset()
00183	reset actor to initial state - used when restarting level without reloading.
00184	*/
00185	function Reset()
00186	{
00187	  Super.Reset();
00188	  bGameEnded = false;
00189	  bOverTime = false;
00190	  bWaitingToStartMatch = true;
00191	  InitGameReplicationInfo();
00192	}
00193	
00194	/* InitLogging()
00195	Set up statistics logging
00196	*/
00197	function InitLogging()
00198	{
00199	  local bool bLoggingWorld;
00200	
00201	  if ( !bLoggingGame )
00202	    return;
00203	
00204	  bLoggingWorld = bWorldLog &&
00205	    ((Level.NetMode == NM_DedicatedServer) || (Level.NetMode == NM_ListenServer));
00206	  if ( bLocalLog || bLoggingWorld )
00207	  {
00208	    StatLog = spawn(StatLogClass);
00209	    Log("Initiating logging using "$StatLog$" class "$Statlogclass);
00210	    StatLog.GenerateLogs(bLocalLog, bLoggingWorld);
00211	    StatLog.StartLog();
00212	    LogGameParameters();
00213	  }
00214	}
00215	
00216	event Timer()
00217	{
00218	  BroadcastHandler.UpdateSentText();
00219	}
00220	
00221	// Called when game shutsdown.
00222	event GameEnding()
00223	{
00224	  EndLogging("serverquit");
00225	}
00226	
00227	//------------------------------------------------------------------------------
00228	// Replication
00229	
00230	function InitGameReplicationInfo()
00231	{
00232	  GameReplicationInfo.bTeamGame = bTeamGame;
00233	  GameReplicationInfo.GameName = GameName;
00234	  GameReplicationInfo.GameClass = string(Class);
00235	}
00236	
00237	native(573) static final function string GetNetworkNumber();
00238	
00239	//------------------------------------------------------------------------------
00240	// Game Querying.
00241	
00242	function string GetInfo()
00243	{
00244	  local string ResultSet;
00245	
00246	  // World logging enabled and working
00247	  if ( StatLog.bWorld && !StatLog.bWorldBatcherError )
00248	    ResultSet = "\\worldlog\\true";
00249	  else
00250	    ResultSet = "\\worldlog\\false";
00251	
00252	  // World logging activated
00253	  if ( StatLog.bWorld )
00254	    ResultSet = ResultSet$"\\wantworldlog\\true";
00255	  else
00256	    ResultSet = ResultSet$"\\wantworldlog\\false";
00257	
00258	  return ResultSet;
00259	}
00260	
00261	function string GetRules()
00262	{
00263	  local string ResultSet;
00264	  local Mutator M;
00265	  local string NextMutator, NextDesc;
00266	  local string EnabledMutators;
00267	  local int Num, i;
00268	
00269	  ResultSet = "";
00270	
00271	  EnabledMutators = "";
00272	  for (M = BaseMutator.NextMutator; M != None; M = M.NextMutator)
00273	  {
00274	    Num = 0;
00275	    NextMutator = "";
00276	    GetNextIntDesc("Engine.Mutator", 0, NextMutator, NextDesc);
00277	    while( (NextMutator != "") && (Num < 50) )
00278	    {
00279	      if(NextMutator ~= string(M.Class))
00280	      {
00281	        i = InStr(NextDesc, ",");
00282	        if(i != -1)
00283	          NextDesc = Left(NextDesc, i);
00284	
00285	        if(EnabledMutators != "")
00286	          EnabledMutators = EnabledMutators $ ", ";
00287	         EnabledMutators = EnabledMutators $ NextDesc;
00288	         break;
00289	      }
00290	
00291	      Num++;
00292	      GetNextIntDesc("Engine.Mutator", Num, NextMutator, NextDesc);
00293	    }
00294	  }
00295	  if(EnabledMutators != "")
00296	    ResultSet = ResultSet $ "\\mutators\\"$EnabledMutators;
00297	
00298	  ResultSet = ResultSet$"\\listenserver\\"$string(Level.NetMode==NM_ListenServer);
00299	//  Resultset = ResultSet$"\\changelevels\\"$bChangeLevels;
00300	  if ( GameRulesModifiers != None )
00301	    ResultSet = ResultSet$GameRulesModifiers.GetRules();
00302	
00303	  return ResultSet;
00304	}
00305	
00306	// Return the server's port number.
00307	function int GetServerPort()
00308	{
00309	  local string S;
00310	  local int i;
00311	
00312	  // Figure out the server's port.
00313	  S = Level.GetAddressURL();
00314	  i = InStr( S, ":" );
00315	  assert(i>=0);
00316	  return int(Mid(S,i+1));
00317	}
00318	
00319	function bool SetPause( BOOL bPause, PlayerController P )
00320	{
00321	  if( bPauseable || P.IsA('Admin') || Level.Netmode==NM_Standalone )
00322	  {
00323	    if( bPause )
00324	      Level.Pauser=P.PlayerReplicationInfo;
00325	    else
00326	      Level.Pauser=None;
00327	    return True;
00328	  }
00329	  else return False;
00330	}
00331	
00332	//------------------------------------------------------------------------------
00333	// Stat Logging.
00334	
00335	function LogGameParameters()
00336	{
00337	  local Mutator M;
00338	
00339	  for (M = BaseMutator; M != None; M = M.NextMutator)
00340	    StatLog.LogMutator(M);
00341	
00342	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameName"$Chr(9)$GameName);
00343	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameClass"$Chr(9)$Class);// <-- Move to c++
00344	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameVersion"$Chr(9)$Level.EngineVersion);
00345	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MinNetVersion"$Chr(9)$Level.MinNetVersion);
00346	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"WeaponsStay"$Chr(9)$bCoopWeaponMode);
00347	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GoreLevel"$Chr(9)$GoreLevel);
00348	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"TeamGame"$Chr(9)$bTeamGame);
00349	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"GameSpeed"$Chr(9)$int(GameSpeed*100));
00350	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MaxSpectators"$Chr(9)$MaxSpectators);
00351	  StatLog.LogEventString(StatLog.GetTimeStamp()$Chr(9)$"game"$Chr(9)$"MaxPlayers"$Chr(9)$MaxPlayers);
00352	}
00353	
00354	//------------------------------------------------------------------------------
00355	// Game parameters.
00356	
00357	//
00358	// Set gameplay speed.
00359	//
00360	function SetGameSpeed( Float T )
00361	{
00362	  local float OldSpeed;
00363	
00364	  OldSpeed = GameSpeed;
00365	  GameSpeed = FMax(T, 0.1);
00366	  Level.TimeDilation = GameSpeed;
00367	  if ( GameSpeed != OldSpeed )
00368	    SaveConfig();
00369	  SetTimer(Level.TimeDilation, true);
00370	}
00371	
00372	//
00373	// Called after setting low or high detail mode.
00374	//
00375	event DetailChange()
00376	{
00377	  local actor A;
00378	  local zoneinfo Z;
00379	  local skyzoneinfo S;
00380	
00381	  if( !Level.bHighDetailMode )
00382	  {
00383	    foreach DynamicActors(class'Actor', A)
00384	    {
00385	      if( A.bHighDetail && !A.bGameRelevant )
00386	        A.Destroy();
00387	    }
00388	  }
00389	  foreach AllActors(class'ZoneInfo', Z)
00390	    Z.LinkToSkybox();
00391	}
00392	
00393	//------------------------------------------------------------------------------
00394	// Player start functions
00395	
00396	//
00397	// Grab the next option from a string.
00398	//
00399	function bool GrabOption( out string Options, out string Result )
00400	{
00401	  if( Left(Options,1)=="?" )
00402	  {
00403	    // Get result.
00404	    Result = Mid(Options,1);
00405	    if( InStr(Result,"?")>=0 )
00406	      Result = Left( Result, InStr(Result,"?") );
00407	
00408	    // Update options.
00409	    Options = Mid(Options,1);
00410	    if( InStr(Options,"?")>=0 )
00411	      Options = Mid( Options, InStr(Options,"?") );
00412	    else
00413	      Options = "";
00414	
00415	    return true;
00416	  }
00417	  else return false;
00418	}
00419	
00420	//
00421	// break up a key=value pair into its key and value.
00422	//
00423	function GetKeyValue( string Pair, out string Key, out string Value )
00424	{
00425	  if( InStr(Pair,"=")>=0 )
00426	  {
00427	    Key   = Left(Pair,InStr(Pair,"="));
00428	    Value = Mid(Pair,InStr(Pair,"=")+1);
00429	  }
00430	  else
00431	  {
00432	    Key   = Pair;
00433	    Value = "";
00434	  }
00435	}
00436	
00437	/* ParseOption()
00438	 Find an option in the options string and return it.
00439	*/
00440	function string ParseOption( string Options, string InKey )
00441	{
00442	  local string Pair, Key, Value;
00443	  while( GrabOption( Options, Pair ) )
00444	  {
00445	    GetKeyValue( Pair, Key, Value );
00446	    if( Key ~= InKey )
00447	      return Value;
00448	  }
00449	  return "";
00450	}
00451	
00452	/* Initialize the game.
00453	 The GameInfo's InitGame() function is called before any other scripts (including
00454	 PreBeginPlay() ), and is used by the GameInfo to initialize parameters and spawn
00455	 its helper classes.
00456	 Warning: this is called before actors' PreBeginPlay.
00457	*/
00458	event InitGame( string Options, out string Error )
00459	{
00460	  local string InOpt, LeftOpt;
00461	  local int pos;
00462	  local class<Mutator> MClass;
00463	  local class<AccessControl> ACClass;
00464	  local class<GameRules> GRClass;
00465	  local class<BroadcastHandler> BHClass;
00466	
00467	  log("_________________________________");
00468	  log( "InitGame:" @ Options );
00469	//  MaxPlayers = Min( 32,GetIntOption( Options, "MaxPlayers", MaxPlayers ));
00470	  InOpt = ParseOption( Options, "Difficulty" );
00471	  if( InOpt != "" )
00472	    Difficulty = int(InOpt);
00473	
00474	  InOpt = ParseOption( Options, "GameSpeed");
00475	  if( InOpt != "" )
00476	  {
00477	    log(" GameSpeed"@InOpt);
00478	    SetGameSpeed(float(InOpt));
00479	  }
00480	
00481	  MClass = class<Mutator>(DynamicLoadObject(MutatorClass, class'Class'));
00482	  BaseMutator = spawn(MClass);
00483	
00484	  BHClass = class<BroadcastHandler>(DynamicLoadObject(BroadcastHandlerClass,Class'Class'));
00485	  BroadcastHandler = spawn(BHClass);
00486	
00487	  InOpt = ParseOption( Options, "AccessControl");
00488	  if( InOpt != "" )
00489	    ACClass = class<AccessControl>(DynamicLoadObject(InOpt, class'Class'));
00490	  if ( ACClass != None )
00491	    AccessControl = Spawn(ACClass);
00492	  else
00493	  {
00494	    ACClass = class<AccessControl>(DynamicLoadObject(AccessControlClass, class'Class'));
00495	    AccessControl = Spawn(ACClass);
00496	  }
00497	
00498	  InOpt = ParseOption( Options, "AdminPassword");
00499	  if( InOpt!="" )
00500	    AccessControl.SetAdminPassword(InOpt);
00501	
00502	  InOpt = ParseOption( Options, "GameRules");
00503	  if ( InOpt != "" )
00504	  {
00505	    log(" Game Rules"@InOpt);
00506	    while ( InOpt != "" )
00507	    {
00508	      pos = InStr(InOpt,",");
00509	      if ( pos > 0 )
00510	      {
00511	        LeftOpt = Left(InOpt, pos);
00512	        InOpt = Right(InOpt, Len(InOpt) - pos - 1);
00513	      }
00514	      else
00515	      {
00516	        LeftOpt = InOpt;
00517	        InOpt = "";
00518	      }
00519	      log("  Add game rules "$LeftOpt);
00520	      GRClass = class<GameRules>(DynamicLoadObject(LeftOpt, class'Class'));
00521	      if ( GRClass != None )
00522	      {
00523	        if ( GameRulesModifiers == None )
00524	          GameRulesModifiers = Spawn(GRClass);
00525	        else
00526	          GameRulesModifiers.AddGameRules(Spawn(GRClass));
00527	      }
00528	    }
00529	  }
00530	
00531	  log(" Base Mutator is "$BaseMutator);
00532	  InOpt = ParseOption( Options, "Mutator");
00533	  if ( InOpt != "" )
00534	  {
00535	    log(" Mutators"@InOpt);
00536	    while ( InOpt != "" )
00537	    {
00538	      pos = InStr(InOpt,",");
00539	      if ( pos > 0 )
00540	      {
00541	        LeftOpt = Left(InOpt, pos);
00542	        InOpt = Right(InOpt, Len(InOpt) - pos - 1);
00543	      }
00544	      else
00545	      {
00546	        LeftOpt = InOpt;
00547	        InOpt = "";
00548	      }
00549	      log("  Add mutator "$LeftOpt);
00550	      MClass = class<Mutator>(DynamicLoadObject(LeftOpt, class'Class'));
00551	      if ( MClass != None )
00552	        BaseMutator.AddMutator(Spawn(MClass));
00553	    }
00554	  }
00555	
00556	  InOpt = ParseOption( Options, "GamePassword");
00557	  if( InOpt != "" )
00558	  {
00559	    AccessControl.SetGamePassWord(InOpt);
00560	    log( " GamePassword" @ InOpt );
00561	  }
00562	
00563	  InOpt = ParseOption( Options, "LocalLog");
00564	  if( InOpt ~= "true" )
00565	    bLocalLog = True;
00566	
00567	  InOpt = ParseOption( Options, "WorldLog");
00568	  if( InOpt ~= "true" )
00569	    bWorldLog = True;
00570	}
00571	
00572	//
00573	// Return beacon text for serverbeacon.
00574	//
00575	event string GetBeaconText()
00576	{
00577	  return
00578	    Level.ComputerName
00579	  $"|"$ Left(Level.Title,24)
00580	  $"|"$ GameName
00581	  $"|"$ BeaconName
00582	  $"|"$ NumPlayers $"/"$ MaxPlayers;
00583	}
00584	
00585	/* ProcessServerTravel()
00586	 Optional handling of ServerTravel for network games.
00587	*/
00588	function ProcessServerTravel( string URL, bool bItems )
00589	{
00590	  local playercontroller P, LocalPlayer;
00591	
00592	  EndLogging("mapchange");
00593	
00594	  // Notify clients we're switching level and give them time to receive.
00595	  // We call PreClientTravel directly on any local PlayerPawns (ie listen server)
00596	  log("ProcessServerTravel:"@URL);
00597	  foreach DynamicActors( class'PlayerController', P )
00598	    if( NetConnection( P.Player)!=None )
00599	      P.ClientTravel( URL, TRAVEL_Relative, bItems );
00600	    else
00601	    {
00602	      LocalPlayer = P;
00603	      P.PreClientTravel();
00604	    }
00605	
00606	  if ( (Level.NetMode == NM_ListenServer) && (LocalPlayer != None) )
00607	    Level.NextURL = Level.NextURL$"?Skin="$LocalPlayer.GetDefaultURL("Skin")
00608	           $"?Face="$LocalPlayer.GetDefaultURL("Face")
00609	           $"?Team="$LocalPlayer.GetDefaultURL("Team")
00610	           $"?Name="$LocalPlayer.GetDefaultURL("Name")
00611	           $"?Class="$LocalPlayer.GetDefaultURL("Class");
00612	
00613	  // Switch immediately if not networking.
00614	  if( Level.NetMode!=NM_DedicatedServer && Level.NetMode!=NM_ListenServer )
00615	    Level.NextSwitchCountdown = 0.0;
00616	}
00617	
00618	//
00619	// Accept or reject a player on the server.
00620	// Fails login if you set the Error to a non-empty string.
00621	//
00622	event PreLogin
00623	(
00624	  string Options,
00625	  string Address,
00626	  out string Error,
00627	  out string FailCode
00628	)
00629	{
00630	  local bool bSpectator;
00631	  local string spec;
00632	
00633	  spec = ParseOption ( Options, "SpectatorOnly" );
00634	  bSpectator = ( spec != "" );
00635	
00636	  AccessControl.PreLogin(Options, Address, Error, FailCode, bSpectator);
00637	}
00638	
00639	function int GetIntOption( string Options, string ParseString, int CurrentValue)
00640	{
00641	  local string InOpt;
00642	
00643	  InOpt = ParseOption( Options, ParseString );
00644	  if ( InOpt != "" )
00645	  {
00646	    log(ParseString@InOpt);
00647	    return int(InOpt);
00648	  }
00649	  return CurrentValue;
00650	}
00651	
00652	function bool AtCapacity(bool bSpectator)
00653	{
00654	  if ( Level.NetMode == NM_Standalone )
00655	    return false;
00656	
00657	  if ( bSpectator )
00658	    return ( (NumSpectators >= MaxSpectators)
00659	      && ((Level.NetMode != NM_ListenServer) || (NumPlayers > 0)) );
00660	  else
00661	    return ( (MaxPlayers>0) && (NumPlayers>=MaxPlayers) );
00662	}
00663	
00664	//
00665	// Log a player in.
00666	// Fails login if you set the Error string.
00667	// PreLogin is called before Login, but significant game time may pass before
00668	// Login is called, especially if content is downloaded.
00669	//
00670	event PlayerController Login
00671	(
00672	  string Portal,
00673	  string Options,
00674	  out string Error
00675	)
00676	{
00677	  local NavigationPoint StartSpot;
00678	  local PlayerController NewPlayer;
00679	  local class<Pawn> DesiredPawnClass;
00680	  local Pawn      TestPawn;
00681	  local string          InName, InPassword, InChecksum, InClass;
00682	  local byte            InTeam;
00683	  local bool bSpectator;
00684	  local int i;
00685	  local Actor A;
00686	
00687	  bSpectator = ( ParseOption( Options, "SpectatorOnly" ) != "" );
00688	
00689	  // Make sure there is capacity. (This might have changed since the PreLogin call).
00690	  if ( AtCapacity(bSpectator) )
00691	  {
00692	    Error=GameMessageClass.Default.MaxedOutMessage;
00693	    return None;
00694	  }
00695	
00696	  BaseMutator.ModifyLogin(Portal, Options);
00697	
00698	  // Get URL options.
00699	  InName     = Left(ParseOption ( Options, "Name"), 20);
00700	  InTeam     = GetIntOption( Options, "Team", 255 ); // default to "no team"
00701	  InPassword = ParseOption ( Options, "Password" );
00702	  InChecksum = ParseOption ( Options, "Checksum" );
00703	
00704	  log( "Login:" @ InName );
00705	  if( InPassword != "" )
00706	    log( "Password"@InPassword );
00707	
00708	  // Pick a team (if need teams)
00709	  InTeam = PickTeam(InTeam);
00710	
00711	  // Find a start spot.
00712	  StartSpot = FindPlayerStart( None, InTeam, Portal );
00713	
00714	  if( StartSpot == None )
00715	  {
00716	    Error = GameMessageClass.Default.FailedPlaceMessage;
00717	    return None;
00718	  }
00719	
00720	  // Init player's administrative privileges
00721	  if ( AccessControl.AdminLogin(NewPlayer, InPassword) )
00722	  {
00723	    NewPlayer = spawn(AccessControl.AdminClass,,,StartSpot.Location,StartSpot.Rotation);
00724	    bSpectator = true;
00725	  }
00726	  else
00727	  {
00728	    if ( PlayerControllerClass == None )
00729	      PlayerControllerClass = class<PlayerController>(DynamicLoadObject(PlayerControllerClassName, class'Class'));
00730	    NewPlayer = spawn(PlayerControllerClass,,,StartSpot.Location,StartSpot.Rotation);
00731	  }
00732	
00733	  // Handle spawn failure.
00734	  if( NewPlayer == None )
00735	  {
00736	    log("Couldn't spawn player controller of class "$PlayerControllerClass);
00737	    Error = GameMessageClass.Default.FailedSpawnMessage;
00738	    return None;
00739	  }
00740	
00741	  NewPlayer.StartSpot = StartSpot;
00742	
00743	  // Init player's name
00744	  if( InName=="" )
00745	    InName=DefaultPlayerName;
00746	  if( Level.NetMode!=NM_Standalone || NewPlayer.PlayerReplicationInfo.PlayerName==DefaultPlayerName )
00747	    ChangeName( NewPlayer, InName, false );
00748	
00749	  // Init player's replication info
00750	  NewPlayer.GameReplicationInfo = GameReplicationInfo;
00751	
00752	  NewPlayer.GotoState('Spectating');
00753	
00754	  if ( bSpectator )
00755	  {
00756	    NewPlayer.bOnlySpectator = true;
00757	    NumSpectators++;
00758	    return NewPlayer;
00759	  }
00760	
00761	  // Change player's team.
00762	  if ( !ChangeTeam(newPlayer, InTeam) )
00763	  {
00764	    Error = GameMessageClass.Default.FailedTeamMessage;
00765	    return None;
00766	  }
00767	
00768	  // Set the player's ID.
00769	  NewPlayer.PlayerReplicationInfo.PlayerID = CurrentID++;
00770	
00771	  InClass = ParseOption( Options, "Class" );
00772	  if ( InClass != "" )
00773	  {
00774	    DesiredPawnClass = class<Pawn>(DynamicLoadObject(InClass, class'Class'));
00775	    if ( DesiredPawnClass != None )
00776	      NewPlayer.PawnClass = DesiredPawnClass;
00777	  }
00778	
00779	  // Log it.
00780	  if ( StatLog != None )
00781	    StatLog.LogPlayerConnect(NewPlayer);
00782	  NewPlayer.ReceivedSecretChecksum = !(InChecksum ~= "NoChecksum");
00783	
00784	  NumPlayers++;
00785	
00786	  // If we are a server, broadcast a welcome message.
00787	  if( Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer )
00788	    BroadcastLocalizedMessage(GameMessageClass, 1, NewPlayer.PlayerReplicationInfo);
00789	
00790	  // if delayed start, don't give a pawn to the player yet
00791	  // Normal for multiplayer games
00792	  if ( bDelayedStart )
00793	  {
00794	    NewPlayer.GotoState('PlayerWaiting');
00795	    return NewPlayer;
00796	  }
00797	
00798	  // Try to match up to existing unoccupied player in level,
00799	  // for savegames and coop level switching.
00800	  ForEach DynamicActors(class'Pawn', TestPawn )
00801	  {
00802	    if ( (TestPawn!=None) && (PlayerController(TestPawn.Controller)!=None) && (PlayerController(TestPawn.Controller).Player==None) && (TestPawn.Health > 0) &&  (TestPawn.PawnName~=InName) )
00803	    {
00804	      NewPlayer.Destroy();
00805	      TestPawn.SetRotation(TestPawn.Controller.Rotation);
00806	      TestPawn.bInitializeAnimation = false; // FIXME - temporary workaround for lack of meshinstance serialization
00807	      TestPawn.PlayWaiting();
00808	      return PlayerController(TestPawn.Controller);
00809	    }
00810	  }
00811	
00812	  return newPlayer;
00813	}
00814	
00815	/* StartMatch()
00816	Start the game - inform all actors that the match is starting, and spawn player pawns
00817	*/
00818	function StartMatch()
00819	{
00820	  local Controller P;
00821	  local Actor A;
00822	
00823	  if (StatLog != None)
00824	    StatLog.LogGameStart();
00825	
00826	  // tell all actors the game is starting
00827	  ForEach AllActors(class'Actor', A)
00828	    A.MatchStarting();
00829	
00830	  // start human players first
00831	  for ( P = Level.ControllerList; P!=None; P=P.nextController )
00832	    if ( P.IsA('PlayerController') && (P.Pawn == None) )
00833	    {
00834	      if ( bGameEnded ) return; // telefrag ended the game with ridiculous frag limit
00835	      else if ( !PlayerController(P).bOnlySpectator  )
00836	        RestartPlayer(P);
00837	      SendStartMessage(PlayerController(P));
00838	    }
00839	
00840	  // start AI players
00841	  for ( P = Level.ControllerList; P!=None; P=P.nextController )
00842	    if ( P.bIsPlayer && !P.IsA('PlayerController') )
00843	      RestartPlayer(P);
00844	
00845	  bWaitingToStartMatch = false;
00846	}
00847	
00848	//
00849	// Restart a player.
00850	//
00851	function RestartPlayer( Controller aPlayer )
00852	{
00853	  local NavigationPoint startSpot;
00854	  local bool foundStart;
00855	  local int TeamNum,i;
00856	  local class<Pawn> DefaultPlayerClass;
00857	
00858	  if( bRestartLevel && Level.NetMode!=NM_DedicatedServer && Level.NetMode!=NM_ListenServer )
00859	    return;
00860	
00861	  if ( (aPlayer.PlayerReplicationInfo == None) || (aPlayer.PlayerReplicationInfo.Team == None) )
00862	    TeamNum = 255;
00863	  else
00864	    TeamNum = aPlayer.PlayerReplicationInfo.Team.TeamIndex;
00865	
00866	  startSpot = FindPlayerStart(aPlayer, TeamNum);
00867	  if( startSpot == None )
00868	  {
00869	    log(" Player start not found!!!");
00870	    return;
00871	  }
00872	
00873	  if ( (aPlayer.PlayerReplicationInfo.Team != None)
00874	    && ((aPlayer.PawnClass == None) || !aPlayer.PlayerReplicationInfo.Team.BelongsOnTeam(aPlayer.PawnClass)) )
00875	      aPlayer.PawnClass = class<Pawn>(DynamicLoadObject(aPlayer.PlayerReplicationInfo.Team.DefaultPlayerClassName, class'Class'));
00876	
00877	  if ( aPlayer.PawnClass != None )
00878	    aPlayer.Pawn = Spawn(aPlayer.PawnClass,,,StartSpot.Location,StartSpot.Rotation);
00879	
00880	  if( aPlayer.Pawn==None )
00881	  {
00882	    DefaultPlayerClass = class<Pawn>(DynamicLoadObject(GetDefaultPlayerClassName(aPlayer), class'Class'));
00883	    aPlayer.Pawn = Spawn(DefaultPlayerClass,,,StartSpot.Location,StartSpot.Rotation);
00884	  }
00885	  if ( aPlayer.Pawn == None )
00886	  {
00887	    log("Couldn't spawn player of type "$aPlayer.PawnClass$" at "$StartSpot);
00888	    aPlayer.GotoState('Dead');
00889	    return;
00890	  }
00891	
00892	  aPlayer.Possess(aPlayer.Pawn);
00893	  aPlayer.PawnClass = aPlayer.Pawn.Class;
00894	
00895	  PlayTeleportEffect(aPlayer, true, true);
00896	  aPlayer.ClientSetRotation(aPlayer.Pawn.Rotation);
00897	  AddDefaultInventory(aPlayer.Pawn);
00898	  TriggerEvent( StartSpot.Event, StartSpot, aPlayer.Pawn);
00899	}
00900	
00901	function string GetDefaultPlayerClassName(Controller C)
00902	{
00903	  return DefaultPlayerClassName;
00904	}
00905	
00906	function SendStartMessage(PlayerController P)
00907	{
00908	  P.ClearProgressMessages();
00909	}
00910	
00911	//
00912	// Called after a successful login. This is the first place
00913	// it is safe to call replicated functions on the PlayerPawn.
00914	//
00915	event PostLogin( PlayerController NewPlayer )
00916	{
00917	  local Controller P;
00918	  local class<Scoreboard> S;
00919	  local class<HUD> H;
00920	
00921	  if ( !bDelayedStart )
00922	  {
00923	    // start match, or let player enter, immediately
00924	    bRestartLevel = false;  // let player spawn once in levels that must be restarted after every death
00925	    if ( bWaitingToStartMatch )
00926	      StartMatch();
00927	    else
00928	      RestartPlayer(newPlayer);
00929	    bRestartLevel = Default.bRestartLevel;
00930	  }
00931	
00932	    // tell client what hud and scoreboard to use
00933	  if ( HUDType != "" )
00934	    H = class<HUD>(DynamicLoadObject(HUDType, class'Class'));
00935	  if ( ScoreboardType != "" )
00936	    S = class<Scoreboard>(DynamicLoadObject(ScoreboardType, class'Class'));
00937	  NewPlayer.ClientSetHUD(H,S);
00938	
00939	  // Replicate skins - to avoid loading pauses in multiplayer games
00940	  if ( Level.NetMode != NM_Standalone )
00941	  {
00942	    for ( P=Level.ControllerList; P!=None; P=P.NextController )
00943	      if ( P != NewPlayer )
00944	      {
00945	        // send other players' skins to new player
00946	        if ( P.Pawn != None )
00947	        {
00948	          NewPlayer.ClientReplicateSkins(P.Pawn.Skins[0], P.Pawn.Skins[1], P.Pawn.Skins[2], P.Pawn.Skins[3]);
00949	        }
00950	
00951	        // send new player's skins to any player which hasn't started play yet
00952	        if ( (NewPlayer.Pawn != None)
00953	          && (P.PlayerReplicationInfo != None)
00954	          && P.PlayerReplicationInfo.bWaitingPlayer
00955	          && (PlayerController(P) != None) )
00956	        {
00957	          PlayerController(P).ClientReplicateSkins(NewPlayer.Skins[0], NewPlayer.Skins[1], NewPlayer.Skins[2], NewPlayer.Skins[3]);
00958	        }
00959	      }
00960	  }
00961	
00962	  if ( NewPlayer.Pawn != None )
00963	    NewPlayer.Pawn.ClientSetRotation(NewPlayer.Pawn.Rotation);
00964	}
00965	
00966	//
00967	// Player exits.
00968	//
00969	function Logout( Controller Exiting )
00970	{
00971	  local bool bMessage;
00972	
00973	  bMessage = true;
00974	  if ( PlayerController(Exiting) != None )
00975	  {
00976	    if ( PlayerController(Exiting).bOnlySpectator )
00977	    {
00978	      bMessage = false;
00979	      if ( Level.NetMode == NM_DedicatedServer )
00980	        NumSpectators--;
00981	    }
00982	    else
00983	      NumPlayers--;
00984	  }
00985	  if( bMessage && (Level.NetMode==NM_DedicatedServer || Level.NetMode==NM_ListenServer) )
00986	    BroadcastLocalizedMessage(GameMessageClass, 4, Exiting.PlayerReplicationInfo);
00987	
00988	  if ( StatLog != None )
00989	    StatLog.LogPlayerDisconnect(Exiting);
00990	}
00991	
00992	//
00993	// Examine the passed player's inventory, and accept or discard each item.
00994	// AcceptInventory needs to gracefully handle the case of some inventory
00995	// being accepted but other inventory not being accepted (such as the default
00996	// weapon).  There are several things that can go wrong: A weapon's
00997	// AmmoType not being accepted but the weapon being accepted -- the weapon
00998	// should be killed off. Or the player's selected inventory item, active
00999	// weapon, etc. not being accepted, leaving the player weaponless or leaving
01000	// the HUD inventory rendering messed up (AcceptInventory should pick another
01001	// applicable weapon/item as current).
01002	//
01003	event AcceptInventory(pawn PlayerPawn)
01004	{
01005	  //default accept all inventory except default weapon (spawned explicitly)
01006	}
01007	
01008	//
01009	// Spawn any default inventory for the player.
01010	//
01011	function AddDefaultInventory( pawn PlayerPawn )
01012	{
01013	  local Weapon newWeapon;
01014	  local class<Weapon> WeapClass;
01015	
01016	  // Spawn default weapon.
01017	  WeapClass = BaseMutator.GetDefaultWeapon();
01018	  if( (WeapClass!=None) && (PlayerPawn.FindInventoryType(WeapClass)==None) )
01019	  {
01020	    newWeapon = Spawn(WeapClass,,,PlayerPawn.Location);
01021	    if( newWeapon != None )
01022	    {
01023	      newWeapon.GiveTo(PlayerPawn);
01024	      newWeapon.BringUp();
01025	      newWeapon.bCanThrow = false; // don't allow default weapon to be thrown out
01026	    }
01027	  }
01028	  SetPlayerDefaults(PlayerPawn);
01029	}
01030	
01031	/* SetPlayerDefaults()
01032	 first make sure pawn properties are back to default, then give mutators an opportunity
01033	 to modify them
01034	*/
01035	function SetPlayerDefaults(Pawn PlayerPawn)
01036	{
01037	  PlayerPawn.JumpZ = PlayerPawn.Default.JumpZ;
01038	  PlayerPawn.AirControl = PlayerPawn.Default.AirControl;
01039	  BaseMutator.ModifyPlayer(PlayerPawn);
01040	}
01041	
01042	function NotifyKilled(Controller Killer, Controller Killed, Pawn KilledPawn )
01043	{
01044	  local Controller C;
01045	
01046	  for ( C=Level.ControllerList; C!=None; C=C.nextController )
01047	    C.NotifyKilled(Killer, Killed, KilledPawn);
01048	}
01049	
01050	function Killed( Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> damageType )
01051	{
01052	  local String Message, KillerWeapon, OtherWeapon;
01053	  local name logtype;
01054	
01055	  NotifyKilled(Killer,Killed,KilledPawn);
01056	
01057	  if ( Killed.bIsPlayer && !Level.bLonePlayer )
01058	  { // ELR don't message if loneplayer = solo game
01059	    Killed.PlayerReplicationInfo.Deaths += 1;
01060	    BroadcastDeathMessage(Killer, Killed, damageType);
01061	    if ( (StatLog != None) && (Killer != None) && Killer.bIsPlayer )
01062	    {
01063	      if ( DamageType.Default.DamageWeaponName != "" )
01064	        KillerWeapon = DamageType.Default.DamageWeaponName;
01065	      else
01066	        KillerWeapon = "None";
01067	
01068	      if (KilledPawn.Weapon != None)
01069	        OtherWeapon = KilledPawn.Weapon.ItemName;
01070	      else
01071	        OtherWeapon = "None";
01072	      StatLog.LogKill(
01073	        Killer.PlayerReplicationInfo,
01074	        Killed.PlayerReplicationInfo,
01075	        KillerWeapon,
01076	        OtherWeapon,
01077	        damageType
01078	      );
01079	    }
01080	  }
01081	
01082	  log("Killed"@Killer@Killed);
01083	  ScoreKill(Killer, Killed);
01084	  DiscardInventory(KilledPawn);
01085	}
01086	
01087	function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> damageType, vector HitLocation)
01088	{
01089	  if ( GameRulesModifiers == None )
01090	    return false;
01091	  return GameRulesModifiers.PreventDeath(Killed,Killer, damageType,HitLocation);
01092	}
01093	
01094	function BroadcastDeathMessage(Controller Killer, Controller Other, class<DamageType> damageType)
01095	{
01096	  if ( (Killer == Other) || (Killer == None) )
01097	    BroadcastLocalizedMessage(DeathMessageClass, 1, None, Other.PlayerReplicationInfo, damageType);
01098	  else
01099	    BroadcastLocalizedMessage(DeathMessageClass, 0, Killer.PlayerReplicationInfo, Other.PlayerReplicationInfo, damageType);
01100	}
01101	
01102	
01103	// %k = Owner's PlayerName (Killer)
01104	// %o = Other's PlayerName (Victim)
01105	// %w = Owner's Weapon ItemName
01106	native(572) static final function string ParseKillMessage( string KillerName, string VictimName, string DeathMessage );
01107	
01108	function Kick( string S )
01109	{
01110	  AccessControl.Kick(S);
01111	}
01112	function KickBan( string S )
01113	{
01114	  AccessControl.KickBan(S);
01115	}
01116	
01117	function bool IsOnTeam(Controller Other, int TeamNum)
01118	{
01119	  if ( bTeamGame && (Other != None) && (Other.PlayerReplicationInfo.Team.TeamIndex == TeamNum) )
01120	    return true;
01121	  return false;
01122	}
01123	
01124	//-------------------------------------------------------------------------------------
01125	// Level gameplay modification.
01126	
01127	//
01128	// Return whether Viewer is allowed to spectate from the
01129	// point of view of ViewTarget.
01130	//
01131	function bool CanSpectate( PlayerController Viewer, actor ViewTarget )
01132	{
01133	  return true;
01134	}
01135	
01136	/* Use reduce damage for teamplay modifications, etc.
01137	*/
01138	function int ReduceDamage( int Damage, pawn injured, pawn instigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType );
01139	
01140	//
01141	// Return whether an item should respawn.
01142	//
01143	function bool ShouldRespawn( Pickup Other )
01144	{
01145	  if( Level.NetMode == NM_StandAlone )
01146	    return false;
01147	
01148	  return Other.ReSpawnTime!=0.0;
01149	}
01150	
01151	/* Called when pawn has a chance to pick Item up (i.e. when
01152	   the pawn touches a weapon pickup). Should return true if
01153	   he wants to pick it up, false if he does not want it.
01154	*/
01155	function bool PickupQuery( Pawn Other, Pickup item )
01156	{
01157	  local byte bAllowPickup;
01158	
01159	  if ( (GameRulesModifiers != None) && GameRulesModifiers.OverridePickupQuery(Other, item, bAllowPickup) )
01160	    return (bAllowPickup == 1);
01161	
01162	  if ( Other.Inventory == None )
01163	    return true;
01164	  else
01165	    return !Other.Inventory.HandlePickupQuery(Item);
01166	}
01167	
01168	/* Discard a player's inventory after he dies.
01169	*/
01170	function DiscardInventory( Pawn Other )
01171	{
01172	  local actor dropped;
01173	  local inventory Inv,Next;
01174	  local float speed;
01175	
01176	  if( (Other.Weapon!=None) && Other.Weapon.bCanThrow && Other.Weapon.HasAmmo() )
01177	  {
01178	    if ( Other.Weapon.PickupAmmoCount == 0 )
01179	      Other.Weapon.PickupAmmoCount = 1;
01180	    speed = VSize(Other.Velocity);
01181	    if (speed != 0)
01182	      Other.TossWeapon(Normal(Other.Velocity/speed + 0.5 * VRand()) * (speed + 280));
01183	    else
01184	      Other.TossWeapon(vect(0,0,0));
01185	  }
01186	  Other.Weapon = None;
01187	  Other.SelectedItem = None;
01188	  Inv = Other.Inventory;
01189	  while ( Inv != None )
01190	  {
01191	    Next = Inv.Inventory;
01192	    Inv.Destroy();
01193	    Inv = Next;
01194	  }
01195	}
01196	
01197	/* Try to change a player's name.
01198	*/
01199	function ChangeName( Controller Other, coerce string S, bool bNameChange )
01200	{
01201	  if( S == "" )
01202	    return;
01203	  if ( StatLog != None)
01204	    StatLog.LogNameChange(Other);
01205	  Other.PlayerReplicationInfo.SetPlayerName(S);
01206	  if( bNameChange && (PlayerController(Other) != None) )
01207	    BroadcastLocalizedMessage( GameMessageClass, 2, Other.PlayerReplicationInfo );
01208	}
01209	
01210	/* Return whether a team change is allowed.
01211	*/
01212	function bool ChangeTeam(Controller Other, int N)
01213	{
01214	  return true;
01215	}
01216	
01217	// return wether a class change is allowed
01218	function bool ChangeClass(Controller Other, class<Pawn> InClass)
01219	{
01220	  return false;
01221	}
01222	
01223	/* Return a picked team number if none was specified
01224	*/
01225	function byte PickTeam(byte Current)
01226	{
01227	  return Current;
01228	}
01229	
01230	/* Play an inventory respawn effect.
01231	*/
01232	function float PlaySpawnEffect( pickup P )
01233	{
01234	  return 0.3;
01235	}
01236	
01237	/* Send a player to a URL.
01238	*/
01239	function SendPlayer( PlayerController aPlayer, string URL )
01240	{
01241	  aPlayer.ClientTravel( URL, TRAVEL_Relative, true );
01242	}
01243	
01244	/* Play a teleporting special effect.
01245	*/
01246	function PlayTeleportEffect( actor Incoming, bool bOut, bool bSound)
01247	{
01248	  Incoming.MakeNoise(1.0);
01249	}
01250	
01251	/* Restart the game.
01252	*/
01253	function RestartGame()
01254	{
01255	//  local string NextMap;
01256	//  local MapList myList;
01257	//  local class<MapList> ML;
01258	
01259	  if ( (GameRulesModifiers != None) && GameRulesModifiers.HandleRestartGame() )
01260	    return;
01261	
01262	/*
01263	  // these server travels should all be relative to the current URL
01264	  if ( bChangeLevels && !bAlreadyChanged && (MapListType != "") )
01265	  {
01266	    // open a the nextmap actor for this game type and get the next map
01267	    bAlreadyChanged = true;
01268	    ML = class<MapList>(DynamicLoadObject(MapListType, class'Class'));
01269	    myList = spawn(ML);
01270	    NextMap = myList.GetNextMap();
01271	    myList.Destroy();
01272	    if ( NextMap == "" )
01273	      NextMap = GetMapName(MapPrefix, NextMap,1);
01274	
01275	    if ( NextMap != "" )
01276	    {
01277	      Level.ServerTravel(NextMap, false);
01278	      return;
01279	    }
01280	  }
01281	*/
01282	
01283	  Level.ServerTravel( "?Restart", false );
01284	}
01285	
01286	//==========================================================================
01287	// Message broadcasting functions (handled by the BroadCastHandler)
01288	
01289	event Broadcast( Actor Sender, coerce string Msg, optional name Type )
01290	{
01291	  BroadcastHandler.Broadcast(Sender,Msg,Type);
01292	}
01293	
01294	function BroadcastTeam( Controller Sender, coerce string Msg, optional name Type )
01295	{
01296	  BroadcastHandler.BroadcastTeam(Sender,Msg,Type);
01297	}
01298	
01299	/*
01300	 Broadcast a localized message to all players.
01301	 Most message deal with 0 to 2 related PRIs.
01302	 The LocalMessage class defines how the PRI's and optional actor are used.
01303	*/
01304	event BroadcastLocalized( actor Sender, class<LocalMessage> Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
01305	{
01306	  BroadcastHandler.AllowBroadcastLocalized(Sender,Message,Switch,RelatedPRI_1,RelatedPRI_2,OptionalObject);
01307	}
01308	
01309	//==========================================================================
01310	
01311	function bool CheckEndGame(PlayerReplicationInfo Winner, string Reason)
01312	{
01313	  local Controller P;
01314	
01315	  if ( (GameRulesModifiers != None) && !GameRulesModifiers.CheckEndGame(Winner, Reason) )
01316	    return false;
01317	
01318	  // all player cameras focus on winner or final scene (picked by gamerules)
01319	  for ( P=Level.ControllerList; P!=None; P=P.NextController )
01320	  {
01321	    P.ClientGameEnded();
01322	    P.GotoState('GameEnded');
01323	  }
01324	  return true;
01325	}
01326	
01327	/* End of game.
01328	*/
01329	function EndGame( PlayerReplicationInfo Winner, string Reason )
01330	{
01331	  // don't end game if not really ready
01332	  if ( !CheckEndGame(Winner, Reason) )
01333	  {
01334	    bOverTime = true;
01335	    return;
01336	  }
01337	
01338	  bGameEnded = true;
01339	  TriggerEvent('EndGame', self, None);
01340	  EndLogging(Reason);
01341	}
01342	
01343	function EndLogging(string Reason)
01344	{
01345	  if ( StatLog == None )
01346	    return;
01347	  StatLog.LogGameEnd(Reason);
01348	  StatLog.StopLog();
01349	  StatLog.Destroy();
01350	  StatLog = None;
01351	}
01352	
01353	/* Return the 'best' player start for this player to start from.
01354	 */
01355	function NavigationPoint FindPlayerStart( Controller Player, optional byte InTeam, optional string incomingName )
01356	{
01357	  local NavigationPoint N, BestStart;
01358	  local Teleporter Tel;
01359	  local float BestRating, NewRating;
01360	  local byte Team;
01361	  local int test, loop;
01362	
01363	  // always pick StartSpot at start of match
01364	
01365	  if( Level.bLonePlayer == true )
01366	  {
01367	      if ( (Player != None) && (Player.StartSpot != None)
01368	        && (bWaitingToStartMatch || ((Player.PlayerReplicationInfo != None) && Player.PlayerReplicationInfo.bWaitingPlayer))  )
01369	      {
01370	        return Player.StartSpot;
01371	      }
01372	  }
01373	
01374	  if ( GameRulesModifiers != None )
01375	  {
01376	    N = GameRulesModifiers.FindPlayerStart(Player,InTeam,incomingName);
01377	    if ( N != None )
01378	        return N;
01379	  }
01380	
01381	  // if incoming start is specified, then just use it
01382	  if( incomingName!="" )
01383	    foreach AllActors( class 'Teleporter', Tel )
01384	      if( string(Tel.Tag)~=incomingName )
01385	        return Tel;
01386	
01387	  // use InTeam if player doesn't have a team yet
01388	  if ( (Player != None) && (Player.PlayerReplicationInfo != None) )
01389	  {
01390	    if ( Player.PlayerReplicationInfo.Team != None )
01391	      Team = Player.PlayerReplicationInfo.Team.TeamIndex;
01392	    else
01393	      Team = 0;
01394	  }
01395	  else
01396	    Team = InTeam;
01397	
01398	//log("");
01399	//log("Search....");
01400	//log("");
01401	
01402	  for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
01403	  {
01404	    if( N.IsA('PlayerStart') )
01405	    {
01406	        NewRating = RatePlayerStart(N,InTeam,Player);
01407	
01408	        //log("    >"@N@NewRating);
01409	
01410	        if ( NewRating > BestRating )
01411	        {
01412	          BestRating = NewRating;
01413	          BestStart = N;
01414	          //test = loop;
01415	        }
01416	
01417	        Loop++;
01418	    }
01419	  }
01420	
01421	//StatPlayerStart[test]++;
01422	//
01423	//test=0;
01424	//
01425	//for( loop=0 ; loop<7; loop++ )
01426	// test += StatPlayerStart[loop];
01427	//
01428	//  loop=0;
01429	//
01430	//  for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
01431	//  {
01432	//    if( N.IsA('PlayerStart') )
01433	//    {
01434	//        log(" >"@N@":"@StatPlayerStart[loop]*100/test$"%");
01435	//        Loop++;
01436	//    }
01437	//  }
01438	//
01439	//log("");
01440	//log("Respawn="@test);
01441	//log("");
01442	
01443	  if ( BestStart == None )
01444	  {
01445	    log("Warning - PATHS NOT DEFINED or NO PLAYERSTART");
01446	    foreach AllActors( class 'NavigationPoint', N )
01447	    {
01448	      NewRating = RatePlayerStart(N,0,Player);
01449	      if ( NewRating > BestRating )
01450	      {
01451	        BestRating = NewRating;
01452	        BestStart = N;
01453	      }
01454	    }
01455	  }
01456	
01457	  return BestStart;
01458	}
01459	
01460	/* Rate whether player should choose this NavigationPoint as its start
01461	default implementation is for single player game
01462	*/
01463	function float RatePlayerStart(NavigationPoint N, byte Team, Controller Player)
01464	{
01465	  local PlayerStart P;
01466	
01467	  P = PlayerStart(N);
01468	  if ( P != None )
01469	  {
01470	    if ( P.bSinglePlayerStart )
01471	    {
01472	      if ( P.bEnabled )
01473	        return 1000;
01474	      return 20;
01475	    }
01476	    return 10;
01477	  }
01478	  return 0;
01479	}
01480	
01481	function ScoreObjective(PlayerReplicationInfo Scorer, Int Score)
01482	{
01483	  if ( Scorer != None )
01484	  {
01485	    Scorer.Score += Score;
01486	    if ( Scorer.Team != None )
01487	      Scorer.Team.Score += Score;
01488	  }
01489	  if ( GameRulesModifiers != None )
01490	    GameRulesModifiers.ScoreObjective(Scorer,Score);
01491	
01492	  CheckScore(Scorer);
01493	}
01494	
01495	/* CheckScore()
01496	see if this score means the game ends
01497	*/
01498	function CheckScore(PlayerReplicationInfo Scorer)
01499	{
01500	  if ( (GameRulesModifiers != None) && GameRulesModifiers.CheckScore(Scorer) )
01501	    return;
01502	}
01503	
01504	function ScoreKill(Controller Killer, Controller Other)
01505	{
01506	  if (killer == Other)
01507	    Other.PlayerReplicationInfo.Score -= 1;
01508	  else if ( killer.PlayerReplicationInfo != None )
01509	    killer.PlayerReplicationInfo.Score += 1;
01510	
01511	  if ( GameRulesModifiers != None )
01512	    GameRulesModifiers.ScoreKill(Killer, Other);
01513	
01514	  CheckScore(Killer.PlayerReplicationInfo);
01515	}
01516	
01517	defaultproperties
01518	{
01519	     DetailLevel=2
01520	     bRestartLevel=True
01521	     bPauseable=True
01522	     bCanViewOthers=True
01523	     bWaitingToStartMatch=True
01524	     bLocalLog=True
01525	     bWorldLog=True
01526	     GameSpeed=1.000000
01527	     HUDType="Engine.HUD"
01528	     MaxSpectators=2
01529	     MaxPlayers=16
01530	     DefaultPlayerName="Player"
01531	     GameName="Game"
01532	     DeathMessageClass=Class'Engine.LocalMessage'
01533	     GameMessageClass=Class'Engine.GameMessage'
01534	     MutatorClass="Engine.Mutator"
01535	     AccessControlClass="Engine.AccessControl"
01536	     BroadcastHandlerClass="Engine.BroadcastHandler"
01537	     PlayerControllerClassName="Engine.PlayerController"
01538	     GameReplicationInfoClass=Class'Engine.GameReplicationInfo'
01539	     StatLogClass=Class'Engine.StatLogFile'
01540	}

End Source Code