‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_wasp.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\system_shared;
6 #using scripts\shared\array_shared;
7 #using scripts\shared\util_shared;
8 
9 #using scripts\shared\vehicle_shared;
10 #using scripts\shared\vehicle_death_shared;
11 #using scripts\shared\vehicle_ai_shared;
12 #using scripts\shared\clientfield_shared;
13 
14 #insert scripts\shared\shared.gsh;
15 #insert scripts\shared\statemachine.gsh;
16 #insert scripts\shared\archetype_shared\archetype_shared.gsh;
17 
18 #insert scripts\shared\ai\utility.gsh;
19 #insert scripts\shared\version.gsh;
20 
21 #define WASP_MOVE_DIST_MIN 80
22 #define WASP_MOVE_DIST_MAX 500
23 
24 #define WASP_ENEMY_TOO_CLOSE_DIST 250
25 
26 #define WASP_GROUP_RADIUS 140
27 #define WASP_GROUP_SIZE 3
28 
29 #define WASP_GUARD_ACQUIRE_ENEMY_DIST 1000
30 #define WASP_GUARD_LOSE_ENEMY_DIST 1200
31 #define WASP_GUARD_KEEP_ENEMY_DIST 300
32 
33 #define WASP_HOVER_RADIUS 50
34 
35 #define WASP_NEARGOAL_DIST 40
36 
37 #using_animtree( "generic" );
38 
39 #namespace wasp;
40 
41 ‪REGISTER_SYSTEM( "wasp", &‪__init__, undefined )
42 
43 function ‪__init__()
44 {
45  vehicle::add_main_callback( "wasp", &‪wasp_initialize );
46  ‪clientfield::register( "vehicle", "rocket_wasp_hijacked", ‪VERSION_SHIP, 1, "int" );
47 }
48 
50 {
51  self UseAnimTree( #animtree );
52 
53  Target_Set( self, ( 0, 0, 0 ) );
54 
55  self.health = self.healthdefault;
56 
58 
59  self EnableAimAssist();
60  self SetNearGoalNotifyDist( ‪WASP_NEARGOAL_DIST );
61 
62  //self SetVehicleAvoidance( true ); // this is ORCA avoidance
63 
64  self SetHoverParams( ‪WASP_HOVER_RADIUS, 100.0, 100.0 );
65 
66  self.fovcosine = 0; // +/-90 degrees = 180
67  self.fovcosinebusy = 0; //+/- 55 degrees = 110 fov
68 
69  self.vehAirCraftCollisionEnabled = true;
70 
71  assert( isdefined( self.scriptbundlesettings ) );
72 
73  self.settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
74  self.goalRadius = 999999;
75  self.goalHeight = 999999;
76  self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
77 
78  self.variant = "mg";
79 
80  if ( IsSubStr( self.vehicleType, "rocket" ) )
81  {
82  self.variant = "rocket";
83  }
84 
85  self.overrideVehicleDamage = &‪drone_callback_damage;
86  self.allowFriendlyFireDamageOverride = &‪drone_AllowFriendlyFireDamage;
87 
88  self thread ‪vehicle_ai::nudge_collision();
89 
90  //disable some cybercom abilities
91  if( IsDefined( level.vehicle_initializer_cb ) )
92  {
93  [[level.vehicle_initializer_cb]]( self );
94  }
95 
96  if ( self.variant === "rocket" )
97  {
98  self.ignoreFireFly = true;
100  }
101 
103 
104  ‪defaultRole();
105 }
106 
107 function ‪defaultRole()
108 {
110 
111  self ‪vehicle_ai::get_state_callbacks( "combat" ).enter_func = &‪state_combat_enter;
112  self ‪vehicle_ai::get_state_callbacks( "combat" ).update_func = &‪state_combat_update;
113 
114  self ‪vehicle_ai::get_state_callbacks( "death" ).update_func = &‪state_death_update;
115 
116  self ‪vehicle_ai::get_state_callbacks( "driving" ).update_func = &‪wasp_driving;
117 
118  self ‪vehicle_ai::get_state_callbacks( "emped" ).update_func = &‪state_emped_update;
119 
120  self ‪vehicle_ai::add_state( "guard",
124 
126  ‪vehicle_ai::add_utility_connection( "guard", "combat" );
127  ‪vehicle_ai::add_interrupt_connection( "guard", "emped", "emped" );
128  ‪vehicle_ai::add_interrupt_connection( "guard", "surge", "surge" );
129  ‪vehicle_ai::add_interrupt_connection( "guard", "off", "shut_off" );
130  ‪vehicle_ai::add_interrupt_connection( "guard", "pain", "pain" );
131  ‪vehicle_ai::add_interrupt_connection( "guard", "driving", "enter_vehicle" );
132 
134 }
135 
136 // ----------------------------------------------
137 // State: death
138 // ----------------------------------------------
139 function ‪state_death_update( params )
140 {
141  self endon( "death" );
142 
143  if ( isArray( self.followers ) )
144  {
145  foreach( follower in self.followers )
146  {
147  if ( isdefined( follower ) )
148  {
149  follower.leader = undefined;
150  }
151  }
152  }
153 
154  death_type = ‪vehicle_ai::get_death_type( params );
155 
156  // gib death
157  if ( !isdefined( death_type ) && isdefined( params ) )
158  {
159  if ( isdefined( params.weapon ) )
160  {
161  if ( params.weapon.doannihilate )
162  {
163  death_type = "gibbed";
164  }
165  else if ( params.weapon.dogibbing && isdefined( params.attacker ) )
166  {
167  dist = Distance( self.origin, params.attacker.origin );
168  if ( dist < params.weapon.maxgibdistance )
169  {
170  gib_chance = 1.0 - ( dist / params.weapon.maxgibdistance );
171  //if( RandomFloatRange( 0.0, 1.0 ) < gib_chance )
172  if ( RandomFloatRange( 0.0, 2.0 ) < gib_chance ) // less chance for now, weapons are tuned to gib too much
173  {
174  death_type = "gibbed";
175  }
176  }
177  }
178  }
179 
180  if ( isdefined( params.meansOfDeath ) )
181  {
182  meansOfDeath = params.meansOfDeath;
183  if ( meansOfDeath === "MOD_EXPLOSIVE" || meansOfDeath === "MOD_GRENADE_SPLASH" || meansOfDeath === "MOD_PROJECTILE_SPLASH" || meansOfDeath === "MOD_PROJECTILE" )
184  {
185  death_type = "gibbed";
186  }
187  }
188  }
189 
190  // crash
191  if ( !isdefined( death_type ) )
192  {
193  crash_style = RandomInt( 3 );
194  switch( crash_style )
195  {
196  case 0:
197  // barrel_rolling camera is too crazy, so show gibbed to the player instead
198  if ( self.hijacked === true )
199  {
200  params.death_type = "gibbed";
202  }
203  else
204  {
206  }
207  break;
208 
209  case 1: ‪vehicle_death::plane_crash(); break;
210  default: ‪vehicle_death::random_crash( params.vDir );
211  }
213  }
214  else
215  {
216  params.death_type = death_type;
218  }
219 }
220 
221 // ----------------------------------------------
222 // State: emped
223 // ----------------------------------------------
224 function ‪state_emped_update( params )
225 {
226  self endon ( "death" );
227  self endon ( "change_state" );
228 
230 
231  gravity = 400;
232 
233  self notify( "end_nudge_collision" );
234 
235  // emp down time
236  empdowntime = params.notify_param[0];
237  assert( isdefined( empdowntime ) );
238  ‪vehicle_ai::Cooldown( "emped_timer", empdowntime );
239 
240  wait RandomFloat( 0.2 );
241 
242  // give it a spin
243  ang_vel = self GetAngularVelocity();
244  pitch_vel = ‪math::randomSign() * RandomFloatRange( 200, 250 );
245  yaw_vel = ‪math::randomSign() * RandomFloatRange( 200, 250 );
246  roll_vel = ‪math::randomSign() * RandomFloatRange( 200, 250 );
247  ang_vel += ( pitch_vel, yaw_vel, roll_vel );
248  self SetAngularVelocity( ang_vel );
249 
250  // let it fall
251  if ( IsPointInNavVolume( self.origin, "navvolume_small" ) )
252  {
253  self.position_before_fall = self.origin;
254  }
255 
256  self CancelAIMove();
257  self SetPhysAcceleration( ( 0, 0, -gravity ) );
258 
259  killonimpact_speed = self.settings.killonimpact_speed;
260  if( self.health <= 20 )
261  {
262  killonimpact_speed = 1;
263  }
264 
265  self ‪fall_and_bounce( killonimpact_speed, self.settings.killonimpact_time );
266 
267  self notify( "landed" );
268 
269  // forcefully stablize just in case
270  self SetVehVelocity( ( 0, 0, 0 ) );
271  self SetPhysAcceleration( ( 0, 0, -gravity * 0.1 ) );
272  self SetAngularVelocity( ( 0, 0, 0 ) );
273 
274  // wait emp down time
275  while( !‪vehicle_ai::IsCooldownReady( "emped_timer" ) )
276  {
277  timeLeft = max( ‪vehicle_ai::GetCooldownLeft( "emped_timer" ), 0.5 );
278  wait timeLeft;
279  }
280 
281  // get back up
282  self.abnormal_status.emped = false;
283  self ‪vehicle::toggle_emp_fx( false );
285 
286  bootup_timer = 1.6;
287  while( bootup_timer > 0 )
288  {
289  self ‪vehicle::lights_on();
290  wait 0.4;
291  self ‪vehicle::lights_off();
292  wait 0.4;
293  bootup_timer -= 0.8;
294  }
295 
296  self ‪vehicle::lights_on();
297 
298  if ( isdefined( self.position_before_fall ) )
299  {
300  originoffset = (0,0,5);
301  goalpoint = self GetClosestPointOnNavVolume( self.origin + originoffset, 50 );
302  if ( isdefined( goalpoint ) && SightTracePassed( self.origin + originoffset, goalpoint, false, self ) )
303  {
304  self SetVehGoalPos( goalpoint, false, false );
305  self ‪util::waittill_any_timeout( 0.3, "near_goal", "goal", "change_state", "death" );
306 
307  if ( isdefined( self.enemy ) )
308  {
309  self SetLookAtEnt( self.enemy );
310  }
311 
312  ‪startTime = GetTime();
313  self.current_pathto_pos = self.position_before_fall;
314  foundGoal = self SetVehGoalPos( self.current_pathto_pos, true, true );
315  while ( !foundGoal && ‪vehicle_ai::TimeSince( ‪startTime ) < 3 )
316  {
317  foundGoal = self SetVehGoalPos( self.current_pathto_pos, true, true );
318  wait 0.3;
319  }
320 
321  if ( foundGoal )
322  {
323  self ‪util::waittill_any_timeout( 1, "near_goal", "goal", "change_state", "death" );
324  }
325  else
326  {
327  self SetVehGoalPos( self.origin, true, false );
328  }
329  wait 1;
330  self.position_before_fall = undefined;
332  }
333  }
334 
335  // not able to get up
336  self ‪vehicle::lights_off();
337 }
338 
339 function ‪fall_and_bounce( killOnImpact_speed, killOnImpact_time )
340 {
341  self endon( "death" );
342  self endon( "change_state" );
343 
344  maxBounceTime = 3;
345  bounceScale = 0.3;
346  velocityLoss = 0.3;
347  maxAngle = 12;
348  bouncedTime = 0;
349  angularVelStablizeParams = ( 0.3, 0.5, 0.2 ); // stablize pitch and roll more
350  anglesStablizeInitialScale = 0.6;
351  anglesStablizeIncrement = 0.2;
352 
353  fallStart = GetTime();
354  while ( bouncedTime < maxBounceTime && LengthSquared( self.velocity ) > ‪SQR( 10 ) )
355  {
356  self waittill( "veh_collision", impact_vel, normal );
357 
358  // if too fast or dropping for too long, kill on impact
359  if ( LengthSquared( impact_vel ) > ‪SQR( killOnImpact_speed ) || ( ‪vehicle_ai::TimeSince( fallStart ) > killOnImpact_time && LengthSquared( impact_vel ) > ‪SQR( killOnImpact_speed * 0.8 ) ) )
360  {
361  self ‪kill();
362  }
363  // don't have a safe point to get back to
364  else if ( !isdefined( self.position_before_fall ) )
365  {
366  self ‪kill();
367  }
368  else
369  {
370  fallStart = GetTime();
371  }
372 
373  // bounce velocity
374  oldvelocity = self.velocity; // current velocity (self.velocity) and impact velocity (impact_vel) can be very different
375  vel_hitDir = -VectorProjection( impact_vel, normal ); // negate of impact velocity along surface normal is the bounce velocity
376  vel_hitDirUp = VectorProjection( vel_hitDir, (0,0,1) );
377 
378  velscale = min( bounceScale * ( bouncedTime + 1 ), 0.9 ); // don't go too big
379  newVelocity = ( oldvelocity - VectorProjection( oldvelocity, vel_hitDir ) ) * ( 1 - velocityLoss ); // clear velocity in bounce direction, and add velocity loss
380  newVelocity += vel_hitDir * velscale; // add bounce velocity
381 
382  // adjust angular velocity and angles so it lays flat on ground
383  shouldBounce = ( VectorDot( normal, (0,0,1) ) > 0.76 ); // roughly 45 degrees
384  if ( shouldBounce )
385  {
386  // stablize angular velocity
387  // stablize more if velocity is low
388  velocityLengthSqr = LengthSquared( newVelocity );
389  stablizeScale = MapFloat( ‪SQR( 5 ), ‪SQR( 60 ), 0.1, 1, velocityLengthSqr );
390 
391  ang_vel = self GetAngularVelocity();
392  ang_vel *= angularVelStablizeParams * stablizeScale;
393  self SetAngularVelocity( ang_vel );
394 
395  // bring angles to flat
396  angles = self.angles;
397  anglesStablizeScale = min( anglesStablizeInitialScale - bouncedTime * anglesStablizeIncrement, 0.1 ); // don't go too small
398  pitch = angles[0];
399  yaw = angles[1];
400  roll = angles[2];
401  surfaceAngles = VectorToAngles( normal );
402  surfaceRoll = surfaceAngles[2];
403  if ( pitch < -maxAngle || pitch > maxAngle )
404  {
405  pitch *= anglesStablizeScale;
406  }
407  if ( roll < surfaceRoll - maxAngle || roll > surfaceRoll + maxAngle )
408  {
409  roll = LerpFloat( surfaceRoll, roll, anglesStablizeScale );
410  }
411  self.angles = ( pitch, yaw, roll ); // setting the angles clears the velocity so we have to set velocity after this
412  }
413 
414  self SetVehVelocity( newVelocity );
415  self ‪vehicle_ai::collision_fx( normal );
416 
417  if ( shouldBounce )
418  {
419  bouncedTime++;
420  }
421  }
422 }
423 
424 // ----------------------------------------------
425 // State: guard
426 // ----------------------------------------------
428 {
429  self._guard_points = [];
430  ‪ARRAY_ADD( self._guard_points, (150, -110, 110) );
431  ‪ARRAY_ADD( self._guard_points, (150, 110, 110) );
432  ‪ARRAY_ADD( self._guard_points, (120, -110, 80) );
433  ‪ARRAY_ADD( self._guard_points, (120, 110, 80) );
434  ‪ARRAY_ADD( self._guard_points, (180, 0, 140) );
435 }
436 
437 /#
439 {
440  self endon ( "death" );
441 
442  if ( self.isdebugdrawing === true )
443  {
444  return;
445  }
446 
447  self.isdebugdrawing = true;
448  while( true )
449  {
450  foreach( point in self.debugpointsarray )
451  {
452  color = ‪RED;
453  if ( IsPointInNavVolume( point, "navvolume_small" ) )
454  {
455  color = ‪GREEN;
456  }
457 
458  debugstar( point, 5, color );
459  }
461  }
462 }
463 #/
464 
465 function ‪get_guard_points( owner )
466 {
467  assert( self._guard_points.size > 0, "wasp has no guard points" );
468 
469  //self.debugpointsarray = [];
470  // /# self thread guard_points_debug(); #/
471 
472  points_array = [];
473 
474  foreach( point in self._guard_points )
475  {
476  offset = RotatePoint( point, owner.angles );
477  worldPoint = offset + owner.origin + owner GetVelocity() * 0.5;
478  //ARRAY_ADD( self.debugpointsarray, worldPoint );
479 
480  if ( IsPointInNavVolume( worldPoint, "navvolume_small" ) )
481  {
482  ‪ARRAY_ADD( points_array, worldPoint );
483  }
484  }
485 
486  if ( points_array.size < 1 )
487  {
488  queryResult = PositionQuery_Source_Navigation( owner.origin + (0,0,50), 25, 200, 100, 1.2 * self.radius, self );
489  PositionQuery_Filter_Sight( queryResult, owner.origin + (0,0,10), (0, 0, 0), self, 3 );
490 
491  foreach( point in queryResult.data )
492  {
493  if ( point.visibility === true && BulletTracePassed( owner.origin + (0,0,10), point.origin, false, self, self, false, true ) )
494  {
495  ‪ARRAY_ADD( points_array, point.origin );
496  }
497  }
498  }
499 
500  return points_array;
501 }
502 
503 function ‪state_guard_can_enter( from_state, to_state, connection )
504 {
505  if ( self.enable_guard !== true || !isdefined( self.owner ) )
506  {
507  return false;
508  }
509 
510  if ( !isdefined( self.enemy ) || !self VehSeenRecently( self.enemy, 3 ) )
511  {
512  return true;
513  }
514 
515  // if enemy is far away from owner, and wasp is not very close to it
516  if ( DistanceSquared( self.owner.origin, self.enemy.origin ) > ‪SQR( ‪WASP_GUARD_LOSE_ENEMY_DIST ) &&
517  DistanceSquared( self.origin, self.enemy.origin ) > ‪SQR( ‪WASP_GUARD_KEEP_ENEMY_DIST ) )
518  {
519  return true;
520  }
521 
522  if ( !IsPointInNavVolume( self.origin, "navvolume_small" ) )
523  {
524  return true;
525  }
526 
527  return false;
528 }
529 
530 function ‪state_guard_enter( params )
531 {
532  if ( self.enable_target_laser === true )
533  {
534  self LaserOff();
535  }
536 
537  self ‪update_main_guard();
538 }
539 
541 {
542  if ( isdefined( self.owner ) && !isAlive( self.owner.main_guard ) || self.owner.main_guard.owner !== self.owner )
543  {
544  self.owner.main_guard = self;
545  }
546 }
547 
548 function ‪state_guard_exit( params )
549 {
550  if ( isdefined( self.owner ) && self.owner.main_guard === self )
551  {
552  self.owner.main_guard = undefined;
553  }
554 }
555 
556 function ‪test_get_back_point( point )
557 {
558  if ( SightTracePassed( self.origin, point, false, self ) )
559  {
560  if ( BulletTracePassed( self.origin, point, false, self, self, false, true ) )
561  {
562  return 1;
563  }
564 
565  return 0;
566  }
567 
568  return -1;
569 }
570 
571 function ‪test_get_back_queryresult( queryResult )
572 {
573  getbackPoint = undefined;
574  foreach( point in queryResult.data )
575  {
576  testresult = ‪test_get_back_point( point.origin );
577  if ( testresult == 1 )
578  {
579  return point.origin;
580  }
581  else if ( testresult == 0 )
582  {
584  }
585  }
586 
587  return undefined;
588 }
589 
590 function ‪state_guard_update( params )
591 {
592  self endon( "death" );
593  self endon( "change_state" );
594 
595  self SetHoverParams( 20.0, 40.0, 30.0 );
596 
597  timeNotAtGoal = GetTime();
598  pointIndex = 0;
599  stuckCount = 0;
600 
601  while( 1 )
602  {
603  if( isdefined( self.enemy ) && DistanceSquared( self.owner.origin, self.enemy.origin ) < ‪SQR( ‪WASP_GUARD_ACQUIRE_ENEMY_DIST ) && self VehSeenRecently( self.enemy, 1 ) && IsPointInNavVolume( self.origin, "navvolume_small" ) )
604  {
606  wait 1;
607  }
608  else
609  {
610  owner = self.owner;
611  if ( !isdefined( owner ) )
612  {
613  wait 1;
614  continue;
615  }
616 
617  usePathfinding = true;
618  onNavVolume = IsPointInNavVolume( self.origin, "navvolume_small" );
619  if ( !onNavVolume )
620  {
621  // off nav volume, try getting back
622  getbackPoint = undefined;
623 
624  // try closest point
625  pointOnNavVolume = self GetClosestPointOnNavVolume( self.origin, 500 );
626  if ( isdefined( pointOnNavVolume ) )
627  {
628  if ( ‪test_get_back_point( pointOnNavVolume ) == 1 )
629  {
630  getbackPoint = pointOnNavVolume;
631  }
632  }
633 
634  // try query points on horizontal level
635  if ( !isdefined( getbackPoint ) )
636  {
637  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 1500, 200, 80, self );
638  getbackPoint = ‪test_get_back_queryresult( queryResult );
639  }
640 
641  // try vertical points
642  if ( !isdefined( getbackPoint ) )
643  {
644  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 300, 700, 30, self );
645  getbackPoint = ‪test_get_back_queryresult( queryResult );
646  }
647 
648  if ( isdefined( getbackPoint ) )
649  {
650  if ( DistanceSquared( getbackPoint, self.origin ) > ‪SQR( ‪WASP_NEARGOAL_DIST * 0.5 ) )
651  {
652  self.current_pathto_pos = getbackPoint;
653  usePathfinding = false;
654  self.vehAirCraftCollisionEnabled = false;
655  }
656  else
657  {
658  onNavVolume = true;
659  }
660  }
661  else
662  {
663  stuckCount++;
664  if ( stuckCount == 1 )
665  {
666  stuckLocation = self.origin;
667  }
668  else if ( stuckCount > 10 )
669  {
670  /#
671  assert( false, "Wasp fall outside of NavVolume at " + self.origin );
672  v_box_min = ( -self.radius, -self.radius, -self.radius );
673  v_box_max = ( self.radius, self.radius, self.radius );
674  Box( self.origin, v_box_min, v_box_max, self.angles[1], (1,0,0), 1, false, 1000000 );
675  if ( isdefined( stuckLocation ) )
676  {
677  Line( stuckLocation, self.origin, (1,0,0), 1, true, 1000000 );
678  }
679  #/
680  self Kill();
681  }
682  }
683  }
684 
685  if ( onNavVolume )
686  {
687  self ‪update_main_guard();
688 
689  if ( owner.main_guard === self )
690  {
691  guardPoints = ‪get_guard_points( owner );
692  if ( guardPoints.size < 1 )
693  {
694  wait 1;
695  continue;
696  }
697 
698  stuckCount = 0;
699  self.vehAirCraftCollisionEnabled = true;
700 
701  if ( guardPoints.size <= pointIndex )
702  {
703  pointIndex = RandomInt( Int( min( self._guard_points.size, guardPoints.size ) ) );
704  timeNotAtGoal = GetTime();
705  }
706 
707  self.current_pathto_pos = guardPoints[pointIndex];
708  }
709  else
710  {
711  main_guard = owner.main_guard;
712  if( isalive( main_guard ) && isdefined( main_guard.current_pathto_pos ) )
713  {
714  query_position = main_guard.current_pathto_pos;
715  queryResult = PositionQuery_Source_Navigation( query_position, 20, ‪WASP_GROUP_RADIUS, 100, 20, self, 15 );
716 
717  if ( queryResult.data.size > 0 )
718  {
719  self.current_pathto_pos = queryResult.data[ queryResult.data.size - 1 ].origin;
720  }
721  }
722  }
723  }
724 
725  if ( IsDefined( self.current_pathto_pos ) )
726  {
727  distanceToGoalSq = DistanceSquared( self.current_pathto_pos, self.origin );
728  if ( !onNavVolume || distanceToGoalSq > ‪SQR( 60 ) )
729  {
730  if ( distanceToGoalSq > ‪SQR( 600 ) )
731  {
732  self SetSpeed( self.settings.defaultMoveSpeed * 2 );
733  }
734  else if ( distanceToGoalSq < ‪SQR( 100 ) )
735  {
736  self SetSpeed( self.settings.defaultMoveSpeed * 0.3 );
737  }
738  else
739  {
740  self SetSpeed( self.settings.defaultMoveSpeed );
741  }
742 
743  timeNotAtGoal = GetTime();
744  }
745  else // already at goal
746  {
747  if ( ‪vehicle_ai::TimeSince( timeNotAtGoal ) > 4 )
748  {
749  pointIndex = RandomInt( self._guard_points.size );
750  timeNotAtGoal = GetTime();
751  }
752 
753  wait 0.2;
754  continue;
755  }
756 
757  if ( self SetVehGoalPos( self.current_pathto_pos, true, usePathfinding ) )
758  {
759  self playsound ( "veh_wasp_direction" );
760 
761  self ClearLookAtEnt();
762  self notify( "fire_stop" ); // stop shooting
763  //self.noshoot = true;
764 
765  self thread ‪path_update_interrupt();
766  if ( onNavVolume )
767  {
769  }
770  else
771  {
773  }
774  //self.noshoot = undefined;
775  }
776  else
777  {
778  wait 0.5;
779  }
780  }
781  else
782  {
783  wait 0.5;
784  }
785  }
786  }
787 }
788 
789 // ----------------------------------------------
790 // State: combat
791 // ----------------------------------------------
792 function ‪state_combat_enter( params )
793 {
794  if ( self.enable_target_laser === true )
795  {
796  self LaserOn();
797  }
798 
799  if ( IsDefined( self.owner ) && IsDefined( self.owner.enemy ) )
800  {
801  self.favoriteEnemy = self.owner.enemy;
802  }
803  self thread ‪turretFireUpdate();
804 }
805 
807 {
808  self endon( "death" );
809  self endon( "change_state" );
810 
811  isRocketType = ( self.variant === "rocket" );
812 
813  while( 1 )
814  {
815  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
816  {
817  if( DistanceSquared( self.enemy.origin, self.origin ) < ‪SQR( 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax ) * 3 ) )
818  {
819  self SetLookAtEnt( self.enemy );
820 
821  if( isRocketType )
822  {
823  self SetTurretTargetEnt( self.enemy, self.enemy GetVelocity() * 0.3 - ‪vehicle_ai::GetTargetEyeOffset( self.enemy ) * 0.3 );
824  }
825  else
826  {
827  self SetTurretTargetEnt( self.enemy, -‪vehicle_ai::GetTargetEyeOffset( self.enemy ) * 0.3 );
828  }
829 
830  startAim = GetTime();
831  while ( !self.turretontarget && ‪vehicle_ai::TimeSince( startAim ) < 3 )
832  {
833  wait 0.2;
834  }
835 
836  if ( isdefined( self.enemy ) && self.turretontarget && self.noshoot !== true )
837  {
838  if( isRocketType )
839  {
840  for( i = 0; i < 2 && isdefined( self.enemy ); i++ )
841  {
842  self FireWeapon( 0, self.enemy );
843  fired = true;
844  wait 0.25;
845  }
846  }
847  else
848  {
849  self ‪vehicle_ai::fire_for_time( RandomFloatRange( self.settings.turret_fire_burst_min, self.settings.turret_fire_burst_max ), 0, self.enemy );
850  }
851 
852  if( isdefined( self.settings.turret_cooldown_max ) )
853  {
854  ‪DEFAULT( self.settings.turret_cooldown_min, 0 );
855  wait( RandomFloatRange( self.settings.turret_cooldown_min, self.settings.turret_cooldown_max ) );
856  }
857  }
858  else
859  {
860  if( isdefined( self.settings.turret_enemy_detect_freq ) )
861  wait self.settings.turret_enemy_detect_freq;
862  }
863 
864  self SetTurretTargetRelativeAngles( (15,0,0), 0 );
865  }
866 
867  if( isRocketType )
868  {
869  if( isdefined( self.enemy ) && IsAI( self.enemy ) )
870  {
871  wait( RandomFloatRange( 4, 7 ) );
872  }
873  else
874  {
875  wait( RandomFloatRange( 3, 5 ) );
876  }
877  }
878  else
879  {
880  if( isdefined( self.enemy ) && IsAI( self.enemy ) )
881  {
882  wait( RandomFloatRange( 2, 2.5 ) );
883  }
884  else
885  {
886  wait( RandomFloatRange( 0.5, 1.5 ) );
887  }
888  }
889  }
890  else
891  {
892  wait 0.4;
893  }
894  }
895 }
896 
897 
899 {
900  self endon( "death" );
901  self endon( "change_state" );
902  self endon( "near_goal" );
903  self endon( "reached_end_node" );
904 
905  old_enemy = self.enemy;
906 
907  wait 1;
908 
909  while( 1 )
910  {
911  if( isdefined( self.current_pathto_pos ) )
912  {
913  if( distance2dSquared( self.current_pathto_pos, self.goalpos ) > ‪SQR( self.goalradius ) )
914  {
915  wait 0.2;
916  self notify( "near_goal" );
917  }
918  }
919 
920  if ( isdefined( self.enemy ) )
921  {
922  if ( self.noshoot !== true && self VehCanSee( self.enemy ) )
923  {
924  self SetTurretTargetEnt( self.enemy );
925  self SetLookAtEnt( self.enemy );
926  }
927 
928  if( !isdefined( old_enemy ) )
929  {
930  self notify( "near_goal" ); // new enemy
931  }
932  else if( self.enemy != old_enemy )
933  {
934  self notify( "near_goal" ); // new enemy
935  }
936 
937  if( self VehCanSee( self.enemy ) && distance2dSquared( self.origin, self.enemy.origin ) < ‪SQR( ‪WASP_ENEMY_TOO_CLOSE_DIST ) )
938  {
939  self notify( "near_goal" );
940  }
941  }
942 
943  wait 0.2;
944  }
945 }
946 
948 {
949  self endon( "change_state" );
950  self endon( "death" );
951 
952  wait 0.1;
953 
954  time = ‪timeout;
955  cant_see_count = 0;
956 
957  while( time > 0 )
958  {
959  if( isdefined( self.current_pathto_pos ) )
960  {
961  if( distanceSquared( self.current_pathto_pos, self.goalpos ) > ‪SQR( self.goalradius ) )
962  {
963  break;
964  }
965  }
966 
967  if( isdefined( self.enemy ) )
968  {
969  if ( !self vehCanSee( self.enemy ) )
970  {
971  cant_see_count++;
972  if( cant_see_count >= 3 )
973  {
974  break;
975  }
976  }
977  else
978  {
979  cant_see_count = 0;
980  }
981 
982  if( distance2dSquared( self.origin, self.enemy.origin ) < ‪SQR( ‪WASP_ENEMY_TOO_CLOSE_DIST ) )
983  {
984  break;
985  }
986 
987  // height check
988  goalHeight = self.enemy.origin[2] + 0.5 * ( self.settings.engagementHeightMin + self.settings.engagementHeightMax );
989  distFromPreferredHeight = abs( self.origin[2] - goalHeight );
990  if ( distFromPreferredHeight > 100 )
991  {
992  break;
993  }
994 
995  if( isplayer( self.enemy ) && self.enemy islookingat( self ) )
996  {
997  if ( ‪math::cointoss() )
998  {
999  wait RandomFloatRange( 0.1, 0.5 );
1000  }
1001 
1002  self ‪drop_leader(); // gotta move away fast, we'll pick him up again in a bit
1003  break;
1004  }
1005  }
1006 
1007  if( isdefined( self.leader ) && isdefined( self.leader.current_pathto_pos ) )
1008  {
1009  if( distanceSquared( self.origin, self.leader.current_pathto_pos ) > ‪SQR( ‪WASP_GROUP_RADIUS + 25 ) )
1010  {
1011  //wait RandomFloatRange( 0.1, 0.3 );
1012  break;
1013  }
1014  }
1015 
1016  wait 0.3;
1017  time -= 0.3;
1018  }
1019 }
1020 
1021 function ‪drop_leader()
1022 {
1023  if( isdefined( self.leader ) )
1024  {
1025  ArrayRemoveValue( self.leader.followers, self );
1026  self.leader = undefined;
1027  }
1028 }
1029 
1031 {
1032  //if self.no_group is set to true, don't find a leader
1033  if( isdefined( self.no_group ) && self.no_group == true )
1034  {
1035  return;
1036  }
1037 
1038  if( isdefined( self.leader ) )
1039  {
1040  return; // already have a leader
1041  }
1042 
1043  if( isdefined( self.followers ) )
1044  {
1045  self.followers = array::remove_dead( self.followers, false );
1046  if( self.followers.size > 0 ) // we are a leader
1047  {
1048  return;
1049  }
1050  }
1051 
1052  team_mates = GetAITeamArray( self.team );
1053 
1054  foreach( guy in team_mates )
1055  {
1056  if( isdefined( guy.archetype ) && guy.archetype == "wasp" )
1057  {
1058  if( isdefined( guy.leader ) )
1059  {
1060  continue; // guy is already a follower
1061  }
1062 
1063  if( guy == self )
1064  {
1065  continue;
1066  }
1067 
1068  if( distanceSquared( self.origin, guy.origin ) > ‪SQR( 700 ) )
1069  {
1070  continue; // guy too far
1071  }
1072 
1073  if( !isdefined( guy.followers ) )
1074  {
1075  guy.followers = [];
1076  }
1077 
1078  if( guy.followers.size >= ‪WASP_GROUP_SIZE-1 )
1079  {
1080  continue; // already full group
1081  }
1082 
1083  // found a leader
1084  guy.followers[ guy.followers.size ] = self;
1085  self.leader = guy;
1086  break;
1087  }
1088  }
1089 }
1090 
1091 function ‪should_fly_forward( distanceToGoalSq )
1092 {
1093  if ( self.always_face_enemy === true )
1094  {
1095  return false;
1096  }
1097 
1098  if( distanceToGoalSq < ‪SQR( 250 ) )
1099  {
1100  return false;
1101  }
1102 
1103  // always face enemy when backing away
1104  if( isdefined( self.enemy ) )
1105  {
1106  to_goal = VectorNormalize( self.current_pathto_pos - self.origin );
1107  to_enemy = VectorNormalize( self.enemy.origin - self.origin );
1108 
1109  dot = VectorDot( to_goal, to_enemy );
1110  if( abs( dot ) > 0.7 )
1111  {
1112  return false;
1113  }
1114  }
1115 
1116  if( distanceToGoalSq > ‪SQR( 400 ) )
1117  {
1118  return RandomInt( 100 ) > 25;
1119  }
1120 
1121  return RandomInt( 100 ) > 50;
1122 }
1123 
1124 function ‪state_combat_update( params )
1125 {
1126  self endon( "change_state" );
1127  self endon( "death" );
1128 
1129  // allow script to set goalpos and whatever else before moving
1130  wait .1;
1131 
1132  stuckCount = 0;
1133 
1134  for( ;; )
1135  {
1136  self SetSpeed( self.settings.defaultMoveSpeed );
1137 
1138  self ‪update_leader();
1139 
1140  if ( ‪IS_TRUE( self.inpain ) )
1141  {
1142  wait 0.1;
1143  }
1144  else
1145  {
1146  if ( self.enable_guard === true )
1147  {
1149  }
1150 
1151  if ( IsDefined( self.enemy ) )
1152  {
1153  self SetTurretTargetEnt( self.enemy );
1154  self SetLookAtEnt( self.enemy );
1155 
1156  self ‪wait_till_something_happens( RandomFloatRange( 2, 5 ) );
1157  }
1158 
1159  if ( !IsDefined( self.enemy ) )
1160  {
1161  self ClearLookAtEnt();
1162 
1163  AIArray = GetAITeamArray( "all" );
1164  foreach ( AI in AIArray )
1165  {
1166  self GetPerfectInfo( AI );
1167  }
1168 
1169  players = GetPlayers( "all" );
1170  foreach ( player in players )
1171  {
1172  self GetPerfectInfo( player );
1173  }
1174 
1175  wait 1;
1176  }
1177 
1178  usePathfinding = true;
1179  onNavVolume = IsPointInNavVolume( self.origin, "navvolume_small" );
1180  if ( !onNavVolume )
1181  {
1182  // off nav volume, try getting back
1183  getbackPoint = undefined;
1184 
1185  if ( self.aggresive_navvolume_recover === true ) // MP specific
1186  {
1188  }
1189 
1190  pointOnNavVolume = self GetClosestPointOnNavVolume( self.origin, 100 );
1191  if ( isdefined( pointOnNavVolume ) )
1192  {
1193  if ( SightTracePassed( self.origin, pointOnNavVolume, false, self ) )
1194  {
1195  getbackPoint = pointOnNavVolume;
1196  }
1197  }
1198 
1199  if ( !isdefined( getbackPoint ) )
1200  {
1201  queryResult = PositionQuery_Source_Navigation( self.origin, 0, 200, 100, 2 * self.radius, self );
1202  PositionQuery_Filter_Sight( queryResult, self.origin, (0, 0, 0), self, 1 );
1203  getbackPoint = undefined;
1204  foreach( point in queryResult.data )
1205  {
1206  if ( point.visibility === true )
1207  {
1208  getbackPoint = point.origin;
1209  break;
1210  }
1211  }
1212  }
1213 
1214  if ( isdefined( getbackPoint ) )
1215  {
1216  self.current_pathto_pos = getbackPoint;
1217  usePathfinding = false;
1218  }
1219  else
1220  {
1221  stuckCount++;
1222  if ( stuckCount == 1 )
1223  {
1224  stuckLocation = self.origin;
1225  }
1226  else if ( stuckCount > 10 )
1227  {
1228  /#
1229  assert( false, "Wasp fall outside of NavVolume at " + self.origin );
1230  v_box_min = ( -self.radius, -self.radius, -self.radius );
1231  v_box_max = ( self.radius, self.radius, self.radius );
1232  Box( self.origin, v_box_min, v_box_max, self.angles[1], (1,0,0), 1, false, 1000000 );
1233  if ( isdefined( stuckLocation ) )
1234  {
1235  Line( stuckLocation, self.origin, (1,0,0), 1, true, 1000000 );
1236  }
1237  #/
1238  self Kill();
1239  }
1240  }
1241  }
1242  else
1243  {
1244  stuckCount = 0;
1245 
1246  if( self.goalforced )
1247  {
1248  goalpos = self GetClosestPointOnNavVolume( self.goalpos, 100 );
1249  if ( isdefined( goalpos ) )
1250  {
1251  self.current_pathto_pos = goalpos;
1252  usePathfinding = true;
1253  }
1254  else
1255  {
1256  self.current_pathto_pos = self.goalpos;
1257  usePathfinding = false;
1258  }
1259  }
1260  else if ( IsDefined( self.enemy ) )
1261  {
1262  self.current_pathto_pos = ‪GetNextMovePosition_tactical();
1263  usePathfinding = true;
1264  }
1265  else
1266  {
1267  self.current_pathto_pos = ‪GetNextMovePosition_wander();
1268  usePathfinding = true;
1269  }
1270  }
1271 
1272  if ( IsDefined( self.current_pathto_pos ) )
1273  {
1274  distanceToGoalSq = DistanceSquared( self.current_pathto_pos, self.origin );
1275 
1276  if ( !onNavVolume || distanceToGoalSq > ‪SQR( ‪WASP_HOVER_RADIUS * 1.5 ) )
1277  {
1278  if ( distanceToGoalSq > ‪SQR( 2000 ) )
1279  {
1280  self SetSpeed( self.settings.defaultMoveSpeed * 2 );
1281  }
1282 
1283  if ( self SetVehGoalPos( self.current_pathto_pos, true, usePathfinding ) )
1284  {
1285  if ( IsDefined( self.enemy ) )
1286  {
1287  self playsound ( "veh_wasp_direction" );
1288  }
1289  else
1290  {
1291  self playsound ( "veh_wasp_vox" );
1292  }
1293 
1294  if ( ‪should_fly_forward( distanceToGoalSq ) )
1295  {
1296  // fly foward if flying far
1297  self ClearLookAtEnt();
1298  self notify( "fire_stop" ); // stop shooting
1299  self.noshoot = true;
1300  }
1301  self thread ‪path_update_interrupt();
1303  self.noshoot = undefined;
1304  }
1305  }
1306  }
1307  }
1308  }
1309 }
1310 
1311 function ‪GetNextMovePosition_wander() // no self.enemy
1312 {
1313  queryMultiplier = 1;
1314 
1315  queryResult = PositionQuery_Source_Navigation( self.origin, ‪WASP_MOVE_DIST_MIN, ‪WASP_MOVE_DIST_MAX * queryMultiplier, 130, 3 * self.radius * queryMultiplier, self, self.radius * queryMultiplier );
1316  PositionQuery_Filter_DistanceToGoal( queryResult, self );
1318 
1319  self.isOnNav = queryResult.centerOnNav;
1320 
1321  best_point = undefined;
1322  best_score = -999999;
1323 
1324  foreach ( point in queryResult.data )
1325  {
1326  randomScore = randomFloatRange( 0, 100 );
1327  distToOriginScore = point.distToOrigin2D * 0.2;
1328 
1329  point.score += randomScore + distToOriginScore;
1330  ADD_POINT_SCORE(point, "distToOrigin", distToOriginScore );
1331 
1332  if ( point.score > best_score )
1333  {
1334  best_score = point.score;
1335  best_point = point;
1336  }
1337  }
1338 
1339  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
1340 
1341  if( !isdefined( best_point ) )
1342  {
1343  return undefined;
1344  }
1345 
1346  return best_point.origin;
1347 }
1348 
1349 function ‪GetNextMovePosition_tactical() // has self.enemy
1350 {
1351  if( !isdefined( self.enemy ) )
1352  {
1353  return self ‪GetNextMovePosition_wander();
1354  }
1355 
1356  // distance based multipliers
1357  selfDistToTarget = Distance2D( self.origin, self.enemy.origin );
1358 
1359  goodDist = 0.5 * ( self.settings.engagementDistMin + self.settings.engagementDistMax );
1360 
1361  closeDist = 1.2 * goodDist;
1362  farDist = 3 * goodDist;
1363 
1364  queryMultiplier = MapFloat( closeDist, farDist, 1, 3, selfDistToTarget );
1365 
1366  preferedHeightRange = 35;
1367  randomness = 30;
1368 
1369  avoid_locations = [];
1370  avoid_radius = 50;
1371 
1372  // query
1373  if( isalive( self.leader ) && isdefined( self.leader.current_pathto_pos ) )
1374  {
1375  query_position = self.leader.current_pathto_pos;
1376 
1377  queryResult = PositionQuery_Source_Navigation( query_position, 0, ‪WASP_GROUP_RADIUS, 100, 35, self, 25 );
1378 
1379  /*foreach( guy in self.leader.followers )
1380  {
1381  if( isdefined( guy ) && guy != self )
1382  {
1383  if( isdefined( guy.current_pathto_pos ) )
1384  {
1385  avoid_locations[ avoid_locations.size ] = guy.current_pathto_pos;
1386  }
1387  }
1388  }*/
1389  }
1390  else if ( isalive( self.owner ) && self.enable_guard === true )
1391  {
1392  ownerorigin = self GetClosestPointOnNavVolume( self.owner.origin + (0,0,40), 50 );
1393  if ( isdefined( ownerorigin ) )
1394  {
1395  queryResult = PositionQuery_Source_Navigation( ownerorigin, 0, ‪WASP_MOVE_DIST_MAX * min( queryMultiplier, 1.5 ), 130, 3 * self.radius, self );
1396  if ( isdefined( queryResult ) && isdefined( queryResult.data ) )
1397  {
1398  PositionQuery_Filter_Sight( queryResult, self.owner GetEye(), (0, 0, 0), self, 5, self, "visowner" );
1399  PositionQuery_Filter_Sight( queryResult, self.enemy GetEye(), (0, 0, 0), self, 5, self, "visenemy" );
1400  foreach ( point in queryResult.data )
1401  {
1402  if ( point.visowner === true )
1403  {
1404  ADD_POINT_SCORE( point, "visowner", 300 );
1405  }
1406 
1407  if ( point.visenemy === true )
1408  {
1409  ADD_POINT_SCORE( point, "visenemy", 300 );
1410  }
1411  }
1412  }
1413  }
1414  }
1415  else
1416  {
1417  queryResult = PositionQuery_Source_Navigation( self.origin, 0, ‪WASP_MOVE_DIST_MAX * min( queryMultiplier, 2 ), 130, 3 * self.radius * queryMultiplier, self, 2.2 * self.radius * queryMultiplier );
1418 
1419  team_mates = GetAITeamArray( self.team );
1420 
1421  avoid_radius = ‪WASP_GROUP_RADIUS;
1422 
1423  foreach( guy in team_mates )
1424  {
1425  if( isdefined( guy.archetype ) && guy.archetype == "wasp" )
1426  {
1427  // avoid other leaders if we are a leader
1428  if( isdefined( guy.followers ) && guy.followers.size > 0 && guy != self )
1429  {
1430  if( isdefined( guy.current_pathto_pos ) )
1431  {
1432  avoid_locations[ avoid_locations.size ] = guy.current_pathto_pos;
1433  }
1434  }
1435  }
1436  }
1437  }
1438 
1439  //If there are no data points to query for points to path to, then just return out undefined
1440  if( !isdefined( queryResult ) || !isdefined( queryResult.data ) || queryResult.data.size == 0)
1441  {
1442  return undefined;
1443  }
1444 
1445  // filter
1446  PositionQuery_Filter_DistanceToGoal( queryResult, self );
1447  PositionQuery_Filter_InClaimedLocation( queryResult, self );
1449  self ‪vehicle_ai::PositionQuery_Filter_EngagementDist( queryResult, self.enemy, self.settings.engagementDistMin, self.settings.engagementDistMax );
1450  self ‪vehicle_ai::PositionQuery_Filter_EngagementHeight( queryResult, self.enemy, self.settings.engagementHeightMin, self.settings.engagementHeightMax );
1451 
1452  // score points
1453  best_point = undefined;
1454  best_score = -999999;
1455 
1456  foreach ( point in queryResult.data )
1457  {
1458  ADD_POINT_SCORE( point, "random", randomFloatRange( 0, randomness ) );
1459 
1460  ADD_POINT_SCORE( point, "engagementDist", -point.distAwayFromEngagementArea );
1461  ADD_POINT_SCORE( point, "height", -point.distEngagementHeight * 1.4 );
1462 
1463  if( point.disttoorigin2d < 120 )
1464  {
1465  ADD_POINT_SCORE( point, "tooCloseToSelf", (120 - point.disttoorigin2d) * -1.5 );
1466  }
1467 
1468  foreach( location in avoid_locations )
1469  {
1470  if( distanceSquared( point.origin, location ) < ‪SQR( avoid_radius ) )
1471  {
1472  ADD_POINT_SCORE( point, "tooCloseToOthers", -avoid_radius );
1473  }
1474  }
1475 
1476  if( point.inClaimedLocation )
1477  {
1478  ADD_POINT_SCORE( point, "inClaimedLocation", -500 );
1479  }
1480 
1481  if ( point.score > best_score )
1482  {
1483  best_score = point.score;
1484  best_point = point;
1485  }
1486  }
1487 
1488  self ‪vehicle_ai::PositionQuery_DebugScores( queryResult );
1489 
1490  if( !isdefined( best_point ) )
1491  {
1492  return undefined;
1493  }
1494 
1495  /#
1496  if ( ‪IS_TRUE( GetDvarInt("hkai_debugPositionQuery") ) )
1497  {
1498  recordLine( self.origin, best_point.origin, (0.3,1,0) );
1499  recordLine( self.origin, self.enemy.origin, (1,0,0.4) );
1500  }
1501 #/
1502 
1503  return best_point.origin;
1504 }
1505 
1506 function ‪drone_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
1507 {
1508  iDamage = ‪vehicle_ai::shared_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );
1509 
1510  return iDamage;
1511 }
1512 
1513 function ‪drone_AllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon )
1514 {
1515  if ( isdefined( eAttacker ) && isdefined( eAttacker.archetype ) && isdefined( sMeansOfDeath )
1516  && eAttacker.archetype == ‪ARCHETYPE_WASP && sMeansOfDeath == "MOD_EXPLOSIVE" )
1517  {
1518  return true;
1519  }
1520 
1521  return false;
1522 }
1523 
1524 // ----------------------------------------------
1525 // State: driving
1526 // ----------------------------------------------
1527 
1528 function ‪wasp_driving( params )
1529 {
1530  self endon( "change_state" );
1531 
1532  driver = self GetSeatOccupant( 0 );
1533 
1534  if( isPlayer( driver ) )
1535  {
1536  ‪clientfield::set( "rocket_wasp_hijacked", 1 );
1537  }
1538 
1539  if( isPlayer( driver ) && isDefined( self.playerDrivenVersion) )
1540  {
1541  self thread ‪wasp_manage_camera_swaps();
1542  }
1543 
1544 }
1545 
1547 {
1548  self endon ( "death" );
1549  self endon ( "change_state" );
1550 
1551  driver = self GetSeatOccupant( 0 );
1552 
1553  driver endon( "disconnect" );
1554 
1555  cam_low_type = self.vehicletype;
1556  cam_high_type = self.playerDrivenVersion;
1557 }
‪defaultRole
‪function defaultRole()
Definition: _wasp.gsc:107
‪timeout
‪function timeout(n_time, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:762
‪add_interrupt_connection
‪function add_interrupt_connection(from_state_name, to_state_name, on_notify, checkfunc)
Definition: statemachine_shared.gsc:90
‪startTime
‪class AnimationAdjustmentInfoZ startTime
‪add_state
‪function add_state(name, enter_func, update_func, exit_func, reenter_func)
Definition: statemachine_shared.gsc:59
‪lights_off
‪function lights_off(localClientNum)
Definition: vehicle_shared.csc:652
‪evaluate_connections
‪function evaluate_connections(eval_func, params)
Definition: statemachine_shared.gsc:266
‪randomSign
‪function randomSign()
Definition: math_shared.gsc:179
‪plane_crash
‪function plane_crash()
Definition: vehicle_death_shared.gsc:1485
‪should_fly_forward
‪function should_fly_forward(distanceToGoalSq)
Definition: _wasp.gsc:1091
‪toggle_emp_fx
‪function toggle_emp_fx(on)
Definition: vehicle_shared.gsc:2863
‪WASP_GROUP_SIZE
‪#define WASP_GROUP_SIZE
Definition: _wasp.gsc:27
‪WASP_GUARD_KEEP_ENEMY_DIST
‪#define WASP_GUARD_KEEP_ENEMY_DIST
Definition: _wasp.gsc:31
‪IsCooldownReady
‪function IsCooldownReady(name, timeForward_seconds)
Definition: vehicle_ai_shared.gsc:1968
‪update_main_guard
‪function update_main_guard()
Definition: _wasp.gsc:540
‪InitThreatBias
‪function InitThreatBias()
Definition: vehicle_ai_shared.gsc:60
‪GetNextMovePosition_tactical
‪function GetNextMovePosition_tactical()
Definition: _wasp.gsc:1349
‪emp_startup_fx
‪function emp_startup_fx()
Definition: vehicle_ai_shared.gsc:1457
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪state_emped_update
‪function state_emped_update(params)
Definition: _wasp.gsc:224
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪__init__
‪function __init__()
Definition: _wasp.gsc:43
‪cointoss
‪function cointoss()
Definition: math_shared.csc:171
‪DeleteWhenSafe
‪function DeleteWhenSafe(time=4)
Definition: vehicle_death_shared.gsc:1761
‪wasp_driving
‪function wasp_driving(params)
Definition: _wasp.gsc:1528
‪GetNextMovePosition_wander
‪function GetNextMovePosition_wander()
Definition: _wasp.gsc:1311
‪defaultstate_death_update
‪function defaultstate_death_update(params)
Definition: vehicle_ai_shared.gsc:1355
‪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
‪WASP_GUARD_ACQUIRE_ENEMY_DIST
‪#define WASP_GUARD_ACQUIRE_ENEMY_DIST
Definition: _wasp.gsc:29
‪state_guard_enter
‪function state_guard_enter(params)
Definition: _wasp.gsc:530
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪GREEN
‪#define GREEN
Definition: shared.gsh:176
‪ARCHETYPE_WASP
‪#define ARCHETYPE_WASP
Definition: archetype_shared.gsh:37
‪collision_fx
‪function collision_fx(normal)
Definition: vehicle_ai_shared.gsc:427
‪RED
‪#define RED
Definition: shared.gsh:175
‪shared_callback_damage
‪function shared_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: vehicle_ai_shared.gsc:726
‪WASP_MOVE_DIST_MAX
‪#define WASP_MOVE_DIST_MAX
Definition: _wasp.gsc:22
‪guard_points_debug
‪function guard_points_debug()
Definition: _wasp.gsc:438
‪StartInitialState
‪function StartInitialState(defaultState="combat")
Definition: vehicle_ai_shared.gsc:866
‪WASP_GUARD_LOSE_ENEMY_DIST
‪#define WASP_GUARD_LOSE_ENEMY_DIST
Definition: _wasp.gsc:30
‪GetTargetEyeOffset
‪function GetTargetEyeOffset(target)
Definition: vehicle_ai_shared.gsc:142
‪PositionQuery_Filter_EngagementHeight
‪function PositionQuery_Filter_EngagementHeight(queryResult, enemy, engagementHeightMin, engagementHeightMax)
Definition: vehicle_ai_shared.gsc:2229
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪drone_AllowFriendlyFireDamage
‪function drone_AllowFriendlyFireDamage(eInflictor, eAttacker, sMeansOfDeath, weapon)
Definition: _wasp.gsc:1513
‪WASP_HOVER_RADIUS
‪#define WASP_HOVER_RADIUS
Definition: _wasp.gsc:33
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪fall_and_bounce
‪function fall_and_bounce(killOnImpact_speed, killOnImpact_time)
Definition: _wasp.gsc:339
‪kill
‪function kill(ent_1, str_tag1, ent_2, str_tag2, str_beam_type)
Definition: beam_shared.csc:41
‪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
‪waittill_pathing_done
‪function waittill_pathing_done(maxtime=15)
Definition: vehicle_ai_shared.gsc:340
‪WASP_NEARGOAL_DIST
‪#define WASP_NEARGOAL_DIST
Definition: _wasp.gsc:35
‪PositionQuery_DebugScores
‪function PositionQuery_DebugScores(queryResult)
Definition: vehicle_ai_shared.gsc:2010
‪path_update_interrupt
‪function path_update_interrupt()
Definition: _wasp.gsc:898
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪fire_for_time
‪function fire_for_time(n_time, n_index=0)
Definition: turret_shared.gsc:953
‪PositionQuery_Filter_OutOfGoalAnchor
‪function PositionQuery_Filter_OutOfGoalAnchor(queryResult, tolerance=1)
Definition: vehicle_ai_shared.gsc:2104
‪wasp_initialize
‪function wasp_initialize()
Definition: _wasp.gsc:49
‪state_guard_exit
‪function state_guard_exit(params)
Definition: _wasp.gsc:548
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪state_death_update
‪function state_death_update(params)
Definition: _wasp.gsc:139
‪random_crash
‪function random_crash(hitdir)
Definition: vehicle_death_shared.gsc:1556
‪drop_leader
‪function drop_leader()
Definition: _wasp.gsc:1021
‪state_combat_enter
‪function state_combat_enter(params)
Definition: _wasp.gsc:792
‪wait_till_something_happens
‪function wait_till_something_happens(timeout)
Definition: _wasp.gsc:947
‪state_guard_update
‪function state_guard_update(params)
Definition: _wasp.gsc:590
‪init_guard_points
‪function init_guard_points()
Definition: _wasp.gsc:427
‪PositionQuery_Filter_EngagementDist
‪function PositionQuery_Filter_EngagementDist(queryResult, enemy, engagementDistanceMin, engagementDistanceMax)
Definition: vehicle_ai_shared.gsc:2116
‪GetCooldownLeft
‪function GetCooldownLeft(name)
Definition: vehicle_ai_shared.gsc:1961
‪WASP_ENEMY_TOO_CLOSE_DIST
‪#define WASP_ENEMY_TOO_CLOSE_DIST
Definition: _wasp.gsc:24
‪state_guard_can_enter
‪function state_guard_can_enter(from_state, to_state, connection)
Definition: _wasp.gsc:503
‪drone_callback_damage
‪function drone_callback_damage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal)
Definition: _wasp.gsc:1506
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪get_guard_points
‪function get_guard_points(owner)
Definition: _wasp.gsc:465
‪state_combat_update
‪function state_combat_update(params)
Definition: _wasp.gsc:1124
‪TimeSince
‪function TimeSince(startTimeInMilliseconds)
Definition: vehicle_ai_shared.gsc:1930
‪wasp_manage_camera_swaps
‪function wasp_manage_camera_swaps()
Definition: _wasp.gsc:1546
‪add_utility_connection
‪function add_utility_connection(from_state_name, to_state_name, checkfunc, defaultScore)
Definition: statemachine_shared.gsc:112
‪test_get_back_queryresult
‪function test_get_back_queryresult(queryResult)
Definition: _wasp.gsc:571
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪update_leader
‪function update_leader()
Definition: _wasp.gsc:1030
‪turretFireUpdate
‪function turretFireUpdate()
Definition: _wasp.gsc:806
‪lights_on
‪function lights_on(localClientNum, team)
Definition: vehicle_shared.csc:404
‪WASP_GROUP_RADIUS
‪#define WASP_GROUP_RADIUS
Definition: _wasp.gsc:26
‪get_state_callbacks
‪function get_state_callbacks(statename)
Definition: vehicle_ai_shared.gsc:927
‪WASP_MOVE_DIST_MIN
‪#define WASP_MOVE_DIST_MIN
Definition: _wasp.gsc:21
‪test_get_back_point
‪function test_get_back_point(point)
Definition: _wasp.gsc:556
‪barrel_rolling_crash
‪function barrel_rolling_crash()
Definition: vehicle_death_shared.gsc:1524
‪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