‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_bot_loadout.gsc
Go to the documentation of this file.
1 #using scripts\shared\array_shared;
2 #using scripts\shared\rank_shared;
3 
4 #insert scripts\shared\shared.gsh;
5 #insert scripts\shared\statstable_shared.gsh;
6 
7 #using scripts\mp\killstreaks\_killstreaks;
8 
9 #using scripts\mp\bots\_bot;
10 
11 #define BOT_ALLOCATION_MAX 10
12 #define BOT_ALLOCATION_UNLOCK_MAX 3
13 #define BOT_RANK_ALL_OPTIONS_AVAILABLE 20
14 #define BOT_RANK_OPTIONS_MULTIPLIER 4
15 
16 #namespace bot_loadout;
17 
18 // Item Whitelist
19 //========================================
20 
21 function ‪in_whitelist( itemName )
22 {
23  if ( !isdefined( itemName ) )
24  return false;
25 
26  switch( itemName )
27  {
28  // Secondaries
29  case "WEAPON_KNIFE_LOADOUT":
30 
31  case "WEAPON_PISTOL_STANDARD":
32  case "WEAPON_PISTOL_BURST":
33  case "WEAPON_PISTOL_FULLAUTO":
34 
35  case "WEAPON_LAUNCHER_STANDARD":
36  case "WEAPON_LAUNCHER_LOCKONLY":
37 
38  case "WEAPON_SMG_STANDARD":
39  case "WEAPON_SMG_BURST":
40  case "WEAPON_SMG_FASTFIRE":
41  case "WEAPON_SMG_LONGRANGE":
42  case "WEAPON_SMG_VERSATILE":
43  case "WEAPON_SMG_CAPACITY":
44 
45  // Primaries
46  case "WEAPON_AR_STANDARD":
47  case "WEAPON_AR_ACCURATE":
48  case "WEAPON_AR_CQB":
49  case "WEAPON_AR_DAMAGE":
50  case "WEAPON_AR_FASTBURST":
51  case "WEAPON_AR_LONGBURST":
52  case "WEAPON_AR_MARKSMAN":
53 
54  case "WEAPON_LMG_CQB":
55  case "WEAPON_LMG_HEAVY":
56  case "WEAPON_LMG_LIGHT":
57  case "WEAPON_LMG_SLOWFIRE":
58 
59  case "WEAPON_SNIPER_FASTBOLT":
60  case "WEAPON_SNIPER_FASTSEMI":
61  case "WEAPON_SNIPER_POWERBOLT":
62  case "WEAPON_SNIPER_CHARGESHOT":
63 
64  case "WEAPON_SHOTGUN_FULLAUTO":
65  case "WEAPON_SHOTGUN_PRECISION":
66  case "WEAPON_SHOTGUN_PUMP":
67  case "WEAPON_SHOTGUN_SEMIAUTO":
68 
69  // Lethals
70  case "WEAPON_FRAGGRENADE":
71  case "WEAPON_HATCHET":
72  case "WEAPON_STICKY_GRENADE":
73  //case "WEAPON_SATCHEL_CHARGE":
74  case "WEAPON_BOUNCINGBETTY":
75  case "WEAPON_INCENDIARY_GRENADE":
76 
77  // Tacticals
78  case "WEAPON_WILLY_PETE":
79  case "WEAPON_STUN_GRENADE":
80  case "WEAPON_EMPGRENADE":
81  case "WEAPON_FLASHBANG":
82  case "WEAPON_PROXIMITY_GRENADE":
83  //case "WEAPON_PDA_HACK":
84  //case "WEAPON_TROPHY_SYSTEM":
85 
86  // Killstreaks
87  //case "KILLSTREAK_RCBOMB":
88  case "KILLSTREAK_RECON":
89  case "KILLSTREAK_COUNTER_UAV":
90  //case "KILLSTREAK_SUPPLY_DROP":
91  //case "KILLSTREAK_MICROWAVE_TURRET":
92  //case "KILLSTREAK_REMOTE_MISSILE":
93  //case "KILLSTREAK_PLANEMORTAR":
94  //case "KILLSTREAK_AUTO_TURRET":
95  //case "KILLSTREAK_AI_TANK_DROP":
96  //case "KILLSTREAK_HELICOPTER_COMLINK":
97  case "KILLSTREAK_SATELLITE":
98  //case "KILLSTREAK_EMP":
99  //case "KILLSTREAK_HELICOPTER_GUNNER":
100  case "KILLSTREAK_RAPS":
101  //case "KILLSTREAK_DRONE_STRIKE":
102  //case "KILLSTREAK_DART":
103  case "KILLSTREAK_SENTINEL":
104 
105  // TU Something Weapons
106  //case "WEAPON_MELEE_KNUCKLES":
107  //case "WEAPON_MELEE_BUTTERFLY":
108  //case "WEAPON_MELEE_WRENCH":
109 
110  // TU 6 Weapons
111  //case "WEAPON_PISTOL_SHOTGUN":
112  //case "WEAPON_AR_GARAND":
113  //case "WEAPON_SPECIAL_CROSSBOW":
114  //case "WEAPON_MELEE_CROWBAR":
115  //case "WEAPON_MELEE_SWORD":
116  return true;
117  }
118 
119  return false;
120 }
121 
122 // Classes
123 //========================================
124 
126 {
127  primaryWeapons = self ‪get_available_items( undefined, "primary" );
128  secondaryWeapons = self ‪get_available_items( undefined, "secondary" );
129  lethals = self ‪get_available_items( undefined, "primarygadget" );
130  tacticals = self ‪get_available_items( undefined, "secondarygadget" );
131  if ( ‪IS_TRUE( level.perksEnabled ) )
132  {
133  specialties1 = self ‪get_available_items( undefined, "specialty1" );
134  specialties2 = self ‪get_available_items( undefined, "specialty2" );
135  specialties3 = self ‪get_available_items( undefined, "specialty3" );
136  }
137 
138  foreach( className, classValue in level.classMap )
139  {
140  if ( !isSubstr( className, "custom" ) )
141  {
142  continue;
143  }
144 
145  classIndex = int( className[className.size-1] );
146 
147  ‪pickedItems = [];
148 
149  pick_item( ‪pickedItems, primaryWeapons );
150 
151  if ( RandomInt( 100 ) < 95 ) // 5% chance to be a boxer for Scronce
152  {
153  pick_item( ‪pickedItems, secondaryWeapons );
154  }
155 
156  // Shuffle these selections around a bit so the classes don't all look the same when the allocation is low
157  otherItems = Array ( lethals, tacticals, specialties1, specialties2, specialties3 );
158  otherItems = array::randomize( otherItems );
159 
160  for ( i = 0; i < otherItems.size; i ++ )
161  {
162  pick_item( ‪pickedItems, otherItems[i] );
163  }
164 
165  // Add items up to the max allocation
166  for ( i = 0; i < ‪pickedItems.size && i < level.maxAllocation; i++ )
167  {
168  self BotClassAddItem( classIndex, ‪pickedItems[i] );
169  }
170 
171  // TODO: Pick primary/secondary attachments, extra perks, extra lethal, extra tactical, overkill
172 /*
173  primaryWeapon = self GetLoadoutWeapon( classIndex, "primary" );
174 
175  if ( primaryWeapon != level.weaponNone && primaryWeapon.supportedAttachments.size )
176  {
177  attachment = array::random( primaryWeapon.supportedAttachments );
178  self BotClassAddAttachment( classIndex, primaryWeapon, attachment, "primary" );
179  }
180 
181  secondaryWeapon = self GetLoadoutWeapon( classIndex, "secondary" );
182 
183  if ( secondaryWeapon != level.weaponNone && secondaryWeapon.supportedAttachments.size )
184  {
185  attachment = array::random( secondaryWeapon.supportedAttachments );
186  self BotClassAddAttachment( classIndex, secondaryWeapon, attachment, "secondary" );
187  }
188 */
189  }
190 }
191 
192 function pick_item( &‪pickedItems, items )
193 {
194  if ( !isdefined( items ) || items.size <= 0 )
195  {
196  return;
197  }
198 
199  ‪pickedItems[‪pickedItems.size] = array::random( items );
200 }
201 
202 function ‪pick_classes()
203 {
204  self.loadoutClasses = [];
205  self.launcherClassCount = 0;
206 
207  foreach( className, classValue in level.classMap )
208  {
209  if ( isSubstr( className, "custom" ) )
210  {
211  if ( level.disableCAC )
212  {
213  continue;
214  }
215 
216  classIndex = int( className[className.size-1] );
217  }
218  else
219  {
220  // Things bots could use better in the default classes:
221  // C4, Trophy System, Lock on only launcher
222  classIndex = level.classToClassNum[ classValue ];
223  }
224 
225  primary = self GetLoadoutWeapon( classIndex, "primary" );
226  secondary = self GetLoadoutWeapon( classIndex, "secondary" );
227 
228  botClass = SpawnStruct();
229  botClass.name = className;
230  botClass.index = classIndex;
231  botClass.value = classValue;
232  botClass.primary = primary;
233  botClass.secondary = secondary;
234 
235  if ( botClass.secondary.isRocketLauncher )
236  {
237  self.launcherClassCount++;
238  }
239 
240  self.loadoutClasses[ self.loadoutClasses.size ] = botClass;
241  }
242 }
243 
245 {
246  currValue = self.pers["class"];
247  if ( !isdefined( currValue ) )
248  {
249  return undefined;
250  }
251 
252  foreach( botClass in self.loadoutClasses )
253  {
254  if ( botClass.value == currValue )
255  {
256  return botClass;
257  }
258  }
259 
260  return undefined;
261 }
262 
263 // Specialists
264 //========================================
265 
267 {
268  if ( RandomInt( 2 ) < 1 || !self ‪pick_hero_ability() )
269  {
270  self ‪pick_hero_weapon();
271  }
272 }
273 
275 {
276  heroWeaponRef = self GetHeroWeaponName();
277 
278  if ( IsItemRestricted( heroWeaponRef ) )
279  {
280  return false;
281  }
282 
283  heroWeaponName = self ‪get_item_name( heroWeaponRef );
284  self BotClassAddItem( 0, heroWeaponName );
285 
286  return true;
287 }
288 
290 {
291  heroAbilityRef = self GetHeroAbilityName();
292 
293  if ( IsItemRestricted( heroAbilityRef ) )
294  {
295  return false;
296  }
297 
298  heroAbilityName = self ‪get_item_name( heroAbilityRef );
299  self BotClassAddItem( 0, heroAbilityName );
300 
301  return true;
302 }
303 
304 // Killstreaks
305 //========================================
306 
308 {
309  killstreaks = array::randomize( self ‪get_available_items( "killstreak" ) );
310 
311  for( i = 0; i < 3 && i < killstreaks.size; i++ )
312  {
313  self BotClassAddItem( 0, killstreaks[i] );
314  }
315 }
316 
317 
318 // Get Items
319 //========================================
320 
321 function ‪get_available_items( filterGroup, filterSlot )
322 {
323  // Get unlocked and unrestricted items
324  items = [];
325 
326  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
327  {
328  row = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
329 
330  if ( row < 0 )
331  {
332  continue;
333  }
334 
335  ‪name = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_NAME );
336 
337  if ( ‪name == "" || !‪in_whitelist( ‪name ) )
338  {
339  continue;
340  }
341 
342  allocation = Int( tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_ALLOCATION ) );
343 
344  if ( allocation < 0 )
345  {
346  continue;
347  }
348 
349  ref = tableLookupColumnForRow( level.statsTableId, row, ‪STATS_TABLE_COL_REFERENCE );
350 
351  if ( IsItemRestricted( ref ) )
352  {
353  continue;
354  }
355 
356  number = Int( tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_NUMBERING ) );
357 
358  if ( !SessionModeIsPrivate() && self IsItemLocked( number ) )
359  {
360  continue;
361  }
362 
363  if ( isdefined( filterGroup ) )
364  {
365  group = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_GROUP );
366 
367  if ( group != filterGroup )
368  {
369  continue;
370  }
371  }
372 
373  if ( isdefined( filterSlot ) )
374  {
375  slot = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_SLOT );
376 
377  if ( slot != filterSlot )
378  {
379  continue;
380  }
381  }
382 
383  items[items.size] = ‪name;
384  }
385 
386  return items;
387 }
388 
389 function ‪get_item_name( itemReference )
390 {
391  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
392  {
393  row = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
394 
395  if ( row < 0 )
396  {
397  continue;
398  }
399 
400  reference = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_REFERENCE );
401 
402  if ( reference != itemReference )
403  {
404  continue;
405  }
406 
407  ‪name = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_NAME );
408 
409  return ‪name;
410  }
411 
412  return undefined;
413 }
414 
415 // Not in use
416 
417 function ‪init()
418 {
419  level endon( "game_ended" );
420 
421  level.bot_banned_killstreaks = Array ( "KILLSTREAK_RCBOMB",
422  "KILLSTREAK_QRDRONE",
423  "KILLSTREAK_REMOTE_MISSILE",
424  "KILLSTREAK_REMOTE_MORTAR",
425  "KILLSTREAK_HELICOPTER_GUNNER" );
426  for ( ;; )
427  {
428  level waittill( "connected", player );
429 
430  if ( !player IsTestClient() )
431  {
432  continue;
433  }
434 
435  player thread ‪on_bot_connect();
436  }
437 }
438 
440 {
441  self endon( "disconnect" );
442 
443  if ( isdefined( self.pers[ "bot_loadout" ] ) )
444  {
445  return;
446  }
447 
448  wait( 0.10 );
449 
450  if ( self GetEntityNumber() % 2 == 0 )
451  {
453  }
454 
455  self ‪bot::set_rank();
456 
457  self BotSetRandomCharacterCustomization();
458 
459  if ( level.onlineGame && !SessionModeIsPrivate() )
460  {
461  self BotSetDefaultClass( 5, "class_assault" );
462  self BotSetDefaultClass( 6, "class_smg" );
463  self BotSetDefaultClass( 7, "class_lmg" );
464  self BotSetDefaultClass( 8, "class_cqb" );
465  self BotSetDefaultClass( 9, "class_sniper" );
466  }
467  else
468  {
469  self BotSetDefaultClass( 5, "class_assault" );
470  self BotSetDefaultClass( 6, "class_smg" );
471  self BotSetDefaultClass( 7, "class_lmg" );
472  self BotSetDefaultClass( 8, "class_cqb" );
473  self BotSetDefaultClass( 9, "class_sniper" );
474  }
475 
476  max_allocation = ‪BOT_ALLOCATION_MAX;
477 
478  if ( !SessionModeIsPrivate() )
479  {
480  for ( i = 1; i <= ‪BOT_ALLOCATION_UNLOCK_MAX; i++ )
481  {
482  if ( self IsItemLocked( rank::GetItemIndex( "feature_allocation_slot_" + i ) ) )
483  {
484  max_allocation--;
485  }
486  }
487  }
488 
489  self ‪construct_loadout( max_allocation );
490  self.pers[ "bot_loadout" ] = true;
491 }
492 
493 function ‪construct_loadout( allocation_max )
494 {
495  if ( !SessionModeIsPrivate() && self IsItemLocked( rank::GetItemIndex( "feature_cac" ) ) )
496  {
497  // cac still locked
498  return;
499  }
500 
501  pixbeginevent( "bot_construct_loadout" );
502 
503  item_list = ‪build_item_list();
504 
505 // item_list["primary"] = [];
506 // item_list["primary"][0] = "WEAPON_RIOTSHIELD";
507 
508  ‪construct_class( 0, item_list, allocation_max );
509  ‪construct_class( 1, item_list, allocation_max );
510  ‪construct_class( 2, item_list, allocation_max );
511  ‪construct_class( 3, item_list, allocation_max );
512  ‪construct_class( 4, item_list, allocation_max );
513 
514  killstreaks = item_list["killstreak1"];
515 
516  if ( isdefined( item_list["killstreak2"] ) )
517  {
518  killstreaks = ArrayCombine( killstreaks, item_list["killstreak2"], true, false );
519  }
520 
521  if ( isdefined( item_list["killstreak3"] ) )
522  {
523  killstreaks = ArrayCombine( killstreaks, item_list["killstreak3"], true, false );
524  }
525 
526  if ( isdefined( killstreaks ) && killstreaks.size )
527  {
528  ‪choose_weapon( 0, killstreaks );
529  ‪choose_weapon( 0, killstreaks );
530  ‪choose_weapon( 0, killstreaks );
531  }
532 
533  self.claimed_items = undefined;
534  pixendevent();
535 }
536 
537 function ‪construct_class( constructclass, items, allocation_max )
538 {
539  allocation = 0;
540 
541  claimed_count = ‪build_claimed_list( items );
542  self.claimed_items = [];
543 
544  // primary
545  weapon = ‪choose_weapon( constructclass, items["primary"] );
546  claimed_count["primary"]++;
547  allocation++;
548 
549  // secondary
550  weapon = ‪choose_weapon( constructclass, items["secondary"] );
551  ‪choose_weapon_option( constructclass, "camo", 1 );
552 }
553 
554 function ‪make_choice( chance, claimed, max_claim )
555 {
556  return ( claimed < max_claim && RandomInt( 100 ) < chance );
557 }
558 
559 function ‪chose_action( action1, chance1, action2, chance2, action3, chance3, action4, chance4 )
560 {
561  chance1 = Int( chance1 / 10 );
562  chance2 = Int( chance2 / 10 );
563  chance3 = Int( chance3 / 10 );
564  chance4 = Int( chance4 / 10 );
565 
566  actions = [];
567 
568  for( i = 0; i < chance1; i++ )
569  {
570  actions[ actions.size ] = action1;
571  }
572 
573  for( i = 0; i < chance2; i++ )
574  {
575  actions[ actions.size ] = action2;
576  }
577 
578  for( i = 0; i < chance3; i++ )
579  {
580  actions[ actions.size ] = action3;
581  }
582 
583  for( i = 0; i < chance4; i++ )
584  {
585  actions[ actions.size ] = action4;
586  }
587 
588  return array::random( actions );
589 }
590 
591 function ‪item_is_claimed( item )
592 {
593  foreach( claim in self.claimed_items )
594  {
595  if ( claim == item )
596  {
597  return true;
598  }
599  }
600 
601  return false;
602 }
603 
604 function ‪choose_weapon( weaponclass, items )
605 {
606  if ( !isdefined( items ) || !items.size )
607  {
608  return undefined;
609  }
610 
611  start = RandomInt( items.size );
612 
613  for( i = 0; i < items.size; i++ )
614  {
615  weapon = items[ start ];
616 
617  if ( !‪item_is_claimed( weapon ) )
618  {
619  break;
620  }
621 
622  start = ( start + 1 ) % items.size;
623  }
624 
625  self.claimed_items[ self.claimed_items.size ] = weapon;
626 
627  self BotClassAddItem( weaponclass, weapon );
628  return weapon;
629 }
630 
631 function ‪build_weapon_options_list( optionType )
632 {
633  level.botWeaponOptionsId[optionType] = [];
634  level.botWeaponOptionsProb[optionType] = [];
635 
636  csv_filename = "gamedata/weapons/common/attachmentTable.csv";
637  prob = 0;
638  for ( row = 0 ; row < 255 ; row++ )
639  {
640  if ( tableLookupColumnForRow( csv_filename, row, ‪ATTACHMENT_TABLE_COL_TYPE ) == optionType )
641  {
642  index = level.botWeaponOptionsId[optionType].size;
643  level.botWeaponOptionsId[optionType][index] = Int( tableLookupColumnForRow( csv_filename, row, ‪ATTACHMENT_TABLE_COL_NUMBERING ) );
644  prob += Int( tableLookupColumnForRow( csv_filename, row, ‪ATTACHMENT_TABLE_COL_BOT_PROB ) );
645  level.botWeaponOptionsProb[optionType][index] = prob;
646  }
647  }
648 }
649 
650 function ‪choose_weapon_option( weaponclass, optionType, primary )
651 {
652  if ( !isdefined( level.botWeaponOptionsId ) )
653  {
654  level.botWeaponOptionsId = [];
655  level.botWeaponOptionsProb = [];
656 
658  ‪build_weapon_options_list( "reticle" );
659  }
660 
661  // weapon options cannot be set in local matches
662  if ( !level.onlineGame && !level.systemLink )
663  return;
664 
665  // Increase the range of the probability to reduce the chances of picking the option when the bot's level is less than BOT_RANK_ALL_OPTIONS_AVAILABLE
666  // (in system link all options are available)
667  numOptions = level.botWeaponOptionsProb[optionType].size;
668  maxProb = level.botWeaponOptionsProb[optionType][numOptions-1];
669  if ( !level.systemLink && self.pers[ "rank" ] < ‪BOT_RANK_ALL_OPTIONS_AVAILABLE )
670  maxProb += ‪BOT_RANK_OPTIONS_MULTIPLIER * maxProb * ( ( ‪BOT_RANK_ALL_OPTIONS_AVAILABLE - self.pers[ "rank" ] ) / ‪BOT_RANK_ALL_OPTIONS_AVAILABLE );
671 
672  rnd = RandomInt( Int( maxProb ) );
673  for (i=0 ; i<numOptions ; i++)
674  {
675  if ( level.botWeaponOptionsProb[optionType][i] > rnd )
676  {
677  self BotClassSetWeaponOption( weaponclass, primary, optionType, level.botWeaponOptionsId[optionType][i] );
678  break;
679  }
680  }
681 }
682 
683 function ‪choose_primary_attachments( weaponclass, weapon, allocation, allocation_max )
684 {
685  attachments = weapon.supportedAttachments;
686  remaining = allocation_max - allocation;
687 
688  if ( !attachments.size || !remaining )
689  {
690  return 0;
691  }
692 
693  attachment_action = ‪chose_action( "3_attachments", 25, "2_attachments", 35, "1_attachments", 35, "none", 5 );
694 
695  if ( remaining >= 4 && attachment_action == "3_attachments" )
696  {
697  a1 = array::random( attachments );
698  self BotClassAddAttachment( weaponclass, weapon, a1, "primaryattachment1" );
699  count = 1;
700 
701  attachments = GetWeaponAttachments( weapon, a1 );
702 
703  if ( attachments.size )
704  {
705  a2 = array::random( attachments );
706  self BotClassAddAttachment( weaponclass, weapon, a2, "primaryattachment2" );
707  count++;
708 
709  attachments = GetWeaponAttachments( weapon, a1, a2 );
710 
711  if ( attachments.size )
712  {
713  a3 = array::random( attachments );
714  self BotClassAddItem( weaponclass, "BONUSCARD_PRIMARY_GUNFIGHTER" );
715  self BotClassAddAttachment( weaponclass, weapon, a3, "primaryattachment3" );
716  return 4;
717  }
718  }
719 
720  return count;
721  }
722  else if ( remaining >= 2 && attachment_action == "2_attachments" )
723  {
724  a1 = array::random( attachments );
725  self BotClassAddAttachment( weaponclass, weapon, a1, "primaryattachment1" );
726 
727  attachments = GetWeaponAttachments( weapon, a1 );
728 
729  if ( attachments.size )
730  {
731  a2 = array::random( attachments );
732  self BotClassAddAttachment( weaponclass, weapon, a2, "primaryattachment2" );
733  return 2;
734  }
735 
736  return 1;
737  }
738  else if ( remaining >= 1 && attachment_action == "1_attachments" )
739  {
740  ‪a = array::random( attachments );
741  self BotClassAddAttachment( weaponclass, weapon, ‪a, "primaryattachment1" );
742  return 1;
743  }
744 
745  return 0;
746 }
747 
748 function ‪choose_secondary_attachments( weaponclass, weapon, allocation, allocation_max )
749 {
750  attachments = weapon.supportedAttachments ;
751  remaining = allocation_max - allocation;
752 
753  if ( !attachments.size || !remaining )
754  {
755  return 0;
756  }
757 
758  attachment_action = ‪chose_action( "2_attachments", 10, "1_attachments", 40, "none", 50, "none", 0 );
759 
760  if ( remaining >= 3 && attachment_action == "2_attachments" )
761  {
762  a1 = array::random( attachments );
763  self BotClassAddAttachment( weaponclass, weapon, a1, "secondaryattachment1" );
764 
765  attachments = GetWeaponAttachments( weapon, a1 );
766 
767  if ( attachments.size )
768  {
769  a2 = array::random( attachments );
770  self BotClassAddItem( weaponclass, "BONUSCARD_SECONDARY_GUNFIGHTER" );
771  self BotClassAddAttachment( weaponclass, weapon, a2, "secondaryattachment2" );
772  return 3;
773  }
774 
775  return 1;
776  }
777  else if ( remaining >= 1 && attachment_action == "1_attachments" )
778  {
779  ‪a = array::random( attachments );
780  self BotClassAddAttachment( weaponclass, weapon, ‪a, "secondaryattachment1" );
781  return 1;
782  }
783 
784  return 0;
785 }
786 
788 {
789  items = [];
790 
791  for( i = 0; i < ‪STATS_TABLE_MAX_ITEMS; i++ )
792  {
793  row = tableLookupRowNum( level.statsTableID, ‪STATS_TABLE_COL_NUMBERING, i );
794 
795  if ( row > -1 )
796  {
797  slot = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_SLOT );
798 
799  if ( slot == "" )
800  {
801  continue;
802  }
803 
804  number = Int( tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_NUMBERING ) );
805 
806  if ( !SessionModeIsPrivate() && self IsItemLocked( number ) )
807  {
808  continue;
809  }
810 
811  allocation = Int( tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_ALLOCATION ) );
812 
813  if ( allocation < 0 )
814  {
815  continue;
816  }
817 
818  ‪name = tableLookupColumnForRow( level.statsTableID, row, ‪STATS_TABLE_COL_NAME );
819 /*
820  if ( item_is_banned( slot, name ) )
821  {
822  continue;
823  }
824 */
825  if ( !isdefined( items[slot] ) )
826  {
827  items[slot] = [];
828  }
829 
830  items[ slot ][ items[slot].size ] = ‪name;
831  }
832  }
833 
834  return items;
835 }
836 
837 function ‪item_is_banned( slot, item )
838 {
839  if ( item == "WEAPON_KNIFE_BALLISTIC" )
840  {
841  return true;
842  }
843 
844  if ( GetDvarInt("tu6_enableDLCWeapons") == 0 && item == "WEAPON_PEACEKEEPER" )
845  {
846  return true;
847  }
848 
849  if ( slot != "killstreak1" && slot != "killstreak2" && slot != "killstreak3" )
850  {
851  return false;
852  }
853 
854  foreach( banned in level.bot_banned_killstreaks )
855  {
856  if ( item == banned )
857  {
858  return true;
859  }
860  }
861 
862  return false;
863 }
864 
865 function ‪build_claimed_list( items )
866 {
867  claimed = [];
868  keys = GetArrayKeys( items );
869 
870  foreach( key in keys )
871  {
872  claimed[ key ] = 0;
873  }
874 
875  return claimed;
876 }
‪pick_hero_weapon
‪function pick_hero_weapon()
Definition: _bot_loadout.gsc:274
‪in_whitelist
‪function in_whitelist(itemName)
Definition: _bot_loadout.gsc:21
‪get_item_name
‪function get_item_name(itemReference)
Definition: _bot_loadout.gsc:389
‪BOT_ALLOCATION_MAX
‪#define BOT_ALLOCATION_MAX
Definition: _bot_loadout.gsc:11
‪choose_weapon
‪function choose_weapon(weaponclass, items)
Definition: _bot_loadout.gsc:604
‪get_available_items
‪function get_available_items(filterGroup, filterSlot)
Definition: _bot_loadout.gsc:321
‪build_classes
‪function build_classes()
Definition: _bot_loadout.gsc:125
‪BOT_RANK_ALL_OPTIONS_AVAILABLE
‪#define BOT_RANK_ALL_OPTIONS_AVAILABLE
Definition: _bot_loadout.gsc:13
‪BOT_ALLOCATION_UNLOCK_MAX
‪#define BOT_ALLOCATION_UNLOCK_MAX
Definition: _bot_loadout.gsc:12
‪construct_loadout
‪function construct_loadout(allocation_max)
Definition: _bot_loadout.gsc:493
‪build_weapon_options_list
‪function build_weapon_options_list(optionType)
Definition: _bot_loadout.gsc:631
‪choose_weapon_option
‪function choose_weapon_option(weaponclass, optionType, primary)
Definition: _bot_loadout.gsc:650
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪a
‪function add_remove_list a
Definition: util_shared.csc:906
‪STATS_TABLE_COL_NUMBERING
‪#define STATS_TABLE_COL_NUMBERING
Definition: _statstable.gsh:3
‪init
‪function init()
Definition: _bot_loadout.gsc:417
‪STATS_TABLE_COL_GROUP
‪#define STATS_TABLE_COL_GROUP
Definition: _statstable.gsh:4
‪ATTACHMENT_TABLE_COL_BOT_PROB
‪#define ATTACHMENT_TABLE_COL_BOT_PROB
Definition: _statstable.gsh:20
‪STATS_TABLE_COL_ALLOCATION
‪#define STATS_TABLE_COL_ALLOCATION
Definition: _statstable.gsh:14
‪pick_killstreaks
‪function pick_killstreaks()
Definition: _bot_loadout.gsc:307
‪chose_action
‪function chose_action(action1, chance1, action2, chance2, action3, chance3, action4, chance4)
Definition: _bot_loadout.gsc:559
‪choose_secondary_attachments
‪function choose_secondary_attachments(weaponclass, weapon, allocation, allocation_max)
Definition: _bot_loadout.gsc:748
‪BOT_RANK_OPTIONS_MULTIPLIER
‪#define BOT_RANK_OPTIONS_MULTIPLIER
Definition: _bot_loadout.gsc:14
‪STATS_TABLE_COL_SLOT
‪#define STATS_TABLE_COL_SLOT
Definition: _statstable.gsh:15
‪STATS_TABLE_MAX_ITEMS
‪#define STATS_TABLE_MAX_ITEMS
Definition: _statstable.gsh:1
‪make_choice
‪function make_choice(chance, claimed, max_claim)
Definition: _bot_loadout.gsc:554
‪STATS_TABLE_COL_NAME
‪#define STATS_TABLE_COL_NAME
Definition: _statstable.gsh:5
‪ATTACHMENT_TABLE_COL_TYPE
‪#define ATTACHMENT_TABLE_COL_TYPE
Definition: _statstable.gsh:19
‪set_rank
‪function set_rank()
Definition: _bot.gsc:600
‪construct_class
‪function construct_class(constructclass, items, allocation_max)
Definition: _bot_loadout.gsc:537
‪build_item_list
‪function build_item_list()
Definition: _bot_loadout.gsc:787
‪STATS_TABLE_COL_REFERENCE
‪#define STATS_TABLE_COL_REFERENCE
Definition: _statstable.gsh:6
‪ATTACHMENT_TABLE_COL_NUMBERING
‪#define ATTACHMENT_TABLE_COL_NUMBERING
Definition: _statstable.gsh:18
‪choose_primary_attachments
‪function choose_primary_attachments(weaponclass, weapon, allocation, allocation_max)
Definition: _bot_loadout.gsc:683
‪pick_hero_ability
‪function pick_hero_ability()
Definition: _bot_loadout.gsc:289
‪pick_classes
‪function pick_classes()
Definition: _bot_loadout.gsc:202
‪build_claimed_list
‪function build_claimed_list(items)
Definition: _bot_loadout.gsc:865
‪on_bot_connect
‪function on_bot_connect()
Definition: _bot_loadout.gsc:439
‪name
‪class GroundFx name
‪get_current_class
‪function get_current_class()
Definition: _bot_loadout.gsc:244
‪item_is_banned
‪function item_is_banned(slot, item)
Definition: _bot_loadout.gsc:837
‪pick_hero_gadget
‪function pick_hero_gadget()
Definition: _bot_loadout.gsc:266
‪pickedItems
‪function pick_item pickedItems
Definition: _bot_loadout.gsc:193
‪item_is_claimed
‪function item_is_claimed(item)
Definition: _bot_loadout.gsc:591
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265