1
0
KF2-Dev-Scripts/KFGame/Classes/AICommand.uc
2020-12-13 18:01:13 +03:00

565 lines
16 KiB
Ucode

//=============================================================================
// AICommand
//=============================================================================
// Base class for AICommands (based on GOW2-GOW3)
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class AICommand extends GameAICommand
within KFAIController
native(AI)
DependsOn(KFPawn)
dependson(KFAiBehaviorTypes);
/** Reference to the KFAIController using this command */
var KFAIController AIOwner;
/** When a command is paused, the new command is cached here until the original command resumes */
var AICommand CachedChildCommand;
/** Can the AI perform an attack when using this command? */
var bool bAllowedToAttack;
/** When command is active, AILog category from this command will be overridden to this name */
var string OverrideLogCategory;
/** When true, this command can interrupt the pause AICommand */
var bool bInterruptPauseCommand;
/** When true, this command can will disable the movement plugin on push and enable on popped*/
var bool bDisableMovementPluginOnPushed;
cpptext
{
virtual void TickCommand(FLOAT DeltaTime);
}
/*********************************************************************************************
* Initialization
********************************************************************************************* */
/** Cache AIOwner */
function PrePushed( GameAIController AI )
{
AIOwner = Outer;
Super.PrePushed( AI );
}
function Pushed()
{
if( bUsePluginsForMovement && MovementPlugin != none && bDisableMovementPluginOnPushed )
{
MovementPlugin.DisablePlugin();
}
Super.Pushed();
}
/** Clear AIOwner */
function PostPopped()
{
AIOwner = none;
Super.PostPopped();
}
/** Command has been paused by another command */
function Paused(GameAICommand NewCommand)
{
`AILog( GetFuncName()$" ["$self$"] setting CachedChildCommand to "$NewCommand, 'Command_Base' );
CachedChildCommand = AICommand( NewCommand );
Super.Paused(NewCommand);
}
/** Command has resumed execution */
function Resumed( Name OldCommandName )
{
`AILog( GetFuncName()$" Command resumed, setting CachedChildCommand to none", 'Command_Base' );
CachedChildCommand = none;
Super.Resumed( OldCommandName );
}
/** Command is being popped off the stack */
function Popped()
{
if( bUsePluginsForMovement && MovementPlugin != none && bDisableMovementPluginOnPushed )
{
MovementPlugin.EnablePlugin();
}
if( MyKFPawn != none && MyKFPawn.IsAliveAndWell() )
{
UpdateCommandHistory();
`AILog( GetFuncName()$" Command Popped, setting CachedChildCommand to none", 'Command_Base' );
}
CachedChildCommand = none;
if( AIOwner != none )
{
AIOwner.NotifyCommandFinished( self );
}
Super.Popped();
}
/** Called from TickCommand and is used to call special moves and functions ontop of an AI Command */
event HandleAICommandSpecialAction();
/** Can this command be pushed by special moves? */
function bool AllowPushOfDefaultCommandForSpecialMove( ESpecialMove SM )
{
return true;
}
/** Access the parent AICommand, if any exists */
function AICommandBase GetParentCommand()
{
local GameAICommand ParentCommand;
ParentCommand = CommandList;
while( ParentCommand != none && ParentCommand.ChildCommand != self )
{
ParentCommand = ParentCommand.ChildCommand;
}
if( ParentCommand != none )
{
return ParentCommand;
}
return none;
}
/*********************************************************************************************
* Notifications
* Important event notifications are often forwarded from KFAIController to the top level
* AICommand and on to any child commands.
********************************************************************************************* */
function bool NotifyHearNoise( float Loudness, Actor NoiseMaker, optional Name NoiseType )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() Loudness: "$Loudness$" NoiseMaker: "$NoiseMaker$" Type: "$NoiseType, 'HearNoise' );
return CachedChildCommand.NotifyHearNoise( Loudness, NoiseMaker, NoiseType );
}
return false;
}
function bool NotifyCombatBehaviorChange( name BehaviorName, bool bEnabled )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() BehaviorName: "$BehaviorName$" bEnabled: "$bEnabled );
return CachedChildCommand.NotifyCombatBehaviorChange( BehaviorName, bEnabled );
}
return false;
}
/** Allows AICommands to reject switching enemy to NewEnemy */
function bool CanChangeEnemy( Pawn NewEnemy )
{
if( CachedChildCommand != None )
{
return CachedChildCommand.CanChangeEnemy( NewEnemy );
}
return true;
}
/** Notification from controller that enemy has changed. Sends OldEnemy to support movement goal re-evaluations. */
function NotifyEnemyChanged( optional Pawn OldEnemy )
{
if( CachedChildCommand != None )
{
CachedChildCommand.NotifyEnemyChanged( OldEnemy );
}
}
/** Notification that a pending door is now open */
function NotifyDoorOpened()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'NotifyDoorOpened' );
CachedChildCommand.NotifyDoorOpened();
}
}
/** Notification from controller that enemy has become visible */
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 );
}
return false;
}
/** Notification from controller that enemy is no longer visible */
function bool NotifyEnemyNotVisible()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'EnemyNotVisible' );
return CachedChildCommand.NotifyEnemyNotVisible();
}
return false;
}
/** Notification from controller that my pawn's base has changed */
function bool NotifyBaseChange( actor NewBase, vector NewFloor )
{
if( CachedChildCommand != None )
{
//`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'HitWall' );
if( CachedChildCommand.NotifyBaseChange( NewBase, NewFloor ) )
{
return true;
}
}
return false;
}
/** Notification from controller that my pawn has landed */
function bool NotifyLanded( vector HitNormal, actor FloorActor )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() HitNormal:"$HitNormal$" FloorActor:"$FloorActor$" notifying "$CachedChildCommand$" and letting it handle the event.", 'PathWarning' );
return CachedChildCommand.NotifyLanded( HitNormal, FloorActor );
}
return false;
}
/** Notification that my current enemy is surrounded by other NPCs */
function bool EnemyIsSurrounded()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'PathWarning' );
return CachedChildCommand.EnemyIsSurrounded();
}
return false;
}
/** Notification from controller that my pawn has collided with an obstruction (during a latent move) */
function bool NotifyHitWall( vector HitNormal, actor Wall )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'HitWall' );
return CachedChildCommand.NotifyHitWall( HitNormal, Wall );
}
return false;
}
/** Notification from controller that my pawn has collided with an obstruction while falling (during a latent move) */
function bool NotifyFallingHitWall( vector HitNormal, actor Wall )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'HitWall' );
return CachedChildCommand.NotifyFallingHitWall( HitNormal, Wall );
}
return false;
}
/** Notification that a nearby Husk has become suicidal */
function bool NotifyHuskSuicide( KFPawn_Monster Husk )
{
return false;
if( CachedAICommandList != none )
{
if( CachedAICommandList.NotifyHuskSuicide( Husk ) )
{
return true;
}
}
return false;
}
/** Notification that my pawn has bumped into something - usually another NPC */
function bool NotifyBump( actor Other, vector HitNormal )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'BumpEvent' );
if( CachedChildCommand.NotifyBump( Other, HitNormal ) )
{
return true;
}
}
return false;
}
function bool NotifyLatentPostPhysWalking()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'PostPhysWalking' );
if( CachedChildCommand.NotifyLatentPostPhysWalking() )
{
return true;
}
}
return false;
}
function bool NotifyTouch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'TouchEvent' );
if( CachedChildCommand.NotifyTouch( Other, OtherComp, HitLocation, HitNormal ) )
{
return true;
}
}
return false;
}
function bool NotifyMovingOnToDestructibleEdge( KFDestructibleActor TheDestructiblePathObject, out KFNavMeshMovementStepData EdgeData, out Vector outMove2Point )
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'NotifyZedStuck' );
if( CachedChildCommand.NotifyMovingOnToDestructibleEdge( TheDestructiblePathObject, EdgeData, outMove2Point ) )
{
return true;
}
}
return false;
}
function bool NotifyNpcTerminallyStuck()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'NotifyNpcTerminallyStuck' );
if( CachedChildCommand.NotifyNpcTerminallyStuck() )
{
return true;
}
}
return false;
}
function bool NotifyNpcInGrannyMode()
{
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() notifying "$CachedChildCommand$" and letting it handle the event.", 'NotifyNpcInGrannyMode' );
if( CachedChildCommand.NotifyNpcInGrannyMode() )
{
return true;
}
}
return false;
}
/** Ignore timer transitions to other commands? */
function bool ShouldIgnoreTimeTransitions()
{
local bool bShouldIgnore;
if(CachedChildCommand != none)
{
bShouldIgnore = CachedChildCommand.ShouldIgnoreTimeTransitions();
}
if( bShouldIgnore )
{
`AILog( GetFuncName()$"() returning TRUE - ignoring time transitions", 'CombatTransitions' );
}
return bShouldIgnore;
}
/** Checks to see if we're allowed to fire our weapon in this command, passing through to children until blocked. */
function bool IsAllowedToAttack()
{
local bool bCanAttack;
bCanAttack = ( bAllowedToAttack && (CachedChildCommand == None || CachedChildCommand.IsAllowedToAttack()) );
if( !bCanAttack )
{
`AILog( GetFuncName()$"() returning false because !bAllowedToAttack" );
}
return bCanAttack;
}
/** Checks if Pawn P exists and is still alive */
function bool IsPawnAlive( Pawn P )
{
if( P == none )
{
return false;
}
if( P.Controller == none || !P.IsAliveAndWell() )
{
return false;
}
return true;
}
/** Checks if Controller C exists, its pawn exists and is still alive */
function bool IsControllerAlive( Controller C )
{
if( C == none )
{
return false;
}
if( C.Pawn == none || !C.Pawn.IsAliveAndWell() )
{
return false;
}
return true;
}
/** Should the AI re-evaluate their current target and possibly choose a different one? */
function bool ShouldSelectTarget()
{
if( CachedChildCommand != None )
{
return CachedChildCommand.ShouldSelectTarget();
}
return true;
}
function AdjustEnemyRating(out float out_Rating, Pawn EnemyPawn)
{
if (CachedChildCommand != None)
{
CachedChildCommand.AdjustEnemyRating(out_Rating, EnemyPawn);
}
}
/*********************************************************************************************
* Pathfinding & Movement
********************************************************************************************* */
/** Called from native code during latent movement, gives NPC a chance to find direct path to goal */
function FindDirectPath()
{
`AILog( GetFuncName(), 'Move_DirectPath' );
if (CachedChildCommand != None)
{
`AILog( GetFuncName()$"(), [I am "$self$"] letting "$CachedChildCommand$" decide what to do about it.", 'Move_DirectPath' );
CachedChildCommand.FindDirectPath();
}
}
/** Called from native code during latent movement when current move is considered unreachable */
function bool MoveUnreachable( Vector AttemptedDest, Actor AttemptedTarget )
{
if( AttemptedTarget != none )
{
`AILog( GetFuncName()$" AttemptedTarget: "$AttemptedTarget, 'PathWarning' );
}
if( CachedChildCommand != None )
{
`AILog( GetFuncName()$"() letting "$CachedChildCommand$" decide what to do about it.", 'PathWarning' );
return CachedChildCommand.MoveUnreachable( AttemptedDest, AttemptedTarget );
}
return false;
}
/** Notification that NPC's path needs to be updated */
function NotifyNeedRepath()
{
if(CachedChildCommand != none)
{
`AILog( GetFuncName()$"() "$self$" called, letting "$CachedChildCommand$" decide what to do about it.", 'PathWarning' );
CachedChildCommand.NotifyNeedRepath();
}
else
{
`AILog( GetFuncName()$"() "$self$" called.", 'PathWarning' );
}
}
/*********************************************************************************************
* Debugging
********************************************************************************************* */
/** Update command history (debugging) */
function UpdateCommandHistory()
{
local int i;
if( Outer.Pawn != none )
{
for( i = 0; i < KFAICommandHistory.Length; i++ )
{
if( KFAICommandHistory[i].CmdName != "" && KFAICommandHistory[i].CmdName == string( Name ) )
{
if( Status == 'Aborted' )
{
KFAICommandHistory[i].bAborted = true;
}
if( Status == 'Failure')
{
KFAICommandHistory[i].bFailure = true;
}
if( Status == 'Success')
{
KFAICommandHistory[i].bSuccess = true;
}
UpdateHistoryString( "Status: "$Status );
//HistoryString = "Status: "$Status;
KFAICommandHistory[i].Duration = `TimeSince(KFAICommandHistory[i].TimeStamp);
KFAICommandHistory[i].VerboseString = HistoryString;
}
}
}
}
/** Update the command's HistoryString, which is output when DumpCommandHistory() is called */
function UpdateHistoryString( string AddString )
{
if( Outer.Pawn != none )
{
if( CommandHistoryNum > 0 )
{
HistoryString = HistoryString$" "$AddString;
}
}
}
/** Debug event to draw command-specific text to HUD */
simulated event DrawDebug( HUD H, Name Category )
{
if( ChildCommand != None )
{
ChildCommand.DrawDebug( H,Category );
}
}
/** Used when dumping command history to log file */
event string GetDebugVerboseText()
{
return HistoryString;
}
/** Is this AICommand permitted to interrupt an active AICommand_Pause? */
static function bool CanInterruptPauseCommand()
{
return default.bInterruptPauseCommand;
}
DefaultProperties
{
bAllowedToAttack=true
bInterruptPauseCommand=false
bDisableMovementPluginOnPushed=true
}