2 #using scripts\shared\ai\systems\ai_interface;
3 #using scripts\shared\ai\systems\animation_state_machine_utility;
4 #using scripts\shared\ai\systems\behavior_state_machine;
5 #using scripts\shared\ai\systems\behavior_tree_utility;
6 #using scripts\shared\ai\systems\blackboard;
8 #using scripts\shared\ai\archetype_utility;
9 #using scripts\shared\ai_shared;
10 #using scripts\shared\array_shared;
12 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
13 #insert scripts\shared\ai\systems\blackboard.gsh;
14 #insert scripts\shared\ai\systems\behavior.gsh;
15 #insert scripts\shared\ai\systems\behavior_state_machine.gsh;
16 #insert scripts\shared\ai\systems\behavior_tree.gsh;
17 #insert scripts\shared\ai\utility.gsh;
18 #insert scripts\shared\shared.gsh;
65 entity.lastTacticalScanTime = GetTime();
70 #define TACTICAL_SCAN_INTERVAL 2000
73 if ( IsDefined( entity.lastTacticalScanTime ) &&
79 if( !entity HasPath() )
84 if ( IsDefined( entity.enemy ) )
89 if ( entity ShouldFaceMotion() )
98 animation = entity AsmGetCurrentDeltaAnimation();
101 if ( IsDefined( animation ) )
103 animTime = entity GetAnimTime( animation );
104 return animTime <= 0.05;
110 #define TACTICAL_SCAN_BLEND_OUT 0.2
113 if( !entity HasPath() )
118 if ( IsDefined( entity.enemy ) )
123 if ( entity ShouldFaceMotion() )
132 animation = entity AsmGetCurrentDeltaAnimation();
134 if ( IsDefined( animation ) )
136 animLength = GetAnimLength( animation );
137 animTime = entity GetAnimTime( animation ) * animLength;
141 return normalizedTime < 1.0;
147 #define PAIN_TIME_WINDOW 3000
148 #define PAIN_CHANCE 0.25
151 if ( ( !IsDefined( entity.startPainTime ) || ( entity.startPainTime +
PAIN_TIME_WINDOW ) < GetTime() ) &&
162 entity.startPainTime = GetTime();
167 #define PAIN_TIME_LENGTH 100
175 return ( entity HasValidInterrupt(
"pain") );
183 if( behaviorTreeEntity HasPath() )
185 if( IsDefined( behaviorTreeEntity.node )
186 && IsCoverNode( behaviorTreeEntity.node )
187 && IsDefined( behaviorTreeEntity.pathGoalPos )
188 && DistanceSquared( behaviorTreeEntity.pathGoalPos, behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node ) ) < 8
200 behaviorTreeEntity ClearPath();
201 behaviorTreeEntity.keepClaimedNode =
true;
206 behaviorTreeEntity ClearPath();
207 behaviorTreeEntity.keepClaimedNode =
true;
212 goingToCoverNode = IsDefined( behaviorTreeEntity.node ) && IsCoverNode( behaviorTreeEntity.node );
214 if( !goingToCoverNode )
219 if( IsDefined( behaviorTreeEntity.pathGoalPos ) )
221 if( IsDefined( behaviorTreeEntity.arrivalfinalpos ) )
223 if( behaviorTreeEntity.arrivalfinalpos != behaviorTreeEntity.pathGoalPos )
227 else if ( behaviorTreeEntity.replannedCoverArrival ===
false &&
228 IsDefined( behaviorTreeEntity.exitPos ) &&
229 IsDefined( behaviorTreeEntity.predictedExitPos ) )
231 behaviorTreeEntity.replannedCoverArrival =
true;
233 exitDir = VectorNormalize( behaviorTreeEntity.predictedExitPos - behaviorTreeEntity.exitPos );
234 currentDir = VectorNormalize( behaviorTreeEntity.origin - behaviorTreeEntity.exitPos );
242 if ( VectorDot( exitDir, currentDir ) < Cos( 30 ) )
245 behaviorTreeEntity.predictedArrivalDirectionValid =
false;
257 if( !behaviorTreeEntity HasPath() )
270 if( IsDefined( behaviorTreeEntity.arrivalFinalPos ) )
272 goalPos = behaviorTreeEntity.arrivalFinalPos;
276 goalPos = behaviorTreeEntity.pathGoalPos;
280 if( Isdefined( behaviorTreeEntity.pathStartPos ) && Isdefined( goalPos ) )
282 pathDist = DistanceSquared( behaviorTreeEntity.pathStartPos, goalPos );
284 if( pathDist <
SQR( 250 ) )
290 if( !behaviorTreeEntity ShouldFaceMotion() )
300 if( !behaviorTreeEntity HasPath() )
303 if(
IS_TRUE( behaviorTreeEntity.accurateFire ) )
309 if( IsDefined( behaviorTreeEntity.enemy ) )
317 if( !behaviorTreeEntity HasPath() )
321 if(
IS_TRUE( behaviorTreeEntity.accurateFire ) )
327 if( IsDefined( behaviorTreeEntity.enemy ) )
336 randomChance = RandomInt( 100 );
338 if( randomChance > 50 )
344 if( randomChance > 25 )
356 if( !behaviorTreeEntity HasPath() )
360 if( IsDefined( behaviorTreeEntity.enemy ) && ( !
IS_TRUE( behaviorTreeEntity.accurateFire ) && !behaviorTreeEntity
humanShouldSprint() ) )
363 if( !behaviorTreeEntity ASMIsTransitionRunning() )
367 if ( !IsDefined( behaviorTreeEntity.replannedCoverArrival ) )
370 behaviorTreeEntity.replannedCoverArrival =
false;
375 behaviorTreeEntity.replannedCoverArrival = undefined;
383 if( !behaviorTreeEntity HasPath() )
389 if( !behaviorTreeEntity ASMIsTransitionRunning() )
393 if ( !IsDefined( behaviorTreeEntity.replannedCoverArrival ) )
396 behaviorTreeEntity.replannedCoverArrival =
false;
401 behaviorTreeEntity.replannedCoverArrival = undefined;
404 if( IsDefined( behaviorTreeEntity.enemy ) )
435 if ( arrivalAngle >= 45 && arrivalAngle <= 120 )
444 if ( arrivalAngle >= 120 && arrivalAngle <= 165 )
453 if ( arrivalAngle >= 165 && arrivalAngle <= 195 )
462 if ( arrivalAngle >= 195 && arrivalAngle <= 240 )
471 if ( arrivalAngle >= 240 && arrivalAngle <= 315 )
492 if ( facingAngle >= 45 && facingAngle <= 135 )
501 if ( facingAngle >= -45 && facingAngle <= 45 )
510 if ( facingAngle >= 0 && facingAngle <= 90 )
519 if ( facingAngle >= -135 && facingAngle <= -45 )
528 if ( facingAngle >= -90 && facingAngle <= 0 )
535 #define DEFAULT_TAC_ARRIVE_DISTANCE 35
536 #define MINIMUM_TAC_ARRIVE_DISTANCE 25
537 #define MINIMUM_TAC_ARRIVE_ANGLE 60
542 if ( getDvarInt(
"enableTacticalArrival") != 1 )
548 if ( !IsDefined( behaviorTreeEntity.node ) )
573 arrivalDvar = getDvarInt(
"tacArrivalDistance" );
574 if ( arrivalDvar != 0 )
576 arrivalDistance = arrivalDvar;
580 nodeOffsetPosition = behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node );
582 if ( Distance( nodeOffsetPosition, behaviorTreeEntity.origin ) > arrivalDistance ||
599 entityAngles = VectorToAngles( behaviorTreeEntity.origin - nodeOffsetPosition );
666 if( !IsDefined( arrivalAnim ) )
669 if( IsDefined( behaviorTreeEntity.node ) && IsDefined( behaviorTreeEntity.pathGoalPos ) )
671 if( !IsCoverNode( behaviorTreeEntity.node ) )
676 nodeOffsetPosition = behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node );
678 if( nodeOffsetPosition != behaviorTreeEntity.pathGoalPos )
683 if( IsDefined( arrivalAnim ) )
687 isSplitArrival = ( splitTime < 1 );
689 nodeApproachYaw = behaviorTreeEntity GetNodeOffsetAngles( behaviorTreeEntity.node )[1];
691 angle = (0, nodeApproachYaw - GetAngleDelta( arrivalAnim ), 0);
695 forwardDir = AnglesToForward( angle );
696 rightDir = AnglesToRight( angle );
699 animLength = GetAnimLength( arrivalAnim );
700 moveDelta = GetMoveDelta( arrivalAnim, 0, (animLength - 0.2) / animLength );
701 preMoveDelta = GetMoveDelta( arrivalAnim, 0, splitTime );
702 postMoveDelta = moveDelta - preMoveDelta;
705 forward = VectorScale( forwardDir, postMoveDelta[0] );
706 right = VectorScale( rightDir, postMoveDelta[1] );
707 coverEnterPos = nodeOffsetPosition - forward + right;
708 postEnterPos = coverEnterPos;
711 forward = VectorScale( forwardDir, preMoveDelta[0] );
712 right = VectorScale( rightDir, preMoveDelta[1] );
713 coverEnterPos = coverEnterPos - forward + right;
716 RecordLine( postEnterPos, nodeOffsetPosition,
ORANGE,
"Animscript", behaviorTreeEntity );
717 RecordLine( coverEnterPos, postEnterPos,
ORANGE,
"Animscript", behaviorTreeEntity );
720 if( !behaviorTreeEntity MayMoveFromPointToPoint( postEnterPos, nodeOffsetPosition,
true,
false ) )
725 if( !behaviorTreeEntity MayMoveFromPointToPoint( coverEnterPos, postEnterPos,
true,
false ) )
732 forwardDir = AnglesToForward( angle );
733 rightDir = AnglesToRight( angle );
735 moveDeltaArray = GetMoveDelta( arrivalAnim );
736 forward = VectorScale( forwardDir, moveDeltaArray[0] );
737 right = VectorScale( rightDir, moveDeltaArray[1] );
738 coverEnterPos = nodeOffsetPosition - forward + right;
740 if( !behaviorTreeEntity MayMoveFromPointToPoint( coverEnterPos, nodeOffsetPosition,
true,
true ) )
752 if( IsPointOnNavMesh( coverEnterPos, behaviorTreeEntity ) )
754 /# RecordCircle( coverEnterPos, 2, (1,0,0),
"Script", behaviorTreeEntity ); #/
755 behaviorTreeEntity UsePosition( coverEnterPos, behaviorTreeEntity.pathGoalPos );
765 #define ARRIVAL_HEIGHT_TOLERANCE 30
768 distSqToNode = DistanceSquared(
self.origin, coverPos );
769 distSqFromNodeToEnterPos = DistanceSquared( coverPos, coverEnterPos );
772 awayFromEnterPos = distSqToNode >= ( distSqFromNodeToEnterPos + 150 );
774 if( !awayFromEnterPos )
777 trace = GroundTrace( coverEnterPos + ( 0, 0, 72 ), coverEnterPos + ( 0, 0, -72 ),
false,
false,
false );
783 if ( GetDvarInt(
"ai_debugArrivals" ) )
785 RecordCircle( coverEnterPos, 1, (1,0,0),
"Animscript" );
786 Record3DText(
"Arrival Start Position", coverEnterPos,
RED,
"Animscript", undefined, 0.4 );
788 RecordCircle(
trace[
"position" ], 1, (1,0,0),
"Animscript" );
789 Record3DText(
"Distance To Ground: " + Int( Abs(
trace[
"position" ][2] - coverPos[2] ) ),
trace[
"position" ] + ( 0, 0, 5 ),
RED,
"Animscript", undefined, 0.4 );
792 RecordLine( coverEnterPos,
trace[
"position" ], (1,0,0),
"Animscript" );
805 if ( !isdefined( level.animArrivalSplitTimes ) )
807 level.animArrivalSplitTimes = [];
810 if ( isdefined( level.animArrivalSplitTimes[arrivalAnim] ) )
812 return level.animArrivalSplitTimes[arrivalAnim];
820 Assert( times.size > 0 );
821 bestsplit = times[0];
826 animLength = GetAnimLength( arrivalAnim );
827 normalizedLength = (animLength - 0.2) / animLength;
829 angleDelta = getAngleDelta( arrivalAnim, 0, normalizedLength );
830 fullDelta = getMoveDelta( arrivalAnim, 0, normalizedLength );
833 bestvalue = -100000000;
835 for ( i = 0; i < numiter; i++ )
837 splitTime = 1.0 * i / (numiter - 1);
839 delta = getMoveDelta( arrivalAnim, 0, splitTime );
840 delta =
DeltaRotate( fullDelta - delta, 180 - angleDelta );
843 delta = ( delta[0], 0 - delta[1], delta[2] );
845 val = min( delta[0] - 32, delta[1] );
847 if ( val > bestvalue || bestsplit < 0 )
850 bestsplit = splitTime;
855 level.animArrivalSplitTimes[arrivalAnim] = bestsplit;
864 return ( delta[0] * cosine - delta[1] * sine, delta[1] * cosine + delta[0] * sine, 0);