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

271 lines
6.8 KiB
Ucode

//=============================================================================
// AICommand_HeadlessWander
//=============================================================================
// Command used by headless Zeds during the last few moments of their lives.
// Unlike most commands, this one should not allow any transitions to other
// commands. If a Zed begins using this command, it should stay active until
// the Zed dies after bleeding out by some other means.
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class AICommand_HeadlessWander extends AICommand
within KFAIController;
var Controller EventInstigator;
var float RandomMoveDist;
var float DotCheck;
var float LastHeadlessAttackTime;
var bool bDebugWander;
var vector Dest;
static function bool HeadlessWander( KFAIController AI )
{
local AICommand_HeadlessWander Cmd;
if( AI != None )
{
Cmd = new(AI) class'AICommand_HeadlessWander';
if( Cmd != None )
{
//Cmd.EventInstigator = Controller(UserActor);
AI.PushCommand(Cmd);
return true;
}
}
return false;
}
/** Set things up for the start of the command */
function Pushed()
{
if( Steering != none )
{
Steering.EnableDefaultAcceleration();
}
/** Make sure I'm not sprinting anymore */
MyKFPawn.SetSprinting( false );
/** Disallow AdjustFromWall() instigated jumps over obstructions */
MyKFPawn.bCanJumpOverWalls = false;
/** Slow my Pawn's rotation rate */
RotationRateMultiplier = 0.33f;
LastHeadlessAttackTime = WorldInfo.TimeSeconds;
/** Reset my focus and focalpoint */
Focus = None;
SetFocalPoint(vect(0,0,0));
/** Turn off HeadTracking, if it's currently on */
MyKFPawn.StopLookingAtPawn();
/** Allow combat, since I might try to blindly swipe at any Zed/player I happen to bump */
bAllowCombatTransitions = true;
/** Don't allow notifications from TickMeleeDecision() about being in attack range */
DisableMeleeRangeEventProbing();
/** Stop any latent MoveTo/MoveTowards */
StopAllLatentMovement();
/** Zero non-falling accel and velocity */
AIZeroMovementVariables();
if( MyKFPawn.IsDoingSpecialMove() )
{
/** This is a special case - interrupt any current special move I'm doing */
MyKFPawn.EndSpecialMove();
}
if( MyKFPawn != none && MyKFPawn.bCanCloak && MyKFPawn.bIsCloaking )
{
/** Uncloak (Stalker) */
MyKFPawn.SetCloaked( false );
}
GotoState( 'RandomWander' );
}
function Popped()
{
if( Steering != none )
{
Steering.DisableDefaultAcceleration();
}
super.Popped();
}
function bool AllowTransitionTo( class<GameAICommand> AttemptCommand )
{
return false; // One way ticket
}
function bool ShouldRunSomewhereElse()
{
return FRand() < 0.4f;
}
function vector CalcTurnDirection( rotator Direction, float Spread )
{
local float Radius, ZDelta, YDelta;
local vector X, Y, Z, Offset;
Radius = Tan( Spread / 2.0 * PI / 180.f );
ZDelta = Radius - ( 2 * Radius * FRand() );
YDelta = Radius - ( 2 * Radius * FRand() );
GetAxes( Direction, X, Y, Z );
Offset = ( ZDelta * Z ) + ( YDelta * Y );
return vector( Direction ) + Offset;
}
state RandomWander
{
function vector GetRandomMovePoint()
{
local float Dot;
local vector TryPt, RandTryPoint;
local vector TryDir;
local int i;
//TryDir = VRand();
TryDir = CalcTurnDirection( Pawn.Rotation, 65.f );
TryDir.Z = 0.f;
TryDir = Normal(TryDir);
TryPt = Pawn.Location + TryDir * RandomMoveDist;
if( bDebugWander )
{
PauseAndShowMsg( "WAITING" );
`log( "Initial TryDir:"$TryDir$" TryPt: "$TryPt );
DrawDebugSphere( TryPt, 32, 8, 0, 255, 0, TRUE );
}
for( i = 0; i < 15; i++ )
{
if( bDebugWander )
{
PauseAndShowMsg( "WAITING : "$i );
}
TryDir = CalcTurnDirection( Pawn.Rotation, RandRange(60,120) ); //VRand();
TryDir.Z = 0.f;
TryDir = Normal(TryDir);
RandTryPoint = Pawn.Location + TryDir * RandomMoveDist;
Dot = normal( RandTryPoint - Pawn.Location ) dot vector(Pawn.Rotation);
if( Dot < DotCheck )
{
if( bDebugWander )
{
`log( "Fail i: "$i$" FAILED DOT CHECK (Dot:"$Dot$" versus DotCheck:"$DotCheck$")" );
DrawDebugSphere( RandTryPoint, 24, 8, 255, 0, 0, TRUE );
}
continue;
}
else if( bDebugWander )
{
`log( "Success i: "$i$" DOT: "$Dot$" TryDir: "$TryDir$" RandTryPoint: "$RandTryPoint );
DrawDebugSphere( RandTryPoint, 24, 8, 0, 0, 255, TRUE );
DrawDebugLine( Pawn.Location, RandTryPoint, 0, 0, 255, TRUE );
}
TryPt = Pawn.Location + TryDir * RandomMoveDist;
if( PointReachable( TryPt ) )
{
//DrawDebugLine( Pawn.Location, Pawn.Location + TryDir * RandomMoveDist, 0, 255, 0, TRUE );
return TryPt;
}
}
return TryPt;
}
Begin:
GetRandomMovePoint();
if( bDebugWander )
{
Sleep(0.f);
PauseAndShowMsg( "WAITING" );
Sleep(0.f);
Goto( 'Begin' );
}
//SetMovePoint( GetRandomMovePoint(), none );
MoveTo( GetRandomMovePoint(), none );
if( ShouldRunSomewhereElse() )
{
GotoState( 'RunSomewhere' );
}
// if( FRand() < 0.23f )
// {
// Sleep( RandRange( 0.1f, 0.5f ) );
// }
Goto('Begin');
}
function bool NotifyHearNoise( float Loudness, Actor NoiseMaker, optional Name NoiseType )
{
`AILog( "HearNoise: "$Loudness$" NoiseMaker: "$NoiseMaker$" Type: "$NoiseType, 'HeadlessWander' );
return false;
}
state RunSomewhere
{
function bool RunToDest()
{
local Pawn CurEnemy;
local float CurDistSq, BestDistSq;
local Pawn BestEnemy;
local bool bRunToPlayer;
BestDistSq = MAXINT;
foreach WorldInfo.AllPawns( class'Pawn', CurEnemy )
{
CurDistSq = VSizeSq( CurEnemy.Location - Pawn.Location );
if( BestEnemy == none || CanSee(CurEnemy) )
{
if( CurDistSq < BestDistSq )
{
BestEnemy = CurEnemy;
BestDistSq = CurDistSq;
}
}
}
bRunToPlayer = FRand() < 0.55f;
BestDistSq = MAXINT;
foreach WorldInfo.AllPawns( class'Pawn', CurEnemy )
{
CurDistSq = VSizeSq( CurEnemy.Location - Pawn.Location );
if( BestEnemy == none ||
(bRunToPlayer == Pawn.IsHumanControlled()
&& CurDistSq < BestDistSq
&& (!bIsPlayer || CanSee(CurEnemy)) ) )
{
BestEnemy = CurEnemy;
BestDistSq = CurDistSq;
}
}
if( BestEnemy != none )
{
Dest = BestEnemy.Location;
return true;
}
return false;
}
Begin:
if( RunToDest() )
{
MoveTo( Dest );
Dest = vect(0,0,0);
GotoState( 'RandomWander' );
}
else
{
AbortCommand( self );
}
}
DefaultProperties
{
bIgnoreNotifies=true
bIgnoreStepAside=true
RandomMoveDist=232.f
DotCheck=0.86f
bDebugWander=false
}