rott/kf_sources/Engine/Classes/PlayerController.uc
2026-07-14 20:27:09 +07:00

7853 lines
212 KiB
Ucode

//=============================================================================
// PlayerController
//
// PlayerControllers are used by human players to control pawns.
//
// This is a built-in Unreal class and it shouldn't be modified.
// for the change in Possess().
//=============================================================================
class PlayerController extends Controller
config(user)
native
nativereplication
exportstructs
DependsOn(Interactions);
// Player info.
var const player Player;
// player input control
var globalconfig bool bLookUpStairs; // look up/down stairs (player)
var globalconfig bool bSnapToLevel; // Snap to level eyeheight when not mouselooking
var globalconfig bool bAlwaysMouseLook;
var globalconfig bool bKeyboardLook; // no snapping when true
var bool bCenterView;
// Player control flags
var bool bBehindView; // Outside-the-player view.
var bool bFrozen; // set when game ends or player dies to temporarily prevent player from restarting (until cleared by timer)
var bool bPressedJump;
var bool bDoubleJump;
var bool bUpdatePosition;
var bool bIsTyping;
var bool bFixedCamera; // used to fix camera in position (to view animations)
var bool bJumpStatus; // used in net games
var bool bUpdating;
var globalconfig bool bNeverSwitchOnPickup; // if true, don't automatically switch to picked up weapon
var bool bHideSpectatorBeacons;
var bool bZooming;
var bool bHideVehicleNoEntryIndicator;
var globalconfig bool bAlwaysLevel;
var bool bSetTurnRot;
var bool bCheatFlying; // instantly stop in flying mode
var bool bFreeCamera; // free camera when in behindview mode (for checking out player models and animations)
var bool bZeroRoll;
var bool bCameraPositionLocked;
var bool bViewBot;
var bool UseFixedVisibility;
var bool bFreeCam; // In FreeCam mode to adjust the cam rotator
var bool bFreeCamZoom; // In zoom mode
var bool bFreeCamSwivel; // In swivel mode
var bool bBlockCloseCamera;
var bool bValidBehindCamera;
var bool bForcePrecache;
var bool bClientDemo;
var const bool bAllActorsRelevant; // used by UTTV. DO NOT SET THIS TRUE - it has a huge impact on network performance
var bool bShortConnectTimeOut; // when true, reduces connect timeout to 15 seconds
var bool bPendingDestroy; // when true, playercontroller is being destroyed
var bool bEnableAmbientShake;
var globalconfig bool bNoVoiceMessages;
var globalconfig bool bNoTextToSpeechVoiceMessages;
var globalconfig bool bNoVoiceTaunts;
var globalconfig bool bNoAutoTaunts;
var globalconfig bool bAutoTaunt;
var globalconfig bool bNoMatureLanguage;
var globalconfig bool bDynamicNetSpeed;
var globalconfig bool bSmallWeapons;
var bool bWeaponViewShake;
var globalconfig bool bLandingShake;
var globalconfig bool bAimingHelp;
var(ForceFeedback) globalconfig bool bEnablePickupForceFeedback;
var(ForceFeedback) globalconfig bool bEnableWeaponForceFeedback;
var(ForceFeedback) globalconfig bool bEnableDamageForceFeedback;
var(ForceFeedback) globalconfig bool bEnableGUIForceFeedback;
var(ForceFeedback) bool bForceFeedbackSupported; // true if a device is detected
var(VoiceChat) bool bVoiceChatEnabled; // Whether voice chat is enabled on this client
var(VoiceChat) globalconfig bool bEnableInitialChatRoom; // Enables speaking on DefaultActiveChannel upon joining server
var bool bViewingMatineeCinematic;
var bool bCustomListener;
var bool bAcuteHearing; // makes playercontroller hear much better (used to magnify hit sounds caused by player)
var bool bMenuBeforeRespawn; //forces the midgame menu to pop up before player can click to respawn
var bool bSkippedLastUpdate, bLastPressedJump;
var globalconfig bool bEnableStatsTracking;
var globalconfig bool bOnlySpeakTeamText;
var bool bWasSpeedHack;
var bool bIsSpaceFighter; // hack for spacefighter joystick controls
var const bool bWasSaturated; // used by servers to identify saturated client connections
var float FOVBias;
// Voice Chat
struct StoredChatPassword
{
var string ChatRoomName;
var string ChatRoomPassword;
};
// Contains a bit-mask of which channels to auto-join
// 1 - Public, 2 - Local, 4 - Team
var(VoiceChat) globalconfig byte AutoJoinMask;
var input byte
bStrafe, bSnapLevel, bLook, bFreeLook, bTurn180, bTurnToNearest, bXAxis, bYAxis;
var EDoubleClickDir DoubleClickDir; // direction of movement key double click (for special moves)
var globalconfig byte AnnouncerLevel; // 0=none, 1=no possession announcements, 2=all
var globalconfig byte AnnouncerVolume; // 1 to 4
var globalconfig float TextToSpeechVoiceVolume;
var float MaxResponseTime; // how long server will wait for client move update before setting position
var float WaitDelay; // Delay time until can restart
var pawn AcknowledgedPawn; // used in net games so client can acknowledge it possessed a pawn
var input float
aBaseX, aBaseY, aBaseZ, aMouseX, aMouseY,
aForward, aTurn, aStrafe, aUp, aLookUp;
// Vehicle Move Replication
var float aLastForward, aLastStrafe, aLastUp, NumServerDrives, NumSkips;
// if _RO_
var rotator WeaponBufferRotation;
// end _RO
// Vehicle Check Radius
var float VehicleCheckRadius; // Radius that is checked for nearby vehicles when pressing use
var bool bSuccessfulUse; // gives PC a hint that UsedBy was successful
// Camera info.
var int ShowFlags;
var int Misc1,Misc2;
var int RendMap;
var float OrthoZoom; // Orthogonal/map view zoom factor.
var const actor ViewTarget;
var const Controller RealViewTarget;
var PlayerController DemoViewer;
var float CameraDist; // multiplier for behindview camera dist
var range CameraDistRange;
var vector OldCameraLoc; // used in behindview calculations
var rotator OldCameraRot;
var transient array<CameraEffect> CameraEffects; // A stack of camera effects.
// We don't want these as configs. It makes it too easy to hack
// if _RO_
var float DesiredFOV;
var float DefaultFOV;
//else
//var globalconfig float DesiredFOV;
//var globalconfig float DefaultFOV;
// end _RO
var float ZoomLevel, DesiredZoomLevel;
// Audio.
var vector ListenerLocation;
var rotator ListenerRotation;
// Fixed visibility.
var vector FixedLocation;
var rotator FixedRotation;
var matrix RenderWorldToCamera;
// Screen flashes
var vector FlashScale, FlashFog;
var float ConstantGlowScale;
var vector ConstantGlowFog;
var globalconfig float ScreenFlashScaling;
// Distance fog fading.
var color LastDistanceFogColor;
var float LastDistanceFogStart;
var float LastDistanceFogEnd;
var float CurrentDistanceFogEnd;
var float TimeSinceLastFogChange;
var int LastZone;
// Remote Pawn ViewTargets
var rotator TargetViewRotation;
var rotator BlendedTargetViewRotation;
var float TargetEyeHeight;
var vector TargetWeaponViewOffset;
var HUD myHUD; // heads up display info
var float LastPlaySound;
var float LastPlaySpeech;
// Music info.
var string Song;
var EMusicTransition Transition;
// Move buffering for network games. Clients save their un-acknowledged moves in order to replay them
// when they get position updates from the server.
var SavedMove SavedMoves; // buffered moves pending position updates
var SavedMove FreeMoves; // freed moves, available for buffering
var SavedMove PendingMove;
var float CurrentTimeStamp,LastUpdateTime,ServerTimeStamp,TimeMargin, ClientUpdateTime;
var float MaxTimeMargin;
var globalconfig float TimeMarginSlack; // OBSOLETE
var Weapon OldClientWeapon;
var int WeaponUpdate;
// Progess Indicator - used by the engine to provide status messages (HUD is responsible for displaying these).
var string ProgressMessage[4];
var color ProgressColor[4];
var float ProgressTimeOut;
// Localized strings
var localized string QuickSaveString;
var localized string NoPauseMessage;
var localized string ViewingFrom;
var localized string OwnCamera;
// ReplicationInfo
var GameReplicationInfo GameReplicationInfo;
var VoiceChatReplicationInfo VoiceReplicationInfo;
var VotingReplicationInfoBase VoteReplicationInfo;
// Stats Logging
var globalconfig string StatsUsername;
var globalconfig string StatsPassword;
var class<LocalMessage> LocalMessageClass;
var(VoiceChat) class<ChatRoomMessage> ChatRoomMessageClass;
// view shaking (affects roll, and offsets camera position)
var vector ShakeOffsetRate;
var vector ShakeOffset; //current magnitude to offset camera from shake
var vector ShakeOffsetTime;
var vector ShakeOffsetMax;
var vector ShakeRotRate;
var vector ShakeRotMax;
var rotator ShakeRot;
var vector ShakeRotTime;
var float AmbientShakeFalloffStartTime;
var float AmbientShakeFalloffTime; // Time taken for shaking to stop after AmbientShakeFalloffStartTime has passed.
var vector AmbientShakeOffsetMag;
var float AmbientShakeOffsetFreq;
var rotator AmbientShakeRotMag;
var float AmbientShakeRotFreq;
var Pawn TurnTarget;
var config int EnemyTurnSpeed;
var int GroundPitch;
var rotator TurnRot180;
var vector OldFloor; // used by PlayerSpider mode - floor for which old rotation was based;
// Components ( inner classes )
var private transient CheatManager CheatManager; // Object within playercontroller that manages "cheat" commands
var class<CheatManager> CheatClass; // class of my CheatManager
var private transient PlayerInput PlayerInput; // Object within playercontroller that manages player input.
var config class<PlayerInput> InputClass; // class of my PlayerInput
var private transient AdminBase AdminManager;
var transient MaplistManagerBase MapHandler; // Used by AdminBase
var string PlayerChatType;
var PlayerChatManager ChatManager; // Manages all chat, speech, and voice messages sent to player
var const vector FailedPathStart;
// Camera control for debugging/tweaking
// BehindView Camera Adjustments
var rotator CameraDeltaRotation; // The rotator delta adjustment
var float CameraDeltaRad; // The zoom delta adjustment
var rotator CameraSwivel; // The swivel adjustment
// For drawing player names
struct PlayerNameInfo
{
var string mInfo;
var color mColor;
var float mXPos;
var float mYPos;
};
var(TeamBeacon) float TeamBeaconMaxDist;
var(TeamBeacon) float TeamBeaconPlayerInfoMaxDist;
var(TeamBeacon) Texture TeamBeaconTexture;
var(TeamBeacon) Texture LinkBeaconTexture;
var(TeamBeacon) Texture SpeakingBeaconTexture;
var(TeamBeacon) Color TeamBeaconTeamColors[2];
var(TeamBeacon) Color TeamBeaconCustomColor;
var private const array<PlayerNameInfo> PlayerNameArray;
// Demo recording view rotation
var int DemoViewPitch;
var int DemoViewYaw;
var Security PlayerSecurity; // Used for Cheat Protection
var float LoginDelay;
var float NextLoginTime;
var float ForcePrecacheTime;
var float LastPingUpdate;
var float ExactPing;
var float OldPing;
var float SpectateSpeed;
var globalconfig float DynamicPingThreshold;
var float NextSpeedChange;
var float VoiceChangeLimit;
var int ClientCap;
var(Menu) config string MidGameMenuClass; // Menu that is shown when Escape is pressed
var(Menu) config string DemoMenuClass; // Menu used for demos
var(Menu) config string AdminMenuClass; // Menu that is shown when adminmenu command is used
var(Menu) config string ChatPasswordMenuClass; // Menu that appears when attempting to join a chatroom that has a password
var(VoiceChat) globalconfig array<StoredChatPassword> StoredChatPasswords;
var VoiceChatRoom ActiveRoom; // The chatroom we're currently speaking to
var(VoiceChat) globalconfig string LastActiveChannel; // Stores the currently active channel when switching maps
var(VoiceChat) globalconfig string VoiceChatCodec; // Which voice chat codec to request in internet games (will only be used if it exists on server)
var(VoiceChat) globalconfig string VoiceChatLANCodec; // Which voice chat codec to request in LAN games
var(VoiceChat) globalconfig string ChatPassword; // Password for our personal chat room
var(VoiceChat) globalconfig string DefaultActiveChannel; // Channel we initially want to make active
// ClientAdjustPosition replication (event called at end of frame)
struct ClientAdjustment
{
var float TimeStamp;
var name newState;
var EPhysics newPhysics;
var vector NewLoc;
var vector NewVel;
var actor NewBase;
var vector NewFloor;
};
var ClientAdjustment PendingAdjustment;
var AnnouncerQueueManager AnnouncerQueueManager; // Handling Announcer Queueing
var AnnouncerVoice StatusAnnouncer;
var AnnouncerVoice RewardAnnouncer;
var float LastActiveTime; // used to kick idlers
var Actor CalcViewActor; // optimize PlayerCalcView
var vector CalcViewActorLocation;
var vector CalcViewLocation;
var rotator CalcViewRotation;
var float LastPlayerCalcView;
var float LastBroadcastTime;
var string LastBroadcastString[4];
var float LastSpeedHackLog;
var string PlayerOwnerName; // for savegames
// if _RO_
// Motion Blur vars
var float BlurTime; // How long blur effect should last
var float ColorFadeTime; // How long blur effect should last
// Spectating stuff
var bool bLockedBehindView; // Whether this player is in locked chase mode or not. Set by the game class
var bool bFirstPersonSpectateOnly; // Whether this player can spectate in third person. Set by the game class
var bool bAllowRoamWhileSpectating; // Whether this player can roam around while spectating. Set by the game class
var bool bViewBlackWhenDead; // Force a blacked out view when the player is dead spectating
var bool bViewBlackOnDeadNotViewingPlayers; // Force a blacked out view when the player is dead spectating and not viewing another player
var bool bAllowRoamWhileDeadSpectating; // Whether this player can roam around while spectating dead. Set by the game class
// Steam
var class<SteamStatsAndAchievementsBase> SteamStatsAndAchievementsClass; // Stats and Achievements class setting
var SteamStatsAndAchievementsBase SteamStatsAndAchievements; // Created on the Server and replicated to the Client to allow Steam Stats to be controlled by the Server but sent to Steam by the Client
// Steam Workshop
var int TotalSubscribedFiles;
var int NextSubscribedFileToFetch;
var int SubscribedFileDownloadIndex;
var string SubscribedFileDownloadTitle;
var float DownloadFileProgress;
// end _RO_
replication
{
// Things the server should send to the client.
reliable if( bNetDirty && bNetOwner && Role==ROLE_Authority )
GameReplicationInfo, VoiceReplicationInfo, ChatManager, LoginDelay;
unreliable if ( bNetOwner && Role==ROLE_Authority && (ViewTarget != Pawn) && (Pawn(ViewTarget) != None) )
TargetViewRotation, TargetEyeHeight;
reliable if( bDemoRecording && Role==ROLE_Authority )
DemoViewPitch, DemoViewYaw;
// Functions server can call.
reliable if( Role==ROLE_Authority )
ClientSetHUD,ClientReliablePlaySound, FOV, StartZoom,
ToggleZoom, StopZoom, EndZoom, ClientSetMusic, ClientRestart, ClientReset,
ClientAdjustGlow,
ClientSetBehindView, ClientSetFixedCamera, ClearProgressMessages,
ProgressCommand, SetProgressMessage, SetProgressTime,
GivePawn, ClientGotoState,
ClientSetActiveRoom, ChatRoomMessage,
ClientValidate, ClientSetWeaponViewShake,
ClientSetViewTarget, ClientCapBandwidth,
ClientOpenMenu, ClientCloseMenu, ClientReplaceMenu, ClientNetworkMessage,
AdminReply;
reliable if ( (Role == ROLE_Authority) )
ClientMessage, TeamMessage, ReceiveLocalizedMessage, QueueAnnouncement;
unreliable if( Role==ROLE_Authority && !bDemoRecording )
ClientPlaySound, PlayAnnouncement, PlayRewardAnnouncement, PlayStatusAnnouncement;
reliable if( Role==ROLE_Authority && !bDemoRecording )
ClientStopForceFeedback, ClientTravel, ClientSetClassicView;
unreliable if( Role==ROLE_Authority )
SetFOVAngle, ClientDamageShake, ClientFlash,ClientUpdateFlagHolder,
ClientAdjustPosition, ShortClientAdjustPosition, VeryShortClientAdjustPosition, LongClientAdjustPosition;
unreliable if( (!bDemoRecording || bClientDemoRecording && bClientDemoNetFunc) && Role==ROLE_Authority )
ClientHearSound;
reliable if( bClientDemoRecording && ROLE==ROLE_Authority )
DemoClientSetHUD;
// Functions client can call.
unreliable if( Role<ROLE_Authority )
ServerUpdatePing, ShortServerMove, ServerMove, RocketServerMove;
reliable if( Role<ROLE_Authority )
ServerShortTimeout;
unreliable if( Role<ROLE_Authority )
ServerVoiceCommand,
DualServerMove, DualRocketServerMove, TurretServerMove, DualTurretServerMove, DualSpaceFighterServerMove, SpaceFighterServerMove,
ServerSay, ServerTeamSay, ServerSetHandedness, ServerSetAutotaunt, ServerViewNextPlayer, ServerViewSelf,ServerUse, ServerDrive, ServerToggleBehindView;
reliable if( Role<ROLE_Authority )
ServerSpeech, ServerPause, SetPause, ServerMutate, ServerAcknowledgePossession,
PrevItem, ActivateItem, ServerReStartGame, AskForPawn,
ChangeName, ChangeVoiceType, ServerChangeTeam, Suicide,
ServerThrowWeapon, BehindView, Typing,
ServerValidationResponse, ServerVerifyViewTarget, ServerSpectateSpeed, ServerSetClientDemo,
ServerSpectate, BecomeSpectator, BecomeActivePlayer;
// Server Admin replicated functions
reliable if( Role<ROLE_Authority )
Admin, AdminCommand, ServerAdminLogin, ServerAdminLoginSilent, AdminLogout, AdminDebug;
// Voice-chat replicated function
reliable if (Role < ROLE_Authority)
ServerSetChatPassword, ServerJoinVoiceChannel, ServerLeaveVoiceChannel, ServerSpeak,
ServerChangeVoiceChatMode, ServerChatRestriction, ServerRequestBanInfo, ServerGetWeaponStats;
reliable if ( Role < ROLE_Authority )
ServerChatDebug;
reliable if (ROLE==ROLE_Authority)
ResetFOV, ClientBecameSpectator, ClientBecameActivePlayer;
// if _RO_
// Functions server can call.
reliable if( Role==ROLE_Authority )
ClientResetMovement;
// Spectating stuff, moved here to take advantage of native replication
reliable if (bNetDirty && bNetOwner && Role == ROLE_Authority)
bLockedBehindView, bFirstPersonSpectateOnly, bAllowRoamWhileSpectating,
bViewBlackWhenDead, bViewBlackOnDeadNotViewingPlayers, bAllowRoamWhileDeadSpectating,
SteamStatsAndAchievements;
reliable if ( Role < ROLE_Authority )
ServerInitializeSteamStatInt, ServerInitializeSteamStatFloat, ServerSteamStatsAndAchievementsInitialized;
// end RO
}
native final function SetNetSpeed(int NewSpeed);
native final function string GetPlayerIDHash();
native final function string GetPlayerNetworkAddress();
native final function string GetServerNetworkAddress();
native function string ConsoleCommand( string Command, optional bool bWriteToLog );
native final function LevelInfo GetEntryLevel();
native(544) final function ResetKeyboard();
native final private function ResetInput();
native final function SetViewTarget(Actor NewViewTarget);
native event ClientTravel( string URL, ETravelType TravelType, bool bItems );
native final function string GetURLProtocol();
native final function string GetDefaultURL(string Option);
// Execute a console command in the context of this player, then forward to Actor.ConsoleCommand.
native function CopyToClipboard( string Text );
native function string PasteFromClipboard();
// Validation.
private native event ClientValidate(string C);
private native event ServerValidationResponse(string R);
native final function bool CheckSpeedHack(float DeltaTime);
/* FindStairRotation()
returns an integer to use as a pitch to orient player view along current ground (flat, up, or down)
*/
native(524) final function int FindStairRotation(float DeltaTime);
native event ClientHearSound (
actor Actor,
int Id,
sound S,
vector SoundLocation,
vector Parameters,
bool Attenuate
);
//if _RO_
native final function bool PostFX_IsReady(); //Returns true if postfx system has been inited successfully and is ready to do blur or b&w postfx processing
native final function bool PostFX_IsBloomCapable(); //Returns true if postfx system has inited successfully and is bloom capable
native final function PostFX_SetActive(int Effect, bool Active); //Sets an effect active/inactive
native final function bool PostFX_IsActive(int Effect); //Returns true if an effect is active
native final function PostFX_SetParameter(int Effect, int Param, float Value); //Sets an effect parameter ...
simulated function NotifySpeakingInTeamChannel(); // Gets called by the hud when the player is speaking in the team channel. Put here to avoid casting
native final function string GetServerIP();
native final function bool CharacterAvailable(string CharName);
native final function bool PurchaseCharacter(string CharName); // If this is a purchasable Character, this opens the Steam Store Page for it and returns true(otherwise returns false)
native static final function Advertising_EnterZone(string ZoneName);
native static final function Advertising_ExitZone();
native final function OpenUPNPPorts();
// Steam Workshop
simulated native function EnumerateSubscribedSteamWorkshopFiles();
simulated native function GetSubscribedSteamWorkshopFileDetails(int Index);
simulated native function DownloadSubscribedSteamWorkshopFile(int Index);
//end _RO_
exec function GetWeaponStats()
{
}
function ServerGetWeaponStats(Weapon W)
{
if ( (Pawn == None) || (Pawn.Weapon == None) )
{
log("Weapon stats requested by "$PlayerReplicationInfo.PlayerName$" with pawn "$Pawn$" and no weapon");
return;
}
log("Weapon stats requested by "$PlayerReplicationInfo.PlayerName$" for "$Pawn.Weapon);
if ( W != None )
W.StartDebugging();
Pawn.Weapon.StartDebugging();
}
simulated event PostBeginPlay()
{
local class<PlayerChatManager> PlayerChatClass;
super.PostBeginPlay();
MaxTimeMargin = Level.MaxTimeMargin;
MaxResponseTime = Default.MaxResponseTime * Level.TimeDilation;
if ( Level.NetMode == NM_Client )
SpawnDefaultHUD();
if (Level.LevelEnterText != "" )
ClientMessage(Level.LevelEnterText);
FixFOV();
SetViewDistance();
SetViewTarget(self); // MUST have a view target!
LastActiveTime = Level.TimeSeconds;
if ( Level.NetMode == NM_Standalone )
AddCheats();
bForcePrecache = (Role < ROLE_Authority);
ForcePrecacheTime = Level.TimeSeconds + 1.2;
if ( Level.Game != None )
MapHandler = Level.Game.MaplistHandler;
if ( (PlayerChatType != "") && (Role == ROLE_Authority) )
{
PlayerChatClass = class<PlayerChatManager>(DynamicLoadObject(PlayerChatType, class'Class'));
if ( PlayerChatClass != None )
ChatManager = Spawn(PlayerChatClass, Self);
}
}
simulated function bool BeyondViewDistance(vector OtherLocation, float CullDistance)
{
local float Dist;
if ( ViewTarget == None )
return true;
Dist = VSize(OtherLocation - ViewTarget.Location);
if ( (CullDistance > 0) && (CullDistance < Dist * FOVBias) )
return true;
return ( Region.Zone.bDistanceFog && (Dist > Region.Zone.DistanceFogEnd) );
}
event KickWarning()
{
ReceiveLocalizedMessage( class'GameMessage', 15 );
}
function ResetTimeMargin()
{
TimeMargin = -0.1;
MaxTimeMargin = Level.MaxTimeMargin;
}
function ServerShortTimeout()
{
local Actor A;
bShortConnectTimeOut = true;
ResetTimeMargin();
// quick update of pickups and gameobjectives since this player is now relevant
if ( Level.Game.NumPlayers < 8 )
{
ForEach AllActors(class'Actor', A)
if ( (A.NetUpdateFrequency < 1) && !A.bOnlyRelevantToOwner )
A.NetUpdateTime = FMin(A.NetUpdateTime, Level.TimeSeconds + 0.2 * FRand());
}
else
{
ForEach AllActors(class'Actor', A)
if ( (A.NetUpdateFrequency < 1) && !A.bOnlyRelevantToOwner )
A.NetUpdateTime = FMin(A.NetUpdateTime, Level.TimeSeconds + 0.5 * FRand());
}
}
function Actor GetPathTo(Actor Dest)
{
local int i;
local Actor Best;
local vector Dir;
if ( Dest == None )
return Dest;
if ( (Pawn.Physics != PHYS_Falling) && ((RouteGoal != Dest) || (Level.TimeSeconds - LastRouteFind > 1+FRand())) )
{
MoveTarget = FindPathToward(Dest, false);
if ( MoveTarget == None )
return Dest;
}
if ( RouteCache[0] == None )
return Dest;
if ( RouteCache[1] == None )
return RouteCache[0];
Best = RouteCache[0];
Dir = Normal(RouteCache[1].Location - RouteCache[0].Location);
// return furthest visible path in a relatively straight line from first
for ( i=0; i<5; i++ )
{
if ( (RouteCache[i] == None) || (VSize(Pawn.Location - RouteCache[i].Location) > 2000) )
break;
if ( ((Normal(RouteCache[i].Location - RouteCache[0].Location) Dot Dir) > 0.7)
&& LineOfSightTo(RouteCache[i]) )
Best = RouteCache[i];
}
return Best;
}
// This is called by the low level audio code whenever a stream is finished
//!! Only for music started with PlayStream()
simulated event StreamFinished(int StreamHandle, Interactions.EStreamFinishReason Reason)
{
local int i;
if ( Player != None )
{
for ( i = 0; i < Player.LocalInteractions.Length; i++ )
if ( Player.LocalInteractions[i] != None )
Player.LocalInteractions[i].StreamFinished( StreamHandle, Reason );
}
}
exec function KillAll(class<actor> aClass)
{
local Actor A;
local Controller C;
if (Role != ROLE_Authority)
return;
//notification
if (CheatManager != None)
CheatManager.ReportCheat("KillAll");
for (C = Level.ControllerList; C != None; C = C.NextController)
if (PlayerController(C) != None)
PlayerController(C).ClientMessage("Killed all "$string(aClass));
if ( ClassIsChildOf(aClass, class'AIController') )
{
Level.Game.KillBots(Level.Game.NumBots);
return;
}
if ( ClassIsChildOf(aClass, class'Pawn') )
{
KillAllPawns(class<Pawn>(aClass));
return;
}
ForEach DynamicActors(class 'Actor', A)
if ( ClassIsChildOf(A.class, aClass) )
A.Destroy();
}
// Kill non-player pawns and their controllers
function KillAllPawns(class<Pawn> aClass)
{
local Pawn P;
Level.Game.KillBots(Level.Game.NumBots);
ForEach DynamicActors(class'Pawn', P)
if ( ClassIsChildOf(P.Class, aClass)
&& !P.IsPlayerPawn() )
{
if ( P.Controller != None )
P.Controller.Destroy();
P.Destroy();
}
}
exec function ToggleScreenShotMode()
{
if ( myHUD.bCrosshairShow )
{
myHUD.bCrosshairShow = false;
SetWeaponHand("Hidden");
myHUD.bHideHUD = true;
TeamBeaconMaxDist = 0;
bHideVehicleNoEntryIndicator = true;
}
else
{
// return to normal
myHUD.bCrosshairShow = true;
SetWeaponHand("Right");
myHUD.bHideHUD = false;
TeamBeaconMaxDist = default.TeamBeaconMaxDist;
bHideVehicleNoEntryIndicator = false;
}
}
exec function SetSpectateSpeed(Float F)
{
SpectateSpeed = F;
ServerSpectateSpeed(F);
}
function ClientSetWeaponViewShake(Bool B)
{
bWeaponViewShake = B;
}
function ClientSetClassicView()
{
Level.bClassicView = true;
}
function ServerSpectateSpeed(Float F)
{
SpectateSpeed = F;
}
function ServerGivePawn()
{
GivePawn(Pawn);
}
function ClientCapBandwidth(int Cap)
{
ClientCap = Cap;
if ( (Player != None) && (Player.CurrentNetSpeed > Cap) )
SetNetSpeed(Cap);
}
function PendingStasis()
{
bStasis = true;
Pawn = None;
GotoState('Scripting');
}
function AddCheats()
{
// if _RO_
// Overriden so we can do this during Dev. Maybe remove before shipping
// if ( CheatManager == None && (Level.NetMode == NM_Standalone ||
// Level.NetMode != NM_Client) )
// CheatManager = new(self) CheatClass;
// else
// Assuming that this never gets called for NM_Client
if ( CheatManager == None && (Level.NetMode == NM_Standalone) )
CheatManager = new(self) CheatClass;
// endif _RO_
}
function MakeAdmin()
{
if ( AdminManager == None && Level != None && Level.Game != None && Level.Game.AccessControl != None)
{
if (Level.Game.AccessControl.AdminClass == None)
Log("AdminClass is None");
else
AdminManager = new(self) Level.Game.AccessControl.AdminClass;
}
}
function HandlePickup(Pickup pick)
{
ReceiveLocalizedMessage(pick.MessageClass,,,,pick.class);
}
event ClientSetViewTarget( Actor a )
{
local bool bNewViewTarget;
if ( A == None )
{
if ( ViewTarget != self )
SetLocation(CalcViewLocation);
ServerVerifyViewTarget();
}
else
{
bNewViewTarget = (ViewTarget != a);
SetViewTarget( a );
if (bNewViewTarget)
a.POVChanged(self, false);
}
}
function ServerVerifyViewTarget()
{
if ( ViewTarget == self )
return;
if ( ViewTarget == None )
return;
ClientSetViewTarget(ViewTarget);
}
/* SpawnDefaultHUD()
Spawn a HUD (make sure that PlayerController always has valid HUD, even if \
ClientSetHUD() hasn't been called\
*/
function SpawnDefaultHUD()
{
myHUD = spawn(class'HUD',self);
}
/* Reset()
reset actor to initial state - used when restarting level without reloading.
*/
function Reset()
{
local vehicle DrivenVehicle;
DrivenVehicle = Vehicle(Pawn);
if( DrivenVehicle != None )
DrivenVehicle.KDriverLeave(true); // Force the driver out of the car
if ( Pawn != None )
PawnDied( Pawn );
super.Reset();
SetViewTarget( Self );
ClientSetViewTarget( self );
ClientSetFixedCamera( false );
bBehindView = false;
WaitDelay = Level.TimeSeconds + 2;
SetViewDistance();
FixFOV();
if ( PlayerReplicationInfo.bOnlySpectator )
GotoState('Spectating');
else
GotoState('PlayerWaiting');
}
event ClientReset()
{
bBehindView = false;
bFixedCamera = false;
SetViewTarget( self );
SetViewDistance();
if ( PlayerReplicationInfo.bOnlySpectator )
GotoState('Spectating');
else
GotoState('PlayerWaiting');
}
function CleanOutSavedMoves()
{
local SavedMove Next;
// clean out saved moves
while ( SavedMoves != None )
{
Next = SavedMoves.NextMove;
SavedMoves.Destroy();
SavedMoves = Next;
}
if ( PendingMove != None )
{
PendingMove.Destroy();
PendingMove = None;
}
}
/* InitInputSystem()
Spawn the appropriate class of PlayerInput
Only called for playercontrollers that belong to local players
*/
event InitInputSystem()
{
PlayerInput = new(self) InputClass;
}
/* ClientGotoState()
server uses this to force client into NewState
*/
function ClientGotoState(name NewState, name NewLabel)
{
GotoState(NewState,NewLabel);
}
function AskForPawn()
{
if ( IsInState('GameEnded') )
ClientGotoState('GameEnded', 'Begin');
else if ( IsInState('RoundEnded') )
ClientGotoState('RoundEnded', 'Begin');
else if ( Pawn != None )
GivePawn(Pawn);
else
{
bFrozen = false;
ServerRestartPlayer();
}
}
function GivePawn(Pawn NewPawn)
{
if ( NewPawn == None )
return;
Pawn = NewPawn;
NewPawn.Controller = self;
ClientRestart(Pawn);
}
/* GetFacingDirection()
returns direction faced relative to movement dir
0 = forward
16384 = right
32768 = back
49152 = left
*/
function int GetFacingDirection()
{
local vector X,Y,Z, Dir;
GetAxes(Pawn.Rotation, X,Y,Z);
Dir = Normal(Pawn.Acceleration);
if ( Y Dot Dir > 0 )
return ( 49152 + 16384 * (X Dot Dir) );
else
return ( 16384 - 16384 * (X Dot Dir) );
}
// Possess a pawn
function Possess(Pawn aPawn)
{
if ( PlayerReplicationInfo.bOnlySpectator )
return;
ResetFOV();
aPawn.PossessedBy(self);
Pawn = aPawn;
Pawn.bStasis = false;
ResetTimeMargin();
CleanOutSavedMoves(); // don't replay moves previous to possession
if ( Vehicle(Pawn) != None && Vehicle(Pawn).Driver != None )
PlayerReplicationInfo.bIsFemale = Vehicle(Pawn).Driver.bIsFemale;
else
PlayerReplicationInfo.bIsFemale = Pawn.bIsFemale;
ServerSetHandedness(Handedness);
ServerSetAutoTaunt(bAutoTaunt);
Restart();
}
function AcknowledgePossession(Pawn P)
{
if ( Viewport(Player) != None )
{
AcknowledgedPawn = P;
if ( P != None )
P.SetBaseEyeHeight();
ServerAcknowledgePossession(P, Handedness, bAutoTaunt);
}
}
function ServerAcknowledgePossession(Pawn P, float NewHand, bool bNewAutoTaunt)
{
ResetTimeMargin();
AcknowledgedPawn = P;
ServerSetHandedness(NewHand);
ServerSetAutoTaunt(bNewAutoTaunt);
}
// unpossessed a pawn (not because pawn was killed)
function UnPossess()
{
if ( Pawn != None )
{
SetLocation(Pawn.Location);
Pawn.RemoteRole = ROLE_SimulatedProxy;
Pawn.UnPossessed();
CleanOutSavedMoves(); // don't replay moves previous to unpossession
if ( Viewtarget == Pawn )
SetViewTarget(self);
}
Pawn = None;
GotoState('Spectating');
}
function ViewNextBot()
{
if ( CheatManager != None )
CheatManager.ViewBot();
}
// unpossessed a pawn (because pawn was killed)
function PawnDied(Pawn P)
{
if ( P != Pawn )
return;
EndZoom();
if ( Pawn != None )
Pawn.RemoteRole = ROLE_SimulatedProxy;
if ( ViewTarget == Pawn )
bBehindView = true;
Super.PawnDied(P);
}
simulated function ClientUpdateFlagHolder(PlayerReplicationInfo PRI, int i)
{
if ( (Role == ROLE_Authority) || (GameReplicationInfo == None) )
return;
GameReplicationInfo.FlagHolder[i] = PRI;
}
simulated function ClientSetHUD(class<HUD> newHUDClass, class<Scoreboard> newScoringClass )
{
if ( myHUD != None )
myHUD.Destroy();
if (newHUDClass == None)
myHUD = None;
else
{
myHUD = spawn (newHUDClass, self);
if (myHUD == None)
log ("PlayerController::ClientSetHUD(): Could not spawn a HUD of class "$newHUDClass, 'Error');
else
myHUD.SetScoreBoardClass( newScoringClass );
}
if( Level.Song != "" && Level.Song != "None" )
ClientSetInitialMusic( Level.Song, MTRAN_Fade );
}
// jdf ---
// Server ignores this call, client plays effect
simulated function ClientPlayForceFeedback( String EffectName )
{
if (bForceFeedbackSupported && Viewport(Player) != None)
PlayFeedbackEffect( EffectName );
}
simulated function StopForceFeedback( optional String EffectName )
{
if (bForceFeedbackSupported && Viewport(Player) != None)
StopFeedbackEffect( EffectName );
}
function ClientStopForceFeedback( optional String EffectName )
{
if (bForceFeedbackSupported && Viewport(Player) != None)
StopFeedbackEffect( EffectName );
}
// --- jdf
final function float UpdateFlashComponent(float current, float Step, float goal)
{
if ( goal > current )
return FMin(current + Step, goal);
else
return FMax(current - Step, goal);
}
function ViewFlash(float DeltaTime)
{
local vector goalFog;
local float goalscale, delta, Step;
local PhysicsVolume ViewVolume;
delta = FMin(0.1, DeltaTime);
goalScale = 1; // + ConstantGlowScale;
goalFog = vect(0,0,0); // ConstantGlowFog;
if ( Pawn != None )
{
if ( bBehindView )
ViewVolume = Level.GetPhysicsVolume(CalcViewLocation);
else
ViewVolume = Pawn.HeadVolume;
goalScale += ViewVolume.ViewFlash.X;
goalFog += ViewVolume.ViewFog;
}
Step = 0.6 * delta * ScreenFlashScaling;
FlashScale.X = UpdateFlashComponent(FlashScale.X,step,goalScale);
FlashScale = FlashScale.X * vect(1,1,1);
FlashFog.X = UpdateFlashComponent(FlashFog.X,step,goalFog.X);
FlashFog.Y = UpdateFlashComponent(FlashFog.Y,step,goalFog.Y);
FlashFog.Z = UpdateFlashComponent(FlashFog.Z,step,goalFog.Z);
}
simulated event ReceiveLocalizedMessage( class<LocalMessage> Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
// Wait for player to be up to date with replication when joining a server, before stacking up messages
if ( Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
Message.Static.ClientReceive( Self, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
if ( Message.static.IsConsoleMessage(Switch) && (Player != None) && (Player.Console != None) )
Player.Console.Message(Message.Static.GetString(Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject),0 );
}
simulated event ChatRoomMessage( byte Result, int ChannelIndex, optional PlayerReplicationInfo RelatedPRI )
{
local VoiceChatRoom VCR;
local string str;
if ( VoiceReplicationInfo != None && ChatRoomMessageClass != None )
{
VCR = VoiceReplicationInfo.GetChannelAt(ChannelIndex);
if ( VCR != None )
str = VCR.GetTitle();
if ( (str ~= "Team") || (str ~= "Public") || (str ~= "Local") )
return;
ClientMessage( ChatRoomMessageClass.static.AssembleMessage(Result, str, RelatedPRI) );
}
}
event ClientMessage( coerce string S, optional Name Type )
{
// Wait for player to be up to date with replication when joining a server, before stacking up messages
if ( Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
if (Type == '')
Type = 'Event';
TeamMessage(PlayerReplicationInfo, S, Type);
}
function bool AllowTextToSpeech(PlayerReplicationInfo PRI, name Type)
{
if ( bNoTextToSpeechVoiceMessages || (PRI == None) )
return false;
if ( Type == 'Say' )
{
//if _RO_
if ( PRI.bSilentAdmin )
return true;
//end _RO_
if ( PRI.bAdmin || ((GameReplicationInfo != None) && !GameReplicationInfo.bTeamGame) || (PRI == PlayerReplicationInfo) )
return true;
if ( IsInState('GameEnded') || IsInState('RoundEnded') )
return true;
return !bOnlySpeakTeamText;
}
else if ( Type == 'TeamSay' )
return true;
return false;
}
event TeamMessage( PlayerReplicationInfo PRI, coerce string S, name Type )
{
local string c;
// Wait for player to be up to date with replication when joining a server, before stacking up messages
if ( Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
if( AllowTextToSpeech(PRI, Type) )
TextToSpeech( S, TextToSpeechVoiceVolume );
if ( Type == 'TeamSayQuiet' )
Type = 'TeamSay';
if ( myHUD != None )
myHUD.Message( PRI, c$S, Type );
if ( (Player != None) && (Player.Console != None) )
{
if ( PRI!=None )
{
if ( PRI.Team!=None && GameReplicationInfo.bTeamGame)
{
if (PRI.Team.TeamIndex==0)
c = chr(27)$chr(200)$chr(1)$chr(1);
else if (PRI.Team.TeamIndex==1)
c = chr(27)$chr(125)$chr(200)$chr(253);
}
S = PRI.PlayerName$": "$S;
}
Player.Console.Chat( c$s, 6.0, PRI );
}
}
simulated function PlayBeepSound();
simulated function PrecacheAnnouncements()
{
if ( RewardAnnouncer != None )
RewardAnnouncer.PrecacheAnnouncements(true);
if ( StatusAnnouncer != None )
StatusAnnouncer.PrecacheAnnouncements(false);
}
simulated function PlayStatusAnnouncement(name AName, byte AnnouncementLevel, optional bool bForce)
{
local float Atten;
local sound ASound;
// Wait for player to be up to date with replication when joining a server, before stacking up messages
if ( Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
if ( (AnnouncementLevel > AnnouncerLevel) || (StatusAnnouncer == None) )
return;
if ( !bForce && (Level.TimeSeconds - LastPlaySound < 1) )
return;
LastPlaySound = Level.TimeSeconds; // so voice messages won't overlap
LastPlaySpeech = Level.TimeSeconds; // don't want chatter to overlap announcements
Atten = 2.0 * FClamp(0.1 + float(AnnouncerVolume)*0.225,0.2,1.0);
ASound = StatusAnnouncer.GetSound(AName);
if ( ASound != None )
ClientPlaySound(ASound,true,Atten,SLOT_Talk);
}
simulated function PlayRewardAnnouncement(name AName, byte AnnouncementLevel, optional bool bForce)
{
local float Atten;
local sound ASound;
// Wait for player to be up to date with replication when joining a server, before stacking up messages
if ( Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
if ( (AnnouncementLevel > AnnouncerLevel) || (RewardAnnouncer == None) )
return;
if ( !bForce && (Level.TimeSeconds - LastPlaySound < 1) )
return;
LastPlaySound = Level.TimeSeconds; // so voice messages won't overlap
LastPlaySpeech = Level.TimeSeconds; // don't want chatter to overlap announcements
Atten = 2.0 * FClamp(0.1 + float(AnnouncerVolume)*0.225,0.2,1.0);
ASound = RewardAnnouncer.GetSound(AName);
if ( ASound != None )
ClientPlaySound(ASound,true,Atten,SLOT_Talk);
}
// PlayAnnouncement is OBSOLETE
simulated function PlayAnnouncement(sound ASound, byte AnnouncementLevel, optional bool bForce)
{
local float Atten;
if ( AnnouncementLevel > AnnouncerLevel )
return;
if ( !bForce && (Level.TimeSeconds - LastPlaySound < 1) )
return;
LastPlaySound = Level.TimeSeconds; // so voice messages won't overlap
LastPlaySpeech = Level.TimeSeconds; // don't want chatter to overlap announcements
Atten = 2.0 * FClamp(0.1 + float(AnnouncerVolume)*0.225,0.2,1.0);
ClientPlaySound(ASound,true,Atten,SLOT_Talk);
}
// CustomizeAnnouncer is obsolete
function Sound CustomizeAnnouncer(Sound AnnouncementSound)
{
return AnnouncementSound;
}
simulated function QueueAnnouncement( name ASoundName, byte AnnouncementLevel,
optional AnnouncerQueueManager.EAPriority Priority, optional byte Switch )
{
if ( AnnouncementLevel > AnnouncerLevel || Level.NetMode == NM_DedicatedServer || GameReplicationInfo == None )
return;
if ( AnnouncerQueueManager == None )
{
AnnouncerQueueManager = Spawn(class'AnnouncerQueueManager');
AnnouncerQueueManager.InitFor( Self );
}
if ( AnnouncerQueueManager != None )
AnnouncerQueueManager.AddItemToQueue( ASoundName, Priority, Switch );
}
function bool AllowVoiceMessage(name MessageType)
{
if ( Level.NetMode == NM_Standalone )
return true;
if ( Level.TimeSeconds - OldMessageTime < 3 )
{
if ( (MessageType == 'TAUNT') || (MessageType == 'AUTOTAUNT') )
return false;
if ( Level.TimeSeconds - OldMessageTime < 1 )
return false;
}
if ( Level.TimeSeconds - OldMessageTime < 6 )
OldMessageTime = Level.TimeSeconds + 3;
else
OldMessageTime = Level.TimeSeconds;
return true;
}
//Play a sound client side (so only client will hear it
simulated function ClientPlaySound(sound ASound, optional bool bVolumeControl, optional float inAtten, optional ESoundSlot slot )
{
local float atten;
atten = 1.0;
if( bVolumeControl )
atten = FClamp(inAtten,0,2);
if ( ViewTarget != None )
ViewTarget.PlaySound(ASound, slot, atten,,,,false);
}
simulated function ClientReliablePlaySound(sound ASound, optional bool bVolumeControl )
{
ClientPlaySound(ASound, bVolumeControl);
}
simulated event Destroyed()
{
local SavedMove Next;
local Vehicle DrivenVehicle;
local Pawn Driver;
// cheatmanager, adminmanager, and playerinput cleaned up in C++ PostScriptDestroyed()
if ( AdminManager != None )
AdminManager.DoLogout();
StopFeedbackEffect();
if ( Pawn != None )
{
// If its a vehicle, just destroy the driver, otherwise do the normal.
DrivenVehicle = Vehicle(Pawn);
if( DrivenVehicle != None )
{
Driver = DrivenVehicle.Driver;
DrivenVehicle.KDriverLeave(true); // Force the driver out of the car
if ( Driver != None )
{
Driver.Health = 0;
Driver.Died( self, class'Suicided', Driver.Location );
}
}
else
{
Pawn.Health = 0;
Pawn.Died( self, class'Suicided', Pawn.Location );
}
}
if ( myHUD != None )
myHud.Destroy();
if ( AnnouncerQueueManager != None )
AnnouncerQueueManager.Destroy();
while ( FreeMoves != None )
{
Next = FreeMoves.NextMove;
FreeMoves.Destroy();
FreeMoves = Next;
}
while ( SavedMoves != None )
{
Next = SavedMoves.NextMove;
SavedMoves.Destroy();
SavedMoves = Next;
}
if( PlayerSecurity != None )
{
PlayerSecurity.Destroy();
PlayerSecurity = None;
}
if ( ChatManager != None )
ChatManager.Destroy();
super.Destroyed();
}
function ClientSetMusic( string NewSong, EMusicTransition NewTransition )
{
local float FadeIn, FadeOut;
switch (NewTransition)
{
case MTRAN_Segue:
FadeIn = 7.0;
FadeOut = 3.0;
break;
case MTRAN_Fade:
FadeIn = 3.0;
FadeOut = 3.0;
break;
case MTRAN_FastFade:
FadeIn = 1.0;
FadeOut = 1.0;
break;
case MTRAN_SlowFade:
FadeIn = 5.0;
FadeOut = 5.0;
break;
}
StopAllMusic( FadeOut );
if ( NewSong != "" )
PlayMusic( NewSong, FadeIn );
Song = NewSong;
Transition = NewTransition;
if (Player!=None && Player.Console!=None)
Player.Console.SetMusic(NewSong);
}
function ClientSetInitialMusic( string NewSong, EMusicTransition NewTransition )
{
local string SongName;
if ( Song != "" )
return;
SongName = NewSong;
if (Player!=None && Player.Console!=None)
SongName = Player.Console.SetInitialMusic(NewSong);
ClientSetMusic(SongName,NewTransition);
}
// ------------------------------------------------------------------------
// Zooming/FOV change functions
function ToggleZoomWithMax(float MaxZoomLevel)
{
if ( DefaultFOV != DesiredFOV )
EndZoom();
else
StartZoomWithMax(MaxZoomLevel);
}
function StartZoomWithMax(float MaxZoomLevel)
{
DesiredZoomLevel = MaxZoomLevel;
myHUD.FadeZoom();
ZoomLevel = 0.0;
bZooming = true;
}
function ToggleZoom()
{
ToggleZoomWithMax(0.9);
}
function StartZoom()
{
StartZoomWithMax(0.9);
}
function StopZoom()
{
bZooming = false;
}
function EndZoom()
{
if ( DesiredFOV != DefaultFOV )
myHUD.FadeZoom();
bZooming = false;
DesiredFOV = DefaultFOV;
}
simulated function FixFOV()
{
FOVAngle = Default.DefaultFOV;
DesiredFOV = Default.DefaultFOV;
DefaultFOV = Default.DefaultFOV;
}
// if _RO_
// Sets the far clipping view distance based on the level settings
simulated function SetViewDistance()
{
switch (Level.ViewDistanceLevel)
{
case VDL_Default_1000m:
ConsoleCommand("FARCLIP 65536");
break;
case VDL_Medium_2000m:
ConsoleCommand("FARCLIP 131072");
break;
case VDL_High_3000m:
ConsoleCommand("FARCLIP 196608");
break;
case VDL_Extreme_4000m:
ConsoleCommand("FARCLIP 262144");
break;
default:
ConsoleCommand("FARCLIP 65536");
}
}
// end _RO_
function SetFOV(float NewFOV)
{
DesiredFOV = NewFOV;
FOVAngle = NewFOV;
}
function ResetFOV()
{
DesiredFOV = DefaultFOV;
FOVAngle = DefaultFOV;
}
exec function FOV(float F)
{
if( (F >= 80.0) || (Level.Netmode==NM_Standalone) || PlayerReplicationInfo.bOnlySpectator )
{
DefaultFOV = FClamp(F, 1, 170);
DesiredFOV = DefaultFOV;
SaveConfig();
}
}
exec function Mutate(string MutateString)
{
ServerMutate(MutateString);
}
function ServerMutate(string MutateString)
{
if( Level.NetMode == NM_Client )
return;
Level.Game.BaseMutator.Mutate(MutateString, Self);
}
exec function SetSensitivity(float F)
{
PlayerInput.UpdateSensitivity(F);
}
exec function SetMouseSmoothing( int Mode )
{
PlayerInput.UpdateSmoothing( Mode );
}
exec function SetMouseAccel(float F)
{
PlayerInput.UpdateAccel(F);
}
exec function ForceReload()
{
if ( (Pawn != None) && (Pawn.Weapon != None) )
{
//Pawn.Weapon.ForceReload(); //merge_hack
}
}
// ------------------------------------------------------------------------
// Messaging functions
function bool AllowTextMessage(string Msg)
{
local int i;
//if _RO_
if ( PlayerReplicationInfo.bSilentAdmin )
return true;
//end _RO_
if ( (Level.NetMode == NM_Standalone) || PlayerReplicationInfo.bAdmin )
return true;
if ( ( Level.Pauser == none) && (Level.TimeSeconds - LastBroadcastTime < 2 ) )
return false;
// lower frequency if same text
if ( Level.TimeSeconds - LastBroadcastTime < 5 )
{
Msg = Left(Msg,Clamp(len(Msg) - 4, 8, 64));
for ( i=0; i<4; i++ )
if ( LastBroadcastString[i] ~= Msg )
return false;
}
for ( i=3; i>0; i-- )
LastBroadcastString[i] = LastBroadcastString[i-1];
LastBroadcastTime = Level.TimeSeconds;
return true;
}
// Send a message to all players.
exec function Say( string Msg )
{
Msg = Left(Msg,128);
if ( AllowTextMessage(Msg) )
ServerSay(Msg);
}
function ServerSay( string Msg )
{
local controller C;
Msg = Level.Game.StripColor(Msg);
// center print admin messages which start with #
//if _RO_
if ( (PlayerReplicationInfo.bAdmin || PlayerReplicationInfo.bSilentAdmin) && left(Msg,1) == "#" )
//else
//if (PlayerReplicationInfo.bAdmin && left(Msg,1) == "#" )
//end _RO_
{
Msg = right(Msg,len(Msg)-1);
for( C=Level.ControllerList; C!=None; C=C.nextController )
if( C.IsA('PlayerController') )
{
PlayerController(C).ClearProgressMessages();
PlayerController(C).SetProgressTime(6);
PlayerController(C).SetProgressMessage(0, Msg, class'Canvas'.Static.MakeColor(255,255,255));
}
return;
}
Level.Game.Broadcast(self, Msg, 'Say');
}
exec function TeamSay( string Msg )
{
Msg = Left(Msg,128);
if ( AllowTextMessage(Msg) )
ServerTeamSay(Msg);
}
function ServerTeamSay( string Msg )
{
LastActiveTime = Level.TimeSeconds;
Msg = Level.Game.StripColor(Msg);
if( !GameReplicationInfo.bTeamGame )
{
Say( Msg );
return;
}
Level.Game.BroadcastTeam( self, Level.Game.ParseMessageString( Level.Game.BaseMutator , self, Msg ) , 'TeamSay');
}
// ------------------------------------------------------------------------
function ServerSetAutoTaunt(bool Value)
{
bAutoTaunt = Value;
}
exec function SetAutoTaunt(bool Value)
{
class'PlayerController'.default.bAutoTaunt = Value;
class'PlayerController'.static.StaticSaveConfig();
bAutoTaunt = Value;
ServerSetAutoTaunt(Value);
}
// ------------------------------------------------------------------------
function ServerSetHandedness( float hand)
{
Handedness = hand;
if ( (Pawn != None) && (Pawn.Weapon != None) )
Pawn.Weapon.SetHand(Handedness);
}
function SetHand(int IntValue)
{
Handedness = IntValue;
SaveConfig();
if( (Pawn != None) && (Pawn.Weapon != None) )
Pawn.Weapon.SetHand(Handedness);
ServerSetHandedness(Handedness);
}
exec function SetWeaponHand ( string S )
{
if ( S ~= "Left" )
Handedness = -1;
else if ( S~= "Right" )
Handedness = 1;
else if ( S ~= "Center" )
Handedness = 0;
else if ( S ~= "Hidden" )
Handedness = 2;
SetHand(Handedness);
}
function bool IsDead()
{
return false;
}
exec function ShowGun ()
{
if( Handedness == 2 )
Handedness = 1;
else
Handedness = 2;
SetHand(Handedness);
}
event PreClientTravel()
{
log("PreClientTravel");
ClientStopForceFeedback(); // jdf
}
function ClientSetFixedCamera(bool B)
{
bFixedCamera = B;
}
function ClientSetBehindView(bool B)
{
local bool bWasBehindView;
bWasBehindView = bBehindView;
bBehindView = B;
CameraDist = Default.CameraDist;
if (bBehindView != bWasBehindView)
ViewTarget.POVChanged(self, true);
if (Vehicle(Pawn) != None)
{
Vehicle(Pawn).bDesiredBehindView = B;
Pawn.SaveConfig();
}
}
// if _RO_
function ClientVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID, optional Pawn soundSender, optional vector senderLocation)
// else
// function ClientVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID)
// end if _RO_
{
local VoicePack V;
if ( (Sender == None) || (Sender.voicetype == None) || (Player.Console == None) )
return;
V = Spawn(Sender.voicetype, self);
if ( V != None )
V.ClientInitialize(Sender, Recipient, messagetype, messageID);
}
/* ForceDeathUpdate()
Make sure ClientAdjustPosition immediately informs client of pawn's death
*/
function ForceDeathUpdate()
{
LastUpdateTime = Level.TimeSeconds - 10;
}
/* RocketServerMove()
compressed version of server move for PlayerRocketing state
*/
// Modified to handle Red Orchestra movements
function RocketServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View
)
{
local byte NewActions;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View);
}
/* DualRocketServerMove()
compressed version of server move for PlayerRocketing state
*/
function DualRocketServerMove
(
float TimeStamp0,
vector InAccel0,
bool NewbDuck0,
byte ClientRoll0,
int View0,
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View
)
{
local byte NewActions, NewActions0;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
if (NewbDuck0)
NewActions0 += 2;
ServerMove(TimeStamp0,InAccel0,vect(0,0,0),NewActions0, DCLICK_NONE,ClientRoll0,View0);
ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View);
}
function SpaceFighterServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
int ViewPitch,
int ViewYaw,
int ViewRoll
)
{
local Rotator BackupView;
local byte NewActions;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
BackupView.Pitch = ViewPitch;
BackupView.Yaw = ViewYaw;
BackupView.Roll = ViewRoll;
SetRotation( BackupView );
if ( Pawn != None )
Pawn.SetRotation( BackupView );
Global.ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,0,0);
}
function DualSpaceFighterServerMove
(
float TimeStamp0,
vector InAccel0,
bool NewbDuck0,
int ViewPitch0,
int ViewYaw0,
int ViewRoll0,
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
int ViewPitch,
int ViewYaw,
int ViewRoll
)
{
local Rotator BackupView;
local byte NewActions, NewActions0;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
if (NewbDuck0)
NewActions0 += 2;
BackupView.Pitch = ViewPitch0;
BackupView.Yaw = ViewYaw0;
BackupView.Roll = ViewRoll0;
SetRotation( BackupView );
if ( Pawn != None )
Pawn.SetRotation( BackupView );
Global.ServerMove(TimeStamp0,InAccel0,vect(0,0,0),NewActions0, DCLICK_NONE,0,0);
BackupView.Pitch = ViewPitch;
BackupView.Yaw = ViewYaw;
BackupView.Roll = ViewRoll;
SetRotation( BackupView );
if ( Pawn != None )
Pawn.SetRotation( BackupView );
Global.ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,0,0);
}
/* TurretServerMove()
compressed version of server move for PlayerTurreting state
*/
function TurretServerMove
(
float TimeStamp,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View,
optional int FreeAimRot
)
{
local byte NewActions;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
ServerMove(TimeStamp,Vect(0,0,0),ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View,FreeAimRot);
}
/* DualTurretServerMove()
compressed version of server move for PlayerTurreting state
*/
function DualTurretServerMove
(
float TimeStamp0,
bool NewbDuck0,
byte ClientRoll0,
int View0,
float TimeStamp,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View,
optional int FreeAimRot
)
{
local byte NewActions, NewActions0;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
if (NewbDuck0)
NewActions0 += 2;
ServerMove(TimeStamp0,Vect(0,0,0),vect(0,0,0),NewActions0, DCLICK_NONE,ClientRoll0,View0,FreeAimRot);
ServerMove(TimeStamp,Vect(0,0,0),ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View,FreeAimRot);
}
/* ShortServerMove()
compressed version of server move for bandwidth saving
*/
// Converted to handle Red Orchestra movement
function ShortServerMove
(
float TimeStamp,
vector ClientLoc,
byte NewActions,
byte ClientRoll,
int View,
optional int FreeAimRot
)
{
ServerMove(TimeStamp,vect(0,0,0),ClientLoc,NewActions,DCLICK_None,ClientRoll,View,FreeAimRot);
}
/* DualServerMove()
- replicated function sent by client to server - contains client movement and firing info for two moves
*/
// Modified to handle Red Orchestra movement
function DualServerMove
(
float TimeStamp0,
vector InAccel0,
byte NewActions0,
eDoubleClickDir DoubleClickMove0,
int View0,
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
ServerMove(TimeStamp0,InAccel0,vect(0,0,0),NewActions0,DoubleClickMove0,
ClientRoll,View0,FreeAimRot);
if ( ClientLoc == vect(0,0,0) )
ClientLoc = vect(0.1,0,0);
ServerMove(TimeStamp,InAccel,ClientLoc,NewActions,DoubleClickMove,ClientRoll,View,FreeAimRot,OldTimeDelta,OldAccel);
}
/* ServerMove()
- replicated function sent by client to server - contains client movement and firing info.
*/
// Modified to support Red Orchestra's movement needs
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
local float DeltaTime, clientErr, OldTimeStamp;
local rotator DeltaRot, Rot, ViewRot;
local vector Accel, LocDiff;
local int maxPitch, ViewPitch, ViewYaw;
local bool NewbPressedJump, OldbRun, OldbSprint;
local eDoubleClickDir OldDoubleClickMove;
local bool NewbRun, NewbDuck, NewbJumpStatus, NewbSprint, NewbCrawl;
local int FreeAimPitch, FreeAimYaw;
local rotator NewFreeAimRot;
// If this move is outdated, discard it.
if ( CurrentTimeStamp >= TimeStamp )
return;
if ( AcknowledgedPawn != Pawn )
{
OldTimeDelta = 0;
InAccel = vect(0,0,0);
GivePawn(Pawn);
}
// Decode bit mask
NewbRun = (NewActions & 1) != 0;
NewbDuck = (NewActions & 2) != 0;
NewbJumpStatus = (NewActions & 4) != 0;
NewbSprint = (NewActions & 8) != 0;
NewbCrawl = (NewActions & 16) != 0;
// if OldTimeDelta corresponds to a lost packet, process it first
if ( OldTimeDelta != 0 )
{
OldTimeStamp = TimeStamp - float(OldTimeDelta)/500 - 0.001;
if ( CurrentTimeStamp < OldTimeStamp - 0.001 )
{
// split out components of lost move (approx)
// Accel is encoded using 8 bits per component (Last 24 out of 32 go into this)
Accel.X = OldAccel >>> 23;
if ( Accel.X > 127 )
Accel.X = -1 * (Accel.X - 128);
Accel.Y = (OldAccel >>> 15) & 255;
if ( Accel.Y > 127 )
Accel.Y = -1 * (Accel.Y - 128);
Accel.Z = (OldAccel >>> 7) & 255;
if ( Accel.Z > 127 )
Accel.Z = -1 * (Accel.Z - 128);
Accel *= 20;
OldbRun = ( (OldAccel & 64) != 0 );
OldbSprint = ( (OldAccel & 32) != 0 );
NewbPressedJump = ( (OldAccel & 16) != 0 );
if ( NewbPressedJump )
bJumpStatus = NewbJumpStatus;
switch (OldAccel & 7) // First 3 bits define double click move
{
case 0:
OldDoubleClickMove = DCLICK_None;
break;
case 1:
OldDoubleClickMove = DCLICK_Left;
break;
case 2:
OldDoubleClickMove = DCLICK_Right;
break;
case 3:
OldDoubleClickMove = DCLICK_Forward;
break;
case 4:
OldDoubleClickMove = DCLICK_Back;
break;
}
//log("Recovered move from "$OldTimeStamp$" acceleration "$Accel$" from "$OldAccel);
OldTimeStamp = FMin(OldTimeStamp, CurrentTimeStamp + MaxResponseTime);
MoveAutonomous(OldTimeStamp - CurrentTimeStamp, OldbRun, (bDuck == 1), NewbPressedJump, OldbSprint, (bCrawl == 1), OldDoubleClickMove, Accel, rot(0,0,0));
CurrentTimeStamp = OldTimeStamp;
}
}
// View components
ViewPitch = View/32768;
ViewYaw = 2 * (View - 32768 * ViewPitch);
ViewPitch *= 2;
// If _RO_
if( Pawn != none && Pawn.Weapon != none )
{
// Free-aim vars
FreeAimPitch = FreeAimRot/32768;
FreeAimYaw = 2 * (FreeAimRot - 32768 * FreeAimPitch);
FreeAimPitch *= 2;
NewFreeAimRot.Pitch = FreeAimPitch;
NewFreeAimRot.Yaw = FreeAimYaw;
Pawn.Weapon.SetServerOrientation(NewFreeAimRot);
}
// end _RO_
// Make acceleration.
Accel = InAccel * 0.1;
NewbPressedJump = (bJumpStatus != NewbJumpStatus);
bJumpStatus = NewbJumpStatus;
// Save move parameters.
DeltaTime = FMin(MaxResponseTime,TimeStamp - CurrentTimeStamp);
if ( Pawn == None )
{
ResetTimeMargin();
}
else if ( !CheckSpeedHack(DeltaTime) )
{
bWasSpeedHack = true;
DeltaTime = 0;
Pawn.Velocity = vect(0,0,0);
}
else if ( bWasSpeedHack )
{
// if have had a speedhack detection, then modify deltatime if getting too far ahead again
if ( (TimeMargin > 0.5 * Level.MaxTimeMargin) && (Level.MaxTimeMargin > 0) )
DeltaTime *= 0.8;
}
CurrentTimeStamp = TimeStamp;
ServerTimeStamp = Level.TimeSeconds;
ViewRot.Pitch = ViewPitch;
ViewRot.Yaw = ViewYaw;
ViewRot.Roll = 0;
if ( NewbPressedJump || (InAccel != vect(0,0,0)) )
LastActiveTime = Level.TimeSeconds;
if ( Pawn == None || Pawn.bServerMoveSetPawnRot )
SetRotation(ViewRot);
if ( AcknowledgedPawn != Pawn )
return;
if ( (Pawn != None) && Pawn.bServerMoveSetPawnRot )
{
Rot.Roll = 256 * ClientRoll;
Rot.Yaw = ViewYaw;
if ( (Pawn.Physics == PHYS_Swimming) || (Pawn.Physics == PHYS_Flying) )
maxPitch = 2;
else
maxPitch = 0;
if ( (ViewPitch > maxPitch * RotationRate.Pitch) && (ViewPitch < 65536 - maxPitch * RotationRate.Pitch) )
{
If (ViewPitch < 32768)
Rot.Pitch = maxPitch * RotationRate.Pitch;
else
Rot.Pitch = 65536 - maxPitch * RotationRate.Pitch;
}
else
Rot.Pitch = ViewPitch;
DeltaRot = (Rotation - Rot);
Pawn.SetRotation(Rot);
}
// Perform actual movement
if ( (Level.Pauser == None) && (DeltaTime > 0) )
MoveAutonomous(DeltaTime, NewbRun, NewbDuck, NewbPressedJump, NewbSprint, NewbCrawl, DoubleClickMove, Accel, DeltaRot);
// Accumulate movement error.
if ( ClientLoc == vect(0,0,0) )
return; // first part of double servermove
else if ( Level.TimeSeconds - LastUpdateTime > 0.3 )
ClientErr = 10000;
else if ( Level.TimeSeconds - LastUpdateTime > 180.0/Player.CurrentNetSpeed )
{
if ( Pawn == None )
LocDiff = Location - ClientLoc;
else
LocDiff = Pawn.Location - ClientLoc;
ClientErr = LocDiff Dot LocDiff;
}
// If client has accumulated a noticeable positional error, correct him.
if ( ClientErr > 3 )
{
if ( Pawn == None )
{
PendingAdjustment.newPhysics = Physics;
PendingAdjustment.NewLoc = Location;
PendingAdjustment.NewVel = Velocity;
}
else
{
PendingAdjustment.newPhysics = Pawn.Physics;
PendingAdjustment.NewVel = Pawn.Velocity;
PendingAdjustment.NewBase = Pawn.Base;
if ( (Mover(Pawn.Base) != None) || (Vehicle(Pawn.Base) != None) )
PendingAdjustment.NewLoc = Pawn.Location - Pawn.Base.Location;
else
PendingAdjustment.NewLoc = Pawn.Location;
PendingAdjustment.NewFloor = Pawn.Floor;
}
//if ( (ClientErr != 10000) && (Pawn != None) )
// log(" Client Error at "$TimeStamp$" is "$ClientErr$" with acceleration "$Accel$" LocDiff "$LocDiff$" Physics "$Pawn.Physics);
LastUpdateTime = Level.TimeSeconds;
PendingAdjustment.TimeStamp = TimeStamp;
PendingAdjustment.newState = GetStateName();
}
//log("Server moved stamp "$TimeStamp$" location "$Pawn.Location$" Acceleration "$Pawn.Acceleration$" Velocity "$Pawn.Velocity);
}
/* Called on server at end of tick when PendingAdjustment has been set.
Done this way to avoid ever sending more than one ClientAdjustment per server tick.
*/
event SendClientAdjustment()
{
if ( AcknowledgedPawn != Pawn )
{
PendingAdjustment.TimeStamp = 0;
return;
}
if ( (Pawn == None) || (Pawn.Physics != PHYS_Spider) )
{
if ( PendingAdjustment.NewVel == vect(0,0,0) )
{
ShortClientAdjustPosition
(
PendingAdjustment.TimeStamp,
PendingAdjustment.newState,
PendingAdjustment.newPhysics,
PendingAdjustment.NewLoc.X,
PendingAdjustment.NewLoc.Y,
PendingAdjustment.NewLoc.Z,
PendingAdjustment.NewBase
);
}
else
ClientAdjustPosition
(
PendingAdjustment.TimeStamp,
PendingAdjustment.newState,
PendingAdjustment.newPhysics,
PendingAdjustment.NewLoc.X,
PendingAdjustment.NewLoc.Y,
PendingAdjustment.NewLoc.Z,
PendingAdjustment.NewVel.X,
PendingAdjustment.NewVel.Y,
PendingAdjustment.NewVel.Z,
PendingAdjustment.NewBase
);
}
else
LongClientAdjustPosition
(
PendingAdjustment.TimeStamp,
PendingAdjustment.newState,
PendingAdjustment.newPhysics,
PendingAdjustment.NewLoc.X,
PendingAdjustment.NewLoc.Y,
PendingAdjustment.NewLoc.Z,
PendingAdjustment.NewVel.X,
PendingAdjustment.NewVel.Y,
PendingAdjustment.NewVel.Z,
PendingAdjustment.NewBase,
PendingAdjustment.NewFloor.X,
PendingAdjustment.NewFloor.Y,
PendingAdjustment.NewFloor.Z
);
PendingAdjustment.TimeStamp = 0;
}
// Only executed on server
function ServerDrive(float InForward, float InStrafe, float aUp, bool InJump, int View)
{
local rotator ViewRotation;
// Added to handle setting of the correct ViewRotation on the server in network games --Dave@Psyonix
ViewRotation.Pitch = View/32768;
ViewRotation.Yaw = 2 * (View - 32768 * ViewRotation.Pitch);
ViewRotation.Pitch *= 2;
ViewRotation.Roll = 0;
SetRotation(ViewRotation);
ProcessDrive(InForward, InStrafe, aUp, InJump);
}
function ProcessDrive(float InForward, float InStrafe, float InUp, bool InJump)
{
ClientGotoState(GetStateName(), 'Begin');
}
function ProcessMove ( float DeltaTime, vector newAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if ( (Pawn != None) && (Pawn.Acceleration != newAccel) )
Pawn.Acceleration = newAccel;
}
// Modifed to support Red Orchestra movement
final function MoveAutonomous
(
float DeltaTime,
bool NewbRun,
bool NewbDuck,
bool NewbPressedJump,
bool NewbSprint,
bool NewbCrawl,
eDoubleClickDir DoubleClickMove,
vector newAccel,
rotator DeltaRot
)
{
if ( (Pawn != None) && Pawn.bHardAttach )
return;
if ( NewbRun )
bRun = 1;
else
bRun = 0;
if ( NewbDuck )
bDuck = 1;
else
bDuck = 0;
bPressedJump = NewbPressedJump;
if (NewbSprint)
bSprint = 1;
else
bSprint = 0;
if (NewbCrawl)
bCrawl = 1;
else
bCrawl = 0;
HandleWalking();
ProcessMove(DeltaTime, newAccel, DoubleClickMove, DeltaRot);
if ( Pawn != None )
Pawn.AutonomousPhysics(DeltaTime);
else
AutonomousPhysics(DeltaTime);
//log("Role "$Role$" moveauto time "$100 * DeltaTime$" ("$Level.TimeDilation$")");
}
/* VeryShortClientAdjustPosition
bandwidth saving version, when velocity is zeroed, and pawn is walking
*/
function VeryShortClientAdjustPosition
(
float TimeStamp,
float NewLocX,
float NewLocY,
float NewLocZ,
Actor NewBase
)
{
local vector Floor;
if ( Pawn != None )
Floor = Pawn.Floor;
LongClientAdjustPosition(TimeStamp,'PlayerWalking',PHYS_Walking,NewLocX,NewLocY,NewLocZ,0,0,0,NewBase,Floor.X,Floor.Y,Floor.Z);
}
/* ShortClientAdjustPosition
bandwidth saving version, when velocity is zeroed
*/
function ShortClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
Actor NewBase
)
{
local vector Floor;
if ( Pawn != None )
Floor = Pawn.Floor;
LongClientAdjustPosition(TimeStamp,newState,newPhysics,NewLocX,NewLocY,NewLocZ,0,0,0,NewBase,Floor.X,Floor.Y,Floor.Z);
}
/* ClientAdjustPosition
- pass newloc and newvel in components so they don't get rounded
*/
function ClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
float NewVelX,
float NewVelY,
float NewVelZ,
Actor NewBase
)
{
local vector Floor;
if ( Pawn != None )
Floor = Pawn.Floor;
LongClientAdjustPosition(TimeStamp,newState,newPhysics,NewLocX,NewLocY,NewLocZ,NewVelX,NewVelY,NewVelZ,NewBase,Floor.X,Floor.Y,Floor.Z);
}
/* LongClientAdjustPosition
long version, when care about pawn's floor normal
*/
function LongClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
float NewVelX,
float NewVelY,
float NewVelZ,
Actor NewBase,
float NewFloorX,
float NewFloorY,
float NewFloorZ
)
{
local vector NewLocation, NewVelocity, NewFloor;
local Actor MoveActor;
local SavedMove CurrentMove;
local float NewPing;
// update ping
if ( (PlayerReplicationInfo != None) && !bDemoOwner )
{
NewPing = FMin(1.5, Level.TimeSeconds - TimeStamp);
if ( ExactPing < 0.004 )
ExactPing = FMin(0.3,NewPing);
else
{
if ( NewPing > 2 * ExactPing )
NewPing = FMin(NewPing, 3*ExactPing);
ExactPing = FMin(0.99, 0.99 * ExactPing + 0.008 * NewPing); // placebo effect
}
PlayerReplicationInfo.Ping = Min(250.0 * ExactPing, 255);
PlayerReplicationInfo.bReceivedPing = true;
if ( Level.TimeSeconds - LastPingUpdate > 4 )
{
if ( bDynamicNetSpeed && (OldPing > DynamicPingThreshold * 0.001) && (ExactPing > DynamicPingThreshold * 0.001) )
{
if ( Level.MoveRepSize < 64 )
Level.MoveRepSize += 8;
else if ( Player.CurrentNetSpeed >= 6000 )
SetNetSpeed(Player.CurrentNetSpeed - 1000);
OldPing = 0;
}
else
OldPing = ExactPing;
LastPingUpdate = Level.TimeSeconds;
ServerUpdatePing(1000 * ExactPing);
}
}
if ( Pawn != None )
{
if ( Pawn.bTearOff )
{
Pawn = None;
if ( !IsInState('GameEnded') && !IsInState('RoundEnded') && !IsInState('Dead') )
{
GotoState('Dead');
}
return;
}
MoveActor = Pawn;
if ( (ViewTarget != Pawn)
&& ((ViewTarget == self) || ((Pawn(ViewTarget) != None) && (Pawn(ViewTarget).Health <= 0))) )
{
bBehindView = false;
SetViewTarget(Pawn);
}
}
else
{
MoveActor = self;
if( GetStateName() != newstate )
{
if ( NewState == 'GameEnded' || NewState == 'RoundEnded' )
GotoState(NewState);
else if ( IsInState('Dead') )
{
if ( (NewState != 'PlayerWalking') && (NewState != 'PlayerSwimming') )
{
GotoState(NewState);
}
return;
}
else if ( NewState == 'Dead' )
GotoState(NewState);
}
}
if ( CurrentTimeStamp >= TimeStamp )
return;
CurrentTimeStamp = TimeStamp;
NewLocation.X = NewLocX;
NewLocation.Y = NewLocY;
NewLocation.Z = NewLocZ;
NewVelocity.X = NewVelX;
NewVelocity.Y = NewVelY;
NewVelocity.Z = NewVelZ;
// skip update if no error
CurrentMove = SavedMoves;
while ( CurrentMove != None )
{
if ( CurrentMove.TimeStamp <= CurrentTimeStamp )
{
SavedMoves = CurrentMove.NextMove;
CurrentMove.NextMove = FreeMoves;
FreeMoves = CurrentMove;
if ( CurrentMove.TimeStamp == CurrentTimeStamp )
{
FreeMoves.Clear();
if ( ((Mover(NewBase) != None) || (Vehicle(NewBase) != None))
&& (NewBase == CurrentMove.EndBase) )
{
if ( (GetStateName() == NewState)
&& IsInState('PlayerWalking')
&& ((MoveActor.Physics == PHYS_Walking) || (MoveActor.Physics == PHYS_Falling)) )
{
if ( VSize(CurrentMove.SavedRelativeLocation - NewLocation) < 3 )
{
CurrentMove = None;
return;
}
else if ( (Vehicle(NewBase) != None)
&& (VSize(Velocity) < 3) && (VSize(NewVelocity) < 3)
&& (VSize(CurrentMove.SavedRelativeLocation - NewLocation) < 30) )
{
CurrentMove = None;
return;
}
}
}
else if ( (VSize(CurrentMove.SavedLocation - NewLocation) < 3)
&& (VSize(CurrentMove.SavedVelocity - NewVelocity) < 3)
&& (GetStateName() == NewState)
&& IsInState('PlayerWalking')
&& ((MoveActor.Physics == PHYS_Walking) || (MoveActor.Physics == PHYS_Falling)) )
{
CurrentMove = None;
return;
}
CurrentMove = None;
}
else
{
FreeMoves.Clear();
CurrentMove = SavedMoves;
}
}
else
CurrentMove = None;
}
if ( MoveActor.bHardAttach )
{
if ( MoveActor.Base == None )
{
if ( NewBase != None )
MoveActor.SetBase(NewBase);
if ( MoveActor.Base == None )
MoveActor.bHardAttach = false;
else
return;
}
else
return;
}
NewFloor.X = NewFloorX;
NewFloor.Y = NewFloorY;
NewFloor.Z = NewFloorZ;
if ( (Mover(NewBase) != None) || (Vehicle(NewBase) != None) )
NewLocation += NewBase.Location;
if ( !bDemoOwner )
{
//if ( Pawn != None )
// log("Client "$Role$" adjust "$self$" stamp "$TimeStamp$" time "$Level.TimeSeconds$" location "$MoveActor.Location);
MoveActor.bCanTeleport = false;
if ( !MoveActor.SetLocation(NewLocation) && (Pawn(MoveActor) != None)
&& (MoveActor.CollisionHeight > Pawn(MoveActor).CrouchHeight)
&& !Pawn(MoveActor).bIsCrouched
&& (newPhysics == PHYS_Walking)
&& (MoveActor.Physics != PHYS_Karma) && (MoveActor.Physics != PHYS_KarmaRagDoll) )
{
MoveActor.SetPhysics(newPhysics);
Pawn(MoveActor).ForceCrouch();
MoveActor.SetLocation(NewLocation);
}
MoveActor.bCanTeleport = true;
}
// Hack. Don't let network change physics mode of karma stuff on the client.
if( (MoveActor.Physics != newPhysics) && (MoveActor.Physics != PHYS_Karma) && (MoveActor.Physics != PHYS_KarmaRagDoll)
&& (newPhysics != PHYS_Karma) && (newPhysics != PHYS_KarmaRagDoll) )
{
MoveActor.SetPhysics(newPhysics);
}
if ( MoveActor != self )
MoveActor.SetBase(NewBase, NewFloor);
MoveActor.Velocity = NewVelocity;
if( GetStateName() != newstate )
GotoState(newstate);
bUpdatePosition = true;
}
function ServerUpdatePing(int NewPing)
{
PlayerReplicationInfo.Ping = Min(0.25 * NewPing, 250);
PlayerReplicationInfo.bReceivedPing = true;
}
// Modified to support Red Orchestra movement
function ClientUpdatePosition()
{
local SavedMove CurrentMove;
local byte realbRun, realbDuck, realbSprint, realbCrawl;
local bool bRealJump;
// Dont do any network position updates on things running PHYS_Karma
if( Pawn != None && (Pawn.Physics == PHYS_Karma || Pawn.Physics == PHYS_KarmaRagDoll) )
return;
bUpdatePosition = false;
realbRun= bRun;
realbDuck = bDuck;
realbSprint = bSprint;
realbCrawl = bCrawl;
bRealJump = bPressedJump;
CurrentMove = SavedMoves;
bUpdating = true;
while ( CurrentMove != None )
{
if ( (PendingMove == CurrentMove) && (Pawn != None) )
PendingMove.SetInitialPosition(Pawn);
if ( CurrentMove.TimeStamp <= CurrentTimeStamp )
{
SavedMoves = CurrentMove.NextMove;
CurrentMove.NextMove = FreeMoves;
FreeMoves = CurrentMove;
FreeMoves.Clear();
CurrentMove = SavedMoves;
}
else
{
MoveAutonomous(CurrentMove.Delta, CurrentMove.bRun, CurrentMove.bDuck, CurrentMove.bPressedJump, CurrentMove.bSprint, CurrentMove.bCrawl, CurrentMove.DoubleClickMove, CurrentMove.Acceleration, rot(0,0,0));
if ( Pawn != None )
{
CurrentMove.SavedLocation = Pawn.Location;
CurrentMove.SavedVelocity = Pawn.Velocity;
CurrentMove.EndBase = Pawn.Base;
if ( (CurrentMove.EndBase != None) && !CurrentMove.EndBase.bWorldGeometry )
CurrentMove.SavedRelativeLocation = Pawn.Location - CurrentMove.EndBase.Location;
}
CurrentMove = CurrentMove.NextMove;
}
}
bUpdating = false;
bDuck = realbDuck;
bRun = realbRun;
bSprint = realbSprint;
bCrawl = realbCrawl;
bPressedJump = bRealJump;
}
final function SavedMove GetFreeMove()
{
local SavedMove s, first;
local int i;
if ( FreeMoves == None )
{
// don't allow more than 100 saved moves
For ( s=SavedMoves; s!=None; s=s.NextMove )
{
i++;
if ( i > 100 )
{
first = SavedMoves;
SavedMoves = SavedMoves.NextMove;
first.Clear();
first.NextMove = None;
// clear out all the moves
While ( SavedMoves != None )
{
s = SavedMoves;
SavedMoves = SavedMoves.NextMove;
s.Clear();
s.NextMove = FreeMoves;
FreeMoves = s;
}
return first;
}
}
return Spawn(class'SavedMove');
}
else
{
s = FreeMoves;
FreeMoves = FreeMoves.NextMove;
s.NextMove = None;
return s;
}
}
function int CompressAccel(int C)
{
if ( C >= 0 )
C = Min(C, 127);
else
C = Min(abs(C), 127) + 128;
return C;
}
/*
========================================================================
Here's how player movement prediction, replication and correction works in network games:
Every tick, the PlayerTick() function is called. It calls the PlayerMove() function (which is implemented
in various states). PlayerMove() figures out the acceleration and rotation, and then calls ProcessMove()
(for single player or listen servers), or ReplicateMove() (if its a network client).
ReplicateMove() saves the move (in the PendingMove list), calls ProcessMove(), and then replicates the move
to the server by calling the replicated function ServerMove() - passing the movement parameters, the client's
resultant position, and a timestamp.
ServerMove() is executed on the server. It decodes the movement parameters and causes the appropriate movement
to occur. It then looks at the resulting position and if enough time has passed since the last response, or the
position error is significant enough, the server calls ClientAdjustPosition(), a replicated function.
ClientAdjustPosition() is executed on the client. The client sets its position to the servers version of position,
and sets the bUpdatePosition flag to true.
When PlayerTick() is called on the client again, if bUpdatePosition is true, the client will call
ClientUpdatePosition() before calling PlayerMove(). ClientUpdatePosition() replays all the moves in the pending
move list which occured after the timestamp of the move the server was adjusting.
*/
//
// Replicate this client's desired movement to the server.
//
// Modified to support Red Orchestra movement
function ReplicateMove
(
float DeltaTime,
vector NewAccel,
eDoubleClickDir DoubleClickMove,
rotator DeltaRot
)
{
local SavedMove NewMove, OldMove, AlmostLastMove, LastMove;
local byte ClientRoll;
local float OldTimeDelta, NetMoveDelta;
local int OldAccel;
local vector BuildAccel, AccelNorm, MoveLoc, CompareAccel;
local bool bPendingJumpStatus;
MaxResponseTime = Default.MaxResponseTime * Level.TimeDilation;
DeltaTime = FMin(DeltaTime, MaxResponseTime);
// find the most recent move, and the most recent interesting move
if ( SavedMoves != None )
{
LastMove = SavedMoves;
AlmostLastMove = LastMove;
AccelNorm = Normal(NewAccel);
while ( LastMove.NextMove != none )
{
// find most recent interesting move to send redundantly
if ( LastMove.IsJumpMove() )
{
OldMove = LastMove;
}
else if ( (Pawn != None) && ((OldMove == None) || !OldMove.IsJumpMove()) )
{
// see if acceleration direction changed
if ( OldMove != None )
CompareAccel = Normal(OldMove.Acceleration);
else
CompareAccel = AccelNorm;
if ( (LastMove.Acceleration != CompareAccel) && ((normal(LastMove.Acceleration) Dot CompareAccel) < 0.95) )
OldMove = LastMove;
}
AlmostLastMove = LastMove;
LastMove = LastMove.NextMove;
}
if ( LastMove.IsJumpMove() )
{
OldMove = LastMove;
}
else if ( (Pawn != None) && ((OldMove == None) || !OldMove.IsJumpMove()) )
{
// see if acceleration direction changed
if ( OldMove != None )
CompareAccel = Normal(OldMove.Acceleration);
else
CompareAccel = AccelNorm;
if ( (LastMove.Acceleration != CompareAccel) && ((normal(LastMove.Acceleration) Dot CompareAccel) < 0.95) )
OldMove = LastMove;
}
}
// Get a SavedMove actor to store the movement in.
NewMove = GetFreeMove();
if ( NewMove == None )
return;
NewMove.SetMoveFor(self, DeltaTime, NewAccel, DoubleClickMove);
// Simulate the movement locally.
ProcessMove(NewMove.Delta, NewMove.Acceleration, NewMove.DoubleClickMove, DeltaRot);
// see if the two moves could be combined
if ( (PendingMove != None) && (Pawn != None) && (Pawn.Physics == PHYS_Walking)
&& (NewMove.Delta + PendingMove.Delta < MaxResponseTime)
&& (NewAccel != vect(0,0,0))
&& (PendingMove.SavedPhysics == PHYS_Walking)
&& !PendingMove.bPressedJump && !NewMove.bPressedJump
&& (PendingMove.bRun == NewMove.bRun)
&& (PendingMove.bDuck == NewMove.bDuck)
&& (PendingMove.bSprint == NewMove.bSprint)
&& (PendingMove.bCrawl == NewMove.bCrawl)
&& (PendingMove.DoubleClickMove == DCLICK_None)
&& (NewMove.DoubleClickMove == DCLICK_None)
&& ((Normal(PendingMove.Acceleration) Dot Normal(NewAccel)) > 0.99)
&& (Level.TimeDilation >= 0.9))
{
Pawn.SetLocation(PendingMove.GetStartLocation());
Pawn.Velocity = PendingMove.StartVelocity;
if ( PendingMove.StartBase != Pawn.Base);
Pawn.SetBase(PendingMove.StartBase);
Pawn.Floor = PendingMove.StartFloor;
NewMove.Delta += PendingMove.Delta;
NewMove.SetInitialPosition(Pawn);
// remove pending move from move list
if ( LastMove == PendingMove )
{
if ( SavedMoves == PendingMove )
{
SavedMoves.NextMove = FreeMoves;
FreeMoves = SavedMoves;
SavedMoves = None;
}
else
{
PendingMove.NextMove = FreeMoves;
FreeMoves = PendingMove;
if ( AlmostLastMove != None )
{
AlmostLastMove.NextMove = None;
LastMove = AlmostLastMove;
}
}
FreeMoves.Clear();
}
PendingMove = None;
}
if ( Pawn != None )
Pawn.AutonomousPhysics(NewMove.Delta);
else
AutonomousPhysics(DeltaTime);
NewMove.PostUpdate(self);
if ( SavedMoves == None )
SavedMoves = NewMove;
else
LastMove.NextMove = NewMove;
if ( PendingMove == None )
{
// Decide whether to hold off on move
if ( (Player.CurrentNetSpeed > 10000) && (GameReplicationInfo != None) && (GameReplicationInfo.PRIArray.Length <= 10) )
NetMoveDelta = 0.011;
else
NetMoveDelta = FMax(0.0222,2 * Level.MoveRepSize/Player.CurrentNetSpeed);
if ( (Level.TimeSeconds - ClientUpdateTime) * Level.TimeDilation * 0.91 < NetMoveDelta )
{
PendingMove = NewMove;
return;
}
}
ClientUpdateTime = Level.TimeSeconds;
// check if need to redundantly send previous move
if ( OldMove != None )
{
// old move important to replicate redundantly
OldTimeDelta = FMin(255, (Level.TimeSeconds - OldMove.TimeStamp) * 500);
BuildAccel = 0.05 * OldMove.Acceleration + vect(0.5, 0.5, 0.5);
OldAccel = (CompressAccel(BuildAccel.X) << 23)
+ (CompressAccel(BuildAccel.Y) << 15)
+ (CompressAccel(BuildAccel.Z) << 7);
if ( OldMove.bRun )
OldAccel += 64;
if ( OldMove.bSprint )
OldAccel += 32;
if ( OldMove.bPressedJump )
OldAccel += 16;
OldAccel += OldMove.DoubleClickMove;
}
// Send to the server
ClientRoll = (Rotation.Roll >> 8) & 255;
if ( PendingMove != None )
{
if ( PendingMove.bPressedJump )
bJumpStatus = !bJumpStatus;
bPendingJumpStatus = bJumpStatus;
}
if ( NewMove.bPressedJump )
bJumpStatus = !bJumpStatus;
if ( Pawn == None )
MoveLoc = Location;
else
MoveLoc = Pawn.Location;
CallServerMove
(
NewMove.TimeStamp,
NewMove.Acceleration * 10,
MoveLoc,
NewMove.bRun,
NewMove.bDuck,
bPendingJumpStatus,
bJumpStatus,
NewMove.bSprint,
NewMove.bCrawl,
NewMove.DoubleClickMove,
ClientRoll,
(32767 & (Rotation.Pitch/2)) * 32768 + (32767 & (Rotation.Yaw/2)),
(32767 & (WeaponBufferRotation.Pitch/2)) * 32768 + (32767 & (WeaponBufferRotation.Yaw/2)),
OldTimeDelta,
OldAccel
);
PendingMove = None;
}
// Converted to handle Red Orchestra movement
function CallServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbRun,
bool NewbDuck,
bool NewbPendingJumpStatus,
bool NewbJumpStatus,
bool NewbSprint,
bool NewbCrawl,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
local byte NewActions0;
local byte NewActions;
local bool bCombine;
// Put together new actions to send (compressed into one byte)
if (NewbRun)
NewActions = 1;
if (NewbDuck)
NewActions += 2;
if (NewbJumpStatus)
NewActions += 4;
if (NewbSprint)
NewActions += 8;
if (NewbCrawl)
NewActions += 16;
if ( PendingMove != None )
{
if ( PendingMove.bRun )
NewActions0 = 1;
if ( PendingMove.bDuck )
NewActions0 += 2;
if ( NewbPendingJumpStatus )
NewActions0 += 4;
if ( PendingMove.bSprint )
NewActions0 += 8;
if ( PendingMove.bCrawl )
NewActions0 += 16;
// send two moves simultaneously
if ( (InAccel == vect(0,0,0))
&& (PendingMove.StartVelocity == vect(0,0,0))
&& (DoubleClickMove == DCLICK_None)
&& (PendingMove.Acceleration == vect(0,0,0)) && (PendingMove.DoubleClickMove == DCLICK_None))
{
if ( Pawn == None )
bCombine = (Velocity == vect(0,0,0));
else
bCombine = (Pawn.Velocity == vect(0,0,0));
if ( bCombine )
{
if ( OldTimeDelta == 0 )
{
ShortServerMove
(
TimeStamp,
ClientLoc,
NewActions,
ClientRoll,
View,
FreeAimRot
);
}
else
{
ServerMove
(
TimeStamp,
InAccel,
ClientLoc,
NewActions,
DoubleClickMove,
ClientRoll,
View,
FreeAimRot,
OldTimeDelta,
OldAccel
);
}
return;
}
}
if ( OldTimeDelta == 0 )
DualServerMove
(
PendingMove.TimeStamp,
PendingMove.Acceleration * 10,
NewActions0,
PendingMove.DoubleClickMove,
(32767 & (PendingMove.Rotation.Pitch/2)) * 32768 + (32767 & (PendingMove.Rotation.Yaw/2)),
TimeStamp,
InAccel,
ClientLoc,
NewActions,
DoubleClickMove,
ClientRoll,
View,
FreeAimRot
);
else
DualServerMove
(
PendingMove.TimeStamp,
PendingMove.Acceleration * 10,
NewActions0,
PendingMove.DoubleClickMove,
(32767 & (PendingMove.Rotation.Pitch/2)) * 32768 + (32767 & (PendingMove.Rotation.Yaw/2)),
TimeStamp,
InAccel,
ClientLoc,
NewActions,
DoubleClickMove,
ClientRoll,
View,
FreeAimRot,
OldTimeDelta,
OldAccel
);
}
else if ( OldTimeDelta != 0 )
{
ServerMove
(
TimeStamp,
InAccel,
ClientLoc,
NewActions,
DoubleClickMove,
ClientRoll,
View,
FreeAimRot,
OldTimeDelta,
OldAccel
);
}
else if ( (InAccel == vect(0,0,0)) && (DoubleClickMove == DCLICK_None))
{
ShortServerMove
(
TimeStamp,
ClientLoc,
NewActions,
ClientRoll,
View,
FreeAimRot
);
}
else
ServerMove
(
TimeStamp,
InAccel,
ClientLoc,
NewActions,
DoubleClickMove,
ClientRoll,
View,
FreeAimRot
);
}
function HandleWalking()
{
if ( Pawn != None )
Pawn.SetWalking( (bRun != 0) && !Region.Zone.IsA('WarpZoneInfo') );
}
function ServerRestartGame()
{
}
function SetFOVAngle(float newFOV)
{
FOVAngle = newFOV;
}
exec function SetFlashScaling(float F)
{
ScreenFlashScaling = FClamp(F,0,1);
}
function ClientFlash( float scale, vector fog )
{
FlashScale = (scale + (1 - ScreenFlashScaling) * (1 - Scale)) * vect(1,1,1);
flashfog = ScreenFlashScaling * 0.001 * fog;
}
function ClientAdjustGlow( float scale, vector fog )
{
ConstantGlowScale += scale;
ConstantGlowFog += 0.001 * fog;
}
function DamageShake(int damage) //send type of damage too!
{
ClientDamageShake(damage);
}
// function ShakeView( float shaketime, float RollMag, vector OffsetMag, float RollRate, vector OffsetRate, float OffsetTime)
private function ClientDamageShake(int damage)
{
// todo: add properties!
ShakeView( Damage * vect(30,0,0),
120000 * vect(1,0,0),
0.15 + 0.005 * damage,
damage * vect(0,0,0.03),
vect(1,1,1),
0.2);
}
function WeaponShakeView(vector shRotMag, vector shRotRate, float shRotTime,
vector shOffsetMag, vector shOffsetRate, float shOffsetTime)
{
if ( bWeaponViewShake )
ShakeView(shRotMag * (1.0 - ZoomLevel), shRotRate, shRotTime, shOffsetMag * (1.0 - ZoomLevel), shOffsetRate, shOffsetTime);
}
/* ShakeView()
Call this function to shake the player's view
shaketime = how long to roll view
RollMag = how far to roll view as it shakes
OffsetMag = max view offset
RollRate = how fast to roll view
OffsetRate = how fast to offset view
OffsetTime = how long to offset view (number of shakes)
*/
function ShakeView(vector shRotMag, vector shRotRate, float shRotTime,
vector shOffsetMag, vector shOffsetRate, float shOffsetTime)
{
if ( VSize(shRotMag) > VSize(ShakeRotMax) )
{
ShakeRotMax = shRotMag;
ShakeRotRate = shRotRate;
ShakeRotTime = shRotTime * vect(1,1,1);
}
if ( VSize(shOffsetMag) > VSize(ShakeOffsetMax) )
{
ShakeOffsetMax = shOffsetMag;
ShakeOffsetRate = shOffsetRate;
ShakeOffsetTime = shOffsetTime * vect(1,1,1);
}
}
function StopViewShaking()
{
ShakeRotMax = vect(0,0,0);
ShakeRotRate = vect(0,0,0);
ShakeRotTime = vect(0,0,0);
ShakeOffsetMax = vect(0,0,0);
ShakeOffsetRate = vect(0,0,0);
ShakeOffsetTime = vect(0,0,0);
}
//pass in FalloffStartTime = 0 for constant shaking
event SetAmbientShake(float FalloffStartTime, float FalloffTime, vector OffsetMag, float OffsetFreq, rotator RotMag, float RotFreq)
{
bEnableAmbientShake = true;
AmbientShakeFalloffStartTime = FalloffStartTime;
AmbientShakeFalloffTime = FalloffTime;
AmbientShakeOffsetMag = OffsetMag;
AmbientShakeOffsetFreq = OffsetFreq;
AmbientShakeRotMag = RotMag;
AmbientShakeRotFreq = RotFreq;
}
event ShakeViewEvent(vector shRotMag, vector shRotRate, float shRotTime, vector shOffsetMag, vector shOffsetRate, float shOffsetTime)
{
ShakeView(shRotMag, shRotRate, shRotTime, shOffsetMag, shOffsetRate, shOffsetTime);
}
function damageAttitudeTo(pawn Other, float Damage)
{
if ( (Other != None) && (Other != Pawn) && (Damage > 0) )
Enemy = Other;
}
function Typing( bool bTyping )
{
bIsTyping = bTyping;
if ( (Pawn != None) && !Pawn.bTearOff )
Pawn.bIsTyping = bIsTyping;
}
//*************************************************************************************
// Normal gameplay execs
// Type the name of the exec function at the console to execute it
exec function Jump( optional float F )
{
if ( Level.Pauser == PlayerReplicationInfo )
SetPause(False);
else
bPressedJump = true;
}
// Send a voice message of a certain type to a certain player.
exec function Speech( name Type, int Index, string Callsign )
{
ServerSpeech(Type,Index,Callsign);
}
// if _RO_
// implemented in ROPlayer
exec function xSpeech(name Type, int Index, PlayerReplicationInfo SquadLeader) {}
// end if _RO_
function ServerSpeech( name Type, int Index, string Callsign )
{
// log("Type:"$Type@"Index:"$Index@"Callsign:"$Callsign);
if(PlayerReplicationInfo.VoiceType != None)
PlayerReplicationInfo.VoiceType.static.PlayerSpeech( Type, Index, Callsign, self );
}
exec function RestartLevel()
{
if( Level.Netmode==NM_Standalone )
ClientTravel( "?restart", TRAVEL_Relative, false );
}
exec function LocalTravel( string URL )
{
if( Level.Netmode==NM_Standalone )
ClientTravel( URL, TRAVEL_Relative, true );
}
// ------------------------------------------------------------------------
// Loading and saving
/* QuickSave()
Save game to slot 9
*/
exec function QuickSave()
{
if ( (Pawn != None) && (Pawn.Health > 0)
&& (Level.NetMode == NM_Standalone) )
{
ClientMessage(QuickSaveString);
ConsoleCommand("SaveGame 9");
}
}
/* QuickLoad()
Load game from slot 9
*/
exec function QuickLoad()
{
if ( Level.NetMode == NM_Standalone )
ClientTravel( "?load=9", TRAVEL_Absolute, false);
}
/* SetPause()
Try to pause game; returns success indicator.
Replicated to server in network games.
*/
function bool SetPause( BOOL bPause )
{
bFire = 0;
bAltFire = 0;
return Level.Game.SetPause(bPause, self);
}
/* Pause()
Command to try to pause the game.
*/
exec function Pause()
{
if ( bDemoOwner )
{
if ( Level.Pauser == None )
Level.Pauser = PlayerReplicationInfo;
else
Level.Pauser = None;
}
else
ServerPause();
}
function ServerPause()
{
// Pause if not already
if(Level.Pauser == None)
SetPause(true);
else
SetPause(false);
}
exec function ShowMenu()
{
local bool bCloseHUDScreen;
if ( MyHUD != None )
{
bCloseHUDScreen = MyHUD.bShowScoreboard || MyHUD.bShowLocalStats;
if ( MyHUD.bShowScoreboard )
MyHUD.bShowScoreboard = false;
if ( MyHUD.bShowLocalStats )
MyHUD.bShowLocalStats = false;
if ( bCloseHUDScreen )
return;
}
ShowMidGameMenu(true);
}
function ShowMidGameMenu(bool bPause)
{
// Pause if not already
if(bPause && Level.Pauser == None)
SetPause(true);
StopForceFeedback(); // jdf - no way to pause feedback
// Open menu
if (bDemoOwner)
ClientopenMenu(DemoMenuClass);
else
ClientOpenMenu(MidGameMenuClass);
}
// Activate specific inventory item
exec function ActivateInventoryItem( class InvItem )
{
local Powerups Inv;
Inv = Powerups(Pawn.FindInventoryType(InvItem));
if ( Inv != None )
Inv.Activate();
}
// ------------------------------------------------------------------------
// Weapon changing functions
/* ThrowWeapon()
Throw out current weapon, and switch to a new weapon
*/
exec function ThrowWeapon()
{
if ( (Pawn == None) || (Pawn.Weapon == None) )
return;
ServerThrowWeapon();
}
function ServerThrowWeapon()
{
local Vector TossVel;
if (Pawn.CanThrowWeapon())
{
TossVel = Vector(GetViewRotation());
TossVel = TossVel * ((Pawn.Velocity dot TossVel) + 150) + Vect(0,0,100);
Pawn.TossWeapon(TossVel);
ClientSwitchToBestWeapon();
}
}
/* PrevWeapon()
- switch to previous inventory group weapon
*/
exec function PrevWeapon()
{
if ( Level.Pauser != None )
return;
if ( Pawn != None )
Pawn.PrevWeapon();
else if ( bBehindView )
CameraDist = FMax(CameraDistRange.Min, CameraDist - 1.0);
}
/* NextWeapon()
- switch to next inventory group weapon
*/
exec function NextWeapon()
{
if ( Level.Pauser != None )
return;
if ( Pawn != None )
Pawn.NextWeapon();
else if ( bBehindView )
CameraDist = FMin(CameraDistRange.Max, CameraDist + 1.0);
}
exec function PipedSwitchWeapon(byte F)
{
if ( (Pawn == None) || (Pawn.PendingWeapon != None) )
return;
SwitchWeapon(F);
}
// The player wants to switch to weapon group number F.
exec function SwitchWeapon(byte F)
{
if ( Pawn != None )
Pawn.SwitchWeapon(F);
}
exec function GetWeapon(class<Weapon> NewWeaponClass )
{
local Inventory Inv;
local int Count;
if ( (Pawn == None) || (Pawn.Inventory == None) || (NewWeaponClass == None) )
return;
if ( (Pawn.Weapon != None) && (Pawn.Weapon.Class == NewWeaponClass) && (Pawn.PendingWeapon == None) )
{
Pawn.Weapon.Reselect();
return;
}
if ( Pawn.PendingWeapon != None && Pawn.PendingWeapon.bForceSwitch )
return;
for ( Inv=Pawn.Inventory; Inv!=None; Inv=Inv.Inventory )
{
if ( Inv.Class == NewWeaponClass )
{
Pawn.PendingWeapon = Weapon(Inv);
if ( !Pawn.PendingWeapon.HasAmmo() )
{
ClientMessage( Pawn.PendingWeapon.ItemName$Pawn.PendingWeapon.MessageNoAmmo );
Pawn.PendingWeapon = None;
return;
}
Pawn.Weapon.PutDown();
return;
}
Count++;
if ( Count > 1000 )
return;
}
}
// The player wants to select previous item
exec function PrevItem()
{
local Inventory Inv;
local Powerups LastItem;
if ( (Level.Pauser!=None) || (Pawn == None) )
return;
if (Pawn.SelectedItem==None)
{
Pawn.SelectedItem = Pawn.Inventory.SelectNext();
Return;
}
if (Pawn.SelectedItem.Inventory!=None)
for( Inv=Pawn.SelectedItem.Inventory; Inv!=None; Inv=Inv.Inventory )
{
if (Inv==None) Break;
if ( Inv.IsA('Powerups') && Powerups(Inv).bActivatable) LastItem=Powerups(Inv);
}
for( Inv=Pawn.Inventory; Inv!=Pawn.SelectedItem; Inv=Inv.Inventory )
{
if (Inv==None) Break;
if ( Inv.IsA('Powerups') && Powerups(Inv).bActivatable) LastItem=Powerups(Inv);
}
if (LastItem!=None)
Pawn.SelectedItem = LastItem;
}
// The player wants to active selected item
exec function ActivateItem()
{
if( Level.Pauser!=None )
return;
if ( (Pawn != None) && (Pawn.SelectedItem!=None) )
Pawn.SelectedItem.Activate();
}
// The player wants to fire.
exec function Fire( optional float F )
{
if ( Level.NetMode == NM_StandAlone && bViewingMatineeCinematic )
{
Level.Game.SceneAbort();
}
if ( Level.Pauser == PlayerReplicationInfo )
{
SetPause(false);
return;
}
if( bDemoOwner || (Pawn == None) )
return;
Pawn.Fire(F);
}
// The player wants to alternate-fire.
exec function AltFire( optional float F )
{
if ( Level.Pauser == PlayerReplicationInfo )
{
SetPause(false);
return;
}
if( bDemoOwner || (Pawn == None) )
return;
Pawn.AltFire(F);
}
// The player wants to use something in the level.
exec function Use()
{
ServerUse();
}
function ServerUse()
{
local Actor A;
local Vehicle DrivenVehicle, EntryVehicle, V;
if ( Role < ROLE_Authority )
return;
if ( Level.Pauser == PlayerReplicationInfo )
{
SetPause(false);
return;
}
if (Pawn == None || !Pawn.bCanUse)
return;
DrivenVehicle = Vehicle(Pawn);
if( DrivenVehicle != None )
{
DrivenVehicle.KDriverLeave(false);
return;
}
// Check for nearby vehicles
ForEach Pawn.VisibleCollidingActors(class'Vehicle', V, VehicleCheckRadius)
{
// Found a vehicle within radius
EntryVehicle = V.FindEntryVehicle(Pawn);
if (EntryVehicle != None && EntryVehicle.TryToDrive(Pawn))
return;
}
// Send the 'DoUse' event to each actor player is touching.
ForEach Pawn.TouchingActors(class'Actor', A)
A.UsedBy(Pawn);
if ( Pawn.Base != None )
Pawn.Base.UsedBy( Pawn );
}
exec function Suicide()
{
local float MinSuicideInterval;
if ( Level.NetMode == NM_Standalone )
MinSuicideInterval = 1;
else
MinSuicideInterval = 10;
if ( (Pawn != None) && (Level.TimeSeconds - Pawn.LastStartTime > MinSuicideInterval) )
Pawn.Suicide();
}
exec function SetName(coerce string S)
{
//ifdef _KF_
S = Player.GUIController.SteamGetUserName();
//endif _KF_
ChangeName(S);
UpdateURL("Name", S, true);
SaveConfig();
}
exec function SetVoice( coerce string S )
{
if ( Level.NetMode == NM_StandAlone )
{
if ( PlayerReplicationInfo != None )
PlayerReplicationInfo.SetCharacterVoice(S);
}
else ChangeVoiceType(S);
UpdateURL("Voice", S, True);
}
function ChangeVoiceType(string NewVoiceType)
{
if ( VoiceChangeLimit > Level.TimeSeconds )
return;
VoiceChangeLimit = Level.TimeSeconds + 10.0; // TODO - probably better to hook this up to the same limit system that playernames use
if ( NewVoiceType != "" && PlayerReplicationInfo != None )
PlayerReplicationInfo.SetCharacterVoice(NewVoiceType);
}
function ChangeName( coerce string S )
{
if ( Len(S) > 20 )
S = left(S,20);
ReplaceText(S, " ", "_");
ReplaceText(S, "\"", "");
Level.Game.ChangeName( self, S, true );
}
exec function SwitchTeam()
{
if ( (PlayerReplicationInfo.Team == None) || (PlayerReplicationInfo.Team.TeamIndex == 1) )
ServerChangeTeam(0);
else
ServerChangeTeam(1);
}
exec function ChangeTeam( int N )
{
ServerChangeTeam(N);
}
function ServerChangeTeam( int N )
{
local TeamInfo OldTeam;
OldTeam = PlayerReplicationInfo.Team;
Level.Game.ChangeTeam(self, N, true);
if ( Level.Game.bTeamGame && (PlayerReplicationInfo.Team != OldTeam) )
{
if ( (OldTeam != None) && (PlayerReplicationInfo.Team != None)
&& (PlayerReplicationInfo.Team.Size > OldTeam.Size) )
Adrenaline = 0;
if ( Pawn != None )
Pawn.PlayerChangedTeam();
}
}
exec function SwitchLevel( string URL )
{
if( Level.NetMode==NM_Standalone || Level.netMode==NM_ListenServer )
Level.ServerTravel( URL, false );
}
event ProgressCommand(string Cmd, string Msg1, string Msg2)
{
local string c,v;
log(Name$".ProgressCommand Cmd '"$Cmd$"' Msg1 '"$Msg1$"' Msg2 '"$Msg2$"'");
Divide(Cmd, ":", C, V);
// Checking for bActive prevents multiple status message menus from being opened. However, this also
// prevents status messages from appearing if another menu is open.
// Instead, place checks for bActive in places where ProgressCommand is called, but we don't want to override other menus.
if ( C~="menu" /*&& (!Player.GUIController.bActive)*/ )
ClientOpenMenu(v, false, Msg1, Msg2);
}
exec function ClearProgressMessages()
{
local int i;
for (i=0; i<ArrayCount(ProgressMessage); i++)
{
ProgressMessage[i] = "";
ProgressColor[i] = class'Canvas'.Static.MakeColor(255,255,255);
}
}
exec event SetProgressMessage( int Index, string S, color C )
{
if ( Index < ArrayCount(ProgressMessage) )
{
ProgressMessage[Index] = S;
ProgressColor[Index] = C;
}
}
exec event SetProgressTime( float T )
{
ProgressTimeOut = T + Level.TimeSeconds;
}
function Restart()
{
Super.Restart();
ServerTimeStamp = 0;
ResetTimeMargin();
EnterStartState();
bBehindView = Pawn.PointOfView();
ClientRestart(Pawn);
SetViewTarget(Pawn);
}
function EnterStartState()
{
local name NewState;
if ( Pawn.PhysicsVolume.bWaterVolume )
{
if ( Pawn.HeadVolume.bWaterVolume )
Pawn.BreathTime = Pawn.UnderWaterTime;
NewState = Pawn.WaterMovementState;
}
else
NewState = Pawn.LandMovementState;
if ( IsInState(NewState) )
BeginState();
else
GotoState(NewState);
}
function ClientRestart(Pawn NewPawn)
{
local bool bNewViewTarget;
Pawn = NewPawn;
if ( (Pawn != None) && Pawn.bTearOff )
{
Pawn.Controller = None;
Pawn = None;
}
AcknowledgePossession(Pawn);
if ( Pawn == None )
{
GotoState('WaitingForPawn');
return;
}
Pawn.ClientRestart();
bNewViewTarget = (ViewTarget != Pawn);
SetViewTarget(Pawn);
bBehindView = Pawn.PointOfView();
BehindView(bBehindView);
if (bNewViewTarget)
Pawn.POVChanged(self, false);
CleanOutSavedMoves();
EnterStartState();
}
exec function BehindView( Bool B )
{
if ( Level.NetMode == NM_Standalone || bDemoOwner || Level.Game.bAllowBehindView || Vehicle(Pawn) != None || PlayerReplicationInfo.bOnlySpectator || PlayerReplicationInfo.bAdmin || IsA('Admin') )
{
if ( (Vehicle(Pawn)==None) || (Vehicle(Pawn).bAllowViewChange) ) // Allow vehicles to limit view changes
{
ClientSetBehindView(B);
bBehindView = B;
}
}
}
exec function ToggleBehindView()
{
ServerToggleBehindview();
}
function ServerToggleBehindView()
{
local bool B;
if ( Level.NetMode == NM_Standalone || Level.Game.bAllowBehindView || Vehicle(Pawn) != None || PlayerReplicationInfo.bOnlySpectator || PlayerReplicationInfo.bAdmin || IsA('Admin') )
{
if ( (Vehicle(Pawn)==None) || (Vehicle(Pawn).bAllowViewChange) ) // Allow vehicles to limit view changes
{
B = !bBehindView;
ClientSetBehindView(B);
bBehindView = B;
}
}
}
//=============================================================================
// functions.
// Just changed to pendingWeapon
function ChangedWeapon()
{
if ( Pawn != None && Pawn.Weapon != None )
{
Pawn.Weapon.SetHand(Handedness);
LastPawnWeapon = Pawn.Weapon.Class;
}
}
event TravelPostAccept()
{
if ( Pawn.Health <= 0 )
Pawn.Health = Pawn.Default.Health;
}
// if _RO_
// Implemented in subclass
simulated function UpdateBlurEffect(float DeltaTime){}
// end _RO_
event PlayerTick( float DeltaTime )
{
if ( bForcePrecache )
{
if ( Level.TimeSeconds > ForcePrecacheTime )
{
bForcePrecache = false;
Level.FillPrecacheMaterialsArray( false );
Level.FillPrecacheStaticMeshesArray( false );
}
}
else if ( !bShortConnectTimeOut )
{
bShortConnectTimeOut = true;
ServerShortTimeout();
}
if ( Pawn != AcknowledgedPawn )
{
if ( Role < ROLE_Authority )
{
// make sure old pawn controller is right
if ( (AcknowledgedPawn != None) && (AcknowledgedPawn.Controller == self) )
AcknowledgedPawn.Controller = None;
}
AcknowledgePossession(Pawn);
}
PlayerInput.PlayerInput(DeltaTime);
if ( bUpdatePosition )
ClientUpdatePosition();
if ( !IsSpectating() && Pawn != None )
Pawn.RawInput(DeltaTime, aBaseX, aBaseY, aBaseZ, aMouseX, aMouseY, aForward, aTurn, aStrafe, aUp, aLookUp);
PlayerMove(DeltaTime);
// if _RO_
// Update the motion blur effect
if( Level.NetMode != NM_DedicatedServer )
{
if( BlurTime > 0 || ColorFadeTime > 0)
UpdateBlurEffect(DeltaTime);
}
// end _RO_
}
function PlayerMove(float DeltaTime);
//
/* AdjustAim()
Calls this version for player aiming help.
Aimerror not used in this version.
Only adjusts aiming at pawns
*/
function rotator AdjustAim(FireProperties FiredAmmunition, vector projStart, int aimerror)
{
local vector FireDir, AimSpot, HitNormal, HitLocation, OldAim, AimOffset;
local actor BestTarget;
local float bestAim, bestDist, projspeed;
local actor HitActor;
local bool bNoZAdjust, bLeading;
local rotator AimRot;
FireDir = vector(Rotation);
if ( FiredAmmunition.bInstantHit )
HitActor = Trace(HitLocation, HitNormal, projStart + 10000 * FireDir, projStart, true);
else
HitActor = Trace(HitLocation, HitNormal, projStart + 4000 * FireDir, projStart, true);
if ( (HitActor != None) && HitActor.bProjTarget )
{
BestTarget = HitActor;
bNoZAdjust = true;
OldAim = HitLocation;
BestDist = VSize(BestTarget.Location - Pawn.Location);
}
else
{
// adjust aim based on FOV
bestAim = 0.90;
if ( (Level.NetMode == NM_Standalone) && bAimingHelp )
{
bestAim = 0.93;
if ( FiredAmmunition.bInstantHit )
bestAim = 0.97;
if ( FOVAngle < DefaultFOV - 8 )
bestAim = 0.99;
}
else if ( FiredAmmunition.bInstantHit )
bestAim = 1.0;
BestTarget = PickTarget(bestAim, bestDist, FireDir, projStart, FiredAmmunition.MaxRange);
if ( BestTarget == None )
{
if (bBehindView)
return Pawn.Rotation;
else
return Rotation;
}
OldAim = projStart + FireDir * bestDist;
}
InstantWarnTarget(BestTarget,FiredAmmunition,FireDir);
ShotTarget = Pawn(BestTarget);
if ( !bAimingHelp || (Level.NetMode != NM_Standalone) )
{
if (bBehindView)
return Pawn.Rotation;
else
return Rotation;
}
// aim at target - help with leading also
if ( !FiredAmmunition.bInstantHit )
{
projspeed = FiredAmmunition.ProjectileClass.default.speed;
BestDist = vsize(BestTarget.Location + BestTarget.Velocity * FMin(1, 0.02 + BestDist/projSpeed) - projStart);
bLeading = true;
FireDir = BestTarget.Location + BestTarget.Velocity * FMin(1, 0.02 + BestDist/projSpeed) - projStart;
AimSpot = projStart + bestDist * Normal(FireDir);
// if splash damage weapon, try aiming at feet - trace down to find floor
if ( FiredAmmunition.bTrySplash
&& ((BestTarget.Velocity != vect(0,0,0)) || (BestDist > 1500)) )
{
HitActor = Trace(HitLocation, HitNormal, AimSpot - BestTarget.CollisionHeight * vect(0,0,2), AimSpot, false);
if ( (HitActor != None)
&& FastTrace(HitLocation + vect(0,0,4),projstart) )
return rotator(HitLocation + vect(0,0,6) - projStart);
}
}
else
{
FireDir = BestTarget.Location - projStart;
AimSpot = projStart + bestDist * Normal(FireDir);
}
AimOffset = AimSpot - OldAim;
// adjust Z of shooter if necessary
if ( bNoZAdjust || (bLeading && (Abs(AimOffset.Z) < BestTarget.CollisionHeight)) )
AimSpot.Z = OldAim.Z;
else if ( AimOffset.Z < 0 )
AimSpot.Z = BestTarget.Location.Z + 0.4 * BestTarget.CollisionHeight;
else
AimSpot.Z = BestTarget.Location.Z - 0.7 * BestTarget.CollisionHeight;
if ( !bLeading )
{
// if not leading, add slight random error ( significant at long distances )
if ( !bNoZAdjust )
{
AimRot = rotator(AimSpot - projStart);
if ( FOVAngle < DefaultFOV - 8 )
AimRot.Yaw = AimRot.Yaw + 200 - Rand(400);
else
AimRot.Yaw = AimRot.Yaw + 375 - Rand(750);
return AimRot;
}
}
else if ( !FastTrace(projStart + 0.9 * bestDist * Normal(FireDir), projStart) )
{
FireDir = BestTarget.Location - projStart;
AimSpot = projStart + bestDist * Normal(FireDir);
}
return rotator(AimSpot - projStart);
}
function bool NotifyLanded(vector HitNormal)
{
return bUpdating;
}
//=============================================================================
// Player Control
// Player view.
// Compute the rendering viewpoint for the player.
//
function AdjustView(float DeltaTime )
{
// teleporters affect your FOV, so adjust it back down
if ( FOVAngle != DesiredFOV )
{
if ( FOVAngle > DesiredFOV )
FOVAngle = FOVAngle - FMax(7, 0.9 * DeltaTime * (FOVAngle - DesiredFOV));
else
FOVAngle = FOVAngle - FMin(-7, 0.9 * DeltaTime * (FOVAngle - DesiredFOV));
if ( Abs(FOVAngle - DesiredFOV) <= 10 )
FOVAngle = DesiredFOV;
}
// adjust FOV for weapon zooming
if ( bZooming )
{
ZoomLevel = FMin(ZoomLevel + DeltaTime, DesiredZoomLevel);
DesiredFOV = FClamp(90.0 - (ZoomLevel * 88.0), 1, 170);
}
}
function CalcBehindView(out vector CameraLocation, out rotator CameraRotation, float Dist)
{
local vector View,HitLocation,HitNormal;
local float ViewDist,RealDist;
local vector globalX,globalY,globalZ;
local vector localX,localY,localZ;
CameraRotation = Rotation;
CameraRotation.Roll = 0;
CameraLocation.Z += 12;
// add view rotation offset to cameraview (amb)
CameraRotation += CameraDeltaRotation;
View = vect(1,0,0) >> CameraRotation;
// add view radius offset to camera location and move viewpoint up from origin (amb)
RealDist = Dist;
Dist += CameraDeltaRad;
if( Trace( HitLocation, HitNormal, CameraLocation - Dist * vector(CameraRotation), CameraLocation,false,vect(10,10,10) ) != None )
ViewDist = FMin( (CameraLocation - HitLocation) Dot View, Dist );
else
ViewDist = Dist;
if ( !bBlockCloseCamera || !bValidBehindCamera || (ViewDist > 10 + FMax(ViewTarget.CollisionRadius, ViewTarget.CollisionHeight)) )
{
//Log("Update Cam ");
bValidBehindCamera = true;
OldCameraLoc = CameraLocation - ViewDist * View;
OldCameraRot = CameraRotation;
}
else
{
//Log("Dont Update Cam "$bBlockCloseCamera@bValidBehindCamera@ViewDist);
SetRotation(OldCameraRot);
}
CameraLocation = OldCameraLoc;
CameraRotation = OldCameraRot;
// add view swivel rotation to cameraview (amb)
GetAxes(CameraSwivel,globalX,globalY,globalZ);
localX = globalX >> CameraRotation;
localY = globalY >> CameraRotation;
localZ = globalZ >> CameraRotation;
CameraRotation = OrthoRotation(localX,localY,localZ);
}
function CalcFirstPersonView( out vector CameraLocation, out rotator CameraRotation )
{
local vector x, y, z, AmbShakeOffset;
local rotator AmbShakeRot;
local float FalloffScaling;
GetAxes(Rotation, x, y, z);
if(bEnableAmbientShake)
{
if (AmbientShakeFalloffStartTime > 0 && Level.TimeSeconds - AmbientShakeFalloffStartTime > AmbientShakeFalloffTime)
bEnableAmbientShake = false;
else
{
if (AmbientShakeFalloffStartTime > 0)
{
FalloffScaling = 1.0 - ((Level.TimeSeconds - AmbientShakeFalloffStartTime) / AmbientShakeFalloffTime);
FalloffScaling = FClamp(FalloffScaling, 0.0, 1.0);
}
else
FalloffScaling = 1.0;
AmbShakeOffset = AmbientShakeOffsetMag * FalloffScaling *
sin(Level.TimeSeconds * AmbientShakeOffsetFreq * 2 * Pi);
AmbShakeRot = AmbientShakeRotMag * FalloffScaling *
sin(Level.TimeSeconds * AmbientShakeRotFreq * 2 * Pi);
}
}
// First-person view.
CameraRotation = Normalize(Rotation + ShakeRot + AmbShakeRot); // amb
CameraLocation = CameraLocation + Pawn.EyePosition() + Pawn.WalkBob +
ShakeOffset.X * x +
ShakeOffset.Y * y +
ShakeOffset.Z * z +
AmbShakeOffset;
}
event AddCameraEffect(CameraEffect NewEffect,optional bool RemoveExisting)
{
if(RemoveExisting)
RemoveCameraEffect(NewEffect);
CameraEffects.Length = CameraEffects.Length + 1;
CameraEffects[CameraEffects.Length - 1] = NewEffect;
}
event RemoveCameraEffect(CameraEffect ExEffect)
{
local int EffectIndex;
for(EffectIndex = 0;EffectIndex < CameraEffects.Length;EffectIndex++)
if(CameraEffects[EffectIndex] == ExEffect)
{
CameraEffects.Remove(EffectIndex,1);
return;
}
}
exec function CreateCameraEffect(class<CameraEffect> EffectClass)
{
AddCameraEffect(new EffectClass);
}
simulated function rotator GetViewRotation()
{
if ( bBehindView && (Pawn != None) )
return Pawn.Rotation;
return Rotation;
}
function CacheCalcView(actor ViewActor, vector CameraLocation, rotator CameraRotation)
{
CalcViewActor = ViewActor;
if (ViewActor != None)
CalcViewActorLocation = ViewActor.Location;
CalcViewLocation = CameraLocation;
CalcViewRotation = CameraRotation;
LastPlayerCalcView = Level.TimeSeconds;
}
event PlayerCalcView(out actor ViewActor, out vector CameraLocation, out rotator CameraRotation )
{
local Pawn PTarget;
if ( LastPlayerCalcView == Level.TimeSeconds && CalcViewActor != None && CalcViewActor.Location == CalcViewActorLocation )
{
ViewActor = CalcViewActor;
CameraLocation = CalcViewLocation;
CameraRotation = CalcViewRotation;
return;
}
// If desired, call the pawn's own special callview
if( Pawn != None && Pawn.bSpecialCalcView && (ViewTarget == Pawn) )
{
// try the 'special' calcview. This may return false if its not applicable, and we do the usual.
if ( Pawn.SpecialCalcView(ViewActor, CameraLocation, CameraRotation) )
{
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
return;
}
}
if ( (ViewTarget == None) || ViewTarget.bDeleteMe )
{
if ( bViewBot && (CheatManager != None) )
CheatManager.ViewBot();
else if ( (Pawn != None) && !Pawn.bDeleteMe )
SetViewTarget(Pawn);
else if ( RealViewTarget != None )
SetViewTarget(RealViewTarget);
else
SetViewTarget(self);
}
ViewActor = ViewTarget;
CameraLocation = ViewTarget.Location;
if ( ViewTarget == Pawn )
{
if( bBehindView ) //up and behind
CalcBehindView(CameraLocation, CameraRotation, CameraDist * Pawn.Default.CollisionRadius);
else
CalcFirstPersonView( CameraLocation, CameraRotation );
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
return;
}
if ( ViewTarget == self )
{
if ( bCameraPositionLocked )
CameraRotation = CheatManager.LockedRotation;
else
CameraRotation = Rotation;
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
return;
}
if ( ViewTarget.IsA('Projectile') )
{
if ( Projectile(ViewTarget).bSpecialCalcView && Projectile(ViewTarget).SpecialCalcView(ViewActor, CameraLocation, CameraRotation, bBehindView) )
{
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
return;
}
if ( !bBehindView )
{
CameraLocation += (ViewTarget.CollisionHeight) * vect(0,0,1);
CameraRotation = Rotation;
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
return;
}
}
CameraRotation = ViewTarget.Rotation;
PTarget = Pawn(ViewTarget);
if ( PTarget != None )
{
if ( (Level.NetMode == NM_Client) || (bDemoOwner && (Level.NetMode != NM_Standalone)) )
{
PTarget.SetViewRotation(TargetViewRotation);
CameraRotation = BlendedTargetViewRotation;
PTarget.EyeHeight = TargetEyeHeight;
}
else if ( PTarget.IsPlayerPawn() )
CameraRotation = PTarget.GetViewRotation();
if (PTarget.bSpecialCalcView && PTarget.SpectatorSpecialCalcView(self, ViewActor, CameraLocation, CameraRotation))
{
CacheCalcView(ViewActor, CameraLocation, CameraRotation);
return;
}
if ( !bBehindView )
CameraLocation += PTarget.EyePosition();
}
if ( bBehindView )
{
CameraLocation = CameraLocation + (ViewTarget.Default.CollisionHeight - ViewTarget.CollisionHeight) * vect(0,0,1);
CalcBehindView(CameraLocation, CameraRotation, CameraDist * ViewTarget.Default.CollisionRadius);
}
CacheCalcView(ViewActor,CameraLocation,CameraRotation);
}
function int BlendRot(float DeltaTime, int BlendC, int NewC)
{
if ( Abs(BlendC - NewC) > 32767 )
{
if ( BlendC > NewC )
NewC += 65536;
else
BlendC += 65536;
}
if ( Abs(BlendC - NewC) > 4096 )
BlendC = NewC;
else
BlendC = BlendC + (NewC - BlendC) * FMin(1,24 * DeltaTime);
return (BlendC & 65535);
}
function CheckShake(out float MaxOffset, out float Offset, out float Rate, out float Time, float dt)
{
if ( abs(Offset) < abs(MaxOffset) )
return;
Offset = MaxOffset;
if ( Time > 1 )
{
if ( Time * abs(MaxOffset/Rate) <= 1 )
MaxOffset = MaxOffset * (1/Time - 1);
else
MaxOffset *= -1;
Time -= dt;
Rate *= -1;
}
else
{
MaxOffset = 0;
Offset = 0;
Rate = 0;
}
}
function UpdateShakeRotComponent(out float max, out int current, out float rate, out float time, float dt)
{
local float fCurrent;
current = ((current & 65535) + rate * dt) & 65535;
if ( current > 32768 )
current -= 65536;
fCurrent = current;
CheckShake(max, fCurrent, rate, time, dt);
current = fCurrent;
}
function ViewShake(float DeltaTime)
{
if ( ShakeOffsetRate != vect(0,0,0) )
{
// modify shake offset
ShakeOffset.X += DeltaTime * ShakeOffsetRate.X;
CheckShake(ShakeOffsetMax.X, ShakeOffset.X, ShakeOffsetRate.X, ShakeOffsetTime.X, DeltaTime);
ShakeOffset.Y += DeltaTime * ShakeOffsetRate.Y;
CheckShake(ShakeOffsetMax.Y, ShakeOffset.Y, ShakeOffsetRate.Y, ShakeOffsetTime.Y, DeltaTime);
ShakeOffset.Z += DeltaTime * ShakeOffsetRate.Z;
CheckShake(ShakeOffsetMax.Z, ShakeOffset.Z, ShakeOffsetRate.Z, ShakeOffsetTime.Z, DeltaTime);
}
if ( ShakeRotRate != vect(0,0,0) )
{
UpdateShakeRotComponent(ShakeRotMax.X, ShakeRot.Pitch, ShakeRotRate.X, ShakeRotTime.X, DeltaTime);
UpdateShakeRotComponent(ShakeRotMax.Y, ShakeRot.Yaw, ShakeRotRate.Y, ShakeRotTime.Y, DeltaTime);
UpdateShakeRotComponent(ShakeRotMax.Z, ShakeRot.Roll, ShakeRotRate.Z, ShakeRotTime.Z, DeltaTime);
}
}
function bool TurnTowardNearestEnemy();
function TurnAround()
{
if ( !bSetTurnRot )
{
TurnRot180 = Rotation;
TurnRot180.Yaw += 32768;
bSetTurnRot = true;
}
DesiredRotation = TurnRot180;
bRotateToDesired = ( DesiredRotation.Yaw != Rotation.Yaw );
}
function UpdateRotation(float DeltaTime, float maxPitch)
{
local rotator newRotation, ViewRotation;
if ( bInterpolating || ((Pawn != None) && Pawn.bInterpolating) )
{
ViewShake(deltaTime);
return;
}
// Added FreeCam control for better view control
if (bFreeCam == True)
{
if (bFreeCamZoom == True)
{
CameraDeltaRad += DeltaTime * 0.25 * aLookUp;
}
else if (bFreeCamSwivel == True)
{
CameraSwivel.Yaw += 16.0 * DeltaTime * aTurn;
CameraSwivel.Pitch += 16.0 * DeltaTime * aLookUp;
}
else
{
CameraDeltaRotation.Yaw += 32.0 * DeltaTime * aTurn;
CameraDeltaRotation.Pitch += 32.0 * DeltaTime * aLookUp;
}
}
else
{
ViewRotation = Rotation;
if(Pawn != None && Pawn.Physics != PHYS_Flying) // mmmmm
{
// Ensure we are not setting the pawn to a rotation beyond its desired
if( Pawn.DesiredRotation.Roll < 65535 &&
(ViewRotation.Roll < Pawn.DesiredRotation.Roll || ViewRotation.Roll > 0))
ViewRotation.Roll = 0;
else if( Pawn.DesiredRotation.Roll > 0 &&
(ViewRotation.Roll > Pawn.DesiredRotation.Roll || ViewRotation.Roll < 65535))
ViewRotation.Roll = 0;
}
DesiredRotation = ViewRotation; //save old rotation
if ( bTurnToNearest != 0 )
TurnTowardNearestEnemy();
else if ( bTurn180 != 0 )
TurnAround();
else
{
TurnTarget = None;
bRotateToDesired = false;
bSetTurnRot = false;
ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
}
if (Pawn != None)
ViewRotation.Pitch = Pawn.LimitPitch(ViewRotation.Pitch);
SetRotation(ViewRotation);
ViewShake(deltaTime);
ViewFlash(deltaTime);
NewRotation = ViewRotation;
//NewRotation.Roll = Rotation.Roll;
if ( !bRotateToDesired && (Pawn != None) && (!bFreeCamera || !bBehindView) )
Pawn.FaceRotation(NewRotation, deltatime);
}
}
function ClearDoubleClick()
{
if (PlayerInput != None)
PlayerInput.DoubleClickTimer = 0.0;
}
simulated function bool DodgingIsEnabled()
{
if ( PlayerInput != None )
return PlayerInput.bEnableDodging;
else if ( InputClass != None )
return InputClass.default.bEnableDodging;
else return class'Engine.PlayerInput'.default.bEnableDodging;
}
simulated function SetDodging( bool Enabled )
{
if( PlayerInput != None)
PlayerInput.bEnableDodging = Enabled;
InputClass.default.bEnableDodging = Enabled;
InputClass.static.StaticSaveConfig();
}
// Player movement.
// Player Standing, walking, running, falling.
state PlayerWalking
{
ignores SeePlayer, HearNoise, Bump;
function bool NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
{
if ( NewVolume.bWaterVolume )
GotoState(Pawn.WaterMovementState);
return false;
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local vector OldAccel;
local bool OldCrouch;
if ( Pawn == None )
return;
OldAccel = Pawn.Acceleration;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
if ( bDoubleJump && (bUpdating || Pawn.CanDoubleJump()) )
Pawn.DoDoubleJump(bUpdating);
else if ( bPressedJump )
Pawn.DoJump(bUpdating);
Pawn.SetViewPitch(Rotation.Pitch);
if ( Pawn.Physics != PHYS_Falling )
{
OldCrouch = Pawn.bWantsToCrouch;
if (bDuck == 0)
Pawn.ShouldCrouch(false);
else if ( Pawn.bCanCrouch )
Pawn.ShouldCrouch(true);
}
}
function PlayerMove( float DeltaTime )
{
local vector X,Y,Z, NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation, ViewRotation;
local bool bSaveJump;
if( Pawn == None )
{
GotoState('Dead'); // this was causing instant respawns in mp games
return;
}
GetAxes(Pawn.Rotation,X,Y,Z);
// Update acceleration.
NewAccel = aForward*X + aStrafe*Y;
NewAccel.Z = 0;
if ( VSize(NewAccel) < 1.0 )
NewAccel = vect(0,0,0);
DoubleClickMove = PlayerInput.CheckForDoubleClickMove(1.1*DeltaTime/Level.TimeDilation);
GroundPitch = 0;
ViewRotation = Rotation;
if ( Pawn.Physics == PHYS_Walking )
{
// tell pawn about any direction changes to give it a chance to play appropriate animation
//if walking, look up/down stairs - unless player is rotating view
if ( (bLook == 0)
&& (((Pawn.Acceleration != Vect(0,0,0)) && bSnapToLevel) || !bKeyboardLook) )
{
if ( bLookUpStairs || bSnapToLevel )
{
GroundPitch = FindStairRotation(deltaTime);
ViewRotation.Pitch = GroundPitch;
}
else if ( bCenterView )
{
ViewRotation.Pitch = ViewRotation.Pitch & 65535;
if (ViewRotation.Pitch > 32768)
ViewRotation.Pitch -= 65536;
ViewRotation.Pitch = ViewRotation.Pitch * (1 - 12 * FMin(0.0833, deltaTime));
if ( (Abs(ViewRotation.Pitch) < 250) && (ViewRotation.Pitch < 100) )
ViewRotation.Pitch = -249;
}
}
}
else
{
if ( !bKeyboardLook && (bLook == 0) && bCenterView )
{
ViewRotation.Pitch = ViewRotation.Pitch & 65535;
if (ViewRotation.Pitch > 32768)
ViewRotation.Pitch -= 65536;
ViewRotation.Pitch = ViewRotation.Pitch * (1 - 12 * FMin(0.0833, deltaTime));
if ( (Abs(ViewRotation.Pitch) < 250) && (ViewRotation.Pitch < 100) )
ViewRotation.Pitch = -249;
}
}
Pawn.CheckBob(DeltaTime, Y);
// Update rotation.
SetRotation(ViewRotation);
OldRotation = Rotation;
UpdateRotation(DeltaTime, 1);
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;
}
function BeginState()
{
DoubleClickDir = DCLICK_None;
bPressedJump = false;
GroundPitch = 0;
if ( Pawn != None )
{
if ( Pawn.Mesh == None )
Pawn.SetMesh();
Pawn.ShouldCrouch(false);
if (Pawn.Physics != PHYS_Falling && Pawn.Physics != PHYS_Karma) // FIXME HACK!!!
Pawn.SetPhysics(PHYS_Walking);
}
}
function EndState()
{
GroundPitch = 0;
if ( Pawn != None && bDuck==0 )
Pawn.ShouldCrouch(false);
}
Begin:
}
// player is climbing ladder
state PlayerClimbing
{
ignores SeePlayer, HearNoise, Bump;
function bool NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
{
if ( NewVolume.bWaterVolume )
GotoState(Pawn.WaterMovementState);
else
GotoState(Pawn.LandMovementState);
return false;
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local vector OldAccel;
OldAccel = Pawn.Acceleration;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
if ( bPressedJump )
{
Pawn.DoJump(bUpdating);
if ( Pawn.Physics == PHYS_Falling )
GotoState('PlayerWalking');
}
}
function PlayerMove( float DeltaTime )
{
local vector X,Y,Z, NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation, ViewRotation;
local bool bSaveJump;
GetAxes(Rotation,X,Y,Z);
// Update acceleration.
if ( Pawn.OnLadder != None )
{
NewAccel = aForward*Pawn.OnLadder.ClimbDir;
if ( Pawn.OnLadder.bAllowLadderStrafing )
NewAccel += aStrafe*Y;
}
else
NewAccel = aForward*X + aStrafe*Y;
if ( VSize(NewAccel) < 1.0 )
NewAccel = vect(0,0,0);
ViewRotation = Rotation;
// Update rotation.
SetRotation(ViewRotation);
OldRotation = Rotation;
UpdateRotation(DeltaTime, 1);
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;
}
function BeginState()
{
Pawn.ShouldCrouch(false);
Pawn.ShouldProne(false);
bPressedJump = false;
}
function EndState()
{
if ( Pawn != None )
{
Pawn.ShouldCrouch(false);
Pawn.ShouldProne(false);
}
}
}
// Player movement.
// Player Driving a Karma vehicle.
state PlayerDriving
{
ignores SeePlayer, HearNoise, Bump;
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
}
// Set the throttle, steering etc. for the vehicle based on the input provided
function ProcessDrive(float InForward, float InStrafe, float InUp, bool InJump)
{
local Vehicle CurrentVehicle;
CurrentVehicle = Vehicle(Pawn);
if(CurrentVehicle == None)
return;
//log("Forward:"@InForward@" Strafe:"@InStrafe@" Up:"@InUp);
CurrentVehicle.Throttle = FClamp( InForward/5000.0, -1.0, 1.0 );
CurrentVehicle.Steering = FClamp( -InStrafe/5000.0, -1.0, 1.0 );
CurrentVehicle.Rise = FClamp( InUp/5000.0, -1.0, 1.0 );
}
function PlayerMove( float DeltaTime )
{
local Vehicle CurrentVehicle;
local float NewPing;
CurrentVehicle = Vehicle(Pawn);
// update 'looking' rotation
UpdateRotation(DeltaTime, 2);
// TODO: Don't send things like aForward and aStrafe for gunners who don't need it
// Only servers can actually do the driving logic.
if (Role < ROLE_Authority )
{
if ( (Level.TimeSeconds - LastPingUpdate > 4) && (PlayerReplicationInfo != None) && !bDemoOwner )
{
LastPingUpdate = Level.TimeSeconds;
NewPing = float(ConsoleCommand("GETPING"));
if ( ExactPing < 0.006 )
ExactPing = FMin(0.1,0.001 * NewPing);
else
ExactPing = 0.99 * ExactPing + 0.0001 * NewPing;
PlayerReplicationInfo.Ping = Min(250.0 * ExactPing, 255);
PlayerReplicationInfo.bReceivedPing = true;
OldPing = ExactPing;
ServerUpdatePing(1000 * ExactPing);
}
if (!bSkippedLastUpdate && // in order to skip this update we must not have skipped the last one
(Player.CurrentNetSpeed < 10000) && // and netspeed must be low
(Level.TimeSeconds - ClientUpdateTime < 0.0222) && // and time since last update must be short
bPressedJump == bLastPressedJump && // and update must not contain major changes
aUp - aLastUp < 0.01 && // "
aForward - aLastForward < 0.01 && // "
aStrafe - aLastStrafe < 0.01 // "
)
{
// log("!bSkippedLastUpdate: "$!bSkippedLastUpdate);
// log("(Player.CurrentNetSpeed < 10000): "$(Player.CurrentNetSpeed < 10000));
// log("(Level.TimeSeconds - ClientUpdateTime < 0.0222): "$(Level.TimeSeconds - ClientUpdateTime < 0.0222)$" - "$Level.TimeSeconds - ClientUpdateTime);
// log("bPressedJump == bLastPressedJump: "$bPressedJump == bLastPressedJump);
// log("aUp - aLastUp < 0.01: "$aUp - aLastUp < 0.01);
// log("aForward - aLastForward < 0.01: "$aForward - aLastForward < 0.01);
// log("aStrafe - aLastStrafe < 0.01: "$aStrafe - aLastStrafe < 0.01);
bSkippedLastUpdate = True;
return;
}
else
{
bSkippedLastUpdate = False;
ClientUpdateTime = Level.TimeSeconds;
// Save Move
bLastPressedJump = bPressedJump;
aLastUp = aUp;
aLastForward = aForward;
aLastStrafe = aStrafe;
if (CurrentVehicle != None)
{
CurrentVehicle.Throttle = FClamp( aForward/5000.0, -1.0, 1.0 );
CurrentVehicle.Steering = FClamp( -aStrafe/5000.0, -1.0, 1.0 );
CurrentVehicle.Rise = FClamp( aUp/5000.0, -1.0, 1.0 );
}
ServerDrive(aForward, aStrafe, aUp, bPressedJump, (32767 & (Rotation.Pitch/2)) * 32768 + (32767 & (Rotation.Yaw/2)));
}
}
else
ProcessDrive(aForward, aStrafe, aUp, bPressedJump);
// If the vehicle is being controlled here - set replicated variables.
if (CurrentVehicle != None)
{
if(bFire == 0 && CurrentVehicle.bWeaponIsFiring)
CurrentVehicle.ClientVehicleCeaseFire(False);
if(bAltFire == 0 && CurrentVehicle.bWeaponIsAltFiring)
CurrentVehicle.ClientVehicleCeaseFire(True);
}
}
function BeginState()
{
PlayerReplicationInfo.bReceivedPing = false;
CleanOutSavedMoves();
}
function EndState()
{
CleanOutSavedMoves();
}
}
// Player movement.
// Player walking on walls
state PlayerSpidering
{
ignores SeePlayer, HearNoise, Bump;
event bool NotifyHitWall(vector HitNormal, actor HitActor)
{
Pawn.SetPhysics(PHYS_Spider);
Pawn.SetBase(HitActor, HitNormal);
return true;
}
// if spider mode, update rotation based on floor
function UpdateRotation(float DeltaTime, float maxPitch)
{
local rotator ViewRotation;
local vector MyFloor, CrossDir, FwdDir, OldFwdDir, OldX, RealFloor;
if ( bInterpolating || Pawn.bInterpolating )
{
ViewShake(deltaTime);
return;
}
TurnTarget = None;
bRotateToDesired = false;
bSetTurnRot = false;
if ( (Pawn.Base == None) || (Pawn.Floor == vect(0,0,0)) )
MyFloor = vect(0,0,1);
else
MyFloor = Pawn.Floor;
if ( MyFloor != OldFloor )
{
// smoothly change floor
RealFloor = MyFloor;
MyFloor = Normal(6*DeltaTime * MyFloor + (1 - 6*DeltaTime) * OldFloor);
if ( (RealFloor Dot MyFloor) > 0.999 )
MyFloor = RealFloor;
else
{
// translate view direction
CrossDir = Normal(RealFloor Cross OldFloor);
FwdDir = CrossDir Cross MyFloor;
OldFwdDir = CrossDir Cross OldFloor;
ViewX = MyFloor * (OldFloor Dot ViewX)
+ CrossDir * (CrossDir Dot ViewX)
+ FwdDir * (OldFwdDir Dot ViewX);
ViewX = Normal(ViewX);
ViewZ = MyFloor * (OldFloor Dot ViewZ)
+ CrossDir * (CrossDir Dot ViewZ)
+ FwdDir * (OldFwdDir Dot ViewZ);
ViewZ = Normal(ViewZ);
OldFloor = MyFloor;
ViewY = Normal(MyFloor Cross ViewX);
}
}
if ( (aTurn != 0) || (aLookUp != 0) )
{
// adjust Yaw based on aTurn
if ( aTurn != 0 )
ViewX = Normal(ViewX + 2 * ViewY * Sin(0.0005*DeltaTime*aTurn));
// adjust Pitch based on aLookUp
if ( aLookUp != 0 )
{
OldX = ViewX;
ViewX = Normal(ViewX + 2 * ViewZ * Sin(0.0005*DeltaTime*aLookUp));
ViewZ = Normal(ViewX Cross ViewY);
// bound max pitch
if ( (ViewZ Dot MyFloor) < 0.707 )
{
OldX = Normal(OldX - MyFloor * (MyFloor Dot OldX));
if ( (ViewX Dot MyFloor) > 0)
ViewX = Normal(OldX + MyFloor);
else
ViewX = Normal(OldX - MyFloor);
ViewZ = Normal(ViewX Cross ViewY);
}
}
// calculate new Y axis
ViewY = Normal(MyFloor Cross ViewX);
}
ViewRotation = OrthoRotation(ViewX,ViewY,ViewZ);
SetRotation(ViewRotation);
ViewShake(deltaTime);
ViewFlash(deltaTime);
Pawn.FaceRotation(ViewRotation, deltaTime );
}
function bool NotifyLanded(vector HitNormal)
{
Pawn.SetPhysics(PHYS_Spider);
return bUpdating;
}
function bool NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
{
if ( NewVolume.bWaterVolume )
GotoState(Pawn.WaterMovementState);
return false;
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local vector OldAccel;
OldAccel = Pawn.Acceleration;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
if ( bPressedJump )
Pawn.DoJump(bUpdating);
}
function PlayerMove( float DeltaTime )
{
local vector NewAccel;
local eDoubleClickDir DoubleClickMove;
local rotator OldRotation, ViewRotation;
local bool bSaveJump;
GroundPitch = 0;
ViewRotation = Rotation;
Pawn.CheckBob(DeltaTime,vect(0,0,0));
// Update rotation.
SetRotation(ViewRotation);
OldRotation = Rotation;
UpdateRotation(DeltaTime, 1);
// Update acceleration.
NewAccel = aForward*Normal(ViewX - OldFloor * (OldFloor Dot ViewX)) + aStrafe*ViewY;
if ( VSize(NewAccel) < 1.0 )
NewAccel = vect(0,0,0);
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;
}
function BeginState()
{
if ( Pawn.Mesh == None )
Pawn.SetMesh();
OldFloor = vect(0,0,1);
GetAxes(Rotation,ViewX,ViewY,ViewZ);
DoubleClickDir = DCLICK_None;
Pawn.ShouldCrouch(false);
Pawn.ShouldProne(false);
bPressedJump = false;
if (Pawn.Physics != PHYS_Falling)
Pawn.SetPhysics(PHYS_Spider);
GroundPitch = 0;
Pawn.bCrawler = true;
Pawn.SetCollisionSize(Pawn.Default.CollisionHeight,Pawn.Default.CollisionHeight);
}
function EndState()
{
GroundPitch = 0;
if ( Pawn != None )
{
Pawn.SetCollisionSize(Pawn.Default.CollisionRadius,Pawn.Default.CollisionHeight);
Pawn.ShouldCrouch(false);
Pawn.ShouldProne(false);
Pawn.bCrawler = Pawn.Default.bCrawler;
}
}
}
// Player movement.
// Player Swimming
state PlayerSwimming
{
ignores SeePlayer, HearNoise, Bump;
function bool WantsSmoothedView()
{
return ( !Pawn.bJustLanded );
}
function bool NotifyLanded(vector HitNormal)
{
if ( Pawn.PhysicsVolume.bWaterVolume )
Pawn.SetPhysics(PHYS_Swimming);
else
GotoState(Pawn.LandMovementState);
return bUpdating;
}
function bool NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
{
local actor HitActor;
local vector HitLocation, HitNormal, checkpoint;
if ( !NewVolume.bWaterVolume )
{
Pawn.SetPhysics(PHYS_Falling);
if ( Pawn.Velocity.Z > 0 )
{
if (Pawn.bUpAndOut && Pawn.CheckWaterJump(HitNormal)) //check for waterjump
{
Pawn.velocity.Z = FMax(Pawn.JumpZ,420) + 2 * Pawn.CollisionRadius; //set here so physics uses this for remainder of tick
GotoState(Pawn.LandMovementState);
}
else if ( (Pawn.Velocity.Z > 160) || !Pawn.TouchingWaterVolume() )
GotoState(Pawn.LandMovementState);
else //check if in deep water
{
checkpoint = Pawn.Location;
checkpoint.Z -= (Pawn.CollisionHeight + 6.0);
HitActor = Trace(HitLocation, HitNormal, checkpoint, Pawn.Location, false);
if (HitActor != None)
GotoState(Pawn.LandMovementState);
else
{
Enable('Timer');
SetTimer(0.7,false);
}
}
}
}
else
{
Disable('Timer');
Pawn.SetPhysics(PHYS_Swimming);
}
return false;
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
local vector X,Y,Z, OldAccel;
local bool bUpAndOut;
GetAxes(Rotation,X,Y,Z);
OldAccel = Pawn.Acceleration;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
bUpAndOut = ((X Dot Pawn.Acceleration) > 0) && ((Pawn.Acceleration.Z > 0) || (Rotation.Pitch > 2048));
if ( Pawn.bUpAndOut != bUpAndOut )
Pawn.bUpAndOut = bUpAndOut;
if ( !Pawn.PhysicsVolume.bWaterVolume ) //check for waterjump
NotifyPhysicsVolumeChange(Pawn.PhysicsVolume);
}
function PlayerMove(float DeltaTime)
{
local rotator oldRotation;
local vector X,Y,Z, NewAccel;
GetAxes(Rotation,X,Y,Z);
NewAccel = aForward*X + aStrafe*Y + aUp*vect(0,0,1);
if ( VSize(NewAccel) < 1.0 )
NewAccel = vect(0,0,0);
//add bobbing when swimming
Pawn.CheckBob(DeltaTime, Y);
// Update rotation.
oldRotation = Rotation;
UpdateRotation(DeltaTime, 2);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, NewAccel, DCLICK_None, OldRotation - Rotation);
else
ProcessMove(DeltaTime, NewAccel, DCLICK_None, OldRotation - Rotation);
bPressedJump = false;
}
function Timer()
{
if ( !Pawn.PhysicsVolume.bWaterVolume && (Role == ROLE_Authority) )
GotoState(Pawn.LandMovementState);
Disable('Timer');
}
function BeginState()
{
Disable('Timer');
Pawn.SetPhysics(PHYS_Swimming);
// This ensures we don't get stuck viewing someone else when we respawn
// if _RO_
if( Role==ROLE_Authority )
{
if( Pawn!=none )
{
SetViewTarget(Pawn);
ClientSetViewTarget(Pawn);
}
else
{
SetViewTarget(self);
ClientSetViewTarget(self);
}
ClientSetBehindView(false);
}
// end RO
}
}
state PlayerFlying
{
ignores SeePlayer, HearNoise, Bump;
function PlayerMove(float DeltaTime)
{
local vector X,Y,Z;
GetAxes(Rotation,X,Y,Z);
Pawn.Acceleration = aForward*X + aStrafe*Y;
if ( VSize(Pawn.Acceleration) < 1.0 )
Pawn.Acceleration = vect(0,0,0);
if ( bCheatFlying && (Pawn.Acceleration == vect(0,0,0)) )
Pawn.Velocity = vect(0,0,0);
// Update rotation.
UpdateRotation(DeltaTime, 2);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
}
function BeginState()
{
Pawn.SetPhysics(PHYS_Flying);
}
}
state PlayerSpaceFlying
{
ignores SeePlayer, HearNoise, Bump;
function CallServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbRun,
bool NewbDuck,
bool NewbPendingJumpStatus,
bool NewbJumpStatus,
bool NewbSprint,
bool NewbCrawl,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
local Rotator ViewRot;
if ( Pawn == None )
ViewRot = Rotation;
else
ViewRot = Pawn.Rotation;
if ( PendingMove != None )
{
DualSpaceFighterServerMove
(
PendingMove.TimeStamp,
PendingMove.Acceleration * 10,
PendingMove.bDuck,
PendingMove.Rotation.Pitch,
PendingMove.Rotation.Yaw,
PendingMove.Rotation.Roll,
TimeStamp,
InAccel,
ClientLoc,
NewbDuck,
ViewRot.Pitch,
ViewRot.Yaw,
ViewRot.Roll
);
}
else
SpaceFighterServerMove
(
TimeStamp,
InAccel,
ClientLoc,
NewbDuck,
ViewRot.Pitch,
ViewRot.Yaw,
ViewRot.Roll
);
}
/* ServerMove()
- replicated function sent by client to server - contains client movement and firing info
Passes acceleration in components so it doesn't get rounded.
IGNORE VANILLA SERVER MOVES
*/
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
// If this move is outdated, discard it.
if ( CurrentTimeStamp >= TimeStamp )
return;
if ( AcknowledgedPawn != Pawn )
{
OldTimeDelta = 0;
InAccel = vect(0,0,0);
}
else
Pawn.AutonomousPhysics(TimeStamp - CurrentTimeStamp);
CurrentTimeStamp = TimeStamp;
ServerTimeStamp = Level.TimeSeconds;
}
function PlayerMove(float DeltaTime)
{
if ( Pawn == None )
{
GotoState('dead');
return;
}
Pawn.UpdateRocketAcceleration(DeltaTime, aTurn, aLookUp);
SetRotation( Pawn.Rotation );
ViewShake( DeltaTime );
ViewFlash( DeltaTime );
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, Pawn.Acceleration, DCLICK_None, Pawn.Rotation );
else
ProcessMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if ( Pawn == None )
return;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
if ( DeltaRot != rot(0,0,0) )
{
if ( Pawn.Rotation != DeltaRot )
Pawn.SetRotation( DeltaRot );
if ( Rotation != DeltaRot )
SetRotation( DeltaRot );
}
Pawn.Velocity = Pawn.Acceleration * Pawn.AirSpeed * 0.001;
Pawn.ProcessMove(DeltaTime, NewAccel, DoubleClickMove, DeltaRot);
}
function BeginState()
{
if ( Pawn != None )
Pawn.SetPhysics( PHYS_Flying );
RotationRate.Pitch = 8192; // extending pitch limit
bIsSpaceFighter = true;
}
function EndState()
{
RotationRate.Pitch = default.RotationRate.Pitch; // restoring pitch limit
bIsSpaceFighter = false;
}
}
state PlayerRocketing
{
ignores SeePlayer, HearNoise, Bump;
function CallServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbRun,
bool NewbDuck,
bool NewbPendingJumpStatus,
bool NewbJumpStatus,
bool NewbSprint,
bool NewbCrawl,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
if ( PendingMove != None )
{
DualRocketServerMove
(
PendingMove.TimeStamp,
PendingMove.Acceleration * 10,
PendingMove.bDuck,
((PendingMove.Rotation.Roll >> 8) & 255),
(32767 & (PendingMove.Rotation.Pitch/2)) * 32768 + (32767 & (PendingMove.Rotation.Yaw/2)),
TimeStamp,
InAccel,
ClientLoc,
NewbDuck,
ClientRoll,
View
);
}
else
{
RocketServerMove
(
TimeStamp,
InAccel,
ClientLoc,
NewbDuck,
ClientRoll,
View
);
}
}
/* ServerMove()
- replicated function sent by client to server - contains client movement and firing info
Passes acceleration in components so it doesn't get rounded.
IGNORE VANILLA SERVER MOVES
*/
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
// If this move is outdated, discard it.
if ( CurrentTimeStamp >= TimeStamp )
return;
if ( !CheckSpeedHack(TimeStamp - CurrentTimeStamp) )
{
if ( !bWasSpeedHack )
{
if ( Level.TimeSeconds - LastSpeedHackLog > 20 )
{
log("Possible speed hack by "$PlayerReplicationInfo.PlayerName);
LastSpeedHackLog = Level.TimeSeconds;
}
ClientMessage( "Speed Hack Detected!",'CriticalEvent' );
}
else
bWasSpeedHack = true;
}
else
{
if ( AcknowledgedPawn != Pawn )
{
OldTimeDelta = 0;
InAccel = vect(0,0,0);
}
else
Pawn.AutonomousPhysics(TimeStamp - CurrentTimeStamp);
}
CurrentTimeStamp = TimeStamp;
ServerTimeStamp = Level.TimeSeconds;
}
function RocketServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View
)
{
local byte NewActions;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
Global.ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View);
}
function DualRocketServerMove
(
float TimeStamp0,
vector InAccel0,
bool NewbDuck0,
byte ClientRoll0,
int View0,
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View
)
{
local byte NewActions, NewActions0;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
if (NewbDuck0)
NewActions0 += 2;
Global.ServerMove(TimeStamp0,InAccel0,vect(0,0,0),NewActions0, DCLICK_NONE,ClientRoll0,View0);
Global.ServerMove(TimeStamp,InAccel,ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View);
}
function PlayerMove(float DeltaTime)
{
Pawn.UpdateRocketAcceleration(DeltaTime,aTurn,aLookUp);
SetRotation(Pawn.Rotation);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if ( Pawn == None )
return;
if ( Pawn.Acceleration != NewAccel )
Pawn.Acceleration = NewAccel;
}
function BeginState()
{
if ( Pawn != None )
Pawn.SetPhysics( PHYS_Flying );
RotationRate.Pitch = 8192; // extending pitch limit (limits network weapon aiming)
}
function EndState()
{
RotationRate.Pitch = default.RotationRate.Pitch; // restoring pitch limit
}
}
state PlayerTurreting
{
ignores SeePlayer, HearNoise, Bump;
function CallServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
bool NewbRun,
bool NewbDuck,
bool NewbPendingJumpStatus,
bool NewbJumpStatus,
bool NewbSprint,
bool NewbCrawl,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
if ( PendingMove != None )
{
DualTurretServerMove
(
PendingMove.TimeStamp,
PendingMove.bDuck,
((PendingMove.Rotation.Roll >> 8) & 255),
(32767 & (PendingMove.Rotation.Pitch/2)) * 32768 + (32767 & (PendingMove.Rotation.Yaw/2)),
TimeStamp,
ClientLoc,
NewbDuck,
ClientRoll,
View
);
}
else
TurretServerMove
(
TimeStamp,
ClientLoc,
NewbDuck,
ClientRoll,
View
);
}
/* ServerMove()
- replicated function sent by client to server - contains client movement and firing info
Passes acceleration in components so it doesn't get rounded.
IGNORE VANILLA SERVER MOVES
*/
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
// If this move is outdated, discard it.
if ( CurrentTimeStamp >= TimeStamp )
return;
if ( AcknowledgedPawn != Pawn )
{
OldTimeDelta = 0;
InAccel = vect(0,0,0);
}
if ( AcknowledgedPawn == Pawn && CurrentTimeStamp < TimeStamp )
Pawn.AutonomousPhysics(TimeStamp - CurrentTimeStamp);
CurrentTimeStamp = TimeStamp;
ServerTimeStamp = Level.TimeSeconds;
}
function TurretServerMove
(
float TimeStamp,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View,
optional int FreeAimRot
)
{
local byte NewActions;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
Global.ServerMove(TimeStamp,Vect(0,0,0),ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View,FreeAimRot);
}
/* DualTurretServerMove()
compressed version of server move for PlayerTurreting state
*/
function DualTurretServerMove
(
float TimeStamp0,
bool NewbDuck0,
byte ClientRoll0,
int View0,
float TimeStamp,
vector ClientLoc,
bool NewbDuck,
byte ClientRoll,
int View,
optional int FreeAimRot
)
{
local byte NewActions, NewActions0;
// Put together new actions to send (compressed into one byte)
if (NewbDuck)
NewActions += 2;
if (NewbDuck0)
NewActions0 += 2;
Global.ServerMove(TimeStamp0,Vect(0,0,0),vect(0,0,0),NewActions0, DCLICK_NONE,ClientRoll0,View0,FreeAimRot);
Global.ServerMove(TimeStamp,Vect(0,0,0),ClientLoc,NewActions, DCLICK_NONE,ClientRoll,View,FreeAimRot);
}
function PlayerMove(float DeltaTime)
{
local Vehicle CurrentVehicle;
if ( Pawn == None )
{
GotoState('dead');
return;
}
Pawn.UpdateRocketAcceleration(DeltaTime, aTurn, aLookUp);
if ( !bFreeCamera )
SetRotation( Pawn.Rotation );
ViewShake( deltaTime );
ViewFlash( deltaTime );
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
CurrentVehicle = Vehicle(Pawn);
if ( CurrentVehicle != None )
{
if ( bFire == 0 && CurrentVehicle.bWeaponIsFiring )
CurrentVehicle.ClientVehicleCeaseFire( false );
if ( bAltFire == 0 && CurrentVehicle.bWeaponIsAltFiring )
CurrentVehicle.ClientVehicleCeaseFire( true );
}
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
if ( Pawn == None )
return;
Pawn.Acceleration = newAccel;
}
function BeginState()
{
if ( Pawn != None )
Pawn.SetPhysics( PHYS_Flying );
RotationRate.Pitch = 16384; // extending pitch limit (limits network weapon aiming)
}
function EndState()
{
RotationRate.Pitch = default.RotationRate.Pitch; // restoring pitch limit
}
Begin:
}
function bool IsSpectating()
{
return false;
}
state BaseSpectating
{
function bool IsSpectating()
{
return true;
}
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
{
Acceleration = NewAccel;
MoveSmooth(SpectateSpeed * Normal(Acceleration) * DeltaTime);
}
function PlayerMove(float DeltaTime)
{
local vector X,Y,Z;
if ( (Pawn(ViewTarget) != None) && (Level.NetMode == NM_Client) )
{
if ( Pawn(ViewTarget).bSimulateGravity )
TargetViewRotation.Roll = 0;
BlendedTargetViewRotation.Pitch = BlendRot(DeltaTime, BlendedTargetViewRotation.Pitch, TargetViewRotation.Pitch & 65535);
BlendedTargetViewRotation.Yaw = BlendRot(DeltaTime, BlendedTargetViewRotation.Yaw, TargetViewRotation.Yaw & 65535);
BlendedTargetViewRotation.Roll = BlendRot(DeltaTime, BlendedTargetViewRotation.Roll, TargetViewRotation.Roll & 65535);
}
GetAxes(Rotation,X,Y,Z);
Acceleration = 0.02 * (aForward*X + aStrafe*Y + aUp*vect(0,0,1));
UpdateRotation(DeltaTime, 1);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, Acceleration, DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, Acceleration, DCLICK_None, rot(0,0,0));
}
}
state Scripting
{
// FIXME - IF HIT FIRE, AND NOT bInterpolating, Leave script
exec function Fire( optional float F )
{
}
exec function AltFire( optional float F )
{
Fire(F);
}
}
function ServerViewNextPlayer()
{
local Controller C, Pick;
local bool bFound, bRealSpec, bWasSpec;
local TeamInfo RealTeam;
if( !IsInState('Spectating') )
{
return;
}
bRealSpec = PlayerReplicationInfo.bOnlySpectator;
bWasSpec = !bBehindView && (ViewTarget != Pawn) && (ViewTarget != self);
PlayerReplicationInfo.bOnlySpectator = true;
RealTeam = PlayerReplicationInfo.Team;
// view next player
for ( C=Level.ControllerList; C!=None; C=C.NextController )
{
if ( bRealSpec && (C.PlayerReplicationInfo != None) ) // hack fix for invasion spectating
PlayerReplicationInfo.Team = C.PlayerReplicationInfo.Team;
if ( Level.Game.CanSpectate(self,bRealSpec,C) )
{
if ( Pick == None )
Pick = C;
if ( bFound )
{
Pick = C;
break;
}
else
bFound = ( (RealViewTarget == C) || (ViewTarget == C) );
}
}
PlayerReplicationInfo.Team = RealTeam;
SetViewTarget(Pick);
ClientSetViewTarget(Pick);
if ( (ViewTarget == self) || bWasSpec )
bBehindView = false;
else
bBehindView = true; //bChaseCam;
ClientSetBehindView(bBehindView);
PlayerReplicationInfo.bOnlySpectator = bRealSpec;
}
function ServerViewSelf()
{
SetLocation(ViewTarget.Location);
ClientSetLocation(ViewTarget.Location, Rotation);
bBehindView = false;
SetViewTarget(self);
ClientSetViewTarget(self);
ClientMessage(OwnCamera, 'Event');
}
function LoadPlayers()
{
local int i;
if ( GameReplicationInfo == None )
return;
for ( i=0; i<GameReplicationInfo.PRIArray.Length; i++ )
GameReplicationInfo.PRIArray[i].UpdatePrecacheMaterials();
}
function ServerSpectate()
{
// Proper fix for phantom pawns
if (Pawn != none && !Pawn.bDeleteMe)
{
Pawn.Died(self, class'DamageType', Pawn.Location);
}
GotoState('Spectating');
bBehindView = true;
ServerViewNextPlayer();
}
//active player wants to become a spectator
function BecomeSpectator()
{
if (Role < ROLE_Authority)
return;
if ( !Level.Game.BecomeSpectator(self) )
return;
if ( Pawn != None )
Pawn.Died(self, class'DamageType', Pawn.Location);
if ( PlayerReplicationInfo.Team != None )
PlayerReplicationInfo.Team.RemoveFromTeam(self);
PlayerReplicationInfo.Team = None;
PlayerReplicationInfo.Score = 0;
PlayerReplicationInfo.Deaths = 0;
PlayerReplicationInfo.GoalsScored = 0;
PlayerReplicationInfo.Kills = 0;
ServerSpectate();
// if _RO_
BroadcastLocalizedMessage(class'GameMessage', 14, PlayerReplicationInfo);
// else
// BroadcastLocalizedMessage(Level.Game.GameMessageClass, 14, PlayerReplicationInfo);
// end if _RO_
ClientBecameSpectator();
}
function ClientBecameSpectator()
{
// if _RO_
UpdateURL("SpectatorOnly", "1", false);
// else
// UpdateURL("SpectatorOnly", "1", true);
// end if _RO_
}
//spectating player wants to become active and join the game
function BecomeActivePlayer()
{
if (Role < ROLE_Authority)
return;
if ( !Level.Game.AllowBecomeActivePlayer(self) )
return;
bBehindView = false;
FixFOV();
SetViewDistance();
ServerViewSelf();
PlayerReplicationInfo.bOnlySpectator = false;
Level.Game.NumSpectators--;
Level.Game.NumPlayers++;
PlayerReplicationInfo.Reset();
Adrenaline = 0;
BroadcastLocalizedMessage(Level.Game.GameMessageClass, 1, PlayerReplicationInfo);
if (Level.Game.bTeamGame)
Level.Game.ChangeTeam(self, Level.Game.PickTeam(int(GetURLOption("Team")), None), false);
if (!Level.Game.bDelayedStart)
{
// start match, or let player enter, immediately
Level.Game.bRestartLevel = false; // let player spawn once in levels that must be restarted after every death
if (Level.Game.bWaitingToStartMatch)
Level.Game.StartMatch();
else
Level.Game.RestartPlayer(PlayerController(Owner));
Level.Game.bRestartLevel = Level.Game.Default.bRestartLevel;
}
else
GotoState('PlayerWaiting');
ClientBecameActivePlayer();
}
function ClientBecameActivePlayer()
{
UpdateURL("SpectatorOnly","",true);
}
state Spectating extends BaseSpectating
{
ignores SwitchWeapon, RestartLevel, ClientRestart, Suicide,
ThrowWeapon, NotifyPhysicsVolumeChange, NotifyHeadVolumeChange;
exec function Fire( optional float F )
{
if ( bFrozen )
{
if ( (TimerRate <= 0.0) || (TimerRate > 1.0) )
bFrozen = false;
return;
}
ServerViewNextPlayer();
}
// Return to spectator's own camera.
exec function AltFire( optional float F )
{
bBehindView = false;
ServerViewSelf();
}
function Timer()
{
bFrozen = false;
}
function BeginState()
{
if ( Pawn != None )
{
SetLocation(Pawn.Location);
UnPossess();
}
bCollideWorld = true;
CameraDist = Default.CameraDist;
}
function EndState()
{
PlayerReplicationInfo.bIsSpectator = false;
bCollideWorld = false;
}
}
state AttractMode extends Spectating
{
}
auto state PlayerWaiting extends BaseSpectating
{
ignores SeePlayer, HearNoise, NotifyBump, TakeDamage, PhysicsVolumeChange, NextWeapon, PrevWeapon, SwitchToBestWeapon;
exec function Jump( optional float F )
{
}
exec function Suicide()
{
}
function ServerRestartPlayer()
{
if ( Level.TimeSeconds < WaitDelay )
return;
if ( Level.NetMode == NM_Client )
return;
if ( Level.Game.bWaitingToStartMatch )
PlayerReplicationInfo.bReadyToPlay = true;
else
Level.Game.RestartPlayer(self);
}
exec function Fire(optional float F)
{
LoadPlayers();
if ( !bForcePrecache && (Level.TimeSeconds > 0.2) )
ServerReStartPlayer();
}
exec function AltFire(optional float F)
{
Fire(F);
}
function EndState()
{
if ( Pawn != None )
Pawn.SetMesh();
if ( PlayerReplicationInfo != None )
PlayerReplicationInfo.SetWaitingPlayer(false);
bCollideWorld = false;
}
function BeginState()
{
CameraDist = Default.CameraDist;
if ( PlayerReplicationInfo != None )
PlayerReplicationInfo.SetWaitingPlayer(true);
bCollideWorld = true;
}
}
state WaitingForPawn extends BaseSpectating
{
ignores SeePlayer, HearNoise, KilledBy, SwitchWeapon;
exec function Fire( optional float F )
{
AskForPawn();
}
exec function AltFire( optional float F )
{
}
function LongClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
float NewVelX,
float NewVelY,
float NewVelZ,
Actor NewBase,
float NewFloorX,
float NewFloorY,
float NewFloorZ
)
{
if ( newState == 'GameEnded' || newState == 'RoundEnded' )
GotoState(newState);
}
function PlayerTick(float DeltaTime)
{
Global.PlayerTick(DeltaTime);
if ( Pawn != None )
{
Pawn.Controller = self;
Pawn.bUpdateEyeHeight = true;
//log("Client restart in waitingforpawn");
ClientRestart(Pawn);
}
else if ( (TimerRate <= 0.0) || (TimerRate > 1.0) )
{
SetTimer(0.2,true);
AskForPawn();
}
}
function Timer()
{
AskForPawn();
}
function BeginState()
{
SetTimer(0.2, true);
AskForPawn();
}
function EndState()
{
bBehindView = false;
SetTimer(0.0, false);
}
}
state GameEnded
{
ignores SeePlayer, HearNoise, KilledBy, NotifyBump, HitWall, NotifyHeadVolumeChange, NotifyPhysicsVolumeChange, Falling, TakeDamage, Suicide;
function ServerReStartPlayer()
{
}
function bool IsSpectating()
{
return true;
}
exec function Use() {}
exec function SwitchWeapon(byte T) {}
exec function ThrowWeapon() {}
function Possess(Pawn aPawn)
{
Global.Possess(aPawn);
if (Pawn != None)
Pawn.TurnOff();
}
function ServerReStartGame()
{
if ( Level.Game.PlayerCanRestartGame( Self ) )
Level.Game.RestartGame();
}
exec function Fire( optional float F )
{
if ( Role < ROLE_Authority)
return;
if ( !bFrozen )
ServerReStartGame();
else if ( TimerRate <= 0 )
SetTimer(1.5, false);
}
exec function AltFire( optional float F )
{
Fire(F);
}
function PlayerMove(float DeltaTime)
{
local vector X,Y,Z;
local Rotator ViewRotation;
GetAxes(Rotation,X,Y,Z);
// Update view rotation.
if ( !bFixedCamera )
{
ViewRotation = Rotation;
ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
if (Pawn != None)
ViewRotation.Pitch = Pawn.LimitPitch(ViewRotation.Pitch);
SetRotation(ViewRotation);
}
else if ( ViewTarget != None )
SetRotation(ViewTarget.Rotation);
ViewShake(DeltaTime);
ViewFlash(DeltaTime);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, vect(0,0,0), DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, vect(0,0,0), DCLICK_None, rot(0,0,0));
bPressedJump = false;
}
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
Global.ServerMove(TimeStamp, InAccel, ClientLoc, NewActions,
DoubleClickMove, ClientRoll, (32767 & (Rotation.Pitch/2)) * 32768 + (32767 & (Rotation.Yaw/2)) );
}
function FindGoodView()
{
local vector cameraLoc;
local rotator cameraRot, ViewRotation;
local int tries, besttry;
local float bestdist, newdist;
local int startYaw;
local actor ViewActor;
ViewRotation = Rotation;
ViewRotation.Pitch = 56000;
tries = 0;
besttry = 0;
bestdist = 0.0;
startYaw = ViewRotation.Yaw;
for (tries=0; tries<16; tries++)
{
cameraLoc = ViewTarget.Location;
SetRotation(ViewRotation);
PlayerCalcView(ViewActor, cameraLoc, cameraRot);
newdist = VSize(cameraLoc - ViewTarget.Location);
if (newdist > bestdist)
{
bestdist = newdist;
besttry = tries;
}
ViewRotation.Yaw += 4096;
}
ViewRotation.Yaw = startYaw + besttry * 4096;
SetRotation(ViewRotation);
}
function Timer()
{
bFrozen = false;
}
function LongClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
float NewVelX,
float NewVelY,
float NewVelZ,
Actor NewBase,
float NewFloorX,
float NewFloorY,
float NewFloorZ
)
{
}
function BeginState()
{
local Pawn P;
EndZoom();
StopForceFeedback();
CameraDist = Default.CameraDist;
FOVAngle = DesiredFOV;
bFire = 0;
bAltFire = 0;
if ( Pawn != None )
{
if ( Vehicle(Pawn) != None )
Pawn.StopWeaponFiring();
Pawn.TurnOff();
Pawn.bSpecialHUD = false;
Pawn.SimAnim.AnimRate = 0;
if ( Pawn.Weapon != None )
{
Pawn.Weapon.StopFire(0);
Pawn.Weapon.StopFire(1);
Pawn.Weapon.bEndOfRound = true;
}
}
bFrozen = true;
if ( !bFixedCamera )
{
FindGoodView();
bBehindView = true;
}
SetTimer(5, false);
ForEach DynamicActors(class'Pawn', P)
{
if ( P.Role == ROLE_Authority )
P.RemoteRole = ROLE_DumbProxy;
P.TurnOff();
}
}
Begin:
}
state RoundEnded
{
ignores SeePlayer, HearNoise, KilledBy, NotifyBump, HitWall, NotifyHeadVolumeChange, NotifyPhysicsVolumeChange, Falling, TakeDamage, Suicide;
function ServerReStartPlayer()
{
}
function bool IsSpectating() { return true; }
exec function Use() {}
exec function SwitchWeapon(byte T) {}
exec function ThrowWeapon() {}
exec function Fire(optional float F) {}
exec function AltFire(optional float F) {}
function Possess(Pawn aPawn)
{
Global.Possess(aPawn);
if (Pawn != None)
Pawn.TurnOff();
}
function PlayerMove(float DeltaTime)
{
local vector X,Y,Z;
local Rotator ViewRotation;
GetAxes(Rotation,X,Y,Z);
// Update view rotation.
if ( !bFixedCamera )
{
ViewRotation = Rotation;
ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
if (Pawn != None)
ViewRotation.Pitch = Pawn.LimitPitch(ViewRotation.Pitch);
SetRotation(ViewRotation);
}
else if ( ViewTarget != None )
SetRotation( ViewTarget.Rotation );
ViewShake( DeltaTime );
ViewFlash( DeltaTime );
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, vect(0,0,0), DCLICK_None, rot(0,0,0));
else
ProcessMove(DeltaTime, vect(0,0,0), DCLICK_None, rot(0,0,0));
bPressedJump = false;
}
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
Global.ServerMove(TimeStamp, InAccel, ClientLoc, NewActions,
DoubleClickMove, ClientRoll, (32767 & (Rotation.Pitch/2)) * 32768 + (32767 & (Rotation.Yaw/2)) );
}
function FindGoodView()
{
local vector cameraLoc;
local rotator cameraRot, ViewRotation;
local int tries, besttry;
local float bestdist, newdist;
local int startYaw;
local actor ViewActor;
ViewRotation = Rotation;
ViewRotation.Pitch = 56000;
tries = 0;
besttry = 0;
bestdist = 0.0;
startYaw = ViewRotation.Yaw;
for (tries=0; tries<16; tries++)
{
cameraLoc = ViewTarget.Location;
SetRotation(ViewRotation);
PlayerCalcView(ViewActor, cameraLoc, cameraRot);
newdist = VSize(cameraLoc - ViewTarget.Location);
if ( newdist > bestdist )
{
bestdist = newdist;
besttry = tries;
}
ViewRotation.Yaw += 4096;
}
ViewRotation.Yaw = startYaw + besttry * 4096;
SetRotation(ViewRotation);
}
function Timer()
{
bFrozen = false;
}
function LongClientAdjustPosition
(
float TimeStamp,
name newState,
EPhysics newPhysics,
float NewLocX,
float NewLocY,
float NewLocZ,
float NewVelX,
float NewVelY,
float NewVelZ,
Actor NewBase,
float NewFloorX,
float NewFloorY,
float NewFloorZ
)
{
if ( newState == 'PlayerWaiting' )
GotoState( newState );
}
function BeginState()
{
local Pawn P;
EndZoom();
CameraDist = Default.CameraDist;
FOVAngle = DesiredFOV;
bFire = 0;
bAltFire = 0;
if ( Pawn != None )
{
if ( Vehicle(Pawn) != None )
Pawn.StopWeaponFiring();
Pawn.TurnOff();
Pawn.bSpecialHUD = false;
Pawn.SimAnim.AnimRate = 0;
if ( Pawn.Weapon != None )
{
Pawn.Weapon.StopFire(0);
Pawn.Weapon.StopFire(1);
Pawn.Weapon.bEndOfRound = true;
}
}
bFrozen = true;
bBehindView = true;
if ( !bFixedCamera )
FindGoodView();
SetTimer(5, false);
ForEach DynamicActors(class'Pawn', P)
{
if ( P.Role == ROLE_Authority )
P.RemoteRole = ROLE_DumbProxy;
P.TurnOff();
}
StopForceFeedback();
}
function CalcBehindView(out vector CameraLocation, out rotator CameraRotation, float Dist)
{
local vector View;
local float ViewDist,RealDist;
local vector globalX,globalY,globalZ;
local vector localX,localY,localZ;
local vector HitLocation,HitNormal;
local Actor HitActor;
CameraRotation = Rotation;
CameraRotation.Roll = 0;
CameraLocation.Z += 12;
// add view rotation offset to cameraview (amb)
CameraRotation += CameraDeltaRotation;
View = vect(1,0,0) >> CameraRotation;
// add view radius offset to camera location and move viewpoint up from origin (amb)
RealDist = Dist;
Dist += CameraDeltaRad;
HitActor = Trace( HitLocation, HitNormal, CameraLocation - Dist * vector(CameraRotation), CameraLocation,false,vect(10,10,10));
if ( HitActor != None && !HitActor.IsA('BlockingVolume') )
ViewDist = FMin( (CameraLocation - HitLocation) Dot View, Dist );
else
ViewDist = Dist;
if ( !bBlockCloseCamera || !bValidBehindCamera || (ViewDist > 10 + FMax(ViewTarget.CollisionRadius, ViewTarget.CollisionHeight)) )
{
//Log("Update Cam ");
bValidBehindCamera = true;
OldCameraLoc = CameraLocation - ViewDist * View;
OldCameraRot = CameraRotation;
}
else
{
//Log("Dont Update Cam "$bBlockCloseCamera@bValidBehindCamera@ViewDist);
SetRotation(OldCameraRot);
}
CameraLocation = OldCameraLoc;
CameraRotation = OldCameraRot;
// add view swivel rotation to cameraview (amb)
GetAxes(CameraSwivel,globalX,globalY,globalZ);
localX = globalX >> CameraRotation;
localY = globalY >> CameraRotation;
localZ = globalZ >> CameraRotation;
CameraRotation = OrthoRotation(localX,localY,localZ);
}
Begin:
}
state Dead
{
ignores SeePlayer, HearNoise, KilledBy, SwitchWeapon, NextWeapon, PrevWeapon;
exec function ThrowWeapon()
{
//clientmessage("Throwweapon while dead, pawn "$Pawn$" health "$Pawn.health);
}
function bool IsDead()
{
return true;
}
function ServerReStartPlayer()
{
if ( !Level.Game.PlayerCanRestart( Self ) )
return;
super.ServerRestartPlayer();
}
exec function Fire( optional float F )
{
if ( bFrozen )
{
if ( (TimerRate <= 0.0) || (TimerRate > 1.0) )
bFrozen = false;
return;
}
LoadPlayers();
if (bMenuBeforeRespawn)
{
bMenuBeforeRespawn = false;
ShowMidGameMenu(false);
}
else
ServerReStartPlayer();
}
exec function AltFire( optional float F )
{
Fire(F);
}
exec function Use()
{
if ( bFrozen )
{
if ( (TimerRate <= 0.0) || (TimerRate > 1.0) )
bFrozen = false;
return;
}
if ( Level.Game != None )
Level.Game.DeadUse(self);
}
function ServerMove
(
float TimeStamp,
vector InAccel,
vector ClientLoc,
byte NewActions,
eDoubleClickDir DoubleClickMove,
byte ClientRoll,
int View,
optional int FreeAimRot,
optional byte OldTimeDelta,
optional int OldAccel
)
{
Global.ServerMove(
TimeStamp,
InAccel,
ClientLoc,
0,
DoubleClickMove,
ClientRoll,
View);
}
function PlayerMove(float DeltaTime)
{
local vector X,Y,Z;
local rotator ViewRotation;
if ( !bFrozen )
{
if ( bPressedJump )
{
Fire(0);
bPressedJump = false;
}
GetAxes(Rotation,X,Y,Z);
// Update view rotation.
ViewRotation = Rotation;
ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
if (Pawn != None)
ViewRotation.Pitch = Pawn.LimitPitch(ViewRotation.Pitch);
SetRotation(ViewRotation);
if ( Role < ROLE_Authority ) // then save this move and replicate it
ReplicateMove(DeltaTime, vect(0,0,0), DCLICK_None, rot(0,0,0));
}
else if ( (TimerRate <= 0.0) || (TimerRate > 1.0) )
bFrozen = false;
ViewShake(DeltaTime);
ViewFlash(DeltaTime);
}
function FindGoodView()
{
local vector cameraLoc;
local rotator cameraRot, ViewRotation;
local int tries, besttry;
local float bestdist, newdist;
local int startYaw;
local actor ViewActor;
////log("Find good death scene view");
ViewRotation = Rotation;
ViewRotation.Pitch = 56000;
tries = 0;
besttry = 0;
bestdist = 0.0;
startYaw = ViewRotation.Yaw;
for (tries=0; tries<16; tries++)
{
cameraLoc = ViewTarget.Location;
SetRotation(ViewRotation);
PlayerCalcView(ViewActor, cameraLoc, cameraRot);
newdist = VSize(cameraLoc - ViewTarget.Location);
if (newdist > bestdist)
{
bestdist = newdist;
besttry = tries;
}
ViewRotation.Yaw += 4096;
}
ViewRotation.Yaw = startYaw + besttry * 4096;
SetRotation(ViewRotation);
}
function Timer()
{
if (!bFrozen)
return;
bFrozen = false;
bPressedJump = false;
}
function BeginState()
{
local Actor A;
if ( (Pawn != None) && ((Pawn.Controller == self) || (Pawn.Controller == None)) )
Pawn.Controller = None;
EndZoom();
CameraDist = Default.CameraDist;
FOVAngle = DesiredFOV;
Pawn = None;
Enemy = None;
bBehindView = true;
bFrozen = true;
bJumpStatus = false;
bPressedJump = false;
bBlockCloseCamera = true;
bValidBehindCamera = false;
bFreeCamera = False;
if ( Viewport(Player) != None )
ForEach DynamicActors(class'Actor',A)
A.NotifyLocalPlayerDead(self);
FindGoodView();
SetTimer(1.0, false);
StopForceFeedback();
ClientPlayForceFeedback("Damage"); // jdf
CleanOutSavedMoves();
}
function EndState()
{
StopForceFeedback();
bBlockCloseCamera = false;
CleanOutSavedMoves();
Velocity = vect(0,0,0);
Acceleration = vect(0,0,0);
if ( !PlayerReplicationInfo.bOutOfLives )
bBehindView = false;
bPressedJump = false;
if ( myHUD != None )
myHUD.bShowScoreBoard = false;
StopViewShaking();
}
Begin:
Sleep(3.0);
if ( myHUD != None )
myHUD.bShowScoreBoard = true;
}
//------------------------------------------------------------------------------
// Control options
function ChangeStairLook( bool B )
{
bLookUpStairs = B;
if ( bLookUpStairs )
bAlwaysMouseLook = false;
}
function ChangeAlwaysMouseLook(Bool B)
{
bAlwaysMouseLook = B;
if ( bAlwaysMouseLook )
bLookUpStairs = false;
}
singular event UnPressButtons()
{
bFire = 0;
bAltFire = 0;
// if _RO_
//bDuck = 0;
//
bRun = 0;
bVoiceTalk = 0;
ResetInput();
}
// if _RO_
// Added this here so we can unpress these movement buttons when necessary (like the pawn died)
simulated function ClientResetMovement()
{
bDuck = 0;
bCrawl = 0;
}
// end _RO_
// Replace with good code
event ClientOpenMenu (string Menu, optional bool bDisconnect,optional string Msg1, optional string Msg2)
{
// GUIController calls UnpressButtons() after it's been activated...once active, it swallows
// all input events, preventing GameEngine from parsing script execs commands -- rjp
if ( !Player.GUIController.OpenMenu(Menu, Msg1, Msg2) )
UnPressButtons();
if (bDisconnect)
{
// Use delayed console command, in case the menu that was opened had bDisconnectOnOpen=True -- rjp
if ( Player.Console != None )
Player.Console.DelayedConsoleCommand("DISCONNECT");
else ConsoleCommand("Disconnect");
}
}
event ClientReplaceMenu(string Menu, optional bool bDisconnect,optional string Msg1, optional string Msg2)
{
if ( !Player.GUIController.bActive )
{
if ( !Player.GUIController.ReplaceMenu(Menu,Msg1,Msg2) )
UnpressButtons();
}
else Player.GUIController.ReplaceMenu(Menu,Msg1,Msg2);
if (bDisconnect)
{
if ( Player.Console != None )
Player.Console.DelayedConsoleCommand("Disconnect");
else ConsoleCommand("Disconnect");
}
}
event ClientCloseMenu(optional bool bCloseAll, optional bool bCancel)
{
if (bCloseAll)
Player.GUIController.CloseAll(bCancel,True);
else
Player.GUIController.CloseMenu(bCancel);
}
event ClientNetworkMessage(string ParamA, string ParamB)
{
ClientOpenMenu(Player.GUIController.NetworkMsgMenu, true, ParamA, ParamB);
}
simulated function bool IsMouseInverted()
{
return PlayerInput.bInvertMouse;
}
exec function InvertMouse(optional string Invert)
{
PlayerInput.InvertMouse(Invert);
}
exec function InvertLook()
{
local bool result;
result = PlayerInput.InvertLook();
if (IsOnConsole())
{
class'XBoxPlayerInput'.default.bInvertVLook = result;
class'XBoxPlayerInput'.static.StaticSaveConfig();
}
}
function bool CanRestartPlayer()
{
return !PlayerReplicationInfo.bOnlySpectator;
}
/////////////////////////////////////////////////////////////////////////////
// Admin Handling : Was previously in Admin.uc
//
//
//
// Execute an administrative console command on the server.
exec function Admin( string CommandLine )
{
local string Result;
if (AdminManager != None)
{
if ( Level.Game.AccessControl == None || !Level.Game.AccessControl.CanPerform(Self, "Xc") )
return;
Result = ConsoleCommand( CommandLine );
if (Level.Game.AccessControl.bReplyToGUI)
AdminReply(Result);
else if( Result != "" )
ClientMessage( Result );
}
}
exec function AdminDebug( string CommandLine )
{
if ( AdminManager != None )
{
if ( Level.Game.AccessControl == None || !Level.Game.AccessControl.CanPerform(Self, "Xc") )
return;
ConsoleCommand(CommandLine, True);
}
}
exec function AdminLogin( string CmdLine )
{
if ( Level.TimeSeconds < NextLoginTime )
return;
NextLoginTime = Level.TimeSeconds + LoginDelay;
ServerAdminLogin(CmdLine);
}
function ServerAdminLogin( string CmdLine )
{
local string uname, upass;
if (AdminManager == None)
{
MakeAdmin();
if ( AdminManager != None )
{
if ( !Divide(CmdLine, " ", uname, upass) )
upass = CmdLine;
AdminManager.DoLogin(uname, upass);
if ( !AdminManager.bAdmin )
AdminManager = None;
else AddCheats();
}
}
}
//if _RO_
exec function AdminLoginSilent( string CmdLine )
{
if ( Level.TimeSeconds < NextLoginTime )
return;
NextLoginTime = Level.TimeSeconds + LoginDelay;
ServerAdminLoginSilent(CmdLine);
}
function ServerAdminLoginSilent( string CmdLine )
{
local string uname, upass;
if (AdminManager == None)
{
MakeAdmin();
if ( AdminManager != None )
{
if ( !Divide(CmdLine, " ", uname, upass) )
upass = CmdLine;
AdminManager.DoLoginSilent(uname, upass);
if ( !AdminManager.bAdmin )
AdminManager = None;
else AddCheats();
}
}
}
//end _RO_
function AdminCommand( string CommandLine )
{
if (Left(CommandLine, 11) ~= "AdminLogin ")
{
AdminLogin(Mid(CommandLine, 11));
ReportAdmin("adv="$Level.Game.AccessControl.IsA('AccessControlIni'));
}
else if (Left(CommandLine, 11) ~= "AdminLogout")
{
AdminLogout();
ReportAdmin();
}
else if (Level.Game.AccessControl != None)
{
Level.Game.AccessControl.bReplyToGUI = true;
Admin(CommandLine);
Level.Game.AccessControl.bReplyToGUI = false;
}
}
function ReportAdmin(optional string ReportText)
{
local string str;
if (AdminManager != None && AdminManager.bAdmin)
{
if (Level.Game.AccessControl != None)
{
str = "name=" $ Level.Game.AccessControl.GetAdminName(Self);
if ( ReportText != "" )
str $= ";" $ ReportText;
}
else
{
str = "name=Admin";
if ( ReportText != "" )
str $= ";" $ ReportText;
}
}
else str = ReportText;
AdminReply(str);
}
function AdminReply( string Reply )
{
if (Player.GUIController != None)
Player.GUIController.OnAdminReply(Reply);
}
exec function AdminLogout()
{
if (AdminManager != None)
{
AdminManager.DoLogout();
if (!AdminManager.bAdmin)
AdminManager = None;
}
}
exec function AdminGUI()
{
}
/////////////////////////////////////////////////////////////////////////////
//
// Demo Recording
//
//
// Called on the client during client-side demo recording
simulated event StartClientDemoRec()
{
// Here we replicate functions which the demo never saw.
DemoClientSetHUD( MyHud.Class, MyHud.ScoreBoard.Class );
// tell server to replicate more stuff to me
bClientDemo = true;
ServerSetClientDemo();
}
function ServerSetClientDemo()
{
bClientDemo = true;
}
// Called on the playback client during client-side demo playback
simulated function DemoClientSetHUD(class<HUD> newHUDClass, class<Scoreboard> newScoringClass )
{
if( MyHUD == None )
ClientSetHUD( newHUDClass, newScoringClass );
}
simulated function string GetCustomStatusAnnouncerClass() { return ""; }
simulated function string GetCustomRewardAnnouncerClass() { return ""; }
simulated function SetCustomStatusAnnouncerClass(string NewAnnouncerClass);
simulated function SetCustomRewardAnnouncerClass(string NewAnnouncerClass);
simulated function bool NeedNetNotify()
{
return false;
}
/////////////////////////////////////////////////////////////////////////////
//
// Voice Recognition
//
//
event VoiceCommand( string RecognizedString, string RawString )
{
log(RecognizedString);
TeamMessage( PlayerReplicationInfo, RawString, 'TeamSayQuiet' );
if ( RecognizedString != "" )
ServerVoiceCommand(RecognizedString);
}
exec function command(string RecognizedString)
{
Level.Game.ParseVoiceCommand( self, RecognizedString );
}
function ServerVoiceCommand(string RecognizedString)
{
Level.Game.ParseVoiceCommand( self, RecognizedString );
}
// =====================================================================================================================
// =====================================================================================================================
// Voice Chat
// =====================================================================================================================
// =====================================================================================================================
// Join a voice chatroom by name
exec function Join(string ChanName, string ChanPwd)
{
local int i, idx;
local VoiceChatRoom VCR;
//if _RO_
if (VoiceReplicationInfo == None || !VoiceReplicationInfo.bEnableVoiceChat || !bVoiceChatEnabled)
return;
//else
//if (VoiceReplicationInfo == none || !VoiceReplicationInfo.bEnableVoiceChat)
// return;
//end _RO_
for (i = 0; i < StoredChatPasswords.Length; i++)
{
if (ChanName ~= StoredChatPasswords[i].ChatRoomName)
{
if ( ChanPwd == "" )
ChanPwd = StoredChatPasswords[i].ChatRoomPassword;
else
{
StoredChatPasswords[i].ChatRoomPassword = ChanPwd;
SaveConfig();
}
break;
}
}
if ( i == StoredChatPasswords.Length && ChanPwd != "" )
{
StoredChatPasswords.Length = i + 1;
StoredChatPasswords[i].ChatRoomName = ChanName;
StoredChatPasswords[i].ChatRoomPassword = ChanPwd;
SaveConfig();
}
log("Join "$ChanName@"Password:"$ChanPwd@"PRI:"$PlayerReplicationInfo.PlayerName@"Team:"$PlayerReplicationInfo.Team,'VoiceChat');
if (PlayerReplicationInfo != None && PlayerReplicationInfo.Team != None)
idx = PlayerReplicationInfo.Team.TeamIndex;
VCR = VoiceReplicationInfo.GetChannel(ChanName, idx);
if (VCR != None)
{
if (!VCR.IsMember(PlayerReplicationInfo))
ServerJoinVoiceChannel(VCR.ChannelIndex, ChanPwd);
}
else if ( ChatRoomMessageClass != None )
ClientMessage(ChatRoomMessageClass.static.AssembleMessage(0,ChanName));
}
// Leave a voice chatroom by name
exec function Leave(string ChannelTitle)
{
local VoiceChatRoom VCR;
local int idx;
if (VoiceReplicationInfo == None || !VoiceReplicationInfo.bEnableVoiceChat )
return;
if (PlayerReplicationInfo != None && PlayerReplicationInfo.Team != None)
idx = PlayerReplicationInfo.Team.TeamIndex;
VCR = VoiceReplicationInfo.GetChannel(ChannelTitle, idx);
if (VCR == None && ChatRoomMessageClass != None)
{
ClientMessage(ChatRoomMessageClass.static.AssembleMessage(0,ChannelTitle));
return;
}
if ( VCR == ActiveRoom )
ActiveRoom = None;
ServerLeaveVoiceChannel(VCR.ChannelIndex);
}
// Set a voice chatroom to your active channel
exec function Speak(string ChannelTitle)
{
local int idx;
local VoiceChatRoom VCR;
local string ChanPwd;
//if _RO_
if (VoiceReplicationInfo == None || !VoiceReplicationInfo.bEnableVoiceChat || !bVoiceChatEnabled)
return;
//else
//if (VoiceReplicationInfo == None || !VoiceReplicationInfo.bEnableVoiceChat)
// return;
//end _RO_
if (PlayerReplicationInfo != None && PlayerReplicationInfo.Team != None)
idx = PlayerReplicationInfo.Team.TeamIndex;
// Check that we are a member of this room
VCR = VoiceReplicationInfo.GetChannel(ChannelTitle, idx);
if (VCR == None && ChatRoomMessageClass != None)
{
ClientMessage(ChatRoomMessageClass.static.AssembleMessage(0,ChannelTitle));
return;
}
if (VCR.ChannelIndex >= 0)
{
ChanPwd = FindChannelPassword(ChannelTitle);
ServerSpeak(VCR.ChannelIndex, ChanPwd);
}
else if ( ChatRoomMessageClass != None )
ClientMessage(ChatRoomMessageClass.static.AssembleMessage(0,ChannelTitle));
}
// Set your active channel to the default channel
exec function SpeakDefault()
{
local string str;
str = GetDefaultActiveChannel();
if ( str != "" && (ActiveRoom == None || !(ActiveRoom.GetTitle() ~= str)) )
Speak(str);
}
// Set your active channel to the last active channel
exec function SpeakLast()
{
if ( LastActiveChannel != "" && (ActiveRoom == None || !(ActiveRoom.GetTitle() ~= LastActiveChannel)) )
Speak(LastActiveChannel);
}
// Change the password for you personal chatroom
exec function SetChatPassword(string NewPassword)
{
if (ChatPassword != NewPassword)
{
ChatPassword = NewPassword;
SaveConfig();
ServerSetChatPassword(NewPassword);
}
}
exec function EnableVoiceChat()
{
local bool bCurrent;
bCurrent = bool(ConsoleCommand("get ini:Engine.Engine.AudioDevice UseVoIP"));
ConsoleCommand("set ini:Engine.Engine.AudioDevice UseVoIP"@True);
if ( VoiceReplicationInfo == None )
return;
if ( !VoiceReplicationInfo.bEnableVoiceChat )
{
ChatRoomMessage(15, -1);
return;
}
ChangeVoiceChatMode( True );
InitializeVoiceChat();
// TODO What else needs to be done before a sound reboot?
if (bCurrent == False)
ConsoleCommand("SOUND_REBOOT");
}
exec function DisableVoiceChat()
{
local bool bCurrent;
bCurrent = bool(ConsoleCommand("get ini:Engine.Engine.AudioDevice UseVoIP"));
ConsoleCommand("set ini:Engine.Engine.AudioDevice UseVoIP"@False);
if (VoiceReplicationInfo == None || !VoiceReplicationInfo.bEnableVoiceChat )
return;
ChangeVoiceChatMode( False );
// TODO What else needs to be done before a sound reboot?
if (bCurrent == True)
ConsoleCommand("SOUND_REBOOT");
}
simulated function InitializeVoiceChat()
{
if ( bVoiceChatEnabled )
{
InitPrivateChatRoom();
AutoJoinVoiceChat();
}
}
function InitPrivateChatRoom()
{
ServerChangeVoiceChatMode(True);
if ( ChatPassword != "" )
ServerSetChatPassword(ChatPassword);
}
simulated function string GetDefaultActiveChannel()
{
local string DefaultChannel;
if ( DefaultActiveChannel != "" )
DefaultChannel = DefaultActiveChannel;
else if ( VoiceReplicationInfo != None )
DefaultChannel = VoiceReplicationInfo.GetDefaultChannel();
return DefaultChannel;
}
simulated function AutoJoinVoiceChat();
simulated function ChangeVoiceChatMode( bool bEnable )
{
if (VoiceReplicationInfo == None)
return;
bVoiceChatEnabled = bEnable;
//if _RO_
if ( !bEnable )
ActiveRoom = none;
//end _RO_
if (Level.NetMode == NM_Client || Level.NetMode == NM_ListenServer)
ServerChangeVoiceChatMode( bEnable );
}
simulated function bool ChatBan(int PlayerID, byte Type)
{
log("ChatBan Role:"$GetEnum(enum'ENetRole', Role)@"ChatManager:"$ChatManager@"PlayerID:"$PlayerID@"Type:"$Type,'ChatManager');
if ( Level.NetMode == NM_StandAlone || Level.NetMode == NM_DedicatedServer )
return false;
if ( ChatManager == None )
return false;
if ( ChatManager.SetRestrictionID(PlayerID, Type) )
{
ServerChatRestriction(PlayerID, Type);
return true;
}
log(Name@"ChatBan not successful - could not find player with ID:"@PlayerID,'ChatManager');
return false;
}
simulated function SetChannelPassword(string ChannelName, string ChannelPassword)
{
local int i;
if ( Level.NetMode == NM_DedicatedServer )
return;
for ( i = 0; i < StoredChatPasswords.Length; i++ )
{
if ( StoredChatPasswords[i].ChatRoomName ~= ChannelName )
break;
}
if ( i == StoredChatPasswords.Length )
StoredChatPasswords.Length = i + 1;
StoredChatPasswords[i].ChatRoomName = ChannelName;
StoredChatPasswords[i].ChatRoomPassword = ChannelPassword;
SaveConfig();
}
simulated function string FindChannelPassword(string ChannelName)
{
local int i;
for ( i = 0; i < StoredChatPasswords.Length; i++ )
if ( StoredChatPasswords[i].ChatRoomName ~= ChannelName )
return StoredChatPasswords[i].ChatRoomPassword;
return "";
}
function VoiceChatRoom.EJoinChatResult ServerJoinVoiceChannel(int ChannelIndex, optional string ChannelPassword)
{
local VoiceChatRoom VCR;
local VoiceChatRoom.EJoinChatResult Result;
VCR = VoiceReplicationInfo.GetChannelAt(ChannelIndex);
if (VoiceReplicationInfo == None || PlayerReplicationInfo == None || VCR == None || !VoiceReplicationInfo.bEnableVoiceChat)
return JCR_Invalid;
if ( VoiceReplicationInfo != None )
Result = VoiceReplicationInfo.JoinChannelAt(ChannelIndex, PlayerReplicationInfo, ChannelPassword);
// Take the appropriate action depending on the result received from the VoiceReplicationInfo
switch ( Result )
{
case JCR_NeedPassword: ClientOpenMenu(ChatPasswordMenuClass, false, VCR.GetTitle(), "NEEDPW"); break;
case JCR_WrongPassword: ClientOpenMenu(ChatPasswordMenuClass, False, VCR.GetTitle(), "WRONGPW"); break;
case JCR_Success: Level.Game.ChangeVoiceChannel(PlayerReplicationInfo, ChannelIndex, -1);
default:
if ( ChannelIndex>VoiceReplicationInfo.GetPublicChannelCount(true) )
ChatRoomMessage(Result, ChannelIndex);
}
return Result;
}
function ServerLeaveVoiceChannel(int ChannelIndex)
{
local VoiceChatRoom VCR;
if (VoiceReplicationInfo == None || PlayerReplicationInfo == None)
return;
if ( !VoiceReplicationInfo.bEnableVoiceChat )
{
ChatRoomMessage(15, -1);
return;
}
VCR = VoiceReplicationInfo.GetChannelAt(ChannelIndex);
if (VCR != None && VCR.LeaveChannel(PlayerReplicationInfo))
{
if (VCR == ActiveRoom)
{
ActiveRoom = None;
if ( PlayerReplicationInfo != None )
PlayerReplicationInfo.ActiveChannel = -1;
// not necessary as client will do this itself
// ClientSetActiveRoom(-1);
}
Level.Game.ChangeVoiceChannel( PlayerReplicationInfo, -1, ChannelIndex );
if ( ChannelIndex>VoiceReplicationInfo.GetPublicChannelCount(true) )
ChatRoomMessage(8, ChannelIndex);
}
}
function ServerSpeak(int ChannelIndex, optional string ChannelPassword)
{
local VoiceChatRoom VCR;
local int Index;
if (VoiceReplicationInfo == None)
return;
VCR = VoiceReplicationInfo.GetChannelAt(ChannelIndex);
if ( VCR == None )
{
if ( VoiceReplicationInfo.bEnableVoiceChat )
ChatRoomMessage(0, ChannelIndex);
else ChatRoomMessage(15, ChannelIndex);
return;
}
if ( !VCR.IsMember(PlayerReplicationInfo) )
{
if ( ServerJoinVoiceChannel(ChannelIndex, ChannelPassword) != JCR_Success )
return;
}
Index = -1;
if (ActiveRoom == VCR)
{
ChatRoomMessage(10, ChannelIndex);
log(PlayerReplicationInfo.PlayerName@"no longer speaking on "$VCR.GetTitle(),'VoiceChat');
ActiveRoom = None;
ClientSetActiveRoom(-1);
}
else
{
ActiveRoom = VCR;
log(PlayerReplicationInfo.PlayerName@"speaking on"@VCR.GetTitle(),'VoiceChat');
ChatRoomMessage(9, ChannelIndex);
ClientSetActiveRoom(VCR.ChannelIndex);
Index = VCR.ChannelIndex;
}
if ( PlayerReplicationInfo != None )
PlayerReplicationinfo.ActiveChannel = Index;
}
function ServerSetChatPassword(string NewPassword)
{
ChatPassword = NewPassword;
if (PlayerReplicationInfo != None)
PlayerReplicationInfo.SetChatPassword(NewPassword);
}
function ServerChangeVoiceChatMode( bool bEnable )
{
if (VoiceReplicationInfo == None)
return;
bVoiceChatEnabled = bEnable;
//if _RO_
if ( !bEnable )
ActiveRoom = none;
//end _RO_
if ( bVoiceChatEnabled )
{
if ( VoiceReplicationInfo.bEnableVoiceChat )
VoiceReplicationInfo.AddVoiceChatter(PlayerReplicationInfo);
else ChatRoomMessage(15, -1);
}
else VoiceReplicationInfo.RemoveVoiceChatter(PlayerReplicationInfo);
}
simulated function ClientSetActiveRoom(int ChannelIndex)
{
if ( VoiceReplicationInfo == None || !bVoiceChatEnabled )
return;
if ( ActiveRoom != None )
LastActiveChannel = ActiveRoom.GetTitle();
else LastActiveChannel = "";
ActiveRoom = VoiceReplicationInfo.GetChannelAt(ChannelIndex);
}
// =====================================================================================================================
// =====================================================================================================================
// Chat Manager
// =====================================================================================================================
// =====================================================================================================================
exec function ChatDebug()
{
ChatManager.ChatDebug();
ServerChatDebug();
}
function ServerChatDebug();
function ServerRequestBanInfo(int PlayerID);
function ServerChatRestriction(int PlayerID, byte Type)
{
local PlayerReplicationInfo PRI;
local int i;
log("ServerChatRestriction PlayerID:"$PlayerID@"Type:"$Type,'ChatManager');
if ( ChatManager == None || GameReplicationInfo == None)
return;
for ( i = 0; i < GameReplicationInfo.PRIArray.Length; i++ )
{
log("ServerChatRestriction checking GRI.PRIArray["$i$"].PlayerID:"$GameReplicationInfo.PRIArray[i].PlayerID,'ChatManager');
if ( GameReplicationInfo.PRIArray[i] != None && GameReplicationInfo.PRIArray[i].PlayerID == PlayerID )
{
PRI = GameReplicationInfo.PRIArray[i];
break;
}
}
log("ServerChatRestriction PRI:"$PRI@"PRI.Owner"$PRI.Owner,'ChatManager');
//if _RO_
if ( PRI == None )
return;
ChatManager.SetRestrictionID(PRI.PlayerID, Type);
/*else
if ( PRI == None || PlayerController(PRI.Owner) == None )
return;
ChatManager.SetRestriction(PlayerController(GameReplicationInfo.PRIArray[i].Owner).GetPlayerIDHash(), Type); */
//end _RO_
// If we added a ban for this player and this player is currently in our private chat room, remove the player
if ( bool(Type & 8) && PlayerReplicationInfo != None && PlayerReplicationInfo.PrivateChatRoom != None &&
PlayerReplicationInfo.PrivateChatRoom.IsMember(PRI, True) )
{
ChatRoomMessage(13, -1, PRI);
PlayerReplicationInfo.PrivateChatRoom.RemoveMember(PRI);
}
}
simulated event GainedChild( Actor Other )
{
Super.GainedChild(Other);
if ( VotingReplicationInfoBase(Other) != None )
VoteReplicationInfo = VotingReplicationInfoBase(Other);
}
simulated event LostChild(Actor Other)
{
Super.LostChild(Other);
if ( VotingReplicationInfoBase(Other) != None )
VoteReplicationInfo = None;
}
exec function ShowVoteMenu()
{
if( Level.NetMode != NM_StandAlone && VoteReplicationInfo != none && VoteReplicationInfo.MapVoteEnabled() )
Player.GUIController.OpenMenu(Player.GUIController.GetPropertyText("MapVotingMenu"));
}
// if _RO_
// Semi hax: Used to get mouse sensitivity values for config menu (for some
// reason getting them from PlayerInput defaults doesn't work ingame)
function float GetMouseSensitivity()
{
if (PlayerInput == none)
return class'PlayerInput'.default.MouseSensitivity;
else
return PlayerInput.MouseSensitivity;
}
function float GetMouseAcceleration()
{
if (PlayerInput == none)
return class'PlayerInput'.default.MouseAccelThreshold;
else
return PlayerInput.MouseAccelThreshold;
}
function float GetMouseSmoothingStrength()
{
if (PlayerInput == none)
return class'PlayerInput'.default.MouseSmoothingStrength;
else
return PlayerInput.MouseSmoothingStrength;
}
function ServerInitializeSteamStatInt(byte Index, int Value)
{
if ( SteamStatsAndAchievements != none )
{
SteamStatsAndAchievements.InitializeSteamStatInt(Index, Value);
}
}
function ServerInitializeSteamStatFloat(byte Index, float Value)
{
if ( SteamStatsAndAchievements != none )
{
SteamStatsAndAchievements.InitializeSteamStatFloat(Index, Value);
}
}
function ServerSteamStatsAndAchievementsInitialized()
{
if ( SteamStatsAndAchievements != none )
{
SteamStatsAndAchievements.ServerSteamStatsAndAchievementsInitialized();
}
}
// Steam Workshop
simulated function SyncSteamWorkshop()
{
EnumerateSubscribedSteamWorkshopFiles();
}
simulated event OnSubscribedFilesEnumerated(int FileCount)
{
TotalSubscribedFiles = FileCount;
NextSubscribedFileToFetch = 1;
//log("KFPlayerController.OnSubscribedFilesEnumerated" @ FileCount,'Workshop_Debug');
if ( FileCount > 0 )
{
GetSubscribedSteamWorkshopFileDetails(0);
}
}
simulated event OnGetSubscribedFileDetailsCompleted(int SubscribedFileIndex, string Title, bool bFileExistsLocally)
{
//log("KFPlayerController.OnGetSubscribedFileDetailsCompleted" @ SubscribedFileIndex @ Title @ bFileExistsLocally,'Workshop_Debug');
if ( !bFileExistsLocally )
{
SubscribedFileDownloadIndex = SubscribedFileIndex;
SubscribedFileDownloadTitle = Title;
DownloadSubscribedSteamWorkshopFile(SubscribedFileIndex);
}
else if ( NextSubscribedFileToFetch < TotalSubscribedFiles )
{
GetSubscribedSteamWorkshopFileDetails(NextSubscribedFileToFetch++);
}
}
simulated event OnSubscribedFileDownloadUpdate(float DownloadProgress)
{
// TODO: Update UI Output using SubscribedFileDownloadIndex
//log("KFPlayerController.OnSubscribedFileDownloadUpdate" @ SubscribedFileDownloadIndex @ SubscribedFileDownloadTitle @ DownloadProgress,'Workshop_Debug');
DownloadFileProgress = DownloadProgress;
if ( DownloadProgress >= 1.0 )
{
SubscribedFileDownloadIndex = -1;
if ( NextSubscribedFileToFetch < TotalSubscribedFiles )
{
GetSubscribedSteamWorkshopFileDetails(NextSubscribedFileToFetch++);
}
}
}
// end if _RO_
defaultproperties
{
TeamBeaconMaxDist=6000.f
TeamBeaconPlayerInfoMaxDist=1800.f
TeamBeaconTeamColors[0]=(R=180,G=0,B=0,A=255)
TeamBeaconTeamColors[1]=(R=80,G=80,B=200,A=255)
TeamBeaconCustomColor=(R=255,G=255,B=0,A=255)
bAimingHelp=false
OrthoZoom=+40000.000000
FlashScale=(X=1.000000,Y=1.000000,Z=1.000000)
AnnouncerLevel=2
FOVAngle=90.000
DesiredFOV=90.000000
DefaultFOV=90.000000
Handedness=1.000000
bAlwaysMouseLook=True
ViewingFrom="Now viewing from"
OwnCamera="Now viewing from own camera"
QuickSaveString="Quick Saving"
NoPauseMessage="Game is not pauseable"
bTravel=True
bStasis=False
NetPriority=3
LocalMessageClass=class'LocalMessage'
bIsPlayer=true
bCanOpenDoors=true
bCanDoSpecial=true
Physics=PHYS_None
EnemyTurnSpeed=45000
CheatClass=class'Engine.CheatManager'
InputClass=class'Engine.PlayerInput'
CameraDist=+9.0
CameraDistRange=(Min=3.0,Max=40.0)
bZeroRoll=true
// ifdef _KF_
bDynamicNetSpeed=false
// else
// bDynamicNetSpeed=true
// endif _KF_
VehicleCheckRadius=700.0
// jdf ---
bEnableWeaponForceFeedback=True
bEnablePickupForceFeedback=True
bEnableDamageForceFeedback=True
bEnableGUIForceFeedback=True
bForceFeedbackSupported=True
// --- jdf
ProgressTimeOut=8.0
bAutoTaunt=false
AnnouncerVolume=4
bHideSpectatorBeacons=false
bWeaponViewShake=true
ScreenFlashScaling=+1.0
MaxResponseTime=0.125
SpectateSpeed=+600.0
DynamicPingThreshold=+400.0
ClientCap=0
bSmallWeapons=true
bLandingShake=true
bOnlySpeakTeamText=false
bNoTextToSpeechVoiceMessages=true
TextToSpeechVoiceVolume=1.0
FOVBias=+1.0
LastSpeedHackLog=-100.0
// rjp --
AutoJoinMask=5
bVoiceChatEnabled=True
bEnableInitialChatRoom=True
// if _RO_
MidGameMenuClass="ROInterface.RODisconnectOptionPage"
// else
// MidGameMenuClass="GUI2K4.UT2K4DisconnectOptionPage"
// end if _RO_
AdminMenuClass="GUI2K4.RemoteAdmin"
ChatPasswordMenuClass="GUI2K4.UT2K4ChatPassword"
ChatRoomMessageClass=class'Engine.ChatRoomMessage'
PlayerChatType="Engine.PlayerChatManager"
VoiceChatCodec="CODEC_48NB"
VoiceChatLANCodec="CODEC_96WB"
// -- rjp
}