‪Black Ops 3 Source Code Explorer  0.1
‪An script explorer for Black Ops 3 by ZeRoY
_bot.gsc
Go to the documentation of this file.
1 #using scripts\codescripts\struct;
2 #using scripts\shared\array_shared;
3 #using scripts\shared\callbacks_shared;
4 #using scripts\shared\laststand_shared;
5 #using scripts\shared\math_shared;
6 #using scripts\shared\system_shared;
7 #using scripts\shared\util_shared;
8 
9 #insert scripts\shared\shared.gsh;
10 #insert scripts\shared\bots\_bot.gsh;
11 
12 #using scripts\shared\bots\_bot_combat;
13 #using scripts\shared\bots\bot_buttons;
14 #using scripts\shared\bots\bot_traversals;
15 
16 #namespace bot;
17 
18 #define BOT_MAX_STUCK_CYCLES 3
19 #define BOT_STUCK_DISTANCE 128
20 #define BOT_POSITION_HISTORY_SIZE 5
21 
22 #define BOT_STUCK_RESOLUTION_S 1.5
23 
24 #define BOT_DIVE_RADIUS 128
25 #define BOT_SWIM_HEIGHT_MIN 25
26 #define BOT_SWIM_HEIGHT_MAX 45
27 
28 ‪REGISTER_SYSTEM( "bot", &‪__init__, undefined )
29 
30 function ‪__init__()
31 {
33 
37 
38  // Setup Methods
39  ‪DEFAULT( level.getBotSettings, &‪get_bot_default_settings );
40 
41  // Lifecycle events
42  ‪DEFAULT( level.onBotRemove, &‪bot_void );
43  ‪DEFAULT( level.onBotConnect, &‪bot_void );
44  ‪DEFAULT( level.onBotSpawned, &‪bot_void );
45  ‪DEFAULT( level.onBotKilled, &‪bot_void );
46 
47  // Outside events
48  ‪DEFAULT( level.onBotDamage, &‪bot_void );
49 
50  // Think Events
51  ‪DEFAULT( level.botUpdate, &‪bot_update );
52  ‪DEFAULT( level.botPreCombat, &‪bot_void );
53  ‪DEFAULT( level.botCombat, &‪bot_combat::combat_think );
54  ‪DEFAULT( level.botPostCombat, &‪bot_void );
55  ‪DEFAULT( level.botIdle, &‪bot_void );
56 
57  // Combat Events
58  ‪DEFAULT( level.botThreatDead, &‪bot_combat::clear_threat );
59  ‪DEFAULT( level.botThreatEngage, &‪bot_combat::engage_threat );
60  ‪DEFAULT( level.botUpdateThreatGoal, &‪bot_combat::update_threat_goal );
61  ‪DEFAULT( level.botThreatLost, &‪bot_combat::clear_threat );
62 
63  // Combat Queries
64  //level.botThreatIsAlive
65  ‪DEFAULT( level.botGetThreats, &‪bot_combat::get_bot_threats );
66  ‪DEFAULT( level.botIgnoreThreat, &‪bot_combat::ignore_non_sentient );
67 
68  SetDvar( "bot_maxMantleHeight", 200 );
69  //SetDvar( "bot_enableWallrun", true );
70 /#
71  level thread ‪bot_devgui_think();
72 #/
73 }
74 
75 function ‪init()
76 {
78 }
79 
81 {
82  return false;
83 }
84 
85 function ‪bot_void()
86 {
87 }
88 
89 function ‪bot_unhandled()
90 {
91  return false;
92 }
93 
94 // Add Bots
95 //========================================
96 
97 function ‪add_bots( count, team )
98 {
99  for ( i = 0; i < count; i++ )
100  {
101  ‪add_bot( team );
102  }
103 }
104 
105 function ‪add_bot( team )
106 {
107  botEnt = AddTestClient();
108 
109  if ( !isdefined( botEnt ) )
110  {
111  return undefined;
112  }
113 
114  botEnt BotSetRandomCharacterCustomization();
115 
116  if ( ‪IS_TRUE( level.disableClassSelection ) )
117  {
118  botEnt.pers["class"] = level.defaultClass;
119  botEnt.curClass = level.defaultClass;
120  }
121 
122  if ( level.teamBased && team !== "autoassign" )
123  {
124  botEnt.pers[ "team" ] = team;
125  }
126 
127  return botEnt;
128 }
129 
130 // Remove Bots
131 //========================================
132 
133 function ‪remove_bots( count, team )
134 {
135  players = GetPlayers();
136 
137  foreach( player in players )
138  {
139  if ( !player IsTestClient() )
140  {
141  continue;
142  }
143 
144  if ( isdefined( team ) && player.team != team )
145  {
146  continue;
147  }
148 
149  ‪remove_bot( player );
150 
151  if ( isdefined( count ) )
152  {
153  count--;
154  if ( count <= 0 )
155  {
156  break;
157  }
158  }
159  }
160 }
161 
162 function ‪remove_bot( bot )
163 {
164  if ( !bot IsTestClient() )
165  {
166  return;
167  }
168 
169  bot [[level.onBotRemove]]();
170 
171  bot BotDropClient();
172 }
173 
174 // Utils
175 //========================================
176 
177 function ‪filter_bots( players )
178 {
179  bots = [];
180 
181  foreach( player in players )
182  {
183  if ( player ‪util::is_bot() )
184  {
185  bots[bots.size] = player;
186  }
187  }
188 
189  return bots;
190 }
191 
192 
193 // Events
194 //========================================
195 
197 {
198  if ( !self IsTestClient() )
199  {
200  return;
201  }
202 
203  self endon ( "disconnect" );
204 
205  // Do the bot initialization on connect so it gets called after skiptos
206  self.bot = SpawnStruct();
207  self.bot.threat = SpawnStruct();
208  self.bot.damage = SpawnStruct();
209 
210  self.pers["isBot"] = true;
211 
212  if ( level.teambased )
213  {
214  self notify( "menuresponse", game["menu_team"], self.team );
215  wait 0.5;
216  }
217 
218  self notify( "joined_team" );
219  ‪callback::callback( #"on_joined_team" );
220 
221  self thread [[level.onBotConnect]]();
222 }
223 
225 {
226  if ( !self ‪util::is_bot() )
227  {
228  return;
229  }
230 
231  self ‪clear_stuck();
233  self.bot.prevWeapon = undefined;
234 
235  self BotLookForward();
236 
237  self thread [[level.onBotSpawned]]();
238 
239  self thread ‪bot_combat::wait_damage_loop();
240  self thread ‪wait_bot_path_failed_loop();
241  self thread ‪wait_bot_goal_reached_loop();
242  self thread ‪bot_think_loop();
243 }
244 
246 {
247  if ( !self ‪util::is_bot() )
248  {
249  return;
250  }
251 
252  self thread [[level.onBotKilled]]();
253 
254  self BotReleaseManualControl();
255 }
256 
257 
258 // Think
259 //========================================
260 
262 {
263  self endon( "death" );
264  level endon( "game_ended" );
265 
266  while(1)
267  {
268  self ‪bot_think();
269 
270  wait level.botSettings.thinkInterval;
271  }
272 }
273 
274 function ‪bot_think()
275 {
276  self BotReleaseButtons();
277 
278  if ( level.inprematchperiod ||
279  level.gameEnded ||
280  !IsAlive( self ) )
281  {
282  return;
283  }
284 
285  self ‪check_stuck();
286 
287  self ‪sprint_think();
288 
289  self ‪update_swim();
290 
291  self thread [[level.botUpdate]]();
292 
293  self thread [[level.botPreCombat]]();
294 
295  self thread [[level.botCombat]]();
296 
297  self thread [[level.botPostCombat]]();
298 
299  // No threat and no goal means the bot is idle
300  if ( !self ‪bot_combat::has_threat() && !self BotGoalSet() )
301  {
302  self thread [[level.botIdle]]();
303  }
304 }
305 
306 function ‪bot_update()
307 {
308 
309  // TODO: Cache things that get checked frequently
310 }
311 
312 function ‪update_swim()
313 {
314  if ( !self IsPlayerSwimming() )
315  {
316  self.bot.resurfaceTime = undefined;
317  return;
318  }
319 
320  if ( self IsPlayerUnderwater() )
321  {
322  if ( !isdefined( self.bot.resurfaceTime ) )
323  {
324  self.bot.resurfaceTime = GetTime() + level.botSettings.swimTime;
325  }
326  }
327  else
328  {
329  self.bot.resurfaceTime = undefined;
330  }
331 
332  if ( self BotUnderManualControl() )
333  {
334  return;
335  }
336 
337  goalPosition = self BotGetGoalPosition();
338 
339  // Swim down to a navmesh goal under the water
340  if ( Distance2DSquared( goalPosition, self.origin ) <= ( ‪BOT_DIVE_RADIUS * ‪BOT_DIVE_RADIUS ) &&
341  GetWaterHeight( goalPosition ) > 0 )
342  {
344  return;
345  }
346 
347  if ( isdefined( self.bot.resurfaceTime ) && self.bot.resurfaceTime <= GetTime() )
348  {
349  {
351  return;
352  }
353  }
354 
355  bottomTrace = GroundTrace( self.origin, self.origin + ( 0, 0, -1000 ), false, self, true );
356  swimHeight = self.origin[2] - bottomTrace[ "position" ][2];
357 
358  if ( swimHeight < ‪BOT_SWIM_HEIGHT_MIN )
359  {
360  self ‪bot::press_swim_up();
361 
362  vertDist = ‪BOT_SWIM_HEIGHT_MIN - swimHeight;
363  }
364  else if ( swimHeight > ‪BOT_SWIM_HEIGHT_MAX )
365  {
367 
368  vertDist = swimHeight - ‪BOT_SWIM_HEIGHT_MAX;
369  }
370 
371  if ( isdefined( vertDist ) )
372  {
373  intervalDist = level.botSettings.swimVerticalSpeed * level.botSettings.thinkInterval;
374 
375  if ( intervalDist > vertDist )
376  {
377  self ‪wait_release_swim_buttons( level.botSettings.thinkInterval * vertDist / intervalDist );
378  }
379  }
380 }
381 
382 function ‪wait_release_swim_buttons( waitTime )
383 {
384  self endon( "death" );
385  level endon( "game_ended" );
386 
387  wait waitTime;
388 
391 }
392 
393 // Settings
394 //========================================
395 
397 {
398  level.botSettings = [[level.getBotSettings]]();
399 
400  // Dvar Settings
401  SetDvar( "bot_AllowMelee", ‪VAL( level.botSettings.allowMelee, 0 ) );
402  SetDvar( "bot_AllowGrenades", ‪VAL( level.botSettings.allowGrenades, 0 ) );
403  SetDvar( "bot_AllowKillstreaks", ‪VAL( level.botSettings.allowKillstreaks, 0 ) );
404  SetDvar( "bot_AllowHeroGadgets", ‪VAL( level.botSettings.allowHeroGadgets, 0 ) );
405 
406  SetDvar( "bot_Fov", ‪VAL( level.botSettings.fov, 0 ) );
407  SetDvar( "bot_FovAds", ‪VAL( level.botSettings.fovAds, 0 ) );
408  SetDvar( "bot_PitchSensitivity", level.botSettings.pitchSensitivity );
409  SetDvar( "bot_YawSensitivity", level.botSettings.yawSensitivity );
410 
411  SetDvar( "bot_PitchSpeed", ‪VAL( level.botSettings.pitchSpeed, 0 ) );
412  SetDvar( "bot_PitchSpeedAds", ‪VAL( level.botSettings.pitchSpeedAds, 0 ) );
413  SetDvar( "bot_YawSpeed", ‪VAL( level.botSettings.yawSpeed, 0 ) );
414  SetDvar( "bot_YawSpeedAds", ‪VAL( level.botSettings.yawSpeedAds, 0 ) );
415 
416  SetDvar( "pitchAccelerationTime", ‪VAL( level.botSettings.pitchAccelerationTime, 0 ) );
417  SetDvar( "yawAccelerationTime", ‪VAL( level.botSettings.yawAccelerationTime, 0 ) );
418 
419  SetDvar( "pitchDecelerationThreshold", ‪VAL( level.botSettings.pitchDecelerationThreshold, 0 ) );
420  SetDvar( "yawDecelerationThreshold", ‪VAL( level.botSettings.yawDecelerationThreshold, 0 ) );
421 
422  // Cached Settings
423  meleeRange = GetDvarInt( "player_meleeRangeDefault" ) * ‪VAL( level.botSettings.meleeRangeMultiplier, 0 );
424  level.botSettings.meleeRange = Int( meleeRange );
425  level.botSettings.meleeRangeSq = meleeRange * meleeRange;
426 
427  level.botSettings.threatRadiusMinSq = level.botsettings.threatRadiusMin * level.botsettings.threatRadiusMin;
428  level.botSettings.threatRadiusMaxSq = level.botSettings.threatRadiusMax * level.botSettings.threatRadiusMax;
429 
430  lethalDistanceMin = ‪VAL( level.botSettings.lethalDistanceMin, 0 );
431  level.botSettings.lethalDistanceMinSq = lethalDistanceMin * lethalDistanceMin;
432 
433  lethalDistanceMax = ‪VAL( level.botSettings.lethalDistanceMax, 1024 );
434  level.botSettings.lethalDistanceMaxSq = lethalDistanceMax * lethalDistanceMax;
435 
436  tacticalDistanceMin = ‪VAL( level.botSettings.tacticalDistanceMin, 0 );
437  level.botSettings.tacticalDistanceMinSq = tacticalDistanceMin * tacticalDistanceMin;
438 
439  tacticalDistanceMax = ‪VAL( level.botSettings.tacticalDistanceMax, 1024 );
440  level.botSettings.tacticalDistanceMaxSq = tacticalDistanceMax * tacticalDistanceMax;
441 
442  level.botSettings.swimVerticalSpeed = GetDvarFloat( "player_swimVerticalSpeedMax" );
443  level.botSettings.swimTime = GetDvarFloat( "player_swimTime", 5 ) * 1000;
444 }
445 
447 {
448  return ‪struct::get_script_bundle( "botsettings", "bot_default" );
449 }
450 
451 // Movement
452 //========================================
453 
455 {
456  self.bot.sprintToGoal = true;
457 }
458 
460 {
461  self.bot.sprintToGoal = false;
462 }
463 
464 function ‪sprint_think()
465 {
466  if ( ‪IS_TRUE( self.bot.sprintToGoal ) )
467  {
468  if ( self BotGoalReached() )
469  {
470  self ‪end_sprint_to_goal();
471  return;
472  }
473 
474  self ‪press_sprint_button();
475  return;
476  }
477 }
478 
479 function ‪goal_in_trigger( trigger )
480 {
481  radius = self ‪get_trigger_radius( trigger );
482 
483  return distanceSquared( trigger.origin, self BotGetGoalPosition() ) <= radius * radius;
484 }
485 
486 function ‪point_in_goal( point )
487 {
488  deltaSq = Distance2DSquared( self BotGetGoalPosition(), point );
489  goalRadius = self BotGetGoalRadius();
490 
491  return deltaSq <= goalRadius * goalRadius;
492 }
493 
494 function ‪path_to_trigger( trigger, radius )
495 {
496  // These usually have something inside them, possibly cutting the navmesh
497  if ( trigger.className == "trigger_use" ||
498  trigger.className == "trigger_use_touch" )
499  {
500  ‪DEFAULT( radius, ‪get_trigger_radius( trigger ) );
501 
502  randomAngle = ( 0, RandomInt( 360 ), 0 );
503  randomVec = AnglesToForward( randomAngle );
504 
505  point = trigger.origin + randomVec * radius;
506 
507  self BotSetGoal( point );
508  }
509 
510  ‪DEFAULT( radius, 0 );
511 
512  self BotSetGoal( trigger.origin, Int( radius ) );
513 }
514 
515 function ‪path_to_point_in_trigger( trigger )
516 {
517  mins = trigger GetMins();
518  maxs = trigger GetMaxs();
519 
520  radius = Min( maxs[0], maxs[1] );
521  height = maxs[2] - mins[2];
522 
523  minOrigin = trigger.origin + ( 0, 0, mins[2] );
524 
525  queryHeight = height / 4;
526 
527  queryOrigin = minOrigin + ( 0, 0, queryHeight );
528 
529 /#
530  if ( GetDvarInt( "bot_drawtriggerquery", 0 ) )
531  {
532  drawS = 10;
533  Circle( queryOrigin, radius, (0,1,0), false, true, 20*drawS );
534  Circle( queryOrigin + (0,0,queryHeight), radius, (0,1,0), false, true, 20*drawS );
535  Circle( queryOrigin - (0,0,queryHeight), radius, (0,1,0), false, true, 20*drawS );
536  }
537 #/
538  queryResult = PositionQuery_Source_Navigation( queryOrigin, 0, radius, queryHeight, 17, self );
539 
540  best_point = undefined;
541 
542  foreach ( point in queryResult.data )
543  {
544  point.score = randomFloatRange( 0, 100 );
545 
546  if ( !isdefined( best_point ) || point.score > best_point.score )
547  {
548  best_point = point;
549  }
550  }
551 
552  if ( isdefined( best_point ) )
553  {
554  self BotSetGoal( best_point.origin, ‪BOT_DEFAULT_GOAL_RADIUS );
555  return;
556  }
557 
558  self ‪bot::path_to_trigger( trigger, radius );
559 }
560 
561 function ‪get_trigger_radius( trigger )
562 {
563  maxs = trigger GetMaxs();
564 
565  if ( trigger.classname == "trigger_radius" )
566  {
567  return maxs[0];
568  }
569 
570  return Min( maxs[0], maxs[1] );
571 }
572 
573 function ‪get_trigger_height( trigger )
574 {
575  maxs = trigger GetMaxs();
576 
577  if ( trigger.classname == "trigger_radius" )
578  {
579  return maxs[2];
580  }
581 
582  return maxs[2] * 2;
583 }
584 
585 // Path Failure
586 //========================================
587 
588 function ‪check_stuck()
589 {
590 /#
591  if ( !GetDvarInt( "bot_AllowMovement" ) )
592  {
593  return;
594  }
595 #/
596 
597  if ( self BotUnderManualControl() ||
598  self BotGoalReached() ||
599  self util::isstunned() ||
600  self IsMeleeing() ||
601  self MeleeButtonPressed() ||
602  // Target is within 128 units, probably meleeing
603  ( self ‪bot_combat::has_threat() && self.bot.threat.lastDistanceSq < 16384 ) )
604  {
605  return;
606  }
607 
608  velocity = self GetVelocity();
609 
610  if ( velocity[0] == 0 &&
611  velocity[1] == 0 &&
612  ( velocity[2] == 0 || self IsPlayerSwimming() ) )
613  {
614  ‪DEFAULT( self.bot.stuckCycles, 0 );
615 
616  self.bot.stuckCycles++;
617 
618  if ( self.bot.stuckCycles >= ‪BOT_MAX_STUCK_CYCLES )
619  {
620 /#
621  if ( GetDvarInt( "bot_debugStuck" , 0 ) )
622  {
623  Sphere( self.origin, 16, ( 1, 0, 0 ), 0.25, false, 16, 1200 );
624  iprintln( "Bot " + self.‪name + " not moving at: "+ self.origin );
625  }
626 #/
627  self thread ‪stuck_resolution();
628  }
629  }
630  else
631  {
632  self.bot.stuckCycles = 0;
633  }
634 
635  // Only do this check if we're moving and don't have a visible
636  // Bots could be adsing or meleeing or all kinds of things
637  if ( !self ‪bot_combat::threat_visible() )
638  {
640  }
641 }
642 
644 {
645  if ( GetTime() < self.bot.checkPositionTime )
646  return;
647 
648  self.bot.checkPositionTime = GetTime() + 500;
649 
650  self.bot.positionHistory[self.bot.positionHistoryIndex] = self.origin;
651  self.bot.positionHistoryIndex = ( self.bot.positionHistoryIndex + 1 ) % ‪BOT_POSITION_HISTORY_SIZE;
652 
653  if ( self.bot.positionHistory.size < ‪BOT_POSITION_HISTORY_SIZE )
654  return;
655 
656  maxDistSq = undefined;
657 
658  for( i = 0; i < self.bot.positionHistory.size; i++ )
659  {
660 /#
661  if ( GetDvarInt( "bot_debugStuck" , 0 ) )
662  {
663  Line( self.bot.positionHistory[i], self.bot.positionHistory[i] + ( 0, 0, 72 ), ( 0, 1, 0 ), 1, false, 10 );
664  }
665 #/
666  for ( j = i + 1; j < self.bot.positionHistory.size; j++ )
667  {
668  distSq = DistanceSquared( self.bot.positionHistory[i], self.bot.positionHistory[j] );
669 
670  // Early out if we find evidence of enough movement
672  {
673  return;
674  }
675  }
676  }
677 
678 /#
679  if ( GetDvarInt( "bot_debugStuck" , 0 ) )
680  {
681  Sphere( self.origin, ‪BOT_STUCK_DISTANCE, ( 1, 0, 0 ), 0.25, false, 16, 1200 );
682  iprintln( "Bot " + self.‪name + " hanging out at: "+ self.origin );
683  }
684 #/
685  self thread ‪stuck_resolution();
686 }
687 
689 {
690  self endon( "death" );
691  level endon( "game_ended" );
692 
693  self ‪clear_stuck();
694 
695  self BotTakeManualControl();
696 
697  escapeAngle = self GetAngles()[1] + 180 + RandomIntRange( -60, 60 );;
698  escapeDir = AnglesToForward( ( 0, escapeAngle, 0 ) );
699 
700  self BotSetMoveAngle( escapeDir );
701  self BotSetMoveMagnitude( 1 );
702 
704 
705  self BotReleaseManualControl();
706 }
707 
708 function ‪clear_stuck()
709 {
710  self.bot.stuckCycles = 0;
711  self.bot.positionHistory = [];
712  self.bot.positionHistoryIndex = 0;
713  self.bot.checkPositionTime = 0;
714 }
715 
716 function ‪camp()
717 {
718  self BotSetGoal( self.origin );
719 
721 }
722 
723 // 0 - Unknown
724 // 1 - Invalid Start ( Bot off navmesh )
725 // 2 - Invalid End ( Can't get desination point on navmesh )
726 // 3 - Unreachable ( Can't get path )
727 
729 {
730  self endon( "death" );
731  level endon( "game_ended" );
732 
733  while( 1 )
734  {
735  self waittill( "bot_path_failed", reason );
736 
737 /#
738  if ( GetDvarInt( "bot_debugStuck" , 0 ) )
739  {
740  goalPosition = self BotGetGoalPosition();
741  Box( self.origin, ( -15, -15, 0 ), ( 15, 15, 72 ), 0, ( 0, 1, 0 ), 0.25, false, 1200 );
742  Box( goalPosition, ( -15, -15, 0 ), ( 15, 15, 72 ), 0, ( 1, 0, 0 ), 0.25, false, 1200 );
743  Line( self.origin, goalPosition, ( 1, 1, 1 ), 1, false, 1200 );
744  iprintln( "Bot " + self.‪name + " path failed from: " + self.origin + " to: " + goalPosition );
745  }
746 #/
747 
748  self thread ‪stuck_resolution();
749  }
750 }
751 
753 {
754  self endon( "death" );
755  level endon( "game_ended" );
756 
757  while( 1 )
758  {
759  self waittill( "bot_goal_reached", reason );
760 
761  self ‪clear_stuck();
762  }
763 }
764 
765 // Hero Stuff
766 //========================================
767 
769 {
770  currentWeapon = self GetCurrentWeapon();
771 
772  if ( self GetWeaponAmmoClip( currentWeapon ) ||
773  !currentWeapon.isheroweapon)
774  {
775  return;
776  }
777 
778  if ( isdefined( self.lastDroppableWeapon ) && self hasWeapon(self.lastDroppableWeapon) )
779  {
780  self SwitchToWeapon( self.lastDroppableWeapon );
781  }
782 }
783 
785 {
786  weapons = self GetWeaponsList();
787 
788  foreach( weapon in weapons )
789  {
790  slot = self GadgetGetSlot( weapon );
791 
792  if ( slot < 0 ||
793  !self GadgetIsReady( slot ) ||
794  self GadgetIsActive( slot ) )
795  {
796  continue;
797  }
798 
799  return weapon;
800  }
801 
802  return level.weaponNone;
803 }
804 
806 {
807  weapons = self GetWeaponsList();
808 
809  foreach( weapon in weapons )
810  {
811  if ( !‪is_gun_gadget( weapon ) )
812  {
813  continue;
814  }
815 
816  slot = self GadgetGetSlot( weapon );
817 
818  if ( slot < 0 ||
819  !self GadgetIsReady( slot ) ||
820  self GadgetIsActive( slot ) )
821  {
822  continue;
823  }
824 
825  return weapon;
826  }
827 
828  return level.weaponNone;
829 }
830 
831 function ‪is_gun_gadget( weapon )
832 {
833  if ( !isdefined( weapon ) ||
834  weapon == level.weaponNone ||
835  !weapon.isHeroWeapon )
836  {
837  return false;
838  }
839 
840  // TODO: May need to add more of these
841  return weapon.isBulletWeapon ||
842  weapon.isProjectileWeapon ||
843  weapon.isLauncher ||
844  weapon.isGasWeapon;
845 }
846 
847 function ‪activate_hero_gadget( weapon )
848 {
849  if ( !isdefined( weapon ) ||
850  weapon == level.weaponNone ||
851  !weapon.isgadget )
852  {
853  return;
854  }
855 
856  if ( ‪is_gun_gadget( weapon ) )
857  {
858  self SwitchToWeapon( weapon );
859  }
860  else if ( weapon.isHeroWeapon )
861  {
863  }
864  else
865  {
866  self BotPressButtonForGadget( weapon );
867  }
868 }
869 
870 
871 // Coop Methods
872 //========================================
873 
875 {
877 
878  if ( self ‪bot_combat::has_threat() )
879  {
880  return;
881  }
882 
883  if ( self IsReloading() ||
884  self IsSwitchingWeapons() ||
885  self IsThrowingGrenade() ||
886  self FragButtonPressed() ||
887  self SecondaryOffhandButtonPressed() ||
888  self IsMeleeing() ||
889  self IsRemoteControlling() ||
890  self IsInVehicle() ||
891  self IsWeaponViewOnlyLinked() )
892  {
893  return;
894  }
895 
896  if ( self ‪bot_combat::switch_weapon() )
897  {
898  return;
899  }
900 
901  if ( self ‪bot_combat::reload_weapon() )
902  {
903  return;
904  }
905 }
906 
908 {
909  if ( self ‪revive_players() )
910  {
911  if ( self ‪bot_combat::has_threat() )
912  {
914  self BotSetGoal( self.origin );
915  }
916 
917  return;
918  }
919 
921 }
922 
923 // Following
924 //========================================
925 
926 #define COOP_FOLLOW_RADIUS_MIN 150
927 #define COOP_FOLLOW_RADIUS_MAX 300
928 
930 {
931  // Favor the host
932  host = ‪bot::get_host_player();
933 
934  if ( !IsAlive( host ) )
935  {
936  players = ArraySort( level.players, self.origin );
937 
938  foreach( player in players )
939  {
940  if ( !player ‪util::is_bot() &&
941  player.team == self.team &&
942  IsAlive( player ) )
943  {
944  break;
945  }
946  }
947  }
948  else
949  {
950  player = host;
951  }
952 
953  if ( isdefined( player ) )
954  {
955  //self thread follow_entity( player, COOP_FOLLOW_RADIUS_MIN, COOP_FOLLOW_RADIUS_MAX );
956 
957  fwd = AnglesToForward( player.angles );
958  botDir = self.origin - player.origin;
959 
960  if ( VectorDot( botDir, fwd ) < 0 )
961  self thread ‪lead_player( player, ‪COOP_FOLLOW_RADIUS_MIN );
962  }
963 }
964 
965 function ‪lead_player( player, followMin )
966 {
967  radiusMin = followMin - 32;
968  radiusMax = followMin;
969 
970  dotMin = 0.85;
971  dotMax = 0.92;
972 
973  queryResult = PositionQuery_Source_Navigation( player.origin, radiusMin, radiusMax, 150, 32, self );
974 
975  fwd = AnglesToForward( player.angles );
976 
977  point = player.origin + fwd * 72;
978 
979  self BotSetGoal( point, 42 );
980  self ‪sprint_to_goal();
981 }
982 
983 function ‪follow_entity( entity, radiusMin, radiusMax )
984 {
986  ‪DEFAULT( radiusMax, radiusMin + 1 );
987 
988  if ( !‪point_in_goal( entity.origin ) )
989  {
990  radius = RandomIntRange( radiusMin, radiusMax );
991  self BotSetGoal( entity.origin, radius );
992  self ‪sprint_to_goal();
993  }
994 }
995 
996 
997 // Navmesh Wander
998 //========================================
999 
1000 function ‪navmesh_wander( fwd, radiusMin, radiusMax, spacing, fwdDot )
1001 {
1002  ‪DEFAULT( radiusMin, ‪VAL( level.botSettings.wanderMin, 0 ) );
1003  ‪DEFAULT( radiusMax, ‪VAL( level.botSettings.wanderMax, 0 ) );
1004  ‪DEFAULT( spacing, ‪VAL( level.botSettings.wanderSpacing, 0 ) );
1005  ‪DEFAULT( fwdDot, ‪VAL( level.botSettings.wanderFwdDot, 0 ) );
1006 
1007  ‪DEFAULT( fwd, AnglesToForward( self.angles ) );
1008 
1009  // Don't factor in pitch or elevation
1010  fwd = VectorNormalize( ( fwd[0], fwd[1], 0 ) );
1011  queryResult = PositionQuery_Source_Navigation( self.origin, radiusMin, radiusMax, 150, spacing, self );
1012 
1013  best_point = undefined;
1014 
1015  origin = ( self.origin[0], self.origin[1], 0 );
1016 
1017  foreach ( point in queryResult.data )
1018  {
1019  movePoint = ( point.origin[0], point.origin[1], 0 );
1020  moveDir = VectorNormalize( movePoint - origin );
1021  dot = VectorDot( moveDir, fwd );
1022 
1023  point.score = MapFloat( radiusMin, radiusMax, 0, 50, point.distToOrigin2D );
1024 
1025  if ( dot > fwdDot )
1026  {
1027  point.score += randomFloatRange( 30, 50 );
1028  }
1029  else if ( dot > 0 )
1030  {
1031  point.score += randomFloatRange( 10, 35 );
1032  }
1033  else
1034  {
1035  point.score += randomFloatRange( 0, 15 );
1036  }
1037  if ( !isdefined( best_point ) || point.score > best_point.score )
1038  {
1039  best_point = point;
1040  }
1041  }
1042 
1043  if( isdefined( best_point ) )
1044  {
1045  self BotSetGoal( best_point.origin, radiusMin );
1046  }
1047  else
1048  {
1049 /#
1050  if ( GetDvarInt( "bot_debugStuck" , 0 ) )
1051  {
1052  Circle( self.origin, radiusMin, ( 1, 0, 0 ), false, true, 1200 );
1053  Circle( self.origin, radiusMax, ( 1, 0, 0 ), false, true, 1200 );
1054  Sphere( self.origin, 16, ( 0, 1, 0 ), 0.25, false, 16, 1200 );
1055  iprintln( "Bot " + self.‪name + " can't find wander point at: "+ self.origin );
1056  }
1057 #/
1058  self thread ‪stuck_resolution();
1059  }
1060 }
1061 
1062 // Goal Approach Pathing
1063 //========================================
1064 
1065 #define APPROACH_GOAL_RADIUS_MAX 1500
1066 #define APPROACH_GOAL_SPACING 128
1067 
1068 function ‪approach_goal_trigger( trigger, radiusMax, spacing )
1069 {
1072 
1073  distSq = DistanceSquared( self.origin, trigger.origin );
1074 
1075  if ( distSq < radiusMax * radiusMax )
1076  {
1077  self ‪path_to_point_in_trigger( trigger );
1078  return;
1079  }
1080 
1081  radiusMin = self ‪get_trigger_radius( trigger );
1082 
1083  self ‪approach_point( trigger.origin, radiusMin, radiusMax, spacing );
1084 }
1085 
1086 function ‪approach_point( point, radiusMin, radiusMax, spacing )
1087 {
1088  ‪DEFAULT( radiusMin, 0 );
1091 
1092  distSq = DistanceSquared( self.origin, point );
1093 
1094  if ( distSq < radiusMax * radiusMax )
1095  {
1096  self BotSetGoal( point, ‪BOT_DEFAULT_GOAL_RADIUS );
1097  return;
1098  }
1099 
1100  queryResult = PositionQuery_Source_Navigation( point, radiusMin, radiusMax, 150, spacing, self );
1101 
1102  fwd = AnglesToForward( self.angles );
1103 
1104  // Don't factor in pitch or elevation
1105  fwd = ( fwd[0], fwd[1], 0 );
1106  origin = ( self.origin[0], self.origin[1], 0 );
1107 
1108  best_point = undefined;
1109 
1110  foreach ( point in queryResult.data )
1111  {
1112  movePoint = ( point.origin[0], point.origin[1], 0 );
1113  moveDir = VectorNormalize( movePoint - origin );
1114  dot = VectorDot( moveDir, fwd );
1115 
1116  point.score = randomFloatRange( 0, 50 );
1117 
1118  if ( dot < .5 ) // Favor points in the 240 degree arc towards the bot
1119  {
1120  point.score += randomFloatRange( 30, 50 );
1121  }
1122  else
1123  {
1124  point.score += randomFloatRange( 0, 15 );
1125  }
1126 
1127  if ( !isdefined( best_point ) || point.score > best_point.score )
1128  {
1129  best_point = point;
1130  }
1131  }
1132 
1133  if ( isdefined( best_point ) )
1134  {
1135  self BotSetGoal( best_point.origin, ‪BOT_DEFAULT_GOAL_RADIUS );
1136  }
1137 }
1138 
1139 
1140 // Revive
1141 //========================================
1142 
1144 {
1145  players = self ‪get_team_players_in_laststand();
1146 
1147  if ( players.size > 0 )
1148  {
1149  ‪revive_player( players[0] );
1150  return true;
1151  }
1152 
1153  return false;
1154 }
1155 
1157 {
1158  players = [];
1159 
1160  foreach( player in level.players )
1161  {
1162  if ( player != self && player ‪laststand::player_is_in_laststand() && player.team == self.team )
1163  {
1164  players[players.size] = player;
1165  }
1166  }
1167 
1168  players = ArraySort( players, self.origin );
1169 
1170  return players;
1171 }
1172 
1173 function ‪revive_player( player )
1174 {
1175  if ( !‪point_in_goal( player.origin ) )
1176  {
1177  self BotSetGoal( player.origin, 64 );
1178  self ‪sprint_to_goal();
1179  return;
1180  }
1181 
1182  if ( self BotGoalReached() )
1183  {
1184  self BotSetLookAnglesFromPoint( player GetCentroid() );
1185  self ‪tap_use_button();
1186  }
1187 }
1188 
1189 
1190 // Cornering
1191 //========================================
1192 
1193 #define DEFAULT_START_CORNER_DIST 64
1194 #define DEFAULT_CORNER_DIST 128
1195 
1196 function ‪watch_bot_corner( startCornerDist, cornerDist )
1197 {
1198  self endon( "death" );
1199  self endon( "bot_combat_target" );
1200  level endon( "game_ended" );
1201 
1202  ‪DEFAULT( startCornerDist, ‪DEFAULT_START_CORNER_DIST );
1203  ‪DEFAULT( cornerDist, ‪DEFAULT_CORNER_DIST );
1204 
1205  startCornerDistSq = cornerDist * cornerDist;
1206  cornerDistSq = cornerDist * cornerDist;
1207 
1208  while ( 1 )
1209  {
1210  self waittill( "bot_corner", centerPoint, enterPoint, leavePoint, angle, nextEnterPoint );
1211 
1212  if ( self ‪bot_combat::has_threat() )
1213  {
1214  continue;
1215  }
1216 
1217  if( Distance2DSquared( self.origin, enterPoint ) < startCornerDistSq ||
1218  Distance2DSquared( leavePoint, nextEnterPoint ) < cornerDistSq )
1219  {
1220  continue;
1221  }
1222 
1223  self thread ‪wait_corner_radius( startCornerDistSq, centerPoint, enterPoint, leavePoint, angle, nextEnterPoint );
1224  }
1225 }
1226 
1227 function ‪wait_corner_radius( startCornerDistSq, centerPoint, enterPoint, leavePoint, angle, nextEnterPoint )
1228 {
1229  self endon( "death" );
1230  self endon( "bot_corner" );
1231  self endon( "bot_goal_reached" );
1232  self endon( "bot_combat_target" );
1233  level endon( "game_ended" );
1234 
1235  while( Distance2DSquared( self.origin, enterPoint ) > startCornerDistSq )
1236  {
1237  if ( self ‪bot_combat::has_threat() )
1238  {
1239  return;
1240  }
1241 
1243  }
1244 
1245  // + standing viewheight
1246  self BotLookAtPoint( ( nextEnterPoint[0], nextEnterPoint[1], nextEnterPoint[1] + 60 ) );
1247 
1248  self thread ‪finish_corner();
1249 }
1250 
1252 {
1253  self endon( "death" );
1254  self endon( "combat_target" );
1255  level endon( "game_ended" );
1256 
1257  self ‪util::waittill_any( "bot_corner", "bot_goal_reached" );
1258 
1259  self BotLookForward();
1260 }
1261 
1262 
1263 // Utilities
1264 //========================================
1265 
1267 {
1268  players = GetPlayers();
1269 
1270  foreach( player in players )
1271  {
1272  if ( player IsHost() )
1273  {
1274  return player;
1275  }
1276  }
1277 
1278  return undefined;
1279 }
1280 
1281 function ‪fwd_dot( point )
1282 {
1283  angles = self GetPlayerAngles();
1284  fwd = AnglesToForward( angles );
1285 
1286  delta = point - self GetEye();
1287  delta = VectorNormalize( delta );
1288 
1289  dot = VectorDot( fwd, delta );
1290  return dot;
1291 }
1292 
1293 // TODO: fwd_dot2d ?
1294 
1296 {
1297  weapons = self GetWeaponsList();
1298 
1299  foreach( weapon in weapons )
1300  {
1301  if ( weapon.isRocketLauncher )
1302  {
1303  return true;
1304  }
1305  }
1306 
1307  return false;
1308 }
1309 
1310 function ‪kill_bot()
1311 {
1312  self DoDamage( self.health, self.origin );
1313 }
1314 
1315 /#
1316 
1317 // Debugging
1318 //========================================
1319 
1320 function ‪kill_bots()
1321 {
1322  foreach( player in level.players )
1323  {
1324  if ( player ‪util::is_bot() )
1325  {
1326  player ‪kill_bot();
1327  }
1328  }
1329 }
1330 
1331 function ‪add_bot_at_eye_trace( team )
1332 {
1333  host = ‪util::getHostPlayer();
1334 
1335  ‪trace = host ‪eye_trace();
1336 
1337  direction_vec = host.origin - ‪trace["position"];
1338  direction = VectorToAngles( direction_vec );
1339 
1340  yaw = direction[1];
1341  bot = ‪add_bot( team );
1342 
1343  if ( isdefined( bot ) )
1344  {
1345  bot waittill( "spawned_player" );
1346 
1347  bot SetOrigin( ‪trace[ "position" ] );
1348  bot SetPlayerAngles( ( bot.angles[0], yaw, bot.angles[2] ) );
1349  }
1350 
1351  return bot;
1352 }
1353 
1354 function ‪eye_trace()
1355 {
1356  direction = self GetPlayerAngles();
1357  direction_vec = AnglesToForward( direction );
1358  eye = self GetEye();
1359 
1360  scale = 8000;
1361  direction_vec = ( direction_vec[0] * scale, direction_vec[1] * scale, direction_vec[2] * scale );
1362 
1363  return bullettrace( eye, eye + direction_vec, 0, undefined );
1364 }
1365 
1366 // Route Debugging
1367 //========================================
1368 
1370 {
1371  iprintln( "Debug Patrol:" );
1372  points = self ‪get_nav_points();
1373 
1374  if ( !isdefined( points ) || points.size == 0 )
1375  {
1376  iprintln( "Route Debug Cancelled" );
1377  return;
1378  }
1379 
1380  iprintln( "Sending bots to chosen points" );
1381 
1382  players = GetPlayers();
1383  foreach( player in players )
1384  {
1385  if ( !player ‪util::is_bot() )
1386  {
1387  continue;
1388  }
1389 
1390  player thread ‪debug_patrol( points );
1391  }
1392 }
1393 
1395 {
1396  iprintln( "Square (X) - Add Point" );
1397  iprintln( "Cross (A) - Done" );
1398  iprintln( "Circle (B) - Cancel" );
1399 
1400  points = [];
1401  while ( 1 )
1402  {
1404 
1405  point = self ‪eye_trace()["position"];
1406  if ( isdefined( point ) )
1407  {
1408  point = GetClosestPointOnNavMesh( point, 128 );
1409 
1410  if ( isdefined( point ) )
1411  {
1412  Sphere( point, 16, ( 0, 0, 1 ), 0.25, false, 16, 1 );
1413  }
1414  }
1415 
1416  if ( self ButtonPressed( "BUTTON_X" ) )
1417  {
1418  if ( isdefined( point ) && ( points.size == 0 || Distance2D( point, points[points.size-1] ) > 16 ) )
1419  {
1420  points[points.size] = point;
1421  }
1422  }
1423  else if ( self ButtonPressed( "BUTTON_A" ) )
1424  {
1425  return points;
1426  }
1427  else if ( self ButtonPressed( "BUTTON_B" ) )
1428  {
1429  return undefined;
1430  }
1431 
1432  for ( i = 0; i < points.size; i++ )
1433  {
1434  Sphere( points[i], 16, ( 0, 1, 0 ), 0.25, false, 16, 1 );
1435  }
1436  }
1437 }
1438 
1439 function ‪debug_patrol( points )
1440 {
1441  self notify( "debug_patrol" );
1442  self endon( "death" );
1443  self endon( "debug_patrol" );
1444 
1445  i = 0;
1446 
1447  //self end_sprint_to_goal();
1448 
1449  while( 1 )
1450  {
1451  self BotSetGoal( points[i], ‪BOT_DEFAULT_GOAL_RADIUS );
1452  self ‪bot::sprint_to_goal();
1453  self waittill( "bot_goal_reached" );
1454 
1455  i = ( i + 1 ) % points.size;
1456  }
1457 }
1458 
1459 
1460 // Devgui
1461 //========================================
1462 
1464 {
1465  while( 1 )
1466  {
1467  wait( 0.25 );
1468 
1469  cmd = GetDvarString( "devgui_bot", "" );
1470 
1471  if ( !isdefined( level.botDevguiCmd ) || ![[level.botDevguiCmd]](cmd) )
1472  {
1473  host = ‪util::getHostPlayer();
1474 
1475  switch( cmd )
1476  {
1477  case "remove_all":
1478  ‪remove_bots();
1479  break;
1480  case "laststand":
1481  ‪kill_bots();
1482  break;
1483  case "routes":
1484  host ‪devgui_debug_route();
1485  break;
1486  default:
1487  break;
1488  }
1489  }
1490 
1491  SetDvar( "devgui_bot", "" );
1492  }
1493 }
1494 
1495 function ‪coop_bot_devgui_cmd( cmd )
1496 {
1497  host = ‪get_host_player();
1498 
1499  switch( cmd )
1500  {
1501  case "add":
1502  ‪add_bot( host.team );
1503  return true;
1504  case "add_3":
1505  ‪add_bots( 3, host.team );
1506  return true;
1507  case "add_crosshair":
1509  return true;
1510  case "remove":
1511  ‪remove_bots( 1 );
1512  return true;
1513  break;
1514  }
1515 
1516  return false;
1517 }
1518 
1519 // Debug Drawing
1520 //========================================
1521 
1522 function ‪debug_star( origin, seconds, color )
1523 {
1524  if ( !isdefined( seconds ) )
1525  {
1526  seconds = 1;
1527  }
1528 
1529  if ( !isdefined( color ) )
1530  {
1531  color = ( 1, 0, 0 );
1532  }
1533 
1534  frames = Int( 20 * seconds );
1535  DebugStar( origin, frames, color );
1536 }
1537 
1538 #/
‪release_swim_down
‪function release_swim_down()
Definition: bot_buttons.gsc:193
‪bot_void
‪function bot_void()
Definition: _bot.gsc:85
‪follow_coop_players
‪function follow_coop_players()
Definition: _bot.gsc:929
‪reload_weapon
‪function reload_weapon()
Definition: _bot_combat.gsc:827
‪callback
‪function callback(event, localclientnum, params)
Definition: callbacks_shared.csc:13
‪filter_bots
‪function filter_bots(players)
Definition: _bot.gsc:177
‪ignore_non_sentient
‪function ignore_non_sentient(entity)
Definition: _bot_combat.gsc:85
‪get_ready_gadget
‪function get_ready_gadget()
Definition: _bot.gsc:784
‪path_to_trigger
‪function path_to_trigger(trigger, radius)
Definition: _bot.gsc:494
‪finish_corner
‪function finish_corner()
Definition: _bot.gsc:1251
‪check_stuck
‪function check_stuck()
Definition: _bot.gsc:588
‪BOT_SWIM_HEIGHT_MAX
‪#define BOT_SWIM_HEIGHT_MAX
Definition: _bot.gsc:26
‪is_bot
‪function is_bot()
Definition: util_shared.gsc:2488
‪lead_player
‪function lead_player(player, followMin)
Definition: _bot.gsc:965
‪coop_post_combat
‪function coop_post_combat()
Definition: _bot.gsc:907
‪end_sprint_to_goal
‪function end_sprint_to_goal()
Definition: _bot.gsc:459
‪get_nav_points
‪function get_nav_points()
Definition: _bot.gsc:1394
‪update_swim
‪function update_swim()
Definition: _bot.gsc:312
‪bot_devgui_think
‪function bot_devgui_think()
Definition: _bot.gsc:1463
‪has_threat
‪function has_threat()
Definition: _bot_combat.gsc:93
‪BOT_STUCK_DISTANCE
‪#define BOT_STUCK_DISTANCE
Definition: _bot.gsc:19
‪tap_use_button
‪function tap_use_button()
Definition: bot_buttons.gsc:58
‪wait_release_swim_buttons
‪function wait_release_swim_buttons(waitTime)
Definition: _bot.gsc:382
‪COOP_FOLLOW_RADIUS_MIN
‪#define COOP_FOLLOW_RADIUS_MIN
Definition: _bot.gsc:926
‪on_start_gametype
‪function on_start_gametype(func, obj)
Definition: callbacks_shared.csc:285
‪add_bot_at_eye_trace
‪function add_bot_at_eye_trace(team)
Definition: _bot.gsc:1331
‪DEFAULT_START_CORNER_DIST
‪#define DEFAULT_START_CORNER_DIST
Definition: _bot.gsc:1193
‪revive_players
‪function revive_players()
Definition: _bot.gsc:1143
‪stuck_resolution
‪function stuck_resolution()
Definition: _bot.gsc:688
‪remove_bots
‪function remove_bots(count, team)
Definition: _bot.gsc:133
‪VAL
‪#define VAL(__var, __default)
Definition: shared.gsh:272
‪get_bot_threats
‪function get_bot_threats(maxDistance)
Definition: _bot_combat.gsc:68
‪activate_hero_gadget
‪function activate_hero_gadget(weapon)
Definition: _bot.gsc:847
‪point_in_goal
‪function point_in_goal(point)
Definition: _bot.gsc:486
‪trace
‪function trace(from, to, target)
Definition: grapple.gsc:369
‪on_player_connect
‪function on_player_connect()
Definition: _bot.gsc:196
‪debug_star
‪function debug_star(origin, seconds, color)
Definition: _bot.gsc:1522
‪clear_stuck
‪function clear_stuck()
Definition: _bot.gsc:708
‪IS_TRUE
‪#define IS_TRUE(__a)
Definition: shared.gsh:251
‪approach_goal_trigger
‪function approach_goal_trigger(trigger, radiusMax, spacing)
Definition: _bot.gsc:1068
‪stow_gun_gadget
‪function stow_gun_gadget()
Definition: _bot.gsc:768
‪init
‪function init()
Definition: _bot.gsc:67
‪revive_player
‪function revive_player(player)
Definition: _bot.gsc:1173
‪bot_think
‪function bot_think()
Definition: _bot.gsc:274
‪follow_entity
‪function follow_entity(entity, radiusMin, radiusMax)
Definition: _bot.gsc:983
‪wait_corner_radius
‪function wait_corner_radius(startCornerDistSq, centerPoint, enterPoint, leavePoint, angle, nextEnterPoint)
Definition: _bot.gsc:1227
‪sprint_think
‪function sprint_think()
Definition: _bot.gsc:464
‪BOT_DEFAULT_GOAL_RADIUS
‪#define BOT_DEFAULT_GOAL_RADIUS
Definition: _bot.gsh:12
‪wait_bot_goal_reached_loop
‪function wait_bot_goal_reached_loop()
Definition: _bot.gsc:752
‪wait_bot_path_failed_loop
‪function wait_bot_path_failed_loop()
Definition: _bot.gsc:728
‪wait_damage_loop
‪function wait_damage_loop()
Definition: _bot_combat.gsc:976
‪BOT_MAX_STUCK_CYCLES
‪#define BOT_MAX_STUCK_CYCLES
Definition: _bot.gsc:18
‪bot_post_combat
‪function bot_post_combat()
Definition: _bot_clean.gsc:36
‪DEFAULT_CORNER_DIST
‪#define DEFAULT_CORNER_DIST
Definition: _bot.gsc:1194
‪DEFAULT
‪#define DEFAULT(__var, __default)
Definition: shared.gsh:270
‪debug_patrol
‪function debug_patrol(points)
Definition: _bot.gsc:1439
‪on_spawned
‪function on_spawned(func, obj)
Definition: callbacks_shared.csc:245
‪add_bot
‪function add_bot(team)
Definition: _bot.gsc:105
‪bot_think_loop
‪function bot_think_loop()
Definition: _bot.gsc:261
‪fwd_dot
‪function fwd_dot(point)
Definition: _bot.gsc:1281
‪switch_weapon
‪function switch_weapon()
Definition: _bot_combat.gsc:697
‪path_to_point_in_trigger
‪function path_to_point_in_trigger(trigger)
Definition: _bot.gsc:515
‪get_host_player
‪function get_host_player()
Definition: _bot.gsc:1266
‪approach_point
‪function approach_point(point, radiusMin, radiusMax, spacing)
Definition: _bot.gsc:1086
‪waittill_any
‪function waittill_any(str_notify1, str_notify2, str_notify3, str_notify4, str_notify5)
Definition: util_shared.csc:375
‪has_launcher
‪function has_launcher()
Definition: _bot.gsc:1295
‪is_bot_ranked_match
‪function is_bot_ranked_match()
Definition: _bot.gsc:80
‪combat_think
‪function combat_think()
Definition: _bot_combat.gsc:20
‪bot_pre_combat
‪function bot_pre_combat()
Definition: _bot_ball.gsc:49
‪threat_visible
‪function threat_visible()
Definition: _bot_combat.gsc:98
‪get_ready_gun_gadget
‪function get_ready_gun_gadget()
Definition: _bot.gsc:805
‪init_bot_settings
‪function init_bot_settings()
Definition: _bot.gsc:396
‪add_bots
‪function add_bots(count, team)
Definition: _bot.gsc:97
‪navmesh_wander
‪function navmesh_wander(fwd, radiusMin, radiusMax, spacing, fwdDot)
Definition: _bot.gsc:1000
‪kill_bots
‪function kill_bots()
Definition: _bot.gsc:1320
‪REGISTER_SYSTEM
‪#define REGISTER_SYSTEM(__sys, __func_init_preload, __reqs)
Definition: shared.gsh:204
‪check_stuck_position
‪function check_stuck_position()
Definition: _bot.gsc:643
‪on_player_killed
‪function on_player_killed()
Definition: _bot.gsc:245
‪clear_threat
‪function clear_threat()
Definition: _bot_combat.gsc:126
‪coop_pre_combat
‪function coop_pre_combat()
Definition: _bot.gsc:874
‪getHostPlayer
‪function getHostPlayer()
Definition: util_shared.gsc:2904
‪release_swim_up
‪function release_swim_up()
Definition: bot_buttons.gsc:183
‪get_team_players_in_laststand
‪function get_team_players_in_laststand()
Definition: _bot.gsc:1156
‪BOT_STUCK_RESOLUTION_S
‪#define BOT_STUCK_RESOLUTION_S
Definition: _bot.gsc:22
‪is_gun_gadget
‪function is_gun_gadget(weapon)
Definition: _bot.gsc:831
‪player_is_in_laststand
‪function player_is_in_laststand()
Definition: laststand_shared.gsc:18
‪on_player_spawned
‪function on_player_spawned()
Definition: _bot.gsc:224
‪coop_bot_devgui_cmd
‪function coop_bot_devgui_cmd(cmd)
Definition: _bot.gsc:1495
‪press_swim_down
‪function press_swim_down()
Definition: bot_buttons.gsc:188
‪watch_bot_corner
‪function watch_bot_corner(startCornerDist, cornerDist)
Definition: _bot.gsc:1196
‪get_script_bundle
‪function get_script_bundle(str_type, str_name)
Definition: struct.csc:45
‪kill_bot
‪function kill_bot()
Definition: _bot.gsc:1310
‪tap_offhand_special_button
‪function tap_offhand_special_button()
Definition: bot_buttons.gsc:173
‪get_trigger_height
‪function get_trigger_height(trigger)
Definition: _bot.gsc:573
‪update_threat_goal
‪function update_threat_goal()
Definition: _bot_clean.gsc:158
‪APPROACH_GOAL_RADIUS_MAX
‪#define APPROACH_GOAL_RADIUS_MAX
Definition: _bot.gsc:1065
‪get_trigger_radius
‪function get_trigger_radius(trigger)
Definition: _bot.gsc:561
‪on_connect
‪function on_connect()
Definition: _arena.gsc:20
‪BOT_DIVE_RADIUS
‪#define BOT_DIVE_RADIUS
Definition: _bot.gsc:24
‪remove_bot
‪function remove_bot(bot)
Definition: _bot.gsc:162
‪eye_trace
‪function eye_trace()
Definition: _bot.gsc:1354
‪goal_in_trigger
‪function goal_in_trigger(trigger)
Definition: _bot.gsc:479
‪press_crouch_button
‪function press_crouch_button()
Definition: bot_buttons.gsc:63
‪name
‪class GroundFx name
‪press_swim_up
‪function press_swim_up()
Definition: bot_buttons.gsc:178
‪__init__
‪function __init__()
Definition: _bot.gsc:44
‪devgui_debug_route
‪function devgui_debug_route()
Definition: _bot.gsc:1369
‪get_bot_default_settings
‪function get_bot_default_settings()
Definition: _bot.gsc:446
‪bot_unhandled
‪function bot_unhandled()
Definition: _bot.gsc:89
‪press_sprint_button
‪function press_sprint_button()
Definition: bot_buttons.gsc:78
‪camp
‪function camp()
Definition: _bot.gsc:716
‪engage_threat
‪function engage_threat()
Definition: _bot_combat.gsc:234
‪sprint_to_goal
‪function sprint_to_goal()
Definition: _bot.gsc:454
‪BOT_SWIM_HEIGHT_MIN
‪#define BOT_SWIM_HEIGHT_MIN
Definition: _bot.gsc:25
‪bot_update
‪function bot_update()
Definition: _bot.gsc:306
‪BOT_POSITION_HISTORY_SIZE
‪#define BOT_POSITION_HISTORY_SIZE
Definition: _bot.gsc:20
‪WAIT_SERVER_FRAME
‪#define WAIT_SERVER_FRAME
Definition: shared.gsh:265
‪APPROACH_GOAL_SPACING
‪#define APPROACH_GOAL_SPACING
Definition: _bot.gsc:1066