‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
vehicle_death_shared.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\flag_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\sound_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 
11 #insert scripts\shared\shared.gsh;
12 
13 #define ANIMTREE "generic"
14 
15 #namespace vehicle_death;
16 
17 ‪REGISTER_SYSTEM( "vehicle_death", &‪__init__, undefined )
18 
19 // _vehicle_death.gsc - all things related to vehicles dying
20 
21 // Utility rain functions:
22 
23 
24 #using_animtree( ANIMTREE );
25 
26 function ‪__init__()
27 {
28 }
29 
30 function ‪main()
31 {
32  self endon( "nodeath_thread" );
33 
34  while ( isdefined( self ) )
35  {
36  // waittill death twice. in some cases the vehicle dies and does a bunch of stuff. then it gets deleted. which it then needs to do more stuff
37  self waittill( "death", attacker, damageFromUnderneath, weapon, point, dir );
38 
39  if( isdefined( self.death_enter_cb ) )
40  [[self.death_enter_cb]]();
41 
42  if ( isdefined( self.script_deathflag ) )
43  {
44  level ‪flag::set( self.script_deathflag );
45  }
46 
47  if ( !isdefined( self.‪delete_on_death ) )
48  {
49  self thread ‪play_death_audio();
50  }
51 
52  if ( !isdefined( self ) )
53  {
54  return;
55  }
56 
58 
59  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
60  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
61 
62  if ( ‪vehicle::is_corpse( self ) )
63  {
64  // Cleanup Riders
65  if ( !‪IS_TRUE( self.dont_kill_riders ) )
66  {
68  }
69 
70  // kills some destructible fxs
71  self notify( "delete_destructible" );
72 
73  // Done here
74  return;
75  }
76 
78 
79  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
80  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
81 
82  // Run vehicle death thread
83  if ( isdefined( level.vehicle_death_thread[ self.vehicletype ] ) )
84  {
85  thread [[ level.vehicle_death_thread[ self.vehicletype ] ]]();
86  }
87 
88  if ( !isdefined( self.‪delete_on_death ) )
89  {
90  // Do radius damage
91  thread ‪death_radius_damage();
92  }
93 
94  is_aircraft = ( ‪IS_PLANE( self ) || ‪IS_HELICOPTER( self ) );
95 
96  if ( !isdefined( self.destructibledef ) )
97  {
98  if ( !is_aircraft && !( self.vehicleType == "horse" || self.vehicleType == "horse_player" || self.vehicleType == "horse_player_low" || self.vehicleType == "horse_low" || self.vehicleType == "horse_axis" ) && isdefined( self.deathmodel ) && self.deathmodel != "" )
99  {
100  self thread ‪set_death_model( self.deathmodel, self.modelswapdelay );
101  }
102 
103  // Do death_fx if it has not been mantled
104  if ( !isdefined( self.‪delete_on_death ) && ( !isdefined( self.mantled ) || !self.mantled ) && !isdefined( self.nodeathfx ) )
105  {
106  thread ‪death_fx();
107  }
108 
109  if ( isdefined( self.‪delete_on_death ) )
110  {
112 
113  if ( self.disconnectPathOnStop === true )
114  {
116  }
117 
118  if ( !‪IS_TRUE( self.no_free_on_death ) )
119  {
120  self freevehicle();
121  self.isacorpse = true;
122 
124 
125  if ( isdefined( self ) )
126  {
127  self notify( "death_finished" );
128  self delete();
129  }
130  }
131 
132  continue;
133  }
134  }
135 
136 // // makes riders blow up
137 // if ( isdefined( self.riders ) && self.riders.size > 0 )
138 // {
139 // vehicle_aianim::blowup_riders();
140 // }
141 
142  // Place a bad place cylinder if specified
143  thread ‪death_make_badplace( self.vehicletype );
144 
145  // Send vehicle type specific notify
146  if ( isdefined( level.vehicle_deathnotify ) && isdefined( level.vehicle_deathnotify[ self.vehicletype ] ) )
147  {
148  level notify( level.vehicle_deathnotify[ self.vehicletype ], attacker );
149  }
150 
151  if ( Target_IsTarget( self ) )
152  {
153  Target_Remove( self );
154  }
155 
156  // all the vehicles get the same jolt..
157  if ( self.classname == "script_vehicle" )
158  {
159  self thread ‪death_jolt( self.vehicletype );
160  }
161 
162  if ( ‪do_scripted_crash() )
163  {
164  // Check for scripted crash
165  self thread ‪death_update_crash( point, dir );
166  }
167 
168  // Clear turret target
169  if ( isdefined( self.turretweapon ) && self.turretweapon != level.weaponNone)
170  {
171  self clearTurretTarget();
172  }
173 
174  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
175  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
176 
177  // Wait here until we're finished with a crash or rolling death
179 
180  if ( isdefined( self ) )
181  {
182  while ( isdefined( self ) && isdefined( self.dontfreeme ) )
183  {
184  wait( .05 );
185  }
186 
187  // send notifies
188  self notify( "stop_looping_death_fx" );
189  self notify( "death_finished" );
190 
191  wait .05;
192 
193  if ( isdefined( self ) )
194  {
195  if ( ‪vehicle::is_corpse( self ) )
196  {
197  continue;
198  }
199 
200  if ( !isdefined( self ) )
201  {
202  continue;
203  }
204 
205  // AE 2-18-09: if the player is using it, then spit them out or kill them before freeing the vehicle
206  occupants = self GetVehOccupants();
207  if ( isdefined( occupants ) && occupants.size )
208  {
209  for ( i = 0; i < occupants.size; i++ )
210  {
211  self usevehicle( occupants[i], 0 );
212  }
213  }
214 
215  if ( !‪IS_TRUE( self.no_free_on_death ) )
216  {
217  self freevehicle();
218  self.isacorpse = true;
219  }
220 
221  if ( self.modeldummyon )
222  {
223  self hide();
224  }
225  }
226  }
227  }
228 }
229 
231 {
232  return !isdefined( self.‪do_scripted_crash ) || ‪IS_TRUE( self.‪do_scripted_crash );
233 }
234 
236 {
237  if ( isdefined ( self ) && ‪IS_HELICOPTER( self ) )
238  {
239  if ( !isdefined ( self.death_counter ) )
240  {
241  self.death_counter = 0;
242  }
243  if ( self.death_counter == 0 )
244  {
245  self.death_counter++;
246  self playsound ( "exp_veh_helicopter_hit" );
247  }
248  }
249 }
250 
252 {
253  self playloopsound( "veh_drone_spin", .05 );
254  level ‪util::waittill_any( "crash_move_done", "death" );
255  self stoploopsound( .02 );
256 }
257 
258 function ‪set_death_model( sModel, fDelay )
259 {
260  if( !isdefined( sModel ) )
261  return;
262 
263 
264  if ( isdefined( fDelay ) && ( fDelay > 0 ) )
265  {
266  wait fDelay;
267  }
268 
269  if ( !isdefined( self ) )
270  {
271  return;
272  }
273 
274  if ( isdefined( self.deathmodel_attached ) )
275  {
276  return;
277  }
278 
279  eModel = vehicle::get_dummy();
280  if ( !isdefined( eModel ) )
281  {
282  return;
283  }
284 
285  if ( !isdefined( eModel.death_anim ) && ( isdefined( eModel.animtree ) ) )
286  {
287  eModel ClearAnim( %root, 0 );
288  }
289 
290  // SetModel can remove the destructible so only do if if we are really trying to swap to a specified death model
291  if( sModel != self.vehmodel )
292  {
293  eModel SetModel( sModel );
294  eModel SetEnemyModel( sModel );
295  }
296 }
297 
298 
299 function ‪aircraft_crash( point, dir )
300 {
301  self.crashing = true;
302 
303  if ( isdefined( self.unloading ) )
304  {
305  while ( isdefined( self.unloading ) )
306  {
308  }
309  }
310 
311  if ( !isdefined( self ) )
312  {
313  return;
314  }
315 
316  self thread ‪aircraft_crash_move( point, dir );
317  self thread ‪play_spinning_plane_sound();
318 }
319 
320 function ‪helicopter_crash( point, dir )
321 {
322  self.crashing = true;
323  self thread ‪play_crashing_loop();
324 
325  if ( isdefined( self.unloading ) )
326  {
327  while ( isdefined( self.unloading ) )
328  {
330  }
331  }
332 
333  if ( !isdefined( self ) )
334  {
335  return;
336  }
337 
338  //self thread helicopter_crash_move( point, dir );
339  self thread ‪helicopter_crash_movement( point, dir );
340 
341 }
342 
343 function ‪helicopter_crash_movement( point, dir )
344 {
345  self endon( "crash_done" );
346 
347  self CancelAIMove();
348  self ClearVehGoalPos();
349 
350  if ( isdefined( level.heli_crash_smoke_trail_fx ) )
351  {
352  if ( IsSubStr( self.vehicletype, "v78" ) )
353  {
354  playfxontag( level.heli_crash_smoke_trail_fx, self, "tag_origin" );
355  }
356  else if ( self.vehicletype == "drone_firescout_axis" || self.vehicletype == "drone_firescout_isi" )
357  {
358  playfxontag( level.heli_crash_smoke_trail_fx, self, "tag_main_rotor" );
359  }
360  else
361  {
362  playfxontag( level.heli_crash_smoke_trail_fx, self, "tag_engine_left" );
363  }
364  }
365 
366  crash_zones = ‪struct::get_array( "heli_crash_zone", "targetname" );
367  if ( crash_zones.size > 0 )
368  {
369  best_dist = 99999;
370  best_idx = -1;
371 
372  if ( isdefined( self.a_crash_zones ) )
373  {
374  crash_zones = self.a_crash_zones;
375  }
376 
377  for ( i = 0; i < crash_zones.size; i++ )
378  {
379  vec_to_crash_zone = crash_zones[i].origin - self.origin;
380  vec_to_crash_zone = ( vec_to_crash_zone[0], vec_to_crash_zone[1], 0 );
381  dist = Length( vec_to_crash_zone );
382  vec_to_crash_zone /= dist;
383 
384  veloctiy_scale = -VectorDot( self.velocity, vec_to_crash_zone );
385  dist += 500 * veloctiy_scale;
386 
387  if ( dist < best_dist )
388  {
389  best_dist = dist;
390  best_idx = i;
391  }
392  }
393 
394  if ( best_idx != -1 )
395  {
396  self.crash_zone = crash_zones[best_idx];
397  self thread ‪helicopter_crash_zone_accel( dir );
398  }
399  }
400  else
401  {
402  if( isdefined( dir ) )
403  dir = VectorNormalize( dir );
404  else
405  dir = ( 1,0,0 );
406  side_dir = VectorCross( dir, ( 0,0,1 ) );
407  side_dir_mag = RandomFloatRange( -500, 500 );
408  side_dir_mag += ‪math::sign( side_dir_mag ) * 60;
409  side_dir *= side_dir_mag;
410  side_dir += ( 0,0,150 );
411 
412  self SetPhysAcceleration( ( RandomIntRange( -500, 500 ), RandomIntRange( -500, 500 ), -1000 ) );
413  self SetVehVelocity( self.velocity + side_dir );
414  self thread ‪helicopter_crash_accel();
415  if( isdefined( point ) )
416  self thread ‪helicopter_crash_rotation( point, dir );
417  else
418  self thread ‪helicopter_crash_rotation( self.origin, dir );
419  }
420 
421  //self thread helicopter_collision();
422  self thread ‪crash_collision_test();
423 
424  wait 15;
425 
426  // failsafe notify
427  if ( IsDefined( self ) )
428  {
429  self notify( "crash_done" );
430  }
431 }
432 
434 {
435  self endon( "crash_done" );
436  self endon( "crash_move_done" );
437  self endon( "death" );
438 
439  if ( !isdefined( self.crash_accel ) )
440  {
441  self.crash_accel = RandomFloatRange( 50, 80 );
442  }
443 
444  while ( isdefined( self ) )
445  {
446  self SetVehVelocity( self.velocity + AnglesToUp( self.angles ) * self.crash_accel );
447  wait 0.1;
448  }
449 }
450 
451 function ‪helicopter_crash_rotation( point, dir )
452 {
453  self endon( "crash_done" );
454  self endon( "crash_move_done" );
455  self endon( "death" );
456 
457  start_angles = self.angles;
458  ‪VEC_SET_X( start_angles, start_angles[0] + 10 ); //RandomIntRange( -5, 5 ) );
459  ‪VEC_SET_Z( start_angles, start_angles[2] + 10 ); //RandomIntRange( -5, 5 ) );
460 
461  ang_vel = self GetAngularVelocity();
462  ang_vel = ( 0, ang_vel[1] * RandomFloatRange( 2, 3 ), 0 );
463  self SetAngularVelocity( ang_vel );
464 
465  point_2d = ( point[0], point[1], self.origin[2] );
466 
467  torque = ( 0, RandomIntRange( 90, 180 ), 0 );
468  if ( self GetAngularVelocity()[1] < 0 )
469  {
470  torque *= -1;
471  }
472 
473  if ( Distance( self.origin, point_2d ) > 5 )
474  {
475  local_hit_point = point_2d - self.origin;
476 
477  dir_2d = ( dir[0], dir[1], 0 );
478  if ( Length( dir_2d ) > 0.01 )
479  {
480  dir_2d = VectorNormalize( dir_2D );
481  torque = VectorCross( VectorNormalize( local_hit_point ), dir );
482  torque = ( 0, 0, torque[2] );
483  torque = VectorNormalize( torque );
484  torque = ( 0, torque[2] * 180, 0 );
485  }
486  }
487 
488  while ( 1 )
489  {
490  ang_vel = self GetAngularVelocity();
491  ang_vel += torque * 0.05;
492 
493  const max_angluar_vel = 360;
494  if ( ang_vel[1] < max_angluar_vel * -1 )
495  {
496  ang_vel = ( ang_vel[0], max_angluar_vel * -1, ang_vel[2] );
497  }
498  else if ( ang_vel[1] > max_angluar_vel )
499  {
500  ang_vel = ( ang_vel[0], max_angluar_vel, ang_vel[2] );
501  }
502 
503  self SetAngularVelocity( ang_vel );
504 
506  }
507 }
508 
510 {
511  self endon( "crash_done" );
512  self endon( "crash_move_done" );
513 
514  torque = ( 0, RandomIntRange( 90, 150 ), 0 );
515  ang_vel = self GetAngularVelocity();
516  torque *= ‪math::sign( ang_vel[1] );
517 
518  // if you don't have any roll give it a little
519  if ( Abs( self.angles[2] ) < 3.0 )
520  {
521  self.angles = ( self.angles[0], self.angles[1], RandomIntRange( 3, 6 ) * ‪math::sign( self.angles[2] ) );
522  }
523 
524  is_vtol = IsSubStr( self.vehicletype, "v78" );
525 
526  if ( is_vtol )
527  {
528  torque *= 0.3;
529  }
530 
531  while ( isdefined( self ) )
532  {
533  assert( isdefined( self.crash_zone ) );
534 
535  dist = Distance2D( self.origin, self.crash_zone.origin );
536  if ( dist < self.crash_zone.radius )
537  {
538  //if ( isdefined( self.crash_zone.angles ) )
539  // self.crash_vel = Length( self.velocity ) * AnglesToForward( self.crash_zone.angles );
540 
541  self SetPhysAcceleration( ( 0, 0, -400 ) );
542  self.crash_accel = 0;
543  }
544  else
545  {
546  self SetPhysAcceleration( ( 0, 0, -50 ) );
547  }
548 
549  self.crash_vel = self.crash_zone.origin - self.origin;
550  self.crash_vel = ( self.crash_vel[0], self.crash_vel[1], 0 );
551  self.crash_vel = VectorNormalize( self.crash_vel );
552  self.crash_vel *= self GetMaxSpeed() * 0.5;
553 
554  if ( is_vtol )
555  {
556  self.crash_vel *= 0.5;
557  }
558 
559  crash_vel_forward = AnglesToUp( self.angles ) * self GetMaxSpeed() * 2;
560  crash_vel_forward = ( crash_vel_forward[0], crash_vel_forward[1], 0 );
561  self.crash_vel += crash_vel_forward;
562 
563  vel_x = DiffTrack( self.crash_vel[0], self.velocity[0], 1, 0.1 );
564  vel_y = DiffTrack( self.crash_vel[1], self.velocity[1], 1, 0.1 );
565  vel_z = DiffTrack( self.crash_vel[2], self.velocity[2], 1, 0.1 );
566 
567  self SetVehVelocity( ( vel_x, vel_y, vel_z ) );
568 
569  ang_vel = self GetAngularVelocity();
570  ang_vel = ( 0, ang_vel[1], 0 );
571  ang_vel += torque * 0.1;
572 
573  max_angluar_vel = 200;
574  if ( is_vtol )
575  {
576  max_angluar_vel = 100;
577  }
578 
579  if ( ang_vel[1] < max_angluar_vel * -1 )
580  {
581  ang_vel = ( ang_vel[0], max_angluar_vel * -1, ang_vel[2] );
582  }
583  else if ( ang_vel[1] > max_angluar_vel )
584  {
585  ang_vel = ( ang_vel[0], max_angluar_vel, ang_vel[2] );
586  }
587 
588  self SetAngularVelocity( ang_vel );
589 
590  wait( 0.1 );
591  }
592 }
593 
595 {
596  self endon( "crash_done" );
597 
598  while ( 1 )
599  {
600  self waittill( "veh_collision", velocity, normal );
601 
602  ang_vel = self GetAngularVelocity() * 0.5;
603  self SetAngularVelocity( ang_vel );
604 
605  // bounce off walls
606  if ( normal[2] < 0.7 )
607  {
608  self SetVehVelocity( self.velocity + normal * 70 );
609  }
610  else
611  {
612  //self.crash_accel *= 0.5;
613  //self SetVehVelocity( self.velocity * 0.8 );
614  //TODO T7 - function port
615  //CreateDynEntAndLaunch( self.deathmodel, self.origin, self.angles, self.origin, self.velocity * 0.03, self.deathfx );
616 
617  self notify( "crash_done" );
618  }
619  }
620 }
621 
623 {
624  ent = ‪Spawn ( "script_origin", self.origin );
625  ent linkto ( self );
626  ent playloopsound ( "exp_heli_crash_loop" );
627  self ‪util::waittill_any ( "death", "snd_impact" );
628  ent delete();
629 
630 }
631 function ‪helicopter_explode( delete_me )
632 {
633  self endon( "death" );
634 
636 
637  if ( isdefined( delete_me ) && delete_me == true )
638  {
639  self Delete();
640  }
641 
642  self thread ‪set_death_model( self.deathmodel, self.modelswapdelay );
643 }
644 
645 function ‪aircraft_crash_move( point, dir )
646 {
647  self endon( "crash_move_done" );
648  self endon( "death" );
649 
650  self thread ‪crash_collision_test();
651  self ClearVehGoalPos();
652  self CancelAIMove();
653  self SetRotorSpeed( 0.2 );
654 
655  // swap to deathmodel here
656  if ( isdefined( self ) && isdefined( self.vehicletype ) )
657  {
658  b_custom_deathmodel_setup = true;
659  switch ( self.vehicletype )
660  {
661 
662  default:
663  b_custom_deathmodel_setup = false;
664  break;
665  }
666 
667  if ( b_custom_deathmodel_setup )
668  {
669  self.deathmodel_attached = true; // this will not add another deathmodel
670  }
671  }
672 
673  ang_vel = self GetAngularVelocity();
674  ang_vel = ( 0, 0, 0 );
675 
676  self SetAngularVelocity( ang_vel );
677 
678  nodes = self GetVehicleAvoidanceNodes( 10000 );
679  closest_index = -1;
680  best_dist = 999999;
681  if ( nodes.size > 0 )
682  {
683  for ( i = 0; i < nodes.size; i++ )
684  {
685  dir = VectorNormalize( nodes[i] - self.origin );
686  forward = AnglesToForward( self.angles );
687  dot = VectorDot( dir, forward );
688  if ( dot < 0.0 )
689  {
690  continue;
691  }
692 
693  dist = Distance2D( self.origin, nodes[i] );
694  if ( dist < best_dist )
695  {
696  best_dist = dist;
697  closest_index = i;
698  }
699  }
700 
701  if ( closest_index >= 0 )
702  {
703  o = nodes[closest_index];
704  o = ( o[0], o[1], self.origin[2] );
705 
706  //Line( self.origin, o, ( 1, 1, 1 ), false, 10000 );
707  //Circle( o, 2000, ( 1, 1, 0 ), true, 10000 );
708 
709  dir = VectorNormalize( o - self.origin );
710 
711  self SetVehVelocity( self.velocity + dir * 2000 );
712  }
713  else
714  {
715  self SetVehVelocity( self.velocity + AnglesToRight( self.angles ) * RandomIntRange( -1000, 1000 ) + ( 0, 0, RandomIntRange( 0, 1500 ) ) );
716  }
717  }
718  else
719  {
720  self SetVehVelocity( self.velocity + AnglesToRight( self.angles ) * RandomIntRange( -1000, 1000 ) + ( 0, 0, RandomIntRange( 0, 1500 ) ) );
721  }
722 
723  //self SetVehVelocity( self.velocity + AnglesToRight( self.angles ) * RandomIntRange( -1000, 1000 ) + ( 0, 0, RandomIntRange( 0, 1500 ) ) );
724  self thread ‪delay_set_gravity( RandomFloatRange( 1.5, 3 ) );
725 
726  torque = ( 0, RandomIntRange( -90, 90 ), RandomIntRange( 90, 720 ) );
727  if ( RandomInt( 100 ) < 50 )
728  {
729  torque = ( torque[0], torque[1], -torque[2] );
730  }
731 
732  while ( isdefined( self ) )
733  {
734  ang_vel = self GetAngularVelocity();
735  ang_vel += torque * 0.05;
736 
737  const max_angluar_vel = 500;
738  if ( ang_vel[2] < max_angluar_vel * -1 )
739  {
740  ang_vel = ( ang_vel[0], ang_vel[1], max_angluar_vel * -1 );
741  }
742  else if ( ang_vel[2] > max_angluar_vel )
743  {
744  ang_vel = ( ang_vel[0], ang_vel[1], max_angluar_vel );
745  }
746 
747  self SetAngularVelocity( ang_vel );
748 
750  }
751 }
752 
754 {
755  self endon( "crash_move_done" );
756  self endon( "death" );
757 
758  wait( ‪delay );
759 
760  self SetPhysAcceleration( ( RandomIntRange( -1600, 1600 ), RandomIntRange( -1600, 1600 ), -1600 ) );
761 }
762 
763 function ‪helicopter_crash_move( point, dir )
764 {
765  self endon( "crash_move_done" );
766  self endon( "death" );
767 
768  self thread ‪crash_collision_test();
769  self CancelAIMove();
770  self ClearVehGoalPos();
771  self SetTurningAbility( 0 );
772 
773 
774  self SetPhysAcceleration( ( 0, 0, -800 ) );
775 
776  vel = self.velocity;
777  dir = VectorNormalize( dir );
778 
779  ang_vel = self GetAngularVelocity();
780  ang_vel = ( 0, ang_vel[1] * RandomFloatRange( 1, 3 ), 0 );
781  self SetAngularVelocity( ang_vel );
782 
783  point_2d = ( point[0], point[1], self.origin[2] );
784 
785  torque = ( 0, 720, 0 );
786  if ( Distance( self.origin, point_2d ) > 5 )
787  {
788  local_hit_point = point_2d - self.origin;
789 
790  dir_2d = ( dir[0], dir[1], 0 );
791  if ( Length( dir_2d ) > 0.01 )
792  {
793  dir_2d = VectorNormalize( dir_2D );
794  torque = VectorCross( VectorNormalize( local_hit_point ), dir );
795  torque = ( 0, 0, torque[2] );
796  torque = VectorNormalize( torque );
797  torque = ( 0, torque[2] * 180, 0 );
798  }
799  }
800 
801  while ( 1 )
802  {
803  ang_vel = self GetAngularVelocity();
804  ang_vel += torque * 0.05;
805 
806  const max_angluar_vel = 360;
807  if ( ang_vel[1] < max_angluar_vel * -1 )
808  {
809  ang_vel = ( ang_vel[0], max_angluar_vel * -1, ang_vel[2] );
810  }
811  else if ( ang_vel[1] > max_angluar_vel )
812  {
813  ang_vel = ( ang_vel[0], max_angluar_vel, ang_vel[2] );
814  }
815 
816  self SetAngularVelocity( ang_vel );
817 
819  }
820 }
821 
822 
823 function ‪boat_crash( point, dir )
824 {
825  self.crashing = true;
826  // self thread play_crashing_loop();
827 
828  if ( isdefined( self.unloading ) )
829  {
830  while ( isdefined( self.unloading ) )
831  {
833  }
834  }
835 
836  if ( !isdefined( self ) )
837  {
838  return;
839  }
840 
841  self thread ‪boat_crash_movement( point, dir );
842 }
843 
844 function ‪boat_crash_movement( point, dir )
845 {
846  self endon( "crash_move_done" );
847  self endon( "death" );
848 
849  // self thread crash_collision_test();
850  self CancelAIMove();
851  self ClearVehGoalPos();
852 
853  self SetPhysAcceleration( ( 0, 0, -50 ) );
854 
855  vel = self.velocity;
856  dir = VectorNormalize( dir );
858 
859  ang_vel = self GetAngularVelocity();
860  ang_vel = ( 0, 0, 0 );
861  self SetAngularVelocity( ang_vel );
862 
863  torque = ( RandomIntRange( -5, -3 ), 0, ( RandomIntRange( 0, 100 ) < 50 ? -5 : 5 ) );
864 
865  self thread ‪boat_crash_monitor( point, dir, 4 );
866 
867  while ( 1 )
868  {
869  ang_vel = self GetAngularVelocity();
870  ang_vel += torque * 0.05;
871 
872  const max_angluar_vel = 360;
873  if ( ang_vel[1] < max_angluar_vel * -1 )
874  {
875  ang_vel = ( ang_vel[0], max_angluar_vel * -1, ang_vel[2] );
876  }
877  else if ( ang_vel[1] > max_angluar_vel )
878  {
879  ang_vel = ( ang_vel[0], max_angluar_vel, ang_vel[2] );
880  }
881 
882  self SetAngularVelocity( ang_vel );
883 
884  velocity = self.velocity;
885  ‪VEC_SET_X( velocity, velocity[0] * 0.975 );
886  ‪VEC_SET_Y( velocity, velocity[1] * 0.975 );
887  self SetVehVelocity( velocity );
888 
890  }
891 }
892 
893 function ‪boat_crash_monitor( point, dir, crash_time )
894 {
895  self endon( "death" );
896 
897  wait( crash_time );
898 
899  self notify( "crash_move_done" );
900  self ‪crash_stop();
901  self notify( "crash_done" );
902 }
903 
904 function ‪crash_stop()
905 {
906  self endon( "death" );
907 
908  self SetPhysAcceleration( ( 0, 0, 0 ) );
909  self SetRotorSpeed( 0 );
910 
911  speed = self GetSpeedMPH();
912  while ( speed > 2 )
913  {
914  velocity = self.velocity;
915  velocity *= 0.9;
916  self SetVehVelocity( velocity );
917 
918  angular_velocity = self GetAngularVelocity();
919  angular_velocity *= 0.9;
920  self SetAngularVelocity( angular_velocity );
921 
922  speed = self GetSpeedMPH();
923 
925  }
926 
927  self SetVehVelocity( ( 0, 0, 0 ) );
928  self SetAngularVelocity( ( 0, 0, 0 ) );
929 
930  self ‪vehicle::toggle_tread_fx( false );
931  self ‪vehicle::toggle_exhaust_fx( false );
932  self ‪vehicle::toggle_sounds( false );
933 }
934 
936 {
937  self endon( "death" );
938 
939  self waittill( "veh_collision", velocity, normal );
940 
941  self ‪helicopter_explode();
942  self notify( "crash_move_done" );
943 
944  if ( normal[2] > 0.7 )
945  {
946  forward = AnglesToForward( self.angles );
947  right = VectorCross( normal, forward );
948  desired_forward = VectorCross( right, normal );
949  self SetPhysAngles( VectorToAngles( desired_forward ) );
950 
951  self ‪crash_stop();
952  self notify( "crash_done" );
953  }
954  else
955  {
957  self Delete();
958  }
959 }
960 
961 function ‪crash_path_check( node )
962 {
963  // find a crashnode on the current path
964  // this only works on ground info_vehicle_node vheicles. not dynamic helicopter script_origin paths. they have their own dynamic crashing.
965  targ = node;
966  search_depth = 5;
967 
968  while ( isdefined( targ ) && search_depth >= 0 )
969  {
970  if ( ( isdefined( targ.detoured ) ) && ( targ.detoured == 0 ) )
971  {
972  detourpath = ‪vehicle::path_detour_get_detourpath( getvehiclenode( targ.target, "targetname" ) );
973  if ( isdefined( detourpath ) && isdefined( detourpath.script_crashtype ) )
974  {
975  return true;
976  }
977  }
978  if ( isdefined( targ.target ) )
979  {
980  // Edited for the case of nodes targetting eachother for looping paths 1/30/08 TFlame
981  targ1 = getvehiclenode( targ.target, "targetname" );
982  if ( isdefined( targ1 ) && isdefined( targ1.target ) && isdefined( targ.targetname ) && targ1.target == targ.targetname )
983  {
984  return false;
985  }
986  else if ( isdefined( targ1 ) && targ1 == node ) // circular case -AP 1/15/09
987  {
988  return false;
989  }
990  else
991  {
992  targ = targ1;
993  }
994 
995  }
996  else
997  {
998  targ = undefined;
999  }
1000 
1001  search_depth--;
1002  }
1003  return false;
1004 
1005 }
1006 
1007 function ‪death_firesound( sound )
1008 {
1009  self thread ‪sound::loop_on_tag( sound, undefined, false );
1010  self ‪util::waittill_any( "fire_extinguish", "stop_crash_loop_sound" );
1011  if ( !isdefined( self ) )
1012  {
1013  return;
1014  }
1015  self notify( "stop sound" + sound );
1016 }
1017 
1018 function ‪death_fx()
1019 {
1020  // going to use vehicletypes for identifying a vehicles association with effects.
1021  // will add new vehicle types if vehicle is different enough that it needs to use
1022  // different effect. also handles the sound
1023  if ( self vehicle::is_destructible() )
1024  {
1025  return;
1026  }
1027 
1029 
1030  if(isdefined(self.‪do_death_fx))
1031  {
1032  self [[self.do_death_fx]]();
1033  }
1034  else
1035  {
1036  self ‪vehicle::do_death_fx();
1037  }
1038 }
1039 
1040 
1041 function ‪death_make_badplace( type )
1042 {
1043  if ( !isdefined( level.vehicle_death_badplace[ type ] ) )
1044  {
1045  return;
1046  }
1047 
1048  struct = level.vehicle_death_badplace[ type ];
1049  if ( isdefined( struct.‪delay ) )
1050  {
1051  wait struct.delay;
1052  }
1053 
1054  if ( !isdefined( self ) )
1055  {
1056  return;
1057  }
1058 
1059  badplace_box( "vehicle_kill_badplace", struct.duration, self.origin, struct.radius, "all" );
1060 }
1061 
1062 function ‪death_jolt( type )
1063 {
1064  self endon( "death" );
1065 
1066  if ( ‪IS_TRUE( self.ignore_death_jolt ) )
1067  {
1068  return;
1069  }
1070 
1071  self JoltBody( ( self.origin + ( 23, 33, 64 ) ), 3 );
1072 
1073  if ( isdefined( self.death_anim ) )
1074  {
1075  self AnimScripted( "death_anim", self.origin, self.angles, self.death_anim, "normal", %root, 1, 0 );
1076  self waittillmatch( "death_anim", "end" );
1077  }
1078  else // if ( !isdefined( self.destructibledef ) )
1079  {
1080  if ( self.isphysicsvehicle )
1081  {
1082  num_launch_multiplier = 1;
1083 
1084  if ( isdefined( self.physicslaunchdeathscale ) )
1085  {
1086  num_launch_multiplier = self.physicslaunchdeathscale;
1087  }
1088 
1089  self LaunchVehicle( (0, 0, 180) * num_launch_multiplier, (RandomFloatRange(5, 10), RandomFloatRange(-5, 5), 0), true, false, true );
1090  }
1091  }
1092 }
1093 
1094 function ‪deathrollon()
1095 {
1096  if ( self.health > 0 )
1097  {
1098  self.rollingdeath = 1;
1099  }
1100 }
1101 
1103 {
1104  self.rollingdeath = undefined;
1105  self notify( "deathrolloff" );
1106 }
1107 
1108 function ‪loop_fx_on_vehicle_tag( effect, loopTime, tag )
1109 {
1110  assert( isdefined( effect ) );
1111  assert( isdefined( tag ) );
1112  assert( isdefined( loopTime ) );
1113 
1114  self endon( "stop_looping_death_fx" );
1115 
1116  while ( isdefined( self ) )
1117  {
1118  playfxontag( effect, ‪deathfx_ent(), tag );
1119  wait loopTime;
1120  }
1121 }
1122 
1123 function ‪deathfx_ent()
1124 {
1125  if ( !isdefined( self.‪deathfx_ent ) )
1126  {
1127  ent = ‪Spawn( "script_model", ( 0, 0, 0 ) );
1128  emodel = vehicle::get_dummy();
1129  ent setmodel( self.model );
1130  ent.origin = emodel.origin;
1131  ent.angles = emodel.angles;
1132  ent notsolid();
1133  ent hide();
1134  ent linkto( emodel );
1135  self.deathfx_ent = ent;
1136  }
1137  else
1138  {
1139  self.deathfx_ent setmodel( self.model );
1140  }
1141  return self.deathfx_ent;
1142 }
1143 
1145 {
1146  script_linkname = self.script_linkname;
1147  targetname = self.targetname;
1148 
1149  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
1150  // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
1151  if ( isdefined( script_linkname ) )
1152  {
1153  ArrayRemoveValue( level.vehicle_link[ script_linkname ], self );
1154  }
1155 
1156  if ( isdefined( self.script_VehicleSpawngroup ) )
1157  {
1158  if ( isdefined( level.vehicle_SpawnGroup[ self.script_VehicleSpawngroup ] ) )
1159  {
1160  ArrayRemoveValue( level.vehicle_SpawnGroup[ self.script_VehicleSpawngroup ], self );
1161  ArrayRemoveValue( level.vehicle_SpawnGroup[ self.script_VehicleSpawngroup ], undefined );
1162  }
1163  }
1164 
1165  if ( isdefined( self.script_VehicleStartMove ) )
1166  {
1167  ArrayRemoveValue( level.vehicle_StartMoveGroup[ self.script_VehicleStartMove ], self );
1168  }
1169 
1170  if ( isdefined( self.script_vehicleGroupDelete ) )
1171  {
1172  ArrayRemoveValue( level.vehicle_DeleteGroup[ self.script_vehicleGroupDelete ], self );
1173  }
1174 }
1175 
1177 {
1178  // if vehicle is gone then delete the ai here.
1179  if ( isdefined( self.riders ) )
1180  {
1181  for ( j = 0; j < self.riders.size; j++ )
1182  {
1183  if ( isdefined( self.riders[ j ] ) )
1184  {
1185  self.riders[ j ] delete();
1186  }
1187  }
1188  }
1189 
1190  if ( ‪vehicle::is_corpse( self ) )
1191  {
1192  self.riders = [];
1193  }
1194 }
1195 
1196 function ‪death_radius_damage( meansOfDamage = "MOD_EXPLOSIVE" )
1197 {
1198  self endon( "death" );
1199 
1200  if ( !isdefined( self ) || self.abandoned === true || self.damage_on_death === false || self.radiusdamageradius <= 0 )
1201  {
1202  return;
1203  }
1204 
1205  position = self.origin + ( 0,0,15 );
1206  radius = self.radiusdamageradius;
1207  damageMax = self.radiusdamagemax;
1208  damageMin = self.radiusdamagemin;
1209  attacker = self;
1210 
1212 
1213  if ( isdefined( self ) )
1214  {
1215  self RadiusDamage( position, radius, damageMax, damageMin, attacker, meansOfDamage );
1216  }
1217 }
1218 
1219 
1220 function ‪death_update_crash( point, dir )
1221 {
1222  if ( !isdefined( self.destructibledef ) )
1223  {
1224  if ( isdefined( self.script_crashtypeoverride ) )
1225  {
1226  crashtype = self.script_crashtypeoverride;
1227  }
1228  else if ( ‪IS_PLANE( self ) )
1229  {
1230  crashtype = "aircraft";
1231  }
1232  else if ( ‪IS_HELICOPTER( self ) )
1233  {
1234  crashtype = "helicopter";
1235  }
1236  else if ( ‪IS_BOAT( self ) )
1237  {
1238  crashtype = "boat";
1239  }
1240  else if ( isdefined( self.currentnode ) && ‪crash_path_check( self.currentnode ) )
1241  {
1242  crashtype = "none";
1243  }
1244  else
1245  {
1246  crashtype = "tank"; // tanks used to be the only vehicle that would stop. legacy nonsense from CoD1
1247  }
1248 
1249  if ( crashtype == "aircraft" )
1250  {
1251  self thread ‪aircraft_crash( point, dir );
1252  }
1253  else if ( crashtype == "helicopter" )
1254  {
1255  if ( isdefined( self.script_nocorpse ) )
1256  {
1257  // GLocke - Does not drop a physics script model on death
1258  self thread ‪helicopter_explode();
1259  }
1260  else
1261  {
1262  self thread ‪helicopter_crash( point, dir );
1263  }
1264  }
1265  else if ( crashtype == "boat" )
1266  {
1267  self thread ‪boat_crash( point, dir );
1268  }
1269  else if ( crashtype == "tank" )
1270  {
1271  if ( !isdefined( self.rollingdeath ) )
1272  {
1273  self ‪vehicle::set_speed( 0, 25, "Dead" );
1274  }
1275  else
1276  {
1277  // dpg 3/12/08 removed this. if you need it for something, let someone know
1278  self waittill( "deathrolloff" );
1279  self ‪vehicle::set_speed( 0, 25, "Dead, finished path intersection" );
1280  }
1281 
1282  wait .4;
1283 
1284  if ( isdefined( self ) && !‪vehicle::is_corpse( self ) )
1285  {
1286  self ‪vehicle::set_speed( 0, 10000, "deadstop" );
1287 
1288  self notify( "deadstop" );
1289  if ( self.disconnectPathOnStop === true )
1290  {
1292  }
1293 
1294  if ( ( isdefined( self.tankgetout ) ) && ( self.tankgetout > 0 ) )
1295  {
1296  // tankgetout will never get notified if there are no guys getting out
1297  self waittill( "animsdone" );
1298  }
1299  }
1300  }
1301  }
1302 }
1303 
1305 {
1306  self endon( "death" );
1307 
1308  if ( isdefined( self ) && ( ‪IS_PLANE( self ) || ‪IS_BOAT( self ) ) )
1309  {
1310  if ( ( isdefined( self.crashing ) ) && ( self.crashing == true ) )
1311  {
1312  self waittill( "crash_done" );
1313  }
1314  }
1315  else
1316  {
1317  wait 0.2; // don't check the velocity right away because we might have been launched
1318 
1319  if ( self.isphysicsvehicle )
1320  {
1321  self ClearVehGoalPos();
1322  self CancelAIMove();
1323  //GLocke 2/16/10 - just wait for physics vehicles to get close to 0
1324  stable_count = 0;
1325  while( stable_count < 3 )
1326  {
1327  if ( isdefined( self.velocity ) && LengthSquared( self.velocity ) > 1.0 )
1328  {
1329  stable_count = 0;
1330  }
1331  else
1332  {
1333  stable_count++;
1334  }
1335  wait( 0.3 );
1336  }
1338  }
1339  else
1340  {
1341  while ( isdefined( self ) && self GetSpeedMPH() > 0 )
1342  {
1343  wait( 0.3 );
1344  }
1345  }
1346  }
1347 }
1348 
1349 #define DAMAGE_FILTER_MIN_TIME 500
1350 function ‪vehicle_damage_filter_damage_watcher( driver, heavy_damage_threshold )
1351 {
1352  self endon( "death" );
1353  self endon( "exit_vehicle" );
1354  self endon( "end_damage_filter" );
1355 
1356  if ( !isdefined( heavy_damage_threshold ) )
1357  {
1358  heavy_damage_threshold = 100;
1359  }
1360 
1361  while ( 1 )
1362  {
1363  self waittill( "damage", ‪damage, attacker, direction, point, type, tagName, modelName, partname, weapon );
1364 
1365  Earthquake( 0.25, 0.15, self.origin, 512, self );
1366  driver PlayRumbleOnEntity( "damage_light" );
1367 
1368  time = GetTime();
1369  if ( ( time - level.n_last_damage_time ) > ‪DAMAGE_FILTER_MIN_TIME )
1370  {
1371  level.n_hud_damage = true;
1372 
1373  if ( ‪damage > heavy_damage_threshold )
1374  {
1375  driver playsound ( "veh_damage_filter_heavy" );
1376  }
1377  else
1378  {
1379  driver playsound ( "veh_damage_filter_light" );
1380  }
1381 
1382  level.n_last_damage_time = GetTime();
1383  }
1384  }
1385 }
1386 
1388 {
1389  self ‪util::waittill_any( "exit_vehicle", "death", "end_damage_filter" );
1390 }
1391 
1392 function ‪vehicle_damage_filter( vision_set, heavy_damage_threshold, filterid = 0, b_use_player_damage = false )
1393 {
1394  self endon( "death" );
1395  self endon( "exit_vehicle" );
1396  self endon( "end_damage_filter" );
1397 
1398  driver = self GetSeatOccupant( 0 );
1399 
1400  if ( !isdefined( self.damage_filter_init ) )
1401  {
1402  //rpc( "scripts/_vehicle", "init_damage_filter", filterid );
1403  self.damage_filter_init = true;
1404  }
1405  else
1406  {
1407  //rpc( "scripts/_vehicle", "damage_filter_enable", 0, filterid );
1408  }
1409 
1410  if ( isdefined( vision_set ) )
1411  {
1412  //TODO T7 - convert to use manager
1413  /*level.player.save_visionset = level.player GetVisionSetNaked();
1414  level.player VisionSetNaked( vision_set, 0.5 );*/
1415  }
1416 
1417  level.n_hud_damage = false;
1418  level.n_last_damage_time = GetTime();
1419 
1420  damagee = ( ‪IS_TRUE( b_use_player_damage ) ? driver : self );
1421 
1422  damagee thread ‪vehicle_damage_filter_damage_watcher( driver, heavy_damage_threshold );
1423  damagee thread ‪vehicle_damage_filter_exit_watcher( driver );
1424 
1425  while ( 1 )
1426  {
1427  if ( ‪IS_TRUE( level.n_hud_damage ) )
1428  {
1429  time = GetTime();
1430  if ( ( time - level.n_last_damage_time ) > ‪DAMAGE_FILTER_MIN_TIME )
1431  {
1432  //rpc( "scripts/_vehicle", "damage_filter_off" );
1433  level.n_hud_damage = false;
1434  }
1435  }
1436 
1438  }
1439 }
1440 
1441 // self == vehicle
1442 function ‪flipping_shooting_death( attacker, hitDir )
1443 {
1444  // do we need this?
1445  if( isdefined( self.‪delete_on_death ) )
1446  {
1447  if ( isdefined( self ) )
1448  {
1449  self delete();
1450  }
1451 
1452  return;
1453  }
1454 
1455  if ( !isdefined( self ) )
1456  {
1457  return;
1458  }
1459 
1460  self endon( "death" ); //quit thread if deleted
1461 
1463 
1464  self DisableAimAssist();
1465 
1468  self thread ‪vehicle_death::set_death_model( self.deathmodel, self.modelswapdelay );
1469 
1470  self ‪vehicle::toggle_tread_fx( false );
1471  self ‪vehicle::toggle_exhaust_fx( false );
1472  self ‪vehicle::toggle_sounds( false );
1473  self ‪vehicle::lights_off();
1474  self thread ‪flipping_shooting_crash_movement( attacker, hitDir );
1475 
1476  self waittill( "crash_done" );
1477 
1478  while( ‪IS_TRUE( self.controlled ) )
1480 
1481  // A dynEnt will be spawned in the collision thread when it hits the ground and "crash_done" notify will be sent
1482  self delete();
1483 }
1484 
1485 function ‪plane_crash()
1486 {
1487  self endon( "death" );
1488 
1489  self SetPhysAcceleration( ( 0, 0, -1000 ) );
1490  self.vehcheckforpredictedcrash = true; // code field to get veh_predictedcollision notify
1491 
1492  forward = AnglesToForward( self.angles );
1493  forward_mag = RandomFloatRange( 0, 300 );
1494  forward_mag += ‪math::sign( forward_mag ) * 400;
1495  forward *= forward_mag;
1496 
1497  new_vel = forward + (self.velocity * 0.2);
1498 
1499  ang_vel = self GetAngularVelocity();
1500 
1501  yaw_vel = RandomFloatRange( 0, 130 ) * ‪math::sign( ang_vel[1] );
1502  yaw_vel += ‪math::sign( yaw_vel ) * 20;
1503 
1504  ang_vel = ( RandomFloatRange( -1, 1 ), yaw_vel, 0 );
1505 
1506  // setup the roll to look correct
1507  roll_amount = ( abs( ang_vel[1] ) / 150.0 ) * 30.0;
1508  if( ang_vel[1] > 0 )
1509  {
1510  roll_amount = -roll_amount;
1511  }
1512 
1513  self.angles = ( self.angles[0], self.angles[1], roll_amount );
1514  ang_vel = ( ang_vel[0], ang_vel[1], roll_amount * 0.9 );
1515 
1516  // set how much of the forward velocity to rotate when the vehicle rotates, more like a plane
1517  self.velocity_rotation_frac = 1.0;//RandomFloatRange( 0.95, 0.99 );
1518 
1519  self.crash_accel = RandomFloatRange( 65, 90 );
1520 
1521  ‪set_movement_and_accel( new_vel, ang_vel );
1522 }
1523 
1525 {
1526  self endon( "death" );
1527 
1528  self SetPhysAcceleration( ( 0, 0, -1000 ) );
1529  self.vehcheckforpredictedcrash = true; // code field to get veh_predictedcollision notify
1530 
1531  forward = AnglesToForward( self.angles );
1532  forward_mag = RandomFloatRange( 0, 250 );
1533  forward_mag += ‪math::sign( forward_mag ) * 300;
1534  forward *= forward_mag;
1535 
1536  new_vel = forward + (0,0,70);
1537 
1538  ang_vel = self GetAngularVelocity();
1539  yaw_vel = RandomFloatRange( 0, 60 ) * ‪math::sign( ang_vel[1] );
1540  yaw_vel += ‪math::sign( yaw_vel ) * 30;
1541 
1542  roll_vel = RandomFloatRange( -200, 200 );
1543  roll_vel += ‪math::sign( roll_vel ) * 300;
1544  ang_vel = ( RandomFloatRange( -5, 5 ), yaw_vel, roll_vel );
1545 
1546  // set how much of the forward velocity to rotate when the vehicle rotates, more like a plane
1547  self.velocity_rotation_frac = 1.0;//RandomFloatRange( 0.95, 0.99 );
1548 
1549  self.crash_accel = RandomFloatRange( 145, 210 );
1550 
1551  self SetPhysAcceleration( ( 0, 0, -250 ) );
1552 
1553  ‪set_movement_and_accel( new_vel, ang_vel );
1554 }
1555 
1556 function ‪random_crash( hitdir )
1557 {
1558  self endon( "death" );
1559 
1560  self SetPhysAcceleration( ( 0, 0, -1000 ) );
1561  self.vehcheckforpredictedcrash = true; // code field to get veh_predictedcollision notify
1562 
1563  if( !isdefined( hitdir ) )
1564  {
1565  hitdir = (1,0,0);
1566  }
1567  hitdir = VectorNormalize( hitdir );
1568 
1569  side_dir = VectorCross( hitdir, (0,0,1) );
1570  side_dir_mag = RandomFloatRange( -280, 280 );
1571  side_dir_mag += ‪math::sign( side_dir_mag ) * 150;
1572  side_dir *= side_dir_mag;
1573 
1574  forward = AnglesToForward( self.angles );
1575  forward_mag = RandomFloatRange( 0, 300 );
1576  forward_mag += ‪math::sign( forward_mag ) * 30;
1577  forward *= forward_mag;
1578 
1579  new_vel = (self.velocity * 1.2) + forward + side_dir + (0,0,50);
1580 
1581  ang_vel = self GetAngularVelocity();
1582  ang_vel = ( ang_vel[0] * 0.3, ang_vel[1], ang_vel[2] * 1.2 );
1583 
1584  yaw_vel = RandomFloatRange( 0, 130 ) * ‪math::sign( ang_vel[1] );
1585  yaw_vel += ‪math::sign( yaw_vel ) * 50;
1586 
1587  ang_vel += ( RandomFloatRange( -5, 5 ), yaw_vel, RandomFloatRange( -18, 18 ) );
1588 
1589  // set how much of the forward velocity to rotate when the vehicle rotates, more like a plane
1590  self.velocity_rotation_frac = RandomFloatRange( 0.3, 0.99 );
1591 
1592  self.crash_accel = RandomFloatRange( 65, 90 );
1593 
1594  ‪set_movement_and_accel( new_vel, ang_vel );
1595 }
1596 
1597 function ‪set_movement_and_accel( new_vel, ang_vel )
1598 {
1599  self ‪death_fx();
1600  self thread ‪death_radius_damage();
1601 
1602  self SetVehVelocity( new_vel );
1603  self SetAngularVelocity( ang_vel );
1604 
1605  if( !isdefined( self.off ) )
1606  {
1607  self thread ‪flipping_shooting_crash_accel();
1608  }
1609  self thread ‪vehicle_ai::nudge_collision();
1610 
1611  //drone death sounds JM - play 1 shot hit, turn off main loop, thread dmg loop
1612  self playsound("veh_wasp_dmg_hit");
1613  self ‪vehicle::toggle_sounds( 0 );
1614 
1615  if( !isdefined( self.off ) )
1616  {
1617  self thread ‪flipping_shooting_dmg_snd();
1618  }
1619 
1620  wait 0.1;
1621 
1622  if( RandomInt( 100 ) < 40 && !isdefined( self.off ) && self.variant !== "rocket" )
1623  {
1624  self thread ‪vehicle_ai::fire_for_time( RandomFloatRange( 0.7, 2.0 ) );
1625  }
1626 
1627  ‪result = self ‪util::waittill_any_timeout( 15, "crash_done" );
1628 
1629  if ( ‪result === "crash_done" )
1630  {
1632  self ‪vehicle_death::set_death_model( self.deathmodel, self.modelswapdelay );
1633  }
1634  else
1635  {
1636  // failsafe notify
1637  self notify( "crash_done" );
1638  }
1639 }
1640 
1641 function ‪flipping_shooting_crash_movement( attacker, hitdir )
1642 {
1643  self endon( "crash_done" );
1644  self endon( "death" );
1645 
1646  self CancelAIMove();
1647  self ClearVehGoalPos();
1648  self ClearLookAtEnt();
1649 
1650  self SetPhysAcceleration( ( 0, 0, -1000 ) );
1651  self.vehcheckforpredictedcrash = true; // code field to get veh_predictedcollision notify
1652 
1653  if( !isdefined( hitdir ) )
1654  {
1655  hitdir = (1,0,0);
1656  }
1657 
1658  hitdir = VectorNormalize( hitdir );
1659 
1660  new_vel = self.velocity;
1661 
1662  self.crash_style = -1;
1663  if( self.crash_style == -1 )
1664  {
1665  self.crash_style = RandomInt( 3 );
1666  }
1667 
1668  switch( self.crash_style )
1669  {
1670  case 0: ‪barrel_rolling_crash(); break;
1671  case 1: ‪plane_crash(); break;
1672  default: ‪random_crash( hitdir );
1673  }
1674 }
1675 
1677 {
1678  dmg_ent = ‪Spawn("script_origin", self.origin);
1679  dmg_ent linkto (self);
1680  dmg_ent PlayLoopSound ("veh_wasp_dmg_loop");
1681  self ‪util::waittill_any("crash_done", "death");
1682  dmg_ent stoploopsound(1);
1683  wait (2);
1684  dmg_ent delete();
1685 }
1686 
1688 {
1689  self endon( "crash_done" );
1690  self endon( "death" );
1691 
1692  count = 0;
1693 
1694  prev_forward = AnglesToForward( self.angles );
1695  prev_forward_vel = VectorDot( self.velocity, prev_forward ) * self.velocity_rotation_frac;
1696  if( prev_forward_vel < 0 )
1697  {
1698  prev_forward_vel = 0;
1699  }
1700 
1701  while( 1 )
1702  {
1703  self SetVehVelocity( self.velocity + AnglesToUp( self.angles ) * self.crash_accel );
1704  self.crash_accel *= 0.98;
1705 
1706  // Rotate part of the velocity
1707  new_velocity = self.velocity;
1708  new_velocity -= prev_forward * prev_forward_vel;
1709 
1710  forward = AnglesToForward( self.angles );
1711  new_velocity += forward * prev_forward_vel;// * 0.98;
1712 
1713  prev_forward = forward;
1714  prev_forward_vel = VectorDot( new_velocity, prev_forward ) * self.velocity_rotation_frac;
1715  if( prev_forward_vel < 10 )
1716  {
1717  new_velocity += forward * 40;
1718  prev_forward_vel = 0;
1719  }
1720 
1721  self SetVehVelocity( new_velocity );
1722 
1723  wait 0.1;
1724 
1725  count++;
1726  if ( count % 8 == 0 && RandomInt( 100 ) > 40 )
1727  {
1728  if ( self.velocity[2] > 130.0 )
1729  {
1730  self.crash_accel *= 0.75;
1731  }
1732  else if ( self.velocity[2] < 40.0 && count < 60 )
1733  {
1734  if ( Abs( self.angles[0] ) > 35 || Abs( self.angles[2] ) > 35 ) // tilted
1735  {
1736  self.crash_accel = RandomFloatRange( 100, 150 );
1737  }
1738  else
1739  {
1740  self.crash_accel = RandomFloatRange( 45, 70 );
1741  }
1742  }
1743  }
1744  }
1745 }
1746 
1748 {
1749  sound_ent = ‪Spawn( "script_origin", self.origin );
1750  sound_ent PlayLoopSound( "veh_qrdrone_death_fire_loop" , .1 );
1751  wait 11;
1752  sound_ent StopLoopSound( 1 );
1753  sound_ent delete();
1754 }
1755 
1756 function ‪FreeWhenSafe( time = 4 )
1757 {
1758  self thread ‪DelayedRemove_thread( time, false );
1759 }
1760 
1761 function ‪DeleteWhenSafe( time = 4 )
1762 {
1763  self thread ‪DelayedRemove_thread( time, true );
1764 }
1765 
1766 function ‪DelayedRemove_thread( time, shouldDelete )
1767 {
1768  if ( !isdefined( self ) )
1769  {
1770  return;
1771  }
1772 
1773  self endon ( "death" );
1774  self endon ( "free_vehicle" );
1775 
1776  if ( shouldDelete === true )
1777  {
1778  self SetVehVelocity( ( 0, 0, 0 ) );
1779  self Ghost();
1780  self NotSolid();
1781  }
1782 
1784 
1785  if ( shouldDelete === true )
1786  {
1787  self Delete();
1788  }
1789  else
1790  {
1791  self FreeVehicle();
1792  }
1793 }
1794 
1795 function ‪CleanUp()
1796 {
1797  if ( isdefined( self.cleanup_after_time ) )
1798  {
1799  wait self.cleanup_after_time;
1800  if ( isdefined( self ) )
1801  {
1802  self Delete();
1803  }
1804  }
1805 }
‪set_death_model
‪function set_death_model(sModel, fDelay)
Definition: vehicle_death_shared.gsc:258
‪vehicle_damage_filter_exit_watcher
‪function vehicle_damage_filter_exit_watcher(driver)
Definition: vehicle_death_shared.gsc:1387
‪helicopter_explode
‪function helicopter_explode(delete_me)
Definition: vehicle_death_shared.gsc:631
‪loop_fx_on_vehicle_tag
‪function loop_fx_on_vehicle_tag(effect, loopTime, tag)
Definition: vehicle_death_shared.gsc:1108
‪lights_off
‪function lights_off(localClientNum)
Definition: vehicle_shared.csc:652
‪flipping_shooting_crash_accel
‪function flipping_shooting_crash_accel()
Definition: vehicle_death_shared.gsc:1687
‪helicopter_crash
‪function helicopter_crash(point, dir)
Definition: vehicle_death_shared.gsc:320
‪plane_crash
‪function plane_crash()
Definition: vehicle_death_shared.gsc:1485
‪helicopter_collision
‪function helicopter_collision()
Definition: vehicle_death_shared.gsc:594
‪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
‪DAMAGE_FILTER_MIN_TIME
‪#define DAMAGE_FILTER_MIN_TIME
Definition: vehicle_death_shared.gsc:1349
‪death_fx
‪function death_fx()
Definition: vehicle_death_shared.gsc:1018
‪toggle_tread_fx
‪function toggle_tread_fx(on)
Definition: vehicle_shared.gsc:3357
‪delay_set_gravity
‪function delay_set_gravity(delay)
Definition: vehicle_death_shared.gsc:753
‪play_death_audio
‪function play_death_audio()
Definition: vehicle_death_shared.gsc:235
‪IS_HELICOPTER
‪#define IS_HELICOPTER(__e)
Definition: shared.gsh:351
‪sign
‪function sign(x)
Definition: math_shared.csc:164
‪nudge_collision
‪function nudge_collision()
Definition: vehicle_ai_shared.gsc:437
‪death_update_crash
‪function death_update_crash(point, dir)
Definition: vehicle_death_shared.gsc:1220
‪flipping_shooting_crash_movement
‪function flipping_shooting_crash_movement(attacker, hitdir)
Definition: vehicle_death_shared.gsc:1641
‪DelayedRemove_thread
‪function DelayedRemove_thread(time, shouldDelete)
Definition: vehicle_death_shared.gsc:1766
‪get_array
‪function get_array(kvp_value, kvp_key="targetname")
Definition: struct.csc:34
‪toggle_exhaust_fx
‪function toggle_exhaust_fx(on)
Definition: vehicle_shared.gsc:3335
‪waittill_crash_done_or_stopped
‪function waittill_crash_done_or_stopped()
Definition: vehicle_death_shared.gsc:1304
‪vehicle_damage_filter_damage_watcher
‪function vehicle_damage_filter_damage_watcher(driver, heavy_damage_threshold)
Definition: vehicle_death_shared.gsc:1350
‪play_crashing_loop
‪function play_crashing_loop()
Definition: vehicle_death_shared.gsc:622
‪DeleteWhenSafe
‪function DeleteWhenSafe(time=4)
Definition: vehicle_death_shared.gsc:1761
‪main
‪function main()
Definition: vehicle_death_shared.gsc:30
‪loop_on_tag
‪function loop_on_tag(alias, tag, bStopSoundOnDeath)
Definition: sound_shared.gsc:66
‪helicopter_crash_zone_accel
‪function helicopter_crash_zone_accel(dir)
Definition: vehicle_death_shared.gsc:509
‪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
‪boat_crash_monitor
‪function boat_crash_monitor(point, dir, crash_time)
Definition: vehicle_death_shared.gsc:893
‪delay
‪function delay(time_or_notify, str_endon, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:784
‪helicopter_crash_move
‪function helicopter_crash_move(point, dir)
Definition: vehicle_death_shared.gsc:763
‪set_speed
‪function set_speed(speed, rate, msg)
Definition: vehicle_shared.gsc:1577
‪explode_notify_wrapper
‪function explode_notify_wrapper()
Definition: util_shared.gsc:1082
‪death_cleanup_riders
‪function death_cleanup_riders()
Definition: vehicle_death_shared.gsc:1176
‪death_radius_damage
‪function death_radius_damage(meansOfDamage="MOD_EXPLOSIVE")
Definition: vehicle_death_shared.gsc:1196
‪aircraft_crash_move
‪function aircraft_crash_move(point, dir)
Definition: vehicle_death_shared.gsc:645
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪helicopter_crash_movement
‪function helicopter_crash_movement(point, dir)
Definition: vehicle_death_shared.gsc:343
‪crash_collision_test
‪function crash_collision_test()
Definition: vehicle_death_shared.gsc:935
‪flipping_shooting_death
‪function flipping_shooting_death(attacker, hitDir)
Definition: vehicle_death_shared.gsc:1442
‪FreeWhenSafe
‪function FreeWhenSafe(time=4)
Definition: vehicle_death_shared.gsc:1756
‪__init__
‪function __init__()
Definition: vehicle_death_shared.gsc:26
‪boat_crash
‪function boat_crash(point, dir)
Definition: vehicle_death_shared.gsc:823
‪VEC_SET_X
‪#define VEC_SET_X(_v, _x)
Definition: shared.gsh:259
‪is_corpse
‪function is_corpse(veh)
Definition: vehicle_shared.gsc:3401
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪aircraft_crash
‪function aircraft_crash(point, dir)
Definition: vehicle_death_shared.gsc:299
‪helicopter_crash_accel
‪function helicopter_crash_accel()
Definition: vehicle_death_shared.gsc:433
‪fire_for_time
‪function fire_for_time(n_time, n_index=0)
Definition: turret_shared.gsc:953
‪do_scripted_crash
‪function do_scripted_crash()
Definition: vehicle_death_shared.gsc:230
‪waitForTimeAndNetworkFrame
‪function waitForTimeAndNetworkFrame(time)
Definition: util_shared.gsc:2741
‪death_firesound
‪function death_firesound(sound)
Definition: vehicle_death_shared.gsc:1007
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪deathrolloff
‪function deathrolloff()
Definition: vehicle_death_shared.gsc:1102
‪flipping_shooting_dmg_snd
‪function flipping_shooting_dmg_snd()
Definition: vehicle_death_shared.gsc:1676
‪random_crash
‪function random_crash(hitdir)
Definition: vehicle_death_shared.gsc:1556
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪play_spinning_plane_sound
‪function play_spinning_plane_sound()
Definition: vehicle_death_shared.gsc:251
‪crash_path_check
‪function crash_path_check(node)
Definition: vehicle_death_shared.gsc:961
‪deathfx_ent
‪function deathfx_ent()
Definition: vehicle_death_shared.gsc:1123
‪path_detour_get_detourpath
‪function path_detour_get_detourpath(detournode)
Definition: vehicle_shared.gsc:316
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪death_make_badplace
‪function death_make_badplace(type)
Definition: vehicle_death_shared.gsc:1041
‪CleanUp
‪function CleanUp()
Definition: vehicle_death_shared.gsc:1795
‪death_jolt
‪function death_jolt(type)
Definition: vehicle_death_shared.gsc:1062
‪crash_stop
‪function crash_stop()
Definition: vehicle_death_shared.gsc:904
‪helicopter_crash_rotation
‪function helicopter_crash_rotation(point, dir)
Definition: vehicle_death_shared.gsc:451
‪boat_crash_movement
‪function boat_crash_movement(point, dir)
Definition: vehicle_death_shared.gsc:844
‪do_death_fx
‪function do_death_fx()
Definition: vehicle_shared.gsc:2855
‪do_death_dynents
‪function do_death_dynents(special_status=1)
Definition: vehicle_shared.gsc:2874
‪set_movement_and_accel
‪function set_movement_and_accel(new_vel, ang_vel)
Definition: vehicle_death_shared.gsc:1597
‪death_fire_loop_audio
‪function death_fire_loop_audio()
Definition: vehicle_death_shared.gsc:1747
‪toggle_sounds
‪function toggle_sounds(on)
Definition: vehicle_shared.gsc:3379
‪deathrollon
‪function deathrollon()
Definition: vehicle_death_shared.gsc:1094
‪result
‪function result(death, attacker, mod, weapon)
Definition: _zm_aat_blast_furnace.gsc:46
‪IS_PLANE
‪#define IS_PLANE(__e)
Definition: shared.gsh:350
‪delete_on_death
‪function delete_on_death(ent)
Definition: util_shared.gsc:1796
‪disconnect_paths
‪function disconnect_paths(detail_level=2, move_allowed=true)
Definition: vehicle_shared.gsc:3580
‪VEC_SET_Z
‪#define VEC_SET_Z(_v, _z)
Definition: shared.gsh:261
‪IS_BOAT
‪#define IS_BOAT(__e)
Definition: shared.gsh:352
‪VEC_SET_Y
‪#define VEC_SET_Y(_v, _y)
Definition: shared.gsh:260
‪barrel_rolling_crash
‪function barrel_rolling_crash()
Definition: vehicle_death_shared.gsc:1524
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265