‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_quadrotor.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\gameskill_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\statemachine_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\util_shared;
8 #using scripts\shared\vehicle_shared;
9 #using scripts\shared\vehicle_ai_shared;
10 #using scripts\shared\vehicle_death_shared;
11 #using scripts\shared\flag_shared;
12 
13 #insert scripts\shared\shared.gsh;
14 #insert scripts\shared\statemachine.gsh;
15 
16 #insert scripts\shared\ai\utility.gsh;
17 
18 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate01" );
19 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate02" );
20 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate03" );
21 #precache( "fx", "_t6/destructibles/fx_quadrotor_damagestate04" );
22 #precache( "fx", "_t6/destructibles/fx_quadrotor_crash01" );
23 #precache( "fx", "_t6/destructibles/fx_quadrotor_nudge01" );
24 #precache( "fx", "_t6/electrical/fx_elec_sp_emp_stun_quadrotor" );
25 
26 #namespace quadrotor;
27 
28 ‪REGISTER_SYSTEM( "quadrotor", &‪__init__, undefined )
29 
30 function ‪__init__()
31 {
32  vehicle::add_main_callback( "heli_quadrotor",&‪quadrotor_think );
33  vehicle::add_main_callback( "heli_quadrotor_rts",&‪quadrotor_think );
34 
35 // SetSavedDvar( "vehHelicopterLookaheadTime", .07 );
36 
37  level._effect[ "quadrotor_damage01" ] = "_t6/destructibles/fx_quadrotor_damagestate01";
38  level._effect[ "quadrotor_damage02" ] = "_t6/destructibles/fx_quadrotor_damagestate02";
39  level._effect[ "quadrotor_damage03" ] = "_t6/destructibles/fx_quadrotor_damagestate03";
40  level._effect[ "quadrotor_damage04" ] = "_t6/destructibles/fx_quadrotor_damagestate04";
41 
42  level._effect[ "quadrotor_crash" ] = "_t6/destructibles/fx_quadrotor_crash01";
43  level._effect[ "quadrotor_nudge" ] = "_t6/destructibles/fx_quadrotor_nudge01";
44 
45  level._effect[ "quadrotor_stun" ] = "_t6/electrical/fx_elec_sp_emp_stun_quadrotor";
46 
47 }
48 
50 {
51  self.maxhealth = 200;//TODO T7 - added this because the MP callbacks want it. Can probably get rid of this later
52  self EnableAimAssist();
53  self SetHoverParams( 25.0, 120.0, 80 );
54  self SetNearGoalNotifyDist( 30 );
55 
56  self.flyheight = GetDvarFloat( "g_quadrotorFlyHeight" );
57 
58  self.fovcosine = 0; // +/-90 degrees = 180
59  self.fovcosinebusy = 0.574; //+/- 55 degrees = 110 fov
60 
61  self.vehAirCraftCollisionEnabled = true;
62 
63  if ( !IsDefined( self.heightAboveGround ) )
64  {
65  self.heightAboveGround = 100;
66  }
67 
68  if( !isdefined( self.goalradius ) )
69  {
70  self.goalradius = 600;
71  }
72 
73  if( !isdefined( self.goalpos ) )
74  {
75  self.goalpos = self.origin;
76  }
77 
78  self.original_vehicle_type = self.vehicletype;
79 
80  self.state_machine = ‪statemachine::create( "quadrotorbrain", self );
81  ‪main = self.state_machine ‪statemachine::add_state( "main", undefined,&‪quadrotor_main, undefined );
82  scripted = self.state_machine ‪statemachine::add_state( "scripted", undefined, &‪quadrotor_scripted, undefined );
83 
84  ‪vehicle_ai::add_interrupt_connection( "scripted", "main", "enter_vehicle" );
85  ‪vehicle_ai::add_interrupt_connection( "scripted", "main", "scripted" );
86  ‪vehicle_ai::add_interrupt_connection( "scripted", "main", "enter_vehicle" );
87  ‪vehicle_ai::add_interrupt_connection( "main", "scripted", "exit_vehicle" );
88  ‪vehicle_ai::add_interrupt_connection( "main", "scripted", "main" );
89  ‪vehicle_ai::add_interrupt_connection( "main", "scripted", "scripted_done" );
90 
91  self thread ‪quadrotor_death();
92  self thread ‪quadrotor_damage();
93  self HidePart( "tag_viewmodel" );
94 
95  self.overrideVehicleDamage =&‪QuadrotorCallback_VehicleDamage;
96 
97  // Set the first state
98  if ( isdefined( self.script_startstate ) )
99  {
100  if( self.script_startstate == "off" )
101  {
102  self ‪quadrotor_off();
103  }
104  else
105  {
106  self.state_machine ‪statemachine::set_state( self.script_startstate );
107  }
108  }
109  else
110  {
111  // Set the first state
113  }
114 
115  self thread ‪quadrotor_set_team( self.team );
116 
117  // start the update
118  // No need for this update any more since all connections are on notifies
119  //self.state_machine statemachine::update( 0.05 );
120 }
121 
123 {
124  if( !IsAlive( self ) )
125  return false;
126 
127  driver = self GetSeatOccupant( 0 );
128  if( isdefined( driver ) )
129  return false;
130 
131  return true;
132 }
133 
135 {
136  self.state_machine ‪statemachine::set_state( "scripted" );
137 }
138 
140 {
141  self.state_machine ‪statemachine::set_state( "scripted" );
142  self ‪vehicle::lights_off();
143  self ‪vehicle::toggle_tread_fx( 0 );
144  self ‪vehicle::toggle_sounds( 0 );
145  self HidePart( "tag_rotor_fl" );
146  self HidePart( "tag_rotor_fr" );
147  self HidePart( "tag_rotor_rl" );
148  self HidePart( "tag_rotor_rr" );
149  if( !isdefined( self.‪emped ) )
150  {
151  self DisableAimAssist();
152  }
153  self.off = true;
154 }
155 
156 function ‪quadrotor_on()
157 {
158  self ‪vehicle::lights_on();
159  self ‪vehicle::toggle_tread_fx( 1 );
160  self ‪vehicle::toggle_sounds( 1 );
161  self ShowPart( "tag_rotor_fl" );
162  self ShowPart( "tag_rotor_fr" );
163  self ShowPart( "tag_rotor_rl" );
164  self ShowPart( "tag_rotor_rr" );
165  self EnableAimAssist();
166  self.off = undefined;
168 }
169 
171 {
172  self.goalpos = self.origin;
173  self.state_machine ‪statemachine::set_state( "main" );
174 }
175 
177 {
178  self thread ‪quadrotor_blink_lights();
179  self thread ‪quadrotor_fireupdate();
180  self thread ‪quadrotor_movementupdate();
181  self thread ‪quadrotor_collision();
182 }
183 
185 {
186  self endon( "death" );
187  self endon( "change_state" );
188 
189  while( 1 )
190  {
191  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
192  {
193  enemy_is_hind = false;
194  if( isdefined( self.enemy ) && isdefined( self.enemy.vehicletype ) )
195  {
196  enemy_is_hind = self.enemy.vehicletype == "heli_hind_afghan_rts";
197  }
198 
199  if( DistanceSquared( self.enemy.origin, self.origin ) < 1280 * 1280 || enemy_is_hind )
200  {
201  self SetTurretTargetEnt( self.enemy );
202  self ‪quadrotor_fire_for_time( RandomFloatRange( 0.3, 0.6 ) );
203  }
204 
205  if( isdefined( self.enemy ) && IsAI( self.enemy ) )
206  {
207  wait( RandomFloatRange( 2, 2.5 ) );
208  }
209  else
210  {
211  wait( RandomFloatRange( 0.5, 1.5 ) );
212  }
213  }
214  else
215  {
216  wait 0.4;
217  }
218  }
219 }
220 
221 function ‪quadrotor_check_move( position )
222 {
223  results = PhysicsTraceEx( self.origin, position, (-15,-15,-5), (15,15,5), self );
224 
225  if( results["fraction"] == 1 )
226  {
227  return true;
228  }
229 
230  return false;
231 }
232 
234 {
235  if( isdefined( self.enemy ) )
236  {
237  if( IsAI( self.enemy ) )
238  offset = 45;
239  else // don't want quadrotors to fly above quadrotors
240  offset = -100;
241 
242  if( self.enemy.origin[2] + offset > goalpos[2] )
243  {
244  goal_z = self.enemy.origin[2] + offset;
245  if( goal_z > goalpos[2] + 400 )
246  {
247  goal_z = goalpos[2] + 400;
248  }
249  results = PhysicsTraceEx( goalpos, ( goalpos[0], goalpos[1], goal_z ), (-15,-15,-5), (15,15,5), self );
250 
251  if( results["fraction"] == 1 )
252  {
253  goalpos = ( goalpos[0], goalpos[1], goal_z );
254  }
255  }
256  }
257 
258  return goalpos;
259 }
260 
262 {
263  start = pos + (0,0,self.flyheight);
264  ‪end = pos + (0,0,-self.flyheight);
265  ‪trace = BulletTrace( start, ‪end, false, self, false, false );
266  ‪end = ‪trace["position"];
267 
268  pos = ‪end + (0,0,self.flyheight);
269 
270  z = self GetHeliHeightLockHeight( pos );
271  pos = ( pos[0], pos[1], z );
272 
273  return pos;
274 }
275 
277 {
278  self endon( "death" );
279  self endon( "change_state" );
280 
281  if( self.vehonpath )
282  {
283  self ‪flag::wait_till( "goal_reached" );
284  }
285 }
286 
288 {
289  self endon( "death" );
290  self endon( "change_state" );
291 
292  self ‪flag::clear( "goal_reached" );
293  self ‪util::waittill_any( "near_goal", "reached_end_node", "force_goal" );
294  self ‪flag::set( "goal_reached" );
295 }
296 
298 {
299  self endon( "death" );
300  self endon( "change_state" );
301 
302  assert( IsAlive( self ) );
303 
304  // make sure when we start this that we get above the ground
305  old_goalpos = self.goalpos;
306  self.goalpos = self ‪make_sure_goal_is_well_above_ground( self.goalpos );
307 
308  if( !self.vehonpath )
309  {
310  if( isdefined( self.attachedpath ) )
311  {
312  // Need to wait, we may be attached to a path but haven't started it yet and we don't want to give a new goal and mess up the path
313  self ‪util::script_delay();
314  }
315  // Make sure we get off the ground otherwise our lookahead will have issues
316  else if( DistanceSquared( self.origin, self.goalpos ) < 100*100 && ( self.goalpos[2] > old_goalpos[2] + 10 || self.origin[2] + 10 < self.goalpos[2] ) )
317  {
318  self SetVehGoalPos( self.goalpos, true );
319  self PathVariableOffset( (0,0,20), 2 );
320  self ‪util::waittill_any_timeout( 4, "near_goal", "force_goal" );
321  }
322  else
323  {
324  goalpos = self ‪quadrotor_get_closest_node();
325  self SetVehGoalPos( goalpos, true );
326  self ‪util::waittill_any_timeout( 2, "near_goal", "force_goal" );
327  }
328  }
329 
330  assert( IsAlive( self ) );
331 
332  if ( !self ‪flag::exists( "goal_reached" ) )
333  {
334  self ‪flag::init( "goal_reached" );
335  }
336 
337  searchRadius = 100;
338  goalfailures = 0;
339 
340  while( 1 )
341  {
343  self thread ‪goal_flag_monitor();
344 
345  goalpos = undefined;
346 
347  while ( !IsDefined(goalpos) )
348  {
349  goalpos = ‪quadrotor_find_new_position();
350  }
351 
352  if ( isdefined( level.ai_quadrotor_goal ) )
353  {
354  goalpos = level.ai_quadrotor_goal;
355  }
356 
357  adjustedGoal = self GetClosestPointOnNavVolume( goalpos, searchRadius );
358  if ( isdefined( adjustedGoal ) )
359  {
360  goalpos = adjustedGoal;
361  }
362 
363  self.goalpos = goalpos;
364 
365  self thread ‪quadrotor_blink_lights();
366  if( self SetVehGoalPos( goalpos, true, 2 ) )
367  {
368  goalfailures = 0;
369 
370  if( isdefined( self.goal_node ) )
371  self.goal_node.quadrotor_claimed = true;
372 
373  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
374  {
375  if( RandomInt( 100 ) > 50 )
376  {
377  self SetLookAtEnt( self.enemy );
378  }
379  }
380 
381  self ‪util::waittill_any_timeout( 12, "near_goal", "force_goal", "reached_end_node" );
382 
383  if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
384  {
385  self SetLookAtEnt( self.enemy );
386  wait RandomFloatRange( 3, 6 );
387  self ClearLookAtEnt();
388  }
389 
390  if( isdefined( self.goal_node ) )
391  self.goal_node.quadrotor_claimed = undefined;
392  }
393  else
394  {
395  goalfailures++;
396 
397  if( isdefined( self.goal_node ) )
398  {
399  self.goal_node.quadrotor_fails = true;
400  }
401 
402  if( goalfailures == 1 )
403  {
404  wait 0.5;
405  continue; // try again
406  }
407  else if( goalfailures == 2 )
408  {
409  // just go up and down, then try to find another goal
410  goalpos = self.origin;
411  }
412  else if( goalfailures == 3 )
413  {
414  // try to fix our position and go up and down
415  goalpos = self.origin;
416  self SetVehGoalPos( goalpos, true );
417  self waittill( "near_goal" );
418  }
419  else if( goalfailures > 3 )
420  {
421  /#
422  println( "WARNING: Quadrotor can't find path to goal over 4 times." + self.origin + " " + goalpos );
423  line( self.origin, goalpos, (1,1,1), 1, 100 );
424  #/
425  // assign a new goal position because the one we have is probably bad
426  self.goalpos = ‪make_sure_goal_is_well_above_ground( goalpos );
427  }
428 
429  old_goalpos = goalpos;
430 
431  offset = ( RandomFloatRange(-50,50), RandomFloatRange(-50,50), RandomFloatRange(50, 150) );
432 
433  goalpos = goalpos + offset;
434 
435  goalpos = ‪quadrotor_adjust_goal_for_enemy_height( goalpos );
436 
437  if( self ‪quadrotor_check_move( goalpos ) )
438  {
439  self SetVehGoalPos( goalpos, true );
440  self ‪util::waittill_any( "near_goal", "force_goal", "start_vehiclepath" );
441 
442  wait RandomFloatRange( 1, 3 );
443 
444  if( !self.vehonpath )
445  {
446  self SetVehGoalPos( old_goalpos, true );
447  self ‪util::waittill_any( "near_goal", "force_goal", "start_vehiclepath" );
448  }
449  }
450  wait 0.5;
451  }
452  }
453 }
454 
456 {
457  nodes = GetNodesInRadiusSorted( self.origin, 200, 0, 500, "Path" );
458 
459  if( nodes.size == 0 )
460  {
461  nodes = GetNodesInRadiusSorted( self.goalpos, 3000, 0, 2000, "Path" );
462  }
463 
464  foreach( node in nodes )
465  {
466  if( node.type == "BAD NODE" )
467  {
468  continue;
469  }
470 
471  return ‪make_sure_goal_is_well_above_ground( node.origin );
472  }
473 
474  return self.origin;
475 }
476 
478 {
479  position = undefined;
480 
481  while ( !isdefined( position ) )
482  {
483  wait( 1 );
484  position = self GetRandomPointOnNavVolume();
485  }
486 
487  goalpos = self.origin;// TODO need new way of find new position
488 
489  return goalpos;
490 }
491 
493 {
494  self.origin = self ‪quadrotor_get_closest_node();
495 }
496 
498 {
499  self waittill( "exit_vehicle", player );
500 
501  player.ignoreme = false;
502  player DisableInvulnerability();
503  //TODO T7 - function port if needed
504  //player SetClientDvar( "cg_fov", 65 );
505 
506  self ShowPart( "tag_turret" );
507  self ShowPart( "body_animate_jnt" );
508  self ShowPart( "tag_flaps" );
509  self ShowPart( "tag_ammo_case" );
510  self HidePart( "tag_viewmodel" );
511  self SetHeliHeightLock( false );
512  self EnableAimAssist();
513  self SetVehicleType( self.original_vehicle_type );
514  self.attachedpath = undefined;
516  self.goalpos = self.origin;
517 }
518 
520 {
521  // do nothing state
522  driver = self GetSeatOccupant( 0 );
523  if( isdefined(driver) )
524  {
525  self DisableAimAssist();
526  self HidePart( "tag_turret" );
527  self HidePart( "body_animate_jnt" );
528  self HidePart( "tag_flaps" );
529  self HidePart( "tag_ammo_case" );
530  self ShowPart( "tag_viewmodel" );
531  self SetHeliHeightLock( true );
532  self thread ‪vehicle_death::vehicle_damage_filter( "firestorm_turret" );
533  self thread ‪quadrotor_set_team( driver.team );
534  driver.ignoreme = true;
535  driver EnableInvulnerability();
536  //TODO T7 - function port if needed
537  //driver SetClientDvar( "cg_fov", 90 );
538  self SetVehicleType( "heli_quadrotor_rts_player" );
539 
540  if( isdefined( self.vehicle_weapon_override ) )
541  {
542  self SetVehWeapon( self.vehicle_weapon_override );
543  }
544 
545  self thread ‪quadrotor_exit_vehicle();
546  //self thread quadrotor_update_rumble();
547  self thread ‪quadrotor_collision_player();
548  //self thread quadrotor_self_destruct();
549  }
550 
551  if( isdefined( self.goal_node ) && isdefined( self.goal_node.quadrotor_claimed ) )
552  {
553  self.goal_node.quadrotor_claimed = undefined;
554  }
555 
556  self ClearTargetEntity();
557  self CancelAIMove();
558  self ClearVehGoalPos();
559  self PathVariableOffsetClear();
560  self PathFixedOffsetClear();
561  self ClearLookAtEnt();
562 }
563 
564 function ‪quadrotor_get_damage_effect( health_pct )
565 {
566  if( health_pct < .25 )
567  {
568  return level._effect[ "quadrotor_damage04" ];
569  }
570  else if( health_pct < .5 )
571  {
572  return level._effect[ "quadrotor_damage03" ];
573  }
574  else if( health_pct < .75 )
575  {
576  return level._effect[ "quadrotor_damage02" ];
577  }
578  else if( health_pct < 0.9 )
579  {
580  return level._effect[ "quadrotor_damage01" ];
581  }
582 
583  return undefined;
584 }
585 
586 function ‪quadrotor_play_single_fx_on_tag( effect, tag )
587 {
588  if( isdefined( self.damage_fx_ent ) )
589  {
590  if( self.damage_fx_ent.effect == effect )
591  {
592  // already playing
593  return;
594  }
595  self.damage_fx_ent delete();
596  }
597 
598 
599  ent = ‪Spawn( "script_model", ( 0, 0, 0 ) );
600  ent SetModel( "tag_origin" );
601  ent.origin = self GetTagOrigin( tag );
602  ent.angles = self GetTagAngles( tag );
603  ent NotSolid();
604  ent Hide();
605  ent LinkTo( self, tag );
606  ent.effect = effect;
607  playfxontag( effect, ent, "tag_origin" );
608  ent playsound("veh_qrdrone_sparks");
609 
610 
611  self.damage_fx_ent = ent;
612 }
613 
615 {
616  max_health = self.healthdefault;
617  if( isdefined( self.health_max ) )
618  {
619  max_health = self.health_max;
620  }
621 
622  effect = ‪quadrotor_get_damage_effect( self.health / max_health );
623  if( isdefined( effect ) )
624  {
625  ‪quadrotor_play_single_fx_on_tag( effect, "tag_origin" );
626  }
627  else
628  {
629  if( isdefined( self.damage_fx_ent ) )
630  {
631  self.damage_fx_ent delete();
632  }
633  }
634 }
635 
637 {
638  self endon( "crash_done" );
639 
640  while( isdefined(self) )
641  {
642  self waittill( "damage", ‪damage, undefined /*attacker*/, dir, point, type );
643 
644  if( self.health > 0 && ‪damage > 1 ) // emp does one damage and we don't want to look like it damaged us
645  {
647  }
648 
649  if( isdefined( self.off ) )
650  {
651  continue;
652  }
653 
654  if( type == "MOD_EXPLOSIVE" || type == "MOD_GRENADE_SPLASH" || type == "MOD_PROJECTILE_SPLASH" )
655  {
656  self SetVehVelocity( self.velocity + VectorNormalize(dir) * 300 );
657  ang_vel = self GetAngularVelocity();
658  ang_vel += ( RandomFloatRange( -300, 300 ), RandomFloatRange( -300, 300 ), RandomFloatRange( -300, 300 ) );
659  self SetAngularVelocity( ang_vel );
660  }
661  else
662  {
663  ang_vel = self GetAngularVelocity();
664  yaw_vel = RandomFloatRange( -320, 320 );
665 
666  if( yaw_vel < 0 )
667  yaw_vel -= 150;
668  else
669  yaw_vel += 150;
670 
671  ang_vel += ( RandomFloatRange( -150, 150 ), yaw_vel, RandomFloatRange( -150, 150 ) );
672  self SetAngularVelocity( ang_vel );
673  }
674 
675  wait 0.3;
676  }
677 }
678 
680 {
681  if( isdefined( self.damage_fx_ent ) )
682  {
683  self.damage_fx_ent delete();
684  }
685 
686  if( isdefined( self.stun_fx ) )
687  {
688  self.stun_fx delete();
689  }
690 }
691 
693 {
694  wait 0.1;
695 
696  self notify( "nodeath_thread" ); // Kill off the vehicle_death::main thread
697 
698  self waittill( "death", attacker, damageFromUnderneath, weapon, point, dir );
699 
700  self notify( "nodeath_thread" ); // Kill off the vehicle_death::main thread, just making sure
701 
702  if( isdefined( self.goal_node ) && isdefined( self.goal_node.quadrotor_claimed ) )
703  {
704  self.goal_node.quadrotor_claimed = undefined;
705  }
706 
707  if( isdefined( self.‪delete_on_death ) )
708  {
709  if ( isdefined( self ) )
710  {
712  self delete();
713  }
714 
715  return;
716  }
717 
718  if ( !isdefined( self ) )
719  {
720  return;
721  }
722 
723  self endon( "death" ); //quit thread if deleted
724 
726 
727  self DisableAimAssist();
728 
729  self ‪death_fx();
731  self thread ‪vehicle_death::set_death_model( self.deathmodel, self.modelswapdelay );
732 
733  self ‪vehicle::toggle_tread_fx( false );
734  self ‪vehicle::toggle_exhaust_fx( false );
735  self ‪vehicle::toggle_sounds( false );
736  self ‪vehicle::lights_off();
737  self thread ‪quadrotor_crash_movement( attacker, dir );
738 
740 
741  self waittill( "crash_done" );
742 
743  // A dynEnt will be spawned in the collision thread when it hits the ground and "crash_done" notify will be sent
744  //self freeVehicle();
745  //self Hide(); // Hide our self so the particle effect doesn't blink out
746  //wait 5;
747  self delete();
748 }
749 
750 function ‪death_fx()
751 {
753  self playsound("veh_qrdrone_sparks");
754 }
755 
756 function ‪quadrotor_crash_movement( attacker, hitdir )
757 {
758  self endon( "crash_done" );
759  self endon( "death" );
760 
761  self CancelAIMove();
762  self ClearVehGoalPos();
763  self ClearLookAtEnt();
764 
765  self SetPhysAcceleration( ( 0, 0, -800 ) );
766  self.vehcheckforpredictedcrash = true; // code field to get veh_predictedcollision notify
767 
768  if( !isdefined( hitdir ) )
769  {
770  hitdir = (1,0,0);
771  }
772 
773  side_dir = VectorCross( hitdir, (0,0,1) );
774  side_dir_mag = RandomFloatRange( -100, 100 );
775  side_dir_mag += ‪math::sign( side_dir_mag ) * 80;
776  side_dir *= side_dir_mag;
777 
778  self SetVehVelocity( self.velocity + (0,0,100) + VectorNormalize( side_dir ) );
779 
780  ang_vel = self GetAngularVelocity();
781  ang_vel = ( ang_vel[0] * 0.3, ang_vel[1], ang_vel[2] * 0.3 );
782 
783  yaw_vel = RandomFloatRange( 0, 210 ) * ‪math::sign( ang_vel[1] );
784  yaw_vel += ‪math::sign( yaw_vel ) * 180;
785 
786  ang_vel += ( RandomFloatRange( -1, 1 ), yaw_vel, RandomFloatRange( -1, 1 ) );
787 
788  self SetAngularVelocity( ang_vel );
789 
790  self.crash_accel = RandomFloatRange( 75, 110 );
791 
792  if( !isdefined( self.off ) )
793  {
794  self thread ‪quadrotor_crash_accel();
795  }
796  self thread ‪quadrotor_collision();
797 
798  //drone death sounds JM - play 1 shot hit, turn off main loop, thread dmg loop
799  self playsound("veh_qrdrone_dmg_hit");
800  self ‪vehicle::toggle_sounds( 0 );
801 
802  if( !isdefined( self.off ) )
803  {
804  self thread ‪qrotor_dmg_snd();
805  }
806 
807  wait 0.1;
808 
809  if( RandomInt( 100 ) < 40 && !isdefined( self.off ) )
810  {
811  self thread ‪quadrotor_fire_for_time( RandomFloatRange( 0.7, 2.0 ) );
812  }
813 
814  wait 15;
815 
816  // failsafe notify
817  self notify( "crash_done" );
818 }
819 
820 
822 {
823  dmg_ent = ‪Spawn("script_origin", self.origin);
824  dmg_ent linkto (self);
825  dmg_ent PlayLoopSound ("veh_qrdrone_dmg_loop");
826  self ‪util::waittill_any("crash_done", "death");
827  dmg_ent stoploopsound(1);
828  wait (2);
829  dmg_ent delete();
830 }
831 
832 
833 function ‪quadrotor_fire_for_time( totalFireTime )
834 {
835  self endon( "crash_done" );
836  self endon( "change_state" );
837  self endon( "death" );
838 
839  if( isdefined( self.‪emped ) )
840  return;
841 
842  weapon = self SeatGetWeapon( 0 );
843  fireTime = weapon.fireTime;
844  time = 0;
845  aiFireChance = 1;
846 
847  if( weapon.name == "quadrotor_turret_explosive" )
848  {
849  if( totalFireTime < fireTime * 2 )
850  totalFireTime = fireTime * 2;
851 
852  // 1 in 2 bullets will be real
853  aiFireChance = 1;
854  }
855  else
856  {
857  // fire less, unlees shooting player or a bigdog or mentioned specifically from level script
858  if( ( isdefined( self.enemy ) && !IsPlayer( self.enemy ) && !‪IS_TRUE( self.enemy.isBigDog ) ) ||
859  isdefined( self.fire_half_blanks ) )
860  {
861  // 1 in 2 bullets will be real
862  aiFireChance = 2;
863  }
864  }
865 
866  fireCount = 1;
867 
868  while( time < totalFireTime && !isdefined( self.‪emped ) )
869  {
870  if( isdefined( self.enemy ) && isdefined(self.enemy.attackerAccuracy) && self.enemy.attackerAccuracy == 0 )
871  {
872  self FireWeapon( 0, self.enemy );
873  }
874  else if( aiFireChance > 1 )
875  {
876  self FireWeapon();
877  }
878  else
879  {
880  self FireWeapon();
881  }
882 
883  fireCount++;
884  wait fireTime;
885  time += fireTime;
886  }
887 }
888 
890 {
891  self endon( "crash_done" );
892  self endon( "death" );
893 
894  count = 0;
895 
896  while( 1 )
897  {
898  self SetVehVelocity( self.velocity + AnglesToUp( self.angles ) * self.crash_accel );
899  self.crash_accel *= 0.98;
900 
901  wait 0.1;
902 
903  count++;
904  if( count % 8 == 0 )
905  {
906  if( RandomInt( 100 ) > 40 )
907  {
908  if( self.velocity[2] > 150.0 )
909  {
910  self.crash_accel *= 0.75;
911  }
912  else if( self.velocity[2] < 40.0 && count < 60 )
913  {
914  if( Abs( self.angles[0] ) > 30 || Abs( self.angles[2] ) > 30 )
915  {
916  self.crash_accel = RandomFloatRange( 160, 200 );
917  }
918  else
919  {
920  self.crash_accel = RandomFloatRange( 85, 120 );
921  }
922  }
923  }
924  }
925  }
926 }
927 
929 {
930  self endon( "crash_done" );
931  self endon( "death" );
932 
933  while( 1 )
934  {
935  self waittill( "veh_predictedcollision", velocity, normal );
936  if( normal[2] >= 0.6 )
937  {
938  self notify( "veh_collision", velocity, normal );
939  }
940  }
941 }
942 
944 {
945  self endon( "change_state" );
946  self endon( "crash_done" );
947  self endon( "death" );
948 
949  while( 1 )
950  {
951  self waittill( "veh_collision", velocity, normal );
952  driver = self GetSeatOccupant( 0 );
953  if( isdefined( driver ) && LengthSquared( velocity ) > 70*70 )
954  {
955  Earthquake( 0.25, 0.25, driver.origin, 50 );
956  driver PlayRumbleOnEntity( "damage_heavy" );
957  }
958  }
959 }
960 
962 {
963  self endon( "change_state" );
964  self endon( "crash_done" );
965  self endon( "death" );
966 
967  if( !IsAlive( self ) )
968  {
969  self thread ‪quadrotor_predicted_collision();
970  }
971 
972  while( 1 )
973  {
974  self waittill( "veh_collision", velocity, normal );
975  ang_vel = self GetAngularVelocity() * 0.5;
976  self SetAngularVelocity( ang_vel );
977 
978  // bounce off walls
979  if( normal[2] < 0.6 || ( IsAlive( self ) && !isdefined( self.‪emped ) ) )
980  {
981  self SetVehVelocity( self.velocity + normal * 90 );
982  self PlaySound( "veh_wasp_wall_imp" );
983  if( normal[2] < 0.6 )
984  {
985  fx_origin = self.origin - normal * 28;
986  }
987  else
988  {
989  fx_origin = self.origin - normal * 10;
990  }
991  PlayFX( level._effect[ "quadrotor_nudge" ], fx_origin, normal );
992  }
993  else
994  {
995 
996  if( isdefined( self.‪emped ) )
997  {
998  if( isdefined( self.bounced ) )
999  {
1000  self playsound( "veh_wasp_wall_imp" );
1001  self SetVehVelocity( (0,0,0) );
1002  self SetAngularVelocity( (0,0,0) );
1003  if( self.angles[0] < 0 )
1004  {
1005  if( self.angles[0] < -15 )
1006  {
1007  self.angles = ( -15, self.angles[1], self.angles[2] );
1008  }
1009  else if( self.angles[0] > -10 )
1010  {
1011  self.angles = ( -10, self.angles[1], self.angles[2] );
1012  }
1013  }
1014  else
1015  {
1016  if( self.angles[0] > 15 )
1017  {
1018  self.angles = ( 15, self.angles[1], self.angles[2] );
1019  }
1020  else if( self.angles[0] < 10 )
1021  {
1022  self.angles = ( 10, self.angles[1], self.angles[2] );
1023  }
1024  }
1025 
1026  self.bounced = undefined;
1027  self notify( "landed" );
1028  return;
1029  }
1030  else
1031  {
1032  self.bounced = true;
1033  self SetVehVelocity( self.velocity + normal * 120 );
1034  self playsound( "veh_wasp_wall_imp" );
1035  if( normal[2] < 0.6 )
1036  {
1037  fx_origin = self.origin - normal * 28;
1038  }
1039  else
1040  {
1041  fx_origin = self.origin - normal * 10;
1042  }
1043  PlayFX( level._effect[ "quadrotor_nudge" ], fx_origin, normal );
1044  }
1045  }
1046  else
1047  {
1048  CreateDynEntAndLaunch( self.deathmodel, self.origin, self.angles, self.origin, self.velocity * 0.01, level._effect[ "quadrotor_crash" ] );
1049  self playsound( "veh_qrdrone_explo" );
1050  self thread ‪death_fire_loop_audio();
1051  self notify( "crash_done" );
1052  }
1053  }
1054  }
1055 }
1056 
1058 {
1059  sound_ent = ‪Spawn( "script_origin", self.origin );
1060  sound_ent PlayLoopSound( "veh_qrdrone_death_fire_loop" , .1 );
1061  wait 11;
1062  sound_ent StopLoopSound( 1 );
1063  sound_ent delete();
1064 }
1065 
1066 function ‪quadrotor_set_team( team )
1067 {
1068  self.team = team;
1069  if( isdefined( self.vehmodelenemy ) )
1070  {
1071  if( isSubstr( level.script, "so_rts_" ) )
1072  {
1073  }
1074  else
1075  {
1076  if( team == "axis" )
1077  {
1078  self SetModel( self.vehmodelenemy );
1079  self SetVehWeapon( GetWeapon( "quadrotor_turret_enemy" ) );
1080  }
1081  else
1082  {
1083  self SetModel( self.vehmodel );
1084  self SetVehWeapon( GetWeapon( "quadrotor_turret" ) );
1085  }
1086  }
1087  }
1088 
1089  if( !isdefined( self.off ) )
1090  {
1092  }
1093 }
1094 
1096 {
1097  self endon( "death" );
1098 
1099  self ‪vehicle::lights_off();
1100  wait 0.1;
1101  self ‪vehicle::lights_on();
1102 }
1103 
1104 // Lots of gross hardcoded values! :(
1106 {
1107  self endon( "death" );
1108  self endon( "exit_vehicle" );
1109 
1110  while ( 1 )
1111  {
1112  vr = Abs( self GetSpeed() / self GetMaxSpeed() );
1113 
1114  if ( vr < 0.1 )
1115  {
1116  level.player PlayRumbleOnEntity( "quadrotor_fly" );
1117  wait( 0.35 );
1118  }
1119  else
1120  {
1121  time = RandomFloatRange( 0.1, 0.2 );
1122  Earthquake( RandomFloatRange( 0.1, 0.15 ), time, self.origin, 200 );
1123  level.player PlayRumbleOnEntity( "quadrotor_fly" );
1124  wait( time );
1125  }
1126  }
1127 }
1128 
1130 {
1131  self endon( "death" );
1132  self endon( "exit_vehicle" );
1133 
1134  const max_self_destruct_time = 5;
1135 
1136  self_destruct = false;
1137  self_destruct_time = 0;
1138 
1139  while ( 1 )
1140  {
1141  if ( !self_destruct )
1142  {
1143  if ( level.player MeleeButtonPressed() )
1144  {
1145  self_destruct = true;
1146  self_destruct_time = max_self_destruct_time;
1147  }
1148 
1150  continue;
1151  }
1152  else
1153  {
1154  IPrintLnBold( self_destruct_time );
1155 
1156  wait( 1 );
1157 
1158  self_destruct_time -= 1;
1159  if ( self_destruct_time == 0 )
1160  {
1161  driver = self GetSeatOccupant( 0 );
1162  if( isdefined(driver) )
1163  {
1164  driver DisableInvulnerability();
1165  }
1166 
1167  Earthquake( 3, 1, self.origin, 256 );
1168  RadiusDamage( self.origin, 1000, 15000, 15000, level.player, "MOD_EXPLOSIVE" );
1169  self DoDamage( self.health + 1000, self.origin );
1170  }
1171 
1172  continue;
1173  }
1174  }
1175 }
1176 
1178 {
1179  self endon( "death" );
1180  self endon( "emped" );
1181  self endon( "landed" );
1182 
1183  while( isdefined( self.‪emped ) )
1184  {
1185  velocity = self.velocity; // setting the angles clears the velocity so we save it off and set it back
1186  self.angles = ( self.angles[0] * 0.85, self.angles[1], self.angles[2] * 0.85 );
1187  ang_vel = self GetAngularVelocity() * 0.85;
1188  self SetAngularVelocity( ang_vel );
1189  self SetVehVelocity( velocity );
1191  }
1192 }
1193 
1195 {
1196  self endon( "death" );
1197  self notify( "emped" );
1198  self endon( "emped" );
1199 
1200  self.emped = true;
1201 
1202  PlaySoundAtPosition( "veh_qrdrone_emp_down", self.origin );
1203  self ‪quadrotor_off();
1204 
1205  self SetPhysAcceleration( ( 0, 0, -600 ) );
1206  self thread ‪quadrotor_level_out_for_landing();
1207  self thread ‪quadrotor_collision();
1208 
1209  if( !isdefined( self.stun_fx ) )
1210  {
1211  self.stun_fx = ‪Spawn( "script_model", self.origin );
1212  self.stun_fx SetModel( "tag_origin" );
1213  self.stun_fx LinkTo( self, "tag_origin", (0,0,0), (0,0,0) );
1214  PlayFXOnTag( level._effect[ "quadrotor_stun" ], self.stun_fx, "tag_origin" );
1215  }
1216 
1217  wait RandomFloatRange( 4, 7 );
1218 
1219  self.stun_fx delete();
1220 
1221  self.emped = undefined;
1222  self SetPhysAcceleration( ( 0, 0, 0 ) );
1223  self ‪quadrotor_on();
1224  self playsound ("veh_qrdrone_boot_qr");
1225 }
1226 
1227 function ‪quadrotor_temp_bullet_shield( invulnerable_time )
1228 {
1229  self notify( "bullet_shield" );
1230  self endon( "bullet_shield" );
1231 
1232  self.bullet_shield = true;
1233 
1234  wait invulnerable_time;
1235 
1236  if( isdefined( self ) )
1237  {
1238  self.bullet_shield = undefined;
1239  wait 3;
1240  if( isdefined( self ) && self.health < 40 )
1241  {
1242  self.health = 40;
1243  }
1244  }
1245 }
1246 
1247 function ‪QuadrotorCallback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName )
1248 {
1249  driver = self GetSeatOccupant( 0 );
1250 
1251  if( weapon.isEmp && sMeansOfDeath != "MOD_IMPACT" )
1252  {
1253  if( !isdefined( driver ) )
1254  {
1255  if( !isdefined( self.off ) )
1256  {
1257  self thread ‪quadrotor_emped();
1258  }
1259  }
1260  }
1261 
1262 
1263  if( isdefined( driver ) )
1264  {
1265  if( sMeansOfDeath == "MOD_BULLET" )
1266  {
1267  if( isdefined( self.bullet_shield ) )
1268  {
1269  iDamage = 3;
1270  }
1271  }
1272 
1273  if( !isdefined( self.bullet_shield ) )
1274  {
1275  // Try not to let the play die suddenly
1276  self thread ‪quadrotor_temp_bullet_shield( 0.35 );
1277  }
1278 
1279  // Lets get some hit indicators
1280  //driver FinishPlayerDamage( eInflictor, eAttacker, 1, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, "none", 0, psOffsetTime );
1281  }
1282 
1283  return iDamage;
1284 }
‪waittill_pathing_done
‪function waittill_pathing_done()
Definition: _quadrotor.gsc:276
‪quadrotor_crash_accel
‪function quadrotor_crash_accel()
Definition: _quadrotor.gsc:889
‪set_death_model
‪function set_death_model(sModel, fDelay)
Definition: vehicle_death_shared.gsc:258
‪script_delay
‪function script_delay()
Definition: util_shared.gsc:970
‪add_interrupt_connection
‪function add_interrupt_connection(from_state_name, to_state_name, on_notify, checkfunc)
Definition: statemachine_shared.gsc:90
‪quadrotor_crash_movement
‪function quadrotor_crash_movement(attacker, hitdir)
Definition: _quadrotor.gsc:756
‪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
‪set_state
‪function set_state(name, state_params)
Definition: statemachine_shared.gsc:133
‪quadrotor_update_damage_fx
‪function quadrotor_update_damage_fx()
Definition: _quadrotor.gsc:614
‪quadrotor_off
‪function quadrotor_off()
Definition: _quadrotor.gsc:139
‪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
‪death_fx
‪function death_fx()
Definition: _quadrotor.gsc:750
‪quadrotor_movementupdate
‪function quadrotor_movementupdate()
Definition: _quadrotor.gsc:297
‪toggle_tread_fx
‪function toggle_tread_fx(on)
Definition: vehicle_shared.gsc:3357
‪clear
‪function clear(str_flag)
Definition: flag_shared.csc:130
‪sign
‪function sign(x)
Definition: math_shared.csc:164
‪quadrotor_adjust_goal_for_enemy_height
‪function quadrotor_adjust_goal_for_enemy_height(goalpos)
Definition: _quadrotor.gsc:233
‪quadrotor_emped
‪function quadrotor_emped()
Definition: _quadrotor.gsc:1194
‪quadrotor_update_rumble
‪function quadrotor_update_rumble()
Definition: _quadrotor.gsc:1105
‪quadrotor_level_out_for_landing
‪function quadrotor_level_out_for_landing()
Definition: _quadrotor.gsc:1177
‪can_enter_main
‪function can_enter_main()
Definition: _quadrotor.gsc:122
‪toggle_exhaust_fx
‪function toggle_exhaust_fx(on)
Definition: vehicle_shared.gsc:3335
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪quadrotor_main
‪function quadrotor_main()
Definition: _quadrotor.gsc:176
‪death_cleanup_level_variables
‪function death_cleanup_level_variables()
Definition: vehicle_death_shared.gsc:1144
‪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
‪quadrotor_on
‪function quadrotor_on()
Definition: _quadrotor.gsc:156
‪quadrotor_find_new_position
‪function quadrotor_find_new_position()
Definition: _quadrotor.gsc:477
‪goal_flag_monitor
‪function goal_flag_monitor()
Definition: _quadrotor.gsc:287
‪quadrotor_check_move
‪function quadrotor_check_move(position)
Definition: _quadrotor.gsc:221
‪__init__
‪function __init__()
Definition: _quadrotor.gsc:30
‪death_radius_damage
‪function death_radius_damage(meansOfDamage="MOD_EXPLOSIVE")
Definition: vehicle_death_shared.gsc:1196
‪quadrotor_fireupdate
‪function quadrotor_fireupdate()
Definition: _quadrotor.gsc:184
‪quadrotor_exit_vehicle
‪function quadrotor_exit_vehicle()
Definition: _quadrotor.gsc:497
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪quadrotor_temp_bullet_shield
‪function quadrotor_temp_bullet_shield(invulnerable_time)
Definition: _quadrotor.gsc:1227
‪quadrotor_cleanup_fx
‪function quadrotor_cleanup_fx()
Definition: _quadrotor.gsc:679
‪quadrotor_set_team
‪function quadrotor_set_team(team)
Definition: _quadrotor.gsc:1066
‪quadrotor_collision_player
‪function quadrotor_collision_player()
Definition: _quadrotor.gsc:943
‪quadrotor_think
‪function quadrotor_think()
Definition: _quadrotor.gsc:49
‪make_sure_goal_is_well_above_ground
‪function make_sure_goal_is_well_above_ground(pos)
Definition: _quadrotor.gsc:261
‪quadrotor_blink_lights
‪function quadrotor_blink_lights()
Definition: _quadrotor.gsc:1095
‪end
‪function end(final)
Definition: _killcam.gsc:511
‪QuadrotorCallback_VehicleDamage
‪function QuadrotorCallback_VehicleDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, psOffsetTime, damageFromUnderneath, modelIndex, partName)
Definition: _quadrotor.gsc:1247
‪quadrotor_play_single_fx_on_tag
‪function quadrotor_play_single_fx_on_tag(effect, tag)
Definition: _quadrotor.gsc:586
‪quadrotor_teleport_to_nearest_node
‪function quadrotor_teleport_to_nearest_node()
Definition: _quadrotor.gsc:492
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪create
‪function create(name, origin, team, shader, alpha, scale)
Definition: objpoints_shared.gsc:32
‪quadrotor_damage
‪function quadrotor_damage()
Definition: _quadrotor.gsc:636
‪wait_till
‪function wait_till(str_flag)
Definition: flag_shared.csc:189
‪quadrotor_scripted
‪function quadrotor_scripted()
Definition: _quadrotor.gsc:519
‪quadrotor_get_closest_node
‪function quadrotor_get_closest_node()
Definition: _quadrotor.gsc:455
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪quadrotor_start_ai
‪function quadrotor_start_ai()
Definition: _quadrotor.gsc:170
‪quadrotor_fire_for_time
‪function quadrotor_fire_for_time(totalFireTime)
Definition: _quadrotor.gsc:833
‪emped
‪function emped(down_time)
Definition: _siegebot.gsc:1359
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪qrotor_dmg_snd
‪function qrotor_dmg_snd()
Definition: _quadrotor.gsc:821
‪init
‪function init()
Definition: struct.csc:1
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪main
‪function main()
Definition: _global_fx.csc:17
‪quadrotor_self_destruct
‪function quadrotor_self_destruct()
Definition: _quadrotor.gsc:1129
‪exists
‪function exists(str_flag)
Definition: flag_shared.csc:43
‪death_fire_loop_audio
‪function death_fire_loop_audio()
Definition: _quadrotor.gsc:1057
‪quadrotor_start_scripted
‪function quadrotor_start_scripted()
Definition: _quadrotor.gsc:134
‪quadrotor_get_damage_effect
‪function quadrotor_get_damage_effect(health_pct)
Definition: _quadrotor.gsc:564
‪do_death_fx
‪function do_death_fx()
Definition: vehicle_shared.gsc:2855
‪toggle_sounds
‪function toggle_sounds(on)
Definition: vehicle_shared.gsc:3379
‪quadrotor_collision
‪function quadrotor_collision()
Definition: _quadrotor.gsc:961
‪delete_on_death
‪function delete_on_death(ent)
Definition: util_shared.gsc:1796
‪lights_on
‪function lights_on(localClientNum, team)
Definition: vehicle_shared.csc:404
‪quadrotor_predicted_collision
‪function quadrotor_predicted_collision()
Definition: _quadrotor.gsc:928
‪quadrotor_death
‪function quadrotor_death()
Definition: _quadrotor.gsc:692
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265