//============================================================================= // KFMGA_AnimatedTrap //============================================================================= // Any trap-style minigame event that uses a similar idle/activate/deactivate // set of animations. Manually handles movement to avoid client/server // collision disagreements for collision assumed to be moving via-anims, // or problems typical of client/server matinees. //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC // - Dan Weiss //============================================================================= class KFMGA_AnimatedTrap extends SkeletalMeshActor placeable implements(KFInterface_MinigameActor); /** Animation looping while the game is in the deactivated state. Plays into activation. */ var() name DeactivatedIdleAnim; /** Animation triggered when activation begins. Plays into activated idle. */ var() name ActivationAnim; /** Animation looping while in the activated state. Plays into deactivation. */ var() name ActivatedIdleAnim; /** Animation triggered when deactivating. Plays into deactivated idle. */ var() name DeactivationAnim; /** Activation state */ var repnotify bool bActivated; /** Amount to move to rest/back to original */ var() Vector MovementVector; /** Amount of time to handle move */ var() float MovementTime; /** Movement curve */ var InterpCurveVector MovementCurve; /** Sounds for start and end of various phases */ var() AkEvent ActivationStart; var() AkEvent ActivationEnd; var() AkEvent DeactivationStart; var() AkEvent DeactivationEnd; var AkComponent CageSFXComponent; var AkEvent CurStartSound; var AkEvent CurEndSound; /** VFX for start and end of various phases */ var() ParticleSystemComponent ActivationStartFX; var() ParticleSystemComponent ActivationEndFX; var() ParticleSystemComponent DeactivationStartFX; var() ParticleSystemComponent DeactivationEndFX; var ParticleSystemComponent CurStartFX; var ParticleSystemComponent CurEndFX; replication { if (Role == ROLE_Authority) bActivated; } simulated event ReplicatedEvent(name VarName) { super.ReplicatedEvent(VarName); if (VarName == 'bActivated') { if (bActivated) { PlayActivation(); } else { PlayDeactivation(); } } } simulated event PostBeginPlay() { super.PostBeginPlay(); SkeletalMeshComponent.PlayAnim(DeactivatedIdleAnim, , true); SetTickIsDisabled(false); } /** Called on rigged games to check whether a target at a specific bone can be played */ simulated event bool CanPlayAkEvent(Actor inOwner, name BoneName) { return true; } function Activated(KFTrigger_MinigameButton ActivationSource) { if (!bActivated) { ClearTimer('PlayDeactivationIdle'); bActivated = true; PlayActivation(); } } function Deactivated() { if (bActivated) { ClearTimer('ActivationIdle'); bActivated = false; PlayDeactivation(); } } /** Bunch of animation code. Activation->Idle and Deactivation->Idle basically work as pairs trigged by a minigame button. */ simulated function PlayActivation() { SkeletalMeshComponent.StopAnim(); if (ActivationAnim != '') { SetTimer(SkeletalMeshComponent.GetAnimLength(ActivationAnim), false, 'PlayActivationIdle'); SkeletalMeshComponent.PlayAnim(ActivationAnim); } else { PlayActivationIdle(); } CurStartSound = ActivationStart; CurEndSound = ActivationEnd; CurStartFX = ActivationStartFX; CurEndFX = ActivationEndFX; SetMoveActivationCurve(); } simulated function PlayActivationIdle() { SkeletalMeshComponent.StopAnim(); if (ActivatedIdleAnim != '') { SkeletalMeshComponent.PlayAnim(ActivatedIdleAnim,,true); } } simulated function PlayDeactivation() { SkeletalMeshComponent.StopAnim(); if (DeactivationAnim != '') { SetTimer(SkeletalMeshComponent.GetAnimLength(DeactivationAnim), false, 'PlayDeactivationIdle'); SkeletalMeshComponent.PlayAnim(DeactivationAnim); } else { PlayDeactivationIdle(); } CurStartSound = DeactivationStart; CurEndSound = DeactivationEnd; CurStartFX = DeactivationStartFX; CurEndFX = DeactivationEndFX; SetMoveDeactivationCurve(); } simulated function PlayDeactivationIdle() { SkeletalMeshComponent.StopAnim(); if (DeactivatedIdleAnim != '') { SkeletalMeshComponent.PlayAnim(DeactivatedIdleAnim, , true); } } /** Curves for movement in and out of the activated idle point */ simulated function SetMoveActivationCurve() { MovementCurve.Points.Length = 2; MovementCurve.Points[0].InVal = 0; MovementCurve.Points[0].OutVal = Location; MovementCurve.Points[0].InterpMode = CIM_CurveAuto; MovementCurve.Points[1].InVal = MovementTime; MovementCurve.Points[1].OutVal = Location + MovementVector; MovementCurve.Points[1].InterpMode = CIM_CurveAuto; GoToState('Moving'); } simulated function SetMoveDeactivationCurve() { MovementCurve.Points.Length = 2; MovementCurve.Points[0].InVal = 0; MovementCurve.Points[0].OutVal = Location; MovementCurve.Points[0].InterpMode = CIM_CurveAuto; MovementCurve.Points[1].InVal = MovementTime; MovementCurve.Points[1].OutVal = Location - MovementVector; MovementCurve.Points[1].InterpMode = CIM_CurveAuto; GoToState('Moving'); } /** Only allow activation while not in the moving state */ function bool CanBeActivated(KFTrigger_MinigameButton ActivationSource) { return true; } simulated function EndMovement(); simulated state Moving { simulated event BeginState(Name PreviousStateName) { super.BeginState(PreviousStateName); SetTimer(MovementTime, false, 'EndMovement'); CageSFXComponent.PlayEvent(CurStartSound, , false, true); CurStartFX.ActivateSystem(true); } simulated event Tick(float DeltaTime) { local float TimerCount; global.Tick(DeltaTime); //Watch for return to 0 on last tick when timer finishes TimerCount = GetTimerCount('EndMovement'); if (TimerCount > 0) { SetLocation(EvalInterpCurveVector(MovementCurve, TimerCount)); } } simulated function EndMovement() { CageSFXComponent.PlayEvent(CurEndSound, , false, true); CurEndFX.ActivateSystem(true); GoToState('Auto'); } /** Don't allow activation while it's moving */ function bool CanBeActivated(KFTrigger_MinigameButton ActivationSource) { return false; } } defaultproperties { RemoteRole = ROLE_SimulatedProxy NetPriority = +00002.500000 bUpdateSimulatedPosition = true bAlwaysRelevant = true Begin Object class=AkComponent Name=CageSFX0 End Object CageSFXComponent=CageSFX0 Components.Add(CageSFX0) Begin Object class=ParticleSystemComponent Name=PSC0 bAutoActivate=false End Object ActivationStartFX=PSC0 Components.Add(PSC0) Begin Object class=ParticleSystemComponent Name=PSC1 bAutoActivate=false End Object ActivationEndFX=PSC1 Components.Add(PSC1) Begin Object class=ParticleSystemComponent Name=PSC2 bAutoActivate=false End Object DeactivationStartFX=PSC2 Components.Add(PSC2) Begin Object class=ParticleSystemComponent Name=PSC3 bAutoActivate=false End Object DeactivationEndFX=PSC3 Components.Add(PSC3) }