‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
archetype_robot.gsc
Go to the documentation of this file.
1 #using scripts\shared\ai_shared;
2 #using scripts\shared\clientfield_shared;
3 #using scripts\shared\laststand_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\spawner_shared;
6 #using scripts\shared\gameskill_shared;
7 #using scripts\shared\util_shared;
8 #using scripts\shared\system_shared;
9 
10 #using scripts\shared\ai\archetype_cover_utility;
11 #using scripts\shared\ai\archetype_locomotion_utility;
12 #using scripts\shared\ai\archetype_mocomps_utility;
13 #using scripts\shared\ai\archetype_robot_interface;
14 #using scripts\shared\ai\archetype_utility;
15 
16 #using scripts\shared\ai\systems\ai_blackboard;
17 #using scripts\shared\ai\systems\ai_interface;
18 #using scripts\shared\ai\systems\ai_squads;
19 #using scripts\shared\ai\systems\animation_state_machine_mocomp;
20 #using scripts\shared\ai\systems\animation_state_machine_utility;
21 #using scripts\shared\ai\systems\behavior_state_machine;
22 #using scripts\shared\ai\systems\behavior_tree_utility;
23 #using scripts\shared\ai\systems\blackboard;
24 #using scripts\shared\ai\systems\debug;
25 #using scripts\shared\ai\systems\destructible_character;
26 #using scripts\shared\ai\systems\gib;
27 #using scripts\shared\ai\systems\shared;
28 
29 #using scripts\shared\vehicles\_raps;
30 
31 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
32 #insert scripts\shared\shared.gsh;
33 #insert scripts\shared\version.gsh;
34 #insert scripts\shared\ai\archetype_robot.gsh;
35 #insert scripts\shared\ai\utility.gsh;
36 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
37 #insert scripts\shared\ai\systems\behavior.gsh;
38 #insert scripts\shared\ai\systems\behavior_state_machine.gsh;
39 #insert scripts\shared\ai\systems\behavior_tree.gsh;
40 #insert scripts\shared\ai\systems\blackboard.gsh;
41 #insert scripts\shared\ai\systems\gib.gsh;
42 
43 ‪REGISTER_SYSTEM( "robot", &‪__init__, undefined )
44 
45 function ‪__init__()
46 {
47  // INIT BLACKBOARD
49 
50  // INIT ROBOT ON SPAWN
52 
54  {
56  "actor",
61 
63  "actor",
68 
70  "actor",
75 
77  "actor",
82  }
83 
86 }
87 
88 #namespace RobotSoldierBehavior;
89 
91 {
92  // ------- ROBOT ACTIONS -----------//
93  ‪BT_REGISTER_ACTION( "robotStepIntoAction", &‪stepIntoInitialize, undefined, &‪stepIntoTerminate );
94  ‪BT_REGISTER_ACTION( "robotStepOutAction", &‪stepOutInitialize, undefined, &‪stepOutTerminate );
95  ‪BT_REGISTER_ACTION( "robotTakeOverAction", &‪takeOverInitialize, undefined, &‪takeOverTerminate );
97 
98  // ------- ROBOT ACTION APIS ----------//
99  ‪BT_REGISTER_API( "robotBecomeCrawler", &‪robotBecomeCrawler );
100  ‪BT_REGISTER_API( "robotDropStartingWeapon", &‪robotDropStartingWeapon );
101  ‪BT_REGISTER_API( "robotDontTakeCover", &‪robotDontTakeCover );
102  ‪BT_REGISTER_API( "robotCoverOverInitialize", &‪robotCoverOverInitialize );
103  ‪BT_REGISTER_API( "robotCoverOverTerminate", &‪robotCoverOverTerminate );
104  ‪BT_REGISTER_API( "robotExplode", &‪robotExplode );
105  ‪BT_REGISTER_API( "robotExplodeTerminate", &‪robotExplodeTerminate );
106  ‪BT_REGISTER_API( "robotDeployMiniRaps", &‪robotDeployMiniRaps );
107  ‪BT_REGISTER_API( "robotMoveToPlayer", &‪moveToPlayerUpdate );
108  ‪BT_REGISTER_API( "robotStartSprint", &‪robotStartSprint );
109  ‪BSM_REGISTER_API( "robotStartSprint", &‪robotStartSprint );
110  ‪BT_REGISTER_API( "robotStartSuperSprint", &‪robotStartSuperSprint );
111  ‪BT_REGISTER_API( "robotTacticalWalkActionStart", &‪robotTacticalWalkActionStart );
112  ‪BSM_REGISTER_API( "robotTacticalWalkActionStart", &‪robotTacticalWalkActionStart );
113  ‪BT_REGISTER_API( "robotDie", &‪robotDie );
114  ‪BT_REGISTER_API( "robotCleanupChargeMeleeAttack", &‪robotCleanupChargeMeleeAttack );
115 
116  // ------- ROBOT CONDITIONS -----------//
117  ‪BT_REGISTER_API( "robotIsMoving", &‪robotIsMoving );
118  ‪BT_REGISTER_API( "robotAbleToShoot", &‪robotAbleToShootCondition );
119  ‪BT_REGISTER_API( "robotCrawlerCanShootEnemy", &‪robotCrawlerCanShootEnemy );
120  ‪BT_REGISTER_API( "canMoveToEnemy", &‪canMoveToEnemyCondition );
121  ‪BT_REGISTER_API( "canMoveCloseToEnemy", &‪canMoveCloseToEnemyCondition );
122  ‪BT_REGISTER_API( "hasMiniRaps", &‪hasMiniRaps );
123  ‪BT_REGISTER_API( "robotIsAtCover", &‪robotIsAtCoverCondition );
124  ‪BT_REGISTER_API( "robotShouldTacticalWalk", &‪robotShouldTacticalWalk );
125  ‪BT_REGISTER_API( "robotHasCloseEnemyToMelee", &‪robotHasCloseEnemyToMelee );
126  ‪BT_REGISTER_API( "robotHasEnemyToMelee", &‪robotHasEnemyToMelee );
127  ‪BT_REGISTER_API( "robotRogueHasCloseEnemyToMelee", &‪robotRogueHasCloseEnemyToMelee );
128  ‪BT_REGISTER_API( "robotRogueHasEnemyToMelee", &‪robotRogueHasEnemyToMelee );
129  ‪BT_REGISTER_API( "robotIsCrawler", &‪robotIsCrawler );
130  ‪BT_REGISTER_API( "robotIsMarching", &‪robotIsMarching );
131  ‪BT_REGISTER_API( "robotPrepareForAdjustToCover", &‪robotPrepareForAdjustToCover );
132  ‪BT_REGISTER_API( "robotShouldAdjustToCover", &‪robotShouldAdjustToCover );
133  ‪BT_REGISTER_API( "robotShouldBecomeCrawler", &‪robotShouldBecomeCrawler );
134  ‪BT_REGISTER_API( "robotShouldReactAtCover", &‪robotShouldReactAtCover );
135  ‪BT_REGISTER_API( "robotShouldExplode", &‪robotShouldExplode );
136  ‪BT_REGISTER_API( "robotShouldShutdown", &‪robotShouldShutdown );
137  ‪BT_REGISTER_API( "robotSupportsOverCover", &‪robotSupportsOverCover );
138  ‪BT_REGISTER_API( "shouldStepIn", &‪shouldStepInCondition );
139  ‪BT_REGISTER_API( "shouldTakeOver", &‪shouldTakeOverCondition );
140  ‪BT_REGISTER_API( "supportsStepOut", &‪supportsStepOutCondition );
141  ‪BT_REGISTER_API( "setDesiredStanceToStand", &‪setDesiredStanceToStand );
142  ‪BT_REGISTER_API( "setDesiredStanceToCrouch", &‪setDesiredStanceToCrouch );
143  ‪BT_REGISTER_API( "toggleDesiredStance", &‪toggleDesiredStance );
144  ‪BT_REGISTER_API( "robotMovement", &‪robotMovement );
145  ‪BT_REGISTER_API( "robotDelayMovement", &‪robotDelayMovement );
146  ‪BT_REGISTER_API( "robotInvalidateCover", &‪robotInvalidateCover );
147  ‪BT_REGISTER_API( "robotShouldChargeMelee", &‪robotShouldChargeMelee );
148  ‪BT_REGISTER_API( "robotShouldMelee", &‪robotShouldMelee );
149  ‪BT_REGISTER_API( "robotScriptRequiresToSprint", &‪scriptRequiresToSprintCondition );
150  ‪BT_REGISTER_API( "robotScanExposedPainTerminate", &‪robotScanExposedPainTerminate );
151  ‪BT_REGISTER_API( "robotTookEmpDamage", &‪robotTookEmpDamage );
152  ‪BT_REGISTER_API( "robotNoCloseEnemyService", &‪robotNoCloseEnemyService );
153 
154  ‪BT_REGISTER_API( "robotWithinSprintRange", &‪robotWithinSprintRange );
155  ‪BT_REGISTER_API( "robotWithinSuperSprintRange", &‪robotWithinSuperSprintRange );
156  ‪BSM_REGISTER_API( "robotWithinSuperSprintRange", &‪robotWithinSuperSprintRange );
157  ‪BT_REGISTER_API( "robotOutsideTacticalWalkRange", &‪robotOutsideTacticalWalkRange );
158  ‪BT_REGISTER_API( "robotOutsideSprintRange", &‪robotOutsideSprintRange );
159  ‪BT_REGISTER_API( "robotOutsideSuperSprintRange", &‪robotOutsideSuperSprintRange );
160  ‪BSM_REGISTER_API( "robotOutsideSuperSprintRange", &‪robotOutsideSuperSprintRange );
161 
162  ‪BT_REGISTER_API( "robotLightsOff", &‪robotLightsOff );
163  ‪BT_REGISTER_API( "robotLightsFlicker", &‪robotLightsFlicker );
164  ‪BT_REGISTER_API( "robotLightsOn", &‪robotLightsOn );
165 
166  ‪BT_REGISTER_API( "robotShouldGibDeath", &‪robotShouldGibDeath );
167 
168  // ------- ROBOT - PROCEDURAL TRAVERSE BEHAVIOR -----------//
170  ‪BT_REGISTER_API( "robotCalcProceduralTraversal", &‪robotCalcProceduralTraversal );
171  ‪BT_REGISTER_API( "robotProceduralLanding", &‪robotProceduralLandingUpdate );
172  ‪BT_REGISTER_API( "robotTraverseEnd", &‪robotTraverseEnd );
173  ‪BT_REGISTER_API( "robotTraverseRagdollOnDeath", &‪robotTraverseRagdollOnDeath );
174  ‪BT_REGISTER_API( "robotShouldProceduralTraverse", &‪robotShouldProceduralTraverse );
175  ‪BT_REGISTER_API( "robotWallrunTraverse", &‪robotWallrunTraverse );
176  ‪BT_REGISTER_API( "robotShouldWallrun", &‪robotShouldWallrun );
177  ‪BT_REGISTER_API( "robotSetupWallRunJump", &‪robotSetupWallRunJump );
178  ‪BT_REGISTER_API( "robotSetupWallRunLand", &‪robotSetupWallRunLand );
179  ‪BT_REGISTER_API( "robotWallrunStart", &‪robotWallrunStart );
180  ‪BT_REGISTER_API( "robotWallrunEnd", &‪robotWallrunEnd );
181 
182  // ------- ROBOT - JUKE BEHAVIOR -----------//
183  ‪BT_REGISTER_API( "robotCanJuke", &‪robotCanJuke );
184  ‪BT_REGISTER_API( "robotCanTacticalJuke", &‪robotCanTacticalJuke );
185  ‪BT_REGISTER_API( "robotCanPreemptiveJuke", &‪robotCanPreemptiveJuke );
186  ‪BT_REGISTER_API( "robotJukeInitialize", &‪robotJukeInitialize );
187  ‪BT_REGISTER_API( "robotPreemptiveJukeTerminate", &‪robotPreemptiveJukeTerminate );
188 
189  // ------- ROBOT - COVER SCAN BEHAVIOR -----------//
190  ‪BT_REGISTER_API( "robotCoverScanInitialize", &‪robotCoverScanInitialize );
191  ‪BT_REGISTER_API( "robotCoverScanTerminate", &‪robotCoverScanTerminate );
192  ‪BT_REGISTER_API( "robotIsAtCoverModeScan", &‪robotIsAtCoverModeScan );
193 
194  // ------- ROBOT SERVICES -----------//
195  ‪BT_REGISTER_API( "robotExposedCoverService", &‪robotExposedCoverService );
196  ‪BT_REGISTER_API( "robotPositionService", &‪robotPositionService );
197  ‪BT_REGISTER_API( "robotTargetService", &‪robotTargetService );
198  ‪BT_REGISTER_API( "robotTryReacquireService", &‪robotTryReacquireService );
199  ‪BT_REGISTER_API( "robotRushEnemyService", &‪robotRushEnemyService );
200  ‪BT_REGISTER_API( "robotRushNeighborService", &‪robotRushNeighborService );
201  ‪BT_REGISTER_API( "robotCrawlerService", &‪robotCrawlerService );
202  ‪BT_REGISTER_API( "robotMoveToPlayerService", &‪moveToPlayerUpdate );
203 
204  // ------- ROBOT MOCOMPS -----------//
209 }
210 
211 function ‪robotCleanupChargeMeleeAttack( behaviorTreeEntity )
212 {
213  ‪AiUtility::meleeReleaseMutex( behaviorTreeEntity );
214  ‪AiUtility::releaseClaimNode( behaviorTreeEntity );
215  ‪Blackboard::SetBlackBoardAttribute( behaviorTreeEntity, ‪MELEE_ENEMY_TYPE, undefined);
216 }
217 
218 function private ‪robotLightsOff( entity, asmStateName )
219 {
220  entity ‪ai::set_behavior_attribute( "robot_lights", ‪ROBOT_LIGHTS_OFF );
221 
223 
224  return ‪BHTN_SUCCESS;
225 }
226 
227 function private ‪robotLightsFlicker( entity, asmStateName )
228 {
229  entity ‪ai::set_behavior_attribute( "robot_lights", ‪ROBOT_LIGHTS_FLICKER );
230 
232 
233  entity notify( "emp_fx_start" );
234 
235  return ‪BHTN_SUCCESS;
236 }
237 
238 function private ‪robotLightsOn( entity, asmStateName )
239 {
240  entity ‪ai::set_behavior_attribute( "robot_lights", ‪ROBOT_LIGHTS_ON );
241 
243 
244  return ‪BHTN_SUCCESS;
245 }
246 
247 function private ‪robotShouldGibDeath( entity, asmStateName )
248 {
249  return entity.gibDeath;
250 }
251 
252 function private ‪robotEmpIdleInitialize( entity, asmStateName )
253 {
254  entity.empStopTime = GetTime() + entity.empShutdownTime;
255 
256  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
257 
258  entity notify( "emp_shutdown_start" );
259 
260  return ‪BHTN_RUNNING;
261 }
262 
263 function private ‪robotEmpIdleUpdate( entity, asmStateName )
264 {
265  if ( GetTime() < entity.empStopTime || entity ‪ai::get_behavior_attribute( "shutdown" ) )
266  {
267  if ( entity ASMGetStatus() == ‪ASM_STATE_COMPLETE )
268  {
269  // Loop the idle animation until enough time has passed.
270  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
271  }
272 
273  return ‪BHTN_RUNNING;
274  }
275 
276  return ‪BHTN_SUCCESS;
277 }
278 
279 function private ‪robotEmpIdleTerminate( entity, asmStateName )
280 {
281  entity notify( "emp_shutdown_end" );
282 
283  return ‪BHTN_SUCCESS;
284 }
285 
286 function ‪robotProceduralTraversalUpdate( entity, asmStateName )
287 {
288  assert( IsDefined( entity.traversal ) );
289 
290  traversal = entity.traversal;
291 
292  t = min( ( GetTime() - traversal.startTime ) / traversal.totalTime, 1 );
293  curveRemaining = traversal.curveLength * ( 1 - t );
294 
295  if ( curveRemaining < traversal.landingDistance )
296  {
297  traversal.landing = true;
298  return ‪BHTN_SUCCESS;
299  }
300 
301  return ‪BHTN_RUNNING;
302 }
303 
304 function ‪robotProceduralLandingUpdate( entity, asmStateName )
305 {
306  if ( IsDefined( entity.traversal ) )
307  {
308  entity Finishtraversal();
309  }
310 
311  return ‪BHTN_RUNNING;
312 }
313 
314 function ‪robotCalcProceduralTraversal( entity, asmStateName )
315 {
316  if ( !IsDefined( entity.traverseStartNode ) ||
317  !IsDefined( entity.traverseEndNode ) )
318  {
319  return true;
320  }
321 
322  entity.traversal = SpawnStruct();
323 
324  traversal = entity.traversal;
325 
326  // Static data
327  traversal.landingDistance = 24; // Inches
328  traversal.minimumSpeed = 18; // Feet
329 
330  traversal.startNode = entity.traverseStartNode;
331  traversal.endNode = entity.traverseEndNode;
332 
333  startIsWallrun = traversal.startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
334  endIsWallrun = traversal.endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
335 
336  // Bezier start and end points
337  traversal.startPoint1 = entity.origin;
338  traversal.endPoint1 = traversal.endNode.origin;
339 
340  if ( endIsWallrun )
341  {
342  // Find the offset point from the wall to jump to, this prevents the AI from clipping during landings.
343  faceNormal = GetNavMeshFaceNormal( traversal.endPoint1, 30 );
344  traversal.endPoint1 += faceNormal * ‪ROBOT_DIAMETER / 2;
345  }
346 
347  if ( !IsDefined( traversal.endPoint1 ) )
348  {
349  // This indicates the end node is way off the navmesh.
350  traversal.endPoint1 = traversal.endNode.origin;
351  }
352 
353  traversal.distanceToEnd = Distance( traversal.startPoint1, traversal.endPoint1 );
354  traversal.absHeightToEnd = Abs( traversal.startPoint1[2] - traversal.endPoint1[2] );
355  traversal.absLengthToEnd = Distance2D( traversal.startPoint1, traversal.endPoint1 );
356 
357  // Calculate approximate speed. Longer traversals require faster movement.
358  speedBoost = 0;
359 
360  if ( traversal.absLengthToEnd > 200 )
361  {
362  speedBoost = 16;
363  }
364  else if ( traversal.absLengthToEnd > 120 )
365  {
366  speedBoost = 8;
367  }
368  else if ( traversal.absLengthToEnd > 80 || traversal.absHeightToEnd > 80 )
369  {
370  speedBoost = 4;
371  }
372 
373  if ( IsDefined( entity.traversalSpeedBoost ) )
374  {
375  speedBoost = entity [[ entity.traversalSpeedBoost ]]();
376  }
377 
378  traversal.speedOnCurve = ( traversal.minimumSpeed + speedBoost ) * 12; // Inches per second
379  // End of speed calculations
380 
381  // Bezier control points
382  heightOffset = max( traversal.absHeightToEnd * 0.8, min( traversal.absLengthToEnd, 96 ) );
383 
384  traversal.startPoint2 = entity.origin + ( 0, 0, heightOffset );
385  traversal.endPoint2 = traversal.endPoint1 + ( 0, 0, heightOffset );
386 
387  // Adjust the lower control point to make a symmetric curve.
388  if ( traversal.startPoint1[2] < traversal.endPoint1[2] )
389  {
390  traversal.startPoint2 += ( 0, 0, traversal.absHeightToEnd );
391  }
392  else
393  {
394  traversal.endPoint2 += ( 0, 0, traversal.absHeightToEnd );
395  }
396 
397  // Wallrun traversals may jump directly off or onto the wall, adjust bezier control points.
398  if ( startIsWallrun || endIsWallrun )
399  {
400  startDirection = ‪robotStartJumpDirection();
401  endDirection = ‪robotEndJumpDirection();
402 
403  if ( startDirection == "out" )
404  {
405  point2Scale = 0.5;
406  towardEnd = ( traversal.endNode.origin - entity.origin ) * point2Scale;
407 
408  traversal.startPoint2 = entity.origin + ( towardEnd[0], towardEnd[1], 0 );
409  traversal.endPoint2 = traversal.endPoint1 + ( 0, 0, traversal.absHeightToEnd * point2Scale );
410 
411  traversal.angles = entity.angles;
412  }
413 
414  if ( endDirection == "in" )
415  {
416  point2Scale = 0.5;
417  towardStart = ( entity.origin - traversal.endNode.origin ) * point2Scale;
418 
419  traversal.startPoint2 = entity.origin + ( 0, 0, traversal.absHeightToEnd * point2Scale );
420  traversal.endPoint2 = traversal.endNode.origin + ( towardStart[0], towardStart[1], 0 );
421 
422  faceNormal = GetNavMeshFaceNormal( traversal.endNode.origin, 30 );
423  direction = ‪_CalculateWallrunDirection( traversal.startNode.origin, traversal.endNode.origin );
424  moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
425 
426  if ( direction == "right" )
427  {
428  moveDirection = -moveDirection;
429  }
430 
431  traversal.angles = VectortoAngles( moveDirection );
432  }
433 
434  // These are animation specific, and speed specific.
435  if ( endIsWallrun )
436  {
437  traversal.landingDistance = 110;
438  }
439  else
440  {
441  traversal.landingDistance = 60;
442  }
443 
444  // Wallruns require faster movement.
445  traversal.speedOnCurve *= 1.2;
446  }
447 
448  /#
449  // Draw Bezier control point extents.
450  RecordLine( traversal.startPoint1, traversal.startPoint2, ‪ORANGE, "Animscript", entity );
451  RecordLine( traversal.startPoint1, traversal.endPoint1, ‪ORANGE, "Animscript", entity );
452  RecordLine( traversal.endPoint1, traversal.endPoint2, ‪ORANGE, "Animscript", entity );
453  RecordLine( traversal.startPoint2, traversal.endPoint2, ‪ORANGE, "Animscript", entity );
454 
455  Record3DText( traversal.absLengthToEnd, traversal.endPoint1 + (0, 0, 12), ‪ORANGE, "Animscript", entity );
456  #/
457 
458  // Calculate an approximate length of the curve.
459  segments = 10;
460  previousPoint = traversal.startPoint1;
461  traversal.curveLength = 0;
462 
463  for ( index = 1; index <= segments; index++ )
464  {
465  t = index / segments;
466 
467  nextPoint = ‪CalculateCubicBezier( t, traversal.startPoint1, traversal.startPoint2, traversal.endPoint2, traversal.endPoint1 );
468 
469  /#
470  recordLine( previousPoint, nextPoint, ‪GREEN, "Animscript", entity );
471  #/
472 
473  traversal.curveLength += Distance( previousPoint, nextPoint );
474 
475  previousPoint = nextPoint;
476  }
477 
478  // Traversal time based on speed.
479  traversal.startTime = GetTime();
480  traversal.endTime = traversal.startTime + traversal.curveLength * ( 1000 / traversal.speedOnCurve );
481  traversal.totalTime = traversal.endTime - traversal.startTime;
482 
483  traversal.landing = false;
484 
485  return true;
486 }
487 
488 function ‪robotTraverseStart( entity, asmStateName )
489 {
490  entity.skipdeath = true;
491 
492  // Reset the traversal timings after playing a jump animation.
493  traversal = entity.traversal;
494 
495  traversal.startTime = GetTime();
496  traversal.endTime = traversal.startTime + traversal.curveLength * ( 1000 / traversal.speedOnCurve );
497  traversal.totalTime = traversal.endTime - traversal.startTime;
498 
499  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
500 
501  return ‪BHTN_RUNNING;
502 }
503 
504 function ‪robotTraverseEnd( entity )
505 {
507 
508  entity.skipdeath = false;
509  entity.traversal = undefined;
510 
511  entity notify( "traverse_end" );
512 
513  return ‪BHTN_SUCCESS;
514 }
515 
516 function private ‪robotTraverseRagdollOnDeath( entity, asmStateName )
517 {
518  if ( !IsAlive( entity ) )
519  {
520  entity StartRagdoll();
521  }
522 
523  return ‪BHTN_SUCCESS;
524 }
525 
526 function private ‪robotShouldProceduralTraverse( entity )
527 {
528  if ( IsDefined( entity.traverseStartNode ) && IsDefined( entity.traverseEndNode ) )
529  {
530  isProcedural = entity ‪ai::get_behavior_attribute( "traversals" ) == "procedural" ||
531  entity.traverseStartNode.spawnflags & ‪SPAWNFLAG_PATH_PROCEDURAL ||
532  entity.traverseEndNode.spawnflags & ‪SPAWNFLAG_PATH_PROCEDURAL;
533 
534  return isProcedural;
535  }
536 
537  return false;
538 }
539 
540 function private ‪robotWallrunTraverse( entity )
541 {
542  startNode = entity.traverseStartNode;
543  endNode = entity.traverseEndNode;
544 
545  if ( IsDefined( startNode ) &&
546  IsDefineD( endNode ) &&
547  entity ShouldStartTraversal() )
548  {
549  startIsWallrun = startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
550  endIsWallrun = endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
551 
552  return startIsWallrun || endIsWallrun;
553  }
554 
555  return false;
556 }
557 
558 function private ‪robotShouldWallrun( entity )
559 {
561 }
562 
563 function private ‪mocompRobotStartWallrunInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
564 {
565  entity SetRepairPaths( false );
566  entity OrientMode( "face angle", entity.angles[1] );
567  entity.blockingPain = true;
568  entity.clampToNavMesh = false;
569 
570  // entity OrientMode( "face motion" );
571  entity AnimMode( ‪AI_ANIM_MOVE_CODE_NOGRAVITY, false );
572  entity SetAvoidanceMask( "avoid none" );
573 }
574 
575 function private ‪mocompRobotStartWallrunUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
576 {
577  faceNormal = GetNavMeshFaceNormal( entity.origin, 30 );
578  positionOnWall = GetClosestPointOnNavMesh( entity.origin, 30, 0 );
580 
581  if ( IsDefined( faceNormal ) && IsDefined( positionOnWall ) )
582  {
583  // Ignore any slank in the face normal.
584  faceNormal = ( faceNormal[0], faceNormal[1], 0 );
585  faceNormal = VectorNormalize( faceNormal );
586 
587  moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
588 
589  if ( direction == "right" )
590  {
591  moveDirection = -moveDirection;
592  }
593 
594  forwardPositionOnWall = GetClosestPointOnNavMesh( positionOnWall + moveDirection * 12, 30, 0 );
595 
596  anglesToEnd = VectortoAngles( forwardPositionOnWall - positionOnWall );
597 
598  /# recordLine( positionOnWall, forwardPositionOnWall, ‪RED, "Animscript", entity ); #/
599 
600  entity OrientMode( "face angle", anglesToEnd[1] );
601  }
602 }
603 
604 function private ‪mocompRobotStartWallrunTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
605 {
606  entity SetRepairPaths( true );
607  entity SetAvoidanceMask( "avoid all" );
608  entity.blockingPain = false;
609  entity.clampToNavMesh = true;
610 }
611 
612 function private ‪CalculateCubicBezier( t, p1, p2, p3, p4 )
613 {
614  return ‪pow( 1 - t, 3 ) * p1 +
615  3 * ‪pow( 1 - t, 2 ) * t * p2 +
616  3 * ( 1 - t ) * ‪pow( t, 2 ) * p3 +
617  ‪pow( t, 3 ) * p4;
618 }
619 
620 function private ‪mocompRobotStartTraversalInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
621 {
622  startNode = entity.traverseStartNode;
623  startIsWallrun = startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
624  endNode = entity.traverseEndNode;
625  endIsWallrun = endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
626 
627  if ( !endIsWallrun )
628  {
629  angleToEnd = VectortoAngles( entity.traverseEndNode.origin - entity.traverseStartNode.origin );
630  entity OrientMode( "face angle", angleToEnd[1] );
631 
632  if ( startIsWallrun )
633  {
634  entity AnimMode( ‪AI_ANIM_MOVE_CODE_NOGRAVITY, false );
635  }
636  else
637  {
638  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS, false );
639  }
640  }
641  else
642  {
643  // Orient toward the direction of the movement along the wall.
644  faceNormal = GetNavMeshFaceNormal( endNode.origin, 30 );
645  direction = ‪_CalculateWallrunDirection( startNode.origin, endNode.origin );
646  moveDirection = VectorCross( faceNormal, ( 0, 0, 1 ) );
647 
648  if ( direction == "right" )
649  {
650  moveDirection = -moveDirection;
651  }
652 
653  /# recordLine( endNode.origin, endNode.origin + faceNormal * 20, ‪RED, "Animscript", entity ); #/
654  /# recordLine( endNode.origin, endNode.origin + moveDirection * 20, ‪RED, "Animscript", entity ); #/
655 
656  angles = VectortoAngles( moveDirection );
657  entity OrientMode( "face angle", angles[1] );
658 
659  if ( startIsWallrun )
660  {
661  entity AnimMode( ‪AI_ANIM_MOVE_CODE_NOGRAVITY, false );
662  }
663  else
664  {
665  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS, false );
666  }
667  }
668 
669  entity SetRepairPaths( false );
670  entity.blockingPain = true;
671  entity.clampToNavMesh = false;
672 
673  entity PathMode( "dont move" );
674 }
675 
676 function private ‪mocompRobotStartTraversalTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
677 {
678 }
679 
680 function private ‪mocompRobotProceduralTraversalInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
681 {
682  traversal = entity.traversal;
683 
684  entity SetAvoidanceMask( "avoid none" );
685  entity OrientMode( "face angle", entity.angles[1] );
686  entity SetRepairPaths( false );
687 
688  // Initial jump can noclip.
689  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP, false );
690  entity.blockingPain = true;
691  entity.clampToNavMesh = false;
692 
693  if ( IsDefined( traversal ) && traversal.landing )
694  {
695  // Traversal is still going on, and we're landing.
696  entity AnimMode( ‪AI_ANIM_USE_ANGLE_DELTAS, false );
697  }
698 }
699 
700 function private ‪mocompRobotProceduralTraversalUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
701 {
702  traversal = entity.traversal;
703 
704  if ( IsDefined( traversal ) )
705  {
706  if ( entity IsPaused() )
707  {
708  traversal.startTime += ‪SERVER_FRAME * 1000;
709  return;
710  }
711 
712  endIsWallrun = traversal.endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
713  realT = ( GetTime() - traversal.startTime ) / traversal.totalTime;
714  t = min( realT, 1 );
715 
716  if ( t < 1.0 || realT == 1.0 || !endIsWallrun )
717  {
718  currentPos = ‪CalculateCubicBezier( t, traversal.startPoint1, traversal.startPoint2, traversal.endPoint2, traversal.endPoint1 );
719 
720  angles = entity.angles;
721 
722  if ( IsDefined( traversal.angles ) )
723  {
724  angles = traversal.angles;
725  }
726 
727  // TODO(David Young 3-5-15): Convert to anim mode eventually.
728  entity ForceTeleport( currentPos, angles, false );
729  }
730  else
731  {
732  entity AnimMode( ‪AI_ANIM_MOVE_CODE_NOGRAVITY, false );
733  }
734  }
735 }
736 
737 function private ‪mocompRobotProceduralTraversalTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
738 {
739  traversal = entity.traversal;
740 
741  if ( IsDefined( traversal ) && GetTime() >= traversal.endTime )
742  {
743  // entity ForceTeleport( traversal.endPoint1, entity.angles, false );
744 
745  endIsWallrun = traversal.endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
746 
747  if ( !endIsWallrun )
748  {
749  // Landed on the ground, allow repathing.
750  entity PathMode( "move allowed" );
751  }
752  }
753 
754  entity.clampToNavMesh = true;
755  entity.blockingPain = false;
756  entity SetRepairPaths( true );
757  entity SetAvoidanceMask( "avoid all" );
758 }
759 
760 function private ‪mocompIgnorePainFaceEnemyInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
761 {
762  entity.blockingpain = true;
763 
764  if ( IsDefined( entity.enemy ) )
765  {
766  entity OrientMode( "face enemy" );
767  }
768  else
769  {
770  entity OrientMode( "face angle", entity.angles[1] );
771  }
772 
773  entity AnimMode( ‪AI_ANIM_USE_POS_DELTAS );
774 }
775 
776 function private ‪mocompIgnorePainFaceEnemyUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
777 {
778  if ( IsDefined( entity.enemy ) && entity GetAnimTime( mocompAnim ) < 0.5 )
779  {
780  entity OrientMode( "face enemy" );
781  }
782  else
783  {
784  entity OrientMode( "face angle", entity.angles[1] );
785  }
786 }
787 
788 function private ‪mocompIgnorePainFaceEnemyTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
789 {
790  entity.blockingpain = false;
791 }
792 
793 function private ‪_CalculateWallrunDirection( startPosition, endPosition )
794 {
795  entity = self;
796 
797  faceNormal = GetNavMeshFaceNormal( endPosition, 30 );
798 
799  /# recordLine( startPosition, endPosition, ‪ORANGE, "Animscript", entity ); #/
800 
801  if ( IsDefined( faceNormal ) )
802  {
803  /# recordLine( endPosition, endPosition + faceNormal * 12, ‪ORANGE, "Animscript", entity ); #/
804 
805  angles = VectorToAngles( faceNormal );
806  right = AnglesToRight( angles );
807 
808  d = -VectorDot( right, endPosition );
809 
810  if ( VectorDot( right, startPosition ) + d > 0 )
811  {
812  return "right";
813  }
814 
815  return "left";
816  }
817 
818  return "unknown";
819 }
820 
821 function private ‪robotWallrunStart()
822 {
823  entity = self;
824  entity.skipdeath = true;
825 
826  entity PushActors( false );
827  entity PushPlayer( true );
828  entity.pushable = false;
829 }
830 
831 function private ‪robotWallrunEnd()
832 {
833  entity = self;
834 
836 
837  entity.skipdeath = false;
838 
839  entity PushActors( true );
840  entity PushPlayer( false );
841  entity.pushable = true;
842 }
843 
844 function private ‪robotSetupWallRunJump()
845 {
846  entity = self;
847  startNode = entity.traverseStartNode;
848  endNode = entity.traverseEndNode;
849 
850  direction = "unknown";
851  jumpDirection = "unknown";
852  traversalType = "unknown";
853 
854  if ( IsDefined( startNode ) && IsDefined( endNode ) )
855  {
856  startIsWallrun = startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
857  endIsWallrun = endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
858 
859  if ( endIsWallrun )
860  {
861  direction = ‪_CalculateWallrunDirection( startNode.origin, endNode.origin );
862  }
863  else
864  {
865  direction = ‪_CalculateWallrunDirection( endNode.origin, startNode.origin );
866 
867  if ( direction == "right" )
868  {
869  direction = "left";
870  }
871  else
872  {
873  direction = "right";
874  }
875  }
876  jumpDirection = ‪robotStartJumpDirection();
877  traversalType = ‪robotTraversalType( startNode );
878  }
879 
883 
884  ‪robotCalcProceduralTraversal( entity, undefined );
885 
886  return ‪BHTN_RUNNING;
887 }
888 
889 function private ‪robotSetupWallRunLand()
890 {
891  entity = self;
892  startNode = entity.traverseStartNode;
893  endNode = entity.traverseEndNode;
894 
895  landDirection = "unknown";
896  traversalType = "unknown";
897 
898  if ( IsDefined( startNode ) && IsDefined( endNode ) )
899  {
900  landDirection = ‪robotEndJumpDirection( );
901  traversalType = ‪robotTraversalType( endNode );
902  }
903 
906 
907  return ‪BHTN_RUNNING;
908 }
909 
910 function private ‪robotStartJumpDirection()
911 {
912  entity = self;
913  startNode = entity.traverseStartNode;
914  endNode = entity.traverseEndNode;
915 
916  if ( IsDefined( startNode ) && IsDefined( endNode ) )
917  {
918  startIsWallrun = startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
919  endIsWallrun = endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
920 
921  if ( startIsWallrun )
922  {
923  absLengthToEnd = Distance2D( startNode.origin, endNode.origin );
924 
925  if ( startNode.origin[2] - endNode.origin[2] > 48 &&
926  absLengthToEnd < 250 )
927  {
928  // End position is below the start position, jump outwards.
929  return "out";
930  }
931  }
932 
933  return "up";
934  }
935 
936  return "unknown";
937 }
938 
939 function private ‪robotEndJumpDirection()
940 {
941  entity = self;
942  startNode = entity.traverseStartNode;
943  endNode = entity.traverseEndNode;
944 
945  if ( IsDefined( startNode ) && IsDefined( endNode ) )
946  {
947  startIsWallrun = startNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
948  endIsWallrun = endNode.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN;
949 
950  if ( endIsWallrun )
951  {
952  absLengthToEnd = Distance2D( startNode.origin, endNode.origin );
953 
954  if ( endNode.origin[2] - startNode.origin[2] > 48 &&
955  absLengthToEnd < 250 )
956  {
957  // start position is below the end position, jump outwards.
958  return "in";
959  }
960  }
961 
962  return "down";
963  }
964 
965  return "unknown";
966 }
967 
968 function private ‪robotTraversalType( node )
969 {
970  if ( IsDefined( node ) )
971  {
972  if ( node.spawnflags & ‪SPAWNFLAG_PATH_WALLRUN )
973  {
974  return "wall";
975  }
976 
977  return "ground";
978  }
979 
980  return "unknown";
981 }
982 
984 {
985  entity = self;
986 
987  // CREATE BLACKBOARD
989 
990  // CREATE INTERFACE
992 
993  // USE UTILITY BLACKBOARD
995 
996  // CREATE ROBOT BLACKBOARD
999  ‪BB_REGISTER_ATTRIBUTE( ‪MOVE_MODE, "normal", undefined );
1001  ‪BB_REGISTER_ATTRIBUTE( ‪ROBOT_JUMP_DIRECTION, undefined, undefined );
1002  ‪BB_REGISTER_ATTRIBUTE( ‪ROBOT_LOCOMOTION_TYPE, undefined, undefined );
1003  ‪BB_REGISTER_ATTRIBUTE( ‪ROBOT_TRAVERSAL_TYPE, undefined, undefined );
1004  ‪BB_REGISTER_ATTRIBUTE( ‪ROBOT_WALLRUN_DIRECTION, undefined, undefined );
1005  ‪BB_REGISTER_ATTRIBUTE( ‪ROBOT_MODE, "normal", undefined );
1006 
1007  // REGISTER ANIMSCRIPTED CALLBACK
1008  entity.___ArchetypeOnAnimscriptedCallback = &‪ArchetypeRobotOnAnimScriptedCallback;
1009 
1010  // ENABLE DEBUGGING IN ODYSSEY
1012 
1013  // THREAD PRE BULLET FIRE CALLBACK
1014  if ( SessionModeIsCampaignGame() || SessionModeIsZombiesGame() )
1015  {
1016  self thread ‪gameskill::accuracy_buildup_before_fire( self );
1017  }
1018 
1019  // RUN SNIPER GLINT AND LASER IF ACCURATE FIRE IS ON
1020  if( self.accurateFire )
1021  {
1022  self thread ‪AiUtility::preShootLaserAndGlintOn( self );
1023  self thread ‪AiUtility::postShootLaserAndGlintOff( self );
1024  }
1025 }
1026 
1027 function private ‪robotCrawlerCanShootEnemy( entity )
1028 {
1029  if ( !IsDefined( entity.enemy ) )
1030  {
1031  return false;
1032  }
1033 
1034  aimLimits = entity GetAimLimitsFromEntry( "robot_crawler" );
1035 
1036  yawToEnemy = AngleClamp180(
1037  VectorToAngles( ( entity LastKnownPos( entity.enemy ) ) - entity.origin )[1] - entity.angles[1] );
1038 
1039  angleEpsilon = 10;
1040 
1041  return yawToEnemy <= ( aimLimits[‪AIM_LEFT] + angleEpsilon ) &&
1042  yawToEnemy >= ( aimLimits[‪AIM_RIGHT] + angleEpsilon );
1043 }
1044 
1046 {
1047  // UNREGISTER THE BLACKBOARD
1048  entity.__blackboard = undefined;
1049 
1050  // REREGISTER BLACKBOARD
1052 }
1053 
1054 function private ‪robotGetGibbedLimbs()
1055 {
1056  entity = self;
1057 
1058  rightArmGibbed = ‪GibServerUtils::IsGibbed( entity, ‪GIB_TORSO_RIGHT_ARM_FLAG );
1059  leftArmGibbed = ‪GibServerUtils::IsGibbed( entity, ‪GIB_TORSO_LEFT_ARM_FLAG );
1060 
1061  if ( rightArmGibbed && leftArmGibbed )
1062  {
1063  return "both_arms";
1064  }
1065  else if ( rightArmGibbed )
1066  {
1067  return "right_arm";
1068  }
1069  else if ( leftArmGibbed )
1070  {
1071  return "left_arm";
1072  }
1073 
1074  return "none";
1075 }
1076 
1077 function private ‪robotInvalidateCover( entity )
1078 {
1079  entity.steppedOutOfCover = false;
1080  entity PathMode( "move allowed" );
1081 }
1082 
1083 function private ‪robotDelayMovement( entity )
1084 {
1085  entity PathMode( "move delayed", false, RandomFloatRange( 1, 2 ) );
1086 }
1087 
1088 function private ‪robotMovement( entity )
1089 {
1091  {
1093  }
1094 }
1095 
1096 function private ‪robotCoverScanInitialize( entity )
1097 {
1101 
1102  ‪AiUtility::keepClaimNode( entity );
1103 
1104  ‪AiUtility::chooseCoverDirection( entity, true );
1105 
1106  entity.steppedOutOfCoverNode = entity.node;
1107 }
1108 
1109 function private ‪robotCoverScanTerminate( entity )
1110 {
1112 
1113  entity.steppedOutOfCover = true;
1114  entity.steppedOutTime = GetTime() - ( ‪MAX_EXPOSED_TIME * 1000 );
1115 
1117 
1118  entity PathMode( "dont move" );
1119 }
1120 
1121 function ‪robotCanJuke( entity )
1122 {
1123  if ( !entity ‪ai::get_behavior_attribute( "phalanx" ) &&
1124  !‪IS_TRUE( entity.steppedOutOfCover ) &&
1125  ‪AiUtility::canJuke( entity ) )
1126  {
1127  jukeEvents = ‪Blackboard::GetBlackboardEvents( "actor_juke" );
1128  tooCloseJukeDistanceSqr = 240 * 240;
1129 
1130  foreach ( event in jukeEvents )
1131  {
1132  if ( Distance2DSquared( entity.origin, event.data.origin ) <= tooCloseJukeDistanceSqr )
1133  {
1134  return false;
1135  }
1136  }
1137 
1138  return true;
1139  }
1140 
1141  return false;
1142 }
1143 
1144 function ‪robotCanTacticalJuke( entity )
1145 {
1146  if ( entity HasPath () &&
1148  {
1150  entity, ‪ROBOT_TACTICAL_JUKE_RADIUS, entity.jukeDistance );
1151 
1152  return ‪jukeDirection != "forward";
1153  }
1154 
1155  return false;
1156 }
1157 
1158 function ‪robotCanPreemptiveJuke( entity )
1159 {
1160  if ( !IsDefined( entity.enemy ) || !IsPlayer( entity.enemy ) )
1161  {
1162  return false;
1163  }
1164 
1166  {
1167  return false;
1168  }
1169 
1170  if ( !entity.shouldPreemptiveJuke )
1171  {
1172  return false;
1173  }
1174 
1175  if ( IsDefined( entity.nextPreemptiveJuke ) && entity.nextPreemptiveJuke > GetTime() )
1176  {
1177  return false;
1178  }
1179 
1180  if ( entity.enemy PlayerADS() < entity.nextPreemptiveJukeAds )
1181  {
1182  return false;
1183  }
1184 
1185  jukeMaxDistance = ‪ROBOT_JUKE_PREEMPTIVE_MAX_DISTANCE;
1186 
1187  if ( IsWeapon( entity.enemy.currentweapon ) &&
1188  IsDefined( entity.enemy.currentweapon.enemycrosshairrange ) &&
1189  entity.enemy.currentweapon.enemycrosshairrange > 0)
1190  {
1191  jukeMaxDistance = entity.enemy.currentweapon.enemycrosshairrange;
1192 
1193  if ( jukeMaxDistance > ( ‪ROBOT_JUKE_PREEMPTIVE_MAX_DISTANCE * 2 ) )
1194  {
1195  // limit the weapons preemptive juking out to twice the max distance (1200)
1196  jukeMaxDistance = ‪ROBOT_JUKE_PREEMPTIVE_MAX_DISTANCE * 2;
1197  }
1198  }
1199 
1200  // Only juke if the robot is close enough to their enemy.
1201  if ( DistanceSquared( entity.origin, entity.enemy.origin ) < ‪SQR( jukeMaxDistance ) )
1202  {
1203  angleDifference = AbsAngleClamp180( entity.angles[1] - entity.enemy.angles[1] );
1204 
1205  /#
1206  record3DText( angleDifference, entity.origin + (0, 0, 5), ‪GREEN, "Animscript" );
1207  #/
1208 
1209  // Make sure the robot could actually see their enemy.
1210  if ( angleDifference > 135 )
1211  {
1212  enemyAngles = entity.enemy GetGunAngles();
1213  toEnemy = entity.enemy.origin - entity.origin;
1214  forward = AnglesToForward( enemyAngles );
1215  dotProduct = Abs( VectorDot( VectorNormalize( toEnemy ), forward ) );
1216 
1217  /#
1218  record3DText( ACos( dotProduct ), entity.origin + (0, 0, 10), ‪GREEN, "Animscript" );
1219  #/
1220 
1221  // Make sure the player is aiming close to the robot.
1222  if ( dotProduct > 0.9848 )
1223  {
1224  // Less than cos(10 degrees) between forard vector and vector to enemy.
1225  return ‪robotCanJuke( entity );
1226  }
1227  }
1228  }
1229 
1230  return false;
1231 }
1232 
1233 function ‪robotIsAtCoverModeScan( entity )
1234 {
1236 
1237  return coverMode == ‪COVER_SCAN_MODE;
1238 }
1239 
1240 function private ‪robotPrepareForAdjustToCover( entity )
1241 {
1242  ‪AiUtility::keepClaimNode( entity );
1243 
1245 }
1246 
1247 function private ‪robotCrawlerService( entity )
1248 {
1249  if ( IsDefined( entity.crawlerLifeTime ) &&
1250  entity.crawlerLifeTime <= GetTime() &&
1251  entity.health > 0 )
1252  {
1253  entity Kill();
1254  }
1255 
1256  return true;
1257 }
1258 
1259 function ‪robotIsCrawler( entity )
1260 {
1261  return entity.isCrawler;
1262 }
1263 
1264 function private ‪robotBecomeCrawler( entity )
1265 {
1266  if ( !entity ‪ai::get_behavior_attribute( "can_become_crawler" ) )
1267  {
1268  return;
1269  }
1270 
1271  entity.isCrawler = true;
1272  entity.becomeCrawler = false;
1273  entity AllowPitchAngle( 1 );
1274  entity SetPitchOrient();
1275  entity.crawlerLifeTime = GetTime() + RandomIntRange( 10000, 20000 );
1276  entity notify( "bhtn_action_notify", "rbCrawler" );
1277 }
1278 
1280 {
1281  return entity.becomeCrawler;
1282 }
1283 
1284 function private ‪robotIsMarching( entity )
1285 {
1286  return ‪Blackboard::GetBlackBoardAttribute( entity, ‪MOVE_MODE ) == "marching";
1287 }
1288 
1289 function private ‪robotLocomotionSpeed()
1290 {
1291  entity = self;
1292 
1293  if ( ‪robotIsMindControlled() == "mind_controlled" )
1294  {
1295  switch ( ‪ai::GetAiAttribute( entity, "rogue_control_speed" ) )
1296  {
1297  case "walk":
1298  return ‪LOCOMOTION_SPEED_WALK;
1299  case "run":
1300  return ‪LOCOMOTION_SPEED_RUN;
1301  case "sprint":
1303  }
1304  }
1305  else if ( ‪ai::GetAiAttribute( entity, "sprint" ) )
1306  {
1308  }
1309 
1310  return ‪LOCOMOTION_SPEED_WALK;
1311 }
1312 
1313 function private ‪robotCoverOverInitialize( behaviorTreeEntity )
1314 {
1315  ‪AiUtility::setCoverShootStartTime( behaviorTreeEntity );
1316  ‪AiUtility::keepClaimNode( behaviorTreeEntity );
1319 }
1320 
1321 function private ‪robotCoverOverTerminate( behaviorTreeEntity )
1322 {
1323  ‪AiUtility::cleanupCoverMode( behaviorTreeEntity );
1324  ‪AiUtility::clearCoverShootStartTime( behaviorTreeEntity );
1325 }
1326 
1327 function private ‪robotIsMindControlled()
1328 {
1329  entity = self;
1330 
1331  if ( entity.controlLevel > 1 )
1332  {
1333  return "mind_controlled";
1334  }
1335 
1336  return "normal";
1337 }
1338 
1339 function private ‪robotDontTakeCover( entity )
1340 {
1341  entity.combatmode = "no_cover";
1342  entity.resumeCover = GetTime() + ‪ROBOT_RESUME_COVER_TIME;
1343 }
1344 
1345 function private ‪_IsValidPlayer( player )
1346 {
1347  if( !IsDefined( player ) ||
1348  !IsAlive( player ) ||
1349  !IsPlayer( player ) ||
1350  player.sessionstate == "spectator" ||
1351  player.sessionstate == "intermission" ||
1353  player.ignoreme )
1354  {
1355  return false;
1356  }
1357 
1358  return true;
1359 }
1360 
1361 function private ‪robotRushEnemyService( entity )
1362 {
1363  if ( !IsDefined( entity.enemy ) )
1364  {
1365  return false;
1366  }
1367 
1368  distanceToEnemy = Distance2DSquared( entity.origin, entity.enemy.origin );
1369 
1370  if ( distanceToEnemy >= ‪ROBOT_RUSHER_DISTANCE_SQ &&
1371  distanceToEnemy <= ‪ROBOT_RUSHER_MAX_ENEMY_DISTANCE_SQ )
1372  {
1373  findPathResult = entity FindPath( entity.origin, entity.enemy.origin, true, false );
1374 
1375  if ( findPathResult )
1376  {
1377  entity ‪ai::set_behavior_attribute( "move_mode", "rusher" );
1378  }
1379  }
1380 }
1381 
1382 function private ‪_IsValidRusher( entity, neighbor )
1383 {
1384  return IsDefined( neighbor ) &&
1385  IsDefined( neighbor.archetype ) &&
1386  neighbor.archetype == "robot" &&
1387  IsDefined( neighbor.team ) &&
1388  entity.team == neighbor.team &&
1389  entity != neighbor &&
1390  IsDefined( neighbor.enemy ) &&
1391  neighbor ‪ai::get_behavior_attribute( "move_mode" ) == "normal" &&
1392  !( neighbor ‪ai::get_behavior_attribute( "phalanx" ) ) &&
1393  neighbor ‪ai::get_behavior_attribute( "rogue_control" ) == "level_0" &&
1394  DistanceSquared( entity.origin, neighbor.origin ) < ‪ROBOT_RUSHER_NEIGHBOR_DISTANCE_SQ &&
1395  DistanceSquared( neighbor.origin, neighbor.enemy.origin ) < ‪ROBOT_RUSHER_MAX_ENEMY_DISTANCE_SQ;
1396 }
1397 
1398 function private ‪robotRushNeighborService( entity )
1399 {
1400  actors = GetAiArray();
1401 
1402  closestEnemy = undefined;
1403  closestEnemyDistance = undefined;
1404 
1405  foreach( index, ai in actors )
1406  {
1407  if ( ‪_IsValidRusher( entity, ai ) )
1408  {
1409  enemyDistance = DistanceSquared( entity.origin, ai.origin );
1410 
1411  if ( !IsDefined( closestEnemyDistance ) ||
1412  enemyDistance < closestEnemyDistance )
1413  {
1414  closestEnemyDistance = enemyDistance;
1415  closestEnemy = ai;
1416  }
1417  }
1418  }
1419 
1420  if ( IsDefined( closestEnemy ) )
1421  {
1422  findPathResult = entity FindPath( closestEnemy.origin, closestEnemy.enemy.origin, true, false );
1423 
1424  if ( findPathResult )
1425  {
1426  closestEnemy ‪ai::set_behavior_attribute( "move_mode", "rusher" );
1427  }
1428  }
1429 }
1430 
1431 function private ‪_FindClosest( entity, entities )
1432 {
1433  closest = SpawnStruct();
1434 
1435  if ( entities.size > 0 )
1436  {
1437  closest.entity = entities[0];
1438  closest.distanceSquared = DistanceSquared( entity.origin, closest.entity.origin );
1439 
1440  for ( index = 1; index < entities.size; index++ )
1441  {
1442  distanceSquared = DistanceSquared( entity.origin, entities[index].origin );
1443 
1444  if ( distanceSquared < closest.distanceSquared )
1445  {
1446  closest.distanceSquared = distanceSquared;
1447  closest.entity = entities[index];
1448  }
1449  }
1450  }
1451 
1452  return closest;
1453 }
1454 
1455 function private ‪robotTargetService( entity )
1456 {
1457  if ( ‪robotAbleToShootCondition( entity ) )
1458  {
1459  return false;
1460  }
1461 
1462  if ( ‪IS_TRUE( entity.ignoreall ) )
1463  {
1464  return false;
1465  }
1466 
1467  // Wait to select a new target so long as the current one is alive.
1468  if ( IsDefined( entity.nextTargetServiceUpdate ) &&
1469  entity.nextTargetServiceUpdate > GetTime() &&
1470  IsAlive( entity.favoriteenemy ) )
1471  {
1472  return false;
1473  }
1474 
1475  positionOnNavMesh = GetClosestPointOnNavMesh( entity.origin, ‪ROBOT_NAVMESH_TOLERANCE );
1476 
1477  if ( !IsDefined( positionOnNavMesh ) )
1478  {
1479  return;
1480  }
1481 
1482  // Clean up favoriteenemy information if set.
1483  if ( IsDefined( entity.favoriteenemy ) &&
1484  IsDefined( entity.favoriteenemy._currentRogueRobot ) &&
1485  entity.favoriteenemy._currentRogueRobot == entity )
1486  {
1487  entity.favoriteenemy._currentRogueRobot = undefined;
1488  }
1489 
1490  aiEnemies = [];
1491  playerEnemies = [];
1492  ai = GetAiArray();
1493  players = GetPlayers();
1494 
1495  // Add AI's that are on different teams.
1496  foreach( index, value in ai )
1497  {
1498  // if this entity is a sentient and this robot is told to ignore it, skip over and consider others.
1499  if ( IsSentient( value ) && entity GetIgnoreEnt( value ) )
1500  {
1501  continue;
1502  }
1503 
1504  // Throw out other AI's that are outside the entity's goalheight.
1505  // This prevents considering enemies on other floors.
1506  if ( value.team != entity.team && IsActor( value ) && !IsDefined( entity.favoriteenemy ) )
1507  {
1508  enemyPositionOnNavMesh = GetClosestPointOnNavMesh( value.origin, ‪ROBOT_NAVMESH_TOLERANCE, ‪ROBOT_DIAMETER );
1509 
1510  if ( IsDefined( enemyPositionOnNavMesh ) &&
1511  entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh, true, false ) )
1512  {
1513  aiEnemies[aiEnemies.size] = value;
1514  }
1515  }
1516  }
1517 
1518  // Add valid players
1519  foreach( index, value in players )
1520  {
1521  if ( ‪_IsValidPlayer( value ) && value.team != entity.team )
1522  {
1523  // if this robot is told to ignore this player, skip over and consider others.
1524  if ( IsSentient( value ) && entity GetIgnoreEnt( value ) )
1525  {
1526  continue;
1527  }
1528 
1529  enemyPositionOnNavMesh = GetClosestPointOnNavMesh( value.origin, ‪ROBOT_NAVMESH_TOLERANCE, ‪ROBOT_DIAMETER );
1530 
1531  if ( IsDefined( enemyPositionOnNavMesh ) &&
1532  entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh, true, false ) )
1533  {
1534  playerEnemies[playerEnemies.size] = value;
1535  }
1536  }
1537  }
1538 
1539  closestPlayer = ‪_FindClosest( entity, playerEnemies );
1540  closestAI = ‪_FindClosest( entity, aiEnemies );
1541 
1542  if ( !IsDefined( closestPlayer.entity ) && !IsDefined( closestAI.entity ) )
1543  {
1544  // No player or actor to choose, bail out.
1545  return;
1546  }
1547  else if ( !IsDefined( closestAI.entity ) )
1548  {
1549  // Only has a player to choose.
1550  entity.favoriteenemy = closestPlayer.entity;
1551  }
1552  else if ( !IsDefined( closestPlayer.entity ) )
1553  {
1554  // Only has an AI to choose.
1555  entity.favoriteenemy = closestAI.entity;
1556  entity.favoriteenemy._currentRogueRobot = entity;
1557  }
1558  else if ( closestAI.distanceSquared < closestPlayer.distanceSquared )
1559  {
1560  // AI is closer than a player, time for additional checks.
1561  entity.favoriteenemy = closestAI.entity;
1562  entity.favoriteenemy._currentRogueRobot = entity;
1563  }
1564  else
1565  {
1566  // Player is closer, choose them.
1567  entity.favoriteenemy = closestPlayer.entity;
1568  }
1569 
1570  entity.nextTargetServiceUpdate = GetTime() + RandomIntRange( 2500, 3500 );
1571 }
1572 
1573 function private ‪setDesiredStanceToStand( behaviorTreeEntity )
1574 {
1575  currentStance = ‪Blackboard::GetBlackBoardAttribute( behaviorTreeEntity, ‪STANCE );
1576 
1577  if( currentStance == ‪STANCE_CROUCH )
1578  {
1580  }
1581 }
1582 
1583 function private ‪setDesiredStanceToCrouch( behaviorTreeEntity )
1584 {
1585  currentStance = ‪Blackboard::GetBlackBoardAttribute( behaviorTreeEntity, ‪STANCE );
1586 
1587  if( currentStance == ‪STANCE_STAND )
1588  {
1590  }
1591 }
1592 
1593 function private ‪toggleDesiredStance( entity )
1594 {
1595  currentStance = ‪Blackboard::GetBlackBoardAttribute( entity, ‪STANCE );
1596 
1597  if( currentStance == ‪STANCE_STAND )
1598  {
1600  }
1601  else
1602  {
1604  }
1605 }
1606 
1607 function private ‪robotShouldShutdown( entity )
1608 {
1609  return entity ‪ai::get_behavior_attribute( "shutdown" );
1610 }
1611 
1612 function private ‪robotShouldExplode( entity )
1613 {
1614  if ( entity.controlLevel >= 3 )
1615  {
1616  if ( entity ‪ai::get_behavior_attribute( "rogue_force_explosion" ) )
1617  {
1618  return true;
1619  }
1620  else if ( IsDefined( entity.enemy ) )
1621  {
1622  enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
1623 
1624  return enemyDistSq < ( ‪ROBOT_DETONATION_RANGE * ‪ROBOT_DETONATION_RANGE );
1625  }
1626  }
1627 
1628  return false;
1629 }
1630 
1631 function private ‪robotShouldAdjustToCover( entity )
1632 {
1633  if( !IsDefined( entity.node ) )
1634  {
1635  return false;
1636  }
1637 
1639 }
1640 
1641 function private ‪robotShouldReactAtCover( behaviorTreeEntity )
1642 {
1643  return
1645  ‪AiUtility::canBeFlanked( behaviorTreeEntity ) &&
1646  behaviorTreeEntity IsAtCoverNodeStrict() &&
1647  behaviorTreeEntity IsFlankedAtCoverNode() &&
1648  !behaviorTreeEntity HasPath();
1649 }
1650 
1651 function private ‪robotExplode( entity )
1652 {
1653  entity.allowDeath = false;
1654  entity.noCyberCom = true;
1655 }
1656 
1657 function private ‪robotExplodeTerminate( entity )
1658 {
1660 
1661  entity RadiusDamage(
1662  entity.origin + (0, 0, ‪ROBOT_HEIGHT / 2),
1666  entity,
1668 
1669  if ( ‪math::cointoss() )
1670  {
1671  ‪GibServerUtils::GibLeftArm( entity );
1672  }
1673  else
1674  {
1675  ‪GibServerUtils::GibRightArm( entity );
1676  }
1677 
1678  ‪GibServerUtils::GibLegs( entity );
1679  ‪GibServerUtils::GibHead( entity );
1680 
1683 
1684  if ( IsAlive( entity ) )
1685  {
1686  entity.allowDeath = true;
1687  entity Kill();
1688  }
1689 
1690  entity StartRagdoll();
1691 }
1692 
1693 function private ‪robotExposedCoverService( entity )
1694 {
1695  // Allows robot AI to move away from their "step out" cover position when
1696  // the node becomes invalid.
1697  if ( IsDefined( entity.steppedOutOfCover ) &&
1698  IsDefined( entity.steppedOutOfCoverNode ) &&
1699  ( !entity IsCoverValid( entity.steppedOutOfCoverNode ) ||
1700  entity HasPath() ||
1701  !entity IsSafeFromGrenade() ) )
1702  {
1703  entity.steppedOutOfCover = false;
1704  entity PathMode( "move allowed" );
1705  }
1706 
1707  if ( IsDefined( entity.resumeCover ) && GetTime() > entity.resumeCover )
1708  {
1709  entity.combatMode = "cover";
1710  entity.resumeCover = undefined;
1711  }
1712 }
1713 
1714 function private ‪robotIsAtCoverCondition( entity )
1715 {
1716  enemyTooClose = false;
1717 
1718  if( IsDefined( entity.enemy ) )
1719  {
1720  lastKnownEnemyPos = entity LastKnownPos( entity.enemy );
1721  distanceToEnemySqr = Distance2DSquared( entity.origin, lastKnownEnemyPos );
1722  enemyTooClose = distanceToEnemySqr <= ( ‪ROBOT_INVALID_COVER_DISTANCE * ‪ROBOT_INVALID_COVER_DISTANCE );
1723  }
1724 
1725  return !enemyTooClose &&
1726  !entity.steppedOutOfCover &&
1727  entity IsAtCoverNodeStrict() &&
1728  entity ShouldUseCoverNode() &&
1729  !entity HasPath() &&
1730  entity IsSafeFromGrenade() &&
1731  entity.combatMode != "no_cover";
1732 }
1733 
1734 function private ‪robotSupportsOverCover( entity )
1735 {
1736  if ( IsDefined( entity.node ) )
1737  {
1738  if ( ‪NODE_SUPPORTS_STANCE_STAND( entity.node ) )
1739  {
1740  return ‪NODE_COVER_STAND(entity.node);
1741  }
1742 
1743  return ‪NODE_COVER_LEFT(entity.node) ||
1744  ‪NODE_COVER_RIGHT(entity.node) ||
1745  ‪NODE_COVER_CROUCH(entity.node);
1746  }
1747 
1748  return false;
1749 }
1750 
1751 function private ‪canMoveToEnemyCondition( entity )
1752 {
1753  if ( !IsDefined( entity.enemy ) || entity.enemy.health <= 0 )
1754  {
1755  return false;
1756  }
1757 
1758  positionOnNavMesh = GetClosestPointOnNavMesh( entity.origin, ‪ROBOT_NAVMESH_TOLERANCE );
1759  enemyPositionOnNavMesh = GetClosestPointOnNavMesh( entity.enemy.origin, ‪ROBOT_NAVMESH_TOLERANCE, ‪ROBOT_DIAMETER );
1760 
1761  if ( !IsDefined( positionOnNavMesh ) || !IsDefined( enemyPositionOnNavMesh ) )
1762  {
1763  return false;
1764  }
1765 
1766  findPathResult = entity FindPath( positionOnNavMesh, enemyPositionOnNavMesh, true, false );
1767 
1768  /#
1769  if ( !findPathResult )
1770  {
1771  record3DText( "NO PATH", enemyPositionOnNavMesh + (0, 0, 5), ‪ORANGE, "Animscript" );
1772  recordLine( positionOnNavMesh, enemyPositionOnNavMesh, ‪ORANGE, "Animscript", entity );
1773  }
1774  #/
1775 
1776  return findPathResult;
1777 }
1778 
1779 function private ‪canMoveCloseToEnemyCondition( entity )
1780 {
1781  if ( !IsDefined( entity.enemy ) || entity.enemy.health <= 0 )
1782  {
1783  return false;
1784  }
1785 
1786  queryResult = PositionQuery_Source_Navigation(
1787  entity.enemy.origin,
1788  0,
1792  entity );
1793 
1794  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1795 
1796  return queryResult.data.size > 0;
1797 }
1798 
1799 function private ‪robotStartSprint( entity )
1800 {
1802 
1803  return true;
1804 }
1805 
1806 function private ‪robotStartSuperSprint( entity )
1807 {
1809 
1810  return true;
1811 }
1812 
1813 function private ‪robotTacticalWalkActionStart( entity )
1814 {
1816  ‪AiUtility::setCanBeFlanked( entity, false );
1817 
1820 
1821  return true;
1822 }
1823 
1824 function private ‪robotDie( entity )
1825 {
1826  if ( IsAlive( entity ) )
1827  {
1828  entity Kill();
1829  }
1830 }
1831 
1832 function private ‪moveToPlayerUpdate( entity, asmStateName )
1833 {
1834  entity.keepclaimednode = false;
1835 
1836  positionOnNavMesh = GetClosestPointOnNavMesh(entity.origin, ‪ROBOT_NAVMESH_TOLERANCE );
1837 
1838  if ( !IsDefined( positionOnNavMesh ) )
1839  {
1840  // Not on the navmesh, bail out.
1841  return ‪BHTN_SUCCESS;
1842  }
1843 
1844  if ( ‪IS_TRUE( entity.ignoreall ) )
1845  {
1846  entity ClearUsePosition();
1847  return ‪BHTN_SUCCESS;
1848  }
1849 
1850  if ( !IsDefined( entity.enemy ) )
1851  {
1852  return ‪BHTN_SUCCESS;
1853  }
1854 
1855  if ( ‪robotRogueHasCloseEnemyToMelee( entity ) )
1856  {
1857  // Already at their enemy, bail out.
1858  return ‪BHTN_SUCCESS;
1859  }
1860 
1861  if ( entity.allowPushActors )
1862  {
1863  if ( IsDefined( entity.enemy ) &&
1864  DistanceSquared( entity.origin, entity.enemy.origin ) > ‪SQR( 300 ) )
1865  {
1866  // Allow clipping with other AI's at a distance, this helps when the AI's move diagonally into each other.
1867  entity PushActors( false );
1868  }
1869  else
1870  {
1871  // Force AI's to push each other close to their enemy.
1872  entity PushActors( true );
1873  }
1874  }
1875 
1876  if ( entity AsmIsTransDecRunning() || entity AsmIsTransitionRunning() )
1877  {
1878  // Let the transition animation finish before trying to zig-zag.
1879  return ‪BHTN_SUCCESS;
1880  }
1881 
1882  if ( !IsDefined( entity.lastKnownEnemyPos) )
1883  {
1884  entity.lastKnownEnemyPos = entity.enemy.origin;
1885  }
1886 
1887  shouldRepath = !IsDefined( entity.lastValidEnemyPos );
1888 
1889  if ( !shouldRepath && IsDefined( entity.enemy ) )
1890  {
1891  if ( IsDefined( entity.nextMoveToPlayerUpdate ) && entity.nextMoveToPlayerUpdate <= GetTime() )
1892  {
1893  // It's been a while, repath!
1894  shouldRepath = true;
1895  }
1896  else if ( DistanceSquared( entity.lastKnownEnemyPos, entity.enemy.origin ) > ‪SQR( 72 ) )
1897  {
1898  // Enemy has moved far enough to force repathing.
1899  shouldRepath = true;
1900  }
1901  else if ( DistanceSquared( entity.origin, entity.enemy.origin ) <= ‪SQR( 120 ) )
1902  {
1903  // Repath if close to the enemy.
1904  shouldRepath = true;
1905  }
1906  else if ( IsDefined( entity.pathGoalPos ) )
1907  {
1908  // Repath if close to the current goal position.
1909  distanceToGoalSqr = DistanceSquared( entity.origin, entity.pathGoalPos );
1910 
1911  shouldRepath = distanceToGoalSqr < ‪SQR( 72 );
1912  }
1913  }
1914 
1915  if ( shouldRepath )
1916  {
1917  entity.lastKnownEnemyPos = entity.enemy.origin;
1918 
1919  // Find the closest pathable position on the navmesh to the enemy.
1920  queryResult = PositionQuery_Source_Navigation(
1921  entity.lastKnownEnemyPos,
1922  0,
1926  entity );
1927 
1928  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1929 
1930  if ( queryResult.data.size > 0 )
1931  {
1932  entity.lastValidEnemyPos = queryResult.data[0].origin;
1933  }
1934 
1935  if ( IsDefined( entity.lastValidEnemyPos ) )
1936  {
1937  entity UsePosition( entity.lastValidEnemyPos );
1938 
1939  // Randomized zig-zag path following if 20+ feet away from the enemy.
1940  if ( DistanceSquared( entity.origin, entity.lastValidEnemyPos ) > ‪SQR( 240 ) )
1941  {
1942  path = entity CalcApproximatePathToPosition( entity.lastValidEnemyPos, false );
1943 
1944  /#
1945  if ( GetDvarInt( "ai_debugZigZag" ) )
1946  {
1947  for ( index = 1; index < path.size; index++ )
1948  {
1949  RecordLine( path[index - 1], path[index], ‪ORANGE, "Animscript", entity );
1950  }
1951  }
1952  #/
1953 
1954  deviationDistance = RandomIntRange( 240, 480 ); // 20 to 40 feet
1955 
1956  segmentLength = 0;
1957 
1958  // Walks the current path to find the point where the AI should deviate from their normal path.
1959  for ( index = 1; index < path.size; index++ )
1960  {
1961  currentSegLength = Distance( path[index - 1], path[index] );
1962 
1963  if ( ( segmentLength + currentSegLength ) > deviationDistance )
1964  {
1965  remainingLength = deviationDistance - segmentLength;
1966 
1967  seedPosition = path[index - 1] + ( VectorNormalize( path[index] - path[index - 1] ) * remainingLength );
1968 
1969  /# RecordCircle( seedPosition, 2, ‪ORANGE, "Animscript", entity ); #/
1970 
1971  innerZigZagRadius = 0;
1972  outerZigZagRadius = 64;
1973 
1974  // Find a point offset from the deviation point along the path.
1975  queryResult = PositionQuery_Source_Navigation(
1976  seedPosition,
1977  innerZigZagRadius,
1978  outerZigZagRadius,
1979  0.5 * ‪ROBOT_HEIGHT,
1980  16,
1981  entity,
1982  16 );
1983 
1984  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
1985 
1986  if ( queryResult.data.size > 0 )
1987  {
1988  point = queryResult.data[ RandomInt( queryResult.data.size ) ];
1989 
1990  // Use the deviated point as the path instead.
1991  entity UsePosition( point.origin );
1992  }
1993 
1994  break;
1995  }
1996 
1997  segmentLength += currentSegLength;
1998  }
1999  }
2000  }
2001 
2002  // Force repathing after a certain amount of time to smooth out movement.
2003  entity.nextMoveToPlayerUpdate = GetTime() + RandomIntRange(2000, 3000);
2004  }
2005 
2006  return ‪BHTN_RUNNING;
2007 }
2008 
2009 function private ‪robotShouldChargeMelee(entity)
2010 {
2011  if( ‪AiUtility::shouldMutexMelee( entity )
2012  && ‪robotHasEnemyToMelee( entity ))
2013  {
2014  return true;
2015  }
2016 
2017  return false;
2018 }
2019 
2020 function private ‪robotHasEnemyToMelee( entity )
2021 {
2022  if ( IsDefined( entity.enemy ) &&
2023  IsSentient( entity.enemy ) &&
2024  entity.enemy.health > 0 )
2025  {
2026  enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
2027 
2028  if ( enemyDistSq < ‪SQR( entity.chargeMeleeDistance ) && Abs( entity.enemy.origin[2] - entity.origin[2] ) < 24 )
2029  {
2030  yawToEnemy = AngleClamp180( entity.angles[ 1 ] -
2031  ‪GET_YAW(entity, entity.enemy.origin ) );
2032 
2033  return abs( yawToEnemy ) <= ‪MELEE_YAW_THRESHOLD;
2034  }
2035  }
2036 
2037  return false;
2038 }
2039 
2040 function private ‪robotRogueHasEnemyToMelee( entity )
2041 {
2042  if ( IsDefined( entity.enemy ) &&
2043  IsSentient( entity.enemy ) &&
2044  entity.enemy.health > 0 &&
2045  entity ‪ai::get_behavior_attribute( "rogue_control" ) != "level_3" )
2046  {
2047  if ( !entity CanSee( entity.enemy ) )
2048  {
2049  return false;
2050  }
2051 
2052  return DistanceSquared( entity.origin, entity.enemy.origin ) < ‪SQR( 132 );
2053  }
2054 
2055  return false;
2056 }
2057 
2058 function private ‪robotShouldMelee(entity)
2059 {
2060  if( ‪AiUtility::shouldMutexMelee( entity )
2061  && ‪robotHasCloseEnemyToMelee( entity ))
2062  {
2063  return true;
2064  }
2065 
2066  return false;
2067 }
2068 
2069 function private ‪robotHasCloseEnemyToMelee( entity )
2070 {
2071  if ( IsDefined( entity.enemy ) &&
2072  IsSentient( entity.enemy ) &&
2073  entity.enemy.health > 0 )
2074  {
2075  if ( !entity CanSee( entity.enemy ) )
2076  {
2077  return false;
2078  }
2079 
2080  enemyDistSq = DistanceSquared( entity.origin, entity.enemy.origin );
2081 
2082  if ( enemyDistSq < ‪MELEE_RANGE_SQ )
2083  {
2084  yawToEnemy = AngleClamp180( entity.angles[ 1 ] -
2085  ‪GET_YAW(entity, entity.enemy.origin ) );
2086 
2087  return abs( yawToEnemy ) <= ‪MELEE_YAW_THRESHOLD;
2088  }
2089  }
2090 
2091  return false;
2092 }
2093 
2094 function private ‪robotRogueHasCloseEnemyToMelee( entity )
2095 {
2096  if ( IsDefined( entity.enemy ) &&
2097  IsSentient( entity.enemy ) &&
2098  entity.enemy.health > 0 &&
2099  entity ‪ai::get_behavior_attribute( "rogue_control" ) != "level_3" )
2100  {
2101  return DistanceSquared( entity.origin, entity.enemy.origin ) < ‪MELEE_RANGE_SQ;
2102  }
2103 
2104  return false;
2105 }
2106 
2107 function private ‪scriptRequiresToSprintCondition( entity )
2108 {
2109  // TODO (David Young 1-29-14): Design is requesting that forcing sprint
2110  // always occurs, regardless of distance.
2111  /*
2112  if ( entity HasPath() &&
2113  DistanceSquared( entity.pathstartpos, entity.pathgoalpos ) <= ROBOT_WALK_MIN_DISTANCE_SQ )
2114  {
2115  return false;
2116  }
2117  */
2118 
2119  // if the script interface needs sprinting, then no randomness
2120  return entity ‪ai::get_behavior_attribute( "sprint" ) &&
2121  !entity ‪ai::get_behavior_attribute( "disablesprint" );
2122 }
2123 
2124 function private ‪robotScanExposedPainTerminate( entity )
2125 {
2128 }
2129 
2130 function private ‪robotTookEmpDamage( entity )
2131 {
2132  if ( IsDefined( entity.damageweapon ) && IsDefined( entity.damagemod ) )
2133  {
2134  weapon = entity.damageweapon;
2135 
2136  return entity.damagemod == "MOD_GRENADE_SPLASH" &&
2137  IsDefined( weapon.rootweapon ) &&
2138  isSubStr(weapon.rootweapon.name,"emp_grenade"); //checking substring for emp grenade variant; probably this should be a gdt checkbox 'emp damage' or similar
2139  }
2140  return false;
2141 }
2142 
2143 function private ‪robotNoCloseEnemyService( entity )
2144 {
2145  if ( IsDefined( entity.enemy ) &&
2146  ‪AiUtility::shouldMelee( entity ) )
2147  {
2148  entity ClearPath();
2149  return true;
2150  }
2151 
2152  return false;
2153 }
2154 
2155 function private ‪_robotOutsideMovementRange( entity, range, useEnemyPos )
2156 {
2157  assert( IsDefined( range ) );
2158 
2159  if ( !IsDefined( entity.enemy ) && !entity HasPath() )
2160  {
2161  return false;
2162  }
2163 
2164  goalPos = entity.pathgoalpos;
2165 
2166  if ( IsDefined( entity.enemy ) && useEnemyPos )
2167  {
2168  goalPos = entity LastKnownPos( entity.enemy );
2169  }
2170 
2171  if( !isdefined( goalPos ) )
2172  {
2173  return false;
2174  }
2175 
2176  outsideRange = DistanceSquared( entity.origin, goalPos ) > ‪SQR( range );
2177 
2178  return outsideRange;
2179 }
2180 
2181 function private ‪robotOutsideSuperSprintRange( entity )
2182 {
2183  return !‪robotWithinSuperSprintRange( entity );
2184 }
2185 
2186 function private ‪robotWithinSuperSprintRange( entity )
2187 {
2188  if ( entity ‪ai::get_behavior_attribute( "supports_super_sprint" ) &&
2189  !entity ‪ai::get_behavior_attribute( "disablesprint" ) )
2190  {
2191  return ‪_robotOutsideMovementRange( entity, entity.superSprintDistance, false );
2192  }
2193 
2194  return false;
2195 }
2196 
2197 function private ‪robotOutsideSprintRange( entity )
2198 {
2199  if ( entity ‪ai::get_behavior_attribute( "supports_super_sprint" ) &&
2200  !entity ‪ai::get_behavior_attribute( "disablesprint" ) )
2201  {
2202  return ‪_robotOutsideMovementRange( entity, entity.superSprintDistance * 1.15, false );
2203  }
2204 
2205  return false;
2206 }
2207 
2208 function private ‪robotOutsideTacticalWalkRange( entity )
2209 {
2210  if ( entity ‪ai::get_behavior_attribute( "disablesprint" ) )
2211  {
2212  return false;
2213  }
2214 
2215  if ( IsDefined( entity.enemy ) &&
2216  DistanceSquared( entity.origin, entity.goalPos ) < ‪SQR( entity.minWalkDistance ) )
2217  {
2218  // Slow down when closing in on the enemy.
2219  return false;
2220  }
2221 
2222  return ‪_robotOutsideMovementRange( entity, entity.runAndGunDist * 1.15, true );
2223 }
2224 
2225 function private ‪robotWithinSprintRange( entity )
2226 {
2227  if ( entity ‪ai::get_behavior_attribute( "disablesprint" ) )
2228  {
2229  return false;
2230  }
2231 
2232  if ( IsDefined( entity.enemy ) &&
2233  DistanceSquared( entity.origin, entity.goalPos ) < ‪SQR( entity.minWalkDistance ) )
2234  {
2235  // Slow down when closing in on the enemy.
2236  return false;
2237  }
2238 
2239  return ‪_robotOutsideMovementRange( entity, entity.runAndGunDist, true );
2240 }
2241 
2242 function private ‪shouldTakeOverCondition( entity )
2243 {
2244  switch ( entity.controlLevel )
2245  {
2246  case 0:
2247  return IsInArray( ‪array( "level_1", "level_2", "level_3" ),
2248  entity ‪ai::get_behavior_attribute( "rogue_control" ) );
2249  case 1:
2250  return IsInArray( ‪array( "level_2", "level_3" ),
2251  entity ‪ai::get_behavior_attribute( "rogue_control" ) );
2252  case 2:
2253  return entity ‪ai::get_behavior_attribute( "rogue_control" ) == "level_3";
2254  }
2255 
2256  return false;
2257 }
2258 
2259 function private ‪hasMiniRaps( entity )
2260 {
2261  return IsDefined( entity.miniRaps );
2262 }
2263 
2264 function private ‪robotIsMoving( entity )
2265 {
2266  velocity = entity GetVelocity();
2267  velocity = ( velocity[0], 0, velocity[1] );
2268 
2269  velocitySqr = LengthSquared( velocity );
2270 
2271  return velocitySqr > ‪SQR( 24 );
2272 }
2273 
2274 function private ‪robotAbleToShootCondition( entity )
2275 {
2276  // Mind control level 2 and 3 are the only robots that can't shoot.
2277  return entity.controlLevel <= 1;
2278 }
2279 
2280 function private ‪robotShouldTacticalWalk( entity )
2281 {
2282  if ( !entity HasPath() )
2283  {
2284  return false;
2285  }
2286 
2287  return !‪robotIsMarching( entity );
2288 }
2289 
2290 function private ‪_robotCoverPosition( entity )
2291 {
2292  if( entity IsFlankedAtCoverNode() )
2293  {
2294  return false;
2295  }
2296 
2297  if( entity ShouldHoldGroundAgainstEnemy() )
2298  {
2299  return false;
2300  }
2301 
2302  shouldUseCoverNode = undefined;
2303  itsBeenAWhile = GetTime() > entity.nextFindBestCoverTime;
2304  isAtScriptGoal = undefined;
2305 
2306  if ( IsDefined( entity.robotNode ) )
2307  {
2308  isAtScriptGoal = entity IsPosAtGoal( entity.robotNode.origin );
2309  shouldUseCoverNode = entity IsCoverValid( entity.robotNode );
2310  }
2311  else
2312  {
2313  isAtScriptGoal = entity IsAtGoal();
2314  shouldUseCoverNode = entity ShouldUseCoverNode();
2315  }
2316 
2317  shouldLookForBetterCover = !shouldUseCoverNode || itsBeenAWhile || !isAtScriptGoal;
2318 
2319 /#
2320  recordEntText( "ChooseBetterCoverReason: shouldUseCoverNode:" + shouldUseCoverNode
2321  + " itsBeenAWhile:" + itsBeenAWhile
2322  + " isAtScriptGoal:" + isAtScriptGoal
2323  , entity, ( shouldLookForBetterCover ? ‪GREEN : ‪RED ), "Animscript" );
2324 #/
2325 
2326  // Only search for a new cover node if the AI isn't trying to keep their current claimed node.
2327  if ( shouldLookForBetterCover && IsDefined( entity.enemy ) && !entity.keepClaimedNode )
2328  {
2329  transitionRunning = entity ASMIsTransitionRunning();
2330  subStatePending = entity ASMIsSubStatePending();
2331  transDecRunning = entity AsmIsTransDecRunning();
2332  isBehaviorTreeInRunningState = entity GetBehaviortreeStatus() == ‪BHTN_RUNNING;
2333 
2334  if ( !transitionRunning && !subStatePending && !transDecRunning && isBehaviorTreeInRunningState )
2335  {
2336  nodes = entity FindBestCoverNodes( entity.goalRadius, entity.goalPos );
2337  node = undefined;
2338 
2339  // Find the first unclaimed node or the node that is already claimed by entity.
2340  for ( nodeIndex = 0; nodeIndex < nodes.size; nodeIndex++ )
2341  {
2342  if ( entity.robotNode === nodes[nodeIndex] ||
2343  !IsDefined( nodes[nodeIndex].robotClaimed ) )
2344  {
2345  node = nodes[nodeIndex];
2346  break;
2347  }
2348  }
2349 
2350  // This covers a case where a robot is sent to a node specifically.
2351  if ( IsEntity( entity.node ) &&
2352  ( !IsDefined( entity.robotNode ) || entity.robotNode != entity.node ) )
2353  {
2354  entity.robotNode = entity.node;
2355  entity.robotNode.robotClaimed = true;
2356  }
2357 
2358  goingToDifferentNode =
2359  IsDefined( node ) &&
2360  ( !IsDefined( entity.robotNode ) || node != entity.robotNode ) &&
2361  ( !IsDefined( entity.steppedOutOfCoverNode ) || entity.steppedOutOfCoverNode != node );
2362 
2364 
2365  if ( goingToDifferentNode )
2366  {
2367  if ( RandomFloat( 1 ) <= ‪ROBOT_CHOOSE_COVER_CHANCE || entity ‪ai::get_behavior_attribute( "force_cover" ) )
2368  {
2369  ‪AiUtility::useCoverNodeWrapper( entity, node );
2370  }
2371  else
2372  {
2373  searchRadius = entity.goalRadius;
2374 
2375  if ( searchRadius > ( ‪ROBOT_OFF_COVER_NODE_MAX_DISTANCE / 2 ) )
2376  {
2377  searchRadius = ‪ROBOT_OFF_COVER_NODE_MAX_DISTANCE / 2;
2378  }
2379 
2380  coverNodePoints = ‪util::PositionQuery_PointArray(
2381  node.origin,
2383  searchRadius,
2386 
2387  if ( coverNodePoints.size > 0 )
2388  {
2389  entity UsePosition( coverNodePoints[ RandomInt( coverNodePoints.size ) ] );
2390  }
2391  else
2392  {
2393  entity UsePosition( entity GetNodeOffsetPosition( node ) );
2394  }
2395  }
2396 
2397  if ( IsDefined( entity.robotNode ) )
2398  {
2399  entity.robotNode.robotClaimed = undefined;
2400  }
2401 
2402  entity.robotNode = node;
2403  entity.robotNode.robotClaimed = true;
2404 
2405  entity PathMode( "move delayed", false, RandomFloatRange( 0.25, 2 ) );
2406 
2407  return true;
2408  }
2409  }
2410  }
2411 
2412  return false;
2413 }
2414 
2415 function private ‪_robotEscortPosition( entity )
2416 {
2417  if ( entity ‪ai::get_behavior_attribute( "move_mode" ) == "escort" )
2418  {
2419  escortPosition = entity ‪ai::get_behavior_attribute( "escort_position" );
2420 
2421  if ( !IsDefined( escortPosition ) )
2422  {
2423  return true;
2424  }
2425 
2426  if ( Distance2DSquared( entity.origin, escortPosition ) <=
2428  {
2429  return true;
2430  }
2431 
2432  if ( IsDefined( entity.escortNextTime ) &&
2433  GetTime() < entity.escortNextTime )
2434  {
2435  return true;
2436  }
2437 
2438  if ( entity GetPathMode() == "dont move" )
2439  {
2440  return true;
2441  }
2442 
2443  positionOnNavMesh = GetClosestPointOnNavMesh( escortPosition, ‪ROBOT_NAVMESH_TOLERANCE );
2444 
2445  if ( !IsDefined( positionOnNavMesh ) )
2446  {
2447  positionOnNavMesh = escortPosition;
2448  }
2449 
2450  queryResult = PositionQuery_Source_Navigation(
2451  positionOnNavMesh,
2454  0.5 * ‪ROBOT_HEIGHT,
2455  16,
2456  entity,
2457  16 );
2458 
2459  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2460 
2461  if ( queryResult.data.size > 0 )
2462  {
2463  closestPoint = undefined;
2464  closestDistance = undefined;
2465 
2466  foreach ( point in queryResult.data )
2467  {
2468  if ( !point.inclaimedlocation )
2469  {
2470  newClosestDistance = Distance2DSquared( entity.origin, point.origin );
2471 
2472  if ( !IsDefined( closestPoint ) ||
2473  newClosestDistance < closestDistance )
2474  {
2475  closestPoint = point.origin;
2476  closestDistance = newClosestDistance;
2477  }
2478  }
2479  }
2480 
2481  if ( IsDefined( closestPoint ) )
2482  {
2483  entity UsePosition( closestPoint );
2484  entity.escortNextTime = GetTime() + RandomIntRange( 200, 300 );
2485  }
2486  }
2487 
2488  return true;
2489  }
2490 
2491  return false;
2492 }
2493 
2494 function private ‪_robotRusherPosition( entity )
2495 {
2496  if ( entity ‪ai::get_behavior_attribute( "move_mode" ) == "rusher" )
2497  {
2498  entity PathMode( "move allowed" );
2499 
2500  if ( !IsDefined( entity.enemy ) )
2501  {
2502  return true;
2503  }
2504 
2505  distToEnemySqr = Distance2DSquared( entity.origin, entity.enemy.origin );
2506 
2507  if ( distToEnemySqr <= ‪SQR( entity.robotRusherMaxRadius ) &&
2508  distToEnemySqr >= ‪SQR( entity.robotRusherMinRadius ) )
2509  {
2510  return true;
2511  }
2512 
2513  if ( IsDefined( entity.rusherNextTime ) &&
2514  GetTime() < entity.rusherNextTime )
2515  {
2516  return true;
2517  }
2518 
2519  positionOnNavMesh = GetClosestPointOnNavMesh( entity.enemy.origin, ‪ROBOT_NAVMESH_TOLERANCE );
2520 
2521  if ( !IsDefined( positionOnNavMesh ) )
2522  {
2523  positionOnNavMesh = entity.enemy.origin;
2524  }
2525 
2526  queryResult = PositionQuery_Source_Navigation(
2527  positionOnNavMesh,
2528  entity.robotRusherMinRadius,
2529  entity.robotRusherMaxRadius,
2530  0.5 * ‪ROBOT_HEIGHT,
2531  16,
2532  entity,
2533  16 );
2534 
2535  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2536  PositionQuery_Filter_Sight( queryResult, entity.enemy.origin, entity GetEye() - entity.origin, entity, 2, entity.enemy );
2537 
2538  if ( queryResult.data.size > 0 )
2539  {
2540  closestPoint = undefined;
2541  closestDistance = undefined;
2542 
2543  foreach ( point in queryResult.data )
2544  {
2545  if ( !point.inclaimedlocation && point.visibility === true )
2546  {
2547  newClosestDistance = Distance2DSquared( entity.origin, point.origin );
2548 
2549  if ( !IsDefined( closestPoint ) ||
2550  newClosestDistance < closestDistance )
2551  {
2552  closestPoint = point.origin;
2553  closestDistance = newClosestDistance;
2554  }
2555  }
2556  }
2557 
2558  if ( IsDefined( closestPoint ) )
2559  {
2560  entity UsePosition( closestPoint );
2561  entity.rusherNextTime = GetTime() + RandomIntRange( 500, 1500 );
2562  }
2563  }
2564 
2565  return true;
2566  }
2567 
2568  return false;
2569 }
2570 
2571 function private ‪_robotGuardPosition( entity )
2572 {
2573  if ( entity ‪ai::get_behavior_attribute( "move_mode" ) == "guard" )
2574  {
2575  if ( entity GetPathMode() == "dont move" )
2576  {
2577  return true;
2578  }
2579 
2580  if ( ( !IsDefined( entity.guardPosition ) ||
2581  DistanceSquared( entity.origin , entity.guardPosition ) < ‪SQR( 60 ) ) )
2582  {
2583  entity PathMode( "move delayed", true, RandomFloatRange( 1, 1.5 ) );
2584 
2585  queryResult = PositionQuery_Source_Navigation(
2586  entity.goalPos,
2587  0,
2588  entity.goalradius / 2,
2589  0.5 * ‪ROBOT_HEIGHT,
2590  36,
2591  entity,
2592  72 );
2593 
2594  PositionQuery_Filter_InClaimedLocation( queryResult, entity );
2595 
2596  if ( queryResult.data.size > 0 )
2597  {
2598  minimumDistanceSq = entity.goalradius * 0.2;
2599  minimumDistanceSq = minimumDistanceSq * minimumDistanceSq;
2600 
2601  distantPoints = [];
2602 
2603  foreach( point in queryResult.data )
2604  {
2605  if ( DistanceSquared( entity.origin, point.origin ) > minimumDistanceSq )
2606  {
2607  distantPoints[ distantPoints.size ] = point;
2608  }
2609  }
2610 
2611  if ( distantPoints.size > 0 )
2612  {
2613  randomPosition = distantPoints[ RandomInt( distantPoints.size ) ];
2614 
2615  entity.guardPosition = randomPosition.origin;
2616  entity.intermediateGuardPosition = undefined;
2617  entity.intermediateGuardTime = undefined;
2618  }
2619  }
2620  }
2621 
2622  // Checks every second to make sure the robot has moved. If less than 2 feet
2623  // have changed, then set the guard position to be the robots current position
2624  // so a new guard position can be selected.
2625  currentTime = GetTime();
2626 
2627  if ( !IsDefined( entity.intermediateGuardTime ) ||
2628  entity.intermediateGuardTime < currentTime )
2629  {
2630  if ( IsDefined( entity.intermediateGuardPosition ) &&
2631  DistanceSquared( entity.intermediateGuardPosition , entity.origin ) < ‪SQR( 24 ) )
2632  {
2633  entity.guardPosition = entity.origin;
2634  }
2635 
2636  entity.intermediateGuardPosition = entity.origin;
2637  entity.intermediateGuardTime = currentTime + 3000;
2638  }
2639 
2640  if ( IsDefined( entity.guardPosition ) )
2641  {
2642  // Keep reapplying the guardPosition.
2643  entity UsePosition( entity.guardPosition );
2644 
2645  return true;
2646  }
2647  }
2648 
2649  entity.guardPosition = undefined;
2650  entity.intermediateGuardPosition = undefined;
2651  entity.intermediateGuardTime = undefined;
2652 
2653  return false;
2654 }
2655 
2656 function private ‪robotPositionService( entity )
2657 {
2658  /#
2659  if ( GetDvarInt( "ai_debugLastKnown" ) && IsDefined( entity.enemy ) )
2660  {
2661  lastKnownPos = entity LastKnownPos( entity.enemy );
2662  recordLine( entity.origin, lastKnownPos, ‪ORANGE, "Animscript", entity );
2663  record3DText( "lastKnownPos", lastKnownPos + (0, 0, 5), ‪ORANGE, "Animscript" );
2664  }
2665  #/
2666 
2667  // Release robotNode information upon death.
2668  if ( !IsAlive( entity ) )
2669  {
2670  if ( IsDefined( entity.robotNode ) )
2671  {
2673  entity.robotNode.robotClaimed = undefined;
2674  entity.robotNode = undefined;
2675  }
2676 
2677  return false;
2678  }
2679 
2680  if ( entity.disableRepath )
2681  {
2682  return false;
2683  }
2684 
2685  // Early out tests.
2686  if ( !‪robotAbleToShootCondition( entity ) )
2687  {
2688  return false;
2689  }
2690 
2691  if ( entity ‪ai::get_behavior_attribute( "phalanx" ) )
2692  {
2693  return false;
2694  }
2695 
2696  if( ‪AiSquads::isFollowingSquadLeader( entity ) )
2697  {
2698  return false;
2699  }
2700 
2701  // Position selection logic, ordered by priority.
2702  if ( ‪_robotRusherPosition( entity ) )
2703  {
2704  return true;
2705  }
2706 
2707  if ( ‪_robotGuardPosition( entity ) )
2708  {
2709  return true;
2710  }
2711 
2712  if ( ‪_robotEscortPosition( entity ) )
2713  {
2714  return true;
2715  }
2716 
2717  if ( !‪AiUtility::isSafeFromGrenades( entity ) )
2718  {
2721  }
2722 
2723  if ( ‪_robotCoverPosition( entity ) )
2724  {
2725  return true;
2726  }
2727 
2728  // Go into exposed.
2729  return false;
2730 }
2731 
2732 function private ‪robotDropStartingWeapon( entity, asmStateName )
2733 {
2734  if ( entity.weapon.name == level.weaponNone.name )
2735  {
2736  entity ‪shared::placeWeaponOn( entity.startingWeapon, "right" );
2737  entity thread ‪shared::DropAIWeapon();
2738  }
2739 }
2740 
2741 function private ‪robotJukeInitialize( entity )
2742 {
2744  entity ClearPath();
2745  entity notify( "bhtn_action_notify", "rbJuke" );
2746 
2747  ‪jukeInfo = SpawnStruct();
2748  ‪jukeInfo.origin = entity.origin;
2749  ‪jukeInfo.entity = entity;
2750 
2751  ‪Blackboard::AddBlackboardEvent( "actor_juke", ‪jukeInfo, 3000 );
2752 }
2753 
2754 function private ‪robotPreemptiveJukeTerminate( entity )
2755 {
2756  entity.nextPreemptiveJuke = GetTime() + RandomIntRange( 4000, 6000 );
2757  entity.nextPreemptiveJukeAds = RandomFloatRange( 0.5, 0.95 );
2758 }
2759 
2760 function private ‪robotTryReacquireService( entity )
2761 {
2762  moveMode = entity ‪ai::get_behavior_attribute( "move_mode" );
2763  if ( moveMode == "rusher" || moveMode == "escort" || moveMode == "guard" )
2764  {
2765  return false;
2766  }
2767 
2768  if ( !IsDefined( entity.reacquire_state ) )
2769  {
2770  entity.reacquire_state = 0;
2771  }
2772 
2773  if ( !IsDefined( entity.enemy ) )
2774  {
2775  entity.reacquire_state = 0;
2776  return false;
2777  }
2778 
2779  if ( entity HasPath() )
2780  {
2781  return false;
2782  }
2783 
2784  if ( !‪robotAbleToShootCondition( entity ) )
2785  {
2786  return false;
2787  }
2788 
2789  if ( entity ‪ai::get_behavior_attribute( "force_cover" ) )
2790  {
2791  return false;
2792  }
2793 
2794  if ( entity CanSee( entity.enemy ) && entity CanShootEnemy() )
2795  {
2796  entity.reacquire_state = 0;
2797  return false;
2798  }
2799 
2800  // don't do reacquire unless facing enemy
2801  dirToEnemy = VectorNormalize( entity.enemy.origin - entity.origin );
2802  forward = AnglesToForward( entity.angles );
2803 
2804  if ( VectorDot( dirToEnemy, forward ) < ‪COS_60 )
2805  {
2806  entity.reacquire_state = 0;
2807  return false;
2808  }
2809 
2810  switch ( entity.reacquire_state )
2811  {
2812  case 0:
2813  case 1:
2814  case 2:
2815  step_size = ‪REACQUIRE_STEP_SIZE + entity.reacquire_state * ‪REACQUIRE_STEP_SIZE;
2816  reacquirePos = entity ReacquireStep( step_size );
2817  break;
2818 
2819  case 4:
2820  if ( !( entity CanSee( entity.enemy ) ) || !( entity CanShootEnemy() ) )
2821  {
2822  entity FlagEnemyUnattackable();
2823  }
2824  break;
2825 
2826  default:
2827  if ( entity.reacquire_state > ‪REACQUIRE_RESET )
2828  {
2829  entity.reacquire_state = 0;
2830  return false;
2831  }
2832  break;
2833  }
2834 
2835  if ( IsVec( reacquirePos ) )
2836  {
2837  entity UsePosition( reacquirePos );
2838  return true;
2839  }
2840 
2841  entity.reacquire_state++;
2842  return false;
2843 }
2844 
2845 function private ‪takeOverInitialize( entity, asmStateName )
2846 {
2847  switch ( entity ‪ai::get_behavior_attribute( "rogue_control" ) )
2848  {
2849  case "level_1":
2851  break;
2852  case "level_2":
2854  break;
2855  case "level_3":
2857  break;
2858  }
2859 
2860  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
2861  return ‪BHTN_RUNNING;
2862 }
2863 
2864 function private ‪takeOverTerminate( entity, asmStateName )
2865 {
2866  switch ( entity ‪ai::get_behavior_attribute( "rogue_control" ) )
2867  {
2868  case "level_2":
2869  case "level_3":
2870  entity thread ‪shared::DropAIWeapon();
2871  break;
2872  }
2873 
2874  return ‪BHTN_SUCCESS;
2875 }
2876 
2877 function private ‪stepIntoInitialize( entity, asmStateName )
2878 {
2879  // TODO(David Young 9-2-14): This is required in a very rare case, determine why that is.
2881 
2882  ‪AiUtility::useCoverNodeWrapper( entity, entity.steppedOutOfCoverNode );
2884  ‪AiUtility::keepClaimNode( entity );
2885 
2886  entity.steppedOutOfCoverNode = undefined;
2887 
2888  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
2889 
2890  return ‪BHTN_RUNNING;
2891 }
2892 
2893 function private ‪stepIntoTerminate( entity, asmStateName )
2894 {
2895  entity.steppedOutOfCover = false;
2896 
2898 
2899  entity PathMode( "move allowed" );
2900 
2901  return ‪BHTN_SUCCESS;
2902 }
2903 
2904 function private ‪stepOutInitialize( entity, asmStateName )
2905 {
2906  entity.steppedOutOfCoverNode = entity.node;
2907 
2908  ‪AiUtility::keepClaimNode( entity );
2909 
2910  if ( ‪math::cointoss() )
2911  {
2913  }
2914  else
2915  {
2917  }
2918 
2920 
2921  ‪AiUtility::chooseCoverDirection( entity, true );
2922 
2923  ‪AnimationStateNetworkUtility::RequestState( entity, asmStateName );
2924 
2925  return ‪BHTN_RUNNING;
2926 }
2927 
2928 function private ‪stepOutTerminate( entity, asmStateName )
2929 {
2930  entity.steppedOutOfCover = true;
2931  entity.steppedOutTime = GetTime();
2932 
2934 
2935  entity PathMode( "dont move" );
2936 
2937  return ‪BHTN_SUCCESS;
2938 }
2939 
2940 function private ‪supportsStepOutCondition( entity )
2941 {
2942  return ‪NODE_COVER_LEFT( entity.node ) ||
2943  ‪NODE_COVER_RIGHT( entity.node ) ||
2944  ‪NODE_COVER_PILLAR( entity.node );
2945 }
2946 
2947 function private ‪shouldStepInCondition( entity )
2948 {
2949  if ( !IsDefined( entity.steppedOutOfCover ) ||
2950  !entity.steppedOutOfCover ||
2951  !IsDefined( entity.steppedOutTime ) ||
2952  !entity.steppedOutOfCover )
2953  {
2954  return false;
2955  }
2956 
2957  exposedTimeInSeconds = (GetTime() - entity.steppedOutTime) / 1000;
2958 
2959  exceededTime = exposedTimeInSeconds >= ‪MIN_EXPOSED_TIME ||
2960  exposedTimeInSeconds >= ‪MAX_EXPOSED_TIME;
2961 
2962  suppressed = entity.suppressionMeter > entity.suppressionThreshold;
2963 
2964  return exceededtime || ( exceededtime && suppressed );
2965 }
2966 
2967 function private ‪robotDeployMiniRaps()
2968 {
2969  entity = self;
2970 
2971  if ( IsDefined( entity ) && IsDefined( entity.miniRaps ) )
2972  {
2973  /*
2974  raps = SpawnVehicle(
2975  ROBOT_MINI_RAPS_SPAWNER,
2976  entity.miniRaps.origin + ROBOT_MINI_RAPS_OFFSET_POSITION,
2977  ( 0, 0, 0 ) );
2978  */
2979 
2980  positionOnNavMesh = GetClosestPointOnNavMesh( entity.origin, ‪ROBOT_NAVMESH_TOLERANCE );
2981 
2982  raps = SpawnVehicle(
2984  positionOnNavMesh,
2985  ( 0, 0, 0 ) );
2986  raps.team = entity.team;
2988 
2989  /*
2990  entity.miniRaps Delete();
2991  */
2992  entity.miniRaps = undefined;
2993  }
2994 }
2995 
2996 // end #namespace RobotSoldierBehavior;
2997 
2998 #namespace RobotSoldierServerUtils;
2999 
3000 function private ‪_tryGibbingHead( entity, ‪damage, hitLoc, isExplosive )
3001 {
3002  if ( isExplosive &&
3003  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_HEAD_EXPLOSION_CHANCE )
3004  {
3005  ‪GibServerUtils::GibHead( entity );
3006  }
3007  else if ( IsInArray( ‪array( "head", "neck", "helmet" ), hitLoc ) &&
3008  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_HEAD_HEADSHOT_CHANCE )
3009  {
3010  ‪GibServerUtils::GibHead( entity );
3011  }
3012  else if ( ( entity.health - ‪damage ) <= 0 &&
3013  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_HEAD_DEATH_CHANCE )
3014  {
3015  ‪GibServerUtils::GibHead( entity );
3016  }
3017 }
3018 
3019 function private ‪_tryGibbingLimb( entity, ‪damage, hitLoc, isExplosive, ‪onDeath )
3020 {
3021  // Early out if one arm is already gibbed.
3024  {
3025  return;
3026  }
3027 
3028  if ( isExplosive &&
3029  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LIMB_EXPLOSION_CHANCE )
3030  {
3031  if ( ‪onDeath && ‪math::cointoss() )
3032  {
3033  // Only gib the right arm if the robot died.
3035  }
3036  else
3037  {
3039  }
3040  }
3041  else if ( IsInArray( ‪array( "left_hand", "left_arm_lower", "left_arm_upper" ), hitLoc ) )
3042  {
3044  }
3045  else if ( ‪onDeath &&
3046  IsInArray( ‪array( "right_hand", "right_arm_lower", "right_arm_upper" ), hitLoc ) )
3047  {
3049  }
3050  else if ( ‪RobotSoldierBehavior::robotIsMindControlled() == "mind_controlled" &&
3051  IsInArray( ‪array( "right_hand", "right_arm_lower", "right_arm_upper" ), hitLoc ) )
3052  {
3054  }
3055  else if ( ‪onDeath && RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LIMB_DEATH_CHANCE )
3056  {
3057  if ( ‪math::cointoss() )
3058  {
3060  }
3061  else
3062  {
3064  }
3065  }
3066 }
3067 
3068 function private ‪_tryGibbingLegs( entity, ‪damage, hitLoc, isExplosive, attacker )
3069 {
3070  if ( !IsDefined( attacker ) )
3071  {
3072  attacker = entity;
3073  }
3074 
3075  // Gib on death.
3076  canGibLegs = ( entity.health - ‪damage ) <= 0 && entity.allowdeath;
3077 
3078  // Gib based on damage.
3079  ‪if ( entity ‪ai::get_behavior_attribute( "can_become_crawler" ) )
3080  {
3081  canGibLegs = canGibLegs ||
3082  ( ( ( entity.health - ‪damage ) / entity.maxHealth ) <= ‪ROBOT_GIB_LEG_HEALTH_THRESHOLD &&
3083  DistanceSquared( entity.origin, attacker.origin ) <= ‪ROBOT_CRAWL_MAX_DISTANCE &&
3085  entity.allowdeath );
3086  }
3087 
3088  if ( entity.gibDeath &&
3089  ( entity.health - ‪damage ) <= 0 &&
3090  entity.allowdeath &&
3092  {
3093  // Don't gib legs on death, let a gib animation do it.
3094  return;
3095  }
3096 
3097  if ( ( entity.health - ‪damage ) <= 0 &&
3098  entity.allowdeath &&
3099  isExplosive &&
3100  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LEGS_EXPLOSION_CHANCE )
3101  {
3102  ‪GibServerUtils::GibLegs( entity );
3103  entity StartRagdoll();
3104  }
3105  else if ( canGibLegs &&
3106  IsInArray( ‪array( "left_leg_upper", "left_leg_lower", "left_foot" ), hitLoc ) &&
3107  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LEGS_CHANCE )
3108  {
3109  if ( ( entity.health - ‪damage ) > 0 )
3110  {
3111  ‪BecomeCrawler( entity );
3112  }
3113 
3115  }
3116  else if ( canGibLegs &&
3117  IsInArray( ‪array( "right_leg_upper", "right_leg_lower", "right_foot" ), hitLoc ) &&
3118  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LEGS_CHANCE )
3119  {
3120  if ( ( entity.health - ‪damage ) > 0 )
3121  {
3122  ‪BecomeCrawler( entity );
3123  }
3124 
3126  }
3127  else if ( ( entity.health - ‪damage ) <= 0 &&
3128  entity.allowdeath &&
3129  RandomFloatRange( 0, 1 ) <= ‪ROBOT_GIB_LEGS_DEATH_CHANCE )
3130  {
3131  // Randomly gib a leg when dead.
3132  if ( ‪math::cointoss() )
3133  {
3135  }
3136  else
3137  {
3139  }
3140  }
3141 }
3142 
3143 function private ‪robotGibDamageOverride(
3144  inflictor, attacker, ‪damage, flags, meansOfDeath, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3145 {
3146  entity = self;
3147 
3148  if ( IsDefined( attacker ) && ( attacker.team == entity.team ) )
3149  {
3150  return ‪damage;
3151  }
3152 
3153  if ( !entity ‪ai::get_behavior_attribute( "can_gib" ) )
3154  {
3155  return ‪damage;
3156  }
3157 
3158  // Check if any gibbing is allowed.
3159  if ( ( ( entity.health - ‪damage ) / entity.maxHealth ) > ‪ROBOT_GIB_HEALTH_THRESHOLD )
3160  {
3161  return ‪damage;
3162  }
3163 
3164  // Enable spawning gib pieces.
3165  ‪GibServerUtils::ToggleSpawnGibs( entity, true );
3167 
3168  isExplosive = IsInArray(
3169  ‪array(
3170  "MOD_CRUSH",
3171  "MOD_GRENADE",
3172  "MOD_GRENADE_SPLASH",
3173  "MOD_PROJECTILE",
3174  "MOD_PROJECTILE_SPLASH",
3175  "MOD_EXPLOSIVE" ),
3176  meansOfDeath );
3177 
3178  ‪_tryGibbingHead( entity, ‪damage, hitLoc, isExplosive );
3179  ‪_tryGibbingLimb( entity, ‪damage, hitLoc, isExplosive, false );
3180  ‪_tryGibbingLegs( entity, ‪damage, hitLoc, isExplosive, attacker );
3181 
3182  return ‪damage;
3183 }
3184 
3185 function private ‪robotDeathOverride(
3186  inflictor, attacker, ‪damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3187 {
3188  entity = self;
3189 
3190  entity ‪ai::set_behavior_attribute( "robot_lights", ‪ROBOT_LIGHTS_DEATH );
3191 
3192  return ‪damage;
3193 }
3194 
3195 function private ‪robotGibDeathOverride(
3196  inflictor, attacker, ‪damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3197 {
3198  entity = self;
3199 
3200  if ( !entity ‪ai::get_behavior_attribute( "can_gib" ) || entity.skipdeath )
3201  {
3202  return ‪damage;
3203  }
3204 
3205  // Enable spawning gib pieces.
3206  ‪GibServerUtils::ToggleSpawnGibs( entity, true );
3208 
3209  isExplosive = false;
3210 
3211  if ( entity.controlLevel >= 3 )
3212  {
3215 
3217  ‪GibServerUtils::GibHead( entity );
3218  if ( ‪math::cointoss() )
3219  {
3221  }
3222  else
3223  {
3225  }
3226  ‪GibServerUtils::GibLegs( entity );
3227 
3228  velocity = entity GetVelocity() / 9;
3229 
3230  entity StartRagdoll();
3231  entity LaunchRagdoll(
3232  ( velocity[0] + RandomFloatRange( -10, 10 ),
3233  velocity[1] + RandomFloatRange( -10, 10 ),
3234  RandomFloatRange( 40, 50 ) ),
3235  "j_mainroot" );
3236 
3237  PhysicsExplosionSphere(
3238  entity.origin + (0, 0, ‪ROBOT_HEIGHT / 2), 120, 32, 1 );
3239  }
3240  else {
3241  isExplosive = IsInArray(
3242  ‪array(
3243  "MOD_CRUSH",
3244  "MOD_GRENADE",
3245  "MOD_GRENADE_SPLASH",
3246  "MOD_PROJECTILE",
3247  "MOD_PROJECTILE_SPLASH",
3248  "MOD_EXPLOSIVE" ),
3249  meansOfDeath );
3250 
3251  ‪_tryGibbingLimb( entity, ‪damage, hitLoc, isExplosive, true );
3252  }
3253 
3254  return ‪damage;
3255 }
3256 
3258  inflictor, attacker, ‪damage, meansOfDeath, weapon, dir, hitLoc, offsetTime )
3259 {
3260  entity = self;
3261 
3262  if ( entity.skipdeath )
3263  {
3264  return ‪damage;
3265  }
3266 
3267  // Enable spawning gib pieces.
3269 
3270  pieceCount = ‪DestructServerUtils::GetPieceCount( entity );
3271  possiblePieces = [];
3272 
3273  // Find all pieces that haven't been destroyed yet.
3274  for ( index = 1; index <= pieceCount; index++ )
3275  {
3276  if ( !‪DestructServerUtils::IsDestructed( entity, index ) &&
3277  RandomFloatRange( 0, 1 ) <= ‪ROBOT_DESTRUCT_DEATH_CHANCE )
3278  {
3279  possiblePieces[ possiblePieces.size ] = index;
3280  }
3281  }
3282 
3283  gibbedPieces = 0;
3284 
3285  // Destroy up to the maximum number of pieces.
3286  for ( index = 0; index < possiblePieces.size && possiblePieces.size > 1 && gibbedPieces < ‪ROBOT_DESTRUCT_MAX_DEATH_PIECES; index++ )
3287  {
3288  randomPiece = RandomIntRange( 0, possiblePieces.size - 1 );
3289 
3290  if ( !‪DestructServerUtils::IsDestructed( entity, possiblePieces[ randomPiece ] ) )
3291  {
3292  ‪DestructServerUtils::DestructPiece( entity, possiblePieces[ randomPiece ] );
3293  gibbedPieces++;
3294  }
3295  }
3296 
3297  return ‪damage;
3298 }
3299 
3300 function private ‪robotDamageOverride(
3301  inflictor, attacker, ‪damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3302 {
3303  entity = self;
3304 
3305  if( hitLoc != "helmet" || hitLoc != "head" || hitLoc != "neck" )
3306  {
3307  if( isDefined( attacker ) && !isPlayer( attacker ) && !isVehicle( attacker ) )
3308  {
3309  dist = DistanceSquared( entity.origin, attacker.origin );
3310 
3311  if( dist < 256*256 )
3312  {
3313  ‪damage = Int( ‪damage * 10 );
3314  }
3315  else
3316  {
3317  ‪damage = Int( ‪damage * 1.5 );
3318  }
3319  }
3320  }
3321 
3322 
3323  // Reduce headshot damage to robots in script, since this is hardcoded elsewhere for AI's.
3324  if ( hitLoc == "helmet" || hitLoc == "head" || hitLoc == "neck" )
3325  {
3327  }
3328 
3329  if ( IsDefined( dir ) &&
3330  IsDefined( meansOfDamage ) &&
3331  IsDefined( hitLoc ) &&
3332  VectorDot( AnglesToForward( entity.angles ), dir ) > 0 )
3333  {
3334  // Bullet came from behind.
3335  isBullet = IsInArray(
3336  ‪array( "MOD_RIFLE_BULLET", "MOD_PISTOL_BULLET" ),
3337  meansOfDamage );
3338 
3339  isTorsoShot = IsInArray(
3340  ‪array( "torso_upper", "torso_lower" ),
3341  hitLoc );
3342 
3343  if ( isBullet && isTorsoShot )
3344  {
3346  }
3347  }
3348 
3349  // TODO(David Young 9-23-14): This is a hacky way to guarantee a kill when a sticky_grenade lands on a robot.
3350  if ( weapon.name == "sticky_grenade" )
3351  {
3352  switch ( meansOfDamage )
3353  {
3354  case "MOD_IMPACT":
3355  entity.stuckWithStickyGrenade = true;
3356  break;
3357  case "MOD_GRENADE_SPLASH":
3358  if ( ‪IS_TRUE( entity.stuckWithStickyGrenade ) )
3359  {
3360  ‪damage = entity.health;
3361  }
3362  break;
3363  }
3364  }
3365 
3366  if ( meansOfDamage == "MOD_TRIGGER_HURT" && entity.ignoreTriggerDamage )
3367  {
3368  ‪damage = 0;
3369  }
3370 
3371  return ‪damage;
3372 }
3373 
3375  inflictor, attacker, ‪damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex )
3376 {
3377  entity = self;
3378 
3379  isExplosive = IsInArray(
3380  ‪array(
3381  "MOD_CRUSH",
3382  "MOD_GRENADE",
3383  "MOD_GRENADE_SPLASH",
3384  "MOD_PROJECTILE",
3385  "MOD_PROJECTILE_SPLASH",
3386  "MOD_EXPLOSIVE" ),
3387  meansOfDamage );
3388 
3389  if ( isExplosive )
3390  {
3392  }
3393 
3394  return ‪damage;
3395 }
3396 
3397 function private ‪findClosestNavMeshPositionToEnemy( enemy )
3398 {
3399  enemyPositionOnNavMesh = undefined;
3400 
3401  for ( toleranceLevel = 1; toleranceLevel <= ‪ROBOT_NAVMESH_MAX_TOLERANCE_LEVELS; toleranceLevel++ )
3402  {
3403  enemyPositionOnNavMesh = GetClosestPointOnNavMesh(
3404  enemy.origin,
3405  ‪ROBOT_NAVMESH_TOLERANCE * toleranceLevel,
3407 
3408  if ( IsDefined( enemyPositionOnNavMesh ) )
3409  {
3410  break;
3411  }
3412  }
3413 
3414  return enemyPositionOnNavMesh;
3415 }
3416 
3417 function private ‪robotChooseCoverDirection( entity, stepOut )
3418 {
3419  if ( !IsDefined( entity.node ) )
3420  {
3421  return;
3422  }
3423 
3424  coverDirection = ‪Blackboard::GetBlackBoardAttribute( entity, ‪COVER_DIRECTION );
3427 }
3428 
3429 function private ‪robotSoldierSpawnSetup()
3430 {
3431  entity = self;
3432  entity.isCrawler = false;
3433  entity.becomeCrawler = false;
3434  entity.combatmode = "cover";
3435  entity.fullHealth = entity.health;
3436  entity.controlLevel = 0;
3437  entity.steppedOutOfCover = false;
3438  entity.ignoreTriggerDamage = false;
3439  entity.startingWeapon = entity.weapon;
3440  entity.jukeDistance = ‪ROBOT_JUKE_DISTANCE;
3441  entity.jukeMaxDistance = ‪ROBOT_JUKE_MAX_DISTANCE;
3442  entity.entityRadius = ‪ROBOT_DIAMETER / 2;
3443  entity.empShutdownTime = ‪ROBOT_EMP_SHUTDOWN_TIME;
3444  entity.NoFriendlyfire = true;
3445  entity.ignorerunAndgundist = true;
3446  entity.disableRepath = false;
3447 
3448  entity.robotRusherMaxRadius = ‪ROBOT_RUSHER_MAX_RADIUS;
3449  entity.robotRusherMinRadius = ‪ROBOT_RUSHER_MIN_RADIUS;
3450 
3451  entity.gibDeath = ‪math::cointoss();
3452 
3453  // Movement parameters
3454  entity.minWalkDistance = ‪ROBOT_WALK_MIN_DISTANCE;
3455  entity.superSprintDistance = ‪ROBOT_SUPER_SPRINT_DISTANCE;
3456 
3457  entity.treatAllCoversAsGeneric = true;
3458  entity.onlyCrouchArrivals = true;
3459 
3460  entity.chargeMeleeDistance = 125;
3461  entity.allowPushActors = true;
3462 
3463  entity.nextPreemptiveJukeAds = RandomFloatRange( 0.5, 0.95 );
3464  entity.shouldPreemptiveJuke = ‪math::cointoss();
3465 
3467  ‪GibServerUtils::ToggleSpawnGibs( entity, true );
3468 
3470 
3471  /#
3472  if ( GetDvarInt( "ai_robotForceProcedural" ) )
3473  {
3474  entity ‪ai::set_behavior_attribute( "traversals", "procedural" );
3475  }
3476  #/
3477 
3478  entity thread ‪CleanUpEquipment( entity );
3479 
3483  AiUtility::AddAiOverrideDamageCallback( entity, &‪robotGibDamageOverride );
3487 
3488  /#
3489  if ( GetDvarInt( "ai_robotForceControl" ) == 1 )
3490  entity ‪ai::set_behavior_attribute( "rogue_control", "level_1" );
3491  else if ( GetDvarInt( "ai_robotForceControl" ) == 2 )
3492  entity ‪ai::set_behavior_attribute( "rogue_control", "level_2" );
3493  else if ( GetDvarInt( "ai_robotForceControl" ) == 3 )
3494  entity ‪ai::set_behavior_attribute( "rogue_control", "level_3" );
3495 
3496  if ( GetDvarInt( "ai_robotSpawnForceControl" ) == 1 )
3497  entity ‪ai::set_behavior_attribute( "rogue_control", "forced_level_1" );
3498  else if ( GetDvarInt( "ai_robotSpawnForceControl" ) == 2 )
3499  entity ‪ai::set_behavior_attribute( "rogue_control", "forced_level_2" );
3500  else if ( GetDvarInt( "ai_robotSpawnForceControl" ) == 3 )
3501  entity ‪ai::set_behavior_attribute( "rogue_control", "forced_level_3" );
3502  #/
3503 
3504  if ( GetDvarInt( "ai_robotForceCrawler" ) == 1 )
3505  entity ‪ai::set_behavior_attribute( "force_crawler", "gib_legs" );
3506  else if ( GetDvarInt( "ai_robotForceCrawler" ) == 2 )
3507  entity ‪ai::set_behavior_attribute( "force_crawler", "remove_legs" );
3508 
3509  // entity ai::set_behavior_attribute( "robot_mini_raps", true );
3510  // robotGiveWasp( entity );
3511  // entity thread robotDeployWasp( entity );
3512 }
3513 
3514 function private ‪robotGiveWasp( entity )
3515 {
3516  if ( IsDefined( entity ) && !IsDefined( entity.wasp ) )
3517  {
3518  wasp = ‪Spawn( "script_model", ( 0, 0, 0 ) );
3519  wasp SetModel( "veh_t7_drone_attack_red" );
3520  wasp SetScale( 0.75 );
3521  wasp LinkTo( entity, "j_spine4", ( 5, -15, 0 ), ( 0, 0, 90 ) );
3522  entity.wasp = wasp;
3523  }
3524 }
3525 
3526 function private ‪robotDeployWasp( entity )
3527 {
3528  entity endon( "death" );
3529 
3530  wait RandomFloatRange( 7, 10 );
3531 
3532  if ( IsDefined( entity ) && IsDefined( entity.wasp ) )
3533  {
3534  spawnOffset = ( 5, -15, 0 );
3535 
3536  while ( !IsPointInNavvolume( entity.wasp.origin + spawnOffset, "small volume" ) )
3537  {
3538  wait 1;
3539  }
3540 
3541  entity.wasp Unlink();
3542 
3543  wasp = SpawnVehicle( "spawner_bo3_wasp_enemy", entity.wasp.origin + spawnOffset, ( 0, 0, 0 ) );
3544 
3545  entity.wasp Delete();
3546  }
3547 
3548  entity.wasp = undefined;
3549 }
3550 
3551 function private ‪RapsDetonateCountdown( entity )
3552 {
3553  entity endon( "death" );
3554 
3555  wait RandomFloatRange(
3558 
3560 }
3561 
3562 function private ‪BecomeCrawler( entity )
3563 {
3564  if ( !‪RobotSoldierBehavior::robotIsCrawler( entity ) &&
3565  entity ‪ai::get_behavior_attribute( "can_become_crawler" ) )
3566  {
3567  entity.becomeCrawler = true;
3568  }
3569 }
3570 
3571 function private ‪CleanUpEquipment( entity )
3572 {
3573  entity waittill( "death" );
3574 
3575  if ( !IsDefined( entity ) )
3576  {
3577  return;
3578  }
3579 
3580  if ( IsDefined( entity.miniRaps ) )
3581  {
3582  /*
3583  entity.miniRaps Delete();
3584  */
3585  entity.miniRaps = undefined;
3586  }
3587 
3588  if ( IsDefined( entity.wasp ) )
3589  {
3590  entity.wasp Delete();
3591  entity.wasp = undefined;
3592  }
3593 }
3594 
3596 {
3597  entity = self;
3598 
3599  if ( entity.controlLevel >= 1 )
3600  {
3601  return;
3602  }
3603 
3604  entity.team = "team3";
3605  entity.controlLevel = 1;
3607  entity ‪ai::set_behavior_attribute( "rogue_control", "level_1" );
3608 }
3609 
3611 {
3612  entity = self;
3613 
3614  if ( entity.controlLevel >= 2 )
3615  {
3616  return;
3617  }
3618 
3619  rogue_melee_weapon = GetWeapon( "rogue_robot_melee" );
3620 
3621  locomotionTypes = ‪array( "alt1", "alt2", "alt3", "alt4", "alt5" );
3622 
3623  ‪Blackboard::SetBlackBoardAttribute( entity, ‪ROBOT_LOCOMOTION_TYPE, locomotionTypes[ RandomInt( locomotionTypes.size ) ] );
3624  entity ASMSetAnimationRate( RandomFloatRange( 0.95, 1.05 ) );
3626  entity.combatmode = "no_cover";
3627  entity SetAvoidanceMask( "avoid none" );
3628  entity.controlLevel = 2;
3629  entity ‪shared::placeWeaponOn( entity.weapon, "none" );
3630  entity.meleeweapon = rogue_melee_weapon;
3631  entity.dontDropWeapon = true;
3632  entity.ignorepathenemyfightdist = true;
3633 
3634  if ( entity ‪ai::get_behavior_attribute( "rogue_allow_predestruct" ) )
3635  {
3637  }
3638 
3639  // Half the health when robots become mind controlled.
3640  if ( entity.health > entity.maxhealth * 0.6 )
3641  {
3642  entity.health = int( entity.maxhealth * 0.6 );
3643  }
3644 
3646  entity ‪ai::set_behavior_attribute( "rogue_control", "level_2" );
3647  entity ‪ai::set_behavior_attribute( "can_become_crawler", false );
3648 }
3649 
3651 {
3652  entity = self;
3653 
3654  if ( entity.controlLevel >= 3 )
3655  {
3656  return;
3657  }
3658 
3660  entity.controlLevel = 3;
3661 
3663  entity ‪ai::set_behavior_attribute( "rogue_control", "level_3" );
3664 }
3665 
3666 function ‪robotEquipMiniRaps( entity, attribute, oldValue, value )
3667 {
3668  entity.miniRaps = value;
3669 
3670  // Do not display a miniraps on a robot.
3671  /*
3672  if ( IsDefined( entity ) && !IsDefined( entity.miniRaps ) )
3673  {
3674  entity.miniRaps = Spawn( "script_model", ( 0, 0, 0 ) );
3675  entity.miniRaps SetModel( ROBOT_MINI_RAPS_MODEL );
3676  entity.miniRaps LinkTo(
3677  entity,
3678  ROBOT_MINI_RAPS_LINK_TO_BONE,
3679  ROBOT_MINI_RAPS_OFFSET_POSITION,
3680  ( 0, 0, 0 ) );
3681  }
3682  */
3683 }
3684 
3685 function ‪robotLights( entity, attribute, oldValue, value )
3686 {
3687  if ( value == ‪ROBOT_LIGHTS_HACKED )
3688  {
3690  }
3691  else if ( value == ‪ROBOT_LIGHTS_ON )
3692  {
3694  }
3695  else if ( value == ‪ROBOT_LIGHTS_FLICKER )
3696  {
3698  }
3699  else if ( value == ‪ROBOT_LIGHTS_OFF )
3700  {
3702  }
3703  else if ( value == ‪ROBOT_LIGHTS_DEATH )
3704  {
3706  }
3707 }
3708 
3709 function ‪RandomGibRogueRobot( entity )
3710 {
3711  ‪GibServerUtils::ToggleSpawnGibs( entity, false );
3712 
3713  if ( ‪math::cointoss() )
3714  {
3715  if ( ‪math::cointoss() )
3716  {
3718  }
3719  else if ( ‪math::cointoss() )
3720  {
3722  }
3723  }
3724  else
3725  {
3726  if ( ‪math::cointoss() )
3727  {
3729  }
3730  else if ( ‪math::cointoss() )
3731  {
3733  }
3734  }
3735 }
3736 
3737 function ‪rogueControlAttributeCallback( entity, attribute, oldValue, value )
3738 {
3739  switch ( value )
3740  {
3741  case "forced_level_1":
3742  if ( entity.controlLevel <= 0 )
3743  {
3745  }
3746  break;
3747  case "forced_level_2":
3748  if ( entity.controlLevel <= 1 )
3749  {
3751  ‪DestructServerUtils::ToggleSpawnGibs( entity, false );
3752 
3753  if ( entity ‪ai::get_behavior_attribute( "rogue_allow_pregib" ) )
3754  {
3755  ‪RandomGibRogueRobot( entity );
3756  }
3757  }
3758  break;
3759  case "forced_level_3":
3760  if ( entity.controlLevel <= 2 )
3761  {
3763  ‪DestructServerUtils::ToggleSpawnGibs( entity, false );
3764 
3765  if ( entity ‪ai::get_behavior_attribute( "rogue_allow_pregib" ) )
3766  {
3767  ‪RandomGibRogueRobot( entity );
3768  }
3769  }
3770  break;
3771  }
3772 }
3773 
3774 function ‪robotMoveModeAttributeCallback( entity, attribute, oldValue, value )
3775 {
3776  entity.ignorepathenemyfightdist = false;
3778 
3779  if ( value != "guard" )
3780  {
3781  entity.guardPosition = undefined;
3782  }
3783 
3784  switch ( value )
3785  {
3786  case "normal":
3787  break;
3788  case "rambo":
3789  entity.ignorepathenemyfightdist = true;
3790  break;
3791  case "marching":
3792  entity.ignorepathenemyfightdist = true;
3793  ‪Blackboard::SetBlackBoardAttribute( entity, ‪MOVE_MODE, "marching" );
3794  break;
3795  case "rusher":
3796  if ( !entity ‪ai::get_behavior_attribute( "can_become_rusher" ) )
3797  {
3798  entity ‪ai::set_behavior_attribute( "move_mode", oldValue );
3799  }
3800  break;
3801  }
3802 }
3803 
3804 function ‪robotForceCrawler( entity, attribute, oldValue, value )
3805 {
3807  {
3808  return;
3809  }
3810 
3811  if ( !entity ‪ai::get_behavior_attribute( "can_become_crawler" ) )
3812  {
3813  return;
3814  }
3815 
3816  switch ( value )
3817  {
3818  case "normal":
3819  return;
3820  break;
3821  case "gib_legs":
3822  ‪GibServerUtils::ToggleSpawnGibs( entity, true );
3824  break;
3825  case "remove_legs":
3826  ‪GibServerUtils::ToggleSpawnGibs( entity, false );
3827  ‪DestructServerUtils::ToggleSpawnGibs( entity, false );
3828  break;
3829  }
3830 
3831  if ( value == "gib_legs" || value == "remove_legs" )
3832  {
3833  if ( ‪math::cointoss() )
3834  {
3835  if ( ‪math::cointoss() )
3836  {
3838  }
3839  else
3840  {
3842  }
3843  }
3844  else
3845  {
3846  ‪GibServerUtils::GibLegs( entity );
3847  }
3848 
3849  // Set the robot to "crawler" levels of health.
3850  if ( entity.health > ( entity.maxHealth * ‪ROBOT_GIB_LEG_HEALTH_THRESHOLD ) )
3851  {
3852  entity.health = Int( entity.maxHealth * ‪ROBOT_GIB_LEG_HEALTH_THRESHOLD );
3853  }
3854 
3856 
3857  if ( value == "gib_legs" )
3858  {
3859  ‪BecomeCrawler( entity );
3860  }
3861  else
3862  {
3864  }
3865  }
3866 }
3867 
3868 function ‪rogueControlForceGoalAttributeCallback( entity, attribute, oldValue, value )
3869 {
3870  if ( !IsVec( value ) )
3871  {
3872  return;
3873  }
3874 
3875  rogueControlled = IsInArray( ‪array( "level_2", "level_3" ),
3876  entity ‪ai::get_behavior_attribute( "rogue_control" ) );
3877 
3878  if ( !rogueControlled )
3879  {
3880  entity ‪ai::set_behavior_attribute( "rogue_control_force_goal", undefined );
3881  }
3882  else
3883  {
3884  entity.favoriteenemy = undefined;
3885  entity ClearPath();
3886 
3887  entity UsePosition( entity ‪ai::get_behavior_attribute( "rogue_control_force_goal" ) );
3888  }
3889 }
3890 
3891 function ‪rogueControlSpeedAttributeCallback( entity, attribute, oldValue, value )
3892 {
3893  switch ( value )
3894  {
3895  case "walk":
3897  break;
3898  case "run":
3900  break;
3901  case "sprint":
3903  break;
3904  }
3905 }
3906 
3907 function ‪robotTraversalAttributeCallback( entity, attribute, oldValue, value )
3908 {
3909  switch ( value )
3910  {
3911  case "normal":
3912  entity.manualTraverseMode = false;
3913  break;
3914  case "procedural":
3915  entity.manualTraverseMode = true;
3916  break;
3917  }
3918 }
3919 
3920 // end #namespace RobotSoldierServerUtils;
‪robotRogueHasEnemyToMelee
‪function private robotRogueHasEnemyToMelee(entity)
Definition: archetype_robot.gsc:2040
‪IsDestructed
‪function IsDestructed(entity, pieceNumber)
Definition: destructible_character.gsc:24
‪chooseJukeDirection
‪function chooseJukeDirection(entity)
Definition: archetype_locomotion_utility.gsc:555
‪shouldStepInCondition
‪function private shouldStepInCondition(entity)
Definition: archetype_robot.gsc:2947
‪COVER_MODE
‪#define COVER_MODE
Definition: blackboard.gsh:41
‪ROBOT_GIB_LEGS_CHANCE
‪#define ROBOT_GIB_LEGS_CHANCE
Definition: archetype_robot.gsh:35
‪ROBOT_LIGHTS_BITS
‪#define ROBOT_LIGHTS_BITS
Definition: archetype_robot.gsh:180
‪robotWallrunStart
‪function private robotWallrunStart()
Definition: archetype_robot.gsc:821
‪robotDeployWasp
‪function private robotDeployWasp(entity)
Definition: archetype_robot.gsc:3526
‪robotExplode
‪function private robotExplode(entity)
Definition: archetype_robot.gsc:1651
‪robotEmpIdleInitialize
‪function private robotEmpIdleInitialize(entity, asmStateName)
Definition: archetype_robot.gsc:252
‪DestructNumberRandomPieces
‪function DestructNumberRandomPieces(entity, num_pieces_to_destruct=0)
Definition: destructible_character.gsc:22
‪ROBOT_RUSHER_MAX_ENEMY_DISTANCE_SQ
‪#define ROBOT_RUSHER_MAX_ENEMY_DISTANCE_SQ
Definition: archetype_robot.gsh:86
‪canMoveToEnemyCondition
‪function private canMoveToEnemyCondition(entity)
Definition: archetype_robot.gsc:1751
‪canJuke
‪function canJuke(entity)
Definition: archetype_locomotion_utility.gsc:532
‪robotHasCloseEnemyToMelee
‪function private robotHasCloseEnemyToMelee(entity)
Definition: archetype_robot.gsc:2069
‪robotGibDeathOverride
‪function private robotGibDeathOverride(inflictor, attacker, damage, meansOfDeath, weapon, dir, hitLoc, offsetTime)
Definition: archetype_robot.gsc:3195
‪robotPrepareForAdjustToCover
‪function private robotPrepareForAdjustToCover(entity)
Definition: archetype_robot.gsc:1240
‪shouldMelee
‪function shouldMelee(entity)
Definition: archetype_utility.gsc:2707
‪ASM_STATE_COMPLETE
‪#define ASM_STATE_COMPLETE
Definition: animation_state_machine.gsh:15
‪_robotCoverPosition
‪function private _robotCoverPosition(entity)
Definition: archetype_robot.gsc:2290
‪hasMiniRaps
‪function private hasMiniRaps(entity)
Definition: archetype_robot.gsc:2259
‪robotTraversalType
‪function private robotTraversalType(node)
Definition: archetype_robot.gsc:968
‪jukeInfo
Definition: archetype_apothicon_fury.gsc:1188
‪robotShouldWallrun
‪function private robotShouldWallrun(entity)
Definition: archetype_robot.gsc:558
‪robotHasEnemyToMelee
‪function private robotHasEnemyToMelee(entity)
Definition: archetype_robot.gsc:2020
‪ROBOT_INVALID_COVER_DISTANCE
‪#define ROBOT_INVALID_COVER_DISTANCE
Definition: archetype_robot.gsh:77
‪cleanupCoverMode
‪function cleanupCoverMode(behaviorTreeEntity)
Definition: archetype_cover_utility.gsc:564
‪AddAIOverrideDamageCallback
‪function AddAIOverrideDamageCallback(entity, callback, addToFront)
Definition: archetype_utility.gsc:542
‪robotCrawlerCanShootEnemy
‪function private robotCrawlerCanShootEnemy(entity)
Definition: archetype_robot.gsc:1027
‪REACQUIRE_STEP_SIZE
‪#define REACQUIRE_STEP_SIZE
Definition: behavior.gsh:92
‪GIBBED_LIMBS
‪#define GIBBED_LIMBS
Definition: blackboard.gsh:146
‪BT_REGISTER_API
‪#define BT_REGISTER_API(name, function)
Definition: behavior.gsh:1
‪robotAbleToShootCondition
‪function private robotAbleToShootCondition(entity)
Definition: archetype_robot.gsc:2274
‪ROBOT_MIND_CONTROL_EXPLOSION_ON
‪#define ROBOT_MIND_CONTROL_EXPLOSION_ON
Definition: archetype_robot.gsh:171
‪supportsStepOutCondition
‪function private supportsStepOutCondition(entity)
Definition: archetype_robot.gsc:2940
‪CleanUpEquipment
‪function private CleanUpEquipment(entity)
Definition: archetype_robot.gsc:3571
‪NODE_COVER_STAND
‪#define NODE_COVER_STAND(_node)
Definition: utility.gsh:9
‪preShootLaserAndGlintOn
‪function preShootLaserAndGlintOn(ai)
Definition: archetype_utility.gsc:3051
‪robotPreemptiveJukeTerminate
‪function private robotPreemptiveJukeTerminate(entity)
Definition: archetype_robot.gsc:2754
‪robotCalcProceduralTraversal
‪function robotCalcProceduralTraversal(entity, asmStateName)
Definition: archetype_robot.gsc:314
‪robotTraversalAttributeCallback
‪function robotTraversalAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3907
‪ROBOT_MINI_RAPS_AUTO_DETONATE_MIN_TIME
‪#define ROBOT_MINI_RAPS_AUTO_DETONATE_MIN_TIME
Definition: archetype_robot.gsh:135
‪DropAIWeapon
‪function DropAIWeapon()
Definition: shared.gsc:226
‪ROBOT_ESCORT_MIN_RADIUS
‪#define ROBOT_ESCORT_MIN_RADIUS
Definition: archetype_robot.gsh:149
‪robotTookEmpDamage
‪function private robotTookEmpDamage(entity)
Definition: archetype_robot.gsc:2130
‪robotStartSuperSprint
‪function private robotStartSuperSprint(entity)
Definition: archetype_robot.gsc:1806
‪AddAIOverrideKilledCallback
‪function AddAIOverrideKilledCallback(entity, callback)
Definition: archetype_utility.gsc:618
‪robotTraverseEnd
‪function robotTraverseEnd(entity)
Definition: archetype_robot.gsc:504
‪_IsValidRusher
‪function private _IsValidRusher(entity, neighbor)
Definition: archetype_robot.gsc:1382
‪mocompIgnorePainFaceEnemyInit
‪function private mocompIgnorePainFaceEnemyInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:760
‪BSM_REGISTER_API
‪#define BSM_REGISTER_API(name, scriptFunction)
Definition: behavior_state_machine.gsh:17
‪ROBOT_RUSHER_DISTANCE_SQ
‪#define ROBOT_RUSHER_DISTANCE_SQ
Definition: archetype_robot.gsh:80
‪ROBOT_GIB_LEG_HEALTH_THRESHOLD
‪#define ROBOT_GIB_LEG_HEALTH_THRESHOLD
Definition: archetype_robot.gsh:31
‪GIB_TORSO_RIGHT_ARM_FLAG
‪#define GIB_TORSO_RIGHT_ARM_FLAG
Definition: gib.gsh:25
‪robotOutsideSprintRange
‪function private robotOutsideSprintRange(entity)
Definition: archetype_robot.gsc:2197
‪forceRobotSoldierMindControlLevel2
‪function private forceRobotSoldierMindControlLevel2()
Definition: archetype_robot.gsc:3610
‪GibLeftArm
‪function GibLeftArm(entity)
Definition: gib.gsc:450
‪ROBOT_MIND_CONTROL_LEVEL_0
‪#define ROBOT_MIND_CONTROL_LEVEL_0
Definition: archetype_robot.gsh:162
‪REACQUIRE_RESET
‪#define REACQUIRE_RESET
Definition: behavior.gsh:93
‪AI_ANIM_MOVE_CODE_NOGRAVITY
‪#define AI_ANIM_MOVE_CODE_NOGRAVITY
Definition: animation_state_machine.gsh:78
‪robotLocomotionSpeed
‪function private robotLocomotionSpeed()
Definition: archetype_robot.gsc:1289
‪useCoverNodeWrapper
‪function useCoverNodeWrapper(behaviorTreeEntity, node)
Definition: archetype_utility.gsc:1495
‪_robotRusherPosition
‪function private _robotRusherPosition(entity)
Definition: archetype_robot.gsc:2494
‪robotOutsideTacticalWalkRange
‪function private robotOutsideTacticalWalkRange(entity)
Definition: archetype_robot.gsc:2208
‪ROBOT_JUKE_DISTANCE
‪#define ROBOT_JUKE_DISTANCE
Definition: archetype_robot.gsh:141
‪ROBOT_MIND_CONTROL_EXPLOSION_CLIENTFIELD
‪#define ROBOT_MIND_CONTROL_EXPLOSION_CLIENTFIELD
Definition: archetype_robot.gsh:167
‪stepIntoTerminate
‪function private stepIntoTerminate(entity, asmStateName)
Definition: archetype_robot.gsc:2893
‪robotDestructDeathOverride
‪function private robotDestructDeathOverride(inflictor, attacker, damage, meansOfDeath, weapon, dir, hitLoc, offsetTime)
Definition: archetype_robot.gsc:3257
‪robotEmpIdleUpdate
‪function private robotEmpIdleUpdate(entity, asmStateName)
Definition: archetype_robot.gsc:263
‪robotCoverScanInitialize
‪function private robotCoverScanInitialize(entity)
Definition: archetype_robot.gsc:1096
‪robotProceduralLandingUpdate
‪function robotProceduralLandingUpdate(entity, asmStateName)
Definition: archetype_robot.gsc:304
‪findClosestNavMeshPositionToEnemy
‪function private findClosestNavMeshPositionToEnemy(enemy)
Definition: archetype_robot.gsc:3397
‪rogueControlAttributeCallback
‪function rogueControlAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3737
‪robotRogueHasCloseEnemyToMelee
‪function private robotRogueHasCloseEnemyToMelee(entity)
Definition: archetype_robot.gsc:2094
‪ROBOT_EMP_SHUTDOWN_TIME
‪#define ROBOT_EMP_SHUTDOWN_TIME
Definition: archetype_robot.gsh:95
‪canMoveCloseToEnemyCondition
‪function private canMoveCloseToEnemyCondition(entity)
Definition: archetype_robot.gsc:1779
‪robotDeathOverride
‪function private robotDeathOverride(inflictor, attacker, damage, meansOfDeath, weapon, dir, hitLoc, offsetTime)
Definition: archetype_robot.gsc:3185
‪ROBOT_EMP_OFF
‪#define ROBOT_EMP_OFF
Definition: archetype_robot.gsh:176
‪detonate
‪function detonate(attacker)
Definition: vehicle_ai_shared.gsc:1650
‪robotShouldGibDeath
‪function private robotShouldGibDeath(entity, asmStateName)
Definition: archetype_robot.gsc:247
‪takeOverTerminate
‪function private takeOverTerminate(entity, asmStateName)
Definition: archetype_robot.gsc:2864
‪robotWallrunEnd
‪function private robotWallrunEnd()
Definition: archetype_robot.gsc:831
‪robotIsAtCoverModeScan
‪function robotIsAtCoverModeScan(entity)
Definition: archetype_robot.gsc:1233
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪robotShouldShutdown
‪function private robotShouldShutdown(entity)
Definition: archetype_robot.gsc:1607
‪mocompRobotStartTraversalInit
‪function private mocompRobotStartTraversalInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:620
‪NODE_COVER_PILLAR
‪#define NODE_COVER_PILLAR(_node)
Definition: utility.gsh:8
‪NODE_COVER_LEFT
‪#define NODE_COVER_LEFT(_node)
Definition: utility.gsh:6
‪BHTN_RUNNING
‪#define BHTN_RUNNING
Definition: behavior_tree.gsh:9
‪onDeath
‪function onDeath()
Definition: _spawning.gsc:184
‪MIND_CONTROL
‪#define MIND_CONTROL
Definition: blackboard.gsh:144
‪_IsValidPlayer
‪function private _IsValidPlayer(player)
Definition: archetype_robot.gsc:1345
‪cointoss
‪function cointoss()
Definition: math_shared.csc:171
‪robotSetupWallRunJump
‪function private robotSetupWallRunJump()
Definition: archetype_robot.gsc:844
‪LOCOMOTION_SPEED_WALK
‪#define LOCOMOTION_SPEED_WALK
Definition: blackboard.gsh:156
‪mocompRobotProceduralTraversalUpdate
‪function private mocompRobotProceduralTraversalUpdate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:700
‪ROBOT_JUKE_PREEMPTIVE_MAX_DISTANCE
‪#define ROBOT_JUKE_PREEMPTIVE_MAX_DISTANCE
Definition: archetype_robot.gsh:72
‪robotWallrunTraverse
‪function private robotWallrunTraverse(entity)
Definition: archetype_robot.gsc:540
‪BecomeCrawler
‪function private BecomeCrawler(entity)
Definition: archetype_robot.gsc:3562
‪BB_REGISTER_ATTRIBUTE
‪#define BB_REGISTER_ATTRIBUTE(name, defaultValue, getter)
Definition: blackboard.gsh:1
‪ROBOT_LIGHTS_CLIENTFIELD
‪#define ROBOT_LIGHTS_CLIENTFIELD
Definition: archetype_robot.gsh:179
‪GetPieceCount
‪function GetPieceCount(entity)
Definition: destructible_character.gsc:23
‪ToggleSpawnGibs
‪function ToggleSpawnGibs(entity, shouldSpawnGibs)
Definition: destructible_character.gsc:19
‪robotShouldProceduralTraverse
‪function private robotShouldProceduralTraverse(entity)
Definition: archetype_robot.gsc:526
‪resetCoverParameters
‪function resetCoverParameters(behaviorTreeEntity)
Definition: archetype_cover_utility.gsc:430
‪GET_YAW
‪#define GET_YAW(__self, __org)
Definition: utility.gsh:26
‪MELEE_YAW_THRESHOLD
‪#define MELEE_YAW_THRESHOLD
Definition: behavior.gsh:61
‪clearCoverShootStartTime
‪function clearCoverShootStartTime(behaviorTreeEntity)
Definition: archetype_cover_utility.gsc:544
‪PositionQuery_PointArray
‪function PositionQuery_PointArray(origin, minSearchRadius, maxSearchRadius, halfHeight, innerSpacing, reachableBy_Ent)
Definition: util_shared.gsc:3462
‪forceRobotSoldierMindControlLevel3
‪function private forceRobotSoldierMindControlLevel3()
Definition: archetype_robot.gsc:3650
‪robotIsAtCoverCondition
‪function private robotIsAtCoverCondition(entity)
Definition: archetype_robot.gsc:1714
‪ROBOT_MIND_CONTROL_EXPLOSION_TYPE
‪#define ROBOT_MIND_CONTROL_EXPLOSION_TYPE
Definition: archetype_robot.gsh:169
‪stepIntoInitialize
‪function private stepIntoInitialize(entity, asmStateName)
Definition: archetype_robot.gsc:2877
‪mocompIgnorePainFaceEnemyTerminate
‪function private mocompIgnorePainFaceEnemyTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:788
‪mocompIgnorePainFaceEnemyUpdate
‪function private mocompIgnorePainFaceEnemyUpdate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:776
‪ROBOT_LIGHTS_ON
‪#define ROBOT_LIGHTS_ON
Definition: archetype_robot.gsh:182
‪BB_GetLocomotionFaceEnemyQuadrant
‪function BB_GetLocomotionFaceEnemyQuadrant()
Definition: archetype_utility.gsc:879
‪ROBOT_MODE
‪#define ROBOT_MODE
Definition: blackboard.gsh:152
‪LOCOMOTION_SPEED_SPRINT
‪#define LOCOMOTION_SPEED_SPRINT
Definition: blackboard.gsh:158
‪ROBOT_MINI_RAPS_AUTO_DETONATE_MAX_TIME
‪#define ROBOT_MINI_RAPS_AUTO_DETONATE_MAX_TIME
Definition: archetype_robot.gsh:137
‪ROBOT_RESUME_COVER_TIME
‪#define ROBOT_RESUME_COVER_TIME
Definition: archetype_robot.gsh:66
‪SetBlackBoardAttribute
‪function SetBlackBoardAttribute(entity, attributeName, attributeValue)
Definition: blackboard.gsc:56
‪robotNoCloseEnemyService
‪function private robotNoCloseEnemyService(entity)
Definition: archetype_robot.gsc:2143
‪robotSupportsOverCover
‪function private robotSupportsOverCover(entity)
Definition: archetype_robot.gsc:1734
‪calculateCoverDirection
‪function calculateCoverDirection(behaviorTreeEntity, stepOut)
Definition: archetype_cover_utility.gsc:451
‪setCanBeFlanked
‪function setCanBeFlanked(behaviorTreeEntity, canBeFlanked)
Definition: archetype_cover_utility.gsc:559
‪if
‪if(on_off)
Definition: util_shared.csc:908
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪GetBlackBoardAttribute
‪function GetBlackBoardAttribute(entity, attributeName)
Definition: blackboard.gsc:32
‪ROBOT_GIB_HEAD_DEATH_CHANCE
‪#define ROBOT_GIB_HEAD_DEATH_CHANCE
Definition: archetype_robot.gsh:28
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪GREEN
‪#define GREEN
Definition: shared.gsh:176
‪ROBOT_GIB_LIMB_EXPLOSION_CHANCE
‪#define ROBOT_GIB_LIMB_EXPLOSION_CHANCE
Definition: archetype_robot.gsh:45
‪robotWithinSprintRange
‪function private robotWithinSprintRange(entity)
Definition: archetype_robot.gsc:2225
‪mocompRobotProceduralTraversalTerminate
‪function private mocompRobotProceduralTraversalTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:737
‪robotTacticalWalkActionStart
‪function private robotTacticalWalkActionStart(entity)
Definition: archetype_robot.gsc:1813
‪RegisterUtilityBlackboardAttributes
‪function RegisterUtilityBlackboardAttributes()
Definition: archetype_utility.gsc:139
‪accuracy_buildup_before_fire
‪function accuracy_buildup_before_fire(ai)
Definition: gameskill_shared.gsc:2144
‪robotSetupWallRunLand
‪function private robotSetupWallRunLand()
Definition: archetype_robot.gsc:889
‪shouldMutexMelee
‪function shouldMutexMelee(behaviorTreeEntity)
Definition: archetype_utility.gsc:2663
‪ROBOT_TRAVERSAL_TYPE
‪#define ROBOT_TRAVERSAL_TYPE
Definition: blackboard.gsh:151
‪COS_60
‪#define COS_60
Definition: behavior.gsh:91
‪mocompRobotStartTraversalTerminate
‪function private mocompRobotStartTraversalTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:676
‪ROBOT_MINI_RAPS_SPAWNER
‪#define ROBOT_MINI_RAPS_SPAWNER
Definition: archetype_robot.gsh:129
‪robotOutsideSuperSprintRange
‪function private robotOutsideSuperSprintRange(entity)
Definition: archetype_robot.gsc:2181
‪mocompRobotStartWallrunTerminate
‪function private mocompRobotStartWallrunTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:604
‪RED
‪#define RED
Definition: shared.gsh:175
‪ROBOT_LIGHTS_DEATH
‪#define ROBOT_LIGHTS_DEATH
Definition: archetype_robot.gsh:186
‪robotDestructRandomPieces
‪function private robotDestructRandomPieces(inflictor, attacker, damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex)
Definition: archetype_robot.gsc:3374
‪shouldTakeOverCondition
‪function private shouldTakeOverCondition(entity)
Definition: archetype_robot.gsc:2242
‪calculateJukeDirection
‪function calculateJukeDirection(entity, entityRadius, jukeDistance)
Definition: archetype_locomotion_utility.gsc:447
‪_robotOutsideMovementRange
‪function private _robotOutsideMovementRange(entity, range, useEnemyPos)
Definition: archetype_robot.gsc:2155
‪robotLightsFlicker
‪function private robotLightsFlicker(entity, asmStateName)
Definition: archetype_robot.gsc:227
‪robotScanExposedPainTerminate
‪function private robotScanExposedPainTerminate(entity)
Definition: archetype_robot.gsc:2124
‪ArchetypeRobotOnAnimScriptedCallback
‪function private ArchetypeRobotOnAnimScriptedCallback(entity)
Definition: archetype_robot.gsc:1045
‪isSafeFromGrenades
‪function isSafeFromGrenades(entity)
Definition: archetype_utility.gsc:1382
‪GibRightLeg
‪function GibRightLeg(entity)
Definition: gib.gsc:496
‪canBeFlanked
‪function canBeFlanked(behaviorTreeEntity)
Definition: archetype_cover_utility.gsc:554
‪STANCE
‪#define STANCE
Definition: blackboard.gsh:36
‪GibLeftLeg
‪function GibLeftLeg(entity)
Definition: gib.gsc:485
‪SPAWNFLAG_PATH_WALLRUN
‪#define SPAWNFLAG_PATH_WALLRUN
Definition: shared.gsh:87
‪moveToPlayerUpdate
‪function private moveToPlayerUpdate(entity, asmStateName)
Definition: archetype_robot.gsc:1832
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪pow
‪function pow(base, exp)
Definition: math_shared.gsc:544
‪RegisterRobotInterfaceAttributes
‪function RegisterRobotInterfaceAttributes()
Definition: archetype_robot_interface.gsc:8
‪STANCE_STAND
‪#define STANCE_STAND
Definition: blackboard.gsh:273
‪ROBOT_RUSHER_MAX_RADIUS
‪#define ROBOT_RUSHER_MAX_RADIUS
Definition: archetype_robot.gsh:147
‪DESIRED_STANCE
‪#define DESIRED_STANCE
Definition: blackboard.gsh:18
‪__init__
‪function __init__()
Definition: archetype_robot.gsc:45
‪ROBOT_DETONATION_INNER_DAMAGE
‪#define ROBOT_DETONATION_INNER_DAMAGE
Definition: archetype_robot.gsh:117
‪robotStartSprint
‪function private robotStartSprint(entity)
Definition: archetype_robot.gsc:1799
‪robotIsMarching
‪function private robotIsMarching(entity)
Definition: archetype_robot.gsc:1284
‪ROBOT_RUSHER_MIN_RADIUS
‪#define ROBOT_RUSHER_MIN_RADIUS
Definition: archetype_robot.gsh:145
‪robotTraverseStart
‪function robotTraverseStart(entity, asmStateName)
Definition: archetype_robot.gsc:488
‪ROBOT_MIND_CONTROL_LEVEL_1
‪#define ROBOT_MIND_CONTROL_LEVEL_1
Definition: archetype_robot.gsh:163
‪ROBOT_OFF_COVER_NODE_MAX_DISTANCE
‪#define ROBOT_OFF_COVER_NODE_MAX_DISTANCE
Definition: archetype_robot.gsh:113
‪LOCOMOTION_SPEED_SUPER_SPRINT
‪#define LOCOMOTION_SPEED_SUPER_SPRINT
Definition: blackboard.gsh:159
‪ROBOT_LIGHTS_OFF
‪#define ROBOT_LIGHTS_OFF
Definition: archetype_robot.gsh:184
‪robotChooseCoverDirection
‪function private robotChooseCoverDirection(entity, stepOut)
Definition: archetype_robot.gsc:3417
‪MELEE_RANGE_SQ
‪#define MELEE_RANGE_SQ
Definition: behavior.gsh:54
‪ROBOT_ESCORT_MAX_RADIUS
‪#define ROBOT_ESCORT_MAX_RADIUS
Definition: archetype_robot.gsh:151
‪ENABLE_BLACKBOARD_DEBUG_TRACKING
‪#define ENABLE_BLACKBOARD_DEBUG_TRACKING(self)
Definition: blackboard.gsh:7
‪ROBOT_GIB_HEAD_HEADSHOT_CHANCE
‪#define ROBOT_GIB_HEAD_HEADSHOT_CHANCE
Definition: archetype_robot.gsh:21
‪ROBOT_SUPER_SPRINT_DISTANCE
‪#define ROBOT_SUPER_SPRINT_DISTANCE
Definition: archetype_robot.gsh:92
‪NODE_COVER_RIGHT
‪#define NODE_COVER_RIGHT(_node)
Definition: utility.gsh:7
‪robotMoveModeAttributeCallback
‪function robotMoveModeAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3774
‪AIM_LEFT
‪#define AIM_LEFT
Definition: blackboard.gsh:257
‪ROBOT_LIGHTS_HACKED
‪#define ROBOT_LIGHTS_HACKED
Definition: archetype_robot.gsh:185
‪setNextFindBestCoverTime
‪function setNextFindBestCoverTime(behaviorTreeEntity, node)
Definition: archetype_utility.gsc:1512
‪ASM_REGISTER_MOCOMP
‪#define ASM_REGISTER_MOCOMP(name, initFunction, updateFunction, terminateFunction)
Definition: animation_state_machine.gsh:1
‪robotTargetService
‪function private robotTargetService(entity)
Definition: archetype_robot.gsc:1455
‪robotDropStartingWeapon
‪function private robotDropStartingWeapon(entity, asmStateName)
Definition: archetype_robot.gsc:2732
‪setDesiredStanceToCrouch
‪function private setDesiredStanceToCrouch(behaviorTreeEntity)
Definition: archetype_robot.gsc:1583
‪LOCOMOTION_SPEED_TYPE
‪#define LOCOMOTION_SPEED_TYPE
Definition: blackboard.gsh:155
‪LOCOMOTION_FACE_ENEMY_FRONT
‪#define LOCOMOTION_FACE_ENEMY_FRONT
Definition: blackboard.gsh:72
‪stepOutTerminate
‪function private stepOutTerminate(entity, asmStateName)
Definition: archetype_robot.gsc:2928
‪ROBOT_WALK_MIN_DISTANCE
‪#define ROBOT_WALK_MIN_DISTANCE
Definition: archetype_robot.gsh:89
‪robotInvalidateCover
‪function private robotInvalidateCover(entity)
Definition: archetype_robot.gsc:1077
‪ROBOT_HEADSHOT_MULTIPLIER
‪#define ROBOT_HEADSHOT_MULTIPLIER
Definition: archetype_robot.gsh:60
‪ROBOT_GIB_HEAD_EXPLOSION_CHANCE
‪#define ROBOT_GIB_HEAD_EXPLOSION_CHANCE
Definition: archetype_robot.gsh:25
‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP
‪#define AI_ANIM_USE_BOTH_DELTAS_NOCLIP
Definition: animation_state_machine.gsh:83
‪PREVIOUS_COVER_DIRECTION
‪#define PREVIOUS_COVER_DIRECTION
Definition: blackboard.gsh:47
‪ROBOT_LIGHTS_FLICKER
‪#define ROBOT_LIGHTS_FLICKER
Definition: archetype_robot.gsh:183
‪robotGiveWasp
‪function private robotGiveWasp(entity)
Definition: archetype_robot.gsc:3514
‪ROBOT_GIB_LIMB_DEATH_CHANCE
‪#define ROBOT_GIB_LIMB_DEATH_CHANCE
Definition: archetype_robot.gsh:48
‪mocompRobotStartWallrunUpdate
‪function private mocompRobotStartWallrunUpdate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:575
‪ROBOT_MIND_CONTROL_LEVEL_3
‪#define ROBOT_MIND_CONTROL_LEVEL_3
Definition: archetype_robot.gsh:165
‪ROBOT_LOCOMOTION_TYPE
‪#define ROBOT_LOCOMOTION_TYPE
Definition: blackboard.gsh:149
‪RapsDetonateCountdown
‪function private RapsDetonateCountdown(entity)
Definition: archetype_robot.gsc:3551
‪DEFAULT_MOVEMENT_STANCE
‪#define DEFAULT_MOVEMENT_STANCE
Definition: blackboard.gsh:281
‪AI_ANIM_USE_BOTH_DELTAS
‪#define AI_ANIM_USE_BOTH_DELTAS
Definition: animation_state_machine.gsh:82
‪ROBOT_MIND_CONTROL_BITS
‪#define ROBOT_MIND_CONTROL_BITS
Definition: archetype_robot.gsh:160
‪ROBOT_DIAMETER
‪#define ROBOT_DIAMETER
Definition: archetype_robot.gsh:105
‪ROBOT_DETONATION_RANGE
‪#define ROBOT_DETONATION_RANGE
Definition: archetype_robot.gsh:115
‪robotCanJuke
‪function robotCanJuke(entity)
Definition: archetype_robot.gsc:1121
‪ROBOT_HEIGHT
‪#define ROBOT_HEIGHT
Definition: archetype_robot.gsh:103
‪_robotGuardPosition
‪function private _robotGuardPosition(entity)
Definition: archetype_robot.gsc:2571
‪SERVER_FRAME
‪#define SERVER_FRAME
Definition: shared.gsh:264
‪DestructPiece
‪function DestructPiece(entity, pieceNumber)
Definition: destructible_character.gsc:25
‪AddBlackboardEvent
‪function AddBlackboardEvent(eventName, data, timeToLiveInMillis)
Definition: ai_blackboard.gsc:47
‪GIB_LOCATION
‪#define GIB_LOCATION
Definition: blackboard.gsh:141
‪_CalculateWallrunDirection
‪function private _CalculateWallrunDirection(startPosition, endPosition)
Definition: archetype_robot.gsc:793
‪_robotEscortPosition
‪function private _robotEscortPosition(entity)
Definition: archetype_robot.gsc:2415
‪IsGibbed
‪function IsGibbed(localClientNum, entity, gibFlag)
Definition: gib.csc:734
‪releaseClaimNode
‪function releaseClaimNode(behaviorTreeEntity)
Definition: archetype_utility.gsc:2188
‪ArchetypeRobotBlackboardInit
‪function private ArchetypeRobotBlackboardInit()
Definition: archetype_robot.gsc:983
‪rogueControlForceGoalAttributeCallback
‪function rogueControlForceGoalAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3868
‪robotMovement
‪function private robotMovement(entity)
Definition: archetype_robot.gsc:1088
‪robotIsMindControlled
‪function private robotIsMindControlled()
Definition: archetype_robot.gsc:1327
‪ROBOT_WALLRUN_DIRECTION
‪#define ROBOT_WALLRUN_DIRECTION
Definition: blackboard.gsh:150
‪AI_ANIM_USE_POS_DELTAS
‪#define AI_ANIM_USE_POS_DELTAS
Definition: animation_state_machine.gsh:79
‪ROBOT_STEP_IN
‪#define ROBOT_STEP_IN
Definition: blackboard.gsh:147
‪robotTryReacquireService
‪function private robotTryReacquireService(entity)
Definition: archetype_robot.gsc:2760
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪array
‪function filter array
Definition: array_shared.csc:16
‪rogueControlSpeedAttributeCallback
‪function rogueControlSpeedAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3891
‪setCoverShootStartTime
‪function setCoverShootStartTime(behaviorTreeEntity)
Definition: archetype_cover_utility.gsc:549
‪keepClaimNode
‪function keepClaimNode(behaviorTreeEntity)
Definition: archetype_utility.gsc:2181
‪ROBOT_MIND_CONTROL_CLIENTFIELD
‪#define ROBOT_MIND_CONTROL_CLIENTFIELD
Definition: archetype_robot.gsh:159
‪NODE_SUPPORTS_STANCE_STAND
‪#define NODE_SUPPORTS_STANCE_STAND(__node)
Definition: utility.gsh:20
‪GetAiAttribute
‪function GetAiAttribute(entity, attribute)
Definition: ai_interface.gsc:118
‪setDesiredStanceToStand
‪function private setDesiredStanceToStand(behaviorTreeEntity)
Definition: archetype_robot.gsc:1573
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪ROBOT_EMP_CLIENTFIELD
‪#define ROBOT_EMP_CLIENTFIELD
Definition: archetype_robot.gsh:173
‪RandomGibRogueRobot
‪function RandomGibRogueRobot(entity)
Definition: archetype_robot.gsc:3709
‪robotPositionService
‪function private robotPositionService(entity)
Definition: archetype_robot.gsc:2656
‪robotProceduralTraversalUpdate
‪function robotProceduralTraversalUpdate(entity, asmStateName)
Definition: archetype_robot.gsc:286
‪ROBOT_TACTICAL_JUKE_RADIUS
‪#define ROBOT_TACTICAL_JUKE_RADIUS
Definition: archetype_robot.gsh:143
‪ROBOT_NAVMESH_TOLERANCE
‪#define ROBOT_NAVMESH_TOLERANCE
Definition: archetype_robot.gsh:107
‪robotLightsOff
‪function private robotLightsOff(entity, asmStateName)
Definition: archetype_robot.gsc:218
‪robotWithinSuperSprintRange
‪function private robotWithinSuperSprintRange(entity)
Definition: archetype_robot.gsc:2186
‪robotLightsOn
‪function private robotLightsOn(entity, asmStateName)
Definition: archetype_robot.gsc:238
‪chooseCoverDirection
‪function chooseCoverDirection(behaviorTreeEntity, stepOut)
Definition: archetype_cover_utility.gsc:438
‪robotIsCrawler
‪function robotIsCrawler(entity)
Definition: archetype_robot.gsc:1259
‪BHTN_SUCCESS
‪#define BHTN_SUCCESS
Definition: behavior_tree.gsh:8
‪ROBOT_EMP_BITS
‪#define ROBOT_EMP_BITS
Definition: archetype_robot.gsh:174
‪ROBOT_EMP_ON
‪#define ROBOT_EMP_ON
Definition: archetype_robot.gsh:177
‪ROBOT_POSITION_QUERY_RADIUS
‪#define ROBOT_POSITION_QUERY_RADIUS
Definition: archetype_robot.gsh:123
‪robotCoverScanTerminate
‪function private robotCoverScanTerminate(entity)
Definition: archetype_robot.gsc:1109
‪add_archetype_spawn_function
‪function add_archetype_spawn_function(archetype, spawn_func)
Definition: ai_shared.csc:23
‪robotDeployMiniRaps
‪function private robotDeployMiniRaps()
Definition: archetype_robot.gsc:2967
‪robotDie
‪function private robotDie(entity)
Definition: archetype_robot.gsc:1824
‪scriptRequiresToSprintCondition
‪function private scriptRequiresToSprintCondition(entity)
Definition: archetype_robot.gsc:2107
‪ROBOT_MIND_CONTROL_EXPLOSION_BITS
‪#define ROBOT_MIND_CONTROL_EXPLOSION_BITS
Definition: archetype_robot.gsh:168
‪ROBOT_DESTRUCT_DEATH_CHANCE
‪#define ROBOT_DESTRUCT_DEATH_CHANCE
Definition: archetype_robot.gsh:9
‪ROBOT_DESTRUCT_MAX_DEATH_PIECES
‪#define ROBOT_DESTRUCT_MAX_DEATH_PIECES
Definition: archetype_robot.gsh:13
‪ROBOT_MIND_CONTROL_LEVEL_2
‪#define ROBOT_MIND_CONTROL_LEVEL_2
Definition: archetype_robot.gsh:164
‪COVER_SCAN_MODE
‪#define COVER_SCAN_MODE
Definition: blackboard.gsh:114
‪ROBOT_POSITION_QUERY_MOVE_DIST_MAX
‪#define ROBOT_POSITION_QUERY_MOVE_DIST_MAX
Definition: archetype_robot.gsh:125
‪jukeDirection
‪var jukeDirection
Definition: archetype_apothicon_fury.gsc:1167
‪mocompRobotProceduralTraversalInit
‪function private mocompRobotProceduralTraversalInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:680
‪robotDelayMovement
‪function private robotDelayMovement(entity)
Definition: archetype_robot.gsc:1083
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪GIB_TORSO_LEFT_ARM_FLAG
‪#define GIB_TORSO_LEFT_ARM_FLAG
Definition: gib.gsh:26
‪robotBecomeCrawler
‪function private robotBecomeCrawler(entity)
Definition: archetype_robot.gsc:1264
‪robotEquipMiniRaps
‪function robotEquipMiniRaps(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3666
‪COVER_DIRECTION
‪#define COVER_DIRECTION
Definition: blackboard.gsh:46
‪RegisterBehaviorScriptFunctions
‪function RegisterBehaviorScriptFunctions()
Definition: archetype_robot.gsc:90
‪set_behavior_attribute
‪function set_behavior_attribute(attribute, value)
Definition: ai_shared.gsc:159
‪_tryGibbingLegs
‪function private _tryGibbingLegs(entity, damage, hitLoc, isExplosive, attacker)
Definition: archetype_robot.gsc:3068
‪ROBOT_LIGHTS_TYPE
‪#define ROBOT_LIGHTS_TYPE
Definition: archetype_robot.gsh:181
‪robotCrawlerService
‪function private robotCrawlerService(entity)
Definition: archetype_robot.gsc:1247
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪player_is_in_laststand
‪function player_is_in_laststand()
Definition: laststand_shared.gsc:18
‪ROBOT_CRAWL_MAX_DISTANCE
‪#define ROBOT_CRAWL_MAX_DISTANCE
Definition: archetype_robot.gsh:75
‪_tryGibbingLimb
‪function private _tryGibbingLimb(entity, damage, hitLoc, isExplosive, onDeath)
Definition: archetype_robot.gsc:3019
‪ROBOT_DETONATION_OUTER_DAMAGE
‪#define ROBOT_DETONATION_OUTER_DAMAGE
Definition: archetype_robot.gsh:119
‪ROBOT_GIB_HEALTH_THRESHOLD
‪#define ROBOT_GIB_HEALTH_THRESHOLD
Definition: archetype_robot.gsh:17
‪ROBOT_GIB_LEGS_DEATH_CHANCE
‪#define ROBOT_GIB_LEGS_DEATH_CHANCE
Definition: archetype_robot.gsh:38
‪robotTraverseRagdollOnDeath
‪function private robotTraverseRagdollOnDeath(entity, asmStateName)
Definition: archetype_robot.gsc:516
‪CalculateCubicBezier
‪function private CalculateCubicBezier(t, p1, p2, p3, p4)
Definition: archetype_robot.gsc:612
‪MAX_EXPOSED_TIME
‪#define MAX_EXPOSED_TIME
Definition: archetype_robot.gsh:57
‪robotDontTakeCover
‪function private robotDontTakeCover(entity)
Definition: archetype_robot.gsc:1339
‪robotRushNeighborService
‪function private robotRushNeighborService(entity)
Definition: archetype_robot.gsc:1398
‪SPAWNFLAG_PATH_PROCEDURAL
‪#define SPAWNFLAG_PATH_PROCEDURAL
Definition: shared.gsh:84
‪shouldRegisterClientFieldForArchetype
‪function shouldRegisterClientFieldForArchetype(archetype)
Definition: ai_shared.csc:72
‪robotShouldExplode
‪function private robotShouldExplode(entity)
Definition: archetype_robot.gsc:1612
‪robotShouldAdjustToCover
‪function private robotShouldAdjustToCover(entity)
Definition: archetype_robot.gsc:1631
‪_tryGibbingHead
‪function private _tryGibbingHead(entity, damage, hitLoc, isExplosive)
Definition: archetype_robot.gsc:3000
‪robotCanTacticalJuke
‪function robotCanTacticalJuke(entity)
Definition: archetype_robot.gsc:1144
‪robotLights
‪function robotLights(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3685
‪robotEndJumpDirection
‪function private robotEndJumpDirection()
Definition: archetype_robot.gsc:939
‪ROBOT_JUMP_DIRECTION
‪#define ROBOT_JUMP_DIRECTION
Definition: blackboard.gsh:148
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪AI_ANIM_USE_ANGLE_DELTAS
‪#define AI_ANIM_USE_ANGLE_DELTAS
Definition: animation_state_machine.gsh:80
‪ROBOT_EMP_TYPE
‪#define ROBOT_EMP_TYPE
Definition: archetype_robot.gsh:175
‪MELEE_ENEMY_TYPE
‪#define MELEE_ENEMY_TYPE
Definition: blackboard.gsh:409
‪ROBOT_NAVMESH_MAX_TOLERANCE_LEVELS
‪#define ROBOT_NAVMESH_MAX_TOLERANCE_LEVELS
Definition: archetype_robot.gsh:109
‪ROBOT_CHOOSE_COVER_CHANCE
‪#define ROBOT_CHOOSE_COVER_CHANCE
Definition: archetype_robot.gsh:51
‪toggleDesiredStance
‪function private toggleDesiredStance(entity)
Definition: archetype_robot.gsc:1593
‪ROBOT_BACKSHOT_MULTIPLIER
‪#define ROBOT_BACKSHOT_MULTIPLIER
Definition: archetype_robot.gsh:63
‪robotIsMoving
‪function private robotIsMoving(entity)
Definition: archetype_robot.gsc:2264
‪ROBOT_OFF_COVER_NODE_MIN_DISTANCE
‪#define ROBOT_OFF_COVER_NODE_MIN_DISTANCE
Definition: archetype_robot.gsh:111
‪COVER_OVER_MODE
‪#define COVER_OVER_MODE
Definition: blackboard.gsh:111
‪STANCE_CROUCH
‪#define STANCE_CROUCH
Definition: blackboard.gsh:274
‪MOVE_MODE
‪#define MOVE_MODE
Definition: blackboard.gsh:145
‪DestructRandomPieces
‪function DestructRandomPieces(entity)
Definition: destructible_character.gsc:26
‪GibLegs
‪function GibLegs(entity)
Definition: gib.gsc:507
‪robotExposedCoverService
‪function private robotExposedCoverService(entity)
Definition: archetype_robot.gsc:1693
‪ROBOT_MIND_CONTROL_TYPE
‪#define ROBOT_MIND_CONTROL_TYPE
Definition: archetype_robot.gsh:161
‪GetBlackboardEvents
‪function GetBlackboardEvents(eventName)
Definition: ai_blackboard.gsc:64
‪robotShouldChargeMelee
‪function private robotShouldChargeMelee(entity)
Definition: archetype_robot.gsc:2009
‪robotShouldMelee
‪function private robotShouldMelee(entity)
Definition: archetype_robot.gsc:2058
‪robotGetGibbedLimbs
‪function private robotGetGibbedLimbs()
Definition: archetype_robot.gsc:1054
‪ROBOT_JUKE_MAX_DISTANCE
‪#define ROBOT_JUKE_MAX_DISTANCE
Definition: archetype_robot.gsh:69
‪RequestState
‪function RequestState(entity, stateName)
Definition: animation_state_machine_utility.gsc:8
‪robotStartJumpDirection
‪function private robotStartJumpDirection()
Definition: archetype_robot.gsc:910
‪AIM_RIGHT
‪#define AIM_RIGHT
Definition: blackboard.gsh:256
‪robotForceCrawler
‪function robotForceCrawler(entity, attribute, oldValue, value)
Definition: archetype_robot.gsc:3804
‪ROBOT_DETONATION_DAMAGE_TYPE
‪#define ROBOT_DETONATION_DAMAGE_TYPE
Definition: archetype_robot.gsh:121
‪isFollowingSquadLeader
‪function isFollowingSquadLeader(ai)
Definition: ai_squads.gsc:260
‪robotExplodeTerminate
‪function private robotExplodeTerminate(entity)
Definition: archetype_robot.gsc:1657
‪stepOutInitialize
‪function private stepOutInitialize(entity, asmStateName)
Definition: archetype_robot.gsc:2904
‪_FindClosest
‪function private _FindClosest(entity, entities)
Definition: archetype_robot.gsc:1431
‪ORANGE
‪#define ORANGE
Definition: shared.gsh:179
‪GibRightArm
‪function GibRightArm(entity)
Definition: gib.gsc:467
‪GibHead
‪function GibHead(entity)
Definition: gib.gsc:443
‪robotShouldReactAtCover
‪function private robotShouldReactAtCover(behaviorTreeEntity)
Definition: archetype_robot.gsc:1641
‪BT_REGISTER_ACTION
‪#define BT_REGISTER_ACTION(name, initFunction, updateFunction, terminateFunction)
Definition: behavior.gsh:4
‪get_behavior_attribute
‪function get_behavior_attribute(attribute)
Definition: ai_shared.gsc:184
‪HandleDamage
‪function HandleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex, modelIndex)
Definition: destructible_character.gsc:20
‪ARCHETYPE_ROBOT
‪#define ARCHETYPE_ROBOT
Definition: archetype_shared.gsh:8
‪robotCanPreemptiveJuke
‪function robotCanPreemptiveJuke(entity)
Definition: archetype_robot.gsc:1158
‪robotJukeInitialize
‪function private robotJukeInitialize(entity)
Definition: archetype_robot.gsc:2741
‪meleeReleaseMutex
‪function meleeReleaseMutex(behaviorTreeEntity)
Definition: archetype_utility.gsc:2639
‪robotShouldBecomeCrawler
‪function robotShouldBecomeCrawler(entity)
Definition: archetype_robot.gsc:1279
‪LOCOMOTION_SPEED_RUN
‪#define LOCOMOTION_SPEED_RUN
Definition: blackboard.gsh:157
‪CreateInterfaceForEntity
‪function CreateInterfaceForEntity(entity)
Definition: ai_interface.gsc:110
‪placeWeaponOn
‪function placeWeaponOn(weapon, position)
Definition: shared.gsc:58
‪takeOverInitialize
‪function private takeOverInitialize(entity, asmStateName)
Definition: archetype_robot.gsc:2845
‪robotCleanupChargeMeleeAttack
‪function robotCleanupChargeMeleeAttack(behaviorTreeEntity)
Definition: archetype_robot.gsc:211
‪robotCoverOverInitialize
‪function private robotCoverOverInitialize(behaviorTreeEntity)
Definition: archetype_robot.gsc:1313
‪robotEmpIdleTerminate
‪function private robotEmpIdleTerminate(entity, asmStateName)
Definition: archetype_robot.gsc:279
‪chooseBestCoverNodeASAP
‪function chooseBestCoverNodeASAP(behaviorTreeEntity)
Definition: archetype_utility.gsc:1546
‪robotShouldTacticalWalk
‪function private robotShouldTacticalWalk(entity)
Definition: archetype_robot.gsc:2280
‪robotSoldierSpawnSetup
‪function private robotSoldierSpawnSetup()
Definition: archetype_robot.gsc:3429
‪postShootLaserAndGlintOff
‪function postShootLaserAndGlintOff(ai)
Definition: archetype_utility.gsc:3090
‪robotCoverOverTerminate
‪function private robotCoverOverTerminate(behaviorTreeEntity)
Definition: archetype_robot.gsc:1321
‪forceRobotSoldierMindControlLevel1
‪function private forceRobotSoldierMindControlLevel1()
Definition: archetype_robot.gsc:3595
‪NODE_COVER_CROUCH
‪#define NODE_COVER_CROUCH(_node)
Definition: utility.gsh:10
‪ROBOT_GIB_LEGS_EXPLOSION_CHANCE
‪#define ROBOT_GIB_LEGS_EXPLOSION_CHANCE
Definition: archetype_robot.gsh:42
‪robotDamageOverride
‪function private robotDamageOverride(inflictor, attacker, damage, flags, meansOfDamage, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex)
Definition: archetype_robot.gsc:3300
‪mocompRobotStartWallrunInit
‪function private mocompRobotStartWallrunInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_robot.gsc:563
‪ROBOT_RUSHER_NEIGHBOR_DISTANCE_SQ
‪#define ROBOT_RUSHER_NEIGHBOR_DISTANCE_SQ
Definition: archetype_robot.gsh:83
‪robotGibDamageOverride
‪function private robotGibDamageOverride(inflictor, attacker, damage, flags, meansOfDeath, weapon, point, dir, hitLoc, offsetTime, boneIndex, modelIndex)
Definition: archetype_robot.gsc:3143
‪MIN_EXPOSED_TIME
‪#define MIN_EXPOSED_TIME
Definition: archetype_robot.gsh:54
‪robotRushEnemyService
‪function private robotRushEnemyService(entity)
Definition: archetype_robot.gsc:1361