1
0
KF2-Dev-Scripts/KFGame/Classes/AICommand_Base_Zed.uc

216 lines
6.4 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// AICommand_Base_Zed
//=============================================================================
// Base AI command for Zeds. Zeds don't wander (yet?) - they simply choose a
// valid enemy and use this command to begin moving to their enemy and to
// start melee attacks if they happen to be in range once the move to enemy
// command pops and this command resumes.
//
// Zeds who need special handling can subclass this.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class AICommand_Base_Zed extends AICommand_Base_Combat
within KFAIController_Monster
implements(LatentActionObserver)
native(AI);
var name CachedAttackTag;
var byte AttackFlags;
var bool bFailedPathfind;
var bool bWaitingOnMovementPlugIn;
/*********************************************************************************************
* Initialization
********************************************************************************************* */
function Pushed()
{
Super.Pushed();
EnableSeePlayer();
`AILog( self$" "$GetFuncName()$"() using AttackRange of "$AttackRange, 'Command_Base' );
GotoState( DefaultStateName );
}
function Paused( GameAICommand NewCommand )
{
`AILog( self$" "$GetFuncName()$"() Paused for "$NewCommand, 'Command_Base' );
Super.Paused( NewCommand );
}
function Resumed( name OldCommandName )
{
`AILog( self$" "$GetFuncName()$"() (OldCommandName: "$OldCommandName$")", 'Command_Base' );
Super.Resumed( OldCommandName );
EnableProbingMeleeRangeEvents( true );
}
/*********************************************************************************************
* Movement & Pathing
********************************************************************************************* */
native function OnLatentFinished(BaseAIController Observer, Object Action, byte FinishResult);
function bool NotifyBump( Actor Other, Vector HitNormal )
{
// To be enabled
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() Other: "$Other$" HitNormal: "$HitNormal$" notifying "$CachedChildCommand$" and letting it handle the event.", 'SeePlayer' );
return CachedChildCommand.NotifyBump( Other, HitNormal );
}
return false;
}
function NotifyEnemyChanged( optional Pawn OldEnemy )
{
super.NotifyEnemyChanged( OldEnemy );
GotoState( DefaultStateName );
}
/*********************************************************************************************
* Combat
********************************************************************************************* */
function bool NotifyPlayerBecameVisible( Pawn VisiblePlayer )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() Seen: "$VisiblePlayer$" notifying "$CachedChildCommand$" and letting it handle the event.", 'SeePlayer' );
return CachedChildCommand.NotifyPlayerBecameVisible( VisiblePlayer );
}
`AILog( GetFuncName()$"() : "$VisiblePlayer$" ignoring this event", 'SeePlayer' );
//DisableSeePlayer();
return false;
}
function bool ShouldAttackWhileMoving()
{
`AILog( self$" ShouldAttackWhileMoving() returning true", 'Command_Base' );
return true;
}
function bool ShouldSelectTarget()
{
if( Enemy == none || !Enemy.IsAliveAndWell() )
{
`AILog( self$" "$GetFuncName()$"() returning TRUE", 'Command_Base' );
return true;
}
return false;
}
/*********************************************************************************************
* Base Zed Command State
********************************************************************************************* */
state ZedBaseCommand `DEBUGSTATE
{
event BeginState( name PreviousStateName )
{
}
event EndState( name NextStateName )
{
}
Begin:
`AILog( self$" "$GetStateName()$" [Begin Label]", 'Command_Base' );
if( Pawn.Physics == PHYS_Falling )
{
DisableMeleeRangeEventProbing();
WaitForLanding();
}
// Don't do any sort of AI processing in incap states
if( MyKFPawn.IsIncapacitated() )
{
DisableMeleeRangeEventProbing();
Sleep( 0.1f );
Goto( 'Begin' );
}
EnableMeleeRangeEventProbing();
// Check for any interrupt transitions
CheckInterruptCombatTransitions();
// Select nearest enemy if current enemy is invalid
if (!IsValidAttackTarget(KFPawn(Enemy)) || !Enemy.IsAliveAndWell() || !Enemy.CanAITargetThisPawn(MyKFPawn.Controller))
{
SelectEnemy();
}
// If enemy is still invalid or melee range events are disabled, pause and loop back
if( (Enemy == none && DoorEnemy == none) || !bIsProbingMeleeRangeEvents )
{
`AILog( self$" Enemy: "$Enemy$" bIsProbingMeleeRangeEvents: "$bIsProbingMeleeRangeEvents, 'Command_Base' );
Sleep( 0.1f + FRand() * 0.3f );
Goto( 'Begin' );
}
// Handle special case if I'm supposed to be attacking a door
if( DoorEnemy != none && DoorEnemy.Health > 0 && VSizeSq( DoorEnemy.Location - Pawn.Location ) < (DoorMeleeDistance * DoorMeleeDistance) ) //200UU
{
`AILog( self$" DoorEnemy: "$DoorEnemy$" starting melee attack", 'Command_Base' );
UpdateHistoryString( "[Attacking : "$DoorEnemy$" at "$WorldInfo.TimeSeconds$"]" );
class'AICommand_Attack_Melee'.static.Melee( Outer, DoorEnemy );
}
if( IsValidAttackTarget(KFPawn(Enemy)) )
{
`AILog( "Calling SetEnemyMoveGoal [Dist:"$VSize(Enemy.Location - Pawn.Location)$"] using offset of "$AttackRange$", because IsWithinBasicMeleeRange() returned false ", 'Command_Base' );
bWaitingOnMovementPlugIn = true;
SetEnemyMoveGoal(self, true,,, ShouldAttackWhileMoving() );
while( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
{
Sleep(0.03);
}
`AiLog("Back from waiting for the movement plug in!!!");
if( Enemy == none )
{
Sleep( FRand() + 0.1f );
Goto( 'Begin' );
}
}
else
{
`AILog("Enemy is invalid melee target" @ Enemy, 'Command_Base');
bFailedToMoveToEnemy = true;
}
// Check combat transitions
CheckCombatTransition();
if( bFailedToMoveToEnemy )
{
if( bFailedPathfind )
{
bFailedPathfind = false;
Sleep( 0.f );
}
else
{
Sleep( 0.f );
}
SetEnemy( GetClosestEnemy( Enemy ) );
}
else
{
Sleep(0.f);
}
Goto('Begin');
}
DefaultProperties
{
DefaultStateName=ZedBaseCommand
bAllowedToAttack=true
bDisableMovementPluginOnPushed=false
}