‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_scoreevents.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 
3 #using scripts\shared\callbacks_shared;
4 #using scripts\shared\challenges_shared;
5 #using scripts\shared\killstreaks_shared;
6 #using scripts\shared\rank_shared;
7 #using scripts\shared\scoreevents_shared;
8 #using scripts\shared\system_shared;
9 #using scripts\shared\util_shared;
10 #using scripts\shared\abilities\_ability_player;
11 #using scripts\shared\weapons\_weapon_utils;
12 
13 #insert scripts\shared\abilities\gadgets\_gadget_vision_pulse.gsh;
14 #insert scripts\shared\shared.gsh;
15 
16 #using scripts\mp\gametypes\_globallogic_score;
17 
18 #using scripts\mp\_challenges;
19 #using scripts\mp\_util;
20 #using scripts\mp\killstreaks\_killstreaks;
21 #using scripts\mp\_teamops;
22 
23 #insert scripts\shared\scoreevents_shared.gsh;
24 
25 #namespace scoreevents;
26 
27 ‪REGISTER_SYSTEM( "scoreevents", &‪__init__, undefined )
28 
29 function ‪__init__()
30 {
32 }
33 
34 function ‪init()
35 {
36  level.scoreEventCallbacks = [];
37  level.scoreEventGameEndCallback =&‪onGameEnd;
38 
40 }
41 function ‪scoreEventTableLookupInt( index, scoreEventColumn )
42 {
43  return int( tableLookup( ‪getScoreEventTableName(), 0, index, scoreEventColumn ) );
44 }
45 
46 function ‪scoreEventTableLookup( index, scoreEventColumn )
47 {
48  return tableLookup( ‪getScoreEventTableName(), 0, index, scoreEventColumn );
49 }
50 
52 {
53  if ( !isdefined( level.scoreEventCallbacks[‪callback] ) )
54  {
55  level.scoreEventCallbacks[‪callback] = [];
56  }
57  level.scoreEventCallbacks[‪callback][level.scoreEventCallbacks[‪callback].size] = func;
58 }
59 
60 function ‪scoreEventPlayerKill( data, time )
61 {
62  victim = data.victim;
63  attacker = data.attacker;
64  time = data.time;
65  level.numKills++;
66  attacker.lastKilledPlayer = victim;
67  wasDefusing = data.wasDefusing;
68  wasPlanting = data.wasPlanting;
69  victimWasOnGround = data.victimOnGround;
70  attackerWasOnGround = data.attackerOnGround;
71  meansOfDeath = data.sMeansOfDeath;
72  attackerTraversing = data.attackerTraversing;
73  attackerWallRunning = data.attackerWallRunning;
74  attackerDoubleJumping = data.attackerDoubleJumping;
75  attackerSliding = data.attackerSliding;
76  victimWasWallRunning = data.victimWasWallRunning;
77  victimWasDoubleJumping = data.victimWasDoubleJumping;
78  attackerSpeedburst = data.attackerSpeedburst;
79  victimSpeedburst = data.victimSpeedburst;
80  victimCombatEfficieny = data.victimCombatEfficieny;
81  attackerflashbackTime = data.attackerflashbackTime;
82  victimflashbackTime = data.victimflashbackTime;
83  victimSpeedburstLastOnTime = data.victimSpeedburstLastOnTime;
84  victimCombatEfficiencyLastOnTime = data.victimCombatEfficiencyLastOnTime;
85  victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
86  attackerVisionPulseActivateTime = data.attackerVisionPulseActivateTime;
87  victimVisionPulseActivateTime = data.victimVisionPulseActivateTime;
88  attackerVisionPulseArray = data.attackerVisionPulseArray;
89  victimVisionPulseArray = data.victimVisionPulseArray;
90  attackerVisionPulseOriginArray = data.attackerVisionPulseOriginArray;
91  victimVisionPulseOriginArray = data.victimVisionPulseOriginArray;
92  attackerVisionPulseOrigin = data.attackerVisionPulseOrigin;
93  victimVisionPulseOrigin = data.victimVisionPulseOrigin;
94  attackerWasFlashed = data.attackerWasFlashed;
95  attackerWasConcussed = data.attackerWasConcussed;
96  victimWasUnderwater = data.wasUnderwater;
97  victimHeroAbilityActive = data.victimHeroAbilityActive;
98  victimHeroAbility = data.victimHeroAbility;
99  attackerHeroAbilityActive = data.attackerHeroAbilityActive;
100  attackerHeroAbility = data.attackerHeroAbility;
101  attackerWasHeatWaveStunned = data.attackerWasHeatWaveStunned;
102  victimWasHeatWaveStunned = data.victimWasHeatWaveStunned;
103  victimElectrifiedBy = data.victimElectrifiedBy;
104  victimWasInSlamState = data.victimWasInSlamState;
105  victimBledOut = data.bledOut;
106  victimWasLungingWithArmBlades = data.victimWasLungingWithArmBlades;
107  victimPowerArmorLastTookDamageTime = data.victimPowerArmorLastTookDamageTime;
108  victimHeroWeaponKillsThisActivation = data.victimHeroWeaponKillsThisActivation;
109  victimGadgetPower = data.victimGadgetPower;
110  victimGadgetWasActiveLastDamage = ( data.victimGadgetWasActiveLastDamage === true );
111  victimIsThiefOrRoulette = data.victimIsThiefOrRoulette;
112  attackerIsRoulette = data.attackerIsRoulette;
113  victimHeroAbilityName = data.victimHeroAbilityName; // note that victim hero ability name cannot be reliably taken from victimHeroAbility, so this is done instead
114  attackerInVehicleArchetype = data.attackerInVehicleArchetype;
115  if ( isdefined( victimHeroAbilityName ) )
116  victimHeroAbilityEquipped = GetWeapon( victimHeroAbilityName );
117 
118  if ( victimBledOut == true ) // do not process player killed score events if the player bled out
119  return;
120 
121  exlosiveDamage = false;
122  attackerShotVictim = ( meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_RIFLE_BULLET" || meansOfDeath == "MOD_HEAD_SHOT" );
123 
124  weapon = level.weaponNone;
125  inflictor = data.eInflictor;
126  isGrenade = false;
127  if ( isdefined( data.weapon ) )
128  {
129  weapon = data.weapon;
130  weaponClass = ‪util::getWeaponClass( data.weapon );
131  isGrenade = weapon.isGrenadeWeapon;
132  killstreak = ‪killstreaks::get_from_weapon( data.weapon );
133  }
134 
135  victim.anglesOnDeath = victim getPlayerAngles();
136 
137  if ( meansOfDeath == "MOD_GRENADE" || meansOfDeath == "MOD_GRENADE_SPLASH" || meansOfDeath == "MOD_EXPLOSIVE" || meansOfDeath == "MOD_EXPLOSIVE_SPLASH" || meansOfDeath == "MOD_PROJECTILE" || meansOfDeath == "MOD_PROJECTILE_SPLASH" )
138  {
139  if ( weapon == level.weaponNone && isdefined( data.victim.explosiveInfo["weapon"] ) )
140  weapon = data.victim.explosiveInfo["weapon"];
141 
142  exlosiveDamage = true;
143  }
144 
145 
146  if ( !isdefined( killstreak ) )
147  {
148  if ( level.teamBased )
149  {
150  if ( isdefined( victim.lastKillTime ) && ( victim.lastKillTime > time - 3000 ) )
151  {
152  if ( isdefined( victim.lastkilledplayer ) && victim.lastkilledplayer ‪util::IsEnemyPlayer( attacker ) == false && attacker != victim.lastkilledplayer )
153  {
154  ‪processScoreEvent( "kill_enemy_who_killed_teammate", attacker, victim, weapon );
155  victim RecordKillModifier("avenger");
156  }
157  }
158 
159  if ( isdefined( victim.damagedPlayers ) )
160  {
161  keys = getarraykeys(victim.damagedPlayers);
162 
163  for ( i = 0; i < keys.size; i++ )
164  {
165  key = keys[i];
166  if ( key == attacker.clientid )
167  continue;
168 
169  if ( !isdefined( victim.damagedPlayers[key].entity ) )
170  continue;
171 
172  if ( attacker ‪util::IsEnemyPlayer( victim.damagedPlayers[key].entity ) )
173  continue;
174 
175  if ( ( time - victim.damagedPlayers[key].time ) < 1000 )
176  {
177  ‪processScoreEvent( "kill_enemy_injuring_teammate", attacker, victim, weapon );
178  if ( isdefined( victim.damagedPlayers[key].entity ) )
179  {
180  victim.damagedPlayers[key].entity.lastRescuedBy = attacker;
181  victim.damagedPlayers[key].entity.lastRescuedTime = time;
182  }
183  victim RecordKillModifier("defender");
184  }
185  }
186  }
187  }
188 
189  if ( isGrenade == false || ( weapon.name == "hero_gravityspikes" ) )
190  {
191  if ( victimWasDoubleJumping == true )
192  {
193  if ( attackerDoubleJumping == true )
194  {
195  ‪processScoreEvent( "kill_enemy_while_both_in_air", attacker, victim, weapon );
196  }
197 
198  ‪processScoreEvent( "kill_enemy_that_is_in_air", attacker, victim, weapon );
199  attacker addPlayerStat( "kill_enemy_that_in_air", 1 );
200  }
201 
202  if ( attackerDoubleJumping == true )
203  {
204  ‪processScoreEvent( "kill_enemy_while_in_air", attacker, victim, weapon );
205  attacker addPlayerStat( "kill_while_in_air", 1 );
206  }
207 
208  if ( victimWasWallRunning == true )
209  {
210  ‪processScoreEvent( "kill_enemy_that_is_wallrunning", attacker, victim, weapon );
211  attacker addPlayerStat( "kill_enemy_thats_wallrunning", 1 );
212  }
213 
214  if ( attackerWallRunning == true )
215  {
216  ‪processScoreEvent( "kill_enemy_while_wallrunning", attacker, victim, weapon );
217  attacker addPlayerStat( "kill_while_wallrunning", 1 );
218  }
219 
220  if ( attackerSliding == true )
221  {
222  ‪processScoreEvent( "kill_enemy_while_sliding", attacker, victim, weapon );
223  attacker addPlayerStat( "kill_while_sliding", 1 );
224  }
225 
226  if ( attackerTraversing == true )
227  {
228  ‪processScoreEvent( "traversal_kill", attacker, victim, weapon );
229  attacker addPlayerStat( "kill_while_mantling", 1 );
230  }
231 
232  if ( attackerWasFlashed )
233  {
234  ‪processScoreEvent( "kill_enemy_while_flashbanged", attacker, victim, weapon );
235  }
236 
237  if ( attackerWasConcussed )
238  {
239  ‪processScoreEvent( "kill_enemy_while_stunned", attacker, victim, weapon );
240  }
241 
242  if ( attackerWasHeatWaveStunned )
243  {
244  ‪processScoreEvent( "kill_enemy_that_heatwaved_you", attacker, victim, weapon );
245  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
246  }
247 
248  if ( victimWasHeatWaveStunned )
249  {
250  if ( isdefined( victim._heat_wave_stunned_by ) &&
251  isdefined( victim._heat_wave_stunned_by[attacker.clientid] ) &&
252  victim._heat_wave_stunned_by[attacker.clientid] >= time )
253  {
254  ‪processScoreEvent( "heatwave_kill", attacker, victim, weapon );
255  attacker ‪hero_ability_kill_event( getWeapon( "gadget_heat_wave" ), ‪get_equipped_hero_ability( victimHeroAbilityName ) );
257  attacker thread ‪specialistStatAbilityUsage( 4, false );
258  }
259 
260  if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_heat_wave" )
261  {
262  ‪processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
263  }
264  }
265  }
266 
267  if ( attackerSpeedburst == true )
268  {
269  ‪processScoreEvent( "speed_burst_kill", attacker, victim, weapon );
270  attacker ‪hero_ability_kill_event( GetWeapon( "gadget_speed_burst" ), ‪get_equipped_hero_ability( victimHeroAbilityName ) );
272  attacker thread ‪specialistStatAbilityUsage( 4, false );
273 
274  if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_speed_burst" )
275  {
276  ‪processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
277  }
278  }
279 
280  if ( victimSpeedburstLastOnTime > time - 50 )
281  {
282  ‪processScoreEvent( "kill_enemy_who_is_speedbursting", attacker, victim, weapon );
283  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
284  }
285 
286  if ( victimCombatEfficiencyLastOnTime > time - 50 )
287  {
288  ‪processScoreEvent( "kill_enemy_who_is_using_focus", attacker, victim, weapon );
289  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
290  }
291 
292  if ( attackerflashbackTime != 0 && attackerflashbackTime > time - 4000 )
293  {
294  ‪processScoreEvent( "flashback_kill", attacker, victim, weapon );
295  attacker ‪hero_ability_kill_event( GetWeapon( "gadget_flashback" ), ‪get_equipped_hero_ability( victimHeroAbilityName ) );
297  attacker thread ‪specialistStatAbilityUsage( 4, false );
298 
299  if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_flashback" )
300  {
301  ‪processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
302  }
303  }
304 
305  if ( victimflashbackTime != 0 && victimflashbackTime > time - 4000 )
306  {
307  ‪processScoreEvent( "kill_enemy_who_has_flashbacked", attacker, victim, weapon );
308  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
309  }
310 
311  if ( victimWasInSlamState )
312  {
313  ‪processScoreEvent( "end_enemy_gravity_spike_attack", attacker, victim, weapon );
314  attacker ‪util::player_contract_event( "killed_hero_weapon_enemy" );
315  }
316 
318  {
319  ‪processScoreEvent( "kill_enemy_who_has_high_score", attacker, victim, weapon );
320  }
321 
322  if ( victimWasUnderwater && exlosiveDamage )
323  {
324  ‪processScoreEvent( "kill_underwater_enemy_explosive", attacker, victim, weapon );
325  }
326 
327  if ( isdefined ( victimElectrifiedBy ) && victimElectrifiedBy != attacker )
328  {
329  ‪processScoreEvent( "electrified", victimElectrifiedBy, victim, weapon );
330  }
331 
332  if ( victimVisionPulseActivateTime != 0 && victimVisionPulseActivateTime > time - 4000 )
333  {
334  gadgetWeapon = getWeapon("gadget_vision_pulse");
335  for ( i = 0; i < victimVisionPulseArray.size; i++ )
336  {
337  player = victimVisionPulseArray[i];
338  if ( player == attacker )
339  {
340  gadget = GetWeapon( "gadget_vision_pulse" );
341 
342  if ( victimVisionPulseActivateTime + 300 > time - gadgetWeapon.gadget_pulse_duration )
343  {
344  distanceToPulse = distance( victimVisionPulseOriginArray[i], victimVisionPulseOrigin );
345 
346  ratio = distanceToPulse / gadgetWeapon.gadget_pulse_max_range;
347  timing = ratio * gadgetWeapon.gadget_pulse_duration;
348  if ( victimVisionPulseActivateTime + 300 > time - timing )
349  {
350  break;
351  }
352  }
353 
354  ‪processScoreEvent( "kill_enemy_that_pulsed_you", attacker, victim, weapon );
355  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
356  break;
357  }
358  }
359 
360  if ( isdefined( victimHeroAbility ) )
361  {
362  attacker notify( "hero_shutdown", victimHeroAbility );
363  attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
364  }
365  }
366 
367  if ( attackerVisionPulseActivateTime != 0 && attackerVisionPulseActivateTime > time - ( ‪VISION_PULSE_DURATION + ‪VISION_PULSE_REVEAL_TIME + 500 ) )
368  {
369  gadgetWeapon = getWeapon("gadget_vision_pulse");
370  for ( i = 0; i < attackerVisionPulseArray.size; i++ )
371  {
372  player = attackerVisionPulseArray[i];
373  if ( player == victim )
374  {
375  gadget = GetWeapon( "gadget_vision_pulse" );
376 
377  if ( attackerVisionPulseActivateTime > time - gadgetWeapon.gadget_pulse_duration )
378  {
379  distanceToPulse = distance( attackerVisionPulseOriginArray[i], attackerVisionPulseOrigin );
380 
381  ratio = distanceToPulse / gadgetWeapon.gadget_pulse_max_range;
382  timing = ratio * gadgetWeapon.gadget_pulse_duration;
383  if ( attackerVisionPulseActivateTime > time - timing )
384  {
385  break;
386  }
387  }
388 
389  ‪processScoreEvent( "vision_pulse_kill", attacker, victim, weapon );
390  attacker ‪hero_ability_kill_event( gadgetWeapon, ‪get_equipped_hero_ability( victimHeroAbilityName ) );
392  attacker thread ‪specialistStatAbilityUsage( 4, false );
393 
394  if ( attackerIsRoulette && !victimIsThiefOrRoulette && victimHeroAbilityName === "gadget_vision_pulse" )
395  {
396  ‪processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
397  }
398  break;
399  }
400  }
401  }
402 
403  if ( victimHeroAbilityActive && isdefined ( victimHeroAbility ) )
404  {
405  attacker notify( "hero_shutdown", victimHeroAbility );
406  attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
407 
408  switch( victimHeroAbility.name )
409  {
410  case "gadget_armor":
411  ‪processScoreEvent( "kill_enemy_who_has_powerarmor", attacker, victim, weapon );
412  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
413  break;
414  case "gadget_resurrect":
415  ‪processScoreEvent( "kill_enemy_that_used_resurrect", attacker, victim, weapon );
416  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
417  break;
418  case "gadget_camo":
419  ‪processScoreEvent( "kill_enemy_that_is_using_optic_camo", attacker, victim, weapon );
420  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
421  break;
422  case "gadget_clone":
423  ‪processScoreEvent( "end_enemy_psychosis", attacker, victim, weapon );
424  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
425  break;
426  }
427  }
428  else
429  {
430  if ( isdefined( victimPowerArmorLastTookDamageTime ) && ( time - victimPowerArmorLastTookDamageTime <= 3000 ) )
431  {
432  attacker notify( "hero_shutdown", victimHeroAbility );
433  attacker notify( "hero_shutdown_gadget", victimHeroAbility, victim );
434  ‪processScoreEvent( "kill_enemy_who_has_powerarmor", attacker, victim, weapon );
435  attacker ‪util::player_contract_event( "killed_hero_ability_enemy" );
436  }
437  }
438 
439 
440  if ( isdefined( data.victimWeapon ) && isdefined( data.victimWeapon.isHeroWeapon ) && data.victimWeapon.isHeroWeapon == true )
441  {
442  attacker notify( "hero_shutdown", data.victimWeapon );
443  attacker notify( "hero_shutdown_gadget", data.victimWeapon, victim );
444  }
445  else if ( isdefined( victim.heroWeapon ) && victimGadgetWasActiveLastDamage && victimGadgetPower < 100 )
446  {
447  // need to do this for some hero weapons like armblades
448  attacker notify( "hero_shutdown", victim.heroWeapon );
449  attacker notify( "hero_shutdown_gadget", victim.heroWeapon, victim );
450  }
451 
452  if ( attackerHeroAbilityActive && isdefined ( attackerHeroAbility ) )
453  {
454  abilityToCheck = undefined;
455 
456  switch( attackerHeroAbility.name )
457  {
458  case "gadget_armor":
459  {
460  ‪processScoreEvent( "power_armor_kill", attacker, victim, weapon );
461  attacker ‪hero_ability_kill_event( attackerHeroAbility, ‪get_equipped_hero_ability( victimHeroAbilityName ) );
463  attacker thread ‪specialistStatAbilityUsage( 4, false );
464  abilityToCheck = attackerHeroAbility.name;
465  }
466  break;
467  case "gadget_resurrect":
468  {
469  ‪processScoreEvent( "resurrect_kill", attacker, victim, weapon );
470  attacker ‪hero_ability_kill_event( attackerHeroAbility, ‪get_equipped_hero_ability( victimHeroAbilityName ) );
472  attacker thread ‪specialistStatAbilityUsage( 4, false );
473  abilityToCheck = attackerHeroAbility.name;
474  }
475  break;
476  case "gadget_camo":
477  {
478  ‪processScoreEvent( "optic_camo_kill", attacker, victim, weapon );
479  attacker ‪hero_ability_kill_event( attackerHeroAbility, ‪get_equipped_hero_ability( victimHeroAbilityName ) );
481  attacker thread ‪specialistStatAbilityUsage( 4, false );
482  abilityToCheck = attackerHeroAbility.name;
483  }
484  break;
485  case "gadget_clone":
486  {
487  ‪processScoreEvent( "kill_enemy_while_using_psychosis", attacker, victim, weapon );
488  attacker ‪hero_ability_kill_event( attackerHeroAbility, ‪get_equipped_hero_ability( victimHeroAbilityName ) );
490  attacker thread ‪specialistStatAbilityUsage( 4, false );
491  abilityToCheck = attackerHeroAbility.name;
492  }
493  break;
494  }
495 
496  if ( attackerIsRoulette && !victimIsThiefOrRoulette && isdefined( abilityToCheck ) && victimHeroAbilityName === abilityToCheck )
497  {
498  ‪processScoreEvent( "kill_enemy_with_their_hero_ability", attacker, victim, weapon );
499  }
500  }
501 
502  if ( victimWasLungingWithArmBlades )
503  {
504  ‪processScoreEvent( "end_enemy_armblades_attack", attacker, victim, weapon );
505  }
506 
507  if ( isdefined( data.victimWeapon ) )
508  {
509  ‪killedHeroWeaponEnemy( attacker, victim, weapon, data.victimWeapon, victimGadgetPower, victimGadgetWasActiveLastDamage );
510 
511  if ( data.victimWeapon.name == "minigun" )
512  {
513  ‪processScoreEvent( "killed_death_machine_enemy", attacker, victim, weapon );
514  }
515  else if ( data.victimWeapon.name == "m32" )
516  {
517  ‪processScoreEvent( "killed_multiple_grenade_launcher_enemy", attacker, victim, weapon );
518  }
519 
520  // armblade is special case since the victimWeapon can be a primary or secondary weapon
521  is_hero_armblade_and_active = ( isdefined( victim.heroweapon ) && victim.heroweapon.name == "hero_armblade" && victimGadgetWasActiveLastDamage );
522 
523  if ( ( data.victimWeapon.inventorytype == "hero" || is_hero_armblade_and_active ) && victimGadgetPower < 100 )
524  {
525  if ( victimHeroWeaponKillsThisActivation == 0 )
526  {
527  attacker AddPlayerStat( "kill_before_specialist_weapon_use", 1 );
528  }
529 
530  if ( weapon.inventorytype == "hero" )
531  {
532  attacker AddPlayerStat( "kill_specialist_with_specialist", 1 );
533  }
534 
535  // add here
536  attacker_is_thief = ( isdefined( attacker.heroweapon ) && attacker.heroweapon.name == "gadget_thief" );
537  if ( !attacker_is_thief )
538  {
539  ‪processScoreEvent( "end_enemy_specialist_weapon", attacker, victim, weapon );
540  }
541  }
542  }
543 
544  if ( weapon.rootweapon.name == "frag_grenade" )
545  {
546  attacker thread ‪updateSingleFragMultiKill( victim, weapon, weaponClass, killstreak );
547  }
548 
549  attacker thread updateMultiKills( weapon, weaponClass, killstreak, victim );
550 
551  if ( level.numKills == 1 )
552  {
553  victim RecordKillModifier("firstblood");
554  ‪processScoreEvent( "first_kill", attacker, victim, weapon );
555  }
556  else
557  {
558  if ( isdefined( attacker.lastKilledBy ) )
559  {
560  if ( attacker.lastKilledBy == victim )
561  {
562  level.globalPaybacks++;
563  ‪processScoreEvent( "revenge_kill", attacker, victim, weapon );
564  attacker AddWeaponStat( weapon, "revenge_kill", 1 );
565  victim RecordKillModifier("revenge");
566  attacker.lastKilledBy = undefined;
567  }
568  }
569  if ( victim ‪killstreaks::is_an_a_killstreak() )
570  {
571  level.globalBuzzKills++;
572  ‪processScoreEvent( "stop_enemy_killstreak", attacker, victim, weapon );
573  victim RecordKillModifier("buzzkill");
574  }
575  if ( isdefined( victim.lastManSD ) && victim.lastManSD == true )
576  {
577  ‪processScoreEvent( "final_kill_elimination", attacker, victim, weapon );
578  if ( isdefined( attacker.lastManSD ) && attacker.lastManSD == true )
579  {
580  ‪processScoreEvent( "elimination_and_last_player_alive", attacker, victim, weapon );
581  }
582  }
583  }
584 
585  if ( ‪is_weapon_valid( meansOfDeath, weapon, weaponClass, killstreak ) )
586  {
587  if ( isdefined( victim.vAttackerOrigin ) )
588  attackerOrigin = victim.vAttackerOrigin;
589  else
590  attackerOrigin = attacker.origin;
591  distToVictim = distanceSquared( victim.origin, attackerOrigin );
592  weap_min_dmg_range = ‪get_distance_for_weapon( weapon, weaponClass );
593  if ( distToVictim > weap_min_dmg_range )
594  {
595  attacker ‪challenges::longDistanceKillMP( weapon );
596  if ( weapon.rootweapon.name == "hatchet" )
597  {
599  }
600  ‪processScoreEvent( "longshot_kill", attacker, victim, weapon );
601  attacker.pers["longshots"]++;
602  attacker.longshots = attacker.pers["longshots"];
603  victim RecordKillModifier("longshot");
604  }
605 
606  // Record kill distances and num of entries
607  killdistance = distance( victim.origin, attackerOrigin );
608  attacker.pers["kill_distances"] += killdistance;
609  attacker.pers["num_kill_distance_entries"]++;
610  }
611 
612  if ( isAlive( attacker ) )
613  {
614  if ( attacker.health < ( attacker.maxHealth * 0.35 ) )
615  {
616  attacker.lastKillWhenInjured = time;
617  ‪processScoreEvent( "kill_enemy_when_injured", attacker, victim, weapon );
618 
619  attacker AddWeaponStat( weapon, "kill_enemy_when_injured", 1 );
621  {
622  attacker AddPlayerStat( "perk_bulletflinch_kills", 1 );
623  }
624  }
625  }
626  else
627  {
628  if ( isdefined( attacker.deathtime ) && ( ( attacker.deathtime + 800 ) < time ) && !attacker IsInVehicle() )
629  {
630  level.globalAfterlifes++;
631  ‪processScoreEvent( "kill_enemy_after_death", attacker, victim, weapon );
632  victim RecordKillModifier("posthumous");
633  }
634  }
635 
636  if( attacker.cur_death_streak >= SCORE_EVENT_DEATH_STREAK_COUNT_REQUIRED )
637  {
638  level.globalComebacks++;
639  ‪processScoreEvent( "comeback_from_deathstreak", attacker, victim, weapon );
640  victim RecordKillModifier("comeback");
641  }
642 
643  if ( isdefined( victim.lastMicrowavedBy ) )
644  {
645  foreach( beingMicrowavedBy in victim.beingMicrowavedBy )
646  {
647  if ( isdefined( beingMicrowavedBy ) && ( attacker ‪util::IsEnemyPlayer( beingMicrowavedBy ) == false ) )
648  {
649  if ( beingMicrowavedBy != attacker )
650  {
651  scoreGiven = ‪processScoreEvent( "microwave_turret_assist", beingMicrowavedBy, victim, weapon );
652  if ( isdefined ( scoreGiven ) )
653  {
654  beingMicrowavedBy ‪challenges::earnedMicrowaveAssistScore( scoreGiven );
655  }
656  }
657  else
658  {
659  attackerMicrowavedVictim = true;
660  }
661  }
662  }
663 
664  if ( attackerMicrowavedVictim === true && weapon.name != "microwave_turret" )
665  {
667  }
668  }
669 
670  if ( ‪weapon_utils::isMeleeMOD( meansOfDeath ) && !weapon.isRiotShield )
671  {
672  // "stabs" are now "melees"
673  attacker.pers["stabs"]++;
674  attacker.stabs = attacker.pers["stabs"];
675 
676  if ( meansOfDeath == "MOD_MELEE_WEAPON_BUTT" && weapon.name != "ball" )
677  {
678  ‪processScoreEvent( "kill_enemy_with_gunbutt", attacker, victim, weapon );
679  }
680  else if ( ‪weapon_utils::isPunch( weapon ) )
681  {
682  ‪processScoreEvent( "kill_enemy_with_fists", attacker, victim, weapon );
683  }
684  else if ( ‪weapon_utils::isNonBareHandsMelee( weapon ) )
685  {
686  vAngles = victim.anglesOnDeath[1];
687  pAngles = attacker.anglesOnKill[1];
688  angleDiff = AngleClamp180( vAngles - pAngles );
689 
690  if ( angleDiff > -30 && angleDiff < 70 )
691  {
692  level.globalBackstabs++;
693  ‪processScoreEvent( "backstabber_kill", attacker, victim, weapon );
694 
695  weaponPickedUp = false;
696  if( isdefined( attacker.pickedUpWeapons ) && isdefined( attacker.pickedUpWeapons[weapon] ) )
697  {
698  weaponPickedUp = true;
699  }
700 
701  attacker AddWeaponStat( weapon, "backstabber_kill", 1, attacker.class_num, weaponPickedUp, undefined, attacker.primaryLoadoutGunSmithVariantIndex, attacker.secondaryLoadoutGunSmithVariantIndex );
702  attacker.pers["backstabs"]++;
703  attacker.backstabs = attacker.pers["backstabs"];
704  }
705  }
706  }
707  else
708  {
709  if ( isdefined ( victim.firstTimeDamaged ) && victim.firstTimeDamaged == time && !‪IS_TRUE( weapon.isHeroWeapon ) )
710  {
711  if ( attackerShotVictim )
712  {
713  attacker thread updateOneShotMultiKills( victim, weapon, victim.firstTimeDamaged );
714  attacker AddWeaponStat( weapon, "kill_enemy_one_bullet", 1 );
715  }
716  }
717  }
718 
719  if ( isdefined( attacker.tookWeaponFrom[ weapon ] ) && isdefined( attacker.tookWeaponFrom[ weapon ].previousOwner ) )
720  {
721  pickedUpWeapon = attacker.tookWeaponFrom[ weapon ];
722  if ( pickedUpWeapon.previousOwner == victim )
723  {
724  ‪processScoreEvent( "kill_enemy_with_their_weapon", attacker, victim, weapon );
725  attacker AddWeaponStat( weapon, "kill_enemy_with_their_weapon", 1 );
726  if ( isdefined( pickedUpWeapon.sWeapon ) && isdefined( pickedUpWeapon.sMeansOfDeath ) && ‪weapon_utils::isMeleeMOD( pickedUpWeapon.sMeansOfDeath ) )
727  {
728  foreach( meleeWeapon in level.meleeWeapons )
729  {
730  if ( weapon != meleeWeapon && pickedUpWeapon.sWeapon.rootweapon == meleeWeapon )
731  {
732  attacker AddWeaponStat( meleeWeapon, "kill_enemy_with_their_weapon", 1 );
733  break; // once found and handled, no need to continue
734  }
735  }
736  }
737  }
738  }
739 
740  if ( wasDefusing )
741  {
742  ‪processScoreEvent( "killed_bomb_defuser", attacker, victim, weapon );
743  }
744  else if ( wasPlanting )
745  {
746  ‪processScoreEvent( "killed_bomb_planter", attacker, victim, weapon );
747  }
748 
749  ‪heroWeaponKill( attacker, victim, weapon );
750 
751  } // end if ( !isdefined( killstreak ) )
752 
753  ‪specificWeaponKill( attacker, victim, weapon, killstreak, inflictor );
754 
755  if( isdefined( level.vtol ) && isdefined( level.vtol.owner ) && ( weapon.name == "helicopter_gunner_turret_secondary" || weapon.name == "helicopter_gunner_turret_tertiary" ) )
756  {
757  attacker addplayerstat( "kill_as_support_gunner", 1 );
758 
759  ‪processScoreEvent( "mothership_assist_kill", level.vtol.owner, victim, weapon );
760  }
761 
762  if ( isdefined( attackerInVehicleArchetype ) )
763  {
764  if ( attackerInVehicleArchetype == "siegebot" )
765  {
766  if ( meansOfDeath == "MOD_CRUSH" )
767  {
768  ‪processScoreEvent( "kill_enemy_with_siegebot_crush", attacker, victim, weapon );
769  }
770 
771  ‪DEFAULT( attacker.siegebot_kills, 0 );
772 
773  attacker.siegebot_kills++;
774 
775  if ( attacker.siegebot_kills % 5 == 0 )
776  {
777  ‪processScoreEvent( "siegebot_killstreak_5", attacker, victim, weapon );
778  }
779  }
780  }
781 
782  switch ( weapon.rootweapon.name )
783  {
784  case "hatchet":
785  {
786  attacker.pers["tomahawks"]++;
787  attacker.tomahawks = attacker.pers["tomahawks"];
788 
789  ‪processScoreEvent( "hatchet_kill", attacker, victim, weapon );
790 
791  if ( isdefined( data.victim.explosiveInfo["projectile_bounced"] ) && data.victim.explosiveInfo["projectile_bounced"] == true )
792  {
793  level.globalBankshots++;
794 
795  ‪processScoreEvent( "bounce_hatchet_kill", attacker, victim, weapon );
796  }
797  }
798  break;
799  case "supplydrop":
800  case "inventory_supplydrop":
801  case "supplydrop_marker":
802  case "inventory_supplydrop_marker":
803  {
804  if ( meansOfDeath == "MOD_HIT_BY_OBJECT" || meansOfDeath == "MOD_CRUSH" )
805  {
806  ‪processScoreEvent( "kill_enemy_with_care_package_crush", attacker, victim, weapon );
807  }
808  else
809  {
810  ‪processScoreEvent( "kill_enemy_with_hacked_care_package", attacker, victim, weapon );
811  }
812  }
813  break;
814 
815  }
816 
817  if( isdefined( killstreak ) )
818  {
819  attacker thread updateMultiKills( weapon, weaponClass, killstreak, victim );
820 
821  victim RecordKillModifier("killstreak");
822  }
823 
824  attacker.cur_death_streak = 0;
825  attacker disabledeathstreak();
826 }
827 
828 function ‪get_equipped_hero_ability( ability_name )
829 {
830  if ( !isdefined( ability_name ) )
831  return undefined;
832 
833  return GetWeapon( ability_name );
834 }
835 
836 function ‪heroWeaponKill( attacker, victim, weapon )
837 {
838  if ( !isdefined( weapon ) )
839  {
840  return;
841  }
842 
843  if ( isdefined( weapon.isHeroWeapon ) && !weapon.isHeroWeapon )
844  {
845  return;
846  }
847 
848  switch( weapon.name )
849  {
850  case "hero_minigun":
851  case "hero_minigun_body3":
852  event = "minigun_kill";
853  break;
854  case "hero_flamethrower":
855  event = "flamethrower_kill";
856  break;
857  case "hero_lightninggun":
858  case "hero_lightninggun_arc":
859  event = "lightninggun_kill";
860  break;
861  case "hero_chemicalgelgun":
862  case "hero_firefly_swarm":
863  event = "gelgun_kill";
864  break;
865  case "hero_pineapplegun":
866  case "hero_pineapple_grenade":
867  event = "pineapple_kill";
868  break;
869  case "hero_armblade":
870  event = "armblades_kill";
871  break;
872  case "hero_bowlauncher":
873  case "hero_bowlauncher2":
874  case "hero_bowlauncher3":
875  case "hero_bowlauncher4":
876  event = "bowlauncher_kill";
877  break;
878  case "hero_gravityspikes":
879  event = "gravityspikes_kill";
880  break;
881  case "hero_annihilator":
882  event = "annihilator_kill";
883  break;
884  default:
885  return;
886  }
887 
888  ‪processScoreEvent( event, attacker, victim, weapon );
889 }
890 
891 function ‪killedHeroWeaponEnemy( attacker, victim, weapon, victim_weapon, victim_gadget_power, victimGadgetWasActiveLastDamage )
892 {
893  if ( !isdefined( victim_weapon ) )
894  {
895  return;
896  }
897 
898  if ( victim_gadget_power >= 100 )
899  return;
900 
901  switch( victim_weapon.name )
902  {
903  case "hero_minigun":
904  case "hero_minigun_body3":
905  event = "killed_minigun_enemy";
906  break;
907  case "hero_flamethrower":
908  event = "killed_flamethrower_enemy";
909  break;
910  case "hero_lightninggun":
911  case "hero_lightninggun_arc":
912  event = "killed_lightninggun_enemy";
913  break;
914  case "hero_chemicalgelgun":
915  event = "killed_gelgun_enemy";
916  break;
917  case "hero_pineapplegun":
918  event = "killed_pineapple_enemy";
919  break;
920  case "hero_bowlauncher":
921  case "hero_bowlauncher2":
922  case "hero_bowlauncher3":
923  case "hero_bowlauncher4":
924  event = "killed_bowlauncher_enemy";
925  break;
926  case "hero_gravityspikes":
927  event = "killed_gravityspikes_enemy";
928  break;
929  case "hero_annihilator":
930  event = "killed_annihilator_enemy";
931  break;
932 
933  default:
934  if ( isdefined( victim.heroWeapon ) && victim.heroWeapon.name == "hero_armblade" && victimGadgetWasActiveLastDamage )
935  {
936  event = "killed_armblades_enemy";
937  }
938  else
939  {
940  return;
941  }
942  }
943 
944  ‪processScoreEvent( event, attacker, victim, weapon );
945  attacker ‪util::player_contract_event( "killed_hero_weapon_enemy" );
946 }
947 
948 function ‪specificWeaponKill( attacker, victim, weapon, killstreak, inflictor )
949 {
950  switchWeapon = weapon.name;
951 
952  if( isdefined( killstreak ) )
953  {
954  switchWeapon = killstreak;
955  }
956  switch( switchWeapon )
957  {
958  case "remote_missile":
959  case "inventory_remote_missile":
960  event = "remote_missile_kill";
961  break;
962  case "autoturret":
963  case "inventory_autoturret":
964  event = "sentry_gun_kill";
965  break;
966  case "planemortar":
967  case "inventory_planemortar":
968  event = "plane_mortar_kill";
969  break;
970  case "ai_tank_drop":
971  case "inventory_ai_tank_drop":
972  event = "aitank_kill";
973  if ( isdefined( inflictor ) && isdefined( inflictor.controlled ) )
974  {
975  if ( inflictor.controlled == true )
976  {
977  attacker addPlayerStat( "kill_with_controlled_ai_tank", 1 );
978  }
979  }
980  break;
981  case "microwave_turret":
982  case "inventory_microwave_turret":
983  case "microwaveturret":
984  case "inventory_microwaveturret":
985  event = "microwave_turret_kill";
986  break;
987  case "raps":
988  case "inventory_raps":
989  event = "raps_kill";
990  break;
991  case "sentinel":
992  case "inventory_sentinel":
993  {
994  event = "sentinel_kill";
995  if ( isdefined( inflictor ) && isdefined( inflictor.controlled ) )
996  {
997  if ( inflictor.controlled == true )
998  {
999  attacker addPlayerStat( "kill_with_controlled_sentinel", 1 );
1000  }
1001  }
1002  }
1003  break;
1004  case "combat_robot":
1005  case "inventory_combat_robot":
1006  event = "combat_robot_kill";
1007  break;
1008  case "rcbomb":
1009  case "inventory_rcbomb":
1010  event = "hover_rcxd_kill";
1011  break;
1012  case "helicopter_gunner":
1013  case "helicopter_gunner_assistant":
1014  case "inventory_helicopter_gunner":
1015  case "inventory_helicopter_gunner_assistant":
1016  event = "vtol_mothership_kill";
1017  break;
1018  case "helicopter_comlink":
1019  case "inventory_helicopter_comlink":
1020  event = "helicopter_comlink_kill";
1021  break;
1022  case "drone_strike":
1023  case "inventory_drone_strike":
1024  event = "drone_strike_kill";
1025  break;
1026  case "dart":
1027  case "inventory_dart":
1028  case "dart_turret":
1029  event = "dart_kill";
1030  break;
1031  default:
1032  return;
1033  }
1034 
1035  if ( isdefined( inflictor ) )
1036  {
1037  if ( isdefined( inflictor.killstreak_id ) && isdefined( level.matchRecorderKillstreakKills[inflictor.killstreak_id] ) )
1038  {
1039  level.matchRecorderKillstreakKills[inflictor.killstreak_id]++;
1040  }
1041  else if ( isdefined( inflictor.killcament ) && isdefined( inflictor.killcament.killstreak_id ) && isdefined( level.matchRecorderKillstreakKills[inflictor.killcament.killstreak_id] ) )
1042  {
1043  level.matchRecorderKillstreakKills[inflictor.killcament.killstreak_id]++;
1044  }
1045  }
1046 
1047  ‪processScoreEvent( event, attacker, victim, weapon );
1048 }
1049 
1050 function ‪multiKill( killCount, weapon )
1051 {
1052  assert( killCount > 1 );
1053 
1054  self ‪challenges::multiKill( killCount, weapon );
1055 
1056  if ( killCount > 8 )
1057  {
1058  ‪processScoreEvent( "multikill_more_than_8", self, undefined, weapon );
1059  }
1060  else
1061  {
1062  ‪processScoreEvent( "multikill_" + killCount, self, undefined, weapon );
1063  }
1064 
1065  if ( killCount > 2 )
1066  {
1067  if ( isdefined( self.challenge_objectiveDefensiveKillcount ) && self.challenge_objectiveDefensiveKillcount > 0 )
1068  {
1069  self.challenge_objectiveDefensiveTripleKillMedalOrBetterEarned = true;
1070  }
1071  }
1072 
1073  self RecordMultiKill( killCount );
1074 }
1075 
1076 function ‪multiHeroAbilityKill( killCount, weapon )
1077 {
1078  if ( killcount > 1 )
1079  {
1080  self addPlayerStat( "multikill_2_with_heroability", int( killCount / 2 ) );
1081  self AddWeaponStat( weapon, "heroability_doublekill", int( killCount / 2 ) );
1082  self addPlayerStat( "multikill_3_with_heroability", int( killCount / 3 ) );
1083  self AddWeaponStat( weapon, "heroability_triplekill", int( killCount / 3 ) );
1084  }
1085 }
1086 
1087 function ‪is_weapon_valid( meansOfDeath, weapon, weaponClass, killstreak )
1088 {
1089  valid_weapon = false;
1090 
1091  if ( isdefined( killstreak ) )
1092  valid_weapon = false;
1093  else if ( ‪get_distance_for_weapon( weapon, weaponClass ) == 0 )
1094  valid_weapon = false;
1095  else if ( meansOfDeath == "MOD_PISTOL_BULLET" || meansOfDeath == "MOD_RIFLE_BULLET" )
1096  valid_weapon = true;
1097  else if ( meansOfDeath == "MOD_HEAD_SHOT" )
1098  valid_weapon = true;
1099  else if ( weapon.rootweapon.name == "hatchet" && meansOfDeath == "MOD_IMPACT" )
1100  valid_weapon = true;
1101  else
1102  {
1103  baseWeapon = ‪challenges::getBaseWeapon( weapon );
1104  if ( baseWeapon == level.weaponSpecialCrossbow && meansOfDeath == "MOD_IMPACT" )
1105  valid_weapon = true;
1106  else if ( baseWeapon == level.weaponBallisticKnife && meansOfDeath == "MOD_IMPACT" )
1107  valid_weapon = true;
1108  else if ( ( baseWeapon.forceDamageHitLocation || baseWeapon == level.weaponShotgunEnergy || baseWeapon == level.weaponSpecialDiscGun ) && meansofDeath == "MOD_PROJECTILE" )
1109  valid_weapon = true;
1110  }
1111 
1112  return valid_weapon;
1113 }
1114 
1115 
1116 function ‪updateSingleFragMultiKill( victim, weapon, weaponClass, killstreak )
1117 {
1118  self endon ( "disconnect" );
1119  level endon ( "game_ended" );
1120 
1121  self notify ( "updateSingleFragMultiKill" );
1122  self endon ( "updateSingleFragMultiKill" );
1123 
1124  if ( !isdefined (self.recent_SingleFragMultiKill) || self.recent_SingleFragMultiKillID != victim.explosiveinfo["damageid"] )
1125  self.recent_SingleFragMultiKill = 0;
1126 
1127  self.recent_SingleFragMultiKillID = victim.explosiveinfo["damageid"];
1128  self.recent_SingleFragMultiKill++;
1129 
1130  self ‪waitTillTimeoutOrDeath( 0.05 );
1131 
1132  if ( self.recent_SingleFragMultiKill >= 2 )
1133  {
1134  ‪processScoreEvent( "frag_multikill", self, victim, weapon );
1135  }
1136 
1137  self.recent_SingleFragMultiKill = 0;
1138 }
1139 
1140 function ‪updatemultikills( weapon, weaponClass, killstreak, victim )
1141 {
1142  self endon ( "disconnect" );
1143  level endon ( "game_ended" );
1144 
1145  self notify ( "updateRecentKills" );
1146  self endon ( "updateRecentKills" );
1147 
1148  baseWeaponParam = [[ level.get_base_weapon_param ]]( weapon );
1149  baseWeapon = GetWeapon( GetRefFromItemIndex( GetBaseWeaponItemIndex( baseWeaponParam ) ) );
1150 
1151  if ( !isdefined( self.recentKillVariables ) )
1152  {
1154  }
1155 
1156  if ( !isdefined( self.recentKillCountWeapon ) || self.recentKillCountWeapon != baseWeapon )
1157  {
1158  self.recentKillCountSameWeapon = 0;
1159  self.recentKillCountWeapon = baseWeapon;
1160  }
1161 
1162  if (!isdefined(killstreak))
1163  {
1164  self.recentKillCountSameWeapon++;
1165  self.recentKillCount++;
1166  }
1167 
1168  if ( isdefined( weaponClass ) )
1169  {
1170  if ( weaponClass == "weapon_lmg" || weaponClass == "weapon_smg" )
1171  {
1172  if ( self PlayerAds() < 1.0 )
1173  {
1174  self.recent_LMG_SMG_KillCount++;
1175  }
1176  }
1177  if ( weaponClass == "weapon_grenade" )
1178  {
1179  self.recentLethalCount++;
1180  }
1181  }
1182 
1183  if ( weapon.name == "satchel_charge" )
1184  {
1185  self.recentC4KillCount++;
1186  }
1187 
1188  if ( isdefined( level.killstreakWeapons ) && isdefined( level.killstreakWeapons[weapon] ) )
1189  {
1190  switch( level.killstreakWeapons[weapon] )
1191  {
1192  case "remote_missile":
1193  case "inventory_remote_missile":
1194  {
1195  self.recentRemoteMissileCount++;
1196  }
1197  break;
1198  case "rcbomb":
1199  case "inventory_rcbomb":
1200  {
1201  self.recentRCBombCount++;
1202  }
1203  break;
1204  }
1205  }
1206 
1207 
1208  if ( isdefined( weapon.isHeroWeapon ) && weapon.isHeroWeapon == true )
1209  {
1210  self.recentHeroKill = getTime();
1211  self.recentHeroWeaponKillCount++;
1212  if ( isdefined( victim ) )
1213  {
1214  self.recentHeroWeaponVictims[ victim GetEntityNumber() ] = victim;
1215  }
1216  switch( weapon.name )
1217  {
1218  case "hero_annihilator":
1219  self.recentAnihilatorCount++;
1220  break;
1221  case "hero_minigun":
1222  case "hero_minigun_body3":
1223  self.recentMiniGunCount++;
1224  break;
1225  case "hero_bowlauncher":
1226  case "hero_bowlauncher2":
1227  case "hero_bowlauncher3":
1228  case "hero_bowlauncher4":
1229  self.recentBowLauncherCount++;
1230  break;
1231  case "hero_flamethrower":
1232  self.recentFlameThrowerCount++;
1233  break;
1234  case "hero_gravityspikes":
1235  self.recentGravitySpikesCount++;
1236  break;
1237  case "hero_lightninggun":
1238  case "hero_lightninggun_arc":
1239  self.recentLightningGunCount++;
1240  break;
1241  case "hero_pineapplegun":
1242  case "hero_pineapple_grenade":
1243  self.recentPineappleGunCount++;
1244  break;
1245  case "hero_chemicalgun":
1246  case "hero_firefly_swarm":
1247  self.recentGelGunCount++;
1248  break;
1249  case "hero_armblade":
1250  self.recentArmBladeCount++;
1251  break;
1252  }
1253  }
1254 
1255  if ( isdefined( self.heroAbility ) && isdefined( victim ) )
1256  {
1258  {
1259  if ( isdefined( self.recentHeroAbilityKillWeapon ) && self.recentHeroAbilityKillWeapon != self.heroAbility )
1260  {
1261  self.recentHeroAbilityKillCount = 0;
1262  }
1263  self.recentHeroAbilityKillWeapon = self.heroAbility;
1264  self.recentHeroAbilityKillCount++;
1265  }
1266  }
1267 
1268  if ( isdefined ( killstreak ) )
1269  {
1270  switch( killstreak )
1271  {
1272  case "remote_missile":
1273  self.recentRemoteMissileKillCount++;
1274  break;
1275  case "rcbomb":
1276  self.recentRCBombKillCount++;
1277  break;
1278  case "inventory_m32":
1279  case "m32":
1280  self.recentMGLKillCount++;
1281  break;
1282  }
1283  }
1284 
1285  if ( self.recentKillCountSameWeapon == 2 )
1286  {
1287  self AddWeaponStat( weapon, "multikill_2", 1 );
1288  }
1289  else if ( self.recentKillCountSameWeapon == 3 )
1290  {
1291  self AddWeaponStat( weapon, "multikill_3", 1 );
1292  }
1293 
1294  self ‪waitTillTimeoutOrDeath( 4.0 );
1295 
1296  if ( self.recent_LMG_SMG_KillCount >= 3 )
1298 
1299  if ( self.recentRCBombKillCount >= 2 )
1301 
1302  if ( self.recentMGLKillCount >= 3 )
1304 
1305  if ( self.recentRemoteMissileKillCount >= 3 )
1307 
1308 
1309  if ( self.recentHeroWeaponKillCount > 1 )
1310  {
1311  self ‪scoreevents::hero_weapon_multikill_event( self.recentHeroWeaponKillCount, weapon );
1312  }
1313 
1314  if ( self.recentHeroWeaponKillCount > 5 )
1315  {
1316  ArrayRemoveValue( self.recentHeroWeaponVictims, undefined );
1317  if ( self.recentHeroWeaponVictims.size > 5 )
1318  {
1319  self addPlayerStat( "kill_entire_team_with_specialist_weapon", 1 );
1320  }
1321  }
1322 
1323  if ( self.recentAnihilatorCount >= 3 )
1324  {
1325  ‪processScoreEvent( "annihilator_multikill", self, undefined, weapon );
1327  }
1328  else if ( self.recentAnihilatorCount == 2 )
1329  {
1330  ‪processScoreEvent( "annihilator_multikill_2", self, undefined, weapon );
1332  }
1333  if ( self.recentMiniGunCount >= 3 )
1334  {
1335  ‪processScoreEvent( "minigun_multikill", self, undefined, weapon );
1337  }
1338  else if ( self.recentMiniGunCount == 2 )
1339  {
1340  ‪processScoreEvent( "minigun_multikill_2", self, undefined, weapon );
1342  }
1343  if ( self.recentBowLauncherCount >= 3 )
1344  {
1345  ‪processScoreEvent( "bowlauncher_multikill", self, undefined, weapon );
1347  }
1348  else if ( self.recentBowLauncherCount == 2 )
1349  {
1350  ‪processScoreEvent( "bowlauncher_multikill_2", self, undefined, weapon );
1352  }
1353  if ( self.recentFlameThrowerCount >= 3 )
1354  {
1355  ‪processScoreEvent( "flamethrower_multikill", self, undefined, weapon );
1357  }
1358  else if ( self.recentFlameThrowerCount == 2 )
1359  {
1360  ‪processScoreEvent( "flamethrower_multikill_2", self, undefined, weapon );
1362  }
1363  if ( self.recentGravitySpikesCount >= 3 )
1364  {
1365  ‪processScoreEvent( "gravityspikes_multikill", self, undefined, weapon );
1367  }
1368  else if ( self.recentGravitySpikesCount == 2 )
1369  {
1370  ‪processScoreEvent( "gravityspikes_multikill_2", self, undefined, weapon );
1372  }
1373  if ( self.recentLightningGunCount >= 3 )
1374  {
1375  ‪processScoreEvent( "lightninggun_multikill", self, undefined, weapon );
1377  }
1378  else if ( self.recentLightningGunCount == 2 )
1379  {
1380  ‪processScoreEvent( "lightninggun_multikill_2", self, undefined, weapon );
1382  }
1383  if ( self.recentPineappleGunCount >= 3 )
1384  {
1385  ‪processScoreEvent( "pineapple_multikill", self, undefined, weapon );
1387  }
1388  else if ( self.recentPineappleGunCount == 2 )
1389  {
1390  ‪processScoreEvent( "pineapple_multikill_2", self, undefined, weapon );
1392  }
1393  if ( self.recentGelGunCount >= 3 )
1394  {
1395  ‪processScoreEvent( "gelgun_multikill", self, undefined, weapon );
1397  }
1398  else if ( self.recentGelGunCount == 2 )
1399  {
1400  ‪processScoreEvent( "gelgun_multikill_2", self, undefined, weapon );
1402  }
1403  if ( self.recentArmBladeCount >= 3 )
1404  {
1405  ‪processScoreEvent( "armblades_multikill", self, undefined, weapon );
1407  }
1408  else if ( self.recentArmBladeCount == 2 )
1409  {
1410  ‪processScoreEvent( "armblades_multikill_2", self, undefined, weapon );
1412  }
1413 
1414  if ( self.recentC4KillCount >= 2 )
1415  {
1416  ‪processScoreEvent( "c4_multikill", self, undefined, weapon );
1417  }
1418  if ( self.recentRemoteMissileCount >= 3 )
1419  {
1420  self addPlayerStat( "multikill_3_remote_missile", 1 );
1421  }
1422  if ( self.recentRCBombCount >= 2 )
1423  {
1424  self addPlayerStat( "multikill_2_rcbomb", 1 );
1425  }
1426  if ( self.recentLethalCount >= 2 )
1427  {
1428  if ( !isdefined( self.pers["challenge_kills_double_kill_lethal"] ) )
1429  {
1430  self.pers["challenge_kills_double_kill_lethal"] = 0;
1431  }
1432 
1433  self.pers["challenge_kills_double_kill_lethal"]++;
1434  if ( self.pers["challenge_kills_double_kill_lethal"] >= 3 )
1435  {
1436  self addPlayerStat( "kills_double_kill_3_lethal", 1 );
1437  }
1438  }
1439 
1440  if ( self.recentKillCount > 1 )
1441  self ‪multiKill( self.recentKillCount, weapon );
1442 
1443  if ( self.recentHeroAbilityKillCount > 1 )
1444  {
1445  self ‪multiHeroAbilityKill( self.recentHeroAbilityKillCount, self.recentHeroAbilityKillWeapon );
1446  self ‪scoreevents::hero_ability_multikill_event( self.recentHeroAbilityKillCount, self.recentHeroAbilityKillWeapon );
1447  }
1448 
1450 }
1451 
1453 {
1454  self.recent_LMG_SMG_KillCount = 0;
1455  self.recentAnihilatorCount = 0;
1456  self.recentArmBladeCount = 0;
1457  self.recentBowLauncherCount = 0;
1458  self.recentC4KillCount = 0;
1459  self.recentFlameThrowerCount = 0;
1460  self.recentGelGunCount = 0;
1461  self.recentGravitySpikesCount = 0;
1462  self.recentHeroAbilityKillCount = 0;
1463  self.recentHeroWeaponKillCount = 0;
1464  self.recentHeroWeaponVictims = [];
1465  self.recentKillCount = 0;
1466  self.recentKillCountSameWeapon = 0;
1467  self.recentKillCountWeapon = undefined;
1468  self.recentLethalCount = 0;
1469  self.recentLightningGunCount = 0;
1470  self.recentMGLKillCount = 0;
1471  self.recentMiniGunCount = 0;
1472  self.recentPineappleGunCount = 0;
1473  self.recentRCBombCount = 0;
1474  self.recentRCBombKillCount = 0;
1475  self.recentRemoteMissileCount = 0;
1476  self.recentRemoteMissileKillCount = 0;
1477 
1478  self.recentKillVariables = true;
1479 }
1480 
1482 {
1483  self endon( "death" );
1484  wait( ‪timeout );
1485 }
1486 
1487 function ‪updateoneshotmultikills( victim, weapon, firstTimeDamaged )
1488 {
1489  self endon( "death" );
1490  self endon( "disconnect" );
1491  self notify( "updateoneshotmultikills" + firstTimeDamaged );
1492  self endon( "updateoneshotmultikills" + firstTimeDamaged );
1493  if ( !isdefined( self.oneshotmultikills ) || firstTimeDamaged > ‪VAL( self.oneshotmultikillsdamagetime, 0 ) )
1494  {
1495  self.oneshotmultikills = 0;
1496  }
1497 
1498  self.oneshotmultikills++;
1499  self.oneshotmultikillsdamagetime = firstTimeDamaged;
1500 
1501  wait( 1.0 );
1502  if ( self.oneshotmultikills > 1 )
1503  {
1504  ‪processScoreEvent( "kill_enemies_one_bullet", self, victim, weapon );
1505  }
1506  else
1507  {
1508  ‪processScoreEvent( "kill_enemy_one_bullet", self, victim, weapon );
1509  }
1510  self.oneshotmultikills = 0;
1511 }
1512 
1513 function ‪get_distance_for_weapon( weapon, weaponClass )
1514 {
1515  // this is special for the long shot medal
1516  // need to do this on a per weapon category basis, to better control it
1517 
1518  distance = 0;
1519 
1520  if( !isdefined( weaponClass ) )
1521  {
1522  return 0;
1523  }
1524 
1525  // special case weapons
1526  if ( weapon.rootweapon.name == "pistol_shotgun" )
1527  {
1528  weaponClass = "weapon_cqb"; // per design
1529  }
1530 
1531 
1532  switch ( weaponClass )
1533  {
1534  case "weapon_smg":
1535  distance = 1500 * 1500;
1536  break;
1537 
1538  case "weapon_assault":
1539  distance = 1750 * 1750;
1540  break;
1541 
1542  case "weapon_lmg":
1543  distance = 1750 * 1750;
1544  break;
1545 
1546  case "weapon_sniper":
1547  distance = 2000 * 2000;
1548  break;
1549 
1550  case "weapon_pistol":
1551  distance = 1000 * 1000;
1552  break;
1553 
1554  case "weapon_cqb":
1555  distance = 550 * 550;
1556  break;
1557 
1558 
1559  case "weapon_special":
1560  {
1561  baseWeapon = ‪challenges::getBaseWeapon( weapon );
1562  if ( baseWeapon == level.weaponBallisticKnife || baseWeapon == level.weaponSpecialCrossbow || baseWeapon == level.weaponSpecialDiscGun )
1563  {
1564  distance = 1500 * 1500;
1565  }
1566  }
1567  break;
1568  case "weapon_grenade":
1569  if ( weapon.rootweapon.name == "hatchet" )
1570  {
1571  distance = 1500 * 1500;
1572  }
1573  break;
1574  default:
1575  distance = 0;
1576  break;
1577  }
1578 
1579  return distance;
1580 }
1581 
1582 
1583 function ‪onGameEnd( data )
1584 {
1585  player = data.player;
1586  winner = data.winner;
1587 
1588  if ( isdefined( winner ) )
1589  {
1590  if ( level.teambased )
1591  {
1592  if ( winner != "tie" && player.team == winner )
1593  {
1594  ‪processScoreEvent( "won_match", player );
1595  return;
1596  }
1597  }
1598  else
1599  {
1600  placement = level.placement["all"];
1601  topThreePlayers = min( 3, placement.size );
1602 
1603  for ( index = 0; index < topThreePlayers; index++ )
1604  {
1605  if ( level.placement["all"][index] == player )
1606  {
1607  ‪processScoreEvent( "won_match", player );
1608  return;
1609  }
1610  }
1611  }
1612  }
1613  ‪processScoreEvent( "completed_match", player );
1614 }
1615 
1616 
1618 {
1619  if( level.rankedMatch )
1620  {
1621  if ( !isdefined( self.pers["specialistMedalAchievement"] ) )
1622  {
1623  self.pers["specialistMedalAchievement"] = 0;
1624  }
1625  self.pers["specialistMedalAchievement"]++;
1626  if ( self.pers["specialistMedalAchievement"] == 5 )
1627  {
1628  self GiveAchievement( "MP_SPECIALIST_MEDALS" ); // Get 5 Medals based on a Specialist Ability in a single game.
1629  }
1630 
1631  self ‪util::player_contract_event( "earned_specialist_ability_medal" );
1632  }
1633 }
1634 
1635 function ‪specialistStatAbilityUsage( usageSingleGame, multiTrackPerLife )
1636 {
1637  self endon ( "disconnect" );
1638  level endon ( "game_ended" );
1639 
1640  self notify ( "updatethread specialistStatAbilityUsage" );
1641  self endon ( "updatethread specialistStatAbilityUsage" );
1642 
1643  isRoulette = ( self.isRoulette === true );
1644  if ( isdefined( self.heroAbility ) && !isRoulette )
1645  {
1646  self addWeaponStat( self.heroAbility, "combatRecordStat", 1 );
1647  }
1648 
1649  self ‪challenges::processSpecialistChallenge( "kills_ability" );
1650  if ( !isdefined( self.pers["specialistUsagePerGame"] ) )
1651  {
1652  self.pers["specialistUsagePerGame"] = 0;
1653  }
1654  self.pers["specialistUsagePerGame"]++;
1655  if ( self.pers["specialistUsagePerGame"] >= usageSingleGame )
1656  {
1657  self ‪challenges::processSpecialistChallenge( "kill_one_game_ability" );
1658  self.pers["specialistUsagePerGame"] = 0;
1659  }
1660 
1661  if ( multiTrackPerLife )
1662  {
1663  self.pers["specialistStatAbilityUsage"]++;
1664  if ( self.pers["specialistStatAbilityUsage"] >= 2 )
1665  {
1666  self ‪challenges::processSpecialistChallenge( "multikill_ability" );
1667  }
1668  }
1669  else
1670  {
1671  if ( !isdefined( self.‪specialistStatAbilityUsage ) )
1672  {
1673  self.specialistStatAbilityUsage = 0;
1674  }
1675 
1676  self.specialistStatAbilityUsage++;
1677  self ‪waitTillTimeoutOrDeath( 4.0 );
1678  if ( self.‪specialistStatAbilityUsage >= 2 )
1679  {
1680  self ‪challenges::processSpecialistChallenge( "multikill_ability" );
1681  }
1682  self.specialistStatAbilityUsage = 0;
1683  }
1684 }
1685 
1687 {
1688  if ( level.rankedMatch )
1689  {
1690  self GiveAchievement( "MP_MULTI_KILL_MEDALS" ); // Get a Specialist-based medal that requires 3 or more rapid kills while using any Specialist Weapon.
1691  self ‪challenges::processSpecialistChallenge( "multikill_weapon" );
1692  }
1693 }
1694 
‪processScoreEvent
‪function processScoreEvent(event, player, victim, weapon)
Definition: scoreevents_shared.gsc:19
‪getBaseWeapon
‪function getBaseWeapon(weapon)
Definition: _challenges.gsc:1459
‪timeout
‪function timeout(n_time, func, arg1, arg2, arg3, arg4, arg5, arg6)
Definition: util_shared.csc:762
‪callback
‪function callback(event, localclientnum, params)
Definition: callbacks_shared.csc:13
‪getWeaponClass
‪function getWeaponClass(weapon)
Definition: util_shared.gsc:2676
‪init
‪function init()
Definition: _scoreevents.gsc:34
‪updateoneshotmultikills
‪function updateoneshotmultikills(victim, weapon, firstTimeDamaged)
Definition: _scoreevents.gsc:1487
‪VISION_PULSE_DURATION
‪#define VISION_PULSE_DURATION
Definition: _gadget_vision_pulse.gsh:34
‪resetRecentKillVariables
‪function resetRecentKillVariables()
Definition: _scoreevents.gsc:1452
‪multi_RemoteMissile_Kill
‪function multi_RemoteMissile_Kill()
Definition: challenges_shared.gsc:1329
‪is_weapon_valid
‪function is_weapon_valid(meansOfDeath, weapon, weaponClass, killstreak)
Definition: _scoreevents.gsc:1087
‪multiKill
‪function multiKill(killCount, weapon)
Definition: _scoreevents.gsc:1050
‪specificWeaponKill
‪function specificWeaponKill(attacker, victim, weapon, killstreak, inflictor)
Definition: _scoreevents.gsc:948
‪multiHeroAbilityKill
‪function multiHeroAbilityKill(killCount, weapon)
Definition: _scoreevents.gsc:1076
‪__init__
‪function __init__()
Definition: _scoreevents.gsc:29
‪on_start_gametype
‪function on_start_gametype(func, obj)
Definition: callbacks_shared.csc:285
‪player_contract_event
‪function player_contract_event(event_name, param1=undefined, param2=undefined, param3=undefined)
Definition: _util.gsc:1161
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪hero_ability_kill_event
‪function hero_ability_kill_event(ability, victim_ability)
Definition: scoreevents_shared.gsc:355
‪has_toughness_perk_purchased_and_equipped
‪function has_toughness_perk_purchased_and_equipped()
Definition: util_shared.gsc:4159
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪killedHeroWeaponEnemy
‪function killedHeroWeaponEnemy(attacker, victim, weapon, victim_weapon, victim_gadget_power, victimGadgetWasActiveLastDamage)
Definition: _scoreevents.gsc:891
‪isHighestScoringPlayer
‪function isHighestScoringPlayer(player)
Definition: challenges_shared.gsc:497
‪registerScoreEventCallback
‪function registerScoreEventCallback(callback, func)
Definition: _scoreevents.gsc:51
‪IsEnemyPlayer
‪function IsEnemyPlayer(player)
Definition: util_shared.csc:1220
‪longDistanceKillMP
‪function longDistanceKillMP(weapon)
Definition: _challenges.gsc:1851
‪killWhileDamagingWithHPM
‪function killWhileDamagingWithHPM()
Definition: challenges_shared.gsc:608
‪processSpecialistChallenge
‪function processSpecialistChallenge(statName)
Definition: _challenges.gsc:1927
‪specialistMedalAchievement
‪function specialistMedalAchievement()
Definition: _scoreevents.gsc:1617
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪get_from_weapon
‪function get_from_weapon(weapon)
Definition: _killstreaks.gsc:806
‪waitTillTimeoutOrDeath
‪function waitTillTimeoutOrDeath(timeout)
Definition: _scoreevents.gsc:1481
‪hero_weapon_multikill_event
‪function hero_weapon_multikill_event(killcount, weapon)
Definition: scoreevents_shared.gsc:383
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪getScoreEventTableName
‪function getScoreEventTableName()
Definition: scoreevents_shared.gsc:169
‪specialistStatAbilityUsage
‪function specialistStatAbilityUsage(usageSingleGame, multiTrackPerLife)
Definition: _scoreevents.gsc:1635
‪heroWeaponKill
‪function heroWeaponKill(attacker, victim, weapon)
Definition: _scoreevents.gsc:836
‪gadget_CheckHeroAbilityKill
‪function gadget_CheckHeroAbilityKill(attacker)
Definition: _ability_player.gsc:529
‪scoreEventTableLookup
‪function scoreEventTableLookup(index, scoreEventColumn)
Definition: _scoreevents.gsc:46
‪isPunch
‪function isPunch(weapon)
Definition: _weapon_utils.gsc:28
‪is_an_a_killstreak
‪function is_an_a_killstreak()
Definition: _killstreaks.gsc:520
‪multi_RCBomb_Kill
‪function multi_RCBomb_Kill()
Definition: challenges_shared.gsc:1324
‪isNonBareHandsMelee
‪function isNonBareHandsMelee(weapon)
Definition: _weapon_utils.gsc:38
‪multi_MGL_Kill
‪function multi_MGL_Kill()
Definition: challenges_shared.gsc:1335
‪updateSingleFragMultiKill
‪function updateSingleFragMultiKill(victim, weapon, weaponClass, killstreak)
Definition: _scoreevents.gsc:1116
‪earnedMicrowaveAssistScore
‪function earnedMicrowaveAssistScore(score)
Definition: challenges_shared.gsc:962
‪longDistanceHatchetKill
‪function longDistanceHatchetKill()
Definition: challenges_shared.gsc:613
‪scoreEventTableLookupInt
‪function scoreEventTableLookupInt(index, scoreEventColumn)
Definition: _scoreevents.gsc:41
‪get_distance_for_weapon
‪function get_distance_for_weapon(weapon, weaponClass)
Definition: _scoreevents.gsc:1513
‪updatemultikills
‪function updatemultikills(weapon, weaponClass, killstreak, victim)
Definition: _scoreevents.gsc:1140
‪multikillMedalAchievement
‪function multikillMedalAchievement()
Definition: _scoreevents.gsc:1686
‪onGameEnd
‪function onGameEnd(data)
Definition: _scoreevents.gsc:1583
‪VISION_PULSE_REVEAL_TIME
‪#define VISION_PULSE_REVEAL_TIME
Definition: _gadget_vision_pulse.gsh:35
‪multi_LMG_SMG_Kill
‪function multi_LMG_SMG_Kill()
Definition: challenges_shared.gsc:1269
‪scoreEventPlayerKill
‪function scoreEventPlayerKill(data, time)
Definition: _scoreevents.gsc:60
‪isMeleeMOD
‪function isMeleeMOD(mod)
Definition: _weapon_utils.gsc:23
‪get_equipped_hero_ability
‪function get_equipped_hero_ability(ability_name)
Definition: _scoreevents.gsc:828
‪hero_ability_multikill_event
‪function hero_ability_multikill_event(killcount, ability)
Definition: scoreevents_shared.gsc:369