## 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