‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_parasite.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\math_shared;
4 #using scripts\shared\statemachine_shared;
5 #using scripts\shared\callbacks_shared;
6 #using scripts\shared\clientfield_shared;
7 #using scripts\shared\system_shared;
8 #using scripts\shared\array_shared;
9 #using scripts\shared\util_shared;
10 #using scripts\shared\ai_shared;
11 
12 #using scripts\shared\vehicle_shared;
13 #using scripts\shared\vehicle_death_shared;
14 #using scripts\shared\vehicle_ai_shared;
15 #using scripts\shared\ai\systems\blackboard;
16 #using scripts\shared\ai\blackboard_vehicle;
17 #using scripts\shared\ai\systems\ai_interface;
18 
19 #insert scripts\shared\shared.gsh;
20 #insert scripts\shared\version.gsh;
21 #insert scripts\shared\statemachine.gsh;
22 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
23 
24 #insert scripts\shared\ai\utility.gsh;
25 #insert scripts\shared\ai\systems\blackboard.gsh;
26 #using scripts\shared\ai\zombie_utility;
27 
28 #define PARASITE_RADIUS 20
29 
30 #define PARASITE_MAX_TIME_AT_SAME_POSITION 1.0
31 #define PARASITE_CHANGE_POSITION_TOATTACK_TARGET_DELAY 0.5
32 
33 #define PARASITE_AWAY_FROM_CHARACTER 300
34 
35 #define PARASITE_ENEMY_TOO_CLOSE_DIST 250
36 
37 //reduce these defines to have the parasite make more movements close together
38 #define PARASITE_TOO_CLOSE_TO_SELF_DIST 75
39 #define PARASITE_MOVE_DIST_MAX 225
40 #define PARASITE_JUKE_MOVE_DIST_MAX 300
41 
42 #define PARASITE_REPATH_RANGE 100
43 
44 #define PARASITE_FIRE_CHANCE 30
45 #define PARASITE_MELEE_CHANCE 50
46 #define PARASITE_MELEE_DIST 64
47 
48 #namespace parasite;
49 
50 ‪REGISTER_SYSTEM( "parasite", &‪__init__, undefined )
51 
52 #using_animtree( "generic" );
53 
54 function ‪__init__()
55 {
56  vehicle::add_main_callback( "parasite", &‪parasite_initialize );
57 
58  ‪clientfield::register( "vehicle", "parasite_tell_fx", ‪VERSION_SHIP, 1, "int" );
59  ‪clientfield::register( "vehicle", "parasite_secondary_deathfx", ‪VERSION_SHIP, 1, "int" );
60  ‪clientfield::register( "toplayer", "parasite_damage", ‪VERSION_SHIP, 1, "counter" );
61 
63 
65  "parasite",
66  "firing_rate",
67  "slow",
68  ‪array( "slow", "medium", "fast" ) );
69 }
70 
72 {
73  self notify( "parasite_damage_thread" );
74  self endon( "parasite_damage_thread" );
75 
76  self endon( "death" );
77 
78  while ( true )
79  {
80  self waittill( "damage", n_ammount, e_attacker );
81 
82  if ( IsDefined( e_attacker ) && ‪IS_TRUE( e_attacker.is_parasite ) && !‪IS_TRUE(e_attacker.squelch_damage_overlay) )
83  {
84  self ‪clientfield::increment_to_player( "parasite_damage" );
85  }
86  }
87 }
88 
89 function private ‪is_target_valid( target )
90 {
91  if( !IsDefined( target ) )
92  {
93  return false;
94  }
95 
96  if( !IsAlive( target ) )
97  {
98  return false;
99  }
100 
101  if( IsPlayer( target ) && target.sessionstate == "spectator" )
102  {
103  return false;
104  }
105 
106  if( IsPlayer( target ) && target.sessionstate == "intermission" )
107  {
108  return false;
109  }
110 
111  if( ‪IS_TRUE( target.ignoreme ) )
112  {
113  return false;
114  }
115 
116  if( target IsNoTarget() )
117  {
118  return false;
119  }
120 
121  if( IsDefined( self.is_target_valid_cb ) )
122  {
123  return self [[ self.is_target_valid_cb ]]( target );
124  }
125 
126  return true;
127 }
128 
130 {
131  parasite_targets = GetPlayers();
132  least_hunted = parasite_targets[0];
133  for( i = 0; i < parasite_targets.size; i++ )
134  {
135  if ( !isdefined( parasite_targets[i].hunted_by ) )
136  {
137  parasite_targets[i].hunted_by = 0;
138  }
139 
140  if( !‪is_target_valid( parasite_targets[i] ) )
141  {
142  continue;
143  }
144 
145  if( !‪is_target_valid( least_hunted ) )
146  {
147  least_hunted = parasite_targets[i];
148  }
149 
150  if( parasite_targets[i].hunted_by < least_hunted.hunted_by )
151  {
152  least_hunted = parasite_targets[i];
153  }
154 
155  }
156  // do not return the default first player if he is invalid
157  if( !‪is_target_valid( least_hunted ) )
158  {
159  return undefined;
160  }
161  else
162  {
163  return least_hunted;
164  }
165 }
166 
167 function ‪set_parasite_enemy( enemy )
168 {
169  if( !‪is_target_valid( enemy ) )
170  {
171  return;
172  }
173 
174  if( IsDefined( self.parasiteEnemy ) )
175  {
176  if( !IsDefined( self.parasiteEnemy.hunted_by ) )
177  {
178  self.parasiteEnemy.hunted_by = 0;
179  }
180  if( self.parasiteEnemy.hunted_by > 0 )
181  {
182  self.parasiteEnemy.hunted_by--;
183  }
184  }
185 
186  self.parasiteEnemy = enemy;
187  if( !IsDefined( self.parasiteEnemy.hunted_by ) )
188  {
189  self.parasiteEnemy.hunted_by = 0;
190  }
191  self.parasiteEnemy.hunted_by++;
192  self SetLookAtEnt( self.parasiteEnemy );
193  self SetTurretTargetEnt( self.parasiteEnemy );
194 }
195 
197 {
198  self endon( "change_state" );
199  self endon( "death" );
200 
201  for( ;; )
202  {
203  if ( ‪IS_TRUE( self.ignoreall ) )
204  {
205  wait 0.5;
206  continue;
207  }
208 
209  if( ‪is_target_valid( self.parasiteEnemy ) )
210  {
211  wait 0.5;
212  continue;
213  }
214  //decide who the enemy should be
215  target = ‪get_parasite_enemy();
216 
217  if( !isDefined( target ) )
218  {
219  self.parasiteEnemy = undefined;
220  }
221  else
222  {
223  self.parasiteEnemy = target;
224  //update hunted_by
225  self.parasiteEnemy.hunted_by += 1;
226  self SetLookAtEnt( self.parasiteEnemy );
227  self SetTurretTargetEnt( self.parasiteEnemy );
228  }
229 
230  wait 0.5;
231  }
232 }
233 
235 {
236  self useanimtree( #animtree );
237 
238  // AI SPECIFIC INITIALIZATION
242 
244 
245  self.health = self.healthdefault;
246 
248 
249  self EnableAimAssist();
250  self SetNearGoalNotifyDist( 25 );
251 
252  self SetDrawInfrared( true );
253 
254  self.fovcosine = 0;
255  self.fovcosinebusy = 0;
256 
257  self.vehAirCraftCollisionEnabled = true;
258 
259  assert( isdefined( self.scriptbundlesettings ) );
260 
261  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
262  self.goalRadius = 999999;
263  self.goalHeight = 4000;
264  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
265 
266  self.is_parasite = true;
267 
268  self thread ‪vehicle_ai::nudge_collision();
269 
270  if( IsDefined( level.vehicle_initializer_cb ) )
271  {
272  [[level.vehicle_initializer_cb]]( self );
273  }
274 
275  ‪defaultRole();
276 }
277 
278 function ‪defaultRole()
279 {
281 
282  self ‪vehicle_ai::get_state_callbacks( "combat" ).enter_func = &‪state_combat_enter;
283  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
284 
285  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
286 
288 
290 }
291 
292 // ----------------------------------------------
293 //BB getter functions
294 // ----------------------------------------------
296 {
297  return self ‪ai::get_behavior_attribute( "firing_rate" );
298 }
299 
300 // ----------------------------------------------
301 // State: death
302 // ----------------------------------------------
303 function ‪state_death_update( params )
304 {
305  self endon( "death" );
306 
307  self ASMRequestSubstate( "death@stationary" );
308 
309  if( IsDefined( self.parasiteEnemy ) && IsDefined( self.parasiteEnemy.hunted_by ) )
310  {
311  self.parasiteEnemy.hunted_by--;
312  }
313 
314  self SetPhysAcceleration( ( 0, 0, -300 ) );
315  self.vehcheckforpredictedcrash = true;
316 
317  self thread ‪vehicle_death::death_fx();
318  self playsound( "zmb_parasite_explo" );
319 
320  self ‪util::waittill_notify_or_timeout( "veh_predictedcollision", 4.0 );
321 
322  self ‪clientfield::set( "parasite_secondary_deathfx", 1 );
323 
324  //make sure the client gets a chance to play the second fx before deleting
325  wait 0.2;
326 
327  self Delete();
328 }
329 
330 // ----------------------------------------------
331 // State: combat
332 // ----------------------------------------------
333 function ‪state_combat_enter( params )
334 {
335  if ( IsDefined( self.owner ) && IsDefined( self.owner.enemy ) )
336  {
337  self.parasiteEnemy = self.owner.enemy;
338  }
339  self thread ‪parasite_target_selection();
340 }
341 
342 function ‪state_combat_update( params )
343 {
344  self endon( "change_state" );
345  self endon( "death" );
346 
347  lastTimeChangePosition = 0;
348  self.shouldGotoNewPosition = false;
349  self.lastTimeTargetInSight = 0;
350  self.lastTimeJuked = false;
351 
352  //request movement animations
353  self ASMRequestSubstate( "locomotion@movement" );
354 
355  for( ;; )
356  {
357  if( IsDefined( self._override_parasite_combat_speed ) )
358  {
359  self SetSpeed( self._override_parasite_combat_speed );
360  }
361  else
362  {
363  self SetSpeed( self.settings.defaultMoveSpeed );
364  }
365 
366  if ( ‪IS_TRUE( self.inpain ) )
367  {
368  wait 0.1;
369  }
370  else if ( !IsDefined( self.parasiteEnemy ) )
371  {
372  //no enemy, do nothing
373  wait( 0.25 );
374  }
375  else
376  {
377  if( self.goalforced )
378  {
379  returnData = [];
380  returnData[ "origin" ] = self GetClosestPointOnNavVolume( self.goalpos, 100 );
381  returnData[ "centerOnNav" ] = IsPointInNavVolume( self.origin, "navvolume_small" );
382  }
383  //prevent two consecutive forward jukes, and force juke if path was interrupted ( possibly due to collision )
384  else if( ( RandomInt( 100 ) < self.settings.jukeprobability && !‪IS_TRUE( self.lastTimeJuked ) ) || ‪IS_TRUE( self._override_juke ) )
385  {
386  returnData = ‪GetNextMovePosition_forwardjuke();
387  self.lastTimeJuked = true;
388  self._override_juke = undefined;
389  }
390  else
391  {
392  returnData = ‪GetNextMovePosition_tactical();
393  self.lastTimeJuked = false;
394  }
395  self.current_pathto_pos = returnData[ "origin" ];
396  if ( IsDefined( self.current_pathto_pos ) )
397  {
398  if( IsDefined( self.stuckTime ) )
399  {
400  self.stuckTime = undefined;
401  }
402  if ( self SetVehGoalPos( self.current_pathto_pos, true, returnData[ "centerOnNav" ] ) )
403  {
404  self thread ‪path_update_interrupt();
405 
406  //AUDIO: Was on JUST the juke, but I've moved it for any movement to make it more interesting
407  self playsound( "zmb_vocals_parasite_juke" );
408 
410  }
411  else
412  {
413  //failsafe, cannot pathfind
414  wait( 0.1 );
415  }
416  }
417  else
418  {
419  if( !‪IS_TRUE( returnData[ "centerOnNav" ] ) )
420  {
421  //not on navmesh, no valid goto points, kill parasite as failsafe
422  if( !IsDefined( self.stuckTime ) )
423  {
424  self.stuckTime = GetTime();
425  }
426  if( GetTime() - self.stuckTime > 10000 )
427  {
428  self DoDamage( self.health + 100, self.origin );
429  }
430  }
431  }
432 
433  if( ‪IS_TRUE( self.lastTimeJuked ) )
434  {
435  if( RandomInt( 100 ) < ‪PARASITE_MELEE_CHANCE && IsDefined( self.parasiteEnemy ) && Distance2DSquared( self.origin, self.parasiteEnemy.origin ) < ‪SQR( ‪PARASITE_MELEE_DIST ) )
436  {
437  //parasite melee bite
438  self.parasiteEnemy DoDamage( self.settings.meleedamage, self.parasiteEnemy.origin, self );
439  }
440  else
441  {
442  self ‪fire_pod_logic( self.lastTimeJuked );
443  }
444  }
445  else
446  {
447  if( RandomInt( 100 ) < ‪PARASITE_FIRE_CHANCE )
448  {
449  self ‪fire_pod_logic( self.lastTimeJuked );
450  }
451  }
452  }
453  }
454 }
455 
456 function ‪fire_pod_logic( choseToJuke )
457 {
458  if( IsDefined( self.parasiteEnemy ) && self VehCanSee( self.parasiteEnemy ) && Distance2DSquared( self.parasiteEnemy.origin, self.origin ) < ‪SQR( 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax ) * 3 ) )
459  {
460  //switch to fire animation
461  self ASMRequestSubstate( "fire@stationary" );
462 
463  //do the tell
464  self PlaySound( "zmb_vocals_parasite_preattack" );
465  self ‪clientfield::set( "parasite_tell_fx", 1 );
466 
467  //reached the point in the animation to adjust the turret
468  self waittill( "pre_fire" );
469 
470  if( IsDefined( self.parasiteEnemy ) && self VehCanSee( self.parasiteEnemy ) && Distance2DSquared( self.parasiteEnemy.origin, self.origin ) < ‪SQR( 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax ) * 3 ) )
471  {
472  //fire the projectile at the predicted player position
473  self SetTurretTargetEnt( self.parasiteEnemy, self.parasiteEnemy GetVelocity() * 0.3 );
474  }
475 
476  self ‪vehicle_ai::waittill_asm_complete( "fire@stationary", 5 );
477 
478  //switch back to locomotion
479  self ASMRequestSubstate( "locomotion@movement" );
480 
481  //cleanup the fx
482  self ‪clientfield::set( "parasite_tell_fx", 0 );
483 
484  if( !choseToJuke )
485  {
486  wait RandomFloatRange( 0.25, 0.5 );
487  }
488  }
489  else
490  {
491  wait RandomFloatRange( 1, 2 );
492  }
493 }
494 
495 function ‪GetNextMovePosition_tactical() // has self.parasiteEnemy
496 {
497  self endon( "change_state" );
498  self endon( "death" );
499 
500  // distance based multipliers
501  selfDistToTarget = Distance2D( self.origin, self.parasiteEnemy.origin );
502 
503  goodDist = 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax );
504 
505  closeDist = 1.2 * goodDist;
506  farDist = 3 * goodDist;
507 
508  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
509 
510  //the preferred height range should be half the max possible difference to not exceed valid heights for points near the goalheight
511  preferedHeightRange = 0.5 * ( self.settings.engagementHeightMax - self.settings.engagementHeightMin );
512  randomness = 30;
513 
514  // query
515  queryResult = PositionQuery_Source_Navigation( self.origin, ‪PARASITE_TOO_CLOSE_TO_SELF_DIST, ‪PARASITE_MOVE_DIST_MAX * queryMultiplier, 75, ‪PARASITE_RADIUS * queryMultiplier, self, ‪PARASITE_RADIUS * queryMultiplier );
516  //turn off collision, we are not on the navvolume
517  if( !‪IS_TRUE( queryResult.centerOnNav ) )
518  {
519  self.vehAirCraftCollisionEnabled = false;
520  }
521  else
522  {
523  self.vehAirCraftCollisionEnabled = true;
524  }
525  // filter
526  PositionQuery_Filter_DistanceToGoal( queryResult, self );
528  self ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, self.parasiteEnemy, self.settings.engagementDistMin, self.settings.engagementDistMax );
529 
530  goalHeight = self.parasiteEnemy.origin[2] + 0.5 * ( self.settings.engagementHeightMin + self.settings.engagementHeightMax );
531 
532  // score points
533  best_point = undefined;
534  best_score = -999999;
535  trace_count = 0;
536  foreach ( point in queryResult.data )
537  {
538  if( !‪IS_TRUE( queryResult.centerOnNav ) )
539  {
540  if( SightTracePassed( self.origin, point.origin, false, undefined ) )
541  {
542  trace_count++;
543  if( trace_count > 3 )
544  {
546  trace_count = 0;
547  }
548  if( !BulletTracePassed( self.origin, point.origin, false, self ) )
549  {
550  continue;
551  }
552  }
553  else
554  {
555  continue;
556  }
557  }
558 
559  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, randomness ) );
560 
561  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
562 
563  // height
564  distFromPreferredHeight = abs( point.origin[2] - goalHeight );
565  if ( distFromPreferredHeight > preferedHeightRange )
566  {
567  heightScore = MapFloat( 0, 500, 0, 2000, distFromPreferredHeight );
568  ADD_POINT_SCORE( point, "height", -heightScore );
569  }
570 
571  if ( point.score > best_score )
572  {
573  best_score = point.score;
574  best_point = point;
575  }
576  }
577  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
578 
579  /#
580  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
581  {
582  recordLine( self.origin, best_point.origin, (0.3,1,0) );
583  recordLine( self.origin, self.parasiteEnemy.origin, (1,0,0.4) );
584  }
585 #/
586  returnData = [];
587  returnData[ "origin" ] = ( ( IsDefined( best_point ) ) ? best_point.origin : undefined );
588  returnData[ "centerOnNav" ] = queryResult.centerOnNav;
589  return returnData;
590 }
591 
592 
593 function ‪GetNextMovePosition_forwardjuke() // has self.parasiteEnemy
594 {
595  self endon( "change_state" );
596  self endon( "death" );
597 
598  // distance based multipliers
599  selfDistToTarget = Distance2D( self.origin, self.parasiteEnemy.origin );
600 
601  goodDist = 0.5 * ( self.settings.forwardJukeEngagementDistMin + self.settings.forwardJukeEngagementDistMax );
602 
603  closeDist = 1.2 * goodDist;
604  farDist = 3 * goodDist;
605 
606  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
607 
608  preferedHeightRange = 0.5 * ( self.settings.forwardJukeEngagementHeightMax - self.settings.forwardJukeEngagementHeightMin );
609  randomness = 30;
610 
611  // query
612  queryResult = PositionQuery_Source_Navigation( self.origin, ‪PARASITE_TOO_CLOSE_TO_SELF_DIST, ‪PARASITE_JUKE_MOVE_DIST_MAX * queryMultiplier, 75, ‪PARASITE_RADIUS * queryMultiplier, self, ‪PARASITE_RADIUS * queryMultiplier );
613  if( !‪IS_TRUE( queryResult.centerOnNav ) )
614  {
615  self.vehAirCraftCollisionEnabled = false;
616  }
617  else
618  {
619  self.vehAirCraftCollisionEnabled = true;
620  }
621  // filter
622  PositionQuery_Filter_DistanceToGoal( queryResult, self );
624  self ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, self.parasiteEnemy, self.settings.forwardJukeEngagementDistMin, self.settings.forwardJukeEngagementDistMax );
625 
626  goalHeight = self.parasiteEnemy.origin[2] + 0.5 * ( self.settings.forwardJukeEngagementHeightMin + self.settings.forwardJukeEngagementHeightMax );
627 
628  // score points
629  best_point = undefined;
630  best_score = -999999;
631  trace_count = 0;
632 
633  foreach ( point in queryResult.data )
634  {
635  if( !‪IS_TRUE( queryResult.centerOnNav ) )
636  {
637  if( SightTracePassed( self.origin, point.origin, false, undefined ) )
638  {
639  trace_count++;
640  if( trace_count > 3 )
641  {
643  trace_count = 0;
644  }
645  if( !BulletTracePassed( self.origin, point.origin, false, self ) )
646  {
647  continue;
648  }
649  }
650  else
651  {
652  continue;
653  }
654  }
655 
656  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, randomness ) );
657 
658  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
659 
660  // height
661  distFromPreferredHeight = abs( point.origin[2] - goalHeight );
662  if ( distFromPreferredHeight > preferedHeightRange )
663  {
664  heightScore = MapFloat( 0, 500, 0, 2000, distFromPreferredHeight );
665  ADD_POINT_SCORE( point, "height", -heightScore );
666  }
667 
668  if ( point.score > best_score )
669  {
670  best_score = point.score;
671  best_point = point;
672  }
673  }
674  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
675 
676  /#
677  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
678  {
679  recordLine( self.origin, best_point.origin, (0.3,1,0) );
680  recordLine( self.origin, self.parasiteEnemy.origin, (1,0,0.4) );
681  }
682 #/
683 
684  returnData = [];
685  returnData[ "origin" ] = ( ( IsDefined( best_point ) ) ? best_point.origin : undefined );
686  returnData[ "centerOnNav" ] = queryResult.centerOnNav;
687  return returnData;
688 }
689 
691 {
692  self endon( "death" );
693  self endon( "change_state" );
694  self endon( "near_goal" );
695  self endon( "reached_end_node" );
696 
697  wait 1;
698 
699  while( 1 )
700  {
701  if( isdefined( self.current_pathto_pos ) )
702  {
703  if( distance2dSquared( self.current_pathto_pos, self.goalpos ) > ‪SQR( self.goalradius ) )
704  {
705  wait 0.2;
706  self._override_juke = true;
707  self notify( "near_goal" );
708  }
709  }
710  wait 0.2;
711  }
712 }
713 
714 
715 // ----------------------------------------------
716 // pain/hit reaction
717 // ----------------------------------------------
718 function ‪drone_pain_for_time( time, stablizeParam, restoreLookPoint )
719 {
720  self endon( "death" );
721 
722  self.painStartTime = GetTime();
723 
724  if ( !‪IS_TRUE( self.inpain ) )
725  {
726  self.inpain = true;
727 
728  self PlaySound( "zmb_vocals_parasite_pain" );
729 
730  while ( GetTime() < self.painStartTime + time * 1000 )
731  {
732  self SetVehVelocity( self.velocity * stablizeParam );
733  self SetAngularVelocity( self GetAngularVelocity() * stablizeParam );
734  wait 0.1;
735  }
736 
737  if ( isdefined( restoreLookPoint ) )
738  {
739  restoreLookEnt = ‪Spawn( "script_model", restoreLookPoint );
740  restoreLookEnt SetModel( "tag_origin" );
741 
742  self ClearLookAtEnt();
743  self SetLookAtEnt( restoreLookEnt );
744  self setTurretTargetEnt( restoreLookEnt );
745  wait 1.5;
746 
747  self ClearLookAtEnt();
748  self ClearTurretTarget();
749  restoreLookEnt delete();
750  }
751 
752  self.inpain = false;
753  }
754 }
755 
756 function ‪drone_pain( eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName )
757 {
758  if ( !‪IS_TRUE( self.inpain ) )
759  {
760  yaw_vel = ‪math::randomSign() * RandomFloatRange( 280, 320 );
761 
762  ang_vel = self GetAngularVelocity();
763  ang_vel += ( RandomFloatRange( -120, -100 ), yaw_vel, RandomFloatRange( -200, 200 ) );
764  self SetAngularVelocity( ang_vel );
765 
766  self thread ‪drone_pain_for_time( 0.8, 0.7 );
767  }
768 }
‪call_custom_add_state_callbacks
‪function call_custom_add_state_callbacks()
Definition: vehicle_ai_shared.gsc:1152
‪PARASITE_TOO_CLOSE_TO_SELF_DIST
‪#define PARASITE_TOO_CLOSE_TO_SELF_DIST
Definition: _parasite.gsc:38
‪state_combat_enter
‪function state_combat_enter(params)
Definition: _parasite.gsc:333
‪PARASITE_MELEE_CHANCE
‪#define PARASITE_MELEE_CHANCE
Definition: _parasite.gsc:45
‪randomSign
‪function randomSign()
Definition: math_shared.gsc:179
‪drone_pain_for_time
‪function drone_pain_for_time(time, stablizeParam, restoreLookPoint)
Definition: _parasite.gsc:718
‪PARASITE_FIRING_RATE
‪#define PARASITE_FIRING_RATE
Definition: blackboard.gsh:193
‪RegisterMatchedInterface
‪function RegisterMatchedInterface(archetype, attribute, defaultValue, possibleValues, callbackFunction)
Definition: ai_interface.gsc:143
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪GetNextMovePosition_forwardjuke
‪function GetNextMovePosition_forwardjuke()
Definition: _parasite.gsc:593
‪set_parasite_enemy
‪function set_parasite_enemy(enemy)
Definition: _parasite.gsc:167
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪BB_REGISTER_ATTRIBUTE
‪#define BB_REGISTER_ATTRIBUTE(name, defaultValue, getter)
Definition: blackboard.gsh:1
‪GetNextMovePosition_tactical
‪function GetNextMovePosition_tactical()
Definition: _parasite.gsc:495
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪defaultRole
‪function defaultRole()
Definition: _parasite.gsc:278
‪PARASITE_FIRE_CHANCE
‪#define PARASITE_FIRE_CHANCE
Definition: _parasite.gsc:44
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪on_spawned
‪function on_spawned(func, obj)
Definition: callbacks_shared.csc:245
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪waittill_notify_or_timeout
‪function waittill_notify_or_timeout(msg, timer)
Definition: util_shared.csc:473
‪init_state_machine_for_role
‪function init_state_machine_for_role(rolename)
Definition: vehicle_ai_shared.gsc:1034
‪death_fx
‪function death_fx()
Definition: _qrdrone.gsc:958
‪get_parasite_enemy
‪function get_parasite_enemy()
Definition: _parasite.gsc:129
‪waittill_pathing_done
‪function waittill_pathing_done(maxtime=15)
Definition: vehicle_ai_shared.gsc:340
‪PositionQuery_DebugScores
‪function PositionQuery_DebugScores(queryResult)
Definition: vehicle_ai_shared.gsc:2010
‪increment_to_player
‪function increment_to_player(str_field_name, n_increment_count=1)
Definition: clientfield_shared.gsc:169
‪PositionQuery_Filter_OutOfGoalAnchor
‪function PositionQuery_Filter_OutOfGoalAnchor(queryResult, tolerance=1)
Definition: vehicle_ai_shared.gsc:2104
‪parasite_damage
‪function parasite_damage()
Definition: _parasite.gsc:71
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪fire_pod_logic
‪function fire_pod_logic(choseToJuke)
Definition: _parasite.gsc:456
‪array
‪function filter array
Definition: array_shared.csc:16
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪waittill_asm_complete
‪function waittill_asm_complete(substate_to_wait, timeout=10)
Definition: vehicle_ai_shared.gsc:374
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪PARASITE_MELEE_DIST
‪#define PARASITE_MELEE_DIST
Definition: _parasite.gsc:46
‪RegisterVehicleBlackBoardAttributes
‪function RegisterVehicleBlackBoardAttributes()
Definition: blackboard_vehicle.gsc:24
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪CreateBlackBoardForEntity
‪function CreateBlackBoardForEntity(entity)
Definition: blackboard.gsc:77
‪state_death_update
‪function state_death_update(params)
Definition: _parasite.gsc:303
‪is_target_valid
‪function private is_target_valid(target)
Definition: _parasite.gsc:89
‪PARASITE_MOVE_DIST_MAX
‪#define PARASITE_MOVE_DIST_MAX
Definition: _parasite.gsc:39
‪path_update_interrupt
‪function path_update_interrupt()
Definition: _parasite.gsc:690
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪drone_pain
‪function drone_pain(eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName)
Definition: _parasite.gsc:756
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪parasite_initialize
‪function parasite_initialize()
Definition: _parasite.gsc:234
‪PARASITE_RADIUS
‪#define PARASITE_RADIUS
Definition: _parasite.gsc:28
‪get_behavior_attribute
‪function get_behavior_attribute(attribute)
Definition: ai_shared.gsc:184
‪state_combat_update
‪function state_combat_update(params)
Definition: _parasite.gsc:342
‪CreateInterfaceForEntity
‪function CreateInterfaceForEntity(entity)
Definition: ai_interface.gsc:110
‪__init__
‪function __init__()
Definition: _parasite.gsc:54
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪parasite_target_selection
‪function private parasite_target_selection()
Definition: _parasite.gsc:196
‪getParasiteFiringRate
‪function getParasiteFiringRate()
Definition: _parasite.gsc:295
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪PARASITE_JUKE_MOVE_DIST_MAX
‪#define PARASITE_JUKE_MOVE_DIST_MAX
Definition: _parasite.gsc:40