221 lines
5.9 KiB
Ucode
221 lines
5.9 KiB
Ucode
//=============================================================================
|
|
// KFSM_MeleeAttack
|
|
//=============================================================================
|
|
// Handles close-range melee attacks, and base class for all NPC melee attacks.
|
|
// An attack is considered to be a melee attack if there are no projectiles
|
|
// involved (i.e, just play an animation-based attack)
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2015 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
|
|
class KFSM_MeleeAttack extends KFSM_PlaySingleAnim
|
|
native(SpecialMoves);
|
|
|
|
/** If Interruptible, is this attack affected by parry stumble */
|
|
var transient bool bCannotBeParried;
|
|
|
|
static function byte PackFlagsBase(KFPawn P)
|
|
{
|
|
local byte StrikeFlags;
|
|
local KFPawn_Monster KFPM;
|
|
|
|
KFPM = KFPawn_Monster(P);
|
|
if ( KFPM == none || P.MyKFAIC == none )
|
|
{
|
|
return 255;
|
|
}
|
|
|
|
if( KFPM != none && KFPM.PawnAnimInfo != none )
|
|
{
|
|
StrikeFlags = KFPM.PawnAnimInfo.GetStrikeFlags(P.MyKFAIC.PendingAnimStrikeIndex);
|
|
|
|
if( StrikeFlags != 255 )
|
|
{
|
|
//class'AICommand_Attack_Melee'.static.Melee( self, Enemy, StrikeFlags );
|
|
P.MyKFAIC.UpdatePendingStrike();
|
|
}
|
|
}
|
|
return StrikeFlags;
|
|
}
|
|
|
|
/** Unpack Special move flags */
|
|
function UnpackSpecialMoveFlags()
|
|
{
|
|
local byte AtkIndex, AtkVariant;
|
|
|
|
AtkIndex = KFPOwner.SpecialMoveFlags & 15;
|
|
AtkVariant = KFPOwner.SpecialMoveFlags >> 4;
|
|
|
|
// setup next attack animation based on SpecialMoveFlags
|
|
AnimName = KFPOwner.PawnAnimInfo.InitMeleeSpecialMove(self, AtkIndex, AtkVariant);
|
|
|
|
// for now all non-RootMotion are also interruptible
|
|
bCanBeInterrupted = (bCanBeInterrupted || !bUseRootMotion);
|
|
}
|
|
|
|
/**
|
|
* Can a new special move override this one before it is finished?
|
|
* This is only if CanDoSpecialMove() == TRUE && !bForce when starting it.
|
|
*/
|
|
function bool CanOverrideMoveWith( Name NewMove )
|
|
{
|
|
if ( bCanBeInterrupted && (NewMove == 'KFSM_Stunned' || NewMove == 'KFSM_Stumble' || NewMove == 'KFSM_Knockdown' || NewMove == 'KFSM_Frozen') )
|
|
{
|
|
return TRUE; // for NotifyAttackParried
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
function SpecialMoveStarted( bool bForced, name PrevMove )
|
|
{
|
|
local KFPawn_Monster KFPM;
|
|
|
|
bUseRootMotion = false;
|
|
bCanBeInterrupted = false;
|
|
|
|
UnpackSpecialMoveFlags();
|
|
|
|
KFPM = KFPawn_Monster(KFPOwner);
|
|
if ( KFPM != none && KFPM.bCanCloak && KFPM.bIsCloaking )
|
|
{
|
|
KFPM.SetCloaked(false);
|
|
}
|
|
|
|
Super.SpecialMoveStarted( bForced, PrevMove );
|
|
}
|
|
|
|
function SpecialMoveEnded(Name PrevMove, Name NextMove)
|
|
{
|
|
local KFPawn_Monster KFPM;
|
|
|
|
PawnOwner.ClearTimer(nameof(InterruptCheckTimer), self);
|
|
|
|
// prevent this anim from triggering melee impact notifies during AbortBlendOutTime
|
|
if ( bCanBeInterrupted && KFPOwner.BodyStanceNodes[AnimStance].bIsPlayingCustomAnim )
|
|
{
|
|
KFPOwner.BodyStanceNodes[AnimStance].SetNotifyWeightThreshold(0.8f);
|
|
}
|
|
|
|
KFPM = KFPawn_Monster(KFPOwner);
|
|
if ( KFPM != none )
|
|
{
|
|
if( KFPM.bCanCloak && KFPM.bCloakOnMeleeEnd && !KFPM.bIsCloaking )
|
|
{
|
|
KFPM.SetCloaked(true);
|
|
}
|
|
|
|
KFPM.MeleeSpecialMoveEnded();
|
|
}
|
|
|
|
Super.SpecialMoveEnded(PrevMove, NextMove);
|
|
}
|
|
|
|
/** Called from SpecialMoveStarted */
|
|
function PlayAnimation()
|
|
{
|
|
local float InterruptTime;
|
|
|
|
if( AnimName == '' )
|
|
{
|
|
`warn( KFPOwner$" "$GetFuncName()$" "$self$" attempting special move attack but the AttackAnims array is empty!" );
|
|
return;
|
|
}
|
|
|
|
`AILog_Ext( GetFuncName()$" "$self$" chose attack animation "$AnimName, 'Command_SpecialMove', AIOwner );
|
|
if( bCanBeInterrupted )
|
|
{
|
|
InterruptTime = KFSkeletalMeshComponent(PawnOwner.Mesh).GetAnimInterruptTime(AnimName);
|
|
PawnOwner.SetTimer(InterruptTime, false, nameof(InterruptCheckTimer), self);
|
|
}
|
|
|
|
PlaySpecialMoveAnim( AnimName, AnimStance, BlendInTime, BlendOutTime, KFPOwner.AttackSpeedModifier);
|
|
}
|
|
|
|
/** Notification from the pawn that a medium (aka gun) or heavy (aka melee) affliction has been activated */
|
|
function NotifyHitReactionInterrupt()
|
|
{
|
|
// only non-RM attacks can be aborted
|
|
if ( bCanBeInterrupted )
|
|
{
|
|
KFPOwner.EndSpecialMove();
|
|
|
|
// Reset melee timer after interrupt
|
|
if( AIOwner != None )
|
|
{
|
|
AIOwner.LastGetStrikeTime = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Called by owning AI Command when AI behavior decides to stop this attack */
|
|
function AbortedByAICommand()
|
|
{
|
|
local KFPawn_Monster KFPMOwner;
|
|
|
|
if ( bCanBeInterrupted )
|
|
{
|
|
if( !KFPOwner.IsTimerActive( nameof(InterruptCheckTimer), self) )
|
|
{
|
|
KFPMOwner = KFPawn_Monster(KFPOwner);
|
|
KFPOwner.EndSpecialMove();
|
|
if( KFPMOwner != none )
|
|
{
|
|
KFPMOwner.NotifyAnimInterrupt();
|
|
}
|
|
if( AIOwner != None )
|
|
{
|
|
// Reset melee timer after interrupt
|
|
AIOwner.LastGetStrikeTime = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Called when it's safe to interrupt this animation */
|
|
function InterruptCheckTimer()
|
|
{
|
|
local AICommand_Attack_Melee MeleeCommand;
|
|
local KFPawn_Monster KFPMOwner;
|
|
|
|
if ( bCanBeInterrupted && AIOwner != None )
|
|
{
|
|
MeleeCommand = AICommand_Attack_Melee(AIOwner.GetActiveCommand());
|
|
if( MeleeCommand != none && MeleeCommand.bAttackAborted )
|
|
{
|
|
KFPMOwner = KFPawn_Monster(KFPOwner);
|
|
if( KFPMOwner != none )
|
|
{
|
|
KFPMOwner.NotifyAnimInterrupt();
|
|
}
|
|
KFPOwner.EndSpecialMove();
|
|
|
|
// Reset melee timer after interrupt
|
|
AIOwner.LastGetStrikeTime = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Called when owning pawn has damage parried during this move */
|
|
function bool CanInterruptWithParry()
|
|
{
|
|
return !bCannotBeParried;
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
BlendInTime=0.2f
|
|
BlendOutTime=0.33f
|
|
|
|
// ---------------------------------------------
|
|
// Animations
|
|
bUseRootMotion=false
|
|
AbortBlendOutTime=0.5f
|
|
|
|
// ---------------------------------------------
|
|
// SpecialMove
|
|
Handle=KFSM_MeleeAttack
|
|
bDisableSteering=false
|
|
bDisableMovement=true
|
|
bUseHigherMeshSmoothingThreshold=true
|
|
} |