‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_helicopter.gsc
Go to the documentation of this file.
1 #using scripts\shared\challenges_shared;
2 #using scripts\shared\clientfield_shared;
3 #using scripts\shared\damagefeedback_shared;
4 #using scripts\shared\hostmigration_shared;
5 #using scripts\shared\killstreaks_shared;
6 #using scripts\shared\math_shared;
7 #using scripts\shared\scoreevents_shared;
8 #using scripts\shared\tweakables_shared;
9 #using scripts\shared\util_shared;
10 #using scripts\shared\weapons\_weaponobjects;
11 #using scripts\shared\weapons\_heatseekingmissile;
12 
13 #using scripts\mp\_challenges;
14 #using scripts\mp\_util;
15 #using scripts\mp\gametypes\_globallogic_audio;
16 #using scripts\mp\gametypes\_globallogic_player;
17 #using scripts\mp\gametypes\_hostmigration;
18 #using scripts\mp\gametypes\_spawning;
19 #using scripts\mp\killstreaks\_airsupport;
20 #using scripts\mp\killstreaks\_dogs;
21 #using scripts\mp\killstreaks\_flak_drone;
22 #using scripts\mp\killstreaks\_killstreak_bundles;
23 #using scripts\mp\killstreaks\_killstreak_detect;
24 #using scripts\mp\killstreaks\_killstreak_hacking;
25 #using scripts\mp\killstreaks\_killstreakrules;
26 #using scripts\mp\killstreaks\_killstreaks;
27 
28 #insert scripts\mp\_hacker_tool.gsh;
29 #insert scripts\mp\killstreaks\_killstreaks.gsh;
30 #insert scripts\shared\shared.gsh;
31 #insert scripts\shared\version.gsh;
32 
33 #using_animtree ( "mp_vehicles" );
34 
35 #namespace helicopter;
36 
37 #precache( "locationselector", "compass_objpoint_helicopter" );
38 #precache( "string", "MP_DESTROYED_HELICOPTER");
39 #precache( "string", "KILLSTREAK_DESTROYED_HELICOPTER_GUNNER");
40 #precache( "string", "KILLSTREAK_EARNED_HELICOPTER_COMLINK" );
41 #precache( "string", "KILLSTREAK_HELICOPTER_COMLINK_NOT_AVAILABLE" );
42 #precache( "string", "KILLSTREAK_HELICOPTER_COMLINK_INBOUND" );
43 #precache( "string", "KILLSTREAK_HELICOPTER_COMLINK_HACKED" );
44 #precache( "string", "KILLSTREAK_DESTROYED_SUPPLY_DROP_DEPLOY_SHIP" );
45 #precache( "string", "mpl_killstreak_heli" );
46 #precache( "fx", "killstreaks/fx_heli_exp_lg" );
47 #precache( "fx", "killstreaks/fx_heli_exp_md" );
48 #precache( "fx", "killstreaks/fx_vtol_exp" );
49 #precache( "fx", "killstreaks/fx_heli_exp_sm" );
50 #precache( "fx", "killstreaks/fx_heli_smk_trail_engine_33" );
51 #precache( "fx", "killstreaks/fx_heli_smk_trail_engine_66" );
52 #precache( "fx", "killstreaks/fx_heli_smk_trail_tail" );
53 #precache( "fx", "killstreaks/fx_heli_smk_trail_engine" );
54 #precache( "fx", "killstreaks/fx_sc_lights_grn" );
55 #precache( "fx", "killstreaks/fx_sc_lights_red" );
56 
57 #define HELI_ENTRANCE_Z_HELP 1000
58 #define HELICOPTER_COMLINK "helicopter_comlink"
59 #define INVENTORY_HELICOPTER_COMLINK "inventory_helicopter_comlink"
60 
61 function ‪precachehelicopter(model,type)
62 {
63  if(!isdefined(type))
64  type = "blackhawk";
65 
66  level.vehicle_deathmodel[model] = model;
67 
68 
69  /* SETUP WEAPON TAGS */
70 
72  // helicopter sounds:
73  level.heli_sound["hit"] = "evt_helicopter_hit";
74  level.heli_sound["hitsecondary"] = "evt_helicopter_hit";
75  level.heli_sound["damaged"] = "null";
76  level.heli_sound["spinloop"] = "evt_helicopter_spin_loop";
77  level.heli_sound["spinstart"] = "evt_helicopter_spin_start";
78  level.heli_sound["crash"] = "evt_helicopter_midair_exp";
79  level.heli_sound["missilefire"] = "wpn_hellfire_fire_npc";
80 }
81 
82 function ‪useKillstreakHelicopter( hardpointType )
83 {
84  if ( self ‪killstreakrules::isKillstreakAllowed( hardpointType, self.team ) == false)
85  return false;
86 
87  if ( (!isdefined( level.heli_paths ) || !level.heli_paths.size) )
88  {
89  /#iprintlnbold("Need to add helicopter paths to the level");#/
90  return false;
91  }
92 
93  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
94  {
95  ‪result = self ‪selectHelicopterLocation( hardpointType );
96  if ( !isdefined(‪result) || ‪result == false )
97  return false;
98  }
99 
100  destination = 0;
101  missilesEnabled = false;
102  if ( hardpointType == "helicopter_x2" )
103  {
104  missilesEnabled = true;
105  }
106 
107  assert( level.heli_paths.size > 0, "No non-primary helicopter paths found in map" );
108 
109  random_path = randomint( level.heli_paths[destination].size );
110 
111  startnode = level.heli_paths[destination][random_path];
112 
113  protectLocation = undefined;
114  armored = false;
115  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
116  {
117  protectLocation = (level.helilocation[0], level.helilocation[1], int(‪airsupport::getMinimumFlyHeight()) -200 );
118  armored = false;
119 
120  startnode = ‪getValidProtectLocationStart(random_path, protectLocation, destination );
121  }
122 
123  killstreak_id = self ‪killstreakrules::killstreakStart( hardpointType, self.team );
124  if ( killstreak_id == -1 )
125  return false;
126 
127  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
128  {
130  }
131 
132  self ‪killstreaks::play_killstreak_start_dialog( hardpointType, self.team, killstreak_id );
133  self thread ‪announceHelicopterInbound( hardpointType );
134 
135  thread ‪heli_think( self, startnode, self.team, missilesEnabled, protectLocation, hardpointType, armored, killstreak_id );
136 
137  return true;
138 }
139 
140 function ‪announceHelicopterInbound(hardpointType)
141 {
142  team = self.team;
143 
144  self AddWeaponStat( ‪killstreaks::get_killstreak_weapon( hardpointtype ), "used", 1 );
145 }
146 
147 // generate path graph from script_origins
149 {
150  // collecting all start nodes in the map to generate path arrays
151  path_start = getentarray( "heli_start", "targetname" ); // start pointers, point to the actual start node on path
152  path_dest = getentarray( "heli_dest", "targetname" ); // dest pointers, point to the actual dest node on path
153  loop_start = getentarray( "heli_loop_start", "targetname" ); // start pointers for loop path in the map
154  gunner_loop_start = getentarray( "heli_gunner_loop_start", "targetname" ); // start pointers for gunner loop path in the map
155  leave_nodes = getentarray( "heli_leave", "targetname" ); // points where the helicopter leaves to
156  crash_start = getentarray( "heli_crash_start", "targetname" ); // start pointers, point to the actual start node on crash path
157 
158  assert( ( isdefined( path_start ) && isdefined( path_dest ) ), "Missing path_start or path_dest" );
159 
160  // for each destination, loop through all start nodes in level to populate array of start nodes that leads to this destination
161  for (i=0; i<path_dest.size; i++)
162  {
163  startnode_array = [];
164  isPrimaryDest = false;
165 
166  // destnode is the final destination from multiple start nodes
167  destnode_pointer = path_dest[i];
168  destnode = getent( destnode_pointer.target, "targetname" );
169 
170  // for each start node, traverse to its dest., if same dest. then append to startnode_array
171  for ( j=0; j<path_start.size; j++ )
172  {
173  toDest = false;
174  currentnode = path_start[j];
175  // traverse through path to dest.
176  while( isdefined( currentnode.target ) )
177  {
178  nextnode = getent( currentnode.target, "targetname" );
179  if ( nextnode.origin == destnode.origin )
180  {
181  toDest = true;
182  break;
183  }
184 
185  currentnode = nextnode;
186  }
187  if ( toDest )
188  {
189  startnode_array[startnode_array.size] = getent( path_start[j].target, "targetname" ); // the actual start node on path, not start pointer
190  if ( isdefined( path_start[j].script_noteworthy ) && ( path_start[j].script_noteworthy == "primary" ) )
191  isPrimaryDest = true;
192  }
193  }
194  assert( ( isdefined( startnode_array ) && startnode_array.size > 0 ), "No path(s) to destination" );
195 
196  // load the array of start nodes that lead to this destination node into level.heli_paths array as an element
197  if ( isPrimaryDest )
198  level.heli_primary_path = startnode_array;
199  else
200  level.heli_paths[level.heli_paths.size] = startnode_array;
201  }
202 
203  // loop paths array
204  for (i=0; i<loop_start.size; i++)
205  {
206  startnode = getent( loop_start[i].target, "targetname" );
207  level.heli_loop_paths[level.heli_loop_paths.size] = startnode;
208  }
209  assert( isdefined( level.heli_loop_paths[0] ), "No helicopter loop paths found in map" );
210 
211  // chopper gunner paths
212  for ( i = 0 ; i < gunner_loop_start.size ; i++ )
213  {
214  startnode = getent( gunner_loop_start[i].target, "targetname" );
215  startnode.isGunnerPath = true;
216  level.heli_loop_paths[level.heli_loop_paths.size] = startnode;
217  }
218 
219  // start nodes
220  for (i=0; i<path_start.size; i++)
221  {
222  // do not consider "primary" starts as a path_start for supply drops
223  if ( isdefined( path_start[ i ].script_noteworthy ) && ( path_start[ i ].script_noteworthy == "primary" ) )
224  continue;
225 
226  level.heli_startnodes[level.heli_startnodes.size] = path_start[i];
227  }
228  assert( isdefined( level.heli_startnodes[0] ), "No helicopter start nodes found in map" );
229 
230  // leave nodes
231  for (i=0; i<leave_nodes.size; i++)
232  level.heli_leavenodes[level.heli_leavenodes.size] = leave_nodes[i];
233  assert( isdefined( level.heli_leavenodes[0] ), "No helicopter leave nodes found in map" );
234 
235  // crash paths
236  for (i=0; i<crash_start.size; i++)
237  {
238  crash_start_node = getent( crash_start[i].target, "targetname" );
239  level.heli_crash_paths[level.heli_crash_paths.size] = crash_start_node;
240  }
241  assert( isdefined( level.heli_crash_paths[0] ), "No helicopter crash paths found in map" );
242 }
243 
244 function ‪init()
245 {
246  path_start = getentarray( "heli_start", "targetname" ); // start pointers, point to the actual start node on path
247  loop_start = getentarray( "heli_loop_start", "targetname" ); // start pointers for loop path in the map
248 
249 
250  level.chaff_offset["attack"] = ( -130, 0, -140 );
251 
252  level.chopperComlinkFriendly = "veh_t7_drone_hunter";
253  level.chopperComlinkEnemy = "veh_t7_drone_hunter";
254  level.chopperRegular = "veh_t7_drone_hunter";
255 
256  ‪precachehelicopter( level.chopperRegular );
257  ‪precachehelicopter( level.chopperComlinkFriendly );
258  ‪precachehelicopter( level.chopperComlinkEnemy );
259 
260  ‪clientfield::register( "helicopter", "heli_comlink_bootup_anim", ‪VERSION_SHIP, 1, "int");
261  ‪clientfield::register( "helicopter", "heli_warn_targeted", ‪VERSION_SHIP, 1, "int" );
262  ‪clientfield::register( "helicopter", "heli_warn_locked", ‪VERSION_SHIP, 1, "int" );
263  ‪clientfield::register( "helicopter", "heli_warn_fired", ‪VERSION_SHIP, 1, "int" );
264 
265  ‪clientfield::register( "helicopter", "active_camo", ‪VERSION_SHIP, 3, "int" );
266 
267 
268  ‪clientfield::register( "vehicle", "heli_comlink_bootup_anim", ‪VERSION_SHIP, 1, "int");
269  ‪clientfield::register( "vehicle", "heli_warn_targeted", ‪VERSION_SHIP, 1, "int" );
270  ‪clientfield::register( "vehicle", "heli_warn_locked", ‪VERSION_SHIP, 1, "int" );
271  ‪clientfield::register( "vehicle", "heli_warn_fired", ‪VERSION_SHIP, 1, "int" );
272 
273  ‪clientfield::register( "vehicle", "active_camo", ‪VERSION_SHIP, 3, "int" );
274 
275 
276  // array of paths, each element is an array of start nodes that all leads to a single destination node
277  level.heli_paths = [];
278  level.heli_loop_paths = [];
279  level.heli_startnodes = [];
280  level.heli_leavenodes = [];
281  level.heli_crash_paths = [];
282 
283  level.last_start_node_index = 0;
284 
285  // helicopter fx
286  level.chopper_fx["explode"]["death"] = "killstreaks/fx_heli_exp_lg";
287  level.chopper_fx["explode"]["guard"] = "killstreaks/fx_heli_exp_md";
288  level.chopper_fx["explode"]["gunner"] = "killstreaks/fx_vtol_exp";
289  level.chopper_fx["explode"]["large"] = "killstreaks/fx_heli_exp_sm";
290  level.chopper_fx["damage"]["light_smoke"] = "killstreaks/fx_heli_smk_trail_engine_33";
291  level.chopper_fx["damage"]["heavy_smoke"] = "killstreaks/fx_heli_smk_trail_engine_66";
292  level.chopper_fx["smoke"]["trail"] = "killstreaks/fx_heli_smk_trail_tail";
293  level.chopper_fx["fire"]["trail"]["large"] = "killstreaks/fx_heli_smk_trail_engine";
294 
295  level._effect["heli_comlink_light"]["friendly"] = "_debug/fx_debug_deleted_fx";
296  level._effect["heli_comlink_light"]["enemy"] = "_debug/fx_debug_deleted_fx";
297 
298  level.heliComlinkBootupAnim = %veh_anim_future_heli_gearup_bay_open;
299 
300  ‪killstreaks::register("helicopter_comlink", "helicopter_comlink", "killstreak_helicopter_comlink", "helicopter_used",&‪useKillstreakHelicopter, true );
301  ‪killstreaks::register_strings("helicopter_comlink", &"KILLSTREAK_EARNED_HELICOPTER_COMLINK", &"KILLSTREAK_HELICOPTER_COMLINK_NOT_AVAILABLE", &"KILLSTREAK_HELICOPTER_COMLINK_INBOUND", undefined, &"KILLSTREAK_HELICOPTER_COMLINK_HACKED" );
302  ‪killstreaks::register_dialog("helicopter_comlink", "mpl_killstreak_heli", "helicopterDialogBundle", "helicopterPilotDialogBundle", "friendlyHelicopter", "enemyHelicopter", "enemyHelicopterMultiple", "friendlyHelicopterHacked", "enemyHelicopterHacked", "requestHelicopter", "threatHelicopter" );
303  ‪killstreaks::register_alt_weapon("helicopter_comlink", "cobra_20mm_comlink" );
304  ‪killstreaks::set_team_kill_penalty_scale( "helicopter_comlink", 0.0 );
305 
306  // TODO: Move to killstreak data
307  level.killstreaks["helicopter_comlink"].threatOnKill = true;
308  level.killstreaks["inventory_helicopter_comlink"].threatOnKill = true;
309 
310  if ( !path_start.size && !loop_start.size)
311  return;
312 
314 }
315 
316 function ‪heli_get_dvar_int( dvar, def )
317 {
318  return int( ‪heli_get_dvar( dvar, def ) );
319 }
320 
321 // dvar set/fetch/check
322 function ‪heli_get_dvar( dvar, def )
323 {
324  if ( GetDvarString( dvar ) != "" )
325  return getdvarfloat( dvar );
326  else
327  {
328  SetDvar( dvar, def );
329  return Float( def );
330  }
331 }
332 
333 function ‪set_goal_pos( goalPos, ‪stop )
334 {
335  self.heliGoalPos = goalpos;
336  self setvehgoalpos( goalPos, ‪stop );
337 }
338 
339 function ‪spawn_helicopter( owner, origin, angles, model, targetname, target_offset, hardpointType, killstreak_id )
340 {
341  chopper = spawnHelicopter( owner, origin, angles, model, targetname );
342  chopper.owner = owner;
343  chopper ‪clientfield::set( "enemyvehicle", ‪ENEMY_VEHICLE_ACTIVE );
344  chopper.attackers = [];
345  chopper.attackerData = [];
346  chopper.attackerDamage = [];
347  chopper.flareAttackerDamage = [];
348  chopper.destroyFunc =&‪destroyHelicopter;
349  chopper.hardpointType = hardpointType;
350  chopper.killstreak_id = killstreak_id;
351  chopper.pilotIsTalking = false;
352  chopper SetDrawInfrared( true );
353  chopper.allowContinuedLockonAfterInvis = true;
354  chopper.soundmod = "heli";
355 
356  if ( !isdefined( target_offset ) )
357  target_offset = (0,0,0);
358 
359  chopper.target_offset = target_offset;
360 
361  Target_Set(chopper, target_offset);
362 
363  if( ( hardpointtype == "helicopter_comlink" ) || ( hardpointtype == "inventory_helicopter_comlink" ) )
364  {
365  chopper.allowHackingAfterCloak = true;
366  chopper.flak_drone = ‪flak_drone::spawn( chopper, &‪OnFlakDroneDestroyed );
367  chopper.treat_owner_damage_as_friendly_fire = true;
368  chopper.ignore_team_kills = true;
369  chopper ‪init_active_camo();
370  }
371 
372  return chopper;
373 }
374 
376 {
377  chopper = self;
378 
379  if ( !isdefined( chopper ) )
380  {
381  return;
382  }
383  chopper.numFlares = 0;
384  chopper ‪killstreaks::play_pilot_dialog_on_owner( "weaponDestroyed", "helicopter_comlink", chopper.killstreak_id );
385 
387 }
388 
389 function ‪explodeOnContact( hardpointtype )
390 {
391  self endon ( "death" );
392  wait (10);
393  for (;;)
394  {
395  self waittill("touch");
396  self thread ‪heli_explode();
397  }
398 }
399 
400 function ‪getValidProtectLocationStart(random_path, protectLocation, destination )
401 {
402  startnode = level.heli_paths[destination][random_path];
403  path_index = ( random_path + 1 ) % level.heli_paths[destination].size;
404 
405  inNoFly = ‪airsupport::crossesNoFlyZone( protectLocation + (0,0,1), protectLocation );
406  if( isdefined(inNoFly))
407  {
408  protectLocation = (protectLocation[0], protectLocation[1], level.noFlyZones[inNoFly].origin[2] + level.noFlyZones[inNoFly].height);
409  }
410 
411  noFlyZone = ‪airsupport::crossesNoFlyZone( startnode.origin, protectLocation );
412  while ( isdefined(noFlyZone) && path_index != random_path )
413  {
414  startnode = level.heli_paths[destination][path_index];
415 
416  if( isDefined(noFlyZone) )
417  {
418  path_index = ( path_index + 1 ) % level.heli_paths[destination].size;
419  }
420  }
421 
422  // if we dont have a valid position at this point just return
423  return level.heli_paths[destination][path_index];
424 }
425 
426 function ‪getValidRandomLeaveNode( start )
427 {
428  if( self === level.vtol )
429  {
430  foreach( node in level.heli_leavenodes )
431  {
432  if ( isdefined( node.script_noteworthy ) && ( node.script_noteworthy == "primary" ) )
433  return node;
434  }
435  }
436 
437  random_leave_node = randomInt( level.heli_leavenodes.size );
438  leavenode = level.heli_leavenodes[random_leave_node];
439  path_index = ( random_leave_node + 1 ) % level.heli_leavenodes.size;
440  noFlyZone = ‪airsupport::crossesNoFlyZone( leavenode.origin, start );
441  isPrimary = ( leavenode.script_noteworthy === "primary" );
442 
443  while( ( isdefined( noFlyZone ) || isPrimary ) && ( path_index != random_leave_node ) )
444  {
445  leavenode = level.heli_leavenodes[path_index];
446  noFlyZone = ‪airsupport::crossesNoFlyZone( leavenode.origin, start );
447  isPrimary = ( leavenode.script_noteworthy === "primary" );
448  path_index = ( path_index + 1 ) % level.heli_leavenodes.size;
449  }
450 
451  // if we dont have a valid position at this point just return
452  return level.heli_leavenodes[path_index];
453 }
454 
456 {
457  path_index = randomInt( level.heli_startnodes.size );
458  best_index = path_index;
459 
460  count = 0;
461  for( i = 0; i < level.heli_startnodes.size; i++ )
462  {
463  startnode = level.heli_startnodes[path_index];
464  noFlyZone = ‪airsupport::crossesNoFlyZone( startnode.origin, dest );
465 
466  if( !isdefined( noFlyZone ) ) // we didnt hit any noflyzones
467  {
468  best_index = path_index;
469  if( path_index != level.last_start_node_index ) // if possible, we dont want to pickup the previous index
470  break;
471  }
472  path_index = ( path_index + 1 ) % level.heli_startnodes.size;
473  }
474 
475  level.last_start_node_index = best_index;
476  return level.heli_startnodes[best_index];
477 }
478 
479 function ‪getValidRandomCrashNode( start )
480 {
481  random_leave_node = randomInt( level.heli_crash_paths.size );
482  leavenode = level.heli_crash_paths[random_leave_node];
483  path_index = ( random_leave_node + 1 ) % level.heli_crash_paths.size;
484 
485  noFlyZone = ‪airsupport::crossesNoFlyZone( leavenode.origin, start );
486  while ( isdefined(noFlyZone) && path_index != random_leave_node )
487  {
488  leavenode = level.heli_crash_paths[path_index];
489  noFlyZone = ‪airsupport::crossesNoFlyZone( leavenode.origin, start );
490  path_index = ( path_index + 1 ) % level.heli_crash_paths.size;
491  }
492 
493  // if we dont have a valid position at this point just return
494  return level.heli_crash_paths[path_index];
495 }
496 
498 {
499  chopper = self;
500  owner thread ‪watchForEarlyLeave( chopper );
501 }
502 
503 function ‪HackedCallbackPost( hacker )
504 {
505  heli = self;
506  if ( isdefined ( heli.flak_drone ) )
507  {
508  heli.flak_drone flak_drone::configureteam( heli, true );
509  }
510  heli.endTime = getTime() + ‪killstreak_bundles::get_hack_timeout() * 1000;
511  heli.killstreakEndTime = int( heli.endTime );
512 }
513 
514 
515 // spawn helicopter at a start node and monitors it
516 function ‪heli_think( owner, startnode, heli_team, missilesEnabled, protectLocation, hardpointType, armored, killstreak_id )
517 {
518  heliOrigin = startnode.origin;
519  heliAngles = startnode.angles;
520 
521  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
522  {
523  chopperModelFriendly = level.chopperComlinkFriendly;
524  chopperModelEnemy = level.chopperComlinkEnemy;
525  }
526  else
527  {
528  chopperModelFriendly = level.chopperRegular;
529  chopperModelEnemy = level.chopperRegular;
530  }
531 
532  chopper = ‪spawn_helicopter( owner, heliOrigin, heliAngles, "heli_ai_mp", chopperModelFriendly, (0,0,100), hardpointType, killstreak_id );
533  chopper.harpointType = hardpointType;
534 
535  chopper ‪killstreaks::configure_team( hardpointType, killstreak_id, owner, "helicopter", undefined, &‪ConfigureTeamPost );
536 
537  if ( hardpointType == ‪HELICOPTER_COMLINK || hardpointType == ‪INVENTORY_HELICOPTER_COMLINK )
538  {
540  }
541 
542  chopper setEnemyModel(chopperModelEnemy);
543 
544  chopper thread ‪watchForEMP();
545 
546  //Delay the SAM turret targeting the chopper until it has had a chance to enter the play space.
547  Target_SetTurretAquire( chopper, false );
548  chopper thread ‪SAMTurretWatcher();
549 
550  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
551  chopper.defaultWeapon = GetWeapon( "cobra_20mm_comlink" );
552  else
553  chopper.defaultWeapon = GetWeapon( "cobra_20mm" );
554 
555  chopper.requiredDeathCount = owner.deathCount;
556  chopper.chaff_offset = level.chaff_offset["attack"];
557 
558  minigun_snd_ent = ‪spawn( "script_origin", chopper GetTagOrigin( "tag_flash" ) );
559  minigun_snd_ent LinkTo( chopper, "tag_flash", (0,0,0), (0,0,0) );
560  chopper.minigun_snd_ent = minigun_snd_ent;
561  minigun_snd_ent thread ‪AutoStopSound();
562 
563  chopper thread ‪heli_existance();
564 
565  level.chopper = chopper;
566 
567  //chopper.crashType = "explode"; //want attack helicopters and chopper gunners to spin out
568 
569  chopper.reached_dest = false; // has helicopter reached destination
570  if ( armored )
571  chopper.maxhealth = level.heli_amored_maxhealth;// max armored health
572  else
573  chopper.maxhealth = level.heli_maxhealth; // max health
574 
575  chopper.rocketDamageOneShot = level.heli_maxhealth + 1; // Make it so the heatseeker blows it up in one hit
576  chopper.rocketDamageTwoShot = (level.heli_maxhealth / 2) + 1; // Make it so the heatseeker blows it up in two hit
577 
578  if ( ( hardpointType == "helicopter_comlink" ) || ( hardpointType == "inventory_helicopter_comlink" ) )
579  {
580  chopper.numFlares = 0; // no flares, let the flak drone do the work of intercepting the missile
581  }
582  else if( hardpointType == "helicopter_guard")
583  {
584  chopper.numFlares = 1;
585  }
586  else
587  {
588  chopper.numFlares = 2; // 2 flares for chopper gunner, 1 for attack/guard
589  }
590 
591  chopper.flareOffset = (0,0,-256); // offset from vehicle to start the flares
592  chopper.waittime = level.heli_dest_wait; // the time helicopter will stay stationary at destination
593  chopper.loopcount = 0; // how many times helicopter circled the map
594  chopper.evasive = false; // evasive manuvering
595  chopper.health_bulletdamageble = level.heli_armor; // when damage taken is above this value, helicopter can be damage by bullets to its full amount
596  chopper.health_evasive = level.heli_armor; // when damage taken is above this value, helicopter performs evasive manuvering
597  chopper.targeting_delay = level.heli_targeting_delay; // delay between per targeting scan - in seconds
598  chopper.primaryTarget = undefined; // primary target ( player )
599  chopper.secondaryTarget = undefined; // secondary target ( player )
600  chopper.attacker = undefined; // last player that shot the helicopter
601  chopper.missile_ammo = level.heli_missile_max; // initial missile ammo
602  chopper.currentstate = "ok"; // health state
603  chopper.lastRocketFireTime = -1;
604 
605  // helicopter loop threads
606  if ( isdefined(protectLocation) )
607  {
608  chopper thread ‪heli_protect( startNode, protectLocation, hardpointType, heli_team );
609  chopper ‪clientfield::set( "heli_comlink_bootup_anim", 1 );
610  }
611  else
612  {
613  chopper thread ‪heli_fly( startnode, 2.0, hardpointType ); // fly heli to given node and continue on its path
614  }
615 
616  chopper thread ‪heli_damage_monitor( hardpointtype ); // monitors damage
617  chopper thread ‪wait_for_killed(); // monitors player kills
618  chopper thread ‪heli_health( hardpointType ); // display helicopter's health through smoke/fire
619  chopper thread ‪attack_targets( missilesEnabled, hardpointType ); // enable attack
620  chopper thread ‪heli_targeting( missilesEnabled, hardpointType ); // targeting logic
621  chopper thread ‪heli_missile_regen(); // regenerates missile ammo
622 
623  if( hardpointtype != "helicopter_comlink" )
624  {
625  chopper thread ‪heatseekingmissile::MissileTarget_ProximityDetonateIncomingMissile("crashing", "death"); // fires chaff if needed
626  chopper thread ‪create_flare_ent( (0,0,-100) );
627  }
628 }
629 
631 {
632  self endon( "death" );
633  level waittill( "game_ended" );
634 
635  self StopLoopSound();
636 }
637 
639 {
640  self waittill( "leaving" );
641 
643 }
644 
645 function ‪create_flare_ent( offset )
646 {
647  self.flare_ent = ‪spawn( "script_model", self GetTagOrigin("tag_origin") );
648  self.flare_ent SetModel( "tag_origin" );
649  self.flare_ent LinkTo( self, "tag_origin", offset );
650 }
651 
653 {
654  self endon( "death" );
655  self endon( "crashing" );
656  self endon( "leaving" );
657 
658  for( ;; )
659  {
660  if( self.missile_ammo >= level.heli_missile_max )
661  self waittill( "missile fired" );
662  else
663  {
664  // regenerates faster when damaged
665  if ( self.currentstate == "heavy smoke" )
666  wait( level.heli_missile_regen_time/4 );
667  else if ( self.currentstate == "light smoke" )
668  wait( level.heli_missile_regen_time/2 );
669  else
670  wait( level.heli_missile_regen_time );
671  }
672  if( self.missile_ammo < level.heli_missile_max )
673  self.missile_ammo++;
674  }
675 }
676 
677 // helicopter targeting logic
678 function ‪heli_targeting( missilesEnabled, hardpointType )
679 {
680  self endon( "death" );
681  self endon( "crashing" );
682  self endon( "leaving" );
683 
684  // targeting sweep cycle
685  for ( ;; )
686  {
687  // array of helicopter's targets
688  targets = [];
689  targetsMissile = [];
690  // scan for all players in game
691  players = level.players;
692  for (i = 0; i < players.size; i++)
693  {
694  player = players[i];
695 
696  if ( self ‪canTargetPlayer_turret( player, hardpointType ) )
697  {
698  if( isdefined( player ) )
699  targets[targets.size] = player;
700  }
701  if ( missilesEnabled && ( self ‪canTargetPlayer_missile( player, hardpointType ) ) )
702  {
703  if( isdefined( player ) )
704  targetsMissile[targetsMissile.size] = player;
705  }
706  else
707  continue;
708  }
709 
711 
712  foreach( dog in dogs )
713  {
714  if ( self ‪canTargetDog_turret( dog ) )
715  {
716  targets[targets.size] = dog;
717  }
718  if ( missilesEnabled && (self ‪canTargetDog_missile( dog ) ) )
719  {
720  targetsMissile[targetsMissile.size] = dog;
721  }
722  }
723 
724  tanks = GetEntArray( "talon", "targetname" );
725  tanks = ArrayCombine( tanks, GetEntArray( "siegebot", "targetname" ), false, false );
726 
727  foreach( tank in tanks )
728  {
729  if ( self ‪canTargetTank_turret( tank ) )
730  {
731  targets[targets.size] = tank;
732  }
733  }
734 
735  actors = GetActorArray();
736  foreach( actor in actors )
737  {
738  if( isdefined( actor ) && isdefined( actor.isAiClone ) && IsAlive( actor ) )
739  {
740  if ( self ‪canTargetActor_turret( actor, hardpointType ) )
741  {
742  targets[targets.size] = actor;
743  }
744  }
745  }
746 
747  // no targets found
748  if ( targets.size == 0 && targetsMissile.size == 0 )
749  {
750  self.primaryTarget = undefined;
751  self.secondaryTarget = undefined;
752  self SetGoalYaw(RandomInt(360));
753  wait ( self.targeting_delay );
754  continue;
755  }
756 
757  if( targets.size == 1 )
758  {
759  if( isdefined( targets[0].isAiClone ) )
760  {
762  }
763  else if( isdefined( targets[0].type ) && (targets[0].type == "dog" || targets[0].type == "tank_drone"))
764  {
765  ‪killstreaks::update_dog_threat( targets[0] );
766  }
767  else if ( isdefined( targets[0].killstreakType ) )
768  {
770  }
771  else
772  {
774  }
775 
776  self.primaryTarget = targets[0]; // primary only
777  self notify( "primary acquired" );
778  self.secondaryTarget = undefined;
779  }
780  else if ( targets.size > 1 )
781  ‪assignPrimaryTargets( targets );
782 
783  if( targetsMissile.size == 1 )
784  {
785  if( !isdefined( targetsMissile[0].type ) || targetsMissile[0].type != "dog" || targets[0].type == "tank_drone")
786  {
787  self ‪killstreaks::update_missile_player_threat( targetsMissile[0] );
788  }
789  else if( targetsMissile[0].type == "dog" )
790  {
791  self ‪killstreaks::update_missile_dog_threat( targetsMissile[0] );
792  }
793 
794  self.secondaryTarget = targetsMissile[0]; // primary only
795  self notify( "secondary acquired" );
796  }
797  else if( targetsMissile.size > 1 )
798  ‪assignSecondaryTargets( targetsMissile );
799 
800  wait ( self.targeting_delay );
801 
802  }
803 }
804 
805 // targetability
806 function ‪canTargetPlayer_turret( player, hardpointType )
807 {
808  canTarget = true;
809 
810  if ( !isalive( player ) || player.sessionstate != "playing" )
811  return false;
812 
813  if ( player.ignoreme === true )
814  return false;
815 
816  if ( player == self.owner )
817  {
818  self ‪check_owner( hardpointType );
819  return false;
820  }
821 
822  if ( player ‪airsupport::canTargetPlayerWithSpecialty() == false )
823  return false;
824 
825  if ( distance( player.origin, self.origin ) > level.heli_visual_range )
826  return false;
827 
828  if ( !isdefined( player.team ) )
829  return false;
830 
831  if ( level.teamBased && player.team == self.team )
832  return false;
833 
834  if ( player.team == "spectator" )
835  return false;
836 
837  if ( isdefined( player.spawntime ) && ( gettime() - player.spawntime )/1000 <= level.heli_target_spawnprotection )
838  return false;
839 
840  heli_centroid = self.origin + ( 0, 0, -160 );
841  heli_forward_norm = anglestoforward( self.angles );
842  heli_turret_point = heli_centroid + 144*heli_forward_norm;
843 
844  visible_amount = player sightConeTrace( heli_turret_point, self);
845 
846  if ( visible_amount < level.heli_target_recognition )
847  return false;
848 
849  return canTarget;
850 }
851 
852 function ‪canTargetActor_turret( actor, hardpointType )
853 {
854  helicopter = self;
855 
856  canTarget = true;
857 
858  if( !isalive( actor ) )
859  return actor;
860 
861  if( !isdefined( actor.team ) )
862  return false;
863 
864  if( level.teamBased && actor.team == helicopter.team )
865  return false;
866 
867  if( DistanceSquared( actor.origin, helicopter.origin ) > ( level.heli_visual_range * level.heli_visual_range ) )
868  return false;
869 
870  heli_centroid = helicopter.origin + ( 0, 0, -160 );
871  heli_forward_norm = anglestoforward( helicopter.angles );
872  heli_turret_point = heli_centroid + 144 * heli_forward_norm;
873 
874  visible_amount = actor sightConeTrace( heli_turret_point, helicopter );
875  if( visible_amount < level.heli_target_recognition )
876  return false;
877 
878  return canTarget;
879 }
880 
881 function ‪getVerticalTan( startOrigin, endOrigin )
882 {
883  vector = endOrigin - startOrigin;
884 
885  opposite = startOrigin[2] - endOrigin[2];
886  if ( opposite < 0 )
887  opposite *= 1;
888 
889  adjacent = distance2d( startOrigin, endOrigin );
890 
891  if ( adjacent < 0 )
892  adjacent *= 1;
893 
894  if ( adjacent < 0.01 )
895  adjacent = 0.01;
896 
897  tangent = opposite / adjacent;
898 
899  return tangent;
900 }
901 
902 
903 
904 // targetability
905 function ‪canTargetPlayer_missile( player, hardpointType )
906 {
907  canTarget = true;
908 
909  if ( !isalive( player ) || player.sessionstate != "playing" )
910  return false;
911 
912  if ( player.ignoreme === true )
913  return false;
914 
915  if ( player == self.owner )
916  {
917  self ‪check_owner( hardpointType );
918  return false;
919  }
920 
921  if ( player ‪airsupport::canTargetPlayerWithSpecialty() == false )
922  return false;
923 
924  if ( distance( player.origin, self.origin ) > level.heli_missile_range )
925  return false;
926 
927  if ( !isdefined( player.team ) )
928  return false;
929 
930  if ( level.teamBased && player.team == self.team )
931  return false;
932 
933  if ( player.team == "spectator" )
934  return false;
935 
936  if ( isdefined( player.spawntime ) && ( gettime() - player.spawntime )/1000 <= level.heli_target_spawnprotection )
937  return false;
938 
939  if ( self ‪target_cone_check( player, level.heli_missile_target_cone ) == false )
940  return false;
941 
942  heli_centroid = self.origin + ( 0, 0, -160 );
943  heli_forward_norm = anglestoforward( self.angles );
944  heli_turret_point = heli_centroid + 144*heli_forward_norm;
945 
946  if (!isdefined(player.lastHit))
947  player.lastHit = 0;
948 
949  player.lastHit = self HeliTurretSightTrace( heli_turret_point, player, player.lastHit );
950  if (player.lastHit != 0)
951  return false;
952 
953  return canTarget;
954 }
955 
956 // targetability
957 function ‪canTargetDog_turret( dog )
958 {
959  canTarget = true;
960 
961  if ( !isdefined( dog ) )
962  return false;
963 
964  if ( distance( dog.origin, self.origin ) > level.heli_visual_range )
965  return false;
966 
967  if ( !isdefined( dog.team ) )
968  return false;
969 
970  if ( level.teamBased && (dog.team == self.team) )
971  return false;
972 
973  if ( isdefined(dog.script_owner) && self.owner == dog.script_owner )
974  return false;
975 
976  heli_centroid = self.origin + ( 0, 0, -160 );
977  heli_forward_norm = anglestoforward( self.angles );
978  heli_turret_point = heli_centroid + 144*heli_forward_norm;
979 
980  if (!isdefined(dog.lastHit))
981  dog.lastHit = 0;
982 
983  dog.lastHit = self HeliTurretDogTrace( heli_turret_point, dog, dog.lastHit );
984  if ( dog.lastHit != 0 )
985  return false;
986 
987  return canTarget;
988 }
989 
990 // targetability
991 function ‪canTargetDog_missile( dog )
992 {
993  canTarget = true;
994 
995  if ( !isdefined( dog ) )
996  return false;
997 
998  if ( distance( dog.origin, self.origin ) > level.heli_missile_range )
999  return false;
1000 
1001  if ( !isdefined( dog.team ) )
1002  return false;
1003 
1004  if ( level.teamBased && (dog.team == self.team) )
1005  return false;
1006 
1007  if ( isdefined(dog.script_owner) && self.owner == dog.script_owner )
1008  return false;
1009 
1010  // TODO
1011  //should do a view cone to cut down on processing
1012 
1013  heli_centroid = self.origin + ( 0, 0, -160 );
1014  heli_forward_norm = anglestoforward( self.angles );
1015  heli_turret_point = heli_centroid + 144*heli_forward_norm;
1016 
1017  if (!isdefined(dog.lastHit))
1018  dog.lastHit = 0;
1019 
1020  dog.lastHit = self HeliTurretDogTrace( heli_turret_point, dog, dog.lastHit );
1021  if (dog.lastHit != 0)
1022  return false;
1023 
1024  return canTarget;
1025 }
1026 
1027 
1028 // targetability
1029 function ‪canTargetTank_turret( tank )
1030 {
1031  canTarget = true;
1032 
1033  if ( !isdefined( tank ) )
1034  return false;
1035 
1036  if ( tank.ignoreme === true )
1037  return false;
1038 
1039  if ( distance( tank.origin, self.origin ) > level.heli_visual_range )
1040  return false;
1041 
1042  if ( !isdefined( tank.team ) )
1043  return false;
1044 
1045  if ( level.teamBased && (tank.team == self.team) )
1046  return false;
1047 
1048  if ( isdefined(tank.owner) && self.owner == tank.owner )
1049  return false;
1050 
1051  return canTarget;
1052 }
1053 
1054 // assign targets to primary and secondary
1055 function ‪assignPrimaryTargets( targets )
1056 {
1057  for( idx=0; idx<targets.size; idx++ )
1058  {
1059  if( isdefined( targets[idx].isAiClone ) )
1060  {
1061  ‪killstreaks::update_actor_threat( targets[idx] );
1062  }
1063  else if ( isdefined( targets[idx].type ) && targets[idx].type == "dog" )
1064  {
1065  ‪killstreaks::update_dog_threat( targets[idx] );
1066  }
1067  else if ( IsPlayer( targets[idx] ) )
1068  {
1069  ‪killstreaks::update_player_threat( targets[idx] );
1070  }
1071  else
1072  {
1074  }
1075  }
1076 
1077  assert( targets.size >= 2, "Not enough targets to assign primary and secondary" );
1078 
1079  // find primary target, highest threat level
1080  highest = 0;
1081  second_highest = 0;
1082  primaryTarget = undefined;
1083 
1084  // find max and second max, 2n
1085  for( idx=0; idx<targets.size; idx++ )
1086  {
1087  assert( isdefined( targets[idx].threatlevel ), "Target player does not have threat level" );
1088  if( targets[idx].threatlevel >= highest )
1089  {
1090  highest = targets[idx].threatlevel;
1091  primaryTarget = targets[idx];
1092  }
1093  }
1094 
1095  assert( isdefined( primaryTarget ), "Targets exist, but none was assigned as primary" );
1096  self.primaryTarget = primaryTarget;
1097  self notify( "primary acquired" );
1098 }
1099 
1100 // assign targets to primary and secondary
1101 function ‪assignSecondaryTargets( targets )
1102 {
1103  for( idx = 0; idx < targets.size; idx++ )
1104  {
1105  if( !isdefined( targets[idx].type ) || targets[idx].type != "dog" )
1106  {
1107  self ‪killstreaks::update_missile_player_threat ( targets[idx] );
1108  }
1109  else if( targets[idx].type == "dog" || targets[0].type == "tank_drone")
1110  {
1112  }
1113  }
1114 
1115  assert( targets.size >= 2, "Not enough targets to assign primary and secondary" );
1116 
1117  // find primary target, highest threat level
1118  highest = 0;
1119  second_highest = 0;
1120  primaryTarget = undefined;
1121  secondaryTarget = undefined;
1122 
1123  // find max and second max, 2n
1124  for( idx=0; idx<targets.size; idx++ )
1125  {
1126  assert( isdefined( targets[idx].missilethreatlevel ), "Target player does not have threat level" );
1127  if( targets[idx].missilethreatlevel >= highest )
1128  {
1129  highest = targets[idx].missilethreatlevel;
1130  secondaryTarget = targets[idx];
1131  }
1132  }
1133 
1134  assert( isdefined( secondaryTarget ), "1+ targets exist, but none was assigned as secondary" );
1135  self.secondaryTarget = secondaryTarget;
1136  self notify( "secondary acquired" );
1137 
1138 
1139  //TODO Maybe missiles do not target the ones on the primary list?
1140  //assert( self.secondaryTarget != self.primaryTarget, "Primary and secondary targets are the same" );
1141 }
1142 
1143 // resets helicopter's motion values
1144 function ‪heli_reset()
1145 {
1146  self clearTargetYaw();
1147  self clearGoalYaw();
1148  self setspeed( 60, 25 );
1149  self setyawspeed( 75, 45, 45 );
1150  //self setjitterparams( (30, 30, 30), 4, 6 );
1151  self setmaxpitchroll( 30, 30 );
1152  self setneargoalnotifydist( 256 );
1153  self setturningability(0.9);
1154 }
1155 
1156 function ‪heli_wait( waittime )
1157 {
1158  self endon ( "death" );
1159  self endon ( "crashing" );
1160  self endon ( "evasive" );
1161 
1162  self thread ‪heli_hover();
1163  wait( waittime );
1164  ‪heli_reset();
1165 
1166  self notify( "stop hover" );
1167 }
1168 
1169 // hover movements
1170 function ‪heli_hover()
1171 {
1172  // stop hover when anything at all happens
1173  self endon( "death" );
1174  self endon( "stop hover" );
1175  self endon( "evasive" );
1176  self endon( "leaving" );
1177  self endon( "crashing" );
1178  randInt = randomint(360);
1179  self setgoalyaw( self.angles[1]+randInt );
1180 
1181 }
1182 
1184 {
1185  self endon( "death" );
1186  self endon( "crashing" );
1187  self endon( "leaving" );
1188 
1189  self.bda = 0;
1190 
1191  while(1)
1192  {
1193  self waittill( "killed", victim );
1194 
1195  if ( !isdefined( self.owner ) || !isdefined( victim ) )
1196  continue;
1197 
1198  if ( self.owner == victim ) // killed himself
1199  continue;
1200 
1201  // no kill confirm on team kill. May want another VO.
1202  if ( level.teamBased && self.owner.team == victim.team )
1203  continue;
1204 
1205  self thread ‪wait_for_bda_timeout();
1206  }
1207 }
1208 
1210 {
1211  self endon( "killed" );
1212 
1213  wait( 2.5 );
1214 
1215  if ( !isdefined( self ) )
1216  return;
1217 
1218  self ‪play_bda_dialog();
1219 }
1220 
1222 {
1223  if (self.bda == 1)
1224  {
1225  bdaDialog = "kill1";
1226  }
1227  else if (self.bda == 2)
1228  {
1229  bdaDialog = "kill2";
1230  }
1231  else if (self.bda == 3)
1232  {
1233  bdaDialog = "kill3";
1234  }
1235  else if (self.bda > 3)
1236  {
1237  bdaDialog = "killMultiple";
1238  }
1239 
1240  self ‪killstreaks::play_pilot_dialog_on_owner( bdaDialog, self.killstreakType, self.killstreak_id );
1241 
1242  self notify( "bda_dialog", bdaDialog );
1243 
1244  self.bda = 0;
1245 }
1246 
1248 {
1249  helicopter = self;
1250  hackedDamageTaken = helicopter.maxhealth - helicopter.hackedHealth;
1251  assert ( hackedDamageTaken > 0 );
1252  if ( hackedDamageTaken > helicopter.damageTaken )
1253  {
1254  helicopter.damageTaken = hackedDamageTaken;
1255  }
1256 }
1257 
1258 function ‪heli_damage_monitor( hardpointtype )
1259 {
1260  helicopter = self;
1261  self endon( "death" );
1262  self endon( "crashing" );
1263 
1264  self.damageTaken = 0;
1265 
1266  last_hit_vo = 0;
1267  hit_vo_spacing = 6000;
1268 
1269  tableHealth = ‪killstreak_bundles::get_max_health( hardpointtype );
1270  if ( isdefined( tableHealth ) )
1271  {
1272  self.maxhealth = tableHealth;
1273  }
1274 
1275  helicopter.hackedHealthUpdateCallback = &‪heli_hacked_health_update;
1276  helicopter.hackedHealth = ‪killstreak_bundles::get_hacked_health( hardpointtype );
1277 
1278  if ( !isdefined( self.attackerData ) )
1279  {
1280  self.attackers = [];
1281  self.attackerData = [];
1282  self.attackerDamage = [];
1283  self.flareAttackerDamage = [];
1284  }
1285 
1286  for( ;; )
1287  {
1288  // this damage is done to self.health which isnt used to determine the helicopter's health, damageTaken is.
1289  self waittill( "damage", ‪damage, attacker, direction, point, type, modelName, tagName, partname, weapon, flags, inflictor, chargeLevel );
1290 
1291  if( !isdefined( attacker ) || !isplayer( attacker ) )
1292  continue;
1293 
1294  heli_friendlyfire = ‪weaponobjects::friendlyFireCheck( self.owner, attacker );
1295  // skip damage if friendlyfire is disabled
1296  if( !heli_friendlyfire )
1297  continue;
1298 
1299  if ( !level.hardcoreMode )
1300  {
1301  if( isdefined( self.owner ) && attacker == self.owner )
1302  continue;
1303 
1304  if ( level.teamBased )
1305  isValidAttacker = (isdefined( attacker.team ) && attacker.team != self.team);
1306  else
1307  isValidAttacker = true;
1308 
1309  if ( !isValidAttacker )
1310  continue;
1311  }
1312 
1313  self.attacker = attacker;
1314 
1315  weapon_damage = ‪killstreak_bundles::get_weapon_damage( hardpointType, self.maxhealth, attacker, weapon, type, ‪damage, flags, chargeLevel );
1316 
1317  if ( !isdefined( weapon_damage ) )
1318  {
1319  if ( type == "MOD_RIFLE_BULLET" || type == "MOD_PISTOL_BULLET" )
1320  {
1321  hasFMJ = attacker HasPerk( "specialty_armorpiercing" );
1322 
1323  if ( hasFMJ )
1324  {
1325  ‪damage += int( ‪damage * level.cac_armorpiercing_data );
1326  }
1327 
1328  ‪damage *= level.heli_armor_bulletdamage;
1329  }
1330  else if( type == "MOD_PROJECTILE" || type == "MOD_PROJECTILE_SPLASH" || type == "MOD_EXPLOSIVE" )
1331  {
1332  shouldUpdateDamage = ( ( weapon.statIndex != level.weaponPistolEnergy.statIndex )
1333  && ( weapon.statIndex != level.weaponSpecialCrossbow.statIndex )
1334  && ( weapon.statIndex != level.weaponSmgNailGun.statIndex ) );
1335 
1336  if ( shouldUpdateDamage )
1337  {
1338  switch ( weapon.name )
1339  {
1340  case "tow_turret":
1341  if( isdefined( self.rocketDamageTwoShot ) )
1342  {
1343  // 2 shot kill
1344  ‪damage = self.rocketDamageTwoShot;
1345  }
1346  else if( isdefined( self.rocketDamageOneShot ) )
1347  {
1348  // 1 shot kill
1349  ‪damage = self.rocketDamageOneShot;
1350  }
1351  break;
1352  default:
1353  if( isdefined( self.rocketDamageOneShot ) )
1354  {
1355  // 1 shot kill
1356  ‪damage = self.rocketDamageOneShot;
1357  }
1358  break;
1359  }
1360  }
1361  }
1362 
1363  weapon_damage = ‪damage;
1364  }
1365 
1366  if ( weapon_damage > 0 )
1367  self ‪challenges::trackAssists( attacker, weapon_damage, false );
1368 
1369  self.damageTaken += weapon_damage;
1370 
1371  playerControlled = false;
1372 
1373  if( self.damageTaken > self.maxhealth && !isdefined(self.xpGiven) )
1374  {
1375  self.xpGiven = true;
1376 
1377  switch( hardpointtype )
1378  {
1379  case "helicopter_gunner":
1380  playerControlled = true;
1381  event = "destroyed_vtol_mothership";
1382  break;
1383  case "helicopter_comlink":
1384  case "inventory_helicopter_comlink":
1385  event = "destroyed_helicopter_comlink";
1386  if ( self.leaving !== true )
1387  {
1388  self ‪killstreaks::play_destroyed_dialog_on_owner( self.killstreakType, self.killstreak_id );
1389  }
1390  break;
1391  case "supply_drop":
1392  case "supply_drop_combat_robot":
1393  if( isdefined( helicopter.killstreakWeaponName ) )
1394  {
1395  switch( helicopter.killstreakWeaponName )
1396  {
1397  case "inventory_ai_tank_drop":
1398  case "ai_tank_drop":
1399  case "inventory_ai_tank_marker":
1400  case "ai_tank_drop_marker":
1401  case "ai_tank_marker":
1402  {
1403  event = "destroyed_helicopter_agr_drop";
1404  }
1405  break;
1406  case "combat_robot_drop":
1407  case "inventory_combat_robot_drop":
1408  case "combat_robot_marker":
1409  case "inventory_combat_robot_marker":
1410  {
1411  event = "destroyed_helicopter_giunit_drop";
1412  }
1413  break;
1414  default:
1415  {
1416  event = "destroyed_helicopter_supply_drop";
1417  }
1418  break;
1419  }
1420  }
1421  else
1422  {
1423  event = "destroyed_helicopter_supply_drop";
1424  }
1425  break;
1426  }
1427 
1428  if ( isdefined( event ) )
1429  {
1430  if( isdefined( self.owner ) && self.owner ‪util::IsEnemyPlayer( attacker ) )
1431  {
1432  ‪challenges::destroyedHelicopter( attacker, weapon, type, false );
1433  ‪challenges::destroyedAircraft( attacker, weapon, playerControlled );
1434  ‪scoreevents::processScoreEvent( event, attacker, self.owner, weapon );
1435  attacker ‪challenges::addFlySwatterStat( weapon, self );
1436  if ( playerControlled == true )
1437  {
1439  }
1440  if ( hardpointtype == "helicopter_player_gunner" )
1441  {
1442  attacker AddWeaponStat( weapon, "destroyed_controlled_killstreak", 1 );
1443  }
1444  }
1445  else
1446  {
1447  //Destroyed Friendly Killstreak
1448  }
1449  }
1450 
1451  // do give stats to killstreak weapons
1452  // we need the kill stat so that we know how many kills the weapon has gotten (even on helicopters) for challenges
1453  // we need the destroyed stat for the same reason as the kill stat and these have different challenges associated
1454  //attacker _properks::destroyedKillstreak();
1455 
1456  weaponStatName = "destroyed";
1457  switch( weapon.name )
1458  {
1459  // SAM Turrets keep the kills stat for shooting things down because we used destroyed for when you destroy a SAM Turret
1460  case "auto_tow":
1461  case "tow_turret":
1462  case "tow_turret_drop":
1463  weaponStatName = "kills";
1464  break;
1465  }
1466  attacker AddWeaponStat( weapon, weaponStatName, 1 );
1467 
1468  notifyString = undefined;
1469  killstreakReference = undefined;
1470  switch( hardpointtype )
1471  {
1472  case "helicopter_gunner":
1473  killstreakReference = "killstreak_helicopter_gunner";
1474  break;
1475  case "helicopter_player_gunner":
1476  killstreakReference = "killstreak_helicopter_player_gunner";
1477  break;
1478  case "helicopter_player_firstperson":
1479  killstreakReference = "killstreak_helicopter_player_firstperson";
1480  break;
1481  case "helicopter_comlink":
1482  case "inventory_helicopter_comlink":
1483  case "helicopter":
1484  case "helicopter_x2":
1485  notifyString = &"KILLSTREAK_DESTROYED_HELICOPTER";
1486  killstreakReference = "killstreak_helicopter_comlink";
1487  break;
1488  case "supply_drop":
1489  notifyString = &"KILLSTREAK_DESTROYED_SUPPLY_DROP_DEPLOY_SHIP";
1490  killstreakReference = "killstreak_supply_drop";
1491  break;
1492  case "helicopter_guard":
1493  killstreakReference = "killstreak_helicopter_guard";
1494  }
1495 
1496  // increment the destroyed stat for this, we aren't using the weaponStatName variable from above because it could be "kills" and we don't want that
1497  if( isdefined( killstreakReference ) )
1498  {
1499  level.globalKillstreaksDestroyed++;
1500  attacker AddWeaponStat( GetWeapon( hardpointtype ), "destroyed", 1 );
1501  }
1502 
1503  if( hardpointtype == "helicopter_player_gunner" )
1504  {
1505  self.owner SendKillstreakDamageEvent( 600 );
1506  }
1507 
1508  if ( isdefined( notifyString ) )
1509  {
1510  LUINotifyEvent( &"player_callout", 2, notifyString, attacker.entnum );
1511  }
1512 
1513  if ( isdefined( self.attackers ) )
1514  {
1515  for ( j = 0; j < self.attackers.size; j++ )
1516  {
1517  player = self.attackers[j];
1518 
1519  if ( !isdefined( player ) )
1520  continue;
1521 
1522  if ( player == attacker )
1523  continue;
1524 
1525  flare_done = self.flareAttackerDamage[player.clientId];
1526  if ( isdefined ( flare_done ) && flare_done == true )
1527  {
1528  ‪scoreevents::processScoreEvent( "aircraft_flare_assist", player );
1529  }
1530  else
1531  {
1532  damage_done = self.attackerDamage[player.clientId];
1533  player thread ‪processCopterAssist( self, damage_done);
1534  }
1535  }
1536  self.attackers = [];
1537  }
1538  attacker notify( "destroyed_helicopter" );
1539 
1540  if( Target_IsTarget( self ) )
1541  {
1542  Target_remove( self );
1543  }
1544  }
1545  else if ( isdefined( self.owner ) && IsPlayer( self.owner ) )
1546  {
1547  if ( last_hit_vo + hit_vo_spacing < GetTime() )
1548  {
1549  if ( type == "MOD_PROJECTILE" || RandomIntRange(0,3) == 0 )
1550  {
1551  // TODO CDC - change to new pilot dialog
1552  //self.owner PlayLocalSound(level.heli_vo[self.team]["hit"]);
1553  last_hit_vo = GetTime();
1554  }
1555  }
1556  }
1557 
1558  if( ( hardpointtype == "helicopter_comlink" ) || ( hardpointtype == "inventory_helicopter_comlink" ) )
1559  {
1561  }
1562  }
1563 }
1564 
1566 {
1567  heli = self;
1568  heli.active_camo_supported = true;
1569  heli.active_camo_damage = 0;
1570  heli.active_camo_disabled = false;
1571  heli.camo_state = ‪HELICOPTER_CAMO_STATE_OFF;
1573 
1574  if( isdefined( heli.flak_drone ) )
1575  {
1577  }
1578 }
1579 
1581 {
1582  heli = self;
1583 
1584  if( !isdefined( heli.active_camo_supported ) )
1585  {
1586  return;
1587  }
1588 
1589  if( state == ‪HELICOPTER_CAMO_STATE_OFF )
1590  {
1591  //Target_Set( heli, heli.target_offset );
1592  heli ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_OFF );
1593  if( heli.camo_state == ‪HELICOPTER_CAMO_STATE_ON )
1594  heli playsound ("veh_hind_cloak_off");
1595  heli.camo_state = ‪HELICOPTER_CAMO_STATE_OFF;
1596  heli.camo_state_switch_time = gettime();
1597  }
1598  else if( state == ‪HELICOPTER_CAMO_STATE_ON )
1599  {
1600  if( heli.active_camo_disabled )
1601  {
1602  return;
1603  }
1604 
1605  //if( Target_IsTarget( heli ) )
1606  //{
1607  //Target_Remove( heli );
1608  //}
1609 
1610  heli ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_ON );
1611 
1612  if( heli.camo_state == ‪HELICOPTER_CAMO_STATE_OFF )
1613  heli playsound ("veh_hind_cloak_on");
1614  heli.camo_state = ‪HELICOPTER_CAMO_STATE_ON;
1615  heli.camo_state_switch_time = gettime();
1616 
1617  if ( isdefined( heli.owner ) )
1618  {
1619  if ( isdefined( heli.play_camo_dialog ) && heli.play_camo_dialog )
1620  {
1621  heli ‪killstreaks::play_pilot_dialog_on_owner( "activateCounter", "helicopter_comlink", self.killstreak_id );
1622  // Only play the cloak line once
1623  heli.play_camo_dialog = false;
1624  }
1625  else if ( !isdefined( heli.play_camo_dialog ) )
1626  {
1627  // Don't play camo dialog when initializing the copter
1628  heli.play_camo_dialog = true;
1629  }
1630  }
1631  }
1632  else if( state == ‪HELICOPTER_CAMO_STATE_FLICKER )
1633  {
1634  heli ‪clientfield::set( "toggle_lights", ‪CF_TOGGLE_LIGHTS_OFF );
1635  }
1636 
1637  if( isdefined( heli.flak_drone ) )
1638  {
1639  heli.flak_drone ‪flak_drone::SetCamoState( state );
1640  }
1641 
1642  heli ‪clientfield::set( "active_camo", state );
1643 }
1644 
1646 {
1647  self endon( "death" );
1648  self endon( "crashing" );
1649 
1650  heli = self;
1651 
1652  heli.active_camo_damage += ‪damage;
1653 
1654  if( heli.active_camo_damage > ‪HELICOPTER_CAMO_DAMAGE_LIMIT )
1655  {
1656  heli.active_camo_disabled = true;
1657  heli thread ‪heli_active_camo_damage_disable();
1658  }
1659  else
1660  {
1664  }
1665 }
1666 
1668 {
1669  self endon( "death" );
1670  self endon( "crashing" );
1671 
1672  heli = self;
1673  heli notify( "heli_active_camo_damage_disable" );
1674  heli endon( "heli_active_camo_damage_disable" );
1675 
1677 
1679 
1680  heli.active_camo_damage = 0;
1681  heli.active_camo_disabled = false;
1683 }
1684 
1685 function ‪heli_health( hardpointType, playerNotify )
1686 {
1687  self endon( "death" );
1688  self endon( "crashing" );
1689 
1690  self.currentstate = "ok";
1691  self.laststate = "ok";
1692  self setdamagestage( 3 );
1693  damageState = 3;
1694 
1695  tableHealth = ‪killstreak_bundles::get_max_health( hardpointType );
1696 
1697  if ( isdefined( tableHealth ) )
1698  {
1699  self.maxhealth = tableHealth;
1700  }
1701 
1702  for ( ;; )
1703  {
1704  self waittill( "damage", ‪damage, attacker, direction, point, type, modelName, tagName, partname, weapon );
1706 
1707  if( self.damageTaken > self.maxhealth )
1708  {
1709  damageState = 0;
1710  self setDamageStage( damageState );
1711 
1713 
1714  self thread ‪heli_crash( hardpointType, self.owner, playerNotify );
1715  }
1716  else if ( self.damageTaken >= (self.maxhealth * 0.66) && damageState >= 2 )
1717  {
1718  self ‪killstreaks::play_pilot_dialog_on_owner( "damaged", "helicopter_comlink", self.killstreak_id );
1719 
1720  //self setdamagestage( 1 );
1721  if ( isdefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" )
1722  {
1723  PlayFXOnTag( level.chopper_fx["damage"]["heavy_smoke"], self, "tag_origin");
1724  }
1725  else
1726  {
1727  PlayFXOnTag( level.chopper_fx["damage"]["heavy_smoke"], self, "tag_main_rotor");
1728  }
1729  damageState = 1;
1730  self.currentstate = "heavy smoke";
1731  self.evasive = true;
1732  self notify("damage state");
1733  }
1734  else if ( self.damageTaken >= (self.maxhealth * 0.33) && damageState == 3 )
1735  {
1736  //self setdamagestage( 2 );
1737  if ( isdefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" )
1738  {
1739  PlayFXOnTag( level.chopper_fx["damage"]["light_smoke"], self, "tag_origin");
1740  }
1741  else
1742  {
1743  PlayFXOnTag( level.chopper_fx["damage"]["light_smoke"], self, "tag_main_rotor");
1744  }
1745  damageState = 2;
1746  self.currentstate = "light smoke";
1747  self notify("damage state");
1748  }
1749  }
1750 }
1751 
1752 // evasive manuvering - helicopter circles the map for awhile then returns to path
1753 function ‪heli_evasive( hardpointType )
1754 {
1755  // only one instance allowed
1756  self notify( "evasive" );
1757 
1758  self.evasive = true;
1759 
1760  // set helicopter path to circle the map level.heli_loopmax number of times
1761  loop_startnode = level.heli_loop_paths[0];
1762 
1763  gunnerPathFound = true;
1764  if ( hardpointType == "helicopter_gunner" )
1765  {
1766  gunnerPathFound = false;
1767  for ( i = 0 ; i < level.heli_loop_paths.size ; i++ )
1768  {
1769  if ( isdefined( level.heli_loop_paths[i].isGunnerPath ) && level.heli_loop_paths[i].isGunnerPath )
1770  {
1771  loop_startnode = level.heli_loop_paths[i];
1772  gunnerPathFound = true;
1773  break;
1774  }
1775  }
1776  }
1777  assert( gunnerPathFound, "No chopper gunner loop paths found in map" );
1778 
1779  startwait = 2;
1780  if ( isdefined( self.doNotStop ) && self.doNotStop )
1781  startwait = 0;
1782 
1783  self thread ‪heli_fly( loop_startnode, startwait, hardpointType );
1784 }
1785 
1786 function ‪notify_player( player, playerNotify, ‪delay )
1787 {
1788  if ( !isdefined(player) )
1789  return;
1790 
1791  if ( !isdefined(playerNotify) )
1792  return;
1793 
1794  player endon( "disconnect" );
1795  player endon( playerNotify );
1796 
1797  wait (‪delay);
1798 
1799  player notify( playerNotify );
1800 }
1801 
1803 {
1804  self.owner endon( "disconnect" );
1805  self endon( "death" );
1806 
1807  wait (‪delay);
1808 }
1809 
1810 // attach helicopter on crash path
1811 function ‪heli_crash( hardpointType, player, playerNotify )
1812 {
1813  self endon( "death" );
1814  self notify( "crashing" );
1815 
1817 
1818  self stoploopsound(0);
1819  if( isdefined( self.minigun_snd_ent ) )
1820  {
1821  self.minigun_snd_ent StopLoopSound();
1822  }
1823  if( isdefined( self.alarm_snd_ent ) )
1824  {
1825  self.alarm_snd_ent StopLoopSound();
1826  }
1827 
1828  //TODO : Play crash alert vo CDC
1829 
1830  // these types are for the chopper and player controlled heli
1831  crashTypes = [];
1832  crashTypes[0] = "crashOnPath";
1833  crashTypes[1] = "spinOut";
1834 
1835  crashType = crashTypes[randomInt(2)];
1836 
1837  // ai chopper should just explode
1838  if ( isdefined( self.crashType ) )
1839  crashType = self.crashType;
1840 
1841  switch (crashType)
1842  {
1843  case "explode":
1844  {
1845  thread ‪notify_player( player, playerNotify, 0 );
1846  self thread ‪heli_explode();
1847  }
1848  break;
1849  case "crashOnPath":
1850  {
1851  if ( isdefined( player ) )
1852  self thread ‪play_going_down_vo( 0.5 );
1853 
1854  thread ‪notify_player( player, playerNotify, 4 );
1855  self ‪clear_client_flags();
1856  self thread ‪crashOnNearestCrashPath( hardpointType );
1857  }
1858  break;
1859  case "spinOut":
1860  {
1861  if ( isdefined( player ) )
1862  self thread ‪play_going_down_vo( 0.5 );
1863  thread ‪notify_player( player, playerNotify, 4 );
1864  self ‪clear_client_flags();
1865 
1866  ‪heli_reset();
1867 
1868  heli_speed = 30+randomInt(50);
1869  heli_accel = 10+randomInt(25);
1870 
1871  // helicopter leaves randomly towards one of the leave origins
1872  leavenode = ‪getValidRandomCrashNode( self.origin );
1873  // movement change due to damage
1874  self setspeed( heli_speed, heli_accel );
1875  self ‪set_goal_pos( (leavenode.origin), 0 );
1876 
1877  rateOfSpin = 45 + randomint(90);
1878 
1880 
1881  // helicopter losing control and spins
1882  self thread ‪heli_spin( rateOfSpin );
1883  //TODO : pilot call in VO
1884 
1885 
1886  self ‪util::waittill_any_timeout( RandomIntRange(4, 6), "near_goal" ); //self waittillmatch( "goal" );
1887 
1888  if ( isdefined( player ) && isdefined( playerNotify ) )
1889  player notify( playerNotify ); // make sure
1890  self thread ‪heli_explode();
1891  }
1892  break;
1893  }
1894 
1895  self thread ‪explodeOnContact( hardpointtype );
1896 
1897  time = randomIntRange(4, 6);
1898  self thread ‪waitThenExplode( time );
1899 }
1900 
1902 {
1903  self endon ( "death" );
1904  self SetRotorSpeed( 0.6 );
1905 }
1906 
1907 function ‪waitThenExplode( time )
1908 {
1909  self endon( "death" );
1910 
1911  wait( time );
1912 
1913  self thread ‪heli_explode();
1914 }
1915 
1916 function ‪crashOnNearestCrashPath( hardpointType )
1917 {
1918  crashPathDistance = -1;
1919  crashPath = level.heli_crash_paths[0];
1920  for ( i = 0; i < level.heli_crash_paths.size; i++ )
1921  {
1922  currentDistance = distance(self.origin, level.heli_crash_paths[i].origin);
1923  if ( crashPathDistance == -1 || crashPathDistance > currentDistance )
1924  {
1925  crashPathDistance = currentDistance;
1926  crashPath = level.heli_crash_paths[i];
1927  }
1928  }
1929 
1930  heli_speed = 30+randomInt(50);
1931  heli_accel = 10+randomInt(25);
1932 
1933  // movement change due to damage
1934  self setspeed( heli_speed, heli_accel );
1935 
1937 
1938  // fly to crash path
1939  self thread ‪heli_fly( crashPath, 0, hardpointType );
1940 
1941  rateOfSpin = 45 + randomint(90);
1942 
1943  // helicopter losing control and spins
1944  self thread ‪heli_spin( rateOfSpin );
1945 
1946  // wait until helicopter is on the crash path
1947  self waittill ( "path start" );
1948 
1949 
1950  self waittill( "destination reached" );
1951  self thread ‪heli_explode();
1952 }
1953 
1954 //This is a temporary solution for playing fx while we are switching to new models with new tag naming conventions.
1955 function ‪CheckHelicopterTag( tagName )
1956 {
1957  if( isdefined( self.model ) )
1958  {
1959  if( self.model == "veh_t7_drone_hunter" )
1960  {
1961  switch( tagName )
1962  {
1963  case "tag_engine_left":
1964  return "tag_fx_exhaust2";
1965  case "tag_engine_right":
1966  return "tag_fx_exhaust1";
1967  case "tail_rotor_jnt":
1968  return "tag_fx_tail";
1969  default:
1970  break;
1971  }
1972  }
1973  }
1974 
1975  return tagName;
1976 }
1977 
1979 {
1980  self endon( "death" );
1981 
1982  playFxOnTag( level.chopper_fx["explode"]["large"], self, self ‪CheckHelicopterTag( "tag_engine_left" ) );
1983 // self playSound ( level.heli_sound["hitsecondary"] );
1984  self playSound ( level.heli_sound["hit"] );
1985 
1986  // form smoke trails on tail after explosion
1987  if ( isdefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" )
1988  {
1989  self thread ‪trail_fx( level.chopper_fx["smoke"]["trail"], self ‪CheckHelicopterTag( "tag_engine_right" ), "stop tail smoke" );
1990  }
1991  else
1992  {
1993  self thread ‪trail_fx( level.chopper_fx["smoke"]["trail"], self ‪CheckHelicopterTag( "tail_rotor_jnt" ), "stop tail smoke" );
1994  }
1995 
1996  self setdamagestage( 0 );
1997  // form fire smoke trails on body after explosion
1998  self thread ‪trail_fx( level.chopper_fx["fire"]["trail"]["large"], self ‪CheckHelicopterTag( "tag_engine_left" ), "stop body fire" );
1999 
2000  wait ( 3.0 );
2001 
2002  if ( !isdefined( self ) )
2003  return;
2004 
2005  playFxOnTag( level.chopper_fx["explode"]["large"], self, self ‪CheckHelicopterTag( "tag_engine_left" ) );
2006  self playSound ( level.heli_sound["hitsecondary"] );
2007 }
2008 
2009 // self spin at one rev per 2 sec
2010 function ‪heli_spin( speed )
2011 {
2012  self endon( "death" );
2013 
2014  // tail explosion that caused the spinning
2015 // playfxontag( level.chopper_fx["explode"]["medium"], self, "tail_rotor_jnt" );
2016  // play hit sound immediately so players know they got it
2017 
2018  // play heli crashing spinning sound
2019  self thread ‪spinSoundShortly();
2020 
2021  // spins until death
2022  self setyawspeed( speed, speed / 3 , speed / 3 );
2023  while ( isdefined( self ) )
2024  {
2025  self settargetyaw( self.angles[1]+(speed*0.9) );
2026  wait ( 1 );
2027  }
2028 }
2029 
2031 {
2032  self endon( "death" );
2033 
2034  wait .25;
2035 
2036  self stopLoopSound();
2037  wait .05;
2038  self playLoopSound( level.heli_sound["spinloop"] );
2039  wait .05;
2040  self playSound( level.heli_sound["spinstart"] );
2041 }
2042 
2043 function ‪trail_fx( ‪trail_fx, trail_tag, stop_notify )
2044 {
2045  playfxontag( ‪trail_fx, self, trail_tag );
2046 }
2047 
2049 {
2050  team = self.originalteam;
2051 
2052  if ( Target_IsTarget(self) )
2053  Target_remove( self );
2054 
2056 
2057  if( isdefined( self.interior_model ) )
2058  {
2059  self.interior_model Delete();
2060  self.interior_model = undefined;
2061  }
2062  if( isdefined( self.minigun_snd_ent ) )
2063  {
2064  self.minigun_snd_ent StopLoopSound();
2065  self.minigun_snd_ent Delete();
2066  self.minigun_snd_ent = undefined;
2067  }
2068  if( isdefined( self.alarm_snd_ent ) )
2069  {
2070  self.alarm_snd_ent Delete();
2071  self.alarm_snd_ent = undefined;
2072  }
2073  if ( isdefined( self.flare_ent ) )
2074  {
2075  self.flare_ent Delete();
2076  self.flare_ent = undefined;
2077  }
2078 
2079  ‪killstreakrules::killstreakStop( self.hardpointType, team, self.killstreak_id );
2080 
2081  self delete();
2082 }
2083 
2084 // crash explosion
2086 {
2087  self endon( "death" );
2088 
2089  forward = ( self.origin + ( 0, 0, 100 ) ) - self.origin;
2090  if( isdefined(self.helitype) && self.helitype == "littlebird" )
2091  {
2092  playfx( level.chopper_fx["explode"]["guard"], self.origin, forward );
2093  }
2094  else if ( isdefined( self.vehicletype ) && self.vehicletype == "heli_player_gunner_mp" )
2095  {
2096  playfx( level.chopper_fx["explode"]["gunner"], self.origin, forward );
2097  }
2098  else
2099  {
2100  playfx( level.chopper_fx["explode"]["death"], self.origin, forward );
2101  }
2102 
2103  // play heli explosion sound
2104  self PlaySound ( level.heli_sound["crash"] );
2105 
2106  wait( 0.1 );
2107 
2108  assert( isdefined( self.destroyFunc ) );
2109  self [[self.destroyFunc]]();
2110 }
2111 
2113 {
2114  self ‪clientfield::set( "heli_warn_fired", 0 );
2115  self ‪clientfield::set( "heli_warn_targeted", 0 );
2116  self ‪clientfield::set( "heli_warn_locked", 0 );
2117 }
2118 
2119 // helicopter leaving parameter, can not be damaged while leaving
2120 function ‪heli_leave()
2121 {
2122  self notify( "destintation reached" );
2123  self notify( "leaving" );
2124 
2125  hardpointType = self.hardpointType;
2126 
2127  self.leaving = true;
2128 
2129  if( !‪IS_TRUE( self.detroyScoreEventGiven ) )
2130  {
2131  self ‪killstreaks::play_pilot_dialog_on_owner( "timeout", hardpointType );
2132  self ‪killstreaks::play_taacom_dialog_response_on_owner( "timeoutConfirmed", hardpointType );
2133  }
2134 
2135  // helicopter leaves randomly towards one of the leave origins
2136  leavenode = ‪getValidRandomLeaveNode( self.origin );
2137 
2138  ‪heli_reset();
2139  self ClearLookAtEnt();
2140  exitAngles = VectorToAngles(leavenode.origin - self.origin);
2141  self SetGoalYaw( exitAngles[1] );
2142  wait ( 1.5 );
2143 
2144  if ( !isdefined( self ) )
2145  {
2146  return;
2147  }
2148 
2149  self setspeed( 180, 65 );
2150 
2151 
2152  self ‪set_goal_pos( self.origin + ( leavenode.origin - self.origin ) / 2 + ( 0, 0, ‪HELI_ENTRANCE_Z_HELP ), false );
2153  self waittill( "near_goal" );
2154  if( isdefined( self ) )
2155  {
2156  self ‪set_goal_pos( leavenode.origin, true );
2157  self waittillmatch( "goal" );
2158  if( isdefined( self ) )
2159  {
2160  self stoploopsound(1);
2162  if( isdefined( self.alarm_snd_ent ) )
2163  {
2164  self.alarm_snd_ent StopLoopSound();
2165  self.alarm_snd_ent Delete();
2166  self.alarm_snd_ent = undefined;
2167  }
2168 
2169  assert( isdefined( self.destroyFunc ) );
2170  self [[self.destroyFunc]]();
2171  }
2172  }
2173 }
2174 
2175 // flys helicopter from given start node to a destination on its path
2176 function ‪heli_fly( currentnode, startwait, hardpointType )
2177 {
2178  self endon( "death" );
2179  self endon( "leaving" );
2180 
2181  // only one thread instance allowed
2182  self notify( "flying" );
2183  self endon( "flying" );
2184 
2185  // if owner switches teams, helicopter should leave
2186  self endon( "abandoned" );
2187 
2188  self.reached_dest = false;
2189  ‪heli_reset();
2190 
2191  pos = self.origin;
2192  wait( startwait );
2193 
2194  while ( isdefined( currentnode.target ) )
2195  {
2196  nextnode = getent( currentnode.target, "targetname" );
2197  assert( isdefined( nextnode ), "Next node in path is undefined, but has targetname" );
2198 
2199  // offsetted
2200  pos = nextnode.origin+(0,0,30);
2201 
2202  // motion change via node
2203  if( isdefined( currentnode.script_airspeed ) && isdefined( currentnode.script_accel ) )
2204  {
2205  heli_speed = currentnode.script_airspeed;
2206  heli_accel = currentnode.script_accel;
2207  }
2208  else
2209  {
2210  heli_speed = 30+randomInt(20);
2211  heli_accel = 10+randomInt(5);
2212  }
2213 
2214  if ( isdefined( self.pathSpeedScale ) )
2215  {
2216  heli_speed *= self.pathSpeedScale;
2217  heli_accel *= self.pathSpeedScale;
2218  }
2219 
2220  // fly nonstop until final destination
2221  if ( !isdefined( nextnode.target ) )
2222  ‪stop = 1;
2223  else
2224  ‪stop = 0;
2225 
2226  // if in damaged state, do not stop at any node other than destination
2227  if( self.currentstate == "heavy smoke" || self.currentstate == "light smoke" )
2228  {
2229  // movement change due to damage
2230  self setspeed( heli_speed, heli_accel );
2231  self ‪set_goal_pos( (pos), ‪stop );
2232 
2233  self waittill( "near_goal" ); //self waittillmatch( "goal" );
2234  self notify( "path start" );
2235  }
2236  else
2237  {
2238  // if the node has helicopter stop time value, we stop
2239  if( isdefined( nextnode.script_delay ) && !isdefined( self.doNotStop ) )
2240  ‪stop = 1;
2241 
2242  self setspeed( heli_speed, heli_accel );
2243  self ‪set_goal_pos( (pos), ‪stop );
2244 
2245  if ( !isdefined( nextnode.script_delay ) || isdefined( self.doNotStop ) )
2246  {
2247  self waittill( "near_goal" ); //self waittillmatch( "goal" );
2248  self notify( "path start" );
2249  }
2250  else
2251  {
2252  // post beta addition --- (
2253  self setgoalyaw( nextnode.angles[1] );
2254  // post beta addition --- )
2255 
2256  self waittillmatch( "goal" );
2257  ‪heli_wait( nextnode.script_delay );
2258  }
2259  }
2260 
2261  // increment loop count when helicopter is circling the map
2262  for( index = 0; index < level.heli_loop_paths.size; index++ )
2263  {
2264  if ( level.heli_loop_paths[index].origin == nextnode.origin )
2265  self.loopcount++;
2266  }
2267  if( self.loopcount >= level.heli_loopmax )
2268  {
2269  self thread ‪heli_leave();
2270  return;
2271  }
2272  currentnode = nextnode;
2273  }
2274 
2275  self setgoalyaw( currentnode.angles[1] );
2276  self.reached_dest = true; // sets flag true for helicopter circling the map
2277  self notify ( "destination reached" );
2278  // wait at destination
2279  if ( isdefined( self.waittime ) && self.waittime > 0 )
2280  ‪heli_wait( self.waittime );
2281 
2282  // if still alive, switch to evasive manuvering
2283  if( isdefined( self ) )
2284  self thread ‪heli_evasive( hardpointType );
2285 }
2286 
2287 function ‪heli_random_point_in_radius( protectDest, nodeHeight )
2288 {
2289  min_distance = Int(level.heli_protect_radius * .2);
2290  direction = randomintrange(0,360);
2291  distance = randomintrange(min_distance, level.heli_protect_radius);
2292 
2293  x = cos(direction);
2294  y = sin(direction);
2295  x = x * distance;
2296  y = y * distance;
2297 
2298  return (protectDest[0] + x, protectDest[1] + y, nodeHeight);
2299 }
2300 
2301 function ‪heli_get_protect_spot(protectDest, nodeHeight)
2302 {
2303  protect_spot = ‪heli_random_point_in_radius( protectDest, nodeHeight );
2304 
2305  tries = 10;
2306  noFlyZone = ‪airsupport::crossesNoFlyZone( protectDest, protect_spot );
2307  while( tries != 0 && isdefined( noFlyZone ) )
2308  {
2309  protect_spot = ‪heli_random_point_in_radius( protectDest, nodeHeight );
2310  tries--;
2311  noFlyZone = ‪airsupport::crossesNoFlyZone( protectDest, protect_spot );
2312  }
2313 
2314  noFlyZoneHeight = ‪airsupport::getNoFlyZoneHeightCrossed( protectDest, protect_spot, nodeHeight );
2315  return ( protect_spot[0], protect_spot[1], noFlyZoneHeight );
2316 }
2317 
2318 function ‪wait_or_waittill( time, msg1, msg2, msg3 )
2319 {
2320  self endon( msg1 );
2321  self endon( msg2 );
2322  self endon( msg3 );
2323  wait( time );
2324  return true;
2325 }
2326 
2328 {
2329  self setmaxpitchroll( 30, 30 );
2330  heli_speed = 30+randomInt(20);
2331  heli_accel = 10+randomInt(5);
2332  self setspeed( heli_speed, heli_accel );
2333  self setyawspeed( 75, 45, 45 );
2334 }
2335 
2337 {
2338  self setmaxpitchroll( 30, 90 );
2339  heli_speed = 50+randomInt(20);
2340  heli_accel = 30+randomInt(5);
2341  self setspeed( heli_speed, heli_accel );
2342  self setyawspeed( 100, 75, 75 );
2343 }
2344 
2346 {
2347  self setmaxpitchroll( 0, 90 );
2348  self setspeed( 20, 10 );
2349  self setyawspeed( 55, 25, 25 );
2350 }
2351 
2352 
2353 function ‪is_targeted()
2354 {
2355  if ( isdefined(self.locking_on) && self.locking_on )
2356  return true;
2357 
2358  if ( isdefined(self.locked_on) && self.locked_on )
2359  return true;
2360 
2361  if ( isdefined(self.locking_on_hacking) && self.locking_on_hacking )
2362  return true;
2363 
2364  return false;
2365 }
2366 
2367 function ‪heli_mobilespawn( protectDest )
2368 {
2369  self endon( "death" );
2370 
2371  self notify( "flying" );
2372  self endon( "flying" );
2373 
2374  self endon( "abandoned" );
2375 
2376  IPrintLnBold( "PROTECT ORIGIN: ("+protectDest[0]+","+protectDest[1]+","+protectDest[2]+")\n" );
2377 
2378  ‪heli_reset();
2379 
2380  self SetHoverParams( 50, 100, 50 );
2381 
2382  wait( 2 );
2383 
2385 
2386  self ‪set_goal_pos( protectDest, 1 );
2387 
2388  self waittill( "near_goal" );
2389 
2391 }
2392 
2393 // flys helicopter from given start node to a destination on its path
2394 function ‪heli_protect( startNode, protectDest, hardpointType, heli_team )
2395 {
2396  self endon( "death" );
2397 
2398  // only one thread instance allowed
2399  self notify( "flying" );
2400  self endon( "flying" );
2401 
2402  // if owner switches teams, helicopter should leave
2403  self endon( "abandoned" );
2404 
2405  self.reached_dest = false;
2406  ‪heli_reset();
2407 
2408  self SetHoverParams( 50, 100, 50);
2409 
2410  wait( 2 );
2411 
2412  currentDest = protectDest;
2413 
2414  nodeHeight = protectDest[2];
2415 
2416  nextnode = startNode;
2417 
2418  heightOffset = 0;
2419  if ( heli_team == "axis" )
2420  {
2421  heightOffset = 400;
2422  }
2423 
2424  protectDest = ( protectDest[0], protectDest[1], nodeHeight );
2425  noFlyZoneHeight = ‪airsupport::getNoFlyZoneHeight( protectDest );
2426  protectDest = ( protectDest[0], protectDest[1], noFlyZoneHeight + heightOffset );
2427  currentDest = protectDest;
2428  ‪startTime = gettime();
2429  self.endTime = ‪startTime + ( level.heli_protect_time * 1000 );
2430  self.killstreakEndTime = int( self.endTime );
2431 
2432  self SetSpeed( 150, 80 );
2433 
2434  self ‪set_goal_pos( self.origin + ( currentDest - self.origin ) / 3 + ( 0, 0, ‪HELI_ENTRANCE_Z_HELP ), false );
2435  self waittill( "near_goal" );
2436 
2437  heli_speed = 30+randomInt(20);
2438  heli_accel = 10+randomInt(5);
2439 
2440  self thread ‪updateTargetYaw();
2441 
2442  mapEnter = true;
2443 
2444  while ( getTime() < self.endTime )
2445  {
2446  ‪stop = 1;
2447 
2448  if( !mapEnter )
2449  {
2450  self ‪updateSpeed();
2451  }
2452  else
2453  {
2454  mapEnter = false;
2455  }
2456 
2457  // movement change due to damage
2458  self ‪set_goal_pos( (currentDest), ‪stop );
2459 
2460  self thread ‪updateSpeedOnLock();
2461  self ‪util::waittill_any( "near_goal", "locking on", "locking on hacking" );
2463  self notify( "path start" );
2464 
2465  if ( !self ‪is_targeted() )
2466  {
2467 
2468  waittillframeend;
2469 
2470  time = level.heli_protect_pos_time;
2471 
2472  if ( self.evasive == true )
2473  {
2474  time = 2.0;
2475  }
2476 
2478 
2479  ‪wait_or_waittill ( time, "locking on", "locking on hacking", "damage state" );
2480  }
2481  else
2482  {
2483  wait 2;
2484  }
2485 
2486  prevDest = currentDest;
2487  currentDest = ‪heli_get_protect_spot(protectDest, nodeHeight);
2488  noFlyZoneHeight = ‪airsupport::getNoFlyZoneHeight( currentDest );
2489  currentDest = ( currentDest[0], currentDest[1], noFlyZoneHeight + heightOffset );
2490  noFlyZones = ‪airsupport::crossesNoFlyZones( prevDest, currentDest );
2491  if ( isdefined( noFlyZones ) && ( noFlyZones.size > 0 ) )
2492  {
2493  currentDest = prevDest;
2494  }
2495  }
2496 
2498  self thread ‪heli_leave();
2499 }
2500 
2502 {
2503  self endon( "death" );
2504  self endon( "crashing" );
2505  self endon( "leaving" );
2506 
2507  self ‪util::waittill_any( "near_goal", "locking on", "locking on hacking" );
2508 
2509  self ‪updateSpeed();
2510 }
2511 
2512 function ‪updateSpeed()
2513 {
2514  if ( self ‪is_targeted() || ( isdefined(self.evasive) && self.evasive ) )
2515  {
2517  }
2518  else
2519  {
2521  }
2522 }
2523 
2525 {
2526  self notify( "endTargetYawUpdate" );
2527  self endon( "death" );
2528  self endon( "crashing" );
2529  self endon( "leaving" );
2530 
2531  self endon( "endTargetYawUpdate" );
2532 
2533  for(;;)
2534  {
2535  if ( isdefined( self.primaryTarget ) )
2536  {
2537  yaw = ‪math::get_2d_yaw( self.origin, self.primaryTarget.origin );
2538  self setTargetYaw( yaw );
2539  }
2540 
2541  wait( 1 );
2542  }
2543 }
2544 
2545 function ‪fire_missile( sMissileType, iShots, eTarget )
2546 {
2547  if ( !isdefined( iShots ) )
2548  iShots = 1;
2549  assert( self.health > 0 );
2550 
2551  weapon = undefined;
2552  weaponShootTime = undefined;
2553  tags = [];
2554  switch( sMissileType )
2555  {
2556  case "ffar":
2557  weapon = GetWeapon( "hind_FFAR" );
2558  tags[ 0 ] = "tag_store_r_2";
2559  break;
2560  default:
2561  assertMsg( "Invalid missile type specified. Must be ffar" );
2562  break;
2563  }
2564  assert( isdefined( weapon ) );
2565  assert( tags.size > 0 );
2566 
2567  weaponShootTime = weapon.fireTime;
2568  assert( isdefined( weaponShootTime ) );
2569 
2570  self setVehWeapon( weapon );
2571  nextMissileTag = -1;
2572  for( i = 0 ; i < iShots ; i++ ) // I don't believe iShots > 1 is properly supported; we don't set the weapon each time
2573  {
2574  nextMissileTag++;
2575  if ( nextMissileTag >= tags.size )
2576  nextMissileTag = 0;
2577 
2578  eMissile = self ‪fireWeapon( 0, eTarget );
2579  eMissile.killcament = self;
2580  self.lastRocketFireTime = gettime();
2581 
2582  if ( i < iShots - 1 )
2583  wait weaponShootTime;
2584  }
2585  // avoid calling setVehWeapon again this frame or the client doesn't hear about the original weapon change
2586 }
2587 
2588 function ‪check_owner( hardpointType )
2589 {
2590  if ( !isdefined( self.owner ) || !isdefined( self.owner.team ) || self.owner.team != self.team )
2591  {
2592  self notify ( "abandoned" );
2593  self thread ‪heli_leave();
2594  }
2595 }
2596 
2597 function ‪attack_targets( missilesEnabled, hardpointType )
2598 {
2599  //self thread turret_kill_players();
2600  self thread ‪attack_primary( hardpointType );
2601  if ( missilesEnabled )
2602  self thread ‪attack_secondary( hardpointType );
2603 }
2604 
2605 // missile only
2606 function ‪attack_secondary( hardpointType )
2607 {
2608  self endon( "death" );
2609  self endon( "crashing" );
2610  self endon( "leaving" );
2611 
2612  for( ;; )
2613  {
2614  if ( isdefined( self.secondaryTarget ) )
2615  {
2616  self.secondaryTarget.antithreat = undefined;
2617  self.missileTarget = self.secondaryTarget;
2618 
2619  antithreat = 0;
2620 
2621  while( isdefined( self.missileTarget ) && isalive( self.missileTarget ) )
2622  {
2623  // if selected target is not in missile hit range, skip
2624  if( self ‪target_cone_check( self.missileTarget, level.heli_missile_target_cone ) )
2625  self thread ‪missile_support( self.missileTarget, level.heli_missile_rof, true, undefined );
2626  else
2627  break;
2628 
2629  // lower targets threat after shooting
2630  antithreat += 100;
2631  self.missileTarget.antithreat = antithreat;
2632 
2633  wait level.heli_missile_rof;
2634 
2635  // target might disconnect or change during last assault cycle
2636  if ( !isdefined( self.secondaryTarget ) || ( isdefined( self.secondaryTarget ) && self.missileTarget != self.secondaryTarget ) )
2637  break;
2638  }
2639  // reset the antithreat factor
2640  if ( isdefined( self.missileTarget ) )
2641  self.missileTarget.antithreat = undefined;
2642  }
2643  self waittill( "secondary acquired" );
2644 
2645  // check if owner has left, if so, leave
2646  self ‪check_owner( hardpointType );
2647  }
2648 }
2649 
2650 function ‪turret_target_check( turretTarget, attackAngle )
2651 {
2652 
2653  targetYaw = ‪math::get_2d_yaw( self.origin, turretTarget.origin );
2654  chopperYaw = self.angles[1];
2655 
2656  if ( targetYaw < 0 )
2657  targetYaw = targetYaw * -1;
2658 
2659  targetYaw = int( targetYaw ) % 360;
2660 
2661  if ( chopperYaw < 0 )
2662  chopperYaw = chopperYaw * -1;
2663 
2664  chopperYaw = int( chopperYaw ) % 360;
2665 
2666  if ( chopperYaw > targetYaw )
2667  difference = chopperYaw - targetYaw;
2668  else
2669  difference = targetYaw - chopperYaw;
2670 
2671  return ( difference <= attackAngle );
2672 }
2673 
2674 // check if missile is in hittable sight zone
2675 function ‪target_cone_check( target, coneCosine )
2676 {
2677  heli2target_normal = vectornormalize( target.origin - self.origin );
2678  heli2forward = anglestoforward( self.angles );
2679  heli2forward_normal = vectornormalize( heli2forward );
2680 
2681  heli_dot_target = vectordot( heli2target_normal, heli2forward_normal );
2682 
2683  if ( heli_dot_target >= coneCosine )
2684  {
2685  return true;
2686  }
2687  return false;
2688 }
2689 
2690 
2691 
2692 // if wait for turret turning is too slow, enable missile assault support
2693 function ‪missile_support( target_player, rof, instantfire, endon_notify )
2694 {
2695  self endon( "death" );
2696  self endon( "crashing" );
2697  self endon( "leaving" );
2698 
2699  if ( isdefined ( endon_notify ) )
2700  self endon( endon_notify );
2701 
2702  self.turret_giveup = false;
2703 
2704  if ( !instantfire )
2705  {
2706  wait( rof );
2707  self.turret_giveup = true;
2708  self notify( "give up" );
2709  }
2710 
2711  if ( isdefined( target_player ) )
2712  {
2713  if ( level.teambased )
2714  {
2715  // if target near friendly, do not shoot missile, target already has lower threat level at this stage
2716  for (i = 0; i < level.players.size; i++)
2717  {
2718  player = level.players[i];
2719  if ( isdefined( player.team ) && player.team == self.team && distance( player.origin, target_player.origin ) <= level.heli_missile_friendlycare )
2720  {
2721  self notify ( "missile ready" );
2722  return;
2723  }
2724  }
2725  }
2726  else
2727  {
2728  player = self.owner;
2729  if ( isdefined( player ) && isdefined( player.team ) && player.team == self.team && distance( player.origin, target_player.origin ) <= level.heli_missile_friendlycare )
2730  {
2731  self notify ( "missile ready" );
2732  return;
2733  }
2734  }
2735  }
2736 
2737  if ( self.missile_ammo > 0 && isdefined( target_player ) )
2738  {
2739  self ‪fire_missile( "ffar", 1, target_player );
2740  self.missile_ammo--;
2741  self notify( "missile fired" );
2742  }
2743  else
2744  {
2745  return;
2746  }
2747 
2748  if ( instantfire )
2749  {
2750  wait ( rof );
2751  self notify ( "missile ready" );
2752  }
2753 }
2754 
2755 // mini-gun with missile support
2756 function ‪attack_primary( hardpointType )
2757 {
2758  self endon( "death" );
2759  self endon( "crashing" );
2760  self endon( "leaving" );
2761  level endon( "game_ended" );
2762 
2763  for( ;; )
2764  {
2765  if ( isdefined( self.primaryTarget ) )
2766  {
2767  self.primaryTarget.antithreat = undefined;
2768  self.turretTarget = self.primaryTarget;
2769  antithreat = 0;
2770  last_pos = undefined;
2771 
2772  while( isdefined( self.turretTarget ) && isalive( self.turretTarget ) )
2773  {
2774 
2775  //Look at target
2776  if ( (hardpointType == "helicopter_comlink") || (hardpointType == "inventory_helicopter_comlink") )
2777  self SetLookAtEnt( self.turretTarget );
2778 
2779  helicopterTurretMaxAngle = ‪heli_get_dvar_int( "scr_helicopterTurretMaxAngle", level.helicopterTurretMaxAngle );
2780  while ( isdefined( self.turretTarget ) && isalive( self.turretTarget ) && self ‪turret_target_check( self.turretTarget, helicopterTurretMaxAngle ) == false )
2781  wait( 0.1 );
2782 
2783  if ( !isdefined( self.turretTarget ) || !isalive( self.turretTarget ) )
2784  break;
2785 
2786  // shoots one clip of mini-gun non stop
2787  self setTurretTargetEnt( self.turretTarget, ( 0, 0, 50 ) );
2788 
2789  self waittill( "turret_on_target" );
2791 
2792  /*
2793  self util::waittill_any( "turret_on_target", "give up" );
2794  if( isdefined( self.turret_giveup ) && self.turret_giveup )
2795  break;
2796  */
2797 
2798  self notify( "turret_on_target" );
2799  //play some targeting Dialog CDC
2800  if (!self.pilotIsTalking)
2801  {
2802  //self thread PlayPilotDialog ("attackheli_target");
2803  }
2804 
2805  self thread ‪turret_target_flag( self.turretTarget );
2806 
2807  wait 1;
2808 
2810 
2811  // wait for turret to spinup and fire
2812  wait( level.heli_turret_spinup_delay );
2813 
2814  // fire gun =================================
2815  weaponShootTime = self.defaultWeapon.fireTime;
2816  self setVehWeapon( self.defaultWeapon );
2817 
2818  // shoot full clip at target, if target lost, shoot at the last position recorded, if target changed, sweep onto next target
2819  for( i = 0 ; i < level.heli_turretClipSize ; i++ )
2820  {
2821  // if turret on primary target, keep last position of the target in case target lost
2822  if ( isdefined( self.turretTarget ) && isdefined( self.primaryTarget ) )
2823  {
2824  if ( self.primaryTarget != self.turretTarget )
2825  self setTurretTargetEnt( self.primaryTarget, ( 0, 0, 40 ) );
2826  }
2827  else
2828  {
2829  if ( isdefined( self.targetlost ) && self.targetlost && isdefined( self.turret_last_pos ) )
2830  {
2831  self setturrettargetvec( self.turret_last_pos );
2832  }
2833  else
2834  {
2835  self clearturrettarget();
2836  }
2837  }
2838  if ( gettime() != self.lastRocketFireTime )
2839  {
2840  // fire one bullet
2841  self setVehWeapon( self.defaultWeapon );
2842  miniGun = self ‪fireWeapon();
2843  //self.minigun_snd_ent PlayLoopSound( "wpn_attack_chopper_minigun_fire_loop_npc" );//now in gdt
2844  }
2845 
2846  // wait for RoF
2847  if ( i < level.heli_turretClipSize - 1 )
2848  wait weaponShootTime;
2849  }
2850  //self.minigun_snd_ent StopLoopSound();
2851  //self.minigun_snd_ent PlaySound("wpn_attack_chopper_minigun_fire_loop_ring_npc");//now in gdt
2852  self notify( "turret reloading" );
2853  // end fire gun ==============================
2854 
2855  // wait for turret reload
2856  wait( level.heli_turretReloadTime );
2857 
2858  wait( 3 ); // cooldown before recloaking
2859 
2861 
2862  // lower the target's threat since already assaulted on
2863  if ( isdefined( self.turretTarget ) && isalive( self.turretTarget ) )
2864  {
2865  antithreat += 100;
2866  self.turretTarget.antithreat = antithreat;
2867  }
2868 
2869  // primary target might disconnect or change during last assault cycle, if so, find new target
2870  if ( !isdefined( self.primaryTarget ) || ( isdefined( self.turretTarget ) && isdefined( self.primaryTarget ) && self.primaryTarget != self.turretTarget ) )
2871  break;
2872  }
2873  // reset the antithreat factor
2874  if ( isdefined( self.turretTarget ) )
2875  self.turretTarget.antithreat = undefined;
2876  }
2877  self waittill( "primary acquired" );
2878 
2879  // check if owner has left, if so, leave
2880  self ‪check_owner( hardpointType );
2881  }
2882 }
2883 
2884 // target lost flaging
2885 function ‪turret_target_flag( turrettarget )
2886 {
2887  // forcing single thread instance
2888  self notify( "flag check is running" );
2889  self endon( "flag check is running" );
2890 
2891  self endon( "death" );
2892  self endon( "crashing" );
2893  self endon( "leaving" );
2894  self endon( "turret reloading" );
2895 
2896  // ends on target player death or undefined
2897  if ( isdefined( turrettarget ) )
2898  {
2899  turrettarget endon( "death" );
2900  turrettarget endon( "disconnect" );
2901  }
2902 
2903  self.targetlost = false;
2904  self.turret_last_pos = undefined;
2905 
2906  while( isdefined( turrettarget ) )
2907  {
2908  heli_centroid = self.origin + ( 0, 0, -160 );
2909  heli_forward_norm = anglestoforward( self.angles );
2910  heli_turret_point = heli_centroid + 144*heli_forward_norm;
2911 
2912  sight_rec = turrettarget sightconetrace( heli_turret_point, self );
2913  if ( sight_rec < level.heli_target_recognition )
2914  break;
2915 
2917  }
2918 
2919  if( isdefined( turrettarget ) && isdefined( turrettarget.origin ) )
2920  {
2921  assert( isdefined( turrettarget.origin ), "turrettarget.origin is undefined after isdefined check" );
2922  self.turret_last_pos = turrettarget.origin + ( 0, 0, 40 );
2923  assert( isdefined( self.turret_last_pos ), "self.turret_last_pos is undefined after setting it #1" );
2924  self setturrettargetvec( self.turret_last_pos );
2925  assert( isdefined( self.turret_last_pos ), "self.turret_last_pos is undefined after setting it #2" );
2926  self.targetlost = true;
2927  }
2928  else
2929  {
2930  self.targetlost = undefined;
2931  self.turret_last_pos = undefined;
2932  }
2933 }
2934 
2936 {
2937  self endon( "emp_jammed" );
2938  self endon( "emp_grenaded" );
2939 
2940  self waittill( "confirm_location", location );
2941 
2942  return location;
2943 }
2944 
2945 function ‪selectHelicopterLocation(hardpointtype)
2946 {
2947  self beginLocationComlinkSelection( "compass_objpoint_helicopter", 1500 );
2948  self.selectingLocation = true;
2949 
2950  self thread ‪airsupport::endSelectionThink();
2951 
2952  location = self ‪waittill_confirm_location();
2953 
2954  if ( !isdefined( location ) )
2955  {
2956  // selection was cancelled
2957  return false;
2958  }
2959 
2960  if ( self ‪killstreakrules::isKillstreakAllowed( hardpointType, self.team ) == false )
2961  {
2962  return false;
2963  }
2964 
2965  level.helilocation = location;
2966 
2967  return ‪airsupport::finishHardpointLocationUsage( location, undefined );
2968 }
2969 
2970 function ‪processCopterAssist( destroyedCopter, damagedone )
2971 {
2972  self endon( "disconnect" );
2973  destroyedCopter endon( "disconnect" );
2974 
2975  wait .05;
2976 
2977  if ( !isdefined( level.teams[self.team] ) )
2978  return;
2979 
2980  if ( self.team == destroyedCopter.team )
2981  return;
2982 
2983  assist_level = "aircraft_destruction_assist";
2984 
2985  assist_level_value = int( ceil( ( damagedone.damage / destroyedCopter.maxhealth ) * 4 ) );
2986 
2987  if ( assist_level_value > 0 )
2988  {
2989  if ( assist_level_value > 3 )
2990  {
2991  assist_level_value = 3;
2992  }
2993  assist_level = assist_level + "_" + ( assist_level_value * 25 );
2994  }
2995 
2996  ‪scoreevents::processScoreEvent( assist_level, self );
2997 }
2998 
2999 //Allow the SAM turret to attack choppers
3001 {
3002  self endon( "death" );
3003  self endon( "crashing" );
3004  self endon( "leaving" );
3005  level endon( "game_ended" );
3006 
3007  self ‪util::waittill_any( "turret_on_target", "path start", "near_goal" );
3008 
3009  Target_SetTurretAquire( self, true );
3010 }
3011 
3012 function ‪PlayPilotDialog( dialog, time, voice, shouldWait )
3013 {
3014  self endon( "death" );
3015  level endon( "remote_end" );
3016 
3017  if (isdefined(time))
3018  {
3019  wait time;
3020  }
3021  if (!isdefined(self.pilotVoiceNumber))
3022  {
3023  self.pilotVoiceNumber = 0;
3024  }
3025  if (isdefined(voice))
3026  {
3027  voicenumber = voice;
3028  }
3029  else
3030  {
3031  voicenumber = self.pilotVoiceNumber;
3032  }
3033  soundAlias = level.teamPrefix[self.team] + voicenumber + "_" + dialog;
3034 
3035  if ( isdefined ( self.owner ) )
3036  {
3037  self.owner ‪playPilotTalking( shouldWait, soundAlias );
3038  }
3039 }
3040 
3041 function ‪playPilotTalking( shouldWait, soundAlias )
3042 {
3043  self endon( "disconnect" );
3044  self endon( "joined_team" );
3045  self endon( "joined_spectators" );
3046 
3047  tryCounter = 0;
3048  while( isdefined(self.pilotTalking) && self.pilotTalking && tryCounter < 10 )
3049  {
3050  if ( isdefined( shouldWait ) && !shouldWait )
3051  return;
3052  wait 1;
3053  tryCounter++;
3054  }
3055  self.pilotTalking = true;
3056  self playLocalSound(soundAlias);
3057  wait 3;
3058  self.pilotTalking = false;
3059 }
3060 
3061 function ‪watchForEarlyLeave( chopper )
3062 {
3063  chopper notify( "watchForEarlyLeave_helicopter" );
3064  chopper endon( "watchForEarlyLeave_helicopter" );
3065  chopper endon( "death" );
3066  self endon( "heli_timeup" );
3067 
3068  self ‪util::waittill_any( "joined_team", "disconnect" );
3069 
3070  if ( isdefined( chopper ) )
3071  chopper thread ‪heli_leave();
3072 
3073  if ( isdefined( self ) )
3074  self notify( "heli_timeup" );
3075 }
3076 
3077 function ‪watchForEMP()
3078 {
3079  heli = self;
3080 
3081  heli endon( "death" );
3082  heli endon( "heli_timeup" );
3083 
3084  heli.owner waittill( "emp_jammed" );
3085  heli thread ‪heli_explode();
3086 }
‪HELICOPTER_CAMO_STATE_FLICKER
‪#define HELICOPTER_CAMO_STATE_FLICKER
Definition: _killstreaks.gsh:222
‪updateSpeed
‪function updateSpeed()
Definition: _helicopter.gsc:2512
‪waitTillHostMigrationDone
‪function waitTillHostMigrationDone()
Definition: hostmigration_shared.gsc:193
‪heli_crash
‪function heli_crash(hardpointType, player, playerNotify)
Definition: _helicopter.gsc:1811
‪processScoreEvent
‪function processScoreEvent(event, player, victim, weapon)
Definition: scoreevents_shared.gsc:19
‪getValidRandomLeaveNode
‪function getValidRandomLeaveNode(start)
Definition: _helicopter.gsc:426
‪set_heli_speed_hover
‪function set_heli_speed_hover()
Definition: _helicopter.gsc:2345
‪startTime
‪class AnimationAdjustmentInfoZ startTime
‪turret_target_check
‪function turret_target_check(turretTarget, attackAngle)
Definition: _helicopter.gsc:2650
‪heli_existance
‪function heli_existance()
Definition: _helicopter.gsc:638
‪processCopterAssist
‪function processCopterAssist(destroyedCopter, damagedone)
Definition: _helicopter.gsc:2970
‪CheckHelicopterTag
‪function CheckHelicopterTag(tagName)
Definition: _helicopter.gsc:1955
‪damagedRotorFX
‪function damagedRotorFX()
Definition: _helicopter.gsc:1901
‪heli_wait
‪function heli_wait(waittime)
Definition: _helicopter.gsc:1156
‪getValidRandomStartNode
‪function getValidRandomStartNode(dest)
Definition: _helicopter.gsc:455
‪attack_secondary
‪function attack_secondary(hardpointType)
Definition: _helicopter.gsc:2606
‪HackedCallbackPost
‪function HackedCallbackPost(hacker)
Definition: _helicopter.gsc:503
‪HELI_ENTRANCE_Z_HELP
‪#define HELI_ENTRANCE_Z_HELP
Definition: _helicopter.gsc:57
‪calledInComlinkChopper
‪function calledInComlinkChopper()
Definition: _challenges.gsc:1741
‪destroyedHelicopter
‪function destroyedHelicopter(attacker, weapon, damageType, playerControlled)
Definition: challenges_shared.gsc:1369
‪getVerticalTan
‪function getVerticalTan(startOrigin, endOrigin)
Definition: _helicopter.gsc:881
‪explodeOnContact
‪function explodeOnContact(hardpointtype)
Definition: _helicopter.gsc:389
‪heli_think
‪function heli_think(owner, startnode, heli_team, missilesEnabled, protectLocation, hardpointType, armored, killstreak_id)
Definition: _helicopter.gsc:516
‪get_weapon_damage
‪function get_weapon_damage(killstreakType, maxhealth, attacker, weapon, type, damage, flags, chargeShotLevel)
Definition: _killstreak_bundles.gsc:295
‪heli_get_protect_spot
‪function heli_get_protect_spot(protectDest, nodeHeight)
Definition: _helicopter.gsc:2301
‪play_going_down_vo
‪function play_going_down_vo(delay)
Definition: _helicopter.gsc:1802
‪finishHardpointLocationUsage
‪function finishHardpointLocationUsage(location, usedCallback)
Definition: _airsupport.gsc:58
‪heli_random_point_in_radius
‪function heli_random_point_in_radius(protectDest, nodeHeight)
Definition: _helicopter.gsc:2287
‪OnFlakDroneDestroyed
‪function OnFlakDroneDestroyed()
Definition: _helicopter.gsc:375
‪MissileTarget_ProximityDetonateIncomingMissile
‪function MissileTarget_ProximityDetonateIncomingMissile(endon1, endon2, allowDirectDamage)
Definition: _heatseekingmissile.gsc:1085
‪getMinimumFlyHeight
‪function getMinimumFlyHeight()
Definition: _airsupport.gsc:167
‪init_active_camo
‪function init_active_camo()
Definition: _helicopter.gsc:1565
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪play_killstreak_start_dialog
‪function play_killstreak_start_dialog(killstreakType, team, killstreakId)
Definition: _killstreaks.gsc:1905
‪heli_fly
‪function heli_fly(currentnode, startwait, hardpointType)
Definition: _helicopter.gsc:2176
‪set_heli_speed_evasive
‪function set_heli_speed_evasive()
Definition: _helicopter.gsc:2336
‪heli_protect
‪function heli_protect(startNode, protectDest, hardpointType, heli_team)
Definition: _helicopter.gsc:2394
‪canTargetTank_turret
‪function canTargetTank_turret(tank)
Definition: _helicopter.gsc:1029
‪getNoFlyZoneHeight
‪function getNoFlyZoneHeight(point)
Definition: _airsupport.gsc:352
‪check_owner
‪function check_owner(hardpointType)
Definition: _helicopter.gsc:2588
‪clear_client_flags
‪function clear_client_flags()
Definition: _helicopter.gsc:2112
‪get_hack_timeout
‪function get_hack_timeout()
Definition: _killstreak_bundles.gsc:36
‪play_pilot_dialog_on_owner
‪function play_pilot_dialog_on_owner(dialogKey, killstreakType, killstreakId)
Definition: _killstreaks.gsc:2010
‪spawn_helicopter
‪function spawn_helicopter(owner, origin, angles, model, targetname, target_offset, hardpointType, killstreak_id)
Definition: _helicopter.gsc:339
‪heli_active_camo_damage_disable
‪function heli_active_camo_damage_disable()
Definition: _helicopter.gsc:1667
‪addFlySwatterStat
‪function addFlySwatterStat(weapon, aircraft)
Definition: challenges_shared.gsc:86
‪spinSoundShortly
‪function spinSoundShortly()
Definition: _helicopter.gsc:2030
‪ENEMY_VEHICLE_ACTIVE
‪#define ENEMY_VEHICLE_ACTIVE
Definition: _hacker_tool.gsh:2
‪wait_for_bda_timeout
‪function wait_for_bda_timeout()
Definition: _helicopter.gsc:1209
‪wait_or_waittill
‪function wait_or_waittill(time, msg1, msg2, msg3)
Definition: _helicopter.gsc:2318
‪attack_targets
‪function attack_targets(missilesEnabled, hardpointType)
Definition: _helicopter.gsc:2597
‪destroyedPlayerControlledAircraft
‪function destroyedPlayerControlledAircraft()
Definition: challenges_shared.gsc:1397
‪HELICOPTER_CAMO_STATE_OFF
‪#define HELICOPTER_CAMO_STATE_OFF
Definition: _killstreaks.gsh:220
‪heli_evasive
‪function heli_evasive(hardpointType)
Definition: _helicopter.gsc:1753
‪play_bda_dialog
‪function play_bda_dialog()
Definition: _helicopter.gsc:1221
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪turret_target_flag
‪function turret_target_flag(turrettarget)
Definition: _helicopter.gsc:2885
‪crossesNoFlyZones
‪function crossesNoFlyZones(start, end)
Definition: _airsupport.gsc:410
‪waittill_any_timeout
‪function waittill_any_timeout(n_timeout, string1, string2, string3, string4, string5)
Definition: util_shared.csc:423
‪canTargetPlayer_missile
‪function canTargetPlayer_missile(player, hardpointType)
Definition: _helicopter.gsc:905
‪watchForEMP
‪function watchForEMP()
Definition: _helicopter.gsc:3077
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪destroyHelicopter
‪function destroyHelicopter()
Definition: _helicopter.gsc:2048
‪updateSpeedOnLock
‪function updateSpeedOnLock()
Definition: _helicopter.gsc:2501
‪PlayPilotDialog
‪function PlayPilotDialog(dialog, time, voice, shouldWait)
Definition: _helicopter.gsc:3012
‪heli_leave
‪function heli_leave()
Definition: _helicopter.gsc:2120
‪set_goal_pos
‪function set_goal_pos(goalPos, stop)
Definition: _helicopter.gsc:333
‪delay
‪function delay(time_or_notify, str_endon, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:784
‪canTargetActor_turret
‪function canTargetActor_turret(actor, hardpointType)
Definition: _helicopter.gsc:852
‪attack_primary
‪function attack_primary(hardpointType)
Definition: _helicopter.gsc:2756
‪HELICOPTER_CAMO_STATE_ON
‪#define HELICOPTER_CAMO_STATE_ON
Definition: _killstreaks.gsh:221
‪heli_missile_regen
‪function heli_missile_regen()
Definition: _helicopter.gsc:652
‪IsEnemyPlayer
‪function IsEnemyPlayer(player)
Definition: util_shared.csc:1220
‪heli_get_dvar
‪function heli_get_dvar(dvar, def)
Definition: _helicopter.gsc:322
‪heli_path_graph
‪function heli_path_graph()
Definition: _helicopter.gsc:148
‪precachehelicopter
‪function precachehelicopter(model, type)
Definition: _helicopter.gsc:61
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪get_killstreak_weapon
‪function get_killstreak_weapon(killstreak)
Definition: killstreaks_shared.gsc:106
‪heli_active_camo_damage_update
‪function heli_active_camo_damage_update(damage)
Definition: _helicopter.gsc:1645
‪get_2d_yaw
‪function get_2d_yaw(start, end)
Definition: math_shared.gsc:516
‪update_dog_threat
‪function update_dog_threat(dog)
Definition: _killstreaks.gsc:3083
‪wait_for_killed
‪function wait_for_killed()
Definition: _helicopter.gsc:1183
‪canTargetPlayerWithSpecialty
‪function canTargetPlayerWithSpecialty()
Definition: _airsupport.gsc:1228
‪is_targeted
‪function is_targeted()
Definition: _helicopter.gsc:2353
‪init
‪function init()
Definition: _helicopter.gsc:244
‪heli_hover
‪function heli_hover()
Definition: _helicopter.gsc:1170
‪assignSecondaryTargets
‪function assignSecondaryTargets(targets)
Definition: _helicopter.gsc:1101
‪update_non_player_threat
‪function update_non_player_threat(non_player)
Definition: _killstreaks.gsc:3039
‪heli_health
‪function heli_health(hardpointType, playerNotify)
Definition: _helicopter.gsc:1685
‪destroyedAircraft
‪function destroyedAircraft(attacker, weapon, playerControlled)
Definition: challenges_shared.gsc:1405
‪waitThenExplode
‪function waitThenExplode(time)
Definition: _helicopter.gsc:1907
‪dog_manager_get_dogs
‪function dog_manager_get_dogs()
Definition: _dogs.gsc:625
‪play_destroyed_dialog_on_owner
‪function play_destroyed_dialog_on_owner(killstreakType, killstreakId)
Definition: _killstreaks.gsc:1982
‪isKillstreakAllowed
‪function isKillstreakAllowed(hardpointType, team)
Definition: _killstreakrules.gsc:352
‪canTargetDog_turret
‪function canTargetDog_turret(dog)
Definition: _helicopter.gsc:957
‪set_team_kill_penalty_scale
‪function set_team_kill_penalty_scale(killstreakType, scale, isInventory)
Definition: _killstreaks.gsc:404
‪getNoFlyZoneHeightCrossed
‪function getNoFlyZoneHeightCrossed(start, end, minHeight)
Definition: _airsupport.gsc:430
‪AutoStopSound
‪function AutoStopSound()
Definition: _helicopter.gsc:630
‪HELICOPTER_CAMO_DAMAGE_LIMIT
‪#define HELICOPTER_CAMO_DAMAGE_LIMIT
Definition: _killstreaks.gsh:224
‪fire_missile
‪function fire_missile(sMissileType, iShots, eTarget)
Definition: _helicopter.gsc:2545
‪CF_TOGGLE_LIGHTS_OFF
‪#define CF_TOGGLE_LIGHTS_OFF
Definition: shared.gsh:520
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪target_cone_check
‪function target_cone_check(target, coneCosine)
Definition: _helicopter.gsc:2675
‪SAMTurretWatcher
‪function SAMTurretWatcher()
Definition: _helicopter.gsc:3000
‪getValidRandomCrashNode
‪function getValidRandomCrashNode(start)
Definition: _helicopter.gsc:479
‪canTargetDog_missile
‪function canTargetDog_missile(dog)
Definition: _helicopter.gsc:991
‪trail_fx
‪function trail_fx(trail_fx, trail_tag, stop_notify)
Definition: _helicopter.gsc:2043
‪watchForEarlyLeave
‪function watchForEarlyLeave(chopper)
Definition: _helicopter.gsc:3061
‪get_max_health
‪function get_max_health(killstreakType)
Definition: _killstreak_bundles.gsc:188
‪remove_influencers
‪function remove_influencers()
Definition: _spawning.gsc:405
‪CF_TOGGLE_LIGHTS_ON
‪#define CF_TOGGLE_LIGHTS_ON
Definition: shared.gsh:519
‪HELICOPTER_COMLINK
‪#define HELICOPTER_COMLINK
Definition: _helicopter.gsc:58
‪getValidProtectLocationStart
‪function getValidProtectLocationStart(random_path, protectLocation, destination)
Definition: _helicopter.gsc:400
‪heli_set_active_camo_state
‪function heli_set_active_camo_state(state)
Definition: _helicopter.gsc:1580
‪register_dialog
‪function register_dialog(killstreakType, informDialog, taacomDialogBundleKey, pilotDialogArrayKey, startDialogKey, enemyStartDialogKey, enemyStartMultipleDialogKey, hackedDialogKey, hackedStartDialogKey, requestDialogKey, threatDialogKey, isInventory)
Definition: _killstreaks.gsc:239
‪heli_explode
‪function heli_explode()
Definition: _helicopter.gsc:2085
‪set_heli_speed_normal
‪function set_heli_speed_normal()
Definition: _helicopter.gsc:2327
‪assignPrimaryTargets
‪function assignPrimaryTargets(targets)
Definition: _helicopter.gsc:1055
‪heli_targeting
‪function heli_targeting(missilesEnabled, hardpointType)
Definition: _helicopter.gsc:678
‪waittill_confirm_location
‪function waittill_confirm_location()
Definition: _helicopter.gsc:2935
‪notify_player
‪function notify_player(player, playerNotify, delay)
Definition: _helicopter.gsc:1786
‪register_strings
‪function register_strings(killstreakType, receivedText, notUsableText, inboundText, inboundNearPlayerText, hackedText, utilizesAirspace=true, isInventory=false)
Definition: _killstreaks.gsc:223
‪killstreakStop
‪function killstreakStop(hardpointType, team, id)
Definition: _killstreakrules.gsc:293
‪heli_reset
‪function heli_reset()
Definition: _helicopter.gsc:1144
‪missile_support
‪function missile_support(target_player, rof, instantfire, endon_notify)
Definition: _helicopter.gsc:2693
‪heli_hacked_health_update
‪function heli_hacked_health_update(hacker)
Definition: _helicopter.gsc:1247
‪get_hacked_health
‪function get_hacked_health(killstreakType)
Definition: _killstreak_bundles.gsc:202
‪selectHelicopterLocation
‪function selectHelicopterLocation(hardpointtype)
Definition: _helicopter.gsc:2945
‪stop
‪function stop(n_blend=0.2)
Definition: animation_shared.gsc:97
‪heli_mobilespawn
‪function heli_mobilespawn(protectDest)
Definition: _helicopter.gsc:2367
‪killstreakStart
‪function killstreakStart(hardpointType, team, hacked, displayTeamMessage)
Definition: _killstreakrules.gsc:184
‪heli_damage_monitor
‪function heli_damage_monitor(hardpointtype)
Definition: _helicopter.gsc:1258
‪crossesNoFlyZone
‪function crossesNoFlyZone(start, end)
Definition: _airsupport.gsc:391
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪crashOnNearestCrashPath
‪function crashOnNearestCrashPath(hardpointType)
Definition: _helicopter.gsc:1916
‪update_missile_dog_threat
‪function update_missile_dog_threat(dog)
Definition: _killstreaks.gsc:3139
‪INVENTORY_HELICOPTER_COMLINK
‪#define INVENTORY_HELICOPTER_COMLINK
Definition: _helicopter.gsc:59
‪useKillstreakHelicopter
‪function useKillstreakHelicopter(hardpointType)
Definition: _helicopter.gsc:82
‪trackAssists
‪function trackAssists(attacker, damage, isFlare)
Definition: challenges_shared.gsc:26
‪playPilotTalking
‪function playPilotTalking(shouldWait, soundAlias)
Definition: _helicopter.gsc:3041
‪configure_team
‪function configure_team(killstreakType, killstreakId, owner, influencerType, configureTeamPreFunction, configureTeamPostFunction, isHacked=false)
Definition: _killstreaks.gsc:2806
‪update_player_threat
‪function update_player_threat(player)
Definition: _killstreaks.gsc:2997
‪play_taacom_dialog_response_on_owner
‪function play_taacom_dialog_response_on_owner(dialogKey, killstreakType, killstreakId)
Definition: _killstreaks.gsc:2036
‪canTargetPlayer_turret
‪function canTargetPlayer_turret(player, hardpointType)
Definition: _helicopter.gsc:806
‪register_alt_weapon
‪function register_alt_weapon(killstreakType, weaponName, isInventory)
Definition: _killstreaks.gsc:318
‪create_flare_ent
‪function create_flare_ent(offset)
Definition: _helicopter.gsc:645
‪updateTargetYaw
‪function updateTargetYaw()
Definition: _helicopter.gsc:2524
‪update_missile_player_threat
‪function update_missile_player_threat(player)
Definition: _killstreaks.gsc:3109
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪HELICOPTER_CAMO_FLICKER_DURATION
‪#define HELICOPTER_CAMO_FLICKER_DURATION
Definition: _killstreaks.gsh:223
‪enable_hacking
‪function enable_hacking(killstreakName, preHackFunction, postHackFunction)
Definition: _killstreak_hacking.gsc:22
‪announceHelicopterInbound
‪function announceHelicopterInbound(hardpointType)
Definition: _helicopter.gsc:140
‪result
‪function result(death, attacker, mod, weapon)
Definition: _zm_aat_blast_furnace.gsc:46
‪death_notify_wrapper
‪function death_notify_wrapper(attacker, damageType)
Definition: util_shared.gsc:1070
‪isHacked
‪function isHacked()
Definition: util_shared.gsc:2493
‪endSelectionThink
‪function endSelectionThink()
Definition: _airsupport.gsc:102
‪HELICOPTER_CAMO_DAMAGE_DURATION
‪#define HELICOPTER_CAMO_DAMAGE_DURATION
Definition: _killstreaks.gsh:225
‪friendlyFireCheck
‪function friendlyFireCheck(owner, attacker, forcedFriendlyFireRule)
Definition: _weaponobjects.gsc:2733
‪SetCamoState
‪function SetCamoState(state)
Definition: _flak_drone.gsc:505
‪ConfigureTeamPost
‪function ConfigureTeamPost(owner, isHacked)
Definition: _helicopter.gsc:497
‪heli_spin
‪function heli_spin(speed)
Definition: _helicopter.gsc:2010
‪update_actor_threat
‪function update_actor_threat(actor)
Definition: _killstreaks.gsc:3053
‪heli_get_dvar_int
‪function heli_get_dvar_int(dvar, def)
Definition: _helicopter.gsc:316
‪heli_secondary_explosions
‪function heli_secondary_explosions()
Definition: _helicopter.gsc:1978
‪fireWeapon
‪function fireWeapon(weaponName)
Definition: end_game_taunts.csc:1118
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265