‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
archetype_human_locomotion.gsc
Go to the documentation of this file.
1 // COMMON AI SYSTEMS INCLUDES
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;
7 // ADDITIONAL INCLUDES
8 #using scripts\shared\ai\archetype_utility;
9 #using scripts\shared\ai_shared;
10 #using scripts\shared\array_shared;
11 
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;
19 
21 {
22  // ------- PREPARE FOR MOVEMENT -----------//
23  ‪BT_REGISTER_API( "prepareForMovement", &‪prepareForMovement );
24  ‪BSM_REGISTER_API( "prepareForMovement", &‪prepareForMovement );
25 
26  // ------- TACTICAL WALK ARRIVE -----------//
27  ‪BT_REGISTER_API( "shouldTacticalArrive", &‪shouldTacticalArriveCondition );
28 
29  // ------- SPRINT -----------//
30  ‪BT_REGISTER_API( "humanShouldSprint", &‪humanShouldSprint );
31 
32  // ------- ARRIVAL -----------//
33  ‪BSM_REGISTER_API( "planHumanArrivalAtCover", &‪planHumanArrivalAtCover );
34  ‪BSM_REGISTER_API( "shouldPlanArrivalIntoCover", &‪shouldPlanArrivalIntoCover );
35  ‪BSM_REGISTER_CONDITION( "shouldArriveExposed", &‪shouldArriveExposed );
36 
37  // ------- LOCOMOTION UPDATE -----------//
38  ‪BSM_REGISTER_API( "nonCombatLocomotionUpdate", &‪nonCombatLocomotionUpdate );
39  ‪BSM_REGISTER_API( "combatLocomotionStart", &‪combatLocomotionStart );
40  ‪BSM_REGISTER_API( "combatLocomotionUpdate", &‪combatLocomotionUpdate );
41  ‪BSM_REGISTER_CONDITION( "humanNonCombatLocomotionCondition", &‪humanNonCombatLocomotionCondition );
42  ‪BSM_REGISTER_CONDITION( "humanCombatLocomotionCondition", &‪humanCombatLocomotionCondition );
43 
44  ‪BSM_REGISTER_CONDITION( "shouldSwitchToTacticalWalkFromRun", &‪shouldSwitchToTacticalWalkFromRun );
45 
46  ‪BT_REGISTER_API( "prepareToStopNearEnemy", &‪prepareToStopNearEnemy );
47  ‪BSM_REGISTER_CONDITION( "prepareToStopNearEnemy", &‪prepareToStopNearEnemy );
48  ‪BT_REGISTER_API( "prepareToMoveAwayFromNearByEnemy", &‪prepareToMoveAwayFromNearByEnemy );
49 
50  ‪BSM_REGISTER_CONDITION( "shouldTacticalWalkPain", &‪shouldTacticalWalkPain );
51  ‪BSM_REGISTER_CONDITION( "beginTacticalWalkPain", &‪beginTacticalWalkPain );
52  ‪BSM_REGISTER_CONDITION( "shouldContinueTacticalWalkPain", &‪shouldContinueTacticalWalkPain );
53 
54  ‪BSM_REGISTER_CONDITION( "shouldTacticalWalkScan", &‪shouldTacticalWalkScan );
55  ‪BSM_REGISTER_CONDITION( "continueTacticalWalkScan", &‪continueTacticalWalkScan );
56  ‪BSM_REGISTER_API( "tacticalWalkScanTerminate", &‪tacticalWalkScanTerminate );
57 
58  // ------- PAIN -----------//
59  ‪BSM_REGISTER_CONDITION( "BSMLocomotionHasValidPainInterrupt", &‪BSMLocomotionHasValidPainInterrupt ); // only to be used by the BSM
60 }
61 
62 // ------- PAIN -----------//
63 function private ‪tacticalWalkScanTerminate( entity )
64 {
65  entity.lastTacticalScanTime = GetTime();
66 
67  return true;
68 }
69 
70 #define TACTICAL_SCAN_INTERVAL 2000
71 function private ‪shouldTacticalWalkScan( entity )
72 {
73  if ( IsDefined( entity.lastTacticalScanTime ) &&
74  ( entity.lastTacticalScanTime + ‪TACTICAL_SCAN_INTERVAL ) > GetTime() )
75  {
76  return false;
77  }
78 
79  if( !entity HasPath() )
80  {
81  return false;
82  }
83 
84  if ( IsDefined( entity.enemy ) )
85  {
86  return false;
87  }
88 
89  if ( entity ShouldFaceMotion() )
90  {
91  if ( ‪ai::HasAiAttribute( entity, "forceTacticalWalk" ) &&
92  !‪ai::GetAiAttribute( entity, "forceTacticalWalk" ) )
93  {
94  return false;
95  }
96  }
97 
98  animation = entity AsmGetCurrentDeltaAnimation();
99 
100  // Scan animations can only be played at tactical walk animation boundaries.
101  if ( IsDefined( animation ) )
102  {
103  animTime = entity GetAnimTime( animation );
104  return animTime <= 0.05;
105  }
106 
107  return false;
108 }
109 
110 #define TACTICAL_SCAN_BLEND_OUT 0.2
111 function private ‪continueTacticalWalkScan( entity )
112 {
113  if( !entity HasPath() )
114  {
115  return false;
116  }
117 
118  if ( IsDefined( entity.enemy ) )
119  {
120  return false;
121  }
122 
123  if ( entity ShouldFaceMotion() )
124  {
125  if ( ‪ai::HasAiAttribute( entity, "forceTacticalWalk" ) &&
126  !‪ai::GetAiAttribute( entity, "forceTacticalWalk" ) )
127  {
128  return false;
129  }
130  }
131 
132  animation = entity AsmGetCurrentDeltaAnimation();
133 
134  if ( IsDefined( animation ) )
135  {
136  animLength = GetAnimLength( animation );
137  animTime = entity GetAnimTime( animation ) * animLength;
138 
139  normalizedTime = ( animTime + ‪TACTICAL_SCAN_BLEND_OUT ) / animLength;
140 
141  return normalizedTime < 1.0;
142  }
143 
144  return false;
145 }
146 
147 #define PAIN_TIME_WINDOW 3000
148 #define PAIN_CHANCE 0.25
149 function private ‪shouldTacticalWalkPain( entity )
150 {
151  if ( ( !IsDefined( entity.startPainTime ) || ( entity.startPainTime + ‪PAIN_TIME_WINDOW ) < GetTime() ) &&
152  RandomFloat( 1.0 ) > ‪PAIN_CHANCE )
153  {
154  return ‪BSMLocomotionHasValidPainInterrupt( entity );
155  }
156 
157  return false;
158 }
159 
160 function private ‪beginTacticalWalkPain( entity )
161 {
162  entity.startPainTime = GetTime();
163 
164  return true;
165 }
166 
167 #define PAIN_TIME_LENGTH 100
168 function private ‪shouldContinueTacticalWalkPain( entity )
169 {
170  return ( entity.startPainTime + ‪PAIN_TIME_LENGTH ) >= GetTime();
171 }
172 
173 function private ‪BSMLocomotionHasValidPainInterrupt( entity )
174 {
175  return ( entity HasValidInterrupt("pain") );
176 }
177 
178 function private ‪shouldArriveExposed( behaviorTreeEntity )
179 {
180  if( behaviorTreeEntity ‪ai::get_behavior_attribute( "disablearrivals" ) )
181  return false;
182 
183  if( behaviorTreeEntity HasPath() )
184  {
185  if( IsDefined( behaviorTreeEntity.node )
186  && IsCoverNode( behaviorTreeEntity.node )
187  && IsDefined( behaviorTreeEntity.pathGoalPos )
188  && DistanceSquared( behaviorTreeEntity.pathGoalPos, behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node ) ) < 8
189  )
190  {
191  return false;
192  }
193  }
194 
195  return true;
196 }
197 
198 function private ‪prepareToStopNearEnemy( behaviorTreeEntity )
199 {
200  behaviorTreeEntity ClearPath();
201  behaviorTreeEntity.keepClaimedNode = true;
202 }
203 
204 function private ‪prepareToMoveAwayFromNearByEnemy( behaviorTreeEntity )
205 {
206  behaviorTreeEntity ClearPath();
207  behaviorTreeEntity.keepClaimedNode = true;
208 }
209 
210 function private ‪shouldPlanArrivalIntoCover( behaviorTreeEntity )
211 {
212  goingToCoverNode = IsDefined( behaviorTreeEntity.node ) && IsCoverNode( behaviorTreeEntity.node );
213 
214  if( !goingToCoverNode )
215  {
216  return false;
217  }
218 
219  if( IsDefined( behaviorTreeEntity.pathGoalPos ) )
220  {
221  if( IsDefined( behaviorTreeEntity.arrivalfinalpos ) )
222  {
223  if( behaviorTreeEntity.arrivalfinalpos != behaviorTreeEntity.pathGoalPos )
224  {
225  return true;
226  }
227  else if ( behaviorTreeEntity.replannedCoverArrival === false &&
228  IsDefined( behaviorTreeEntity.exitPos ) &&
229  IsDefined( behaviorTreeEntity.predictedExitPos ) )
230  {
231  behaviorTreeEntity.replannedCoverArrival = true;
232 
233  exitDir = VectorNormalize( behaviorTreeEntity.predictedExitPos - behaviorTreeEntity.exitPos );
234  currentDir = VectorNormalize( behaviorTreeEntity.origin - behaviorTreeEntity.exitPos );
235 
236  // If the AI deviated more than 30 degrees from the exit direction we used
237  // for planning an arrival, force a replan. This can typically happen when
238  // an exit animation moves the AI out of cover in a different direction
239  // than we planned for.
240  // Without replanning the AI's path can change significantly enough that
241  // the original planned arrival will be aborted.
242  if ( VectorDot( exitDir, currentDir ) < Cos( 30 ) )
243  {
244  // Force the predicted arrival direction to be recalculated upon a replan.
245  behaviorTreeEntity.predictedArrivalDirectionValid = false;
246  return true;
247  }
248  }
249  }
250  }
251 
252  return false;
253 }
254 
255 function private ‪shouldSwitchToTacticalWalkFromRun( behaviorTreeEntity )
256 {
257  if( !behaviorTreeEntity HasPath() )
258  {
259  return false;
260  }
261 
262  if ( ‪ai::HasAiAttribute( behaviorTreeEntity, "forceTacticalWalk" ) &&
263  ‪ai::GetAiAttribute( behaviorTreeEntity, "forceTacticalWalk" ) )
264  {
265  return true;
266  }
267 
268  goalPos = undefined;
269 
270  if( IsDefined( behaviorTreeEntity.arrivalFinalPos ) )
271  {
272  goalPos = behaviorTreeEntity.arrivalFinalPos;
273  }
274  else
275  {
276  goalPos = behaviorTreeEntity.pathGoalPos;
277  }
278 
279  // for moving short distances
280  if( Isdefined( behaviorTreeEntity.pathStartPos ) && Isdefined( goalPos ) )
281  {
282  pathDist = DistanceSquared( behaviorTreeEntity.pathStartPos, goalPos );
283 
284  if( pathDist < ‪SQR( 250 ) )
285  {
286  return true;
287  }
288  }
289 
290  if( !behaviorTreeEntity ShouldFaceMotion() )
291  {
292  return true;
293  }
294 
295  return false;
296 }
297 
298 function private ‪humanNonCombatLocomotionCondition( behaviorTreeEntity )
299 {
300  if( !behaviorTreeEntity HasPath() )
301  return false;
302 
303  if( ‪IS_TRUE( behaviorTreeEntity.accurateFire ) )
304  return true;
305 
306  if( behaviorTreeEntity ‪humanShouldSprint() )
307  return true;
308 
309  if( IsDefined( behaviorTreeEntity.enemy ) )
310  return false;
311 
312  return true;
313 }
314 
315 function private ‪humanCombatLocomotionCondition( behaviorTreeEntity )
316 {
317  if( !behaviorTreeEntity HasPath() )
318  return false;
319 
320  // AI's like snipers will not fire when on the move.
321  if( ‪IS_TRUE( behaviorTreeEntity.accurateFire ) )
322  return false;
323 
324  if( behaviorTreeEntity ‪humanShouldSprint() )
325  return false;
326 
327  if( IsDefined( behaviorTreeEntity.enemy ) )
328  return true;
329 
330  return false;
331 }
332 
333 function private ‪combatLocomotionStart( behaviorTreeEntity )
334 {
335  // Choose a runNGun variation.
336  randomChance = RandomInt( 100 );
337 
338  if( randomChance > 50 )
339  {
341  return true;
342  }
343 
344  if( randomChance > 25 )
345  {
347  return true;
348  }
349 
351  return true;
352 }
353 
354 function private ‪nonCombatLocomotionUpdate( behaviorTreeEntity )
355 {
356  if( !behaviorTreeEntity HasPath() )
357  return false;
358 
359  // AI will go into CombatLocomotion, unless they are set to accurate fire or sprinting
360  if( IsDefined( behaviorTreeEntity.enemy ) && ( !‪IS_TRUE( behaviorTreeEntity.accurateFire ) && !behaviorTreeEntity ‪humanShouldSprint() ) )
361  return false;
362 
363  if( !behaviorTreeEntity ASMIsTransitionRunning() )
364  {
366 
367  if ( !IsDefined( behaviorTreeEntity.replannedCoverArrival ) )
368  {
369  // Force an arrival replan once the transition animation completes.
370  behaviorTreeEntity.replannedCoverArrival = false;
371  }
372  }
373  else
374  {
375  behaviorTreeEntity.replannedCoverArrival = undefined;
376  }
377 
378  return true;
379 }
380 
381 function private ‪combatLocomotionUpdate( behaviorTreeEntity )
382 {
383  if( !behaviorTreeEntity HasPath() )
384  return false;
385 
386  if( behaviorTreeEntity ‪humanShouldSprint() )
387  return false;
388 
389  if( !behaviorTreeEntity ASMIsTransitionRunning() )
390  {
392 
393  if ( !IsDefined( behaviorTreeEntity.replannedCoverArrival ) )
394  {
395  // Force an arrival replan once the transition animation completes.
396  behaviorTreeEntity.replannedCoverArrival = false;
397  }
398  }
399  else
400  {
401  behaviorTreeEntity.replannedCoverArrival = undefined;
402  }
403 
404  if( IsDefined( behaviorTreeEntity.enemy ) )
405  return true;
406 
407  return false;
408 }
409 
410 
411 // ------- PREPARE FOR MOVEMENT -----------//
412 function private ‪prepareForMovement( behaviorTreeEntity )
413 {
415 
416  return true;
417 }
418 
419 // ------- TACTICAL WALK ARRIVE -----------//
420 
421 // Here's how the arrival angles look relative to the cover node x, with the direction
422 // numbers on the outside
423 // 7 8 9
424 //
425 // 45 0 315
426 //
427 // 4 90 x 270 6
428 //
429 // 135 180 225
430 //
431 // 1 2 3
432 
433 function private ‪isArrivingFour( arrivalAngle )
434 {
435  if ( arrivalAngle >= 45 && arrivalAngle <= 120 )
436  {
437  return true;
438  }
439  return false;
440 }
441 
442 function private ‪isArrivingOne( arrivalAngle )
443 {
444  if ( arrivalAngle >= 120 && arrivalAngle <= 165 )
445  {
446  return true;
447  }
448  return false;
449 }
450 
451 function private ‪isArrivingTwo( arrivalAngle )
452 {
453  if ( arrivalAngle >= 165 && arrivalAngle <= 195 )
454  {
455  return true;
456  }
457  return false;
458 }
459 
460 function private ‪isArrivingThree( arrivalAngle )
461 {
462  if ( arrivalAngle >= 195 && arrivalAngle <= 240 )
463  {
464  return true;
465  }
466  return false;
467 }
468 
469 function private ‪isArrivingSix( arrivalAngle )
470 {
471  if ( arrivalAngle >= 240 && arrivalAngle <= 315 )
472  {
473  return true;
474  }
475  return false;
476 }
477 
478 // Here's how the facing angles look relative to the player x, with the direction
479 // numbers on the outside
480 // 7 8 9
481 //
482 // 45 0 -45
483 //
484 // 4 90 x -90 6
485 //
486 // 135 180/-180 -135
487 //
488 // 1 2 3
489 
490 function private ‪isFacingFour( facingAngle )
491 {
492  if ( facingAngle >= 45 && facingAngle <= 135 )
493  {
494  return true;
495  }
496  return false;
497 }
498 
499 function private ‪isFacingEight( facingAngle )
500 {
501  if ( facingAngle >= -45 && facingAngle <= 45 )
502  {
503  return true;
504  }
505  return false;
506 }
507 
508 function private ‪isFacingSeven( facingAngle )
509 {
510  if ( facingAngle >= 0 && facingAngle <= 90 )
511  {
512  return true;
513  }
514  return false;
515 }
516 
517 function private ‪isFacingSix( facingAngle )
518 {
519  if ( facingAngle >= -135 && facingAngle <= -45 )
520  {
521  return true;
522  }
523  return false;
524 }
525 
526 function private ‪isFacingNine( facingAngle )
527 {
528  if ( facingAngle >= -90 && facingAngle <= 0 )
529  {
530  return true;
531  }
532  return false;
533 }
534 
535 #define DEFAULT_TAC_ARRIVE_DISTANCE 35
536 #define MINIMUM_TAC_ARRIVE_DISTANCE 25
537 #define MINIMUM_TAC_ARRIVE_ANGLE 60
538 
539 function private ‪shouldTacticalArriveCondition( behaviorTreeEntity )
540 {
541  // TEMP: Alden Higgins 7-30-2014 don't tactical arrive unless dvar is set
542  if ( getDvarInt("enableTacticalArrival") != 1 )
543  {
544  return false;
545  }
546 
547  // Check if behaviorTreeEntity has a cover node as a goal
548  if ( !IsDefined( behaviorTreeEntity.node ) )
549  {
550  return false;
551  }
552 
553  // TEMP: Alden Higgins 7-31-2014 Temporary check cover node type as new tactical arrival animations are added
554  if ( !‪NODE_COVER_LEFT( behaviorTreeEntity.node )
555 // && !NODE_COVER_RIGHT( behaviorTreeEntity.node )
556 // && !NODE_COVER_STAND( behaviorTreeEntity.node )
557 // && !NODE_COVER_CROUCH( behaviorTreeEntity.node )
558  )
559  {
560  return false;
561  }
562 
563  // TEMP: Alden Higgins 8-5-2014 Temporary check cover node stance as well
564  stance = ‪Blackboard::GetBlackBoardAttribute( behaviorTreeEntity, ‪ARRIVAL_STANCE );
565  if ( stance != ‪STANCE_STAND )
566  {
567  return false;
568  }
569 
570  arrivalDistance = ‪DEFAULT_TAC_ARRIVE_DISTANCE;
571  /#
572  // Can be used for testing purposes to see if an animation works better from a different distance
573  arrivalDvar = getDvarInt( "tacArrivalDistance" );
574  if ( arrivalDvar != 0 )
575  {
576  arrivalDistance = arrivalDvar;
577  }
578  #/
579 
580  nodeOffsetPosition = behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node );
581 
582  if ( Distance( nodeOffsetPosition, behaviorTreeEntity.origin ) > arrivalDistance ||
583  Distance( nodeOffsetPosition, behaviorTreeEntity.origin ) < ‪MINIMUM_TAC_ARRIVE_DISTANCE )
584  {
585  return false;
586  }
587 
588  // If the player is entering from an angle less than minimumTacArrivalAngle degrees away from the cover node's forward angles
589  // then don't tactically arrive...here's a diagram where x is the cover node, the dashes are the cover's geo, and the angles
590  // are the differences from the node's forward that we are checking:
591  //
592  // 45 25 0 25 45
593  // 60 60
594  // -----
595  // 90 x 90
596  //
597  // 135 180 135
598  //
599  entityAngles = VectorToAngles( behaviorTreeEntity.origin - nodeOffsetPosition );
600  if ( abs( behaviorTreeEntity.node.angles[ 1 ] - entityAngles[ 1 ] ) < ‪MINIMUM_TAC_ARRIVE_ANGLE )
601  {
602  return false;
603  }
604 
605  tacticalFaceAngle = ‪Blackboard::GetBlackBoardAttribute( behaviorTreeEntity, ‪TACTICAL_ARRIVAL_FACING_YAW );
606  arrivalAngle = ‪Blackboard::GetBlackBoardAttribute( behaviorTreeEntity, ‪LOCOMOTION_ARRIVAL_YAW );
607  // Check and make sure the player is facing the right way depending on the the angle they arrive at in order to play a tactical arrival
608  if ( ‪isArrivingFour( arrivalAngle ) )
609  {
610  if ( !‪isFacingSix( tacticalFaceAngle ) && !‪isFacingEight( tacticalFaceAngle ) && !‪isFacingFour( tacticalFaceAngle ) )
611  {
612  return false;
613  }
614  }
615  else if ( ‪isArrivingOne( arrivalAngle ) )
616  {
617  if ( !‪isFacingNine( tacticalFaceAngle ) && !‪isFacingSeven( tacticalFaceAngle ) )
618  {
619  return false;
620  }
621  }
622  else if ( ‪isArrivingTwo( arrivalAngle ) )
623  {
624  if ( !‪isFacingEight( tacticalFaceAngle ) )
625  {
626  return false;
627  }
628  }
629  else if ( ‪isArrivingThree( arrivalAngle ) )
630  {
631  if ( !‪isFacingSeven( tacticalFaceAngle ) && !‪isFacingNine( tacticalFaceAngle ) )
632  {
633  return false;
634  }
635  }
636  else if ( ‪isArrivingSix( arrivalAngle ) )
637  {
638  if ( !‪isFacingFour( tacticalFaceAngle ) && !‪isFacingEight( tacticalFaceAngle ) && !‪isFacingSix( tacticalFaceAngle ) )
639  {
640  return false;
641  }
642  }
643  else
644  {
645  return false;
646  }
647  return true;
648 }
649 
650 // ------- SPRINT -----------//
651 function private ‪humanShouldSprint()
652 {
654 
655  return ( currentLocoMovementType == ‪HUMAN_LOCOMOTION_MOVEMENT_SPRINT );
656 }
657 
658 // ------- ARRIVAL PLANNER -----------//
659 function private ‪planHumanArrivalAtCover( behaviorTreeEntity, arrivalAnim )
660 {
661  if( behaviorTreeEntity ‪ai::get_behavior_attribute( "disablearrivals" ) )
662  return false;
663 
665 
666  if( !IsDefined( arrivalAnim ) )
667  return false;
668 
669  if( IsDefined( behaviorTreeEntity.node ) && IsDefined( behaviorTreeEntity.pathGoalPos ) )
670  {
671  if( !IsCoverNode( behaviorTreeEntity.node ) )
672  {
673  return false;
674  }
675 
676  nodeOffsetPosition = behaviorTreeEntity GetNodeOffsetPosition( behaviorTreeEntity.node );
677 
678  if( nodeOffsetPosition != behaviorTreeEntity.pathGoalPos )
679  {
680  return false;
681  }
682 
683  if( IsDefined( arrivalAnim ) )
684  {
685  isRight = ‪NODE_COVER_RIGHT(behaviorTreeEntity.node);
686  splitTime = ‪GetArrivalSplitTime( arrivalAnim, isRight );
687  isSplitArrival = ( splitTime < 1 );
688 
689  nodeApproachYaw = behaviorTreeEntity GetNodeOffsetAngles( behaviorTreeEntity.node )[1];
690 
691  angle = (0, nodeApproachYaw - GetAngleDelta( arrivalAnim ), 0);
692 
693  if( isSplitArrival )
694  {
695  forwardDir = AnglesToForward( angle );
696  rightDir = AnglesToRight( angle );
697 
698  // TODO(David Young 2-25-15): This assumes a blend out of 0.2 seconds.
699  animLength = GetAnimLength( arrivalAnim );
700  moveDelta = GetMoveDelta( arrivalAnim, 0, (animLength - 0.2) / animLength );
701  preMoveDelta = GetMoveDelta( arrivalAnim, 0, splitTime );
702  postMoveDelta = moveDelta - preMoveDelta;
703 
704  // post delta
705  forward = VectorScale( forwardDir, postMoveDelta[0] );
706  right = VectorScale( rightDir, postMoveDelta[1] );
707  coverEnterPos = nodeOffsetPosition - forward + right;
708  postEnterPos = coverEnterPos;
709 
710  // pre delta
711  forward = VectorScale( forwardDir, preMoveDelta[0] );
712  right = VectorScale( rightDir, preMoveDelta[1] );
713  coverEnterPos = coverEnterPos - forward + right;
714 
715  /#
716  RecordLine( postEnterPos, nodeOffsetPosition, ‪ORANGE, "Animscript", behaviorTreeEntity );
717  RecordLine( coverEnterPos, postEnterPos, ‪ORANGE, "Animscript", behaviorTreeEntity );
718  #/
719 
720  if( !behaviorTreeEntity MayMoveFromPointToPoint( postEnterPos, nodeOffsetPosition, true, false ) )
721  {
722  return false;
723  }
724 
725  if( !behaviorTreeEntity MayMoveFromPointToPoint( coverEnterPos, postEnterPos, true, false ) )
726  {
727  return false;
728  }
729  }
730  else
731  {
732  forwardDir = AnglesToForward( angle );
733  rightDir = AnglesToRight( angle );
734 
735  moveDeltaArray = GetMoveDelta( arrivalAnim );
736  forward = VectorScale( forwardDir, moveDeltaArray[0] );
737  right = VectorScale( rightDir, moveDeltaArray[1] );
738  coverEnterPos = nodeOffsetPosition - forward + right;
739 
740  if( !behaviorTreeEntity MayMoveFromPointToPoint( coverEnterPos, nodeOffsetPosition, true, true ) )
741  {
742  return false;
743  }
744  }
745 
746  if( !‪checkCoverArrivalConditions( coverEnterPos, nodeOffsetPosition ) )
747  {
748  return false;
749  }
750 
751  // Make sure the arrival pos is clear
752  if( IsPointOnNavMesh( coverEnterPos, behaviorTreeEntity ) )
753  {
754  /# RecordCircle( coverEnterPos, 2, (1,0,0), "Script", behaviorTreeEntity ); #/
755  behaviorTreeEntity UsePosition( coverEnterPos, behaviorTreeEntity.pathGoalPos );
756 
757  return true;
758  }
759  }
760  }
761 
762  return false;
763 }
764 
765 #define ARRIVAL_HEIGHT_TOLERANCE 30
766 function private ‪checkCoverArrivalConditions( coverEnterPos, coverPos )
767 {
768  distSqToNode = DistanceSquared( self.origin, coverPos );
769  distSqFromNodeToEnterPos = DistanceSquared( coverPos, coverEnterPos );
770 
771  // check if the AI is enough distance away from the coverEnterPos
772  awayFromEnterPos = distSqToNode >= ( distSqFromNodeToEnterPos + 150 );
773 
774  if( !awayFromEnterPos )
775  return false;
776 
777  ‪trace = GroundTrace( coverEnterPos + ( 0, 0, 72 ), coverEnterPos + ( 0, 0, -72 ), false, false, false );
778 
779  // Make sure the arrival position is within a height tolerance to the cover position.
780  if ( IsDefined( ‪trace[ "position" ] ) && Abs( ‪trace[ "position" ][2] - coverPos[2] ) > ‪ARRIVAL_HEIGHT_TOLERANCE )
781  {
782 /#
783  if ( GetDvarInt( "ai_debugArrivals" ) )
784  {
785  RecordCircle( coverEnterPos, 1, (1,0,0), "Animscript" );
786  Record3DText( "Arrival Start Position", coverEnterPos, ‪RED, "Animscript", undefined, 0.4 );
787 
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 );
790  Record3DText( "Ground Position Below Height Tolerance of " + ‪ARRIVAL_HEIGHT_TOLERANCE, ‪trace[ "position" ], ‪RED, "Animscript", undefined, 0.4 );
791 
792  RecordLine( coverEnterPos, ‪trace[ "position" ], (1,0,0), "Animscript" );
793  }
794 #/
795  return false;
796  }
797 
798  return true;
799 }
800 
801 // TODO - This function is very expensive,
802 // we need to have cover_split notetrack in all the arrival/exit animations wherever there is a split.
803 function private ‪GetArrivalSplitTime( arrivalAnim, isright )
804 {
805  if ( !isdefined( level.animArrivalSplitTimes ) )
806  {
807  level.animArrivalSplitTimes = [];
808  }
809 
810  if ( isdefined( level.animArrivalSplitTimes[arrivalAnim] ) )
811  {
812  return level.animArrivalSplitTimes[arrivalAnim];
813  }
814 
815  bestsplit = -1;
816 
817  if( AnimHasNotetrack( arrivalAnim, ‪ARRIVAL_COVER_SPLIT_NOTETRACK ) )
818  {
819  times = GetNotetrackTimes( arrivalAnim, ‪ARRIVAL_COVER_SPLIT_NOTETRACK );
820  Assert( times.size > 0 );
821  bestsplit = times[0];
822  }
823  else
824  {
825  // TODO(David Young 2-25-15): Hardcoded assumption of 0.2 blendout.
826  animLength = GetAnimLength( arrivalAnim );
827  normalizedLength = (animLength - 0.2) / animLength;
828 
829  angleDelta = getAngleDelta( arrivalAnim, 0, normalizedLength );
830  fullDelta = getMoveDelta( arrivalAnim, 0, normalizedLength );
831  const numiter = 100;
832 
833  bestvalue = -100000000;
834 
835  for ( i = 0; i < numiter; i++ )
836  {
837  splitTime = 1.0 * i / (numiter - 1);
838 
839  delta = getMoveDelta( arrivalAnim, 0, splitTime );
840  delta = ‪DeltaRotate( fullDelta - delta, 180 - angleDelta );
841 
842  if ( isright )
843  delta = ( delta[0], 0 - delta[1], delta[2] );
844 
845  val = min( delta[0] - 32, delta[1] );
846 
847  if ( val > bestvalue || bestsplit < 0 )
848  {
849  bestvalue = val;
850  bestsplit = splitTime;
851  }
852  }
853  }
854 
855  level.animArrivalSplitTimes[arrivalAnim] = bestsplit;
856 
857  return bestsplit;
858 }
859 
860 function private ‪DeltaRotate( delta, yaw )
861 {
862  cosine = cos( yaw );
863  sine = sin( yaw );
864  return ( delta[0] * cosine - delta[1] * sine, delta[1] * cosine + delta[0] * sine, 0);
865 }
‪PAIN_TIME_WINDOW
‪#define PAIN_TIME_WINDOW
Definition: archetype_human_locomotion.gsc:147
‪humanShouldSprint
‪function private humanShouldSprint()
Definition: archetype_human_locomotion.gsc:651
‪isArrivingFour
‪function private isArrivingFour(arrivalAngle)
Definition: archetype_human_locomotion.gsc:433
‪isArrivingOne
‪function private isArrivingOne(arrivalAngle)
Definition: archetype_human_locomotion.gsc:442
‪BT_REGISTER_API
‪#define BT_REGISTER_API(name, function)
Definition: behavior.gsh:1
‪shouldPlanArrivalIntoCover
‪function private shouldPlanArrivalIntoCover(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:210
‪PAIN_TIME_LENGTH
‪#define PAIN_TIME_LENGTH
Definition: archetype_human_locomotion.gsc:167
‪combatLocomotionUpdate
‪function private combatLocomotionUpdate(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:381
‪PAIN_CHANCE
‪#define PAIN_CHANCE
Definition: archetype_human_locomotion.gsc:148
‪isArrivingThree
‪function private isArrivingThree(arrivalAngle)
Definition: archetype_human_locomotion.gsc:460
‪BSMLocomotionHasValidPainInterrupt
‪function private BSMLocomotionHasValidPainInterrupt(entity)
Definition: archetype_human_locomotion.gsc:173
‪BSM_REGISTER_API
‪#define BSM_REGISTER_API(name, scriptFunction)
Definition: behavior_state_machine.gsh:17
‪GetArrivalSplitTime
‪function private GetArrivalSplitTime(arrivalAnim, isright)
Definition: archetype_human_locomotion.gsc:803
‪prepareForMovement
‪function private prepareForMovement(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:412
‪ARRIVAL_STANCE
‪#define ARRIVAL_STANCE
Definition: blackboard.gsh:25
‪humanCombatLocomotionCondition
‪function private humanCombatLocomotionCondition(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:315
‪shouldArriveExposed
‪function private shouldArriveExposed(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:178
‪HUMAN_LOCOMOTION_MOVEMENT_SPRINT
‪#define HUMAN_LOCOMOTION_MOVEMENT_SPRINT
Definition: blackboard.gsh:126
‪NODE_COVER_LEFT
‪#define NODE_COVER_LEFT(_node)
Definition: utility.gsh:6
‪isFacingFour
‪function private isFacingFour(facingAngle)
Definition: archetype_human_locomotion.gsc:490
‪combatLocomotionStart
‪function private combatLocomotionStart(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:333
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪HasAiAttribute
‪function HasAiAttribute(entity, attribute)
Definition: ai_interface.gsc:132
‪SetBlackBoardAttribute
‪function SetBlackBoardAttribute(entity, attributeName, attributeValue)
Definition: blackboard.gsc:56
‪isFacingSeven
‪function private isFacingSeven(facingAngle)
Definition: archetype_human_locomotion.gsc:508
‪RUN_N_GUN_VARIATION
‪#define RUN_N_GUN_VARIATION
Definition: blackboard.gsh:222
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪GetBlackBoardAttribute
‪function GetBlackBoardAttribute(entity, attributeName)
Definition: blackboard.gsc:32
‪LOCOMOTION_ARRIVAL_YAW
‪#define LOCOMOTION_ARRIVAL_YAW
Definition: blackboard.gsh:64
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪RED
‪#define RED
Definition: shared.gsh:175
‪RUN_N_GUN_FORWARD
‪#define RUN_N_GUN_FORWARD
Definition: blackboard.gsh:223
‪prepareToMoveAwayFromNearByEnemy
‪function private prepareToMoveAwayFromNearByEnemy(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:204
‪STANCE
‪#define STANCE
Definition: blackboard.gsh:36
‪STANCE_STAND
‪#define STANCE_STAND
Definition: blackboard.gsh:273
‪DESIRED_STANCE
‪#define DESIRED_STANCE
Definition: blackboard.gsh:18
‪isArrivingSix
‪function private isArrivingSix(arrivalAngle)
Definition: archetype_human_locomotion.gsc:469
‪RUN_N_GUN_STRAFE_2
‪#define RUN_N_GUN_STRAFE_2
Definition: blackboard.gsh:225
‪TACTICAL_SCAN_BLEND_OUT
‪#define TACTICAL_SCAN_BLEND_OUT
Definition: archetype_human_locomotion.gsc:110
‪TACTICAL_SCAN_INTERVAL
‪#define TACTICAL_SCAN_INTERVAL
Definition: archetype_human_locomotion.gsc:70
‪RegisterBehaviorScriptfunctions
‪function autoexec RegisterBehaviorScriptfunctions()
Definition: archetype_human_locomotion.gsc:20
‪checkCoverArrivalConditions
‪function private checkCoverArrivalConditions(coverEnterPos, coverPos)
Definition: archetype_human_locomotion.gsc:766
‪NODE_COVER_RIGHT
‪#define NODE_COVER_RIGHT(_node)
Definition: utility.gsh:7
‪RUN_N_GUN_STRAFE_1
‪#define RUN_N_GUN_STRAFE_1
Definition: blackboard.gsh:224
‪isFacingNine
‪function private isFacingNine(facingAngle)
Definition: archetype_human_locomotion.gsc:526
‪DEFAULT_MOVEMENT_STANCE
‪#define DEFAULT_MOVEMENT_STANCE
Definition: blackboard.gsh:281
‪ARRIVAL_COVER_SPLIT_NOTETRACK
‪#define ARRIVAL_COVER_SPLIT_NOTETRACK
Definition: behavior.gsh:68
‪shouldContinueTacticalWalkPain
‪function private shouldContinueTacticalWalkPain(entity)
Definition: archetype_human_locomotion.gsc:168
‪TACTICAL_ARRIVAL_FACING_YAW
‪#define TACTICAL_ARRIVAL_FACING_YAW
Definition: blackboard.gsh:65
‪MINIMUM_TAC_ARRIVE_ANGLE
‪#define MINIMUM_TAC_ARRIVE_ANGLE
Definition: archetype_human_locomotion.gsc:537
‪nonCombatLocomotionUpdate
‪function private nonCombatLocomotionUpdate(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:354
‪planHumanArrivalAtCover
‪function private planHumanArrivalAtCover(behaviorTreeEntity, arrivalAnim)
Definition: archetype_human_locomotion.gsc:659
‪GetAiAttribute
‪function GetAiAttribute(entity, attribute)
Definition: ai_interface.gsc:118
‪ARRIVAL_HEIGHT_TOLERANCE
‪#define ARRIVAL_HEIGHT_TOLERANCE
Definition: archetype_human_locomotion.gsc:765
‪isArrivingTwo
‪function private isArrivingTwo(arrivalAngle)
Definition: archetype_human_locomotion.gsc:451
‪BSM_REGISTER_CONDITION
‪#define BSM_REGISTER_CONDITION(name, scriptFunction)
Definition: behavior_state_machine.gsh:14
‪HUMAN_LOCOMOTION_MOVEMENT_TYPE
‪#define HUMAN_LOCOMOTION_MOVEMENT_TYPE
Definition: blackboard.gsh:124
‪MINIMUM_TAC_ARRIVE_DISTANCE
‪#define MINIMUM_TAC_ARRIVE_DISTANCE
Definition: archetype_human_locomotion.gsc:536
‪shouldSwitchToTacticalWalkFromRun
‪function private shouldSwitchToTacticalWalkFromRun(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:255
‪isFacingSix
‪function private isFacingSix(facingAngle)
Definition: archetype_human_locomotion.gsc:517
‪beginTacticalWalkPain
‪function private beginTacticalWalkPain(entity)
Definition: archetype_human_locomotion.gsc:160
‪shouldTacticalArriveCondition
‪function private shouldTacticalArriveCondition(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:539
‪prepareToStopNearEnemy
‪function private prepareToStopNearEnemy(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:198
‪isFacingEight
‪function private isFacingEight(facingAngle)
Definition: archetype_human_locomotion.gsc:499
‪DeltaRotate
‪function private DeltaRotate(delta, yaw)
Definition: archetype_human_locomotion.gsc:860
‪shouldTacticalWalkScan
‪function private shouldTacticalWalkScan(entity)
Definition: archetype_human_locomotion.gsc:71
‪ORANGE
‪#define ORANGE
Definition: shared.gsh:179
‪get_behavior_attribute
‪function get_behavior_attribute(attribute)
Definition: ai_shared.gsc:184
‪tacticalWalkScanTerminate
‪function private tacticalWalkScanTerminate(entity)
Definition: archetype_human_locomotion.gsc:63
‪DEFAULT_TAC_ARRIVE_DISTANCE
‪#define DEFAULT_TAC_ARRIVE_DISTANCE
Definition: archetype_human_locomotion.gsc:535
‪shouldTacticalWalkPain
‪function private shouldTacticalWalkPain(entity)
Definition: archetype_human_locomotion.gsc:149
‪humanNonCombatLocomotionCondition
‪function private humanNonCombatLocomotionCondition(behaviorTreeEntity)
Definition: archetype_human_locomotion.gsc:298
‪continueTacticalWalkScan
‪function private continueTacticalWalkScan(entity)
Definition: archetype_human_locomotion.gsc:111