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_RESETQUEUE 18
21 #define BOT_CMD_WHILE 19 // TODO: Not implemented yet
22 #define BOT_CMD_WEND 20 // TODO: Not implemented yet
23 #define BOT_CMD_CHASE 20 // TODO: Not implemented yet
25 #define BOT_CMD_COUNTER 19 // Update this value if you add/remove a command
27 // NOTE: Following commands should be implemented on the bot ai
28 // If a new command should be handled by the target ai(s) please declare it here
29 .float(vector) cmd_moveto;
30 .float() cmd_resetgoal;
33 #define BOT_CMD_PARAMETER_NONE 0
34 #define BOT_CMD_PARAMETER_FLOAT 1
35 #define BOT_CMD_PARAMETER_STRING 2
36 #define BOT_CMD_PARAMETER_VECTOR 3
37 #define BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME 4
39 float bot_cmds_initialized;
40 float bot_cmd_parm_type[BOT_CMD_COUNTER];
41 string bot_cmd_string[BOT_CMD_COUNTER];
44 entity bot_cmd; // Current command
46 .float is_bot_cmd; // Tells if the entity is a bot command
47 .float bot_cmd_index; // Position of the command in the queue
48 .float bot_cmd_type; // If of command (see the BOT_CMD_* defines)
49 .float bot_cmd_parm_float; // Field to store a float parameter
50 .string bot_cmd_parm_string; // Field to store a string parameter
51 .vector bot_cmd_parm_vector; // Field to store a vector parameter
52 .float bot_cmd_execution_counter; // How many times this command on the queue was executed
54 .float bot_cmd_execution_index; // Position in the queue of the command to be executed
55 .float bot_cmd_queue_index; // Position of the last command in the queue
57 .entity bot_cmd_next; // next command of the same bot (field on a command), or next command for this bot to execute (field on a bot)
58 .entity bot_cmd_newest; // last command of this bot (field on a bot, used for adding new commands)
60 // Initialize global commands list
61 // NOTE: New commands should be initialized here
62 void bot_commands_init()
64 bot_cmd_string[BOT_CMD_NULL] = "";
65 bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
67 bot_cmd_string[BOT_CMD_PAUSE] = "pause";
68 bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
70 bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
71 bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
73 bot_cmd_string[BOT_CMD_WAIT] = "wait";
74 bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
76 bot_cmd_string[BOT_CMD_TURN] = "turn";
77 bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
79 bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
80 bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
82 bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
83 bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
85 bot_cmd_string[BOT_CMD_CC] = "cc";
86 bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
88 bot_cmd_string[BOT_CMD_IF] = "if";
89 bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
91 bot_cmd_string[BOT_CMD_ELSE] = "else";
92 bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
94 bot_cmd_string[BOT_CMD_FI] = "fi";
95 bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
97 bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
98 bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
100 bot_cmd_string[BOT_CMD_AIM] = "aim";
101 bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
103 bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
104 bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
106 bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
107 bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
109 bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
110 bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
112 bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
113 bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
115 bot_cmd_string[BOT_CMD_WAIT_UNTIL] = "wait_until";
116 bot_cmd_parm_type[BOT_CMD_WAIT_UNTIL] = BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME;
118 bot_cmd_string[BOT_CMD_RESETQUEUE] = "resetqueue";
119 bot_cmd_parm_type[BOT_CMD_RESETQUEUE] = BOT_CMD_PARAMETER_NONE;
121 bot_cmds_initialized = TRUE;
124 // Returns first bot with matching name
125 entity find_bot_by_name(string name)
129 bot = findchainflags(flags, FL_CLIENT);
132 if(clienttype(bot) == CLIENTTYPE_BOT)
133 if(bot.netname==name)
142 // Returns a bot by number on list
143 entity find_bot_by_number(float number)
148 bot = findchainflags(flags, FL_CLIENT);
151 if(clienttype(bot) == CLIENTTYPE_BOT)
162 void bot_clearqueue()
164 entity head, newhead;
166 head = findchainfloat(is_bot_cmd, TRUE);
171 newhead = head.chain;
179 self.bot_cmd_queue_index = 0;
180 self.bot_cmd_execution_index = 0;
183 entity bot_spawncmd(entity bot, float type)
187 bot.bot_cmd_queue_index++;
191 cmd.is_bot_cmd = TRUE;
192 cmd.bot_cmd_type = type;
193 cmd.bot_cmd_index = bot.bot_cmd_queue_index;
195 if(bot.bot_cmd_newest)
196 bot.bot_cmd_newest.bot_cmd_next = cmd;
197 bot.bot_cmd_newest = cmd;
202 void bot_debugcmd(entity cmd)
204 print(strcat("Owner: ",cmd.owner.netname, "\n"));
205 print(strcat("Cmd Type: ",ftos(cmd.bot_cmd_type), "\n"));
206 print(strcat("Cmd Index: ",ftos(cmd.bot_cmd_index), "\n"));
208 print(strcat("Param Float: ",ftos(cmd.bot_cmd_parm_float), "\n"));
209 print(strcat("Param String: ",cmd.bot_cmd_parm_string, "\n"));
210 print(strcat("Param Vector: ",vtos(cmd.bot_cmd_parm_vector), "\n"));
212 print(strcat("Bot queue index: ", ftos(cmd.owner.bot_cmd_queue_index), "\n"));
213 print(strcat("Bot execution index: ", ftos(cmd.owner.bot_cmd_execution_index), "\n\n"));
216 void bot_queuecommand(entity bot, string cmdstring, string parm)
219 local float cmd_parm_type, i;
224 if(!bot_cmds_initialized)
227 for(i=1;i<BOT_CMD_COUNTER;++i)
229 if(bot_cmd_string[i]!=cmdstring)
232 cmd_parm_type = bot_cmd_parm_type[i];
234 if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
236 print("ERROR: A parameter is required for this command\n");
240 // Load command into queue
241 cmd = bot_spawncmd(bot, i);
244 switch(cmd_parm_type)
246 case BOT_CMD_PARAMETER_FLOAT:
247 cmd.bot_cmd_parm_float = stof(parm);
249 case BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME:
250 cmd.bot_cmd_parm_float = stof(parm) + time;
252 case BOT_CMD_PARAMETER_STRING:
253 cmd.bot_cmd_parm_string = strzone(parm);
255 case BOT_CMD_PARAMETER_VECTOR:
256 cmd.bot_cmd_parm_vector = stov(parm);
263 print("ERROR: No such command\n");
266 void bot_cmdhelp(string scmd)
268 local float i, ntype;
271 if(!bot_cmds_initialized)
274 for(i=1;i<BOT_CMD_COUNTER;++i)
276 if(bot_cmd_string[i]!=scmd)
279 ntype = bot_cmd_parm_type[i];
283 case BOT_CMD_PARAMETER_FLOAT:
284 case BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME:
285 stype = "float number";
287 case BOT_CMD_PARAMETER_STRING:
290 case BOT_CMD_PARAMETER_VECTOR:
298 print(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
300 print("Description: ");
304 print("Stops the bot completely. Any command other than 'continue' will be ignored.");
306 case BOT_CMD_CONTINUE:
307 print("Disable paused status");
310 print("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
312 case BOT_CMD_WAIT_UNTIL:
313 print("Pause command parsing and bot ai until time is N from NOW (when the command is added). Pressed key will remain pressed");
316 print("Look to the right or left N degrees. For turning to the left use positive numbers.");
319 print("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
321 case BOT_CMD_RESETGOAL:
322 print("Resets the goal stack");
325 print("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
328 print("Perform simple conditional execution.\n");
330 print(" sv_cmd .. if \"condition\"\n");
331 print(" sv_cmd .. <instruction if true>\n");
332 print(" sv_cmd .. <instruction if true>\n");
333 print(" sv_cmd .. else\n");
334 print(" sv_cmd .. <instruction if false>\n");
335 print(" sv_cmd .. <instruction if false>\n");
336 print(" sv_cmd .. fi\n");
337 print("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
338 print(" Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
339 print("Fields: health, speed, flagcarrier\n");
340 print("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
342 case BOT_CMD_RESETAIM:
343 print("Points the aim to the coordinates x,y 0,0");
346 print("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
347 print("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
348 print("Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
349 print(" aim \"0 90 2\" // Will gradually look to the sky in the next two seconds");
351 case BOT_CMD_PRESSKEY:
352 print("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
353 print("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
354 print("Note: The script will not return the control to the bot ai until all keys are released");
356 case BOT_CMD_RELEASEKEY:
357 print("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
360 print("This command has no description yet.");
367 void bot_list_commands()
372 if(!bot_cmds_initialized)
375 print("List of all available commands:\n");
376 print(" Command\t\t\t\tParameter Type\n");
378 for(i=1;i<BOT_CMD_COUNTER;++i)
380 switch(bot_cmd_parm_type[i])
382 case BOT_CMD_PARAMETER_FLOAT:
383 case BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME:
384 ptype = "float number";
386 case BOT_CMD_PARAMETER_STRING:
389 case BOT_CMD_PARAMETER_VECTOR:
396 print(strcat(" ",bot_cmd_string[i],"\t\t\t\t<",ptype,"> \n"));
401 .float bot_exec_status;
403 #define BOT_EXEC_STATUS_IDLE 0
404 #define BOT_EXEC_STATUS_PAUSED 1
405 #define BOT_EXEC_STATUS_WAITING 2
407 #define CMD_STATUS_EXECUTING 0
408 #define CMD_STATUS_FINISHED 1
409 #define CMD_STATUS_ERROR 2
413 clientcommand(self,bot_cmd.bot_cmd_parm_string);
414 return CMD_STATUS_FINISHED;
417 float bot_cmd_impulse()
419 self.impulse = bot_cmd.bot_cmd_parm_float;
420 return CMD_STATUS_FINISHED;
423 float bot_cmd_continue()
425 self.bot_exec_status &~= BOT_EXEC_STATUS_PAUSED;
426 return CMD_STATUS_FINISHED;
429 .float bot_cmd_wait_time;
432 if(self.bot_exec_status & BOT_EXEC_STATUS_WAITING)
434 if(time>=self.bot_cmd_wait_time)
436 self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
437 return CMD_STATUS_FINISHED;
440 return CMD_STATUS_EXECUTING;
443 self.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
444 self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
445 return CMD_STATUS_EXECUTING;
448 float bot_cmd_wait_until()
450 if(time < bot_cmd.bot_cmd_parm_float)
452 self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
453 return CMD_STATUS_EXECUTING;
455 self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
456 return CMD_STATUS_FINISHED;
461 self.v_angle_y = self.v_angle_y + bot_cmd.bot_cmd_parm_float;
462 self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
463 return CMD_STATUS_FINISHED;
466 float bot_cmd_select_weapon()
470 id = bot_cmd.bot_cmd_parm_float;
472 if(id < WEP_FIRST || id > WEP_LAST)
473 return CMD_STATUS_ERROR;
475 if(client_hasweapon(self, id, TRUE, FALSE))
476 self.switchweapon = id;
478 return CMD_STATUS_FINISHED;
481 .float bot_cmd_condition_status;
483 #define CMD_CONDITION_NONE 0
484 #define CMD_CONDITION_TRUE 1
485 #define CMD_CONDITION_FALSE 2
486 #define CMD_CONDITION_TRUE_BLOCK 4
487 #define CMD_CONDITION_FALSE_BLOCK 8
489 float bot_cmd_eval(string expr)
491 // Search for numbers
492 if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
498 if(substring(expr, 0, 5)=="cvar.")
500 return cvar(substring(expr, 5, strlen(expr)));
509 return vlen(self.velocity);
511 return ((self.flagcarried!=world));
514 print(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
520 local string expr, val_a, val_b;
523 if(self.bot_cmd_condition_status != CMD_CONDITION_NONE)
525 // Only one "if" block is allowed at time
526 print("ERROR: Only one conditional block can be processed at time");
528 return CMD_STATUS_ERROR;
531 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE_BLOCK;
533 // search for operators
534 expr = bot_cmd.bot_cmd_parm_string;
536 cmpofs = strstrofs(expr,"=",0);
540 val_a = substring(expr,0,cmpofs);
541 val_b = substring(expr,cmpofs+1,strlen(expr));
543 if(bot_cmd_eval(val_a)==bot_cmd_eval(val_b))
544 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
546 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
548 return CMD_STATUS_FINISHED;
551 cmpofs = strstrofs(expr,">",0);
555 val_a = substring(expr,0,cmpofs);
556 val_b = substring(expr,cmpofs+1,strlen(expr));
558 if(bot_cmd_eval(val_a)>bot_cmd_eval(val_b))
559 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
561 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
563 return CMD_STATUS_FINISHED;
566 cmpofs = strstrofs(expr,"<",0);
570 val_a = substring(expr,0,cmpofs);
571 val_b = substring(expr,cmpofs+1,strlen(expr));
573 if(bot_cmd_eval(val_a)<bot_cmd_eval(val_b))
574 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
576 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
578 return CMD_STATUS_FINISHED;
581 if(bot_cmd_eval(expr))
582 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
584 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
586 return CMD_STATUS_FINISHED;
591 self.bot_cmd_condition_status &~= CMD_CONDITION_TRUE_BLOCK;
592 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE_BLOCK;
593 return CMD_STATUS_FINISHED;
598 self.bot_cmd_condition_status = CMD_CONDITION_NONE;
599 return CMD_STATUS_FINISHED;
602 float bot_cmd_resetaim()
604 self.v_angle = '0 0 0';
605 return CMD_STATUS_FINISHED;
608 .float bot_cmd_aim_begintime;
609 .float bot_cmd_aim_endtime;
610 .vector bot_cmd_aim_begin;
611 .vector bot_cmd_aim_end;
616 if(self.bot_cmd_aim_endtime)
618 local float progress;
620 progress = min(1 - (self.bot_cmd_aim_endtime - time) / (self.bot_cmd_aim_endtime - self.bot_cmd_aim_begintime),1);
621 self.v_angle = self.bot_cmd_aim_begin + ((self.bot_cmd_aim_end - self.bot_cmd_aim_begin) * progress);
623 if(time>=self.bot_cmd_aim_endtime)
625 self.bot_cmd_aim_endtime = 0;
626 return CMD_STATUS_FINISHED;
629 return CMD_STATUS_EXECUTING;
632 // New aiming direction
634 local float tokens, step;
636 parms = bot_cmd.bot_cmd_parm_string;
638 tokens = tokenizebyseparator(parms, " ");
642 self.v_angle_x -= stof(argv(1));
643 self.v_angle_y += stof(argv(0));
644 return CMD_STATUS_FINISHED;
647 if(tokens<1||tokens>3)
648 return CMD_STATUS_ERROR;
650 step = stof(argv(2));
652 self.bot_cmd_aim_begin = self.v_angle;
654 self.bot_cmd_aim_end_x = self.v_angle_x - stof(argv(1));
655 self.bot_cmd_aim_end_y = self.v_angle_y + stof(argv(0));
656 self.bot_cmd_aim_end_z = 0;
658 self.bot_cmd_aim_begintime = time;
659 self.bot_cmd_aim_endtime = time + step;
661 return CMD_STATUS_EXECUTING;
666 #define BOT_CMD_KEY_NONE 0
667 #define BOT_CMD_KEY_FORWARD 1
668 #define BOT_CMD_KEY_BACKWARD 2
669 #define BOT_CMD_KEY_RIGHT 4
670 #define BOT_CMD_KEY_LEFT 8
671 #define BOT_CMD_KEY_JUMP 16
672 #define BOT_CMD_KEY_ATTACK1 32
673 #define BOT_CMD_KEY_ATTACK2 64
674 #define BOT_CMD_KEY_USE 128
675 #define BOT_CMD_KEY_HOOK 256
676 #define BOT_CMD_KEY_CROUCH 512
678 float bot_presskeys()
680 self.movement = '0 0 0';
682 if(self.bot_cmd_keys == BOT_CMD_KEY_NONE)
685 if(self.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
686 self.movement_x = cvar("sv_maxspeed");
687 else if(self.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
688 self.movement_x = -cvar("sv_maxspeed");
690 if(self.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
691 self.movement_y = cvar("sv_maxspeed");
692 else if(self.bot_cmd_keys & BOT_CMD_KEY_LEFT)
693 self.movement_y = -cvar("sv_maxspeed");
695 if(self.bot_cmd_keys & BOT_CMD_KEY_JUMP)
696 self.BUTTON_JUMP = TRUE;
698 if(self.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
699 self.BUTTON_CROUCH = TRUE;
701 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
702 self.BUTTON_ATCK = TRUE;
704 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
705 self.BUTTON_ATCK2 = TRUE;
707 if(self.bot_cmd_keys & BOT_CMD_KEY_USE)
708 self.BUTTON_USE = TRUE;
714 float bot_cmd_keypress_handler(string key, float enabled)
720 self.bot_cmd_keys = power2of(20) - 1; // >:)
722 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
726 self.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
727 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
730 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
735 self.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
736 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
739 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
744 self.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
745 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
748 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
753 self.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
754 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
757 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
761 self.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
763 self.bot_cmd_keys &~= BOT_CMD_KEY_JUMP;
767 self.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
769 self.bot_cmd_keys &~= BOT_CMD_KEY_CROUCH;
773 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
775 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK1;
779 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
781 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK2;
785 self.bot_cmd_keys |= BOT_CMD_KEY_USE;
787 self.bot_cmd_keys &~= BOT_CMD_KEY_USE;
793 return CMD_STATUS_FINISHED;
796 float bot_cmd_presskey()
800 key = bot_cmd.bot_cmd_parm_string;
802 bot_cmd_keypress_handler(key,TRUE);
804 return CMD_STATUS_FINISHED;
807 float bot_cmd_releasekey()
811 key = bot_cmd.bot_cmd_parm_string;
813 return bot_cmd_keypress_handler(key,FALSE);
816 float bot_cmd_pause()
821 self.BUTTON_ATCK = 0;
822 self.BUTTON_JUMP = 0;
823 self.BUTTON_HOOK = 0;
824 self.BUTTON_CHAT = 0;
825 self.BUTTON_ATCK2 = 0;
826 self.BUTTON_CROUCH = 0;
828 self.movement = '0 0 0';
829 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
831 self.bot_exec_status = self.bot_exec_status | BOT_EXEC_STATUS_PAUSED;
832 return CMD_STATUS_FINISHED;
835 float bot_cmd_moveto()
837 return self.cmd_moveto(bot_cmd.bot_cmd_parm_vector);
840 float bot_cmd_resetgoal()
842 return self.cmd_resetgoal();
845 void bot_command_executed(float rm)
851 self.bot_cmd_execution_index++;
855 if(bot_cmd_parm_type[cmd.bot_cmd_type]==BOT_CMD_PARAMETER_STRING)
857 strunzone(cmd.bot_cmd_parm_string);
859 self.bot_cmd_next = cmd.bot_cmd_next;
860 if(cmd == self.bot_cmd_newest)
861 self.bot_cmd_newest = world;
866 cmd.bot_cmd_execution_counter++;
869 void bot_setcurrentcommand()
875 if(!self.bot_cmd_newest) // no command in the queue?
878 if(self.bot_cmd_execution_index==0)
879 self.bot_cmd_execution_index=1;
881 cmd = self.bot_cmd_next;
883 if(cmd.owner == self)
884 if(cmd.bot_cmd_index == self.bot_cmd_execution_index)
893 print("next bot cmd not set\n");
896 if(cmd && cmd.owner != self)
898 print("next bot cmd has wrong owner ", etos(cmd.owner), " for ", etos(self), "\n");
901 if(cmd && cmd.owner == self && cmd.bot_cmd_index != self.bot_cmd_execution_index)
903 print("next bot cmd has wrong index ", ftos(cmd.bot_cmd_execution_index), " for ", ftos(self.bot_cmd_execution_index), "\n");
907 for (cmd = findchainfloat(bot_cmd_index, self.bot_cmd_execution_index); cmd; cmd = cmd.chain)
912 self.bot_cmd_next = cmd;
913 //print(etos(self), " probably a jump...\n");
919 // This function should be (the only) called directly from the bot ai loop
920 // It maps commands to functions and deal with complex interactions between commands and execution states
921 // NOTE: Of course you need to include your commands here too :)
922 float bot_execute_commands()
924 local float status, ispressingkey;
928 if(self.deadflag!=DEAD_NO)
932 bot_setcurrentcommand();
934 // Keep pressing keys raised by the "presskey" command
935 ispressingkey = bot_presskeys();
938 return ispressingkey;
940 // Ignore all commands except continue when the bot is paused
941 if(self.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
942 if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
944 if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
946 bot_command_executed(TRUE);
947 print( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
953 if not(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE)
954 if(self.bot_cmd_condition_status & CMD_CONDITION_TRUE && self.bot_cmd_condition_status & CMD_CONDITION_FALSE_BLOCK)
956 bot_command_executed(TRUE);
959 else if(self.bot_cmd_condition_status & CMD_CONDITION_FALSE && self.bot_cmd_condition_status & CMD_CONDITION_TRUE_BLOCK)
961 bot_command_executed(TRUE);
965 // Map commands to functions
966 switch(bot_cmd.bot_cmd_type)
969 return ispressingkey;
972 status = bot_cmd_pause();
974 case BOT_CMD_CONTINUE:
975 status = bot_cmd_continue();
978 status = bot_cmd_wait();
980 case BOT_CMD_WAIT_UNTIL:
981 status = bot_cmd_wait_until();
984 status = bot_cmd_turn();
987 status = bot_cmd_moveto();
989 case BOT_CMD_RESETGOAL:
990 status = bot_cmd_resetgoal();
993 status = bot_cmd_cc();
996 status = bot_cmd_if();
999 status = bot_cmd_else();
1002 status = bot_cmd_fi();
1004 case BOT_CMD_RESETAIM:
1005 status = bot_cmd_resetaim();
1008 status = bot_cmd_aim();
1010 case BOT_CMD_PRESSKEY:
1011 status = bot_cmd_presskey();
1013 case BOT_CMD_RELEASEKEY:
1014 status = bot_cmd_releasekey();
1016 case BOT_CMD_SELECTWEAPON:
1017 status = bot_cmd_select_weapon();
1019 case BOT_CMD_IMPULSE:
1020 status = bot_cmd_impulse();
1022 case BOT_CMD_RESETQUEUE:
1024 status = CMD_STATUS_FINISHED;
1027 print(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
1031 if (status==CMD_STATUS_ERROR)
1032 print(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
1034 // Move execution pointer
1035 if(status==CMD_STATUS_EXECUTING)
1041 if(cvar("g_debug_bot_commands"))
1045 switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
1047 case BOT_CMD_PARAMETER_FLOAT:
1048 case BOT_CMD_PARAMETER_FLOAT_RELATIVE_TO_TIME:
1049 parms = ftos(bot_cmd.bot_cmd_parm_float);
1051 case BOT_CMD_PARAMETER_STRING:
1052 parms = bot_cmd.bot_cmd_parm_string;
1054 case BOT_CMD_PARAMETER_VECTOR:
1055 parms = vtos(bot_cmd.bot_cmd_parm_vector);
1061 clientcommand(self,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
1064 bot_command_executed(TRUE);
1067 if(status>-1) // Always true, just to fix a compiler warning