1 // NOTE: New commands should be added here. Do not forget to update BOT_CMD_COUNTER
3 #define BOT_CMD_PAUSE 1
4 #define BOT_CMD_CONTINUE 2
7 #define BOT_CMD_MOVETO 5 // Not implemented yet
8 #define BOT_CMD_RESETGOAL 6 // Not implemented yet
11 #define BOT_CMD_ELSE 9
13 #define BOT_CMD_RESETAIM 11
14 #define BOT_CMD_AIM 12
15 #define BOT_CMD_PRESSKEY 13
16 #define BOT_CMD_RELEASEKEY 14
17 #define BOT_CMD_SELECTWEAPON 15
18 #define BOT_CMD_IMPULSE 16
19 #define BOT_CMD_WAIT_UNTIL 17
20 #define BOT_CMD_WHILE 18 // Not implemented yet
21 #define BOT_CMD_WEND 19 // Not implemented yet
22 #define BOT_CMD_CHASE 20 // Not implemented yet
23 #define BOT_CMD_COUNTER 18
25 // NOTE: Following commands should be implemented on the bot ai
26 // If a new command should be handled by the target ai(s) please declare it here
27 .float(vector) cmd_moveto;
28 .float() cmd_resetgoal;
31 #define BOT_CMD_PARAMETER_NONE 0
32 #define BOT_CMD_PARAMETER_FLOAT 1
33 #define BOT_CMD_PARAMETER_STRING 2
34 #define BOT_CMD_PARAMETER_VECTOR 3
36 float bot_cmds_initialized;
37 float bot_cmd_parm_type[BOT_CMD_COUNTER];
38 string bot_cmd_string[BOT_CMD_COUNTER];
41 entity bot_cmd; // Current command
43 .float is_bot_cmd; // Tells if the entity is a bot command
44 .float bot_cmd_index; // Position of the command in the queue
45 .float bot_cmd_type; // If of command (see the BOT_CMD_* defines)
46 .float bot_cmd_parm_float; // Field to store a float parameter
47 .string bot_cmd_parm_string; // Field to store a string parameter
48 .vector bot_cmd_parm_vector; // Field to store a vector parameter
49 .float bot_cmd_execution_counter; // How many times this command on the queue was executed
51 .float bot_cmd_execution_index; // Position in the queue of the command to be executed
52 .float bot_cmd_queue_index; // Position of the last command in the queue
54 // Initialize global commands list
55 // NOTE: New commands should be initialized here
56 void bot_commands_init()
58 bot_cmd_string[BOT_CMD_NULL] = "";
59 bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
61 bot_cmd_string[BOT_CMD_PAUSE] = "pause";
62 bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
64 bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
65 bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
67 bot_cmd_string[BOT_CMD_WAIT] = "wait";
68 bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
70 bot_cmd_string[BOT_CMD_TURN] = "turn";
71 bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
73 bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
74 bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
76 bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
77 bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
79 bot_cmd_string[BOT_CMD_CC] = "cc";
80 bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
82 bot_cmd_string[BOT_CMD_IF] = "if";
83 bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
85 bot_cmd_string[BOT_CMD_ELSE] = "else";
86 bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
88 bot_cmd_string[BOT_CMD_FI] = "fi";
89 bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
91 bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
92 bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
94 bot_cmd_string[BOT_CMD_AIM] = "aim";
95 bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
97 bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
98 bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
100 bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
101 bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
103 bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
104 bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
106 bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
107 bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
109 bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
110 bot_cmd_parm_type[BOT_CMD_WAIT_UNTIL] = BOT_CMD_PARAMETER_FLOAT;
112 bot_cmds_initialized = TRUE;
115 // Returns first bot with matching name
116 entity find_bot_by_name(string name)
120 bot = findchainflags(flags, FL_CLIENT);
123 if(clienttype(bot) == CLIENTTYPE_BOT)
124 if(bot.netname==name)
133 // Returns a bot by number on list
134 entity find_bot_by_number(float number)
139 bot = findchainflags(flags, FL_CLIENT);
142 if(clienttype(bot) == CLIENTTYPE_BOT)
153 void bot_clearqueue()
155 entity head, newhead;
157 head = findchainfloat(is_bot_cmd, TRUE);
162 newhead = head.chain;
170 self.bot_cmd_queue_index = 0;
171 self.bot_cmd_execution_index = 0;
174 entity bot_spawncmd(entity bot, float type)
178 bot.bot_cmd_queue_index++;
182 cmd.is_bot_cmd = TRUE;
183 cmd.bot_cmd_type = type;
184 cmd.bot_cmd_index = bot.bot_cmd_queue_index;
189 void bot_debugcmd(entity cmd)
191 print(strcat("Owner: ",cmd.owner.netname, "\n"));
192 print(strcat("Cmd Type: ",ftos(cmd.bot_cmd_type), "\n"));
193 print(strcat("Cmd Index: ",ftos(cmd.bot_cmd_index), "\n"));
195 print(strcat("Param Float: ",ftos(cmd.bot_cmd_parm_float), "\n"));
196 print(strcat("Param String: ",cmd.bot_cmd_parm_string, "\n"));
197 print(strcat("Param Vector: ",vtos(cmd.bot_cmd_parm_vector), "\n"));
199 print(strcat("Bot queue index: ", ftos(cmd.owner.bot_cmd_queue_index), "\n"));
200 print(strcat("Bot execution index: ", ftos(cmd.owner.bot_cmd_execution_index), "\n\n"));
203 void bot_queuecommand(entity bot, string cmdstring, string parm)
206 local float cmd_parm_type, i;
211 if(!bot_cmds_initialized)
214 for(i=1;i<BOT_CMD_COUNTER;++i)
216 if(bot_cmd_string[i]!=cmdstring)
219 cmd_parm_type = bot_cmd_parm_type[i];
221 if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
223 print("ERROR: A parameter is required for this command\n");
227 // Load command into queue
228 cmd = bot_spawncmd(bot, i);
231 switch(cmd_parm_type)
233 case BOT_CMD_PARAMETER_FLOAT:
234 cmd.bot_cmd_parm_float = stof(parm);
236 case BOT_CMD_PARAMETER_STRING:
237 cmd.bot_cmd_parm_string = strzone(parm);
239 case BOT_CMD_PARAMETER_VECTOR:
240 cmd.bot_cmd_parm_vector = stov(parm);
247 print("ERROR: No such command\n");
250 void bot_cmdhelp(string scmd)
252 local float i, ntype;
255 if(!bot_cmds_initialized)
258 for(i=1;i<BOT_CMD_COUNTER;++i)
260 if(bot_cmd_string[i]!=scmd)
263 ntype = bot_cmd_parm_type[i];
267 case BOT_CMD_PARAMETER_FLOAT:
268 stype = "float number";
270 case BOT_CMD_PARAMETER_STRING:
273 case BOT_CMD_PARAMETER_VECTOR:
281 print(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
283 print("Description: ");
287 print("Stops the bot completely. Any command other than 'continue' will be ignored.");
289 case BOT_CMD_CONTINUE:
290 print("Disable paused status");
293 print("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
295 case BOT_CMD_WAIT_UNTIL:
296 print("Pause command parsing and bot ai until time is N. Pressed key will remain pressed");
299 print("Look to the right or left N degrees. For turning to the left use positive numbers.");
302 print("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
304 case BOT_CMD_RESETGOAL:
305 print("Resets the goal stack");
308 print("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
311 print("Perform simple conditional execution.\n");
313 print(" sv_cmd .. if \"condition\"\n");
314 print(" sv_cmd .. <instruction if true>\n");
315 print(" sv_cmd .. <instruction if true>\n");
316 print(" sv_cmd .. else\n");
317 print(" sv_cmd .. <instruction if false>\n");
318 print(" sv_cmd .. <instruction if false>\n");
319 print(" sv_cmd .. fi\n");
320 print("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
321 print(" Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
322 print("Fields: health, speed, flagcarrier\n");
323 print("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
325 case BOT_CMD_RESETAIM:
326 print("Points the aim to the coordinates x,y 0,0");
329 print("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
330 print("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
331 print("Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
332 print(" aim \"0 90 2\" // Will gradually look to the sky in the next two seconds");
334 case BOT_CMD_PRESSKEY:
335 print("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
336 print("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
337 print("Note: The script will not return the control to the bot ai until all keys are released");
339 case BOT_CMD_RELEASEKEY:
340 print("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
343 print("This command has no description yet.");
350 void bot_list_commands()
355 if(!bot_cmds_initialized)
358 print("List of all available commands:\n");
359 print(" Command\t\t\t\tParameter Type\n");
361 for(i=1;i<BOT_CMD_COUNTER;++i)
363 switch(bot_cmd_parm_type[i])
365 case BOT_CMD_PARAMETER_FLOAT:
366 ptype = "float number";
368 case BOT_CMD_PARAMETER_STRING:
371 case BOT_CMD_PARAMETER_VECTOR:
378 print(strcat(" ",bot_cmd_string[i],"\t\t\t\t<",ptype,"> \n"));
383 .float bot_exec_status;
385 #define BOT_EXEC_STATUS_IDLE 0
386 #define BOT_EXEC_STATUS_PAUSED 1
387 #define BOT_EXEC_STATUS_WAITING 2
389 #define CMD_STATUS_EXECUTING 0
390 #define CMD_STATUS_FINISHED 1
391 #define CMD_STATUS_ERROR 2
395 clientcommand(self,bot_cmd.bot_cmd_parm_string);
396 return CMD_STATUS_FINISHED;
399 float bot_cmd_impulse()
401 self.impulse = bot_cmd.bot_cmd_parm_float;
402 return CMD_STATUS_FINISHED;
405 float bot_cmd_continue()
407 self.bot_exec_status &~= BOT_EXEC_STATUS_PAUSED;
408 return CMD_STATUS_FINISHED;
411 .float bot_cmd_wait_time;
414 if(self.bot_exec_status & BOT_EXEC_STATUS_WAITING)
416 if(time>=self.bot_cmd_wait_time)
418 self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
419 return CMD_STATUS_FINISHED;
422 return CMD_STATUS_EXECUTING;
425 self.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
426 self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
427 return CMD_STATUS_EXECUTING;
430 float bot_cmd_wait_until()
432 if(time < bot_cmd.bot_cmd_parm_float)
434 self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
435 return CMD_STATUS_EXECUTING;
437 self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
438 return CMD_STATUS_FINISHED;
443 self.v_angle_y = self.v_angle_y + bot_cmd.bot_cmd_parm_float;
444 self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
445 return CMD_STATUS_FINISHED;
448 float bot_cmd_select_weapon()
452 id = bot_cmd.bot_cmd_parm_float;
454 if(id < WEP_FIRST || id > WEP_LAST)
455 return CMD_STATUS_ERROR;
457 if(client_hasweapon(self, id, TRUE, FALSE))
458 self.switchweapon = id;
460 return CMD_STATUS_FINISHED;
463 .float bot_cmd_condition_status;
465 #define CMD_CONDITION_NONE 0
466 #define CMD_CONDITION_TRUE 1
467 #define CMD_CONDITION_FALSE 2
468 #define CMD_CONDITION_TRUE_BLOCK 4
469 #define CMD_CONDITION_FALSE_BLOCK 8
471 float bot_cmd_eval(string expr)
473 // Search for numbers
474 if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
480 if(substring(expr, 0, 5)=="cvar.")
482 return cvar(substring(expr, 5, strlen(expr)));
491 return vlen(self.velocity);
493 return ((self.flagcarried!=world));
496 print(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
502 local string expr, val_a, val_b;
505 if(self.bot_cmd_condition_status != CMD_CONDITION_NONE)
507 // Only one "if" block is allowed at time
508 print("ERROR: Only one conditional block can be processed at time");
510 return CMD_STATUS_ERROR;
513 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE_BLOCK;
515 // search for operators
516 expr = bot_cmd.bot_cmd_parm_string;
518 cmpofs = strstrofs(expr,"=",0);
522 val_a = substring(expr,0,cmpofs);
523 val_b = substring(expr,cmpofs+1,strlen(expr));
525 if(bot_cmd_eval(val_a)==bot_cmd_eval(val_b))
526 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
528 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
530 return CMD_STATUS_FINISHED;
533 cmpofs = strstrofs(expr,">",0);
537 val_a = substring(expr,0,cmpofs);
538 val_b = substring(expr,cmpofs+1,strlen(expr));
540 if(bot_cmd_eval(val_a)>bot_cmd_eval(val_b))
541 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
543 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
545 return CMD_STATUS_FINISHED;
548 cmpofs = strstrofs(expr,"<",0);
552 val_a = substring(expr,0,cmpofs);
553 val_b = substring(expr,cmpofs+1,strlen(expr));
555 if(bot_cmd_eval(val_a)<bot_cmd_eval(val_b))
556 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
558 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
560 return CMD_STATUS_FINISHED;
563 if(bot_cmd_eval(expr))
564 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
566 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
568 return CMD_STATUS_FINISHED;
573 self.bot_cmd_condition_status &~= CMD_CONDITION_TRUE_BLOCK;
574 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE_BLOCK;
575 return CMD_STATUS_FINISHED;
580 self.bot_cmd_condition_status = CMD_CONDITION_NONE;
581 return CMD_STATUS_FINISHED;
584 float bot_cmd_resetaim()
586 self.v_angle = '0 0 0';
587 return CMD_STATUS_FINISHED;
590 .float bot_cmd_aim_begintime;
591 .float bot_cmd_aim_endtime;
592 .vector bot_cmd_aim_begin;
593 .vector bot_cmd_aim_end;
598 if(self.bot_cmd_aim_endtime)
600 local float progress;
602 progress = min(1 - (self.bot_cmd_aim_endtime - time) / (self.bot_cmd_aim_endtime - self.bot_cmd_aim_begintime),1);
603 self.v_angle = self.bot_cmd_aim_begin + ((self.bot_cmd_aim_end - self.bot_cmd_aim_begin) * progress);
605 if(time>=self.bot_cmd_aim_endtime)
607 self.bot_cmd_aim_endtime = 0;
608 return CMD_STATUS_FINISHED;
611 return CMD_STATUS_EXECUTING;
614 // New aiming direction
616 local float tokens, step;
618 parms = bot_cmd.bot_cmd_parm_string;
620 tokens = tokenizebyseparator(parms, " ");
624 self.v_angle_x -= stof(argv(1));
625 self.v_angle_y += stof(argv(0));
626 return CMD_STATUS_FINISHED;
629 if(tokens<1||tokens>3)
630 return CMD_STATUS_ERROR;
632 step = stof(argv(2));
634 self.bot_cmd_aim_begin = self.v_angle;
636 self.bot_cmd_aim_end_x = self.v_angle_x - stof(argv(1));
637 self.bot_cmd_aim_end_y = self.v_angle_y + stof(argv(0));
638 self.bot_cmd_aim_end_z = 0;
640 self.bot_cmd_aim_begintime = time;
641 self.bot_cmd_aim_endtime = time + step;
643 return CMD_STATUS_EXECUTING;
648 #define BOT_CMD_KEY_NONE 0
649 #define BOT_CMD_KEY_FORWARD 1
650 #define BOT_CMD_KEY_BACKWARD 2
651 #define BOT_CMD_KEY_RIGHT 4
652 #define BOT_CMD_KEY_LEFT 8
653 #define BOT_CMD_KEY_JUMP 16
654 #define BOT_CMD_KEY_ATTACK1 32
655 #define BOT_CMD_KEY_ATTACK2 64
656 #define BOT_CMD_KEY_USE 128
657 #define BOT_CMD_KEY_HOOK 256
658 #define BOT_CMD_KEY_CROUCH 512
660 float bot_presskeys()
662 self.movement = '0 0 0';
664 if(self.bot_cmd_keys == BOT_CMD_KEY_NONE)
667 if(self.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
668 self.movement_x = cvar("sv_maxspeed");
669 else if(self.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
670 self.movement_x = -cvar("sv_maxspeed");
672 if(self.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
673 self.movement_y = cvar("sv_maxspeed");
674 else if(self.bot_cmd_keys & BOT_CMD_KEY_LEFT)
675 self.movement_y = -cvar("sv_maxspeed");
677 if(self.bot_cmd_keys & BOT_CMD_KEY_JUMP)
678 self.BUTTON_JUMP = TRUE;
680 if(self.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
681 self.BUTTON_CROUCH = TRUE;
683 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
684 self.BUTTON_ATCK = TRUE;
686 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
687 self.BUTTON_ATCK2 = TRUE;
689 if(self.bot_cmd_keys & BOT_CMD_KEY_USE)
690 self.BUTTON_USE = TRUE;
696 float bot_cmd_keypress_handler(string key, float enabled)
702 self.bot_cmd_keys = power2of(20) - 1; // >:)
704 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
708 self.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
709 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
712 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
717 self.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
718 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
721 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
726 self.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
727 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
730 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
735 self.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
736 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
739 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
743 self.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
745 self.bot_cmd_keys &~= BOT_CMD_KEY_JUMP;
749 self.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
751 self.bot_cmd_keys &~= BOT_CMD_KEY_CROUCH;
755 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
757 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK1;
761 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
763 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK2;
767 self.bot_cmd_keys |= BOT_CMD_KEY_USE;
769 self.bot_cmd_keys &~= BOT_CMD_KEY_USE;
775 return CMD_STATUS_FINISHED;
778 float bot_cmd_presskey()
782 key = bot_cmd.bot_cmd_parm_string;
784 bot_cmd_keypress_handler(key,TRUE);
786 return CMD_STATUS_FINISHED;
789 float bot_cmd_releasekey()
793 key = bot_cmd.bot_cmd_parm_string;
795 return bot_cmd_keypress_handler(key,FALSE);
798 float bot_cmd_pause()
803 self.BUTTON_ATCK = 0;
804 self.BUTTON_JUMP = 0;
805 self.BUTTON_HOOK = 0;
806 self.BUTTON_CHAT = 0;
807 self.BUTTON_ATCK2 = 0;
808 self.BUTTON_CROUCH = 0;
810 self.movement = '0 0 0';
811 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
813 self.bot_exec_status = self.bot_exec_status | BOT_EXEC_STATUS_PAUSED;
814 return CMD_STATUS_FINISHED;
817 float bot_cmd_moveto()
819 return self.cmd_moveto(bot_cmd.bot_cmd_parm_vector);
822 float bot_cmd_resetgoal()
824 return self.cmd_resetgoal();
827 void bot_command_executed(float rm)
833 self.bot_cmd_execution_index++;
837 if(bot_cmd_parm_type[cmd.bot_cmd_type]==BOT_CMD_PARAMETER_STRING)
839 strunzone(cmd.bot_cmd_parm_string);
845 cmd.bot_cmd_execution_counter++;
848 void bot_setcurrentcommand()
854 if(self.bot_cmd_execution_index==0)
855 self.bot_cmd_execution_index=1;
857 for (cmd = findchainfloat(bot_cmd_index, self.bot_cmd_execution_index); cmd; cmd = cmd.chain)
867 // This function should be (the only) called directly from the bot ai loop
868 // It maps commands to functions and deal with complex interactions between commands and execution states
869 // NOTE: Of course you need to include your commands here too :)
870 float bot_execute_commands()
872 local float status, ispressingkey;
876 bot_setcurrentcommand();
878 // Keep pressing keys raised by the "presskey" command
879 ispressingkey = bot_presskeys();
882 return ispressingkey;
884 // Ignore all commands except continue when the bot is paused
885 if(self.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
886 if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
888 if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
890 bot_command_executed(TRUE);
891 print( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
897 if not(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE)
898 if(self.bot_cmd_condition_status & CMD_CONDITION_TRUE && self.bot_cmd_condition_status & CMD_CONDITION_FALSE_BLOCK)
900 bot_command_executed(TRUE);
903 else if(self.bot_cmd_condition_status & CMD_CONDITION_FALSE && self.bot_cmd_condition_status & CMD_CONDITION_TRUE_BLOCK)
905 bot_command_executed(TRUE);
909 // Map commands to functions
910 switch(bot_cmd.bot_cmd_type)
913 return ispressingkey;
916 status = bot_cmd_pause();
918 case BOT_CMD_CONTINUE:
919 status = bot_cmd_continue();
922 status = bot_cmd_wait();
924 case BOT_CMD_WAIT_UNTIL:
925 status = bot_cmd_wait_until();
928 status = bot_cmd_turn();
931 status = bot_cmd_moveto();
933 case BOT_CMD_RESETGOAL:
934 status = bot_cmd_resetgoal();
937 status = bot_cmd_cc();
940 status = bot_cmd_if();
943 status = bot_cmd_else();
946 status = bot_cmd_fi();
948 case BOT_CMD_RESETAIM:
949 status = bot_cmd_resetaim();
952 status = bot_cmd_aim();
954 case BOT_CMD_PRESSKEY:
955 status = bot_cmd_presskey();
957 case BOT_CMD_RELEASEKEY:
958 status = bot_cmd_releasekey();
960 case BOT_CMD_SELECTWEAPON:
961 status = bot_cmd_select_weapon();
963 case BOT_CMD_IMPULSE:
964 status = bot_cmd_impulse();
967 print(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
971 if (status==CMD_STATUS_ERROR)
972 print(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
974 // Move execution pointer
975 if(status==CMD_STATUS_EXECUTING)
981 if(cvar("g_debug_bot_commands"))
985 switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
987 case BOT_CMD_PARAMETER_FLOAT:
988 parms = ftos(bot_cmd.bot_cmd_parm_float);
990 case BOT_CMD_PARAMETER_STRING:
991 parms = bot_cmd.bot_cmd_parm_string;
993 case BOT_CMD_PARAMETER_VECTOR:
994 parms = vtos(bot_cmd.bot_cmd_parm_vector);
1000 clientcommand(self,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
1003 bot_command_executed(TRUE);