318 lines
8.4 KiB
Ucode
318 lines
8.4 KiB
Ucode
//=============================================================================
|
|
// KFSM_Patriarch_MissileAttack
|
|
//=============================================================================
|
|
// Patriarch's triple missile attack
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2015 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
class KFSM_Patriarch_MissileAttack extends KFSM_PlaySingleAnim;
|
|
|
|
/** Cached reference to Patriarch pawn */
|
|
var KFPawn_ZedPatriarch MyPatPawn;
|
|
|
|
/** Cached reference to Patriarch AI controller */
|
|
var KFAIController_ZedPatriarch MyPatController;
|
|
|
|
/** Missile projectile class */
|
|
var class<KFProj_Missile_Patriarch> MissileClass;
|
|
|
|
/** Load animation names */
|
|
var Name LoadAnimNames[2];
|
|
|
|
/** The load animation chosen */
|
|
var Name LoadAnim;
|
|
|
|
/** Wind down animation name */
|
|
var Name WindDownAnimName;
|
|
|
|
/** Base socket name for each missile */
|
|
var String BaseSocketName;
|
|
|
|
/** Rotation rate to use for special move */
|
|
var rotator MissileFireRotationRate;
|
|
|
|
/** Whether we should allow gun tracking or not */
|
|
var bool bAllowGunTracking;
|
|
|
|
/** Disables or enables missile flocking (attraction) */
|
|
var bool bMissileFlocking;
|
|
|
|
/** How fast the missiles should travel */
|
|
var float InitialMissileSpeed;
|
|
|
|
/** How long a missile should wait after spawning to start seeking */
|
|
var float SeekDelay;
|
|
|
|
/** How much seek force should be applied to the missiles */
|
|
var float SeekForce;
|
|
|
|
/** How much gravity force to apply */
|
|
var float GravForce;
|
|
|
|
/** The distance from the target location before we start applying gravity */
|
|
var float DistToApplyGravitySQ;
|
|
|
|
/** Fire sound */
|
|
var AkEvent FireSound;
|
|
|
|
/** Notification called when Special Move starts */
|
|
function SpecialMoveStarted( bool bForced, Name PrevMove )
|
|
{
|
|
Super.SpecialMoveStarted( bForced,PrevMove );
|
|
|
|
MyPatPawn = KFPawn_ZedPatriarch(KFPOwner);
|
|
|
|
MissileClass = GetProjectileClass();
|
|
|
|
// Set load anim
|
|
if( MyPatPawn.SpecialMoveFlags == 1 )
|
|
{
|
|
LoadAnim = LoadAnimNames[1];
|
|
}
|
|
else
|
|
{
|
|
LoadAnim = LoadAnimNames[0];
|
|
}
|
|
|
|
// Uncloak
|
|
MyPatPawn.SetCloaked( false );
|
|
|
|
// Zero movement
|
|
MyPatPawn.ZeroMovementVariables();
|
|
|
|
// Play wind up
|
|
PlayLoadAnimation();
|
|
|
|
// Cache controller
|
|
MyPatController = KFAIController_ZedPatriarch( MyPatPawn.Controller );
|
|
|
|
// Set a timer to start gun tracking
|
|
if( bAllowGunTracking && MyPatPawn.Role == ROLE_Authority )
|
|
{
|
|
MyPatPawn.SetTimer( KFSkeletalMeshComponent(MyPatPawn.Mesh).GetAnimInterruptTime(LoadAnim), false, nameOf(StartGunTracking), self );
|
|
}
|
|
}
|
|
|
|
/** Retrieve the projectile class */
|
|
function class<KFProj_Missile_Patriarch> GetProjectileClass()
|
|
{
|
|
return MyPatPawn.GetMissileClass();
|
|
}
|
|
|
|
/** Overridden to do nothing */
|
|
function PlayAnimation() {}
|
|
|
|
/** Play the load animation */
|
|
function PlayLoadAnimation()
|
|
{
|
|
bUseRootMotion = false;
|
|
//MyPatPawn.Mesh.RootMotionMode = RMM_Accel;
|
|
//MyPatPawn.BodyStanceNodes[EAS_FullBody].SetRootBoneAxisOption(RBA_Translate, RBA_Translate, RBA_Translate);
|
|
AnimStance = EAS_FullBody;
|
|
AnimName = LoadAnim;
|
|
PlaySpecialMoveAnim( AnimName, AnimStance, BlendInTime, 0.f, 1.f );
|
|
}
|
|
|
|
/** Start gun tracking as the weapon is being brought level */
|
|
function StartGunTracking()
|
|
{
|
|
if( MyPatPawn != none )
|
|
{
|
|
MyPatPawn.SetGunTracking( true );
|
|
}
|
|
}
|
|
|
|
/** Play the fire animation */
|
|
function PlayFireAnimation()
|
|
{
|
|
if( MyPatPawn == none )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bUseRootMotion = false;
|
|
DisableRootMotion();
|
|
MyPatPawn.RotationRate = MissileFireRotationRate;
|
|
AnimStance = EAS_UpperBody;
|
|
AnimName = default.AnimName;
|
|
PlaySpecialMoveAnim( AnimName, AnimStance, 0.f, BlendOutTime, 1.f );
|
|
|
|
// Shoot some missiles on the server
|
|
if( MyPatPawn.Role == ROLE_Authority )
|
|
{
|
|
FireMissiles();
|
|
}
|
|
|
|
// Play our fire sound
|
|
MyPatPawn.PostAkEventOnBone( FireSound, 'BarrelSpinner', true, true );
|
|
}
|
|
|
|
/** Retrieves the aim direction and target location for each missile */
|
|
function GetAimDirAndTargetLoc( int MissileNum, vector MissileLoc, rotator MissileRot, out vector AimDir, out vector TargetLoc )
|
|
{
|
|
MyPatPawn.GetMissileAimDirAndTargetLoc( MissileNum, MissileLoc, MissileRot, AimDir, TargetLoc );
|
|
}
|
|
|
|
function Tick( float DeltaTime )
|
|
{
|
|
super.Tick( DeltaTime );
|
|
|
|
if( MyPatPawn != none && MyPatPawn.Role == ROLE_Authority && !MyPatPawn.bPlayedDeath && MyPatPawn.Physics == PHYS_Walking )
|
|
{
|
|
MyPatPawn.ZeroMovementVariables();
|
|
}
|
|
}
|
|
|
|
/** Fire our three missiles */
|
|
function FireMissiles()
|
|
{
|
|
local KFProj_Missile_Patriarch Missile;
|
|
local Array<KFProj_Missile_Patriarch> FiredMissiles;
|
|
local vector SpawnLoc, TargetLoc, AimDir;
|
|
local rotator SpawnRot;
|
|
local int i,j,k;
|
|
local bool bCurl;
|
|
local float CurlForceMultiplier;
|
|
|
|
// Fire three missiles in a curling spread
|
|
CurlForceMultiplier = 1.f + fRand()*0.1;
|
|
for( i = 0; i < 3; ++i )
|
|
{
|
|
// Spawn a missile at each of the launch bays
|
|
MyPatPawn.Mesh.GetSocketWorldLocationAndRotation( Name( BaseSocketName$String(i+1) ), SpawnLoc, SpawnRot );
|
|
Missile = MyPatPawn.Spawn( MissileClass, MyPatPawn,, SpawnLoc, SpawnRot,, true );
|
|
|
|
GetAimDirAndTargetLoc( i, SpawnLoc, SpawnRot, AimDir, TargetLoc );
|
|
|
|
// If missile flocking is disabled, we still want things like seeking etc
|
|
if( !bMissileFlocking )
|
|
{
|
|
Missile.bCurl = 3;
|
|
Missile.StartCurlTimer();
|
|
}
|
|
|
|
Missile.InitEx( AimDir, CurlForceMultiplier, TargetLoc, InitialMissileSpeed, SeekDelay, SeekForce, GravForce, DistToApplyGravitySQ );
|
|
FiredMissiles[FiredMissiles.Length] = Missile;
|
|
}
|
|
|
|
// To get crazy flying, we tell each projectile in the flock about the others
|
|
if( bMissileFlocking )
|
|
{
|
|
bCurl = false;
|
|
for( i = 0; i < 3; ++i )
|
|
{
|
|
if( FiredMissiles[i] != None )
|
|
{
|
|
j=0;
|
|
for( k = 0; k < 3; k++ )
|
|
{
|
|
if( (i != k) && (FiredMissiles[k] != None) )
|
|
{
|
|
FiredMissiles[i].Flock[j] = FiredMissiles[k];
|
|
j++;
|
|
}
|
|
}
|
|
|
|
FiredMissiles[i].bCurl = 1 + byte(bCurl);
|
|
FiredMissiles[i].StartCurlTimer();
|
|
bCurl = !bCurl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** If we had to interrupt the move because we lost LOS, play a wind down animation */
|
|
function PlayWindDownAnimation()
|
|
{
|
|
MyPatPawn.StopBodyAnim( AnimStance, 0.33f );
|
|
bUseRootMotion = true;
|
|
EnableRootMotion();
|
|
AnimStance = EAS_FullBody;
|
|
AnimName = WindDownAnimName;
|
|
PlaySpecialMoveAnim( AnimName, AnimStance, 0.33f, BlendOutTime, 1.f );
|
|
}
|
|
|
|
/** Plays subsequent animations in the barrage */
|
|
function AnimEndNotify(AnimNodeSequence SeqNode, float PlayedTime, float ExcessTime)
|
|
{
|
|
local name SeqNodeName;
|
|
SeqNodeName = bShouldDeferToPostTick ? DeferredSeqName : SeqNode.AnimSeqName;
|
|
switch( SeqNodeName )
|
|
{
|
|
case LoadAnim:
|
|
PlayFireAnimation();
|
|
break;
|
|
|
|
case default.AnimName:
|
|
MyPatPawn.EndSpecialMove();
|
|
break;
|
|
|
|
case WindDownAnimName:
|
|
MyPatPawn.EndSpecialMove();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/** End special move */
|
|
function SpecialMoveEnded( Name PrevMove, Name NextMove )
|
|
{
|
|
if( MyPatPawn != none )
|
|
{
|
|
MyPatPawn.StartWeaponCooldown();
|
|
|
|
if( bAllowGunTracking )
|
|
{
|
|
MyPatPawn.ClearTimer( nameOf(StartGunTracking) );
|
|
MyPatPawn.SetGunTracking( false );
|
|
}
|
|
MyPatPawn.RotationRate = MyPatPawn.default.RotationRate;
|
|
}
|
|
|
|
// Move was interrupted by something (incap, panic, etc), we need to stop the anim if we're still playing one
|
|
if( KFPOwner.BodyStanceNodes[AnimStance].bIsPlayingCustomAnim
|
|
&& KFPOwner.BodyStanceNodes[AnimStance].GetCustomAnimNodeSeq() != none
|
|
&& KFPOwner.BodyStanceNodes[AnimStance].GetCustomAnimNodeSeq().AnimSeqName == AnimName )
|
|
{
|
|
MyPatPawn.StopBodyAnim( AnimStance, 0.1f );
|
|
}
|
|
|
|
MyPatPawn = none;
|
|
MyPatController = none;
|
|
|
|
super.SpecialMoveEnded( PrevMove, NextMove );
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
// SpecialMove
|
|
Handle=KFSM_Patriarch_MissileAttack
|
|
bDisableSteering=false
|
|
bDisableMovement=true
|
|
bCanBeInterrupted=false
|
|
bAllowGunTracking=true
|
|
bDisableTurnInPlace=false
|
|
bShouldDeferToPostTick=true
|
|
|
|
// Missile settings
|
|
bMissileFlocking=true
|
|
MissileFireRotationRate=(Pitch=15000,Yaw=15000,Roll=15000)
|
|
InitialMissileSpeed=2000.f
|
|
SeekDelay=0.f
|
|
SeekForce=15.f
|
|
GravForce=0.f
|
|
|
|
// Audio
|
|
FireSound=AkEvent'WW_ZED_Patriarch.Play_Mini_Rocket_Fire'
|
|
|
|
// Animation
|
|
AnimName=Rocket_Shoot
|
|
LoadAnimNames[0]=Rocket_TO_Load
|
|
LoadAnimNames[1]=Rocket_TO_LoadQ
|
|
WindDownAnimName=Rocket_TO_Idle
|
|
BaseSocketName="Missile"
|
|
|
|
BlendInTime=0.15f
|
|
BlendOutTime=0.25f
|
|
AbortBlendOutTime=0.1f
|
|
} |