//============================================================================= // AICommand_Attack_Grab //============================================================================= // AI Command for clot grab attack //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC //============================================================================= class AICommand_Attack_Grab extends AICommand_SM_Attack within KFAIController_Monster; /********************************************************************************************* * Push/Pause/Pop/Init ********************************************************************************************* */ /** Simple constructor that pushes a new instance of the command for the AI */ static function bool Grab( KFAIController_Monster AI, optional float InPostSpecialMoveSleepTime=0.f ) { local AICommand_Attack_Grab OtherCmd, Cmd; if (AI != None && AI.Pawn != None ) { OtherCmd = AI.FindCommandOfClass(class'AICommand_Attack_Grab'); if (OtherCmd == None ) { Cmd = new(AI) default.Class; if( InPostSpecialMoveSleepTime > 0.f ) { Cmd.PostSpecialMoveSleepTime = InPostSpecialMoveSleepTime; } AI.PushCommand(Cmd); return true; } } return false; } /** Build debug string */ event String GetDumpString() { return Super.GetDumpString()@"Grab Target:"@Enemy; } function Pushed() { Super.Pushed(); DisableMeleeRangeEventProbing(); `AILog( self$" ... Enemy"@Enemy, 'Command_Attack_Grab' ); } function Resumed(name OldCommandName) { Super.Resumed(OldCommandName); // Otherwise, didn't get there so fail the command Status = 'Failure'; PopCommand(self); } function Paused(GameAICommand NewCommand) { //`warn( "Warning! Paused() for "$self$" - paused by "$NewCommand ); if( Outer.IsDead() || Outer.MyKFPawn == none || !Outer.MyKFPawn.IsAliveAndwell() ) { AbortCommand( self ); } super.Paused(NewCommand); } function Popped() { LastAttackTime_Grab = WorldInfo.TimeSeconds; LastAttackTime_Melee = LastAttackTime_Grab; Super.Popped(); EnableMeleeRangeEventProbing(); } /********************************************************************************************* * Special Move & State ********************************************************************************************* */ state Command_SpecialMove { function BeginState(name PreviousStateName) { super.BeginState(PreviousStateName); MyKFPawn.bForceMaxAccel = false; bIgnoreNotifies = true; // Need to face the target SetDesiredRotation( rotator(Enemy.Location - Pawn.Location) ); } function EndState(name NextStateName) { local KFPawn GP; Super.EndState( NextStateName ); // Clear the interaction pawn once execution is done GP = KFPawn( AIOwner.Pawn ); if( GP != None ) { GP.InteractionPawn = None; } } function SpecialMoveTimeout() { `AILog( self$" Special move timed out", 'Command_Attack_Grab' ); if( MyKFPawn.SpecialMove == SpecialMove || MyKFPawn.SpecialMove == SM_GrappleAttack ) { MyKFPawn.EndSpecialMove(); } Status = 'Failure'; AbortCommand( self ); } // Turn to face the target before doing the special move function bool ShouldFinishRotation() { return true; } function KFPawn GetInteractionPawn() { return KFPawn( Enemy ); } function ESpecialMove GetSpecialMove() { return SM_GrappleAttack; } function bool ExecuteSpecialMove() { AIZeroMovementVariables(); //SetInteractionPawn(); StopLatentExecution(); return (Super.ExecuteSpecialMove()); } function bool IsSpecialMoveComplete() { return (MyKFPawn == None || (!MyKFPawn.IsDoingSpecialMove(SM_GrappleAttack)) && Super.IsSpecialMoveComplete()); } function FinishedSpecialMove() { UpdateLastMeleeTime(); EndOfMeleeAttackNotification(); } } /** Overridden to break grabs on enemy changed */ function NotifyEnemyChanged( optional Pawn OldEnemy ) { if( MyKFPawn != none && MyKFPawn.IsDoingSpecialMove(SM_GrappleAttack) ) { MyKFPawn.EndSpecialMove(); } super.NotifyEnemyChanged( OldEnemy ); } function UpdateLastMeleeTime() { //Outer.UpdateLastMeleeTime(); LastAttackTime_Grab = WorldInfo.TimeSeconds; LastAttackTime_Melee = LastAttackTime_Grab; } DefaultProperties { bShouldCheckSpecialMove=false TimeOutDelaySeconds=50.f }