‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
vehicle_shared.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\array_shared;
4 #using scripts\shared\math_shared;
5 #using scripts\shared\callbacks_shared;
6 #using scripts\shared\clientfield_shared;
7 #using scripts\shared\exploder_shared;
8 #using scripts\shared\flag_shared;
9 #using scripts\shared\spawner_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\trigger_shared;
12 #using scripts\shared\turret_shared;
13 #using scripts\shared\vehicles\_auto_turret;
14 #using scripts\shared\util_shared;
15 #using scripts\shared\vehicleriders_shared;
16 #using scripts\shared\vehicle_death_shared;
17 
18 #insert scripts\shared\shared.gsh;
19 #insert scripts\shared\version.gsh;
20 
21 #define MAX_LIGHTFX_GROUPS 3 // match MAX_LIGHTFX_GROUPS in vehiclecustomsettings.awi
22 #define MAX_AMBIENT_ANIM_GROUPS 3 // match MAX_AMBIENT_ANIM_GROUPS in vehiclecustomsettings.awi
23 
24 #define ANIMTREE "generic"
25 
26 #precache( "material", "black" );
27 #precache( "eventstring", "hud_vehicle_turret_fire" );
28 
29 #namespace vehicle;
30 
31 ‪REGISTER_SYSTEM_EX( "vehicle_shared", &‪__init__, &‪__main__, undefined )
32 
33  /*
34  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
35  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
36 
37 VEHICLE script
38 
39 This handles playing the various effects and animations on a vehicle.
40 function It handles initializing a vehicle( giving it life, turrets, machine guns, treads and things )
41 
42 It also handles spawning of vehicles in a very ugly way for now, we're getting code to make it pretty
43 
44 Most things you see in the vehicle menu in Radiant are handled here. There's all sorts of properties
45 that you can set on a trigger to access some of this functionality. A trigger can spawn a vehicle,
46 toggle different behaviors,
47 
48 
49 HIGH LEVEL FUNCTIONS
50 
51  // init( vehicle )
52  this give the vehicle life, treads, turrets, machine guns, all that good stuff
53 
54  // animmode::main()
55  this is setup, sets up spawners, trigger associations etc is ran on first frame by _load
56 
57  // trigger_process( trigger, vehicles )
58  since triggers are multifunction I made them all happen in the same thread so that
59  the sequencing would be easy to handle
60 
61  // paths()
62  This makes the nodes get notified trigger when they are hit by a vehicle, we hope
63  to move this functionality to CODE side because we have to use a lot of wrappers for
64  attaching a vehicle to a path
65 
66  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
67  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
68  */
69 
70 
71 #using_animtree( ANIMTREE );
72 
73 function ‪__init__()
74 {
75  ‪clientfield::register( "vehicle", "toggle_lockon", ‪VERSION_SHIP, 1, "int" );
76  ‪clientfield::register( "vehicle", "toggle_sounds", ‪VERSION_SHIP, 1, "int" );
77  ‪clientfield::register( "vehicle", "use_engine_damage_sounds", ‪VERSION_SHIP, 2, "int" );
78  ‪clientfield::register( "vehicle", "toggle_treadfx", ‪VERSION_SHIP, 1, "int" );
79  ‪clientfield::register( "vehicle", "toggle_exhaustfx", ‪VERSION_SHIP, 1, "int" );
80  ‪clientfield::register( "vehicle", "toggle_lights", ‪VERSION_SHIP, 2, "int" );
81  ‪clientfield::register( "vehicle", "toggle_lights_group1", ‪VERSION_SHIP, 1, "int" );
82  ‪clientfield::register( "vehicle", "toggle_lights_group2", ‪VERSION_SHIP, 1, "int" );
83  ‪clientfield::register( "vehicle", "toggle_lights_group3", ‪VERSION_SHIP, 1, "int" );
84  ‪clientfield::register( "vehicle", "toggle_lights_group4", ‪VERSION_SHIP, 1, "int" );
85  ‪clientfield::register( "vehicle", "toggle_ambient_anim_group1", ‪VERSION_SHIP, 1, "int" );
86  ‪clientfield::register( "vehicle", "toggle_ambient_anim_group2", ‪VERSION_SHIP, 1, "int" );
87  ‪clientfield::register( "vehicle", "toggle_ambient_anim_group3", ‪VERSION_SHIP, 1, "int" );
88  ‪clientfield::register( "vehicle", "toggle_emp_fx", ‪VERSION_SHIP, 1, "int" );
89  ‪clientfield::register( "vehicle", "toggle_burn_fx", ‪VERSION_SHIP, 1, "int" );
90  ‪clientfield::register( "vehicle", "deathfx", ‪VERSION_SHIP, 2, "int" );
91  ‪clientfield::register( "vehicle", "alert_level", ‪VERSION_SHIP, 2, "int" );
92  ‪clientfield::register( "vehicle", "set_lighting_ent", ‪VERSION_SHIP, 1, "int" );
93  ‪clientfield::register( "vehicle", "use_lighting_ent", ‪VERSION_SHIP, 1, "int" );
94  ‪clientfield::register( "vehicle", "damage_level", ‪VERSION_SHIP, 3, "int" );
95  ‪clientfield::register( "vehicle", "spawn_death_dynents", ‪VERSION_SHIP, 2, "int" );
96  ‪clientfield::register( "vehicle", "spawn_gib_dynents", ‪VERSION_SHIP, 1, "int" );
97 
98  ‪clientfield::register( "helicopter", "toggle_lockon", ‪VERSION_SHIP, 1, "int" );
99  ‪clientfield::register( "helicopter", "toggle_sounds", ‪VERSION_SHIP, 1, "int" );
100  ‪clientfield::register( "helicopter", "use_engine_damage_sounds", ‪VERSION_SHIP, 2, "int" );
101  ‪clientfield::register( "helicopter", "toggle_treadfx", ‪VERSION_SHIP, 1, "int" );
102  ‪clientfield::register( "helicopter", "toggle_exhaustfx", ‪VERSION_SHIP, 1, "int" );
103  ‪clientfield::register( "helicopter", "toggle_lights", ‪VERSION_SHIP, 2, "int" );
104  ‪clientfield::register( "helicopter", "toggle_lights_group1", ‪VERSION_SHIP, 1, "int" );
105  ‪clientfield::register( "helicopter", "toggle_lights_group2", ‪VERSION_SHIP, 1, "int" );
106  ‪clientfield::register( "helicopter", "toggle_lights_group3", ‪VERSION_SHIP, 1, "int" );
107  ‪clientfield::register( "helicopter", "toggle_lights_group4", ‪VERSION_SHIP, 1, "int" );
108  ‪clientfield::register( "helicopter", "toggle_ambient_anim_group1", ‪VERSION_SHIP, 1, "int" );
109  ‪clientfield::register( "helicopter", "toggle_ambient_anim_group2", ‪VERSION_SHIP, 1, "int" );
110  ‪clientfield::register( "helicopter", "toggle_ambient_anim_group3", ‪VERSION_SHIP, 1, "int" );
111  ‪clientfield::register( "helicopter", "toggle_emp_fx", ‪VERSION_SHIP, 1, "int" );
112  ‪clientfield::register( "helicopter", "toggle_burn_fx", ‪VERSION_SHIP, 1, "int" );
113  ‪clientfield::register( "helicopter", "deathfx", ‪VERSION_SHIP, 1, "int" );
114  ‪clientfield::register( "helicopter", "alert_level", ‪VERSION_SHIP, 2, "int" );
115  ‪clientfield::register( "helicopter", "set_lighting_ent", ‪VERSION_SHIP, 1, "int" );
116  ‪clientfield::register( "helicopter", "use_lighting_ent", ‪VERSION_SHIP, 1, "int" );
117  ‪clientfield::register( "helicopter", "damage_level", ‪VERSION_SHIP, 3, "int" );
118  ‪clientfield::register( "helicopter", "spawn_death_dynents", ‪VERSION_SHIP, 2, "int" );
119  ‪clientfield::register( "helicopter", "spawn_gib_dynents", ‪VERSION_SHIP, 1, "int" );
120 
121  ‪clientfield::register( "plane", "toggle_treadfx", ‪VERSION_SHIP, 1, "int" );
122 
123  ‪clientfield::register( "toplayer", "toggle_dnidamagefx", ‪VERSION_SHIP, 1, "int" );
124  ‪clientfield::register( "toplayer", "toggle_flir_postfx", ‪VERSION_SHIP, 2, "int" );
125 
126  ‪clientfield::register( "toplayer", "static_postfx", ‪VERSION_SHIP, 1, "int" );
127 
128  if(isdefined(level.bypassVehicleScripts))
129  {
130  return;
131  }
132 
133  level.heli_default_decel = 10;
134 
135  // put all the vehicles with targetnames into an array so we can spawn vehicles from
136  // a string instead of their vehicle group #
138 
139  // vehicle related dvar initializing goes here
140  ‪setup_dvars();
141 
142  // initialize all the level wide vehicle system variables
144 
145  // pre - associate vehicle triggers and vehicle nodes with stuff.
147 
148  ‪setup_nodes();
149 
150  // send the setup triggers to be processed
151  level array::thread_all_ents( level.vehicle_processtriggers, &‪trigger_process );
152 
153  // CHECKME
154  level.vehicle_processtriggers = undefined;
155 
156  // SCRIPTER_MOD: dguzzo: 3-9-09 : this looks to be used only for arcade mode. going to leave in the one cod:waw reference as an example.
157  // CODER_MOD: Tommy K
158  level.vehicle_enemy_tanks = [];
159  level.vehicle_enemy_tanks[ "vehicle_ger_tracked_king_tiger" ] = true;
160 
161  level thread ‪_watch_for_hijacked_vehicles();
162 
163 }
164 
165 function ‪__main__()
166 {
167  a_all_spawners = GetVehicleSpawnerArray();
168  ‪setup_spawners( a_all_spawners );
169 }
170 
171 // setup_script_gatetrigger( trigger, linkMap )
172 function ‪setup_script_gatetrigger( trigger )
173 {
174  gates = [];
175  if( isdefined( trigger.script_gatetrigger ) )
176  {
177  return level.vehicle_gatetrigger[ trigger.script_gatetrigger ];
178  }
179  return gates;
180 }
181 
182 function ‪trigger_process( trigger )
183 {
184  // these triggers only trigger once where vehicle paths trigger everytime a vehicle crosses them
185  if( isdefined( trigger.classname ) && ( trigger.classname == "trigger_multiple" || trigger.classname == "trigger_radius" || trigger.classname == "trigger_lookat" || trigger.classname == "trigger_box" ))
186  {
187  bTriggeronce = true;
188  }
189  else
190  {
191  bTriggeronce = false;
192  }
193 
194  // override to make a trigger loop
195  if( isdefined( trigger.script_noteworthy ) && trigger.script_noteworthy == "trigger_multiple" )
196  {
197  bTriggeronce = false;
198  }
199 
200  trigger.processed_trigger = undefined; // clear out this flag that was used to get the trigger to this point.
201 
202  gates = ‪setup_script_gatetrigger( trigger );
203 
204  // origin paths and script struct paths get this value
205  script_vehicledetour = isdefined( trigger.script_vehicledetour ) && ( ‪is_node_script_origin( trigger ) || ‪is_node_script_struct( trigger ) ) ;
206 
207  // ground paths get this value
208  detoured = isdefined( trigger.detoured ) && !( ‪is_node_script_origin( trigger ) || ‪is_node_script_struct( trigger ) );
209  gotrigger = true;
210 
211  while( gotrigger )
212  {
213  trigger ‪trigger::wait_till();
214  other = trigger.who;
215 
216 // bbarnes - starting to trim out things we probably don't need.
217 // if ( isdefined( trigger.script_vehicletriggergroup ) )
218 // {
219 // if( !isdefined( other.script_vehicletriggergroup ) )
220 // {
221 // continue;
222 // }
223 //
224 // if( isdefined(other) && other.script_vehicletriggergroup != trigger.script_vehicletriggergroup )
225 // {
226 // continue;
227 // }
228 // }
229 
230  if( isdefined( trigger.enabled ) && !trigger.enabled )
231  {
232  trigger waittill( "enable" );
233  }
234 
235  if ( isdefined( trigger.script_flag_set ) )
236  {
237  if ( isdefined(other) && isdefined( other.vehicle_flags ) )
238  {
239  other.vehicle_flags[ trigger.script_flag_set ] = true;
240  }
241 
242  if ( isdefined(other) )
243  {
244  other notify( "vehicle_flag_arrived", trigger.script_flag_set );
245  }
246 
247  level ‪flag::set( trigger.script_flag_set );
248  }
249 
250  if ( isdefined( trigger.script_flag_clear ) )
251  {
252  if ( isdefined(other) && isdefined( other.vehicle_flags ) )
253  {
254  other.vehicle_flags[ trigger.script_flag_clear ] = false;
255  }
256 
257  level ‪flag::clear( trigger.script_flag_clear );
258  }
259 
260  if( isdefined(other) && script_vehicledetour )
261  {
262  other thread ‪path_detour_script_origin( trigger );
263  }
264  else if ( detoured && isdefined( other ) )
265  {
266  other thread ‪path_detour( trigger );
267  }
268 
269  trigger ‪util::script_delay();
270 
271  if( bTriggeronce )
272  {
273  gotrigger = false;
274  }
275 
276  if ( isdefined( trigger.script_vehicleGroupDelete ) )
277  {
278  if( !isdefined( level.vehicle_DeleteGroup[ trigger.script_vehicleGroupDelete ] ) )
279  {
280  /#println( "failed to find deleteable vehicle with script_vehicleGroupDelete group number: ", trigger.script_vehicleGroupDelete );#/
281  level.vehicle_DeleteGroup[ trigger.script_vehicleGroupDelete ] = [];
282  }
283  array::delete_all( level.vehicle_DeleteGroup[ trigger.script_vehicleGroupDelete ] );
284  }
285 
286  if( isdefined( trigger.script_vehiclespawngroup ) )
287  {
288  level notify( "spawnvehiclegroup" + trigger.script_vehiclespawngroup );
289  level waittill( "vehiclegroup spawned" + trigger.script_vehiclespawngroup );
290  }
291 
292  if ( gates.size > 0 && bTriggeronce )
293  {
294  level array::thread_all_ents( gates,&‪path_gate_open );
295  }
296 
297  if ( isdefined( trigger ) && isdefined( trigger.script_VehicleStartMove ) )
298  {
299  if ( !isdefined( level.vehicle_StartMoveGroup[ trigger.script_VehicleStartMove ] ) )
300  {
301  /#println( "^3Vehicle start trigger is: ", trigger.script_VehicleStartMove );#/
302  return;
303  }
304 
305  foreach ( vehicle in ArrayCopy( level.vehicle_StartMoveGroup[ trigger.script_VehicleStartMove ] ) )
306  {
307  if ( isdefined( vehicle ) )
308  {
309  vehicle thread ‪go_path();
310  }
311  }
312  }
313  }
314 }
315 
316 function ‪path_detour_get_detourpath( detournode )
317 {
318  detourpath = undefined;
319  for( j = 0; j < level.vehicle_detourpaths[ detournode.script_vehicledetour ].size; j++ )
320  {
321  if( level.vehicle_detourpaths[ detournode.script_vehicledetour ][ j ] != detournode )
322  {
323  if( !‪islastnode( level.vehicle_detourpaths[ detournode.script_vehicledetour ][ j ] ) )
324  {
325  detourpath = level.vehicle_detourpaths[ detournode.script_vehicledetour ][ j ];
326  }
327  }
328  }
329 
330  return detourpath;
331 }
332 
333 function ‪path_detour_script_origin( detournode )
334 {
335  detourpath = ‪path_detour_get_detourpath( detournode );
336  if( isdefined( detourpath ) )
337  {
338  self thread ‪paths( detourpath );
339  }
340 }
341 
342 function ‪crash_detour_check( detourpath )
343 {
344  // long somewhat complex set of conditions on which a vehicle will detour through a crashpath.
345  return
346  (
347  isdefined( detourpath.script_crashtype )
348  &&
349  (
350  isdefined( self.deaddriver )
351  || self.health <= 0
352  || detourpath.script_crashtype == "forced"
353  )
354  &&
355  (
356  !isdefined( detourpath.derailed )
357  || ( isdefined( detourpath.script_crashtype ) && detourpath.script_crashtype == "plane" )
358  )
359  );
360 }
361 
362 function ‪crash_derailed_check( detourpath )
363 {
364  return isdefined( detourpath.derailed ) && detourpath.derailed;
365 }
366 
367 function ‪path_detour( node )
368 {
369  detournode = getvehiclenode( node.target, "targetname" );
370  detourpath = ‪path_detour_get_detourpath( detournode );
371 
372  // be more aggressive with this maybe?
373  if( !isdefined( detourpath ) )
374  {
375  return;
376  }
377 
378  if( node.detoured && !isdefined( detourpath.script_vehicledetourgroup ) )
379  {
380  return;
381  }
382 
383  if( ‪crash_detour_check( detourpath ) )
384  {
385  self notify( "crashpath", detourpath );
386  detourpath.derailed = 1;
387  self notify( "newpath" );
388  self setSwitchNode( node, detourpath );
389  return;
390  }
391  else
392  {
393  if( ‪crash_derailed_check( detourpath ) )
394  {
395  return; // .derailed crashpaths fail crash check. this keeps other vehicles from following.
396  }
397 
398  // detour paths specific to grouped vehicles. So they can share a lane and detour when they need to be exciting.
399  if( isdefined( detourpath.script_vehicledetourgroup ) )
400  {
401  if( !isdefined( self.script_vehicledetourgroup ) )
402  {
403  return;
404  }
405 
406  if( detourpath.script_vehicledetourgroup != self.script_vehicledetourgroup )
407  {
408  return;
409  }
410  }
411  }
412 }
413 
414 //PARAMETER CLEANUP
415 function ‪levelstuff( vehicle/*, trigger*/ )
416 {
417  // associate with links
418  if( isdefined( vehicle.script_linkname ) )
419  {
420  level.vehicle_link = ‪array_2d_add( level.vehicle_link, vehicle.script_linkname, vehicle );
421  }
422 
423  if( isdefined( vehicle.script_VehicleSpawngroup ) )
424  {
425  level.vehicle_SpawnGroup = ‪array_2d_add( level.vehicle_SpawnGroup, vehicle.script_VehicleSpawngroup, vehicle );
426  }
427 
428  if( isdefined( vehicle.script_VehicleStartMove ) )
429  {
430  level.vehicle_StartMoveGroup = ‪array_2d_add( level.vehicle_StartMoveGroup, vehicle.script_VehicleStartMove, vehicle );
431  }
432 
433  if( isdefined( vehicle.script_vehicleGroupDelete ) )
434  {
435  level.vehicle_DeleteGroup = ‪array_2d_add( level.vehicle_DeleteGroup, vehicle.script_vehicleGroupDelete, vehicle );
436  }
437 }
438 
439 function ‪_spawn_array( spawners )
440 {
442  return ai;
443 }
444 
446 {
447  living_ai = [];
448  for( i = 0; i < ai.size; i++ )
449  {
450  if ( !‪ai_should_be_added( ai[ i ] ) )
451  {
452  continue;
453  }
454 
455  living_ai[ living_ai.size ] = ai[ i ];
456  }
457  return living_ai;
458 }
459 
460 function ‪ai_should_be_added( ai )
461 {
462  if( isalive( ai ) )
463  {
464  return true;
465  }
466 
467  if ( !isdefined( ai ) )
468  {
469  return false;
470  }
471 
472  if ( !isdefined( ai.classname ) )
473  {
474  return false;
475  }
476 
477  return ai.classname == "script_model";
478 }
479 
480 function ‪sort_by_startingpos( guysarray )
481 {
482  firstarray = [];
483  secondarray = [];
484 
485  for ( i = 0 ; i < guysarray.size ; i++ )
486  {
487  if ( isdefined( guysarray[ i ].script_startingposition ) )
488  {
489  firstarray[ firstarray.size ] = guysarray[ i ];
490  }
491  else
492  {
493  secondarray[ secondarray.size ] = guysarray[ i ];
494  }
495  }
496 
497  return ArrayCombine( firstarray, secondarray, true, false );
498 }
499 
500 function ‪rider_walk_setup( vehicle )
501 {
502  if ( !isdefined( self.script_vehiclewalk ) )
503  {
504  return;
505  }
506 
507  if ( isdefined( self.script_followmode ) )
508  {
509  self.FollowMode = self.script_followmode;
510  }
511  else
512  {
513  self.FollowMode = "cover nodes";
514  }
515 
516  // check if the AI should go to a node after walking with the vehicle
517  if ( !isdefined( self.target ) )
518  {
519  return;
520  }
521 
522  node = getnode( self.target, "targetname" );
523  if( isdefined( node ) )
524  {
525  self.NodeAftervehicleWalk = node;
526  }
527 }
528 
530 {
531  realdetournode = getvehiclenode( node.targetname, "target" );
532  if( !isdefined( realdetournode ) )
533  {
534  return;
535  }
536 
537  realdetournode.detoured = 0;
538  ‪add_proccess_trigger( realdetournode );
539 }
540 
541 function ‪add_proccess_trigger( trigger )
542 {
543  // TODO: next game. stop trying to make everything a trigger. remove trigger process. I'd do it this game but there is too much complexity in Detour nodes.
544  // .processedtrigger is a flag that I set to keep a trigger from getting added twice.
545  if( isdefined( trigger.processed_trigger ) )
546  {
547  return;
548  }
549 
550  ‪ARRAY_ADD( level.vehicle_processtriggers, trigger );
551  trigger.processed_trigger = true;
552 }
553 
554 function ‪islastnode( node )
555 {
556  if( !isdefined( node.target ) )
557  {
558  return true;
559  }
560 
561  if( !isdefined( getvehiclenode( node.target, "targetname" ) ) && !isdefined( ‪get_vehiclenode_any_dynamic( node.target ) ) )
562  {
563  return true;
564  }
565 
566  return false;
567 }
568 
569 function ‪paths( node )
570 {
571  self endon( "death" );
572 
573  assert( isdefined( node ) || isdefined( self.attachedpath ), "vehicle_path() called without a path" );
574  self notify( "newpath" );
575 
576  // dynamicpaths unique. node isn't defined by info vehicle node calls to this function
577  if( isdefined( node ) )
578  {
579  self.attachedpath = node;
580  }
581 
582  pathstart = self.attachedpath;
583  self.currentNode = self.attachedpath;
584 
585  if ( !isdefined( pathstart ) )
586  {
587  return;
588  }
589 
590  self endon( "newpath" );
591 
592  currentPoint = pathstart;
593 
594  while ( isdefined( currentPoint ) )
595  {
596  self waittill( "reached_node", currentPoint );
597 
598  currentPoint ‪enable_turrets( self );
599 
600  if ( !isdefined( self ) )
601  {
602  return;
603  }
604 
605  self.currentNode = currentPoint;
606  self.nextNode = ( isdefined( currentPoint.target ) ? GetVehicleNode( currentPoint.target, "targetname" ) : undefined );
607 
608  if ( isdefined( currentPoint.gateopen ) && !currentPoint.gateopen )
609  {
610  // threaded because vehicle may setspeed( 0, 15 ) and run into the next node
611  self thread ‪path_gate_wait_till_open( currentPoint );
612  }
613 
614  currentPoint notify( "trigger", self );
615 
616  // SRS 05/03/07: added for _planeweapons to drop bombs
617  // amount, delay, delay trace
618  if( isdefined( currentPoint.script_dropbombs ) && currentPoint.script_dropbombs > 0 )
619  {
620  amount = currentPoint.script_dropbombs;
621  ‪delay = 0;
622  delaytrace = 0;
623 
624  if( isdefined( currentPoint.script_dropbombs_delay ) && currentPoint.script_dropbombs_delay > 0 )
625  {
626  ‪delay = currentPoint.script_dropbombs_delay;
627  }
628 
629  if( isdefined( currentPoint.script_dropbombs_delaytrace ) && currentPoint.script_dropbombs_delaytrace > 0 )
630  {
631  delaytrace = currentPoint.script_dropbombs_delaytrace;
632  }
633 
634  self notify( "drop_bombs", amount, ‪delay, delaytrace );
635  }
636 
637  if ( isdefined( currentPoint.script_noteworthy ) )
638  {
639  self notify( currentPoint.script_noteworthy );
640  self notify( "noteworthy", currentPoint.script_noteworthy );
641  }
642 
643  if ( isdefined( currentPoint.script_notify) )
644  {
645  self notify( currentPoint.script_notify );
646  level notify( currentPoint.script_notify );
647  }
648 
649  waittillframeend; // this lets other scripts interupt
650 
651  if ( !isdefined( self ) )
652  {
653  return;
654  }
655 
656  if ( ‪IS_TRUE( currentPoint.script_delete ) )
657  {
658  if ( isdefined( self.riders ) && self.riders.size > 0 )
659  {
660  array::delete_all( self.riders );
661  }
662 
663  ‪VEHICLE_DELETE( self );
664  return;
665  }
666 
667  if( isdefined( currentPoint.script_sound ) )
668  {
669  self playsound( currentPoint.script_sound );
670  }
671 
672  if ( isdefined( currentPoint.script_noteworthy ) )
673  {
674  if ( currentPoint.script_noteworthy == "godon" )
675  {
676  self ‪god_on();
677  }
678  else if ( currentPoint.script_noteworthy == "godoff" )
679  {
680  self ‪god_off();
681  }
682  else if ( currentPoint.script_noteworthy == "drivepath" )
683  {
684  self DrivePath(); // this will auto tilt and stuff for helicopters
685  }
686  else if ( currentPoint.script_noteworthy == "lockpath" )
687  {
688  self StartPath(); // this will stop the auto tilting and lock the heli back on the spline
689  }
690  else if ( currentPoint.script_noteworthy == "brake" )
691  {
692  if ( self.isphysicsvehicle )
693  {
694  self SetBrake( true );
695  }
696 
697  self SetSpeed( 0, 60, 60 );
698  }
699  else if ( currentPoint.script_noteworthy == "resumespeed" )
700  {
701  accel = 30;
702  if ( isdefined( currentPoint.script_float ) )
703  {
704  accel = currentPoint.script_float;
705  }
706  self ResumeSpeed( accel );
707  }
708  }
709 
710  if ( isdefined( currentPoint.script_crashtypeoverride ) )
711  {
712  self.script_crashtypeoverride = currentPoint.script_crashtypeoverride;
713  }
714 
715  if ( isdefined( currentPoint.script_badplace ) )
716  {
717  self.script_badplace = currentPoint.script_badplace;
718  }
719 
720  if ( isdefined( currentPoint.script_team ) )
721  {
722  self.team = currentPoint.script_team;
723  }
724 
725  if ( isdefined( currentPoint.script_turningdir ) )
726  {
727  self notify( "turning", currentPoint.script_turningdir );
728  }
729 
730  if ( isdefined( currentPoint.script_deathroll ) )
731  {
732  if ( currentPoint.script_deathroll == 0 )
733  {
734  self thread ‪vehicle_death::deathrolloff();
735  }
736  else
737  {
738  self thread ‪vehicle_death::deathrollon();
739  }
740  }
741 
742  if ( isdefined( currentPoint.script_exploder ) )
743  {
744  ‪exploder::exploder( currentPoint.script_exploder );
745  }
746 
747  if ( isdefined( currentPoint.script_flag_set ) )
748  {
749  if ( isdefined( self.vehicle_flags ) )
750  {
751  self.vehicle_flags[ currentPoint.script_flag_set ] = true;
752  }
753 
754  self notify( "vehicle_flag_arrived", currentPoint.script_flag_set );
755  level ‪flag::set( currentPoint.script_flag_set );
756  }
757 
758  if ( isdefined( currentPoint.script_flag_clear ) )
759  {
760  if ( isdefined( self.vehicle_flags ) )
761  {
762  self.vehicle_flags[ currentPoint.script_flag_clear ] = false;
763  }
764 
765  level ‪flag::clear( currentPoint.script_flag_clear );
766  }
767 
768  if ( ‪IS_HELICOPTER( self ) && isdefined( self.drivepath ) && self.drivepath == 1 )
769  {
770  if ( isdefined( self.nextNode ) && self.nextNode ‪is_unload_node() )
771  {
772  ‪unload_node_helicopter( undefined );
773  self.attachedpath = self.nextNode;
774  self DrivePath( self.attachedpath );
775  }
776  }
777  else
778  {
779  if ( currentPoint ‪is_unload_node() )
780  {
781  ‪unload_node( currentPoint );
782  }
783  }
784 
785  if ( isdefined( currentPoint.script_wait ) )
786  {
787  ‪pause_path();
788  currentPoint ‪util::script_wait();
789  }
790 
791  if ( isdefined( currentPoint.script_waittill ) )
792  {
793  ‪pause_path();
794  ‪util::waittill_any_ents( self, currentPoint.script_waittill, level, currentPoint.script_waittill );
795  }
796 
797  if( isdefined( currentPoint.script_flag_wait ) )
798  {
799  if ( !isdefined( self.vehicle_flags ) )
800  {
801  self.vehicle_flags = [];
802  }
803 
804  self.vehicle_flags[ currentPoint.script_flag_wait ] = true;
805  self notify( "vehicle_flag_arrived", currentPoint.script_flag_wait );
806  self ‪flag::set( "waiting_for_flag" );
807 
808  // helicopters stop on their own because they know to stop at destination for script_flag_wait
809  // may have to provide a smoother way to stop and go tho, this is rather arbitrary, for tanks
810  // in this case
811 
812  if ( !level ‪flag::get( currentPoint.script_flag_wait ) )
813  {
814  ‪pause_path();
815  level ‪flag::wait_till( currentPoint.script_flag_wait );
816  }
817 
818  self ‪flag::clear( "waiting_for_flag" );
819  }
820 
821  if ( isdefined( self.set_lookat_point ) )
822  {
823  self.set_lookat_point = undefined;
824  self clearLookAtEnt();
825  }
826 
827  if ( isdefined( currentPoint.script_lights_on ) )
828  {
829  if ( currentPoint.script_lights_on )
830  {
831  self ‪lights_on();
832  }
833  else
834  {
835  self ‪lights_off();
836  }
837  }
838 
839  if ( isdefined( currentPoint.script_stopnode ) )
840  {
841  self ‪set_goal_pos( currentPoint.origin, true );
842  }
843 
844  if ( isdefined( self.switchNode ) )
845  {
846  if ( currentPoint == self.switchNode )
847  {
848  self.switchNode = undefined;
849  }
850  }
851  else
852  {
853  if ( !isdefined( currentPoint.target ) )
854  {
855  break;
856  }
857  }
858 
859  ‪resume_path();
860  }
861 
862  self notify( "reached_dynamic_path_end" );
863 
864  if ( isdefined( self.script_delete ) )
865  {
866  self Delete();
867  }
868 }
869 
870 function ‪pause_path()
871 {
872  if ( !‪IS_TRUE( self.vehicle_paused ) )
873  {
874  if ( self.isphysicsvehicle )
875  {
876  self SetBrake( true );
877  }
878 
879  if ( ‪IS_HELICOPTER( self ) )
880  {
881  if ( ‪IS_TRUE( self.drivepath ) )
882  {
883  // hover
884  self SetVehGoalPos( self.origin, true );
885  }
886  else
887  {
888  self SetSpeed( 0, 100, 100 );
889  }
890  }
891  else
892  {
893  self SetSpeed( 0, 35, 35 );
894  }
895 
896  self.vehicle_paused = true;
897  }
898 }
899 
900 function ‪resume_path()
901 {
902  if ( ‪IS_TRUE( self.vehicle_paused ) )
903  {
904  if ( self.isphysicsvehicle )
905  {
906  self SetBrake( false );
907  }
908 
909  if ( ‪IS_HELICOPTER( self ) )
910  {
911  if ( ‪IS_TRUE( self.drivepath ) )
912  {
913  // stop hovering and get back on path
914  self DrivePath( self.currentNode );
915  }
916 
917  self ResumeSpeed( 100 );
918  }
919  else
920  {
921  self ResumeSpeed( 35 );
922  }
923 
924  self.vehicle_paused = undefined;
925  }
926 }
927 
938 function ‪get_on_path( path_start, str_key = "targetname" ) // self == vehicle
939 {
940  if( IsString( path_start ) )
941  {
942  path_start = GetVehicleNode( path_start, str_key );
943  }
944 
945  if( !isdefined( path_start ) )
946  {
947  if( isdefined( self.targetname ) )
948  {
949  AssertMsg( "Start Node not defined for vehicle: " + self.targetname );
950  }
951  else
952  {
953  AssertMsg( "Start Node not defined for vehicle: " + self.targetname );
954  }
955  }
956 
957  //[ceng 4/26/2010] If a vehicle previously used _utility::go_path() then .hasstarted
958  //would be set but never cleared, preventing the vehicle from using _utility::go_path()
959  //again. This allows the vehicle to follow more paths beyond their first.
960  if( isdefined( self.hasstarted ) )
961  {
962  self.hasstarted = undefined;
963  }
964 
965  self.attachedpath = path_start;
966 
967  if ( !‪IS_TRUE( self.drivepath ) )
968  {
969  //self.origin = path_start.origin;
970  self AttachPath( path_start );
971  }
972 
973  if( self.disconnectPathOnStop === true && !IsSentient(self) )
974  {
975  self ‪vehicle::disconnect_paths( self.disconnectPathDetail );
976  }
977 
978  if (‪IS_TRUE(self.isphysicsvehicle))
979  {
980  self SetBrake(true);
981  }
982 
983  self thread ‪paths();
984 }
985 
986 function ‪get_off_path()
987 {
988  self CancelAIMove();
989  self ClearVehGoalPos();
990 }
991 
992 
1005 {
1006  vehicleArray = ‪_scripted_spawn( spawnGroup );
1007  for( i = 0; i < vehicleArray.size; i++ )
1008  {
1009  if (isdefined(vehicleArray[ i ]))
1010  {
1011  vehicleArray[ i ] thread ‪vehicle::go_path();
1012  }
1013  }
1014  return vehicleArray;
1015 }
1016 
1027 function ‪get_on_and_go_path(path_start) // self == vehicle
1028 {
1029  // get_on_path will attach us to the path and allow us to get script_noteworthy notifies from nodes
1030  self ‪vehicle::get_on_path(path_start);
1031 
1032  // go_path starts us on the path
1033  self ‪vehicle::go_path();
1034 }
1035 
1036 // AE 5-15-09: cleaned up by taking out the vehicle parameter and just having the vehicle as self
1037 function ‪go_path() // self == vehicle
1038 {
1039  self endon( "death" );
1040  self endon( "stop path" );
1041 
1042  if( self.isphysicsvehicle )
1043  {
1044  self SetBrake(false);
1045  }
1046 
1047  if( isdefined( self.script_vehiclestartmove ) )
1048  {
1049  ArrayRemoveValue( level.vehicle_StartMoveGroup[ self.script_vehiclestartmove ], self );
1050  }
1051 
1052  if( isdefined( self.hasstarted ) )
1053  {
1054  /#println( "vehicle already moving when triggered with a startmove" );#/
1055  return;
1056  }
1057  else
1058  {
1059  self.hasstarted = true;
1060  }
1061 
1062  self ‪util::script_delay();
1063 
1064  self notify( "start_vehiclepath" );
1065 
1066  if ( ‪IS_TRUE( self.drivepath ) )
1067  {
1068  self DrivePath( self.attachedpath );
1069  }
1070  else
1071  {
1072  self StartPath();
1073  }
1074 
1075  // start waiting for the end of the path
1076  wait .05;
1078 
1079  self waittill( "reached_end_node" );
1080 
1081  if ( self.disconnectPathOnStop === true && !IsSentient( self ) )
1082  {
1083  self ‪vehicle::disconnect_paths( self.disconnectPathDetail );
1084  }
1085 
1086  if( isdefined( self.currentnode ) && isdefined( self.currentnode.script_noteworthy ) && self.currentnode.script_noteworthy == "deleteme" )
1087  {
1088  return;
1089  }
1090 }
1091 
1092 function ‪path_gate_open( node )
1093 {
1094  node.gateopen = true;
1095  node notify( "gate opened" );
1096 }
1097 
1098 function ‪path_gate_wait_till_open( pathspot )
1099 {
1100  self endon( "death" );
1101  self.waitingforgate = true;
1102  self ‪set_speed( 0, 15, "path gate closed" );
1103  pathspot waittill( "gate opened" );
1104  self.waitingforgate = false;
1105 
1106  if( self.health > 0 )
1107  {
1108  ‪script_resume_speed( "gate opened", level.vehicle_ResumeSpeed );
1109  }
1110 }
1111 
1112 function ‪_spawn_group( spawngroup )
1113 {
1114  while( 1 )
1115  {
1116  // waittill we get a notify for our group
1117  level waittill( "spawnvehiclegroup" + spawngroup );
1118 
1119  spawned_vehicles = [];
1120 
1121  // for all spawners in the group
1122  for( i = 0; i < level.vehicle_spawners[ spawngroup ].size; i++ )
1123  {
1124  // spawn the vehicle
1125  spawned_vehicles[ spawned_vehicles.size ] = ‪_vehicle_spawn( level.vehicle_spawners[ spawngroup ][ i ] );
1126  }
1127 
1128  // notify we spawned and pass back spawned vehicles
1129  level notify( "vehiclegroup spawned" + spawngroup, spawned_vehicles );
1130  }
1131 }
1132 
1144 function ‪_scripted_spawn( group )
1145 {
1146  thread ‪_scripted_spawn_go( group );
1147  level waittill( "vehiclegroup spawned" + group, vehicles );
1148  return vehicles;
1149 }
1150 
1151 function ‪_scripted_spawn_go( group )
1152 {
1153  waittillframeend;
1154  level notify( "spawnvehiclegroup" + group );
1155 }
1156 
1157 function ‪set_variables( vehicle )
1158 {
1159  if ( isdefined( vehicle.script_deathflag ) )
1160  {
1161  if ( !level ‪flag::exists( vehicle.script_deathflag ) )
1162  {
1163  level ‪flag::init( vehicle.script_deathflag );
1164  }
1165  }
1166 }
1167 
1168 //TODO T7 - set up a think function and send out a notify once we get a callback so vehicle spawning is similar to AI spawning
1169 function ‪_vehicle_spawn( vspawner, from )
1170 {
1171  if( !isdefined( vspawner ) || !vspawner.count )
1172  {
1173  return;
1174  }
1175 
1176  str_targetname = undefined;
1177  if( isdefined( vspawner.targetname ) )
1178  {
1179  str_targetname = vspawner.targetname + "_vh";
1180  }
1181 
1183 
1184  if( !isdefined( vspawner ) || !vspawner.count )
1185  {
1186  return;
1187  }
1188 
1189  vehicle = vspawner SpawnFromSpawner( str_targetname, true );
1190 
1191  //failed to spawn a vehicle.
1192  if ( !isdefined( vehicle ) )
1193  {
1194  return;
1195  }
1196 
1197  //TODO T7 - bring over _destructible to CP
1198  /*if( isdefined( vehicle.destructibledef ) )
1199  {
1200  vehicle thread destructible::destructible_think();
1201  }*/
1202 
1203  if ( isdefined( vspawner.script_team ) )
1204  {
1205  vehicle SetTeam( vspawner.script_team );
1206  }
1207 
1208  if ( isdefined( vehicle.lockheliheight ) )
1209  {
1210  vehicle SetHeliHeightLock( vehicle.lockheliheight );
1211  }
1212 
1213  if( isdefined( vehicle.targetname ) )
1214  {
1215  level notify( "new_vehicle_spawned" + vehicle.targetname, vehicle );
1216  }
1217 
1218  if( isdefined( vehicle.script_noteworthy ) )
1219  {
1220  level notify( "new_vehicle_spawned" + vehicle.script_noteworthy, vehicle );
1221  }
1222 
1223  if( isdefined(vehicle.script_animname))
1224  {
1225  vehicle.animname = vehicle.script_animname;
1226  }
1227 
1228  if ( isdefined( vehicle.script_animscripted ) )
1229  {
1230  vehicle.supportsAnimScripted = vehicle.script_animscripted;
1231  }
1232 
1233  return vehicle;
1234 }
1235 
1236 function ‪init( vehicle )
1237 {
1238  ‪callback::callback( #"on_vehicle_spawned" );
1239 
1240  vehicle UseAnimTree( #animtree );
1241 
1242  if ( isdefined( vehicle.e_dyn_path ) )
1243  {
1244  vehicle.e_dyn_path LinkTo( vehicle );
1245  }
1246 
1247  vehicle ‪flag::init("waiting_for_flag");
1248  vehicle.takedamage = !‪IS_TRUE(vehicle.script_godmode);
1249 
1250  vehicle.zerospeed = true;
1251 
1252  if( !isdefined( vehicle.modeldummyon ) )
1253  {
1254  vehicle.modeldummyon = false;
1255  }
1256 
1257  if ( ‪IS_TRUE( vehicle.isphysicsvehicle ) )
1258  {
1259  if ( ‪IS_TRUE( vehicle.script_brake ) )
1260  {
1261  vehicle SetBrake( true );
1262  }
1263  }
1264 
1265  type = vehicle.vehicletype;
1266 
1267  // give the vehicle health
1268  vehicle ‪_vehicle_life();
1269 
1270  vehicle thread ‪maingun_fx();
1271 
1272  // getoutrig means fastrope.
1273  vehicle.getoutrig = [];
1274  if( isdefined( level.vehicle_attachedmodels ) && isdefined( level.vehicle_attachedmodels[ type ] ) )
1275  {
1276  rigs = level.vehicle_attachedmodels[ type ];
1277  strings = getarraykeys( rigs );
1278  for( i = 0; i < strings.size; i++ )
1279  {
1280  vehicle.getoutrig[ strings[ i ] ] = undefined;
1281  vehicle.getoutriganimating[ strings[ i ] ] = false;
1282  }
1283  }
1284 
1285  // make ai run way from vehicle
1286  if( isdefined( self.script_badplace ) )
1287  {
1288  vehicle thread ‪_vehicle_bad_place();
1289  }
1290 
1291  if ( isdefined( vehicle.scriptbundlesettings ) )
1292  {
1293  settings = ‪struct::get_script_bundle( "vehiclecustomsettings", vehicle.scriptbundlesettings );
1294 
1295  if ( isdefined( settings ) && isdefined( settings.lightgroups_numGroups ) )
1296  {
1297  if ( settings.lightgroups_numGroups >= 1 && settings.lightgroups_1_always_on === true )
1298  {
1299  vehicle ‪toggle_lights_group( 1, true );
1300  }
1301  if ( settings.lightgroups_numGroups >= 2 && settings.lightgroups_2_always_on === true )
1302  {
1303  vehicle ‪toggle_lights_group( 2, true );
1304  }
1305  if ( settings.lightgroups_numGroups >= 3 && settings.lightgroups_3_always_on === true )
1306  {
1307  vehicle ‪toggle_lights_group( 3, true );
1308  }
1309  if ( settings.lightgroups_numGroups >= 4 && settings.lightgroups_4_always_on === true )
1310  {
1311  vehicle ‪toggle_lights_group( 4, true );
1312  }
1313  }
1314  }
1315 
1316  // regenerate friendly fire damage
1317  if( !vehicle ‪is_cheap() )
1318  {
1319  vehicle ‪friendly_fire_shield();
1320  }
1321 
1322  // handles guys riding and doing stuff on vehicles
1323 // vehicle thread vehicle_aianim::handle_attached_guys();
1324 
1325  // make vehicle shake physics objects.
1326  if( isdefined( vehicle.script_physicsjolt ) && vehicle.script_physicsjolt )
1327  {
1328  //T7 - Request from code to get this ability back if needed
1329  }
1330 
1331  // associate vehicle with living level variables.
1332  ‪levelstuff( vehicle );
1333 
1334  if ( ‪IS_ARTILLERY( vehicle ) )
1335  {
1336  vehicle.disconnectPathOnStop = undefined;
1337  self ‪vehicle::disconnect_paths( 0 );
1338  }
1339  else
1340  {
1341  vehicle.disconnectPathOnStop = self.script_disconnectpaths;
1342  }
1343 
1344  vehicle.disconnectPathDetail = self.script_disconnectpath_detail;
1345  if ( !isdefined( vehicle.disconnectPathDetail ) )
1346  {
1347  vehicle.disconnectPathDetail = 0;
1348  }
1349 
1350  // every vehicle that stops will disconnect its paths
1351  if( !vehicle ‪is_cheap() && !‪IS_PLANE(vehicle) && !‪IS_ARTILLERY( vehicle ) )
1352  {
1353  vehicle thread ‪_disconnect_paths_when_stopped();
1354  }
1355 
1356  if ( !isdefined( vehicle.script_nonmovingvehicle ) )
1357  {
1358  if ( isdefined( vehicle.target ) )
1359  {
1360  path_start = GetVehicleNode( vehicle.target, "targetname" );
1361  if ( !isdefined( path_start ) )
1362  {
1363  path_start = GetEnt(vehicle.target, "targetname" );
1364  if ( !isdefined( path_start ) )
1365  {
1366  path_start = ‪struct::get( vehicle.target, "targetname" );
1367  }
1368  }
1369  }
1370 
1371  if ( isdefined( path_start ) && vehicle.vehicletype != "inc_base_jump_spotlight" )
1372  {
1373  vehicle thread ‪get_on_path( path_start );
1374  }
1375  }
1376 
1377  if ( isdefined( vehicle.script_vehicleattackgroup ) )
1378  {
1379  vehicle thread attack_group_think();
1380  }
1381 
1382  // helicopters do dust kickup fx
1383  if( vehicle ‪has_helicopter_dust_kickup() )
1384  {
1385  if(!level.clientscripts)
1386  {
1387  vehicle thread ‪aircraft_dust_kickup();
1388  }
1389  }
1390 
1391  // spawn the vehicle and it's associated ai
1392  //vehicle spawn_ai_group();
1393  vehicle thread ‪vehicle_death::main();
1394 
1395  // Set myself as a target if specificed
1396  if ( isdefined( vehicle.script_targetset ) && vehicle.script_targetset == 1 )
1397  {
1398  offset = ( 0, 0, 0 );
1399  if ( isdefined( vehicle.script_targetoffset ) )
1400  {
1401  offset = vehicle.script_targetoffset;
1402  }
1403 
1404  Target_Set( vehicle, offset );
1405  }
1406 
1407  if ( ‪IS_TRUE( vehicle.script_vehicleavoidance ) )
1408  {
1409  vehicle SetVehicleAvoidance( true );
1410  }
1411 
1412  vehicle ‪enable_turrets();
1413 
1414  if( isdefined( level.vehicleSpawnCallbackThread ) )
1415  {
1416  level thread [[ level.vehicleSpawnCallbackThread ]]( vehicle );
1417  }
1418 }
1419 
1421 {
1422  if ( !isdefined( self.getoutrig ) )
1423  return;
1424  if ( ! self.getoutrig.size )
1425  return;
1426  keys = GetArrayKeys( self.getoutrig );
1427  for ( i = 0; i < keys.size; i++ )
1428  {
1429  self.getoutrig[ keys[ i ] ] Unlink();
1430  }
1431 }
1432 
1433 function ‪enable_turrets( veh )
1434 {
1435  if ( !isdefined( veh ) )
1436  {
1437  veh = self;
1438  }
1439 
1440  if ( ‪IS_TRUE( self.script_enable_turret0 ) )
1441  {
1442  veh ‪turret::enable( 0 );
1443  }
1444 
1445  if ( ‪IS_TRUE( self.script_enable_turret1 ) )
1446  {
1447  veh ‪turret::enable( 1 );
1448  }
1449 
1450  if ( ‪IS_TRUE( self.script_enable_turret2 ) )
1451  {
1452  veh ‪turret::enable( 2 );
1453  }
1454 
1455  if ( ‪IS_TRUE( self.script_enable_turret3 ) )
1456  {
1457  veh ‪turret::enable( 3 );
1458  }
1459 
1460  if ( ‪IS_TRUE( self.script_enable_turret4 ) )
1461  {
1462  veh ‪turret::enable( 4 );
1463  }
1464 
1465  if ( isdefined( self.script_enable_turret0 ) && !self.script_enable_turret0 )
1466  {
1467  veh ‪turret::disable( 0 );
1468  }
1469 
1470  if ( isdefined( self.script_enable_turret1 ) && !self.script_enable_turret1 )
1471  {
1472  veh ‪turret::disable( 1 );
1473  }
1474 
1475  if ( isdefined( self.script_enable_turret2 ) && !self.script_enable_turret2 )
1476  {
1477  veh ‪turret::disable( 2 );
1478  }
1479 
1480  if ( isdefined( self.script_enable_turret3 ) && !self.script_enable_turret3 )
1481  {
1482  veh ‪turret::disable( 3 );
1483  }
1484 
1485  if ( isdefined( self.script_enable_turret4 ) && !self.script_enable_turret4 )
1486  {
1487  veh ‪turret::disable( 4 );
1488  }
1489 }
1490 
1491 // self == vehicle
1493 {
1494  self notify( "kill_disconnect_paths_forever" );
1495  self.disconnectPathOnStop = false;
1496  self thread ‪_disconnect_paths_when_stopped();
1497 }
1498 
1500 {
1501  if( IsPathfinder( self) )
1502  {
1503  self.disconnectPathOnStop = false;// lets other parts of the script know not to disconnect script
1504  return;
1505  }
1506 
1507  if ( isdefined( self.script_disconnectpaths ) && !self.script_disconnectpaths )
1508  {
1509  self.disconnectPathOnStop = false;// lets other parts of the script know not to disconnect script
1510  return;
1511  }
1512 
1513  self endon( "death" );
1514  self endon( "kill_disconnect_paths_forever" );
1515 
1516  wait 1;
1517  threshold = 3;
1518 
1519  while ( isdefined( self ) )
1520  {
1521  if ( LengthSquared( self.velocity ) < ‪SQR( threshold ) )
1522  {
1523  if ( self.disconnectPathOnStop === true )
1524  {
1525  self ‪vehicle::disconnect_paths( self.disconnectPathDetail );
1526  self notify( "speed_zero_path_disconnect" );
1527  }
1528 
1529  while( LengthSquared( self.velocity ) < ‪SQR( threshold ) )
1530  {
1531  wait 0.05;
1532  }
1533  }
1534 
1536 
1537  while( LengthSquared( self.velocity ) >= ‪SQR( threshold ) )
1538  {
1539  wait 0.05;
1540  }
1541  }
1542 }
1543 
1544 //function disconnect_paths_while_moving( interval )
1545 //{
1546 // if( IsSentient( self) )
1547 // {
1548 // return;
1549 // }
1550 //
1551 // if ( isdefined( self.script_disconnectpaths ) && !self.script_disconnectpaths )
1552 // {
1553 // self.disconnectPathOnStop = true;// lets other parts of the script know not to disconnect script
1554 // return;
1555 // }
1556 //
1557 // self endon( "death" );
1558 // self endon( "kill_disconnect_paths_forever" );
1559 //
1560 // while ( isdefined( self ) )
1561 // {
1562 // if ( Length( self.velocity ) > 1 )
1563 // {
1564 // if ( !isdefined( self.disconnectPathOnStop ) )
1565 // {
1566 // //self vehicle::connect_paths();
1567 // self vehicle::disconnect_paths();
1568 // }
1569 //
1570 // self notify( "moving_path_disconnect" );
1571 // }
1572 //
1573 // wait interval;
1574 // }
1575 //}
1576 
1577 function ‪set_speed( speed, rate, msg )
1578 {
1579  if( self getspeedmph() == 0 && speed == 0 )
1580  {
1581  return; // potential for disaster? keeps messages from overriding previous messages
1582  }
1583 
1584  /#
1585  self thread ‪debug_set_speed( speed, rate, msg );
1586  #/
1587  self setspeed( speed, rate );
1588 }
1589 
1590 function ‪debug_set_speed( speed, rate, msg )
1591 {
1592  /#
1593  self notify( "new debug_vehiclesetspeed" );
1594  self endon( "new debug_vehiclesetspeed" );
1595  self endon( "resuming speed" );
1596  self endon( "death" );
1597  while( 1 )
1598  {
1599  while( GetDvarString( "debug_vehiclesetspeed" ) != "off" )
1600  {
1601  print3d( self.origin + ( 0, 0, 192 ), "vehicle setspeed: " + msg, ( 1, 1, 1 ), 1, 3 );
1602  wait .05;
1603  }
1604  wait .5;
1605  }
1606  #/
1607 }
1608 
1609 function ‪script_resume_speed( msg, rate )
1610 {
1611  self endon( "death" );
1612  fSetspeed = 0;
1613  type = "resumespeed";
1614  if( !isdefined( self.resumemsgs ) )
1615  {
1616  self.resumemsgs = [];
1617  }
1618  if( isdefined( self.waitingforgate ) && self.waitingforgate )
1619  {
1620  return; // ignore resumespeeds on waiting for gate.
1621  }
1622 
1623  if( isdefined( self.attacking ) && self.attacking )
1624  {
1625  fSetspeed = self.attackspeed;
1626  type = "setspeed";
1627  }
1628 
1629  self.zerospeed = false;
1630  if( fSetspeed == 0 )
1631  {
1632  self.zerospeed = true;
1633  }
1634  if( type == "resumespeed" )
1635  {
1636  self resumespeed( rate );
1637  }
1638  else if( type == "setspeed" )
1639  {
1640  self ‪set_speed( fSetspeed, 15, "resume setspeed from attack" );
1641  }
1642  self notify( "resuming speed" );
1643 
1644 }
1645 
1647 {
1648  self notify( "newresumespeedmsag" );
1649  self endon( "newresumespeedmsag" );
1650  self endon( "death" );
1651  while( gettime() < ‪timer && isdefined( self.resumemsgs ) )
1652  {
1653  if( self.resumemsgs.size > 6 )
1654  {
1655  start = self.resumemsgs.size - 5;
1656  }
1657  else
1658  {
1659  start = 0;
1660  }
1661  for( i = start; i < self.resumemsgs.size; i++ ) // only display last 5 messages
1662  {
1663  position = i * 32;
1664  /#print3d( self.origin + ( 0, 0, position ), "resuming speed: " + self.resumemsgs[ i ], ( 0, 1, 0 ), 1, 3 );#/
1665  }
1666  wait .05;
1667  }
1668 }
1669 
1670 function ‪god_on()
1671 {
1672  self.takedamage = false;
1673 }
1674 
1675 function ‪god_off()
1676 {
1677  self.takedamage = true;
1678 }
1679 
1680 function ‪get_normal_anim_time( animation )
1681 {
1682  animtime = self getanimtime( animation );
1683  animlength = getanimlength( animation );
1684  if( animtime == 0 )
1685  {
1686  return 0;
1687  }
1688  return self getanimtime( animation ) / getanimlength( animation );
1689 }
1690 
1691 function ‪setup_dynamic_detour( pathnode , get_func )
1692 {
1693  prevnode = [[ get_func ]]( pathnode.targetname );
1694  assert( isdefined( prevnode ), "detour can't be on start node" );
1695  prevnode.detoured = 0;
1696 }
1697 
1698  /*
1699 function setup_origins()
1700 {
1701  triggers = [];
1702  origins = getentarray( "script_origin", "classname" );
1703  for( i = 0; i < origins.size; i++ )
1704  {
1705  if( isdefined( origins[ i ].script_vehicledetour ) )
1706  {
1707 
1708  level.vehicle_detourpaths = array_2d_add( level.vehicle_detourpaths, origins[ i ].script_vehicledetour, origins[ i ] );
1709  if( level.vehicle_detourpaths[ origins[ i ].script_vehicledetour ].size > 2 )
1710  println( "more than two script_vehicledetour grouped in group number: ", origins[ i ].script_vehicledetour );
1711 
1712  prevnode = getent( origins[ i ].targetname, "target" );
1713  assert( isdefined( prevnode ), "detour can't be on start node" );
1714  triggers[ triggers.size ] = prevnode;
1715  prevnode.detoured = 0;
1716  prevnode = undefined;
1717  }
1718  }
1719  return triggers;
1720 }
1721  */
1722 
1723 function ‪array_2d_add( ‪array, firstelem, newelem )
1724 {
1725  if( !isdefined( ‪array[ firstelem ] ) )
1726  {
1727  ‪array[ firstelem ] = [];
1728  }
1729  ‪array[ firstelem ][ ‪array[ firstelem ].size ] = newelem;
1730  return ‪array;
1731 }
1732 
1733 function ‪is_node_script_origin( pathnode )
1734 {
1735  return isdefined( pathnode.classname ) && pathnode.classname == "script_origin";
1736 }
1737 
1738 // this determines if the node will be sent through trigger_process. The uber trigger function that may get phased out.
1740 {
1741  processtrigger = false;
1742 
1743  // special treatment for start nodes
1745  {
1746  if( isdefined( self.script_crashtype ) )
1747  {
1748  level.vehicle_crashpaths[ level.vehicle_crashpaths.size ] = self;
1749  }
1750 
1751  level.vehicle_startnodes[ level.vehicle_startnodes.size ] = self;
1752  }
1753 
1754  if( isdefined( self.script_vehicledetour ) && isdefined( self.targetname ) )
1755  {
1756  get_func = undefined;
1757  // get_func is differnt for struct types and script_origin types of paths
1758  if( isdefined( get_from_entity( self.targetname ) ) )
1759  {
1760  get_func =&get_from_entity_target;
1761  }
1762  if( isdefined( get_from_spawnstruct( self.targetname ) ) )
1763  {
1764  get_func =&get_from_spawnstruct_target;
1765  }
1766 
1767  if( isdefined( get_func ) )
1768  {
1769  ‪setup_dynamic_detour( self, get_func );
1770  processtrigger = true; // the node with the script_vehicledetour waits for the trigger here unlike ground nodes which need to know 1 node in advanced that there's a detour, tricky tricky.
1771  }
1772  else
1773  {
1774  ‪setup_groundnode_detour( self ); // other trickery. the node is set to process in there.
1775  }
1776 
1777  level.vehicle_detourpaths = ‪array_2d_add( level.vehicle_detourpaths, self.script_vehicledetour, self );
1778  /#
1779  if( level.vehicle_detourpaths[ self.script_vehicledetour ].size > 2 )
1780  {
1781  println( "more than two script_vehicledetour grouped in group number: ", self.script_vehicledetour );
1782  }
1783  #/
1784  }
1785 
1786  // if a gate isn't open then the vehicle will stop there and wait for it to become open.
1787  if( isdefined( self.script_gatetrigger ) )
1788  {
1789  level.vehicle_gatetrigger = ‪array_2d_add( level.vehicle_gatetrigger, self.script_gatetrigger, self );
1790  self.gateopen = false;
1791  }
1792 
1793  // init the flags!
1794  if ( isdefined( self.script_flag_set ) )
1795  {
1796  if ( !isdefined(level.flag) || !isdefined( level.flag[ self.script_flag_set ] ) )
1797  {
1798  level ‪flag::init( self.script_flag_set );
1799  }
1800  }
1801 
1802  // init the flags!
1803  if ( isdefined( self.script_flag_clear ) )
1804  {
1805  if ( !level ‪flag::exists( self.script_flag_clear ) )
1806  {
1807  level ‪flag::init( self.script_flag_clear );
1808  }
1809  }
1810 
1811  if( isdefined( self.‪script_flag_wait ) )
1812  {
1813  if ( !level ‪flag::exists( self.‪script_flag_wait ) )
1814  {
1815  level ‪flag::init( self.‪script_flag_wait );
1816  }
1817  }
1818 
1819  // various nodes that will be sent through trigger_process
1820  if (isdefined( self.script_VehicleSpawngroup )
1821  || isdefined( self.script_VehicleStartMove )
1822  || isdefined( self.script_gatetrigger )
1823  || isdefined( self.script_Vehiclegroupdelete ))
1824  {
1825  processtrigger = true;
1826  }
1827 
1828  if( processtrigger )
1829  {
1830  ‪add_proccess_trigger( self );
1831  }
1832 }
1833 
1835 {
1836  // TODO: move this to _load under the triggers section. larger task than this simple cleanup.
1837 
1838  // the processtriggers array is all the triggers and vehicle node triggers to be put through
1839  // the trigger_process function. This is so that I only do a waittill trigger once
1840  // in script to assure better sequencing on a multi - function trigger.
1841 
1842  // some of the vehiclenodes don't need to waittill trigger on anything and are here only
1843  // for being linked with other trigger
1844 
1845  level.vehicle_processtriggers = [];
1846 
1847  triggers = [];
1848  triggers = ArrayCombine( getallvehiclenodes(), getentarray( "script_origin", "classname" ), true, false );
1849  triggers = ArrayCombine( triggers, level.struct, true, false );
1850  triggers = ArrayCombine( triggers, ‪trigger::get_all(), true, false );
1851  array::thread_all( triggers, &‪node_trigger_process );
1852 
1853 }
1854 
1855 function ‪setup_nodes()
1856 {
1857  a_nodes = GetAllVehicleNodes();
1858  foreach ( node in a_nodes )
1859  {
1860  if ( isdefined( node.script_flag_set ) )
1861  {
1862  if ( !level ‪flag::exists( node.script_flag_set ) )
1863  {
1864  level ‪flag::init( node.script_flag_set );
1865  }
1866  }
1867  }
1868 }
1869 
1871 {
1872  if ( !isdefined( node.targetname ) )
1873  {
1874  return false;
1875  }
1876 
1877  return isdefined( ‪struct::get( node.targetname, "targetname" ) );
1878 }
1879 
1880 function ‪setup_spawners( a_veh_spawners )
1881 {
1882  spawnvehicles = [];
1883  groups = [];
1884 
1885  foreach ( spawner in a_veh_spawners )
1886  {
1887  if ( isdefined( spawner.script_vehiclespawngroup ) )
1888  {
1889  ‪ARRAY_ADD( spawnvehicles[ spawner.script_vehiclespawngroup ], spawner );
1890 
1891  addgroup[ 0 ] = spawner.script_vehiclespawngroup;
1892  groups = ArrayCombine( groups, addgroup, false, false );
1893  }
1894  }
1895 
1896  waittillframeend; //T7 - wait here and let all the vehicle inits run
1897 
1898  foreach ( spawngroup in groups )
1899  {
1900  a_veh_spawners = spawnvehicles[ spawngroup ];
1901 
1902  level.vehicle_spawners[ spawngroup ] = [];
1903 
1904  foreach ( sp in a_veh_spawners )
1905  {
1906  if( sp.count < 1 )
1907  {
1908  sp.count = 1;
1909  }
1910 
1911 // sp vehicle_dynamic_cover();
1912  ‪set_variables( sp );
1913 
1914  ‪ARRAY_ADD( level.vehicle_spawners[ spawngroup ], sp );
1915  }
1916 
1917  level thread ‪_spawn_group( spawngroup );
1918  }
1919 }
1920 
1922 {
1923  if (isdefined(self.destructibledef))
1924  {
1925  self.health = 99999;
1926  }
1927  else
1928  {
1929  type = self.vehicletype;
1930 
1931  if( isdefined( self.script_startinghealth ) )
1932  {
1933  self.health = self.script_startinghealth;
1934  }
1935  else
1936  {
1937  if( self.healthdefault == -1 )
1938  {
1939  return;
1940  }
1941  else
1942  {
1943  self.health = self.healthdefault;
1944  //println("set health: " + self.health);
1945  }
1946  }
1947 
1948  // if( isdefined( level.destructible_model[ self.model ] ) )
1949  // {
1950  // self.health = 2000;
1951  // self.destructible_type = level.destructible_model[ self.model ];
1952  // self destructible::setup_destructibles( true );
1953  // }
1954  }
1955 }
1956 
1958 {
1959 
1960 }
1961 
1962 
1963 function ‪is_cheap()
1964 {
1965  if( !isdefined( self.script_cheap ) )
1966  {
1967  return false;
1968  }
1969 
1970  if( !self.script_cheap )
1971  {
1972  return false;
1973  }
1974 
1975  return true;
1976 }
1977 
1978 
1980 {
1981  if( !‪IS_PLANE(self) )
1982  {
1983  return false;
1984  }
1985 
1986  if( ‪is_cheap() )
1987  {
1988  return false;
1989  }
1990 
1991  return true;
1992 }
1993 
1994 function ‪play_looped_fx_on_tag( effect, durration, tag )
1995 {
1996  eModel = get_dummy();
1997  effectorigin = ‪sys::spawn( "script_origin", eModel.origin );
1998 
1999  self endon( "fire_extinguish" );
2000  thread ‪_play_looped_fx_on_tag_origin_update( tag, effectorigin );
2001  while( 1 )
2002  {
2003  playfx( effect, effectorigin.origin, effectorigin.upvec );
2004  wait durration;
2005  }
2006 }
2007 
2008 function ‪_play_looped_fx_on_tag_origin_update( tag, effectorigin )
2009 {
2010  effectorigin.angles = self gettagangles( tag );
2011  effectorigin.origin = self gettagorigin( tag );
2012  effectorigin.forwardvec = anglestoforward( effectorigin.angles );
2013  effectorigin.upvec = anglestoup( effectorigin.angles );
2014  while( isdefined( self ) && self.classname == "script_vehicle" && self getspeedmph() > 0 )
2015  {
2016  eModel = get_dummy();
2017  effectorigin.angles = eModel gettagangles( tag );
2018  effectorigin.origin = eModel gettagorigin( tag );
2019  effectorigin.forwardvec = anglestoforward( effectorigin.angles );
2020  effectorigin.upvec = anglestoup( effectorigin.angles );
2021  wait .05;
2022  }
2023 }
2024 
2025 function ‪setup_dvars()
2026 {
2027  /#
2028  if( GetDvarString( "debug_vehicleresume" ) == "" )
2029  {
2030  SetDvar( "debug_vehicleresume", "off" );
2031  }
2032  if( GetDvarString( "debug_vehiclesetspeed" ) == "" )
2033  {
2034  SetDvar( "debug_vehiclesetspeed", "off" );
2035  }
2036  #/
2037 }
2038 
2040 {
2041  level.vehicle_ResumeSpeed = 5;
2042  level.vehicle_DeleteGroup = [];
2043  level.vehicle_SpawnGroup = [];
2044  level.vehicle_StartMoveGroup = [];
2045  level.vehicle_DeathSwitch = [];
2046  level.vehicle_gatetrigger = [];
2047  level.vehicle_crashpaths = [];
2048  level.vehicle_link = [];
2049  level.vehicle_detourpaths = [];
2050 // level.vehicle_linkedpaths = [];
2051  level.vehicle_startnodes = [];
2052  level.vehicle_spawners = [];
2053  level.a_vehicle_types = [];
2054  level.a_vehicle_targetnames = [];
2055 
2056  // AE 3-5-09: added this vehicle_walkercount so we can have ai walk with vehicles
2057  level.vehicle_walkercount = [];
2058 
2059  level.helicopter_crash_locations = getentarray( "helicopter_crash_location", "targetname" );
2060 
2061  level.playervehicle = ‪sys::Spawn( "script_origin", ( 0, 0, 0 ) ); // no isdefined for level.playervehicle
2062  level.playervehiclenone = level.playervehicle; // no isdefined for level.playervehicle
2063 
2064  if( !isdefined( level.vehicle_death_thread ) )
2065  {
2066  level.vehicle_death_thread = [];
2067  }
2068  if( !isdefined( level.vehicle_DriveIdle ) )
2069  {
2070  level.vehicle_DriveIdle = [];
2071  }
2072  if( !isdefined( level.vehicle_DriveIdle_r ) )
2073  {
2074  level.vehicle_DriveIdle_r = [];
2075  }
2076  if( !isdefined( level.attack_origin_condition_threadd ) )
2077  {
2078  level.attack_origin_condition_threadd = [];
2079  }
2080  if( !isdefined( level.vehiclefireanim ) )
2081  {
2082  level.vehiclefireanim = [];
2083  }
2084  if( !isdefined( level.vehiclefireanim_settle ) )
2085  {
2086  level.vehiclefireanim_settle = [];
2087  }
2088  if( !isdefined( level.vehicle_hasname ) )
2089  {
2090  level.vehicle_hasname = [];
2091  }
2092  if( !isdefined( level.vehicle_turret_requiresrider ) )
2093  {
2094  level.vehicle_turret_requiresrider = [];
2095  }
2096  if( !isdefined( level.vehicle_isStationary ) )
2097  {
2098  level.vehicle_isStationary = [];
2099  }
2100  if( !isdefined( level.vehicle_compassicon ) )
2101  {
2102  level.vehicle_compassicon = [];
2103  }
2104  if( !isdefined( level.vehicle_unloadgroups ) )
2105  {
2106  level.vehicle_unloadgroups = [];
2107  }
2108 // if( !isdefined( level.vehicle_aianims ) )
2109 // {
2110 // level.vehicle_aianims = [];
2111 // }
2112  if( !isdefined( level.vehicle_unloadwhenattacked ) )
2113  {
2114  level.vehicle_unloadwhenattacked = [];
2115  }
2116  if( !isdefined( level.vehicle_deckdust ) )
2117  {
2118  level.vehicle_deckdust = [];
2119  }
2120  if( !isdefined( level.vehicle_types ) )
2121  {
2122  level.vehicle_types = [];
2123  }
2124  if( !isdefined( level.vehicle_compass_types ) )
2125  {
2126  level.vehicle_compass_types = [];
2127  }
2128  if( !isdefined( level.vehicle_bulletshield ) )
2129  {
2130  level.vehicle_bulletshield = [];
2131  }
2132  if( !isdefined( level.vehicle_death_badplace ) )
2133  {
2134  level.vehicle_death_badplace = [];
2135  }
2136 
2137 // vehicle_aianim::setup_aianimthreads();
2138 
2139 }
2140 
2141 
2142 function ‪attacker_is_on_my_team( attacker )
2143 {
2144  if( ( isdefined( attacker ) ) && isdefined( attacker.team ) && ( isdefined( self.team ) ) && ( attacker.team == self.team ) )
2145  {
2146  return true;
2147  }
2148  else
2149  {
2150  return false;
2151  }
2152 }
2153 
2155 {
2156  if ( isdefined( self.team ) && self.team == "allies" && isdefined( attacker ) && isdefined(level.player) && attacker == level.player )
2157  {
2158  return true; // player is always on the allied team.. hahah! future CoD games that let the player be the enemy be damned!
2159  }
2160  else if( isai( attacker ) && attacker.team == self.team )
2161  {
2162  return true;
2163  }
2164  else
2165  {
2166  return false;
2167  }
2168 }
2169 
2170 function ‪bullet_shielded( type )
2171 {
2172  if ( !isdefined( self.script_bulletshield ) )
2173  {
2174  return false;
2175  }
2176 
2177  type = tolower( type );
2178 
2179  if ( ! isdefined( type ) || ! issubstr( type, "bullet" ) )
2180  {
2181  return false;
2182  }
2183 
2184  if ( self.script_bulletshield )
2185  {
2186  return true;
2187  }
2188  else
2189  {
2190  return false;
2191  }
2192 }
2193 
2195 {
2196  self.friendlyfire_shield = true;
2197 
2198  if ( isdefined( level.vehicle_bulletshield[ self.vehicletype ] ) && !isdefined( self.script_bulletshield ) )
2199  {
2200  self.script_bulletshield = level.vehicle_bulletshield[ self.vehicletype ];
2201  }
2202 }
2203 
2204 function ‪friendly_fire_shield_callback( attacker, amount, type )
2205 {
2206  if( !isdefined(self.friendlyfire_shield) || !self.friendlyfire_shield )
2207  {
2208  return false;
2209  }
2210 
2211  if(
2212  ( ! isdefined( attacker ) && self.team != "neutral" ) ||
2213  ‪attacker_is_on_my_team( attacker ) ||
2214  ‪attacker_troop_is_on_my_team( attacker ) ||
2215  is_destructible() || // destructible pieces take the damage
2216  ‪bullet_shielded( type )
2217  )
2218  {
2219  return true;
2220  }
2221 
2222  return false;
2223 }
2224 
2225 //function vehicle_dynamic_cover()
2226 //{
2227 // if ( isdefined( self.targetname ) )
2228 // {
2229 // ent = GetEnt( self.targetname, "target" );
2230 // if ( isdefined( ent ) )
2231 // {
2232 // if ( isdefined( ent.script_noteworthy ) && ( ent.script_noteworthy == "dynamic_cover" ) )
2233 // {
2234 // e_dyn_path = ent;
2235 // }
2236 // }
2237 // }
2238 //
2239 // if ( isdefined( e_dyn_path ) )
2240 // {
2241 // self.e_dyn_path = e_dyn_path;
2242 // }
2243 // else
2244 // {
2245 // e_dyn_path = self;
2246 // }
2247 //}
2248 
2250 {
2251  self endon( "kill_badplace_forever" );
2252  self endon( "death" );
2253  self endon( "delete" );
2254 
2255  if( isdefined( level.custombadplacethread ) )
2256  {
2257  self thread [[ level.custombadplacethread ]]();
2258  return;
2259  }
2260 
2261  hasturret = isdefined( self.turretweapon ) && self.turretweapon != level.weaponNone;
2262  const bp_duration = .5;
2263  const bp_height = 300;
2264  const bp_angle_left = 17;
2265  const bp_angle_right = 17;
2266 
2267  while ( true )
2268  {
2269  if( !self.script_badplace )
2270  {
2271  // badplace_delete( "tankbadplace" );
2272  while ( !self.script_badplace )
2273  {
2274  wait .5;
2275  }
2276  }
2277 
2278  speed = self GetSpeedMPH();
2279  if ( speed <= 0 )
2280  {
2281  wait bp_duration;
2282  continue;
2283  }
2284 
2285  if ( speed < 5 )
2286  {
2287  bp_radius = 200;
2288  }
2289  else if ( ( speed > 5 ) && ( speed < 8 ) )
2290  {
2291  bp_radius = 350;
2292  }
2293  else
2294  {
2295  bp_radius = 500;
2296  }
2297 
2298  if ( isdefined( self.BadPlaceModifier ) )
2299  {
2300  bp_radius = ( bp_radius * self.BadPlaceModifier );
2301  }
2302 
2303  v_turret_angles = self GetTagAngles( "tag_turret" );
2304 
2305  if ( hasturret && isdefined( v_turret_angles ) )
2306  {
2307  bp_direction = AnglesToForward( v_turret_angles );
2308  }
2309  else
2310  {
2311  bp_direction = AnglesToForward( self.angles );
2312  }
2313 
2314  //badplace_arc( "", bp_duration, self.origin, bp_radius * 1.9, bp_height, bp_direction, bp_angle_left, bp_angle_right, "allies", "axis" );
2315  //badplace_cylinder( "", bp_duration, self.origin, 200, "allies", "axis" );
2316  //badplace_cylinder( "", bp_duration, self.colidecircle[ 1 ].origin, 200, bp_height, "allies", "axis" );
2317  wait bp_duration + .05;
2318  }
2319 }
2320 
2321 //function handle_unload_event()
2322 //{
2323 // self notify( "vehicle_handleunloadevent" );
2324 // self endon( "vehicle_handleunloadevent" );
2325 // self endon( "death" );
2326 //
2327 // type = self.vehicletype;
2328 // while( 1 )
2329 // {
2330 // self waittill( "unload", who );
2331 //
2332 // // setting an unload group unloaded guys resets to "default"
2333 // // SCRIPTER_MOD: JesseS (5/14/2007) - took this out "who" for now, seems to be breaking unloadgroups.
2334 // //if( isdefined( who ) )
2335 // // self.unload_group = who;
2336 // // makes ai unload
2337 // self notify( "groupedanimevent", "unload" );
2338 // }
2339 //}
2340 
2342 {
2343  // the should return undefined
2344  path_start = GetVehicleNode( target, "targetname" );
2345 
2346  if ( !isdefined( path_start ) )
2347  {
2348  path_start = GetEnt( target, "targetname" );
2349  }
2350  else if ( ‪IS_PLANE( self ) )
2351  {
2352  /#
2353  PrintLn( "helicopter node targetname: " + path_start.targetname );
2354  PrintLn( "vehicletype: " + self.vehicletype );
2355  #/
2356  AssertMsg( "helicopter on vehicle path( see console for info )" );
2357  }
2358 
2359  if ( !isdefined( path_start ) )
2360  {
2361  path_start = ‪struct::get( target, "targetname" );
2362  }
2363 
2364  return path_start;
2365 }
2366 
2367 //TODO T7 - ask code how this function differs from vehicle::resume_path()
2369 {
2370  if ( isdefined( self.currentnode.target ) )
2371  {
2372  node = ‪get_vehiclenode_any_dynamic( self.currentnode.target );
2373  }
2374 
2375  if ( isdefined( node ) )
2376  {
2377  self ResumeSpeed( 35 );
2378  ‪paths( node );
2379  }
2380 }
2381 
2382 function ‪land()
2383 {
2384  self setNearGoalNotifyDist( 2 );
2385  self sethoverparams( 0, 0, 10 );
2386  self cleargoalyaw();
2387  self settargetyaw( ‪FLAT_ANGLES( self.angles )[ 1 ] );
2388  self ‪set_goal_pos( ‪GROUNDPOS( self, self.origin ), 1 );
2389  self waittill( "goal" );
2390 }
2391 
2392 function ‪set_goal_pos( origin, bStop )
2393 {
2394  if( self.health <= 0 )
2395  {
2396  return;
2397  }
2398  if( isdefined( self.originheightoffset ) )
2399  {
2400  origin += ( 0, 0, self.originheightoffset ); // TODO - FIXME: this is temporarily set in the vehicles init_local function working on getting it this requirement removed
2401  }
2402  self setvehgoalpos( origin, bStop );
2403 }
2404 
2405 function ‪liftoff( height )
2406 {
2407  if( !isdefined( height ) )
2408  {
2409  height = 512;
2410  }
2411  dest = self.origin + ( 0, 0, height );
2412  self setNearGoalNotifyDist( 10 );
2413  self ‪set_goal_pos( dest, 1 );
2414  self waittill( "goal" );
2415 }
2416 
2418 {
2419  // wait for it to level out before unloading
2420  const offset = 12;
2421  const stabletime = 400;
2422  ‪timer = gettime() + stabletime;
2423  while( isdefined( self ) )
2424  {
2425  if( self.angles[ 0 ] > offset || self.angles [ 0 ] < ( - 1 * offset ) )
2426  {
2427  ‪timer = gettime() + stabletime;
2428  }
2429  if( self.angles[ 2 ] > offset || self.angles [ 2 ] < ( - 1 * offset ) )
2430  {
2431  ‪timer = gettime() + stabletime;
2432  }
2433  if( gettime() > ‪timer )
2434  {
2435  break;
2436  }
2437  wait .05;
2438  }
2439 }
2440 
2441 function ‪unload_node( node )
2442 {
2443  // needed by RTS mode to halt choppers quicker.
2444  // Result is ugly though and should be done properly by someone that knows vehicles at some point.
2445  if( isdefined( self.custom_unload_function ) )
2446  {
2447  [[ self.custom_unload_function ]]();
2448  return;
2449  }
2450 
2451  ‪pause_path();
2452 
2453 // if ( self.riders.size > 0 )
2454 // {
2455 // pathnode = GetNode( node.targetname, "target" );
2456 // if ( isdefined( pathnode ) )
2457 // {
2458 // foreach ( ai_rider in self.riders )
2459 // {
2460 // if ( IsAI( ai_rider ) )
2461 // {
2462 // ai_rider thread spawner::go_to_node( pathnode );
2463 // }
2464 // }
2465 // }
2466 // }
2467 
2468  if ( ‪IS_PLANE( self ) )
2469  {
2471  }
2472  else if ( ‪IS_HELICOPTER( self ) )
2473  {
2474  self SetHoverParams( 0, 0, 10 );
2476  }
2477 
2478  if ( node ‪is_unload_node() )
2479  {
2480  ‪unload( node.script_unload );
2481  }
2482 
2483 // if ( vehicle_aianim::riders_unloadable( node.script_unload ) || IS_TRUE( self.custom_unload ) )
2484 // {
2485 // self waittill( "unloaded" );
2486 // }
2487 }
2488 
2490 {
2491  return ( isdefined( self.script_unload ) && ( self.script_unload != "none" ) );
2492 }
2493 
2495 {
2496  // needed by RTS mode to halt choppers quicker.
2497  // Result is ugly though and should be done properly by someone that knows vehicles at some point.
2498  if( isdefined( self.custom_unload_function ) )
2499  {
2500  self thread [[ self.custom_unload_function ]]();
2501  }
2502 
2503  self SetHoverParams( 0, 0, 10 );
2504 
2505  goal = self.nextNode.origin;
2506 
2507  // find out how far off the ground the drop node is
2508  start = self.nextNode.origin;
2509  ‪end = start - ( 0, 0, 10000 );
2510 
2511  // trace the ground
2512  ‪trace = BulletTrace( start, ‪end, false, undefined, true );
2513  if ( ‪trace["fraction"] <= 1 )
2514  {
2515  goal = ( ‪trace["position"][0], ‪trace["position"][1], ‪trace["position"][2] + self.fastropeoffset );
2516  }
2517 
2518  // For now always do the ri tag
2519  drop_offset_tag = "tag_fastrope_ri";
2520 
2521  // unless there's a custom one set on the helicopter
2522  if( isdefined( self.drop_offset_tag ) )
2523  drop_offset_tag = self.drop_offset_tag;
2524 
2525  // Get offset from drop tag to origin
2526  drop_offset = self GetTagOrigin( "tag_origin" ) - self GetTagOrigin( drop_offset_tag );
2527 
2528  // offset goal
2529  goal += ( drop_offset[0], drop_offset[1], 0 );
2530 
2531  self SetVehGoalPos( goal, 1 );
2532  self waittill( "goal" );
2533  self notify( "unload", self.nextNode.script_unload );
2534 
2535  self waittill( "unloaded" );
2536 }
2537 
2538 function ‪detach_path()
2539 {
2540  self.attachedpath = undefined;
2541  self notify( "newpath" );
2542 
2543  self setGoalyaw( ‪FLAT_ANGLES( self.angles )[ 1 ] );
2544  self setvehgoalpos( self.origin + ( 0, 0, 4 ), 1 );
2545 }
2546 
2548 {
2549  level.vehicle_targetname_array = [];
2550 
2551  vehicles = getentarray( "script_vehicle", "classname" );
2552 
2553  n_highest_group = 0;
2554  // get the highest script_vehicleSpawnGroup in use
2555  foreach ( vh in vehicles )
2556  {
2557  if ( isdefined( vh.script_vehicleSpawnGroup ) )
2558  {
2559  n_spawn_group = Int( vh.script_vehicleSpawnGroup );
2560 
2561  if ( n_spawn_group > n_highest_group )
2562  {
2563  n_highest_group = n_spawn_group;
2564  }
2565  }
2566  }
2567 
2568  for( i = 0; i < vehicles.size; i++ )
2569  {
2570  vehicle = vehicles[ i ];
2571 
2572  if ( isdefined( vehicle.targetname ) && IsVehicleSpawner( vehicle ) )
2573  {
2574  if( !isdefined( vehicle.script_vehicleSpawnGroup ) )
2575  {
2576  // vehicle spawners that have no script_vehiclespawngroup get assigned one, if they have a targetname
2577  n_highest_group++;
2578  vehicle.script_vehicleSpawnGroup = n_highest_group;
2579  }
2580 
2581  if( !isdefined( level.vehicle_targetname_array[ vehicle.targetname ] ) )
2582  {
2583  level.vehicle_targetname_array[ vehicle.targetname ] = [];
2584  }
2585 
2586  level.vehicle_targetname_array[ vehicle.targetname ][ vehicle.script_vehicleSpawnGroup ] = true;
2587  }
2588  }
2589 }
2590 
2591 function ‪simple_spawn( ‪name, b_supress_assert=false )
2592 {
2593  // spawns an array of vehicles that all have the specified targetname in the editor,
2594  // but are deleted at runtime
2595 
2596  Assert( b_supress_assert || isdefined( level.vehicle_targetname_array[ ‪name ] ), "No vehicle spawners had targetname " + ‪name );
2597 
2598  vehicles = [];
2599  if ( isdefined( level.vehicle_targetname_array[ ‪name ] ) )
2600  {
2601  ‪array = level.vehicle_targetname_array[ ‪name ];
2602 
2603  if ( ‪array.size > 0 )
2604  {
2605  keys = GetArrayKeys( ‪array );
2606 
2607  foreach ( key in keys )
2608  {
2609  vehicle_array = ‪_scripted_spawn( key );
2610  vehicles = ArrayCombine( vehicles, vehicle_array, true, false );
2611  }
2612  }
2613  }
2614 
2615  return vehicles;
2616 }
2617 
2618 function ‪simple_spawn_single( ‪name, b_supress_assert=false )
2619 {
2620  vehicle_array = ‪simple_spawn( ‪name, b_supress_assert );
2621  Assert( b_supress_assert || vehicle_array.size == 1, "Tried to spawn a vehicle from targetname " + ‪name + " but it returned " + vehicle_array.size + " vehicles, instead of 1" );
2622 
2623  if ( vehicle_array.size > 0 )
2624  {
2625  return vehicle_array[ 0 ];
2626  }
2627 }
2628 
2630 {
2631  // spawns 1 vehicle and makes sure it gets 1
2632  vehicleArray = ‪simple_spawn( ‪name );
2633  assert( vehicleArray.size == 1, "Tried to spawn a vehicle from targetname " + ‪name + " but it returned " + vehicleArray.size + " vehicles, instead of 1" );
2634 
2635  vehicleArray[ 0 ] thread ‪go_path();
2636  return vehicleArray[ 0 ];
2637 }
2638 
2640 {
2641  // spawns 1 vehicle and makes sure it gets 1
2642  vehicleArray = ‪simple_spawn( ‪name );
2643  for( i = 0; i < vehicleArray.size; i++ )
2644  {
2645  vehicleArray[ i ] thread ‪go_path();
2646  }
2647 
2648  return vehicleArray;
2649 }
2650 
2651 //Wrapper for SpawnVehicle, use this to throttle vehicle spawning
2652 function ‪spawn( modelname, targetname, vehicletype, origin, angles, destructibledef )
2653 {
2654  assert(isdefined(targetname));
2655  assert(isdefined(vehicletype));
2656  assert(isdefined(origin));
2657  assert(isdefined(angles));
2658 
2659  return SpawnVehicle( vehicletype, origin, angles, targetname, destructibledef );
2660 }
2661 
2662 function ‪aircraft_dust_kickup( model )
2663 {
2664  self endon( "death" );
2665  self endon( "death_finished" );
2666  self endon( "stop_kicking_up_dust" );
2667 
2668  assert( isdefined( self.vehicletype ) );
2669 
2670  const maxHeight = 1200;
2671  const minHeight = 350;
2672 
2673  const slowestRepeatWait = 0.15;
2674  const fastestRepeatWait = 0.05;
2675 
2676  const numFramesPerTrace = 3;
2677  doTraceThisFrame = numFramesPerTrace;
2678 
2679  const defaultRepeatRate = 1.0;
2680  repeatRate = defaultRepeatRate;
2681 
2682  ‪trace = undefined;
2683  d = undefined;
2684 
2685  trace_ent = self;
2686  if ( isdefined( model ) )
2687  {
2688  trace_ent = model;
2689  }
2690 
2691  while( isdefined( self ) )
2692  {
2693  if( repeatRate <= 0 )
2694  {
2695  repeatRate = defaultRepeatRate;
2696  }
2697  wait repeatRate;
2698 
2699  if( !isdefined( self ) )
2700  {
2701  return;
2702  }
2703 
2704  doTraceThisFrame -- ;
2705 
2706 
2707  if( doTraceThisFrame <= 0 )
2708  {
2709  doTraceThisFrame = numFramesPerTrace;
2710 
2711  ‪trace = bullettrace( trace_ent.origin, trace_ent.origin - ( 0, 0, 100000 ), false, trace_ent );
2712  /*
2713  trace[ "entity" ]
2714  trace[ "fraction" ]
2715  trace[ "normal" ]
2716  trace[ "position" ]
2717  trace[ "surfacetype" ]
2718  */
2719 
2720  d = distance( trace_ent.origin, ‪trace[ "position" ] );
2721 
2722  repeatRate = ( ( d - minHeight ) / ( maxHeight - minHeight ) ) * ( slowestRepeatWait - fastestRepeatWait ) + fastestRepeatWait;
2723  }
2724 
2725  if( !isdefined( ‪trace ) )
2726  {
2727  continue;
2728  }
2729 
2730  assert( isdefined( d ) );
2731 
2732  if( d > maxHeight )
2733  {
2734  repeatRate = defaultRepeatRate;
2735  continue;
2736  }
2737 
2738  if( isdefined( ‪trace[ "entity" ] ) )
2739  {
2740  repeatRate = defaultRepeatRate;
2741  continue;
2742  }
2743 
2744  if( !isdefined( ‪trace[ "position" ] ) )
2745  {
2746  repeatRate = defaultRepeatRate;
2747  continue;
2748  }
2749 
2750  if( !isdefined( ‪trace[ "surfacetype" ] ) )
2751  {
2752  ‪trace[ "surfacetype" ] = "dirt";
2753  }
2754  assert( isdefined( level._vehicle_effect[ self.vehicletype ] ), self.vehicletype + " vehicle script hasn't run _tradfx properly" );
2755  assert( isdefined( level._vehicle_effect[ self.vehicletype ][ ‪trace[ "surfacetype" ] ] ), "UNKNOWN SURFACE TYPE: " + ‪trace[ "surfacetype" ] );
2756 
2757 
2758  if( level._vehicle_effect[ self.vehicletype ][ ‪trace[ "surfacetype" ] ] != -1 )
2759  {
2760  playfx( level._vehicle_effect[ self.vehicletype ][ ‪trace[ "surfacetype" ] ], ‪trace[ "position" ] );
2761  }
2762  }
2763 }
2764 
2765 function ‪impact_fx( fxname, surfaceTypes )
2766 {
2767  if ( isdefined( fxname ) )
2768  {
2769  body = self GetTagOrigin( "tag_body" );
2770  if ( !isdefined( body ) )
2771  {
2772  body = self.origin + (0,0,10);
2773  }
2774 
2775  ‪trace = BulletTrace( body, body - (0,0,2 * self.radius), false, self );
2776  if( ‪trace["fraction"] < 1.0 && !isdefined( ‪trace[ "entity" ] ) && ( !isdefined(surfaceTypes) || array::contains( surfaceTypes, ‪trace["surfacetype"] ) ) )
2777  {
2778  pos = 0.5 * ( self.origin + ‪trace["position"] );
2779  up = 0.5 * ( ‪trace["normal"] + AnglesToUp( self.angles ) );
2780  forward = AnglesToForward( self.angles );
2781  ‪PlayFx( fxname, pos, up, forward ); // reverse up and forward because impact FX are X-axis up
2782  }
2783  }
2784 }
2785 
2786 function ‪maingun_fx()
2787 {
2788  if( !isdefined( level.vehicle_deckdust[ self.model ] ) )
2789  {
2790  return;
2791  }
2792  self endon( "death" );
2793  while( true )
2794  {
2795  self waittill( "weapon_fired" ); // waits for Code notify when fireWeapon() is called.
2796  playfxontag( level.vehicle_deckdust[ self.model ], self, "tag_engine_exhaust" );
2797  barrel_origin = self gettagorigin( "tag_flash" );
2798  ground = physicstrace( barrel_origin, barrel_origin + ( 0, 0, -128 ) );
2799  physicsExplosionSphere( ground, 192, 100, 1 );
2800  }
2801 }
2802 
2803 function ‪lights_on( team )
2804 {
2805  //lights:
2806  //0 - turn on normal
2807  //1 - turn off
2808  //2 - override to allied color
2809  //3 - override to axis color
2810 
2811  if( IsDefined( team ) )
2812  {
2813  if( team == "allies" )
2814  {
2815  self ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_FORCE_ALLIES );
2816  }
2817  else if( team == "axis" )
2818  {
2819  self ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_FORCE_AXIS );
2820  }
2821  }
2822  else
2823  {
2824  self ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_ON );
2825  }
2826 }
2827 
2828 function ‪lights_off()
2829 {
2830  self ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_OFF );
2831 }
2832 
2833 function ‪toggle_lights_group( groupID, on )
2834 {
2835  bit = 1;
2836  if ( !on )
2837  {
2838  bit = 0;
2839  }
2840 
2841  self ‪clientfield::set( "toggle_lights_group" + groupID, bit );
2842 }
2843 
2844 function ‪toggle_ambient_anim_group( groupID, on )
2845 {
2846  bit = 1;
2847  if ( !on )
2848  {
2849  bit = 0;
2850  }
2851 
2852  self ‪clientfield::set( "toggle_ambient_anim_group" + groupID, bit );
2853 }
2854 
2855 function ‪do_death_fx()
2856 {
2857  deathfxtype = ( ( self.died_by_emp === true ) ? 2 : 1 );
2858 
2859  self ‪clientfield::set( "deathfx", deathfxtype );
2860  self stopsounds();
2861 }
2862 
2863 function ‪toggle_emp_fx( on )
2864 {
2865  self ‪clientfield::set( "toggle_emp_fx", on );
2866 }
2867 
2868 function ‪toggle_burn_fx( on )
2869 {
2870  self ‪clientfield::set( "toggle_burn_fx", on );
2871 }
2872 
2873 // special_status: 1 - normal death; 2 - EMP death; 3 - burn death; 0 - no fx
2874 function ‪do_death_dynents( special_status = 1 )
2875 {
2876  assert( special_status >= 0 && special_status <= 3 );
2877  self ‪clientfield::set( "spawn_death_dynents", special_status );
2878 }
2879 
2881 {
2882  self ‪clientfield::set( "spawn_gib_dynents", 1 );
2883 
2884  numDynents = 2;
2885  for( i = 0; i < numDynents; i++ )
2886  {
2887  hidetag = GetStructField( self.settings, "servo_gib_tag" + i );
2888  if ( isdefined( hidetag ) )
2889  {
2890  self HidePart( hidetag, "", true );
2891  }
2892  }
2893 }
2894 
2895 function ‪set_alert_fx_level( alert_level ) // 0 is off, 1 unaware, 2 alert, 3 combat
2896 {
2897  self ‪clientfield::set( "alert_level", alert_level );
2898 }
2899 
2900 function ‪should_update_damage_fx_level( currentHealth, ‪damage, maxHealth )
2901 {
2902  settings = ‪struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
2903  if ( !isdefined( settings ) )
2904  {
2905  return 0;
2906  }
2907 
2908  currentRatio = ‪math::clamp( float( currentHealth ) / float( maxHealth ), 0.0, 1.0 );
2909  afterDamageRatio = ‪math::clamp( float( currentHealth - ‪damage ) / float( maxHealth ), 0.0, 1.0 );
2910  currentLevel = undefined;
2911  afterDamageLevel = undefined;
2912  switch( ‪VAL( settings.damagestate_numStates, 0 ) )
2913  {
2914  case 6:
2915  if ( settings.damagestate_lv6_ratio >= afterDamageRatio )
2916  {
2917  afterDamageLevel = 6;
2918  currentLevel = 6;
2919  if ( settings.damagestate_lv6_ratio < currentRatio )
2920  {
2921  currentLevel = 5;
2922  }
2923  break;
2924  } // fall through
2925  case 5:
2926  if ( settings.damagestate_lv5_ratio >= afterDamageRatio )
2927  {
2928  afterDamageLevel = 5;
2929  currentLevel = 5;
2930  if ( settings.damagestate_lv5_ratio < currentRatio )
2931  {
2932  currentLevel = 4;
2933  }
2934  break;
2935  } // fall through
2936  case 4:
2937  if ( settings.damagestate_lv4_ratio >= afterDamageRatio )
2938  {
2939  afterDamageLevel = 4;
2940  currentLevel = 4;
2941  if ( settings.damagestate_lv4_ratio < currentRatio )
2942  {
2943  currentLevel = 3;
2944  }
2945  break;
2946  } // fall through
2947  case 3:
2948  if ( settings.damagestate_lv3_ratio >= afterDamageRatio )
2949  {
2950  afterDamageLevel = 3;
2951  currentLevel = 3;
2952  if ( settings.damagestate_lv3_ratio < currentRatio )
2953  {
2954  currentLevel = 2;
2955  }
2956  break;
2957  } // fall through
2958  case 2:
2959  if ( settings.damagestate_lv2_ratio >= afterDamageRatio )
2960  {
2961  afterDamageLevel = 2;
2962  currentLevel = 2;
2963  if ( settings.damagestate_lv2_ratio < currentRatio )
2964  {
2965  currentLevel = 1;
2966  }
2967  break;
2968  } // fall through
2969  case 1:
2970  if ( settings.damagestate_lv1_ratio >= afterDamageRatio )
2971  {
2972  afterDamageLevel = 1;
2973  currentLevel = 1;
2974  if ( settings.damagestate_lv1_ratio < currentRatio )
2975  {
2976  currentLevel = 0;
2977  }
2978  break;
2979  } // fall through
2980  default:
2981  // do nothing
2982  }
2983 
2984  if ( !isdefined( currentLevel ) || !isdefined( afterDamageLevel ) )
2985  {
2986  return 0;
2987  }
2988 
2989  if ( currentLevel != afterDamageLevel )
2990  {
2991  return afterDamageLevel;
2992  }
2993 
2994  return 0;
2995 }
2996 
2997 // self == vehicle
2998 // returns if damage level changed after damage
2999 function ‪update_damage_fx_level( currentHealth, ‪damage, maxHealth )
3000 {
3001  newDamageLevel = ‪should_update_damage_fx_level( currentHealth, ‪damage, maxHealth );
3002  if ( newDamageLevel > 0 )
3003  {
3004  self ‪set_damage_fx_level( newDamageLevel );
3005  return true;
3006  }
3007  return false;
3008 }
3009 
3010 // self == vehicle
3011 // 0 is off, higher level means higher damage
3012 function ‪set_damage_fx_level( damage_level )
3013 {
3014  self ‪clientfield::set( "damage_level", damage_level );
3015 }
3016 
3031 function ‪build_drive( forward, ‪reverse, normalspeed, rate )
3032 {
3033  if( !isdefined( normalspeed ) )
3034  {
3035  normalspeed = 10;
3036  }
3037  level.vehicle_DriveIdle[ self.model ] = forward;
3038 
3039  if( isdefined( ‪reverse ) )
3040  {
3041  level.vehicle_DriveIdle_r[ self.model ] = ‪reverse;
3042  }
3043  level.vehicle_DriveIdle_normal_speed[ self.model ] = normalspeed;
3044  if( isdefined( rate ) )
3045  {
3046  level.vehicle_DriveIdle_animrate[ self.model ] = rate;
3047  }
3048 }
3049 
3051 <br/>
3052 //"Function Name: build_ai_anims( <aithread> , <vehiclethread> )"
3053 //<br/>"Summary: called in individual vehicle file - set threads for ai animation and vehicle animation assignments"
3054 //"Module: Vehicle"
3055 //"CallOn: A vehicle"
3056 //<br/>"Mandatory Argument(s): <aithread> : ai thread"
3057 //<br/>"Optional Argument(s): <vehiclethread> : vehicle thread"
3058 //<br/>"Example:vehicle build_ai_anims(&setanims,&set_vehicle_anims );"
3059 //<br/>"Single Player / Multi Player: singleplayer"
3060 //*! \details **Description:**
3061 <br/>/
3062 //
3063 //function build_ai_anims( aithread, vehiclethread )
3064 //{
3065 // level.vehicle_aianims[ self.vehicletype ] = [[ aithread ]]();
3066 // if( isdefined( vehiclethread ) )
3067 // {
3068 // level.vehicle_aianims[ self.vehicletype ] = [[ vehiclethread ]]( level.vehicle_aianims[ self.vehicletype ] );
3069 // }
3070 //}
3071 
3072 
3074 <br/>
3075 //"Function Name: build_attach_models( <modelsthread> )"
3076 //<br/>"Summary: called in individual vehicle file - thread for building attached models( ropes ) with animation"
3077 //"Module: Vehicle"
3078 //"CallOn: "
3079 //<br/>"Mandatory Argument(s): <modelsthread> : thread"
3080 //<br/>"Example:build_attach_models(&set_attached_models );"
3081 //<br/>"Single Player / Multi Player: singleplayer"
3082 //*! \details **Description:**
3083 <br/>/
3084 //
3085 //function build_attach_models( modelsthread )
3086 //{
3087 // level.vehicle_attachedmodels[ self.vehicletype ] = [[ modelsthread ]]();;
3088 //}
3089 
3091 <br/>
3092 //"Function Name: build_unload_groups( <unloadgroupsthread> )"
3093 //<br/>"Summary: called in individual vehicle file - thread for building unload groups"
3094 //"Module: Vehicle"
3095 //"CallOn: A vehicle"
3096 //<br/>"Mandatory Argument(s): <modelsthread> : thread"
3097 //<br/>"Example:vehicle build_unload_groups(&Unload_Groups );"
3098 //<br/>"Single Player / Multi Player: singleplayer"
3099 //*! \details **Description:**
3100 <br/>/
3101 //
3102 //function build_unload_groups( unloadgroupsthread )
3103 //{
3104 // level.vehicle_unloadgroups[ self.vehicletype ] = [[ unloadgroupsthread ]]();
3105 //}
3106 
3107 function get_from_spawnstruct( target )
3108 {
3109  return ‪struct::get( target, "targetname" );
3110 }
3111 
3112 function get_from_entity( target )
3113 {
3114  return getent( target, "targetname" );
3115 }
3116 
3117 function get_from_spawnstruct_target( target )
3118 {
3119  return ‪struct::get( target, "target" );
3120 }
3121 
3122 function get_from_entity_target( target )
3123 {
3124  return getent( target, "target" );
3125 }
3126 
3127 function is_destructible()
3128 {
3129  return isdefined( self.destructible_type );
3130 }
3131 
3132 // SCRIPTER_MOD: JesseS (5/12/200) - readded script_vehicleattackgroup scripting
3133 // This allows vehicles to attack other vehicles automatically. Just set the script_vehicleattackgroup of the attacker
3134 // to the script_vehiclespawngroup you want to attack.
3135 function attack_group_think()
3136 {
3137  self endon ("death");
3138  self endon ("switch group");
3139  self endon ("killed all targets");
3140 
3141  if (isdefined (self.script_vehicleattackgroupwait))
3142  {
3143  wait (self.script_vehicleattackgroupwait);
3144  }
3145 
3146  for(;;)
3147  {
3148  //get all the vehicles
3149  group = getentarray("script_vehicle", "classname");
3150 
3151  // get our target array
3152  valid_targets = [];
3153  for (i = 0; i< group.size; i++)
3154  {
3155  // dpg: not all script vehicles have a script_vehiclespawngroup
3156  if( !isdefined( group[i].script_vehiclespawngroup ) )
3157  {
3158  continue;
3159  }
3160  // get all vehicles with the same spawngroup as the agroup we want to attack
3161  if (group[i].script_vehiclespawngroup == self.script_vehicleattackgroup)
3162  {
3163  // Make sure we only attack different teams vehicles
3164  if (group[i].team != self.team)
3165  {
3166  ‪ARRAY_ADD(valid_targets, group[i]);
3167  }
3168  }
3169  }
3170 
3171  // Try again every .5 seconds if there are no valid targets.
3172  if (valid_targets.size == 0)
3173  {
3174  wait (0.5);
3175  continue;
3176  }
3177 
3178  // Main loop which makes the vehicle fire on the nearest group it's been set to attack
3179  for (;;)
3180  {
3181  current_target = undefined;
3182  if (valid_targets.size != 0)
3183  {
3184  current_target = self get_nearest_target(valid_targets);
3185  }
3186  else
3187  {
3188  // We killed them all, end this thread
3189  self notify ("killed all targets");
3190  }
3191 
3192  // if it's a death vehicle, remove it from the list of valid targets
3193  if (current_target.health <= 0)
3194  {
3195  ArrayRemoveValue(valid_targets, current_target);
3196  continue;
3197  }
3198  else
3199  {
3200  // set the target ent for the vehicle. offset a bit so it doesnt shoot into the ground
3201  self setturrettargetent( current_target, (0,0,50) );
3202 
3203  // DPG 10/22/07 - in case we want specific wait values on the vehicle
3204  if( isdefined( self.fire_delay_min ) && isdefined( self.fire_delay_max ) )
3205  {
3206  // in case max is less than min
3207  if( self.fire_delay_max < self.fire_delay_min )
3208  {
3209  self.fire_delay_max = self.fire_delay_min;
3210  }
3211 
3212  wait ( randomintrange(self.fire_delay_min, self.fire_delay_max) );
3213  }
3214 
3215  else
3216  {
3217  wait (randomintrange(4, 6));
3218  }
3219  self fireweapon();
3220  }
3221  }
3222  }
3223 
3224 
3225  // if this is called again, just add new group to queue
3226  // queue should be sorted by distance
3227  // delete from queue once vehicle is dead, check to see if vehicles health > 0
3228 }
3229 
3230 // Gets the nearest ent to self
3231 function get_nearest_target(valid_targets)
3232 {
3233  nearest_distsq = 99999999;
3234  nearest = undefined;
3235 
3236  for (i = 0; i < valid_targets.size; i++)
3237  {
3238  if( !isdefined( valid_targets[i] ) )
3239  {
3240  continue;
3241  }
3242  current_distsq = distancesquared( self.origin, valid_targets[i].origin );
3243  if (current_distsq < nearest_distsq)
3244  {
3245  nearest_distsq = current_distsq;
3246  nearest = valid_targets[i];
3247  }
3248  }
3249  return nearest;
3250 }
3251 
3252 //---------------//
3253 // Debug section //
3254 //---------------//
3255 /#
3256 function debug_vehicle()
3257 {
3258  self endon( "death" );
3259 
3260  if( GetDvarString( "debug_vehicle_health" ) == "" )
3261  {
3262  SetDvar( "debug_vehicle_health", "0" );
3263  }
3264 
3265  while( 1 )
3266  {
3267  if( GetDvarInt( "debug_vehicle_health" ) > 0 )
3268  {
3269  print3d( self.origin, "Health: " + self.health, ( 1, 1, 1 ), 1, 3 );
3270  }
3271 
3273  }
3274 }
3275 
3276 
3277 function get_dummy()
3278 {
3279  if ( ‪IS_TRUE( self.modeldummyon ) )
3280  {
3281  eModel = self.modeldummy;
3282  }
3283  else
3284  {
3285  eModel = self;
3286  }
3287  return eModel;
3288 }
3289 
3290 function add_main_callback( vehicleType, ‪main )
3291 {
3292  if ( !isdefined( level.vehicle_main_callback ) )
3293  {
3294  level.vehicle_main_callback = [];
3295  }
3296 
3297  /#
3298  if ( isdefined( level.vehicle_main_callback[ vehicleType ] ) )
3299  {
3300  PrintLn( "WARNING! Main callback function for vehicle " + vehicleType + " already exists. Proceeding with override" );
3301  }
3302  #/
3303 
3304  level.vehicle_main_callback[ vehicleType ] = ‪main;
3305 }
3306 
3307 function vehicle_get_occupant_team()
3308 {
3309  occupants = self GetVehOccupants();
3310 
3311  if ( occupants.size != 0 )
3312  {
3313  // first occupant defines the vehicle team
3314  occupant = occupants[0];
3315 
3316  if ( isplayer(occupant) )
3317  {
3318  return occupant.team;
3319  }
3320  }
3321 
3322  return self.team;
3323 }
3324 
3335 function ‪toggle_exhaust_fx( on )
3336 {
3337  if(!on)
3338  {
3339  self ‪clientfield::set( "toggle_exhaustfx", 1 );
3340  }
3341  else
3342  {
3343  self ‪clientfield::set( "toggle_exhaustfx", 0 );
3344  }
3345 }
3346 
3357 function ‪toggle_tread_fx( on )
3358 {
3359  if(on)
3360  {
3361  self ‪clientfield::set( "toggle_treadfx", 1 );
3362  }
3363  else
3364  {
3365  self ‪clientfield::set( "toggle_treadfx", 0 );
3366  }
3367 }
3368 
3379 function ‪toggle_sounds( on )
3380 {
3381  // this flag number should *NOT* be changed. if it needs to be changed, code must be updated as well. See EF2_DISABLE_VEHICLE_SOUNDS in bg_public.h
3382  if(!on)
3383  {
3384  self ‪clientfield::set( "toggle_sounds", 1 );
3385  }
3386  else
3387  {
3388  self ‪clientfield::set( "toggle_sounds", 0 );
3389  }
3390 }
3391 
3401 function ‪is_corpse( veh )
3402 {
3403  if ( isdefined( veh ) )
3404  {
3405  if ( ‪IS_TRUE( veh.isacorpse ) )
3406  {
3407  return true;
3408  }
3409  else if ( isdefined( veh.classname ) && ( veh.classname == "script_vehicle_corpse" ) )
3410  {
3411  return true;
3412  }
3413  }
3414 
3415  return false;
3416 }
3417 
3419 <br/>
3420 //"Function Name: enter( <vehicle> )"
3421 //<br/>"Summary: This puts the guy into the vehicle and tells him to idle."
3422 //"Module: AI"
3423 //"CallOn: an actor"
3424 //<br/>"Mandatory Argument(s): <vehicle>: the vehicle to get in"
3425 //<br/>"Example:my_ai thread vehicle::enter(my_vehicle);"
3426 //<br/>"Single Player / Multi Player: singleplayer"
3427 //*! \details **Description:**
3428 <br/>/
3429 //function enter( vehicle, tag ) // self == ai
3430 //{
3431 // self vehicle_aianim::vehicle_enter( vehicle, tag );
3432 //}
3433 
3444 function ‪is_on(vehicle) // self == player
3445 {
3446 
3447  if(!isdefined(self.viewlockedentity))
3448  {
3449  return false;
3450  }
3451  else if(self.viewlockedentity == vehicle)
3452  {
3453  return true;
3454  }
3455 
3456  if(!isdefined(self.groundentity))
3457  {
3458  return false;
3459  }
3460  else if(self.groundentity == vehicle)
3461  {
3462  return true;
3463  }
3464 
3465  return false;
3466 }
3467 
3481 function ‪add_spawn_function( veh_targetname, spawn_func, param1, param2, param3, param4 )
3482 {
3483  func = [];
3484  func[ "function" ] =spawn_func;
3485  func[ "param1" ] = param1;
3486  func[ "param2" ] = param2;
3487  func[ "param3" ] = param3;
3488  func[ "param4" ] = param4;
3489 
3490  ‪DEFAULT( level.a_vehicle_targetnames, [] );
3491 
3492  ‪ARRAY_ADD( level.a_vehicle_targetnames[ veh_targetname ], func );
3493 }
3494 
3508 function ‪add_spawn_function_by_type( veh_type, spawn_func, param1, param2, param3, param4 )
3509 {
3510  func = [];
3511  func[ "function" ] =spawn_func;
3512  func[ "param1" ] = param1;
3513  func[ "param2" ] = param2;
3514  func[ "param3" ] = param3;
3515  func[ "param4" ] = param4;
3516 
3517  ‪DEFAULT( level.a_vehicle_types, [] );
3518 
3519  ‪ARRAY_ADD( level.a_vehicle_types[ veh_type ], func );
3520 }
3521 
3535 function ‪add_hijack_function( veh_targetname, spawn_func, param1, param2, param3, param4 )
3536 {
3537  func = [];
3538  func[ "function" ] =spawn_func;
3539  func[ "param1" ] = param1;
3540  func[ "param2" ] = param2;
3541  func[ "param3" ] = param3;
3542  func[ "param4" ] = param4;
3543 
3544  ‪DEFAULT( level.a_vehicle_hijack_targetnames, [] );
3545 
3546  ‪ARRAY_ADD( level.a_vehicle_hijack_targetnames[ veh_targetname ], func );
3547 }
3548 
3550 {
3551  while ( true )
3552  {
3553  level waittill( "ClonedEntity", clone );
3554 
3555  str_targetname = clone.targetname;
3556  if (isdefined( str_targetname ) && StrEndsWith( str_targetname, "_ai" ) )
3557  {
3558  str_targetname = GetSubStr( str_targetname, 0, str_targetname.size - 3 );
3559  }
3560 
3561  waittillframeend;
3562 
3563  if ( isdefined( str_targetname ) && isdefined( level.a_vehicle_hijack_targetnames ) && isdefined( level.a_vehicle_hijack_targetnames[ str_targetname ] ) )
3564  {
3565  foreach ( func in level.a_vehicle_hijack_targetnames[ str_targetname ] )
3566  {
3567  ‪util::single_thread( clone, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ] );
3568  }
3569  }
3570  }
3571 }
3572 
3580 function ‪disconnect_paths( detail_level = 2, move_allowed = true ) // self == vehicle
3581 {
3582  self DisconnectPaths( detail_level, move_allowed );
3583  self EnableObstacle( false );
3584 }
3585 
3592 function ‪connect_paths() // self == vehicle
3593 {
3594  self ConnectPaths();
3595  self EnableObstacle( true );
3596 }
3597 
3598 function ‪init_target_group() // self == vehicle
3599 {
3600  self.target_group = [];
3601 }
3602 
3603 function ‪add_to_target_group( target_ent )
3604 {
3605  assert( isdefined( self.target_group ), "Call init_target_group() first." );
3606 
3607  ‪ARRAY_ADD( self.target_group, target_ent );
3608 }
3609 
3610 function ‪remove_from_target_group( target_ent )
3611 {
3612  assert( isdefined( self.target_group ), "Call init_target_group() first." );
3613 
3614  ArrayRemoveValue( self.target_group, target_ent );
3615 }
3616 
3617 function ‪monitor_missiles_locked_on_to_me( player, wait_time = 0.1 ) // self == monitored_entity which holds the target group
3618 {
3619  monitored_entity = self;
3620 
3621  monitored_entity endon( "death" );
3622 
3623  assert( isdefined( monitored_entity.target_group ), "Call init_lock_on_group() first." );
3624 
3625  player endon( "stop_monitor_missile_locked_on_to_me" );
3626  player endon( "disconnect" );
3627  player endon( "joined_team" );
3628 
3629  // player endon( "death" ); // do not end on death as player can still drive while dead
3630 
3631  while ( 1 )
3632  {
3633  closest_attacker = player ‪get_closest_attacker_with_missile_locked_on_to_me( monitored_entity );
3634  player SetVehicleLockedOnByEnt( closest_attacker );
3635 
3636  wait wait_time;
3637  }
3638 }
3639 
3640 function ‪stop_monitor_missiles_locked_on_to_me() // self == player
3641 {
3642  self notify( "stop_monitor_missile_locked_on_to_me" );
3643 }
3644 
3645 function ‪get_closest_attacker_with_missile_locked_on_to_me( monitored_entity ) // self == entity that holds target group
3646 {
3647  // gets the missile attacker that has the best dot relative to the player's camera view
3648 
3649  assert( isdefined( monitored_entity.target_group ), "Call init_lock_on_group() first." );
3650 
3651  player = self;
3652  closest_attacker = undefined;
3653  closest_attacker_dot = -999;
3654 
3655  view_origin = player GetPlayerCameraPos();
3656  view_forward = AnglesToForward( player GetPlayerAngles() );
3657 
3658  // setup locked on flags for the group
3659  remaining_locked_on_flags = 0;
3660  foreach( target_ent in monitored_entity.target_group )
3661  {
3662  if ( isdefined( target_ent ) && isdefined( target_ent.locked_on ) )
3663  {
3664  remaining_locked_on_flags |= target_ent.locked_on;
3665  }
3666  }
3667 
3668  // find the closest attacker
3669  for ( i = 0; remaining_locked_on_flags && i < level.players.size; i++ )
3670  {
3671  attacker = level.players[ i ];
3672  if ( isdefined( attacker ) )
3673  {
3674  client_flag = ( 1 << attacker getEntityNumber() );
3675  if ( client_flag & remaining_locked_on_flags )
3676  {
3677  to_attacker = VectorNormalize( attacker.origin - view_origin );
3678  attacker_dot = VectorDot( view_forward, to_attacker );
3679 
3680  if ( attacker_dot > closest_attacker_dot )
3681  {
3682  closest_attacker = attacker;
3683  closest_attacker_dot = attacker_dot;
3684  }
3685 
3686  remaining_locked_on_flags &= ~client_flag;
3687  }
3688  }
3689  }
3690 
3691  return closest_attacker;
3692 }
3693 
3694 function ‪set_vehicle_drivable_time_starting_now( duration_ms ) // self == player
3695 {
3696  end_time_ms = GetTime() + duration_ms;
3697 
3698  ‪set_vehicle_drivable_time( duration_ms, end_time_ms );
3699 
3700  return end_time_ms;
3701 }
3702 
3703 function ‪set_vehicle_drivable_time( duration_ms, end_time_ms ) // self == player
3704 {
3705  self SetVehicleDrivableDuration( duration_ms );
3706  self SetVehicleDrivableEndTime( end_time_ms );
3707 }
3708 
3709 function ‪update_damage_as_occupant( damage_taken, max_health ) // self == player
3710 {
3711  damage_taken_normalized = ‪math::clamp( damage_taken / max_health, 0.0, 1.0 );
3712  self SetVehicleDamageMeter( damage_taken_normalized );
3713 
3714  // /# IPrintLn( "Damage Taken: " + damage_taken_normalized ); #/
3715 }
3716 
3717 function ‪stop_monitor_damage_as_occupant( ) // self == player
3718 {
3719  self notify( "stop_monitor_damage_as_occupant" );
3720 }
3721 
3722 function ‪monitor_damage_as_occupant( player ) // self == vehicle
3723 {
3724  player endon( "disconnect" ); // note: no need to end on player death because player can still control
3725  player notify( "stop_monitor_damage_as_occupant" ); // just make sure we never have two of these running
3726  player endon( "stop_monitor_damage_as_occupant" );
3727  self endon( "death" );
3728 
3729  if( !IsDefined( self.maxhealth ) )
3730  {
3731  self.maxhealth = self.healthdefault; // healthdefault if from the GDT
3732  }
3733 
3734  wait 0.1;
3735  player ‪update_damage_as_occupant( self.maxhealth - self.health, self.maxhealth );
3736 
3737  while( 1 )
3738  {
3739  self waittill( "damage" );
3740  waittillframeend;
3741 
3742  player ‪update_damage_as_occupant( self.maxhealth - self.health, self.maxhealth );
3743  }
3744 }
3745 
3746 // this was copied over from cp/_vehicle.gsc so we could nuke that file
3747 function ‪kill_vehicle( attacker )
3748 {
3749  damageOrigin = self.origin + (0,0,1);
3750  self finishVehicleRadiusDamage(attacker, attacker, 32000, 32000, 10, 0, "MOD_EXPLOSIVE", level.weaponNone, damageOrigin, 400, -1, (0,0,1), 0);
3751 }
3752 
3754 {
3755  if ( !IsAlive( self ) )
3756  {
3757  return false;
3758  }
3759 
3760  vehicle = self GetVehicleOccupied();
3761 
3762  if ( isdefined( vehicle ) )
3763  {
3764  seat = vehicle GetOccupantSeat( self );
3765 
3766  if ( isdefined( seat ) && seat == 0 )
3767  {
3768  return true;
3769  }
3770  }
3771 
3772  return false;
3773 }
3774 
3775 /#
3777 {
3778  allvehicles = GetEntArray( "script_vehicle", "classname" );
3779 
3780  vehicletypes = [];
3781 
3782  foreach( veh in allvehicles )
3783  {
3784  vehicletypes[ veh.vehicletype ] = veh.model;
3785  }
3786 
3787  if( IsAssetLoaded( "vehicle", "civ_pickup_mini" ) )
3788  {
3789  veh = SpawnVehicle( "civ_pickup_mini", (0,0,10000), (0,0,0), "debug_spawn_vehicle" );
3790  vehicletypes[ veh.vehicletype ] = veh.model;
3791  veh Delete();
3792  }
3793 
3794  if( IsAssetLoaded( "vehicle", "atv" ) )
3795  {
3796  veh = SpawnVehicle( "atv", (0,0,10000), (0,0,0), "debug_spawn_vehicle" );
3797  vehicletypes[ veh.vehicletype ] = veh.model;
3798  veh Delete();
3799  }
3800 
3801  if( IsAssetLoaded( "vehicle", "prowler_quad" ) )
3802  {
3803  veh = SpawnVehicle( "prowler_quad", (0,0,10000), (0,0,0), "debug_spawn_vehicle" );
3804  vehicletypes[ veh.vehicletype ] = veh.model;
3805  veh Delete();
3806  }
3807 
3808  if( IsAssetLoaded( "vehicle", "rc_car_racer" ) )
3809  {
3810  veh = SpawnVehicle( "rc_car_racer", (0,0,10000), (0,0,0), "debug_spawn_vehicle" );
3811  vehicletypes[ veh.vehicletype ] = veh.model;
3812  veh Delete();
3813  }
3814 
3815  if( IsAssetLoaded( "vehicle", "jeep_fav_player" ) )
3816  {
3817  veh = SpawnVehicle( "jeep_fav_player", (0,0,10000), (0,0,0), "debug_spawn_vehicle" );
3818  vehicletypes[ veh.vehicletype ] = veh.model;
3819  veh Delete();
3820  }
3821 
3822  types = getArrayKeys( vehicletypes );
3823 
3824  if( types.size == 0 )
3825  return;
3826 
3827  type_index = 0;
3828 
3829  while( 1 )
3830  {
3831  if( GetDvarInt( "debug_vehicle_spawn" ) > 0 )
3832  {
3833  player = GetPlayers()[0];
3834 
3835  dynamic_spawn_hud = NewClientHudElem( player );
3836  dynamic_spawn_hud.alignX = "left";
3837  dynamic_spawn_hud.x = 20;
3838  dynamic_spawn_hud.y = 395;
3839  dynamic_spawn_hud.fontscale = 2;
3840 
3841  dynamic_spawn_dummy_model = ‪sys::Spawn( "script_model", (0,0,0) );
3842 
3843  const waittime = 0.3;
3844 
3845  while( GetDvarInt( "debug_vehicle_spawn" ) > 0 )
3846  {
3847  origin = player.origin + AnglesToForward( player getPlayerAngles() ) * 270.0;
3848  origin += (0,0,40);
3849 
3850  if( player UseButtonPressed() )
3851  {
3852  dynamic_spawn_dummy_model Hide();
3853  vehicle = SpawnVehicle( types[type_index], origin, player.angles, "debug_spawn_vehicle" );
3854  vehicle MakeVehicleUsable();
3855 
3856  if( GetDvarInt( "debug_vehicle_spawn" ) == 1 )
3857  {
3858  SetDvar( "debug_vehicle_spawn", "0" );
3859  continue;
3860  }
3861  wait waittime;
3862  }
3863  if( player buttonpressed("DPAD_RIGHT") )
3864  {
3865  dynamic_spawn_dummy_model Hide();
3866  type_index++;
3867  if( type_index >= types.size )
3868  type_index = 0;
3869  wait waittime;
3870  }
3871  if( player buttonpressed("DPAD_LEFT") )
3872  {
3873  dynamic_spawn_dummy_model Hide();
3874  type_index--;
3875  if( type_index < 0 )
3876  type_index = types.size - 1;
3877  wait waittime;
3878  }
3879  type = types[type_index];
3880  dynamic_spawn_hud settext("Press X to spawn vehicle " + type );
3881 
3882  dynamic_spawn_dummy_model SetModel( vehicletypes[type] );
3883  dynamic_spawn_dummy_model Show();
3884  dynamic_spawn_dummy_model NotSolid();
3885  dynamic_spawn_dummy_model.origin = origin;
3886  dynamic_spawn_dummy_model.angles = player.angles;
3888  }
3889 
3890  dynamic_spawn_hud ‪destroy();
3891  dynamic_spawn_dummy_model delete();
3892  }
3893 
3894  wait 2;
3895  }
3896 }
3897 
3899 {
3900  level ‪flag::init( "debug_vehicle_splines" );
3901 
3902  level thread ‪_spline_debug();
3903 
3904  while ( true )
3905  {
3906  level ‪flag::set_val( "debug_vehicle_splines", GetDvarInt( "g_vehicleDrawSplines" ) );
3907  wait .05;
3908  }
3909 }
3910 
3912 {
3913  while ( true )
3914  {
3915  level ‪flag::wait_till( "debug_vehicle_splines" );
3916 
3917  foreach ( nd in GetAllVehicleNodes() )
3918  {
3920  }
3921 
3922  wait .05;
3923  }
3924 }
3925 
3927 {
3928  self.n_debug_display_count = 0;
3929 
3930  if ( ‪is_unload_node() )
3931  {
3932  ‪print_debug_info( "unload: \"" + self.script_unload + "\"" );
3933  }
3934 
3935  if ( isdefined( self.script_notify ) )
3936  {
3937  ‪print_debug_info( "notify: \"" + self.script_notify + "\"" );
3938  }
3939 
3940  if ( ‪IS_TRUE( self.script_delete ) )
3941  {
3942  ‪print_debug_info( "delete" );
3943  }
3944 }
3945 
3946 function ‪print_debug_info( str_info )
3947 {
3948  self.n_debug_display_count++;
3949  Print3D( self.origin - ( 0, 0, self.n_debug_display_count * 20 ), str_info, ‪BLUE, 1, 1 );
3950 }
3951 
3952 #/
‪crash_derailed_check
‪function crash_derailed_check(detourpath)
Definition: vehicle_shared.gsc:362
‪path_gate_open
‪function path_gate_open(node)
Definition: vehicle_shared.gsc:1092
‪monitor_missiles_locked_on_to_me
‪function monitor_missiles_locked_on_to_me(player, wait_time=0.1)
Definition: vehicle_shared.gsc:3617
‪add_proccess_trigger
‪function add_proccess_trigger(trigger)
Definition: vehicle_shared.gsc:541
‪print_resume_speed
‪function print_resume_speed(timer)
Definition: vehicle_shared.gsc:1646
‪script_delay
‪function script_delay()
Definition: util_shared.gsc:970
‪debug_set_speed
‪function debug_set_speed(speed, rate, msg)
Definition: vehicle_shared.gsc:1590
‪callback
‪function callback(event, localclientnum, params)
Definition: callbacks_shared.csc:13
‪VEHICLE_DELETE
‪#define VEHICLE_DELETE(__e)
Definition: shared.gsh:357
‪enable
‪function enable(handler)
Definition: _perplayer.gsc:54
‪exploder
‪function exploder(exploder_id, n_localclientnumber)
Definition: exploder_shared.csc:297
‪_scripted_spawn_go
‪function _scripted_spawn_go(group)
Definition: vehicle_shared.gsc:1151
‪show_node_debug_info
‪function show_node_debug_info()
Definition: vehicle_shared.gsc:3926
‪MAX_SPAWNED_PER_FRAME
‪#define MAX_SPAWNED_PER_FRAME
Definition: shared.gsh:307
‪set_vehicle_drivable_time_starting_now
‪function set_vehicle_drivable_time_starting_now(duration_ms)
Definition: vehicle_shared.gsc:3694
‪_scripted_spawn
‪function _scripted_spawn(group)
Definition: vehicle_shared.gsc:1144
‪__init__
‪function __init__()
Definition: vehicle_shared.gsc:73
‪add_spawn_function
‪function add_spawn_function(veh_targetname, spawn_func, param1, param2, param3, param4)
Definition: vehicle_shared.gsc:3481
‪path_detour_script_origin
‪function path_detour_script_origin(detournode)
Definition: vehicle_shared.gsc:333
‪lights_on
‪function lights_on(team)
Definition: vehicle_shared.gsc:2803
‪array_2d_add
‪function array_2d_add(array, firstelem, newelem)
Definition: vehicle_shared.gsc:1723
‪timer
‪function timer(n_time, str_endon, x, y, height)
Definition: lui_shared.gsc:163
‪toggle_emp_fx
‪function toggle_emp_fx(on)
Definition: vehicle_shared.gsc:2863
‪bullet_shielded
‪function bullet_shielded(type)
Definition: vehicle_shared.gsc:2170
‪init
‪function init(vehicle)
Definition: vehicle_shared.gsc:1236
‪set_damage_fx_level
‪function set_damage_fx_level(damage_level)
Definition: vehicle_shared.gsc:3012
‪toggle_tread_fx
‪function toggle_tread_fx(on)
Definition: vehicle_shared.gsc:3357
‪add_spawn_function_by_type
‪function add_spawn_function_by_type(veh_type, spawn_func, param1, param2, param3, param4)
Definition: vehicle_shared.gsc:3508
‪setup_dynamic_detour
‪function setup_dynamic_detour(pathnode, get_func)
Definition: vehicle_shared.gsc:1691
‪aircraft_dust_kickup
‪function aircraft_dust_kickup(model)
Definition: vehicle_shared.gsc:2662
‪_watch_for_hijacked_vehicles
‪function private _watch_for_hijacked_vehicles()
Definition: vehicle_shared.gsc:3549
‪IS_HELICOPTER
‪#define IS_HELICOPTER(__e)
Definition: shared.gsh:351
‪clear
‪function clear(str_flag)
Definition: flag_shared.csc:130
‪connect_paths
‪function connect_paths()
Definition: vehicle_shared.gsc:3592
‪stop_monitor_missiles_locked_on_to_me
‪function stop_monitor_missiles_locked_on_to_me()
Definition: vehicle_shared.gsc:3640
‪get_off_path
‪function get_off_path()
Definition: vehicle_shared.gsc:986
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪attacker_is_on_my_team
‪function attacker_is_on_my_team(attacker)
Definition: vehicle_shared.gsc:2142
‪toggle_exhaust_fx
‪function toggle_exhaust_fx(on)
Definition: vehicle_shared.gsc:3335
‪setup_groundnode_detour
‪function setup_groundnode_detour(node)
Definition: vehicle_shared.gsc:529
‪remove_from_target_group
‪function remove_from_target_group(target_ent)
Definition: vehicle_shared.gsc:3610
‪path_detour
‪function path_detour(node)
Definition: vehicle_shared.gsc:367
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪trigger_process
‪function trigger_process(trigger)
Definition: vehicle_shared.gsc:182
‪IS_ARTILLERY
‪#define IS_ARTILLERY(__e)
Definition: shared.gsh:354
‪simple_spawn_single_and_drive
‪function simple_spawn_single_and_drive(name)
Definition: vehicle_shared.gsc:2629
‪resume_path_vehicle
‪function resume_path_vehicle()
Definition: vehicle_shared.gsc:2368
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪_vehicle_life
‪function _vehicle_life()
Definition: vehicle_shared.gsc:1921
‪CF_TOGGLE_LIGHTS_FORCE_AXIS
‪#define CF_TOGGLE_LIGHTS_FORCE_AXIS
Definition: shared.gsh:522
‪create_from_spawngroup_and_go_path
‪function create_from_spawngroup_and_go_path(spawnGroup)
Definition: vehicle_shared.gsc:1004
‪update_damage_fx_level
‪function update_damage_fx_level(currentHealth, damage, maxHealth)
Definition: vehicle_shared.gsc:2999
‪unload
‪function unload(str_group="all", str_mode, remove_rider_before_unloading, remove_riders_wait_time)
Definition: vehicleriders_shared.gsc:584
‪simple_spawn_single
‪function simple_spawn_single(name, b_supress_assert=false)
Definition: vehicle_shared.gsc:2618
‪detach_path
‪function detach_path()
Definition: vehicle_shared.gsc:2538
‪get_closest_attacker_with_missile_locked_on_to_me
‪function get_closest_attacker_with_missile_locked_on_to_me(monitored_entity)
Definition: vehicle_shared.gsc:3645
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪is_on
‪function is_on(vehicle)
Definition: vehicle_shared.gsc:3444
‪_vehicle_bad_place
‪function _vehicle_bad_place()
Definition: vehicle_shared.gsc:2249
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪SQR
‪#define SQR(__var)
Definition: shared.gsh:293
‪crash_detour_check
‪function crash_detour_check(detourpath)
Definition: vehicle_shared.gsc:342
‪reverse
‪function reverse()
Definition: traps_shared.gsc:1071
‪delay
‪function delay(time_or_notify, str_endon, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:784
‪set_speed
‪function set_speed(speed, rate, msg)
Definition: vehicle_shared.gsc:1577
‪disable
‪function disable(handler)
Definition: _perplayer.gsc:79
‪enable_turrets
‪function enable_turrets(veh)
Definition: vehicle_shared.gsc:1433
‪rider_walk_setup
‪function rider_walk_setup(vehicle)
Definition: vehicle_shared.gsc:500
‪_remove_non_riders_from_array
‪function _remove_non_riders_from_array(ai)
Definition: vehicle_shared.gsc:445
‪resume_path
‪function resume_path()
Definition: vehicle_shared.gsc:900
‪setup_script_gatetrigger
‪function setup_script_gatetrigger(trigger)
Definition: vehicle_shared.gsc:172
‪has_helicopter_dust_kickup
‪function has_helicopter_dust_kickup()
Definition: vehicle_shared.gsc:1979
‪lights_off
‪function lights_off()
Definition: vehicle_shared.gsc:2828
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪set_alert_fx_level
‪function set_alert_fx_level(alert_level)
Definition: vehicle_shared.gsc:2895
‪script_resume_speed
‪function script_resume_speed(msg, rate)
Definition: vehicle_shared.gsc:1609
‪attacker_troop_is_on_my_team
‪function attacker_troop_is_on_my_team(attacker)
Definition: vehicle_shared.gsc:2154
‪set_vehicle_drivable_time
‪function set_vehicle_drivable_time(duration_ms, end_time_ms)
Definition: vehicle_shared.gsc:3703
‪impact_fx
‪function impact_fx(fxname, surfaceTypes)
Definition: vehicle_shared.gsc:2765
‪_vehicle_spawn
‪function _vehicle_spawn(vspawner, from)
Definition: vehicle_shared.gsc:1169
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪spline_debug
‪function spline_debug()
Definition: vehicle_shared.gsc:3898
‪vehicle_spawner_tool
‪function vehicle_spawner_tool()
Definition: vehicle_shared.gsc:3776
‪is_unload_node
‪function is_unload_node()
Definition: vehicle_shared.gsc:2489
‪add_hijack_function
‪function add_hijack_function(veh_targetname, spawn_func, param1, param2, param3, param4)
Definition: vehicle_shared.gsc:3535
‪friendly_fire_shield
‪function friendly_fire_shield()
Definition: vehicle_shared.gsc:2194
‪setup_spawners
‪function setup_spawners(a_veh_spawners)
Definition: vehicle_shared.gsc:1880
‪setup_targetname_spawners
‪function setup_targetname_spawners()
Definition: vehicle_shared.gsc:2547
‪_spawn_group
‪function _spawn_group(spawngroup)
Definition: vehicle_shared.gsc:1112
‪monitor_damage_as_occupant
‪function monitor_damage_as_occupant(player)
Definition: vehicle_shared.gsc:3722
‪get_on_and_go_path
‪function get_on_and_go_path(path_start)
Definition: vehicle_shared.gsc:1027
‪_vehicle_load_assets
‪function _vehicle_load_assets()
Definition: vehicle_shared.gsc:1957
‪script_flag_wait
‪function script_flag_wait()
Definition: flag_shared.gsc:394
‪REGISTER_SYSTEM_EX
‪#define REGISTER_SYSTEM_EX(__sys, __func_init_preload, __func_init_postload, __reqs)
Definition: shared.gsh:209
‪liftoff
‪function liftoff(height)
Definition: vehicle_shared.gsc:2405
‪end
‪function end(final)
Definition: _killcam.gsc:511
‪is_corpse
‪function is_corpse(veh)
Definition: vehicle_shared.gsc:3401
‪paths
‪function paths(node)
Definition: vehicle_shared.gsc:569
‪detach_getoutrigs
‪function detach_getoutrigs()
Definition: vehicle_shared.gsc:1420
‪simple_spawn
‪function simple_spawn(name, b_supress_assert=false)
Definition: vehicle_shared.gsc:2591
‪CF_TOGGLE_LIGHTS_OFF
‪#define CF_TOGGLE_LIGHTS_OFF
Definition: shared.gsh:520
‪player_is_driver
‪function player_is_driver()
Definition: vehicle_shared.gsc:3753
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪_spline_debug
‪function _spline_debug()
Definition: vehicle_shared.gsc:3911
‪god_off
‪function god_off()
Definition: vehicle_shared.gsc:1675
‪is_cheap
‪function is_cheap()
Definition: vehicle_shared.gsc:1963
‪CF_TOGGLE_LIGHTS_ON
‪#define CF_TOGGLE_LIGHTS_ON
Definition: shared.gsh:519
‪SPAWNFLAG_VEHICLE_NODE_START_NODE
‪#define SPAWNFLAG_VEHICLE_NODE_START_NODE
Definition: shared.gsh:57
‪get_normal_anim_time
‪function get_normal_anim_time(animation)
Definition: vehicle_shared.gsc:1680
‪FLAT_ANGLES
‪#define FLAT_ANGLES(__angles)
Definition: shared.gsh:257
‪update_damage_as_occupant
‪function update_damage_as_occupant(damage_taken, max_health)
Definition: vehicle_shared.gsc:3709
‪SPAWNFLAG
‪#define SPAWNFLAG(__e, __f)
Definition: shared.gsh:95
‪script_wait
‪function script_wait(called_from_spawner=false)
Definition: util_shared.gsc:1930
‪wait_till
‪function wait_till(str_flag)
Definition: flag_shared.csc:189
‪get_vehiclenode_any_dynamic
‪function get_vehiclenode_any_dynamic(target)
Definition: vehicle_shared.gsc:2341
‪enable_auto_disconnect_path
‪function enable_auto_disconnect_path()
Definition: vehicle_shared.gsc:1492
‪go_path
‪function go_path()
Definition: vehicle_shared.gsc:1037
‪deathrolloff
‪function deathrolloff()
Definition: vehicle_death_shared.gsc:1102
‪maingun_fx
‪function maingun_fx()
Definition: vehicle_shared.gsc:2786
‪BLUE
‪#define BLUE
Definition: shared.gsh:177
‪is_node_script_origin
‪function is_node_script_origin(pathnode)
Definition: vehicle_shared.gsc:1733
‪array
‪function filter array
Definition: array_shared.csc:16
‪do_gib_dynents
‪function do_gib_dynents()
Definition: vehicle_shared.gsc:2880
‪setup_nodes
‪function setup_nodes()
Definition: vehicle_shared.gsc:1855
‪add_to_target_group
‪function add_to_target_group(target_ent)
Definition: vehicle_shared.gsc:3603
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪node_trigger_process
‪function node_trigger_process()
Definition: vehicle_shared.gsc:1739
‪unload_node_helicopter
‪function unload_node_helicopter(node)
Definition: vehicle_shared.gsc:2494
‪waittill_any_ents
‪function waittill_any_ents(ent1, string1, ent2, string2, ent3, string3, ent4, string4, ent5, string5, ent6, string6, ent7, string7)
Definition: util_shared.csc:496
‪get_all
‪function get_all(type1, type2, type3, type4, type5, type6, type7, type8, type9)
Definition: trigger_shared.gsc:802
‪GROUNDPOS
‪#define GROUNDPOS(__e, _origin)
Definition: shared.gsh:368
‪friendly_fire_shield_callback
‪function friendly_fire_shield_callback(attacker, amount, type)
Definition: vehicle_shared.gsc:2204
‪path_gate_wait_till_open
‪function path_gate_wait_till_open(pathspot)
Definition: vehicle_shared.gsc:1098
‪global_spawn_throttle
‪function global_spawn_throttle(n_count_per_network_frame)
Definition: spawner_shared.gsc:238
‪ai_should_be_added
‪function ai_should_be_added(ai)
Definition: vehicle_shared.gsc:460
‪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
‪set_val
‪function set_val(str_flag, b_val)
Definition: flag_shared.gsc:123
‪is_node_script_struct
‪function is_node_script_struct(node)
Definition: vehicle_shared.gsc:1870
‪levelstuff
‪function levelstuff(vehicle)
Definition: vehicle_shared.gsc:415
‪play_looped_fx_on_tag
‪function play_looped_fx_on_tag(effect, durration, tag)
Definition: vehicle_shared.gsc:1994
‪simple_spawn_and_drive
‪function simple_spawn_and_drive(name)
Definition: vehicle_shared.gsc:2639
‪__main__
‪function __main__()
Definition: vehicle_shared.gsc:165
‪main
‪function main()
Definition: _global_fx.csc:17
‪exists
‪function exists(str_flag)
Definition: flag_shared.csc:43
‪god_on
‪function god_on()
Definition: vehicle_shared.gsc:1670
‪should_update_damage_fx_level
‪function should_update_damage_fx_level(currentHealth, damage, maxHealth)
Definition: vehicle_shared.gsc:2900
‪toggle_lights_group
‪function toggle_lights_group(groupID, on)
Definition: vehicle_shared.gsc:2833
‪set_variables
‪function set_variables(vehicle)
Definition: vehicle_shared.gsc:1157
‪_spawn_array
‪function _spawn_array(spawners)
Definition: vehicle_shared.gsc:439
‪setup_dvars
‪function setup_dvars()
Definition: vehicle_shared.gsc:2025
‪build_drive
‪function build_drive(forward, reverse, normalspeed, rate)
Definition: vehicle_shared.gsc:3031
‪single_thread
‪function single_thread(entity, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:699
‪destroy
‪function destroy(watcher, owner)
Definition: _decoy.gsc:108
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪setup_triggers
‪function setup_triggers()
Definition: vehicle_shared.gsc:1834
‪sort_by_startingpos
‪function sort_by_startingpos(guysarray)
Definition: vehicle_shared.gsc:480
‪do_death_fx
‪function do_death_fx()
Definition: vehicle_shared.gsc:2855
‪islastnode
‪function islastnode(node)
Definition: vehicle_shared.gsc:554
‪do_death_dynents
‪function do_death_dynents(special_status=1)
Definition: vehicle_shared.gsc:2874
‪init_target_group
‪function init_target_group()
Definition: vehicle_shared.gsc:3598
‪set_goal_pos
‪function set_goal_pos(origin, bStop)
Definition: vehicle_shared.gsc:2392
‪_play_looped_fx_on_tag_origin_update
‪function _play_looped_fx_on_tag_origin_update(tag, effectorigin)
Definition: vehicle_shared.gsc:2008
‪print_debug_info
‪function print_debug_info(str_info)
Definition: vehicle_shared.gsc:3946
‪clamp
‪function clamp(val, val_min, val_max)
Definition: math_shared.csc:16
‪land
‪function land()
Definition: vehicle_shared.gsc:2382
‪kill_vehicle
‪function kill_vehicle(attacker)
Definition: vehicle_shared.gsc:3747
‪toggle_sounds
‪function toggle_sounds(on)
Definition: vehicle_shared.gsc:3379
‪unload_node
‪function unload_node(node)
Definition: vehicle_shared.gsc:2441
‪stop_monitor_damage_as_occupant
‪function stop_monitor_damage_as_occupant()
Definition: vehicle_shared.gsc:3717
‪deathrollon
‪function deathrollon()
Definition: vehicle_death_shared.gsc:1094
‪toggle_burn_fx
‪function toggle_burn_fx(on)
Definition: vehicle_shared.gsc:2868
‪setup_level_vars
‪function setup_level_vars()
Definition: vehicle_shared.gsc:2039
‪IS_PLANE
‪#define IS_PLANE(__e)
Definition: shared.gsh:350
‪pause_path
‪function pause_path()
Definition: vehicle_shared.gsc:870
‪disconnect_paths
‪function disconnect_paths(detail_level=2, move_allowed=true)
Definition: vehicle_shared.gsc:3580
‪name
‪class GroundFx name
‪wait_till_stable
‪function wait_till_stable()
Definition: vehicle_shared.gsc:2417
‪CF_TOGGLE_LIGHTS_FORCE_ALLIES
‪#define CF_TOGGLE_LIGHTS_FORCE_ALLIES
Definition: shared.gsh:521
‪spawn
‪function spawn(modelname, targetname, vehicletype, origin, angles, destructibledef)
Definition: vehicle_shared.gsc:2652
‪toggle_ambient_anim_group
‪function toggle_ambient_anim_group(groupID, on)
Definition: vehicle_shared.gsc:2844
‪_disconnect_paths_when_stopped
‪function _disconnect_paths_when_stopped()
Definition: vehicle_shared.gsc:1499
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪PlayFx
‪function PlayFx(name)
Definition: _counteruav.gsc:390
‪get_on_path
‪function get_on_path(path_start, str_key="targetname")
Definition: vehicle_shared.gsc:938