//============================================================================= // PlayerReplicationInfo. //============================================================================= class PlayerReplicationInfo extends ReplicationInfo native nativereplication; var float Score; // Player's current score. var float Deaths; // Number of player's deaths. var Decoration HasFlag; var byte Ping; var Volume PlayerVolume; var ZoneInfo PlayerZone; var int NumLives; var string PlayerName; // Player name, or blank if none. var string CharacterName, OldCharacterName; var string OldName, PreviousName; // Temporary value. var int PlayerID; // Unique id number. var TeamInfo Team; // Player Team var int TeamID; // Player position in team. var class VoiceType; var string VoiceTypeName; var bool bAdmin; // Player logged in as Administrator //if _RO_ var bool bSilentAdmin; //end _RO_ var bool bIsFemale; var bool bIsSpectator; var bool bOnlySpectator; var bool bWaitingPlayer; var bool bReadyToPlay; var bool bOutOfLives; var bool bBot; var bool bWelcomed; // set after welcome message broadcast (not replicated) var bool bReceivedPing; var bool bNoTeam; // true if no teaminfo for this PRI var bool bTeamNotified; var byte PacketLoss; // Time elapsed. var int StartTime; var localized String StringDead; var localized String StringSpectating; var localized String StringUnknown; var int GoalsScored; // not replicated - used on server side only var int Kills; // not replicated //if _RO_ var float FFKills; // Moved up here to allow Web Admin to display friendly fire kills var SteamStatsAndAchievementsBase SteamStatsAndAchievements; // Reference to the ROSteamStatsAndAchievements Actor created in PlayerController //end _RO_ var vehicle CurrentVehicle; // for performance on clients var LinkedReplicationInfo CustomReplicationInfo; // for use by mod authors // ======================================== // ======================================== // Voice chat // ======================================== // ======================================== var VoiceChatReplicationInfo VoiceInfo; var bool bRegisteredChatRoom; var VoiceChatRoom PrivateChatRoom; // not replicated - simulated spawn var int ActiveChannel; // this player's currently active channel var int VoiceMemberMask; // members of this player's private chatroom var byte VoiceID; // contains the player's unique ID used by voice channels replication { // Things the server should send to the client. reliable if ( bNetDirty && (Role == Role_Authority) ) Score, Kills, Deaths, PlayerVolume, PlayerZone, PlayerName, Team, TeamID, bIsFemale, bAdmin, bIsSpectator, bOnlySpectator, bWaitingPlayer, bReadyToPlay, StartTime, bOutOfLives, CharacterName, VoiceID, VoiceMemberMask, ActiveChannel; reliable if ( bNetDirty && (Role == ROLE_Authority) && bNetOwner && HasFlag == None ) HasFlag; reliable if ( bNetDirty && (Role == Role_Authority) && (!bNetOwner || bDemoRecording) ) PacketLoss, Ping; reliable if ( bNetDirty && (Role == Role_Authority) && bNetInitial ) PlayerID, bBot, VoiceTypeName, bNoTeam, CustomReplicationInfo; } event PostBeginPlay() { if ( Role < ROLE_Authority ) return; if (AIController(Owner) != None) bBot = true; StartTime = Level.Game.GameReplicationInfo.ElapsedTime; Timer(); SetTimer(1.5 + FRand(), true); } simulated event PostNetBeginPlay() { local GameReplicationInfo GRI; local VoiceChatReplicationInfo VRI; if ( Level.GRI != None ) Level.GRI.AddPRI(self); else { ForEach DynamicActors(class'GameReplicationInfo',GRI) { GRI.AddPRI(self); break; } } // VoiceInfo will only have a value if our PlayerID was replicated prior to our PostNetBeginPlay() & VoiceReplicationInfo had been initialized. foreach DynamicActors(class'VoiceChatReplicationInfo', VRI) { VoiceInfo = VRI; break; } if ( Team != None ) bTeamNotified = true; } simulated function bool NeedNetNotify() { return ( !bRegisteredChatRoom || (!bNoTeam && (Team == None)) ); } simulated event PostNetReceive() { local Actor A; local PlayerController PC; if ( !bTeamNotified && (Team != None) ) { bTeamNotified = true; PC = Level.GetLocalPlayerController(); ForEach DynamicActors(class'Actor', A) { // find my pawn and tell it if ( Pawn(A) != None && Pawn(A).PlayerReplicationInfo == self ) { Pawn(A).NotifyTeamChanged(); if ( PC.PlayerReplicationInfo != self ) break; } else if ( A.bNotifyLocalPlayerTeamReceived && PC.PlayerReplicationInfo == self ) A.NotifyLocalPlayerTeamReceived(); //if this is the local player's PRI, tell actors that want to know about it } } if ( !bRegisteredChatRoom && VoiceInfo != None && PlayerID != default.PlayerID && VoiceID != default.VoiceID ) { bRegisteredChatRoom = True; VoiceInfo.AddVoiceChatter(Self); } bNetNotify = NeedNetNotify(); } simulated function Destroyed() { local GameReplicationInfo GRI; if ( Level.GRI != None ) Level.GRI.RemovePRI(self); else { ForEach DynamicActors(class'GameReplicationInfo',GRI) { GRI.RemovePRI(self); break; } } if ( VoiceInfo == None ) foreach DynamicActors( class'VoiceChatReplicationInfo', VoiceInfo ) break; if ( VoiceInfo != None ) VoiceInfo.RemoveVoiceChatter(Self); Super.Destroyed(); } function SetCharacterVoice(string S) { local class NewVoiceType; if ( (Left(S,1) == ".") || (Right(S,1) == ".") || (Left(S,5) ~= "none.") ) { return; } if ( (Level.NetMode == NM_DedicatedServer) && (VoiceType != None) ) { VoiceTypeName = S; return; } if ( S == "" ) { VoiceTypeName = ""; return; } NewVoiceType = class(DynamicLoadObject(S,class'Class')); if ( NewVoiceType != None ) { VoiceType = NewVoiceType; VoiceTypeName = S; } } function SetCharacterName(string S) { CharacterName = S; } /* Reset() reset actor to initial state - used when restarting level without reloading. */ function Reset() { Super.Reset(); Score = 0; Deaths = 0; HasFlag = None; bReadyToPlay = false; NumLives = 0; bOutOfLives = false; } simulated function string GetHumanReadableName() { return PlayerName; } simulated function string GetLocationName() { local string VehicleString; local Vehicle V; if( ( PlayerVolume == None ) && ( PlayerZone == None ) ) { if ( (Owner != None) && Controller(Owner).IsInState('Dead') ) return StringDead; else return StringSpectating; } if ( Owner != None ) { if ( Vehicle(Controller(Owner).Pawn) != None ) VehicleString = Vehicle(Controller(Owner).Pawn).GetVehiclePositionString(); } else if ( Level.NetMode == NM_Client ) { if ( (CurrentVehicle != None) && (CurrentVehicle.PlayerReplicationInfo == self) ) VehicleString = CurrentVehicle.GetVehiclePositionString(); else if ( Level.TimeSeconds - Level.LastVehicleCheck > 1 ) { // vehicles are often bAlwaysRelevant, so may still be relevant ForEach DynamicActors(class'Vehicle', V) if ( V.PlayerReplicationInfo == self ) { VehicleString = V.GetVehiclePositionString(); CurrentVehicle = V; break; } if ( V == None ) Level.LastVehicleCheck = Level.TimeSeconds; } } if( ( PlayerVolume != None ) && ( PlayerVolume.LocationName != class'Volume'.Default.LocationName ) ) { if ( len(PlayerVolume.LocationName@VehicleString) > 32 ) return PlayerVolume.LocationName; return PlayerVolume.LocationName@VehicleString; } else if( PlayerZone != None && ( PlayerZone.LocationName != "" ) ) { if ( len(PlayerZone.LocationName@VehicleString) > 32 ) return PlayerZone.LocationName; return PlayerZone.LocationName@VehicleString; } else if ( VehicleString != "" ) return VehicleString; else if ( Level.Title != Level.Default.Title ) return Level.Title; else return StringUnknown; } simulated function material GetPortrait(); event UpdateCharacter(); function UpdatePlayerLocation() { local Volume V, Best; local Pawn P; local Controller C; C = Controller(Owner); if( C != None ) P = C.Pawn; if( P == None ) { PlayerVolume = None; PlayerZone = None; return; } if ( PlayerZone != P.Region.Zone ) PlayerZone = P.Region.Zone; foreach P.TouchingActors( class'Volume', V ) { if( V.LocationName == "") continue; if( (Best != None) && (V.LocationPriority <= Best.LocationPriority) ) continue; if( V.Encompasses(P) ) Best = V; } if ( PlayerVolume != Best ) PlayerVolume = Best; } /* DisplayDebug() list important controller attributes on canvas */ simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos) { if ( Team != None ) Canvas.DrawText(" PlayerName "$PlayerName$" Team "$Team.GetHumanReadableName() $"("$Team.TeamIndex$") has flag "$HasFlag); else Canvas.DrawText(" PlayerName "$PlayerName$" NO Team"); if ( !bBot ) { YPos += YL; Canvas.SetPos(4, YL); Canvas.DrawText(" bIsSpec:"$bIsSpectator@"OnlySpec:"$bOnlySpectator@"Waiting:"$bWaitingPlayer@"Ready:"$bReadyToPlay@"OutOfLives:"$bOutOfLives); } } event ClientNameChange() { local PlayerController PC; ForEach DynamicActors(class'PlayerController', PC) PC.ReceiveLocalizedMessage( class'GameMessage', 2, self ); } function Timer() { local Controller C; UpdatePlayerLocation(); SetTimer(1.5 + FRand(), true); if( FRand() < 0.65 ) return; if( !bBot ) { C = Controller(Owner); if ( !bReceivedPing ) Ping = Min(int(0.25 * float(C.ConsoleCommand("GETPING"))),255); } } function SetPlayerName(string S) { OldName = PlayerName; PlayerName = S; if ( PlayerController(Owner) != None ) PlayerController(Owner).PlayerOwnerName = S; } function SetWaitingPlayer(bool B) { bIsSpectator = B; bWaitingPlayer = B; } function SetChatPassword( string InPassword ) { if ( PrivateChatRoom != None ) PrivateChatRoom.SetChannelPassword(InPassword); } function SetVoiceMemberMask( int NewMask ) { VoiceMemberMask = NewMask; } simulated function string GetCallSign() { if ( TeamID > 14 ) return ""; return class'GameInfo'.default.CallSigns[TeamID]; } simulated event string GetNameCallSign() { if ( TeamID > 14 ) return PlayerName; return PlayerName$" ["$class'GameInfo'.default.CallSigns[TeamID]$"]"; } // if _RO_ // implemented in ROPlayerReplicationInfo simulated function Material getRolePortrait() { return none; } // end if _RO_ defaultproperties { RemoteRole=ROLE_SimulatedProxy bAlwaysRelevant=True StringSpectating="Spectating" StringUnknown="Unknown" StringDead="Dead" NetUpdateFrequency=1 VoiceID=255 bNetNotify=True }