‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
turret_shared.gsc
Go to the documentation of this file.
1 #using scripts\shared\ai_shared;
2 #using scripts\shared\array_shared;
3 #using scripts\shared\clientfield_shared;
4 #using scripts\shared\flag_shared;
5 #using scripts\shared\flagsys_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\util_shared;
8 #using scripts\shared\vehicleriders_shared;
9 
10 #insert scripts\shared\shared.gsh;
11 #insert scripts\shared\version.gsh;
12 
13 #namespace turret;
14 
15 ‪REGISTER_SYSTEM( "turret", &‪__init__, undefined )
16 
17 /*-----------------------------------------------------------------------------------------------------
18 
19 ******************************************************************
20 Turret Overview
21 ******************************************************************
22 
23  This script handles all turret functionality.
24 
25  Below are a list of script command available.
26 
27  See the module:- t6\game\share\devraw\scripts\module_turret.gsc for a group simple examples that shows the
28  scripter in-game MG Turrent and Helicopter Turret examples.
29 
30  Note: An MG Turret typicaly only has 1 turret.
31  Helicopter can have upto 5 turrets, the main turret and 4 gunner turrets.
32 
33  Setting up an MG Turret in Radient:-
34  - See the file module_turret.gsc for a description of how to setup a manned MG Turret in Radiant.
35 
36 
37 ******************************************************************
38 Using, Activating and Pausing a Turret
39 ******************************************************************
40 
41  is_turret_enabled( n_index )
42  - Checks to see if the turret is enabled.
43 
44  enable( n_index )
45  - Enables the given turret.
46 
47  disable( [n_index] )
48  - Disables the given turret, but it keeps its targetted information.
49 
50  pause( [n_index], <time, 0=infinite> )
51  - Pause turret for X time.
52 
53  unpause( [n_index] )
54  - remove the pause restriction from the turret.
55 
56  stop( <n_index> )
57  - Stops the turrets current action and puts it back in search for enemy mode.
58 
59 
60 ******************************************************************
61 Turret "User" Functios - Turrets that need Users to Operate
62 ******************************************************************
63 
64  does_need_user( <n_index> )
65  - Does the turret need a used (node) to oprerate.
66 
67  does_have_user( <n_index> )
68  - Does the turret currently have a user?
69 
70  get_user( <index> )
71  - Gets the user of this turret.
72 
73  is_current_user( <ai_user>, [n_index] )
74  - Checks to see if an AI is the current user.
75 
76  SetOnTargetAngle( <angle> )
77  - The turret has to be aiming within this number of degrees at the target to get the
78  "turret_on_target" notify.
79 
80 
81 ******************************************************************
82 Turret Targetting Functions
83 ******************************************************************
84 
85  set_target( <e_target>, [v_offset], [n_index] )
86  - Sets the target of this turret.
87 
88  get_target( [n_index] )
89  - Returns turret target data for this turret.
90 
91  clear_target( [n_index] )
92  - Clears turret target data for this turret.
93 
94  set_target_flags( <n_flags>, [n_index] )
95  - Sets a sub-set of targets for the turret.
96 
97  set_target_ent_array( [a_ents] )
98  - Passes an array of targets to the turret to kill.
99 
100  clear_target_ent_array()
101  - Scripters ability to clear the turrets ent target array.
102 
103  set_ignore_ent_array( [a_ents] )
104  - Passes an array of ents to the turret to ignore.
105 
106  clear_ignore_ent_array()
107  - Scripters ability to clear the turrets ent ignore array.
108 
109  set_best_target_func( <::function>, [n_index] )
110  - Custom override function, scripter can use to custermise their choice from potential targets;
111 
112  is_target_in_view( e_target, n_index )
113  - Lets script know if the turret can aim for a target within its GDT movement constraints.
114 
115  can_turret_shoot_target( e_target, n_index )
116  - Basically is there anythinhg blocking the turrets shot (geo etc..)
117 
118  can_hit_target( e_target, turret_index )
119  - Basically combines the two functions above ( is_target_in_view() and can_turret_shoot_target() )
120 
121  set_max_target_distance( n_dist )
122  - Can be used to limit the maximum distance of a turret's target
123 
124  set_min_target_distance( n_dist )
125  - Can be used to limit the minimum distance of a turret's target (from pivot point)
126 
127  set_min_target_distance_squared( n_dist_squared )
128  - Can be used to limit the minimum distance of a turret's target (from pivot point); squared distance version of above
129 
130 
131 ******************************************************************
132 Turret Firing Functions
133 ******************************************************************
134 
135  fire( [n_index] )
136  - Fires a turret.
137 
138  fire_for_time( <n_time> , [n_index] )
139  - Fires a turret for a time, blocks for n_time.
140 
141  shoot_at_target( <ent>, <time> );
142  - Gets a turret to go into manual mode and fire at a specific target, ignoring all other threats.
143 
144  set_burst_parameters( n_fire_min, n_fire_max, n_wait_min, n_wait_max, n_index )
145  - Sets the burst parameters for a turret.
146 
147 
148 ******************************************************************
149 Useful Misc Turret Functions
150 ******************************************************************
151 
152  set_turret_occupy_no_target_time( n_index )
153  - How long an AI will stay inside a turret if there is no target, default is 2.0 seconds.
154 
155  set_turret_ignore_line_of_sight( b_ignore, n_index )
156  - set this turret to ignore line of sight
157 
158  get_weapon( n_index )
159  - Gets the turrets weapon.
160 
161  get_parent( n_index )
162  - Gets the turrets parent entity.
163 
164  enable_laser( n_index, b_enable )
165  - Turns on the laser.
166 
167  enable_emp( n_index, b_enable )
168  - Allows this turret to be emped which shuts it down and turns of the laser if enabled.
169 
170  NOTIFY: "terminate_all_turrets_firing" Use this notify on a vehicle to immediately stop any burst firing loops it may have running.
171 
172 
173 ******************************************************************
174 Script NOTIFIES
175 ******************************************************************
176 
177 TURRET
178  "turret_enabled" - When the turret has been enabled.
179  "turret_disabled" - When the durret has been disabled
180  "user_using_turret" - Sent out when the ai_user first gets on the turret.
181  "_stop_turret" - Sent out when a turret is stops firint at its latest target.
182  "turret_target_out_of_range" - Sent when the target of a turret moves out of range.
183  "target_array_destroyed" - Send out when a target array has bee cleared
184  "shooting" - Sent out bu turret when it starts shooting
185  "turret_on_target" - Sent out when the turret has a target in its sights
186  "gunner_turret_on_target" - Sent out when a turrets gunner has a target in its sights
187  "idle" - Sent out when the turret has no targets in sight
188 
189 ----------------------------------------------------------------------------------------------------- */
190 
191 /*-----------------------------------------------------------------------------------------------------
192  Turret Struct Data
193 
194  is_enabled
195  w_weapon
196  str_team
197  e_parent
198  e_target
199  ai_user
200  e_next_target
201  n_target_flags
202  n_burst_fire_min
203  n_burst_fire_max
204  n_burst_wait_min
205  n_burst_wait_max
206 
207 -----------------------------------------------------------------------------------------------------*/
208 
209 // The amount of time a turret will wait with no target before calling _drop_turret()
210 // dropping the turret causes the user to exit the turret
211 #define MAX_OCCUPY_NO_TARGET_TIME 3600
212 
213 function ‪__init__()
214 {
215  ‪clientfield::register( "vehicle", "toggle_lensflare", ‪VERSION_SHIP, 1, "int" );
216 
217  level._turrets = SpawnStruct();
218 }
219 
229 function ‪get_weapon( n_index = 0 )
230 {
231  w_weapon = self SeatGetWeapon( n_index );
232  return w_weapon;
233 }
234 
244 function ‪get_parent( n_index )
245 {
246  return ‪_get_turret_data( n_index ).e_parent;
247 }
248 
250 {
251  self notify( "laser_death_thread_stop" );
252  self endon( "laser_death_thread_stop" );
253  self waittill( "death" );
254  if(isDefined(self))
255  {
256  self LaserOff();
257  }
258 }
259 
260 function ‪enable_laser( b_enable, n_index )
261 {
262  if ( b_enable )
263  {
264  ‪_get_turret_data( n_index ).has_laser = true;
265  self LaserOn();
266  self thread ‪laser_death_watcher();
267  }
268  else
269  {
270  ‪_get_turret_data( n_index ).has_laser = undefined;
271  self LaserOff();
272  self notify( "laser_death_thread_stop" );
273  }
274 }
275 
277 {
278  self endon( "watch_for_flash_and_stun" );
279  self endon( "death" );
280 
281  while( 1 )
282  {
283  self waittill( "flashbang", pct_dist, pct_angle, attacker, team );
284  self notify( "damage", 1, attacker, undefined, undefined, undefined, undefined, undefined, undefined, "flash_grenade" );
285  }
286 }
287 
288 function ‪watch_for_flash_and_stun( n_index )
289 {
290  self notify( "watch_for_flash_and_stun_end" );
291  self endon( "watch_for_flash_and_stun" );
292  self endon( "death" );
293 
294  self thread ‪watch_for_flash();
295 
296  while ( true )
297  {
298  self waittill( "damage", ‪damage, attacker, direction, point, type, tagName, modelName, partname, weapon );
299 
300  if ( weapon.doStun )
301  {
302  if ( isdefined( self.stunned ) )
303  {
304  continue;
305  }
306 
307  self.stunned = true;
308 
309  ‪stop( n_index, true );
310 
311  wait RandomFloatRange( 5, 7 );
312 
313  self.stunned = undefined;
314  }
315  }
316 }
317 
318 function ‪emp_watcher( n_index )
319 {
320  self notify( "emp_thread_stop" );
321  self endon( "emp_thread_stop" );
322  self endon( "death" );
323 
324  while ( true )
325  {
326  self waittill( "damage", ‪damage, attacker, direction, point, type, tagName, modelName, partname, weapon );
327 
328  if ( weapon.isEmp )
329  {
330  if ( isdefined( self.‪emped ) )
331  {
332  continue;
333  }
334 
335  self.emped = true;
336 
337  if ( isdefined( ‪_get_turret_data( n_index ).has_laser ) )
338  {
339  self LaserOff();
340  }
341 
342  ‪stop( n_index, true );
343 
344  wait RandomFloatRange( 5, 7 );
345 
346  self.emped = undefined;
347 
348  if ( isdefined( ‪_get_turret_data( n_index ).has_laser ) )
349  {
350  self LaserOn();
351  }
352  }
353  }
354 }
355 
356 function ‪enable_emp( b_enable, n_index )
357 {
358  if ( b_enable )
359  {
360  ‪_get_turret_data( n_index ).can_emp = true;
361  self thread ‪emp_watcher( n_index );
362  self.takedamage = true;
363  }
364  else
365  {
366  ‪_get_turret_data( n_index ).can_emp = undefined;
367  self notify( "emp_thread_stop" );
368  }
369 }
370 
371 function ‪set_team( str_team, n_index )
372 {
373  ‪_get_turret_data( n_index ).str_team = str_team;
374 
375  // set the internal code team
376  self.team = str_team;
377 }
378 
379 function ‪get_team( n_index )
380 {
381  str_team = undefined;
382 
383  s_turret = ‪_get_turret_data( n_index );
384 
385  str_team = self.team;
386 
387  if ( !isdefined( s_turret.str_team ) )
388  {
389  s_turret.str_team = str_team;
390  }
391 
392  return str_team;
393 }
394 
404 function ‪is_turret_enabled( n_index )
405 {
406  return ‪_get_turret_data( n_index ).is_enabled;
407 }
408 
418 function ‪does_need_user( n_index )
419 {
420  return ‪IS_TRUE( ‪_get_turret_data( n_index ).b_needs_user );
421 }
422 
432 function ‪does_have_user( n_index )
433 {
434  return IsAlive( ‪get_user( n_index ) );
435 }
436 
447 function ‪get_user( n_index )
448 {
449  return ( self GetSeatOccupant( n_index ) );
450 }
451 
452 function ‪_set_turret_needs_user( n_index, b_needs_user )
453 {
454  s_turret = ‪_get_turret_data( n_index );
455 
456  if ( b_needs_user )
457  {
458  s_turret.b_needs_user = true;
459  self thread ‪watch_for_flash_and_stun( n_index );
460  }
461  else
462  {
463  self notify( "watch_for_flash_and_stun_end" );
464  s_turret.b_needs_user = false;
465  }
466 }
467 
479 // self = turret or vehicle
480 function ‪set_target_ent_array( ‪a_ents, n_index )
481 {
482  s_turret = ‪_get_turret_data( n_index );
483  s_turret.priority_target_array = ‪a_ents;
484 }
485 
496 function ‪add_priority_target( ent_or_ent_array, n_index )
497 {
498  s_turret = ‪_get_turret_data( n_index );
499 
500  // priority_target_array should always take an array
501  if ( !IsArray( ent_or_ent_array ) ) // single ent
502  {
503  a_new_targets = [];
504  a_new_targets[ 0 ] = ent_or_ent_array;
505  }
506  else // array
507  {
508  a_new_targets = ent_or_ent_array;
509  }
510 
511  // add new targets to existing priority_target_array
512  if ( isdefined( s_turret.priority_target_array ) )
513  {
514  a_new_targets = ArrayCombine( s_turret.priority_target_array, a_new_targets, true, false );
515  }
516 
517  s_turret.priority_target_array = a_new_targets;
518 }
519 
530 function ‪clear_target_ent_array( n_index )
531 {
532  s_turret = ‪_get_turret_data( n_index );
533  s_turret.priority_target_array = undefined;
534 }
535 
547 // self = turret or vehicle
548 function ‪set_ignore_ent_array( ‪a_ents, n_index )
549 {
550  s_turret = ‪_get_turret_data( n_index );
551  s_turret.a_ignore_target_array = ‪a_ents;
552 }
553 
564 function ‪clear_ignore_ent_array( n_index )
565 {
566  s_turret = ‪_get_turret_data( n_index );
567  s_turret.a_ignore_target_array = undefined;
568 }
569 
571 {
572  self endon( "death" );
573 
574  while ( IsAlive( ‪get_user( n_index ) ) )
575  {
576  wait .05;
577  }
578 }
579 
590 function ‪is_current_user( ai_user, n_index )
591 {
592  ai_current_user = ‪get_user( n_index );
593  return ( IsAlive( ai_current_user ) && ( ai_user == ai_current_user ) );
594 }
595 
609 function ‪set_burst_parameters( n_fire_min, n_fire_max, n_wait_min, n_wait_max, n_index )
610 {
611  s_turret = ‪_get_turret_data( n_index );
612  s_turret.n_burst_fire_min = n_fire_min;
613  s_turret.n_burst_fire_max = n_fire_max;
614  s_turret.n_burst_wait_min = n_wait_min;
615  s_turret.n_burst_wait_max = n_wait_max;
616 }
617 
618 // For use against human targets
619 function ‪set_torso_targetting( n_index, n_torso_targetting_offset = ( -12 ) )
620 {
621  s_turret = ‪_get_turret_data( n_index );
622  s_turret.n_torso_targetting_offset = n_torso_targetting_offset;
623 }
624 
625 // For use against human targets
626 function ‪set_target_leading( n_index, n_target_leading_factor = 0.1 )
627 {
628  s_turret = ‪_get_turret_data( n_index );
629  s_turret.n_target_leading_factor = n_target_leading_factor;
630 }
631 
632 
643 function ‪set_on_target_angle( n_angle, n_index )
644 {
645  s_turret = ‪_get_turret_data( n_index );
646 
647  if ( !isdefined( n_angle ) )
648  {
649  if ( s_turret.str_guidance_type != "none" )
650  {
651  n_angle = 10;
652  }
653  else
654  {
655  n_angle = 2;
656  }
657  }
658 
659  if ( n_index > 0 )
660  {
661  self SetOnTargetAngle( n_angle, n_index - 1 );
662  }
663  else
664  {
665  self SetOnTargetAngle( n_angle );
666  }
667 }
668 
680 function ‪set_target( ‪e_target, v_offset, n_index )
681 {
682  s_turret = ‪_get_turret_data( n_index );
683 
684  if ( !isdefined( v_offset ) )
685  {
686  v_offset = ‪_get_default_target_offset( ‪e_target, n_index );
687  }
688 
689  if ( !isdefined( n_index ) || n_index == 0 )
690  {
691  self SetTargetEntity( ‪e_target, v_offset );
692  }
693  else
694  {
695  self SetTargetEntity( ‪e_target, v_offset, n_index - 1 );
696  }
697 
698  s_turret.e_target = ‪e_target;
699  s_turret.e_last_target = ‪e_target;
700  s_turret.v_offset = v_offset;
701 }
702 
704 {
705  s_turret = ‪_get_turret_data( n_index );
706  if ( s_turret.str_weapon_type == "bullet" )
707  {
708  if ( isdefined( ‪e_target ) )
709  {
710  if ( IsSentient( self ) && IsSentient( ‪e_target ) )
711  {
712  z_offset = ( IsVehicle( ‪e_target ) ? 0 : ‪VAL( s_turret.n_torso_targetting_offset, 0 ) ); // if both sentients, the code will handle the offset intelligently
713  }
714  else if ( IsPlayer( ‪e_target ) )
715  {
716  z_offset = RandomIntRange( 40, 50 );
717  }
718  else if ( ‪IS_EQUAL( ‪e_target.type, "human" ) )
719  {
720  z_offset = RandomIntRange( 20, 60 );
721  }
722  else if ( ‪IS_EQUAL( ‪e_target.type, "robot" ) )
723  {
724  z_offset = RandomIntRange( 40, 60 );
725  }
726 
727  if ( isdefined(‪e_target.z_target_offset_override) )
728  {
729  if( !isdefined(z_offset) )
730  {
731  z_offset = 0;
732  }
733  z_offset += ‪e_target.z_target_offset_override;
734  }
735  }
736  }
737 
738  ‪DEFAULT( z_offset, 0 );
739  v_offset = ( 0, 0, z_offset );
740 
741  // Apply target leading against human targets
742  if ( ‪VAL( s_turret.n_target_leading_factor, 0 ) != 0 && isdefined( ‪e_target ) && IsSentient( self ) && IsSentient( ‪e_target ) && !IsVehicle( ‪e_target ) )
743  {
744  velocity = ‪e_target GetVelocity();
745  v_offset += velocity * s_turret.n_target_leading_factor;
746  }
747 
748  return v_offset;
749 }
750 
760 function ‪get_target( n_index )
761 {
762  if(isDefined(‪_get_turret_data( n_index ).‪e_target) && ‪IS_TRUE(‪_get_turret_data( n_index ).‪e_target.ignoreme))
763  {
764  ‪clear_target( n_index );
765  }
766  return ‪_get_turret_data( n_index ).e_target;
767 }
768 
769 function ‪is_target( ‪e_target, n_index )
770 {
771  e_current_target = ‪get_target( n_index );
772 
773  if ( isdefined( e_current_target ) )
774  {
775  return ( e_current_target == ‪e_target );
776  }
777 
778  return false;
779 
780 }
781 
791 function ‪clear_target( n_index )
792 {
793  s_turret = ‪_get_turret_data( n_index );
794  s_turret ‪flag::clear( "turret manual" );
795 
796  s_turret.e_next_target = undefined;
797  s_turret.e_target = undefined;
798 
799  if ( !isdefined( n_index ) || ( n_index == 0 ) )
800  {
801  self ClearTurretTarget();
802  }
803  else
804  {
805  self ClearGunnerTarget( n_index - 1 );
806  }
807 }
808 
819 function ‪set_target_flags( n_flags, n_index )
820 {
821  s_turret = ‪_get_turret_data( n_index );
822  s_turret.n_target_flags = n_flags;
823 }
824 
825 function ‪_has_target_flags( n_flags, n_index )
826 {
827  n_current_flags = ‪_get_turret_data( n_index ).n_target_flags;
828  return ( ( n_current_flags & n_flags ) == n_flags);
829 }
830 
831 
842 function ‪set_max_target_distance( n_distance, n_index )
843 {
844  s_turret = ‪_get_turret_data( n_index );
845  s_turret.n_max_target_distance_squared = n_distance * n_distance;
846 }
847 
858 function ‪set_min_target_distance( n_distance, n_index )
859 {
860  s_turret = ‪_get_turret_data( n_index );
861  s_turret.n_min_target_distance_squared = n_distance * n_distance;
862 }
863 
874 function ‪set_min_target_distance_squared( n_distance_squared, n_index )
875 {
876  s_turret = ‪_get_turret_data( n_index );
877  s_turret.n_min_target_distance_squared = n_distance_squared;
878 }
879 
889 function ‪fire( n_index )
890 {
891  s_turret = ‪_get_turret_data( n_index );
892 
893  assert( isdefined( n_index ) && ( n_index >= 0 ), "Invalid index specified to fire vehicle turret." );
894 
895  if ( n_index == 0 )
896  {
897  self FireWeapon( 0, s_turret.e_target );
898  }
899  else
900  {
901  ai_current_user = ‪get_user( n_index );
902  if(isdefined(ai_current_user) && ‪IS_TRUE(ai_current_user.is_disabled))
903  return;
904 
905  if ( isdefined( s_turret.e_target ) )
906  {
907  self SetGunnerTargetEnt( s_turret.e_target, s_turret.v_offset, n_index - 1 );
908  }
909 
910  self FireWeapon( n_index, s_turret.e_target, s_turret.v_offset, s_turret.e_parent );
911  }
912 
913  s_turret.n_last_fire_time = GetTime();
914 }
915 
926 function ‪stop( n_index, b_clear_target = false )
927 {
928  s_turret = ‪_get_turret_data( n_index );
929 
930  s_turret.e_next_target = undefined;
931  s_turret.e_target = undefined;
932 
933  s_turret ‪flag::clear( "turret manual" );
934 
935  if ( b_clear_target )
936  {
937  ‪clear_target( n_index );
938  }
939 
940  self notify( "_stop_turret" + ‪_index( n_index ) );
941 }
942 
953 function ‪fire_for_time( n_time, n_index = 0 )
954 {
955  Assert( isdefined( n_time ), "n_time is a required parameter for _turet::fire_for_time." );
956 
957  self endon( "death" );
958  self endon( "drone_death" );
959 
960  self endon( "_stop_turret" + ‪_index( n_index ) );
961  // MikeA: 4/18/11
962  self endon( "turret_disabled" + ‪_index( n_index ) );
963 
964  /* only one of these threads at a time */
965 
966  self notify( "_fire_turret_for_time" + ‪_index( n_index ) );
967  self endon( "_fire_turret_for_time" + ‪_index( n_index ) );
968 
969  b_fire_forever = false;
970  if ( n_time < 0)
971  {
972  b_fire_forever = true;
973  }
974  else
975  {
976  /#
977  w_weapon = ‪get_weapon( n_index );
978  assert( n_time >= w_weapon.fireTime, "Fire time (" + n_time + ") must be greater than the weapon's fire time. weapon fire time = " + w_weapon.fireTime );
979  #/
980  }
981 
982  while ( ( n_time > 0 ) || b_fire_forever )
983  {
984  //IPrintLnBold( "BURST FIRE START LOOP" );
985 
986  n_burst_time = ‪_burst_fire( n_time, n_index );
987 
988  if ( !b_fire_forever )
989  {
990  n_time -= n_burst_time;
991  }
992  }
993 }
994 
1009 // self = turret or vehicle
1010 function ‪shoot_at_target( ‪e_target, n_time, v_offset, n_index, b_just_once )
1011 {
1012  Assert( isdefined( ‪e_target ), "Undefined target passed to shoot_at_target()." );
1013 
1014  self endon( "drone_death" );
1015  self endon( "death" );
1016 
1017  // Manual mode will stop the turret searching for new targets
1018  s_turret = ‪_get_turret_data( n_index );
1019  s_turret ‪flag::set( "turret manual" );
1020 
1021  ‪_shoot_turret_at_target( ‪e_target, n_time, v_offset, n_index, b_just_once );
1022 
1023  s_turret ‪flag::clear( "turret manual" );
1024 }
1025 
1026 function ‪_shoot_turret_at_target( ‪e_target, n_time, v_offset, n_index, b_just_once )
1027 {
1028  self endon( "drone_death" );
1029  self endon( "death" );
1030  self endon( "_stop_turret" + ‪_index( n_index ) );
1031  self endon( "turret_disabled" + ‪_index( n_index ) );
1032 
1033  // only one of these threads at a time
1034  self notify( "_shoot_turret_at_target" + ‪_index( n_index ) );
1035  self endon( "_shoot_turret_at_target" + ‪_index( n_index ) );
1036 
1037  if ( n_time == -1 )
1038  {
1039  ‪e_target endon( "death" );
1040  }
1041 
1042  if ( !isdefined( b_just_once ) )
1043  {
1044  b_just_once = false;
1045  }
1046 
1047  ‪set_target( ‪e_target, v_offset, n_index );
1048 
1049  if ( !isdefined( self.aim_only_no_shooting ) )
1050  {
1052 
1053  if ( b_just_once )
1054  {
1055  ‪turret::fire( n_index );
1056  }
1057  else
1058  {
1059  ‪fire_for_time( n_time, n_index );
1060  }
1061  }
1062 }
1063 
1065 {
1066  do
1067  {
1068  wait ‪VAL( self.waittill_turret_on_target_delay, 0.5 );
1069  if ( !isdefined( n_index ) || ( n_index == 0 ) )
1070  {
1071  self waittill( "turret_on_target" );
1072  }
1073  else
1074  {
1075  self waittill( "gunner_turret_on_target" );
1076  }
1077  }
1078  while ( isdefined( ‪e_target ) && !‪can_hit_target( ‪e_target, n_index ) );
1079 }
1080 
1092 function ‪shoot_at_target_once( ‪e_target, v_offset, n_index )
1093 {
1094  ‪shoot_at_target( ‪e_target, 0, v_offset, n_index, true );
1095 }
1096 
1108 function ‪enable( n_index, b_user_required, v_offset )
1109 {
1110  if ( isAlive(self) && !‪is_turret_enabled( n_index ) )
1111  {
1112  ‪_get_turret_data( n_index ).is_enabled = true;
1113  self thread ‪_turret_think( n_index, v_offset );
1114  self notify( "turret_enabled" + ‪_index( n_index ) );
1115 
1116  if ( isdefined( b_user_required ) && ( !b_user_required ) )
1117  {
1118  ‪_set_turret_needs_user( n_index, false );
1119  }
1120  else
1121  {
1122  ‪_set_turret_needs_user( n_index, true );
1123  }
1124  }
1125 }
1126 
1137 function ‪enable_auto_use( b_enable = true )
1138 {
1139  self.script_auto_use = b_enable;
1140 }
1141 
1153 function ‪disable_ai_getoff( n_index, b_disable = true )
1154 {
1155  ‪_get_turret_data( n_index ).disable_ai_getoff = b_disable;
1156 }
1157 
1167 function ‪disable( n_index )
1168 {
1169  if ( ‪is_turret_enabled( n_index ) )
1170  {
1171  ‪_drop_turret( n_index );
1172 
1173  // MikeA: 4/18/11
1174  ‪clear_target( n_index );
1175 
1176  ‪_get_turret_data( n_index ).is_enabled = false;
1177 
1178  self notify( "turret_disabled" + ‪_index( n_index ) );
1179  }
1180 }
1181 
1193 function ‪pause( time, n_index )
1194 {
1195  s_turret = ‪_get_turret_data( n_index );
1196 
1197  // Convert time to Milli Seconds
1198  if ( time > 0 )
1199  {
1200  time = time * 1000;
1201  }
1202 
1203  // If already paused, just add on the extra time
1204  if ( isdefined( s_turret.pause ) )
1205  {
1206  s_turret.pause_time = s_turret.pause_time + time;
1207  }
1208  else
1209  {
1210  s_turret.pause = 1;
1211  s_turret.pause_time = time;
1212  ‪stop( n_index );
1213  }
1214 }
1215 
1225 function ‪unpause( n_index )
1226 {
1227  s_turret = ‪_get_turret_data( n_index );
1228  s_turret.pause = undefined;
1229 }
1230 
1231 #define TURRET_LOSE_SIGHT_TIME 3000
1232 
1233 // self = vehicle or turret
1234 function ‪_turret_think( n_index, v_offset )
1235 {
1236  TURRET_THINK_TIME = Max( 1.5, ‪get_weapon( n_index ).fireTime );
1237 
1238  no_target_start_time = 0; // Time when turret last had a target
1239 
1240  self endon( "death" );
1241  self endon( "turret_disabled" + ‪_index( n_index ) );
1242 
1243  /* only one think thread at a time */
1244 
1245  self notify( "_turret_think" + ‪_index( n_index ) );
1246  self endon( "_turret_think" + ‪_index( n_index ) );
1247 
1248  /# self thread ‪_debug_turret_think( n_index ); #/
1249 
1250  self thread ‪_turret_user_think( n_index );
1251 
1252  self thread ‪_turret_new_user_think( n_index );
1253 
1254  s_turret = ‪_get_turret_data( n_index );
1255 
1256  if ( isdefined( s_turret.has_laser ) )
1257  {
1258  self LaserOn();
1259  }
1260 
1261  while ( true )
1262  {
1263  s_turret ‪flag::wait_till_clear( "turret manual" );
1264 
1265  n_time_now = GetTime();
1266 
1267  // Do we want to pause the turret?
1268  if ( self ‪_check_for_paused( n_index ) || isdefined( self.‪emped ) || isdefined( self.stunned ) )
1269  {
1270  wait TURRET_THINK_TIME;
1271  continue;
1272  }
1273 
1274  a_potential_targets = ‪_get_potential_targets( n_index );
1275 
1276  if ( !isdefined( s_turret.e_target )
1277  || ( s_turret.e_target.health < 0 )
1278  || !IsInArray( a_potential_targets, s_turret.e_target )
1279  || s_turret ‪_did_turret_lose_target( n_time_now ) )
1280  {
1281  ‪stop( n_index );
1282  }
1283 
1284  e_original_next_target = s_turret.e_next_target;
1285 
1286  // The turret picks the best candidate from the target array
1287  s_turret.e_next_target = ‪_get_best_target_from_potential( a_potential_targets, n_index );
1288 
1289  /* If we have a new target, shoot at it */
1290  if ( isdefined( s_turret.e_next_target ) )
1291  {
1292  s_turret.b_target_out_of_range = undefined;
1293  s_turret.n_time_lose_sight = undefined;
1294  no_target_start_time = 0;
1295 
1296  if ( ‪_user_check( n_index ) )
1297  {
1298  self thread ‪_shoot_turret_at_target( s_turret.e_next_target, TURRET_THINK_TIME, v_offset, n_index );
1299 
1300  if ( s_turret.e_next_target !== e_original_next_target )
1301  {
1302  self notify( "has_new_target", s_turret.e_next_target );
1303  }
1304  }
1305  }
1306  else
1307  {
1308  if ( !isdefined( self.do_not_clear_targets_during_think ) || !self.do_not_clear_targets_during_think )
1309  ‪clear_target( n_index ); // forget the old target if we don't have a next target
1310 
1311  // If we've been waiting for as target for too long, drop the turret (user AI exits)
1312 
1313  if ( no_target_start_time == 0 )
1314  {
1315  no_target_start_time = n_time_now;
1316  }
1317 
1318  // How long have we been waiting
1319  target_wait_time = ( n_time_now - no_target_start_time );
1320 
1321  // If we've been waitng for a target for too long, drop the turret
1322  if ( isdefined(s_turret.occupy_no_target_time) )
1323  {
1324  occupy_time = s_turret.occupy_no_target_time;
1325  }
1326  else
1327  {
1328  occupy_time = ‪MAX_OCCUPY_NO_TARGET_TIME;
1329  }
1330 
1331  //Only leave the turret if it is automated or if the target is a player and we lost sight
1332  if(!‪IS_TRUE(s_turret.disable_ai_getoff))
1333  {
1334  bWasPlayerTarget = isdefined( s_turret.e_last_target ) && ( s_turret.e_last_target.health > 0 ) && IsPlayer(s_turret.e_last_target);
1335 
1336  if(bWasPlayerTarget)
1337  occupy_time = occupy_time / 4;
1338  }
1339  else
1340  {
1341  bWasPlayerTarget = false;
1342  }
1343 
1344  if ( target_wait_time >= occupy_time )
1345  {
1346  ‪_drop_turret( n_index, !bWasPlayerTarget );
1347  }
1348  }
1349 
1350  if ( !‪IS_TRUE(s_turret.disable_ai_getoff) &&
1351  ‪_has_nearby_player_enemy( n_index, self ) )
1352  {
1353  ‪_drop_turret( n_index, false );
1354  }
1355 
1356  wait TURRET_THINK_TIME;
1357  }
1358 }
1359 
1360 #define NEARBY_DISTANCE_SQ SQR( 300 )
1361 #define NEARBY_DISTANCE_Z 60
1362 #define NEARBY_ENEMY_TIME 1000
1363 function ‪_has_nearby_player_enemy( index, turret )
1364 {
1365  has_nearby_enemy = false;
1366  time = GetTime();
1367 
1368  ai_user = turret ‪get_user( index );
1369 
1370  if ( !IsDefined( ai_user ) )
1371  {
1372  return has_nearby_enemy;
1373  }
1374 
1375  if ( !IsDefined( turret.next_nearby_enemy_time ) )
1376  {
1377  turret.next_nearby_enemy_time = time;
1378  }
1379 
1380  if ( time >= turret.next_nearby_enemy_time )
1381  {
1382  players = GetPlayers();
1383 
1384  foreach ( player in players )
1385  {
1386  if ( turret.team == player.team )
1387  {
1388  continue;
1389  }
1390 
1391  if ( Abs( ai_user.origin[2] - player.origin[2] ) <= ‪NEARBY_DISTANCE_Z &&
1392  Distance2DSquared( ai_user.origin, player.origin ) <= ‪NEARBY_DISTANCE_SQ )
1393  {
1394  has_nearby_enemy = true;
1395  break;
1396  }
1397  }
1398 
1399  turret.next_nearby_enemy_time = time + ‪NEARBY_ENEMY_TIME;
1400  }
1401 
1402  return has_nearby_enemy;
1403 }
1404 
1405 // self = turret struct
1406 function ‪_did_turret_lose_target( n_time_now )
1407 {
1408  if ( ‪IS_TRUE( self.b_target_out_of_range ) )
1409  {
1410  return true;
1411  }
1412  else if ( isdefined( self.n_time_lose_sight ) )
1413  {
1414  return ( ( n_time_now - self.n_time_lose_sight ) > ‪TURRET_LOSE_SIGHT_TIME );
1415  }
1416 
1417  return false;
1418 }
1419 
1420 function ‪_turret_user_think( n_index )
1421 {
1422  self endon( "death" );
1423  self endon( "turret_disabled" + ‪_index( n_index ) );
1424  self endon( "_turret_think" + ‪_index( n_index ) );
1425 
1426  s_turret = ‪_get_turret_data( n_index );
1427 
1428  ai_user = self GetSeatOccupant( n_index );
1429 
1430  if ( IsActor( ai_user ) )
1431  {
1432  self thread ‪_listen_for_damage_on_actor(ai_user, n_index);
1433  }
1434 
1435  while ( true )
1436  {
1437  ‪_waittill_user_change( n_index );
1438  if ( !‪_user_check( n_index ) )
1439  {
1440  ‪stop( n_index, true );
1441  }
1442  else
1443  {
1444  ai_user = self GetSeatOccupant( n_index );
1445 
1446  if ( IsActor( ai_user ) )
1447  {
1448  self thread ‪_listen_for_damage_on_actor(ai_user, n_index);
1449  }
1450  }
1451  }
1452 }
1453 
1454 function ‪_listen_for_damage_on_actor(ai_user, n_index)
1455 {
1456  self endon( "death" );
1457  ai_user endon( "death" );
1458  self endon( "turret_disabled" + ‪_index( n_index ) );
1459  self endon( "_turret_think" + ‪_index( n_index ) );
1460  self endon( "exit_vehicle" );
1461 
1462  while(true)
1463  {
1464  ai_user waittill( "damage", n_amount, e_attacker, v_org, v_dir, str_mod );
1465 
1466  s_turret = ‪_get_turret_data( n_index );
1467 
1468  if(isdefined(s_turret))
1469  {
1470  if(!isdefined(s_turret.e_next_target) && !isdefined(s_turret.e_target))
1471  {
1472  s_turret.e_last_target = e_attacker;
1473  }
1474  }
1475  }
1476 }
1477 
1478 function ‪_waittill_user_change( n_index )
1479 {
1480  ai_user = self GetSeatOccupant( n_index );
1481 
1482  if ( IsAlive( ai_user ) )
1483  {
1484  if ( IsActor( ai_user ) )
1485  {
1486  ai_user endon( "death" );
1487  }
1488  else if ( IsPlayer( ai_user ) )
1489  {
1490  self notify( "turret_disabled" + ‪_index( n_index ) ); //turret was continuing to fire on its own
1491  }
1492  }
1493 
1494  self ‪util::waittill_either( "exit_vehicle", "enter_vehicle" );
1495 }
1496 
1497 // self = turret or vehicle
1498 function ‪_check_for_paused( n_index )
1499 {
1500  s_turret = ‪_get_turret_data( n_index );
1501 
1502  s_turret.pause_start_time = GetTime();
1503 
1504  while ( isdefined( s_turret.pause ) )
1505  {
1506  if ( s_turret.pause_time > 0 )
1507  {
1508  time = GetTime();
1509  paused_time = time - s_turret.pause_start_time;
1510  if( paused_time > s_turret.pause_time )
1511  {
1512  s_turret.pause = undefined;
1513  return true;
1514  }
1515  }
1516 
1518  }
1519 
1520  return false;
1521 }
1522 
1523 // self = vehicle or turret
1524 function ‪_drop_turret( n_index, bExitIfAutomatedOnly )
1525 {
1526  ai_user = ‪get_user( n_index );
1527 
1528  if ( IsAlive( ai_user ) && (‪IS_TRUE( ai_user.turret_auto_use ) || (isdefined(bExitIfAutomatedOnly) && !bExitIfAutomatedOnly)) )
1529  { // only drop turret if auto use, not when scripter puts the AI in the vehicle
1530  ai_user ‪vehicle::get_out();
1531  }
1532 }
1533 
1534 function ‪_turret_new_user_think( n_index )
1535 {
1536  const NEW_USER_THINK_TIME = 3;
1537 
1538  self endon( "death" );
1539  self endon( "_turret_think" + ‪_index( n_index ) );
1540  self endon( "turret_disabled" + ‪_index( n_index ) );
1541 
1542  s_turret = ‪_get_turret_data( n_index );
1543 
1544  if( n_index == 0 )
1545  {
1546  str_gunner_pos = "driver";
1547  }
1548  else
1549  {
1550  str_gunner_pos = "gunner" + n_index;
1551  }
1552 
1553 
1554  while ( true )
1555  {
1556  wait NEW_USER_THINK_TIME;
1557 
1558  if ( ‪does_have_target( n_index ) && !‪_user_check( n_index ) && ‪IS_TRUE( self.script_auto_use ) )
1559  {
1560  str_team = ‪get_team( n_index );
1561  a_users = GetAIArchetypeArray( "human" , str_team );
1562  a_ai_by_vehicle = ArraySortClosest( GetAIArray(), self.origin, 99999, 0, 300 );
1563 
1564  if ( a_users.size > 0 )
1565  {
1566  a_potential_users = [];
1567  if ( isdefined( self.script_auto_use_radius ) )
1568  {
1569  a_potential_users = ArraySort( a_users, self.origin, true, a_potential_users.size, self.script_auto_use_radius );
1570  }
1571  else
1572  {
1573  a_potential_users = ArraySort( a_users, self.origin, true );
1574  }
1575 
1576  ai_user = undefined;
1577  foreach ( ai in a_potential_users )
1578  {
1579  b_enemy_close = false;
1580  foreach ( ai_enemy in a_ai_by_vehicle )
1581  {
1582  if ( ai_enemy.team != ai.team )
1583  {
1584  b_enemy_close = true;
1585  break;
1586  }
1587  }
1588 
1589  if ( b_enemy_close )
1590  {
1591  continue;
1592  }
1593 
1594  if ( ai ‪flagsys::get( "vehiclerider" ) )
1595  {
1596  continue;
1597  }
1598 
1599  if ( !ai ‪vehicle::can_get_in( self, str_gunner_pos ) )
1600  {
1601  continue;
1602  }
1603 
1604  ai_user = ai;
1605  break;
1606  }
1607 
1608  if ( IsAlive( ai_user ) )
1609  {
1610  ai_user.turret_auto_use = true;
1611  ai_user ‪vehicle::get_in( self, str_gunner_pos );
1612  }
1613  }
1614  }
1615  }
1616 }
1617 
1618 function ‪does_have_target( n_index )
1619 {
1620  return isdefined( ‪_get_turret_data( n_index ).e_next_target );
1621 }
1622 
1623 function ‪_user_check( n_index )
1624 {
1625  s_turret = ‪_get_turret_data( n_index );
1626 
1627  if ( ‪does_need_user( n_index ) )
1628  {
1629  b_has_user = ‪does_have_user( n_index );
1630  return b_has_user;
1631  }
1632  else
1633  {
1634  return true;
1635  }
1636 }
1637 
1638 /#
1639 
1640 function ‪_debug_turret_think( n_index )
1641 {
1642  self endon( "death" );
1643  self endon( "_turret_think" + ‪_index( n_index ) );
1644  self endon( "turret_disabled" + ‪_index( n_index ) );
1645 
1646  s_turret = ‪_get_turret_data( n_index );
1647  v_color = ( 0, 0, 1 );
1648 
1649  while ( true )
1650  {
1651  if ( !GetDvarint( "g_debugTurrets") )
1652  {
1653  wait(0.2);
1654  continue;
1655  }
1656 
1657  has_target = isdefined( ‪get_target( n_index ) );
1658 
1659  if ( ( ‪does_need_user( n_index ) && !‪does_have_user( n_index ) )
1660  || !has_target )
1661  {
1662  v_color = ( 1, 1, 0 );
1663  }
1664  else
1665  {
1666  v_color = ( 0, 1, 0 );
1667  }
1668 
1669  str_team = ‪get_team( n_index );
1670  if ( !isdefined( str_team ) )
1671  {
1672  str_team = "no team";
1673  }
1674 
1675  str_target = "target > ";
1676 
1677  ‪e_target = s_turret.e_next_target;
1678  if ( isdefined( ‪e_target ) )
1679  {
1680  if ( IsActor( ‪e_target ) )
1681  {
1682  str_target += "ai";
1683  }
1684  else if ( IsPlayer( ‪e_target ) )
1685  {
1686  str_target += "player";
1687  }
1688  else if ( IsVehicle( ‪e_target ) )
1689  {
1690  str_target += "vehicle";
1691  }
1692  else if ( isdefined( ‪e_target.targetname ) && ( ‪e_target.targetname == "drone" ) )
1693  {
1694  str_target += "drone";
1695  }
1696  else if ( isdefined( ‪e_target.classname ) )
1697  {
1698  str_target += ‪e_target.classname;
1699  }
1700  }
1701  else
1702  {
1703  str_target += "none";
1704  }
1705 
1706  str_debug = self GetEntNum() + ":" + str_team + ":" + str_target;
1707  Record3DText( str_debug, self.origin, v_color, "Script", self );
1708 
1709  wait .05;
1710  }
1711 }
1712 
1713 #/
1714 
1715 /*===================================================================================================
1716  SYSTEM FUNCTIONS
1717 ===================================================================================================*/
1718 
1719 /*===================================================================
1720 SELF: turret or vehicle
1721 PURPOSE: Get the data structure holding the turret info
1722 RETURNS: The turret data struct
1723 [n_index]: optional index of vehicle turret if self is a vehicle
1724 ===================================================================*/
1725 function ‪_get_turret_data( n_index )
1726 {
1727  s_turret = undefined;
1728 
1729  if ( IsVehicle( self ) )
1730  {
1731  if ( isdefined( self.a_turrets ) && isdefined( self.a_turrets[ n_index ] ) )
1732  {
1733  s_turret = self.a_turrets[ n_index ];
1734  }
1735  }
1736  else
1737  {
1738  s_turret = self._turret;
1739  }
1740 
1741  if ( !isdefined( s_turret ) )
1742  {
1743  s_turret = ‪_init_turret( n_index );
1744  }
1745 
1746  return s_turret;
1747 }
1748 
1749 
1750 /*===================================================================
1751 SELF: turret or vehicle
1752 PURPOSE: Get the data structure holding the turret info
1753 RETURNS: The turret data struct
1754 [n_index]: optional index of vehicle turret if self is a vehicle
1755 ===================================================================*/
1756 function ‪has_turret( n_index )
1757 {
1758  if ( isdefined( self.a_turrets ) && isdefined( self.a_turrets[ n_index ] ) )
1759  {
1760  return true;
1761  }
1762 
1763  return false;
1764 }
1765 
1766 /*===================================================================
1767 SELF: turret or vehicle
1768 PURPOSE: Initialize a turret for use in this system
1769 RETURNS: The turret data struct
1770 [n_index]: optional index of vehicle turret if self is a vehicle
1771 ===================================================================*/
1772 
1773 function ‪_init_turret( n_index = 0 )
1774 {
1775  self endon( "death" );
1776 
1777  w_weapon = ‪get_weapon( n_index );
1778 
1779  if ( w_weapon == level.weaponNone )
1780  {
1781  AssertMsg( "Cannot initialize turret. No weapon info." );
1782  return;
1783  }
1784 
1785  ‪util::waittill_asset_loaded( "xmodel", self.model );
1786 
1787  if ( IsVehicle( self ) )
1788  {
1789  s_turret = ‪_init_vehicle_turret( n_index );
1790  }
1791  else
1792  {
1793  AssertMsg( "Misc turrets are no longer supported, please use a supported script_vehicle turret" );
1794  }
1795 
1796  s_turret.w_weapon = w_weapon;
1797  ‪_update_turret_arcs( n_index );
1798 
1799  s_turret.is_enabled = false;
1800  s_turret.e_parent = self;
1801  s_turret.e_target = undefined;
1802  s_turret.b_ignore_line_of_sight = false;
1803  s_turret.v_offset = (0, 0, 0);
1804  s_turret.n_burst_fire_time = 0;
1805  s_turret.n_max_target_distance_squared = undefined;
1806  s_turret.n_min_target_distance_squared = undefined;
1807 
1808  // Defaults
1809  s_turret.str_weapon_type = "bullet";
1810  s_turret.str_guidance_type = "none";
1811 
1812  s_turret.str_weapon_type = w_weapon.type;
1813  s_turret.str_guidance_type = w_weapon.guidedMissileType;
1814 
1815  ‪set_on_target_angle( undefined, n_index );
1816 
1817  s_turret.n_target_flags = ‪TURRET_TARGET_AI | ‪TURRET_TARGET_PLAYERS;
1818 
1820 
1821  s_turret ‪flag::init( "turret manual" );
1822 
1823  return s_turret;
1824 }
1825 
1826 function ‪_update_turret_arcs( n_index )
1827 {
1828  s_turret = ‪_get_turret_data( n_index );
1829  s_turret.rightarc = s_turret.w_weapon.rightArc;
1830  s_turret.leftarc = s_turret.w_weapon.leftArc;
1831  s_turret.toparc = s_turret.w_weapon.topArc;
1832  s_turret.bottomarc = s_turret.w_weapon.bottomArc;
1833 }
1834 
1836 {
1837  switch ( ‪_get_turret_data( n_index ).str_weapon_type )
1838  {
1839  case "bullet":
1841  break;
1842 
1843  case "gas":
1845  break;
1846 
1847  case "grenade":
1849  break;
1850 
1851  case "projectile":
1853  break;
1854 
1855  default:
1856  AssertMsg( "unsupported turret weapon type." );
1857  }
1858 }
1859 
1871 function ‪set_best_target_func( func_get_best_target, n_index )
1872 {
1873  ‪_get_turret_data( n_index ).func_get_best_target = func_get_best_target;
1874 }
1875 
1876 /*===================================================================
1877 SELF: vehicle
1878 PURPOSE: Initialize a vehicle turret for use in this system
1879 RETURNS: The turret data struct
1880 <n_index>: index of vehicle turret
1881 ===================================================================*/
1882 function ‪_init_vehicle_turret( n_index )
1883 {
1884  Assert( isdefined( n_index ) && ( n_index >= 0 ), "Invalid index specified to initialize vehicle turret." );
1885 
1886  s_turret = SpawnStruct();
1887 
1888  v_angles = self GetSeatFiringAngles( n_index );
1889  if ( isdefined( v_angles ) )
1890  {
1891  s_turret.n_rest_angle_pitch = 0;
1892  s_turret.n_rest_angle_yaw = 0;
1893  }
1894 
1895  switch ( n_index )
1896  {
1897  case 0:
1898  s_turret.str_tag_flash = "tag_flash";
1899  s_turret.str_tag_pivot = "tag_barrel";
1900  break;
1901 
1902  case 1:
1903  s_turret.str_tag_flash = "tag_gunner_flash1";
1904  s_turret.str_tag_pivot = "tag_gunner_barrel1";
1905  break;
1906 
1907  case 2:
1908  s_turret.str_tag_flash = "tag_gunner_flash2";
1909  s_turret.str_tag_pivot = "tag_gunner_barrel2";
1910  break;
1911 
1912  case 3:
1913  s_turret.str_tag_flash = "tag_gunner_flash3";
1914  s_turret.str_tag_pivot = "tag_gunner_barrel3";
1915  break;
1916 
1917  case 4:
1918  s_turret.str_tag_flash = "tag_gunner_flash4";
1919  s_turret.str_tag_pivot = "tag_gunner_barrel4";
1920  break;
1921  }
1922 
1923  if ( ‪IS_HELICOPTER( self ) )
1924  {
1925  // helicopters are not likely to shoot themselves, but can also cause problems tracing
1926  // don't ignore ground vehicle like trucks because they are likely to shoot themselves
1927  s_turret.e_trace_ignore = self;
1928  }
1929 
1930  if ( !isdefined( self.a_turrets ) )
1931  {
1932  self.a_turrets = [];
1933  }
1934 
1935  self.a_turrets[n_index] = s_turret;
1936 
1937  if ( n_index > 0 )
1938  {
1939  // If vehicle has a gunner tag, assume it needs a user
1940  tag_origin = self GetTagOrigin( ‪_get_gunner_tag_for_turret_index( n_index ) );
1941  if ( isdefined( tag_origin ) )
1942  {
1943  ‪_set_turret_needs_user( n_index, true );
1944  }
1945  }
1946 
1947  return s_turret;
1948 }
1949 
1950 /*===================================================================
1951 SELF: turret or vehicle
1952 PURPOSE: fires a turret for one burst based on min and max burst
1953 values
1954 RETURNS: the total time of the burst plus wait time
1955 [n_max_time]: the max time that the burst will take
1956 [n_index]: optional index of vehicle turret if self is a vehicle
1957 ===================================================================*/
1958 function ‪_burst_fire( n_max_time, n_index )
1959 {
1960  self endon( "terminate_all_turrets_firing" );
1961 
1962  if ( n_max_time < 0 )
1963  {
1964  n_max_time = 9999;
1965  }
1966 
1967  s_turret = ‪_get_turret_data( n_index );
1968 
1969  n_burst_time = ‪_get_burst_fire_time( n_index );
1970  n_burst_wait = ‪_get_burst_wait_time( n_index );
1971 
1972  if ( !isdefined( n_burst_time ) || ( n_burst_time > n_max_time ) )
1973  {
1974  n_burst_time = n_max_time;
1975  }
1976 
1977  if ( s_turret.n_burst_fire_time >= n_burst_time )
1978  {
1979  s_turret.n_burst_fire_time = 0;
1980 
1981  n_time_since_last_shot = ( GetTime() - s_turret.n_last_fire_time ) / 1000;
1982  if ( n_time_since_last_shot < n_burst_wait )
1983  {
1984  wait ( n_burst_wait - n_time_since_last_shot );
1985  }
1986  }
1987  else
1988  {
1989  n_burst_time = n_burst_time - s_turret.n_burst_fire_time;
1990  }
1991 
1992  w_weapon = ‪get_weapon( n_index );
1993  n_fire_time = w_weapon.fireTime;
1994  n_total_time = 0;
1995 
1996  while ( n_total_time < n_burst_time )
1997  {
1998  ‪turret::fire( n_index );
1999 
2000  n_total_time += n_fire_time; // keep track of time for this instance of burst fire
2001  s_turret.n_burst_fire_time += n_fire_time; // keep track of totall burst time between multiple calls to burst fire
2002 
2003  wait n_fire_time;
2004  }
2005 
2006  if ( n_burst_wait > 0 )
2007  {
2008  wait n_burst_wait;
2009  }
2010 
2011  return n_burst_time + n_burst_wait;
2012 }
2013 
2014 /*===================================================================
2015 SELF: turret or vehicle
2016 PURPOSE: get the random burst time for a turret based on min
2017 and max values
2018 RETURNS: number between burst_min and burst_max, or 0
2019 [n_index]: optional index of vehicle turret if self is a vehicle
2020 ===================================================================*/
2021 function ‪_get_burst_fire_time( n_index)
2022 {
2023  s_turret = ‪_get_turret_data( n_index );
2024  n_time = undefined;
2025 
2026  if ( isdefined( s_turret.n_burst_fire_min ) && isdefined( s_turret.n_burst_fire_max ) )
2027  {
2028  if ( s_turret.n_burst_fire_min == s_turret.n_burst_fire_max )
2029  {
2030  n_time = s_turret.n_burst_fire_min;
2031  }
2032  else
2033  {
2034  n_time = RandomFloatRange( s_turret.n_burst_fire_min, s_turret.n_burst_fire_max );
2035  }
2036  }
2037  else if ( isdefined( s_turret.n_burst_fire_max ) )
2038  {
2039  n_time = RandomFloatRange( 0, s_turret.n_burst_fire_max );
2040  }
2041 
2042  return n_time;
2043 }
2044 
2045 /*===================================================================
2046 SELF: turret or vehicle
2047 PURPOSE: get the random burst wait time for a turret struct based
2048 on min and max values
2049 RETURNS: number between wait_min and wait_max, or 0 by default
2050 [n_index]: optional index of vehicle turret if self is a vehicle
2051 ===================================================================*/
2052 function ‪_get_burst_wait_time( n_index )
2053 {
2054  s_turret = ‪_get_turret_data( n_index );
2055  n_time = 0;
2056 
2057  if ( isdefined( s_turret.n_burst_wait_min ) && isdefined( s_turret.n_burst_wait_max ) )
2058  {
2059  if ( s_turret.n_burst_wait_min == s_turret.n_burst_wait_max )
2060  {
2061  n_time = s_turret.n_burst_wait_min;
2062  }
2063  else
2064  {
2065  n_time = RandomFloatRange( s_turret.n_burst_wait_min, s_turret.n_burst_wait_max );
2066  }
2067  }
2068  else if ( isdefined( s_turret.n_burst_wait_max ) )
2069  {
2070  n_time = RandomFloatRange( 0, s_turret.n_burst_wait_max );
2071  }
2072 
2073  return n_time;
2074 }
2075 
2076 /*===================================================================
2077 PURPOSE: convert a turret index to a string value. used for
2078 unique endons, etc.
2079 RETURNS: string value of index if defined. empty string if not
2080 defined.
2081 [n_index]: optional index of vehicle turret if self is a vehicle
2082 ===================================================================*/
2083 function ‪_index( n_index )
2084 {
2085  return ‪STR( n_index );
2086 }
2087 
2088 /*------------------------------------------------------------------------------------------------------
2089  Targeting Functions
2090 ------------------------------------------------------------------------------------------------------*/
2091 
2092 // self = turret or vehicle
2093 function ‪_get_potential_targets( n_index )
2094 {
2095  s_turret = self ‪_get_turret_data( n_index );
2096 
2097  //************************************************************************************************
2098  // MikeA: For now if we have a target array the only targets we are interested is the target array
2099  //************************************************************************************************
2100 
2101  a_priority_targets = self ‪_get_any_priority_targets( n_index );
2102 
2103  if ( isdefined( a_priority_targets ) && ( a_priority_targets.size > 0 ) )
2104  {
2105  //return arrayCopy( a_priority_targets );
2106  return( a_priority_targets );
2107  }
2108 
2109  //****************************
2110  // Search for a regular target
2111  //****************************
2112 
2113  a_potential_targets = [];
2114 
2115  str_team = ‪get_team( n_index );
2116  if ( self.use_non_teambased_enemy_selection === true && !level.teambased )
2117  {
2118  // get all ai, players, and vehicles
2119 
2120  a_all_targets = [];
2121 
2122  if ( ‪_has_target_flags( ‪TURRET_TARGET_AI, n_index ) )
2123  {
2124  a_ai_targets = GetAIArray();
2125  a_all_targets = ArrayCombine( a_all_targets, a_ai_targets, true, false );
2126  }
2127 
2129  {
2130  a_all_targets = ArrayCombine( a_all_targets, level.players, true, false );
2131  }
2132 
2134  {
2135  a_all_targets = ArrayCombine( a_all_targets, level.vehicles_list, true, false );
2136  }
2137 
2138  // remove all targets not on the same team
2139  for ( i = 0; i < a_all_targets.size; i++ )
2140  {
2141  ‪e_target = a_all_targets[i];
2142 
2143  if ( !isdefined( ‪e_target ) )
2144  continue;
2145 
2146  if ( !isdefined( ‪e_target.team ) )
2147  continue;
2148 
2149  if ( ‪e_target.team == str_team )
2150  continue;
2151 
2152  if( !‪IS_TRUE( level.team_free_targeting ) && ( ‪e_target.team == "free" ) )
2153  continue;
2154 
2155  a_potential_targets[ a_potential_targets.size ] = ‪e_target;
2156  }
2157  }
2158  else if ( isdefined( str_team ) )
2159  {
2160  str_opposite_team = "allies";
2161  if ( str_team == "allies" )
2162  {
2163  str_opposite_team = "axis";
2164  }
2165 
2166  if ( ‪_has_target_flags( ‪TURRET_TARGET_AI, n_index ) )
2167  {
2168  a_ai_targets = GetAITeamArray( str_opposite_team );
2169  if( ‪IS_TRUE( level.team_free_targeting ) )
2170  {
2171  a_ai_targets = ArrayCombine( GetAITeamArray( "free" ), a_ai_targets, true, false );
2172  }
2173  a_potential_targets = ArrayCombine( a_potential_targets, a_ai_targets, true, false );
2174  }
2175 
2177  {
2178  a_potential_targets = ArrayCombine( a_potential_targets, level.aliveplayers[ str_opposite_team ], true, false );
2179  }
2180 
2182  {
2183 // a_drone_targets = _drones::drones_get_array( str_opposite_team ); TODO: _drones has been removed
2184 // a_potential_targets = ArrayCombine( a_potential_targets, a_drone_targets, true, false );
2185  }
2186 
2188  {
2189  a_vehicle_targets = GetVehicleTeamArray( str_opposite_team );
2190  a_potential_targets = ArrayCombine( a_potential_targets, a_vehicle_targets, true, false );
2191  }
2192  }
2193 
2194  if ( isdefined( s_turret.e_target ) && !IsInArray( a_potential_targets, s_turret.e_target ) )
2195  {
2196  a_potential_targets[ a_potential_targets.size ] = s_turret.e_target;
2197  }
2198 
2199  //**************************************
2200  // Remove targets that should be ignored
2201  //**************************************
2202 
2203  if ( isdefined( str_team ) )
2204  {
2205  a_valid_targets = [];
2206 
2207  for ( i = 0; i < a_potential_targets.size; i++ )
2208  {
2209  ‪e_target = a_potential_targets[i];
2210  ignore_target = false;
2211 
2212  assert( isdefined( ‪e_target ), "Undefined potential turret target." );
2213 
2214  // Should we remove the target?
2215  if ( ‪IS_TRUE( ‪e_target.ignoreme ) || !isdefined( ‪e_target.health ) || ( ‪e_target.health <= 0 ) )
2216  {
2217  ignore_target = true;
2218  }
2219  else if ( IsSentient( ‪e_target ) && ( ( ‪e_target IsNoTarget() ) || ( ‪e_target ‪ai::is_dead_sentient() ) ) ) // Removal checks for Sentients Only
2220  {
2221  ignore_target = true;
2222  }
2223  else if ( ‪_is_target_within_range( ‪e_target, s_turret ) == false ) // Remove target if we have a target limit distance set
2224  {
2225  ignore_target = true;
2226  }
2227  else if ( isplayer( ‪e_target ) && ‪e_target hasPerk( "specialty_nottargetedbysentry" ) )
2228  {
2229  ignore_target = true;
2230  }
2231 
2232  if ( !ignore_target )
2233  {
2234  a_valid_targets[ a_valid_targets.size ] = ‪e_target;
2235  }
2236  }
2237 
2238  // Save the new valid targets
2239  a_potential_targets = a_valid_targets;
2240  }
2241 
2242  a_targets = a_potential_targets;
2243 
2244  if ( isdefined( s_turret ) && isdefined( s_turret.a_ignore_target_array ) )
2245  {
2246  while ( true )
2247  {
2248  found_bad_target = 0;
2249  a_targets = a_potential_targets;
2250 
2251  for ( i = 0; i < a_targets.size; i++ )
2252  {
2253  ‪e_target = a_targets[i];
2254  found_bad_target = 0;
2255 
2256  for ( j = 0; j < s_turret.a_ignore_target_array.size; j++ )
2257  {
2258  if ( ‪e_target == s_turret.a_ignore_target_array[ j ] )
2259  {
2260  ArrayRemoveValue( a_potential_targets, ‪e_target );
2261  found_bad_target = 1;
2262  break;
2263  }
2264  }
2265  }
2266 
2267  if ( !found_bad_target )
2268  {
2269  break;
2270  }
2271  }
2272  }
2273 
2274  return a_potential_targets;
2275 }
2276 
2277 // self = Vehicle/MG
2279 {
2280  if ( isdefined( s_turret.n_max_target_distance_squared ) || isdefined( s_turret.n_min_target_distance_squared ) )
2281  {
2282  if ( !isdefined( ‪e_target.origin ) )
2283  return false;
2284 
2285  n_dist_squared = DistanceSquared( ‪e_target.origin, self.origin );
2286 
2287  if ( n_dist_squared > ‪VAL( s_turret.n_max_target_distance_squared, 811711611 ) )
2288  return false;
2289 
2290  if ( n_dist_squared < ‪VAL( s_turret.n_min_target_distance_squared, 0 ) )
2291  return false;
2292  }
2293 
2294  return true;
2295 }
2296 
2297 function ‪_get_any_priority_targets( n_index )
2298 {
2299  a_targets = undefined;
2300 
2301  s_turret = ‪_get_turret_data( n_index );
2302 
2303  // Do we have a set of priority targets?
2304  if ( isdefined( s_turret.priority_target_array ) )
2305  {
2306  while ( true )
2307  {
2308  found_bad_target = 0;
2309  a_targets = s_turret.priority_target_array;
2310 
2311  // Make sure all the priority tagets are still alive
2312  for ( i = 0; i < a_targets.size; i++ )
2313  {
2314  ‪e_target = a_targets[ i ];
2315  bad_index = undefined;
2316 
2317  // Should we remove the target?
2318  if ( !isdefined( ‪e_target ) )
2319  {
2320  bad_index = i;
2321  }
2322  else if ( !IsAlive( ‪e_target ) )
2323  {
2324  bad_index = i;
2325  }
2326  else if ( ‪e_target.health <= 0 )
2327  {
2328  bad_index = i;
2329  }
2330  else if ( IsSentient( ‪e_target ) && ( ‪e_target ‪ai::is_dead_sentient() ) )
2331  {
2332  bad_index = i;
2333  }
2334 
2335  if ( isdefined( bad_index ) )
2336  {
2337  s_turret.priority_target_array = a_targets;
2338  ArrayRemoveValue( s_turret.priority_target_array, ‪e_target );
2339  found_bad_target = 1;
2340  break;
2341  }
2342  }
2343 
2344  // Did we removee any bad targets?
2345  if ( !found_bad_target )
2346  {
2347  return ( s_turret.priority_target_array );
2348  break;
2349  }
2350  else
2351  {
2352  if ( s_turret.priority_target_array.size <= 0 )
2353  {
2354  s_turret.priority_target_array = undefined;
2355  self notify( "target_array_destroyed" );
2356  break;
2357  }
2358  }
2359  }
2360  }
2361 
2362  return( a_targets );
2363 }
2364 
2365 function ‪_get_best_target_from_potential( a_potential_targets, n_index )
2366 {
2367  s_turret = ‪_get_turret_data( n_index );
2368  return [[ s_turret.func_get_best_target ]]( a_potential_targets, n_index );
2369 }
2370 
2371 function ‪_get_best_target_bullet( a_potential_targets, n_index )
2372 {
2373  e_best_target = undefined;
2374 
2375  while ( !isdefined( e_best_target ) && ( a_potential_targets.size > 0 ) )
2376  {
2377  e_closest_target = ArrayGetClosest( self.origin, a_potential_targets );
2378 
2379  if ( !isdefined( e_closest_target ) )
2380  {
2381  break;
2382  }
2383  else if( self ‪can_hit_target( e_closest_target, n_index ) )
2384  {
2385  e_best_target = e_closest_target;
2386  }
2387  else
2388  {
2389  ArrayRemoveValue( a_potential_targets, e_closest_target );
2390  }
2391  }
2392 
2393  return e_best_target;
2394 }
2395 
2396 function ‪_get_best_target_gas( a_potential_targets, n_index )
2397 {
2398  // TODO: TEMP: use bullet function
2399  return ‪_get_best_target_bullet( a_potential_targets, n_index );
2400 }
2401 
2402 function ‪_get_best_target_grenade( a_potential_targets, n_index )
2403 {
2404  // TODO: TEMP: use bullet function
2405  return ‪_get_best_target_bullet( a_potential_targets, n_index );
2406 }
2407 
2408 function ‪_get_best_target_projectile( a_potential_targets, n_index )
2409 {
2410  // TODO: TEMP: use bullet function
2411  return ‪_get_best_target_bullet( a_potential_targets, n_index );
2412 }
2413 
2424 // self = vehicle or turret
2425 function ‪can_hit_target( ‪e_target, n_index )
2426 {
2427  s_turret = ‪_get_turret_data( n_index );
2428  v_offset = ‪_get_default_target_offset( ‪e_target, n_index );
2429 
2430  b_current_target = ‪is_target( ‪e_target, n_index );
2431 
2432  if(isDefined(‪e_target) && ‪IS_TRUE(‪e_target.ignoreme))
2433  return false;
2434 
2435  b_target_in_view = ‪is_target_in_view( ( IsPlayer( ‪e_target ) ? ‪e_target GetTagOrigin( "tag_eye" ) : ‪e_target.origin + v_offset ), n_index );
2436  b_trace_passed = true;
2437 
2438  if ( b_target_in_view )
2439  {
2440  if ( !s_turret.b_ignore_line_of_sight )
2441  {
2442  b_trace_passed = ‪trace_test( ‪e_target, v_offset - ( 0, 0, ( IsVehicle( ‪e_target ) ? 0 : ‪VAL( s_turret.n_torso_targetting_offset, 0 ) ) ), n_index );
2443  }
2444 
2445  if ( b_current_target && !b_trace_passed && !isdefined( s_turret.n_time_lose_sight ) )
2446  {
2447  s_turret.n_time_lose_sight = GetTime();
2448  }
2449  }
2450  else if ( b_current_target )
2451  {
2452  s_turret.b_target_out_of_range = true;
2453  }
2454 
2455  return ( b_target_in_view && b_trace_passed );
2456 }
2457 
2468 //self = turret/vehicle
2469 function ‪is_target_in_view( v_target, n_index )
2470 {
2471  /#
2472  ‪_update_turret_arcs( n_index );
2473  #/
2474 
2475  s_turret = ‪_get_turret_data( n_index );
2476 
2477  v_pivot_pos = self GetTagOrigin( s_turret.str_tag_pivot );
2478  v_angles_to_target = VectorToAngles( v_target - v_pivot_pos );
2479 
2480  n_rest_angle_pitch = s_turret.n_rest_angle_pitch + self.angles[0];
2481  n_rest_angle_yaw = s_turret.n_rest_angle_yaw + self.angles[1];
2482 
2483  n_ang_pitch = AngleClamp180( v_angles_to_target[0] - n_rest_angle_pitch );
2484  n_ang_yaw = AngleClamp180( v_angles_to_target[1] - n_rest_angle_yaw );
2485 
2486  b_out_of_range = false;
2487 
2488  if ( n_ang_pitch > 0 )
2489  {
2490  if ( n_ang_pitch > s_turret.bottomarc )
2491  {
2492  b_out_of_range = true;
2493  }
2494  }
2495  else
2496  {
2497  if ( Abs( n_ang_pitch ) > s_turret.toparc )
2498  {
2499  b_out_of_range = true;
2500  }
2501  }
2502 
2503  if ( n_ang_yaw > 0 )
2504  {
2505  if ( n_ang_yaw > s_turret.leftarc )
2506  {
2507  b_out_of_range = true;
2508  }
2509  }
2510  else
2511  {
2512  if ( Abs( n_ang_yaw ) > s_turret.rightarc )
2513  {
2514  b_out_of_range = true;
2515  }
2516  }
2517 
2518  return !b_out_of_range;
2519 }
2520 
2533 #define TURRET_TRACE_OFFSET 50
2534 //self = turret/vehicle
2535 function ‪trace_test( ‪e_target, v_offset = (0,0,0), n_index )
2536 {
2537  //********************************************************************************
2538  // Old style tracing, reviving to restore functionality in pak3 at this late stage
2539  //********************************************************************************
2540 
2541  if ( isdefined( self.good_old_style_turret_tracing ) )
2542  {
2543  s_turret = ‪_get_turret_data( n_index );
2544 
2545  v_start_org = self GetTagOrigin( s_turret.str_tag_pivot );
2546  if ( ‪e_target SightConeTrace( v_start_org, self ) > .2 )
2547  {
2548  // If we can see the target, make sure we can bullet trace over half way to hit the target
2549  v_target = ‪e_target.origin + v_offset;
2550  v_start_org += VectorNormalize( v_target - v_start_org ) * ‪TURRET_TRACE_OFFSET;
2551  a_trace = BulletTrace( v_start_org, v_target, true, s_turret.e_trace_ignore, true, true );
2552  if ( a_trace["fraction"] > .6 )
2553  {
2554  return true;
2555  }
2556  }
2557 
2558  return false;
2559  }
2560 
2561 
2562  //*************************************************************************************************
2563  // MikeA: I think there is a bug where when we have two people in a vehicle
2564  // If the driver is in the LOS of the gunner and the target, the trace will hit the driver and fail
2565  //*************************************************************************************************
2566 
2567  s_turret = ‪_get_turret_data( n_index );
2568 
2569  v_start_org = self GetTagOrigin( s_turret.str_tag_pivot );
2570  v_target = ‪e_target.origin + v_offset;
2571 
2572  if ( SessionModeIsMultiplayerGame() && IsPlayer( ‪e_target ) )
2573  v_target = ‪e_target GetShootAtPos();
2574 
2575  if ( DistanceSquared( v_start_org, v_target ) < 100*100 )
2576  return true;
2577 
2578  v_dir_to_target = VectorNormalize( v_target - v_start_org );
2579 
2580  v_start_org += v_dir_to_target * ‪TURRET_TRACE_OFFSET;
2581  v_target -= v_dir_to_target * 75; // don't have to see all the way there
2582 
2583  if ( SightTracePassed( v_start_org, v_target, false, self ) )
2584  {
2585  /* too expensive
2586  v_start_org = self GetTagOrigin( s_turret.str_tag_flash );
2587  v_start_org += v_dir_to_target * TURRET_TRACE_OFFSET;
2588 
2589  // If we can see the target, make sure we can bullet trace over half way to hit the target
2590  a_trace = BulletTrace( v_start_org, v_target, true, s_turret.e_trace_ignore, true, true );
2591  if ( a_trace["fraction"] > .6 )
2592  {
2593  return true;
2594  }
2595  */
2596  return true;
2597  }
2598 
2599  return false;
2600 }
2601 
2613 function ‪set_ignore_line_of_sight( b_ignore, n_index )
2614 {
2615  s_turret = ‪_get_turret_data( n_index );
2616  s_turret.b_ignore_line_of_sight = b_ignore;
2617 }
2618 
2630 function ‪set_occupy_no_target_time( time, n_index )
2631 {
2632  s_turret = ‪_get_turret_data( n_index );
2633  s_turret.occupy_no_target_time = time;
2634 }
2635 
2636 //self = turret
2637 function ‪toggle_lensflare( bool )
2638 {
2639  self ‪clientfield::set( "toggle_lensflare", bool );
2640 }
2641 
2643 {
2644  self endon( "death" );
2645  self notify( "disable_lens_flare" );
2646  self endon( "disable_lens_flare" );
2647 
2648  while ( true )
2649  {
2650  ‪e_target = self GetTargetEntity();
2651  if ( self.turretontarget && ( isdefined( ‪e_target ) && IsPlayer( ‪e_target ) ) )
2652  {
2653  if ( IsDefined( self GetTagOrigin( "TAG_LASER" ) ) )
2654  {
2655  ‪e_target ‪util::waittill_player_looking_at( self GetTagOrigin( "TAG_LASER" ), 90 );
2656  if(isDefined(‪e_target))
2657  {
2658  self ‪turret::toggle_lensflare( true );
2659  ‪e_target ‪util::waittill_player_not_looking_at( self GetTagOrigin( "TAG_LASER" ) );
2660  }
2661  self ‪turret::toggle_lensflare( false );
2662  }
2663  else
2664  {
2665  }
2666  }
2667 
2668  wait 0.5;//We don't need to check too often, helps keep resources down if we have a lot of turrets
2669  }
2670 }
2671 
2672 //*****************************************************************************
2673 // If the AI or Drone is manning a Turret, init the vehicles turret
2674 // self = AI User or Drone User
2675 //*****************************************************************************
2676 
2678 {
2679  switch ( n_index )
2680  {
2681  case 1: return "tag_gunner1";
2682  case 2: return "tag_gunner2";
2683  case 3: return "tag_gunner3";
2684  case 4: return "tag_gunner4";
2685  default: AssertMsg( "unsupported turret index for getting gunner tag." );
2686  }
2687 }
2688 
2689 function ‪_get_turret_index_for_tag( str_tag )
2690 {
2691  switch ( str_tag )
2692  {
2693  case "tag_gunner1": return 1;
2694  case "tag_gunner2": return 2;
2695  case "tag_gunner3": return 3;
2696  case "tag_gunner4": return 4;
2697  }
2698 }
‪shoot_at_target
‪function shoot_at_target(e_target, n_time, v_offset, n_index, b_just_once)
Definition: turret_shared.gsc:1010
‪set_ignore_line_of_sight
‪function set_ignore_line_of_sight(b_ignore, n_index)
Definition: turret_shared.gsc:2613
‪toggle_lensflare
‪function toggle_lensflare(bool)
Definition: turret_shared.gsc:2637
‪is_target
‪function is_target(e_target, n_index)
Definition: turret_shared.gsc:769
‪_did_turret_lose_target
‪function _did_turret_lose_target(n_time_now)
Definition: turret_shared.gsc:1406
‪fire
‪function fire(n_index)
Definition: turret_shared.gsc:889
‪enable_auto_use
‪function enable_auto_use(b_enable=true)
Definition: turret_shared.gsc:1137
‪track_lens_flare
‪function track_lens_flare()
Definition: turret_shared.gsc:2642
‪_get_gunner_tag_for_turret_index
‪function _get_gunner_tag_for_turret_index(n_index)
Definition: turret_shared.gsc:2677
‪e_target
‪var e_target
Definition: traps_shared.gsc:2029
‪_get_default_target_offset
‪function _get_default_target_offset(e_target, n_index)
Definition: turret_shared.gsc:703
‪NEARBY_DISTANCE_Z
‪#define NEARBY_DISTANCE_Z
Definition: turret_shared.gsc:1361
‪NEARBY_ENEMY_TIME
‪#define NEARBY_ENEMY_TIME
Definition: turret_shared.gsc:1362
‪emp_watcher
‪function emp_watcher(n_index)
Definition: turret_shared.gsc:318
‪enable
‪function enable(n_index, b_user_required, v_offset)
Definition: turret_shared.gsc:1108
‪set_max_target_distance
‪function set_max_target_distance(n_distance, n_index)
Definition: turret_shared.gsc:842
‪MAX_OCCUPY_NO_TARGET_TIME
‪#define MAX_OCCUPY_NO_TARGET_TIME
Definition: turret_shared.gsc:211
‪clear_target
‪function clear_target(n_index)
Definition: turret_shared.gsc:791
‪_get_best_target_bullet
‪function _get_best_target_bullet(a_potential_targets, n_index)
Definition: turret_shared.gsc:2371
‪enable_emp
‪function enable_emp(b_enable, n_index)
Definition: turret_shared.gsc:356
‪get_out
‪function get_out(str_mode)
Definition: vehicleriders_shared.gsc:481
‪set_target_flags
‪function set_target_flags(n_flags, n_index)
Definition: turret_shared.gsc:819
‪IS_HELICOPTER
‪#define IS_HELICOPTER(__e)
Definition: shared.gsh:351
‪clear
‪function clear(str_flag)
Definition: flag_shared.csc:130
‪set_target
‪function set_target(e_target, v_offset, n_index)
Definition: turret_shared.gsc:680
‪get_in
‪function get_in(vh, str_pos, b_teleport=false)
Definition: vehicleriders_shared.gsc:226
‪_waittill_user_change
‪function _waittill_user_change(n_index)
Definition: turret_shared.gsc:1478
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪waittill_either
‪function waittill_either(msg1, msg2)
Definition: util_shared.gsc:303
‪get_parent
‪function get_parent(n_index)
Definition: turret_shared.gsc:244
‪unpause
‪function unpause(n_index)
Definition: turret_shared.gsc:1225
‪disable_ai_getoff
‪function disable_ai_getoff(n_index, b_disable=true)
Definition: turret_shared.gsc:1153
‪add_priority_target
‪function add_priority_target(ent_or_ent_array, n_index)
Definition: turret_shared.gsc:496
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪_drop_turret
‪function _drop_turret(n_index, bExitIfAutomatedOnly)
Definition: turret_shared.gsc:1524
‪waittill_player_not_looking_at
‪function waittill_player_not_looking_at(origin, dot, do_trace)
Definition: util_shared.gsc:1641
‪_get_burst_fire_time
‪function _get_burst_fire_time(n_index)
Definition: turret_shared.gsc:2021
‪get_team
‪function get_team(n_index)
Definition: turret_shared.gsc:379
‪_get_best_target_gas
‪function _get_best_target_gas(a_potential_targets, n_index)
Definition: turret_shared.gsc:2396
‪trace_test
‪function trace_test(e_target, v_offset=(0, 0, 0), n_index)
Definition: turret_shared.gsc:2535
‪_user_check
‪function _user_check(n_index)
Definition: turret_shared.gsc:1623
‪set_target_leading
‪function set_target_leading(n_index, n_target_leading_factor=0.1)
Definition: turret_shared.gsc:626
‪_turret_new_user_think
‪function _turret_new_user_think(n_index)
Definition: turret_shared.gsc:1534
‪_init_vehicle_turret
‪function _init_vehicle_turret(n_index)
Definition: turret_shared.gsc:1882
‪set_min_target_distance_squared
‪function set_min_target_distance_squared(n_distance_squared, n_index)
Definition: turret_shared.gsc:874
‪get_user
‪function get_user(n_index)
Definition: turret_shared.gsc:447
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪set_team
‪function set_team(str_team, n_index)
Definition: turret_shared.gsc:371
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪set_burst_parameters
‪function set_burst_parameters(n_fire_min, n_fire_max, n_wait_min, n_wait_max, n_index)
Definition: turret_shared.gsc:609
‪set_on_target_angle
‪function set_on_target_angle(n_angle, n_index)
Definition: turret_shared.gsc:643
‪does_have_target
‪function does_have_target(n_index)
Definition: turret_shared.gsc:1618
‪waittill_asset_loaded
‪function waittill_asset_loaded(str_type, str_name)
Definition: util_shared.gsc:1921
‪can_hit_target
‪function can_hit_target(e_target, n_index)
Definition: turret_shared.gsc:2425
‪set_best_target_func_from_weapon_type
‪function set_best_target_func_from_weapon_type(n_index)
Definition: turret_shared.gsc:1835
‪has_turret
‪function has_turret(n_index)
Definition: turret_shared.gsc:1756
‪laser_death_watcher
‪function laser_death_watcher()
Definition: turret_shared.gsc:249
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪TURRET_TARGET_PLAYERS
‪#define TURRET_TARGET_PLAYERS
Definition: shared.gsh:345
‪_is_target_within_range
‪function _is_target_within_range(e_target, s_turret)
Definition: turret_shared.gsc:2278
‪enable_laser
‪function enable_laser(b_enable, n_index)
Definition: turret_shared.gsc:260
‪clear_target_ent_array
‪function clear_target_ent_array(n_index)
Definition: turret_shared.gsc:530
‪get_weapon
‪function get_weapon(n_index=0)
Definition: turret_shared.gsc:229
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪clear_ignore_ent_array
‪function clear_ignore_ent_array(n_index)
Definition: turret_shared.gsc:564
‪_set_turret_needs_user
‪function _set_turret_needs_user(n_index, b_needs_user)
Definition: turret_shared.gsc:452
‪_get_potential_targets
‪function _get_potential_targets(n_index)
Definition: turret_shared.gsc:2093
‪set_torso_targetting
‪function set_torso_targetting(n_index, n_torso_targetting_offset=(-12))
Definition: turret_shared.gsc:619
‪_debug_turret_think
‪function _debug_turret_think(n_index)
Definition: turret_shared.gsc:1640
‪watch_for_flash
‪function watch_for_flash()
Definition: turret_shared.gsc:276
‪STR
‪#define STR(__var)
Definition: shared.gsh:297
‪_init_turret
‪function _init_turret(n_index=0)
Definition: turret_shared.gsc:1773
‪_get_best_target_grenade
‪function _get_best_target_grenade(a_potential_targets, n_index)
Definition: turret_shared.gsc:2402
‪set_best_target_func
‪function set_best_target_func(func_get_best_target, n_index)
Definition: turret_shared.gsc:1871
‪does_need_user
‪function does_need_user(n_index)
Definition: turret_shared.gsc:418
‪_get_burst_wait_time
‪function _get_burst_wait_time(n_index)
Definition: turret_shared.gsc:2052
‪is_dead_sentient
‪function is_dead_sentient()
Definition: ai_shared.gsc:210
‪fire_for_time
‪function fire_for_time(n_time, n_index=0)
Definition: turret_shared.gsc:953
‪_get_turret_index_for_tag
‪function _get_turret_index_for_tag(str_tag)
Definition: turret_shared.gsc:2689
‪_shoot_turret_at_target
‪function _shoot_turret_at_target(e_target, n_time, v_offset, n_index, b_just_once)
Definition: turret_shared.gsc:1026
‪set_ignore_ent_array
‪function set_ignore_ent_array(a_ents, n_index)
Definition: turret_shared.gsc:548
‪set_occupy_no_target_time
‪function set_occupy_no_target_time(time, n_index)
Definition: turret_shared.gsc:2630
‪waittill_player_looking_at
‪function waittill_player_looking_at(origin, arc_angle_degrees=90, do_trace, e_ignore)
Definition: util_shared.gsc:1616
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪_has_target_flags
‪function _has_target_flags(n_flags, n_index)
Definition: turret_shared.gsc:825
‪shoot_at_target_once
‪function shoot_at_target_once(e_target, v_offset, n_index)
Definition: turret_shared.gsc:1092
‪is_current_user
‪function is_current_user(ai_user, n_index)
Definition: turret_shared.gsc:590
‪_index
‪function _index(n_index)
Definition: turret_shared.gsc:2083
‪_burst_fire
‪function _burst_fire(n_max_time, n_index)
Definition: turret_shared.gsc:1958
‪emped
‪function emped(down_time)
Definition: _siegebot.gsc:1359
‪TURRET_TRACE_OFFSET
‪#define TURRET_TRACE_OFFSET
Definition: turret_shared.gsc:2533
‪TURRET_TARGET_AI
‪#define TURRET_TARGET_AI
Definition: shared.gsh:344
‪_listen_for_damage_on_actor
‪function _listen_for_damage_on_actor(ai_user, n_index)
Definition: turret_shared.gsc:1454
‪_waittill_turret_on_target
‪function _waittill_turret_on_target(e_target, n_index)
Definition: turret_shared.gsc:1064
‪_get_turret_data
‪function _get_turret_data(n_index)
Definition: turret_shared.gsc:1725
‪is_target_in_view
‪function is_target_in_view(v_target, n_index)
Definition: turret_shared.gsc:2469
‪stop
‪function stop(n_index, b_clear_target=false)
Definition: turret_shared.gsc:926
‪init
‪function init()
Definition: struct.csc:1
‪NEARBY_DISTANCE_SQ
‪#define NEARBY_DISTANCE_SQ
Definition: turret_shared.gsc:1360
‪_get_best_target_projectile
‪function _get_best_target_projectile(a_potential_targets, n_index)
Definition: turret_shared.gsc:2408
‪TURRET_LOSE_SIGHT_TIME
‪#define TURRET_LOSE_SIGHT_TIME
Definition: turret_shared.gsc:1231
‪a_ents
‪function _query_ents_by_substring_helper a_ents
Definition: util_shared.gsc:3334
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪IS_EQUAL
‪#define IS_EQUAL(__a, __b)
Definition: shared.gsh:250
‪_wait_for_current_user_to_finish
‪function _wait_for_current_user_to_finish(n_index)
Definition: turret_shared.gsc:570
‪get_target
‪function get_target(n_index)
Definition: turret_shared.gsc:760
‪can_get_in
‪function can_get_in(vh, str_pos)
Definition: vehicleriders_shared.gsc:450
‪does_have_user
‪function does_have_user(n_index)
Definition: turret_shared.gsc:432
‪_check_for_paused
‪function _check_for_paused(n_index)
Definition: turret_shared.gsc:1498
‪_has_nearby_player_enemy
‪function _has_nearby_player_enemy(index, turret)
Definition: turret_shared.gsc:1363
‪_get_any_priority_targets
‪function _get_any_priority_targets(n_index)
Definition: turret_shared.gsc:2297
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪disable
‪function disable(n_index)
Definition: turret_shared.gsc:1167
‪pause
‪function pause(time, n_index)
Definition: turret_shared.gsc:1193
‪__init__
‪function __init__()
Definition: turret_shared.gsc:213
‪_turret_user_think
‪function _turret_user_think(n_index)
Definition: turret_shared.gsc:1420
‪TURRET_TARGET_VEHICLES
‪#define TURRET_TARGET_VEHICLES
Definition: shared.gsh:347
‪_get_best_target_from_potential
‪function _get_best_target_from_potential(a_potential_targets, n_index)
Definition: turret_shared.gsc:2365
‪wait_till_clear
‪function wait_till_clear(str_flag)
Definition: flag_shared.csc:248
‪watch_for_flash_and_stun
‪function watch_for_flash_and_stun(n_index)
Definition: turret_shared.gsc:288
‪set_target_ent_array
‪function set_target_ent_array(a_ents, n_index)
Definition: turret_shared.gsc:480
‪TURRET_TARGET_DRONES
‪#define TURRET_TARGET_DRONES
Definition: shared.gsh:346
‪_turret_think
‪function _turret_think(n_index, v_offset)
Definition: turret_shared.gsc:1234
‪set_min_target_distance
‪function set_min_target_distance(n_distance, n_index)
Definition: turret_shared.gsc:858
‪is_turret_enabled
‪function is_turret_enabled(n_index)
Definition: turret_shared.gsc:404
‪_update_turret_arcs
‪function _update_turret_arcs(n_index)
Definition: turret_shared.gsc:1826
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265