361 lines
11 KiB
Ucode
361 lines
11 KiB
Ucode
|
//=============================================================================
|
||
|
// KFSM_FleshpoundKing_ChestBeam
|
||
|
//=============================================================================
|
||
|
// Fleshpound king's chest beam attach. Beam particle code from
|
||
|
// KFSM_Matriarch_PlasmaCannon
|
||
|
//=============================================================================
|
||
|
// Killing Floor 2
|
||
|
// Copyright (C) 2017 Tripwire Interactive LLC
|
||
|
// - Matt 'Squirrlz' Farber
|
||
|
//=============================================================================
|
||
|
class KFSM_FleshpoundKing_ChestBeam extends KFSM_PlaySingleAnim;
|
||
|
|
||
|
/** Cached king pawn owner */
|
||
|
var KFPawn_ZedFleshpoundKing KingPawnOwner;
|
||
|
|
||
|
/** Template for the plasma beam */
|
||
|
var const ParticleSystem BeamPSCTemplate;
|
||
|
|
||
|
/** PSC generated from the beam template. Gets recycled in and out of the emitter pool as needed. */
|
||
|
var ParticleSystemComponent BeamPSC;
|
||
|
|
||
|
/** Template for beam hit location FX */
|
||
|
var const ParticleSystem BeamHitPSCTemplate;
|
||
|
|
||
|
/** PSC for the hit location. On when the beam is hitting anything, off when missing everything */
|
||
|
var ParticleSystemComponent BeamHitPSC;
|
||
|
|
||
|
/** AK Event for start of beam charge */
|
||
|
var AkEvent BeamStartSFX;
|
||
|
|
||
|
/** AK Event for end of special move */
|
||
|
var AkEvent BeamEndSFX;
|
||
|
|
||
|
/** Looping sound for beam hit */
|
||
|
var AkEvent BeamHitSFX;
|
||
|
var AkEvent BeamHitStopSFX;
|
||
|
|
||
|
/** Camera shake impact */
|
||
|
var CameraShake BeamHitShake;
|
||
|
|
||
|
/** Socket to attach origin of beam */
|
||
|
var const Name ChestBeamSocketName;
|
||
|
|
||
|
/** How much time to wait before attempting to sweep to a new target */
|
||
|
var const float TimeUntilTargetChange;
|
||
|
|
||
|
/** Damagetype used for beam attack */
|
||
|
var const class<KFDamageType> BeamDamageType;
|
||
|
|
||
|
/** The maximum length the beam can be (used both for FX and damage) */
|
||
|
var const float MaxBeamLength;
|
||
|
|
||
|
/** The width, height, and depth of the beam, used for damage traces */
|
||
|
var const vector BeamExtent;
|
||
|
|
||
|
/** How much time to wait between damage ticks */
|
||
|
var const float DamageInterval;
|
||
|
|
||
|
/** How much damage to deal per damage tick */
|
||
|
var const int DamagePerTick;
|
||
|
|
||
|
/** How much of a momentum impulse to apply each damage tick */
|
||
|
var const float DamageMomentumImpulse;
|
||
|
|
||
|
/** Draws a debug line between the beam's start and end points */
|
||
|
var const bool bDrawDebugBeam;
|
||
|
|
||
|
function SpecialMoveStarted( bool bForced, Name PrevMove )
|
||
|
{
|
||
|
super.SpecialMoveStarted(bForced, PrevMove);
|
||
|
|
||
|
// Attempt a sweep attack if we have multiple targets in front of us
|
||
|
if( KFPOwner.Role == ROLE_Authority )
|
||
|
{
|
||
|
KFPOwner.SetTimer( TimeUntilTargetChange, false, nameOf(Timer_AttemptTargetChange), self );
|
||
|
}
|
||
|
|
||
|
// Use custom FX/lights
|
||
|
KFPOwner.UpdateGameplayMICParams();
|
||
|
|
||
|
//Start KFP beam SFX
|
||
|
KFPOwner.SetWeaponAmbientSound(BeamStartSFX);
|
||
|
|
||
|
KingPawnOwner = KFPawn_ZedFleshpoundKing(KFPOwner);
|
||
|
}
|
||
|
|
||
|
/** Updates beam PSC */
|
||
|
function Tick( float DeltaTime )
|
||
|
{
|
||
|
super.Tick( DeltaTime );
|
||
|
|
||
|
if( KFPOwner.WorldInfo.NetMode != NM_DedicatedServer && BeamPSC != none && BeamPSC.bIsActive )
|
||
|
{
|
||
|
SetBeamTarget();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function bool IsValidBeamTarget(Actor HitActor)
|
||
|
{
|
||
|
//If we're a pawn or we're a non-resettable static mesh actor
|
||
|
return Pawn(HitActor) != none || (StaticMeshActor(HitActor) != none && !StaticMeshActor(HitActor).bResetCapable) || SkeletalMeshActor(HitActor) != none || StaticMeshCollectionActor(HitActor) != none;
|
||
|
}
|
||
|
|
||
|
function SetBeamTarget()
|
||
|
{
|
||
|
local vector SocketLoc, BeamEnd, HitLocation, HitNormal;
|
||
|
local rotator SocketRot;
|
||
|
local Actor HitActor;
|
||
|
local bool bShouldActivateHit;
|
||
|
|
||
|
KFPOwner.Mesh.GetSocketWorldLocationAndRotation( ChestBeamSocketName, SocketLoc, SocketRot );
|
||
|
BeamEnd = SocketLoc + vector(KFPOwner.Rotation) * MaxBeamLength; // for now use Pawn's rotation, I don't know why but this socket's rotation freaks out during the animation
|
||
|
|
||
|
bShouldActivateHit = false;
|
||
|
foreach KFPOwner.TraceActors(class'Actor', HitActor, HitLocation, HitNormal, BeamEnd, SocketLoc, BeamExtent, , KFPOwner.TRACEFLAG_Bullet)
|
||
|
{
|
||
|
//Beam will be stopped on all valid targets
|
||
|
if (IsValidBeamTarget(HitActor))
|
||
|
{
|
||
|
if (HitActor != none && HitActor.bCanBeDamaged)
|
||
|
{
|
||
|
BeamEnd = HitLocation - vect(0, 0, 64);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BeamEnd = HitLocation;
|
||
|
}
|
||
|
bShouldActivateHit = HitActor != none;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BeamPSC.SetBeamTargetPoint( 0, BeamEnd, 0 );
|
||
|
|
||
|
//Setup impact sound/fx if valid
|
||
|
if (bShouldActivateHit)
|
||
|
{
|
||
|
//Trigger sound and VFX at the same time, use the more reliable SFX
|
||
|
if (BeamHitPSC == none)
|
||
|
{
|
||
|
BeamHitPSC = KFPOwner.WorldInfo.MyEmitterPool.SpawnEmitter(BeamHitPSCTemplate, BeamEnd);
|
||
|
KingPawnOwner.BeamHitAC.PlayEvent(BeamHitSFX);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (BeamHitPSC != none && BeamHitPSC.bIsActive)
|
||
|
{
|
||
|
BeamHitPSC.DeactivateSystem();
|
||
|
BeamHitPSC = none;
|
||
|
KingPawnOwner.BeamHitAC.PlayEvent(BeamHitStopSFX);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Update location of sound/fx
|
||
|
if (BeamHitPSC != none)
|
||
|
{
|
||
|
BeamHitPSC.SetAbsolute(true, true, false);
|
||
|
BeamHitPSC.SetTranslation(BeamEnd);
|
||
|
BeamHitPSC.SetRotation(KFPOwner.Rotation);
|
||
|
}
|
||
|
|
||
|
if( bDrawDebugBeam )
|
||
|
{
|
||
|
KFPOwner.FlushPersistentDebugLines();
|
||
|
KFPOwner.DrawDebugLine( SocketLoc, BeamEnd, 100, 128, 255, true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function ToggleBeam( bool bEnable )
|
||
|
{
|
||
|
local ParticleSysParam SourceParam;
|
||
|
|
||
|
if( bEnable )
|
||
|
{
|
||
|
//Startup visual FX
|
||
|
if( BeamPSCTemplate != none)
|
||
|
{
|
||
|
BeamPSC = KFPOwner.WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment( BeamPSCTemplate, KFPOwner.Mesh, ChestBeamSocketName, true );
|
||
|
if( BeamPSC != none)
|
||
|
{
|
||
|
SourceParam.Name = 'SourceActor';
|
||
|
SourceParam.ParamType = PSPT_Actor;
|
||
|
SourceParam.Actor = KFPOwner;
|
||
|
BeamPSC.InstanceParameters.AddItem( SourceParam );
|
||
|
|
||
|
SetBeamTarget();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start damage timer. We'll do damage on the client too so we affect ragdolls!
|
||
|
KFPOwner.SetTimer( DamageInterval, true, nameOf(Timer_TickDamage), self );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DisableBeamFX();
|
||
|
|
||
|
// Stop dealing damage
|
||
|
KFPOwner.ClearTimer( nameOf(Timer_TickDamage), self );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Turns the beam particle system/sound OFF */
|
||
|
function DisableBeamFX()
|
||
|
{
|
||
|
if( BeamPSC != none && BeamPSC.bIsActive )
|
||
|
{
|
||
|
BeamPSC.DeactivateSystem();
|
||
|
BeamPSC = none;
|
||
|
}
|
||
|
|
||
|
if (BeamHitPSC != none)
|
||
|
{
|
||
|
BeamHitPSC.DeactivateSystem();
|
||
|
BeamHitPSC = none;
|
||
|
}
|
||
|
|
||
|
if (KingPawnOwner.BeamHitAC != none)
|
||
|
{
|
||
|
KingPawnOwner.BeamHitAC.StopEvents();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Timer_AttemptTargetChange()
|
||
|
{
|
||
|
local Pawn P, BestTarget;
|
||
|
local KFAIController_ZedFleshpoundKing KingFPController;
|
||
|
local vector PawnDir;
|
||
|
local float DotAngle, BestAngle;
|
||
|
|
||
|
PawnDir = vector( KFPOwner.Rotation );
|
||
|
|
||
|
foreach KFPOwner.WorldInfo.AllPawns( class'Pawn', P )
|
||
|
{
|
||
|
if( P != KFPOwner
|
||
|
&& P != AIOwner.Enemy
|
||
|
&& P.GetTeamNum() != KFPOwner.GetTeamNum()
|
||
|
&& P.IsAliveAndWell()
|
||
|
&& P.CanAITargetThisPawn(KFPOwner.Controller))
|
||
|
{
|
||
|
DotAngle = PawnDir dot Normal( P.Location - KFPOwner.Location );
|
||
|
if( DotAngle < 0.2f )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Choose the target furthest from the center to create the widest sweep
|
||
|
if( BestAngle == 0.f || DotAngle < BestAngle )
|
||
|
{
|
||
|
BestAngle = DotAngle;
|
||
|
BestTarget = P;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set our new target if we can
|
||
|
if( BestTarget != none )
|
||
|
{
|
||
|
KingFPController = KFAIController_ZedFleshpoundKing( AIOwner );
|
||
|
if( KingFPController != none )
|
||
|
{
|
||
|
KingFPController.ForceTargetChange( BestTarget );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Timer_TickDamage()
|
||
|
{
|
||
|
local vector SocketLoc, BeamDir, EndTrace, HitLocation, HitNormal;
|
||
|
local rotator SocketRot;
|
||
|
local Actor HitActor;
|
||
|
local TraceHitInfo HitInfo;
|
||
|
|
||
|
KFPOwner.Mesh.GetSocketWorldLocationAndRotation( ChestBeamSocketName, SocketLoc, SocketRot );
|
||
|
BeamDir = vector( KFPOwner.Rotation ); // for now use Pawn's rotation, I don't know why but this socket's rotation freaks out during the animation
|
||
|
EndTrace = SocketLoc + BeamDir * MaxBeamLength;
|
||
|
|
||
|
foreach KFPOwner.TraceActors(class'Actor', HitActor, HitLocation, HitNormal, EndTrace, SocketLoc, BeamExtent, , KFPOwner.TRACEFLAG_Bullet)
|
||
|
{
|
||
|
//Beam will be stopped on all valid targets
|
||
|
if (IsValidBeamTarget(HitActor))
|
||
|
{
|
||
|
if (HitActor.bCanBeDamaged)
|
||
|
{
|
||
|
HitActor.TakeDamage(DamagePerTick, KFPOwner.Controller, HitLocation, BeamDir*DamageMomentumImpulse, BeamDamageType, HitInfo, KFPOwner);
|
||
|
if (Pawn(HitActor) != none && PlayerController(Pawn(HitActor).Controller) != none)
|
||
|
{
|
||
|
PlayerController(Pawn(HitActor).Controller).ClientPlayCameraShake(BeamHitShake, 1.f, true);
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function SpecialMoveEnded( Name PrevMove, Name NextMove )
|
||
|
{
|
||
|
super.SpecialMoveEnded(PrevMove, NextMove);
|
||
|
|
||
|
ToggleBeam(false);
|
||
|
|
||
|
//Start KFP beam SFX
|
||
|
KFPOwner.SetWeaponAmbientSound(BeamEndSFX);
|
||
|
|
||
|
// Restore FX/lights
|
||
|
if( KFPOwner != none && KFPOwner.IsAliveAndWell() )
|
||
|
{
|
||
|
KFPOwner.UpdateGameplayMICParams();
|
||
|
}
|
||
|
|
||
|
KFPOwner.FlushPersistentDebugLines(); // temp, @todo: remove
|
||
|
}
|
||
|
|
||
|
|
||
|
DefaultProperties
|
||
|
{
|
||
|
// ---------------------------------------------
|
||
|
// SpecialMove
|
||
|
Handle=KFSM_FleshpoundKing_ChestBeam
|
||
|
AnimName=Atk_ChestBeam
|
||
|
AnimStance=EAS_FullBody
|
||
|
bDisableSteering=false
|
||
|
bDisableMovement=true
|
||
|
bDisableTurnInPlace=true
|
||
|
bCanBeInterrupted=false
|
||
|
bUseCustomRotationRate=true
|
||
|
CustomRotationRate=(Pitch=50000, Yaw=25000, Roll=50000)
|
||
|
|
||
|
// ---------------------------------------------
|
||
|
// Effects
|
||
|
BeamPSCTemplate=ParticleSystem'ZED_Fleshpound_King_EMIT.FX_ChestBeam'
|
||
|
BeamHitPSCTemplate=ParticleSystem'ZED_Fleshpound_King_EMIT.FX_ChestBeam_Impact'
|
||
|
ChestBeamSocketName=ChestBeamSocket
|
||
|
BeamStartSFX=AkEvent'ww_zed_fleshpound_2.Play_King_FP_Beam_Start_LP'
|
||
|
BeamEndSFX=AkEvent'ww_zed_fleshpound_2.Play_King_FP_Beam_End'
|
||
|
BeamHitSFX=AkEvent'ww_zed_fleshpound_2.Play_FP_Beam_Hit_LP'
|
||
|
BeamHitStopSFX=AkEvent'ww_zed_fleshpound_2.Stop_FP_Beam_Hit_LP'
|
||
|
|
||
|
Begin Object Class=CameraShake Name=BeamHitShake0
|
||
|
bSingleInstance=true
|
||
|
OscillationDuration=0.35f
|
||
|
RotOscillation={(Pitch=(Amplitude=250.f,Frequency=60.f),
|
||
|
Yaw=(Amplitude=150.f,Frequency=70.f),
|
||
|
Roll=(Amplitude=150.f,Frequency=100.f))}
|
||
|
End Object
|
||
|
BeamHitShake=BeamHitShake0
|
||
|
|
||
|
// ---------------------------------------------
|
||
|
// KFSM_FleshpoundKing_ChestBeam
|
||
|
BeamDamageType=class'KFDT_FleshpoundKing_ChestBeam'
|
||
|
BeamExtent=(X=15.0f, Y=15.0f, Z=15.0f)
|
||
|
MaxBeamLength=2500.0f //1300
|
||
|
DamageInterval=0.1f
|
||
|
DamagePerTick=10 //15 //7
|
||
|
DamageMomentumImpulse=100.0f
|
||
|
TimeUntilTargetChange=0.75f
|
||
|
|
||
|
// ---------------------------------------------
|
||
|
// Debug
|
||
|
bDrawDebugBeam=false
|
||
|
}
|