‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_hunter.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\gameskill_shared;
4 #using scripts\shared\hostmigration_shared;
5 #using scripts\shared\math_shared;
6 #using scripts\shared\array_shared;
7 #using scripts\shared\statemachine_shared;
8 #using scripts\shared\system_shared;
9 #using scripts\shared\util_shared;
10 #using scripts\shared\vehicle_shared;
11 #using scripts\shared\vehicle_death_shared;
12 #using scripts\shared\vehicle_ai_shared;
13 #using scripts\shared\vehicles\_attack_drone;
14 #using scripts\shared\flag_shared;
15 #using scripts\shared\turret_shared;
16 #using scripts\shared\ai_shared;
17 #using scripts\shared\ai\systems\ai_interface;
18 //#using scripts\cp\_util; // for getOtherTeam function
19 
20 #insert scripts\shared\shared.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 
26 #define HUNTER_RADIUS 200
27 #define HUNTER_HALFHEIGHT 100
28 
29 // Speeds
30 #define HUNTER_UNAWARE_SPEED_RATIO 0.5
31 #define HUNTER_COMBAT_SPEED_RATIO 1.0
32 #define HUNTER_STRAFE_SPEED_RATIO 2.0
33 
34 // scanner
35 #define HUNTER_SCANNER_TAG "tag_gunner_flash3"
36 #define HUNTER_SCANNER_SCANSPEED 1
37 #define HUNTER_SCANNER_PITCH 50 // 0 as horizontal, 90 as straight down
38 #define HUNTER_SCANNER_RANGE_PITCH 20
39 #define HUNTER_SCANNER_RANGE_YAW 45
40 #define HUNTER_SCANNER_FOV 190 //90
41 #define HUNTER_SCANNER_VIEW_DISTANCE 10000
42 
43 // weapon
44 #define HUNTER_MISSILE_WEAPON "hunter_rocket_turret"
45 #define HUNTER_MISSILE_WEAPON_PLAYER "hunter_rocket_turret_player"
46 #define HUNTER_TURRET_RANGE 1500
47 #define HUNTER_MISSILE_LOCKON_DELAY 1.5 // tunable length of persistent sight on target before fire rocket
48 #define HUNTER_MISSILE_MINIMAL_INTERVAL 8
49 
50 // drone
51 #define HUNTER_DRONE_SPAWNER "spawner_bo3_attack_drone_enemy"
52 #define HUNTER_WAITTIME_BEFORE_DEPLOYDRONE 2.2 // will wait this amount of time after player run into a non-reachable space to deploy attack drones
53 
54 // other
55 #define HUNTER_ATTACK_TARGET_RANGE 1200
56 #define HUNTER_FOLLOWING_TARGET_RANGE 1200
57 #define HUNTER_CHANGE_POSITION_TOATTACK_TARGET_DELAY 0.5
58 #define HUNTER_GOAL_POINT_STEP HUNTER_RADIUS * 4
59 
60 // pain
61 #define HUNTER_DAMAGE_AMOUNT_TO_SHOW_PAIN 1000 // 0 to disable
62 
63 // feature control
64 #define HUNTER_ENABLE_SCANNER_FX false
65 #define HUNTER_ENABLE_SIDETURRETS_YIELD_MAINTURRET_TARGET true // if true, side turret will not choose same target as main turret (so the player being targeted won't get cross fired by all three turrets)
66 #define HUNTER_ENABLE_WEAKSPOTS false
67 #define HUNTER_ENABLE_ATTACK_DRONES false
68 
69 #define HUNTER_SEEK_ENEMY_DELAY 1.0
70 
71 #define HUNTER_STRAFE_COOLDOWN 2.0
72 #define HUNTER_STRAFE_DISTANCE_TO_ENEMY_DISTANCE_RATIO 0.08
73 
74 #namespace hunter;
75 
76 ‪REGISTER_SYSTEM( "hunter", &‪__init__, undefined )
77 
78 #using_animtree( "generic" );
79 
80 // ----------------------------------------------
81 // initialization
82 // ----------------------------------------------
83 function ‪__init__()
84 {
86  vehicle::add_main_callback( "hunter", &‪hunter_initialize );
87 }
88 
89 function ‪RegisterInterfaceAttributes( archetype )
90 {
92 
93  // Strafe distance
95  archetype,
96  "strafe_speed",
97  0,
98  0, 100 );
99 
101  archetype,
102  "strafe_distance",
103  0,
104  0, 10000 );
105 }
106 
108 {
109  self.weakSpotTags = [];
111  {
112  ‪ARRAY_ADD( self.weakSpotTags, "tag_target_l" );
113  ‪ARRAY_ADD( self.weakSpotTags, "tag_target_r" );
114  }
115 
116  self.explosiveWeakSpotTags = [];
118  {
119  ‪ARRAY_ADD( self.explosiveWeakSpotTags, "tag_fan_base_l" );
120  ‪ARRAY_ADD( self.explosiveWeakSpotTags, "tag_fan_base_r" );
121  }
122 
123  self.missileTags = [];
124  ‪ARRAY_ADD( self.missileTags, "tag_rocket1" );
125  ‪ARRAY_ADD( self.missileTags, "tag_rocket2" );
126 
127  self.droneAttachTags = [];
129  {
130  ‪ARRAY_ADD( self.droneAttachTags, "tag_drone_attach_l" );
131  ‪ARRAY_ADD( self.droneAttachTags, "tag_drone_attach_r" );
132  }
133 }
134 
136 {
137  self.dronesOwned = [];
138 
140  {
141  foreach( droneTag in self.droneAttachTags )
142  {
143  origin = self GetTagOrigin( droneTag );
144  angles = self GetTagAngles( droneTag );
145 
146  drone = SpawnVehicle( ‪HUNTER_DRONE_SPAWNER, origin, angles );
147 
148  drone.owner = self;
149  drone.attachTag = droneTag;
150  drone.team = self.team;
151 
152  ‪ARRAY_ADD( self.dronesOwned, drone );
153  }
154  }
155 }
156 
158 {
159  self endon( "death" );
160 
161  self UseAnimTree( #animtree );
162 
163  Target_Set( self, ( 0, 0, 90 ) );
164 
166 
167  self.health = self.healthdefault;
168 
170 
171  //self EnableAimAssist();
172  self SetNearGoalNotifyDist( 50 );
173 
174  self SetHoverParams( 15, 100, 40 );
175  self.flyheight = GetDvarFloat( "g_quadrotorFlyHeight" );
176 
177  self.fovcosine = 0; // +/-90 degrees = 180
178  self.fovcosinebusy = 0.574; //+/- 55 degrees = 110 fov
179 
180  self.vehAirCraftCollisionEnabled = true;
181 
182  self.original_vehicle_type = self.vehicletype;
183 
184  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
185 
186  self.goalRadius = 999999;
187  self.goalHeight = 999999;
188  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
189 
191 
192  self.overrideVehicleDamage = &‪HunterCallback_VehicleDamage;
193 
194  self thread ‪vehicle_ai::nudge_collision();
195 
196  //disable some cybercom abilities
197  if( IsDefined( level.vehicle_initializer_cb ) )
198  {
199  [[level.vehicle_initializer_cb]]( self );
200  }
201 
202  self.ignoreFireFly = true;
203  self.ignoreDecoy = true;
205 
206 // self thread hunter_frontScanning();
207 
208 // self hunter_SpawnDrones();
209 //
210 // wait 0.5;
211 //
212 // foreach ( drone in self.dronesOwned )
213 // {
214 // if ( isalive( drone ) )
215 // {
216 // drone vehicle_ai::set_state( "attached" );
217 // }
218 // }
219  self ‪turret::_init_turret( 1 );
220  self ‪turret::_init_turret( 2 );
221 
224 
225  self ‪turret::set_burst_parameters( 1, 2, 1, 2, 1 );
226  self ‪turret::set_burst_parameters( 1, 2, 1, 2, 2 );
227 
230 
232 
233  self PathVariableOffset( (10, 10, -30), 1 );
234 
235  ‪defaultRole();
236 }
237 
238 function ‪defaultRole()
239 {
241 
242  self ‪vehicle_ai::get_state_callbacks( "combat" ).enter_func = &‪state_combat_enter;
243  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
244  self ‪vehicle_ai::get_state_callbacks( "combat" ).exit_func = &‪state_combat_exit;
245 
246  self ‪vehicle_ai::get_state_callbacks( "driving" ).enter_func = &‪hunter_scripted;
247  self ‪vehicle_ai::get_state_callbacks( "scripted" ).enter_func = &‪hunter_scripted;
248 
249  self ‪vehicle_ai::get_state_callbacks( "death" ).enter_func = &‪state_death_enter;
250  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
251 
252  self ‪vehicle_ai::get_state_callbacks( "emped" ).update_func = &‪hunter_emped;
253 
254  self ‪vehicle_ai::add_state( "unaware",
255  undefined,
258 
259  ‪vehicle_ai::add_interrupt_connection( "unaware", "scripted", "enter_scripted" );
260  ‪vehicle_ai::add_interrupt_connection( "unaware", "emped", "emped" );
261  ‪vehicle_ai::add_interrupt_connection( "unaware", "off", "shut_off" );
262  ‪vehicle_ai::add_interrupt_connection( "unaware", "driving", "enter_vehicle" );
263  ‪vehicle_ai::add_interrupt_connection( "unaware", "pain", "pain" );
264 
265  self ‪vehicle_ai::add_state( "strafe",
269 
270  ‪vehicle_ai::add_interrupt_connection( "strafe", "scripted", "enter_scripted" );
271  ‪vehicle_ai::add_interrupt_connection( "strafe", "emped", "emped" );
272  ‪vehicle_ai::add_interrupt_connection( "strafe", "off", "shut_off" );
273  ‪vehicle_ai::add_interrupt_connection( "strafe", "driving", "enter_vehicle" );
274  ‪vehicle_ai::add_interrupt_connection( "strafe", "pain", "pain" );
275  ‪vehicle_ai::add_utility_connection( "strafe", "combat" );
276 
277  ‪vehicle_ai::add_utility_connection( "emped", "strafe" );
278  ‪vehicle_ai::add_utility_connection( "pain", "strafe" );
279 
281 }
282 
283 // ----------------------------------------------
284 // State: death
285 // ----------------------------------------------
286 function ‪shut_off_fx()
287 {
288  self endon( "death" );
289 
290  self notify( "death_shut_off" );
291 
292  if ( isdefined( self.frontScanner ) )
293  {
294  self.frontScanner.sndScanningEnt delete();
295  self.frontScanner delete();
296  }
297 }
298 
299 function ‪kill_drones()
300 {
301  self endon( "death" );
302 
303  foreach ( drone in self.dronesOwned )
304  {
305  if ( isalive( drone ) && Distance2DSquared( self.origin, drone.origin ) < ‪SQR( 80 ) )
306  {
307  damageOrigin = self.origin + (0,0,1);
308  drone finishVehicleRadiusDamage(self.death_info.attacker, self.death_info.attacker, 32000, 32000, 10, 0, "MOD_EXPLOSIVE", level.weaponNone, damageOrigin, 400, -1, (0,0,1), 0);
309  }
310  }
311 }
312 
313 function ‪state_death_enter( params )
314 {
315  self endon( "death" );
316 
317  if ( isdefined( self.fakeTargetEnt ) )
318  {
319  self.fakeTargetEnt Delete();
320  }
321 
323 
324  self.inpain = true;
325 
326  self thread ‪shut_off_fx();
327  //self thread kill_drones();
328 }
329 
330 function ‪state_death_update( params )
331 {
332  self endon( "death" );
333 
334  death_type = ‪vehicle_ai::get_death_type( params );
335  if ( !isdefined( death_type ) )
336  {
337  params.death_type = "gibbed";
338  death_type = params.death_type;
339  }
340 
343  self CancelAIMove();
344  self SetSpeedImmediate( 0 );
345  self SetVehVelocity( ( 0, 0, 0 ) );
346  self SetPhysAcceleration( ( 0, 0, 0 ) );
347  self SetAngularVelocity( ( 0, 0, 0 ) );
349 }
350 // ----------------------------------------------
351 
352 // ----------------------------------------------
353 // State: unaware
354 // ----------------------------------------------
355 function ‪state_unaware_enter( params )
356 {
358  accel = self GetDefaultAcceleration();
359  self SetSpeed( ratio * self.settings.defaultmovespeed, ratio * accel, ratio * accel );
360 }
361 
362 function ‪state_unaware_update( params )
363 {
364  self endon( "change_state" );
365  self endon( "death" );
366 
367  if ( isdefined( self.enemy ) )
368  {
369  self ‪vehicle_ai::set_state( "combat" );
370  }
371 
372  self ClearLookAtEnt();
373  self ‪disable_turrets();
374  self thread ‪Movement_Thread_Wander();
375 
376  while ( 1 )
377  {
378  self waittill( "enemy" );
379  self ‪vehicle_ai::set_state( "combat" );
380  }
381 }
382 
383 function ‪state_unaware_exit( params )
384 {
385  self notify( "end_movement_thread" );
386 }
387 
389 {
390  self endon( "death" );
391  self notify( "end_movement_thread" );
392  self endon( "end_movement_thread" );
393 
394  constMinSearchRadius = 120;
395  constMaxSearchRadius = 800;
396 
397  minSearchRadius = ‪math::clamp( constMinSearchRadius, 0, self.goalRadius );
398  maxSearchRadius = ‪math::clamp( constMaxSearchRadius, constMinSearchRadius, self.goalRadius );
399  halfHeight = 400;
400  innerSpacing = 80;
401  outerSpacing = 50;
402  maxGoalTimeout = 15;
403  timeAtSamePosition = 2.5 + randomfloat( 1 );
404 
405  while ( true )
406  {
407  queryResult = PositionQuery_Source_Navigation( self.origin, minSearchRadius, maxSearchRadius, halfHeight, innerSpacing, self, outerSpacing );
408  PositionQuery_Filter_DistanceToGoal( queryResult, self );
410  ‪vehicle_ai::PositionQuery_Filter_Random( queryResult, 0, 10 );
412 
413  stayAtGoal = timeAtSamePosition > 0.2;
414 
415  foundpath = false;
416  for ( i = 0; i < queryResult.data.size && !foundpath; i++ )
417  {
418  goalPos = queryResult.data[i].origin;
419  foundpath = self SetVehGoalPos( goalPos, stayAtGoal, true );
420  }
421 
422  if ( foundPath )
423  {
424  msg = self ‪util::waittill_any_timeout( maxGoalTimeout, "near_goal", "force_goal", "reached_end_node", "goal" );
425 
426  if ( stayAtGoal )
427  {
428  wait randomFloatRange( 0.5 * timeAtSamePosition, timeAtSamePosition );
429  }
430  }
431  else
432  {
433  wait 1;
434  }
435  }
436 }
437 // ----------------------------------------------
438 
439 // ----------------------------------------------
440 // State: combat
441 // ----------------------------------------------
443 {
444  //self turret::enable( 0, false );
445  self ‪turret::enable( 1, false );
446  self ‪turret::enable( 2, false );
447 }
448 
450 {
451  //self turret::disable( 0 );
452  self ‪turret::disable( 1 );
453  self ‪turret::disable( 2 );
455 }
456 
458 {
459  self SetTurretTargetRelativeAngles( (10, -90, 0), 1 );
460  self SetTurretTargetRelativeAngles( (10, 90, 0), 2 );
461 }
462 
463 function ‪state_combat_enter( params )
464 {
466  accel = self GetDefaultAcceleration();
467  self SetSpeed( ratio * self.settings.defaultmovespeed, ratio * accel, ratio * accel );
468 
469  self ‪hunter_lockon_fx();
470 
471  self ‪enable_turrets();
472 }
473 
474 function ‪state_combat_update( params )
475 {
476  self endon( "change_state" );
477  self endon( "death" );
478 
479  if ( !isdefined( self.enemy ) )
480  {
481  self ‪vehicle_ai::set_state( "unaware" );
482  }
483 
484  self thread ‪Movement_Thread_StayInDistance();
485  self thread ‪Attack_Thread_MainTurret();
486  self thread ‪Attack_Thread_rocket();
487 
488  while ( 1 )
489  {
490  self waittill( "no_enemy" );
491  self ‪vehicle_ai::set_state( "unaware" );
492  }
493 }
494 
495 function ‪state_combat_exit( params )
496 {
497  self notify( "end_attack_thread" );
498  self notify( "end_movement_thread" );
499  self ClearTurretTarget();
500 }
501 // ----------------------------------------------
502 
503 // ----------------------------------------------
504 // State: strafe
505 // ----------------------------------------------
506 function ‪state_strafe_enter( params )
507 {
509  accel = ratio * self GetDefaultAcceleration();
510  speed = ratio * self.settings.defaultmovespeed;
511  strafe_speed_attribute = ‪ai::get_behavior_attribute("strafe_speed");
512  if ( strafe_speed_attribute > 0 )
513  {
514  speed = strafe_speed_attribute;
515  }
516  self SetSpeed( speed , accel, accel );
517 }
518 
519 function ‪state_strafe_update( params )
520 {
521  self endon( "change_state" );
522  self endon( "death" );
523 
524  self ClearVehGoalPos();
525 
526  distanceToTarget = 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax );
527 
528  target = self.origin + AnglesToForward( self.angles ) * distanceToTarget;
529  if ( isdefined( self.enemy ) )
530  {
531  distanceToTarget = Distance( self.origin, self.enemy.origin );
532  }
533 
534  distanceThreshold = 500 + distanceToTarget * ‪HUNTER_STRAFE_DISTANCE_TO_ENEMY_DISTANCE_RATIO;
535  strafe_distance_attribute = ‪ai::get_behavior_attribute("strafe_distance");
536  if ( strafe_distance_attribute > 0 )
537  {
538  distanceThreshold = strafe_distance_attribute;
539  }
540 
541  maxSearchRadius = distanceThreshold * 1.5;
542  halfHeight = 300;
543  outerSpacing = maxSearchRadius * 0.05;
544  innerSpacing = outerSpacing * 2;
545 
546  queryResult = PositionQuery_Source_Navigation( self.origin, 0, maxSearchRadius, halfHeight, innerSpacing, self, outerSpacing );
547  PositionQuery_Filter_Directness( queryResult, self.origin, target );
548  PositionQuery_Filter_DistanceToGoal( queryResult, self );
549  PositionQuery_Filter_InClaimedLocation( queryResult, self );
551 
552  foreach ( point in queryResult.data )
553  {
554  distanceToPointSqr = distanceSquared( point.origin, self.origin );
555  if( distanceToPointSqr < distanceThreshold * 0.5 )
556  {
557  ADD_POINT_SCORE( point, "distAway", -distanceThreshold );
558  }
559  ADD_POINT_SCORE( point, "distAway", sqrt( distanceToPointSqr ) );
560 
561  diffToPreferedDirectness = abs( point.directness - 0 );
562  directnessScore = MapFloat( 0, 1, 1000, 0, diffToPreferedDirectness );
563  if ( diffToPreferedDirectness > 0.1 )
564  {
565  directnessScore -= 500;
566  }
567  ADD_POINT_SCORE( point, "directnessRaw", point.directness );
568  ADD_POINT_SCORE( point, "directness", directnessScore );
569 
570  if ( point.directionChange < 0.6 )
571  {
572  ADD_POINT_SCORE( point, "directionChange", -2000 );
573  }
574  ADD_POINT_SCORE( point, "directionChangeRaw", point.directionChange );
575  }
576 
578  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
579 
580  foreach ( point in queryResult.data )
581  {
582  self.current_pathto_pos = point.origin;
583 
584  foundpath = self SetVehGoalPos( self.current_pathto_pos, true, true );
585 
586  if ( foundPath )
587  {
588  msg = self ‪util::waittill_any_timeout( 5, "near_goal", "force_goal", "goal", "enemy_visible" );
589  break;
590  }
591  }
592 
593  previous_state = self ‪vehicle_ai::get_previous_state();
594 
595  if ( !isdefined( previous_state ) || previous_state == "strafe" )
596  {
597  previous_state = "combat";
598  }
599 
600  self ‪vehicle_ai::set_state( previous_state );
601 }
602 
603 function ‪state_strafe_exit( params )
604 {
606 }
607 
608 // ----------------------------------------------
609 
611 {
612  if( self.goalforced )
613  {
614  return self.goalpos;
615  }
616 
617  selfDistToEnemy = Distance2D( self.origin, enemy.origin );
618 
619  // distance based multipliers
620  goodDist = 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax );
621 
622  tooCloseDist = 0.8 * goodDist;
623  closeDist = 1.2 * goodDist;
624  farDist = 3 * goodDist;
625 
626  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToEnemy );
627 
628  preferedDistAwayFromOrigin = 150;
629 
630  maxSearchRadius = 1000 * queryMultiplier;
631  halfHeight = 300 * queryMultiplier;
632  innerSpacing = 80 * queryMultiplier;
633  outerSpacing = 80 * queryMultiplier;
634 
635  queryResult = PositionQuery_Source_Navigation( self.origin, 0, maxSearchRadius, halfHeight, innerSpacing, self, outerSpacing );
636  PositionQuery_Filter_DistanceToGoal( queryResult, self );
637  PositionQuery_Filter_InClaimedLocation( queryResult, self );
638  PositionQuery_Filter_Sight( queryResult, enemy.origin, self GetEye() - self.origin, self, 0, enemy );
640  self ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, enemy, self.settings.engagementDistMin, self.settings.engagementDistMax );
641  self ‪vehicle_ai::PositionQuery_Filter_Random( queryResult, 0, 30 );
642 
643  goalHeight = enemy.origin[2] + 0.5 * ( self.settings.engagementHeightMin + self.settings.engagementHeightMax );
644 
645  foreach ( point in queryResult.data )
646  {
647  if ( !point.visibility )
648  {
649  ADD_POINT_SCORE( point, "no visibility", -600 );
650  }
651 
652  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
653 
654  // distance from origin
655  ADD_POINT_SCORE( point, "distToOrigin", MapFloat( 0, preferedDistAwayFromOrigin, 0, 600, point.distToOrigin2D ) );
656 
657  if( point.inClaimedLocation )
658  {
659  ADD_POINT_SCORE( point, "inClaimedLocation", -500 );
660  }
661 
662  // height
663  preferedHeightRange = 75;
664  distFromPreferredHeight = abs( point.origin[2] - goalHeight );
665  if ( distFromPreferredHeight > preferedHeightRange )
666  {
667  heightScore = -MapFloat( preferedHeightRange, 5000, 0, 9000, distFromPreferredHeight );
668  ADD_POINT_SCORE( point, "height", heightScore );
669  }
670  }
671  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
672 
674 
675  if( queryResult.data.size )
676  {
677  return queryResult.data[0].origin;
678  }
679 
680  return self.origin;
681 }
682 
684 {
685  self endon( "death" );
686  self notify( "end_movement_thread" );
687  self endon( "end_movement_thread" );
688 
689  maxGoalTimeout = 10;
690 
691  stuckCount = 0;
692 
693  while ( true )
694  {
695  enemy = self.enemy;
696  if ( !isdefined( enemy ) )
697  {
698  wait 1;
699  continue;
700  }
701 
702  usePathfinding = true;
703  onNavVolume = IsPointInNavVolume( self.origin, "navvolume_big" );
704  if ( !onNavVolume )
705  {
706  // off nav volume, try getting back
707  getbackPoint = undefined;
708  pointOnNavVolume = self GetClosestPointOnNavVolume( self.origin, 500 );
709  if ( isdefined( pointOnNavVolume ) )
710  {
711  if ( SightTracePassed( self.origin, pointOnNavVolume, false, self ) )
712  {
713  getbackPoint = pointOnNavVolume;
714  }
715  }
716 
717  if ( !isdefined( getbackPoint ) )
718  {
719  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 800, 400, 1.5 * self.radius );
720  PositionQuery_Filter_Sight( queryResult, self.origin, (0, 0, 0), self, 1 );
721  getbackPoint = undefined;
722  foreach( point in queryResult.data )
723  {
724  if ( point.visibility === true )
725  {
726  getbackPoint = point.origin;
727  break;
728  }
729  }
730  }
731 
732  if ( isdefined( getbackPoint ) )
733  {
734  self.current_pathto_pos = getbackPoint;
735  usePathfinding = false;
736  }
737  else
738  {
739  stuckCount++;
740  if ( stuckCount == 1 )
741  {
742  stuckLocation = self.origin;
743  }
744  else if ( stuckCount > 10 )
745  {
746  /#
747  assert( false, "Hunter fall outside of NavVolume at " + self.origin );
748  v_box_min = ( -self.radius, -self.radius, -self.radius );
749  v_box_max = ( self.radius, self.radius, self.radius );
750  Box( self.origin, v_box_min, v_box_max, self.angles[1], (1,0,0), 1, false, 1000000 );
751  if ( isdefined( stuckLocation ) )
752  {
753  Line( stuckLocation, self.origin, (1,0,0), 1, true, 1000000 );
754  }
755  #/
756  self Kill();
757  }
758  }
759  }
760  else
761  {
762  stuckCount = 0;
763 
764  if( self.goalforced )
765  {
766  goalpos = self GetClosestPointOnNavVolume( self.goalpos, 200 );
767  if ( isdefined( goalpos ) )
768  {
769  self.current_pathto_pos = goalpos;
770  usePathfinding = true;
771  }
772  else
773  {
774  self.current_pathto_pos = self.goalpos;
775  usePathfinding = false;
776  }
777  }
778  else
779  {
780  self.current_pathto_pos = ‪GetNextMovePosition_tactical( enemy );
781  usePathfinding = true;
782  }
783  }
784 
785  if ( !isDefined( self.current_pathto_pos ) )
786  {
787  wait 0.5;
788  continue;
789  }
790 
791  distanceToGoalSq = DistanceSquared( self.current_pathto_pos, self.origin );
792 
793  if ( distanceToGoalSq > ‪SQR( 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax ) ) )
794  {
795  self SetSpeed( self.settings.defaultMoveSpeed * 2 );
796  }
797  else
798  {
799  self SetSpeed( self.settings.defaultMoveSpeed );
800  }
801 
802  self SetLookAtEnt( enemy );
803 
804  foundpath = self SetVehGoalPos( self.current_pathto_pos, true, usePathfinding );
805 
806  if ( foundPath )
807  {
808  /#
809  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
810  {
811  recordLine( self.origin, self.current_pathto_pos, (0.3,1,0) );
812  recordLine( self.origin, enemy.origin, (1,0,0.4) );
813  }
814  #/
815 
816  msg = self ‪util::waittill_any_timeout( maxGoalTimeout, "near_goal", "force_goal", "goal" );
817  }
818  else
819  {
820  wait 0.5;
821  }
822 
823  enemy = self.enemy;
824  if ( isdefined( enemy ) )
825  {
826  goalHeight = enemy.origin[2] + 0.5 * ( self.settings.engagementHeightMin + self.settings.engagementHeightMax );
827  distFromPreferredHeight = abs( self.origin[2] - goalHeight );
828 
829  farDist = self.settings.engagementDistMax;
830  nearDist = self.settings.engagementDistMin;
831 
832  selfDistToEnemy = Distance2D( self.origin, enemy.origin );
833 
834  if ( self VehCanSee( enemy ) && selfDistToEnemy < farDist && selfDistToEnemy > nearDist && distFromPreferredHeight < 230 )
835  {
836  msg = self ‪util::waittill_any_timeout( RandomFloatRange( 2, 4 ), "enemy_not_visible" );
837  if ( msg == "enemy_not_visible" )
838  {
839  msg = self ‪util::waittill_any_timeout( ‪HUNTER_SEEK_ENEMY_DELAY, "enemy_visible" );
840  if ( msg != "timeout" )
841  {
842  wait 1;
843  }
844  }
845  }
846  }
847  else
848  {
849  wait 1;
850  }
851  }
852 }
853 
854 function ‪Delay_Target_ToEnemy_Thread( point, enemy, timeToHit )
855 {
856  self endon( "death" );
857  self endon( "change_state" );
858  self endon( "end_attack_thread" );
859  self endon( "faketarget_stop_moving" );
860  enemy endon( "death" );
861 
862  if ( !isdefined( self.fakeTargetEnt ) )
863  {
864  self.fakeTargetEnt = ‪Spawn( "script_origin", point );
865  }
866 
867  self.fakeTargetEnt Unlink();
868 
869  self.fakeTargetEnt.origin = point;
870  self SetTurretTargetEnt( self.fakeTargetEnt );
871  self waittill( "turret_on_target" );
872 
873  timeStart = GetTime();
874  offset = (0, 0, 0);
875  if( IsSentient( enemy ) )
876  {
877  offset = enemy GetEye() - enemy.origin;
878  }
879 
880  while( GetTime() < timeStart + timeToHit * 1000 )
881  {
882  self.fakeTargetEnt.origin = LerpVector( point, enemy.origin + offset, ( GetTime() - timeStart ) / ( timeToHit * 1000 ) );
885  }
886 
887  self.fakeTargetEnt.origin = enemy.origin + offset;
889  self.fakeTargetEnt LinkTo( enemy );
890 }
891 
893 {
894  self endon( "death" );
895  self endon( "change_state" );
896  self endon( "end_attack_thread" );
897 
898  while( 1 )
899  {
900  enemy = self.enemy;
901  if( isdefined( enemy ) )
902  {
903  self SetLookAtEnt( enemy );
904 
905  if( self VehCanSee( enemy ) )
906  {
907  vectorFromEnemy = VectorNormalize( ‪FLAT_ORIGIN( (self.origin - enemy.origin) ) );
908 
909  self thread ‪Delay_Target_ToEnemy_Thread( enemy.origin + vectorFromEnemy * 300, enemy, 1.5 );
910 
911  self waittill( "turret_on_target" );
912  self ‪vehicle_ai::fire_for_time( 2 + RandomFloat( 0.8 ) );
913 
914  self ClearTurretTarget();
915  self SetTurretTargetRelativeAngles( (15,0,0), 0 );
916 
917  if( isdefined( enemy ) && IsAI( enemy ) )
918  {
919  wait( 2.5 + RandomFloat( 0.5 ) );
920  }
921  else
922  {
923  wait( 2.0 + RandomFloat( 0.4 ) );
924  }
925  }
926  else
927  {
928  wait 0.4;
929  }
930  }
931  else
932  {
933  self ClearTurretTarget();
934  self ClearLookAtEnt();
935  wait 0.4;
936  }
937  }
938 }
939 
941 {
942  self endon( "death" );
943  self endon( "change_state" );
944  self endon( "end_attack_thread" );
945 
946  while( true )
947  {
948  enemy = self.enemy;
949  if ( !isdefined( enemy ) )
950  {
951  wait 1;
952  continue;
953  }
954 
955  if ( isdefined( enemy ) && self VehCanSee( enemy ) && ‪vehicle_ai::IsCooldownReady( "rocket_launcher" ) )
956  {
958 
959  self notify( "end_movement_thread" );
960  self ClearVehGoalPos();
961  self SetVehGoalPos( self.origin, true, false );
962 
963  target = enemy.origin;
964  self SetLookAtEnt( enemy );
965  self ‪hunter_lockon_fx();
966 
968 
969  eye = self GetTagOrigin( "tag_eye" );
970  if ( isdefined( enemy ) )
971  {
972  anglesToTarget = VectorToAngles( enemy.origin - eye );
973  angles = anglesToTarget - self.angles;
974  if ( -30 < angles[0] && angles[0] < 60 && -70 < angles[1] && angles[1] < 70 )
975  {
976  target = enemy.origin;
977  }
978  else
979  {
980  anglesToTarget = VectorToAngles( target - eye );
981  }
982  }
983  else
984  {
985  anglesToTarget = VectorToAngles( target - eye );
986  }
987 
988  rightDir = AnglesToRight( anglesToTarget );
989 
990  randomRange = 30;
991  offset = [];
992  offset[0] = -rightDir * randomRange * 2 + ( RandomFloatRange( -randomRange, randomRange ), RandomFloatRange( -randomRange, randomRange ), 0 );
993  offset[1] = rightDir * randomRange * 2 + ( RandomFloatRange( -randomRange, randomRange ), RandomFloatRange( -randomRange, randomRange ), 0 );
994 
995  self ‪hunter_fire_one_missile( 0, target, offset[0] );
996 
997  wait 0.5;
998 
999  if ( isdefined( enemy ) )
1000  {
1001  eye = self GetTagOrigin( "tag_eye" );
1002  angles = VectorToAngles( enemy.origin - eye ) - self.angles;
1003  if ( -30 < angles[0] && angles[0] < 60 && -70 < angles[1] && angles[1] < 70 )
1004  {
1005  target = enemy.origin;
1006  }
1007  }
1008  self ‪hunter_fire_one_missile( 1, target, offset[1] );
1009 
1010  wait 1;
1011 
1012  self thread ‪Movement_Thread_StayInDistance();
1013  }
1014  wait 0.5;
1015  }
1016 }
1017 // ----------------------------------------------
1018 
1019 // best target of side turrets: closest, can hit, and not target of main turret or other turret
1020 function ‪side_turret_get_best_target( a_potential_targets, n_index )
1021 {
1022  if ( self.ignoreall === true )
1023  {
1024  return undefined;
1025  }
1026 
1027  shouldYield = ‪HUNTER_ENABLE_SIDETURRETS_YIELD_MAINTURRET_TARGET && level.gameskill < 3;
1028 
1029  main_turret_target = self.enemy;
1030 
1031  if ( n_index === 2 )
1032  {
1033  other_turret_target = ‪turret::get_target( 1 );
1034  }
1035 
1036  if ( shouldYield )
1037  {
1038  ArrayRemoveValue( a_potential_targets, main_turret_target );
1039  ArrayRemoveValue( a_potential_targets, other_turret_target );
1040  }
1041 
1042  e_best_target = undefined;
1043 
1044  while ( !isdefined( e_best_target ) && ( a_potential_targets.size > 0 ) )
1045  {
1046  e_closest_target = ArrayGetClosest( self.origin, a_potential_targets );
1047 
1048  if( self ‪turret::can_hit_target( e_closest_target, n_index ) )
1049  {
1050  e_best_target = e_closest_target;
1051  }
1052  else
1053  {
1054  ArrayRemoveValue( a_potential_targets, e_closest_target );
1055  }
1056  }
1057 
1058  return e_best_target;
1059 }
1060 
1061 // ----------------------------------------------
1062 // missile
1063 // ----------------------------------------------
1064 function ‪hunter_fire_one_missile( launcher_index, target, offset, blinkLights, waittimeAfterBlinkLights )
1065 {
1066  self endon( "death" );
1067 
1068  if ( ‪IS_TRUE( blinkLights ) )
1069  {
1071 
1072  if ( isdefined( waittimeAfterBlinkLights ) && waittimeAfterBlinkLights > 0 )
1073  {
1074  wait waittimeAfterBlinkLights;
1075  }
1076  }
1077 
1078  if ( !isdefined( offset ) )
1079  {
1080  offset = ( 0, 0, 0 );
1081  }
1082 
1083  spawnTag = self.missileTags[ launcher_index ];
1084  origin = self GetTagOrigin( spawnTag );
1085  angles = self GetTagAngles( spawnTag );
1086  forward = AnglesToForward( angles );
1087  up = AnglesToUp( angles );
1088 
1089  if ( isdefined( spawnTag ) && isdefined( target ) )
1090  {
1091  weapon = GetWeapon( ‪HUNTER_MISSILE_WEAPON );
1092 
1093  //only do the full MagicBullet parameter list if target is a real entity, and not a script_struct
1094  if ( IsEntity( target ) )
1095  {
1096  missile = MagicBullet( weapon, origin, target.origin + offset, self, target, offset );
1097  //missile thread remote_missile_life();
1098  }
1099  else if ( IsVec( target ) )
1100  {
1101  missile = MagicBullet( weapon, origin, target + offset, self );
1102  }
1103  else
1104  {
1105  missile = MagicBullet( weapon, origin, target.origin + offset, self );
1106  }
1107  }
1108 }
1109 
1111 {
1112  self endon( "death" );
1113 
1115 
1116  playFX( level.remote_mortar_fx["missileExplode"], self.origin );
1117  self playlocalsound( "mpl_ks_reaper_explosion" );
1118  self delete();
1119 }
1120 
1122 {
1123  self thread ‪vehicle_ai::blink_lights_for_time( 1.5 );
1124  self playsound( "veh_hunter_alarm_target" );
1125 }
1126 
1127 //self == hunter
1128 function ‪getEnemyArray( include_ai, include_player )
1129 {
1130  enemyArray = [];
1131 
1132  enemy_team = "allies";//util::getOtherTeam( self.team );
1133 
1134  if ( ‪IS_TRUE( include_ai ) )
1135  {
1136  aiArray = GetAITeamArray( enemy_team );
1137  enemyArray = ArrayCombine( enemyArray, aiArray, false, false );
1138  }
1139 
1140  if ( ‪IS_TRUE( include_player ) )
1141  {
1142  playerArray = GetPlayers( enemy_team );
1143  enemyArray = ArrayCombine( enemyArray, playerArray, false, false );
1144  }
1145 
1146  return enemyArray;
1147 }
1148 
1149 // ----------------------------------------------
1150 // scanner
1151 // ----------------------------------------------
1152 
1153 //self == hunter
1154 function ‪is_point_in_view( point, do_trace )
1155 {
1156  if ( !isdefined( point ) )
1157  {
1158  return false;
1159  }
1160 
1161  scanner = self.frontScanner;
1162  vector_to_point = point - scanner.origin;
1163  in_view = ( LengthSquared( vector_to_point ) <= ‪SQR( ‪HUNTER_SCANNER_VIEW_DISTANCE ) );
1164 
1165  if ( in_view )
1166  {
1167  in_view = ‪util::within_fov( scanner.origin, scanner.angles, point, Cos( ‪HUNTER_SCANNER_FOV ) );
1168  }
1169 
1170  if ( in_view && ‪IS_TRUE( do_trace ) && isdefined( self.enemy ) )
1171  {
1172  in_view = SightTracePassed( scanner.origin, point, false, self.enemy );
1173  }
1174 
1175  return in_view;
1176 }
1177 
1178 //self == hunter
1179 function ‪is_valid_target( target, do_trace )
1180 {
1181  target_is_valid = true;
1182 
1183  // check script properties
1184  if ( ‪IS_TRUE( target.ignoreme ) || ( target.health <= 0 ) )
1185  {
1186  target_is_valid = false;
1187  }
1188  // check sentient properties
1189  else if ( IsSentient( target ) && ( ( target IsNoTarget() ) || ( target ‪ai::is_dead_sentient() ) ) )
1190  {
1191  target_is_valid = false;
1192  }
1193  // check fov
1194  else if ( isdefined( target.origin ) && !‪is_point_in_view( target.origin, do_trace ) )
1195  {
1196  target_is_valid = false;
1197  }
1198 
1199  return target_is_valid;
1200 }
1201 
1202 //self == hunter
1203 function ‪get_enemies_in_view( do_trace )
1204 {
1205  validEnemyArray = [];
1206  enemyArray = ‪getEnemyArray( true, true );
1207 
1208  foreach( enemy in enemyArray )
1209  {
1210  if ( ‪is_valid_target( enemy, do_trace ) )
1211  {
1212  ‪ARRAY_ADD( validEnemyArray, enemy );
1213  }
1214  }
1215 
1216  return validEnemyArray;
1217 }
1218 
1219 // self == hunter
1221 {
1222  self.frontScanner = ‪Spawn( "script_model", self GetTagOrigin( ‪HUNTER_SCANNER_TAG ) );
1223  self.frontScanner SetModel( "tag_origin" );
1224 
1225  self.frontScanner.angles = self GetTagAngles( ‪HUNTER_SCANNER_TAG );
1226  self.frontScanner LinkTo( self, ‪HUNTER_SCANNER_TAG );
1227 
1228  self.frontScanner.owner = self;
1229  self.frontScanner.hasTargetEnt = false;
1230 
1231  self.frontScanner.sndScanningEnt = ‪spawn( "script_origin", self.frontScanner.origin + anglesToForward( self.angles ) * 1000 );
1232  self.frontScanner.sndScanningEnt linkto( self.frontScanner );
1233 
1234  wait 0.25;
1235 
1236  //self.frontScanner thread hunter_scanner_lookTarget( self );
1237 
1239  {
1240  PlayFxOnTag( self.settings.spotlightfx, self.frontScanner, "tag_origin" );
1241  }
1242 }
1243 
1244 // self == hunter
1245 function ‪hunter_scanner_SetTargetEntity( targetEnt, offset )
1246 {
1247  if ( !isdefined( offset ) )
1248  {
1249  offset = ( 0, 0, 0 );
1250  }
1251 
1252  if( IsDefined( targetEnt ) )
1253  {
1254  self.frontScanner.targetEnt = targetEnt;
1255  self.frontScanner.hasTargetEnt = true;
1256  self SetGunnerTargetEnt( self.frontScanner.targetEnt, offset, 2 );
1257  }
1258 }
1259 
1260 // self == hunter
1262 {
1263  self.frontScanner.hasTargetEnt = false;
1264  self ClearGunnerTarget( 2 );
1265 }
1266 
1267 // self == hunter
1269 {
1270  if( IsDefined( targetPos ) )
1271  {
1272  self.frontScanner.targetPos = targetPos;
1273  self SetGunnerTargetVec( self.frontScanner.targetPos, 2 );
1274  }
1275 }
1276 
1278 {
1279  self endon( "death_shut_off" );
1280  self endon( "crash_done" );
1281  self endon( "death" );
1282 
1284 
1285  offsetFactorPitch = 0;
1286  offsetFactorYaw = 0;
1287 
1288  // use 2 different irrational numbers here to help avoiding repetitive patterns
1289  pitchStep = ‪HUNTER_SCANNER_SCANSPEED * 2.23606797749978969640; // irrational number sqrt(5)
1290  yawStep = ‪HUNTER_SCANNER_SCANSPEED * 3.14159265358979323846; // irrational number PI
1291 
1292  pitchRange = ‪HUNTER_SCANNER_RANGE_PITCH;
1293  yawRange = ‪HUNTER_SCANNER_RANGE_YAW;
1294 
1295  scannerDirection = undefined;
1296 
1297  while ( 1 )
1298  {
1299  scannerOrigin = self.frontScanner.origin;
1300 
1301  if ( ‪IS_TRUE( self.inpain ) )
1302  {
1303  wait 0.3;
1304  offset = ( ‪HUNTER_SCANNER_PITCH, 0, 0 ) + ( ‪math::randomSign() * RandomFloatRange( 1, 2 ) * pitchRange, ‪math::randomSign() * RandomFloatRange( 1, 2 ) * yawRange, 0 );
1305  scannerDirection = anglesToForward( self.angles + offset );
1306  }
1307  else if ( !IsDefined( self.enemy ) )
1308  {
1310  {
1311  self.frontScanner.sndScanningEnt playloopsound( "veh_hunter_scanner_loop", 1 );
1312  }
1313 
1314  offsetFactorPitch = offsetFactorPitch + pitchStep;
1315  offsetFactorYaw = offsetFactorYaw + yawStep;
1316 
1317  offset = ( ‪HUNTER_SCANNER_PITCH, 0, 0 ) + ( Sin( offsetFactorPitch ) * pitchRange, Cos( offsetFactorYaw ) * yawRange, 0 );
1318  scannerDirection = anglesToForward( self.angles + offset );
1319 
1320  enemies = ‪get_enemies_in_view( true );
1321 
1322  if ( enemies.size > 0 )
1323  {
1324  closest_enemy = ArrayGetClosest( self.origin, enemies );
1325 
1326  self.favoriteEnemy = closest_enemy;
1327  /# line( scannerOrigin, closest_enemy.origin, ( 0, 1, 0 ), 1, 3 ); #/
1328  }
1329  }
1330  else
1331  {
1332  if ( self ‪is_point_in_view( self.enemy.origin, true ) )
1333  {
1334  self notify ( "hunter_lockOnTargetInSight" );
1335  }
1336  else
1337  {
1338  self notify ( "hunter_lockOnTargetOutSight" );
1339  }
1340 
1341  scannerDirection = VectorNormalize( self.enemy.origin - scannerOrigin );
1342 
1344  {
1345  self.frontScanner.sndScanningEnt stoploopsound( 1 );
1346  }
1347  }
1348 
1349  targetLocation = scannerOrigin + scannerDirection * 1000; // any big value will do
1350  self ‪hunter_scanner_SetTargetPosition( targetLocation );
1351 
1352  /# line( scannerOrigin, self.frontScanner.targetPos, ( 0, 1, 0 ), 1, 1000 ); #/
1353  wait 0.1;
1354  }
1355 }
1356 
1358 {
1359  self waittill( "exit_vehicle", player );
1360 
1361  player.ignoreme = false;
1362  player DisableInvulnerability();
1363 
1364  self SetHeliHeightLock( false );
1365  self EnableAimAssist();
1366  self SetVehicleType( self.original_vehicle_type );
1367  self.attachedpath = undefined;
1368  self SetGoal( self.origin, false, 4096, 512 );
1369 }
1370 
1371 function ‪hunter_scripted( params )
1372 {
1373  // do nothing state
1374  params.driver = self GetSeatOccupant( 0 );
1375  if ( isdefined( params.driver ) )
1376  {
1377  self DisableAimAssist();
1378 
1379  self thread ‪vehicle_death::vehicle_damage_filter( "firestorm_turret" );
1380  //self thread hunter_set_team( driver.team );
1381  params.driver.ignoreme = true;
1382  params.driver EnableInvulnerability();
1383 
1384  if ( isdefined( self.vehicle_weapon_override ) )
1385  {
1386  self SetVehWeapon( self.vehicle_weapon_override );
1387  }
1388 
1389  self thread ‪hunter_exit_vehicle();
1390  //self thread hunter_update_rumble();
1391  self thread ‪hunter_collision_player();
1392  //self thread hunter_self_destruct();
1395  self thread ‪player_fire_update_rocket();
1396  }
1397 
1398  if ( isdefined( self.goal_node ) && isdefined( self.goal_node.hunter_claimed ) )
1399  {
1400  self.goal_node.hunter_claimed = undefined;
1401  }
1402 
1403  self ClearTargetEntity();
1404  self ClearVehGoalPos();
1405  self PathVariableOffsetClear();
1406  self PathFixedOffsetClear();
1407  self ClearLookAtEnt();
1408  self ResumeSpeed();
1409 }
1410 
1412 {
1413  self endon( "death" );
1414  self endon( "exit_vehicle" );
1415 
1416  weapon = self SeatGetWeapon( 1 );
1417  fireTime = weapon.fireTime;
1418 
1419  while( 1 )
1420  {
1421  self SetGunnerTargetVec( self GetTurretTargetVec( 0 ), 0 );
1422  if( self IsDriverFiring( ) )
1423  {
1424  self FireWeapon( 1 );
1425  }
1426  wait fireTime;
1427  }
1428 }
1429 
1431 {
1432  self endon( "death" );
1433  self endon( "exit_vehicle" );
1434 
1435  weapon = self SeatGetWeapon( 2 );
1436  fireTime = weapon.fireTime;
1437 
1438  while( 1 )
1439  {
1440  self SetGunnerTargetVec( self GetTurretTargetVec( 0 ), 1 );
1441  if( self IsDriverFiring( ) )
1442  {
1443  self FireWeapon( 2 );
1444  }
1445  wait fireTime;
1446  }
1447 }
1448 
1450 {
1451  self endon( "death" );
1452  self endon( "exit_vehicle" );
1453 
1454  weapon = GetWeapon( ‪HUNTER_MISSILE_WEAPON_PLAYER );
1455  fireTime = weapon.fireTime;
1456  driver = self GetSeatOccupant( 0 );
1457 
1458  while( 1 )
1459  {
1460 
1461  if( driver ButtonPressed( "BUTTON_A" ) )
1462  {
1463  spawnTag0 = self.missileTags[ 0 ];
1464  spawnTag1 = self.missileTags[ 1 ];
1465  origin0 = self GetTagOrigin( spawnTag0 );
1466  origin1 = self GetTagOrigin( spawnTag1 );
1467  target = self GetTurretTargetVec( 0 );
1468 
1469  MagicBullet( weapon, origin0, target );
1470  MagicBullet( weapon, origin1, target );
1471 
1472  wait fireTime;
1473  }
1474 
1475  Wait 0.05;
1476  }
1477 }
1478 
1480 {
1481  self endon( "change_state" );
1482  self endon( "crash_done" );
1483  self endon( "death" );
1484 
1485  while ( 1 )
1486  {
1487  self waittill( "veh_collision", velocity, normal );
1488  driver = self GetSeatOccupant( 0 );
1489  if ( isdefined( driver ) && LengthSquared( velocity ) > 70 * 70 )
1490  {
1491  Earthquake( 0.25, 0.25, driver.origin, 50 );
1492  driver PlayRumbleOnEntity( "damage_heavy" );
1493  }
1494  }
1495 }
1496 
1497 // Lots of gross hardcoded values! :(
1499 {
1500  self endon( "death" );
1501  self endon( "exit_vehicle" );
1502 
1503  while ( 1 )
1504  {
1505  vr = Abs( self GetSpeed() / self GetMaxSpeed() );
1506 
1507  if ( vr < 0.1 )
1508  {
1509  level.player PlayRumbleOnEntity( "hunter_fly" );
1510  wait 0.35;
1511  }
1512  else
1513  {
1514  time = RandomFloatRange( 0.1, 0.2 );
1515  Earthquake( RandomFloatRange( 0.1, 0.15 ), time, self.origin, 200 );
1516  level.player PlayRumbleOnEntity( "hunter_fly" );
1517  wait time;
1518  }
1519  }
1520 }
1521 
1523 {
1524  self endon( "death" );
1525  self endon( "exit_vehicle" );
1526 
1527  const max_self_destruct_time = 5;
1528 
1529  self_destruct = false;
1530  self_destruct_time = 0;
1531 
1532  while ( 1 )
1533  {
1534  if ( !self_destruct )
1535  {
1536  if ( level.player MeleeButtonPressed() )
1537  {
1538  self_destruct = true;
1539  self_destruct_time = max_self_destruct_time;
1540  }
1541 
1543  continue;
1544  }
1545  else
1546  {
1547  IPrintLnBold( self_destruct_time );
1548 
1549  wait 1;
1550 
1551  self_destruct_time -= 1;
1552  if ( self_destruct_time == 0 )
1553  {
1554  driver = self GetSeatOccupant( 0 );
1555  if ( isdefined( driver ) )
1556  {
1557  driver DisableInvulnerability();
1558  }
1559 
1560  Earthquake( 3, 1, self.origin, 256 );
1561  RadiusDamage( self.origin, 1000, 15000, 15000, level.player, "MOD_EXPLOSIVE" );
1562  self DoDamage( self.health + 1000, self.origin );
1563  }
1564 
1565  continue;
1566  }
1567  }
1568 }
1569 
1571 {
1572  self endon( "death" );
1573  self endon( "emped" );
1574  self endon( "landed" );
1575 
1576  while ( isdefined( self.‪emped ) )
1577  {
1578  velocity = self.velocity; // setting the angles clears the velocity so we save it off and set it back
1579  self.angles = ( self.angles[0] * 0.85, self.angles[1], self.angles[2] * 0.85 );
1580  ang_vel = self GetAngularVelocity() * 0.85;
1581  self SetAngularVelocity( ang_vel );
1582  self SetVehVelocity( velocity );
1584  }
1585 }
1586 
1587 function ‪hunter_emped( params )
1588 {
1589  self endon( "death" );
1590  self endon( "emped" );
1591 
1592  self.emped = true;
1593 
1594  wait RandomFloatRange( 4, 7 );
1595 
1597 
1598 /*
1599  PlaySoundAtPosition( "veh_qrdrone_emp_down", self.origin );
1600 
1601  if ( !isdefined( self.stun_fx ) )
1602  {
1603  self.stun_fx = Spawn( "script_model", self.origin );
1604  self.stun_fx SetModel( "tag_origin" );
1605  self.stun_fx LinkTo( self, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) );
1606  PlayFXOnTag( level._effect[ "hunter_stun" ], self.stun_fx, "tag_origin" );
1607  }
1608 
1609  wait RandomFloatRange( 4, 7 );
1610 
1611  self.stun_fx delete();
1612 
1613  self playsound ( "veh_qrdrone_boot_qr" );
1614 */
1615 }
1616 
1617 // ----------------------------------------------
1618 // pain/hit reaction
1619 // ----------------------------------------------
1620 function ‪hunter_pain_for_time( time, velocityStablizeParam, rotationStablizeParam, restoreLookPoint )
1621 {
1622  self endon( "death" );
1623  self.painStartTime = GetTime();
1624 
1625  if ( !‪IS_TRUE( self.inpain ) )
1626  {
1627  self.inpain = true;
1628 
1629  while ( GetTime() < self.painStartTime + time * 1000 )
1630  {
1631  self SetVehVelocity( self.velocity * velocityStablizeParam );
1632  self SetAngularVelocity( self GetAngularVelocity() * rotationStablizeParam );
1633  wait 0.1;
1634  }
1635 
1636  if ( isdefined( restoreLookPoint ) )
1637  {
1638  restoreLookEnt = ‪Spawn( "script_model", restoreLookPoint );
1639  restoreLookEnt SetModel( "tag_origin" );
1640 
1641  self ClearLookAtEnt();
1642  self SetLookAtEnt( restoreLookEnt );
1643  self setTurretTargetEnt( restoreLookEnt );
1644  wait 1.5;
1645 
1646  self ClearLookAtEnt();
1647  self ClearTurretTarget();
1648  restoreLookEnt delete();
1649  }
1650 
1651  self.inpain = false;
1652  }
1653 }
1654 
1655 function ‪hunter_pain_small( eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName )
1656 {
1657  if( !isdefined( hitPoint ) || !isdefined( hitDirection ) )
1658  {
1659  return;
1660  }
1661 
1662  self SetVehVelocity( self.velocity + VectorNormalize( hitDirection ) * 20 );
1663 
1664  if ( !‪IS_TRUE( self.inpain ) )
1665  {
1666  vecRight = anglesToRight( self.angles );
1667  ‪sign = ‪math::sign( vectorDot( vecRight, hitDirection ) );
1668  yaw_vel = ‪sign * RandomFloatRange( 100, 140 );
1669 
1670  ang_vel = self GetAngularVelocity();
1671  ang_vel += ( RandomFloatRange( -120, -100 ), yaw_vel, RandomFloatRange( -100, 100 ) );
1672  self SetAngularVelocity( ang_vel );
1673 
1674  self thread ‪hunter_pain_for_time( 1.5, 1.0, 0.8 );
1675  }
1676 
1677  self ‪vehicle_ai::set_state( "strafe" );
1678 }
1679 
1680 function ‪HunterCallback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
1681 {
1682  driver = self GetSeatOccupant( 0 );
1683 
1684  // no friendly fire
1685  if ( isdefined( eAttacker ) && eAttacker.team == self.team )
1686  {
1687  return 0;
1688  }
1689 
1690  num_players = GetPlayers().size;
1691  maxDamage = self.healthdefault * ( 0.35 - 0.025 * num_players );
1692  if ( sMeansOfDeath !== "MOD_UNKNOWN" && iDamage > maxDamage )
1693  {
1694  iDamage = maxDamage;
1695  }
1696 
1697  if ( !isdefined( self.damageLevel ) )
1698  {
1699  self.damageLevel = 0;
1700  self.newDamageLevel = self.damageLevel;
1701  }
1702 
1703  newDamageLevel = ‪vehicle::should_update_damage_fx_level( self.health, iDamage, self.healthdefault );
1704  if ( newDamageLevel > self.damageLevel )
1705  {
1706  self.newDamageLevel = newDamageLevel;
1707  }
1708 
1709  if ( self.newDamageLevel > self.damageLevel )
1710  {
1711  self.damageLevel = self.newDamageLevel;
1712  if ( self.pain_when_damagelevel_change === true )
1713  {
1714  ‪hunter_pain_small( eAttacker, sMeansOfDeath, vPoint, vDir, sHitLoc, partName );
1715  }
1716  ‪vehicle::set_damage_fx_level( self.damageLevel );
1717  }
1718 
1719  if ( ‪vehicle_ai::should_emp( self, weapon, sMeansOfDeath, eInflictor, eAttacker ) )
1720  {
1721  ‪hunter_pain_small( eAttacker, sMeansOfDeath, vPoint, vDir, sHitLoc, partName );
1722  }
1723 
1724  return iDamage;
1725 }
‪is_point_in_view
‪function is_point_in_view(point, do_trace)
Definition: _hunter.gsc:1154
‪hunter_scripted
‪function hunter_scripted(params)
Definition: _hunter.gsc:1371
‪add_interrupt_connection
‪function add_interrupt_connection(from_state_name, to_state_name, on_notify, checkfunc)
Definition: statemachine_shared.gsc:90
‪enable
‪function enable(handler)
Definition: _perplayer.gsc:54
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪set_state
‪function set_state(name, state_params)
Definition: statemachine_shared.gsc:133
‪evaluate_connections
‪function evaluate_connections(eval_func, params)
Definition: statemachine_shared.gsc:266
‪randomSign
‪function randomSign()
Definition: math_shared.gsc:179
‪HUNTER_SCANNER_RANGE_YAW
‪#define HUNTER_SCANNER_RANGE_YAW
Definition: _hunter.gsc:39
‪Movement_Thread_StayInDistance
‪function Movement_Thread_StayInDistance()
Definition: _hunter.gsc:683
‪HUNTER_DRONE_SPAWNER
‪#define HUNTER_DRONE_SPAWNER
Definition: _hunter.gsc:51
‪ClearAllLookingAndTargeting
‪function ClearAllLookingAndTargeting()
Definition: vehicle_ai_shared.gsc:697
‪hunter_exit_vehicle
‪function hunter_exit_vehicle()
Definition: _hunter.gsc:1357
‪vehicle_damage_filter
‪function vehicle_damage_filter(vision_set, heavy_damage_threshold, filterid=0, b_use_player_damage=false)
Definition: vehicle_death_shared.gsc:1392
‪side_turrets_forward
‪function side_turrets_forward()
Definition: _hunter.gsc:457
‪state_unaware_exit
‪function state_unaware_exit(params)
Definition: _hunter.gsc:383
‪hunter_SpawnDrones
‪function hunter_SpawnDrones()
Definition: _hunter.gsc:135
‪ClearAllMovement
‪function ClearAllMovement(zeroOutSpeed=false)
Definition: vehicle_ai_shared.gsc:707
‪set_damage_fx_level
‪function set_damage_fx_level(damage_level)
Definition: vehicle_shared.gsc:3012
‪IsCooldownReady
‪function IsCooldownReady(name, timeForward_seconds)
Definition: vehicle_ai_shared.gsc:1968
‪InitThreatBias
‪function InitThreatBias()
Definition: vehicle_ai_shared.gsc:60
‪state_combat_exit
‪function state_combat_exit(params)
Definition: _hunter.gsc:495
‪state_unaware_enter
‪function state_unaware_enter(params)
Definition: _hunter.gsc:355
‪set_target_flags
‪function set_target_flags(n_flags, n_index)
Definition: turret_shared.gsc:819
‪hunter_collision_player
‪function hunter_collision_player()
Definition: _hunter.gsc:1479
‪sign
‪function sign(x)
Definition: math_shared.csc:164
‪hunter_self_destruct
‪function hunter_self_destruct()
Definition: _hunter.gsc:1522
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪player_fire_update_side_turret_1
‪function player_fire_update_side_turret_1()
Definition: _hunter.gsc:1411
‪PositionQuery_Filter_Random
‪function PositionQuery_Filter_Random(queryResult, min, max)
Definition: vehicle_ai_shared.gsc:2088
‪shut_off_fx
‪function shut_off_fx()
Definition: _hunter.gsc:286
‪HUNTER_STRAFE_SPEED_RATIO
‪#define HUNTER_STRAFE_SPEED_RATIO
Definition: _hunter.gsc:32
‪HUNTER_ENABLE_SCANNER_FX
‪#define HUNTER_ENABLE_SCANNER_FX
Definition: _hunter.gsc:64
‪HUNTER_STRAFE_DISTANCE_TO_ENEMY_DISTANCE_RATIO
‪#define HUNTER_STRAFE_DISTANCE_TO_ENEMY_DISTANCE_RATIO
Definition: _hunter.gsc:72
‪RegisterSharedInterfaceAttributes
‪function RegisterSharedInterfaceAttributes(archetype)
Definition: vehicle_ai_shared.gsc:36
‪RegisterInterfaceAttributes
‪function RegisterInterfaceAttributes(archetype)
Definition: _hunter.gsc:89
‪state_strafe_exit
‪function state_strafe_exit(params)
Definition: _hunter.gsc:603
‪get_previous_state
‪function get_previous_state()
Definition: vehicle_ai_shared.gsc:971
‪waitLongDurationWithHostMigrationPause
‪function waitLongDurationWithHostMigrationPause(duration)
Definition: hostmigration_shared.gsc:216
‪HUNTER_UNAWARE_SPEED_RATIO
‪#define HUNTER_UNAWARE_SPEED_RATIO
Definition: _hunter.gsc:30
‪HUNTER_ENABLE_SIDETURRETS_YIELD_MAINTURRET_TARGET
‪#define HUNTER_ENABLE_SIDETURRETS_YIELD_MAINTURRET_TARGET
Definition: _hunter.gsc:65
‪Movement_Thread_Wander
‪function Movement_Thread_Wander()
Definition: _hunter.gsc:388
‪within_fov
‪function within_fov(start_origin, start_angles, end_origin, fov)
Definition: _util.gsc:56
‪defaultstate_death_update
‪function defaultstate_death_update(params)
Definition: vehicle_ai_shared.gsc:1355
‪hunter_scanner_SetTargetEntity
‪function hunter_scanner_SetTargetEntity(targetEnt, offset)
Definition: _hunter.gsc:1245
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪waittill_any_timeout
‪function waittill_any_timeout(n_timeout, string1, string2, string3, string4, string5)
Definition: util_shared.csc:423
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪HUNTER_SCANNER_SCANSPEED
‪#define HUNTER_SCANNER_SCANSPEED
Definition: _hunter.gsc:36
‪set_burst_parameters
‪function set_burst_parameters(n_fire_min, n_fire_max, n_wait_min, n_wait_max, n_index)
Definition: turret_shared.gsc:609
‪HUNTER_STRAFE_COOLDOWN
‪#define HUNTER_STRAFE_COOLDOWN
Definition: _hunter.gsc:71
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪getEnemyArray
‪function getEnemyArray(include_ai, include_player)
Definition: _hunter.gsc:1128
‪disable
‪function disable(handler)
Definition: _perplayer.gsc:79
‪hunter_scanner_init
‪function hunter_scanner_init()
Definition: _hunter.gsc:1220
‪can_hit_target
‪function can_hit_target(e_target, n_index)
Definition: turret_shared.gsc:2425
‪HUNTER_SEEK_ENEMY_DELAY
‪#define HUNTER_SEEK_ENEMY_DELAY
Definition: _hunter.gsc:69
‪hunter_update_rumble
‪function hunter_update_rumble()
Definition: _hunter.gsc:1498
‪player_fire_update_side_turret_2
‪function player_fire_update_side_turret_2()
Definition: _hunter.gsc:1430
‪hunter_frontScanning
‪function hunter_frontScanning()
Definition: _hunter.gsc:1277
‪HUNTER_ENABLE_WEAKSPOTS
‪#define HUNTER_ENABLE_WEAKSPOTS
Definition: _hunter.gsc:66
‪HUNTER_SCANNER_FOV
‪#define HUNTER_SCANNER_FOV
Definition: _hunter.gsc:40
‪TURRET_TARGET_PLAYERS
‪#define TURRET_TARGET_PLAYERS
Definition: shared.gsh:345
‪hunter_emped
‪function hunter_emped(params)
Definition: _hunter.gsc:1587
‪remote_missile_life
‪function remote_missile_life()
Definition: _hunter.gsc:1110
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪is_valid_target
‪function is_valid_target(target, do_trace)
Definition: _hunter.gsc:1179
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪Attack_Thread_MainTurret
‪function Attack_Thread_MainTurret()
Definition: _hunter.gsc:892
‪hunter_initTagArrays
‪function hunter_initTagArrays()
Definition: _hunter.gsc:107
‪state_death_enter
‪function state_death_enter(params)
Definition: _hunter.gsc:313
‪state_unaware_update
‪function state_unaware_update(params)
Definition: _hunter.gsc:362
‪_init_turret
‪function _init_turret(n_index=0)
Definition: turret_shared.gsc:1773
‪set_best_target_func
‪function set_best_target_func(func_get_best_target, n_index)
Definition: turret_shared.gsc:1871
‪Cooldown
‪function Cooldown(name, time_seconds)
Definition: vehicle_ai_shared.gsc:1943
‪init_state_machine_for_role
‪function init_state_machine_for_role(rolename)
Definition: vehicle_ai_shared.gsc:1034
‪PositionQuery_DebugScores
‪function PositionQuery_DebugScores(queryResult)
Definition: vehicle_ai_shared.gsc:2010
‪HUNTER_COMBAT_SPEED_RATIO
‪#define HUNTER_COMBAT_SPEED_RATIO
Definition: _hunter.gsc:31
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪get_enemies_in_view
‪function get_enemies_in_view(do_trace)
Definition: _hunter.gsc:1203
‪is_dead_sentient
‪function is_dead_sentient()
Definition: ai_shared.gsc:210
‪HUNTER_SCANNER_PITCH
‪#define HUNTER_SCANNER_PITCH
Definition: _hunter.gsc:37
‪fire_for_time
‪function fire_for_time(n_time, n_index=0)
Definition: turret_shared.gsc:953
‪PositionQuery_PostProcess_SortScore
‪function PositionQuery_PostProcess_SortScore(queryResult, descending=true)
Definition: vehicle_ai_shared.gsc:2097
‪side_turret_get_best_target
‪function side_turret_get_best_target(a_potential_targets, n_index)
Definition: _hunter.gsc:1020
‪PositionQuery_Filter_OutOfGoalAnchor
‪function PositionQuery_Filter_OutOfGoalAnchor(queryResult, tolerance=1)
Definition: vehicle_ai_shared.gsc:2104
‪Delay_Target_ToEnemy_Thread
‪function Delay_Target_ToEnemy_Thread(point, enemy, timeToHit)
Definition: _hunter.gsc:854
‪HUNTER_MISSILE_WEAPON_PLAYER
‪#define HUNTER_MISSILE_WEAPON_PLAYER
Definition: _hunter.gsc:45
‪hunter_initialize
‪function hunter_initialize()
Definition: _hunter.gsc:157
‪state_strafe_update
‪function state_strafe_update(params)
Definition: _hunter.gsc:519
‪HUNTER_RADIUS
‪#define HUNTER_RADIUS
Definition: _hunter.gsc:26
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪blink_lights_for_time
‪function blink_lights_for_time(time)
Definition: vehicle_ai_shared.gsc:648
‪emped
‪function emped(down_time)
Definition: _siegebot.gsc:1359
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪__init__
‪function __init__()
Definition: _hunter.gsc:83
‪TURRET_TARGET_AI
‪#define TURRET_TARGET_AI
Definition: shared.gsh:344
‪state_combat_update
‪function state_combat_update(params)
Definition: _hunter.gsc:474
‪player_fire_update_rocket
‪function player_fire_update_rocket()
Definition: _hunter.gsc:1449
‪HUNTER_MISSILE_LOCKON_DELAY
‪#define HUNTER_MISSILE_LOCKON_DELAY
Definition: _hunter.gsc:47
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪should_emp
‪function should_emp(vehicle, weapon, meansOfDeath, eInflictor, eAttacker)
Definition: vehicle_ai_shared.gsc:765
‪hunter_scanner_SetTargetPosition
‪function hunter_scanner_SetTargetPosition(targetPos)
Definition: _hunter.gsc:1268
‪RegisterNumericInterface
‪function RegisterNumericInterface(archetype, attribute, defaultValue, minimum, maximum, callbackFunction)
Definition: ai_interface.gsc:169
‪HUNTER_ENABLE_ATTACK_DRONES
‪#define HUNTER_ENABLE_ATTACK_DRONES
Definition: _hunter.gsc:67
‪get_target
‪function get_target(n_index)
Definition: turret_shared.gsc:760
‪hunter_level_out_for_landing
‪function hunter_level_out_for_landing()
Definition: _hunter.gsc:1570
‪should_update_damage_fx_level
‪function should_update_damage_fx_level(currentHealth, damage, maxHealth)
Definition: vehicle_shared.gsc:2900
‪add_utility_connection
‪function add_utility_connection(from_state_name, to_state_name, checkfunc, defaultScore)
Definition: statemachine_shared.gsc:112
‪HUNTER_SCANNER_VIEW_DISTANCE
‪#define HUNTER_SCANNER_VIEW_DISTANCE
Definition: _hunter.gsc:41
‪HUNTER_MISSILE_WEAPON
‪#define HUNTER_MISSILE_WEAPON
Definition: _hunter.gsc:44
‪state_strafe_enter
‪function state_strafe_enter(params)
Definition: _hunter.gsc:506
‪hunter_pain_for_time
‪function hunter_pain_for_time(time, velocityStablizeParam, rotationStablizeParam, restoreLookPoint)
Definition: _hunter.gsc:1620
‪Attack_Thread_rocket
‪function Attack_Thread_rocket()
Definition: _hunter.gsc:940
‪HUNTER_SCANNER_TAG
‪#define HUNTER_SCANNER_TAG
Definition: _hunter.gsc:35
‪FLAT_ORIGIN
‪#define FLAT_ORIGIN(__origin)
Definition: shared.gsh:256
‪GetNextMovePosition_tactical
‪function GetNextMovePosition_tactical(enemy)
Definition: _hunter.gsc:610
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪state_combat_enter
‪function state_combat_enter(params)
Definition: _hunter.gsc:463
‪defaultstate_death_enter
‪function defaultstate_death_enter(params)
Definition: vehicle_ai_shared.gsc:1200
‪state_death_update
‪function state_death_update(params)
Definition: _hunter.gsc:330
‪HunterCallback_VehicleDamage
‪function HunterCallback_VehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _hunter.gsc:1680
‪disable_turrets
‪function disable_turrets()
Definition: _hunter.gsc:449
‪hunter_pain_small
‪function hunter_pain_small(eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName)
Definition: _hunter.gsc:1655
‪HUNTER_SCANNER_RANGE_PITCH
‪#define HUNTER_SCANNER_RANGE_PITCH
Definition: _hunter.gsc:38
‪hunter_lockon_fx
‪function hunter_lockon_fx()
Definition: _hunter.gsc:1121
‪hunter_fire_one_missile
‪function hunter_fire_one_missile(launcher_index, target, offset, blinkLights, waittimeAfterBlinkLights)
Definition: _hunter.gsc:1064
‪clamp
‪function clamp(val, val_min, val_max)
Definition: math_shared.csc:16
‪get_behavior_attribute
‪function get_behavior_attribute(attribute)
Definition: ai_shared.gsc:184
‪enable_turrets
‪function enable_turrets()
Definition: _hunter.gsc:442
‪CreateInterfaceForEntity
‪function CreateInterfaceForEntity(entity)
Definition: ai_interface.gsc:110
‪kill_drones
‪function kill_drones()
Definition: _hunter.gsc:299
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪HUNTER_MISSILE_MINIMAL_INTERVAL
‪#define HUNTER_MISSILE_MINIMAL_INTERVAL
Definition: _hunter.gsc:48
‪get_death_type
‪function get_death_type(params)
Definition: vehicle_ai_shared.gsc:1323
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪defaultRole
‪function defaultRole()
Definition: _hunter.gsc:238
‪hunter_scanner_ClearLookTarget
‪function hunter_scanner_ClearLookTarget()
Definition: _hunter.gsc:1261