‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_spawning.gsc
Go to the documentation of this file.
1 #using scripts\shared\callbacks_shared;
2 #using scripts\shared\clientfield_shared;
3 #using scripts\shared\flag_shared;
4 #using scripts\shared\gameobjects_shared;
5 #using scripts\shared\system_shared;
6 #using scripts\shared\util_shared;
7 #using scripts\shared\weapons\_tacticalinsertion;
8 #using scripts\shared\abilities\gadgets\_gadget_resurrect;
9 
10 #insert scripts\shared\clientfields.gsh;
11 #insert scripts\shared\shared.gsh;
12 
13 #using scripts\mp\gametypes\_spawnlogic;
14 
15 #insert scripts\mp\gametypes\_spawning.gsh;
16 
17 #using scripts\mp\_util;
18 #using scripts\mp\killstreaks\_airsupport;
19 #using scripts\mp\gametypes\_dogtags;
20 
21 #namespace spawning;
22 
23 ‪REGISTER_SYSTEM( "spawning", &‪__init__, undefined )
24 
25 /*
26 _spawning.gsc
27 function Copyright (c) 2008 Certain Affinity, Inc. All rights reserved.
28 Friday April 25, 2008 3:59pm Stefan S.
29 
30 spawn_point[]:
31 --------------
32 "origin" - worldspace origin
33 "score" - desirability for spawning; calculated by applying influencers plus a small amount of randomness
34 
35 spawn_influencer[]:
36 -------------------
37 "type" - one of: "static", "friend", "enemy", "enemy_weapon", "vehicle", "projectile", "airstrike", "dead_friend", "game_mode", "dog"
38 "shape" - one of: "sphere", "cylinder", "pill", "cone", "box"
39 "forward" - worldspace forward vector
40 "up" - worldspace up vector
41 "origin" - worldspace origin
42 "radius" - for sphere, cylinder, pill, cone
43 "axis_length" - for cylinder, pill, cone
44 "width", "height", "depth" - for box
45 "score" - base influencer score
46 "score_curve" - one of: "constant", "linear" (1->0), "inverse_linear" (0->1), "negative_to_positive" (-1 -> +1)
47 
48 level.recently_deceased["<teamname>"][]:
49 --------------------------
50 deceased.angles - angles of the deceased player at TOD
51 deceased.origin - origin of the deceased player at TOD
52 function deceased.timeOfDeathMillis - GetTime() value (in milliseconds) at TOD
53 */
54 
55 /*QUAKED mp_uspawn_influencer (1 0 0) (-16 -16 -16) (16 16 16)
56 Static influencer for unified spawning system
57 "script_shape" Shape of this influencer. Supported shapes for Radiant-placed static influencers are "cylinder" and "sphere".
58 "radius" Radius of the influencer ( whether cylinder or sphere ).
59 "height" Height of the cylinder ( ignored for sphere shapes ).
60 "script_score" The maximum influence this influencer can have.
61 "script_score_curve" The shape of the score falloff as a function of the distance from the primary cylinder axis. Options are: "constant", "linear", "inverse_linear", "negative_to_positive"
62 "script_team" Make this influencer team-specific by specifying "axis" or "allies"
63 "script_gameobjectname" Gametypes for which the influencer is active (space-separated values), can be "[all_modes]" or combination of "dm", "hq", "iwar", "war", "twar", "sd", "dom"
64 "script_twar_flag" Used to associate this influencer with a specific twar flag
65 default:"script_shape" "cylinder"
66 default:"radius" "400"
67 default:"height" "100"
68 default:"script_score" "25"
69 default:"script_score_curve" "constant"
70 default:"script_team" "neutral"
71 default:"script_gameobjectname" "[all_modes]"
72 default:"script_twar_flag" "NONE"
73 */
74 
75 /*QUAKED mp_mobile_spawn (0.0 0.0 1.0) (-16 -16 0) (16 16 72)
76 Mobile spawn point. For use with the mobile spawn killstreak.*/
77 
78 /* ---------- includes */
79 
80 
81 
82 /* ---------- initialization */
83 
84 function ‪__init__()
85 {
86  level ‪init_spawn_system();
87 
88  level.influencers = [];
89  level.recently_deceased= [];
90 
91  foreach( team in level.teams )
92  {
93  level.recently_deceased[ team ]= ‪util::spawn_array_struct();
94  }
95 
97 
98  level.spawnProtectionTime = GetGametypeSetting( "spawnprotectiontime" );
99  level.spawnProtectionTimeMS = int ( ‪VAL( level.spawnProtectionTime, 0 ) * 1000 );
100  level.spawnTrapTriggerTime = GetGametypeSetting( "spawntraptriggertime" );
101 
102  return;
103 }
104 
106 {
107  level.spawnsystem = spawnstruct();
108  spawnsystem = level.spawnsystem;
109 
110  if (!IsDefined( spawnsystem.sideSwitching ))
111  spawnsystem.sideSwitching = 1;
112 
113  spawnsystem.objective_facing_bonus = 0.0;
114 
115  spawnsystem.iSPAWN_TEAMMASK = [];
116  spawnsystem.iSPAWN_TEAMMASK_FREE = ( 1 << 0 );
117  spawnsystem.iSPAWN_TEAMMASK["free"] = spawnsystem.iSPAWN_TEAMMASK_FREE;
118  all = spawnsystem.iSPAWN_TEAMMASK_FREE;
119  count = 1;
120  foreach( team in level.teams )
121  {
122  spawnsystem.iSPAWN_TEAMMASK[team] = ( 1 << count );
123  all = all | spawnsystem.iSPAWN_TEAMMASK[team];
124  count++;
125  }
126  spawnsystem.iSPAWN_TEAMMASK["all"] = all;
127 }
128 
129 
130 /*
131 =============
132 onPlayerConnect
133 
134 =============
135 */
137 {
138  level endon ( "game_ended" );
139 
140  self thread ‪onPlayerSpawned();
141  self thread ‪onTeamChange();
142  self thread ‪onGrenadeThrow();
143 }
144 
145 
146 /*
147 =============
148 onPlayerSpawned
149 
150 =============
151 */
153 {
154  self endon( "disconnect" );
155  level endon ( "game_ended" );
156 
157  for(;;)
158  {
159  self waittill( "spawned_player" );
160 
161  //println("SPAWN:onPlayerSpawned() - spawned player event");
162  self airsupport::clearMonitoredSpeed();
163 
164  self thread ‪initialSpawnProtection();
165 
166  // If radar permanently enabled for the player, enable it
167  if ( isdefined( self.pers["hasRadar"] ) && self.pers["hasRadar"] )
168  {
169  self.hasSpyplane = true;
170  }
171 
172  self ‪enable_player_influencers( true );
173  self thread ‪onDeath();
174  }
175 }
176 
177 /*
178 =============
179 onDeath
180 
181 Drops any carried object when the player dies
182 =============
183 */
184 function ‪onDeath()
185 {
186  self endon( "disconnect" );
187  level endon ( "game_ended" );
188 
189  self waittill ( "death" );
190 
191  self ‪enable_player_influencers( false );
192 
193  // creating on the level so the player does not clean it up
194  level ‪create_friendly_influencer( "friend_dead", self.origin, self.team );
195 }
196 
197 /*
198 =============
199 onTeamChange
200 
201 Changes influencer teams when player changes teams
202 =============
203 */
204 function ‪onTeamChange()
205 {
206  self endon( "disconnect" );
207  level endon ( "game_ended" );
208 
209  while(1)
210  {
211  self waittill ( "joined_team" );
212  self.lastspawnpoint = undefined;
215  }
216 }
217 
218 
219 /*
220 =============
221 onGrenadeThrow
222 
223 Creates an influencer on grenade
224 =============
225 */
227 {
228  self endon( "disconnect" );
229  level endon ( "game_ended" );
230 
231  while(1)
232  {
233  self waittill ( "grenade_fire", grenade, weapon );
234  level thread ‪create_grenade_influencers( self.pers["team"], weapon, grenade );
236  }
237 }
238 
240 {
241  if ( level.teambased )
242  {
243  team_mask = ‪util::getTeamMask( team );
244  }
245  else
246  {
247  team_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
248  }
249 
250  return team_mask;
251 }
252 
253 function ‪get_enemy_team_mask( team )
254 {
255  if ( level.teambased )
256  {
257  team_mask = ‪util::getOtherTeamsMask( team );
258  }
259  else
260  {
261  team_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
262  }
263 
264  return team_mask;
265 }
266 
267 function ‪create_influencer( ‪name, origin, team_mask )
268 {
269  self.influencers[‪name] = AddInfluencer( ‪name, origin, team_mask );
270 
271  self thread ‪watch_remove_influencer();
272 
273  return self.influencers[‪name];
274 }
275 
276 function ‪create_friendly_influencer( ‪name, origin, team )
277 {
278  team_mask = self ‪get_friendly_team_mask( team );
279 
280  self.influencersFriendly[‪name] = ‪create_influencer( ‪name, origin, team_mask );;
281 
282  return self.influencersFriendly[‪name];
283 }
284 
285 function ‪create_enemy_influencer( ‪name, origin, team )
286 {
287  team_mask = self ‪get_enemy_team_mask( team );
288 
289  self.influencersEnemy[‪name] = ‪create_influencer( ‪name, origin, team_mask );
290 
291  return self.influencersEnemy[‪name];
292 }
293 
294 function ‪create_entity_influencer( ‪name, team_mask )
295 {
296  self.influencers[‪name] = AddEntityInfluencer( ‪name, self, team_mask );
297 
298  self thread ‪watch_remove_influencer();
299 
300  return self.influencers[‪name] ;
301 }
302 
304 {
305  team_mask = self ‪get_friendly_team_mask( team );
306 
307  return self ‪create_entity_masked_friendly_influencer( ‪name, team_mask );
308 }
309 
311 {
312  team_mask = self ‪get_enemy_team_mask( team );
313 
314  return self ‪create_entity_masked_enemy_influencer( ‪name, team_mask );
315 }
316 
318 {
319  self.influencersFriendly[‪name] = self ‪create_entity_influencer( ‪name, team_mask );
320 
321  return self.influencersFriendly[‪name];
322 }
323 
325 {
326  self.influencersEnemy[‪name] = self ‪create_entity_influencer( ‪name, team_mask );
327 
328  return self.influencersEnemy[‪name];
329 }
330 
332 {
333  assert( !isdefined(self.influencers) );
334  assert( !isdefined(self.influencers) );
335 
336  if ( !level.teambased )
337  {
338  team_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
339  enemy_teams_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
340  }
341  else if ( isdefined( self.pers["team"] ) )
342  {
343  team = self.pers["team"];
344  team_mask = ‪util::getTeamMask( team );
345  enemy_teams_mask = ‪util::getOtherTeamsMask( team );
346  }
347  else
348  {
349  team_mask = 0;
350  enemy_teams_mask = 0;
351  }
352 
353  angles = self.angles;
354  origin = self.origin;
355  up = (0,0,1);
356  forward = (1,0,0);
357 
358  self.influencers = [];
359  self.friendlyInfluencers = [];
360  self.enemyInfluencers = [];
361 
362  self ‪create_entity_masked_enemy_influencer( "enemy", enemy_teams_mask );
363 
364  if ( level.teambased )
365  {
366  self ‪create_entity_masked_friendly_influencer( "friend", team_mask );
367  }
368 
369  if ( !isdefined(self.pers["team"]) || self.pers["team"] == "spectator" )
370  {
371  self ‪enable_influencers( false );
372  }
373 }
374 
375 // influencers created for every spawn
376 function ‪create_player_spawn_influencers( spawn_origin )
377 {
378  // create a negative influencer for the opposition here
379  level ‪create_enemy_influencer( "enemy_spawn", spawn_origin, self.pers["team"] );
380  level ‪create_friendly_influencer( "friendly_spawn", spawn_origin, self.pers["team"] );
381 }
382 
383 function ‪remove_influencer( to_be_removed )
384 {
385  foreach ( influencer in self.influencers )
386  {
387  if ( influencer == to_be_removed )
388  {
389  RemoveInfluencer( influencer );
390 
391  ArrayRemoveValue( self.influencers, influencer );
392  if ( IsDefined( self.influencersFriendly ) )
393  {
394  ArrayRemoveValue( self.influencersFriendly, influencer );
395  }
396  if ( IsDefined( self.influencersEnemy ) )
397  {
398  ArrayRemoveValue( self.influencersEnemy, influencer );
399  }
400  return;
401  }
402  }
403 }
404 
406 {
407  if ( isdefined( self.influencers ) )
408  {
409  foreach ( influencer in self.influencers )
410  {
411  RemoveInfluencer( influencer );
412  }
413  }
414 
415  self.influencers = [];
416  if ( IsDefined( self.influencersFriendly ) )
417  {
418  self.influencersFriendly = [];
419  }
420  if ( IsDefined( self.influencersEnemy ) )
421  {
422  self.influencersEnemy = [];
423  }
424 }
425 
427 {
428  self endon("death");
429 
430  self notify("watch_remove_influencer" );
431  self endon("watch_remove_influencer" );
432 
433  self waittill("influencer_removed", index );
434 
435  ArrayRemoveValue( self.influencers, index );
436  if ( IsDefined( self.influencersFriendly ) )
437  {
438  ArrayRemoveValue( self.influencersFriendly, index );
439  }
440  if ( IsDefined( self.influencersEnemy ) )
441  {
442  ArrayRemoveValue( self.influencersEnemy, index );
443  }
444 
445  self thread ‪watch_remove_influencer();
446 }
447 
448 
449 function ‪enable_influencers( enabled )
450 {
451  foreach ( influencer in self.influencers )
452  {
453  EnableInfluencer( influencer, enabled );
454  }
455 }
456 
457 function ‪enable_player_influencers( enabled )
458 {
459  if (!isdefined(self.influencers))
461 
462  self ‪enable_influencers( enabled );
463 }
464 
466 {
467  if ( !level.teambased )
468  {
469  team_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
470  enemy_teams_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
471  }
472  else
473  {
474  // for the player influencers we need to pay attention to the switchedsides
475  team = self.pers["team"];
476 
477  team_mask = ‪util::getTeamMask( team );
478  enemy_teams_mask = ‪util::getOtherTeamsMask( team );
479  }
480 
481  if ( isDefined( self.influencersFriendly ) )
482  {
483  foreach ( influencer in self.influencersFriendly )
484  {
485  SetInfluencerTeammask( influencer, team_mask );
486  }
487  }
488  if ( isDefined( self.influencersEnemy ) )
489  {
490  foreach ( influencer in self.influencersEnemy )
491  {
492  SetInfluencerTeammask( influencer, enemy_teams_mask );
493  }
494  }
495 }
496 
497 function ‪create_grenade_influencers( parent_team, weapon, grenade )
498 {
499  spawn_influencer = weapon.spawnInfluencer;
500 
501  if ( IsDefined( grenade.origin ) && spawn_influencer != "" )
502  {
503  if ( !level.teambased )
504  {
505  weapon_team_mask = level.spawnsystem.iSPAWN_TEAMMASK_FREE;
506  }
507  else
508  {
509  weapon_team_mask = ‪util::getOtherTeamsMask( parent_team );
510 
511  // if this is hardcore then we do not want to spawn infront of the weapon either
512  if ( level.friendlyfire )
513  {
514  weapon_team_mask |= ‪util::getTeamMask( parent_team );
515  }
516  }
517 
518  grenade ‪create_entity_masked_enemy_influencer( spawn_influencer, weapon_team_mask );
519  }
520 }
521 
523 {
524  staticInfluencerEnts = GetEntArray( "mp_uspawn_influencer", "classname" );
525 
526  for ( i = 0; i < staticInfluencerEnts.size; i++ )
527  {
528  staticInfluencerEnt = staticInfluencerEnts[ i ];
529 
530  ‪create_map_placed_influencer(staticInfluencerEnt);
531  }
532 }
533 
534 function ‪create_map_placed_influencer( influencer_entity )
535 {
536  influencer_id = -1;
537 
538  if (isdefined(influencer_entity.script_noteworty))
539  {
540  team_mask = ‪util::getTeamMask(influencer_entity.script_team);
541  level ‪create_enemy_influencer( influencer_entity.script_noteworty, influencer_entity.origin, team_mask );
542  }
543  else
544  {
545  assertmsg( "Radiant-placed spawn influencers require the 'script_noteworty' parameter" );
546  }
547 
548  return influencer_id;
549 }
550 
552 {
553  // force spawn points to get precached
554  foreach( team in level.teams )
555  {
556  ‪gatherSpawnPoints( team );
557  }
558 
560 
561  if ( level.teambased )
562  {
563  foreach( team in level.teams )
564  {
565  ‪addSpawnPoints( team, level.player_spawn_points[ team ], ‪SPL_NORMAL );
566  EnableSpawnPointList( ‪SPL_NORMAL, ‪util::getTeamMask( team ) );
567  }
568  }
569  else
570  {
571  foreach( team in level.teams )
572  {
573  ‪addSpawnPoints( "free", level.player_spawn_points[ team ], ‪SPL_NORMAL );
574  EnableSpawnPointList( ‪SPL_NORMAL, ‪util::getTeamMask( team ) );
575  }
576  }
577 
578  level.spawnAllMins = level.spawnMins;
579  level.spawnAllMaxs = level.spawnMaxs;
580 
581  // this will remove all spawnpoints for the other gametypes which are not used
583 }
584 
586 {
587  ‪clearSpawnPoints( SPL_FALLBACK );
588 
589  if ( !IsDefined( level.player_fallback_points ) )
590  return;
591 
592  if ( level.teambased )
593  {
594  foreach( team in level.teams )
595  {
596  ‪addSpawnPoints( team, level.player_fallback_points[ team ], SPL_FALLBACK );
597  }
598  }
599  else
600  {
601  foreach( team in level.teams )
602  {
603  ‪addSpawnPoints( "free", level.player_fallback_points[ team ], SPL_FALLBACK );
604  }
605  }
606 }
607 
608 function ‪add_fallback_spawnpoints( team, point_class )
609 {
610  if ( !IsDefined( level.player_fallback_points ) )
611  {
612  level.player_fallback_points = [];
613 
614  foreach ( level_team in level.teams )
615  {
616  level.player_fallback_points[level_team] = [];
617  }
618  }
619 
621 
622  spawnpoints = ‪spawnlogic::get_spawnpoint_array( point_class );
623 
624  if ( IsDefined( level.allowedGameObjects ) && level.convert_spawns_to_structs )
625  {
626  for ( i = spawnpoints.size - 1; i >= 0; i-- )
627  {
628  if (!‪gameobjects::entity_is_allowed(spawnpoints[i], level.allowedGameObjects))
629  {
630  spawnpoints[i] = undefined;
631  }
632  }
633  ArrayRemoveValue( spawnpoints, undefined );
634  }
635 
636  level.player_fallback_points[team] = spawnpoints;
637  DisableSpawnPointList( SPL_FALLBACK, ‪util::getTeamMask( team ) );
638 }
639 
640 function ‪is_spawn_trapped( team )
641 {
642  // this feature is only on for public match
643  if ( !level.rankedMatch )
644  return false;
645 
646  if ( isDefined( level.aliveTimesAverage[team] ) && ( level.aliveTimesAverage[team] != 0 ) && ( level.aliveTimesAverage[team] < (level.spawnTrapTriggerTime * 1000) ) )
647  return true;
648 
649  return false;
650 }
651 
652 function ‪use_start_spawns(predictedSpawn)
653 {
654  if ( level.alwaysUseStartSpawns )
655  return true;
656 
657  if ( !level.useStartSpawns )
658  return false;
659 
660  // if we have more players then start spawns dont use them
661  if( level.teambased )
662  {
663  spawnteam = self.pers["team"];
664 
665  if ( (level.alivePlayers[spawnteam].size + level.spawningPlayers[self.team].size) >= level.spawn_start[spawnteam].size )
666  {
667  if ( !predictedSpawn )
668  {
669  level.useStartSpawns = false;
670  }
671  return false;
672  }
673  }
674  else if ( (level.alivePlayers["free"].size + level.spawningPlayers["free"].size) >= level.spawn_start.size )
675  {
676  if ( !predictedSpawn )
677  {
678  level.useStartSpawns = false;
679  }
680  return false;
681  }
682 
683  return true;
684 }
685 /* ---------- spawn_point */
686 
687 //void - self= player entity for the player who is spawning
688 function ‪onSpawnPlayer(predictedSpawn)
689 {
690 
691  if (!isdefined( predictedSpawn ))
692  predictedSpawn = false;
693 
694  spawnOverride = self ‪tacticalinsertion::overrideSpawn(predictedSpawn);
695  spawnResurrect = self ‪resurrect::overrideSpawn(predictedSpawn);
696 
697  spawn_origin = undefined;
698  spawn_angles = undefined;
699 
700  if ( spawnResurrect )
701  {
702  spawn_origin = self.resurrect_origin;
703  spawn_angles = self.resurrect_angles;
704  }
705  else if ( spawnOverride )
706  {
707  if (predictedSpawn && isdefined( self.tacticalInsertion ))
708  {
709  // get the tactical insertion position
710  // send this point as a message to the client
711  self predictSpawnPoint( self.tacticalInsertion.origin, self.tacticalInsertion.angles );
712  // println("predicted spawn [TI] - " + self.tacticalInsertion.origin );
713  }
714  return;
715  }
716  else if ( self ‪use_start_spawns( predictedSpawn ) )
717  {
718  if ( !predictedSpawn )
719  {
720  if( level.teambased )
721  {
722  level.spawningPlayers[self.team][level.spawningPlayers[self.team].size] = self;
723  }
724  else
725  {
726  level.spawningPlayers["free"][level.spawningPlayers["free"].size] = self;
727  }
728  }
729 
730  if( level.teambased )
731  {
732  spawnteam = self.pers["team"];
733  if ( game["switchedsides"] )
734  spawnteam = ‪util::getOtherTeam( spawnteam );
735 
736  spawnpoint = ‪spawnlogic::get_spawnpoint_random(level.spawn_start[spawnteam], predictedSpawn);
737  }
738  else
739  {
740  spawnpoint = ‪spawnlogic::get_spawnpoint_random(level.spawn_start, predictedSpawn);
741  }
742 
743  if (isdefined(spawnpoint))
744  {
745  spawn_origin = spawnpoint.origin;
746  spawn_angles = spawnpoint.angles;
747  }
748  }
749  else
750  {
751  // find the most desireable spawn point, and spawn there
752  spawn_point = ‪getSpawnPoint(self, predictedSpawn);
753 
754  if (isdefined(spawn_point))
755  {
756  spawn_origin = spawn_point["origin"];
757  spawn_angles = spawn_point["angles"];
758  }
759  }
760 
761  if ( !isdefined(spawn_origin) )
762  {
763  /# println("ERROR: unable to locate a usable spawn point for player"); #/
765  }
766 
767  if ( predictedSpawn )
768  {
769  self predictSpawnPoint( spawn_origin, spawn_angles );
770  }
771  else
772  {
773  self ‪spawn( spawn_origin, spawn_angles );
774 
775  self.lastspawntime = gettime();
776  self ‪enable_player_influencers( true );
777 
778  // on normal spawns create the spawned influencers
779  if ( !spawnResurrect && !spawnOverride )
780  {
781  self ‪create_player_spawn_influencers( spawn_origin );
782  }
783  }
784 
785  if( ‪IS_TRUE( level.droppedTagRespawn ) )
787 }
788 
789 // spawnPoint: .origin, .angles
791  player_entity,
792  predictedSpawn )
793 {
794 
795  if (!isdefined( predictedSpawn ))
796  predictedSpawn = false;
797 
798  if (level.teambased )
799  {
800  point_team = player_entity.pers["team"];
801  influencer_team = player_entity.pers["team"];
802  }
803  else
804  {
805  point_team = "free";
806  influencer_team = "free";
807  }
808 
809  spawn_trapped = ‪is_spawn_trapped(point_team);
810 
811  if (level.teambased && isdefined(game["switchedsides"]) && game["switchedsides"] && level.spawnsystem.sideSwitching)
812  {
813  point_team = ‪util::getOtherTeam(point_team);
814  }
815 
816  if ( spawn_trapped )
817  {
818  EnableSpawnPointList( SPL_FALLBACK, ‪util::getTeamMask( point_team ) );
819  }
820  else
821  {
822  DisableSpawnPointList( SPL_FALLBACK, ‪util::getTeamMask( point_team ) );
823  }
824 
825  best_spawn = ‪get_best_spawnpoint( point_team, influencer_team, player_entity, predictedSpawn );
826 
827  if (!predictedSpawn)
828  {
829  player_entity.last_spawn_origin = best_spawn["origin"];
830  }
831 
832  return best_spawn;
833 }
834 
835 function ‪get_best_spawnpoint( point_team, influencer_team, player, predictedSpawn )
836 {
837  if (level.teambased )
838  {
839  vis_team_mask = ‪util::getOtherTeamsMask( player.pers["team"] );
840  }
841  else
842  {
843  vis_team_mask = level.spawnsystem.iSPAWN_TEAMMASK["all"];
844  }
845 
846  spawn_point = GetBestSpawnPoint( point_team, influencer_team, vis_team_mask, player, predictedSpawn );
847 
848  return spawn_point;
849 }
850 
851 function ‪gatherSpawnPoints( player_team )
852 {
853  // use cached spawn points when they are available
854  if ( !isdefined( level.player_spawn_points ) )
855  {
856  level.player_spawn_points = [];
857  }
858  else if ( isdefined( level.player_spawn_points[ player_team ] ) )
859  {
860  return;
861  }
862 
863  spawn_entities = ‪spawnlogic::get_team_spawnpoints(player_team);
864  if ( !isdefined(spawn_entities))
865  {
866  spawn_entities = [];
867  }
868 
869  level.player_spawn_points[player_team] = spawn_entities;
870 }
871 
872 /* ---------- private code */
873 
874 /* ---------- spawn_influencer */
875 
876 // These functions add the new influencers to the provided influencers array.
877 
878 function ‪is_hardcore()
879 {
880  return isdefined( level.hardcoreMode )
881  && level.hardcoreMode;
882 }
883 
885  team1,
886  team2)
887 {
888  // If either is undefined, then we don't know; assume they are enemies.
889  // If the game is straight-up deathmatch, everyone is enemies (regardless of their assigned teams).
890  if ( !isdefined( team1 ) || !isdefined( team2 ) || (level.gameType=="dm"))
891  return true;
892 
893  return team1 != "neutral"
894  && team2 != "neutral"
895  && team1 != team2;
896 }
897 
898 // Really would like to get rid of these gametype specific references to spawn points
899 // from this file, however right now there is no way of getting a array of
900 // all spawnpoints in a level. They have to be asked for by classname.
902 {
903  if( level.convert_spawns_to_structs )
904  return;
905 
906  spawn_entity_types = [];
907 
908  // TODO MTEAM - update this funcion for multiteam and just for all the new spawnpoints
909 
910  // dm
911  spawn_entity_types[ spawn_entity_types.size ] = "mp_dm_spawn";
912 
913  // tdm
914  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_allies_start";
915  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_axis_start";
916  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team1_start";
917  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team2_start";
918  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team3_start";
919  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team4_start";
920  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team5_start";
921  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn_team6_start";
922  spawn_entity_types[ spawn_entity_types.size ] = "mp_tdm_spawn";
923 
924  // ctf
925  spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_allies_start";
926  spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_axis_start";
927  spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_allies";
928  spawn_entity_types[ spawn_entity_types.size ] = "mp_ctf_spawn_axis";
929 
930  // dom
931  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_allies_start";
932  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_axis_start";
933  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_flag_a";
934  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_flag_b";
935  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn_flag_c";
936  spawn_entity_types[ spawn_entity_types.size ] = "mp_dom_spawn";
937 
938  // koth
939  // uses TDM spawns
940 
941  // sab
942  spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_allies_start";
943  spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_axis_start";
944  spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_allies";
945  spawn_entity_types[ spawn_entity_types.size ] = "mp_sab_spawn_axis";
946 
947  // sd
948  spawn_entity_types[ spawn_entity_types.size ] = "mp_sd_spawn_attacker";
949  spawn_entity_types[ spawn_entity_types.size ] = "mp_sd_spawn_defender";
950 
951  // dem
952  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_attacker_start";
953  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_defender_start";
954  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_attackerOT_start";
955  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_defenderOT_start";
956  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_attacker";
957  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_defender";
958  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_defender_a";
959  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_defender_b";
960  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_attacker_remove_a";
961  spawn_entity_types[ spawn_entity_types.size ] = "mp_dem_spawn_attacker_remove_b";
962 
963 
964  for ( i = 0; i < spawn_entity_types.size; i++ )
965  {
966  if ( ‪spawn_point_class_name_being_used( spawn_entity_types[i] ) )
967  continue;
968 
969  spawnpoints = ‪spawnlogic::get_spawnpoint_array( spawn_entity_types[i] );
970 
971  ‪delete_all_spawns( spawnpoints );
972  }
973 }
974 
975 function ‪delete_all_spawns( spawnpoints )
976 {
977  for ( i = 0; i < spawnpoints.size; i++ )
978  {
979  spawnpoints[i] delete();
980  }
981 }
982 
984 {
985  if ( !isdefined( level.spawn_point_class_names ) )
986  {
987  return false;
988  }
989 
990  for ( i = 0; i < level.spawn_point_class_names.size; i++ )
991  {
992  if ( level.spawn_point_class_names[i] == ‪name )
993  {
994  return true;
995  }
996  }
997 
998  return false;
999 }
1000 
1001 // callback to process spawn point changes from Radiant Live Update
1003 {
1004  // rebuild the legacy spawn points
1005  foreach( team in level.teams )
1006  {
1008  }
1009 
1010  // make sure the list gets completely rebuilt
1011  level.player_spawn_points = undefined;
1013 }
1014 
1016 {
1017  self endon( "death" );
1018  self endon( "disconnect" );
1019 
1020  self thread ‪airsupport::monitorSpeed( level.spawnProtectionTime );
1021 
1022  if ( !isdefined( level.spawnProtectionTime ) || level.spawnProtectionTime == 0 )
1023  {
1024  return;
1025  }
1026 
1027  self.specialty_nottargetedbyairsupport = true;
1029  self.ignoreme = true;
1030  wait level.spawnProtectionTime;
1032  self.specialty_nottargetedbyairsupport = undefined;
1033  self.ignoreme = false;
1034 }
1035 
1036 function ‪getTeamStartSpawnName( team, spawnpointNameBase )
1037 {
1038  spawn_point_team_name = team;
1039 
1040  if ( !level.multiTeam && game["switchedsides"] )
1041  spawn_point_team_name = ‪util::getOtherTeam( team );
1042 
1043  // for multi-team using slightly different start spawns for axis and allies
1044  if ( level.multiTeam )
1045  {
1046  if ( team == "axis" )
1047  spawn_point_team_name = "team1";
1048  else if ( team == "allies" )
1049  spawn_point_team_name = "team2";
1050 
1051  // for multi-round rotate the teams through all the start points
1052  if ( !‪util::isOneRound() )
1053  {
1054  // to zero based
1055  number = int( getsubstr( spawn_point_team_name, 4, 5) ) - 1;
1056 
1057  // back to one based
1058  number = (( number + game[ "roundsplayed" ]) % level.teams.size) + 1;
1059 
1060  spawn_point_team_name = "team" + number;
1061  }
1062  }
1063 
1064  return spawnpointNameBase + "_" + spawn_point_team_name + "_start" ;
1065 }
1066 
1067 function ‪getTDMStartSpawnName( team )
1068 {
1069  return ‪getTeamStartSpawnName( team, "mp_tdm_spawn" );
1070 }
‪enable_influencers
‪function enable_influencers(enabled)
Definition: _spawning.gsc:449
‪CLIENT_FIELD_KILLSTREAK_SPAWN_PROTECTION
‪#define CLIENT_FIELD_KILLSTREAK_SPAWN_PROTECTION
Definition: clientfields.gsh:10
‪getTeamMask
‪function getTeamMask(team)
Definition: _util.gsc:373
‪onTeamChange
‪function onTeamChange()
Definition: _spawning.gsc:204
‪isOneRound
‪function isOneRound()
Definition: util_shared.gsc:3497
‪updateAllSpawnPoints
‪function updateAllSpawnPoints()
Definition: _spawning.gsc:551
‪create_enemy_influencer
‪function create_enemy_influencer(name, origin, team)
Definition: _spawning.gsc:285
‪onPlayerConnect
‪function onPlayerConnect()
Definition: _spawning.gsc:136
‪gatherSpawnPoints
‪function gatherSpawnPoints(player_team)
Definition: _spawning.gsc:851
‪get_team_spawnpoints
‪function get_team_spawnpoints(team)
Definition: _spawnlogic.gsc:29
‪monitorSpeed
‪function monitorSpeed(spawnProtectionTime)
Definition: _airsupport.gsc:1240
‪watch_remove_influencer
‪function watch_remove_influencer()
Definition: _spawning.gsc:426
‪getSpawnPoint
‪function getSpawnPoint(player_entity, predictedSpawn)
Definition: _spawning.gsc:790
‪onDeath
‪function onDeath()
Definition: _spawning.gsc:184
‪get_best_spawnpoint
‪function get_best_spawnpoint(point_team, influencer_team, player, predictedSpawn)
Definition: _spawning.gsc:835
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪delete_all_spawns
‪function delete_all_spawns(spawnpoints)
Definition: _spawning.gsc:975
‪create_map_placed_influencer
‪function create_map_placed_influencer(influencer_entity)
Definition: _spawning.gsc:534
‪create_friendly_influencer
‪function create_friendly_influencer(name, origin, team)
Definition: _spawning.gsc:276
‪create_influencer
‪function create_influencer(name, origin, team_mask)
Definition: _spawning.gsc:267
‪spawn
‪function spawn(v_origin=(0, 0, 0), v_angles=(0, 0, 0))
Definition: struct.csc:23
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪remove_unused_spawn_entities
‪function remove_unused_spawn_entities()
Definition: _spawning.gsc:901
‪create_map_placed_influencers
‪function create_map_placed_influencers()
Definition: _spawning.gsc:522
‪create_entity_friendly_influencer
‪function create_entity_friendly_influencer(name, team)
Definition: _spawning.gsc:303
‪getOtherTeam
‪function getOtherTeam(team)
Definition: _util.gsc:360
‪add_fallback_spawnpoints
‪function add_fallback_spawnpoints(team, point_class)
Definition: _spawning.gsc:608
‪spawn_array_struct
‪function spawn_array_struct()
Definition: util_shared.gsc:2896
‪rebuild_spawn_points
‪function rebuild_spawn_points(team)
Definition: _spawnlogic.gsc:21
‪clearSpawnPoints
‪function clearSpawnPoints()
Definition: _spawnlogic.gsc:120
‪player_influencers_set_team
‪function player_influencers_set_team()
Definition: _spawning.gsc:465
‪overrideSpawn
‪function overrideSpawn(isPredictedSpawn)
Definition: _gadget_resurrect.gsc:251
‪create_entity_enemy_influencer
‪function create_entity_enemy_influencer(name, team)
Definition: _spawning.gsc:310
‪get_spawnpoint_array
‪function get_spawnpoint_array(classname)
Definition: _spawnlogic.gsc:27
‪CodeCallback_UpdateSpawnPoints
‪function CodeCallback_UpdateSpawnPoints()
Definition: _spawning.gsc:1002
‪is_spawn_trapped
‪function is_spawn_trapped(team)
Definition: _spawning.gsc:640
‪use_start_spawns
‪function use_start_spawns(predictedSpawn)
Definition: _spawning.gsc:652
‪remove_influencers
‪function remove_influencers()
Definition: _spawning.gsc:405
‪create_entity_masked_enemy_influencer
‪function create_entity_masked_enemy_influencer(name, team_mask)
Definition: _spawning.gsc:324
‪is_hardcore
‪function is_hardcore()
Definition: _spawning.gsc:878
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪add_spawn_point_classname
‪function add_spawn_point_classname(spawnPointClassName)
Definition: _spawnlogic.gsc:24
‪abort_level
‪function abort_level()
Definition: callbacks_shared.gsc:1018
‪create_player_influencers
‪function create_player_influencers()
Definition: _spawning.gsc:331
‪onSpawnPlayer
‪function onSpawnPlayer(predictedSpawn)
Definition: _spawning.gsc:688
‪create_entity_masked_friendly_influencer
‪function create_entity_masked_friendly_influencer(name, team_mask)
Definition: _spawning.gsc:317
‪on_spawn_player
‪function on_spawn_player()
Definition: _dogtags.gsc:267
‪entity_is_allowed
‪function entity_is_allowed(entity, allowed_game_modes)
Definition: gameobjects_shared.gsc:83
‪getTDMStartSpawnName
‪function getTDMStartSpawnName(team)
Definition: _spawning.gsc:1067
‪SPL_NORMAL
‪#define SPL_NORMAL
Definition: _spawning.gsh:2
‪getOtherTeamsMask
‪function getOtherTeamsMask(skip_team)
Definition: _util.gsc:382
‪init_spawn_system
‪function init_spawn_system()
Definition: _spawning.gsc:105
‪enable_player_influencers
‪function enable_player_influencers(enabled)
Definition: _spawning.gsc:457
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪spawn_point_class_name_being_used
‪function spawn_point_class_name_being_used(name)
Definition: _spawning.gsc:983
‪__init__
‪function __init__()
Definition: _spawning.gsc:84
‪initialSpawnProtection
‪function initialSpawnProtection()
Definition: _spawning.gsc:1015
‪get_friendly_team_mask
‪function get_friendly_team_mask(team)
Definition: _spawning.gsc:239
‪get_enemy_team_mask
‪function get_enemy_team_mask(team)
Definition: _spawning.gsc:253
‪get_spawnpoint_random
‪function get_spawnpoint_random(spawnpoints, predictedSpawn, isIntermissionSpawn=false)
Definition: _spawnlogic.gsc:33
‪create_player_spawn_influencers
‪function create_player_spawn_influencers(spawn_origin)
Definition: _spawning.gsc:376
‪remove_influencer
‪function remove_influencer(to_be_removed)
Definition: _spawning.gsc:383
‪onGrenadeThrow
‪function onGrenadeThrow()
Definition: _spawning.gsc:226
‪getTeamStartSpawnName
‪function getTeamStartSpawnName(team, spawnpointNameBase)
Definition: _spawning.gsc:1036
‪create_grenade_influencers
‪function create_grenade_influencers(parent_team, weapon, grenade)
Definition: _spawning.gsc:497
‪name
‪class GroundFx name
‪create_entity_influencer
‪function create_entity_influencer(name, team_mask)
Definition: _spawning.gsc:294
‪update_fallback_spawnpoints
‪function update_fallback_spawnpoints()
Definition: _spawning.gsc:585
‪onPlayerSpawned
‪function onPlayerSpawned()
Definition: _spawning.gsc:152
‪on_connecting
‪function on_connecting(func, obj)
Definition: callbacks_shared.gsc:146
‪addSpawnPoints
‪function addSpawnPoints(team, spawnPointName)
Definition: _spawnlogic.gsc:130
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪teams_have_enmity
‪function teams_have_enmity(team1, team2)
Definition: _spawning.gsc:884