Class ExtPlayerController extends KFPlayerController; 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 ) { // 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 ) { 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()$" got item: "$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 killed himself with "$S; } else if( class(DamType)!=None ) return Victim$Chr(6)$"M was burned to death"; else if( class(DamType)!=None ) return Victim$Chr(6)$"M was blown into pieces"; return Victim$Chr(6)$"M had a sudden heart attack"; } 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 was killed by "$Chr(6)$T$Killer$Chr(6)$"M's "$S; } else if( class(DamType)!=None ) return Chr(6)$"O"$Victim$Chr(6)$"M was incinerated by "$Chr(6)$T$Killer; else if( class(DamType)!=None ) return Chr(6)$"O"$Victim$Chr(6)$"M was blown up by "$Chr(6)$T$Killer; return Chr(6)$"O"$Victim$Chr(6)$"M was killed by "$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("Connection Error: "$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); 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("Now viewing from "$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("Now viewing from "$PRI.GetHumanReadableName()); if( CurrentSpectateMode==SMODE_Roaming ) SpectatePlayer( SMODE_PawnFreeCam ); } reliable server function SpectateRoaming() { local Pawn P; P = Pawn(ViewTarget); ClientMessage("Viewing from own camera."); 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; } } 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 }