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

290 lines
7.5 KiB
Ucode

//=============================================================================
// KFSM_Frozen
//=============================================================================
// Used to stop a zed from moving and play a freeze and thaw animation
// for a random amount of time
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// - Jeff Robinson
//=============================================================================
class KFSM_Frozen extends KFSpecialMove;
var() name FrozenAnim;
var() array<name> ThawAnims;
var() float FreezeInTime, FreezeOutTime;
var() Vector2D FreezeDuration;
var float BeginFreezePhaseTime;
var float FreezeMatParamValue;
var protected ParticleSystem FrozenSteamTemplate;
var protected ParticleSystemComponent FrozenSteamEffect;
var protected bool bIsThawing;
var bool bOwnerCouldCloak;
/** Notification called when Special Move starts */
function SpecialMoveStarted(bool bForced, Name PrevMove )
{
super.SpecialMoveStarted( bForced, PrevMove );
bIsThawing = false;
DoFreeze();
}
/** Stop the movement and play the stun animation for all clients */
function DoFreeze()
{
local float TimeUntilThaw;
if ( KFPOwner.Role == ROLE_Authority )
{
// Disable Movement by using the DefaultAICommandClass to call LockdownAI()
TimeUntilThaw = KFPOwner.IncapSettings[AF_Freeze].Duration > 0 ? KFPOwner.IncapSettings[AF_Freeze].Duration : RandRange(FreezeDuration.X, FreezeDuration.Y);
KFPOwner.SetTimer(TimeUntilThaw, false, nameof(DoThaw), self);
// Disable cloaking
KFPOwner.SetCloaked( false );
bOwnerCouldCloak = KFPOwner.bCanCloak;
KFPOwner.bCanCloak = false;
}
if ( PawnOwner.WorldInfo.NetMode != NM_DedicatedServer )
{
BeginFreezePhaseTime = KFPOwner.WorldInfo.TimeSeconds;
KFPOwner.SetTimer( 0.1f, true, nameof(UpdateFreezeInParam), self );
FrozenSteamEffect = KFPOwner.WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment(FrozenSteamTemplate, KFPOwner.Mesh, 'root');
}
// use a really slow rate to emulate being frozen
PlaySpecialMoveAnim( FrozenAnim, EAS_FullBody, FreezeInTime, 0.3f, 0.001f, true );
}
/* Play a random wakeup animation */
function DoThaw()
{
local KFPawn_Monster P;
if ( PawnOwner.Role == ROLE_Authority )
{
// if pawn's head has already been blown off, skip thawing
P = KFPawn_Monster(PawnOwner);
if( P != None && P.bIsHeadless )
{
P.BleedOutTimer();
}
else
{
KFPOwner.SpecialMoveFlags = 1 + Rand( ThawAnims.Length );
KFPOwner.ReplicatedSpecialMove.Flags = KFPOwner.SpecialMoveFlags;
PlayThawAnimation();
}
}
}
/* Play a random wakeup animation */
function PlayThawAnimation()
{
local byte ThawIndex;
ThawIndex = KFPOwner.SpecialMoveFlags - 1;
PlaySpecialMoveAnim(ThawAnims[ThawIndex], EAS_FullBody, FreezeOutTime, 0.3f, 0.5f, false);
bIsThawing = true;
if ( PawnOwner.WorldInfo.NetMode != NM_DedicatedServer )
{
BeginFreezePhaseTime = KFPOwner.WorldInfo.TimeSeconds;
KFPOwner.SetTimer( 0.1f, true, nameof(UpdateFreezeOutParam), self );
// Match the material param blend time to the animation length
FreezeOutTime = PawnOwner.Mesh.GetAnimLength(ThawAnims[ThawIndex]);
}
}
/* Play the wakeup animation for all clients */
function SpecialMoveFlagsUpdated()
{
PlayThawAnimation();
}
function UpdateFreezeInParam()
{
local float Param;
Param = FMin( 1.f, (KFPOwner.WorldInfo.TimeSeconds - BeginFreezePhaseTime) / FreezeInTime );
SetFrozenParameter(Param);
if( Param == 1.f )
{
KFPOwner.ClearTimer( nameof(UpdateFreezeInParam), self );
}
}
function UpdateFreezeOutParam()
{
local float Param;
Param = 1.f - FMin( 1.f, (KFPOwner.WorldInfo.TimeSeconds - BeginFreezePhaseTime) / FreezeOutTime );
SetFrozenParameter(Param);
if( Param == 0.f )
{
KFPOwner.ClearTimer( nameof(UpdateFreezeOutParam), self );
}
}
/** Notification called when Special Move starts when ReplicatedSpecialMove changes*/
function SpecialMoveEnded(Name PrevMove, Name NextMove)
{
super.SpecialMoveEnded( PrevMove, NextMove );
if ( KFPOwner.WorldInfo.NetMode != NM_DedicatedServer )
{
KFPOwner.DetachEmitter( FrozenSteamEffect );
// if we're dead, shatter
if( !KFPOwner.IsAliveAndWell() )
{
PlayDeathEffects();
KFPOwner.ClearTimer( nameof(UpdateFreezeOutParam), self );
}
else if( !bIsThawing ) // Just in case the special move was ended prematurely, we still need to stop the freeze effect
{
BeginFreezePhaseTime = KFPOwner.WorldInfo.TimeSeconds;
FreezeOutTime = 0.5f;
KFPOwner.SetTimer( 0.1f, true, nameof(UpdateFreezeOutParam), self );
}
}
// Restore cloaking flag
if( KFPOwner.Role == ROLE_Authority )
{
KFPOwner.bCanCloak = bOwnerCouldCloak;
}
KFPOwner.ClearTimer( nameof(UpdateFreezeInParam), self );
KFPOwner.ClearTimer( nameof(DoThaw), self );
}
/** Reapply material param (e.g. headless or head chunk during freeze) */
function OnGoreMeshSwap()
{
SetFrozenParameter(FreezeMatParamValue);
}
/** Enable/Disable the Frozen material effect */
function SetFrozenParameter(float FreezeAmount)
{
local MaterialInstanceConstant MIC;
local int i;
if ( PawnOwner.WorldInfo.NetMode != NM_DedicatedServer )
{
FreezeMatParamValue = FreezeAmount;
foreach KFPOwner.CharacterMICs(MIC)
{
MIC.SetScalarParameterValue( 'Scalar_Ice', FreezeMatParamValue );
}
for (i = 0; i < `MAX_COSMETIC_ATTACHMENTS; ++i)
{
if (KFPOwner.ThirdPersonAttachments[i] != none)
{
ApplyFreeze(KFPOwner.ThirdPersonAttachments[i]);
}
}
if (KFPawn_Monster(KFPOwner) != none)
{
for (i = 0; i < KFPawn_Monster(KFPOwner).StaticAttachList.length; i++)
{
if (KFPawn_Monster(KFPOwner).StaticAttachList[i] != none)
{
ApplyFreeze(KFPawn_Monster(KFPOwner).StaticAttachList[i]);
}
}
}
}
}
function ApplyFreeze(MeshComponent MeshToFreeze)
{
local MaterialInstanceConstant MIC;
local int i;
for (i = 0; i < MeshToFreeze.Materials.Length; i++)
{
MIC = MaterialInstanceConstant(MeshToFreeze.GetMaterial(i));
if (MIC != none)
{
MIC.SetScalarParameterValue('Scalar_Ice', FreezeMatParamValue);
}
}
}
/** Do shatter VFX & Gore on death */
function PlayDeathEffects()
{
if ( PawnOwner.WorldInfo.NetMode == NM_DedicatedServer )
{
return;
}
// As long as we were killed by a weapon, add some VFX
if ( PawnOwner.HitDamageType != class'KFDT_Bleeding' )
{
// This happens "just" before ragdoll death is triggered
class'KFDT_Freeze'.static.PlayShatter(KFPOwner, false);
}
else
{
PawnOwner.SetTimer(0.5f, false, nameof(DelayedShatterTimer), self);
}
}
function DelayedShatterTimer()
{
class'KFDT_Freeze'.static.PlayShatter(KFPOwner, true);
}
function bool CanOverrideSpecialMove( Name InMove )
{
if (InMove == 'KFSM_Block')
{
return TRUE;
}
return FALSE;
}
defaultproperties
{
Handle=KFSM_Frozen
FrozenAnim=Stun_Loop_V1
ThawAnims.Add(Stun_Wakeup_V1)
ThawAnims.Add(Stun_Wakeup_V2)
ThawAnims.Add(Stun_Wakeup_V3)
FreezeDuration=(X=3,Y=5)
FreezeInTime=0.5
FreezeOutTime=1
bAllowHitReactions=FALSE
bDisableMovement=TRUE
bLockPawnRotation=TRUE
DefaultAICommandClass=class'KFGame.AICommand_PushedBySM'
bDisablesWeaponFiring=true
bCanOnlyWanderAtEnd=true
FrozenSteamTemplate=ParticleSystem'WEP_Freeze_Grenade_EMIT.FX_Freeze_Grenade_Smoke'
}