‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_battlechatter.gsc
Go to the documentation of this file.
1 #insert scripts\shared\shared.gsh;
2 #insert scripts\shared\version.gsh;
3 
4 #using scripts\codescripts\struct;
5 #using scripts\shared\abilities\gadgets\_gadget_camo;
6 #using scripts\shared\array_shared;
7 #using scripts\shared\callbacks_shared;
8 #using scripts\shared\clientfield_shared;
9 #using scripts\shared\killstreaks_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\util_shared;
12 
13 #using scripts\mp\gametypes\_dev;
14 
15 #using scripts\mp\gametypes\_globallogic;
16 #using scripts\mp\gametypes\_globallogic_audio;
17 
18 #using scripts\mp\killstreaks\_killstreaks;
19 
20 #namespace battlechatter;
21 
22 ‪REGISTER_SYSTEM( "battlechatter", &‪__init__, undefined )
23 
24 #define INCOMING_ALERT "incoming_alert"
25 #define INCOMING_DELAY "incoming_delay"
26 #define KILL_DIALOG "kill_dialog"
27 
28 #define DIALOG_FLAG_TEAM 1
29 #define DIALOG_FLAG_ALL 2
30 #define DIALOG_FLAG_INTERRUPT 4
31 #define DIALOG_FLAG_UNDERWATER 8
32 #define DIALOG_FLAG_EXERT 16 // Plays when VO is turned off
33 #define DIALOG_FLAG_GADGET_READY 32
34 #define DIALOG_FLAG_STOLEN_GADGET_READY 64
35 
36 #define DIALOG_FLAGS_SHOUT 6 // ALL + INTERRUPT
37 #define DIALOG_FLAGS_PAIN 30 // ALL + INTERRUPT + UNDERWATER + EXERT
38 
39 #define STOLEN_GADGET_READY_LINE_COUNT 4
40 
41 #define VOICE_TAG "J_Head"
42 
43 #define NUM_BOOSTS 4
44 #define PLAY_BOOST "play_boost"
45 #define BOOST_START 1
46 #define BOOST_RESPONSE 2
47 
48 function ‪__init__()
49 {
53 
54  level.heroPlayDialog = &‪play_dialog;
55  level.playGadgetReady = &‪play_gadget_ready;
56  level.playGadgetActivate = &‪play_gadget_activate;
57  level.playGadgetSuccess = &‪play_gadget_success;
58  level.playPromotionReaction = &‪play_promotion_reaction;
59  level.playThrowHatchet = &‪play_throw_hatchet;
60 
61  level.bcSounds = [];
62  level.bcSounds[ ‪INCOMING_ALERT ] = [];
63  level.bcSounds[ ‪INCOMING_ALERT ][ "frag_grenade" ] = "incomingFrag";
64  level.bcSounds[ ‪INCOMING_ALERT ][ "incendiary_grenade" ] = "incomingIncendiary";
65  level.bcSounds[ ‪INCOMING_ALERT ][ "sticky_grenade" ] = "incomingSemtex";
66  level.bcSounds[ ‪INCOMING_ALERT ][ "launcher_standard" ] = "threatRpg";
67 
68 
69  level.bcSounds[ ‪INCOMING_DELAY ] = [];
70  level.bcSounds[ ‪INCOMING_DELAY ][ "frag_grenade" ] = "fragGrenadeDelay";
71  level.bcSounds[ ‪INCOMING_DELAY ][ "incendiary_grenade" ] = "incendiaryGrenadeDelay";
72  level.bcSounds[ ‪INCOMING_ALERT ][ "sticky_grenade" ] = "semtexDelay";
73  level.bcSounds[ ‪INCOMING_DELAY ][ "launcher_standard" ] = "missileDelay";
74 
75  level.bcSounds[ ‪KILL_DIALOG ] = [];
76  level.bcSounds[ ‪KILL_DIALOG ][ "assassin" ] = "killSpectre";
77  level.bcSounds[ ‪KILL_DIALOG ][ "grenadier" ] = "killGrenadier";
78  level.bcSounds[ ‪KILL_DIALOG ][ "outrider" ] = "killOutrider";
79  level.bcSounds[ ‪KILL_DIALOG ][ "prophet" ] = "killTechnomancer";
80  level.bcSounds[ ‪KILL_DIALOG ][ "pyro" ] = "killFirebreak";
81  level.bcSounds[ ‪KILL_DIALOG ][ "reaper" ] = "killReaper";
82  level.bcSounds[ ‪KILL_DIALOG ][ "ruin" ] = "killMercenary";
83  level.bcSounds[ ‪KILL_DIALOG ][ "seraph" ] = "killEnforcer";
84  level.bcSounds[ ‪KILL_DIALOG ][ "trapper" ] = "killTrapper";
85  level.bcSounds[ ‪KILL_DIALOG ][ "blackjack" ] = "killBlackjack";
86 
87  if ( level.teambased && !isdefined( game["boostPlayersPicked"] ) )
88  {
89  game["boostPlayersPicked"] = [];
90  foreach ( team in level.teams )
91  {
92  game["boostPlayersPicked"][ team ] = false;
93  }
94  }
95 
96  level.allowbattlechatter = GetGametypeSetting( "allowBattleChatter" );
97 
98  ‪clientfield::register( "world", "boost_number", ‪VERSION_SHIP, 2, "int" );
99  ‪clientfield::register( "allplayers", ‪PLAY_BOOST, ‪VERSION_SHIP, 2, "int" );
100 
101  level thread ‪pick_boost_number();
102 
103  playerDialogBundles = ‪struct::get_script_bundles( "mpdialog_player" );
104  foreach( bundle in playerDialogBundles )
105  {
106  ‪count_keys( bundle, "killGeneric" );
107  ‪count_keys( bundle, "killSniper" );
108 
109  ‪count_keys( bundle, "killSpectre" );
110  ‪count_keys( bundle, "killGrenadier");
111  ‪count_keys( bundle, "killOutrider" );
112  ‪count_keys( bundle, "killTechnomancer" );
113  ‪count_keys( bundle, "killFirebreak" );
114  ‪count_keys( bundle, "killReaper" );
115  ‪count_keys( bundle, "killMercenary" );
116  ‪count_keys( bundle, "killEnforcer" );
117  ‪count_keys( bundle, "killTrapper" );
118  ‪count_keys( bundle, "killBlackjack" );
119  }
120 
121  level.allowSpecialistDialog = ‪mpdialog_value( "enableHeroDialog", false ) && level.allowBattlechatter;
122  level.playStartConversation = ‪mpdialog_value( "enableConversation", false ) && level.allowBattlechatter;
123 }
124 
126 {
127  // Don't set client fields on the first frame
128  wait( 5 );
129 
130  level ‪clientfield::set( "boost_number", RandomInt( ‪NUM_BOOSTS ) );
131 }
132 
134 {
135  self endon( "disconnect" );
136 
137  if ( level.teambased )
138  {
139  if ( self.team == "allies" )
140  {
141  self ‪set_blops_dialog();
142  }
143  else
144  {
145  self ‪set_cdp_dialog();
146  }
147  }
148  else
149  {
150  if ( randomIntRange( 0, 2 ) )
151  {
152  self ‪set_blops_dialog();
153  }
154  else
155  {
156  self ‪set_cdp_dialog();
157  }
158  }
159 
161 
162  if ( level.disablePrematchMessages === true )
163  {
164  return;
165  }
166 
167  if ( ‪IS_TRUE( level.inPrematchPeriod ) && !‪IS_TRUE( self.pers["playedGameMode"] ) && isdefined( level.leaderDialog ) )
168  {
169  if( level.hardcoreMode )
170  self ‪globallogic_audio::leader_dialog_on_player( level.leaderDialog.startHcGameDialog, undefined, undefined, undefined, true );
171  else
172  self ‪globallogic_audio::leader_dialog_on_player( level.leaderDialog.startGameDialog, undefined, undefined, undefined, true );
173 
174  self.pers["playedGameMode"] = true;
175  }
176 }
177 
179 {
180  self.pers["mptaacom"] = "blops_taacom";
181  self.pers["mpcommander"] = "blops_commander";
182 }
183 
185 {
186  self.pers["mptaacom"] = "cdp_taacom";
187  self.pers["mpcommander"] = "cdp_commander";
188 }
189 
191 {
192  self ‪reset_dialog_fields();
193 }
194 
196 {
197  self ‪reset_dialog_fields();
198 
199  // help players be stealthy in splitscreen by not announcing their intentions
200  if ( level.splitscreen )
201  {
202  return;
203  }
204 
205  self thread ‪water_vox();
206 
207  self thread ‪grenade_tracking();
208  self thread ‪missile_tracking();
209  self thread ‪sticky_grenade_tracking();
210 
211  // Don't bother with these in non-team games
212  if ( level.teambased )
213  {
214  self thread ‪enemy_threat();
215  self thread ‪check_boost_start_conversation();
216  }
217 }
218 
220 {
221  self.enemyThreatTime = 0;
222  self.heartbeatsnd = false;
223 
224  self.soundMod = "player";
225 
226  self.voxUnderwaterTime = 0;
227  self.voxEmergeBreath = false;
228  self.voxDrowning = false;
229 
230  self.pilotisSpeaking = false;
231  self.playingDialog = false;
232  self.playingGadgetReadyDialog = false;
233 
234  self.playedGadgetSuccess = true;
235 }
236 
237 function ‪dialog_chance( chanceKey )
238 {
239  dialogChance = ‪mpdialog_value( chanceKey );
240 
241  if ( !isdefined( dialogChance ) || dialogChance <= 0 )
242  {
243  return false;
244  }
245  else if ( dialogChance >= 100 )
246  {
247  return true;
248  }
249 
250  return ( RandomInt( 100 ) < dialogChance );
251 }
252 
253 function ‪mpdialog_value( mpdialogKey, defaultValue )
254 {
255  if ( !isdefined( mpdialogKey ) )
256  {
257  return defaultValue;
258  }
259 
260  mpdialog = ‪struct::get_script_bundle( "mpdialog", "mpdialog_default" );
261 
262  if ( !isdefined( mpdialog ) )
263  {
264  return defaultValue;
265  }
266 
267  structValue = GetStructField( mpdialog, mpdialogKey );
268 
269  if ( !isdefined( structValue ) )
270  {
271  return defaultValue;
272  }
273 
274  return structValue;
275 }
276 
277 function ‪water_vox()
278 {
279  self endon ( "death" );
280  level endon ( "game_ended" );
281 
282  while(1)
283  {
284  interval = ‪mpdialog_value( "underwaterInterval", ‪SERVER_FRAME );
285 
286  if ( interval <= 0 )
287  {
288  assert( interval > 0, "underWaterInterval mpdialog scriptbundle value must be greater than 0" );
289  return;
290  }
291 
292  wait ( interval );
293 
294  if ( self IsPlayerUnderwater() )
295  {
296  if ( !self.voxUnderwaterTime && !self.voxEmergeBreath )
297  {
298  self StopSounds();
299  self.voxUnderwaterTime = GetTime();
300  }
301  else if ( self.voxUnderwaterTime )
302  {
303  if ( GetTime() > self.voxUnderwaterTime + ‪mpdialog_value( "underwaterBreathTime", 0 ) * 1000 )
304  {
305  self.voxUnderwaterTime = 0;
306  self.voxEmergeBreath = true;
307  }
308  }
309  }
310  else
311  {
312  if ( self.voxDrowning )
313  {
314  self thread ‪play_dialog( "exertEmergeGasp", ‪DIALOG_FLAG_INTERRUPT | ‪DIALOG_FLAG_EXERT, ‪mpdialog_value( "playerExertBuffer", 0 ) );
315 
316  self.voxDrowning = false;
317  self.voxEmergeBreath = false;
318  }
319  else if ( self.voxEmergeBreath )
320  {
321  self thread ‪play_dialog( "exertEmergeBreath", ‪DIALOG_FLAG_INTERRUPT | ‪DIALOG_FLAG_EXERT, ‪mpdialog_value( "playerExertBuffer", 0 ) );
322  self.voxEmergeBreath = false;
323  }
324  }
325  }
326 }
327 
328 
329 function ‪pain_vox(meansofDeath)
330 {
331  if( ‪dialog_chance( "smallPainChance" ) )
332  {
333  if( meansOfDeath == "MOD_DROWN" )
334  {
335  dialogKey = "exertPainDrowning";
336  self.voxDrowning = true;
337  }
338  else if ( meansofDeath == "MOD_FALLING" )
339  {
340  dialogKey = "exertPainFalling";
341  }
342  else if ( self IsPlayerUnderwater() )
343  {
344  dialogKey = "exertPainUnderwater";
345  }
346  else
347  {
348  dialogKey = "exertPain";
349  }
350 
351  exertBuffer = ‪mpdialog_value( "playerExertBuffer", 0 );
352  self thread ‪play_dialog( dialogKey, ‪DIALOG_FLAGS_PAIN, exertBuffer );
353  }
354 }
355 
356 function ‪on_player_suicide_or_team_kill( player, type )
357 {
358  self endon( "death" );
359  level endon( "game_ended" );
360 
361  // make sure that this does not execute in the player killed callback time
362  waittillframeend;
363 
364  if( !level.teamBased )
365  {
366  return;
367  }
368 }
369 
370 function ‪on_player_near_explodable( object, type )
371 {
372  self endon( "death" );
373  level endon( "game_ended" );
374 }
375 
376 function ‪enemy_threat()
377 {
378  self endon( "death" );
379  level endon( "game_ended" );
380 
381  while(1)
382  {
383  self waittill ( "weapon_ads" );
384 
385  if ( self HasPerk( "specialty_quieter" ) )
386  {
387  continue;
388  }
389 
390  if( self.enemyThreatTime + ( ‪mpdialog_value( "enemyContactInterval", 0 ) * 1000 ) >= getTime() )
391  {
392  continue;
393  }
394 
395  closest_ally = self ‪get_closest_player_ally( true );
396 
397  if ( !isdefined ( closest_ally ) )
398  {
399  continue;
400  }
401 
402  allyRadius = ‪mpdialog_value( "enemyContactAllyRadius", 0 );
403 
404  if ( DistanceSquared( self.origin, closest_ally.origin ) < allyRadius * allyRadius )
405  {
406  eyePoint = self getEye();
407  dir = AnglesToForward( self GetPlayerAngles() );
408 
409  dir = dir * ‪mpdialog_value( "enemyContactDistance", 0 );
410 
411  endPoint = eyePoint + dir;
412 
413  traceResult = BulletTrace( eyePoint, endPoint, true, self );
414 
415  if ( isdefined( traceResult["entity"] ) && traceResult["entity"].className == "player" && traceResult["entity"].team != self.team )
416  {
417  if( ‪dialog_chance( "enemyContactChance" ) )
418  {
419  self thread ‪play_dialog( "threatInfantry", ‪DIALOG_FLAG_TEAM );
420 
421  level notify ( "level_enemy_spotted", self.team);
422 
423  self.enemyThreatTime = GetTime();
424  }
425  }
426  }
427  }
428 }
429 
430 
431 // self is killed
432 function ‪killed_by_sniper( sniper )
433 {
434  self endon("disconnect");
435  sniper endon("disconnect");
436  level endon( "game_ended" );
437 
438  if ( !level.teamBased )
439  {
440  return false;
441  }
442 
443  // make sure that this does not execute in the player killed callback time
444  waittillframeend;
445 
446  if( ‪dialog_chance( "sniperKillChance" ) )
447  {
448  closest_ally = self ‪get_closest_player_ally();
449 
450  allyRadius = ‪mpdialog_value( "sniperKillAllyRadius", 0 );
451 
452  if( isdefined( closest_ally ) && DistanceSquared( self.origin, closest_ally.origin ) < allyRadius * allyRadius )
453  {
454  closest_ally thread ‪play_dialog( "threatSniper", ‪DIALOG_FLAG_TEAM );
455 
456  sniper.spottedTime = GetTime();
457  sniper.spottedBy = [];
458 
459  players = self ‪get_friendly_players();
460  players = ArraySort( players, self.origin );
461 
462  voiceRadius = ‪mpdialog_value( "playerVoiceRadius", 0 );
463  voiceRadiusSq = voiceRadius * voiceRadius;
464 
465  foreach( player in players )
466  {
467  if ( DistanceSquared( closest_ally.origin, player.origin) <= voiceRadiusSq )
468  {
469  sniper.spottedBy[sniper.spottedBy.size] = player;
470  }
471  }
472  }
473  }
474 }
475 
476 // self is killed
477 function ‪player_killed( attacker, killstreakType )
478 {
479  if ( !level.teamBased )
480  {
481  return;
482  }
483 
484  if ( self === attacker )
485  {
486  // Play hilarious 'Stop killing yourself' dialog
487  return;
488  }
489 
490  // make sure that this does not execute in the player killed callback time
491  waittillframeend;
492 
493  if( isdefined( killstreakType ) )
494  {
495  if ( !isdefined( level.killstreaks[killstreakType] ) ||
496  !isdefined( level.killstreaks[killstreakType].threatOnKill ) ||
497  !level.killstreaks[killstreakType].threatOnKill ||
498  !‪dialog_chance( "killstreakKillChance" ) )
499  {
500  return;
501  }
502 
504  allyRadius = ‪mpdialog_value( "killstreakKillAllyRadius", 0 );
505 
506  if ( isdefined( ally ) && DistanceSquared( self.origin, ally.origin ) < allyRadius * allyRadius )
507  {
508  ally ‪play_killstreak_threat( killstreakType );
509  }
510  }
511 }
512 
513 function ‪say_kill_battle_chatter( attacker, weapon, victim, inflictor )
514 {
515  if ( weapon.skipBattlechatterKill ||
516  !isdefined( attacker ) ||
517  !IsPlayer( attacker ) ||
518  !IsAlive( attacker ) ||
519  attacker IsRemoteControlling() ||
520  attacker IsInVehicle() ||
521  attacker IsWeaponViewOnlyLinked() ||
522  !isdefined( victim ) ||
523  !IsPlayer( victim ) )
524  {
525  return;
526  }
527 
528  // Don't play kill chatter if the player died since initiating the attack
529  if ( isdefined( inflictor ) && !IsPlayer( inflictor ) && inflictor.birthtime < attacker.spawntime )
530  {
531  return;
532  }
533 
534  if ( weapon.inventorytype == "hero" )
535  {
536  ‪DEFAULT( attacker.heroweaponKillCount, 0 );
537 
538  attacker.heroweaponKillCount++;
539 
540  if ( !‪IS_TRUE( attacker.playedGadgetSuccess ) && attacker.heroweaponKillCount === ‪mpdialog_value( "heroWeaponKillCount", 0 ) )
541  {
542  // TODO: Keep trying to play on each kill until successful
543  // TODO: Play to multiple enemies killed together
544  attacker thread ‪play_gadget_success( weapon, "enemyKillDelay", victim );
545  attacker thread ‪hero_weapon_success_reaction();
546  }
547  }
548  else if ( ‪IS_TRUE( attacker.speedburstOn ) )
549  {
550  if ( !‪IS_TRUE( attacker.speedburstKill ) )
551  {
552  speedBurstKillDist = ‪mpdialog_value( "speedBurstKillDistance", 0 );
553  if ( DistanceSquared( attacker.origin, victim.origin ) < speedBurstKillDist * speedBurstKillDist )
554  {
555  attacker.speedburstKill = true;
556  }
557  }
558  }
559  else if ( attacker ‪_gadget_camo::camo_is_inuse( ) ||
560  ( isdefined( attacker.gadget_camo_off_time ) && attacker.gadget_camo_off_time + ( ‪mpdialog_value( "camoKillTime", 0 ) * 1000 ) >= GetTime() ) )
561  {
562  if ( !‪IS_TRUE( attacker.playedGadgetSuccess ) )
563  {
564  attacker thread ‪play_gadget_success( GetWeapon( "gadget_camo" ), "enemyKillDelay", victim );
565  }
566  }
567  else if ( ‪dialog_chance( "enemyKillChance" ) )
568  {
569  if ( isdefined( victim.spottedTime ) &&
570  victim.spottedTime + ‪mpdialog_value( "enemySniperKillTime", 0 ) >= GetTime() &&
571  array::contains( victim.spottedBy, attacker ) &&
572  ‪dialog_chance( "enemySniperKillChance" ) )
573  {
574  killDialog = attacker ‪get_random_key( "killSniper" );
575  }
576  else if ( ‪dialog_chance( "enemyHeroKillChance" ) )
577  {
578  victimDialogName = victim GetMpDialogName();
579  killDialog = attacker ‪get_random_key( level.bcSounds[ ‪KILL_DIALOG ][ victimDialogName ] );
580  }
581  else
582  {
583  killDialog = attacker ‪get_random_key( "killGeneric" );
584  }
585  }
586 
587  // Clear sniper spotted fields
588  victim.spottedTime = undefined;
589  victim.spottedBy = undefined;
590 
591  if ( !isdefined( killDialog ) )
592  {
593  return;
594  }
595 
596  attacker thread ‪wait_play_dialog( ‪mpdialog_value( "enemyKillDelay", 0 ), killDialog, ‪DIALOG_FLAG_TEAM, undefined, victim, "cancel_kill_dialog" );
597 }
598 
599 
601 {
602  self endon( "death" );
603  level endon( "game_ended" );
604 
605  while(1)
606  {
607  self waittill ( "grenade_fire", grenade, weapon );
608 
609  if ( !isdefined( grenade.weapon ) ||
610  !isdefined( grenade.weapon.rootweapon ) ||
611  !‪dialog_chance( "incomingProjectileChance" ) )
612  {
613  continue;
614  }
615 
616  dialogKey = level.bcSounds[ ‪INCOMING_ALERT ][ grenade.weapon.rootweapon.name ];
617 
618  if ( isdefined( dialogKey ) )
619  {
620  waittime = ‪mpdialog_value( level.bcSounds[ ‪INCOMING_DELAY ][ grenade.weapon.rootweapon.name ], ‪SERVER_FRAME );
621  level thread ‪incoming_projectile_alert( self, grenade, dialogKey, waittime );
622  }
623  }
624 }
625 
627 {
628  self endon( "death" );
629  level endon( "game_ended" );
630 
631  while(1)
632  {
633  self waittill ( "missile_fire", missile, weapon );
634 
635  if ( !isdefined( missile.item ) ||
636  !isdefined( missile.item.rootweapon ) ||
637  !‪dialog_chance( "incomingProjectileChance" ) )
638  {
639  continue;
640  }
641 
642  dialogKey = level.bcSounds[ ‪INCOMING_ALERT ][ missile.item.rootweapon.name ];
643 
644  if ( isdefined ( dialogKey ) )
645  {
646  waittime = ‪mpdialog_value( level.bcSounds[ ‪INCOMING_DELAY ][ missile.item.rootweapon.name ], ‪SERVER_FRAME );
647  level thread ‪incoming_projectile_alert( self, missile, dialogKey, waittime );
648  }
649  }
650 }
651 
652 function ‪incoming_projectile_alert( thrower, projectile, dialogKey, waittime )
653 {
654  level endon( "game_ended" );
655  if ( waittime <= 0 )
656  {
657  assert( waittime > 0, "incoming_projectile_alert waittime must be greater than 0" );
658  return;
659  }
660 
661  while(1)
662  {
663  wait( waittime );
664 
665  // HACK: This is a crazy way to try and trigger the warning more often
666  if ( waittime > 0.2 )
667  {
668  waittime = waittime / 2;
669  }
670 
671  // The projectile may have blown up or the like while waiting
672  if ( !isdefined( projectile ) )
673  {
674  return;
675  }
676 
677  //Check if player threw grenade and then quit or switched to spectator
678  if( !isdefined( thrower ) || thrower.team == "spectator" )
679  {
680  return;
681  }
682 
683  if( ( level.players.size ) )
684  {
685  closest_enemy = thrower ‪get_closest_player_enemy( projectile.origin );
686 
687  incomingProjectileRadius = ‪mpdialog_value( "incomingProjectileRadius", 0 );
688 
689  if( isdefined( closest_enemy ) && DistanceSquared( projectile.origin, closest_enemy.origin ) < incomingProjectileRadius * incomingProjectileRadius )
690  {
691  closest_enemy thread ‪play_dialog( dialogKey, ‪DIALOG_FLAGS_SHOUT );
692  return;
693  }
694  }
695  }
696 }
697 
699 {
700  self endon( "death" );
701  level endon( "game_ended" );
702 
703  while(1)
704  {
705  self waittill ( "grenade_stuck", grenade );
706 
707  if ( IsAlive( self ) && isdefined( grenade ) && isdefined( grenade.weapon ) )
708  {
709  if ( grenade.weapon.rootweapon.name == "sticky_grenade" )
710  {
711  self thread ‪play_dialog( "stuckSticky", ‪DIALOG_FLAGS_SHOUT );
712  }
713  }
714  }
715 }
716 
718 {
719  self endon( "death" );
720  level endon( "game_ended" );
721 
722  if ( !level.teambased )
723  {
724  return;
725  }
726 
727  allies = [];
728 
729  allyRadiusSq = ‪mpdialog_value( "playerVoiceRadius", 0 );
730  allyRadiusSq *= allyRadiusSq;
731 
732  foreach( player in level.players )
733  {
734  if ( !isdefined( player ) ||
735  !IsAlive( player ) ||
736  player.sessionstate != "playing" ||
737  player == self ||
738  player.team != self.team )
739  {
740  continue;
741  }
742 
743  distSq = DistanceSquared( self.origin, player.origin );
744 
745  if ( distSq > allyRadiusSq )
746  {
747  continue;
748  }
749 
750  allies[allies.size] = player;
751  }
752 
753  // First do the kill delay wait
754  wait( ‪mpdialog_value( "enemyKillDelay", 0 ) + 0.1 );
755 
756  // Wait for the player to finish talking
757  while ( self.playingDialog )
758  {
759  wait( 0.5 );
760  }
761 
762  allies = ArraySort( allies, self.origin );
763 
764  foreach( player in allies )
765  {
766  if ( !IsAlive( player ) ||
767  player.sessionstate != "playing" ||
768  player.playingDialog ||
769  player IsPlayerUnderwater() ||
770  player IsRemoteControlling() ||
771  player IsInVehicle() ||
772  player IsWeaponViewOnlyLinked() )
773  {
774  continue;
775  }
776 
777  distSq = DistanceSquared( self.origin, player.origin );
778 
779  if ( distSq > allyRadiusSq )
780  {
781  break;
782  }
783 
784  player ‪play_dialog( "heroWeaponSuccessReaction", ‪DIALOG_FLAG_TEAM );
785  break;
786  }
787 }
788 
790 {
791  self endon( "death" );
792  level endon( "game_ended" );
793 
794  if ( !level.teambased )
795  {
796  return;
797  }
798 
799  // Wait for the music cue to finish / start fading
800  wait 9;
801 
802  players = self ‪get_friendly_players();
803  players = ArraySort( players, self.origin );
804 
805  selfDialog = self GetMpDialogName();
806  voiceRadius = ‪mpdialog_value( "playerVoiceRadius", 0 );
807  voiceRadiusSq = voiceRadius * voiceRadius;
808 
809  foreach( player in players )
810  {
811  if ( player == self ||
812  player GetMpDialogName() == selfDialog ||
813  !player ‪can_play_dialog( true ) ||
814  DistanceSquared( self.origin, player.origin ) >= voiceRadiusSq )
815  {
816  continue;
817  }
818 
819  dialogAlias = player ‪get_player_dialog_alias( "promotionReaction" );
820 
821  if ( !isdefined( dialogAlias ) )
822  {
823  continue;
824  }
825 
826  ally = player;
827  break;
828  }
829 
830  if ( isdefined( ally ) )
831  {
832  ally PlaySoundOnTag( dialogAlias, ‪VOICE_TAG, undefined, self );
833  // The ally won't know why they can't talk, but they won't interrupt themselves either
834  ally thread ‪wait_dialog_buffer( ‪mpdialog_value( "playerDialogBuffer", 0 ) );
835  }
836 }
837 
838 function ‪gametype_specific_battle_chatter( event, team )
839 {
840  self endon ( "death" );
841  level endon( "game_ended" );
842 }
843 
844 function ‪play_death_vox( body, attacker, weapon, meansOfDeath )
845 {
846  dialogKey = self ‪get_death_vox( weapon, meansOfDeath );
847  dialogAlias = self ‪get_player_dialog_alias( dialogKey );
848 
849  if ( isdefined( dialogAlias ) )
850  {
851  body PlaySoundOnTag( dialogAlias, ‪VOICE_TAG );
852  }
853 }
854 
855 function ‪get_death_vox( weapon, meansOfDeath )
856 {
857  // Always play drowned if underwater
858  if ( self IsPlayerUnderwater() )
859  {
860  return "exertDeathDrowned";
861  }
862 
863  if ( isdefined( meansOfDeath ) )
864  {
865  switch( meansOfDeath )
866  {
867  case "MOD_BURNED":
868  return "exertDeathBurned";
869  case "MOD_DROWN":
870  return "exertDeathDrowned";
871  }
872  }
873 
874  if ( isdefined( weapon ) && meansOfDeath !== "MOD_MELEE_WEAPON_BUTT" )
875  {
876  switch( weapon.rootweapon.name )
877  {
878  case "knife_loadout":
879  case "hatchet":
880  case "hero_armblade":
881  return "exertDeathStabbed";
882  case "hero_firefly_swarm":
883  return "exertDeathBurned";
884  case "hero_lightninggun_arc":
885  return "exertDeathElectrocuted";
886  }
887  }
888 
889  return "exertDeath";
890 }
891 
892 function ‪play_killstreak_threat( killstreakType )
893 {
894  if ( !isdefined( killstreakType ) || !isdefined( level.killstreaks[killstreakType] ) )
895  {
896  return;
897  }
898 
899  self thread ‪play_dialog( level.killstreaks[killstreakType].threatDialogKey, ‪DIALOG_FLAG_TEAM );
900 }
901 
902 function ‪wait_play_dialog( waitTime, dialogKey, dialogFlags, dialogBuffer, enemy, endNotify )
903 {
904  self endon( "death" );
905  level endon( "game_ended" );
906 
907  if (isdefined( waitTime) && waitTime > 0 )
908  {
909  if ( isdefined( endNotify ) )
910  {
911  self endon( endNotify );
912  }
913 
914  wait ( waitTime );
915  }
916 
917  self thread ‪play_dialog( dialogKey, dialogFlags, dialogBuffer, enemy );
918 }
919 
920 function ‪play_dialog( dialogKey, dialogFlags, dialogBuffer, enemy )
921 {
922  self endon( "death" );
923  level endon( "game_ended" );
924 
925  if ( !isdefined( dialogKey ) ||
926  !IsPlayer( self ) ||
927  !IsAlive( self ) ||
928  level.gameEnded )
929  {
930  return;
931  }
932 
933  if ( !isdefined( dialogFlags ) )
934  {
935  dialogFlags = 0;
936  }
937 
938  if ( !level.allowSpecialistDialog && ( dialogFlags & ‪DIALOG_FLAG_EXERT ) == 0 )
939  {
940  return;
941  }
942 
943  if ( !isdefined( dialogBuffer ) )
944  {
945  dialogBuffer = ‪mpdialog_value( "playerDialogBuffer", 0 );
946  }
947 
948  dialogAlias = self ‪get_player_dialog_alias( dialogKey );
949 
950  if ( !isdefined( dialogAlias ) )
951  {
952  return;
953  }
954 
955  if ( self IsPlayerUnderwater() && !( dialogFlags & ‪DIALOG_FLAG_UNDERWATER ) )
956  {
957  return;
958  }
959 
960  if ( self.playingDialog )
961  {
962  if ( !( dialogFlags & ‪DIALOG_FLAG_INTERRUPT ) )
963  {
964  return;
965  }
966 
967  self StopSounds();
968 
970  }
971 
972  if ( dialogFlags & ‪DIALOG_FLAG_GADGET_READY )
973  {
974  self.playingGadgetReadyDialog = true;
975  }
976 
977  if ( dialogFlags & ‪DIALOG_FLAG_STOLEN_GADGET_READY )
978  {
979  ‪DEFAULT( self.stolenDialogIndex, 0 );
980 
981  dialogAlias = dialogAlias + "_0" + self.stolenDialogIndex;
982 
983  self.stolenDialogIndex++;
984  self.stolenDialogIndex = self.stolenDialogIndex % ‪STOLEN_GADGET_READY_LINE_COUNT;
985  }
986 
987  if ( dialogFlags & ‪DIALOG_FLAG_ALL )
988  {
989  // Plays to all teams
990  self PlaySoundOnTag( dialogAlias, ‪VOICE_TAG );
991  }
992  else if ( dialogFlags & ‪DIALOG_FLAG_TEAM )
993  {
994  // Plays to current team
995  if ( isdefined( enemy ) )
996  {
997  // And the specified enemy
998  self PlaySoundOnTag( dialogAlias, ‪VOICE_TAG, self.team, enemy );
999  }
1000  else
1001  {
1002  self PlaySoundOnTag( dialogAlias, ‪VOICE_TAG, self.team );
1003  }
1004  }
1005  else
1006  {
1007  self PlayLocalSound( dialogAlias );
1008  }
1009 
1010  // FUTURE: Pass dialogKey, dialogBuffer if useful
1011  self notify( "played_dialog" );
1012 
1013  self thread ‪wait_dialog_buffer( dialogBuffer );
1014 }
1015 
1016 function ‪wait_dialog_buffer( dialogBuffer )
1017 {
1018  self endon( "death" );
1019  self endon( "played_dialog" );
1020  self endon( "stop_dialog" );
1021  level endon( "game_ended" );
1022 
1023  self.playingDialog = true;
1024 
1025  if ( isdefined( dialogBuffer ) && dialogBuffer > 0 )
1026  {
1027  wait ( dialogBuffer );
1028  }
1029 
1030  self.playingDialog = false;
1031  self.playingGadgetReadyDialog = false;
1032 }
1033 
1034 function ‪stop_dialog()
1035 {
1036  self notify( "stop_dialog" );
1037 
1038  self StopSounds();
1039 
1040  self.playingDialog = false;
1041  self.playingGadgetReadyDialog = false;
1042 }
1043 
1044 function ‪wait_playback_time( soundAlias )
1045 {
1046  //self endon( "death" );
1047  //level endon( "game_ended" );
1048 }
1049 
1050 function ‪get_player_dialog_alias( dialogKey )
1051 {
1052  if ( !IsPlayer( self ) )
1053  {
1054  return undefined;
1055  }
1056 
1057  bundleName = self GetMpDialogName();
1058 
1059  if ( !isdefined( bundleName ) )
1060  {
1061  return undefined;
1062  }
1063 
1064  playerBundle = ‪struct::get_script_bundle( "mpdialog_player", bundleName );
1065 
1066  if ( !isdefined( playerBundle ) )
1067  {
1068  return undefined;
1069  }
1070 
1071  return ‪globallogic_audio::get_dialog_bundle_alias( playerBundle, dialogKey );
1072 }
1073 
1074 function ‪count_keys( bundle, dialogKey )
1075 {
1076  i = 0;
1077  field = dialogKey + i;
1078  fieldValue = GetStructField( bundle, field );
1079 
1080  while ( isdefined( fieldValue ) )
1081  {
1082  aliasArray[i] = fieldValue;
1083 
1084  i++;
1085  field = dialogKey + i;
1086  fieldValue = GetStructField( bundle, field );
1087  }
1088 
1089  if ( !isdefined( bundle.keyCounts ) )
1090  {
1091  bundle.keyCounts = [];
1092  }
1093 
1094  bundle.keyCounts[dialogKey] = i;
1095 }
1096 
1097 function ‪get_random_key( dialogKey )
1098 {
1099  bundleName = self GetMpDialogName();
1100 
1101  if ( !isdefined( bundleName ) )
1102  {
1103  return undefined;
1104  }
1105 
1106  playerBundle = ‪struct::get_script_bundle( "mpdialog_player", bundleName );
1107 
1108  if ( !isdefined( playerBundle ) ||
1109  !isdefined( playerBundle.keyCounts ) ||
1110  !isdefined( playerBundle.keyCounts[dialogKey] ) )
1111  {
1112  return dialogKey;
1113  }
1114 
1115  return dialogKey + RandomInt( playerBundle.keyCounts[dialogKey] );
1116 }
1117 
1118 // These are called from shared scripts via function pointers
1119 function ‪play_gadget_ready( weapon, userFlip = false )
1120 {
1121  if ( !isdefined( weapon ) )
1122  return;
1123 
1124  dialogKey = undefined;
1125 
1126  switch( weapon.name )
1127  {
1128  case "hero_gravityspikes":
1129  dialogKey = "gravspikesWeaponReady";
1130  break;
1131  case "gadget_speed_burst":
1132  dialogKey = "overdriveAbilityReady";
1133  break;
1134  case "hero_bowlauncher":
1135  case "hero_bowlauncher2":
1136  case "hero_bowlauncher3":
1137  case "hero_bowlauncher4":
1138  dialogKey = "sparrowWeaponReady";
1139  break;
1140  case "gadget_vision_pulse":
1141  dialogKey = "visionpulseAbilityReady";
1142  break;
1143  case "hero_lightninggun":
1144  case "hero_lightninggun_arc":
1145  dialogKey = "tempestWeaponReady";
1146  break;
1147  case "gadget_flashback":
1148  dialogKey = "glitchAbilityReady";
1149  break;
1150  case "hero_pineapplegun":
1151  dialogKey = "warmachineWeaponREady";
1152  break;
1153  case "gadget_armor":
1154  dialogKey = "kineticArmorAbilityReady";
1155  break;
1156  case "hero_annihilator":
1157  dialogKey = "annihilatorWeaponReady";
1158  break;
1159  case "gadget_combat_efficiency":
1160  dialogKey = "combatfocusAbilityReady";
1161  break;
1162  case "hero_chemicalgelgun":
1163  dialogKey = "hiveWeaponReady";
1164  break;
1165  case "gadget_resurrect":
1166  dialogKey = "rejackAbilityReady";
1167  break;
1168  case "hero_minigun":
1169  case "hero_minigun_body3":
1170  dialogKey = "scytheWeaponReady";
1171  break;
1172  case "gadget_clone":
1173  dialogKey = "psychosisAbilityReady";
1174  break;
1175  case "hero_armblade":
1176  dialogKey = "ripperWeaponReady";
1177  break;
1178  case "gadget_camo":
1179  dialogKey = "activeCamoAbilityReady";
1180  break;
1181  case "hero_flamethrower":
1182  dialogKey = "purifierWeaponReady";
1183  break;
1184  case "gadget_heat_wave":
1185  dialogKey = "heatwaveAbilityReady";
1186  break;
1187  default:
1188  return;
1189  }
1190 
1191  // Just a regular ready
1192  if ( !‪IS_TRUE( self.isThief ) && !‪IS_TRUE( self.isRoulette ) )
1193  {
1194  self thread ‪play_dialog( dialogKey );
1195  return;
1196  }
1197 
1198  waitTime = 0;
1199  dialogFlags = ‪DIALOG_FLAG_GADGET_READY;
1200 
1201  if ( userFlip ) // User flipped or rerolled, kill the previous gadget dialog
1202  {
1203  minWaitTime = 0;
1204  if ( self.playingGadgetReadyDialog )
1205  {
1206  self ‪stop_dialog();
1207  minWaitTime = ‪SERVER_FRAME; // Make sure dialog stops
1208  }
1209 
1210  if ( ‪IS_TRUE( self.isThief ) )
1211  {
1212  delayKey = "thiefFlipDelay";
1213  }
1214  else
1215  {
1216  delayKey = "rouletteFlipDelay";
1217  }
1218 
1219  waitTime = ‪mpdialog_value( delayKey, minWaitTime );
1220  dialogFlags += ‪DIALOG_FLAG_STOLEN_GADGET_READY;
1221  }
1222  else // Initial roll or stolen weapon
1223  {
1224  if ( ‪IS_TRUE( self.isThief ) )
1225  {
1226  genericKey = "thiefWeaponReady";
1227  repeatKey = "thiefWeaponRepeat";
1228  repeatThresholdKey = "thiefRepeatThreshold";
1229  chanceKey = "thiefReadyChance";
1230  delayKey = "thiefRevealDelay";
1231  }
1232  else
1233  {
1234  genericKey = "rouletteAbilityReady";
1235  repeatKey = "rouletteAbilityRepeat";
1236  repeatThresholdKey = "rouletteRepeatThreshold";
1237  chanceKey = "rouletteReadyChance";
1238  delayKey = "rouletteRevealDelay";
1239  }
1240 
1241  if ( RandomInt( 100 ) < ‪mpdialog_value( chanceKey, 0 ) )
1242  {
1243  // Play generic earned dialog
1244  dialogKey = genericKey;
1245  }
1246  else
1247  {
1248  waitTime = ‪mpdialog_value( delayKey, 0 );
1249 
1250  if ( self.lastStolenGadget === weapon &&
1251  ( self.lastStolenGadgetTime + ‪mpdialog_value( repeatThresholdKey, 0 ) * 1000 ) > GetTime() )
1252  {
1253  // Play duplicate earned dialog
1254  dialogKey = repeatKey;
1255  }
1256  else
1257  {
1258  dialogFlags += ‪DIALOG_FLAG_STOLEN_GADGET_READY;
1259  }
1260  }
1261  }
1262 
1263  self.lastStolenGadget = weapon;
1264  self.lastStolenGadgetTime = GetTime();
1265 
1266  if ( waitTime ) // Generic lines play instantly
1267  {
1268  // As long as we're not playing dialog, block any kill lines coming in to play the gadget ready
1269  self notify( "cancel_kill_dialog" );
1270  }
1271 
1272  self thread ‪wait_play_dialog( waitTime, dialogKey, dialogFlags );
1273 }
1274 
1275 function ‪play_gadget_activate( weapon )
1276 {
1277  if ( !isdefined( weapon ) )
1278  return;
1279 
1280  dialogKey = undefined;
1281 
1282  switch( weapon.name )
1283  {
1284  case "hero_gravityspikes":
1285  dialogKey = "gravspikesWeaponUse";
1287  dialogBuffer = 0.05;
1288  break;
1289  case "gadget_speed_burst":
1290  dialogKey = "overdriveAbilityUse";
1291  break;
1292  case "hero_bowlauncher":
1293  case "hero_bowlauncher2":
1294  case "hero_bowlauncher3":
1295  case "hero_bowlauncher4":
1296  dialogKey = "sparrowWeaponUse";
1297  break;
1298  case "gadget_vision_pulse":
1299  dialogKey = "visionpulseAbilityUse";
1300  break;
1301  case "hero_lightninggun":
1302  case "hero_lightninggun_arc":
1303  dialogKey = "tempestWeaponUse";
1304  break;
1305  case "gadget_flashback":
1306  dialogKey = "glitchAbilityUse";
1307  break;
1308  case "hero_pineapplegun":
1309  dialogKey = "warmachineWeaponUse";
1310  break;
1311  case "gadget_armor":
1312  dialogKey = "kineticArmorAbilityUse";
1313  break;
1314  case "hero_annihilator":
1315  dialogKey = "annihilatorWeaponUse";
1316  break;
1317  case "gadget_combat_efficiency":
1318  dialogKey = "combatfocusAbilityUse";
1319  break;
1320  case "hero_chemicalgelgun":
1321  dialogKey = "hiveWeaponUse";
1322  break;
1323  case "gadget_resurrect":
1324  dialogKey = "rejackAbilityUse";
1325  break;
1326  case "hero_minigun":
1327  case "hero_minigun_body3":
1328  dialogKey = "scytheWeaponUse";
1329  break;
1330  case "gadget_clone":
1331  dialogKey = "psychosisAbilityUse";
1332  break;
1333  case "hero_armblade":
1334  dialogKey = "ripperWeaponUse";
1335  break;
1336  case "gadget_camo":
1337  dialogKey = "activeCamoAbilityUse";
1338  break;
1339  case "hero_flamethrower":
1340  dialogKey = "purifierWeaponUse";
1341  break;
1342  case "gadget_heat_wave":
1343  dialogKey = "heatwaveAbilityUse";
1344  break;
1345  default:
1346  return;
1347  }
1348 
1349  self thread ‪play_dialog( dialogKey, dialogFlags, dialogBuffer );
1350 }
1351 
1352 function ‪play_gadget_success( weapon, waitKey, victim )
1353 {
1354  if ( !isdefined( weapon ) )
1355  return;
1356 
1357  dialogKey = undefined;
1358 
1359  switch( weapon.name )
1360  {
1361  case "hero_gravityspikes":
1362  dialogKey = "gravspikesWeaponSuccess";
1363  break;
1364  case "gadget_speed_burst":
1365  dialogKey = "overdriveAbilitySuccess";
1366  break;
1367  case "hero_bowlauncher":
1368  case "hero_bowlauncher2":
1369  case "hero_bowlauncher3":
1370  case "hero_bowlauncher4":
1371  dialogKey = "sparrowWeaponSuccess";
1372  break;
1373  case "gadget_vision_pulse":
1374  dialogKey = "visionpulseAbilitySuccess";
1375  break;
1376  case "hero_lightninggun":
1377  case "hero_lightninggun_arc":
1378  dialogKey = "tempestWeaponSuccess";
1379  break;
1380  case "gadget_flashback":
1381  dialogKey = "glitchAbilitySuccess";
1382  break;
1383  case "hero_pineapplegun":
1384  dialogKey = "warmachineWeaponSuccess";
1385  break;
1386  case "gadget_armor":
1387  dialogKey = "kineticArmorAbilitySuccess";
1388  break;
1389  case "hero_annihilator":
1390  dialogKey = "annihilatorWeaponSuccess";
1391  break;
1392  case "gadget_combat_efficiency":
1393  dialogKey = "combatfocusAbilitySuccess";
1394  break;
1395  case "hero_chemicalgelgun":
1396  dialogKey = "hiveWeaponSuccess";
1397  break;
1398  case "gadget_resurrect":
1399  dialogKey = "rejackAbilitySuccess";
1400  break;
1401  case "hero_minigun":
1402  case "hero_minigun_body3":
1403  dialogKey = "scytheWeaponSuccess";
1404  break;
1405  case "gadget_clone":
1406  dialogKey = "psychosisAbilitySuccess";
1407  break;
1408  case "hero_armblade":
1409  dialogKey = "ripperWeaponSuccess";
1410  break;
1411  case "gadget_camo":
1412  dialogKey = "activeCamoAbilitySuccess";
1413  break;
1414  case "hero_flamethrower":
1415  dialogKey = "purifierWeaponSuccess";
1416  break;
1417  case "gadget_heat_wave":
1418  dialogKey = "heatwaveAbilitySuccess";
1419  break;
1420  default:
1421  return;
1422  }
1423 
1424  if ( isdefined( waitKey ) )
1425  {
1426  waitTime = ‪mpdialog_value( waitKey, 0 );
1427  }
1428 
1429  //dialogKey = get_random_key( dialogKey );
1430  dialogKey = dialogKey + "0";
1431 
1432  self.playedGadgetSuccess = true;
1433  self thread ‪wait_play_dialog( waitTime, dialogKey, ‪DIALOG_FLAG_TEAM, undefined, victim );
1434 }
1435 
1437 {
1438  self thread ‪play_dialog( "exertAxeThrow", ‪DIALOG_FLAG_TEAM | ‪DIALOG_FLAG_INTERRUPT | ‪DIALOG_FLAG_EXERT, ‪mpdialog_value( "playerExertBuffer", 0 ) );
1439 }
1440 
1441 // Utils for getting enemies / allies
1442 
1444 {
1445  players = [];
1446 
1447  if ( level.teambased )
1448  {
1449  foreach( team in level.teams )
1450  {
1451  if ( team == self.team )
1452  {
1453  continue;
1454  }
1455 
1456  foreach( player in level.alivePlayers[team] )
1457  {
1458  players[players.size] = player;
1459  }
1460  }
1461  }
1462  else
1463  {
1464  foreach( player in level.activeplayers )
1465  {
1466  if ( player != self )
1467  {
1468  players[players.size] = player;
1469  }
1470  }
1471  }
1472 
1473  return players;
1474 }
1475 
1477 {
1478  players = [];
1479 
1480  if ( level.teambased )
1481  {
1482  foreach( player in level.alivePlayers[self.team] )
1483  {
1484  players[players.size] = player;
1485  }
1486  }
1487  else
1488  {
1489  players[0] = self;
1490  }
1491 
1492  return players;
1493 }
1494 
1495 function ‪can_play_dialog( teamOnly )
1496 {
1497  if ( !IsPlayer( self ) ||
1498  !IsAlive( self ) ||
1499  self.playingDialog === true ||
1500  self IsPlayerUnderwater() ||
1501  self IsRemoteControlling() ||
1502  self IsInVehicle() ||
1503  self IsWeaponViewOnlyLinked() )
1504  {
1505  return false;
1506  }
1507 
1508  if ( isdefined( teamOnly ) && !teamOnly && self HasPerk( "specialty_quieter" ) )
1509  {
1510  return false;
1511  }
1512 
1513  return true;
1514 }
1515 
1516 // Call this on the owning/controlling/attacking player to keep them from being picked in non-team games
1517 function ‪get_closest_player_enemy( origin, teamOnly )
1518 {
1519  ‪DEFAULT( origin, self.origin );
1520 
1521  players = self ‪get_enemy_players();
1522  players = ArraySort( players, origin );
1523 
1524  foreach( player in players )
1525  {
1526  if( !player ‪can_play_dialog( teamOnly ) )
1527  {
1528  continue;
1529  }
1530 
1531  return player;
1532  }
1533 
1534  return undefined;
1535 }
1536 
1537 function ‪get_closest_player_ally( teamOnly )
1538 {
1539  if ( !level.teambased )
1540  {
1541  return undefined;
1542  }
1543 
1544  players = self ‪get_friendly_players();
1545  players = ArraySort( players, self.origin );
1546 
1547  foreach( player in players )
1548  {
1549  if ( player == self ||
1550  !player ‪can_play_dialog( teamOnly ) )
1551  {
1552  continue;
1553  }
1554 
1555  return player;
1556  }
1557 
1558  return undefined;
1559 }
1560 
1561 // Boost Start conversation
1562 
1564 {
1565  if ( !level.playStartConversation )
1566  {
1567  return;
1568  }
1569 
1570  if ( !level.inPrematchPeriod ||
1571  !level.teambased ||
1572  game["boostPlayersPicked"][ self.team ] )
1573  {
1574  return;
1575  }
1576 
1577  players = self ‪get_friendly_players();
1578 
1579  // The spawned player isn't in level.alivePlayers yet
1580  ‪array::add( players, self, false );
1581 
1582  players = array::randomize( players );
1583 
1584  playerIndex = 1;
1585  foreach( player in players )
1586  {
1587  playerDialog = player GetMpDialogName();
1588 
1589  for( i = playerIndex; i < players.size; i++ )
1590  {
1591  playerI = players[i];
1592 
1593  if ( playerDialog != playerI GetMpDialogName() )
1594  {
1595  ‪pick_boost_players( player, playerI );
1596  return;
1597  }
1598  }
1599 
1600  playerIndex++;
1601  }
1602 }
1603 
1604 function ‪pick_boost_players( player1, player2 )
1605 {
1608 
1609  game["boostPlayersPicked"][player1.team] = true;
1610 }
1611 
1612 // Game end dialog
1613 
1614 function ‪game_end_vox( winner )
1615 {
1616  if ( !level.allowSpecialistDialog )
1617  {
1618  return;
1619  }
1620 
1621  gameIsDraw = !isdefined( winner ) || ( level.teamBased && winner == "tie" );
1622 
1623  foreach( player in level.players )
1624  {
1625  if ( player IsSplitScreen() )
1626  {
1627  continue;
1628  }
1629 
1630  if ( gameIsDraw )
1631  {
1632  dialogKey = "boostDraw";
1633  }
1634  else if ( ( level.teamBased && isdefined( level.teams[ winner ] ) && player.pers["team"] == winner ) ||
1635  ( !level.teamBased && player == winner ) )
1636  {
1637  dialogKey = "boostWin";
1638  }
1639  else
1640  {
1641  dialogKey = "boostLoss";
1642  }
1643 
1644  dialogAlias = player ‪get_player_dialog_alias( dialogKey );
1645 
1646  if ( isdefined( dialogAlias ) )
1647  {
1648  player PlayLocalSound( dialogAlias );
1649  }
1650  }
1651 }
1652 
‪VOICE_TAG
‪#define VOICE_TAG
Definition: _battlechatter.gsc:41
‪dialog_chance
‪function dialog_chance(chanceKey)
Definition: _battlechatter.gsc:237
‪on_player_suicide_or_team_kill
‪function on_player_suicide_or_team_kill(player, type)
Definition: _battlechatter.gsc:356
‪DIALOG_FLAGS_SHOUT
‪#define DIALOG_FLAGS_SHOUT
Definition: _battlechatter.gsc:36
‪play_gadget_ready
‪function play_gadget_ready(weapon, userFlip=false)
Definition: _battlechatter.gsc:1119
‪play_dialog
‪function play_dialog(dialogKey, dialogFlags, dialogBuffer, enemy)
Definition: _battlechatter.gsc:920
‪get_script_bundles
‪function get_script_bundles(str_type)
Definition: struct.csc:77
‪mpdialog_value
‪function mpdialog_value(mpdialogKey, defaultValue)
Definition: _battlechatter.gsc:253
‪STOLEN_GADGET_READY_LINE_COUNT
‪#define STOLEN_GADGET_READY_LINE_COUNT
Definition: _battlechatter.gsc:39
‪missile_tracking
‪function missile_tracking()
Definition: _battlechatter.gsc:626
‪BOOST_START
‪#define BOOST_START
Definition: _battlechatter.gsc:45
‪check_boost_start_conversation
‪function check_boost_start_conversation()
Definition: _battlechatter.gsc:1563
‪player_killed
‪function player_killed(attacker, killstreakType)
Definition: _battlechatter.gsc:477
‪play_gadget_activate
‪function play_gadget_activate(weapon)
Definition: _battlechatter.gsc:1275
‪NUM_BOOSTS
‪#define NUM_BOOSTS
Definition: _battlechatter.gsc:43
‪wait_playback_time
‪function wait_playback_time(soundAlias)
Definition: _battlechatter.gsc:1044
‪get_dialog_bundle_alias
‪function get_dialog_bundle_alias(dialogBundle, dialogKey)
Definition: _globallogic_audio.gsc:787
‪on_joined_team
‪function on_joined_team()
Definition: _battlechatter.gsc:133
‪VERSION_SHIP
‪#define VERSION_SHIP
Definition: version.gsh:36
‪get_player_dialog_alias
‪function get_player_dialog_alias(dialogKey)
Definition: _battlechatter.gsc:1050
‪DIALOG_FLAG_INTERRUPT
‪#define DIALOG_FLAG_INTERRUPT
Definition: _battlechatter.gsc:30
‪on_player_connect
‪function on_player_connect()
Definition: _battlechatter.gsc:190
‪INCOMING_DELAY
‪#define INCOMING_DELAY
Definition: _battlechatter.gsc:25
‪DIALOG_FLAG_TEAM
‪#define DIALOG_FLAG_TEAM
Definition: _battlechatter.gsc:28
‪get_closest_player_enemy
‪function get_closest_player_enemy(origin, teamOnly)
Definition: _battlechatter.gsc:1517
‪INCOMING_ALERT
‪#define INCOMING_ALERT
Definition: _battlechatter.gsc:24
‪enemy_threat
‪function enemy_threat()
Definition: _battlechatter.gsc:376
‪on_player_near_explodable
‪function on_player_near_explodable(object, type)
Definition: _battlechatter.gsc:370
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪get_death_vox
‪function get_death_vox(weapon, meansOfDeath)
Definition: _battlechatter.gsc:855
‪DIALOG_FLAGS_PAIN
‪#define DIALOG_FLAGS_PAIN
Definition: _battlechatter.gsc:37
‪camo_is_inuse
‪function camo_is_inuse(slot)
Definition: _gadget_active_camo.gsc:58
‪play_killstreak_threat
‪function play_killstreak_threat(killstreakType)
Definition: _battlechatter.gsc:892
‪add
‪function add(entity, dyingplayer, team, timeout)
Definition: _deathicons.gsc:43
‪grenade_tracking
‪function grenade_tracking()
Definition: _battlechatter.gsc:600
‪hero_weapon_success_reaction
‪function hero_weapon_success_reaction()
Definition: _battlechatter.gsc:717
‪stop_dialog
‪function stop_dialog()
Definition: _battlechatter.gsc:1034
‪get_closest_player_ally
‪function get_closest_player_ally(teamOnly)
Definition: _battlechatter.gsc:1537
‪__init__
‪function __init__()
Definition: _battlechatter.gsc:48
‪get_friendly_players
‪function get_friendly_players()
Definition: _battlechatter.gsc:1476
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪on_spawned
‪function on_spawned(func, obj)
Definition: callbacks_shared.csc:245
‪play_gadget_success
‪function play_gadget_success(weapon, waitKey, victim)
Definition: _battlechatter.gsc:1352
‪killed_by_sniper
‪function killed_by_sniper(sniper)
Definition: _battlechatter.gsc:432
‪flush_dialog
‪function flush_dialog()
Definition: _globallogic_audio.gsc:160
‪play_promotion_reaction
‪function play_promotion_reaction()
Definition: _battlechatter.gsc:789
‪KILL_DIALOG
‪#define KILL_DIALOG
Definition: _battlechatter.gsc:26
‪water_vox
‪function water_vox()
Definition: _battlechatter.gsc:277
‪set_blops_dialog
‪function set_blops_dialog()
Definition: _battlechatter.gsc:178
‪get_random_key
‪function get_random_key(dialogKey)
Definition: _battlechatter.gsc:1097
‪SERVER_FRAME
‪#define SERVER_FRAME
Definition: shared.gsh:264
‪DIALOG_FLAG_STOLEN_GADGET_READY
‪#define DIALOG_FLAG_STOLEN_GADGET_READY
Definition: _battlechatter.gsc:34
‪gametype_specific_battle_chatter
‪function gametype_specific_battle_chatter(event, team)
Definition: _battlechatter.gsc:838
‪on_player_spawned
‪function on_player_spawned()
Definition: _battlechatter.gsc:195
‪pick_boost_players
‪function pick_boost_players(player1, player2)
Definition: _battlechatter.gsc:1604
‪PLAY_BOOST
‪#define PLAY_BOOST
Definition: _battlechatter.gsc:44
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪DIALOG_FLAG_UNDERWATER
‪#define DIALOG_FLAG_UNDERWATER
Definition: _battlechatter.gsc:31
‪say_kill_battle_chatter
‪function say_kill_battle_chatter(attacker, weapon, victim, inflictor)
Definition: _battlechatter.gsc:513
‪count_keys
‪function count_keys(bundle, dialogKey)
Definition: _battlechatter.gsc:1074
‪BOOST_RESPONSE
‪#define BOOST_RESPONSE
Definition: _battlechatter.gsc:46
‪pain_vox
‪function pain_vox(meansofDeath)
Definition: _battlechatter.gsc:329
‪play_death_vox
‪function play_death_vox(body, attacker, weapon, meansOfDeath)
Definition: _battlechatter.gsc:844
‪wait_play_dialog
‪function wait_play_dialog(waitTime, dialogKey, dialogFlags, dialogBuffer, enemy, endNotify)
Definition: _battlechatter.gsc:902
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪reset_dialog_fields
‪function reset_dialog_fields()
Definition: _battlechatter.gsc:219
‪wait_dialog_buffer
‪function wait_dialog_buffer(dialogBuffer)
Definition: _battlechatter.gsc:1016
‪game_end_vox
‪function game_end_vox(winner)
Definition: _battlechatter.gsc:1614
‪register
‪function register()
Definition: _ai_tank.gsc:126
‪DIALOG_FLAG_ALL
‪#define DIALOG_FLAG_ALL
Definition: _battlechatter.gsc:29
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪DIALOG_FLAG_GADGET_READY
‪#define DIALOG_FLAG_GADGET_READY
Definition: _battlechatter.gsc:33
‪pick_boost_number
‪function pick_boost_number()
Definition: _battlechatter.gsc:125
‪on_connect
‪function on_connect()
Definition: _arena.gsc:20
‪leader_dialog_on_player
‪function leader_dialog_on_player(dialogKey, objectiveKey, killstreakId, dialogBufferKey, introDialog)
Definition: _globallogic_audio.gsc:460
‪DIALOG_FLAG_EXERT
‪#define DIALOG_FLAG_EXERT
Definition: _battlechatter.gsc:32
‪set_cdp_dialog
‪function set_cdp_dialog()
Definition: _battlechatter.gsc:184
‪sticky_grenade_tracking
‪function sticky_grenade_tracking()
Definition: _battlechatter.gsc:698
‪can_play_dialog
‪function can_play_dialog(teamOnly)
Definition: _battlechatter.gsc:1495
‪incoming_projectile_alert
‪function incoming_projectile_alert(thrower, projectile, dialogKey, waittime)
Definition: _battlechatter.gsc:652
‪get_enemy_players
‪function get_enemy_players()
Definition: _battlechatter.gsc:1443
‪play_throw_hatchet
‪function play_throw_hatchet()
Definition: _battlechatter.gsc:1436
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265