‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_loadout.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\dev_shared;
6 #using scripts\shared\flag_shared;
7 #using scripts\shared\flagsys_shared;
8 #using scripts\shared\killstreaks_shared;
9 #using scripts\shared\loadout_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\tweakables_shared;
12 #using scripts\shared\util_shared;
13 #using scripts\shared\abilities\_ability_util;
14 #using scripts\shared\weapons\_weapon_utils;
15 #using scripts\shared\abilities\gadgets\_gadget_roulette;
16 
17 #insert scripts\shared\shared.gsh;
18 #insert scripts\shared\statstable_shared.gsh;
19 
20 #using scripts\mp\_armor;
21 #using scripts\mp\_challenges;
22 #using scripts\mp\_util;
23 #using scripts\mp\gametypes\_dev;
24 #using scripts\mp\gametypes\_globallogic_score;
25 #using scripts\mp\gametypes\_globallogic_utils;
26 #using scripts\mp\gametypes\_weapons;
27 #using scripts\mp\killstreaks\_killstreak_weapons;
28 #using scripts\mp\killstreaks\_killstreaks;
29 #using scripts\mp\teams\_teams;
30 
31 #insert scripts\mp\_bonuscard.gsh;
32 
33 #namespace loadout;
34 
35 ‪REGISTER_SYSTEM( "loadout", &‪__init__, undefined )
36 
37 function ‪__init__()
38 {
41 
42 }
43 
44 function ‪on_connect()
45 {
46 }
47 
48 function ‪init()
49 {
50  level.classMap["class_smg"] = "CLASS_SMG";
51  level.classMap["class_cqb"] = "CLASS_CQB";
52  level.classMap["class_assault"] = "CLASS_ASSAULT";
53  level.classMap["class_lmg"] = "CLASS_LMG";
54  level.classMap["class_sniper"] = "CLASS_SNIPER";
55 
56  level.classMap["custom0"] = "CLASS_CUSTOM1";
57  level.classMap["custom1"] = "CLASS_CUSTOM2";
58  level.classMap["custom2"] = "CLASS_CUSTOM3";
59  level.classMap["custom3"] = "CLASS_CUSTOM4";
60  level.classMap["custom4"] = "CLASS_CUSTOM5";
61  level.classMap["custom5"] = "CLASS_CUSTOM6";
62  level.classMap["custom6"] = "CLASS_CUSTOM7";
63  level.classMap["custom7"] = "CLASS_CUSTOM8";
64  level.classMap["custom8"] = "CLASS_CUSTOM9";
65  level.classMap["custom9"] = "CLASS_CUSTOM10";
66 
67  level.maxKillstreaks = 4;
68  level.maxSpecialties = 6;
69  level.maxBonuscards = 3;
70  level.maxAllocation = GetGametypeSetting( "maxAllocation" );
71  level.loadoutKillstreaksEnabled = GetGametypeSetting( "loadoutKillstreaksEnabled" );
72  if( GetDvarInt( "teamOpsEnabled" ) == 1 )
73  level.loadoutKillstreaksEnabled = 1;
74 
75  //override the base melee weapon from _weapons.gsc
76  level.weaponBaseMeleeHeld = GetWeapon( "bare_hands" );
77  level.weaponKnifeLoadout = GetWeapon( "knife_loadout" );
78  level.weaponMeleeKnuckles = GetWeapon( "melee_knuckles" );
79  level.weaponMeleeButterfly = GetWeapon( "melee_butterfly" );
80  level.weaponMeleeWrench = GetWeapon( "melee_wrench" );
81  level.weaponMeleeSword = GetWeapon( "melee_sword" );
82  level.weaponMeleeCrowbar = GetWeapon( "melee_crowbar" );
83  level.weaponSpecialCrossbow = GetWeapon( "special_crossbow" );
84  level.weaponMeleeDagger = GetWeapon( "melee_dagger" );
85  level.weaponMeleeBat = GetWeapon( "melee_bat" );
86  level.weaponMeleeBowie = GetWeapon( "melee_bowie" );
87  level.weaponMeleeMace = GetWeapon( "melee_mace" );
88  level.weaponMeleeFireAxe = GetWeapon( "melee_fireaxe" );
89  level.weaponMeleeBoneGlass = GetWeapon( "melee_boneglass" );
90  level.weaponMeleeImprovise = GetWeapon( "melee_improvise" );
91  level.weaponShotgunEnergy = GetWeapon( "shotgun_energy" );
92  level.weaponPistolEnergy = GetWeapon( "pistol_energy" );
93  level.weaponMeleeShockBaton = GetWeapon( "melee_shockbaton" );
94  level.weaponMeleeNunchuks = GetWeapon( "melee_nunchuks" );
95  level.weaponMeleeBoxing = GetWeapon( "melee_boxing" );
96  level.weaponMeleeKatana = GetWeapon( "melee_katana" );
97  level.weaponMeleeShovel = GetWeapon( "melee_shovel" );
98  level.weaponMeleeProsthetic = GetWeapon( "melee_prosthetic" );
99  level.weaponMeleeChainsaw = GetWeapon( "melee_chainsaw" );
100  level.weaponSpecialDiscGun = GetWeapon( "special_discgun" );
101  level.weaponSmgNailGun = GetWeapon( "smg_nailgun" );
102  level.weaponLauncherMulti = GetWeapon( "launcher_multi" );
103  level.weaponMeleeCrescent = GetWeapon( "melee_crescent" );
104  level.weaponLauncherEx41 = GetWeapon( "launcher_ex41" );
105 
106  level.meleeWeapons = []; // intended for use with medals and challenges, namely "kill_enemy_with_their_weapon"
107  ‪ARRAY_ADD( level.meleeWeapons, level.weaponKnifeLoadout );
108  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeKnuckles );
109  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeButterfly );
110  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeWrench );
111  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeSword );
112  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeCrowbar );
113  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeDagger );
114  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeBat );
115  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeBowie );
116  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeMace );
117  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeFireAxe );
118  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeBoneGlass );
119  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeImprovise );
120  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeShockBaton );
121  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeNunchuks );
122  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeBoxing );
123  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeKatana );
124  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeShovel );
125  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeProsthetic );
126  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeChainsaw );
127  ‪ARRAY_ADD( level.meleeWeapons, level.weaponMeleeCrescent );
128 
129  // placed here for easier integration
130  level.weaponBouncingBetty = GetWeapon( "bouncingbetty" );
131 
132  level.PrestigeNumber = 5;
133 
134  level.defaultClass = "CLASS_ASSAULT";
135 
136  if ( ‪tweakables::getTweakableValue( "weapon", "allowfrag" ) )
137  {
138  level.weapons["frag"] = GetWeapon( "frag_grenade" );
139  }
140  else
141  {
142  level.weapons["frag"] = "";
143  }
144 
145  if ( ‪tweakables::getTweakableValue( "weapon", "allowsmoke" ) )
146  {
147  level.weapons["smoke"] = GetWeapon( "smoke_grenade" );
148  }
149  else
150  {
151  level.weapons["smoke"] = "";
152  }
153 
154  if ( ‪tweakables::getTweakableValue( "weapon", "allowflash" ) )
155  {
156  level.weapons["flash"] = GetWeapon( "flash_grenade" );
157  }
158  else
159  {
160  level.weapons["flash"] = "";
161  }
162 
163  level.weapons["concussion"] = GetWeapon( "concussion_grenade" );
164 
165  if ( ‪tweakables::getTweakableValue( "weapon", "allowsatchel" ) )
166  {
167  level.weapons["satchel_charge"] = GetWeapon( "satchel_charge" );
168  }
169  else
170  {
171  level.weapons["satchel_charge"] = "";
172  }
173 
174  if ( ‪tweakables::getTweakableValue( "weapon", "allowbetty" ) )
175  {
176  level.weapons["betty"] = GetWeapon( "mine_bouncing_betty" );
177  }
178  else
179  {
180  level.weapons["betty"] = "";
181  }
182 
183  if ( ‪tweakables::getTweakableValue( "weapon", "allowrpgs" ) )
184  {
185  level.weapons["rpg"] = GetWeapon( "rpg" );
186  }
187  else
188  {
189  level.weapons["rpg"] = "";
190  }
191 
193 
194  // initializes create a class settings
195  ‪cac_init();
196 
197  ‪load_default_loadout( "CLASS_SMG", 10 );
198  ‪load_default_loadout( "CLASS_CQB", 11 );
199  ‪load_default_loadout( "CLASS_ASSAULT", 12 );
200  ‪load_default_loadout( "CLASS_LMG", 13 );
201  ‪load_default_loadout( "CLASS_SNIPER", 14 );
202 
203  // generating weapon type arrays which classifies the weapon as primary (back stow), pistol, or inventory (side pack stow)
204  // using mp/statstable.csv's weapon grouping data ( numbering 0 - 149 )
205  level.primary_weapon_array = [];
206  level.side_arm_array = [];
207  level.grenade_array = [];
208  level.inventory_array = [];
209  max_weapon_num = 99;
210  for( i = 0; i < max_weapon_num; i++ )
211  {
212  if( !isdefined( level.tbl_weaponIDs[i] ) || level.tbl_weaponIDs[i]["group"] == "" )
213  {
214  continue;
215  }
216  if( !isdefined( level.tbl_weaponIDs[i] ) || level.tbl_weaponIDs[i]["reference"] == "" )
217  {
218  continue;
219  }
220 
221  weapon_type = level.tbl_weaponIDs[i]["group"];
222  weapon = level.tbl_weaponIDs[i]["reference"];
223  attachment = level.tbl_weaponIDs[i]["attachment"];
224 
225  ‪weapon_class_register( weapon, weapon_type );
226 
227  if( isdefined( attachment ) && attachment != "" )
228  {
229  attachment_tokens = strtok( attachment, " " );
230  if( isdefined( attachment_tokens ) )
231  {
232  if( attachment_tokens.size == 0 )
233  ‪weapon_class_register( weapon+"_"+attachment, weapon_type );
234  else
235  {
236  // multiple attachment options
237  for( k = 0; k < attachment_tokens.size; k++ )
238  ‪weapon_class_register( weapon+"_"+attachment_tokens[k], weapon_type );
239  }
240  }
241  }
242  }
243 
245  ‪callback::add_weapon_damage( level.weaponSpecialDiscGun, &‪on_damage_special_discgun );
246 
247 }
248 function ‪on_damage_special_discgun( eAttacker, eInflictor, weapon, meansOfDeath, ‪damage )
249 {
250  if ( weapon != level.weaponSpecialDiscGun )
251  {
252  return;
253  }
254  playsoundatposition ("wpn_disc_bounce_fatal", self.origin);
255 }
256 
258 {
259  currentDvar = 0;
260 
261  level.itemExclusions = [];
262 
263  while( GetDvarInt( "item_exclusion_" + currentDvar ) )
264  {
265  level.itemExclusions[ currentDvar ] = GetDvarInt( "item_exclusion_" + currentDvar );
266  currentDvar++;
267  }
268 
269  level.attachmentExclusions = [];
270 
271  currentDvar = 0;
272  while( GetDvarString( "attachment_exclusion_" + currentDvar ) !="" )
273  {
274  level.attachmentExclusions[ currentDvar ] = GetDvarString( "attachment_exclusion_" + currentDvar );
275  currentDvar++;
276  }
277 
278 }
279 
280 function ‪is_attachment_excluded( attachment )
281 {
282  numExclusions = level.attachmentExclusions.size;
283 
284  for ( exclusionIndex = 0; exclusionIndex < numExclusions; exclusionIndex++ )
285  {
286  if ( attachment == level.attachmentExclusions[ exclusionIndex ] )
287  {
288  return true;
289  }
290  }
291 
292  return false;
293 }
294 
296 {
297  if ( !isdefined( level.statsTableID ) )
298  {
299  statsTableName = ‪util::getStatsTableName();
300  level.statsTableID = TableLookupFindCoreAsset( statsTableName );
301  }
302 }
303 
304 function ‪get_item_count( itemReference )
305 {
307 
308  itemCount = int( tableLookup( level.statsTableID, ‪STATS_TABLE_COL_REFERENCE, itemReference, ‪STATS_TABLE_COL_COUNT ) );
309  if ( itemCount < 1 )
310  {
311  itemCount = 1;
312  }
313 
314  return itemCount;
315 }
316 
317 function ‪getDefaultClassSlotWithExclusions( className, slotName )
318 {
319  itemReference = GetDefaultClassSlot( className, slotName );
320 
322 
323  itemIndex = int( tableLookup( level.statsTableID, ‪STATS_TABLE_COL_REFERENCE, itemReference, ‪STATS_TABLE_COL_NUMBERING ) );
324 
325  if ( ‪loadout::is_item_excluded( itemIndex ) )
326  {
327  itemReference = tableLookup( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, 0, ‪STATS_TABLE_COL_REFERENCE );
328  }
329 
330  return itemReference;
331 }
332 
333 function ‪load_default_loadout( weaponclass, classNum )
334 {
335  level.classToClassNum[ weaponclass ] = classNum;
336 }
337 
338 function ‪weapon_class_register( weaponName, weapon_type )
339 {
340  if( isSubstr( "weapon_smg weapon_cqb weapon_assault weapon_lmg weapon_sniper weapon_shotgun weapon_launcher weapon_knife weapon_special", weapon_type ) )
341  level.primary_weapon_array[GetWeapon( weaponName )] = 1;
342  else if( isSubstr( "weapon_pistol", weapon_type ) )
343  level.side_arm_array[GetWeapon( weaponName )] = 1;
344  else if( weapon_type == "weapon_grenade" )
345  level.grenade_array[GetWeapon( weaponName )] = 1;
346  else if( weapon_type == "weapon_explosive" )
347  level.inventory_array[GetWeapon( weaponName )] = 1;
348  else if( weapon_type == "weapon_rifle" ) // COD5 WEAPON TEST
349  level.inventory_array[GetWeapon( weaponName )] = 1;
350  else
351  assert( false, "Weapon group info is missing from statsTable for: " + weapon_type );
352 }
353 
354 function ‪hero_register_dialog( weapon )
355 {
356  readyVO = weapon.name + "_ready";
357 
358  game["dialog"][readyVO] = readyVO;
359 }
360 
361 // create a class init
362 function ‪cac_init()
363 {
364  level.tbl_weaponIDs = [];
365  level.heroWeaponsTable = [];
366 
368 
369  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
370  {
371  itemRow = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
372 
373  if ( itemRow > -1 )
374  {
375  group_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_GROUP );
376 
377  if ( isSubStr( group_s, "weapon_" ) || group_s == "hero" )
378  {
379  reference_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_REFERENCE );
380  if( reference_s != "" )
381  {
382  weapon = GetWeapon( reference_s );
383 
384  if ( weapon.inventoryType == "hero" )
385  {
386  level.heroWeaponsTable[reference_s] = [];
387  level.heroWeaponsTable[reference_s]["index"] = i;
388 
389  ‪hero_register_dialog( weapon );
390  }
391 
392  level.tbl_weaponIDs[i]["reference"] = reference_s;
393  level.tbl_weaponIDs[i]["group"] = group_s;
394  level.tbl_weaponIDs[i]["count"] = int( tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_COUNT ) );
395  level.tbl_weaponIDs[i]["attachment"] = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_ATTACHMENTS );
396  }
397  }
398  }
399  }
400 
401  level.perkNames = [];
402  level.perkIcons = [];
403  level.perkSpecialties = [];
404 
405  // generating perk data vars collected form statsTable.csv
406  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
407  {
408  itemRow = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
409 
410  if ( itemRow > -1 )
411  {
412  group_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_GROUP );
413 
414  if ( group_s == "specialty" )
415  {
416  reference_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_REFERENCE );
417 
418  if( reference_s != "" )
419  {
420  perkIcon = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_IMAGE );
421  perkName = tableLookupIString( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i, ‪STATS_TABLE_COL_NAME );
422 
423  level.perkNames[ perkIcon ] = perkName;
424 
425  perk_name = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_NAME );
426  level.perkIcons[ perk_name ] = perkIcon;
427  level.perkSpecialties[ perk_name ] = reference_s;
428  }
429  }
430  }
431  }
432 
433  level.killStreakNames = [];
434  level.killStreakIcons = [];
435  level.KillStreakIndices = [];
436 
437  // generating kill streak data vars collected form statsTable.csv
438  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
439  {
440  itemRow = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
441 
442  if ( itemRow > -1 )
443  {
444  group_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_GROUP );
445 
446  if ( group_s == "killstreak" )
447  {
448  reference_s = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_REFERENCE );
449 
450  if( reference_s != "" )
451  {
452  level.tbl_KillStreakData[i] = reference_s;
453  level.killStreakIndices[ reference_s ] = i;
454  icon = tableLookupColumnForRow( level.statsTableID, itemRow, ‪STATS_TABLE_COL_IMAGE );
455  ‪name = tableLookupIString( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i, ‪STATS_TABLE_COL_NAME );
456 
457  level.killStreakNames[ reference_s ] = ‪name;
458  level.killStreakIcons[ reference_s ] = icon;
459  level.killStreakIndices[ reference_s ] = i;
460  }
461  }
462  }
463  }
464 }
465 
466 function ‪getClassChoice( response )
467 {
468  assert( isdefined( level.classMap[ response ] ) );
469 
470  return ( level.classMap[ response ] );
471 }
472 
473 
474 // ============================================================================
475 
476 
477 function ‪getAttachmentString( weaponNum, attachmentNum )
478 {
479  attachmentString = GetItemAttachment( weaponNum, attachmentNum );
480 
481  if ( attachmentString != "none" && ( !‪is_attachment_excluded( attachmentString ) ) )
482  {
483  attachmentString = attachmentString + "_";
484  }
485  else
486  {
487  attachmentString = "";
488  }
489 
490  return attachmentString;
491 }
492 
494 {
495  if ( !isdefined( level.attachmentsDisabled ) )
496  {
497  return false;
498  }
499 
500  return level.attachmentsDisabled;
501 
502 }
503 
504 function ‪getKillStreakIndex( weaponclass, killstreakNum )
505 {
506  killstreakNum++;
507 
508  killstreakString = "killstreak" + killstreakNum;
509 
510  // custom game mode killstreaks
511  if ( GetDvarInt( "custom_killstreak_mode" ) == 2 )
512  {
513  return GetDvarInt( "custom_" + killstreakString );
514  }
515  else
516  {
517  return( self GetLoadoutItem( weaponclass, killstreakString ) );
518  }
519 }
520 
522 {
523  self.killstreak = [];
524 
525  if ( !level.loadoutKillstreaksEnabled )
526  return;
527 
528  classNum = self.class_num_for_global_weapons;
529 
530  sortedKillstreaks = [];
531  currentKillstreak = 0;
532 
533  for ( killstreakNum = 0; killstreakNum < level.maxKillstreaks; killstreakNum++ )
534  {
535  killstreakIndex = ‪getKillStreakIndex( classNum, killstreakNum );
536 
537  if ( isdefined( killstreakIndex ) && ( killstreakIndex > 0 ) )
538  {
539  assert( isdefined( level.tbl_KillStreakData[ killstreakIndex ] ), "KillStreak #:" + killstreakIndex + "'s data is undefined" );
540 
541  if ( isdefined( level.tbl_KillStreakData[ killstreakIndex ] ) )
542  {
543  self.killstreak[ currentKillstreak ] = level.tbl_KillStreakData[ killstreakIndex ];
544  if ( isdefined( level.usingMomentum ) && level.usingMomentum )
545  {
546  killstreakType = ‪killstreaks::get_by_menu_name( self.killstreak[ currentKillstreak ] );
547  if ( isdefined( killstreakType ) )
548  {
549  weapon = ‪killstreaks::get_killstreak_weapon( killstreakType );
550 
551  self GiveWeapon( weapon );
552 
553  if ( isdefined( level.usingScoreStreaks ) && level.usingScoreStreaks )
554  {
555  if( weapon.isCarriedKillstreak )
556  {
557  if( !isdefined( self.pers["held_killstreak_ammo_count"][weapon] ) )
558  self.pers["held_killstreak_ammo_count"][weapon] = 0;
559 
560  if( !isDefined( self.pers["held_killstreak_clip_count"][weapon] ) )
561  self.pers["held_killstreak_clip_count"][weapon] = 0;
562 
563  if( self.pers["held_killstreak_ammo_count"][weapon] > 0 )
564  {
565  self setWeaponAmmoClip( weapon, self.pers["held_killstreak_clip_count"][weapon] );
566  self setWeaponAmmoStock( weapon, self.pers["held_killstreak_ammo_count"][weapon] - self.pers["held_killstreak_clip_count"][weapon] );
567  }
568  else
569  {
570  self ‪setWeaponAmmoOverall( weapon, 0 );
571  }
572  }
573  else
574  {
575  quantity = self.pers["killstreak_quantity"][weapon];
576  if ( !isdefined( quantity ) )
577  {
578  quantity = 0;
579  }
580  self setWeaponAmmoClip( weapon, quantity );
581 
582  }
583  }
584  // Put killstreak in sorted order from lowest to highest momentum cost
585  sortData = spawnstruct();
586  sortData.cost = level.killstreaks[killstreakType].momentumCost;
587  sortData.weapon = weapon;
588  sortIndex = 0;
589  for ( sortIndex = 0 ; sortIndex < sortedKillstreaks.size ; sortIndex++ )
590  {
591  if ( sortedKillstreaks[sortIndex].cost > sortData.cost )
592  break;
593  }
594  for ( i = sortedKillstreaks.size ; i > sortIndex ; i-- )
595  {
596  sortedKillstreaks[i] = sortedKillstreaks[i-1];
597  }
598  sortedKillstreaks[sortIndex] = sortData;
599  }
600  }
601  currentKillstreak++;
602  }
603  }
604  }
605 
606  actionSlotOrder = [];
607  actionSlotOrder[0] = 4;
608  actionSlotOrder[1] = 2;
609  actionSlotOrder[2] = 1;
610  // action slot 3 ( left ) is for alt weapons
611  if ( isdefined( level.usingMomentum ) && level.usingMomentum )
612  {
613  for ( sortIndex = 0 ; (sortIndex < sortedKillstreaks.size && sortIndex < actionSlotOrder.size) ; sortIndex++ )
614  {
615  if( sortedKillstreaks[sortIndex].weapon != level.weaponNone )
616  self SetActionSlot( actionSlotOrder[sortIndex], "weapon", sortedKillstreaks[sortIndex].weapon );
617  }
618  }
619 }
620 
621 function ‪isPerkGroup( perkName )
622 {
623  return ( isdefined( perkName ) && IsString( perkName ) );
624 }
625 
626 // clears all player's custom class variables, prepare for update with new stat data
627 function ‪reset_specialty_slots( class_num )
628 {
629  self.specialty = []; // clear all specialties
630 }
631 
632 //------------------------------------------------------------------------------
633 // self = player
634 //------------------------------------------------------------------------------
635 
637 {
638  self.staticWeaponsStartTime = getTime();
639 }
640 
641 function ‪isEquipmentAllowed( equipment_name )
642 {
643  if ( equipment_name == level.weapontacticalInsertion.name && level.disableTacInsert )
644  return false;
645 
646  return true;
647 }
648 
650 {
651  if ( level.leagueMatch )
652  {
653  return ( IsItemRestricted( item ) );
654  }
655 
656  return false;
657 }
658 
659 function ‪giveLoadoutLevelSpecific( team, weaponclass )
660 {
661  if ( isdefined( level.giveCustomCharacters ) )
662  {
663  self [[level.giveCustomCharacters]]();
664  }
665 
666  if ( isdefined( level.giveCustomLoadout ) )
667  {
668  self [[level.giveCustomLoadout]]();
669  }
670 }
671 
672 function ‪giveLoadout_init( takeAllWeapons )
673 {
674  if( takeAllWeapons )
675  {
676  self takeAllWeapons();
677  }
678 
679  // initialize specialty array
680  self.specialty = [];
681  self.killstreak = [];
682  self.primaryWeaponKill = false;
683  self.secondaryWeaponKill = false;
684  // reset offhand
685  self.grenadeTypePrimary = level.weaponNone;
686  self.grenadeTypePrimaryCount = 0;
687  self.grenadeTypeSecondary = level.weaponNone;
688  self.grenadeTypeSecondaryCount = 0;
689 
690 
691  self notify( "give_map" );
692 }
693 
694 function ‪givePerks()
695 {
696  self.specialty = self GetLoadoutPerks( self.class_num );
697 
698 
699  // SJC: set the player state to have bonus card and primary/secondary weapon info, for codcaster to view it
700  self SetPlayerStateLoadoutBonusCards( self.class_num );
701  self SetPlayerStateLoadoutWeapons( self.class_num );
702 
703  if ( level.leagueMatch )
704  {
705  for ( i = 0; i < self.specialty.size; i++ )
706  {
707  if ( ‪isLeagueItemRestricted( self.specialty[i] ) )
708  {
709  ArrayRemoveIndex( self.specialty, i );
710  i--;
711  }
712  }
713  }
714 
715  // re-registering perks to code since perks are cleared after respawn in case if players switch classes
716  self ‪register_perks();
717 
718  // now that perks are re-registered...
719  // update player momentum taking into account anteup perk; any score less than the initial value is boosted to that value
720  anteup_bonus = GetDvarInt( "perk_killstreakAnteUpResetValue" );
721  momentum_at_spawn_or_game_end = ‪VAL( self.pers["momentum_at_spawn_or_game_end"], 0 );
722  hasNotDoneCombat = !( self.hasDoneCombat === true ); // fixes dev gui bot spawning in grace period
723  if ( ( level.inPreMatchPeriod || ( level.inGracePeriod && hasNotDoneCombat ) ) && momentum_at_spawn_or_game_end < anteup_bonus )
724  {
725  new_momentum = ( self HasPerk( "specialty_anteup" ) ? anteup_bonus : momentum_at_spawn_or_game_end );
726  ‪globallogic_score::_setPlayerMomentum( self, new_momentum, false );
727  }
728 }
729 
730 function ‪setClassNum( weaponClass )
731 {
732  if( isSubstr( weaponclass, "CLASS_CUSTOM" ) )
733  {
734  // ============= custom class selected ==============
735  // gets custom class data from stat bytes
736  // obtains the custom class number
737  self.class_num = int( weaponclass[weaponclass.size-1] )-1;
738 
739  //hacky patch to the system since when it was written it was never thought of that there could be 10 custom slots
740  if( -1 == self.class_num )
741  {
742  self.class_num = 9;
743  }
744 
745 
746  self.class_num_for_global_weapons = self.class_num;
747 
748  // clear of specialty slots, repopulate the current selected class' setup
749  self ‪reset_specialty_slots( self.class_num );
750 
751  playerRenderOptions = self CalcPlayerOptions( self.class_num );
752  self SetPlayerRenderOptions( playerRenderOptions );
753  }
754  else
755  {
756  // ============= selected one of the default classes ==============
757 
758  // load the selected default class's specialties
759  assert( isdefined(self.pers["class"]), "Player during spawn and loadout got no class!" );
760 
761  self.class_num = level.classToClassNum[ weaponclass ];
762  self.class_num_for_global_weapons = 0;
763 
764  self SetPlayerRenderOptions( 0 );
765  }
766 
767  self recordLoadoutIndex( self.class_num );
768 }
769 
771 {
772  //TODO - add melee weapon selection to the CAC stuff and default loadouts
773  self.spawnWeapon = level.weaponBaseMeleeHeld;
774 
775 // /# println( "^5Loadout " + self.name + " GiveWeapon( " + level.weaponBaseMelee.name + " ) -- level.weaponBaseMelee 0" ); #/
776  knifeWeaponOptions = self CalcWeaponOptions( self.class_num, 2 );
777  self GiveWeapon( level.weaponBaseMeleeHeld, knifeWeaponOptions );
778 
779  self.pers["spawnWeapon"] = self.spawnWeapon;
780 
781  switchImmediate = isdefined( self.alreadySetSpawnWeaponOnce );
782  self setSpawnWeapon( self.spawnWeapon, switchImmediate );
783  self.alreadySetSpawnWeaponOnce = true;
784 }
785 
786 function ‪giveWeapons()
787  {
788  spawnWeapon = level.weaponNull;
789  initialWeaponCount = 0;
790 
791  // weapon override for round based gametypes
792  // TODO: if they switched to a sidearm, we shouldn't give them that as their primary!
793  if ( isdefined( self.pers["weapon"] ) && self.pers["weapon"] != level.weaponNone && !self.pers["weapon"].isCarriedKillstreak )
794  {
795  primaryWeapon = self.pers["weapon"];
796  }
797  else
798  {
799  primaryWeapon = self GetLoadoutWeapon( self.class_num, "primary" );
800  }
801 
802  if( primaryWeapon.isCarriedKillstreak )
803  {
804  primaryWeapon = level.weaponNull;
805  }
806 
807  self.pers["primaryWeapon"] = primaryWeapon;
808 
809  // give primary weapon
810  if ( primaryWeapon != level.weaponNull )
811  {
812  primaryWeaponOptions = self CalcWeaponOptions( self.class_num, 0 );
813 
814 // /# println( "^5Loadout " + self.name + " GiveWeapon( " + primaryWeapon.name + " ) -- primary" ); #/
815 
816  acvi = self GetAttachmentCosmeticVariantForWeapon( self.class_num, "primary" );
817  self GiveWeapon( primaryWeapon, primaryWeaponOptions, acvi );
818 
819  self ‪weapons::bestweapon_spawn(primaryWeapon, primaryWeaponOptions, acvi);
820 
821  self.primaryLoadoutWeapon = primaryWeapon;
822  self.primaryLoadoutAltWeapon = primaryWeapon.altWeapon;
823  self.primaryLoadoutGunSmithVariantIndex = self GetLoadoutGunSmithVariantIndex( self.class_num, 0 );
824  if( self HasPerk( "specialty_extraammo" ) )
825  {
826  self giveMaxAmmo( primaryWeapon );
827  }
828 
829  spawnWeapon = primaryWeapon;
830  initialWeaponCount++;
831  }
832 
833  // give seconday weapon
834  sidearm = self GetLoadoutWeapon( self.class_num, "secondary" );
835 
836  if( sidearm.isCarriedKillstreak )
837  sidearm = level.weaponNull;
838 
839  if( sidearm.name == "bowie_knife" )
840  sidearm = level.weaponNull;
841 
842  if ( sidearm != level.weaponNull )
843  {
844  secondaryWeaponOptions = self CalcWeaponOptions( self.class_num, 1 );
845 
846 // /# println( "^5Loadout " + self.name + " GiveWeapon( " + sidearm.name + " ) -- sidearm" ); #/
847 
848  acvi = self GetAttachmentCosmeticVariantForWeapon( self.class_num, "secondary" );
849  self GiveWeapon( sidearm, secondaryWeaponOptions, acvi );
850  self.secondaryLoadoutWeapon = sidearm;
851  self.secondaryLoadoutAltWeapon = sidearm.altWeapon;
852  self.secondaryLoadoutGunSmithVariantIndex = self GetLoadoutGunSmithVariantIndex( self.class_num, 1 );
853 
854  if ( self HasPerk( "specialty_extraammo" ) )
855  {
856  self giveMaxAmmo( sidearm );
857  }
858 
859  if ( spawnWeapon == level.weaponNull )
860  {
861  spawnWeapon = sidearm;
862  }
863 
864  initialWeaponCount++;
865  }
866 
867  if ( !self HasMaxPrimaryWeapons() )
868  {
869  if ( !isUsingT7Melee() )
870  {
871 // /# println( "^5Loadout " + self.name + " GiveWeapon( " + level.weaponBaseMeleeHeld.name + " ) -- level.weaponBaseMeleeHeld 1" ); #/
872  knifeWeaponOptions = self CalcWeaponOptions( self.class_num, 2 );
873  self GiveWeapon( level.weaponBaseMeleeHeld, knifeWeaponOptions );
874  }
875 
876  if ( initialWeaponCount == 0 )
877  {
878  spawnWeapon = level.weaponBaseMeleeHeld;
879  }
880  }
881 
882  if ( !isdefined( self.spawnWeapon ) && isdefined( self.pers["spawnWeapon"] ) )
883  {
884  self.spawnWeapon = self.pers["spawnWeapon"];
885  }
886 
887  if ( isdefined( self.spawnWeapon ) && DoesWeaponReplaceSpawnWeapon( self.spawnWeapon, spawnWeapon ) && !self.pers["changed_class"] )
888  {
889  spawnWeapon = self.spawnWeapon;
890  }
891 
892  self thread ‪loadout::initWeaponAttachments( spawnWeapon );
893 
894  self.pers["changed_class"] = false;
895  self.spawnWeapon = spawnWeapon;
896  self.pers["spawnWeapon"] = self.spawnWeapon;
897 
898  switchImmediate = isdefined( self.alreadySetSpawnWeaponOnce );
899  self setSpawnWeapon( spawnWeapon, switchImmediate );
900  self.alreadySetSpawnWeaponOnce = true;
901 
903 
904  self bbClassChoice( self.class_num, primaryWeapon, sidearm );
905 }
906 
908 {
909  changedClass = self.pers["changed_class"];
910  roundBased = !‪util::isOneRound();
911  firstRound = ‪util::isFirstRound();
912 
913  primaryOffhand = level.weaponNone;
914  primaryOffhandCount = 0;
915 
916  if ( GetDvarint( "gadgetEnabled") == 1 || GetDvarint( "equipmentAsGadgets") == 1 )
917  {
918  primaryOffhand = self GetLoadoutWeapon( self.class_num, "primaryGadget" );
919  primaryOffhandCount = primaryOffhand.startammo;
920  }
921  else
922  {
923  primaryOffhandName = self GetLoadoutItemRef( self.class_num, "primarygrenade" );
924 
925  if ( primaryOffhandName != "" && primaryOffhandName != "weapon_null" )
926  {
927  primaryOffhand = GetWeapon( primaryOffhand );
928  primaryOffhandCount = self GetLoadoutItem( self.class_num, "primarygrenadecount" );
929  }
930  }
931 
932  if ( ‪isLeagueItemRestricted( primaryOffhand.name ) || !‪isEquipmentAllowed( primaryOffhand.name ) )
933  {
934  primaryOffhand = level.weaponNone;
935  primaryOffhandCount = 0;
936  }
937 
938  if ( primaryOffhand == level.weaponNone )
939  {
940  primaryOffhand = GetWeapon( "null_offhand_primary" );
941  primaryOffhandCount = 0;
942  }
943 
944  if ( primaryOffhand != level.weaponNull )
945  {
946  // /# println( "^5Loadout " + self.name + " GiveWeapon( " + primaryOffhand.name + " ) -- primaryOffhand" ); #/
947 
948  self GiveWeapon( primaryOffhand );
949 
950  self SetWeaponAmmoClip( primaryOffhand, primaryOffhandCount );
951  self SwitchToOffhand( primaryOffhand );
952  self.grenadeTypePrimary = primaryOffhand;
953  self.grenadeTypePrimaryCount = primaryOffhandCount;
954 
955  self ‪ability_util::gadget_reset( primaryOffhand, changedClass, roundBased, firstRound );
956  }
957 }
958 
960 {
961  changedClass = self.pers["changed_class"];
962  roundBased = !‪util::isOneRound();
963  firstRound = ‪util::isFirstRound();
964 
965  secondaryOffhand = level.weaponNone;
966  secondaryOffhandCount = 0;
967 
968  if ( GetDvarint( "gadgetEnabled") == 1 || GetDvarint( "equipmentAsGadgets") == 1 )
969  {
970  secondaryOffhand = self GetLoadoutWeapon( self.class_num, "secondaryGadget" );
971  secondaryOffhandCount = secondaryOffhand.startammo;
972  }
973  else
974  {
975  secondaryOffhandName = self GetLoadoutItemRef( self.class_num, "specialgrenade" );
976 
977  if ( secondaryOffhandName != "" && secondaryOffhandName != "weapon_null" )
978  {
979  secondaryOffhand = GetWeapon( secondaryOffhand );
980  secondaryOffhandCount = self GetLoadoutItem( self.class_num, "specialgrenadecount" );
981  }
982  }
983 
984  if ( ‪isLeagueItemRestricted( secondaryOffhand.name ) || !‪isEquipmentAllowed( secondaryOffhand.name ) )
985  {
986  secondaryOffhand = level.weaponNone;
987  secondaryOffhandCount = 0;
988  }
989 
990  if ( secondaryOffhand == level.weaponNone )
991  {
992  secondaryOffhand = GetWeapon( "null_offhand_secondary" );
993  secondaryOffhandCount = 0;
994  }
995 
996  if ( secondaryOffhand != level.weaponNull )
997  {
998  self GiveWeapon( secondaryOffhand );
999 
1000  self SetWeaponAmmoClip( secondaryOffhand, secondaryOffhandCount );
1001  self SwitchToOffhand( secondaryOffhand );
1002  self.grenadeTypeSecondary = secondaryOffhand;
1003  self.grenadeTypeSecondaryCount = secondaryOffhandCount;
1004 
1005  self ‪ability_util::gadget_reset( secondaryOffhand, changedClass, roundBased, firstRound );
1006  }
1007 }
1008 
1010 {
1011  changedClass = self.pers["changed_class"];
1012  roundBased = !‪util::isOneRound();
1013  firstRound = ‪util::isFirstRound();
1014 
1015  classNum = self.class_num_for_global_weapons;
1016 
1017  specialOffhand = level.weaponNone;
1018  specialOffhandCount = 0;
1019 
1020  specialOffhand = self GetLoadoutWeapon( self.class_num_for_global_weapons, "herogadget" );
1021  specialOffhandCount = specialOffhand.startammo;
1022 
1023  if ( isdefined( self.pers[#"rouletteWeapon"] ) )
1024  {
1025  assert( specialOffhand.name == "gadget_roulette" );
1026  specialOffhand = self.pers[#"rouletteWeapon"];
1027  ‪roulette::gadget_roulette_give_earned_specialist( specialOffhand, false ) ;
1028  }
1029 
1030  if ( ‪isLeagueItemRestricted( specialOffhand.name ) || !‪isEquipmentAllowed( specialOffhand.name ) )
1031  {
1032  specialOffhand = level.weaponNone;
1033  specialOffhandCount = 0;
1034  }
1035 
1036  if ( specialOffhand == level.weaponNone )
1037  {
1038  specialOffhand = level.weaponNull;
1039  specialOffhandCount = 0;
1040  }
1041 
1042  if ( specialOffhand != level.weaponNull )
1043  {
1044  self GiveWeapon( specialOffhand );
1045 
1046  self SetWeaponAmmoClip( specialOffhand, specialOffhandCount );
1047  self SwitchToOffhand( specialOffhand );
1048  self.grenadeTypeSpecial = specialOffhand;
1049  self.grenadeTypeSpecialCount = specialOffhandCount;
1050 
1051  self ‪ability_util::gadget_reset( specialOffhand, changedClass, roundBased, firstRound );
1052  }
1053 }
1054 
1056 {
1057  changedClass = self.pers["changed_class"];
1058  roundBased = !‪util::isOneRound();
1059  firstRound = ‪util::isFirstRound();
1060 
1061  classNum = self.class_num_for_global_weapons;
1062  heroWeapon = level.weaponNone;
1063  heroWeaponName = self GetLoadoutItemRef( self.class_num_for_global_weapons, "heroWeapon" );
1064 
1065  if ( heroWeaponName != "" && heroWeaponName != "weapon_null" )
1066  {
1067  if ( heroWeaponName == "hero_minigun" )
1068  {
1069  model = self GetCharacterBodyModel();
1070  if ( IsDefined( model ) && IsSubStr(model, "body3") )
1071  {
1072  heroWeaponName = "hero_minigun_body3";
1073  }
1074  }
1075 
1076  heroWeapon = GetWeapon( heroWeaponName );
1077  }
1078 
1079  if ( heroWeapon != level.weaponNone )
1080  {
1081  self.heroWeapon = heroWeapon;
1082  self GiveWeapon( heroWeapon );
1083 
1084  self ‪ability_util::gadget_reset( heroWeapon, changedClass, roundBased, firstRound );
1085  }
1086 }
1087 
1088 function ‪giveLoadout( team, weaponclass )
1089 {
1090  if ( isdefined( level.giveCustomLoadout ) )
1091  {
1092  spawnWeapon = self [[level.giveCustomLoadout]]();
1093  if( isdefined( spawnWeapon ) )
1094  {
1095  self thread ‪loadout::initWeaponAttachments( spawnWeapon );
1096  }
1097  self.spawnWeapon = spawnWeapon;
1098  }
1099  else
1100  {
1101  self ‪giveLoadout_init( true );
1102 
1103  ‪setClassNum( weaponClass );
1104 
1105  self SetActionSlot( 3, "altMode" );
1106  self SetActionSlot( 4, "" );
1107 
1108  allocationSpent = self GetLoadoutAllocation( self.class_num );
1109  overAllocation = ( allocationSpent > level.maxAllocation );
1110 
1111 
1112  if( !overAllocation )
1113  {
1114  //Perks must come first in case other give-functions check for perks
1115  ‪givePerks();
1116 
1117  ‪giveWeapons();
1119  }
1120  else
1121  {
1123  }
1124 
1126 
1127  if ( GetDvarint( "tu11_enableClassicMode") == 0 )
1128  {
1131  }
1132 
1133  giveKillStreaks();
1134  }
1135 
1136  self ‪teams::set_player_model( undefined, undefined );
1137 
1138  if( isdefined( self.movementSpeedModifier ) )
1139  {
1140  self setMoveSpeedScale( self.movementSpeedModifier * self getMoveSpeedScale() );
1141  }
1142 
1143  // cac specialties that require loop threads
1144  self ‪cac_selector();
1145 
1146  self ‪giveLoadout_finalize( self.spawnWeapon, self.pers["primaryWeapon"] );
1147 }
1148 
1149 function ‪giveLoadout_finalize(spawnWeapon, primaryWeapon)
1150 {
1151  // tagTMR<NOTE>: force first raise anim on initial spawn of match
1152  if ( !isdefined( self.firstSpawn ) )
1153  {
1154  if ( isdefined( spawnWeapon ) )
1155  self InitialWeaponRaise( spawnWeapon );
1156  else
1157  self InitialWeaponRaise( primaryWeapon );
1158  }
1159  else
1160  {
1161  // ... and eliminate first raise anim for all other spawns
1162  self SetEverHadWeaponAll( true );
1163  }
1164 
1165  self.firstSpawn = false;
1166  self.switchedTeamsResetGadgets = false;
1167 
1168  self ‪flagsys::set( "loadout_given" );
1169 }
1170 
1171 // sets the amount of ammo in the gun.
1172 // if the clip maxs out, the rest goes into the stock.
1173 function ‪setWeaponAmmoOverall( weapon, amount )
1174 {
1175  if ( weapon.isClipOnly )
1176  {
1177  self setWeaponAmmoClip( weapon, amount );
1178  }
1179  else
1180  {
1181  self setWeaponAmmoClip( weapon, amount );
1182  diff = amount - self getWeaponAmmoClip( weapon );
1183  assert( diff >= 0 );
1184  self setWeaponAmmoStock( weapon, diff );
1185  }
1186 }
1187 
1189 {
1190  if ( !isdefined( self.pers["class"] ) )
1191  {
1192  self.pers["class"] = "";
1193  }
1194  self.curClass = self.pers["class"];
1195  self.lastClass = "";
1196 
1197  self.detectExplosives = false;
1198  self.bombSquadIcons = [];
1199  self.bombSquadIds = [];
1200  self.reviveIcons = [];
1201  self.reviveIds = [];
1202 }
1203 
1204 
1205 function ‪fadeAway( waitDelay, fadeDelay )
1206 {
1207  wait waitDelay;
1208 
1209  self fadeOverTime( fadeDelay );
1210  self.alpha = 0;
1211 }
1212 
1213 
1214 function ‪setClass( newClass )
1215 {
1216  self.curClass = newClass;
1217 }
1218 
1219 // ============================================================================================
1220 // ======= =======
1221 // ======= Create a Class Specialties =======
1222 // ======= =======
1223 // ============================================================================================
1224 
1226 {
1227  level.cac_armorpiercing_data = GetDvarInt( "perk_armorpiercing", 40 ) / 100;// increased bullet damage by this %
1228  level.cac_bulletdamage_data = GetDvarInt( "perk_bulletDamage", 35 ); // increased bullet damage by this %
1229  level.cac_fireproof_data = GetDvarInt( "perk_fireproof", 20 ); // reduced flame damage by this %
1230  level.cac_armorvest_data = GetDvarInt( "perk_armorVest", 80 ); // multipy damage by this %
1231  level.cac_flakjacket_data = GetDvarInt( "perk_flakJacket", 35 ); // explosive damage is this % of original
1232  level.cac_flakjacket_hardcore_data = GetDvarInt( "perk_flakJacket_hardcore", 9 ); // explosive damage is this % of original for hardcore
1233 }
1234 
1235 // CAC: Selector function, calls the individual cac features according to player's class settings
1236 // Info: Called every time player spawns during loadout stage
1238 {
1239 
1240  self.detectExplosives = false;
1241 
1242 
1243  if ( IsDefined( self.specialty ) )
1244  {
1245  perks = self.specialty;
1246  for( i=0; i<perks.size; i++ )
1247  {
1248  perk = perks[i];
1249  // run scripted perk that thread loops
1250  if( perk == "specialty_detectexplosive" )
1251  self.detectExplosives = true;
1252  }
1253 }
1254 }
1255 
1257 {
1258  perks = self.specialty;
1259  self ClearPerks();
1260  for( i=0; i<perks.size; i++ )
1261  {
1262  perk = perks[i];
1263 
1264  // TO DO: ask code to register the inventory perks and null perk
1265  // not registering inventory and null perks to code
1266  if ( perk == "specialty_null" || isSubStr( perk, "specialty_weapon_" ) || perk == "weapon_null" )
1267  continue;
1268 
1269  if ( !level.perksEnabled )
1270  continue;
1271 
1272  self setPerk( perk );
1273  }
1274 }
1275 
1276 function ‪cac_modified_vehicle_damage( victim, attacker, ‪damage, meansofdeath, weapon, inflictor )
1277 {
1278  // skip conditions
1279  if ( !isdefined( victim) || !isdefined( attacker ) || !isplayer( attacker ) )
1280  return ‪damage;
1281  if ( !isdefined( ‪damage ) || !isdefined( meansofdeath ) || !isdefined( weapon ) )
1282  return ‪damage;
1283 
1284  old_damage = ‪damage;
1285  final_damage = ‪damage;
1286 
1287  // Perk version
1288 
1289  if ( attacker HasPerk( "specialty_bulletdamage" ) && ‪isPrimaryDamage( meansofdeath ) )
1290  {
1291  final_damage = ‪damage*(100+level.cac_bulletdamage_data)/100;
1292  }
1293  else
1294  {
1295  final_damage = old_damage;
1296  }
1297 
1298  // return unchanged damage
1299  return int( final_damage );
1300 }
1301 
1302 function ‪cac_modified_damage( victim, attacker, ‪damage, mod, weapon, inflictor, hitloc )
1303 {
1304  assert( isdefined( victim ) );
1305  assert( isdefined( attacker ) );
1306  assert( IsPlayer( victim ) );
1307 
1308  attacker_is_player = IsPlayer( attacker );
1309 
1310  if ( ‪damage <= 0 )
1311  {
1312  return ‪damage;
1313  }
1314 
1315  final_damage = ‪damage;
1316 
1317  if ( victim != attacker )
1318  {
1319  if ( attacker_is_player && attacker HasPerk( "specialty_bulletdamage" ) && ‪isPrimaryDamage( mod ) )
1320  {
1321  // if victim has armor then do not change damage, it is cancelled out, else damage is increased
1322  if( victim HasPerk( "specialty_armorvest" ) && !‪isHeadDamage( hitloc ) )
1323  {
1324  }
1325  else
1326  {
1327  final_damage = ‪damage * ( 100 + level.cac_bulletdamage_data ) / 100;
1328  }
1329  }
1330  else if ( victim HasPerk( "specialty_armorvest" ) && ‪isPrimaryDamage( mod ) && !‪isHeadDamage( hitloc ) )
1331  {
1332  //If victim has body armor, reduce the damage by the cac armor vest value as a percentage
1333  final_damage = ‪damage * ( level.cac_armorvest_data * .01 );
1334  }
1335  else if ( victim HasPerk( "specialty_fireproof" ) && ‪isFireDamage( weapon, mod ) )
1336  {
1337  final_damage = ‪damage * ( level.cac_fireproof_data * .01 );
1338  }
1339  else if ( victim HasPerk( "specialty_flakjacket" ) && ‪isExplosiveDamage( mod ) && !weapon.ignoresFlakJacket && !victim ‪grenadeStuck( inflictor ) )
1340  {
1341  // put these back in to make FlakJacket a perk again (for easy tuning of system when not body type specfic)
1342  cac_data = ( level.hardcoreMode ? level.cac_flakjacket_hardcore_data : level.cac_flakjacket_data );
1343 
1345  {
1346  if ( level.teambased && attacker.team != victim.team )
1347  {
1348  victim thread ‪challenges::flakjacketProtectedMP( weapon, attacker );
1349  }
1350  else if ( attacker != victim )
1351  {
1352  victim thread ‪challenges::flakjacketProtectedMP( weapon, attacker );
1353  }
1354  }
1355 
1356  final_damage = int( ‪damage * ( cac_data / 100 ) );
1357  }
1358  }
1359 
1360  final_damage = int( final_damage );
1361 
1362  if ( final_damage < 1 )
1363  {
1364  final_damage = 1;
1365  }
1366 
1367  return ( final_damage );
1368 }
1369 
1370 // including grenade launcher, grenade, bazooka, betty, satchel charge
1371 function ‪isExplosiveDamage( meansofdeath )
1372 {
1373  switch( meansofdeath )
1374  {
1375  case "MOD_GRENADE":
1376  case "MOD_GRENADE_SPLASH":
1377  case "MOD_PROJECTILE":
1378  case "MOD_PROJECTILE_SPLASH":
1379  case "MOD_EXPLOSIVE":
1380  return true;
1381  }
1382 
1383  return false;
1384 }
1385 
1386 function ‪hasTacticalMask( player )
1387 {
1388  return ( player HasPerk( "specialty_stunprotection" ) || player HasPerk( "specialty_flashprotection" ) || player HasPerk( "specialty_proximityprotection" ) );
1389 }
1390 
1391 // if primary weapon damage
1392 function ‪isPrimaryDamage( meansofdeath )
1393 {
1394  return( meansofdeath == "MOD_RIFLE_BULLET" || meansofdeath == "MOD_PISTOL_BULLET" );
1395 }
1396 
1397 function ‪isBulletDamage( meansofdeath )
1398 {
1399  return( meansofdeath == "MOD_RIFLE_BULLET" || meansofdeath == "MOD_PISTOL_BULLET" || meansofdeath == "MOD_HEAD_SHOT" );
1400 }
1401 
1402 function ‪isFMJDamage( sWeapon, sMeansOfDeath, attacker )
1403 {
1404  // The Bullet Penetration perk comes from the fmj attachment in the attachmentTable.csv or from the weapon in statstable.csv
1405  return IsDefined( attacker ) && IsPlayer( attacker ) && attacker HasPerk( "specialty_armorpiercing" ) && IsDefined( sMeansOfDeath ) && ‪isBulletDamage( sMeansOfDeath );
1406 }
1407 
1408 function ‪isFireDamage( weapon, meansofdeath )
1409 {
1410  if ( weapon.doesFireDamage && (meansofdeath == "MOD_BURNED" || meansofdeath == "MOD_GRENADE" || meansofdeath == "MOD_GRENADE_SPLASH") )
1411  return true;
1412 
1413  return false;
1414 }
1415 
1416 function ‪isHeadDamage( hitloc )
1417 {
1418  return ( hitloc == "helmet" || hitloc == "head" || hitloc == "neck" );
1419 }
1420 
1421 function ‪grenadeStuck( inflictor )
1422 {
1423  return ( isdefined( inflictor ) && isdefined( inflictor.stucktoplayer ) && inflictor.stucktoplayer == self );
1424 }
‪on_connect
‪function on_connect()
Definition: _loadout.gsc:44
‪register_perks
‪function register_perks()
Definition: _loadout.gsc:1256
‪initWeaponAttachments
‪function initWeaponAttachments(weapon)
Definition: loadout_shared.gsc:41
‪isOneRound
‪function isOneRound()
Definition: util_shared.gsc:3497
‪STATS_TABLE_COL_COUNT
‪#define STATS_TABLE_COL_COUNT
Definition: _statstable.gsh:7
‪givePerks
‪function givePerks()
Definition: _loadout.gsc:694
‪giveLoadout
‪function giveLoadout(team, weaponclass)
Definition: _loadout.gsc:1088
‪has_flak_jacket_perk_purchased_and_equipped
‪function has_flak_jacket_perk_purchased_and_equipped()
Definition: util_shared.gsc:4088
‪giveSecondaryOffhand
‪function giveSecondaryOffhand()
Definition: _loadout.gsc:959
‪on_start_gametype
‪function on_start_gametype(func, obj)
Definition: callbacks_shared.csc:285
‪isHeadDamage
‪function isHeadDamage(hitloc)
Definition: _loadout.gsc:1416
‪getKillStreakIndex
‪function getKillStreakIndex(weaponclass, killstreakNum)
Definition: _loadout.gsc:504
‪cac_selector
‪function cac_selector()
Definition: _loadout.gsc:1237
‪giveLoadout_finalize
‪function giveLoadout_finalize(spawnWeapon, primaryWeapon)
Definition: _loadout.gsc:1149
‪fadeAway
‪function fadeAway(waitDelay, fadeDelay)
Definition: _loadout.gsc:1205
‪giveLoadout_init
‪function giveLoadout_init(takeAllWeapons)
Definition: _loadout.gsc:672
‪gadget_reset
‪function gadget_reset(gadgetWeapon, changedClass, roundBased, firstRound)
Definition: _ability_util.gsc:108
‪giveWeapons
‪function giveWeapons()
Definition: _loadout.gsc:786
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪isPerkGroup
‪function isPerkGroup(perkName)
Definition: _loadout.gsc:621
‪get_by_menu_name
‪function get_by_menu_name(killstreak)
Definition: _killstreaks.gsc:430
‪get_item_count
‪function get_item_count(itemReference)
Definition: _loadout.gsc:304
‪isEquipmentAllowed
‪function isEquipmentAllowed(equipment_name)
Definition: _loadout.gsc:641
‪getTweakableValue
‪function getTweakableValue(category, name)
Definition: _tweakables.gsc:12
‪_setPlayerMomentum
‪function _setPlayerMomentum(player, momentum, updateScore=true)
Definition: _globallogic_score.gsc:584
‪on_damage_special_discgun
‪function on_damage_special_discgun(eAttacker, eInflictor, weapon, meansOfDeath, damage)
Definition: _loadout.gsc:248
‪initStaticWeaponsTime
‪function initStaticWeaponsTime()
Definition: _loadout.gsc:636
‪getDefaultClassSlotWithExclusions
‪function getDefaultClassSlotWithExclusions(className, slotName)
Definition: _loadout.gsc:317
‪givePrimaryOffhand
‪function givePrimaryOffhand()
Definition: _loadout.gsc:907
‪isExplosiveDamage
‪function isExplosiveDamage(meansofdeath)
Definition: _loadout.gsc:1371
‪cac_init
‪function cac_init()
Definition: _loadout.gsc:362
‪giveKillstreaks
‪function giveKillstreaks()
Definition: _loadout.gsc:521
‪STATS_TABLE_COL_NUMBERING
‪#define STATS_TABLE_COL_NUMBERING
Definition: _statstable.gsh:3
‪STATS_TABLE_COL_GROUP
‪#define STATS_TABLE_COL_GROUP
Definition: _statstable.gsh:4
‪damage
‪function damage(trap)
Definition: _zm_trap_electric.gsc:116
‪get_killstreak_weapon
‪function get_killstreak_weapon(killstreak)
Definition: killstreaks_shared.gsc:106
‪getAttachmentsDisabled
‪function getAttachmentsDisabled()
Definition: _loadout.gsc:493
‪STATS_TABLE_COL_ATTACHMENTS
‪#define STATS_TABLE_COL_ATTACHMENTS
Definition: _statstable.gsh:10
‪bestweapon_spawn
‪function bestweapon_spawn(weapon, options, acvi)
Definition: _weapons.gsc:43
‪setClassNum
‪function setClassNum(weaponClass)
Definition: _loadout.gsc:730
‪reset_specialty_slots
‪function reset_specialty_slots(class_num)
Definition: _loadout.gsc:627
‪setClass
‪function setClass(newClass)
Definition: _loadout.gsc:1214
‪init
‪function init()
Definition: _loadout.gsc:48
‪giveLoadoutLevelSpecific
‪function giveLoadoutLevelSpecific(team, weaponclass)
Definition: _loadout.gsc:659
‪STATS_TABLE_MAX_ITEMS
‪#define STATS_TABLE_MAX_ITEMS
Definition: _statstable.gsh:1
‪getAttachmentString
‪function getAttachmentString(weaponNum, attachmentNum)
Definition: _loadout.gsc:477
‪ARRAY_ADD
‪#define ARRAY_ADD(__array, __item)
Definition: shared.gsh:304
‪load_default_loadout
‪function load_default_loadout(weaponclass, classNum)
Definition: _loadout.gsc:333
‪grenadeStuck
‪function grenadeStuck(inflictor)
Definition: _loadout.gsc:1421
‪isFMJDamage
‪function isFMJDamage(sWeapon, sMeansOfDeath, attacker)
Definition: _loadout.gsc:1402
‪STATS_TABLE_COL_NAME
‪#define STATS_TABLE_COL_NAME
Definition: _statstable.gsh:5
‪is_attachment_excluded
‪function is_attachment_excluded(attachment)
Definition: _loadout.gsc:280
‪giveSpecialOffhand
‪function giveSpecialOffhand()
Definition: _loadout.gsc:1009
‪hero_register_dialog
‪function hero_register_dialog(weapon)
Definition: _loadout.gsc:354
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪cac_modified_vehicle_damage
‪function cac_modified_vehicle_damage(victim, attacker, damage, meansofdeath, weapon, inflictor)
Definition: _loadout.gsc:1276
‪add_weapon_damage
‪function add_weapon_damage(weapontype, callback)
Definition: callbacks_shared.gsc:580
‪isFirstRound
‪function isFirstRound()
Definition: util_shared.gsc:3505
‪getClassChoice
‪function getClassChoice(response)
Definition: _loadout.gsc:466
‪STATS_TABLE_COL_REFERENCE
‪#define STATS_TABLE_COL_REFERENCE
Definition: _statstable.gsh:6
‪isFireDamage
‪function isFireDamage(weapon, meansofdeath)
Definition: _loadout.gsc:1408
‪STATS_TABLE_COL_IMAGE
‪#define STATS_TABLE_COL_IMAGE
Definition: _statstable.gsh:8
‪isBulletDamage
‪function isBulletDamage(meansofdeath)
Definition: _loadout.gsc:1397
‪set
‪function set(str_field_name, n_value)
Definition: clientfield_shared.gsc:34
‪create_class_exclusion_list
‪function create_class_exclusion_list()
Definition: _loadout.gsc:257
‪__init__
‪function __init__()
Definition: _loadout.gsc:37
‪giveBaseWeapon
‪function giveBaseWeapon()
Definition: _loadout.gsc:770
‪initPerkDvars
‪function initPerkDvars()
Definition: _loadout.gsc:1225
‪gadget_roulette_give_earned_specialist
‪function gadget_roulette_give_earned_specialist(weapon, playSound)
Definition: _gadget_roulette.gsc:164
‪set_player_model
‪function set_player_model(team, weapon)
Definition: _teams.gsc:349
‪hasTacticalMask
‪function hasTacticalMask(player)
Definition: _loadout.gsc:1386
‪setWeaponAmmoOverall
‪function setWeaponAmmoOverall(weapon, amount)
Definition: _loadout.gsc:1173
‪giveHeroWeapon
‪function giveHeroWeapon()
Definition: _loadout.gsc:1055
‪weapon_class_register
‪function weapon_class_register(weaponName, weapon_type)
Definition: _loadout.gsc:338
‪on_player_connecting
‪function on_player_connecting()
Definition: _loadout.gsc:1188
‪set_statstable_id
‪function set_statstable_id()
Definition: _loadout.gsc:295
‪isLeagueItemRestricted
‪function isLeagueItemRestricted(item)
Definition: _loadout.gsc:649
‪cac_modified_damage
‪function cac_modified_damage(victim, attacker, damage, mod, weapon, inflictor, hitloc)
Definition: _loadout.gsc:1302
‪name
‪class GroundFx name
‪flakjacketProtectedMP
‪function flakjacketProtectedMP(weapon, attacker)
Definition: _challenges.gsc:1936
‪getStatsTableName
‪function getStatsTableName()
Definition: util_shared.csc:1343
‪is_item_excluded
‪function is_item_excluded(itemIndex)
Definition: loadout_shared.gsc:8
‪isPrimaryDamage
‪function isPrimaryDamage(meansofdeath)
Definition: _loadout.gsc:1392
‪on_connecting
‪function on_connecting(func, obj)
Definition: callbacks_shared.gsc:146