Xonotic
scripting.qc
Go to the documentation of this file.
1 #include "scripting.qh"
2 
5 #include <common/state.qh>
6 #include <common/stats.qh>
7 #include <common/weapons/_all.qh>
8 #include <common/wepent.qh>
13 
14 .int state;
15 
20 
22 {
23  if(!bot.bot_cmdqueuebuf_allocated)
24  return;
25  buf_del(bot.bot_cmdqueuebuf);
26  bot.bot_cmdqueuebuf_allocated = false;
27  LOG_TRACE("bot ", bot.netname, " queue cleared");
28 }
29 
30 void bot_queuecommand(entity bot, string cmdstring)
31 {
32  if(!bot.bot_cmdqueuebuf_allocated)
33  {
34  bot.bot_cmdqueuebuf = buf_create();
35  bot.bot_cmdqueuebuf_allocated = true;
36  bot.bot_cmdqueuebuf_start = 0;
37  bot.bot_cmdqueuebuf_end = 0;
38  }
39 
40  bufstr_set(bot.bot_cmdqueuebuf, bot.bot_cmdqueuebuf_end, cmdstring);
41 
42  // if the command was a "sound" command, precache the sound NOW
43  // this prevents lagging!
44  {
45  float sp;
46  string parm;
47  string cmdstr;
48 
49  sp = strstrofs(cmdstring, " ", 0);
50  if(sp >= 0)
51  {
52  parm = substring(cmdstring, sp + 1, -1);
53  cmdstr = substring(cmdstring, 0, sp);
54  if(cmdstr == "sound")
55  {
56  // find the LAST word
57  for (;;)
58  {
59  sp = strstrofs(parm, " ", 0);
60  if(sp < 0)
61  break;
62  parm = substring(parm, sp + 1, -1);
63  }
64  precache_sound(parm);
65  }
66  }
67  }
68 
69  bot.bot_cmdqueuebuf_end += 1;
70 }
71 
72 void bot_dequeuecommand(entity bot, float idx)
73 {
74  if(!bot.bot_cmdqueuebuf_allocated)
75  error("dequeuecommand but no queue allocated");
76  if(idx < bot.bot_cmdqueuebuf_start)
77  error("dequeueing a command in the past");
78  if(idx >= bot.bot_cmdqueuebuf_end)
79  error("dequeueing a command in the future");
80  bufstr_set(bot.bot_cmdqueuebuf, idx, "");
81  if(idx == bot.bot_cmdqueuebuf_start)
82  bot.bot_cmdqueuebuf_start += 1;
83  if(bot.bot_cmdqueuebuf_start >= bot.bot_cmdqueuebuf_end)
84  bot_clearqueue(bot);
85 }
86 
87 string bot_readcommand(entity bot, float idx)
88 {
89  if(!bot.bot_cmdqueuebuf_allocated)
90  error("readcommand but no queue allocated");
91  if(idx < bot.bot_cmdqueuebuf_start)
92  error("reading a command in the past");
93  if(idx >= bot.bot_cmdqueuebuf_end)
94  error("reading a command in the future");
95  return bufstr_get(bot.bot_cmdqueuebuf, idx);
96 }
97 
98 bool bot_havecommand(entity this, int idx)
99 {
100  if(!this.bot_cmdqueuebuf_allocated)
101  return false;
102  if(idx < this.bot_cmdqueuebuf_start)
103  return false;
104  if(idx >= this.bot_cmdqueuebuf_end)
105  return false;
106  return true;
107 }
108 
109 const int MAX_BOT_PLACES = 4;
113 entity bot_getplace(entity this, string placename)
114 {
115  entity e;
116  if(substring(placename, 0, 1) == "@")
117  {
118  int i, p;
119  placename = substring(placename, 1, -1);
120  string s, s2;
121  for(i = 0; i < this.bot_places_count; ++i)
122  if(this.(bot_placenames[i]) == placename)
123  return this.(bot_places[i]);
124  // now: i == this.bot_places_count
125  s = s2 = cvar_string(placename);
126  p = strstrofs(s2, " ", 0);
127  if(p >= 0)
128  {
129  s = substring(s2, 0, p);
130  //print("places: ", placename, " -> ", cvar_string(placename), "\n");
131  cvar_set(placename, strcat(substring(s2, p+1, -1), " ", s));
132  //print("places: ", placename, " := ", cvar_string(placename), "\n");
133  }
134  e = find(NULL, targetname, s);
135  if(!e)
136  LOG_INFO("invalid place ", s);
137  if(i < MAX_BOT_PLACES)
138  {
139  this.(bot_placenames[i]) = strzone(placename);
140  this.(bot_places[i]) = e;
141  this.bot_places_count += 1;
142  }
143  return e;
144  }
145  else
146  {
147  e = find(NULL, targetname, placename);
148  if(!e)
149  LOG_INFO("invalid place ", placename);
150  return e;
151  }
152 }
153 
154 
155 // Initialize global commands list
156 // NOTE: New commands should be initialized here
158 {
161 
162  bot_cmd_string[BOT_CMD_PAUSE] = "pause";
164 
165  bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
167 
168  bot_cmd_string[BOT_CMD_WAIT] = "wait";
170 
171  bot_cmd_string[BOT_CMD_TURN] = "turn";
173 
174  bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
176 
177  bot_cmd_string[BOT_CMD_MOVETOTARGET] = "movetotarget";
179 
180  bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
182 
183  bot_cmd_string[BOT_CMD_CC] = "cc";
185 
186  bot_cmd_string[BOT_CMD_IF] = "if";
188 
189  bot_cmd_string[BOT_CMD_ELSE] = "else";
191 
192  bot_cmd_string[BOT_CMD_FI] = "fi";
194 
195  bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
197 
198  bot_cmd_string[BOT_CMD_AIM] = "aim";
200 
201  bot_cmd_string[BOT_CMD_AIMTARGET] = "aimtarget";
203 
204  bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
206 
207  bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
209 
210  bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
212 
213  bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
215 
216  bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
218 
219  bot_cmd_string[BOT_CMD_BARRIER] = "barrier";
221 
222  bot_cmd_string[BOT_CMD_CONSOLE] = "console";
224 
225  bot_cmd_string[BOT_CMD_SOUND] = "sound";
227 
228  bot_cmd_string[BOT_CMD_DEBUG_ASSERT_CANFIRE] = "debug_assert_canfire";
230 
231  bot_cmds_initialized = true;
232 }
233 
234 // Returns first bot with matching name
236 {
237  FOREACH_CLIENT(IS_BOT_CLIENT(it) && it.netname == name,
238  {
239  return it;
240  });
241 
242  return NULL;
243 }
244 
245 // Returns a bot by number on list
247 {
248  entity bot;
249  float c = 0;
250 
251  if(!number)
252  return NULL;
253 
254  bot = findchainflags(flags, FL_CLIENT); // TODO: doesn't findchainflags loop backwards through entities?
255  while (bot)
256  {
257  if(IS_BOT_CLIENT(bot))
258  {
259  if(++c==number)
260  return bot;
261  }
262  bot = bot.chain;
263  }
264 
265  return NULL;
266 }
267 
268 float bot_decodecommand(string cmdstring)
269 {
270  float cmd_parm_type;
271  float sp;
272  string parm;
273 
274  sp = strstrofs(cmdstring, " ", 0);
275  if(sp < 0)
276  {
277  parm = "";
278  }
279  else
280  {
281  parm = substring(cmdstring, sp + 1, -1);
282  cmdstring = substring(cmdstring, 0, sp);
283  }
284 
287 
288  int i;
289  for(i=1;i<BOT_CMD_COUNTER;++i)
290  {
291  if(bot_cmd_string[i]!=cmdstring)
292  continue;
293 
294  cmd_parm_type = bot_cmd_parm_type[i];
295 
296  if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
297  {
298  LOG_INFO("ERROR: A parameter is required for this command");
299  return 0;
300  }
301 
302  // Load command into queue
303  bot_cmd.bot_cmd_type = i;
304 
305  // Attach parameter
306  switch(cmd_parm_type)
307  {
309  bot_cmd.bot_cmd_parm_float = stof(parm);
310  break;
312  strcpy(bot_cmd.bot_cmd_parm_string, parm);
313  break;
315  if(substring(parm, 0, 1) != "\'")
316  {
317  LOG_INFOF("ERROR: expected vector type \'x y z\', got %s", parm);
318  return 0;
319  }
320  bot_cmd.bot_cmd_parm_vector = stov(parm);
321  break;
322  default:
323  break;
324  }
325  return 1;
326  }
327  LOG_INFO("ERROR: No such command '", cmdstring, "'");
328  return 0;
329 }
330 
331 void bot_cmdhelp(string scmd)
332 {
333  int i, ntype;
334  string stype;
335 
338 
339  for(i=1;i<BOT_CMD_COUNTER;++i)
340  {
341  if(bot_cmd_string[i]!=scmd)
342  continue;
343 
344  ntype = bot_cmd_parm_type[i];
345 
346  switch(ntype)
347  {
349  stype = "float";
350  break;
352  stype = "string";
353  break;
355  stype = "vector";
356  break;
357  default:
358  stype = "none";
359  break;
360  }
361 
362  string desc = "";
363  switch(i)
364  {
365  case BOT_CMD_PAUSE:
366  desc = "Stops the bot completely. Any command other than 'continue' will be ignored.";
367  break;
368  case BOT_CMD_CONTINUE:
369  desc = "Disable paused status";
370  break;
371  case BOT_CMD_WAIT:
372  desc = "Pause command parsing and bot ai for N seconds. Pressed key will remain pressed";
373  break;
374  case BOT_CMD_WAIT_UNTIL:
375  desc = "Pause command parsing and bot ai until time is N from the last barrier. Pressed key will remain pressed";
376  break;
377  case BOT_CMD_BARRIER:
378  desc = "Waits till all bots that have a command queue reach this command. Pressed key will remain pressed";
379  break;
380  case BOT_CMD_TURN:
381  desc = "Look to the right or left N degrees. For turning to the left use positive numbers.";
382  break;
383  case BOT_CMD_MOVETO:
384  desc = "Walk to an specific coordinate on the map. Usage: moveto \'x y z\'";
385  break;
387  desc = "Walk to the specific target on the map";
388  break;
389  case BOT_CMD_RESETGOAL:
390  desc = "Resets the goal stack";
391  break;
392  case BOT_CMD_CC:
393  desc = "Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;";
394  break;
395  case BOT_CMD_IF:
396  desc = "Perform simple conditional execution.\n"
397  "Syntax: \n"
398  " sv_cmd .. if \"condition\"\n"
399  " sv_cmd .. <instruction if true>\n"
400  " sv_cmd .. <instruction if true>\n"
401  " sv_cmd .. else\n"
402  " sv_cmd .. <instruction if false>\n"
403  " sv_cmd .. <instruction if false>\n"
404  " sv_cmd .. fi\n"
405  "Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n"
406  " Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n"
407  "Fields: health, speed, flagcarrier\n"
408  "Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;";
409  break;
410  case BOT_CMD_RESETAIM:
411  desc = "Points the aim to the coordinates x,y 0,0";
412  break;
413  case BOT_CMD_AIM:
414  desc = "Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n"
415  "There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n"
416  "Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n"
417  " aim \"0 90 2\" // Will gradually look to the sky in the next two seconds";
418  break;
419  case BOT_CMD_AIMTARGET:
420  desc = "Points the aim to given target";
421  break;
422  case BOT_CMD_PRESSKEY:
423  desc = "Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use"
424  "Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called"
425  "Note: The script will not return the control to the bot ai until all keys are released";
426  break;
427  case BOT_CMD_RELEASEKEY:
428  desc = "Release previoulsy used keys. Use the parameter \"all\" to release all keys";
429  break;
430  case BOT_CMD_SOUND:
431  desc = "play sound file at bot location";
432  break;
434  desc = "verify the state of the weapon entity";
435  break;
436  default:
437  desc = "This command has no description yet.";
438  break;
439  }
440  LOG_HELP("Command: ", bot_cmd_string[i], "\nParameter: <", stype, ">", "\nDescription: ", desc);
441  }
442 }
443 
445 {
446  int i;
447  string ptype;
448 
451 
452  LOG_HELP("Bot commands:");
453 
454  for(i=1;i<BOT_CMD_COUNTER;++i)
455  {
456  switch(bot_cmd_parm_type[i])
457  {
459  ptype = "float";
460  break;
462  ptype = "string";
463  break;
465  ptype = "vector";
466  break;
467  default:
468  ptype = "none";
469  break;
470  }
471  if (ptype != "none")
472  LOG_HELP(" ^2", bot_cmd_string[i]," ^7<", ptype, ">");
473  else
474  LOG_HELP(" ^2", bot_cmd_string[i]);
475  }
476  LOG_HELP("For help about a specific command, type bot_cmd help <command>");
477 }
478 
479 // Commands code
481 
482 float bot_cmd_cc(entity this)
483 {
484  SV_ParseClientCommand(this, bot_cmd.bot_cmd_parm_string);
485  return CMD_STATUS_FINISHED;
486 }
487 
489 {
490  CS(this).impulse = bot_cmd.bot_cmd_parm_float;
491  return CMD_STATUS_FINISHED;
492 }
493 
495 {
498  return CMD_STATUS_FINISHED;
499 }
500 
502 float bot_cmd_wait(entity this)
503 {
505  {
506  if(time>=this.bot_cmd_wait_time)
507  {
508  this.bot_exec_status &= ~BOT_EXEC_STATUS_WAITING;
509  return CMD_STATUS_FINISHED;
510  }
511  else
512  return CMD_STATUS_EXECUTING;
513  }
514 
515  this.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
517  return CMD_STATUS_EXECUTING;
518 }
519 
521 {
522  if(time < bot_cmd.bot_cmd_parm_float + bot_barriertime)
523  {
525  return CMD_STATUS_EXECUTING;
526  }
528  return CMD_STATUS_FINISHED;
529 }
530 
532 {
533  // 0 = no barrier, 1 = waiting, 2 = waiting finished
534 
535  if(this.bot_barrier == 0) // initialization
536  {
537  this.bot_barrier = 1;
538 
539  //this.colormod = '4 4 0';
540  }
541 
542  if(this.bot_barrier == 1) // find other bots
543  {
544  FOREACH_CLIENT(it.isbot, {
545  if(it.bot_cmdqueuebuf_allocated)
546  if(it.bot_barrier != 1)
547  return CMD_STATUS_EXECUTING; // not all are at the barrier yet
548  });
549 
550  // all bots hit the barrier!
551 
552  // acknowledge barrier
553  FOREACH_CLIENT(it.isbot, { it.bot_barrier = 2; });
554 
556  }
557 
558  // if we get here, the barrier is finished
559  // so end it...
560  this.bot_barrier = 0;
561  //this.colormod = '0 0 0';
562 
563  return CMD_STATUS_FINISHED;
564 }
565 
566 float bot_cmd_turn(entity this)
567 {
568  this.v_angle_y = this.v_angle.y + bot_cmd.bot_cmd_parm_float;
569  this.v_angle_y = this.v_angle.y - floor(this.v_angle.y / 360) * 360;
570  return CMD_STATUS_FINISHED;
571 }
572 
574 {
575  float id = bot_cmd.bot_cmd_parm_float;
576 
577  if(id < WEP_FIRST || id > WEP_LAST)
578  return CMD_STATUS_ERROR;
579 
580  bool success = false;
581 
582  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
583  {
584  .entity weaponentity = weaponentities[slot];
585  if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
586  continue;
587 
588  if(client_hasweapon(this, REGISTRY_GET(Weapons, id), weaponentity, true, false))
589  {
590  success = true;
591  this.(weaponentity).m_switchweapon = REGISTRY_GET(Weapons, id);
592  }
593  }
594 
595  if(!success)
596  return CMD_STATUS_ERROR;
597 
598  return CMD_STATUS_FINISHED;
599 }
600 
602 
603 const int CMD_CONDITION_NONE = 0;
604 const int CMD_CONDITION_true = 1;
605 const int CMD_CONDITION_false = 2;
608 
609 float bot_cmd_eval(entity this, string expr)
610 {
611  // Search for numbers
612  if(IS_DIGIT(substring(expr, 0, 1)))
613  return stof(expr);
614 
615  // Search for cvars
616  if(substring(expr, 0, 5)=="cvar.")
617  return cvar(substring(expr, 5, strlen(expr)));
618 
619  // Search for fields
620  // TODO: expand with support for more fields (key carrier, ball carrier, armor etc)
621  switch(expr)
622  {
623  case "health":
624  return GetResource(this, RES_HEALTH);
625  case "speed":
626  return vlen(this.velocity);
627  case "flagcarrier":
628  return ((this.flagcarried!=NULL));
629  }
630 
631  LOG_INFO("ERROR: Unable to convert the expression '", expr, "' into a numeric value");
632  return 0;
633 }
634 
635 float bot_cmd_if(entity this)
636 {
637  string expr, val_a, val_b;
638  float cmpofs;
639 
641  {
642  // Only one "if" block is allowed at time
643  LOG_INFO("ERROR: Only one conditional block can be processed at time");
644  bot_clearqueue(this);
645  return CMD_STATUS_ERROR;
646  }
647 
649 
650  // search for operators
651  expr = bot_cmd.bot_cmd_parm_string;
652 
653  cmpofs = strstrofs(expr,"=",0);
654 
655  if(cmpofs>0)
656  {
657  val_a = substring(expr,0,cmpofs);
658  val_b = substring(expr,cmpofs+1,strlen(expr));
659 
660  if(bot_cmd_eval(this, val_a)==bot_cmd_eval(this, val_b))
662  else
664 
665  return CMD_STATUS_FINISHED;
666  }
667 
668  cmpofs = strstrofs(expr,">",0);
669 
670  if(cmpofs>0)
671  {
672  val_a = substring(expr,0,cmpofs);
673  val_b = substring(expr,cmpofs+1,strlen(expr));
674 
675  if(bot_cmd_eval(this, val_a)>bot_cmd_eval(this, val_b))
677  else
679 
680  return CMD_STATUS_FINISHED;
681  }
682 
683  cmpofs = strstrofs(expr,"<",0);
684 
685  if(cmpofs>0)
686  {
687  val_a = substring(expr,0,cmpofs);
688  val_b = substring(expr,cmpofs+1,strlen(expr));
689 
690  if(bot_cmd_eval(this, val_a)<bot_cmd_eval(this, val_b))
692  else
694 
695  return CMD_STATUS_FINISHED;
696  }
697 
698  if(bot_cmd_eval(this, expr))
700  else
702 
703  return CMD_STATUS_FINISHED;
704 }
705 
706 float bot_cmd_else(entity this)
707 {
710  return CMD_STATUS_FINISHED;
711 }
712 
713 float bot_cmd_fi(entity this)
714 {
716  return CMD_STATUS_FINISHED;
717 }
718 
720 {
721  this.v_angle = '0 0 0';
722  return CMD_STATUS_FINISHED;
723 }
724 
729 
730 float bot_cmd_aim(entity this)
731 {
732  // Current direction
733  if(this.bot_cmd_aim_endtime)
734  {
735  float progress;
736 
737  progress = min(1 - (this.bot_cmd_aim_endtime - time) / (this.bot_cmd_aim_endtime - this.bot_cmd_aim_begintime),1);
738  this.v_angle = this.bot_cmd_aim_begin + ((this.bot_cmd_aim_end - this.bot_cmd_aim_begin) * progress);
739 
740  if(time>=this.bot_cmd_aim_endtime)
741  {
742  this.bot_cmd_aim_endtime = 0;
743  return CMD_STATUS_FINISHED;
744  }
745  else
746  return CMD_STATUS_EXECUTING;
747  }
748 
749  // New aiming direction
750  string parms;
751  float tokens, step;
752 
753  parms = bot_cmd.bot_cmd_parm_string;
754 
755  tokens = tokenizebyseparator(parms, " ");
756 
757  if(tokens<2||tokens>3)
758  return CMD_STATUS_ERROR;
759 
760  step = (tokens == 3) ? stof(argv(2)) : 0;
761 
762  if(step == 0)
763  {
764  this.v_angle_x -= stof(argv(1));
765  this.v_angle_y += stof(argv(0));
766  return CMD_STATUS_FINISHED;
767  }
768 
769  this.bot_cmd_aim_begin = this.v_angle;
770 
771  this.bot_cmd_aim_end_x = this.v_angle.x - stof(argv(1));
772  this.bot_cmd_aim_end_y = this.v_angle.y + stof(argv(0));
773  this.bot_cmd_aim_end_z = 0;
774 
776  this.bot_cmd_aim_endtime = time + step;
777 
778  return CMD_STATUS_EXECUTING;
779 }
780 
782 {
783  if(this.bot_cmd_aim_endtime)
784  {
785  return bot_cmd_aim(this);
786  }
787 
788  entity e;
789  string parms;
790  vector v;
791  float tokens, step;
792 
793  parms = bot_cmd.bot_cmd_parm_string;
794 
795  tokens = tokenizebyseparator(parms, " ");
796 
797  e = bot_getplace(this, argv(0));
798  if(!e)
799  return CMD_STATUS_ERROR;
800 
801  v = e.origin + (e.mins + e.maxs) * 0.5;
802 
803  if(tokens==1)
804  {
805  this.v_angle = vectoangles(v - (this.origin + this.view_ofs));
806  this.v_angle_x = -this.v_angle.x;
807  return CMD_STATUS_FINISHED;
808  }
809 
810  if(tokens<1||tokens>2)
811  return CMD_STATUS_ERROR;
812 
813  step = stof(argv(1));
814 
815  this.bot_cmd_aim_begin = this.v_angle;
816  this.bot_cmd_aim_end = vectoangles(v - (this.origin + this.view_ofs));
817  this.bot_cmd_aim_end_x = -this.bot_cmd_aim_end.x;
818 
820  this.bot_cmd_aim_endtime = time + step;
821 
822  return CMD_STATUS_EXECUTING;
823 }
824 
826 
827 const int BOT_CMD_KEY_NONE = 0;
828 const int BOT_CMD_KEY_FORWARD = BIT(0);
829 const int BOT_CMD_KEY_BACKWARD = BIT(1);
830 const int BOT_CMD_KEY_RIGHT = BIT(2);
831 const int BOT_CMD_KEY_LEFT = BIT(3);
832 const int BOT_CMD_KEY_JUMP = BIT(4);
833 const int BOT_CMD_KEY_ATTACK1 = BIT(5);
834 const int BOT_CMD_KEY_ATTACK2 = BIT(6);
835 const int BOT_CMD_KEY_USE = BIT(7);
836 const int BOT_CMD_KEY_HOOK = BIT(8);
837 const int BOT_CMD_KEY_CROUCH = BIT(9);
838 const int BOT_CMD_KEY_CHAT = BIT(10);
839 
841 {
842  CS(this).movement = '0 0 0';
843  PHYS_INPUT_BUTTON_JUMP(this) = false;
844  PHYS_INPUT_BUTTON_CROUCH(this) = false;
845  PHYS_INPUT_BUTTON_ATCK(this) = false;
846  PHYS_INPUT_BUTTON_ATCK2(this) = false;
847  PHYS_INPUT_BUTTON_USE(this) = false;
848  PHYS_INPUT_BUTTON_HOOK(this) = false;
849  PHYS_INPUT_BUTTON_CHAT(this) = false;
850 
851  if(this.bot_cmd_keys == BOT_CMD_KEY_NONE)
852  return false;
853 
855  CS(this).movement_x = autocvar_sv_maxspeed;
856  else if(this.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
857  CS(this).movement_x = -autocvar_sv_maxspeed;
858 
860  CS(this).movement_y = autocvar_sv_maxspeed;
861  else if(this.bot_cmd_keys & BOT_CMD_KEY_LEFT)
862  CS(this).movement_y = -autocvar_sv_maxspeed;
863 
864  if(this.bot_cmd_keys & BOT_CMD_KEY_JUMP)
865  PHYS_INPUT_BUTTON_JUMP(this) = true;
866 
868  PHYS_INPUT_BUTTON_CROUCH(this) = true;
869 
871  PHYS_INPUT_BUTTON_ATCK(this) = true;
872 
874  PHYS_INPUT_BUTTON_ATCK2(this) = true;
875 
876  if(this.bot_cmd_keys & BOT_CMD_KEY_USE)
877  PHYS_INPUT_BUTTON_USE(this) = true;
878 
879  if(this.bot_cmd_keys & BOT_CMD_KEY_HOOK)
880  PHYS_INPUT_BUTTON_HOOK(this) = true;
881 
882  if(this.bot_cmd_keys & BOT_CMD_KEY_CHAT)
883  PHYS_INPUT_BUTTON_CHAT(this) = true;
884 
885  return true;
886 }
887 
888 
889 float bot_cmd_keypress_handler(entity this, string key, float enabled)
890 {
891  switch(key)
892  {
893  case "all":
894  if(enabled)
895  this.bot_cmd_keys = (2 ** 20) - 1; // >:)
896  else
898  case "forward":
899  if(enabled)
900  {
903  }
904  else
906  break;
907  case "backward":
908  if(enabled)
909  {
912  }
913  else
915  break;
916  case "left":
917  if(enabled)
918  {
921  }
922  else
924  break;
925  case "right":
926  if(enabled)
927  {
930  }
931  else
933  break;
934  case "jump":
935  if(enabled)
937  else
939  break;
940  case "crouch":
941  if(enabled)
943  else
945  break;
946  case "attack1":
947  if(enabled)
949  else
951  break;
952  case "attack2":
953  if(enabled)
955  else
957  break;
958  case "use":
959  if(enabled)
961  else
962  this.bot_cmd_keys &= ~BOT_CMD_KEY_USE;
963  break;
964  case "hook":
965  if(enabled)
967  else
969  break;
970  case "chat":
971  if(enabled)
973  else
975  break;
976  default:
977  break;
978  }
979 
980  return CMD_STATUS_FINISHED;
981 }
982 
984 {
985  string key;
986 
987  key = bot_cmd.bot_cmd_parm_string;
988 
989  bot_cmd_keypress_handler(this, key,true);
990 
991  return CMD_STATUS_FINISHED;
992 }
993 
995 {
996  string key;
997 
998  key = bot_cmd.bot_cmd_parm_string;
999 
1000  return bot_cmd_keypress_handler(this, key,false);
1001 }
1002 
1004 {
1005  return(this.bot_exec_status & BOT_EXEC_STATUS_PAUSED);
1006 }
1007 
1009 {
1010  PHYS_INPUT_BUTTON_DRAG(this) = false;
1011  PHYS_INPUT_BUTTON_USE(this) = false;
1012  PHYS_INPUT_BUTTON_ATCK(this) = false;
1013  PHYS_INPUT_BUTTON_JUMP(this) = false;
1014  PHYS_INPUT_BUTTON_HOOK(this) = false;
1015  PHYS_INPUT_BUTTON_CHAT(this) = false;
1016  PHYS_INPUT_BUTTON_ATCK2(this) = false;
1017  PHYS_INPUT_BUTTON_CROUCH(this) = false;
1018 
1019  CS(this).movement = '0 0 0';
1021 
1024  return CMD_STATUS_FINISHED;
1025 }
1026 
1028 {
1029  return this.cmd_moveto(this, bot_cmd.bot_cmd_parm_vector);
1030 }
1031 
1033 {
1034  entity e;
1035  e = bot_getplace(this, bot_cmd.bot_cmd_parm_string);
1036  if(!e)
1037  return CMD_STATUS_ERROR;
1038  return this.cmd_moveto(this, e.origin + (e.mins + e.maxs) * 0.5);
1039 }
1040 
1042 {
1043  return this.cmd_resetgoal(this);
1044 }
1045 
1046 
1048 {
1049  string f;
1050  f = bot_cmd.bot_cmd_parm_string;
1051 
1052  float n = tokenizebyseparator(f, " ");
1053 
1054  string sample = f;
1055  float chan = CH_WEAPON_B;
1056  float vol = VOL_BASE;
1057  float atten = ATTEN_MIN;
1058 
1059  if(n >= 1)
1060  sample = argv(n - 1);
1061  if(n >= 2)
1062  chan = stof(argv(0));
1063  if(n >= 3)
1064  vol = stof(argv(1));
1065  if(n >= 4)
1066  atten = stof(argv(2));
1067 
1068  precache_sound(f);
1069  _sound(this, chan, sample, vol, atten);
1070 
1071  return CMD_STATUS_FINISHED;
1072 }
1073 
1074 .entity tuba_note;
1076 {
1077  float f = bot_cmd.bot_cmd_parm_float;
1078 
1079  int slot = 0; // TODO: unhardcode?
1080  .entity weaponentity = weaponentities[slot];
1081  if(this.(weaponentity).state != WS_READY)
1082  {
1083  if(f)
1084  {
1085  this.colormod = '0 8 8';
1086  LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by weaponentity state");
1087  }
1088  }
1089  else if(ATTACK_FINISHED(this, weaponentity) > time)
1090  {
1091  if(f)
1092  {
1093  this.colormod = '8 0 8';
1094  LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, inhibited by ATTACK_FINISHED (", ftos(ATTACK_FINISHED(this, weaponentity) - time), " seconds left)");
1095  }
1096  }
1097  else if(this.(weaponentity).tuba_note)
1098  {
1099  if(f)
1100  {
1101  this.colormod = '8 0 0';
1102  LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " wants to fire, bot still has an active tuba note");
1103  }
1104  }
1105  else
1106  {
1107  if(!f)
1108  {
1109  this.colormod = '8 8 0';
1110  LOG_INFO("Bot ", this.netname, " using ", this.(weaponentity).weaponname, " thinks it has fired, but apparently did not; ATTACK_FINISHED says ", ftos(ATTACK_FINISHED(this, weaponentity) - time), " seconds left");
1111  }
1112  }
1113 
1114  return CMD_STATUS_FINISHED;
1115 }
1116 
1117 //
1118 
1119 void bot_command_executed(entity this, bool rm)
1120 {
1121  entity cmd;
1122 
1123  cmd = bot_cmd;
1124 
1125  if(rm)
1127 
1128  this.bot_cmd_execution_index++;
1129 }
1130 
1132 {
1133  bot_cmd = NULL;
1134 
1135  if(!this.bot_cmd_current)
1136  {
1138  }
1139 
1140  bot_cmd = this.bot_cmd_current;
1141  if(bot_cmd.bot_cmd_index != this.bot_cmd_execution_index || this.bot_cmd_execution_index == 0)
1142  {
1144  {
1145  string cmdstring;
1146  cmdstring = bot_readcommand(this, this.bot_cmd_execution_index);
1147  if(bot_decodecommand(cmdstring))
1148  {
1149  bot_cmd.owner = this;
1150  bot_cmd.bot_cmd_index = this.bot_cmd_execution_index;
1151  }
1152  else
1153  {
1154  // Invalid command, remove from queue
1155  bot_cmd = NULL;
1157  this.bot_cmd_execution_index++;
1158  }
1159  }
1160  else
1161  bot_cmd = NULL;
1162  }
1163 }
1164 
1166 {
1167  FOREACH_CLIENT(it.isbot, {
1168  it.bot_cmd_execution_index = 0;
1169  bot_clearqueue(it);
1170  // also, cancel all barriers
1171  it.bot_barrier = 0;
1172  for(int i = 0; i < it.bot_places_count; ++i)
1173  {
1174  strfree(it.(bot_placenames[i]));
1175  }
1176  it.bot_places_count = 0;
1177  });
1178 
1180 }
1181 
1182 // Here we map commands to functions and deal with complex interactions between commands and execution states
1183 // NOTE: Of course you need to include your commands here too :)
1185 {
1186  float status, ispressingkey;
1187 
1188  // Find command
1189  bot_setcurrentcommand(this);
1190 
1191  // Ignore all commands except continue when the bot is paused
1193  {
1194  // if we have no bot command, better return
1195  // old logic kept pressing previously pressed keys, but that has problems
1196  // (namely, it means you cannot make a bot "normal" ever again)
1197  // to keep a bot walking for a while, use the "wait" bot command
1198  if(bot_cmd == world)
1199  return 0;
1200  }
1201  else if(bot_cmd.bot_cmd_type != BOT_CMD_CONTINUE)
1202  {
1203  if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
1204  {
1205  bot_command_executed(this, true);
1206  LOG_INFO("WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.");
1207  }
1208  return 1;
1209  }
1210 
1211  // Keep pressing keys raised by the "presskey" command
1212  ispressingkey = boolean(bot_presskeys(this));
1213 
1214  // Handle conditions
1215  if (!(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE))
1217  {
1218  bot_command_executed(this, true);
1219  return -1;
1220  }
1222  {
1223  bot_command_executed(this, true);
1224  return -1;
1225  }
1226 
1227  // Map commands to functions
1228  switch(bot_cmd.bot_cmd_type)
1229  {
1230  case BOT_CMD_NULL:
1231  return ispressingkey;
1232  //break;
1233  case BOT_CMD_PAUSE:
1234  status = bot_cmd_pause(this);
1235  break;
1236  case BOT_CMD_CONTINUE:
1237  status = bot_cmd_continue(this);
1238  break;
1239  case BOT_CMD_WAIT:
1240  status = bot_cmd_wait(this);
1241  break;
1242  case BOT_CMD_WAIT_UNTIL:
1243  status = bot_cmd_wait_until(this);
1244  break;
1245  case BOT_CMD_TURN:
1246  status = bot_cmd_turn(this);
1247  break;
1248  case BOT_CMD_MOVETO:
1249  status = bot_cmd_moveto(this);
1250  break;
1251  case BOT_CMD_MOVETOTARGET:
1252  status = bot_cmd_movetotarget(this);
1253  break;
1254  case BOT_CMD_RESETGOAL:
1255  status = bot_cmd_resetgoal(this);
1256  break;
1257  case BOT_CMD_CC:
1258  status = bot_cmd_cc(this);
1259  break;
1260  case BOT_CMD_IF:
1261  status = bot_cmd_if(this);
1262  break;
1263  case BOT_CMD_ELSE:
1264  status = bot_cmd_else(this);
1265  break;
1266  case BOT_CMD_FI:
1267  status = bot_cmd_fi(this);
1268  break;
1269  case BOT_CMD_RESETAIM:
1270  status = bot_cmd_resetaim(this);
1271  break;
1272  case BOT_CMD_AIM:
1273  status = bot_cmd_aim(this);
1274  break;
1275  case BOT_CMD_AIMTARGET:
1276  status = bot_cmd_aimtarget(this);
1277  break;
1278  case BOT_CMD_PRESSKEY:
1279  status = bot_cmd_presskey(this);
1280  break;
1281  case BOT_CMD_RELEASEKEY:
1282  status = bot_cmd_releasekey(this);
1283  break;
1284  case BOT_CMD_SELECTWEAPON:
1285  status = bot_cmd_select_weapon(this);
1286  break;
1287  case BOT_CMD_IMPULSE:
1288  status = bot_cmd_impulse(this);
1289  break;
1290  case BOT_CMD_BARRIER:
1291  status = bot_cmd_barrier(this);
1292  break;
1293  case BOT_CMD_CONSOLE:
1294  localcmd(strcat(bot_cmd.bot_cmd_parm_string, "\n"));
1295  status = CMD_STATUS_FINISHED;
1296  break;
1297  case BOT_CMD_SOUND:
1298  status = bot_cmd_sound(this);
1299  break;
1301  status = bot_cmd_debug_assert_canfire(this);
1302  break;
1303  default:
1304  LOG_INFOF("ERROR: Invalid command on queue with id '%s'", ftos(bot_cmd.bot_cmd_type));
1305  return 0;
1306  }
1307 
1308  if (status==CMD_STATUS_ERROR)
1309  LOG_INFOF("ERROR: The command '%s' returned an error status", bot_cmd_string[bot_cmd.bot_cmd_type]);
1310 
1311  // Move execution pointer
1312  if(status==CMD_STATUS_EXECUTING)
1313  {
1314  return 1;
1315  }
1316  else
1317  {
1319  {
1320  string parms;
1321 
1322  switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
1323  {
1325  parms = ftos(bot_cmd.bot_cmd_parm_float);
1326  break;
1328  parms = bot_cmd.bot_cmd_parm_string;
1329  break;
1331  parms = vtos(bot_cmd.bot_cmd_parm_vector);
1332  break;
1333  default:
1334  parms = "";
1335  break;
1336  }
1337  clientcommand(this,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
1338  }
1339 
1340  bot_command_executed(this, true);
1341  }
1342 
1343  if(status == CMD_STATUS_FINISHED)
1344  return -1;
1345 
1346  return CMD_STATUS_ERROR;
1347 }
1348 
1349 // This function should be (the only) called directly from the bot ai loop
1351 {
1352  int f;
1353  do
1354  {
1355  f = bot_execute_commands_once(this);
1356  }
1357  while(f < 0);
1358  return f;
1359 }
string bot_cmd_string[BOT_CMD_COUNTER]
Definition: scripting.qh:56
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition: player.qh:148
#define PHYS_INPUT_BUTTON_JUMP(s)
Definition: player.qh:147
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition: player.qh:155
#define PHYS_INPUT_BUTTON_CROUCH(s)
Definition: player.qh:150
float bot_cmd_aim_endtime
Definition: scripting.qc:726
string bot_readcommand(entity bot, float idx)
Definition: scripting.qc:87
entity bot_cmd_current
Definition: scripting.qh:60
const int CMD_CONDITION_false_BLOCK
Definition: scripting.qc:607
entity world
Definition: csprogsdefs.qc:15
#define PHYS_INPUT_BUTTON_DRAG(s)
Definition: player.qh:153
float bot_cmd_continue(entity this)
Definition: scripting.qc:494
const int BOT_CMD_MOVETOTARGET
Definition: scripting.qh:31
vector colormod
Definition: powerups.qc:21
const int BOT_CMD_SOUND
Definition: scripting.qh:35
vector view_ofs
Definition: progsdefs.qc:151
#define PHYS_INPUT_BUTTON_HOOK(s)
Definition: player.qh:151
spree_inf s1 s2 s3loc s2 spree_inf s1 s2 s3loc s2 spree_inf s1 s2 s3loc s2 s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2loc s1 s2 f1 f1points s1 s2
Definition: all.inc:438
float bot_decodecommand(string cmdstring)
Definition: scripting.qc:268
const int BOT_CMD_ELSE
Definition: scripting.qh:22
float bot_cmd_impulse(entity this)
Definition: scripting.qc:488
int int number
Definition: impulse.qc:89
vector bot_cmd_aim_begin
Definition: scripting.qc:727
entity find_bot_by_number(float number)
Definition: scripting.qc:246
const int BOT_CMD_KEY_NONE
Definition: scripting.qc:827
bool bot_havecommand(entity this, int idx)
Definition: scripting.qc:98
void bot_relinkplayerlist()
Definition: bot.qc:381
float bot_cmd_resetaim(entity this)
Definition: scripting.qc:719
float bot_execute_commands_once(entity this)
Definition: scripting.qc:1184
const int BOT_CMD_AIMTARGET
Definition: scripting.qh:32
float bot_cmd_sound(entity this)
Definition: scripting.qc:1047
const float ATTEN_MIN
Definition: sound.qh:28
bool autocvar_g_debug_bot_commands
Definition: cvars.qh:62
const int BOT_CMD_AIM
Definition: scripting.qh:25
const int BOT_CMD_KEY_RIGHT
Definition: scripting.qc:830
int bot_cmd_parm_type[BOT_CMD_COUNTER]
Definition: scripting.qh:55
int bot_execute_commands(entity this)
Definition: scripting.qc:1350
void bot_commands_init()
Definition: scripting.qc:157
#define BOT_EXEC_STATUS_WAITING
Definition: scripting.qh:5
int bot_cmd_condition_status
Definition: scripting.qc:601
void bot_command_executed(entity this, bool rm)
Definition: scripting.qc:1119
float bot_cmd_moveto(entity this)
Definition: scripting.qc:1027
#define BOT_EXEC_STATUS_PAUSED
Definition: scripting.qh:4
entity() spawn
#define REGISTRY_GET(id, i)
Definition: registry.qh:43
ClientState CS(Client this)
Definition: state.qh:47
float bot_cmd_wait_time
Definition: scripting.qc:501
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float bot_cmd_wait_until(entity this)
Definition: scripting.qc:520
vector v_angle
Definition: progsdefs.qc:161
const int BOT_CMD_KEY_ATTACK1
Definition: scripting.qc:833
float bot_barriertime
Definition: scripting.qh:68
float bot_cmd_else(entity this)
Definition: scripting.qc:706
float bot_cmd_eval(entity this, string expr)
Definition: scripting.qc:609
float bot_cmd_barrier(entity this)
Definition: scripting.qc:531
string netname
Definition: powerups.qc:20
const int BOT_CMD_RESETAIM
Definition: scripting.qh:24
entity flagcarried
Definition: sv_ctf.qh:82
float atten
Definition: triggers.qh:47
float bot_cmd_cc(entity this)
Definition: scripting.qc:482
const int BOT_CMD_MOVETO
Definition: scripting.qh:18
const int BOT_CMD_CC
Definition: scripting.qh:20
#define CMD_STATUS_ERROR
Definition: scripting.qh:9
const int BOT_CMD_CONTINUE
Definition: scripting.qh:15
const int CMD_CONDITION_NONE
Definition: scripting.qc:603
#define WEP_LAST
Definition: all.qh:305
origin
Definition: ent_cs.qc:114
const int BOT_CMD_KEY_ATTACK2
Definition: scripting.qc:834
int bot_cmd_keys
Definition: scripting.qc:825
const int WS_READY
idle frame
Definition: weapon.qh:38
float bot_cmd_aim(entity this)
Definition: scripting.qc:730
void bot_queuecommand(entity bot, string cmdstring)
Definition: scripting.qc:30
const int BOT_CMD_FI
Definition: scripting.qh:23
float bot_cmdqueuebuf_start
Definition: scripting.qc:18
float bot_cmd_releasekey(entity this)
Definition: scripting.qc:994
#define LOG_HELP(...)
Definition: log.qh:95
float bot_cmd_aimtarget(entity this)
Definition: scripting.qc:781
const int BOT_CMD_KEY_JUMP
Definition: scripting.qc:832
const int BOT_CMD_KEY_USE
Definition: scripting.qc:835
void bot_resetqueues()
Definition: scripting.qc:1165
#define strcpy(this, s)
Definition: string.qh:49
const int BOT_CMD_KEY_BACKWARD
Definition: scripting.qc:829
const int BOT_CMD_KEY_HOOK
Definition: scripting.qc:836
const int BOT_CMD_PAUSE
Definition: scripting.qh:14
RES_HEALTH
Definition: ent_cs.qc:126
float bot_cmd_debug_assert_canfire(entity this)
Definition: scripting.qc:1075
entity tuba_note
Definition: scripting.qc:1074
#define CMD_STATUS_FINISHED
Definition: scripting.qh:8
float bot_cmd_select_weapon(entity this)
Definition: scripting.qc:573
#define buf_create
Definition: dpextensions.qh:63
float bot_cmd_execution_index
Definition: scripting.qh:71
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
float bot_cmd_fi(entity this)
Definition: scripting.qc:713
const int BOT_CMD_PRESSKEY
Definition: scripting.qh:26
void SV_ParseClientCommand(entity this, string command)
Definition: cmd.qc:866
float bot_cmd_movetotarget(entity this)
Definition: scripting.qc:1032
string bot_placenames[MAX_BOT_PLACES]
Definition: scripting.qc:112
float bot_cmd_keypress_handler(entity this, string key, float enabled)
Definition: scripting.qc:889
vector bot_cmd_aim_end
Definition: scripting.qc:728
const int CMD_CONDITION_false
Definition: scripting.qc:605
void bot_clearqueue(entity bot)
Definition: scripting.qc:21
#define LOG_INFOF(...)
Definition: log.qh:71
float bot_cmd_wait(entity this)
Definition: scripting.qc:502
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
const int MAX_WEAPONSLOTS
Definition: weapon.qh:13
float bot_cmd_pause(entity this)
Definition: scripting.qc:1008
#define PHYS_INPUT_BUTTON_USE(s)
Definition: player.qh:154
entity bot_cmd
Definition: scripting.qh:59
float bot_cmd_aim_begintime
Definition: scripting.qc:725
entity bot_places[MAX_BOT_PLACES]
Definition: scripting.qc:111
#define NULL
Definition: post.qh:17
int state
Definition: scripting.qc:14
const int CMD_CONDITION_true
Definition: scripting.qc:604
#define LOG_INFO(...)
Definition: log.qh:70
#define CMD_STATUS_EXECUTING
Definition: scripting.qh:7
const float VOL_BASE
Definition: sound.qh:36
entity bot_getplace(entity this, string placename)
Definition: scripting.qc:113
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition: player.qh:146
float bot_cmd_resetgoal(entity this)
Definition: scripting.qc:1041
#define strstrofs
Definition: dpextensions.qh:42
const int BOT_CMD_DEBUG_ASSERT_CANFIRE
Definition: scripting.qh:36
const int BOT_CMD_CONSOLE
Definition: scripting.qh:34
#define IS_DIGIT(d)
Definition: string.qh:507
int bot_exec_status
Definition: scripting.qc:480
const int BOT_CMD_PARAMETER_VECTOR
Definition: scripting.qh:52
const int BOT_CMD_RESETGOAL
Definition: scripting.qh:19
float bot_places_count
Definition: scripting.qc:110
const int BOT_CMD_WAIT_UNTIL
Definition: scripting.qh:30
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const int BOT_CMD_KEY_FORWARD
Definition: scripting.qc:828
const int BOT_CMD_IMPULSE
Definition: scripting.qh:29
const int CMD_CONDITION_true_BLOCK
Definition: scripting.qc:606
const int BOT_CMD_COUNTER
Definition: scripting.qh:41
float bot_cmd_turn(entity this)
Definition: scripting.qc:566
vector v
Definition: ent_cs.qc:116
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
const int BOT_CMD_RELEASEKEY
Definition: scripting.qh:27
float flags
Definition: csprogsdefs.qc:129
bool bot_presskeys(entity this)
Definition: scripting.qc:840
#define LOG_TRACE(...)
Definition: log.qh:81
const int BOT_CMD_PARAMETER_NONE
Definition: scripting.qh:49
float bot_cmdqueuebuf_end
Definition: scripting.qc:19
float bot_cmdqueuebuf
Definition: scripting.qc:17
#define _sound(e, c, s, v, a)
Definition: sound.qh:50
float bot_barrier
Definition: scripting.qh:69
float bot_cmd_presskey(entity this)
Definition: scripting.qc:983
string targetname
Definition: progsdefs.qc:194
#define tokenizebyseparator
Definition: dpextensions.qh:21
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
entity weaponentities[MAX_WEAPONSLOTS]
Definition: weapon.qh:14
const int BOT_CMD_IF
Definition: scripting.qh:21
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
entity find_bot_by_name(string name)
Definition: scripting.qc:235
float bot_cmd_if(entity this)
Definition: scripting.qc:635
#define ATTACK_FINISHED(ent, w)
Definition: weaponsystem.qh:42
void bot_setcurrentcommand(entity this)
Definition: scripting.qc:1131
bool bot_ispaused(entity this)
Definition: scripting.qc:1003
const int BOT_CMD_BARRIER
Definition: scripting.qh:33
const int BOT_CMD_KEY_CROUCH
Definition: scripting.qc:837
float bot_cmdqueuebuf_allocated
Definition: scripting.qc:16
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
Definition: selection.qc:48
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
const int CH_WEAPON_B
Definition: sound.qh:8
const int BOT_CMD_PARAMETER_FLOAT
Definition: scripting.qh:50
void bot_dequeuecommand(entity bot, float idx)
Definition: scripting.qc:72
const int BOT_CMD_SELECTWEAPON
Definition: scripting.qh:28
const int BOT_CMD_KEY_LEFT
Definition: scripting.qc:831
const int BOT_CMD_KEY_CHAT
Definition: scripting.qc:838
#define boolean(value)
Definition: bool.qh:9
float bot_cmds_initialized
Definition: scripting.qh:54
const int BOT_CMD_WAIT
Definition: scripting.qh:16
void bot_cmdhelp(string scmd)
Definition: scripting.qc:331
const int BOT_CMD_TURN
Definition: scripting.qh:17
void bot_list_commands()
Definition: scripting.qc:444
const int BOT_CMD_PARAMETER_STRING
Definition: scripting.qh:51
float FL_CLIENT
Definition: progsdefs.qc:234
const int MAX_BOT_PLACES
Definition: scripting.qc:109
const int BOT_CMD_NULL
Definition: scripting.qh:13