1
0
KF2-Dev-Scripts/Engine/Classes/KActor.uc
2020-12-13 18:01:13 +03:00

435 lines
12 KiB
Ucode

/**
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
class KActor extends DynamicSMActor
native(Physics)
nativereplication
placeable
ClassGroup(Physics)
showcategories(Navigation);
cpptext
{
// AActor interface
virtual void physRigidBody(FLOAT DeltaTime);
virtual INT* GetOptimizedRepList(BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel);
virtual void OnRigidBodyCollision(const FRigidBodyCollisionInfo& MyInfo, const FRigidBodyCollisionInfo& OtherInfo, const FCollisionImpactData& RigidCollisionData);
UBOOL ShouldTrace(UPrimitiveComponent* Primitive, AActor *SourceActor, DWORD TraceFlags);
/**
* Function that gets called from within Map_Check to allow this actor to check itself
* for any potential errors and register them with map check dialog.
*/
#if WITH_EDITOR
virtual void CheckForErrors();
#endif
virtual void TickSpecial(FLOAT DeltaSeconds);
}
var() bool bDamageAppliesImpulse;
var() repnotify bool bWakeOnLevelStart;
// Impact effects
var ParticleSystemComponent ImpactEffectComponent;
var AudioComponent ImpactSoundComponent;
var AudioComponent ImpactSoundComponent2; // @TODO: This could be turned into a dynamic array; but for the moment just 2 will do.
var float LastImpactTime;
var PhysEffectInfo ImpactEffectInfo;
// Slide effects
var ParticleSystemComponent SlideEffectComponent;
var AudioComponent SlideSoundComponent;
var bool bCurrentSlide;
var bool bSlideActive;
var float LastSlideTime;
var PhysEffectInfo SlideEffectInfo;
/** Enable 'Stay upright' torque, that tries to keep Z axis of KActor pointing along world Z */
var(StayUprightSpring) bool bEnableStayUprightSpring;
/** Torque applied to try and keep KActor horizontal. */
var(StayUprightSpring) float StayUprightTorqueFactor;
/** Max torque that can be applied to try and keep KActor horizontal */
var(StayUprightSpring) float StayUprightMaxTorque;
/** If TRUE limit the maximum speed this object can move. */
var() bool bLimitMaxPhysicsVelocity;
/** If bLimitMaxPhysicsVelocity is TRUE, this is how fast the object can move. */
var() float MaxPhysicsVelocity;
var native const RigidBodyState RBState;
var native const float AngErrorAccumulator;
/** replicated version of DrawScale3D */
var repnotify vector ReplicatedDrawScale3D;
var transient vector InitialLocation;
var transient rotator InitialRotation;
/** whether we need to replicate RBState - used to avoid it for bNoDelete KActors that haven't moved or been awakened yet
* as in that case the client should already have the same data
*/
var transient bool bNeedsRBStateReplication;
/**
* Set TRUE to disable collisions with Pawn rigid bodies on clients. Set this to true if using optimizations that
* could cause the server to miss or ignore contacts that the client might dtect with this KActor, which could cause
* vibration, rubberbanding, and general visual badness.
*/
var bool bDisableClientSidePawnInteractions;
replication
{
if (bNeedsRBStateReplication && Role == ROLE_Authority)
RBState;
if (bNetInitial && Role == ROLE_Authority)
bWakeOnLevelStart, ReplicatedDrawScale3D;
}
/** Util for getting the PhysicalMaterial applied to this KActor's StaticMesh. */
native final function PhysicalMaterial GetKActorPhysMaterial();
/** Forces the resolve the RBState regardless of whether the actor is sleeping */
native final function ResolveRBState();
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
if (bWakeOnLevelStart && (StaticMeshComponent != None) )
{
StaticMeshComponent.WakeRigidBody();
}
else
{
bNeedsRBStateReplication = !bNoDelete;
}
ReplicatedDrawScale3D = DrawScale3D * 1000.0f; // avoids effects of vector rounding
// Initialise impact/slide components (if we are being notified of physics events, and have sounds/effects set up
// in PhysicalMaterial applied to our static mesh.
if((StaticMeshComponent != None) && StaticMeshComponent.bNotifyRigidBodyCollision)
{
SetPhysicalCollisionProperties();
}
InitialLocation = Location;
InitialRotation = Rotation;
if ( bDisableClientSidePawnInteractions && (Role != ROLE_Authority) && (StaticMeshComponent != None) )
{
// on clients, turn off collision with pawn RBs, Let replication handle collision response
// to avoid server/client disagreement.
StaticMeshComponent.SetRBCollidesWithChannel(RBCC_Pawn, FALSE);
}
}
/** called when the actor falls out of the world 'safely' (below KillZ and such) */
simulated event FellOutOfWorld(class<DamageType> dmgType)
{
ShutDown();
Super.FellOutOfWorld(dmgType);
}
simulated event Destroyed()
{
// Let the components play out normally
if( ImpactEffectInfo.Sound != None )
{
if( ImpactSoundComponent != none )
{
ImpactSoundComponent.bAutoDestroy = TRUE;
}
if( ImpactSoundComponent2 != none )
{
ImpactSoundComponent2.bAutoDestroy = TRUE;
}
}
if( SlideEffectInfo.Sound != None )
{
SlideSoundComponent.bAutoDestroy = TRUE;
}
Super.Destroyed();
}
simulated function SetPhysicalCollisionProperties()
{
local PhysicalMaterial PhysMat;
PhysMat = GetKActorPhysMaterial();
// cache effect info
ImpactEffectInfo = PhysMat.FindPhysEffectInfo(EPMET_Impact);
SlideEffectInfo = PhysMat.FindPhysEffectInfo(EPMET_Slide);
if(ImpactEffectInfo.Effect != None)
{
ImpactEffectComponent = new(self) class'ParticleSystemComponent';
//AttachComponent(ImpactEffectComponent);
ImpactEffectComponent.bAutoActivate = FALSE;
ImpactEffectComponent.SetTemplate(ImpactEffectInfo.Effect);
}
`if (`__TW_)
// do nothing
`else
if(ImpactEffectInfo.Sound != None)
{
ImpactSoundComponent = new(self) class'AudioComponent';
//AttachComponent(ImpactSoundComponent);
ImpactSoundComponent.SoundCue = ImpactEffectInfo.Sound;
ImpactSoundComponent2 = new(self) class'AudioComponent';
//AttachComponent(ImpactSoundComponent2);
ImpactSoundComponent2.SoundCue = ImpactEffectInfo.Sound;
}
`endif // __TW_
if(SlideEffectInfo.Effect != None)
{
SlideEffectComponent = new(self) class'ParticleSystemComponent';
//AttachComponent(SlideEffectComponent);
SlideEffectComponent.bAutoActivate = FALSE;
SlideEffectComponent.SetTemplate(SlideEffectInfo.Effect);
}
`if (`__TW_)
// do nothing
`else
if(SlideEffectInfo.Sound != None)
{
SlideSoundComponent = new(self) class'AudioComponent';
//AttachComponent(SlideSoundComponent);
SlideSoundComponent.SoundCue = SlideEffectInfo.Sound;
}
`endif // __TW_
}
/** Makes sure these properties get set up on spawned meshes. Factories do not set the mesh before PostBeginPlay is called. */
simulated event SpawnedByKismet()
{
if(StaticMeshComponent.bNotifyRigidBodyCollision)
{
SetPhysicalCollisionProperties();
}
InitialLocation = Location;
InitialRotation = Rotation;
}
simulated event ReplicatedEvent(name VarName)
{
local vector NewDrawScale3D;
if (VarName == 'bWakeOnLevelStart')
{
if (bWakeOnLevelStart)
{
StaticMeshComponent.WakeRigidBody();
}
}
else if (VarName == nameof(ReplicatedDrawScale3D))
{
NewDrawScale3D = ReplicatedDrawScale3D / 1000.0; // needs to match multiply in PostBeginPlay()
SetDrawScale3D(NewDrawScale3D);
}
else
{
Super.ReplicatedEvent(VarName);
}
}
event ApplyImpulse( Vector ImpulseDir, float ImpulseMag, Vector HitLocation, optional TraceHitInfo HitInfo, optional class<DamageType> DamageType )
{
local vector AppliedImpulse;
AppliedImpulse = Normal(ImpulseDir) * ImpulseMag;
if( HitInfo.HitComponent != None )
{
HitInfo.HitComponent.AddImpulse( AppliedImpulse, HitLocation, HitInfo.BoneName );
}
else
{ // if no HitComponent is passed, default to our CollisionComponent
CollisionComponent.AddImpulse( AppliedImpulse, HitLocation );
}
}
/**
* Default behaviour when shot is to apply an impulse and kick the KActor.
*/
event TakeDamage(int Damage, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
// call Actor's version to handle any SeqEvent_TakeDamage for scripting
Super.TakeDamage(Damage, EventInstigator, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);
if ( bDamageAppliesImpulse && DamageType.default.KDamageImpulse > 0 )
{
if ( VSize(momentum) < 0.001 )
{
`Log("Zero momentum to KActor.TakeDamage");
return;
}
ApplyImpulse(Momentum,
DamageType.default.KDamageImpulse,
HitLocation,
HitInfo,
DamageType);
}
}
/**
* Respond to radial damage as well.
*/
simulated function TakeRadiusDamage
(
Controller InstigatedBy,
float BaseDamage,
float DamageRadius,
class<DamageType> DamageType,
float Momentum,
vector HurtOrigin,
bool bFullDamage,
Actor DamageCauser,
optional float DamageFalloffExponent=1.f
)
{
local int Idx;
local SeqEvent_TakeDamage DmgEvt;
// search for any damage events
for (Idx = 0; Idx < GeneratedEvents.Length; Idx++)
{
DmgEvt = SeqEvent_TakeDamage(GeneratedEvents[Idx]);
if (DmgEvt != None)
{
// notify the event of the damage received
DmgEvt.HandleDamage(self, InstigatedBy, DamageType, BaseDamage);
}
}
if ( bDamageAppliesImpulse && damageType.default.RadialDamageImpulse > 0 && (Role == ROLE_Authority) )
{
CollisionComponent.AddRadialImpulse(HurtOrigin, DamageRadius, damageType.default.RadialDamageImpulse, RIF_Linear, damageType.default.bRadialDamageVelChange);
}
}
/** If this KActor receives a Toggle ON event from Kismet, wake the physics up. */
simulated function OnToggle(SeqAct_Toggle action)
{
if(action.InputLinks[0].bHasImpulse)
{
StaticMeshComponent.WakeRigidBody();
}
}
/**
* Called upon receiving a SeqAct_Teleport action. Grabs
* the first destination available and attempts to teleport
* this actor.
*
* @param inAction - teleport action that was activated
*/
simulated function OnTeleport(SeqAct_Teleport inAction)
{
local array<Object> objVars;
local int idx;
local Actor destActor;
// find the first supplied actor
inAction.GetObjectVars(objVars,"Destination");
for (idx = 0; idx < objVars.Length && destActor == None; idx++)
{
destActor = Actor(objVars[idx]);
}
// and set to that actor's location
if (destActor != None)
{
StaticMeshComponent.SetRBPosition(destActor.Location);
StaticMeshComponent.SetRBRotation(destActor.Rotation);
PlayTeleportEffect(false, true);
}
}
simulated function Reset()
{
`if (`__TW_)
if ( bDeleteMe )
{
return;
}
`endif
StaticMeshComponent.SetRBLinearVelocity( Vect(0,0,0) );
StaticMeshComponent.SetRBAngularVelocity( Vect(0,0,0) );
StaticMeshComponent.SetRBPosition( InitialLocation );
StaticMeshComponent.SetRBRotation( InitialRotation );
if (!bWakeOnLevelStart)
{
StaticMeshComponent.PutRigidBodyToSleep();
}
else
{
StaticMeshComponent.WakeRigidBody();
}
// Resolve the RBState and get all of the needed flags set
ResolveRBState();
// Force replication
bForceNetUpdate = TRUE;
super.Reset();
}
defaultproperties
{
TickGroup=TG_PostAsyncWork
SupportedEvents.Add(class'SeqEvent_RigidBodyCollision')
Begin Object Name=StaticMeshComponent0
WireframeColor=(R=0,G=255,B=128,A=255)
BlockRigidBody=true
RBChannel=RBCC_GameplayPhysics
RBCollideWithChannels=(Default=TRUE,BlockingVolume=TRUE,GameplayPhysics=TRUE,EffectPhysics=TRUE)
bBlockFootPlacement=false
End Object
bDamageAppliesImpulse=true
bNetInitialRotation=true
Physics=PHYS_RigidBody
bStatic=false
bCollideWorld=false
bProjTarget=true
bBlockActors=true
bWorldGeometry=false
bNoDelete=true
bAlwaysRelevant=true
bSkipActorPropertyReplication=false
bUpdateSimulatedPosition=true
bReplicateMovement=true
RemoteRole=ROLE_SimulatedProxy
bCollideActors=true
bNoEncroachCheck=true
bBlocksTeleport=true
bBlocksNavigation=true
bPawnCanBaseOn=false
bSafeBaseIfAsleep=TRUE
bNeedsRBStateReplication=true
StayUprightTorqueFactor=1000.0
StayUprightMaxTorque=1500.0
MaxPhysicsVelocity=350.0
ReplicatedDrawScale3D=(X=1000.0,Y=1000.0,Z=1000.0) // set so that default scale of (1,1,1) doesn't replicate anything
bDisableClientSidePawnInteractions=TRUE
}