Class ExtPlayerController extends KFPlayerController; var localized string GotItemText; var localized string KilledHimselfWith; var localized string WasBurnedToDeath; var localized string WasBlownIntoPeaces; var localized string HadSuddenHeartAttack; var localized string WasKilledBy; var localized string WasIncineratedBy; var localized string WasBlownUpBy; var localized string ConnectionError; var localized string Disconnecting; var localized string NowViewingFrom; var localized string ViewingFromOwnCamera; struct FAdminCmdType { var string Cmd,Info; }; enum EDmgMsgType { DMG_PawnDamage, DMG_EXP, DMG_Heal, }; var string ServerMOTD,PendingMOTD; var ExtPerkManager ActivePerkManager; var class MidGameMenuClass; var class PendingPerkClass; var private transient rotator OldViewRot; var private transient float LastMisfireTime,LastFireTime,MisfireTimer; var private transient byte MisfireCount,MisrateCounter; var transient float NextSpectateChange,NextCommTime; var array AdminCommands; var transient byte DropCount; var transient Object UserAPI; var transient SoundCue BonusMusic; var transient Object BonusFX; // Stats var transient byte TransitListNum; var transient int TransitIndex; // Dramatic end-game camera. var transient vector EndGameCamFocusPos[2],CalcViewLocation; var transient rotator EndGameCamRot,CalcViewRotation; var transient float EndGameCamTimer,LastPlayerCalcView; var transient bool bEndGameCamFocus; var globalconfig bool bShowFPLegs,bHideNameBeacons,bHideKillMsg,bHideDamageMsg,bHideNumberMsg,bNoMonsterPlayer,bNoScreenShake,bRenderModes,bUseKF2DeathMessages,bUseKF2KillMessages; var globalconfig int SelectedEmoteIndex; var bool bMOTDReceived,bNamePlateShown,bNamePlateHidden,bClientHideKillMsg,bClientHideDamageMsg,bClientHideNumbers,bNoDamageTracking,bClientNoZed,bSetPerk; struct SavedSkins { var int ID; var class WepDef; }; var globalconfig array SavedWeaponSkins; replication { // Things the server should send to the client. if (bNetDirty) MidGameMenuClass,ActivePerkManager; } simulated function PostBeginPlay() { Super.PostBeginPlay(); if (WorldInfo.NetMode!=NM_Client && ActivePerkManager==None) { ActivePerkManager = Spawn(class'ExtPerkManager',Self); ActivePerkManager.PlayerOwner = Self; ActivePerkManager.PRIOwner = ExtPlayerReplicationInfo(PlayerReplicationInfo); if (ActivePerkManager.PRIOwner!=None) ActivePerkManager.PRIOwner.PerkManager = ActivePerkManager; SetTimer(0.1,true,'CheckPerk'); } } simulated function Destroyed() { if (ActivePerkManager!=None) ActivePerkManager.PreNotifyPlayerLeave(); Super.Destroyed(); if (ActivePerkManager!=None) ActivePerkManager.Destroy(); } function CheckPerk() { if (CurrentPerk!=ActivePerkManager) { CurrentPerk = ActivePerkManager; if (KFPlayerReplicationInfo(PlayerReplicationInfo)!=None) { KFPlayerReplicationInfo(PlayerReplicationInfo).NetPerkIndex = 0; KFPlayerReplicationInfo(PlayerReplicationInfo).CurrentPerkClass = ActivePerkManager.Class; } } } reliable client function AddAdminCmd(string S) { local int i,j; j = InStr(S,":"); i = AdminCommands.Length; AdminCommands.Length = i+1; if (j==-1) { AdminCommands[i].Cmd = S; AdminCommands[i].Info = S; } else { AdminCommands[i].Cmd = Left(S,j); AdminCommands[i].Info = Mid(S,j+1); } } reliable client function ClientSetHUD(class newHUDType) { Super.ClientSetHUD(newHUDType); SendServerSettings(); } reliable client function ClientSetBonus(SoundCue C, Object FX) { BonusMusic = C; BonusFX = FX; } simulated final function SendServerSettings() { if (LocalPlayer(Player)!=None) ServerSetSettings(bHideKillMsg,bHideDamageMsg,bHideNumberMsg,bNoMonsterPlayer); } reliable server function ServerSetSettings(bool bHideKill, bool bHideDmg, bool bHideNum, bool bNoZ) { bClientHideKillMsg = bHideKill; bClientHideDamageMsg = bHideDmg; bClientHideNumbers = bHideNum; bNoDamageTracking = (bHideDmg && bHideNum); bClientNoZed = bNoZ; } unreliable server function NotifyFixed(byte Mode) { if (Mode==1 && (Pawn==None || (WorldInfo.TimeSeconds-Pawn.SpawnTime)<5.f)) return; OnClientFixed(Self,Mode); if (Default.bRenderModes && ExtPlayerReplicationInfo(PlayerReplicationInfo)!=None) ExtPlayerReplicationInfo(PlayerReplicationInfo).SetFixedData(Mode); } delegate OnClientFixed(ExtPlayerController PC, byte Mode); reliable client event ReceiveLocalizedMessage(class Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject) { if (Message!=class'KFLocalMessage_PlayerKills' && (Message!=class'KFLocalMessage_Game' || (Switch!=KMT_Suicide && Switch!=KMT_Killed))) Super.ReceiveLocalizedMessage(Message,Switch,RelatedPRI_1,RelatedPRI_2,OptionalObject); } function AddZedKill(class MonsterClass, byte Difficulty, class DT, bool bKiller) { // Stats. if (ActivePerkManager!=None) { ActivePerkManager.TotalKills++; ActivePerkManager.PRIOwner.RepKills++; } } unreliable client function ClientPlayCameraShake(CameraShake Shake, optional float Scale=1.f, optional bool bTryForceFeedback, optional ECameraAnimPlaySpace PlaySpace=CAPS_CameraLocal, optional rotator UserPlaySpaceRot) { if (!bNoScreenShake) Super.ClientPlayCameraShake(Shake,Scale,bTryForceFeedback,PlaySpace,UserPlaySpaceRot); } exec final function AwardXP(int XP, optional byte Mode) { if (WorldInfo.NetMode!=NM_Client && ActivePerkManager!=None) ActivePerkManager.EarnedEXP(XP,Mode); } /** Perk xp stat */ function OnPlayerXPAdded(INT XP, class PerkClass) { AwardXP(XP); } function AddSmallRadiusKill(byte Difficulty, class PerkClass) { AwardXP(class'KFPerk_Berserker'.static.GetSmallRadiusKillXP(Difficulty)); } function AddWeldPoints(int PointsWelded) { AwardXP(PointsWelded,1); } function AddHealPoints(int PointsHealed) { AwardXP(PointsHealed,2); } function AddShotsHit(int AddedHits) { local KFWeapon W; local float T; Super.AddShotsHit(AddedHits); W = KFWeapon(Pawn.Weapon); if (W==None) { if (LastMisfireTime>WorldInfo.TimeSeconds) { if (++MisfireCount>15 && (WorldInfo.TimeSeconds-MisfireTimer)>10.f) NotifyFixed(8); LastMisfireTime = WorldInfo.TimeSeconds+2.f; return; } MisfireCount = 0; LastMisfireTime = WorldInfo.TimeSeconds+2.f; MisfireTimer = WorldInfo.TimeSeconds; return; } if (!W.HasAmmo(W.CurrentFireMode)) { if (LastMisfireTime>WorldInfo.TimeSeconds) { if (++MisfireCount>15 && (WorldInfo.TimeSeconds-MisfireTimer)>10.f) NotifyFixed(16); LastMisfireTime = WorldInfo.TimeSeconds+2.f; return; } MisfireCount = 0; LastMisfireTime = WorldInfo.TimeSeconds+2.f; MisfireTimer = WorldInfo.TimeSeconds; return; } T = W.GetFireInterval(W.CurrentFireMode); ActivePerkManager.ModifyRateOfFire(T,W); if ((WorldInfo.TimeSeconds-LastFireTime)<(T*0.5) || !W.IsFiring()) { if ((WorldInfo.TimeSeconds-LastFireTime)>4.f) MisrateCounter = 0; LastFireTime = WorldInfo.TimeSeconds; if (MisrateCounter<5) { ++MisrateCounter; return; } if (LastMisfireTime>WorldInfo.TimeSeconds) { if (++MisfireCount>15 && (WorldInfo.TimeSeconds-MisfireTimer)>10.f) NotifyFixed(2); LastMisfireTime = WorldInfo.TimeSeconds+1.f; return; } MisfireCount = 0; LastMisfireTime = WorldInfo.TimeSeconds+1.f; MisfireTimer = WorldInfo.TimeSeconds; } else MisrateCounter = 0; } // Message of the day. Delegate OnSetMOTD(ExtPlayerController PC, string S); reliable client function ReceiveServerMOTD(string S, bool bFinal) { ServerMOTD $= S; bMOTDReceived = bFinal; } reliable server function ServerSetMOTD(string S, bool bFinal) { PendingMOTD $= S; if (bFinal && PendingMOTD!="") { OnSetMOTD(Self,PendingMOTD); PendingMOTD = ""; } } // TESTING: reliable server function ServerItemDropGet(string Item) { if (DropCount>5 || Len(Item)>100) return; ++DropCount; WorldInfo.Game.Broadcast(Self,PlayerReplicationInfo.GetHumanReadableName()@GotItemText@Item); } reliable client function ReceiveLevelUp(Ext_PerkBase Perk, int NewLevel) { if (Perk!=None) MyGFxHUD.LevelUpNotificationWidget.ShowAchievementNotification(class'KFGFxWidget_LevelUpNotification'.Default.LevelUpString, Perk.PerkName, class'KFGFxWidget_LevelUpNotification'.Default.TierUnlockedString, Perk.GetPerkIconPath(NewLevel), false, NewLevel); } reliable client function ReceiveKillMessage(class Victim, optional bool bGlobal, optional PlayerReplicationInfo KillerPRI) { if (bHideKillMsg || (bGlobal && KillerPRI==None)) return; if (bUseKF2KillMessages) { if (MyGFxHUD != none) { ExtMoviePlayer_HUD(MyGFxHUD).ShowKillMessageX((bGlobal ? KillerPRI : None), None, ,false, Victim); } } else if (KFExtendedHUD(myHUD)!=None && Victim!=None) KFExtendedHUD(myHUD).AddKillMessage(Victim,1,KillerPRI,byte(bGlobal)); } unreliable client function ReceiveDamageMessage(class Victim, int Damage) { if (!bHideDamageMsg && KFExtendedHUD(myHUD)!=None && Victim!=None) KFExtendedHUD(myHUD).AddKillMessage(Victim,Damage,None,2); } unreliable client function ClientNumberMsg(int Count, vector Pos, EDmgMsgType Type) { if (!bHideNumberMsg && KFExtendedHUD(myHUD)!=None) KFExtendedHUD(myHUD).AddNumberMsg(Count,Pos,Type); } reliable client event TeamMessage(PlayerReplicationInfo PRI, coerce string S, name Type, optional float MsgLifeTime ) { //if (((Type == 'Say') || (Type == 'TeamSay')) && (PRI != None)) // SpeakTTS(S, PRI); <- KF built without TTS... // since this is on the client, we can assume that if Player exists, it is a LocalPlayer if (Player!=None) { if (((Type == 'Say') || (Type == 'TeamSay')) && (PRI != None)) S = PRI.GetHumanReadableName()$": "$S; LocalPlayer(Player).ViewportClient.ViewportConsole.OutputText("("$Type$") "$S); } if (MyGFxManager != none && MyGFxManager.PartyWidget != none) { if (!MyGFxManager.PartyWidget.ReceiveMessage(S)) //Fails if message is for updating perks in a steam lobby return; } if (MyGFxHUD != none) { switch (Type) { case 'Log': break; // Console only message. case 'Music': MyGFxHUD.MusicNotification.ShowSongInfo(S); break; case 'Event': MyGFxHUD.HudChatBox.AddChatMessage(S, class 'KFLocalMessage'.default.DefaultColor); break; case 'DeathMessage': //MyGFxHUD.HudChatBox.AddChatMessage(S, "FF0000"); // Console message only. break; case 'Say': case 'TeamSay': if (ExtPlayerReplicationInfo(PRI)!=None && ExtPlayerReplicationInfo(PRI).ShowAdminName()) MyGFxHUD.HudChatBox.AddChatMessage("("$ExtPlayerReplicationInfo(PRI).GetAdminNameAbr()$")"$S, ExtPlayerReplicationInfo(PRI).GetAdminColor()); else MyGFxHUD.HudChatBox.AddChatMessage(S, "64FE2E"); break; case 'Priority': MyGFxHUD.HudChatBox.AddChatMessage(S, class 'KFLocalMessage'.default.PriorityColor); break; case 'CriticalEvent': PopScreenMsg(S); // HIGH|Low|Time break; case 'LowCriticalEvent': MyGFxHUD.ShowNonCriticalMessage(S); break; default: MyGFxHUD.HudChatBox.AddChatMessage(class'KFLocalMessage'.default.SystemString@S, class 'KFLocalMessage'.default.EventColor); } } } final function PopScreenMsg(string S) { local int i; local string L; local float T; T = 4.f; // Get lower part. i = InStr(S,"|"); if (i!=-1) { L = Mid(S,i+1); S = Left(S,i); // Get time. i = InStr(L,"|"); if (i!=-1) { T = float(Mid(L,i+1)); L = Left(L,i); } } MyGFxHUD.DisplayPriorityMessage(S,L,T); } reliable client function ClientKillMessage(class DamType, PlayerReplicationInfo Victim, PlayerReplicationInfo KillerPRI, optional class KillerPawn) { local string Msg,S; local bool bFF; if (Player==None || Victim==None) return; if (bUseKF2DeathMessages && MyGFxHUD!=None) { if (Victim==KillerPRI || (KillerPRI==None && KillerPawn==None)) // Suicide ExtMoviePlayer_HUD(MyGFxHUD).ShowKillMessageX(None, Victim, ,true); else ExtMoviePlayer_HUD(MyGFxHUD).ShowKillMessageX(KillerPRI, Victim, ,true, KillerPawn); } if (Victim==KillerPRI || (KillerPRI==None && KillerPawn==None)) // Suicide { if (Victim.GetTeamNum()==0) { Msg = ParseSuicideMsg(Chr(6)$"O"$Victim.GetHumanReadableName(),DamType); class'KFMusicStingerHelper'.static.PlayPlayerDiedStinger(Self); } else Msg = ParseSuicideMsg(Chr(6)$"K"$Victim.GetHumanReadableName(),DamType); } else { if (KillerPRI!=None && Victim.Team!=None && Victim.Team==KillerPRI.Team) // Team-kill { bFF = true; S = KillerPRI.GetHumanReadableName(); class'KFMusicStingerHelper'.static.PlayTeammateDeathStinger(Self); } else // Killed by monster. { bFF = false; if (KillerPRI!=None) { S = KillerPRI.GetHumanReadableName(); } else { S = class'KFExtendedHUD'.Static.GetNameOf(KillerPawn); if (class(KillerPawn)!=None && class(KillerPawn).Default.MinSpawnSquadSizeType==EST_Boss) // Boss type. S = "the "$S; else S = class'KFExtendedHUD'.Static.GetNameArticle(S)@S; } class'KFMusicStingerHelper'.static.PlayZedKillHumanStinger(Self); } Msg = ParseKillMsg(Victim.GetHumanReadableName(),S,bFF,DamType); } S = Class'KFExtendedHUD'.Static.StripMsgColors(Msg); if (!bUseKF2DeathMessages) KFExtendedHUD(myHUD).AddDeathMessage(Msg,S); ClientMessage(S,'DeathMessage'); } reliable client function ClientZedKillMessage(class DamType, string Victim, optional PlayerReplicationInfo KillerPRI, optional class KillerPawn, optional bool bFFKill) { local string Msg,S; if (Player==None) return; if (bUseKF2DeathMessages && MyGFxHUD!=None) { if (KillerPRI==None && KillerPawn==None) // Suicide ExtMoviePlayer_HUD(MyGFxHUD).ShowKillMessageX(None, None, Victim, true); else ExtMoviePlayer_HUD(MyGFxHUD).ShowKillMessageX(KillerPRI, None, Victim, true, KillerPawn); } if (KillerPRI==None && KillerPawn==None) // Suicide { Msg = ParseSuicideMsg(Chr(6)$"O"$Victim,DamType); } else { if (KillerPRI!=None) // Team-kill { S = KillerPRI.GetHumanReadableName(); } else // Killed by monster. { S = class'KFExtendedHUD'.Static.GetNameOf(KillerPawn); if (class(KillerPawn)!=None && class(KillerPawn).Default.MinSpawnSquadSizeType==EST_Boss) // Boss type. S = "the "$S; else S = class'KFExtendedHUD'.Static.GetNameArticle(S)@S; } Msg = ParseKillMsg(Victim,S,bFFKill,DamType); } S = Class'KFExtendedHUD'.Static.StripMsgColors(Msg); if (!bUseKF2DeathMessages) KFExtendedHUD(myHUD).AddDeathMessage(Msg,S); ClientMessage(S,'DeathMessage'); } simulated final function string ParseSuicideMsg(string Victim, class DamType) { local string S; S = string(DamType.Name); if (Left(S,15)~="KFDT_Ballistic_") { S = Mid(S,15); // Weapon name. return Victim$Chr(6)$"M"@KilledHimselfWith@S; } else if (class(DamType)!=None) return Victim$Chr(6)$"M"@WasBurnedToDeath; else if (class(DamType)!=None) return Victim$Chr(6)$"M"@WasBlownIntoPeaces; return Victim$Chr(6)$"M"@HadSuddenHeartAttack; } simulated final function string ParseKillMsg(string Victim, string Killer, bool bFF, class DamType) { local string T,S; T = (bFF ? "O" : "K"); S = string(DamType.Name); if (Left(S,15)~="KFDT_Ballistic_") { S = Mid(S,15); // Weapon name. return Chr(6)$"O"$Victim$Chr(6)$"M"@WasKilledBy@Chr(6)$T$Killer$Chr(6)$"M's "$S; } else if (class(DamType)!=None) return Chr(6)$"O"$Victim$Chr(6)$"M"@WasIncineratedBy@Chr(6)$T$Killer; else if (class(DamType)!=None) return Chr(6)$"O"$Victim$Chr(6)$"M"@WasBlownUpBy@Chr(6)$T$Killer; return Chr(6)$"O"$Victim$Chr(6)$"M"@WasKilledBy@Chr(6)$T$Killer; } reliable server function ServerCamera(name NewMode) { // <- REMOVED CAMERA LOGGING (PlayerController) if (NewMode == '1st') NewMode = 'FirstPerson'; else if (NewMode == '3rd') NewMode = 'ThirdPerson'; SetCameraMode(NewMode); } exec function Camera(name NewMode) { ServerCamera(PlayerCamera.CameraStyle=='FirstPerson' ? 'ThirdPerson' : 'FirstPerson'); } simulated final function ToggleFPBody(bool bEnable) { bShowFPLegs = bEnable; Class'ExtPlayerController'.Default.bShowFPLegs = bEnable; if (ExtHumanPawn(Pawn)!=None) ExtHumanPawn(Pawn).UpdateFPLegs(); } /*exec function KickBan(string S) { if (WorldInfo.Game!=None) WorldInfo.Game.KickBan(S); }*/ exec function Kick(string S) { if (WorldInfo.Game!=None) WorldInfo.Game.Kick(S); } reliable server function SkipLobby(); Delegate OnChangePerk(ExtPlayerController PC, class NewPerk); reliable server function SwitchToPerk(class PerkClass) { if (PerkClass!=None) OnChangePerk(Self,PerkClass); } Delegate OnBoughtStats(ExtPlayerController PC, class PerkClass, int iStat, int Amount); reliable server function BuyPerkStat(class PerkClass, int iStat, int Amount) { if (PerkClass!=None && Amount>0 && iStat>=0) OnBoughtStats(Self,PerkClass,iStat,Amount); } Delegate OnBoughtTrait(ExtPlayerController PC, class PerkClass, class Trait); reliable server function BoughtTrait(class PerkClass, class Trait) { if (PerkClass!=None && Trait!=None) OnBoughtTrait(Self,PerkClass,Trait); } Delegate OnPerkReset(ExtPlayerController PC, class PerkClass, bool bPrestige); reliable server function ServerResetPerk(class PerkClass, bool bPrestige) { if (PerkClass!=None) OnPerkReset(Self,PerkClass,bPrestige); } Delegate OnAdminHandle(ExtPlayerController PC, int PlayerID, int Action); reliable server function AdminRPGHandle(int PlayerID, int Action) { OnAdminHandle(Self,PlayerID,Action); } simulated reliable client event bool ShowConnectionProgressPopup(EProgressMessageType ProgressType, string ProgressTitle, string ProgressDescription, bool SuppressPasswordRetry = false) { switch (ProgressType) { case PMT_ConnectionFailure : case PMT_PeerConnectionFailure : KFExtendedHUD(myHUD).NotifyLevelChange(); KFExtendedHUD(myHUD).ShowProgressMsg(ConnectionError@ProgressTitle$"|"$ProgressDescription$"|"$Disconnecting,true); return true; case PMT_DownloadProgress : KFExtendedHUD(myHUD).NotifyLevelChange(); case PMT_AdminMessage : KFExtendedHUD(myHUD).ShowProgressMsg(ProgressTitle$"|"$ProgressDescription); return true; } return false; } simulated function CancelConnection() { if (KFExtendedHUD(myHUD)!=None) KFExtendedHUD(myHUD).CancelConnection(); else class'Engine'.Static.GetEngine().GameViewport.ConsoleCommand("Disconnect"); } function NotifyLevelUp(class PerkClass, byte PerkLevel, byte NewPrestigeLevel); function ShowBossNameplate(KFInterface_MonsterBoss KFBoss, optional string PlayerName) { if (!bNamePlateShown) // Dont make multiple bosses pop this up multiple times. { bNamePlateShown = true; Super.ShowBossNameplate(KFBoss,PlayerName); SetTimer(8,false,'HideBossNameplate'); // MAKE sure it goes hidden. } } function HideBossNameplate() { if (!bNamePlateHidden) { bNamePlateHidden = false; Super.HideBossNameplate(); ClearTimer('HideBossNameplate'); if (MyGFxHUD!=None) MyGFxHUD.MusicNotification.SetVisible(true); } } function UpdateRotation(float DeltaTime) { if (OldViewRot!=Rotation && Pawn!=None && Pawn.IsAliveAndWell()) NotifyFixed(1); Super.UpdateRotation(DeltaTime); OldViewRot = Rotation; } reliable server function ServerGetUnloadInfo(byte CallID, class PerkClass, bool bUnload) { OnRequestUnload(Self,CallID,PerkClass,bUnload); } delegate OnRequestUnload(ExtPlayerController PC, byte CallID, class PerkClass, bool bUnload); reliable client function ClientGotUnloadInfo(byte CallID, byte Code, optional int DataA, optional int DataB) { OnClientGetResponse(CallID,Code,DataA,DataB); } delegate OnClientGetResponse(byte CallID, byte Code, int DataA, int DataB); function DefClientResponse(byte CallID, byte Code, int DataA, int DataB); reliable client function ClientUsedAmmo(Ext_T_SupplierInteract S) { if (Pawn!=None && S!=None) S.UsedOnClient(Pawn); } unreliable server function ServerNextSpectateMode() { local Pawn HumanViewTarget; if (!IsSpectating()) return; // switch to roaming if human viewtarget is dead if (CurrentSpectateMode != SMODE_Roaming) { HumanViewTarget = Pawn(ViewTarget); if (HumanViewTarget == none || !HumanViewTarget.IsAliveAndWell()) { SpectateRoaming(); return; } } switch (CurrentSpectateMode) { case SMODE_PawnFreeCam: SpectatePlayer(SMODE_PawnThirdPerson); break; case SMODE_PawnThirdPerson: SpectatePlayer(SMODE_PawnFirstPerson); break; case SMODE_PawnFirstPerson: case SMODE_Roaming: SpectatePlayer(SMODE_PawnFreeCam); break; } } function ViewAPlayer(int dir) { local PlayerReplicationInfo PRI; PRI = GetNextViewablePlayer(dir); if (PRI!=None) { SetViewTarget(PRI); ClientMessage(NowViewingFrom@PRI.GetHumanReadableName()); } } exec function ViewPlayerID(int ID) { ServerViewPlayerID(ID); } reliable server function ServerViewPlayerID(int ID) { local PlayerReplicationInfo PRI; if (!IsSpectating()) return; // Find matching player by ID foreach WorldInfo.GRI.PRIArray(PRI) { if (PRI.PlayerID==ID) break; } if (PRI==None || PRI.PlayerID!=ID || Controller(PRI.Owner)==None || Controller(PRI.Owner).Pawn==None || !WorldInfo.Game.CanSpectate(self, PRI)) return; SetViewTarget(PRI); ClientMessage(NowViewingFrom@PRI.GetHumanReadableName()); if (CurrentSpectateMode==SMODE_Roaming) SpectatePlayer(SMODE_PawnFreeCam); } reliable server function SpectateRoaming() { local Pawn P; P = Pawn(ViewTarget); ClientMessage(ViewingFromOwnCamera); Super.SpectateRoaming(); if (P!=None) { SetLocation(P.Location); SetRotation(P.GetViewRotation()); ClientSetLocation(Location,Rotation); } } reliable client function ClientSetLocation(vector NewLocation, rotator NewRotation) { SetLocation(NewLocation); Super.ClientSetLocation(NewLocation,NewRotation); } unreliable server function ServerPlayLevelUpDialog() { if (NextCommTime=20.f) // Finished view. { bEndGameCamFocus = false; if (LocalPlayer(Player)!=None && KFPawn(ViewTarget)!=None) KFPawn(ViewTarget).SetMeshVisibility(!Global.UsingFirstPersonCamera()); return false; } // Setup other cache params. LastPlayerCalcView = WorldInfo.TimeSeconds; CalcViewLocation.Z = 1.f; RT = WorldInfo.RealTimeSeconds; if (T<4.f) RT += (4.f-T); CalcViewLocation.X = Sin(RT*0.08f); CalcViewLocation.Y = Cos(RT*0.08f); CalcViewLocation = EndGameCamFocusPos[0] + Normal(CalcViewLocation)*350.f; if (Trace(HL,HN,CalcViewLocation,EndGameCamFocusPos[0],false,vect(16,16,16))!=None) CalcViewLocation = HL; CalcViewRotation = rotator(EndGameCamFocusPos[0]-CalcViewLocation); if (T<4.f && LocalPlayer(Player)!=None) // Zoom in to epic death. { T*=0.25; CalcViewLocation = CalcViewLocation*T + EndGameCamFocusPos[1]*(1.f-T); CalcViewRotation = RLerp(EndGameCamRot,CalcViewRotation,T,true); } return true; } simulated event GetPlayerViewPoint(out vector out_Location, out Rotator out_Rotation) { if (bEndGameCamFocus && CalcEndGameCam()) { out_Location = CalcViewLocation; out_Rotation = CalcViewRotation; return; } Super.GetPlayerViewPoint(out_Location,out_Rotation); } exec function DebugRenderMode() { if (WorldInfo.NetMode!=NM_Client) { bRenderModes = !bRenderModes; SaveConfig(); ClientMessage(bRenderModes); } } // Stats traffic. reliable server function ServerRequestStats(byte ListNum) { if (ListNum<3) { TransitListNum = ListNum; TransitIndex = 0; SetTimer(0.001,true,'SendNextList'); } } function SendNextList() { if (!OnClientGetStat(Self,TransitListNum,TransitIndex++)) { ClientGetStat(TransitListNum,true); ClearTimer('SendNextList'); } } simulated reliable client function ClientGetStat(byte ListNum, bool bFinal, optional string N, optional UniqueNetId ID, optional int V) { OnClientReceiveStat(ListNum,bFinal,N,ID,V); } Delegate OnClientReceiveStat(byte ListNum, bool bFinal, string N, UniqueNetId ID, int V); Delegate bool OnClientGetStat(ExtPlayerController PC, byte ListNum, int StatIndex); reliable server function ChangeSpectateMode(bool bSpectator) { OnSpectateChange(Self,bSpectator); } simulated reliable client function ClientSpectateMode(bool bSpectator) { UpdateURL("SpectatorOnly",(bSpectator ? "1" : "0"),false); } Delegate OnSpectateChange(ExtPlayerController PC, bool bSpectator); state RagdollMove extends PlayerWalking { Ignores NotifyPhysicsVolumeChange,ServerCamera,ResetCameraMode; event BeginState(Name PreviousStateName) { FOVAngle = DesiredFOV; if (WorldInfo.NetMode!=NM_Client) SetCameraMode('ThirdPerson'); } event EndState(Name NewState) { FOVAngle = DesiredFOV; if (Pawn!=none && NewState!='Dead') Global.SetCameraMode('FirstPerson'); } function PlayerMove(float DeltaTime) { local rotator OldRotation; if (Pawn == None) GotoState('Dead'); else { // Update rotation. OldRotation = Rotation; UpdateRotation(DeltaTime); bDoubleJump = false; bPressedJump = false; if (Role < ROLE_Authority) // then save this move and replicate it ReplicateMove(DeltaTime, vect(0,0,0), DCLICK_None, OldRotation - Rotation); else ProcessMove(DeltaTime, vect(0,0,0), DCLICK_None, OldRotation - Rotation); } } simulated event GetPlayerViewPoint(out vector out_Location, out Rotator out_Rotation) { local Actor TheViewTarget; local vector HL,HN,EndOffset; if (bEndGameCamFocus && CalcEndGameCam()) { out_Location = CalcViewLocation; out_Rotation = CalcViewRotation; return; } if (Global.UsingFirstPersonCamera()) Global.GetPlayerViewPoint(out_Location,out_Rotation); else { out_Rotation = Rotation; TheViewTarget = GetViewTarget(); if (TheViewTarget==None) TheViewTarget = Self; out_Location = TheViewTarget.Location; EndOffset = out_Location-vector(Rotation)*250.f; if (TheViewTarget.Trace(HL,HN,EndOffset,out_Location,false,vect(16,16,16))!=None) out_Location = HL; else out_Location = EndOffset; } } } state PlayerWalking { ignores SeePlayer, HearNoise, Bump; function PlayerMove(float DeltaTime) { local vector X,Y,Z, NewAccel; local eDoubleClickDir DoubleClickMove; local rotator OldRotation; local bool bSaveJump; if (Pawn == None) { GotoState('Dead'); } else { GetAxes(Pawn.Rotation,X,Y,Z); if (VSZombie(Pawn)!=None) VSZombie(Pawn).ModifyPlayerInput(Self,DeltaTime); // Update acceleration. NewAccel = PlayerInput.aForward*X + PlayerInput.aStrafe*Y; NewAccel.Z = 0; NewAccel = Pawn.AccelRate * Normal(NewAccel); if (IsLocalPlayerController()) { AdjustPlayerWalkingMoveAccel(NewAccel); } DoubleClickMove = PlayerInput.CheckForDoubleClickMove(DeltaTime/WorldInfo.TimeDilation); // Update rotation. OldRotation = Rotation; UpdateRotation(DeltaTime); bDoubleJump = false; if (bPressedJump && Pawn.CannotJumpNow()) { bSaveJump = true; bPressedJump = false; } else { bSaveJump = false; } if (Role < ROLE_Authority) // then save this move and replicate it { ReplicateMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation); } else { ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation); } bPressedJump = bSaveJump; } } } state Dead { event BeginState(Name PreviousStateName) { local KFPlayerInput KFPI; SetTimer(5.f, false, nameof(StartSpectate)); if ((Pawn != None) && (Pawn.Controller == self)) Pawn.Controller = None; Pawn = None; FOVAngle = DesiredFOV; Enemy = None; bPressedJump = false; FindGoodView(); CleanOutSavedMoves(); if (KFPawn(ViewTarget)!=none) { KFPawn(ViewTarget).SetMeshVisibility(true); } // Deactivate any post process effects when we die ResetGameplayPostProcessFX(); if (CurrentPerk != none) CurrentPerk.PlayerDied(); KFPI = KFPlayerInput(PlayerInput); if (KFPI != none) KFPI.HideVoiceComms(); if (MyGFxManager != none) MyGFxManager.CloseMenus(); if (MyGFxHUD != none) MyGFxHUD.ClearBuffIcons(); } simulated event GetPlayerViewPoint(out vector out_Location, out Rotator out_Rotation) { local Actor TheViewTarget; local vector HL,HN,EndOffset; if (bEndGameCamFocus && CalcEndGameCam()) { out_Location = CalcViewLocation; out_Rotation = CalcViewRotation; return; } out_Rotation = Rotation; TheViewTarget = GetViewTarget(); if (TheViewTarget==None) TheViewTarget = Self; out_Location = TheViewTarget.Location; EndOffset = out_Location-vector(Rotation)*400.f; if (TheViewTarget.Trace(HL,HN,EndOffset,out_Location,false,vect(16,16,16))!=None) out_Location = HL; else out_Location = EndOffset; } } exec function RequestSwitchTeam() { ConsoleCommand("disconnect"); } exec function SwitchTeam() { ConsoleCommand("disconnect"); } defaultproperties { InputClass=Class'ExtPlayerInput' PurchaseHelperClass=class'ExtAutoPurchaseHelper' bIgnoreEncroachers=true SpectatorCameraSpeed=900 MidGameMenuClass=class'UI_MidGameMenu' PerkList.Empty() PerkList.Add((PerkClass=Class'ExtPerkManager')) NVG_DOF_FocalDistance=3800.0 NVG_DOF_SharpRadius=2500.0 NVG_DOF_FocalRadius=3500.0 NVG_DOF_MaxNearBlurSize=0.25 }