2017-10-20 02:00:49 +00:00
class Ext _AICommandBasePet extends AICommand _Base _Zed ;
var transient Pawn OwnerPawn ;
var transient float NextSightCheckTime ;
final function vector PickPointNearOwner ( )
{
local byte i ;
local vector V , HL , HN , Start ;
Start = OwnerPawn . Location ;
2020-11-28 20:12:58 +00:00
if ( OwnerPawn . Physics == PHYS _Falling )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Pawn . Trace ( HL , HN , OwnerPawn . Location - vect ( 0 , 0 , 5000 ) , OwnerPawn . Location , false , vect ( 20 , 20 , 60 ) ) != None )
2017-10-20 02:00:49 +00:00
Start = HL ;
}
2020-11-28 20:12:58 +00:00
while ( true )
2017-10-20 02:00:49 +00:00
{
++ i ;
V . X = FRand ( ) - 0.5 ;
V . Y = FRand ( ) - 0.5 ;
V = Start + Normal2D ( V ) * ( 100. f + FRand ( ) * 500. f ) ;
2020-11-28 20:12:58 +00:00
if ( i < 20 && ! FastTrace ( V , Start ) ) // Destination is inside a wall.
2017-10-20 02:00:49 +00:00
continue ;
2020-11-28 20:12:58 +00:00
if ( i < 20 && FastTrace ( V - vect ( 0 , 0 , 100 ) , V ) ) // Destination is above a pit.
2017-10-20 02:00:49 +00:00
continue ;
break ;
}
OwnerPawn = None ;
return V ;
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
final function bool CanSeeOwner ( )
{
local Pawn P ;
NextSightCheckTime = WorldInfo . TimeSeconds + 1. f + FRand ( ) ;
P = Ext _T _MonsterPRI ( PlayerReplicationInfo ) != None ? Ext _T _MonsterPRI ( PlayerReplicationInfo ) . OwnerController . Pawn : None ;
2020-11-28 20:12:58 +00:00
if ( P != None && ! LineOfSightTo ( P ) )
2017-10-20 02:00:49 +00:00
return false ;
return true ;
}
state ZedBaseCommand
{
Begin :
2020-11-28 20:12:58 +00:00
if ( Pawn . Physics == PHYS _Falling )
2017-10-20 02:00:49 +00:00
{
DisableMeleeRangeEventProbing ( ) ;
WaitForLanding ( ) ;
}
EnableMeleeRangeEventProbing ( ) ;
// Check for any interrupt transitions
CheckInterruptCombatTransitions ( ) ;
// Select nearest enemy if current enemy is invalid
2020-11-28 20:12:58 +00:00
if ( Enemy == none || Enemy . Health <= 0 || ! IsValidAttackTarget ( KFPawn ( Enemy ) ) )
2017-10-20 02:00:49 +00:00
SelectEnemy ( ) ;
// Handle special case if I'm supposed to be attacking a door
2020-11-28 20:12:58 +00:00
if ( DoorEnemy != none && DoorEnemy . Health > 0 && VSizeSq ( DoorEnemy . Location - Pawn . Location ) < ( DoorMeleeDistance * DoorMeleeDistance ) ) //200UU
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:04:55 +00:00
` AILog(self $ " DoorEnemy: " $ DoorEnemy $ " starting melee attack", 'Command_Base');
UpdateHistoryString ( "[Attacking : " $DoorEnemy$ " at " $WorldInfo . TimeSeconds$ "]" ) ;
class 'AICommand_Attack_Melee' . static . Melee ( Outer , DoorEnemy ) ;
2017-10-20 02:00:49 +00:00
}
// See if we are close to our owner
RecheckOwner :
2022-07-12 14:39:58 +00:00
OwnerPawn = None ;
if ( Ext _T _MonsterPRI ( PlayerReplicationInfo ) != None
&& Ext _T _MonsterPRI ( PlayerReplicationInfo ) . OwnerController != None )
{
OwnerPawn = Ext _T _MonsterPRI ( PlayerReplicationInfo ) . OwnerController . Pawn ;
}
if ( OwnerPawn != None )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( Enemy != None && LineOfSightTo ( OwnerPawn ) && LineOfSightTo ( Enemy ) ) // We have sight to our owner and can see enemy, go for it!
2017-10-20 02:00:49 +00:00
{
OwnerPawn = None ;
bWaitingOnMovementPlugIn = true ;
2020-11-28 20:04:55 +00:00
SetEnemyMoveGoal ( self , true , , , ShouldAttackWhileMoving ( ) ) ;
2017-10-20 02:00:49 +00:00
NextSightCheckTime = WorldInfo . TimeSeconds + 2. f ;
2020-11-28 20:12:58 +00:00
while ( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( NextSightCheckTime < WorldInfo . TimeSeconds && ! CanSeeOwner ( ) )
2017-10-20 02:00:49 +00:00
{
ClearMovementInfo ( ) ;
GoTo 'RecheckOwner' ;
}
Sleep ( 0.03 ) ;
}
}
2020-11-28 20:12:58 +00:00
else if ( VSizeSq ( OwnerPawn . Location - Pawn . Location ) > 640000. f || ! LineOfSightTo ( OwnerPawn ) ) // 800.f - Need to move closer to our owner.
2017-10-20 02:00:49 +00:00
{
bWaitingOnMovementPlugIn = true ;
SetMovePoint ( PickPointNearOwner ( ) , OwnerPawn , , 300. f ) ;
2020-11-28 20:12:58 +00:00
while ( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
2017-10-20 02:00:49 +00:00
{
Sleep ( 0.03 ) ;
}
}
else // Standing next to our owner.
{
OwnerPawn = None ;
Sleep ( 0.2 + FRand ( ) * 0.5 ) ;
}
}
2020-11-28 20:12:58 +00:00
else if ( IsValidAttackTarget ( KFPawn ( Enemy ) ) )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:04:55 +00:00
` AILog("Calling SetEnemyMoveGoal [Dist:" $ VSize(Enemy.Location - Pawn.Location) $ "] using offset of " $ AttackRange $ ", because IsWithinBasicMeleeRange() returned false ", 'Command_Base');
2017-10-20 02:00:49 +00:00
bWaitingOnMovementPlugIn = true ;
2020-11-28 20:04:55 +00:00
SetEnemyMoveGoal ( self , true , , , ShouldAttackWhileMoving ( ) ) ;
2017-10-20 02:00:49 +00:00
2020-11-28 20:12:58 +00:00
while ( bWaitingOnMovementPlugIn && bUsePluginsForMovement )
2017-10-20 02:00:49 +00:00
{
Sleep ( 0.03 ) ;
}
` AiLog("Back from waiting for the movement plug in!!!");
2020-11-28 20:12:58 +00:00
if ( Enemy == none )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:04:55 +00:00
Sleep ( FRand ( ) + 0.1 f ) ;
Goto ( 'Begin' ) ;
2017-10-20 02:00:49 +00:00
}
}
else
{
` AILog("Enemy is invalid melee target" @ Enemy, 'Command_Base');
bFailedToMoveToEnemy = true ;
}
// Check combat transitions
CheckCombatTransition ( ) ;
2020-11-28 20:12:58 +00:00
if ( bFailedToMoveToEnemy )
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ( bFailedPathfind )
2017-10-20 02:00:49 +00:00
{
bFailedPathfind = false ;
2020-11-28 20:04:55 +00:00
Sleep ( 0. f ) ;
2017-10-20 02:00:49 +00:00
}
else
{
2020-11-28 20:04:55 +00:00
Sleep ( 0. f ) ;
2017-10-20 02:00:49 +00:00
}
2020-11-28 20:04:55 +00:00
SetEnemy ( GetClosestEnemy ( Enemy ) ) ;
2017-10-20 02:00:49 +00:00
}
else
{
Sleep ( 0. f ) ;
}
Goto ( 'Begin' ) ;
}
DefaultProperties
{
}