‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
spawner_shared.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\ai_shared;
4 #using scripts\shared\array_shared;
5 #using scripts\shared\callbacks_shared;
6 #using scripts\shared\colors_shared;
7 #using scripts\shared\flag_shared;
8 #using scripts\shared\gameskill_shared;
9 #using scripts\shared\serverfaceanim_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\trigger_shared;
12 #using scripts\shared\turret_shared;
13 #using scripts\shared\util_shared;
14 
15 #insert scripts\shared\shared.gsh;
16 
17 #namespace spawner;
18 
19 // Values for showing damage and XP popups.
20 #define XP_DISPLAY_TOTAL_TIME 40
21 #define XP_DISPLAY_MAX_HEIGHT_OFFSET 45
22 #define XP_DISPLAY_DELAY_BEFORE_FADE 20
23 #define DEBUG_DAMAGE_DISPLAY_COLOR (0.96, 0.12, 0.12)
24 #define DEBUG_XP_DISPLAY_COLOR (0.83, 0.18, 0.76)
25 
26 
27 // .script_delete a group of guys, only one of which spawns
28 // .script_patroller follow your targeted patrol
29 // .script_followmin
30 // .script_followmax
31 // .script_radius
32 // .script_friendname
33 // .script_startinghealth
34 // .script_accuracy
35 // .script_grenades
36 // .script_sightrange
37 // .script_ignoreme
38 
39 ‪REGISTER_SYSTEM_EX( "spawner", &‪__init__, &‪__main__, undefined )
40 
41 function ‪__init__()
42 {
43  if( GetDvarString( "noai" ) == "" )
44  {
45  SetDvar( "noai", "off" );
46  }
47 
48  // create default threatbiasgroups;
49 
50  /*CreateThreatBiasGroup( "allies" );//TODO T7
51  CreateThreatBiasGroup( "axis" );*/
52 
53  level._nextcoverprint = 0;
54  level._ai_group = [];
55  level.killedaxis = 0;
56  level.ffpoints = 0;
57  level.missionfailed = false;
58  level.gather_delay = [];
59  level.smoke_thrown = [];
60  level.deathflags = [];
61  level.spawner_number = 0;
62  level.go_to_node_arrays = [];
63 
64  level.next_health_drop_time = 0;
65  level.guys_to_die_before_next_health_drop = RandomIntRange( 1, 4 );
66  level.portable_mg_gun_tag = "J_Shoulder_RI"; // need to get J_gun back to make it work properly
67  level.mg42_hide_distance = 1024;
68 
69  level.global_spawn_timer = 0;
70  level.global_spawn_count = 0;
71 
72  if( !isdefined( level.maxFriendlies ) )
73  {
74  level.maxFriendlies = 11;
75  }
76 
77  level.ai_classname_in_level = [];
78 
79  spawners = GetSpawnerArray();
80  for( i = 0; i < spawners.size; i++ )
81  {
82  spawners[i] thread ‪spawn_prethink();
83  }
84 
85  //TODO T7 - MPAI_PETER_TODO _subclass_main::subclass_setup_spawn_functions();
86 
87  thread ‪process_deathflags();
88 
90 
92 
93  level thread ‪spawner_targets_init();
94 
95  level.ai = [];
99 
100  level thread ‪update_nav_triggers();
101 }
102 
103 function ‪__main__()
104 {
105  waittillframeend;
106 
107  ai = GetAISpeciesArray( "all" );
108  array::thread_all( ai, &‪living_ai_prethink );
109 
110  foreach( ai_guy in ai )
111  {
112  if ( IsAlive( ai_guy ) )
113  {
114  ai_guy.overrideActorKilled = &‪callback_Track_Dead_NPCs_By_Type;
115  ai_guy thread ‪spawn_think();
116  }
117  }
118 
119  level thread ‪spawn_throttle_reset();
120 }
121 
123 {
124  level.valid_navmesh_positions = [];
125 
126  a_nav_triggers = GetEntArray( "trigger_navmesh", "classname" );
127 
128  if ( !a_nav_triggers.size )
129  {
130  return;
131  }
132 
133  /* Build a targetname array - Code only wants the targetname, not the individual triggers */
134 
135  level.navmesh_zones = [];
136  foreach ( trig in a_nav_triggers )
137  {
138  level.navmesh_zones[ trig.targetname ] = false;
139  }
140 
141  while ( true )
142  {
143  UpdateNavTriggers();//optimized version of code commented out below
144 // /* Reset all nav zones to be off */
145 //
146 // foreach ( targetname, on in level.navmesh_zones )
147 // {
148 // level.navmesh_zones[ targetname ] = false;
149 // }
150 //
151 // /* Mark valid zones based on if the AI is touching it or goalpos is inside it */
152 //
153 // foreach ( team, a_ai in level.ai )
154 // {
155 // foreach ( ai in a_ai )
156 // {
157 // if ( IsActor( ai ) && IsAlive( ai ) )
158 // {
159 // a_str_trigs = GetNavMeshTriggersForPoint( ai.origin );
160 //
161 // foreach( str_trig in a_str_trigs )
162 // {
163 // level.navmesh_zones[ str_trig ] = true;
164 // }
165 //
166 // a_str_trigs = GetNavMeshTriggersForPoint( ai.goalpos );
167 //
168 // foreach( str_trig in a_str_trigs )
169 // {
170 // level.navmesh_zones[ str_trig ] = true;
171 // }
172 // }
173 // }
174 // }
175 //
176 // /* Go through and actually enable/disable the nav triggers */
177 //
178 // foreach ( targetname, on in level.navmesh_zones )
179 // {
180 // EnableNavMeshTrigger( targetname, on );
181 // }
182 
183  level ‪util::waittill_notify_or_timeout( "update_nav_triggers", 1 );
184  }
185 }
186 
188 {
189  ‪ARRAY_ADD( level.ai[ self.team ], self );
190 
191  self waittill( "death" );
192 
193  if ( isdefined( self ) )
194  {
195  // Check if this AI still belongs to the current team, as its team might have been changed over time
196  if( IsDefined( level.ai ) && IsDefined( level.ai[ self.team ] ) && IsInArray( level.ai[ self.team ], self ) )
197  {
198  ArrayRemoveValue( level.ai[ self.team ], self );
199  }
200  else
201  {
202  // Find if this AI exists in the list of other AI's and remove him from there instead
203  foreach( aiArray in level.ai )
204  {
205  if( IsInArray( aiArray, self ) )
206  {
207  ArrayRemoveValue( aiArray, self );
208  break;
209  }
210  }
211  }
212  }
213  else
214  {
215  foreach ( team, ‪array in level.ai )
216  {
217  for ( i = ‪array.size - 1; i >= 0; i-- )
218  {
219  if ( !isdefined( ‪array[ i ] ) )
220  {
221  ArrayRemoveIndex( ‪array, i );
222  }
223  }
224  }
225  }
226 }
227 
229 {
230  while ( true )
231  {
234  level.global_spawn_count = 0;
235  }
236 }
237 
238 function ‪global_spawn_throttle( n_count_per_network_frame )
239 {
240  if ( !‪IS_TRUE( level.first_frame ) )
241  {
242  while ( level.global_spawn_count >= n_count_per_network_frame )
243  {
245  }
246 
247  level.global_spawn_count++;
248  }
249 }
250 
252 {
253  return;
254 }
255 
257 {
258  volumes = GetEntArray( "info_volume", "classname" );
259  level.deathchain_goalVolume = [];
260  level.goalVolumes = [];
261 
262  for ( i = 0; i < volumes.size; i++ )
263  {
264  volume = volumes[ i ];
265  if ( isdefined( volume.script_deathChain ) )
266  {
267  level.deathchain_goalVolume[ volume.script_deathChain ] = volume;
268  }
269  if ( isdefined( volume.script_goalvolume ) )
270  {
271  level.goalVolumes[ volume.script_goalVolume ] = volume;
272  }
273  }
274 }
275 
276 function ‪precache_player_weapon_drops( weapon_names )
277 {
278  level.ai_classname_in_level_keys = getarraykeys( level.ai_classname_in_level );
279  for ( i = 0 ; i < level.ai_classname_in_level_keys.size ; i++ )
280  {
281  if( weapon_names.size <= 0 )
282  {
283  break;
284  }
285 
286  for( j = 0 ; j < weapon_names.size ; j++ )
287  {
288  weaponName = weapon_names[j];
289 
290  if ( !issubstr( tolower( level.ai_classname_in_level_keys[ i ] ), weaponName ) )
291  {
292  continue;
293  }
294 
295  ArrayRemoveValue( weapon_names, weaponName );
296  break;
297  }
298  }
299  level.ai_classname_in_level_keys = undefined;
300 }
301 
303 {
304  keys = getarraykeys( level.deathflags );
305  level.deathflags = [];
306  for ( i=0; i < keys.size; i++ )
307  {
308  deathflag = keys[ i ];
309  level.deathflags[ deathflag ] = [];
310  level.deathflags[ deathflag ][ "ai" ] = [];
311 
312  if ( !isdefined( level.flag[ deathflag ] ) )
313  {
314  level ‪flag::init( deathflag );
315  }
316  }
317 
318 }
319 
321 {
322  self endon( "death" );
323  self waittill( "count_gone" );
324 }
325 
326 function ‪flood_spawner_scripted( spawners )
327 {
328  assert( isdefined( spawners ) && spawners.size, "Script tried to flood spawn without any spawners" );
329 
330  array::thread_all( spawners,&‪flood_spawner_init );
331  array::thread_all( spawners,&‪flood_spawner_think );
332 }
333 
335 {
336  spawner endon( "death" );
337 
338  self waittill( "death" );
339  if( !isdefined( self ) )
340  {
341  spawner.count++;
342  }
343 }
344 
345 function ‪kill_trigger( trigger )
346 {
347  if( !isdefined( trigger ) )
348  {
349  return;
350  }
351 
352  if( ( isdefined( trigger.targetname ) ) &&( trigger.targetname != "flood_spawner" ) )
353  {
354  return;
355  }
356 
357  trigger Delete();
358 }
359 
361 {
362  self endon( "death" );
363  self waittill( "pain_death" ); // pain that ends in death
364 }
365 
366 function ‪drop_gear()
367 {
368  team = self.team;
370 
371  if( !isdefined( self ) )
372  {
373  return;
374  }
375 
376  if( self.grenadeAmmo <= 0 )
377  {
378  return;
379  }
380 
381  if( isdefined( self.dropweapon ) && !self.dropweapon )
382  {
383  return;
384  }
385 
386  if (!IsDefined( level.nextGrenadeDrop ))
387  {
388  level.nextGrenadeDrop = RandomInt(3);
389  }
390 
391  level.nextGrenadeDrop--;
392  if( level.nextGrenadeDrop > 0 )
393  {
394  return;
395  }
396 
397  level.nextGrenadeDrop = 2 + RandomInt( 2 );
398  const max = 25;
399  const min = 12;
400  ‪spawn_grenade_bag( self.origin +( RandomInt( max )-min, RandomInt( max )-min, 2 ) +( 0, 0, 42 ), ( 0, RandomInt( 360 ), 0 ), self.team );
401 
402 }
403 
404 /* DEAD CODE REMOVAL
405 function random_tire( start, end )
406 {
407  model = util::spawn( "script_model", (0,0,0) );
408  model.angles = ( 0, randomint( 360 ), 0 );
409 
410  dif = randomfloat( 1 );
411  model.origin = start * dif + end * ( 1 - dif );
412  model setmodel( "com_junktire" );
413  vel = math::random_vector( 15000 );
414  vel = ( vel[ 0 ], vel[ 1 ], abs( vel[ 2 ] ) );
415  model physicslaunch( model.origin, vel );
416 
417  wait ( randomintrange ( 8, 12 ) );
418  model delete();
419 }
420 */
421 
422 function ‪spawn_grenade_bag( origin, angles, team )
423 {
424  // delete oldest grenade
425  if( !isdefined( level.grenade_cache ) || !isdefined( level.grenade_cache[team] ) )
426  {
427  level.grenade_cache_index[team] = 0;
428  level.grenade_cache[team] = [];
429  }
430 
431  index = level.grenade_cache_index[team];
432  grenade = level.grenade_cache[team][index];
433  if( isdefined( grenade ) )
434  {
435  grenade Delete();
436  }
437 
438  count = self.grenadeammo;
439  grenade = ‪sys::Spawn( "weapon_" + self.grenadeWeapon.name + level.game_mode_suffix, origin );
440  level.grenade_cache[team][index] = grenade;
441  level.grenade_cache_index[team] = ( index + 1 ) % 16;
442 
443  grenade.angles = angles;
444  grenade.count = count;
445 
446  //grenade SetModel( "grenade_bag" );
447 }
448 
450 {
451  assert( self != level );
452 
453  level.ai_classname_in_level[ self.classname ] = true;
454 
455  /#
456  if (GetDvarString ("noai") != "off")
457  {
458  // NO AI in the level plz
459  self.count = 0;
460  return;
461  }
462  #/
463 
464  // Populate the list of Axis and Ally drone spawners
465 // self _drones::drone_add_spawner(); _drones.gsc has been removed
466 
467  if( isdefined( self.script_aigroup ) )
468  {
469  ‪aigroup_init( self.script_aigroup, self );
470  }
471 
472  if( isdefined( self.script_delete ) )
473  {
474  array_size = 0;
475  if( isdefined( level._ai_delete ) )
476  {
477  if( isdefined( level._ai_delete[self.script_delete] ) )
478  {
479  array_size = level._ai_delete[self.script_delete].size;
480  }
481  }
482 
483  level._ai_delete[self.script_delete][array_size] = self;
484  }
485 
486  if ( isdefined( self.target ) )
487  {
489  }
490 }
491 
493 {
494  level notify( "update_nav_triggers" );
495 
496  while ( IsAlive( self ) )
497  {
498  self ‪util::waittill_either( "death", "goal_changed" );
499  level notify( "update_nav_triggers" );
500  }
501 }
502 
503 // called from _callbacksetup when actor is spawned.
504 function ‪spawn_think( spawner )
505 {
506  self endon( "death" );
507 
508  // do not run the spawn_think again when we already have. This will prevent this thread from
509  // running again on a restart from checkpoint.
510  if ( IsDefined( self.spawn_think_thread_active ) )
511  return;
512 
513  self.spawn_think_thread_active = true;
514 
515  self.spawner = spawner;
516 
517  assert( IsActor( self ) || IsVehicle( self ), __FUNCTION__ + " only supports actors and vehicles." );
518 
519  if ( !IsVehicle( self ) )
520  {
521  if ( !IsAlive( self ) )
522  {
523  return;
524  }
525 
526  self.maxhealth = self.health; // HACK: temp until code sets it
527 
528  self thread ‪update_nav_triggers_for_actor();
529  }
530 
531  self.script_animname = undefined;
532 
533  if ( isdefined( self.script_aigroup ) )
534  {
535  level ‪flag::set( self.script_aigroup + "_spawning" );
536  self thread ‪aigroup_think( level._ai_group[ self.script_aigroup ] );
537  }
538 
539  if ( isdefined( spawner ) && isdefined( spawner.script_dropAmmo ) )
540  {
541  self.disableAmmoDrop = !spawner.script_dropAmmo;
542  }
543 
544  if ( isdefined( spawner ) && isdefined( spawner.spawn_funcs ) )
545  {
546  self.spawn_funcs = spawner.spawn_funcs;
547  }
548 
549  if ( IsAI( self ) )
550  {
551  ‪spawn_think_action( spawner );
552 
553  assert( IsAlive( self ) );
554  assert( isdefined( self.team ) );
555  }
556 
557  self thread ‪run_spawn_functions();
558 
559  self.finished_spawning = true;
560  self notify( "finished spawning" );
561 }
562 
564 {
565  self endon( "death" );
566 
567  if ( !isdefined( level.spawn_funcs ) )
568  {
569  return;
570  }
571 
572  if ( isdefined( self.archetype ) && isdefined( level.spawn_funcs[ self.archetype ] ) )
573  {
574  for (i = 0; i < level.spawn_funcs[ self.archetype ].size; i++)
575  {
576  func = level.spawn_funcs[ self.archetype ][ i ];
577  ‪util::single_thread(self, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ], func[ "param5" ] );
578  }
579  }
580 
581  waittillframeend; // spawn functions should override default settings, so they need to be last
582 
583  ‪callback::callback( #"on_ai_spawned" );
584 
585  if ( IsDefined( level.spawn_funcs[ self.team ] ) )
586  {
587  for (i = 0; i < level.spawn_funcs[ self.team ].size; i++)
588  {
589  func = level.spawn_funcs[ self.team ][ i ];
590  ‪util::single_thread(self, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ], func[ "param5" ] );
591  }
592  }
593 
594  if ( isdefined( self.spawn_funcs ) )
595  {
596  for ( i = 0; i < self.spawn_funcs.size; i++ )
597  {
598  func = self.spawn_funcs[ i ];
599  ‪util::single_thread( self, func[ "function" ], func[ "param1" ], func[ "param2" ], func[ "param3" ], func[ "param4" ], func[ "param5" ] );
600  }
601 
602  /#
603  // keep spawn funcs around in debug
604  return;
605  #/
606 
607  self.spawn_funcs = undefined;
608  }
609 }
610 
612 {
613  if ( isdefined( self.script_deathflag ) )
614  {
615  // later this is turned into the real ddeathflag array
616  level.deathflags[ self.script_deathflag ] = true;
617  }
618 
619  if ( isdefined( self.target ) )
620  {
622  }
623 }
624 
626 {
627  // need to initialize flags on the path chain if need be
629  if ( isdefined( ‪array ) )
630  {
631  targets = ‪array[ "node" ];
632  get_func = ‪array[ "get_target_func" ];
633  for ( i = 0; i < targets.size; i++ )
634  {
635  ‪crawl_target_and_init_flags( targets[ i ], get_func );
636  }
637  }
638 }
639 
641 {
642  /* remove all unnessesary data tranfered from the spawner */
643  self.spawner_number = undefined;
644 }
645 
646 // Actually do the spawn_think
647 function ‪spawn_think_action( spawner )
648 {
650 
651  if ( ‪IS_TRUE( level._use_faceanim ) )
652  {
654  }
655 
656  /* set targetname to the spawner's targetname + "_ai" if a targetname isn't already set */
657 
658  if ( isdefined( spawner ) )
659  {
660  if ( isdefined( spawner.targetname ) && !isdefined( self.targetname ) )
661  {
662  self.targetname = spawner.targetname + "_ai";
663  }
664  }
665 
666  if ( isdefined( spawner ) && isdefined( spawner.script_animname ) )
667  {
668  self.animname = spawner.script_animname;
669  }
670  else if ( isdefined( self.script_animname ) )
671  {
672  self.animname = self.script_animname;
673  }
674 
675  // handle default ai flags for ent_flag * functions
676 // self thread util::ent_flag_init_ai_standards();
677 
678  /#
679  thread ‪show_bad_path();
680  #/
681 
682  if ( isdefined( self.script_forceColor ) )
683  {
684  // send all forcecolor through a centralized function
685  ‪colors::set_force_color( self.script_forceColor );
686 
687  // All AI spawned will do "replace_on_death" unless told not to.
688  if ( ( !isdefined( self.script_no_respawn ) || self.script_no_respawn < 1 ) && !isdefined( level.no_color_respawners_sm ) )
689  {
690  self thread ‪replace_on_death();
691  }
692  }
693 
694  if ( ( isdefined( self.script_moveoverride ) ) &&( self.script_moveoverride == 1 ) )
695  {
696  override = true;
697  }
698  else
699  {
700  override = false;
701  }
702 
703  //SCRIPT_MOD: GLOCKE: built this into the actor damage callback
704  //if( self watches_for_friendly_fire() )
705  //{
706  // level thread _friendlyfire::friendly_fire_think( self );
707  //}
708 
709  // create threatbiasgroups
710  //TODO T7 - function port
711  /*if( isdefined( self.script_threatbiasgroup ) )
712  {
713  self SetThreatBiasGroup( self.script_threatbiasgroup );
714  }
715  else if( self.team == "allies" )
716  {
717  self SetThreatBiasGroup( "allies" );
718  }
719  else
720  {
721  self SetThreatBiasGroup( "axis" );
722  }*/
723 
724  self.heavy_machine_gunner = IsSubStr( self.classname, "mgportable" );
725 
727 
728  if( isdefined( self.script_ignoreme ) )
729  {
730  assert( self.script_ignoreme == true, "Tried to set self.script_ignoreme to false, not allowed. Just set it to undefined." );
731  self.ignoreme = true;
732  }
733 
734 // if ( isdefined( self.script_ignore_suppression ) )
735 // {
736 // assert( self.script_ignore_suppression == true, "Tried to set self.script_ignore_suppresion to false, not allowed. Just set it to undefined." );
737 // self.ignoreSuppression = true;
738 // }
739 
740  if( isdefined( self.script_hero ) )
741  {
742  assert( self.script_hero == 1, "Tried to set script_hero to something other than 1" );
743  //TODO T7 - port if needed
744  //self util::make_hero();
745  }
746 
747  if ( isdefined( self.script_ignoreall ) )
748  {
749  assert( self.script_ignoreall == true, "Tried to set self.script_ignoreme to false, not allowed. Just set it to undefined." );
750  self.ignoreall = true;
751  //self init::clearEnemy();
752  }
753 
754 // // disable reaction feature if needed
755 // if( isdefined( self.script_disablereact ) )
756 // {
757 // self util::disable_react();
758 // }
759 //
760 // // disable pain if needed
761 // if( isdefined( self.script_disablepain ) )
762 // {
763 // self util::disable_pain();
764 // }
765 //
766 // // disable pain if needed
767 // if( isdefined( self.script_disableturns ) )
768 // {
769 // self.disableTurns = true;
770 // }
771 
772  if ( isdefined( self.script_sightrange ) )
773  {
774  self.maxSightDistSqrd = self.script_sightrange;
775  }
776  else if ( ‪IS_EQUAL( self.weaponclass,"gas" ) )
777  {
778  self.maxSightDistSqrd = 1024 * 1024;
779  }
780 
781  if ( self.team != "axis" )
782  {
783  // Set the followmin for friendlies
784  if ( isdefined( self.script_followmin ) )
785  {
786  self.followmin = self.script_followmin;
787  }
788 
789  // Set the followmax for friendlies
790  if ( isdefined( self.script_followmax ) )
791  {
792  self.followmax = self.script_followmax;
793  }
794  }
795 
796  if ( self.team == "axis" )
797  {
798  if ( IsDefined( self.type ) && self.type == "human" )
799  {
800  //self thread drop_gear();
801  //self thread drophealth();
802  }
803  }
804 
805  if ( isdefined( self.script_fightdist ) )
806  {
807  self.pathenemyfightdist = self.script_fightdist;
808  }
809 
810  if ( isdefined( self.script_maxdist ) )
811  {
812  self.pathenemylookahead = self.script_maxdist;
813  }
814 
815  // disable long death like dying pistol behavior
816  if ( isdefined( self.script_longdeath ) )
817  {
818  assert( !self.script_longdeath, "Long death is enabled by default so don't set script_longdeath to true, check ai with export " + self.export );
819  self.a.disableLongDeath = true;
820  assert( self.team != "allies", "Allies can't do long death, so why disable it on guy with export " + self.export );
821  }
822 
823  // Gives AI grenades (defaults for each cod5 aitype are specified in aitypes_charactersettings.gdt)
824  if ( isdefined( self.script_grenades ) )
825  {
826  self.grenadeAmmo = self.script_grenades;
827  }
828 
829  // Puts AI in pacifist mode
830  if ( isdefined( self.script_pacifist ) )
831  {
832  self.pacifist = true;
833  }
834 
835  // Set the health for special cases
836  if ( isdefined( self.script_startinghealth ) )
837  {
838  self.health = self.script_startinghealth;
839  }
840 
841  // GLocke [8/30] allow the AI to be killed during animations (like traversals)
842  if ( isdefined( self.script_allowdeath ) )
843  {
844  self.allowdeath = self.script_allowdeath;
845  }
846 
847  // Force gib support on KVP
848  if ( isdefined( self.script_forcegib ) )
849  {
850  self.force_gib = 1;
851 
852  // use the string as gib ref
853 
854  //TODO T7 - MPAI_PETER_TODO
855  /*if( as_death::isValidGibRef( self.script_forcegib ) )
856  {
857  self.custom_gib_refs[0] = self.script_forcegib;
858  }*/
859  }
860 
861  if ( isdefined( self.script_lights_on ) ) // re-purposing this key for AI, usually used on vehicles
862  {
863  self.has_ir = true;
864  }
865 
866  // starth stealth if needed
867  if ( isdefined( self.script_stealth ) )
868  {
869 // self thread _stealth_logic::stealth_ai(); TODO: _stealth_logic.gsc has been removed
870  }
871 
872  // The AI will spawn and follow a patrol
873  if ( isdefined( self.script_patroller ) )
874  {
875 // self thread _patrol::patrol(); _patrol.gsc has been removed
876  return;
877  }
878 
879  if ( ‪IS_TRUE( self.script_rusher ) )
880  {
881 // self rusher::rush(); _rusher.gsc has been removed
882  return;
883  }
884 //
885 // if( isdefined( self.script_enable_cqb ) )
886 // {
887 // self util::change_movemode("cqb");
888 // }
889 //
890 // if( isdefined( self.script_enable_heat ) )
891 // {
892 // self util::enable_heat();
893 // }
894 
895  // Setup playerseek
896 // if( isdefined( self.script_playerseek ) )
897 // {
898 // if( self.script_playerseek == 1 )
899 // {
900 // self thread util::player_seek(); // direct player seek
901 // return;
902 // }
903 // else
904 // {
905 // self thread util::player_seek( self.script_playerseek ); // delayed player seek
906 // }
907 // }
908 
909  if ( isdefined( self.used_an_mg42 ) ) // This AI was called upon to use an MG42 so he's not going to run to his node.
910  {
911  return;
912  }
913 
914  if ( override )
915  {
917  self SetGoal( self.origin );
918  return;
919  }
920 
921  // SUMEET TODO - Following script will run as a thread and can override the awareness goals.
922  // Disabling it for now. We will investigate further.
923  if ( ‪IS_TRUE( level.using_awareness ) )
924  {
925  return;
926  }
927 
928  if ( ‪IS_ARTILLERY( self ) )//we don't want to check this for turrets
929  {
930  return;
931  }
932 
933  if ( isdefined( self.target ) )
934  {
935  e_goal = GetEnt( self.target, "targetname" );
936  if ( isdefined( e_goal ) )
937  {
938  self SetGoal( e_goal );
939  }
940  else
941  {
942  self thread ‪go_to_node();
943  }
944  }
945  else
946  {
948 
949  if ( isdefined( self.script_spawner_targets ) )
950  {
951  // New way of sending guys to nodes using "script_spawner_targets" key on the spawner
952  self thread ‪go_to_spawner_target( StrTok( self.script_spawner_targets," " ) );
953  }
954  }
955 
956  // set the goal volume after the goal position has been set
957  if ( isdefined( self.script_goalvolume ) )
958  {
959  self thread ‪set_goal_volume();
960  }
961 
962  // override for the default turnrate (ai_turnrate dvar). Degrees per second (360 = one complete turn)
963  if ( isdefined( self.script_turnrate ) )
964  {
965  self.turnrate = self.script_turnrate;
966  }
967  //TODO T7 - port/update if needed
968  //self dds::dds_ai_init();
969 }
970 
972 {
973  self endon( "death" );
974 
975  // wait until frame end so that the AI's goal has a chance to get set
976  waittillframeend;
977 
978  volume = level.goalVolumes[ self.script_goalvolume ];
979  if ( !isdefined( volume ) )
980  return;
981 
982  if ( isdefined( volume.target ) )
983  {
984  node = GetNode( volume.target, "targetname" );
985  ent = GetEnt( volume.target, "targetname" );
986  struct = ‪struct::get( volume.target, "targetname" );
987  pos = undefined;
988 
989  if ( isdefined( node ) )
990  {
991  pos = node;
992  self SetGoal( pos );
993  }
994  else if ( isdefined( ent ) )
995  {
996  pos = ent;
997  self SetGoal( pos.origin );
998  }
999  else if ( isdefined( struct ) )
1000  {
1001  pos = struct;
1002  self SetGoal( pos.origin );
1003  }
1004 
1005  if ( isdefined( pos.radius ) && pos.radius != 0 )
1006  {
1007  self.goalradius = pos.radius;
1008  }
1009 
1010  if ( isdefined( pos.goalheight ) && pos.goalheight != 0 )
1011  {
1012  self.goalheight = pos.goalheight;
1013  }
1014  }
1015 
1016  if ( isdefined( self.target ) )
1017  {
1018  self SetGoal( volume );
1019  }
1020  else if ( isdefined( self.script_spawner_targets ) )
1021  {
1022  self waittill( "spawner_target_set" );
1023  self SetGoal( volume );
1024  }
1025  else
1026  {
1027  self SetGoal( volume );
1028  }
1029 }
1030 
1031 function ‪get_target_ents( target )
1032 {
1033  return GetEntArray( target, "targetname" );
1034 }
1035 
1036 function ‪get_target_nodes( target )
1037 {
1038  return getnodearray( target, "targetname" );
1039 }
1040 
1041 function ‪get_target_structs( target )
1042 {
1043  return ‪struct::get_array( target, "targetname" );
1044 }
1045 
1046 function ‪node_has_radius( node )
1047 {
1048  return isdefined( node.radius ) && node.radius != 0;
1049 }
1050 
1051 function ‪go_to_origin( node, optional_arrived_at_node_func )
1052 {
1053  self ‪go_to_node( node, "origin", optional_arrived_at_node_func );
1054 }
1055 
1056 function ‪go_to_struct( node, optional_arrived_at_node_func )
1057 {
1058  self ‪go_to_node( node, "struct", optional_arrived_at_node_func );
1059 }
1060 
1061 function ‪go_to_node( node, goal_type, optional_arrived_at_node_func )
1062 {
1063  self endon("death");
1064 
1065  if ( isdefined( self.used_an_mg42 ) )// This AI was called upon to use an MG42 so he's not going to run to his node.
1066  {
1067  return;
1068  }
1069 
1070  ‪array = ‪get_node_funcs_based_on_target( node, goal_type );
1071  if ( !isdefined( ‪array ) )
1072  {
1073  self notify( "reached_path_end" );
1074  // no goal type
1075  return;
1076  }
1077 
1078  if ( !isdefined( optional_arrived_at_node_func ) )
1079  {
1080  optional_arrived_at_node_func = &‪util::empty;
1081  }
1082 
1083  ‪go_to_node_using_funcs( ‪array[ "node" ], ‪array[ "get_target_func" ], ‪array[ "set_goal_func_quits" ], optional_arrived_at_node_func );
1084 }
1085 
1088 // //
1089 // This was new functionality for Spawn Manager. Now works for //
1090 // any spawner regardless of how it is spawned. Sends AI to a //
1091 // random node that is in the same 'script_spawner_targets' group. //
1093 
1094 //-- Makes a global array of nodes that is then processed by the spawner targets system
1096 {
1097  allnodes = GetAllNodes();
1098  level.script_spawner_targets_nodes = [];
1099  for( i = 0; i < allnodes.size; i++)
1100  {
1101  if(isdefined(allnodes[i].script_spawner_targets))
1102  {
1103  level.script_spawner_targets_nodes[level.script_spawner_targets_nodes.size] = allnodes[i];
1104  }
1105  }
1106 }
1107 
1108 function ‪go_to_spawner_target(target_names)
1109 {
1110  self endon( "death" );
1111 
1112  self notify( "go_to_spawner_target" );
1113  self endon( "go_to_spawner_target" );
1114 
1115  nodes = [];
1116  a_nodes_unavailable = [];
1117  nodesPresent = false;
1118 
1119  for ( i = 0; i < target_names.size; i++ )
1120  {
1121  target_nodes = ‪get_spawner_target_nodes( target_names[i] );
1122  if ( target_nodes.size > 0 )
1123  {
1124  nodesPresent = true;
1125  }
1126 
1127  foreach ( node in target_nodes )
1128  {
1129  if ( IsNodeOccupied( node ) || ‪IS_TRUE( node.node_claimed ) )
1130  {
1131  ‪ARRAY_ADD( a_nodes_unavailable, node );
1132  }
1133  else if ( ‪SPAWNFLAG( node, ‪SPAWNFLAG_PATH_DISABLED ) )
1134  {
1135  ‪ARRAY_ADD( a_nodes_unavailable, node );
1136  }
1137  else
1138  {
1139  ‪ARRAY_ADD( nodes, node );
1140  }
1141  }
1142  }
1143 
1144  // if not a single node is unoccupied then wait until one is.
1145  if ( nodes.size == 0 )
1146  {
1147  while ( nodes.size == 0 )
1148  {
1149  foreach ( node in a_nodes_unavailable )
1150  {
1151  if ( !IsNodeOccupied( node )
1152  && !‪IS_TRUE( node.node_claimed )
1154  {
1155  ‪ARRAY_ADD( nodes, node );
1156  break;
1157  }
1158  }
1159 
1160  wait .2;
1161  }
1162  }
1163 
1164  Assert( nodesPresent, "No spawner target nodes for AI." );
1165 
1166  goal = undefined;
1167  if ( nodes.size > 0 )
1168  {
1169  goal = array::random( nodes );
1170  }
1171 
1172  if ( isdefined( goal ) )
1173  {
1174  // If script has set the goalradius then use it to go to the spawner target
1175  if ( isdefined( self.script_radius ) )
1176  {
1177  self.goalradius = self.script_radius;
1178  }
1179  else
1180  {
1181  self.goalradius = 400; // TODO: this is temp
1182  }
1183 
1184  goal.node_claimed = true;
1185  self SetGoal( goal );
1186 
1187  self notify( "spawner_target_set" );
1188 
1189  self thread ‪release_spawner_target_node( goal );
1190 
1191  self waittill( "goal" );
1192  }
1193 
1195 }
1196 
1198 {
1199  self ‪util::waittill_any( "death", "goal_changed" );
1200  node.node_claimed = undefined;
1201 }
1202 
1203 // GLocke: 5/26/10 - changed this to use a global level array instead of recreating
1204 // the node array everytime an AI is told to go_to_spawner_target
1206 {
1207  if ( group == "" )
1208  {
1209  return [];
1210  }
1211 
1212  nodes = [];
1213  for ( i = 0; i < level.script_spawner_targets_nodes.size; i++)
1214  {
1215  groups = strtok( level.script_spawner_targets_nodes[i].script_spawner_targets, " ");
1216 
1217  for ( j = 0; j < groups.size; j++)
1218  {
1219  if ( groups[j] == group )
1220  {
1221  nodes[nodes.size] = level.script_spawner_targets_nodes[i];
1222  }
1223  }
1224  }
1225 
1226  return nodes;
1227 }
1228 
1232 
1234 {
1235  assert( ‪array.size > 0, "Somehow array had zero entrees" );
1236  if ( ‪array.size == 1 )
1237  {
1238  return ‪array[ 0 ];
1239  }
1240 
1241  targetname = ‪array[ 0 ].targetname;
1242  if ( !isdefined( level.go_to_node_arrays[ targetname ] ) )
1243  {
1244  level.go_to_node_arrays[ targetname ] = ‪array;
1245  }
1246 
1247  ‪array = level.go_to_node_arrays[ targetname ];
1248 
1249  // return the node at the front of the array and move it to the back of the array.
1250  first = ‪array[ 0 ];
1251  newarray = [];
1252  for ( i = 0; i < ‪array.size - 1; i++ )
1253  {
1254  newarray[ i ] = ‪array[ i + 1 ];
1255  }
1256  newarray[ ‪array.size - 1 ] = ‪array[ 0 ];
1257  level.go_to_node_arrays[ targetname ] = newarray;
1258 
1259  return first;
1260 }
1261 
1262 
1263 function ‪go_to_node_using_funcs( node, get_target_func, set_goal_func_quits, optional_arrived_at_node_func, require_player_dist )
1264 {
1265  // AI is moving to a goal node
1266  self endon( "stop_going_to_node" );
1267  self endon( "death" );
1268 
1269  for ( ;; )
1270  {
1271  // node should always be an array at this point, so lets get just 1 out of the array
1272  node = ‪get_least_used_from_array( node );
1273 
1274  player_wait_dist = require_player_dist;
1275  if( isdefined( node.script_requires_player ) )
1276  {
1277  if( node.script_requires_player > 1 )
1278  player_wait_dist = node.script_requires_player;
1279  else
1280  player_wait_dist = 256;
1281 
1282  node.script_requires_player = false;
1283  }
1284 
1286 
1287  if ( isdefined( node.height ) )
1288  {
1289  self.goalheight = node.height;
1290  }
1291 
1292  [[ set_goal_func_quits ]]( node );
1293  self waittill( "goal" );
1294 
1295  [[ optional_arrived_at_node_func ]]( node );
1296 
1297  if ( isdefined( node.script_flag_set ) )
1298  {
1299  level ‪flag::set( node.script_flag_set );
1300  }
1301 
1302  if ( isdefined( node.script_flag_clear ) )
1303  {
1304  level ‪flag::set( node.script_flag_clear );
1305  }
1306 
1307  if ( isdefined( node.script_ent_flag_set ) )
1308  {
1309  if( !self ‪flag::exists( node.script_ent_flag_set ) )
1310  AssertMsg( "Tried to set a ent flag "+ node.script_ent_flag_set +" on a node, but it doesnt exist." );
1311 
1312  self ‪flag::set( node.script_ent_flag_set );
1313  }
1314 
1315  if ( isdefined( node.script_ent_flag_clear ) )
1316  {
1317  if( !self ‪flag::exists( node.script_ent_flag_clear ) )
1318  AssertMsg( "Tried to clear a ent flag "+ node.script_ent_flag_clear +" on a node, but it doesnt exist." );
1319 
1320  self ‪flag::clear( node.script_ent_flag_clear );
1321  }
1322 
1323  if ( isdefined( node.script_flag_wait ) )
1324  {
1325  level ‪flag::wait_till( node.script_flag_wait );
1326  }
1327 
1328  while ( isdefined( node.script_requires_player ) )
1329  {
1330  node.script_requires_player = false;
1331  if ( self ‪go_to_node_wait_for_player( node, get_target_func, player_wait_dist ) )
1332  {
1333  node.script_requires_player = true;
1334  node notify( "script_requires_player" );
1335  break;
1336  }
1337 
1338  wait 0.1;
1339  }
1340 
1341  if( isdefined( node.script_aigroup ) )
1342  {
1343  ‪waittill_ai_group_cleared( node.script_aigroup );
1344  }
1345 
1346  node ‪util::script_delay();
1347 
1348  if ( !isdefined( node.target ) )
1349  {
1350  break;
1351  }
1352 
1353  nextNode_array = ‪update_target_array( node.target );
1354  if ( !nextNode_array.size )
1355  {
1356  break;
1357  }
1358 
1359  node = nextNode_array;
1360  }
1361 
1362 
1363  if( isdefined( self.arrived_at_end_node_func ) )
1364  [[ self.arrived_at_end_node_func ]]( node );
1365 
1366  self notify( "reached_path_end" );
1367 
1368  if( isdefined( self.delete_on_path_end ) )
1369  self Delete();
1370 
1372 }
1373 
1374 
1375 function ‪go_to_node_wait_for_player( node, get_target_func, dist )
1376 {
1377  //are any of the players closer to the node than we are?
1378  players = GetPlayers();
1379 
1380  for( i=0; i< players.size; i++ )
1381  {
1382  player = players[i];
1383 
1384  if ( distancesquared( player.origin, node.origin ) < distancesquared( self.origin, node.origin ) )
1385  return true;
1386  }
1387 
1388  //are any of the player ahead of us based on our forward angle?
1389  vec = anglestoforward( self.angles );
1390  if ( isdefined( node.target ) )
1391  {
1392  temp = [[ get_target_func ]]( node.target );
1393 
1394  //if we only have one node then we can get the forward from that one to us
1395  if ( temp.size == 1 )
1396  vec = vectornormalize( temp[ 0 ].origin - node.origin );
1397  //otherwise since we dont know which one we're taking yet the next best thing to do is to take the forward of the node we're on
1398  else if ( isdefined( node.angles ) )
1399  vec = anglestoforward( node.angles );
1400  }
1401  //also if there is no target since we're at the end of the chain, the next best thing to do is to take the forward of the node we're on
1402  else if ( isdefined( node.angles ) )
1403  vec = anglestoforward( node.angles );
1404 
1405  vec2 = [];
1406 
1407  for( i=0; i< players.size; i++ )
1408  {
1409  player = players[i];
1410 
1411  vec2[ vec2.size ] = vectornormalize( ( player.origin - self.origin ) );
1412  }
1413 
1414  //i just created a vector which is in the direction i want to
1415  //go, lets see if the player is closer to our goal than we are
1416  for( i=0; i< vec2.size; i++ )
1417  {
1418  value = vec2[i];
1419 
1420  if ( vectordot( vec, value ) > 0 )
1421  return true;
1422  }
1423 
1424  //ok so that just checked if he was a mile away but more towards the target
1425  //than us...but we dont want him to be right on top of us before we start moving
1426  //so lets also do a distance check to see if he's close behind
1427  dist2rd = dist * dist;
1428  for( i=0; i< players.size; i++ )
1429  {
1430  player = players[i];
1431 
1432  if ( distancesquared( player.origin, self.origin ) < dist2rd )
1433  return true;
1434  }
1435 
1436  //ok guess he's not here yet
1437  return false;
1438 }
1439 
1440 
1442 {
1443  self SetGoal( ent.origin );
1444 }
1445 
1447 {
1448  self SetGoal( node );
1449 }
1450 
1451 function ‪remove_crawled( ent )
1452 {
1453  waittillframeend;
1454  if ( isdefined( ent ) )
1455  {
1456  ent.crawled = undefined;
1457  }
1458 }
1459 
1460 function ‪crawl_target_and_init_flags( ent, get_func )
1461 {
1462  targets = [];
1463  index = 0;
1464  for ( ;; )
1465  {
1466  if ( !isdefined( ent.crawled ) )
1467  {
1468  ent.crawled = true;
1469  level thread ‪remove_crawled( ent );
1470 
1471  if ( isdefined( ent.script_flag_set ) )
1472  {
1473  if ( !isdefined( level.flag[ ent.script_flag_set ] ) )
1474  {
1475  level ‪flag::init( ent.script_flag_set );
1476  }
1477  }
1478 
1479  if ( isdefined( ent.script_flag_wait ) )
1480  {
1481  if ( !isdefined( level.flag[ ent.script_flag_wait ] ) )
1482  {
1483  level ‪flag::init( ent.script_flag_wait );
1484  }
1485  }
1486 
1487  if ( isdefined( ent.target ) )
1488  {
1489  new_targets = [[ get_func ]]( ent.target );
1490  ‪array::add( targets, new_targets );
1491  }
1492  }
1493 
1494  index++ ;
1495  if ( index >= targets.size )
1496  {
1497  break;
1498  }
1499 
1500  ent = targets[ index ];
1501  }
1502 }
1503 
1504 function ‪get_node_funcs_based_on_target( node, goal_type )
1505 {
1506  // figure out if its a node or script origin and set the goal_type index based on that.
1507 
1508  // true is for script_origins, false is for nodes
1509  get_target_func[ "origin" ] =&‪get_target_ents;
1510  get_target_func[ "node" ] =&‪get_target_nodes;
1511  get_target_func[ "struct" ] =&‪get_target_structs;
1512 
1513  set_goal_func_quits[ "origin" ] =&‪go_to_node_set_goal_pos;
1514  set_goal_func_quits[ "struct" ] =&‪go_to_node_set_goal_pos;
1515  set_goal_func_quits[ "node" ] =&‪go_to_node_set_goal_node;
1516 
1517  // if you pass a node, we'll assume you actually passed a node. We can make it find out if its a script origin later if we need that functionality.
1518  if ( !isdefined( goal_type ) )
1519  {
1520  goal_type = "node";
1521  }
1522 
1523  ‪array = [];
1524  if ( isdefined( node ) )
1525  {
1526  ‪array[ "node" ][ 0 ] = node;
1527  }
1528  else
1529  {
1530  // if you dont pass a node then we need to figure out what type of target it is
1531  node = GetEntArray( self.target, "targetname" );
1532 
1533  if ( node.size > 0 )
1534  {
1535  goal_type = "origin";
1536  }
1537 
1538  if ( goal_type == "node" )
1539  {
1540  node = getnodearray( self.target, "targetname" );
1541  if ( !node.size )
1542  {
1543  node = ‪struct::get_array( self.target, "targetname" );
1544  if ( !node.size )
1545  {
1546  // Targetting neither
1547  return;
1548  }
1549  goal_type = "struct";
1550  }
1551  }
1552 
1553  ‪array[ "node" ] = node;
1554  }
1555 
1556  ‪array[ "get_target_func" ] = get_target_func[ goal_type ];
1557  ‪array[ "set_goal_func_quits" ] = set_goal_func_quits[ goal_type ];
1558  return ‪array;
1559 }
1560 
1561 //Check to see if target exists and return it
1562 function ‪update_target_array( str_target )
1563 {
1564  //Check if node
1565  a_nd_target = GetNodeArray( str_target, "targetname" );
1566  if( a_nd_target.size )
1567  {
1568  return a_nd_target;
1569  }
1570 
1571  //Check if struct
1572  a_s_target = ‪struct::get_array( str_target, "targetname" );
1573  if( a_s_target.size )
1574  {
1575  return a_s_target;
1576  }
1577 
1578  //Check if "origin"/volume/ent
1579  a_e_target = GetEntArray( str_target, "targetname" );
1580  if( a_e_target.size )
1581  {
1582  return a_e_target;
1583  }
1584 }
1585 
1586 
1588 {
1589  self endon( "death" );
1590  waittillframeend;
1591  if( isdefined( self.script_radius ) )
1592  {
1593  // use the override from radiant
1594  self.goalradius = self.script_radius;
1595  }
1596  else if ( isdefined( node ) && ‪node_has_radius( node ) )
1597  {
1598  self.goalradius = node.radius;
1599  }
1600 
1601  if( ‪IS_TRUE( self.script_forcegoal ) )
1602  {
1603  n_radius = ( self.script_forcegoal > 1 ? self.script_forcegoal : undefined );
1604  self thread ‪ai::force_goal( ‪get_goal( self.target ), n_radius );
1605  }
1606 }
1607 
1608 function ‪get_goal( str_goal, str_key = "targetname" )
1609 {
1610  a_goals = GetNodeArray( str_goal, str_key );
1611  if ( !a_goals.size )
1612  {
1613  a_goals = GetEntArray( str_goal, str_key );
1614  }
1615 
1616  return array::random( a_goals );
1617 }
1618 
1619 function ‪fallback_spawner_think( num, node_array, ignoreWhileFallingBack )
1620 {
1621  self endon( "death" );
1622 
1623  level.max_fallbackers[num]+= self.count;
1624  firstspawn = true;
1625  while( self.count > 0 )
1626  {
1627  self waittill( "spawned", ‪spawn );
1628  if( firstspawn )
1629  {
1630  /#
1631  if( GetDvarString( "fallback" ) == "1" )
1632  {
1633  println( "^a First spawned: ", num );
1634  }
1635  #/
1636  level notify( ( "fallback_firstspawn" + num ) );
1637  firstspawn = false;
1638  }
1639 
1640  ‪WAIT_SERVER_FRAME; // Wait until he does all his usual spawned logic so he will run to his node
1641  if( ‪spawn_failed( ‪spawn ) )
1642  {
1643  level notify( ( "fallbacker_died" + num ) );
1644  level.max_fallbackers[num]--;
1645  continue;
1646  }
1647 
1648  ‪spawn thread ‪fallback_ai_think( num, node_array, "is spawner", ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1649  }
1650 
1651  //level notify( ( "fallbacker_died" + num ) );
1652 }
1653 
1654 function ‪fallback_ai_think_death( ai, num )
1655 {
1656  ai waittill( "death" );
1657  level.current_fallbackers[num]--;
1658 
1659  level notify( ( "fallbacker_died" + num ) );
1660 }
1661 
1662 function ‪fallback_ai_think( num, node_array, spawner, ignoreWhileFallingBack )
1663 {
1664  if( ( !isdefined( self.fallback ) ) ||( !isdefined( self.fallback[num] ) ) )
1665  {
1666  self.fallback[num] = true;
1667  }
1668  else
1669  {
1670  return;
1671  }
1672 
1673  self.script_fallback = num;
1674  if( !isdefined( spawner ) )
1675  {
1676  level.current_fallbackers[num]++;
1677  }
1678 
1679  if( ( isdefined( node_array ) ) &&( level.fallback_initiated[num] ) )
1680  {
1681  self thread ‪fallback_ai( num, node_array, ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1682  }
1683 
1684  level thread ‪fallback_ai_think_death( self, num );
1685 }
1686 
1687 function ‪fallback_death( ai, num )
1688 {
1689  ai waittill( "death" );
1690 
1691  if (isdefined(ai.fallback_node))
1692  {
1693  ai.fallback_node.fallback_occupied = false;
1694  }
1695 
1696  level notify( ( "fallback_reached_goal" + num ) );
1697 // ai notify( "fallback_notify" );
1698 }
1699 
1700 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1701 function ‪fallback_goal( ignoreWhileFallingBack )
1702 {
1703  self waittill( "goal" );
1704  self.ignoresuppression = false;
1705 
1706  if( isdefined( ignoreWhileFallingBack ) && ignoreWhileFallingBack )
1707  {
1708  self.ignoreall = false;
1709  }
1710 
1711  self notify( "fallback_notify" );
1712  self notify( "stop_coverprint" );
1713 }
1714 
1716 {
1717  self notify( "stop_fallback_interrupt" );
1718  self endon( "stop_fallback_interrupt" );
1719 
1720  self endon( "stop_going_to_node" );
1721  self endon ("goto next fallback");
1722  self endon ("fallback_notify");
1723  self endon( "death" );
1724 
1725  while(1)
1726  {
1727  origin = self.origin;
1728  wait 2;
1729  if ( self.origin == origin )
1730  {
1731  self.ignoreall = false;
1732  return;
1733  }
1734  }
1735 }
1736 
1737 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1738 function ‪fallback_ai( num, node_array, ignoreWhileFallingBack )
1739 {
1740  self notify( "stop_going_to_node" );
1741  self endon( "stop_going_to_node" );
1742  self endon ("goto next fallback");
1743  self endon( "death" ); // SRS 5/21/2008: bugfix - this kept running after AIs were dead
1744 
1745  node = undefined;
1746  // set the goalnode
1747  while( 1 )
1748  {
1749  assert((node_array.size >= level.current_fallbackers[num]), "Number of fallbackers exceeds number of fallback nodes for fallback # " + num + ". Add more fallback nodes or reduce possible fallbackers.");
1750 
1751  node = node_array[RandomInt( node_array.size )];
1752  if (!isdefined(node.fallback_occupied) || !node.fallback_occupied)
1753  {
1754  // set the node occupied so we know to find another one
1755  node.fallback_occupied = true;
1756  self.fallback_node = node;
1757  break;
1758  }
1759 
1760  wait( 0.1 );
1761  }
1762  //TODO T7 - function port
1763  //self StopUseTurret();
1764 
1765  self.ignoresuppression = true;
1766 
1767  if( self.ignoreall == false && isdefined( ignoreWhileFallingBack ) && ignoreWhileFallingBack )
1768  {
1769  self.ignoreall = true;
1770  self thread ‪fallback_interrupt();
1771  }
1772 
1773  self SetGoal( node );
1774  if( node.radius != 0 )
1775  {
1776  self.goalradius = node.radius;
1777  }
1778 
1779  self endon( "death" );
1780  level thread ‪fallback_death( self, num );
1781  self thread ‪fallback_goal( ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1782 /#
1783  if( GetDvarString( "fallback" ) == "1" )
1784  {
1785  self thread ‪coverprint( node.origin );
1786  }
1787  #/
1788  self waittill( "fallback_notify" );
1789  level notify( ( "fallback_reached_goal" + num ) );
1790 }
1791 
1792 /#
1793 function ‪coverprint( org )
1794 {
1795  self endon( "fallback_notify" );
1796  self endon( "stop_coverprint" );
1797  self endon ("death");
1798  while( 1 )
1799  {
1800  line( self.origin +( 0, 0, 35 ), org, ( 0.2, 0.5, 0.8 ), 0.5 );
1801  print3d( ( self.origin +( 0, 0, 70 ) ), "Falling Back", ( 0.98, 0.4, 0.26 ), 0.85 );
1803  }
1804 }
1805 #/
1806 
1807 // This gets set up on each fallback trigger
1808 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1809 function ‪fallback_overmind( num, group, ignoreWhileFallingBack, percent )
1810 {
1811  fallback_nodes = undefined;
1812  nodes = GetAllNodes();
1813  for( i = 0; i < nodes.size; i++ )
1814  {
1815  if( ( isdefined( nodes[i].script_fallback ) ) &&( nodes[i].script_fallback == num ) )
1816  {
1817  ‪array::add( fallback_nodes, nodes[i] );
1818  }
1819  }
1820 
1821  if( isdefined( fallback_nodes ) )
1822  {
1823  level thread ‪fallback_overmind_internal( num, group, fallback_nodes, ignoreWhileFallingBack, percent ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1824  }
1825 }
1826 
1827 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1828 function ‪fallback_overmind_internal( num, group, fallback_nodes, ignoreWhileFallingBack, percent )
1829 {
1830  // SCRIPTER_MOD: JesseS (7/13/200): fixed up current vs max fallbackers, added a level max per
1831  // script_fallback
1832  level.current_fallbackers[num] = 0; // currently alive fallbackers
1833  level.max_fallbackers[num] = 0; // maximum fallbackers
1834  level.spawner_fallbackers[num] = 0; // number of fallback spawners
1835  level.fallback_initiated[num] = false; // has fallback started?
1836 
1837 
1838  spawners = GetSpawnerArray();
1839  for( i = 0; i < spawners.size; i++ )
1840  {
1841  if( ( isdefined( spawners[i].script_fallback ) ) &&( spawners[i].script_fallback == num ) )
1842  {
1843  if( spawners[i].count > 0 )
1844  {
1845  spawners[i] thread ‪fallback_spawner_think( num, fallback_nodes, ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1846  level.spawner_fallbackers[num]++;
1847  }
1848  }
1849  }
1850 
1851  assert( level.spawner_fallbackers[num] <= fallback_nodes.size, "There are more fallback spawners than fallback nodes. Add more node or remove spawners from script_fallback: "+ num );
1852 
1853  ai = GetAIArray();
1854  for( i = 0; i < ai.size; i++ )
1855  {
1856  if( ( isdefined( ai[i].script_fallback ) ) &&( ai[i].script_fallback == num ) )
1857  {
1858  ai[i] thread ‪fallback_ai_think( num, undefined, undefined, ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1859  }
1860  }
1861 
1862  if( ( !level.current_fallbackers[num] ) &&( !level.spawner_fallbackers[num] ) )
1863  {
1864  return;
1865  }
1866 
1867  spawners = undefined;
1868  ai = undefined;
1869 
1870  thread ‪fallback_wait( num, group, ignoreWhileFallingBack, percent ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1871  level waittill( ( "fallbacker_trigger" + num ) );
1872 
1873  ‪fallback_add_previous_group(num, fallback_nodes);
1874 
1875  /#
1876  if( GetDvarString( "fallback" ) == "1" )
1877  {
1878  println( "^a fallback trigger hit: ", num );
1879  }
1880  #/
1881 
1882  level.fallback_initiated[num] = true;
1883 
1884  ‪fallback_ai = undefined;
1885  ai = GetAIArray();
1886  for( i = 0; i < ai.size; i++ )
1887  {
1888  if( ( ( isdefined( ai[i].script_fallback ) ) &&( ai[i].script_fallback == num ) ) || ( ( isdefined( ai[i].script_fallback_group ) ) &&( isdefined( group ) ) &&( ai[i].script_fallback_group == group ) ) )
1889  {
1890  ‪array::add( ‪fallback_ai, ai[i] );
1891  }
1892  }
1893  ai = undefined;
1894 
1895  if( !isdefined( ‪fallback_ai ) )
1896  {
1897  return;
1898  }
1899 
1900  if( !isdefined( percent ) )
1901  {
1902  percent = 0.4;
1903  }
1904 
1905  first_half = ‪fallback_ai.size * percent;
1906  first_half = Int( first_half );
1907 
1908  level notify( "fallback initiated " + num );
1909 
1910  ‪fallback_text( ‪fallback_ai, 0, first_half );
1911 
1912  first_half_ai = [];
1913  for( i = 0; i < first_half; i++ )
1914  {
1915  ‪fallback_ai[i] thread ‪fallback_ai( num, fallback_nodes, ignoreWhileFallingBack );
1916  first_half_ai[i] = ‪fallback_ai[i];
1917  }
1918 
1919  // waits until everyone as at their goalnode
1920  for( i = 0; i < first_half; i++ )
1921  {
1922  level waittill( ( "fallback_reached_goal" + num ) );
1923  }
1924 
1925  ‪fallback_text( ‪fallback_ai, first_half, ‪fallback_ai.size );
1926 
1927  // SCRIPTER_MOD: JesseS (7/13/2007): added some stuff to check to make sure both halves get to go to nodes
1928  // turns out that someone else is getting other guys' nodes, so we gotta pick a new one
1929  for( i = 0; i < ‪fallback_ai.size; i++ )
1930  {
1931  if( IsAlive( ‪fallback_ai[i] ) )
1932  {
1933  set_fallback = true;
1934  for (p = 0; p < first_half_ai.size; p++)
1935  {
1936  if ( isalive(first_half_ai[p]))
1937  {
1938  if (‪fallback_ai[i] == first_half_ai[p])
1939  {
1940  set_fallback = false;
1941  }
1942  }
1943  }
1944 
1945  if (set_fallback)
1946  {
1947  ‪fallback_ai[i] thread ‪fallback_ai( num, fallback_nodes, ignoreWhileFallingBack );
1948  }
1949  }
1950  }
1951 }
1952 
1953 function ‪fallback_text( fallbackers, start, ‪end )
1954 {
1955 
1956 
1957  if( GetTime() <= level._nextcoverprint )
1958  {
1959  return;
1960  }
1961 
1962  for( i = start; i < ‪end; i++ )
1963  {
1964  if( !IsAlive( fallbackers[i] ) )
1965  {
1966  continue;
1967  }
1968 
1969  level._nextcoverprint = GetTime() + 2500 + RandomInt( 2000 );
1970 
1971  return;
1972  }
1973 }
1974 
1975 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
1976 function ‪fallback_wait( num, group, ignoreWhileFallingBack, percent )
1977 {
1978  level endon( ( "fallbacker_trigger" + num ) );
1979  /#
1980  if( GetDvarString( "fallback" ) == "1" )
1981  {
1982  println( "^a Fallback wait: ", num );
1983  }
1984  #/
1985  for( i = 0; i < level.spawner_fallbackers[num]; i++ )
1986  {
1987  /#
1988  if( GetDvarString( "fallback" ) == "1" )
1989  {
1990  println( "^a Waiting for spawners to be hit: ", num, " i: ", i );
1991  }
1992  #/
1993  level waittill( ( "fallback_firstspawn" + num ) );
1994  }
1995  /#
1996  if( GetDvarString( "fallback" ) == "1" )
1997  {
1998  println( "^a Waiting for AI to die, fall backers for group ", num, " is ", level.current_fallbackers[num] );
1999  }
2000  #/
2001 
2002  ai = GetAIArray();
2003  for( i = 0; i < ai.size; i++ )
2004  {
2005  if( ( ( isdefined( ai[i].script_fallback ) ) &&( ai[i].script_fallback == num ) ) || ( ( isdefined( ai[i].script_fallback_group ) ) &&( isdefined( group ) ) &&( ai[i].script_fallback_group == group ) ) )
2006  {
2007  ai[i] thread ‪fallback_ai_think( num, undefined, undefined, ignoreWhileFallingBack ); // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
2008  }
2009  }
2010  ai = undefined;
2011 
2012  deadfallbackers = 0;
2013 
2014  while( deadfallbackers < level.max_fallbackers[num] * percent )
2015  {
2016  /#
2017  if( GetDvarString( "fallback" ) == "1" )
2018  {
2019  println( "^cwaiting for " + deadfallbackers + " to be more than " +( level.max_fallbackers[num] * 0.5 ) );
2020  }
2021  #/
2022  level waittill( ( "fallbacker_died" + num ) );
2023  deadfallbackers++;
2024  }
2025 
2026  /#println( deadfallbackers , " fallbackers have died, time to retreat" );#/
2027  level notify( ( "fallbacker_trigger" + num ) );
2028 }
2029 
2030 // for fallback trigger
2031 // SRS 5/3/2008: updated to allow AIs to ignoreall while falling back
2032 // Note: multiple triggers will need to have script_ignoreall set identically on all triggers
2033 // for consistency when AIs decide to ignore while falling back or not.
2034 function ‪fallback_think( trigger )
2035 {
2036  ignoreWhileFallingBack = false;
2037  if( isdefined( trigger.script_ignoreall ) && trigger.script_ignoreall )
2038  {
2039  ignoreWhileFallingBack = true;
2040  }
2041 
2042  if( ( !isdefined( level.fallback ) ) ||( !isdefined( level.fallback[trigger.script_fallback] ) ) )
2043  {
2044  // MikeD (5/7/2008): Added the ability to determine the percent of guys that will fallback
2045  // when this trigger is hit.
2046  percent = 0.5;
2047  if( isdefined( trigger.script_percent ) )
2048  {
2049  percent = trigger.script_percent / 100;
2050  }
2051 
2052  level thread ‪fallback_overmind( trigger.script_fallback, trigger.script_fallback_group, ignoreWhileFallingBack, percent );
2053  }
2054 
2055  trigger waittill( "trigger" );
2056 
2057  level notify( ( "fallbacker_trigger" + trigger.script_fallback ) );
2058 // level notify( ( "fallback" + trigger.script_fallback ) );
2059 
2060  // Maybe throw in a thing to kill triggers with the same fallback? God my hands are cold.
2061  ‪kill_trigger( trigger );
2062 }
2063 
2064 // This is for allowing guys to fallback more than once
2065 function ‪fallback_add_previous_group(num, node_array)
2066 {
2067  // check to see if its the first time or not
2068  if (!isdefined (level.current_fallbackers[num - 1]))
2069  {
2070  return;
2071  }
2072 
2073  // max fallbackers for next group add stragglers from previous group
2074  for (i = 0; i < level.current_fallbackers[num - 1]; i++)
2075  {
2076  level.max_fallbackers[num]++;
2077  }
2078 
2079  // current fallbackers from previous group should be added to next group as well
2080  for (i = 0; i < level.current_fallbackers[num - 1]; i++)
2081  {
2082  level.current_fallbackers[num]++;
2083  }
2084 
2085  ai = GetAIArray();
2086  for( i = 0; i < ai.size; i++ )
2087  {
2088  if( ( ( isdefined( ai[i].script_fallback ) ) && ( ai[i].script_fallback == (num - 1) ) ) )
2089  {
2090  //ai[i] notify( "stop_going_to_node" );
2091  ai[i].script_fallback++;
2092 
2093  if (isdefined (ai[i].fallback_node))
2094  {
2095  ai[i].fallback_node.fallback_occupied = false;
2096  ai[i].fallback_node = undefined;
2097  }
2098 
2099  //ai[i] thread fallback_ai( num, node_array );
2100  }
2101  }
2102 }
2103 
2104 /* DEAD CODE REMOVAL
2105 function delete_me()
2106 {
2107  WAIT_SERVER_FRAME;
2108  self Delete();
2109 }
2110 */
2111 
2112 /* DEAD CODE REMOVAL
2113 function waitframe()
2114 {
2115  WAIT_SERVER_FRAME;
2116 }
2117 */
2118 
2119 /* DEAD CODE REMOVAL
2120 function friendly_mg42_death_notify( guy, mg42 )
2121 {
2122  mg42 endon( "friendly_finished_using_mg42" );
2123  guy waittill( "death" );
2124  mg42 notify( "friendly_finished_using_mg42" );
2125  println( "^a guy using gun died" );
2126 }
2127 */
2128 
2129 /* DEAD CODE REMOVAL
2130 function friendly_mg42_wait_for_use( mg42 )
2131 {
2132  mg42 endon( "friendly_finished_using_mg42" );
2133  self.useable = true;
2134  self setcursorhint("HINT_NOICON");
2135  self setHintString(&"PLATFORM_USEAIONMG42");
2136  self waittill( "trigger" );
2137  println( "^a was used by player, stop using turret" );
2138  self.useable = false;
2139  self SetHintString( "" );
2140  self StopUSeturret();
2141  self notify( "stopped_use_turret" ); // special hook for decoytown guys -nate
2142  mg42 notify( "friendly_finished_using_mg42" );
2143 }
2144 */
2145 
2146 /* DEAD CODE REMOVAL
2147 function friendly_mg42_useable( mg42, node )
2148 {
2149  if( self.useable )
2150  {
2151  return false;
2152  }
2153 
2154  if( ( isdefined( self.turret_use_time ) ) &&( GetTime() < self.turret_use_time ) )
2155  {
2156 // println( "^a Used gun too recently" );
2157  return false;
2158  }
2159 
2160  // check to see if any player is too close.
2161  players = GetPlayers();
2162  for( q = 0; q < players.size; q++ )
2163  {
2164  if( Distancesquared( players[q].origin, node.origin ) < 100 * 100 )
2165  {
2166 // println( "^a player too close" );
2167  return false;
2168  }
2169  }
2170 
2171  if( isdefined( self.chainnode ) )
2172  {
2173  // check to see if all players are too far
2174  player_count = 0;
2175  for( q = 0; q < players.size; q++ )
2176  {
2177  if( Distancesquared( players[q].origin, self.chainnode.origin ) > 1100 * 1100 )
2178  {
2179  player_count++;
2180  }
2181  }
2182 
2183  if( player_count == players.size )
2184  {
2185  // println( "^a too far from chain node" );
2186  return false;
2187  }
2188  }
2189 
2190  return true;
2191 }
2192 */
2193 
2194 /* DEAD CODE REMOVAL
2195 function friendly_mg42_endtrigger( mg42, guy )
2196 {
2197  mg42 endon( "friendly_finished_using_mg42" );
2198  self waittill( "trigger" );
2199  println( "^a Told friendly to leave the MG42 now" );
2200 // guy StopUSeturret();
2201 
2202  mg42 notify( "friendly_finished_using_mg42" );
2203 }
2204 */
2205 
2206 /* DEAD CODE REMOVAL
2207 function noFour()
2208 {
2209  self endon( "death" );
2210  self waittill( "goal" );
2211  self.goalradius = self.oldradius;
2212  if( self.goalradius < 32 )
2213  {
2214  self.goalradius = 400;
2215  }
2216 }
2217 */
2218 
2219 /* DEAD CODE REMOVAL
2220 function friendly_mg42_think( mg42, node )
2221 {
2222  self endon( "death" );
2223  mg42 endon( "friendly_finished_using_mg42" );
2224 
2225  level thread friendly_mg42_death_notify( self, mg42 );
2226 
2227  self.oldradius = self.goalradius;
2228  self.goalradius = 28;
2229  self thread noFour();
2230  self SetGoal( node );
2231 
2232  self.ignoresuppression = true;
2233 
2234  self waittill( "goal" );
2235  self.goalradius = self.oldradius;
2236  if( self.goalradius < 32 )
2237  {
2238  self.goalradius = 400;
2239  }
2240 
2241  self.ignoresuppression = false;
2242 
2243  self.goalradius = self.oldradius;
2244 
2245  // check to see if any play is too close
2246  players = GetPlayers();
2247  for( q = 0; q < players.size; q++ )
2248  {
2249  if( Distancesquared( players[q].origin, node.origin ) < 32 * 32 )
2250  {
2251  mg42 notify( "friendly_finished_using_mg42" );
2252  return;
2253  }
2254  }
2255 
2256  self.friendly_mg42 = mg42; // For making him stop using the mg42 from another script
2257  self thread friendly_mg42_wait_for_use( mg42 );
2258  self thread friendly_mg42_cleanup( mg42 );
2259  self USeturret( mg42 ); // dude should be near the mg42
2260 // println( "^a Told AI to use mg42" );
2261 
2262  if( isdefined( mg42.target ) )
2263  {
2264  stoptrigger = GetEnt( mg42.target, "targetname" );
2265  if( isdefined( stoptrigger ) )
2266  {
2267  stoptrigger thread friendly_mg42_endtrigger( mg42, self );
2268  }
2269  }
2270 
2271  while( 1 )
2272  {
2273  if( Distancesquared( self.origin, node.origin ) < 32*32 )
2274  {
2275  self USeturret( mg42 ); // dude should be near the mg42
2276  }
2277  else
2278  {
2279  break; // a friendly is too far from mg42, stop using turret
2280  }
2281 
2282  if( isdefined( self.chainnode ) )
2283  {
2284  if( Distancesquared( self.origin, self.chainnode.origin ) > 1100*1100 )
2285  {
2286  break; // friendly node is too far, stop using turret
2287  }
2288  }
2289 
2290  wait( 1 );
2291  }
2292 
2293  mg42 notify( "friendly_finished_using_mg42" );
2294 }
2295 */
2296 
2297 /* DEAD CODE REMOVAL
2298 function friendly_mg42_cleanup( mg42 )
2299 {
2300  self endon( "death" );
2301  mg42 waittill( "friendly_finished_using_mg42" );
2302  self friendly_mg42_doneUsingTurret();
2303 }
2304 */
2305 
2306 /* DEAD CODE REMOVAL
2307 function friendly_mg42_doneUsingTurret()
2308 {
2309  self endon( "death" );
2310  turret = self.friendly_mg42;
2311  self.friendly_mg42 = undefined;
2312  self StopUSeturret();
2313  self notify( "stopped_use_turret" ); // special hook for decoytown guys -nate
2314  self.useable = false;
2315  self.goalradius = self.oldradius;
2316  if( !isdefined( turret ) )
2317  {
2318  return;
2319  }
2320 
2321  if( !isdefined( turret.target ) )
2322  {
2323  return;
2324  }
2325 
2326  node = GetNode( turret.target, "targetname" );
2327  oldradius = self.goalradius;
2328  self.goalradius = 8;
2329  self SetGoal( node );
2330  wait( 2 );
2331  self.goalradius = 384;
2332  return;
2333  self waittill( "goal" );
2334  if( isdefined( self.target ) )
2335  {
2336  node = GetNode( self.target, "targetname" );
2337  if( isdefined( node.target ) )
2338  {
2339  node = GetNode( node.target, "targetname" );
2340  }
2341 
2342  if( isdefined( node ) )
2343  {
2344  self SetGoal( node );
2345  }
2346  }
2347  self.goalradius = oldradius;
2348 }
2349 */
2350 
2351 
2352 /* DEAD CODE REMOVAL
2353 function spawnWaypointFriendlies()
2354 {
2355  self.count = 1;
2356  spawn = self spawn_ai();
2357 
2358  if ( spawn_failed( spawn ) )
2359  {
2360  return;
2361  }
2362 
2363  spawn.friendlyWaypoint = true;
2364 }
2365 */
2366 
2367 function ‪aigroup_init( aigroup, spawner )
2368 {
2369  if ( !isdefined( level._ai_group[aigroup] ) )
2370  {
2371  level._ai_group[aigroup] = SpawnStruct();
2372  level._ai_group[aigroup].aigroup = aigroup;
2373  level._ai_group[aigroup].aicount = 0;
2374  level._ai_group[aigroup].killed_count = 0;
2375  level._ai_group[aigroup].ai = [];
2376  level._ai_group[aigroup].spawners = [];
2377  level._ai_group[aigroup].cleared_count = 0;
2378 
2379  if ( !isdefined( level.flag[aigroup + "_cleared"] ) )
2380  {
2381  level ‪flag::init(aigroup + "_cleared");
2382  }
2383 
2384  if ( !isdefined( level.flag[aigroup + "_spawning"] ) )
2385  {
2386  level ‪flag::init(aigroup + "_spawning");
2387  }
2388 
2389  level thread ‪set_ai_group_cleared_flag( level._ai_group[aigroup] );
2390  }
2391 
2392  if ( isdefined( spawner ) )
2393  {
2394  ‪ARRAY_ADD( level._ai_group[aigroup].spawners, spawner );
2395  spawner thread ‪aigroup_spawner_death( level._ai_group[aigroup] );
2396  }
2397 }
2398 
2399 function ‪aigroup_spawner_death( tracker )
2400 {
2401  self ‪util::waittill_any( "death", "aigroup_spawner_death" );
2402  tracker notify( "update_aigroup" );
2403 }
2404 
2405 function ‪aigroup_think( tracker )
2406 {
2407  tracker.aicount++;
2408  tracker.ai[tracker.ai.size] = self;
2409  tracker notify( "update_aigroup" );
2410 
2411  if ( isdefined( self.script_deathflag_longdeath ) )
2412  {
2414  }
2415  else
2416  {
2417  self waittill( "death" );
2418  }
2419 
2420  tracker.aicount--;
2421  tracker.killed_count++;
2422  tracker notify( "update_aigroup" );
2423 
2425 
2426  tracker.ai = ‪array::remove_undefined( tracker.ai );
2427 }
2428 
2429 function ‪set_ai_group_cleared_flag( tracker )
2430 {
2431  waittillframeend; // wait for all spawners to get added to group
2432 
2433  while ( ( tracker.aicount + ‪get_ai_group_spawner_count( tracker.aigroup ) ) > tracker.cleared_count )
2434  {
2435  tracker waittill( "update_aigroup" );
2436  }
2437 
2438  level ‪flag::set( tracker.aigroup + "_cleared" );
2439 }
2440 
2441 // flood_spawner
2442 
2443 function ‪flood_trigger_think( trigger )
2444 {
2445  assert( isdefined( trigger.target ), "flood_spawner at " + trigger.origin + " without target" );
2446 
2447  floodSpawners = GetEntArray( trigger.target, "targetname" );
2448  assert( floodSpawners.size, "flood_spawner at with target " + trigger.target + " without any targets" );
2449 
2450  for(i = 0; i < floodSpawners.size; i++)
2451  {
2452  floodSpawners[i].script_trigger = trigger;
2453  }
2454 
2455 /* choke = true;
2456 
2457  if(isdefined(trigger.script_choke) && !trigger.script_choke)
2458  {
2459  choke = true;
2460  }
2461 
2462  for(i = 0; i < floodSpawners.size; i++)
2463  {
2464  floodSpawners[i].script_choke = choke;
2465  }
2466 
2467  */
2468  array::thread_all( floodSpawners,&‪flood_spawner_init );
2469 
2470  trigger waittill( "trigger" );
2471  // reget the target array since targets may have been deletes, etc... between initialization and triggering
2472  floodSpawners = GetEntArray( trigger.target, "targetname" );
2473 /* if(choke && NumRemoteClients())
2474  {
2475  util::spread_array_thread(floodSpawners,&flood_spawner_think, trigger);
2476  }
2477  else*/
2478  {
2479  array::thread_all( floodSpawners,&‪flood_spawner_think, trigger );
2480  }
2481 }
2482 
2483 
2484 function ‪flood_spawner_init( spawner )
2485 {
2486  Assert( ‪SPAWNFLAG( self, ‪SPAWNFLAG_ACTOR_SPAWNER ), "Spawner at origin" + self.origin + "/" +( self GetOrigin() ) + " is not a spawner!" );
2487 }
2488 
2489 function ‪trigger_requires_player( trigger )
2490 {
2491  if( !isdefined( trigger ) )
2492  {
2493  return false;
2494  }
2495 
2496  return isdefined( trigger.script_requires_player );
2497 }
2498 
2499 function ‪flood_spawner_think( trigger )
2500 {
2501  self endon( "death" );
2502  self notify( "stop current floodspawner" );
2503  self endon( "stop current floodspawner" );
2504 
2505  requires_player = ‪trigger_requires_player( trigger );
2506 
2508 
2509  while( self.count > 0 )
2510  {
2511  // see if any player is touching the trigger.
2512 // AlexL (6/26/2007): This line asserts when trigger is undefined. New version accomodated undefined trigger.
2513 // while( requires_player && !util::any_player_is_touching( trigger ) )
2514  if( requires_player ) // 0 if trigger is undefined
2515  {
2516  while( !‪util::any_player_is_touching( trigger ) )
2517  {
2518  wait( 0.5 );
2519  }
2520  }
2521 
2522  soldier = self ‪spawner::spawn();
2523 
2524  if( ‪spawn_failed( soldier ) )
2525  {
2526  wait( 2 );
2527  continue;
2528  }
2529 
2530  soldier thread ‪reincrement_count_if_deleted( self );
2531 
2532  soldier waittill( "death", attacker );
2533  if ( !‪player_saw_kill( soldier, attacker ) )
2534  {
2535  self.count++;
2536  }
2537 
2538  // soldier was deleted, not killed
2539  if( !isdefined( soldier ) )
2540  {
2541  continue;
2542  }
2543 
2544  if( !‪util::script_wait( true ) )
2545  {
2546  players = GetPlayers();
2547 
2548  if (players.size == 1)
2549  {
2550  wait( RandomFloatrange( 5, 9 ) );
2551  }
2552  else if (players.size == 2)
2553  {
2554  wait( RandomFloatrange( 3, 6 ) );
2555  }
2556  else if (players.size == 3)
2557  {
2558  wait( RandomFloatrange( 1, 4 ) );
2559  }
2560  else if (players.size == 4)
2561  {
2562  wait( RandomFloatrange( 0.5, 1.5 ) );
2563  }
2564  }
2565  }
2566 }
2567 
2568 function ‪player_saw_kill( guy, attacker )
2569 {
2570  if ( isdefined( self.script_force_count ) )
2571  {
2572  if ( self.script_force_count )
2573  {
2574  return true;
2575  }
2576  }
2577 
2578  if ( !isdefined( guy ) )
2579  {
2580  return false;
2581  }
2582 
2583  if ( IsAlive( attacker ) )
2584  {
2585  if ( IsPlayer( attacker ) )
2586  {
2587  return true;
2588  }
2589 
2590  players = GetPlayers();
2591 
2592  for( q = 0; q < players.size; q++ )
2593  {
2594  if ( DistanceSquared( attacker.origin, players[q].origin ) < 200 * 200 )
2595  {
2596  // player was near the guy that killed the ai?
2597  return true;
2598  }
2599  }
2600  }
2601  else
2602  {
2603  if ( isdefined( attacker ) )
2604  {
2605  if ( attacker.classname == "worldspawn" )
2606  {
2607  return false;
2608  }
2609 
2610  player = ‪util::get_closest_player( attacker.origin );
2611  if ( isdefined( player ) && distancesquared( attacker.origin, player.origin ) < 200*200 )
2612  {
2613  // player was near the guy that killed the ai?
2614  return true;
2615  }
2616  }
2617  }
2618 
2619  // get the closest player
2620  closest_player = ‪util::get_closest_player( guy.origin );
2621  if ( isdefined( closest_player ) && distancesquared( guy.origin, closest_player.origin ) < 200*200 )
2622  {
2623  // player was near the guy that got killed?
2624  return true;
2625  }
2626 
2627  // did the player see the guy die?
2628  return bulletTracePassed( closest_player geteye(), guy geteye(), false, undefined );
2629 }
2630 
2632 {
2633  /#
2634  /*if ( GetDvarString( "debug_badpath" ) == "" )
2635  SetDvar( "debug_badpath", "" );*/
2636 
2637  self endon( "death" );
2638  last_bad_path_time = -5000;
2639  bad_path_count = 0;
2640  for ( ;; )
2641  {
2642  self waittill( "bad_path", badPathPos );
2643 
2644  if ( !isdefined(level.debug_badpath) || !level.debug_badpath )
2645  {
2646  continue;
2647  }
2648 
2649  if ( gettime() - last_bad_path_time > 5000 )
2650  {
2651  bad_path_count = 0;
2652  }
2653  else
2654  {
2655  bad_path_count++;
2656  }
2657 
2658  last_bad_path_time = gettime();
2659 
2660  if ( bad_path_count < 10 )
2661  {
2662  continue;
2663  }
2664 
2665  for ( p = 0; p < 10 * 20; p++ )
2666  {
2667  line( self.origin, badPathPos, ( 1, 0.4, 0.1 ), 0, 10 * 20 );
2669  }
2670  }
2671  #/
2672 }
2673 
2674 
2675 //-- self == ai
2677 {
2678  return true;
2679 }
2680 
2692 function ‪spawn( b_force = false, str_targetname, v_origin, v_angles, bIgnoreSpawningLimit )
2693 {
2694  if( IsDefined( level.overrideGlobalSpawnFunc ) && self.team == "axis" )
2695  {
2696  return [[level.overrideGlobalSpawnFunc]]( b_force, str_targetname, v_origin, v_angles );
2697  }
2698 
2699  e_spawned = undefined;
2700  force_spawn = false;
2701  makeroom = false;
2702  infinitespawn = false;
2703  deleteonzerocount = false;
2704 
2705  /#
2706  if ( GetDvarString( "noai" ) != "off" )
2707  {
2708  return;
2709  }
2710  #/
2711 
2713  {
2714  return;
2715  }
2716 
2717  while ( true )
2718  {
2719  if ( !‪IS_TRUE( bIgnoreSpawningLimit ) && !‪IS_TRUE( self.ignorespawninglimit ) ) //TU1 - self.ignorespawninglimit - only to be used when nothing else will suffice
2720  {
2722  }
2723 
2724  if( ‪IS_BONUSZM && !IsDefined( self ) )
2725  {
2726  // sjakatdar TU2 (10/29/2015) In rare cases, the spawner might get deleted which might lead to un-recoverable script errors.
2727  return;
2728  }
2729 
2730  if ( isdefined( self.lastSpawnTime ) && self.lastSpawnTime >= GetTime() )
2731  {
2733  continue;
2734  }
2735 
2736  break;
2737  }
2738 
2739  if ( IsActorSpawner( self ) )
2740  {
2742  {
2743  makeroom = true;
2744  }
2745  }
2746  else if ( IsVehicleSpawner( self ) )
2747  {
2749  {
2750  makeroom = true;
2751  }
2752  }
2753 
2754  // ForceSpawn and InfiniteSpawn flags match between actors and vehicles
2755  if ( b_force || ‪SPAWNFLAG( self, ‪SPAWNFLAG_ACTOR_SCRIPTFORCESPAWN ) || isdefined( self.script_forcespawn ) )
2756  {
2757  force_spawn = true;
2758  }
2759 
2761  {
2762  infinitespawn = true;
2763  }
2764 
2765  if ( !IsDefined( e_spawned ) )
2766  {
2767  female_override = undefined;
2768  use_female = RandomInt( 100 ) < level.female_percent;
2769  if( level.dont_use_female_replacements === true ) //allows female mapping to selectively be disabled for certain sections of a level
2770  {
2771  use_female = 0;
2772  }
2773 
2774  if ( use_female && IsDefined( self.aitypevariant ) )
2775  {
2776  e_spawned = self SpawnFromSpawner( str_targetname, force_spawn, makeroom, infinitespawn, "actor_" + self.aitypevariant );
2777  }
2778  else
2779  {
2780  override_aitype = undefined;
2781 
2782  if( isDefined( level.override_spawned_aitype_func ))
2783  {
2784  override_aitype = [[ level.override_spawned_aitype_func ]]( self );
2785  }
2786 
2787  if( IsDefined( override_aitype ) )
2788  {
2789  e_spawned = self SpawnFromSpawner( str_targetname, force_spawn, makeroom, infinitespawn, override_aitype );
2790  }
2791  else
2792  {
2793  e_spawned = self SpawnFromSpawner( str_targetname, force_spawn, makeroom, infinitespawn );
2794  }
2795  }
2796 
2797  }
2798 
2799  // Store the last spawned time on the spawner
2800  if ( IsDefined( e_spawned ) )
2801  {
2802  if( isdefined( level.run_custom_function_on_ai ) )
2803  {
2804  e_spawned thread [[level.run_custom_function_on_ai]]( self, str_targetname, force_spawn );
2805  }
2806 
2807  if ( isdefined( v_origin ) || isdefined( v_angles ) )
2808  {
2809  e_spawned ‪teleport_spawned( v_origin, v_angles );
2810  }
2811 
2812  self.lastSpawnTime = GetTime();
2813  }
2814 
2815  if ( ( deleteonzerocount || ‪IS_TRUE( self.script_delete_on_zero ) ) && isdefined( self.count ) && ( self.count <= 0 ) )
2816  {
2817  self Delete();
2818  }
2819 
2820  if ( IsSentient( e_spawned ) )
2821  {
2822  if ( !‪spawn_failed( e_spawned ) )
2823  {
2824  return e_spawned;
2825  }
2826  }
2827  else
2828  {
2829  return e_spawned;
2830  }
2831 }
2832 
2833 function ‪teleport_spawned( v_origin, v_angles, b_reset_entity = true )
2834 {
2835  ‪DEFAULT( v_origin, self.origin );
2836  ‪DEFAULT( v_angles, self.angles );
2837 
2838  if ( IsActor( self ) )
2839  {
2840  self ForceTeleport( v_origin, v_angles, true, b_reset_entity );
2841  }
2842  else
2843  {
2844  self.origin = v_origin;
2845  self.angles = v_angles;
2846  }
2847 }
2848 
2850 {
2851  if ( isdefined( level.players ) && level.players.size > 0 )
2852  {
2853  n_player_count = level.players.size;
2854  }
2855  else
2856  {
2857  n_player_count = GetNumExpectedPlayers();
2858  }
2859 
2860  if ( isdefined( self.script_minplayers ) )
2861  {
2862  if ( n_player_count < self.script_minplayers )
2863  {
2864  self Delete();
2865  return false;
2866  }
2867  }
2868 
2869  // TODO: depricated script_numplayers, remove at some point
2870  if ( isdefined( self.script_numplayers ) )
2871  {
2872  if ( n_player_count < self.script_numplayers )
2873  {
2874  self Delete();
2875  return false;
2876  }
2877  }
2879 
2880  if ( isdefined( self.script_maxplayers ) )
2881  {
2882  if ( n_player_count > self.script_maxplayers )
2883  {
2884  self Delete();
2885  return false;
2886  }
2887  }
2888 
2889  return true;
2890 }
2891 
2903 {
2904  if ( IsAlive( ‪spawn ) )
2905  {
2906  if ( !isdefined( ‪spawn.finished_spawning ) )
2907  {
2908  ‪spawn waittill("finished spawning");
2909  }
2910 
2911  waittillframeend;
2912 
2913  if ( IsAlive( ‪spawn ) )
2914  {
2915  return false;
2916  }
2917  }
2918 
2919  return true;
2920 }
2921 
2931 function ‪kill_spawnernum( number )
2932 {
2933  foreach ( sp in GetSpawnerArray( "" + number, "script_killspawner" ) )
2934  {
2935  sp Delete();
2936  }
2937 }
2938 
2949 {
2950  self.replace_on_death = undefined;
2951  self notify( "_disable_reinforcement" );
2952 }
2953 
2964 {
2966 }
2967 
2978 function ‪set_ai_group_cleared_count(aigroup, count)
2979 {
2980  ‪aigroup_init(aigroup);
2981  level._ai_group[aigroup].cleared_count = count;
2982 }
2983 
2993 function ‪waittill_ai_group_cleared( aigroup )
2994 {
2995  assert(isdefined(level._ai_group[aigroup]), "The aigroup "+aigroup+" does not exist");
2996  level ‪flag::wait_till(aigroup + "_cleared");
2997 }
2998 
3008 function ‪waittill_ai_group_count( aigroup, count )
3009 {
3010  while ( ‪get_ai_group_spawner_count( aigroup ) + level._ai_group[ aigroup ].aicount > count )
3011  {
3012  level._ai_group[ aigroup ] waittill( "update_aigroup" );
3013  }
3014 }
3015 
3025 function ‪waittill_ai_group_ai_count( aigroup, count )
3026 {
3027  while( level._ai_group[ aigroup ].aicount > count )
3028  {
3029  level._ai_group[ aigroup ] waittill( "update_aigroup" );
3030  }
3031 }
3032 
3042 function ‪waittill_ai_group_spawner_count( aigroup, count )
3043 {
3044  while ( ‪get_ai_group_spawner_count( aigroup ) > count )
3045  {
3046  level._ai_group[ aigroup ] waittill( "update_aigroup" );
3047  }
3048 }
3049 
3059 function ‪waittill_ai_group_amount_killed( aigroup, amount_killed )
3060 {
3061  while ( level._ai_group[ aigroup ].killed_count < amount_killed )
3062  {
3063  level._ai_group[ aigroup ] waittill( "update_aigroup" );
3064  }
3065 }
3066 
3076 function ‪get_ai_group_count( aigroup )
3077 {
3078  return( ‪get_ai_group_spawner_count( aigroup ) + level._ai_group[ aigroup ].aicount );
3079 }
3080 
3091 {
3092  return( level._ai_group[ aigroup ].aicount );
3093 }
3094 
3096 {
3097  n_count = 0;
3098  foreach ( sp in level._ai_group[ aigroup ].spawners )
3099  {
3100  if ( isdefined( sp ) )
3101  {
3102  n_count += sp.count;
3103  }
3104  }
3105  return n_count;
3106 }
3107 
3117 function ‪get_ai_group_ai( aigroup )
3118 {
3119  aiSet = [];
3120  for( index = 0; index < level._ai_group[ aigroup ].ai.size; index ++ )
3121  {
3122  if( !isAlive( level._ai_group[ aigroup ].ai[ index ] ) )
3123  {
3124  continue;
3125  }
3126 
3127  aiSet[ aiSet.size ] = level._ai_group[ aigroup ].ai[ index ];
3128  }
3129 
3130  return( aiSet );
3131 }
3132 
3149 function ‪add_global_spawn_function( team, spawn_func, param1, param2, param3, param4, param5 )
3150 {
3151  if ( !isdefined( level.spawn_funcs ) )
3152  {
3153  level.spawn_funcs = [];
3154  }
3155 
3156  if ( !isdefined( level.spawn_funcs[team] ) )
3157  {
3158  level.spawn_funcs[team] = [];
3159  }
3160 
3161  func = [];
3162  func[ "function" ] =spawn_func;
3163  func[ "param1" ] = param1;
3164  func[ "param2" ] = param2;
3165  func[ "param3" ] = param3;
3166  func[ "param4" ] = param4;
3167  func[ "param5" ] = param5;
3168 
3169  ‪ARRAY_ADD( level.spawn_funcs[ team ], func );
3170 }
3171 
3188 function ‪add_archetype_spawn_function( archetype, spawn_func, param1, param2, param3, param4, param5 )
3189 {
3190  if ( !isdefined( level.spawn_funcs ) )
3191  {
3192  level.spawn_funcs = [];
3193  }
3194 
3195  if ( !isdefined( level.spawn_funcs[archetype] ) )
3196  {
3197  level.spawn_funcs[archetype] = [];
3198  }
3199 
3200  func = [];
3201  func[ "function" ] = spawn_func;
3202  func[ "param1" ] = param1;
3203  func[ "param2" ] = param2;
3204  func[ "param3" ] = param3;
3205  func[ "param4" ] = param4;
3206  func[ "param5" ] = param5;
3207 
3208  ‪ARRAY_ADD( level.spawn_funcs[ archetype ], func );
3209 }
3210 
3222 function ‪remove_global_spawn_function( team,func )
3223 {
3224  if ( isdefined( level.spawn_funcs ) && isdefined( level.spawn_funcs[team] ) )
3225  {
3226  ‪array = [];
3227  for( i = 0; i < level.spawn_funcs[ team ].size; i++ )
3228  {
3229  if( level.spawn_funcs[ team ][ i ][ "function" ] !=func )
3230  {
3231  ‪array[ ‪array.size ] = level.spawn_funcs[ team ][ i ];
3232  }
3233  }
3234 
3235  level.spawn_funcs[ team ] = ‪array;
3236  }
3237 }
3238 
3252 function ‪add_spawn_function( spawn_func, param1, param2, param3, param4, param5 )
3253 {
3254  assert( !isdefined( level._loadStarted ) || !IsAlive( self ), "Tried to add_spawn_function to a living guy." );
3255 
3256  func = [];
3257  func[ "function" ] =spawn_func;
3258  func[ "param1" ] = param1;
3259  func[ "param2" ] = param2;
3260  func[ "param3" ] = param3;
3261  func[ "param4" ] = param4;
3262  func[ "param5" ] = param5;
3263 
3264  if (!isdefined(self.spawn_funcs))
3265  {
3266  self.spawn_funcs = [];
3267  }
3268 
3269  self.spawn_funcs[ self.spawn_funcs.size ] = func;
3270 }
3271 
3281 {
3282  assert( !isdefined( level._loadStarted ) || !IsAlive( self ), "Tried to remove_spawn_function to a living guy." );
3283 
3284  if ( isdefined( self.spawn_funcs ) )
3285  {
3286  ‪array = [];
3287  for ( i = 0; i < self.spawn_funcs.size; i++ )
3288  {
3289  if ( self.spawn_funcs[ i ][ "function" ] != func )
3290  {
3291  ‪array[ ‪array.size ] = self.spawn_funcs[ i ];
3292  }
3293  }
3294 
3295  assert( self.spawn_funcs.size != ‪array.size, "Tried to remove a function from level.spawn_funcs, but that function didn't exist!" );
3296  self.spawn_funcs = ‪array;
3297  }
3298 }
3299 
3300 
3318 function ‪add_spawn_function_group( str_value, str_key = "targetname", func_spawn, param_1, param_2, param_3, param_4, param_5 )
3319 {
3320  Assert( isdefined( str_value ), "str_value is a required parameter for add_spawn_function_group" );
3321  Assert( isdefined( func_spawn ), "func_spawn is a required parameter for add_spawn_function_group" );
3322 
3323  a_spawners = GetSpawnerArray( str_value, str_key );
3324  array::run_all( a_spawners, &‪add_spawn_function, func_spawn, param_1, param_2, param_3, param_4, param_5 );
3325 }
3326 
3343 function ‪add_spawn_function_ai_group( str_aigroup, func_spawn, param_1, param_2, param_3, param_4, param_5 )
3344 {
3345  assert( isdefined( str_aigroup ), "str_aigroup is a required parameter for add_spawn_function_ai_group" );
3346  assert( isdefined( func_spawn ), "func_spawn is a required parameter for add_spawn_function_ai_group" );
3347 
3348  a_spawners = GetSpawnerArray( str_aigroup, "script_aigroup" );
3349  array::run_all( a_spawners, &‪add_spawn_function, func_spawn, param_1, param_2, param_3, param_4, param_5 );
3350 }
3351 
3363 function ‪remove_spawn_function_ai_group( str_aigroup, func_spawn, param_1, param_2, param_3, param_4, param_5 )
3364 {
3365  assert( isdefined( str_aigroup ), "str_aigroup is a required parameter for remove_spawn_function_ai_group" );
3366  assert( isdefined( func_spawn ), "func_spawn is a required parameter for remove_spawn_function_ai_group" );
3367 
3368  a_spawners = GetSpawnerArray( str_aigroup, "script_aigroup" );
3369  array::run_all( a_spawners, &‪remove_spawn_function, func_spawn );
3370 }
3371 
3383 function ‪simple_flood_spawn( ‪name, spawn_func, spawn_func_2 )
3384 {
3385  spawners = getEntArray( ‪name, "targetname" );
3386  assert( spawners.size, "no spawners with targetname " + ‪name + " found!" );
3387 
3388  // add spawn function to each spawner if specified
3389  if( isdefined( spawn_func ) )
3390  {
3391  for( i = 0; i < spawners.size; i++ )
3392  {
3393  spawners[i] ‪add_spawn_function( spawn_func );
3394  }
3395  }
3396 
3397  if( isdefined( spawn_func_2 ) )
3398  {
3399  for( i = 0; i < spawners.size; i++ )
3400  {
3401  spawners[i] ‪add_spawn_function( spawn_func_2 );
3402  }
3403  }
3404 
3405  for( i = 0; i < spawners.size; i++ )
3406  {
3407  if( i % 2 )
3408  {
3409  //wait for a new network frame to be sent out before spawning in another guy
3411  }
3412 
3413  // same behavior in _spawner's spawner::flood_spawner_scripted() function
3414  spawners[i] thread ‪flood_spawner_init();
3415  spawners[i] thread ‪flood_spawner_think();
3416  }
3417 }
3418 
3435 function ‪simple_spawn( name_or_spawners, spawn_func, param1, param2, param3, param4, param5, bForce )
3436 {
3437  spawners = [];
3438 
3439  if ( IsString( name_or_spawners ) )
3440  {
3441  spawners = GetEntArray( name_or_spawners, "targetname" );
3442  assert( spawners.size, "no spawners with targetname " + name_or_spawners + " found!" );
3443  }
3444  else
3445  {
3446  ‪MAKE_ARRAY( name_or_spawners );
3447  spawners = name_or_spawners;
3448  }
3449 
3450  a_spawned = [];
3451 
3452  foreach ( sp in spawners )
3453  {
3454  e_spawned = sp ‪spawner::spawn( bForce );
3455 
3456  if ( isdefined( e_spawned ) )
3457  {
3458  if ( isdefined( spawn_func ) )
3459  {
3460  ‪util::single_thread( e_spawned, spawn_func, param1, param2, param3, param4, param5 );
3461  }
3462 
3463  ‪ARRAY_ADD( a_spawned, e_spawned );
3464  }
3465  }
3466 
3467  return a_spawned;
3468 }
3469 
3486 function ‪simple_spawn_single( name_or_spawner, spawn_func, param1, param2, param3, param4, param5, bforce )
3487 {
3488  ai = ‪simple_spawn( name_or_spawner, spawn_func, param1, param2, param3, param4, param5, bforce );
3489  assert( ai.size <= 1, "simple_spawn called from simple_spawn_single somehow spawned more than one guy!" );
3490 
3491  if ( ai.size )
3492  {
3493  return ai[0];
3494  }
3495 }
3496 
3497 
3506 function ‪set_targets(spawner_targets)
3507 {
3508  self thread ‪spawner::go_to_spawner_target(StrTok(spawner_targets," "));
3509 }
3510 
3511 
3512 function autoexec ‪init_female_spawn()
3513 {
3514  level.female_percent = 0;
3515  ‪set_female_percent( 30 );
3516 }
3517 
3526 function ‪set_female_percent( percent )
3527 {
3528  level.female_percent = percent;
3529 }
‪replace_on_death
‪function replace_on_death()
Definition: spawner_shared.gsc:2963
‪fallback_add_previous_group
‪function fallback_add_previous_group(num, node_array)
Definition: spawner_shared.gsc:2065
‪get_ai_group_sentient_count
‪function get_ai_group_sentient_count(aigroup)
Definition: spawner_shared.gsc:3090
‪fallback_interrupt
‪function fallback_interrupt()
Definition: spawner_shared.gsc:1715
‪script_delay
‪function script_delay()
Definition: util_shared.gsc:970
‪callback
‪function callback(event, localclientnum, params)
Definition: callbacks_shared.csc:13
‪init_female_spawn
‪function autoexec init_female_spawn()
Definition: spawner_shared.gsc:3512
‪go_to_origin
‪function go_to_origin(node, optional_arrived_at_node_func)
Definition: spawner_shared.gsc:1051
‪MAX_SPAWNED_PER_FRAME
‪#define MAX_SPAWNED_PER_FRAME
Definition: shared.gsh:307
‪set_female_percent
‪function set_female_percent(percent)
Definition: spawner_shared.gsc:3526
‪get_least_used_from_array
‪function get_least_used_from_array(array)
Definition: spawner_shared.gsc:1233
‪update_target_array
‪function update_target_array(str_target)
Definition: spawner_shared.gsc:1562
‪empty
‪function empty(a, b, c, d, e)
Definition: util_shared.csc:32
‪force_goal
‪function force_goal(goto, n_radius, b_shoot=true, str_end_on, b_keep_colors=false, b_should_sprint=false)
Definition: ai_shared.gsc:570
‪goal_volume_init
‪function goal_volume_init()
Definition: spawner_shared.gsc:256
‪flood_trigger_think
‪function flood_trigger_think(trigger)
Definition: spawner_shared.gsc:2443
‪spawn_prethink
‪function spawn_prethink()
Definition: spawner_shared.gsc:449
‪aigroup_init
‪function aigroup_init(aigroup, spawner)
Definition: spawner_shared.gsc:2367
‪fallback_text
‪function fallback_text(fallbackers, start, end)
Definition: spawner_shared.gsc:1953
‪spawn_guys_until_death_or_no_count
‪function spawn_guys_until_death_or_no_count()
Definition: spawner_shared.gsc:320
‪__main__
‪function __main__()
Definition: spawner_shared.gsc:103
‪waittillDeathOrPainDeath
‪function waittillDeathOrPainDeath()
Definition: spawner_shared.gsc:360
‪add_global_spawn_function
‪function add_global_spawn_function(team, spawn_func, param1, param2, param3, param4, param5)
Definition: spawner_shared.gsc:3149
‪colorNode_replace_on_death
‪function colorNode_replace_on_death()
Definition: colors_shared.gsc:1475
‪flood_spawner_init
‪function flood_spawner_init(spawner)
Definition: spawner_shared.gsc:2484
‪simple_flood_spawn
‪function simple_flood_spawn(name, spawn_func, spawn_func_2)
Definition: spawner_shared.gsc:3383
‪clear
‪function clear(str_flag)
Definition: flag_shared.csc:130
‪fallback_ai_think_death
‪function fallback_ai_think_death(ai, num)
Definition: spawner_shared.gsc:1654
‪remove_spawn_function
‪function remove_spawn_function(func)
Definition: spawner_shared.gsc:3280
‪remove_crawled
‪function remove_crawled(ent)
Definition: spawner_shared.gsc:1451
‪grenadeAwareness
‪function grenadeAwareness()
Definition: gameskill_shared.gsc:609
‪spawn_think
‪function spawn_think(spawner)
Definition: spawner_shared.gsc:504
‪run_spawn_functions
‪function run_spawn_functions()
Definition: spawner_shared.gsc:563
‪get_node_funcs_based_on_target
‪function get_node_funcs_based_on_target(node, goal_type)
Definition: spawner_shared.gsc:1504
‪set_targets
‪function set_targets(spawner_targets)
Definition: spawner_shared.gsc:3506
‪waittill_either
‪function waittill_either(msg1, msg2)
Definition: util_shared.gsc:303
‪fallback_overmind_internal
‪function fallback_overmind_internal(num, group, fallback_nodes, ignoreWhileFallingBack, percent)
Definition: spawner_shared.gsc:1828
‪add_archetype_spawn_function
‪function add_archetype_spawn_function(archetype, spawn_func, param1, param2, param3, param4, param5)
Definition: spawner_shared.gsc:3188
‪get_array
‪function get_array(kvp_value, kvp_key="targetname")
Definition: struct.csc:34
‪set_goalradius_based_on_settings
‪function set_goalradius_based_on_settings(node)
Definition: spawner_shared.gsc:1587
‪fallback_think
‪function fallback_think(trigger)
Definition: spawner_shared.gsc:2034
‪IS_ARTILLERY
‪#define IS_ARTILLERY(__e)
Definition: shared.gsh:354
‪update_nav_triggers
‪function update_nav_triggers()
Definition: spawner_shared.gsc:122
‪get_target_nodes
‪function get_target_nodes(target)
Definition: spawner_shared.gsc:1036
‪player_saw_kill
‪function player_saw_kill(guy, attacker)
Definition: spawner_shared.gsc:2568
‪get_target_structs
‪function get_target_structs(target)
Definition: spawner_shared.gsc:1041
‪node_has_radius
‪function node_has_radius(node)
Definition: spawner_shared.gsc:1046
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪get
‪function get(kvp_value, kvp_key="targetname")
Definition: struct.csc:13
‪add
‪function add(entity, dyingplayer, team, timeout)
Definition: _deathicons.gsc:43
‪set_ai_group_cleared_count
‪function set_ai_group_cleared_count(aigroup, count)
Definition: spawner_shared.gsc:2978
‪crawl_through_targets_to_init_flags
‪function crawl_through_targets_to_init_flags()
Definition: spawner_shared.gsc:625
‪SPAWNFLAG_ACTOR_SCRIPTMAKEROOM
‪#define SPAWNFLAG_ACTOR_SCRIPTMAKEROOM
Definition: shared.gsh:49
‪any_player_is_touching
‪function any_player_is_touching(ent, str_team)
Definition: util_shared.gsc:1868
‪show_bad_path
‪function show_bad_path()
Definition: spawner_shared.gsc:2631
‪kill_spawnernum
‪function kill_spawnernum(number)
Definition: spawner_shared.gsc:2931
‪process_deathflags
‪function process_deathflags()
Definition: spawner_shared.gsc:302
‪teleport_spawned
‪function teleport_spawned(v_origin, v_angles, b_reset_entity=true)
Definition: spawner_shared.gsc:2833
‪coverprint
‪function coverprint(org)
Definition: spawner_shared.gsc:1793
‪spawn_grenade_bag
‪function spawn_grenade_bag(origin, angles, team)
Definition: spawner_shared.gsc:422
‪precache_player_weapon_drops
‪function precache_player_weapon_drops(weapon_names)
Definition: spawner_shared.gsc:276
‪set_goal_volume
‪function set_goal_volume()
Definition: spawner_shared.gsc:971
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪crawl_target_and_init_flags
‪function crawl_target_and_init_flags(ent, get_func)
Definition: spawner_shared.gsc:1460
‪add_spawn_function_group
‪function add_spawn_function_group(str_value, str_key="targetname", func_spawn, param_1, param_2, param_3, param_4, param_5)
Definition: spawner_shared.gsc:3318
‪aigroup_spawner_death
‪function aigroup_spawner_death(tracker)
Definition: spawner_shared.gsc:2399
‪update_nav_triggers_for_actor
‪function update_nav_triggers_for_actor()
Definition: spawner_shared.gsc:492
‪wait_network_frame
‪function wait_network_frame(n_count=1)
Definition: util_shared.gsc:64
‪set_ai_group_cleared_flag
‪function set_ai_group_cleared_flag(tracker)
Definition: spawner_shared.gsc:2429
‪callback_Track_Dead_NPCs_By_Type
‪function callback_Track_Dead_NPCs_By_Type()
Definition: spawner_shared.gsc:251
‪fallback_ai_think
‪function fallback_ai_think(num, node_array, spawner, ignoreWhileFallingBack)
Definition: spawner_shared.gsc:1662
‪REGISTER_SYSTEM_EX
‪#define REGISTER_SYSTEM_EX(__sys, __func_init_preload, __func_init_postload, __reqs)
Definition: shared.gsh:209
‪SPAWNFLAG_ACTOR_SCRIPTFORCESPAWN
‪#define SPAWNFLAG_ACTOR_SCRIPTFORCESPAWN
Definition: shared.gsh:52
‪spawn_failed
‪function spawn_failed(spawn)
Definition: spawner_shared.gsc:2902
‪waittill_ai_group_spawner_count
‪function waittill_ai_group_spawner_count(aigroup, count)
Definition: spawner_shared.gsc:3042
‪end
‪function end(final)
Definition: _killcam.gsc:511
‪waittill_ai_group_cleared
‪function waittill_ai_group_cleared(aigroup)
Definition: spawner_shared.gsc:2993
‪waittill_notify_or_timeout
‪function waittill_notify_or_timeout(msg, timer)
Definition: util_shared.csc:473
‪waittill_ai_group_count
‪function waittill_ai_group_count(aigroup, count)
Definition: spawner_shared.gsc:3008
‪get_ai_group_count
‪function get_ai_group_count(aigroup)
Definition: spawner_shared.gsc:3076
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪spawn
‪function spawn(b_force=false, str_targetname, v_origin, v_angles, bIgnoreSpawningLimit)
Definition: spawner_shared.gsc:2692
‪get_ai_group_spawner_count
‪function get_ai_group_spawner_count(aigroup)
Definition: spawner_shared.gsc:3095
‪watches_for_friendly_fire
‪function watches_for_friendly_fire()
Definition: spawner_shared.gsc:2676
‪living_ai_prethink
‪function living_ai_prethink()
Definition: spawner_shared.gsc:611
‪go_to_spawner_target
‪function go_to_spawner_target(target_names)
Definition: spawner_shared.gsc:1108
‪fallback_wait
‪function fallback_wait(num, group, ignoreWhileFallingBack, percent)
Definition: spawner_shared.gsc:1976
‪remove_undefined
‪function remove_undefined(array, b_keep_keys)
Definition: array_shared.csc:56
‪simple_spawn_single
‪function simple_spawn_single(name_or_spawner, spawn_func, param1, param2, param3, param4, param5, bforce)
Definition: spawner_shared.gsc:3486
‪disable_replace_on_death
‪function disable_replace_on_death()
Definition: spawner_shared.gsc:2948
‪SPAWNFLAG
‪#define SPAWNFLAG(__e, __f)
Definition: shared.gsh:95
‪flood_spawner_think
‪function flood_spawner_think(trigger)
Definition: spawner_shared.gsc:2499
‪set_force_color
‪function set_force_color(_color)
Definition: colors_shared.gsc:1800
‪script_wait
‪function script_wait(called_from_spawner=false)
Definition: util_shared.gsc:1930
‪wait_till
‪function wait_till(str_flag)
Definition: flag_shared.csc:189
‪get_goal
‪function get_goal(str_goal, str_key="targetname")
Definition: spawner_shared.gsc:1608
‪fallback_overmind
‪function fallback_overmind(num, group, ignoreWhileFallingBack, percent)
Definition: spawner_shared.gsc:1809
‪add_spawn_function_ai_group
‪function add_spawn_function_ai_group(str_aigroup, func_spawn, param_1, param_2, param_3, param_4, param_5)
Definition: spawner_shared.gsc:3343
‪spawner_targets_init
‪function spawner_targets_init()
Definition: spawner_shared.gsc:1095
‪array
‪function filter array
Definition: array_shared.csc:16
‪flood_spawner_scripted
‪function flood_spawner_scripted(spawners)
Definition: spawner_shared.gsc:326
‪aigroup_think
‪function aigroup_think(tracker)
Definition: spawner_shared.gsc:2405
‪go_to_node_set_goal_pos
‪function go_to_node_set_goal_pos(ent)
Definition: spawner_shared.gsc:1441
‪go_to_struct
‪function go_to_struct(node, optional_arrived_at_node_func)
Definition: spawner_shared.gsc:1056
‪spawn_think_action
‪function spawn_think_action(spawner)
Definition: spawner_shared.gsc:647
‪Spawn
‪function Spawn(parent, onDeathCallback)
Definition: _flak_drone.gsc:427
‪global_ai_array
‪function global_ai_array()
Definition: spawner_shared.gsc:187
‪fallback_goal
‪function fallback_goal(ignoreWhileFallingBack)
Definition: spawner_shared.gsc:1701
‪get_target_ents
‪function get_target_ents(target)
Definition: spawner_shared.gsc:1031
‪MAKE_ARRAY
‪#define MAKE_ARRAY(__array)
Definition: shared.gsh:303
‪init
‪function init()
Definition: struct.csc:1
‪reincrement_count_if_deleted
‪function reincrement_count_if_deleted(spawner)
Definition: spawner_shared.gsc:334
‪remove_spawn_function_ai_group
‪function remove_spawn_function_ai_group(str_aigroup, func_spawn, param_1, param_2, param_3, param_4, param_5)
Definition: spawner_shared.gsc:3363
‪__init__
‪function __init__()
Definition: spawner_shared.gsc:41
‪global_spawn_throttle
‪function global_spawn_throttle(n_count_per_network_frame)
Definition: spawner_shared.gsc:238
‪SPAWNFLAG_VEHICLE_SCRIPTMAKEROOM
‪#define SPAWNFLAG_VEHICLE_SCRIPTMAKEROOM
Definition: shared.gsh:63
‪trigger_requires_player
‪function trigger_requires_player(trigger)
Definition: spawner_shared.gsc:2489
‪drop_gear
‪function drop_gear()
Definition: spawner_shared.gsc:366
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪IS_EQUAL
‪#define IS_EQUAL(__a, __b)
Definition: shared.gsh:250
‪go_to_node_using_funcs
‪function go_to_node_using_funcs(node, get_target_func, set_goal_func_quits, optional_arrived_at_node_func, require_player_dist)
Definition: spawner_shared.gsc:1263
‪waittill_ai_group_ai_count
‪function waittill_ai_group_ai_count(aigroup, count)
Definition: spawner_shared.gsc:3025
‪remove_global_spawn_function
‪function remove_global_spawn_function(team, func)
Definition: spawner_shared.gsc:3222
‪exists
‪function exists(str_flag)
Definition: flag_shared.csc:43
‪spawn_throttle_reset
‪function spawn_throttle_reset()
Definition: spawner_shared.gsc:228
‪single_thread
‪function single_thread(entity, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:699
‪go_to_node_wait_for_player
‪function go_to_node_wait_for_player(node, get_target_func, dist)
Definition: spawner_shared.gsc:1375
‪release_spawner_target_node
‪function release_spawner_target_node(node)
Definition: spawner_shared.gsc:1197
‪get_ai_group_ai
‪function get_ai_group_ai(aigroup)
Definition: spawner_shared.gsc:3117
‪go_to_node_set_goal_node
‪function go_to_node_set_goal_node(node)
Definition: spawner_shared.gsc:1446
‪SPAWNFLAG_PATH_DISABLED
‪#define SPAWNFLAG_PATH_DISABLED
Definition: shared.gsh:81
‪fallback_ai
‪function fallback_ai(num, node_array, ignoreWhileFallingBack)
Definition: spawner_shared.gsc:1738
‪fallback_death
‪function fallback_death(ai, num)
Definition: spawner_shared.gsc:1687
‪check_player_requirements
‪function check_player_requirements()
Definition: spawner_shared.gsc:2849
‪IS_BONUSZM
‪#define IS_BONUSZM
Definition: shared.gsh:532
‪add_spawn_function
‪function add_spawn_function(spawn_func, param1, param2, param3, param4, param5)
Definition: spawner_shared.gsc:3252
‪SPAWNFLAG_ACTOR_SPAWNER
‪#define SPAWNFLAG_ACTOR_SPAWNER
Definition: shared.gsh:48
‪name
‪class GroundFx name
‪simple_spawn
‪function simple_spawn(name_or_spawners, spawn_func, param1, param2, param3, param4, param5, bForce)
Definition: spawner_shared.gsc:3435
‪kill_trigger
‪function kill_trigger(trigger)
Definition: spawner_shared.gsc:345
‪waittill_ai_group_amount_killed
‪function waittill_ai_group_amount_killed(aigroup, amount_killed)
Definition: spawner_shared.gsc:3059
‪fallback_spawner_think
‪function fallback_spawner_think(num, node_array, ignoreWhileFallingBack)
Definition: spawner_shared.gsc:1619
‪go_to_node
‪function go_to_node(node, goal_type, optional_arrived_at_node_func)
Definition: spawner_shared.gsc:1061
‪init_serverfaceanim
‪function init_serverfaceanim()
Definition: serverfaceanim_shared.gsc:21
‪get_closest_player
‪function get_closest_player(org, str_team)
Definition: util_shared.gsc:1338
‪get_spawner_target_nodes
‪function get_spawner_target_nodes(group)
Definition: spawner_shared.gsc:1205
‪SPAWNFLAG_ACTOR_SCRIPTINFINITESPAWN
‪#define SPAWNFLAG_ACTOR_SCRIPTINFINITESPAWN
Definition: shared.gsh:54
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪remove_spawner_values
‪function remove_spawner_values()
Definition: spawner_shared.gsc:640