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

369 lines
9.0 KiB
Ucode

//=============================================================================
// KFSM_DAR_EMPAttack
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2018 Tripwire Interactive LLC
//=============================================================================
class KFSM_DAR_EMPAttack extends KFSM_RangedAttack;
struct EMPBlastHitInfo
{
var Actor HitActor;
var vector HitLocation;
var TraceHitInfo HitInfo;
};
/** Template for the EMP */
var const ParticleSystem EMPPSCTemplate;
/** PSC generated from the EMP template. Gets recycled in and out of the emitter pool as needed. */
var ParticleSystemComponent EMPPSC;
/** Template for EMP hit location FX */
var const ParticleSystem EMPHitPSCTemplate;
/** PSC for the hit location. On when the EMP is hitting anything, off when missing everything */
var ParticleSystemComponent EMPHitPSC;
/** AK Event for start of EMP charge */
var AkEvent EMPStartSFX;
/** AK Event for end of special move */
var AkEvent EMPEndSFX;
/** Looping sound for EMP hit */
var AkEvent EMPHitSFX;
var AkEvent EMPHitStopSFX;
/** Camera shake impact */
var CameraShake EMPHitShake;
/** Socket to attach origin of EMP */
var const name EMPSocketName;
/** Damagetype used for beam attack */
var const class<KFDamageType> EMPDamageType;
/** The maximum length the beam can be (used both for FX and damage) */
var const float MaxEMPLength;
/** The width, height, and depth of the beam, used for damage traces */
var const vector EMPExtent;
/** The total amount of damage an EMP blast will do. */
var int EMPDamage;
/** Cached list of all pawns hit by the EMP Blast. */
var array<EMPBlastHitInfo> Victims;
/** The amount of time after the beam is created before we apply damage. */
var float ApplyDamageDelay;
/** Draws a debug line between the beam's start and end points */
var const bool bDrawDebugEMP;
/** How long will a victim be grappled. */
var float GrappleTime;
function SpecialMoveStarted(bool bForced, name PrevMove)
{
super(KFSM_PlaySingleAnim).SpecialMoveStarted(bForced, PrevMove);
KFPOwner.UpdateGameplayMICParams();
KFPOwner.SetWeaponAmbientSound(EMPStartSFX);
Victims.length = 0;
}
function SpecialMoveEnded(name PrevMove, name NextMove)
{
super.SpecialMoveEnded(PrevMove, NextMove);
DisableEMP();
if (KFPOwner != none && KFPOwner.IsAliveAndWell())
{
KFPOwner.UpdateGameplayMICParams();
if( KFPOwner.IsWeaponAmbientSoundPlaying(EMPStartSFX) )
{
KFPOwner.SetWeaponAmbientSound(EMPEndSFX);
}
}
KFPOwner.FlushPersistentDebugLines();
}
function ToggleEMP(bool bEnabled)
{
local ParticleSysParam SourceParam;
local vector EMPEnd;
local int bHitTarget;
if (bEnabled)
{
DoEMPHit(EMPEnd, bHitTarget);
if (KFPOwner.WorldInfo.NetMode != NM_DedicatedServer)
{
if (EMPPSCTemplate != none)
{
EMPPSC = KFPOwner.WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment(EMPPSCTemplate, KFPOwner.Mesh, EMPSocketName, true);
if (EMPPSC != none)
{
SourceParam.Name = 'SourceActor';
SourceParam.ParamType = PSPT_Actor;
SourceParam.Actor = KFPOwner;
EMPPSC.InstanceParameters.Length = 0;
EMPPSC.InstanceParameters.AddItem(SourceParam);
DoEMPEffects(EMPEnd, bool(bHitTarget));
}
}
}
}
else
{
DisableEMP();
KFPOwner.SetWeaponAmbientSound(EMPEndSFX);
}
}
function DisableEMP()
{
ReleaseVictims();
DeactivatePSC();
DeactivateHitPSC();
}
function bool IsValidTarget(Actor HitActor)
{
return (Pawn(HitActor) != none || (StaticMeshActor(HitActor) != none && !StaticMeshActor(HitActor).bResetCapable) || SkeletalMeshActor(HitActor) != none) && WithinRange(HitActor);
}
function bool WithinRange(Actor HitActor)
{
return VSizeSq(HitActor.Location - KFPOwner.Location) <= Square(MaxEMPLength);
}
function DoEMPHit(out vector out_EMPEnd, out int out_bHitTarget)
{
local vector SocketLocation;
local EMPBlastHitInfo BlastHitInfo;
local rotator SocketRot;
local array<EMPBlastHitInfo> HitList;
local vector HitLoc, HitNrm;
local Actor HitActor;
KFPOwner.Mesh.GetSocketWorldLocationAndRotation(EMPSocketName, SocketLocation, SocketRot);
out_bHitTarget = int(false);
out_EMPEnd = SocketLocation + vector(SocketRot) * MaxEMPLength;
// We set the InteractionPawn for this move specifically, by implementing GetInteractionPawn() in
// AICommand_DAR_EMPAttack:Command_SpecialMove
if (KFPOwner.InteractionPawn != none)
{
if (IsValidTarget(KFPOwner.InteractionPawn))
{
BlastHitInfo.HitActor = KFPOwner.InteractionPawn;
BlastHitInfo.HitLocation = KFPOwner.InteractionPawn.Location;
HitList.AddItem(BlastHitInfo);
}
}
else
{
GetEnemyByTrace(HitList, SocketLocation, out_EMPEnd);
}
foreach HitList(BlastHitInfo)
{
if (IsValidTarget(BlastHitInfo.HitActor))
{
HitActor = KFPOwner.Trace(HitLoc, HitNrm, BlastHitInfo.HitLocation, SocketLocation);
if (HitActor != BlastHitInfo.HitActor)
{
BlastHitInfo.HitLocation = HitLoc;
}
else
{
out_bHitTarget = int(true);
Victims.AddItem(BlastHitInfo);
}
}
}
if (HitList.length == 1)
{
out_EMPEnd = HitList[0].HitLocation - vect(0, 0, 64);
}
if (KFPOwner.Role == ROLE_Authority)
{
if (Victims.length > 0)
{
if (ApplyDamageDelay > 0)
{
KFPOwner.SetTimer(ApplyDamageDelay, false, 'ApplyDamage', self);
}
else
{
ApplyDamage();
}
}
}
}
function GetEnemyByTrace(out array<EMPBlastHitInfo> out_EMPBlastHitInfo, vector StartLocation, vector EndLocation)
{
local vector HitLocation, HitNormal;
local Actor HitActor;
local TraceHitInfo HitInfo;
local EMPBlastHitInfo BlastHitInfo;
out_EMPBlastHitInfo.length = 0;
HitActor = KFPOwner.Trace(HitLocation, HitNormal, EndLocation, StartLocation, , EMPExtent, HitInfo, KFPOwner.TRACEFLAG_Bullet);
if (HitActor != none)
{
if (IsValidTarget(HitActor))
{
BlastHitInfo.HitActor = HitActor;
BlastHitInfo.HitLocation = HitLocation;
BlastHitInfo.HitInfo = HitInfo;
out_EMPBlastHitInfo.AddItem(BlastHitInfo);
}
}
}
function ApplyDamage()
{
local EMPBlastHitInfo BlastHitInfo;
foreach Victims(BlastHitInfo)
{
if(BlastHitInfo.HitActor != none)
{
BlastHitInfo.HitActor.TakeDamage(EMPDamage, KFPOwner.Controller, BlastHitInfo.HitLocation, vector(KFPOwner.Rotation), EMPDamageType, BlastHitInfo.HitInfo, KFPOwner);
if (KFPawn(BlastHitInfo.HitActor) != none)
{
KFPawn(BlastHitInfo.HitActor).DoSpecialMove(SM_DARGrappleVictim, true, PawnOwner);
}
}
}
if (Victims.length > 0)
{
KFPOwner.SetTimer(GrappleTime, false, 'ReleaseVictims', self);
}
}
function ReleaseVictims()
{
local EMPBlastHitInfo BlastHitInfo;
foreach Victims(BlastHitInfo)
{
if (BlastHitInfo.HitActor != none && KFPawn(BlastHitInfo.HitActor) != none)
{
KFPawn(BlastHitInfo.HitActor).EndSpecialMove(SM_DARGrappleVictim);
}
}
Victims.length = 0;
}
function DoEMPEffects(vector EMPEnd, bool bHitTarget)
{
local vector SocketLoc;
local rotator SocketRot;
EMPPSC.SetBeamTargetPoint(0, EMPEnd, 0);
KFPOwner.Mesh.GetSocketWorldLocationAndRotation(EMPSocketName, SocketLoc, SocketRot);
if (bHitTarget)
{
if (EMPHitPSC == none && EMPHitPSCTemplate != none)
{
EMPHitPSC = KFPOwner.WorldInfo.MyEmitterPool.SpawnEmitter(EMPHitPSCTemplate, EMPEnd);
}
if (EMPHitPSC != none)
{
EMPHitPSC.SetAbsolute(true, true, false);
EMPHitPSC.SetTranslation(EMPEnd);
EMPHitPSC.SetRotation(Rotator(EMPEnd - SocketLoc));
}
}
else
{
DeactivateHitPSC();
}
if (bDrawDebugEMP)
{
KFPOwner.FlushPersistentDebugLines();
KFPOwner.DrawDebugLine(SocketLoc, EMPEnd, 100, 128, 255, true);
}
}
function bool DeactivatePSC()
{
if (EMPPSC != none && EMPPSC.bIsActive)
{
EMPPSC.DeactivateSystem();
EMPPSC = none;
return true;
}
return false;
}
function bool DeactivateHitPSC()
{
if (EMPHitPSC != none && EMPHitPSC.bIsActive)
{
EMPHitPSC.DeactivateSystem();
EMPHitPSC = none;
return true;
}
return false;
}
defaultproperties
{
Handle=KFSM_DAR_EMPAttack
// Animation
AnimNames.Add(Atk_Shoot_EMP_V1)
AnimStance=EAS_FullBody
bDisableSteering=false
bDisableMovement=true
bDisableTurnInPlace=true
bUseCustomRotationRate=true
CustomRotationRate=(Pitch=50000, Yaw=25000, Roll=50000)
EMPPSCTemplate=ParticleSystem'ZED_EvilDAR_EMIT.FX_EvilDar_Empblast_Beam'
EMPHitPSCTemplate=ParticleSystem'ZED_EvilDAR_EMIT.FX_EvilDar_Empblast_Impact'
EMPSocketName=EMP_Blast
EMPStartSFX=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_EMP_LP'
EMPEndSFX=AkEvent'WW_ZED_Evil_DAR.Stop_ZED_EvilDAR_SFX_EMP_LP'
EMPHitSFX=none
EMPHitStopSFX=none
EMPDamage=10;
EMPDamageType=class'KFDT_DAR_EMPBlast'
EMPExtent=(X=15.f, Y=15.f, Z=15.f)
MaxEMPLength = 2500.f
GrappleTime=2.5f //1.5
FireOffsets(0)=(X=0.f,Y=0,Z=0)
}