‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
archetype_apothicon_fury.gsc
Go to the documentation of this file.
1 #using scripts\shared\ai_shared;
2 #using scripts\shared\callbacks_shared;
3 #using scripts\shared\clientfield_shared;
4 #using scripts\shared\fx_shared;
5 #using scripts\shared\math_shared;
6 #using scripts\shared\scene_shared;
7 #using scripts\shared\spawner_shared;
8 #using scripts\shared\util_shared;
9 #using scripts\shared\array_shared;
10 
11 #using scripts\shared\ai\systems\animation_state_machine_utility;
12 #using scripts\shared\ai\systems\animation_state_machine_notetracks;
13 #using scripts\shared\ai\systems\animation_state_machine_mocomp;
14 #using scripts\shared\ai\systems\animation_selector_table;
15 #using scripts\shared\ai\archetype_locomotion_utility;
16 #using scripts\shared\ai\archetype_utility;
17 #using scripts\shared\ai\systems\behavior_tree_utility;
18 #using scripts\shared\ai\systems\ai_blackboard;
19 #using scripts\shared\ai\systems\blackboard;
20 #using scripts\shared\ai\systems\debug;
21 #using scripts\shared\ai\systems\gib;
22 #using scripts\shared\ai\zombie_utility;
23 #using scripts\shared\ai\zombie_death;
24 #using scripts\shared\ai\zombie_shared;
25 #using scripts\codescripts\struct;
26 #using scripts\shared\ai\archetype_mocomps_utility;
27 
28 // ZOMBIE (Apothicon shares some functionality with zombies)
29 #using scripts\shared\ai\zombie;
30 
31 //INTERFACE
32 #using scripts\shared\ai\systems\ai_interface;
33 #using scripts\shared\ai\archetype_apothicon_fury_interface;
34 
35 #insert scripts\shared\ai\archetype_damage_effects.gsh;
36 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
37 #insert scripts\shared\ai\systems\animation_state_machine.gsh;
38 #insert scripts\shared\ai\systems\behavior.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 #insert scripts\shared\ai\utility.gsh;
43 #insert scripts\shared\ai\zombie.gsh;
44 #insert scripts\shared\ai\archetype_apothicon_fury.gsh;
45 #insert scripts\shared\shared.gsh;
46 #insert scripts\shared\version.gsh;
47 
48 #precache( "model", FURY_DEATH_MODEL_SWAP );
49 
50 #namespace ApothiconFuryBehavior;
51 
52 function autoexec ‪init()
53 {
54  // INIT BEHAVIORS
56 
57  // INTERFACE
59 
60  // INIT BLACKBOARD
62 
63  // INIT ON SPAWN
66 
67  // CLIENTFIELDS
69  {
70  ‪clientfield::register( "actor", ‪FURY_DAMAGE_CLIENTFIELD, ‪VERSION_DLC4, GetMinBitCountForNum(7), "counter" );
75  }
76 }
77 
79 {
80  // APOTHICON JUKE BEHAVIOR
81  ‪BT_REGISTER_API( "apothiconCanJuke", &‪apothiconCanJuke );
82  ‪BT_REGISTER_API( "apothiconJukeInit", &‪apothiconJukeInit );
83  ‪BT_REGISTER_API( "apothiconPreemptiveJukeService", &‪apothiconPreemptiveJukeService );
84  ‪BT_REGISTER_API( "apothiconPreemptiveJukePending", &‪apothiconPreemptiveJukePending );
85  ‪BT_REGISTER_API( "apothiconPreemptiveJukeDone", &‪apothiconPreemptiveJukeDone );
86 
87  // APOTHICON MOVEMENT
88  ‪BT_REGISTER_API( "apothiconMoveStart", &‪apothiconMoveStart );
89  ‪BT_REGISTER_API( "apothiconMoveUpdate", &‪apothiconMoveUpdate );
90 
91  // APOTHICON MELEE/BAMF MELEE BEHAVIOR
92  ‪BT_REGISTER_API( "apothiconCanMeleeAttack", &‪apothiconCanMeleeAttack );
93  ‪BT_REGISTER_API( "apothiconShouldMeleeCondition", &‪apothiconShouldMeleeCondition );
94  ‪BT_REGISTER_API( "apothiconCanBamf", &‪apothiconCanBamf );
95  ‪BT_REGISTER_API( "apothiconCanBamfAfterJuke", &‪apothiconCanBamfAfterJuke );
96  ‪BT_REGISTER_API( "apothiconBamfInit", &‪apothiconBamfInit );
97 
98  // TAUNT BEHAVIOR
99  ‪BT_REGISTER_API( "apothiconShouldTauntAtPlayer", &‪apothiconShouldTauntAtPlayer );
100  ‪BT_REGISTER_API( "apothiconTauntAtPlayerEvent", &‪apothiconTauntAtPlayerEvent );
101 
102  // APOTHICON FURIOUS MODE
103  ‪BT_REGISTER_API( "apothiconFuriousModeInit", &‪apothiconFuriousModeInit );
104 
105  // APOTHICON KNOCKDOWN
106  ‪BT_REGISTER_API( "apothiconKnockdownService", &‪apothiconKnockdownService );
107  ‪BT_REGISTER_API( "apothiconDeathStart", &‪apothiconDeathStart );
108  ‪BT_REGISTER_API( "apothiconDeathTerminate", &‪apothiconDeathTerminate );
109 
110 
111  // APOTHICON MOCOMPS
115 
116  // APOTHICON NOTETRACKS
122 }
123 
125 {
126  // CREATE BLACKBOARD
128 
129  // APOTHICON SPECIFIC BLACKBOARD
133  ‪BB_REGISTER_ATTRIBUTE( ‪VARIANT_TYPE, 0, undefined );
134 
135  // USE UTILITY BLACKBOARD
137 
138  // CREATE INTERFACE
140 
141  // REGISTER ANIMSCRIPTED CALLBACK
142  self.___ArchetypeOnAnimscriptedCallback = &‪ApothiconFuryOnAnimscriptedCallback;
143 
144  // ENABLE DEBUGGING IN ODYSSEY
146 }
147 
148 function private ‪ApothiconFurySpawnSetup()
149 {
150  self.entityRadius = ‪FURY_RADIUS;
151 
152  // juking
153  self.jukeMaxDistance = ‪FURY_JUKE_MAX_DIST;
154 
155  // no need to update sight, slight increase in performance
156  self.updateSight = false;
157 
158  // To not appear floaty when on the sloped surfaces
159  self AllowPitchAngle(1);
160  self SetPitchOrient();
161 
162  // dont avoid anyone
163  self PushActors( true );
164 
165  // no automatic ragdoll from collision
166  self.skipAutoRagdoll = true;
167 
168  // damage death callback
171 
172  // zigzag setup
173  self.zigzag_distance_min = ‪FURY_ZIGZAG_MIN;
174  self.zigzag_distance_max = ‪FURY_ZIGZAG_MAX;
175 
176  // furious mode
177  self.isFurious = false;
178  self.furiousLevel = 0;
179  self.nextBamfMeleeTime = GetTime();
180 
181  self.nextJukeTime = GetTime();
182  self.nextPreemptiveJukeAds = RandomFloatRange( 0.7, 0.95 );
183 
184  // choose a random variant type for movement and pain animations
186 }
187 
188 function private ‪ApothiconFuryOnAnimscriptedCallback( entity )
189 {
190  // UNREGISTER THE BLACKBOARD
191  entity.__blackboard = undefined;
192 
193  // REREGISTER BLACKBOARD
195 }
196 
197 // APOTHICON GENERIC NOTETRACKS
198 function ‪apothiconDeathDissolve( entity )
199 {
200  if( entity.archetype != ‪ARCHETYPE_APOTHICON_FURY )
201  return;
202 
203  a_zombies = GetAIArchetypeArray( ‪ARCHETYPE_ZOMBIE );
204 
205  a_filtered_zombies = array::filter( a_zombies, false, &‪apothiconZombieEligibleForKnockdown, entity, entity.origin );
206 
207  if( a_filtered_zombies.size > 0 )
208  {
209  foreach( zombie in a_filtered_zombies )
210  {
211  ‪apothiconKnockdownZombie( entity, zombie );
212  }
213  }
214 }
215 
216 function ‪apothiconDeathDissolved( entity )
217 {
218 
219 }
220 
221 // APOTHICON MOCOMPS
222 function private ‪mocompApothiconFuryTeleportInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
223 {
224  entity OrientMode( "face angle", entity.angles[1] );
225  entity SetRepairPaths( false );
226 
228 
229  if( locomotionSpeed == ‪LOCOMOTION_SPEED_WALK )
230  rate = 1.6;
231  else
232  rate = 2;
233 
234  entity ASMSetAnimationRate( rate );
235 
236  Assert( IsDefined( entity.traverseEndNode ) );
237 
238  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP, false );
239 
240  entity NotSolid();
241  entity.blockingPain = true;
242  entity.useGoalAnimWeight = true;
243  entity.bgbIgnoreFearInHeadlights = true;
244 }
245 
246 function private ‪mocompApothiconFuryTeleportTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
247 {
248  if( !IsDefined(entity.traverseEndNode) )
249  {
250  return;
251  }
252 
253  entity ForceTeleport( entity.traverseEndNode.origin, entity.angles );
254  entity ASMSetAnimationRate( 1 );
255  entity Show();
256  entity Solid();
257  entity.blockingPain = false;
258  entity.useGoalAnimWeight = false;
259  entity.bgbIgnoreFearInHeadlights = false;
260 }
261 
263 {
270  var ‪enemy;
271 
273  {
274  ‪adjustMentStarted = false;
275  ‪reAdjustmentStarted = false;
276  }
277 }
278 
279 class AnimationAdjustmentInfoXY
280 {
281  var ‪startTime;
284  var ‪xyDirection; // normalized
286 
288  {
289  ‪adjustMentStarted = false;
290  }
291 }
292 
293 function ‪mocompApothiconFuryJukeInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
294 {
295  entity.isJuking = true;
296 
297  if( IsDefined( entity.jukeInfo ) )
298  entity OrientMode( "face angle", entity.jukeInfo.jukeStartAngles );
299  else
300  entity OrientMode( "face angle", entity.angles[1] );
301 
302  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP, true );
303 
304  entity.usegoalanimweight = true;
305  entity.blockingPain = true;
306  entity PushActors( false );
307  entity.pushable = false;
308 
309  moveDeltaVector = GetMoveDelta( mocompAnim, 0, 1, entity );
310  landPos = entity LocalToWorldCoords( moveDeltaVector );
311 
312  velocity = entity GetVelocity();
313  predictedPos = entity.origin + ( velocity * 0.1 );
314 
315  /#
316  RecordCircle( landPos, 8, ‪BLUE, "Script", entity );
317  Record3DText( "" + Distance( predictedPos, landPos ), landPos, ‪BLUE, "Script" );
318  #/
319 
320  ‪landPosOnGround = entity.jukeInfo.landPosOnGround;
321  heightDiff = ( ‪landPosOnGround[2] - landPos[2] );
322 
323  /#
324  RecordCircle( ‪landPosOnGround, 8, ‪GREEN, "Script", entity );
325  RecordLine( landPos, ‪landPosOnGround, ‪GREEN, "Script", entity );
326  #/
327 
328  // start adjustment at this time
329  Assert( AnimHasNotetrack( mocompanim, ‪FURY_BAMF_NT_START ) );
330  ‪startTime = GetNotetrackTimes( mocompanim, ‪FURY_BAMF_NT_START )[0];
331  vectorToStartTime = GetMoveDelta( mocompanim, 0, ‪startTime, entity );
332  startPos = entity LocalToWorldCoords( vectorToStartTime );
333 
334  // stop adjustment at this time
335  Assert( AnimHasNotetrack( mocompanim, ‪FURY_BAMF_NT_STOP ) );
336  ‪stopTime = GetNotetrackTimes( mocompanim, ‪FURY_BAMF_NT_STOP )[0];
337  vectorToStopTime = GetMoveDelta( mocompanim, 0, ‪stopTime, entity );
338  stopPos = entity LocalToWorldCoords( vectorToStopTime );
339 
340  /#
341  RecordSphere( startPos, 3, ‪BLUE, "Script", entity );
342  RecordSphere( stopPos, 3, ‪BLUE, "Script", entity );
343  RecordLine( predictedPos, startPos, ‪BLUE, "Script", entity );
344  RecordLine( startPos, stopPos, ‪BLUE, "Script", entity );
345  RecordLine( stopPos, landPos, ‪BLUE, "Script", entity );
346  #/
347 
348  newStopPos = stopPos + ( 0, 0, heightDiff );
349 
350  /#
351  RecordLine( startPos, newStopPos, ‪YELLOW, "Script", entity );
352  RecordLine( newStopPos, ‪landPosOnGround, ‪YELLOW, "Script", entity );
353  RecordSphere( newStopPos, 3, ‪YELLOW, "Script", entity );
354  #/
355 
356  entity.AnimationAdjustmentInfoZ = undefined;
357  entity.AnimationAdjustmentInfoZ = new ‪AnimationAdjustmentInfoZ();
358  entity.AnimationAdjustmentInfoZ.startTime = ‪startTime;
359  entity.AnimationAdjustmentInfoZ.‪stopTime = ‪stopTime;
360  entity.AnimationAdjustmentInfoZ.enemy = entity.enemy;
361 
362  animLength = GetAnimLength( mocompanim ) * 1000;
363  ‪startTime = ‪startTime * animLength;
364  ‪stopTime = ‪stopTime * animLength;
365  ‪startTime = Floor( ‪startTime / 50 );
366  ‪stopTime = Floor( ‪stopTime / 50 );
367  adjustDuration = ‪stopTime - ‪startTime;
368 
369  entity.AnimationAdjustmentInfoZ.‪stepSize = ( heightDiff / adjustDuration );
370 
371  entity.AnimationAdjustmentInfoZ.landPosOnGround = ‪landPosOnGround;
372 
373  /#
374  if( heightDiff < 0 )
375  Record3DText( "-" + Distance( landPos, ‪landPosOnGround ) + ":" + entity.AnimationAdjustmentInfoZ.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
376  else
377  Record3DText( "+" + Distance( landPos, ‪landPosOnGround ) + ":" + entity.AnimationAdjustmentInfoZ.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
378  #/
379 }
380 
381 function ‪mocompApothiconFuryJukeUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
382 {
383  times = GetNotetrackTimes( mocompAnim, ‪FURY_BAMF_NT_STOP );
384 
385  if( times.size )
386  time = times[0];
387 
388  animTime = entity GetAnimTime( mocompanim );
389 
390  if( !entity.AnimationAdjustmentInfoZ.adjustMentStarted )
391  {
392  if( animTime >= entity.AnimationAdjustmentInfoZ.startTime )
393  {
394  entity.AnimationAdjustmentInfoZ.adjustMentStarted = true;
395  }
396  }
397 
398  if( entity.AnimationAdjustmentInfoZ.adjustMentStarted && animTime < entity.AnimationAdjustmentInfoZ.stopTime )
399  {
400  adjustedOrigin = entity.origin + ( 0, 0, entity.AnimationAdjustmentInfoZ.stepSize );
401  entity ForceTeleport( adjustedOrigin, entity.angles );
402  }
403  else
404  {
405  if( IsDefined( entity.enemy ) )
406  {
407  entity OrientMode( "face direction", entity.enemy.origin - entity.origin );
408  }
409  }
410 
411  /#RecordCircle( entity.AnimationAdjustmentInfoZ.landPosOnGround, 8, ‪GREEN, "Script", entity );#/
412 }
413 
414 function ‪mocompApothiconFuryJukeTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
415 {
416  entity.blockingPain = false;
417  entity Solid();
418  entity PushActors( true );
419  entity.isJuking = false;
420  entity.usegoalanimweight = false;
421  entity.pushable = true;
422 
423  entity.jukeInfo = undefined;
424 
425  /#RecordCircle( entity.AnimationAdjustmentInfoZ.landPosOnGround, 8, ‪GREEN, "Script", entity );#/
426 
427  if( IsDefined( entity.enemy ) )
428  {
429  entity OrientMode( "face direction", entity.enemy.origin - entity.origin );
430  }
431 }
432 
433 function private ‪RunBamfReAdjustmentAnalysis( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
434 {
435  assert( ‪IS_TRUE( entity.AnimationAdjustmentInfoZ.adjustMentStarted ) );
436 
437  if( ‪IS_TRUE( entity.AnimationAdjustmentInfoZ.reAdjustMentStarted ) )
438  return;
439 
440  reAdjustMentAnimTime = 0.45;
441  animTime = entity GetAnimTime( mocompanim );
442  const reAdjustmentDistThresholdSq = 1024; // 32*32
443 
444  // make sure that the current enemy is same as to when bamfing started
445  if( animTime >= reAdjustMentAnimTime && entity.enemy === entity.AnimationAdjustmentInfoZ.enemy )
446  {
447  meleeStartPosition = entity.AnimationAdjustmentInfoZ.landPosOnGround;
448 
449  if( IsDefined( entity.enemy.last_valid_position ) )
450  {
451  meleeEndPosition = entity.enemy.last_valid_position;
452  }
453  else
454  {
455  meleeEndPosition = entity.enemy.origin;
456 
457  enemyForwardDir = AnglesToForward( entity.enemy.angles );
458  newMeleeEndPosition = meleeEndPosition + ( enemyForwardDir * RandomIntRange( 30, 50 ) );
459  newMeleeEndPosition = GetClosestPointOnNavMesh( newMeleeEndPosition, 20, 50 );
460 
461  if( IsDefined( newMeleeEndPosition ) )
462  meleeEndPosition = newMeleeEndPosition;
463  }
464 
465  if( DistanceSquared( meleeStartPosition, meleeEndPosition ) < reAdjustmentDistThresholdSq )
466  return;
467 
468  if( !‪util::within_fov( meleeEndPosition, entity.enemy.angles, entity.origin, ‪FURY_BAMF_FOV ) )
469  return;
470 
471  if( !‪util::within_fov( meleeStartPosition, entity.angles, meleeEndPosition, ‪FURY_BAMF_FOV ) )
472  return;
473 
474  if( !IsPointOnNavMesh( meleeStartPosition, entity ) )
475  return;
476 
477  if( !IsPointOnNavMesh( meleeEndPosition, entity ) )
478  return;
479 
480  if( !TracePassedOnNavMesh( meleeStartPosition, meleeEndPosition, entity.entityRadius ) )
481  return;
482 
483  if( !entity FindPath( meleeStartPosition, meleeEndPosition ) )
484  return;
485 
486  landPos = entity.AnimationAdjustmentInfoZ.landPosOnGround;
487 
488  /#
489  RecordCircle( meleeEndPosition, 8, ‪CYAN, "Script", entity );
490  RecordCircle( landPos, 8, ‪BLUE, "Script", entity );
491  #/
492 
493  // Z Reajustment
494  zDiff = landPos[2] - meleeEndPosition[2];
495  traceStart = undefined;
496  traceEnd = undefined;
497 
498  if( zDiff < 0 )
499  {
500  // player is above, do a trace above
501  traceOffsetAbove = -zDiff + (30);
502  traceStart = meleeEndPosition + ( 0, 0, traceOffsetAbove );
503  traceEnd = meleeEndPosition + ( 0, 0, -70 );
504  }
505  else
506  {
507  traceOffsetBelow = -zDiff - 30 ;
508  traceStart = meleeEndPosition + ( 0, 0, 70 );
509  traceEnd = meleeEndPosition + ( 0, 0, traceOffsetBelow );
510  }
511 
512  ‪trace = GroundTrace( traceStart, traceEnd, false, entity, true, true );
513  ‪landPosOnGround = ‪trace[ "position" ];
514 
515  ‪landPosOnGround = GetClosestPointOnNavMesh( ‪landPosOnGround, 100, 50 );
516 
517  if( !IsDefined( ‪landPosOnGround ) )
518  return;
519 
520  /#
521  RecordCircle( ‪landPosOnGround, 8, ‪GREEN, "Script", entity );
522  RecordLine( landPos, ‪landPosOnGround, ‪GREEN, "Script", entity );
523  #/
524 
525  assert( IsDefined( entity.AnimationAdjustmentInfoZ ) );
526  ‪startTime = reAdjustMentAnimTime;
527  ‪stopTime = entity.AnimationAdjustmentInfoZ.stopTime;
528 
529  // Z 2nd adjustment
530  entity.AnimationAdjustmentInfoZ2 = new ‪AnimationAdjustmentInfoZ();
531  entity.AnimationAdjustmentInfoZ2.startTime = reAdjustMentAnimTime;
532  entity.AnimationAdjustmentInfoZ2.stopTime = ‪stopTime;
533  entity.AnimationAdjustmentInfoZ2.landPosOnGround = ‪landPosOnGround;
534 
535  animLength = GetAnimLength( mocompanim ) * 1000;
536  ‪startTime = ‪startTime * animLength;
537  ‪stopTime = ‪stopTime * animLength;
538  ‪startTime = Floor( ‪startTime / 50 );
539  ‪stopTime = Floor( ‪stopTime / 50 );
540  adjustDuration = ‪stopTime - ‪startTime;
541 
542  heightDiff = ( ‪landPosOnGround[2] - landPos[2] );
543  entity.AnimationAdjustmentInfoZ2.‪stepSize = ( heightDiff / adjustDuration );
544 
545  /#
546  if( heightDiff < 0 )
547  Record3DText( "- " + entity.AnimationAdjustmentInfoZ2.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
548  else
549  Record3DText( "+ " + entity.AnimationAdjustmentInfoZ2.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
550  #/
551 
552  // XY Reajustment (flattened Z)
553  meleeEndPosition = ( meleeEndPosition[0], meleeEndPosition[1], landPos[2] );
554  ‪xyDirection = VectorNormalize( meleeEndPosition - landPos );
555  xyDistance = Distance( meleeEndPosition, landPos );
556 
557  entity.AnimationAdjustmentInfoXY = new AnimationAdjustmentInfoXY();
558  entity.AnimationAdjustmentInfoXY.startTime = ‪startTime;
559  entity.AnimationAdjustmentInfoXY.‪stopTime = ‪stopTime;
560  entity.AnimationAdjustmentInfoXY.stepSize = ( xyDistance / adjustDuration );
561  entity.AnimationAdjustmentInfoXY.xyDirection = ‪xyDirection;
562  entity.AnimationAdjustmentInfoXY.adjustMentStarted = true;
563 
564  /#
565  Record3DText( "" + xyDistance + " (step:" + entity.AnimationAdjustmentInfoXY.stepSize + ")", meleeEndPosition, ‪BLUE, "Script" );
566  #/
567 
568  // Start Reajustment
569  entity.AnimationAdjustmentInfoZ.reAdjustMentStarted = true;
570  }
571 }
572 
573 function ‪mocompApothiconFuryBamfInit( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
574 {
575  assert( IsDefined( entity.enemy ) );
576 
577  entity.AnimationAdjustmentInfoZ = undefined;
578  entity.AnimationAdjustmentInfoZ2 = undefined;
579  entity.AnimationAdjustmentInfoXY = undefined;
580 
581  entity ClearPath();
582  entity PathMode( "dont move" ); // prevent pathfinding
583  entity.blockingPain = true;
584  entity.useGoalAnimWeight = true;
585  self PushActors( false );
586  entity.isBamfing = true;
587  entity.pushable = false;
588 
589  anglesToEnemy = ‪FLAT_ANGLES( VectorToAngles( entity.enemy.origin - entity.origin ) );
590  entity ForceTeleport( entity.origin, anglesToEnemy );
591  entity OrientMode( "face angle", anglesToEnemy[1] );
592  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP, true );
593 
594  moveDeltaVector = GetMoveDelta( mocompAnim, 0, 1, entity );
595  landPos = entity LocalToWorldCoords( moveDeltaVector );
596 
597  /#
598  RecordCircle( entity.enemy.origin, 8, ‪CYAN, "Script", entity );
599  RecordLine( landPos, entity.enemy.origin, ‪CYAN, "Script", entity );
600 
601  RecordCircle( landPos, 8, ‪BLUE, "Script", entity );
602  Record3DText( "" + Distance( entity.origin, landPos ), landPos, ‪BLUE, "Script" );
603  #/
604 
605  zDiff = entity.origin[2] - entity.enemy.origin[2];
606  traceStart = undefined;
607  traceEnd = undefined;
608 
609  if( zDiff < 0 )
610  {
611  // player is above, do a trace above
612  traceOffsetAbove = -zDiff + (30);
613  traceStart = landpos + ( 0, 0, traceOffsetAbove );
614  traceEnd = landPos + ( 0, 0, -70 );
615  }
616  else
617  {
618  traceOffsetBelow = -zDiff - 30 ;
619  traceStart = landpos + ( 0, 0, 70 );
620  traceEnd = landPos + ( 0, 0, traceOffsetBelow );
621  }
622 
623  ‪trace = GroundTrace( traceStart, traceEnd, false, entity, true, true );
624  ‪landPosOnGround = ‪trace[ "position" ];
625 
626  ‪landPosOnGround = GetClosestPointOnNavMesh( ‪landPosOnGround, 100, 25 );
627 
628  if( !IsDefined( ‪landPosOnGround ) )
629  ‪landPosOnGround = entity.enemy.origin;
630 
631  /#
632  RecordCircle( ‪landPosOnGround, 8, ‪GREEN, "Script", entity );
633  RecordLine( landPos, ‪landPosOnGround, ‪GREEN, "Script", entity );
634  #/
635 
636  heightDiff = ( ‪landPosOnGround[2] - landPos[2] );
637 
638  // start adjustment at this time
639  Assert( AnimHasNotetrack( mocompanim, ‪FURY_BAMF_NT_START ) );
640  ‪startTime = GetNotetrackTimes( mocompanim, ‪FURY_BAMF_NT_START )[0];
641  vectorToStartTime = GetMoveDelta( mocompanim, 0, ‪startTime, entity );
642  startPos = entity LocalToWorldCoords( vectorToStartTime );
643 
644  // stop adjustment at this time
645  Assert( AnimHasNotetrack( mocompanim, ‪FURY_BAMF_NT_STOP ) );
646  ‪stopTime = GetNotetrackTimes( mocompanim, ‪FURY_BAMF_NT_STOP )[0];
647  vectorToStopTime = GetMoveDelta( mocompanim, 0, ‪stopTime, entity );
648  stopPos = entity LocalToWorldCoords( vectorToStopTime );
649 
650  /#
651  RecordSphere( startPos, 3, ‪BLUE, "Script", entity );
652  RecordSphere( stopPos, 3, ‪BLUE, "Script", entity );
653  RecordLine( entity.origin, startPos, ‪BLUE, "Script", entity );
654  RecordLine( startPos, stopPos, ‪BLUE, "Script", entity );
655  RecordLine( stopPos, landPos, ‪BLUE, "Script", entity );
656  #/
657 
658  newStopPos = stopPos + ( 0, 0, heightDiff );
659 
660  /#
661  RecordLine( startPos, newStopPos, ‪GREEN, "Script", entity );
662  RecordLine( newStopPos, ‪landPosOnGround, ‪GREEN, "Script", entity );
663  RecordSphere( newStopPos, 3, ‪GREEN, "Script", entity );
664  #/
665 
666  entity.AnimationAdjustmentInfoZ = new ‪AnimationAdjustmentInfoZ();
667  entity.AnimationAdjustmentInfoZ.startTime = ‪startTime;
668  entity.AnimationAdjustmentInfoZ.‪stopTime = ‪stopTime;
669  entity.AnimationAdjustmentInfoZ.enemy = entity.enemy;
670 
671  animLength = GetAnimLength( mocompanim ) * 1000;
672  ‪startTime = ‪startTime * animLength;
673  ‪stopTime = ‪stopTime * animLength;
674  ‪startTime = Floor( ‪startTime / 50 );
675  ‪stopTime = Floor( ‪stopTime / 50 );
676  adjustDuration = ‪stopTime - ‪startTime;
677 
678  entity.AnimationAdjustmentInfoZ.‪stepSize = ( heightDiff / adjustDuration );
679 
680  entity.AnimationAdjustmentInfoZ.landPosOnGround = ‪landPosOnGround;
681 
682  /#
683  if( heightDiff < 0 )
684  Record3DText( "-" + Distance( landPos, ‪landPosOnGround ) + ":" + entity.AnimationAdjustmentInfoZ.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
685  else
686  Record3DText( "+" + Distance( landPos, ‪landPosOnGround ) + ":" + entity.AnimationAdjustmentInfoZ.stepSize + ":" + adjustDuration, ‪landPosOnGround, ‪ORANGE, "Script" );
687  #/
688 }
689 
690 function ‪mocompApothiconFuryBamfUpdate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
691 {
692  assert( IsDefined( entity.AnimationAdjustmentInfoZ ) );
693 
694  if( !IsDefined( entity.enemy ) )
695  return;
696 
697  animTime = entity GetAnimTime( mocompanim );
698 
699  if( !entity.AnimationAdjustmentInfoZ.adjustMentStarted )
700  {
701  if( animTime >= entity.AnimationAdjustmentInfoZ.startTime )
702  {
703  entity.AnimationAdjustmentInfoZ.adjustMentStarted = true;
704  }
705  }
706 
707  if( entity.AnimationAdjustmentInfoZ.adjustMentStarted && animTime < entity.AnimationAdjustmentInfoZ.stopTime )
708  {
709  // original Z adjustment
710  adjustedOrigin = entity.origin + ( 0, 0, entity.AnimationAdjustmentInfoZ.stepSize );
711 
712  ‪RunBamfReAdjustmentAnalysis( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration );
713 
714  if( ‪IS_TRUE( entity.AnimationAdjustmentInfoZ.reAdjustMentStarted ) )
715  {
716  // 2nd Z adjustment
717  if( IsDefined( entity.AnimationAdjustmentInfoZ2 ) )
718  {
719  adjustedOrigin = adjustedOrigin + ( 0, 0, entity.AnimationAdjustmentInfoZ2.stepSize );
720  }
721 
722  // XY adjustment
723  if( IsDefined( entity.AnimationAdjustmentInfoXY ) )
724  {
725  adjustedOrigin = adjustedOrigin + ( entity.AnimationAdjustmentInfoXY.xyDirection * entity.AnimationAdjustmentInfoXY.stepSize );
726  }
727  }
728 
729  entity ForceTeleport( adjustedOrigin, entity.angles );
730  }
731  else
732  {
733  if( IsDefined( entity.enemy ) )
734  {
735  entity OrientMode( "face direction", entity.enemy.origin - entity.origin );
736  }
737  }
738 }
739 
740 function ‪mocompApothiconFuryBamfTerminate( entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration )
741 {
742  entity PathMode( "move allowed" );
743  entity Solid();
744  entity Show();
745  entity.blockingPain = false;
746  entity.useGoalAnimWeight = false;
747 
748  entity OrientMode( "face angle", entity.angles[1] );
749  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS );
750  entity.isBamfing = false;
751  entity.pushable = true;
752  self PushActors( true );
753 
754  entity.jukeInfo = undefined;
755 
756  if( !IsPointOnNavMesh( entity.origin ) )
757  {
758  clampToNavmeshLocation = GetClosestPointOnNavMesh( entity.origin, 100, 25 );
759 
760  if( IsDefined( clampToNavmeshLocation ) )
761  {
762  entity ForceTeleport( clampToNavmeshLocation );
763  }
764  }
765 }
766 
767 // APOTHICON MELEE
768 function ‪apothiconCanMeleeAttack( entity )
769 {
770  return ( ‪apothiconCanBamf( entity ) || ‪apothiconShouldMeleeCondition( entity ) );
771 }
772 
773 function ‪apothiconShouldMeleeCondition( behaviorTreeEntity )
774 {
775  if( IsDefined( behaviorTreeEntity.enemyoverride ) && IsDefined( behaviorTreeEntity.enemyoverride[1] ) )
776  {
777  return false;
778  }
779 
780  if( !IsDefined( behaviortreeentity.enemy ) )
781  {
782  return false;
783  }
784 
785  if( IsDefined( behaviorTreeEntity.marked_for_death ) )
786  {
787  return false;
788  }
789 
790  if( ‪IS_TRUE( behaviorTreeEntity.ignoreMelee ) )
791  {
792  return false;
793  }
794 
795  if( DistanceSquared( behaviorTreeEntity.origin, behaviorTreeEntity.enemy.origin ) > ‪FURY_MELEE_DIST_SQ )
796  {
797  return false;
798  }
799 
800  yawToEnemy = AngleClamp180( behaviorTreeEntity.angles[ 1 ] - ‪GET_YAW( behaviorTreeEntity, behaviorTreeEntity.enemy.origin ) );
801  if( abs( yawToEnemy ) > ‪ZM_MELEE_YAW )
802  {
803  return false;
804  }
805 
806  return true;
807 }
808 
810 {
811  return ‪apothiconCanBamfInternal( entity );
812 }
813 
814 // APOTHICON BAMF MELEE
815 function ‪apothiconCanBamf( entity )
816 {
817  return ‪apothiconCanBamfInternal( entity );
818 }
819 
820 function ‪apothiconCanBamfInternal( entity, bamfAfterJuke = false )
821 {
822  if( !‪ai::GetAiAttribute( entity, "can_bamf" ) )
823  return false;
824 
825  if( !IsDefined( entity.enemy ) )
826  return false;
827 
828  if( !IsPlayer( entity.enemy ) )
829  return false;
830 
831  if( ‪IS_TRUE( entity.juking ) )
832  return false;
833 
834  if( ‪IS_TRUE( entity.isBamfing ) )
835  return false;
836 
837  if( !bamfAfterJuke )
838  {
839  if( GetTime() < entity.nextBamfMeleeTime )
840  return false;
841 
842  jukeEvents = ‪Blackboard::GetBlackboardEvents( "apothicon_fury_bamf" );
843  tooCloseJukeDistanceSqr = ‪SQR( ‪FURY_TOO_CLOSE_TO_BAMF_DIST );
844 
845  foreach ( event in jukeEvents )
846  {
847  if ( Distance2DSquared( entity.origin, event.data.origin ) <= tooCloseJukeDistanceSqr )
848  {
849  return false;
850  }
851  }
852  }
853 
854  assert( IsDefined( entity.enemy ) );
855  enemyOrigin = entity.enemy.origin;
856 
857  apothiconFurys = GetAIArchetypeArray( ‪ARCHETYPE_APOTHICON_FURY );
858  furiesNearPlayer = 0;
859 
860  foreach( apothiconFury in apothiconFurys )
861  {
862  if( DistanceSquared( enemyOrigin, apothiconFury.origin ) <= ( 80 * 80 ) )
863  furiesNearPlayer++;
864  }
865 
866  if( furiesNearPlayer >= 4 )
867  return false;
868 
869  distanceToEnemySq = DistanceSquared( enemyOrigin, entity.origin );
870  distanceMinThresholdSq = ‪SQR( ‪FURY_BAMF_MELEE_DIST_MIN );
871 
872  if( bamfAfterJuke )
873  distanceMinThresholdSq = ‪SQR( ‪FURY_BAMF_MELEE_DIST_MIN_AFTER_JUKE );
874 
875  if( distanceToEnemySq > distanceMinThresholdSq && distanceToEnemySq < ‪SQR( ‪FURY_BAMF_MELEE_DIST_MAX ) )
876  {
877  if( !‪util::within_fov( enemyOrigin, entity.enemy.angles, entity.origin, ‪FURY_BAMF_FOV ) )
878  return false;
879 
880  if( !‪util::within_fov( entity.origin, entity.angles, enemyOrigin, ‪FURY_BAMF_FOV ) )
881  return false;
882 
883  meleeStartPosition = entity.origin;
884  meleeEndPosition = enemyOrigin;
885 
886  if( !IsPointOnNavMesh( meleeStartPosition, entity ) )
887  return false;
888 
889  if( !IsPointOnNavMesh( meleeEndPosition, entity ) )
890  return false;
891 
892  if( !TracePassedOnNavMesh( meleeStartPosition, meleeEndPosition, entity.entityRadius ) )
893  return false;
894 
895  if( !entity FindPath( meleeStartPosition, meleeEndPosition ) )
896  return false;
897 
898  return true;
899  }
900 
901  return false;
902 }
903 
904 function ‪getBamfMeleeDistance( entity )
905 {
906  distanceToEnemy = Distance( self.enemy.origin, self.origin );
907 
908  return distanceToEnemy;
909 }
910 
911 function ‪apothiconBamfInit( entity )
912 {
913  ‪jukeInfo = SpawnStruct();
914  ‪jukeInfo.origin = entity.origin;
915  ‪jukeInfo.entity = entity;
916 
918 
919  if( IsDefined( level.nextBamfMeleeTimeMin ) && IsDefined( level.nextBamfMeleeTimeMax ) )
920  {
921  entity.nextBamfMeleeTime = GetTime() + RandomFloatRange( level.nextBamfMeleeTimeMin, level.nextBamfMeleeTimeMax );
922  }
923  else
924  {
925  entity.nextBamfMeleeTime = GetTime() + RandomFloatRange( ‪FURY_BAMF_COOLDOWN_MIN, ‪FURY_BAMF_COOLDOWN_MAX );
926  }
927 }
928 
929 // TAUNT BEHAVIOR
931 {
932  tauntEvents = ‪Blackboard::GetBlackboardEvents( "apothicon_fury_taunt" );
933 
934  if( IsDefined( tauntevents ) && tauntevents.size )
935  return false;
936 
937  return true;
938 }
939 
941 {
942  ‪jukeInfo = SpawnStruct();
943  ‪jukeInfo.origin = entity.origin;
944  ‪jukeInfo.entity = entity;
945 
947 }
948 
950 {
951  if( IsDefined( self.damage_direction ) )
952  {
953  return self.damage_direction;
954  }
956 }
957 
958 function ‪apothiconBamfLand( entity )
959 {
960  if( entity.archetype != ‪ARCHETYPE_APOTHICON_FURY )
961  return;
962 
963  if( IsDefined( entity.enemy ) )
964  {
965  entity OrientMode( "face direction", entity.enemy.origin - entity.origin );
966  }
967 
969 
970  if( IsDefined( entity.enemy ) && IsPlayer(entity.enemy) && DistanceSquared( entity.enemy.origin, entity.origin ) <= ‪SQR( ‪FURY_BAMF_MELEE_RANGE ) )
971  {
972  entity.enemy DoDamage( 25, entity.origin, entity, entity, undefined, "MOD_MELEE" );
973  }
974 
975  PhysicsExplosionSphere( entity.origin, ‪FURY_BAMF_MELEE_DAMAGE_MAX, ‪FURY_BAMF_MELEE_DAMAGE_MIN, 10 );
976 }
977 
978 function ‪apothiconMoveStart( entity )
979 {
980  entity.moveTime = GetTime();
981  entity.moveOrigin = entity.origin;
982 }
983 
984 function ‪apothiconMoveUpdate(entity)
985 {
986  if ( IsDefined( entity.move_anim_end_time ) && ( GetTime() >= entity.move_anim_end_time ) )
987  {
988  entity.move_anim_end_time = undefined;
989  return;
990  }
991 
992  if ( !‪IS_TRUE( entity.missingLegs ) && ( GetTime() - entity.moveTime > ‪ZM_MOVE_TIME ) )
993  {
994  distSq = Distance2DSquared( entity.origin, entity.moveOrigin );
995 
996  if ( distSq < ‪ZM_MOVE_DIST_SQ )
997  {
998  if ( IsDefined( entity.cant_move_cb ) )
999  {
1000  entity [[ entity.cant_move_cb ]]();
1001  }
1002  }
1003  else
1004  {
1005  entity.cant_move = false;
1006  }
1007 
1008  entity.moveTime = GetTime();
1009  entity.moveOrigin = entity.origin;
1010  }
1011 }
1012 
1013 // APOTHICON KNOCKDOWN
1015 {
1016  if( ‪IS_TRUE(entity.isJuking) )
1017  return;
1018 
1019  if( ‪IS_TRUE(entity.isBamfing) )
1020  return;
1021 
1022  velocity = entity GetVelocity();
1023  predict_time = 0.5;
1024  predicted_pos = entity.origin + ( velocity * predict_time );
1025  move_dist_sq = DistanceSquared( predicted_pos, entity.origin );
1026  speed = move_dist_sq / predict_time;
1027 
1028  if( speed >= 10 )
1029  {
1030  a_zombies = GetAIArchetypeArray( ‪ARCHETYPE_ZOMBIE );
1031 
1032  a_filtered_zombies = array::filter( a_zombies, false, &‪apothiconZombieEligibleForKnockdown, entity, predicted_pos );
1033 
1034  if( a_filtered_zombies.size > 0 )
1035  {
1036  foreach( zombie in a_filtered_zombies )
1037  {
1038  ‪apothiconKnockdownZombie( entity, zombie );
1039  }
1040  }
1041  }
1042 }
1043 
1044 function private ‪apothiconZombieEligibleForKnockdown( zombie, thrasher, predicted_pos )
1045 {
1046  if( zombie.knockdown === true )
1047  {
1048  return false;
1049  }
1050 
1051  if( ‪IS_TRUE( zombie.missingLegs ) )
1052  {
1053  return false;
1054  }
1055 
1056  knockdown_dist_sq = 48*48;
1057  dist_sq = DistanceSquared( predicted_pos, zombie.origin );
1058 
1059  if( dist_sq > knockdown_dist_sq )
1060  {
1061  return false;
1062  }
1063 
1064  origin = thrasher.origin;
1065 
1066  facing_vec = AnglesToForward( thrasher.angles );
1067  enemy_vec = zombie.origin - origin;
1068 
1069  enemy_yaw_vec = (enemy_vec[0], enemy_vec[1], 0);
1070  facing_yaw_vec = (facing_vec[0], facing_vec[1], 0);
1071 
1072  enemy_yaw_vec = VectorNormalize( enemy_yaw_vec );
1073  facing_yaw_vec = VectorNormalize( facing_yaw_vec );
1074 
1075  enemy_dot = VectorDot( facing_yaw_vec, enemy_yaw_vec );
1076 
1077  if( enemy_dot < 0 )// is enemy behind thrasher
1078  {
1079  return false;
1080  }
1081 
1082  return true;
1083 
1084 }
1085 
1086 function ‪apothiconKnockdownZombie( entity, zombie )
1087 {
1088  zombie.knockdown = true;
1089  zombie.knockdown_type = ‪KNOCKDOWN_SHOVED;
1090  zombie_to_thrasher = entity.origin - zombie.origin;
1091  zombie_to_thrasher_2d = VectorNormalize( ( zombie_to_thrasher[0], zombie_to_thrasher[1], 0 ) );
1092 
1093  zombie_forward = AnglesToForward( zombie.angles );
1094  zombie_forward_2d = VectorNormalize( ( zombie_forward[0], zombie_forward[1], 0 ) );
1095 
1096  zombie_right = AnglesToRight( zombie.angles );
1097  zombie_right_2d = VectorNormalize( ( zombie_right[0], zombie_right[1], 0 ) );
1098 
1099  dot = VectorDot( zombie_to_thrasher_2d, zombie_forward_2d );
1100 
1101  if( dot >= 0.5 )
1102  {
1103  zombie.knockdown_direction = "front";
1104  zombie.getup_direction = ‪GETUP_BACK;
1105  }
1106  else if ( dot < 0.5 && dot > -0.5 )
1107  {
1108  dot = VectorDot( zombie_to_thrasher_2d, zombie_right_2d );
1109  if( dot > 0 )
1110  {
1111  zombie.knockdown_direction = "right";
1112 
1113  if ( ‪math::cointoss() )
1114  {
1115  zombie.getup_direction = ‪GETUP_BACK;
1116  }
1117  else
1118  {
1119  zombie.getup_direction = ‪GETUP_BELLY;
1120  }
1121  }
1122  else
1123  {
1124  zombie.knockdown_direction = "left";
1125  zombie.getup_direction = ‪GETUP_BELLY;
1126  }
1127  }
1128  else
1129  {
1130  zombie.knockdown_direction = "back";
1131  zombie.getup_direction = ‪GETUP_BELLY;
1132  }
1133 }
1134 
1135 // APOTHICON FURIOUS MODE
1137 {
1138  if( !‪ai::GetAiAttribute( entity, "can_be_furious" ) )
1139  return false;
1140 
1141  if( ‪IS_TRUE( entity.isFurious ) )
1142  return false;
1143 
1144  apothiconFurys = GetAIArchetypeArray( ‪ARCHETYPE_APOTHICON_FURY );
1145 
1146  count = 0;
1147 
1148  foreach( apothiconFury in apothiconFurys )
1149  {
1150  if( ‪IS_TRUE( apothiconFury.isFurious ) )
1151  count++;
1152  }
1153 
1154  if( count >= ‪FURY_FURIOUS_MAX_AI )
1155  return false;
1156 
1157  furiousEvents = ‪Blackboard::GetBlackboardEvents( "apothicon_furious_mode" );
1158 
1159  if( !furiousEvents.size && entity.furiousLevel >= ‪FURY_FURIOUS_LEVEL_THRESHOLD )
1160  return true;
1161 
1162  return false;
1163 }
1164 
1166 {
1168  return;
1170  furiousInfo = SpawnStruct();
1171  furiousInfo.origin = entity.origin;
1172  furiousInfo.entity = entity;
1173 
1174  ‪Blackboard::AddBlackboardEvent( "apothicon_furious_mode", furiousInfo, RandomIntRange( ‪FURY_FURIOUS_GLOBAL_DELAY_MIN_MSEC, ‪FURY_FURIOUS_GLOBAL_DELAY_MAX_MSEC ) );
1175 
1176  entity PushActors(false);
1177 
1178  entity.isFurious = true;
1179  //entity ASMSetAnimationRate( 1.3 );
1181 
1183 
1184  entity.health = entity.health * 2;
1185 }
1186 
1187 // APOTHICON JUKE BEHAVIOR
1189 {
1194 }
1195 
1197 {
1198  if( !‪IS_TRUE( entity.isFurious ) )
1199  {
1200  return false;
1201  }
1202 
1203  if ( IsDefined( entity.nextJukeTime ) && entity.nextJukeTime > GetTime() )
1204  {
1205  return false;
1206  }
1207 
1208  if ( IsDefined( entity.enemy ) )
1209  {
1210  if ( !IsPlayer( entity.enemy ) )
1211  {
1212  return false;
1213  }
1214 
1215  if ( entity.enemy PlayerADS() < entity.nextPreemptiveJukeAds )
1216  {
1217  return false;
1218  }
1219  }
1220 
1221  if( ‪apothiconCanJuke( entity ) )
1222  {
1223  entity.apothiconPreemptiveJuke = true;
1224  }
1225 }
1226 
1228 {
1229  return ‪IS_TRUE( entity.apothiconPreemptiveJuke );
1230 }
1231 
1233 {
1234  entity.apothiconPreemptiveJuke = false;
1235 }
1236 
1237 function ‪apothiconCanJuke( entity )
1238 {
1239  if( !‪ai::GetAiAttribute( entity, "can_juke" ) )
1240  return false;
1241 
1242  if( !IsDefined( entity.enemy ) || !IsPlayer(entity.enemy) )
1243  return false;
1244 
1245  if( ‪IS_TRUE( entity.isJuking ) )
1246  {
1247  return false;
1248  }
1249 
1250  if( ‪IS_TRUE( entity.apothiconPreemptiveJuke ) )
1251  {
1252  return true;
1253  }
1254 
1255  if( IsDefined( entity.nextJukeTime ) && GetTime() < entity.nextJukeTime )
1256  {
1257  return false;
1258  }
1259 
1260  jukeEvents = ‪Blackboard::GetBlackboardEvents( "apothicon_fury_juke" );
1261  tooCloseJukeDistanceSqr = ‪SQR( ‪FURY_TOO_CLOSE_TO_JUKE_DIST );
1262 
1263  foreach ( event in jukeEvents )
1264  {
1265  if ( Distance2DSquared( entity.origin, event.data.origin ) <= tooCloseJukeDistanceSqr )
1266  {
1267  return false;
1268  }
1269  }
1270 
1271  if ( Distance2DSquared( entity.origin, entity.enemy.origin ) < ‪SQR( ‪FURY_TOO_CLOSE_TO_JUKE_DIST ) )
1272  {
1273  return false;
1274  }
1275 
1276  if( !‪util::within_fov( entity.enemy.origin, entity.enemy.angles, entity.origin, ‪FURY_BAMF_FOV ) )
1277  return false;
1278 
1279  if( !‪util::within_fov( entity.origin, entity.angles, entity.enemy.origin, ‪FURY_BAMF_FOV ) )
1280  return false;
1281 
1282  if ( IsDefined( entity.jukeMaxDistance ) && IsDefined( entity.enemy ) )
1283  {
1284  maxDistSquared = entity.jukeMaxDistance * entity.jukeMaxDistance;
1285 
1286  if ( Distance2DSquared( entity.origin, entity.enemy.origin ) > maxDistSquared )
1287  {
1288  return false;
1289  }
1290  }
1291 
1292  ‪jukeInfo = ‪calculateJukeInfo( entity );
1293 
1294  if( IsDefined( ‪jukeInfo ) )
1295  {
1296  return true;
1297  }
1298 
1299  return false;
1300 }
1301 
1302 function ‪apothiconJukeInit( entity )
1303 {
1304  ‪jukeInfo = ‪calculateJukeInfo( entity );
1305  assert( IsDefined( ‪jukeInfo ) );
1306 
1309 
1310  entity ClearPath();
1311  entity notify( "bhtn_action_notify", "apothicon_fury_juke" );
1312 
1313  ‪jukeInfo = SpawnStruct();
1314  ‪jukeInfo.origin = entity.origin;
1315  ‪jukeInfo.entity = entity;
1316 
1318 
1319  entity.nextPreemptiveJukeAds = RandomFloatRange( 0.6, 0.8 );
1320 
1321  if( IsDefined( level.nextjukeMeleeTimeMin ) && IsDefined( level.nextjukeMeleeTimeMax ) )
1322  {
1323  entity.nextjukeMeleeTime = GetTime() + RandomFloatRange( level.nextjukeMeleeTimeMin, level.nextjukeMeleeTimeMax );
1324  }
1325  else
1326  {
1327  entity.nextJukeTime = GetTime() + RandomFloatRange( ‪FURY_JUKE_COOLDOWN_MIN, ‪FURY_JUKE_COOLDOWN_MAX );
1328  }
1329 }
1330 
1331 function ‪validateJuke( entity, entityRadius, jukeVector )
1332 {
1333  velocity = entity GetVelocity();
1334  predictedPos = entity.origin + ( velocity * 0.1 );
1335  jukeLandPos = predictedPos + jukeVector;
1336 
1337  if( !IsDefined( jukeLandPos ) )
1338  return undefined;
1339 
1340  traceStart = jukeLandPos + ( 0, 0, 70 );
1341  traceEnd = jukeLandPos + ( 0, 0, -70 );
1342 
1343  ‪trace = GroundTrace( traceStart, traceEnd, false, entity, true, true );
1344  ‪landPosOnGround = ‪trace[ "position" ];
1345 
1346  if( !IsDefined( ‪landPosOnGround ) )
1347  return undefined;
1348 
1349  if( !IsPointOnNavMesh( ‪landPosOnGround ) )
1350  return undefined;
1351 
1352  /#RecordLine( entity.origin, predictedPos, ‪GREEN, "Script", entity );#/
1353  /#RecordSphere( jukeLandPos, 2, ‪RED, "Script", entity );#/
1354  /#RecordLine( predictedPos, jukeLandPos, ‪RED, "Script", entity );#/
1355 
1356  if( IsPointOnNavMesh( ‪landPosOnGround, ( entity.entityRadius * 2.5 ) ) && TracePassedOnNavMesh( predictedPos, ‪landPosOnGround, entity.entityRadius ) )
1357  {
1358  if( !entity IsPosInClaimedLocation( ‪landPosOnGround ) && entity MayMoveFromPointToPoint( predictedPos, ‪landPosOnGround, false, false ) )
1359  {
1360  /#RecordSphere( ‪landPosOnGround, 2, ‪GREEN, "Script", entity );#/
1361  /#RecordLine( predictedPos, ‪landPosOnGround, ‪GREEN, "Script", entity );#/
1362 
1363  return ‪landPosOnGround;
1364  }
1365  }
1366 
1367  return undefined;
1368 }
1369 
1370 function private ‪getJukeVector( entity, jukeAnimAlias )
1371 {
1372  jukeAnim = entity AnimMappingSearch( IString( jukeAnimAlias ) );
1373  localDeltaVector = GetMoveDelta( jukeAnim, 0, 1, entity );
1374  endPoint = entity LocalToWorldCoords( localDeltaVector );
1375 
1376  return ( endpoint - entity.origin );
1377 }
1378 
1379 function private ‪calculateJukeInfo( entity )
1380 {
1381  if( IsDefined( entity.jukeInfo ) )
1382  return entity.jukeInfo;
1383 
1384  // favor forward jukes if its gets away from shooting direction
1385  directionToEnemy = VectorNormalize( entity.enemy.origin - entity.origin );
1386  forwardDir = AnglesToForward( entity.angles );
1387 
1388  possibleJukes = [];
1389  jukeValidDistanceType = [];
1390  entityRadius = entity.entityRadius;
1391 
1392  // JUKE - LEFT
1393  jukeVector = ‪getJukeVector( entity, "anim_zombie_juke_left_long" );
1394  ‪landPosOnGround = ‪validateJuke( entity, entityRadius, jukeVector );
1395 
1396  if( IsDefined( ‪landPosOnGround ) )
1397  {
1398  ‪jukeInfo = new ‪jukeInfo();
1399  ‪jukeInfo.‪jukeDirection = "left";
1402 
1403  ‪ARRAY_ADD( possibleJukes, ‪jukeInfo );
1404  }
1405 
1406  // JUKE - RIGHT
1407  jukeVector = ‪getJukeVector( entity, "anim_zombie_juke_right_long" );
1408  ‪landPosOnGround = ‪validateJuke( entity, entityRadius, jukeVector );
1409 
1410  if( IsDefined( ‪landPosOnGround ) )
1411  {
1412  ‪jukeInfo = new ‪jukeInfo();
1413  ‪jukeInfo.‪jukeDirection = "right";
1416 
1417  ‪ARRAY_ADD( possibleJukes, ‪jukeInfo );
1418  }
1419 
1420  // DIAGONAL JUKE - LEFT
1421  jukeVector = ‪getJukeVector( entity, "anim_zombie_juke_left_front_long" );
1422  ‪landPosOnGround = ‪validateJuke( entity, entityRadius, jukeVector );
1423 
1424  if( IsDefined( ‪landPosOnGround ) )
1425  {
1426  ‪jukeInfo = new ‪jukeInfo();
1427  ‪jukeInfo.‪jukeDirection = "left_front";
1430 
1431  ‪ARRAY_ADD( possibleJukes, ‪jukeInfo );
1432  }
1433 
1434  // DIAGONAL JUKE - RIGHT
1435  jukeVector = ‪getJukeVector( entity, "anim_zombie_juke_right_front_long" );
1436  ‪landPosOnGround = ‪validateJuke( entity, entityRadius, jukeVector );
1437 
1438  if( IsDefined( ‪landPosOnGround ) )
1439  {
1440  ‪jukeInfo = new ‪jukeInfo();
1441  ‪jukeInfo.‪jukeDirection = "right_front";
1444 
1445  ‪ARRAY_ADD( possibleJukes, ‪jukeInfo );
1446  }
1447 
1448  if( possibleJukes.size )
1449  {
1450  ‪jukeInfo = array::random( possibleJukes );
1451 
1452  ‪jukeInfo.‪jukeStartAngles = entity.angles;
1453 
1454  entity.lastJukeInfoUpdateTime = GetTime();
1455  entity.jukeInfo = ‪jukeInfo;
1456 
1457  return ‪jukeInfo;
1458  }
1459 
1460  return undefined;
1461 }
1462 
1463 // APOTHICON NOTETRACKS
1464 function ‪apothiconBamfOut( entity )
1465 {
1466  if( entity.archetype != ‪ARCHETYPE_APOTHICON_FURY )
1467  return;
1468 
1469  entity Ghost();
1470  entity NotSolid();
1471 
1473 
1474  a_zombies = GetAIArchetypeArray( ‪ARCHETYPE_ZOMBIE );
1475 
1476  a_filtered_zombies = array::filter( a_zombies, false, &‪apothiconZombieEligibleForKnockdown, entity, entity.origin );
1477 
1478  if( a_filtered_zombies.size > 0 )
1479  {
1480  foreach( zombie in a_filtered_zombies )
1481  {
1482  ‪apothiconKnockdownZombie( entity, zombie );
1483  }
1484  }
1485 }
1486 
1487 function ‪apothiconBamfIn( entity )
1488 {
1489  if( entity.archetype != ‪ARCHETYPE_APOTHICON_FURY )
1490  return;
1491 
1492  if( IsDefined( entity.traverseEndNode ) )
1493  {
1494  entity ForceTeleport( entity.traverseEndNode.origin, entity.angles );
1495 
1496  // in case if this AI is furious, and bamfing, then we need to avoid any issues
1497  entity Unlink();
1498  entity.isTraveling = false;
1499  entity notify( "travel_complete" );
1500 
1501  entity SetRepairPaths( true );
1502 
1503  entity.blockingPain = false;
1504  entity.useGoalAnimWeight = false;
1505  entity.bgbIgnoreFearInHeadlights = false;
1506 
1507  entity ASMSetAnimationRate( 1 );
1508  entity FinishTraversal();
1509  entity AnimMode( ‪AI_ANIM_USE_BOTH_DELTAS, true );
1510  }
1511 
1512  entity Show();
1513  entity Solid();
1514 
1516 
1517  a_zombies = GetAIArchetypeArray( ‪ARCHETYPE_ZOMBIE );
1518 
1519  a_filtered_zombies = array::filter( a_zombies, false, &‪apothiconZombieEligibleForKnockdown, entity, entity.origin );
1520 
1521  if( a_filtered_zombies.size > 0 )
1522  {
1523  foreach( zombie in a_filtered_zombies )
1524  {
1525  ‪apothiconKnockdownZombie( entity, zombie );
1526  }
1527  }
1528 }
1529 
1530 function ‪apothiconDeathStart( entity )
1531 {
1532  entity SetModel( ‪FURY_DEATH_MODEL_SWAP );
1534  entity NotSolid();
1535 }
1536 
1537 function ‪apothiconDeathTerminate( entity )
1538 {
1539 
1540 }
1541 
1542 function ‪apothiconDamageClientFieldUpdate( entity, sHitLoc )
1543 {
1544  ‪increment = 0;
1545 
1546  if( ‪IS_HITLOC_HEAD(sHitLoc) )
1547  {
1549  }
1550  else if( ‪IS_HITLOC_CHEST(sHitLoc) )
1551  {
1553  }
1554  else if( ‪IS_HITLOC_HIPS(sHitLoc) )
1555  {
1557  }
1558  else if( ‪IS_HITLOC_RIGHT_ARM(sHitLoc) )
1559  {
1561  }
1562  else if( ‪IS_HITLOC_LEFT_ARM(sHitLoc) )
1563  {
1565  }
1566  else if( ‪IS_HITLOC_LEFT_LEG(sHitLoc) )
1567  {
1569  }
1570  else
1571  {
1573  }
1574 
1576 }
1577 
1578 // APOTHICON DAMAGE CALLBACK
1579 function ‪apothiconDamageCallback( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
1580 {
1581  //Wait for the spawn to be complete
1582  if( !‪IS_TRUE( self.zombie_think_done ) )
1583  {
1584  return 0;
1585  }
1586 
1587  if( IsDefined( eAttacker ) && IsPlayer( eAttacker ) && IsDefined( sHitLoc ) )
1588  {
1589  ‪apothiconDamageClientFieldUpdate( self, sHitLoc );
1590  }
1591 
1592  if( IsDefined( sHitLoc ) )
1593  {
1594  if( !‪IS_TRUE( self.isFurious ) )
1595  {
1596  self.furiousLevel += ‪FURY_FURIOUS_LEVEL_STEP;
1597  }
1598  }
1599 
1601 
1602  return iDamage;
1603 }
1604 
1605 function ‪apothiconOnDeath( inflictor, attacker, ‪damage, meansOfDeath, weapon, dir, hitLoc, offsetTimes )
1606 {
1608 
1609  self NotSolid();
1610 
1611  return ‪damage;
1612 }
1613 
1614 // APOTHICON INTERFACE CALLBACKS
1615 #namespace ApothiconFuryBehaviorInterface;
1616 
1617 function ‪moveSpeedAttributeCallback( entity, attribute, oldValue, value )
1618 {
1619  if( ‪IS_TRUE( entity.isFurious ) )
1620  return;
1621 
1622  switch ( value )
1623  {
1624  case "walk":
1626  break;
1627  case "run":
1629  break;
1630  case "sprint":
1632  break;
1633  case "super_sprint":
1635  break;
1636  default:
1637  break;
1638  }
1639 }
1640 
‪FURY_TOO_CLOSE_TO_JUKE_DIST
‪#define FURY_TOO_CLOSE_TO_JUKE_DIST
Definition: archetype_apothicon_fury.gsh:12
‪IMPACT_L_ARM
‪#define IMPACT_L_ARM
Definition: archetype_apothicon_fury.gsh:94
‪FURY_BAMF_GLOBAL_DELAY_MSEC
‪#define FURY_BAMF_GLOBAL_DELAY_MSEC
Definition: archetype_apothicon_fury.gsh:67
‪JUKE_DISTANCE
‪#define JUKE_DISTANCE
Definition: blackboard.gsh:134
‪FURY_JUKE_COOLDOWN_MAX
‪#define FURY_JUKE_COOLDOWN_MAX
Definition: archetype_apothicon_fury.gsh:19
‪IS_HITLOC_LEFT_ARM
‪#define IS_HITLOC_LEFT_ARM(__sHitLoc)
Definition: blackboard.gsh:417
‪YELLOW
‪#define YELLOW
Definition: shared.gsh:178
‪apothiconBamfLand
‪function apothiconBamfLand(entity)
Definition: archetype_apothicon_fury.gsc:958
‪apothiconJukeInit
‪function apothiconJukeInit(entity)
Definition: archetype_apothicon_fury.gsc:1302
‪FURY_BAMF_MELEE_DIST_MIN
‪#define FURY_BAMF_MELEE_DIST_MIN
Definition: archetype_apothicon_fury.gsh:72
‪startTime
‪class AnimationAdjustmentInfoZ startTime
‪apothiconShouldSwitchToFuriousMode
‪function apothiconShouldSwitchToFuriousMode(entity)
Definition: archetype_apothicon_fury.gsc:1136
‪FURY_BAMF_COOLDOWN_MIN
‪#define FURY_BAMF_COOLDOWN_MIN
Definition: archetype_apothicon_fury.gsh:82
‪FURY_DEATH_MODEL_SWAP
‪#define FURY_DEATH_MODEL_SWAP
Definition: archetype_apothicon_fury.gsh:104
‪apothiconKnockdownZombie
‪function apothiconKnockdownZombie(entity, zombie)
Definition: archetype_apothicon_fury.gsc:1086
‪FURY_BAMF_COOLDOWN_MAX
‪#define FURY_BAMF_COOLDOWN_MAX
Definition: archetype_apothicon_fury.gsh:83
‪getJukeVector
‪function private getJukeVector(entity, jukeAnimAlias)
Definition: archetype_apothicon_fury.gsc:1370
‪apothiconDamageClientFieldUpdate
‪function apothiconDamageClientFieldUpdate(entity, sHitLoc)
Definition: archetype_apothicon_fury.gsc:1542
‪jukeInfo
Definition: archetype_apothicon_fury.gsc:1188
‪AddAIOverrideDamageCallback
‪function AddAIOverrideDamageCallback(entity, callback, addToFront)
Definition: archetype_utility.gsc:542
‪FURY_JUKE_CLIENTFIELD
‪#define FURY_JUKE_CLIENTFIELD
Definition: archetype_apothicon_fury.gsh:17
‪BT_REGISTER_API
‪#define BT_REGISTER_API(name, function)
Definition: behavior.gsh:1
‪FURY_JUKE_LONG
‪#define FURY_JUKE_LONG
Definition: archetype_apothicon_fury.gsh:11
‪apothiconFuriousModeInit
‪function apothiconFuriousModeInit(entity)
Definition: archetype_apothicon_fury.gsc:1165
‪FURY_MOVEMENT_VARIANTS
‪#define FURY_MOVEMENT_VARIANTS
Definition: archetype_apothicon_fury.gsh:102
‪AddAIOverrideKilledCallback
‪function AddAIOverrideKilledCallback(entity, callback)
Definition: archetype_utility.gsc:618
‪apothiconCanBamfInternal
‪function apothiconCanBamfInternal(entity, bamfAfterJuke=false)
Definition: archetype_apothicon_fury.gsc:820
‪mocompApothiconFuryBamfTerminate
‪function mocompApothiconFuryBamfTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:740
‪FURY_TAUNT_GLOBAL_DELAY_MSEC
‪#define FURY_TAUNT_GLOBAL_DELAY_MSEC
Definition: archetype_apothicon_fury.gsh:24
‪FURY_BAMF_NT_START
‪#define FURY_BAMF_NT_START
Definition: archetype_apothicon_fury.gsh:14
‪FURY_BAMF_MELEE_DAMAGE_MIN
‪#define FURY_BAMF_MELEE_DAMAGE_MIN
Definition: archetype_apothicon_fury.gsh:64
‪FURY_BAMF_MELEE_DISTANCE_BB
‪#define FURY_BAMF_MELEE_DISTANCE_BB
Definition: archetype_apothicon_fury.gsh:59
‪ZM_MOVE_TIME
‪#define ZM_MOVE_TIME
Definition: zombie.gsh:52
‪FURY_FURIOUS_LEVEL_STEP
‪#define FURY_FURIOUS_LEVEL_STEP
Definition: archetype_apothicon_fury.gsh:45
‪apothiconZombieEligibleForKnockdown
‪function private apothiconZombieEligibleForKnockdown(zombie, thrasher, predicted_pos)
Definition: archetype_apothicon_fury.gsc:1044
‪RegisterApothiconFuryInterfaceAttributes
‪function RegisterApothiconFuryInterfaceAttributes()
Definition: archetype_apothicon_fury_interface.gsc:18
‪stopTime
‪var stopTime
Definition: archetype_apothicon_fury.gsc:282
‪AnimationAdjustmentInfoZ::constructor
‪constructor()
Definition: archetype_apothicon_fury.gsc:272
‪FURY_FURIOUS_GLOBAL_DELAY_MIN_MSEC
‪#define FURY_FURIOUS_GLOBAL_DELAY_MIN_MSEC
Definition: archetype_apothicon_fury.gsh:47
‪cointoss
‪function cointoss()
Definition: math_shared.csc:171
‪ApothiconFuryBlackboardInit
‪function private ApothiconFuryBlackboardInit()
Definition: archetype_apothicon_fury.gsc:124
‪LOCOMOTION_SPEED_WALK
‪#define LOCOMOTION_SPEED_WALK
Definition: blackboard.gsh:156
‪jukeInfo::landPosOnGround
‪var landPosOnGround
Definition: archetype_apothicon_fury.gsc:1193
‪BB_REGISTER_ATTRIBUTE
‪#define BB_REGISTER_ATTRIBUTE(name, defaultValue, getter)
Definition: blackboard.gsh:1
‪ASM_REGISTER_NOTETRACK_HANDLER
‪#define ASM_REGISTER_NOTETRACK_HANDLER(notetrackname, handlerfunction)
Definition: animation_state_machine.gsh:4
‪show_hit_marker
‪function show_hit_marker()
Definition: margwa.gsc:1257
‪apothiconOnDeath
‪function apothiconOnDeath(inflictor, attacker, damage, meansOfDeath, weapon, dir, hitLoc, offsetTimes)
Definition: archetype_apothicon_fury.gsc:1605
‪FURY_RADIUS
‪#define FURY_RADIUS
Definition: archetype_apothicon_fury.gsh:2
‪IS_HITLOC_HIPS
‪#define IS_HITLOC_HIPS(__sHitLoc)
Definition: blackboard.gsh:415
‪FURY_TOO_CLOSE_TO_BAMF_DIST
‪#define FURY_TOO_CLOSE_TO_BAMF_DIST
Definition: archetype_apothicon_fury.gsh:68
‪apothiconTauntAtPlayerEvent
‪function apothiconTauntAtPlayerEvent(entity)
Definition: archetype_apothicon_fury.gsc:940
‪IMPACT_CHEST
‪#define IMPACT_CHEST
Definition: archetype_apothicon_fury.gsh:91
‪apothiconCanJuke
‪function apothiconCanJuke(entity)
Definition: archetype_apothicon_fury.gsc:1237
‪GET_YAW
‪#define GET_YAW(__self, __org)
Definition: utility.gsh:26
‪landPosOnGround
‪var landPosOnGround
Definition: archetype_apothicon_fury.gsc:1169
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪FURY_BAMF_MELEE_RANGE
‪#define FURY_BAMF_MELEE_RANGE
Definition: archetype_apothicon_fury.gsh:62
‪AnimationAdjustmentInfoZ::reAdjustmentStarted
‪var reAdjustmentStarted
Definition: archetype_apothicon_fury.gsc:268
‪FURY_MELEE_DIST_SQ
‪#define FURY_MELEE_DIST_SQ
Definition: archetype_apothicon_fury.gsh:86
‪FURY_JUKE_COOLDOWN_MIN
‪#define FURY_JUKE_COOLDOWN_MIN
Definition: archetype_apothicon_fury.gsh:18
‪within_fov
‪function within_fov(start_origin, start_angles, end_origin, fov)
Definition: _util.gsc:56
‪LOCOMOTION_SPEED_SPRINT
‪#define LOCOMOTION_SPEED_SPRINT
Definition: blackboard.gsh:158
‪stepSize
‪var stepSize
Definition: archetype_apothicon_fury.gsc:283
‪SetBlackBoardAttribute
‪function SetBlackBoardAttribute(entity, attributeName, attributeValue)
Definition: blackboard.gsc:56
‪FURY_BAMF_FOV
‪#define FURY_BAMF_FOV
Definition: archetype_apothicon_fury.gsh:70
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪GetBlackBoardAttribute
‪function GetBlackBoardAttribute(entity, attributeName)
Definition: blackboard.gsc:32
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪GREEN
‪#define GREEN
Definition: shared.gsh:176
‪FURY_BAMF_MELEE_DIST_MAX
‪#define FURY_BAMF_MELEE_DIST_MAX
Definition: archetype_apothicon_fury.gsh:73
‪apothiconMoveUpdate
‪function apothiconMoveUpdate(entity)
Definition: archetype_apothicon_fury.gsc:984
‪RegisterUtilityBlackboardAttributes
‪function RegisterUtilityBlackboardAttributes()
Definition: archetype_utility.gsc:139
‪apothiconBamfOut
‪function apothiconBamfOut(entity)
Definition: archetype_apothicon_fury.gsc:1464
‪ARCHETYPE_APOTHICON_FURY
‪#define ARCHETYPE_APOTHICON_FURY
Definition: archetype_shared.gsh:23
‪RED
‪#define RED
Definition: shared.gsh:175
‪mocompApothiconFuryTeleportTerminate
‪function private mocompApothiconFuryTeleportTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:246
‪apothiconDeathTerminate
‪function apothiconDeathTerminate(entity)
Definition: archetype_apothicon_fury.gsc:1537
‪mocompApothiconFuryBamfUpdate
‪function mocompApothiconFuryBamfUpdate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:690
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪IMPACT_R_ARM
‪#define IMPACT_R_ARM
Definition: archetype_apothicon_fury.gsh:93
‪apothiconDamageCallback
‪function apothiconDamageCallback(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName)
Definition: archetype_apothicon_fury.gsc:1579
‪AnimationAdjustmentInfoZ::stopTime
‪var stopTime
Definition: archetype_apothicon_fury.gsc:265
‪CYAN
‪#define CYAN
Definition: shared.gsh:180
‪apothiconDeathDissolve
‪function apothiconDeathDissolve(entity)
Definition: archetype_apothicon_fury.gsc:198
‪FURY_DEATH_CLIENTFIELD
‪#define FURY_DEATH_CLIENTFIELD
Definition: archetype_apothicon_fury.gsh:56
‪AnimationAdjustmentInfoZ::adjustMentStarted
‪var adjustMentStarted
Definition: archetype_apothicon_fury.gsc:267
‪LOCOMOTION_SPEED_SUPER_SPRINT
‪#define LOCOMOTION_SPEED_SUPER_SPRINT
Definition: blackboard.gsh:159
‪AnimationAdjustmentInfoZ::startTime
‪var startTime
Definition: archetype_apothicon_fury.gsc:264
‪mocompApothiconFuryTeleportInit
‪function private mocompApothiconFuryTeleportInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:222
‪adjustMentStarted
‪var adjustMentStarted
Definition: archetype_apothicon_fury.gsc:285
‪calculateJukeInfo
‪function private calculateJukeInfo(entity)
Definition: archetype_apothicon_fury.gsc:1379
‪IMPACT_L_LEG
‪#define IMPACT_L_LEG
Definition: archetype_apothicon_fury.gsh:96
‪IDGUN_DAMAGE_DIRECTION
‪#define IDGUN_DAMAGE_DIRECTION
Definition: blackboard.gsh:168
‪ENABLE_BLACKBOARD_DEBUG_TRACKING
‪#define ENABLE_BLACKBOARD_DEBUG_TRACKING(self)
Definition: blackboard.gsh:7
‪ApothiconFurySpawnSetup
‪function private ApothiconFurySpawnSetup()
Definition: archetype_apothicon_fury.gsc:148
‪FURY_FURIOUS_LEVEL_THRESHOLD
‪#define FURY_FURIOUS_LEVEL_THRESHOLD
Definition: archetype_apothicon_fury.gsh:44
‪FURY_BAMF_NT_STOP
‪#define FURY_BAMF_NT_STOP
Definition: archetype_apothicon_fury.gsh:15
‪ASM_REGISTER_MOCOMP
‪#define ASM_REGISTER_MOCOMP(name, initFunction, updateFunction, terminateFunction)
Definition: animation_state_machine.gsh:1
‪FURY_FURIOUS_GLOBAL_DELAY_MAX_MSEC
‪#define FURY_FURIOUS_GLOBAL_DELAY_MAX_MSEC
Definition: archetype_apothicon_fury.gsh:48
‪apothiconPreemptiveJukeDone
‪function apothiconPreemptiveJukeDone(entity)
Definition: archetype_apothicon_fury.gsc:1232
‪LOCOMOTION_SPEED_TYPE
‪#define LOCOMOTION_SPEED_TYPE
Definition: blackboard.gsh:155
‪VERSION_DLC4
‪#define VERSION_DLC4
Definition: version.gsh:97
‪AI_ANIM_USE_BOTH_DELTAS_NOCLIP
‪#define AI_ANIM_USE_BOTH_DELTAS_NOCLIP
Definition: animation_state_machine.gsh:83
‪InitApothiconFuryBehaviorsAndASM
‪function private InitApothiconFuryBehaviorsAndASM()
Definition: archetype_apothicon_fury.gsc:78
‪FURY_FURIOUS_MAX_AI
‪#define FURY_FURIOUS_MAX_AI
Definition: archetype_apothicon_fury.gsh:51
‪FURY_JUKE_GLOBAL_DELAY_MSEC
‪#define FURY_JUKE_GLOBAL_DELAY_MSEC
Definition: archetype_apothicon_fury.gsh:13
‪apothiconCanMeleeAttack
‪function apothiconCanMeleeAttack(entity)
Definition: archetype_apothicon_fury.gsc:768
‪mocompApothiconFuryBamfInit
‪function mocompApothiconFuryBamfInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:573
‪xyDirection
‪var xyDirection
Definition: archetype_apothicon_fury.gsc:284
‪IS_HITLOC_RIGHT_ARM
‪#define IS_HITLOC_RIGHT_ARM(__sHitLoc)
Definition: blackboard.gsh:416
‪RunBamfReAdjustmentAnalysis
‪function private RunBamfReAdjustmentAnalysis(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:433
‪AI_ANIM_USE_BOTH_DELTAS
‪#define AI_ANIM_USE_BOTH_DELTAS
Definition: animation_state_machine.gsh:82
‪AnimationAdjustmentInfoZ::landPosOnGround
‪var landPosOnGround
Definition: archetype_apothicon_fury.gsc:269
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪AnimationAdjustmentInfoZ
Definition: archetype_apothicon_fury.gsc:262
‪moveSpeedAttributeCallback
‪function moveSpeedAttributeCallback(entity, attribute, oldValue, value)
Definition: archetype_apothicon_fury.gsc:1617
‪AddBlackboardEvent
‪function AddBlackboardEvent(eventName, data, timeToLiveInMillis)
Definition: ai_blackboard.gsc:47
‪DAMAGE_DIRECTION_BACK
‪#define DAMAGE_DIRECTION_BACK
Definition: blackboard.gsh:332
‪mocompApothiconFuryJukeTerminate
‪function mocompApothiconFuryJukeTerminate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:414
‪FLAT_ANGLES
‪#define FLAT_ANGLES(__angles)
Definition: shared.gsh:257
‪FURY_JUKE_MAX_DIST
‪#define FURY_JUKE_MAX_DIST
Definition: archetype_apothicon_fury.gsh:5
‪increment
‪function increment(str_field_name, n_increment_count=1)
Definition: clientfield_shared.gsc:110
‪KNOCKDOWN_SHOVED
‪#define KNOCKDOWN_SHOVED
Definition: blackboard.gsh:212
‪apothiconKnockdownService
‪function apothiconKnockdownService(entity)
Definition: archetype_apothicon_fury.gsc:1014
‪BB_GetDamageDirection
‪function BB_GetDamageDirection()
Definition: archetype_utility.gsc:344
‪validateJuke
‪function validateJuke(entity, entityRadius, jukeVector)
Definition: archetype_apothicon_fury.gsc:1331
‪BLUE
‪#define BLUE
Definition: shared.gsh:177
‪ApothiconFuryOnAnimscriptedCallback
‪function private ApothiconFuryOnAnimscriptedCallback(entity)
Definition: archetype_apothicon_fury.gsc:188
‪FURY_BAMF_MELEE_DIST_MIN_AFTER_JUKE
‪#define FURY_BAMF_MELEE_DIST_MIN_AFTER_JUKE
Definition: archetype_apothicon_fury.gsh:71
‪FURY_DEATH_DISSOLVED_NT
‪#define FURY_DEATH_DISSOLVED_NT
Definition: archetype_apothicon_fury.gsh:55
‪apothiconBamfInit
‪function apothiconBamfInit(entity)
Definition: archetype_apothicon_fury.gsc:911
‪FURY_BAMF_MELEE_DAMAGE_MAX
‪#define FURY_BAMF_MELEE_DAMAGE_MAX
Definition: archetype_apothicon_fury.gsh:63
‪GetAiAttribute
‪function GetAiAttribute(entity, attribute)
Definition: ai_interface.gsc:118
‪IMPACT_HIPS
‪#define IMPACT_HIPS
Definition: archetype_apothicon_fury.gsh:92
‪apothiconDeathDissolved
‪function apothiconDeathDissolved(entity)
Definition: archetype_apothicon_fury.gsc:216
‪jukeInfo::jukeDirection
‪var jukeDirection
Definition: archetype_apothicon_fury.gsc:1191
‪IS_HITLOC_HEAD
‪#define IS_HITLOC_HEAD(__sHitLoc)
Definition: blackboard.gsh:413
‪ARCHETYPE_ZOMBIE
‪#define ARCHETYPE_ZOMBIE
Definition: archetype_shared.gsh:10
‪FURY_DEATH_START_DISSOLVE_NT
‪#define FURY_DEATH_START_DISSOLVE_NT
Definition: archetype_apothicon_fury.gsh:54
‪add_archetype_spawn_function
‪function add_archetype_spawn_function(archetype, spawn_func)
Definition: ai_shared.csc:23
‪GETUP_BELLY
‪#define GETUP_BELLY
Definition: blackboard.gsh:206
‪ZM_MELEE_YAW
‪#define ZM_MELEE_YAW
Definition: skeleton.gsh:2
‪apothiconMoveStart
‪function apothiconMoveStart(entity)
Definition: archetype_apothicon_fury.gsc:978
‪IMPACT_R_LEG
‪#define IMPACT_R_LEG
Definition: archetype_apothicon_fury.gsh:95
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪apothiconCanBamfAfterJuke
‪function apothiconCanBamfAfterJuke(entity)
Definition: archetype_apothicon_fury.gsc:809
‪constructor
‪constructor()
Definition: archetype_apothicon_fury.gsc:287
‪AnimationAdjustmentInfoZ::stepSize
‪var stepSize
Definition: archetype_apothicon_fury.gsc:266
‪IS_HITLOC_LEFT_LEG
‪#define IS_HITLOC_LEFT_LEG(__sHitLoc)
Definition: blackboard.gsh:421
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪apothiconPreemptiveJukeService
‪class jukeInfo apothiconPreemptiveJukeService(entity)
Definition: archetype_apothicon_fury.gsc:1196
‪apothiconBamfIn
‪function apothiconBamfIn(entity)
Definition: archetype_apothicon_fury.gsc:1487
‪AnimationAdjustmentInfoZ::enemy
‪var enemy
Definition: archetype_apothicon_fury.gsc:270
‪mocompApothiconFuryJukeInit
‪function mocompApothiconFuryJukeInit(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:293
‪FURY_DAMAGE_CLIENTFIELD
‪#define FURY_DAMAGE_CLIENTFIELD
Definition: archetype_apothicon_fury.gsh:27
‪shouldRegisterClientFieldForArchetype
‪function shouldRegisterClientFieldForArchetype(archetype)
Definition: ai_shared.csc:72
‪apothiconShouldTauntAtPlayer
‪function apothiconShouldTauntAtPlayer(entity)
Definition: archetype_apothicon_fury.gsc:930
‪FURY_FURIOUS_MODE_CLIENTFIELD
‪#define FURY_FURIOUS_MODE_CLIENTFIELD
Definition: archetype_apothicon_fury.gsh:46
‪JUKE_DIRECTION
‪#define JUKE_DIRECTION
Definition: blackboard.gsh:133
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪BB_IDGunGetDamageDirection
‪function BB_IDGunGetDamageDirection()
Definition: archetype_apothicon_fury.gsc:949
‪apothiconShouldMeleeCondition
‪function apothiconShouldMeleeCondition(behaviorTreeEntity)
Definition: archetype_apothicon_fury.gsc:773
‪getBamfMeleeDistance
‪function getBamfMeleeDistance(entity)
Definition: archetype_apothicon_fury.gsc:904
‪IMPACT_HEAD
‪#define IMPACT_HEAD
Definition: archetype_apothicon_fury.gsh:90
‪mocompApothiconFuryJukeUpdate
‪function mocompApothiconFuryJukeUpdate(entity, mocompAnim, mocompAnimBlendOutTime, mocompAnimFlag, mocompDuration)
Definition: archetype_apothicon_fury.gsc:381
‪GetBlackboardEvents
‪function GetBlackboardEvents(eventName)
Definition: ai_blackboard.gsc:64
‪jukeInfo::jukeDistance
‪var jukeDistance
Definition: archetype_apothicon_fury.gsc:1192
‪FURY_ZIGZAG_MIN
‪#define FURY_ZIGZAG_MIN
Definition: archetype_apothicon_fury.gsh:40
‪ORANGE
‪#define ORANGE
Definition: shared.gsh:179
‪FURY_ZIGZAG_MAX
‪#define FURY_ZIGZAG_MAX
Definition: archetype_apothicon_fury.gsh:41
‪FURY_BAMF_NT_LAND
‪#define FURY_BAMF_NT_LAND
Definition: archetype_apothicon_fury.gsh:16
‪LOCOMOTION_SPEED_RUN
‪#define LOCOMOTION_SPEED_RUN
Definition: blackboard.gsh:157
‪CreateInterfaceForEntity
‪function CreateInterfaceForEntity(entity)
Definition: ai_interface.gsc:110
‪zombieSpawnSetup
‪function zombieSpawnSetup()
Definition: zombie_utility.gsc:28
‪apothiconDeathStart
‪function apothiconDeathStart(entity)
Definition: archetype_apothicon_fury.gsc:1530
‪jukeInfo::jukeStartAngles
‪var jukeStartAngles
Definition: archetype_apothicon_fury.gsc:1190
‪IS_HITLOC_CHEST
‪#define IS_HITLOC_CHEST(__sHitLoc)
Definition: blackboard.gsh:414
‪init
‪function autoexec init()
Definition: archetype_apothicon_fury.gsc:52
‪FURY_BAMF_LAND_CLIENTFIELD
‪#define FURY_BAMF_LAND_CLIENTFIELD
Definition: archetype_apothicon_fury.gsh:65
‪VARIANT_TYPE
‪#define VARIANT_TYPE
Definition: blackboard.gsh:118
‪apothiconPreemptiveJukePending
‪function apothiconPreemptiveJukePending(entity)
Definition: archetype_apothicon_fury.gsc:1227
‪GETUP_BACK
‪#define GETUP_BACK
Definition: blackboard.gsh:205
‪apothiconCanBamf
‪function apothiconCanBamf(entity)
Definition: archetype_apothicon_fury.gsc:815
‪ZM_MOVE_DIST_SQ
‪#define ZM_MOVE_DIST_SQ
Definition: zombie.gsh:53