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

206 lines
4.9 KiB
Ucode

// a really creepy camera that is always looking in your direction.
// it can be destroyed if you shoot it
// Author: Alex Quick
class CreepyCamera extends Actor
placeable;
var () bool DebugCamera;
// the player this camera is focusing on.
var protected Pawn CameraTarget;
// the rotation of the camera at level startup
var protected Rotator InitialRotation;
// limits on the rotation of the camera
var () const float PitchLimit,YawLimit;
// effect to spawn when this camera is destroyed
var protected class<Emitter> DestructionEffect;
simulated function PostBeginPlay()
{
InitialRotation = Rotation;
DesiredRotation = InitialRotation;
}
simulated function Tick(float DeltaTime)
{
OrientCameraToLocalPlayer();
if(DebugCamera)
{
PrintDebugLogs();
}
}
simulated function PrintDebugLogs()
{
log("======= CAMERA DEBUG ================");
log(" -->"@Self@" TARGET : "@CameraTarget@"InitialRotation :"@InitialRotation@" DesiredRotation :"@DesiredRotation);
}
// turn the camera so its looking at the local player
simulated function OrientCameraToLocalPlayer()
{
local rotator NewRotation;
local byte LockYaw,LockPitch;
if(CameraTarget == none)
{
FindCameraTarget();
}
else
{
NewRotation = Rotator((CameraTarget.Location + (Vect(0,0,1)* CameraTarget.EyeHeight)) - Location) ;
// If the desired rotation goes beyond the camera's limit, stop turning it.
if(CameraTarget.Health <= 0 ||
CameraTarget.bDeleteMe)
{
StopTracking();
return;
}
if(IsOutSideViewFrustrum(CameraTarget,LockYaw,LockPitch))
{
StopTracking();
}
else
{
if(LockPitch == 0)
{
DesiredRotation.Pitch = NewRotation.Pitch;
}
if(LockYaw == 0)
{
DesiredRotation.Yaw = NewRotation.Yaw;
}
}
}
}
simulated function StopTracking()
{
CameraTarget = none;
NetUpdateFrequency = 0.1; // camera isn't really do anything at the moment, so it doesn't need frequent replication updates.
}
simulated function bool IsOutsideViewFrustrum(Pawn TestTarget, optional out byte LockYaw, optional out byte LockPitch)
{
local Rotator RotExtent,IntendedRotation;
IntendedRotation = Rotator((TestTarget.Location + (Vect(0,0,1)* TestTarget.EyeHeight)) - Location) ;
RotExtent = IntendedRotation - InitialRotation;
RotExtent.Yaw = RotExtent.Yaw & 65535;
if( RotExtent.Yaw > YawLimit &&
RotExtent.Yaw < (65535+ (-YawLimit)) )
{
LockYaw = 1;
}
RotExtent.Pitch = RotExtent.Pitch & 65535;
if( RotExtent.Pitch > PitchLimit &&
RotExtent.Pitch < (65535+ (-PitchLimit)) )
{
LockPitch = 1;
}
return LockPitch == 1 && LockYaw == 1;
}
simulated function FindCameraTarget()
{
// do this separately on each client so the camera is looking at them.
if(Level.NetMode == NM_DedicatedServer)
{
return;
}
if(Level.GetLocalPlayerController().Pawn != none &&
Level.GetLocalPlayerController().Pawn.Health > 0)
{
CameraTarget = Level.GetLocalPlayerController().Pawn;
NetUpdateTime = Level.TimeSeconds - 1;
NetUpdateFrequency = default.NetUpdateFrequency;
}
}
simulated function TakeDamage(int Damage, Pawn EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional int HitIndex)
{
DestroyCamera(EventInstigator);
}
function DestroyCamera(Pawn Killer)
{
TriggerEvent(Event,self,Killer);
bHidden = true;
SetCollision(false,false);
bSkipActorPropertyReplication = false;
NetUpdateTime = Level.TimeSeconds - 1;
if(Level.NetMode != NM_DedicatedServer)
{
SpawnDestructionEffect();
}
}
simulated function SpawnDestructionEffect()
{
Spawn(DestructionEffect);
}
simulated event PostNetReceive()
{
if ( bHidden )
{
SpawnDestructionEffect();
bNetNotify = false; // finished
}
}
defaultproperties
{
bDirectional = true
CollisionRadius = 15
Collisionheight = 15
bCollideActors = true
bBlockActors = true
bUseCylinderCollision=true
bBlockZeroExtentTraces=true
bCanBeDamaged=true
DestructionEffect = class 'Emitter_BreakerExplosion'
DrawType = DT_StaticMesh
StaticMesh = StaticMesh'FrightYard_SM.Camera.Trader_Security_Cam'
PitchLimit = 10000
YawLimit = 16000
RotationRate=(Pitch=10000,Yaw=10000,Roll=0)
bFixedRotationDir = false
bRotateToDesired = true
Physics = PHYS_Rotating
// network
bOnlyDirtyReplication=true
bNoDelete=true
bReplicateMovement=false
bAlwaysRelevant=true
bSkipActorPropertyReplication=true
bNetNotify=true
RemoteRole=Role_SimulatedProxy
NetUpdateFrequency=0.1
}