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

422 lines
10 KiB
Ucode

//=============================================================================
// KFRepairableActor
//=============================================================================
// Class for any actor that can be repaired with the welder.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2018 Tripwire Interactive LLC
//=============================================================================
class KFRepairableActor extends KFWeldableActor
hidecategories(Collision, Physics, Object, Mobile)
placeable
native;
var KFRepairableActorTrigger RepairTrigger;
var() const StaticMesh RepairedMesh;
var() const StaticMesh BrokenMesh;
var() StaticMeshComponent RepairableActorMesh;
var() StaticMeshComponent WeldComponent;
var() FXTemplate BreakingEmitterTemplate;
var() FXTemplate BrokenEmitterTemplate;
var ParticleSystemComponent BrokenEmitter;
var() array<AkEvent> ActivationSoundEvents;
var() array<AkEvent> CompletionSoundEvents;
var() array<AkEvent> ResetSoundEvents;
var() vector IconLocationOffset;
var transient bool bRepairComplete;
// bSkipActorPropertyReplication=true prevents bHidden from being replicated automatically,
// so we'll do it ourselves anyway
var transient repnotify bool bHidden_Replicated;
delegate OnRepairCompelete(KFRepairableActor RepairedActor);
cpptext
{
virtual void PostLoad();
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent);
}
replication
{
if (bNetDirty)
bHidden_Replicated;
}
simulated event ReplicatedEvent(name VarName)
{
switch (VarName)
{
case nameof(bHidden_Replicated):
SetHidden(bHidden_Replicated);
break;
default:
super.ReplicatedEvent(VarName);
};
}
simulated private native function SetupComponents();
simulated function PostBeginPlay()
{
local StaticMesh DefaultMesh;
super.PostBeginPlay();
DefaultMesh = RepairableActorMesh.StaticMesh;
SetupComponents();
InitializeIntegrityMIC();
Reset();
if (DefaultMesh != none)
{
// Reset() sets static mesh to RepairedMesh, but we don't want that initially
SetStaticMesh(DefaultMesh);
}
}
simulated function InitializeIntegrityMIC()
{
if (WeldComponent != none && WeldComponent.GetMaterial(0) != none)
{
IntegrityMIC = WeldComponent.CreateAndSetMaterialInstanceConstant(0);
IntegrityMIC.SetScalarParameterValue('Weld', 0.f);
UpdateIntegrityMIC();
}
}
simulated function InitializeRepairableActorMIC()
{
local int MaterialIndex;
local MaterialInstanceConstant NewMIC;
if (WorldInfo.NetMode == NM_DedicatedServer)
{
return;
}
if (RepairableActorMesh == none)
{
return;
}
for (MaterialIndex = 0; MaterialIndex < RepairableActorMesh.GetNumElements(); MaterialIndex++)
{
if(RepairableActorMesh.GetMaterial(MaterialIndex) != none)
{
NewMIC = new class'MaterialInstanceConstant';
NewMIC.SetParent(RepairableActorMesh.GetMaterial(MaterialIndex));
RepairableActorMesh.SetMaterial(MaterialIndex, NewMIC);
}
}
}
simulated function InitializeWeldableComponent()
{
WeldableComponent.SetOwner(self);
WeldableComponent.MaxWeldIntegrity = MaxWeldIntegrity;
WeldableComponent.bWeldable = true;
WeldableComponent.Delegate_OnWeldIntegrityChanged = OnWeldCompWeldIntegrityChanged;
// grab the weldintegrity from the weldable component in case it changed
// before we were able to set the delegate above
WeldIntegrity = WeldableComponent.WeldIntegrity;
WeldableComponent.SetCollisionCylinderSize(200, 200);
}
simulated function OnWeldCompWeldIntegrityChanged(int Amount, KFPawn Welder)
{
if (Role == ROLE_Authority)
{
FastenWeld(Amount, Welder);
}
else
{
WeldIntegrity = WeldableComponent.WeldIntegrity;
UpdateIntegrityMIC();
}
}
function Repair(float Amount, optional KFPawn Welder)
{
FastenWeld(Amount, Welder);
}
function FastenWeld(int Amount, optional KFPawn Welder)
{
// not allowed to unfasten object.
if (Amount > 0 && WeldIntegrity < MaxWeldIntegrity)
{
UpdateWeldIntegrity(Amount);
if (!BeingUnwelded())
{
if (!BeingWelded())
{
WelderPawn = Welder;
}
}
if (WelderPawn == Welder)
{
LastWeldTime = WorldInfo.TimeSeconds;
}
}
if (WeldIntegrity >= MaxWeldIntegrity)
{
CompleteRepair();
}
}
simulated function SetStaticMesh(StaticMesh NewMesh)
{
local int i;
// Change the mesh on client and server so that collision is synced up for welding
if(RepairableActorMesh != none)
{
RepairableActorMesh.SetStaticMesh(NewMesh);
// Need to set materials to none so GetMaterial (called by InitializeRepairableActorMIC)
// actually gets materials from static mesh instead of from materials array. Can't just empty
// array because it's const.
for (i = 0; i < RepairableActorMesh.Materials.Length; ++i)
{
RepairableActorMesh.SetMaterial(i, None);
}
// Re-initialize materials array
InitializeRepairableActorMIC();
bForceNetUpdate = true;
}
}
simulated function PlayDestroyed()
{
local AkEvent ActivationSound;
if (Role == ROLE_Authority)
{
bIsDestroyed = true;
bWasRepaired = false;
bRepairComplete = false;
UpdateWeldIntegrity(-WeldIntegrity);
WeldableComponent.SetDestroyed(true);
WeldableComponent.SetWeldIntegrity(0);
foreach ActivationSoundEvents(ActivationSound)
{
PlaySoundBase(ActivationSound,, WorldInfo.NetMode == NM_DedicatedServer);
}
}
SetStaticMesh(BrokenMesh);
if(WorldInfo.NetMode != NM_DedicatedServer)
{
if (BreakingEmitterTemplate.ParticleTemplate != none)
{
WorldInfo.MyEmitterPool.SpawnEmitter(BreakingEmitterTemplate.ParticleTemplate, Location + BreakingEmitterTemplate.RelativeOffset, BreakingEmitterTemplate.RelativeRotation);
}
if (BrokenEmitterTemplate.ParticleTemplate != none)
{
BrokenEmitter = WorldInfo.MyEmitterPool.SpawnEmitter(BrokenEmitterTemplate.ParticleTemplate, Location + BrokenEmitterTemplate.RelativeOffset, BrokenEmitterTemplate.RelativeRotation);
}
}
// activate kismet event
OnKismetEvent(ERepairableActorEvent_Activated);
}
simulated function CompleteRepair()
{
if (Role == ROLE_Authority)
{
bRepairComplete = true;
bForceNetUpdate = true;
}
Reset();
if (RepairFXTemplate.ParticleTemplate != none)
{
WorldInfo.MyEmitterPool.SpawnEmitter(RepairFXTemplate.ParticleTemplate, Location + RepairFXTemplate.RelativeOffset);
}
OnRepairCompelete(self);
// repaired kismet event
OnKismetEvent(ERepairableActorEvent_Repaired);
}
simulated function Reset()
{
local AkEvent CompletionSound, ResetSound;
if (Role == ROLE_Authority)
{
WeldIntegrity = MaxWeldIntegrity;
bIsDestroyed = false;
bWasRepaired = true;
WeldableComponent.SetWeldIntegrity(MaxWeldIntegrity);
WeldableComponent.SetDestroyed(false);
if (bRepairComplete)
{
foreach CompletionSoundEvents(CompletionSound)
{
PlaySoundBase(CompletionSound,, WorldInfo.NetMode == NM_DedicatedServer);
}
}
else
{
foreach ResetSoundEvents(ResetSound)
{
PlaySoundBase(ResetSound,, WorldInfo.NetMode == NM_DedicatedServer);
}
}
}
if (BrokenEmitter != none)
{
BrokenEmitter.DeactivateSystem();
BrokenEmitter = none;
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
SetStaticMesh(RepairedMesh);
}
}
simulated function UpdateIntegrityMIC()
{
local float IntegrityScalar;
if (IntegrityMIC != none)
{
if (WeldIntegrity > 0)
{
IntegrityScalar = float(WeldIntegrity) / float(MaxWeldIntegrity);
}
else
{
IntegrityScalar = 0;
}
IntegrityMIC.SetScalarParameterValue('Weld', IntegrityScalar);
if (WeldComponent != none)
{
if (WeldComponent.HiddenGame && WeldIntegrity > 0)
{
WeldComponent.SetHidden(false);
}
else
{
WeldComponent.SetHidden(true);
}
}
}
}
/** Handler for SeqAct_ToggleHidden, just sets bHidden. */
simulated function OnToggleHidden(SeqAct_ToggleHidden Action)
{
super.OnToggleHidden(Action);
// replicate bHidden here, because bSkipActorPropertyReplication=true prevents it from happening automatically
if (Role == ROLE_Authority)
{
bHidden_Replicated = bHidden;
}
}
simulated function OnKismetEvent(int EventType)
{
local int i;
local array<int> OutputLinksToActivate;
local KFSeqEvent_RepairableActor ProgressEvent;
OutputLinksToActivate.AddItem(EventType);
for (i = 0; i < GeneratedEvents.Length; i++)
{
ProgressEvent = KFSeqEvent_RepairableActor(GeneratedEvents[i]);
if (ProgressEvent != none)
{
ProgressEvent.Reset();
ProgressEvent.CheckActivate(self, self, , OutputLinksToActivate);
}
}
}
defaultproperties
{
Physics=PHYS_None
bEdShouldSnap=true
bStatic=false
bNoDelete=true
bTickIsDisabled=true
RemoteRole = ROLE_SimulatedProxy
bAlwaysRelevant=true
bOnlyDirtyReplication=true
bSkipActorPropertyReplication=true
bIgnoreNetRelevancyCollision=true
NetUpdateFrequency=0.1
bReplicateRigidBodyLocation=true
bCollideActors=true
bBlockActors=true
bWorldGeometry=true
bCollideWorld=false
bNoEncroachCheck=false
bProjTarget=false
bCanStepUpOn=false
bMovable=false
MaxWeldIntegrity=1500
BreakingEmitterTemplate=(ParticleTemplate=ParticleSystem'FX_Gore_EMIT_THREE.FX_HeadExplode_dh_px')
BrokenEmitterTemplate=(ParticleTemplate=ParticleSystem'FX_Environmental_EMIT_THREE.FX_Carnival_Electric_Malfunction_01')
RepairFXTemplate=(ParticleTemplate=ParticleSystem'FX_Environmental_EMIT_THREE.FX_Carnival_Game_Entry_01')
Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
bAllowApproximateOcclusion=TRUE
bForceDirectLightMap=TRUE
bUsePrecomputedShadows=TRUE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
// Collision
CollideActors=TRUE
BlockActors=TRUE
BlockRigidBody=TRUE
RBChannel=RBCC_GameplayPhysics
RBCollideWithChannels=(Default=TRUE,GameplayPhysics=TRUE,EffectPhysics=TRUE,DeadPawn=FALSE,Pickup=TRUE,FlexAsset=FALSE)
End Object
RepairableActorMesh=StaticMeshComponent0
Begin Object Class=StaticMeshComponent Name=StaticMeshComponent1
bAllowApproximateOcclusion=TRUE
bForceDirectLightMap=TRUE
bUsePrecomputedShadows=TRUE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
CollideActors=FALSE
BlockRigidBody=FALSE
End Object
WeldComponent=StaticMeshComponent1
SupportedEvents.Add(class'KFSeqEvent_RepairableActor')
}