1 // NOTE: New commands should be added here. Do not forget to update BOT_CMD_COUNTER
\r
2 #define BOT_CMD_NULL 0
\r
3 #define BOT_CMD_PAUSE 1
\r
4 #define BOT_CMD_CONTINUE 2
\r
5 #define BOT_CMD_WAIT 3
\r
6 #define BOT_CMD_TURN 4
\r
7 #define BOT_CMD_MOVETO 5 // Not implemented yet
\r
8 #define BOT_CMD_RESETGOAL 6 // Not implemented yet
\r
10 #define BOT_CMD_IF 8
\r
11 #define BOT_CMD_ELSE 9
\r
12 #define BOT_CMD_FI 10
\r
13 #define BOT_CMD_RESETAIM 11
\r
14 #define BOT_CMD_AIM 12
\r
15 #define BOT_CMD_PRESSKEY 13
\r
16 #define BOT_CMD_RELEASEKEY 14
\r
17 #define BOT_CMD_SELECTWEAPON 15
\r
18 #define BOT_CMD_IMPULSE 16
\r
19 #define BOT_CMD_WHILE 17 // Not implemented yet
\r
20 #define BOT_CMD_WEND 18 // Not implemented yet
\r
21 #define BOT_CMD_CHASE 19 // Not implemented yet
\r
22 #define BOT_CMD_COUNTER 17
\r
24 // NOTE: Following commands should be implemented on the bot ai
\r
25 // If a new command should be handled by the target ai(s) please declare it here
\r
26 .float(vector) cmd_moveto;
\r
27 .float() cmd_resetgoal;
\r
30 #define BOT_CMD_PARAMETER_NONE 0
\r
31 #define BOT_CMD_PARAMETER_FLOAT 1
\r
32 #define BOT_CMD_PARAMETER_STRING 2
\r
33 #define BOT_CMD_PARAMETER_VECTOR 3
\r
35 float bot_cmds_initialized;
\r
36 float bot_cmd_parm_type[BOT_CMD_COUNTER];
\r
37 string bot_cmd_string[BOT_CMD_COUNTER];
\r
39 // Bots command queue
\r
40 entity bot_cmd; // Current command
\r
42 .float is_bot_cmd; // Tells if the entity is a bot command
\r
43 .float bot_cmd_index; // Position of the command in the queue
\r
44 .float bot_cmd_type; // If of command (see the BOT_CMD_* defines)
\r
45 .float bot_cmd_parm_float; // Field to store a float parameter
\r
46 .string bot_cmd_parm_string; // Field to store a string parameter
\r
47 .vector bot_cmd_parm_vector; // Field to store a vector parameter
\r
48 .float bot_cmd_execution_counter; // How many times this command on the queue was executed
\r
50 .float bot_cmd_execution_index; // Position in the queue of the command to be executed
\r
51 .float bot_cmd_queue_index; // Position of the last command in the queue
\r
53 // Initialize global commands list
\r
54 // NOTE: New commands should be initialized here
\r
55 void bot_commands_init()
\r
57 bot_cmd_string[BOT_CMD_NULL] = "";
\r
58 bot_cmd_parm_type[BOT_CMD_NULL] = BOT_CMD_PARAMETER_NONE;
\r
60 bot_cmd_string[BOT_CMD_PAUSE] = "pause";
\r
61 bot_cmd_parm_type[BOT_CMD_PAUSE] = BOT_CMD_PARAMETER_NONE;
\r
63 bot_cmd_string[BOT_CMD_CONTINUE] = "continue";
\r
64 bot_cmd_parm_type[BOT_CMD_CONTINUE] = BOT_CMD_PARAMETER_NONE;
\r
66 bot_cmd_string[BOT_CMD_WAIT] = "wait";
\r
67 bot_cmd_parm_type[BOT_CMD_WAIT] = BOT_CMD_PARAMETER_FLOAT;
\r
69 bot_cmd_string[BOT_CMD_TURN] = "turn";
\r
70 bot_cmd_parm_type[BOT_CMD_TURN] = BOT_CMD_PARAMETER_FLOAT;
\r
72 bot_cmd_string[BOT_CMD_MOVETO] = "moveto";
\r
73 bot_cmd_parm_type[BOT_CMD_MOVETO] = BOT_CMD_PARAMETER_VECTOR;
\r
75 bot_cmd_string[BOT_CMD_RESETGOAL] = "resetgoal";
\r
76 bot_cmd_parm_type[BOT_CMD_RESETGOAL] = BOT_CMD_PARAMETER_NONE;
\r
78 bot_cmd_string[BOT_CMD_CC] = "cc";
\r
79 bot_cmd_parm_type[BOT_CMD_CC] = BOT_CMD_PARAMETER_STRING;
\r
81 bot_cmd_string[BOT_CMD_IF] = "if";
\r
82 bot_cmd_parm_type[BOT_CMD_IF] = BOT_CMD_PARAMETER_STRING;
\r
84 bot_cmd_string[BOT_CMD_ELSE] = "else";
\r
85 bot_cmd_parm_type[BOT_CMD_ELSE] = BOT_CMD_PARAMETER_NONE;
\r
87 bot_cmd_string[BOT_CMD_FI] = "fi";
\r
88 bot_cmd_parm_type[BOT_CMD_FI] = BOT_CMD_PARAMETER_NONE;
\r
90 bot_cmd_string[BOT_CMD_RESETAIM] = "resetaim";
\r
91 bot_cmd_parm_type[BOT_CMD_RESETAIM] = BOT_CMD_PARAMETER_NONE;
\r
93 bot_cmd_string[BOT_CMD_AIM] = "aim";
\r
94 bot_cmd_parm_type[BOT_CMD_AIM] = BOT_CMD_PARAMETER_STRING;
\r
96 bot_cmd_string[BOT_CMD_PRESSKEY] = "presskey";
\r
97 bot_cmd_parm_type[BOT_CMD_PRESSKEY] = BOT_CMD_PARAMETER_STRING;
\r
99 bot_cmd_string[BOT_CMD_RELEASEKEY] = "releasekey";
\r
100 bot_cmd_parm_type[BOT_CMD_RELEASEKEY] = BOT_CMD_PARAMETER_STRING;
\r
102 bot_cmd_string[BOT_CMD_SELECTWEAPON] = "selectweapon";
\r
103 bot_cmd_parm_type[BOT_CMD_SELECTWEAPON] = BOT_CMD_PARAMETER_FLOAT;
\r
105 bot_cmd_string[BOT_CMD_IMPULSE] = "impulse";
\r
106 bot_cmd_parm_type[BOT_CMD_IMPULSE] = BOT_CMD_PARAMETER_FLOAT;
\r
108 bot_cmds_initialized = TRUE;
\r
111 // Returns first bot with matching name
\r
112 entity find_bot_by_name(string name)
\r
116 bot = findchainflags(flags, FL_CLIENT);
\r
119 if(clienttype(bot) == CLIENTTYPE_BOT)
\r
120 if(bot.netname==name)
\r
129 // Returns a bot by number on list
\r
130 entity find_bot_by_number(float number)
\r
135 bot = findchainflags(flags, FL_CLIENT);
\r
138 if(clienttype(bot) == CLIENTTYPE_BOT)
\r
149 void bot_clearqueue()
\r
151 entity head, newhead;
\r
153 head = findchainfloat(is_bot_cmd, TRUE);
\r
158 newhead = head.chain;
\r
160 if(head.owner==self)
\r
166 self.bot_cmd_queue_index = 0;
\r
167 self.bot_cmd_execution_index = 0;
\r
170 entity bot_spawncmd(entity bot, float type)
\r
174 bot.bot_cmd_queue_index++;
\r
178 cmd.is_bot_cmd = TRUE;
\r
179 cmd.bot_cmd_type = type;
\r
180 cmd.bot_cmd_index = bot.bot_cmd_queue_index;
\r
185 void bot_debugcmd(entity cmd)
\r
187 print(strcat("Owner: ",cmd.owner.netname, "\n"));
\r
188 print(strcat("Cmd Type: ",ftos(cmd.bot_cmd_type), "\n"));
\r
189 print(strcat("Cmd Index: ",ftos(cmd.bot_cmd_index), "\n"));
\r
191 print(strcat("Param Float: ",ftos(cmd.bot_cmd_parm_float), "\n"));
\r
192 print(strcat("Param String: ",cmd.bot_cmd_parm_string, "\n"));
\r
193 print(strcat("Param Vector: ",vtos(cmd.bot_cmd_parm_vector), "\n"));
\r
195 print(strcat("Bot queue index: ", ftos(cmd.owner.bot_cmd_queue_index), "\n"));
\r
196 print(strcat("Bot execution index: ", ftos(cmd.owner.bot_cmd_execution_index), "\n\n"));
\r
199 void bot_queuecommand(entity bot, string cmdstring, string parm)
\r
202 local float cmd_parm_type, i;
\r
207 if(!bot_cmds_initialized)
\r
208 bot_commands_init();
\r
210 for(i=1;i<BOT_CMD_COUNTER;++i)
\r
212 if(bot_cmd_string[i]!=cmdstring)
\r
215 cmd_parm_type = bot_cmd_parm_type[i];
\r
217 if(cmd_parm_type!=BOT_CMD_PARAMETER_NONE&&parm=="")
\r
219 print("ERROR: A parameter is required for this command\n");
\r
223 // Load command into queue
\r
224 cmd = bot_spawncmd(bot, i);
\r
226 // Attach parameter
\r
227 switch(cmd_parm_type)
\r
229 case BOT_CMD_PARAMETER_FLOAT:
\r
230 cmd.bot_cmd_parm_float = stof(parm);
\r
232 case BOT_CMD_PARAMETER_STRING:
\r
233 cmd.bot_cmd_parm_string = strzone(parm);
\r
235 case BOT_CMD_PARAMETER_VECTOR:
\r
236 cmd.bot_cmd_parm_vector = stov(parm);
\r
243 print("ERROR: No such command");
\r
246 void bot_cmdhelp(string scmd)
\r
248 local float i, ntype;
\r
249 local string stype;
\r
251 if(!bot_cmds_initialized)
\r
252 bot_commands_init();
\r
254 for(i=1;i<BOT_CMD_COUNTER;++i)
\r
256 if(bot_cmd_string[i]!=scmd)
\r
259 ntype = bot_cmd_parm_type[i];
\r
263 case BOT_CMD_PARAMETER_FLOAT:
\r
264 stype = "float number";
\r
266 case BOT_CMD_PARAMETER_STRING:
\r
269 case BOT_CMD_PARAMETER_VECTOR:
\r
277 print(strcat("Command: ",bot_cmd_string[i],"\nParameter: <",stype,"> \n"));
\r
279 print("Description: ");
\r
282 case BOT_CMD_PAUSE:
\r
283 print("Stops the bot completely. Any command other than 'continue' will be ignored.");
\r
285 case BOT_CMD_CONTINUE:
\r
286 print("Disable paused status");
\r
289 print("Pause command parsing and bot ai for N seconds. Pressed key will remain pressed");
\r
292 print("Look to the right or left N degrees. For turning to the left use positive numbers.");
\r
295 print("Walk to an specific coordinate on the map. Usage: moveto \"x y z\"");
\r
297 case BOT_CMD_RESETGOAL:
298 print("Resets the goal stack");
\r
301 print("Execute client command. Examples: cc \"say something\"; cc god; cc \"name newnickname\"; cc kill;");
\r
304 print("Perform simple conditional execution.\n");
\r
305 print("Syntax: \n");
\r
306 print(" sv_cmd .. if \"condition\"\n");
\r
307 print(" sv_cmd .. <instruction if true>\n");
\r
308 print(" sv_cmd .. <instruction if true>\n");
\r
309 print(" sv_cmd .. else\n");
\r
310 print(" sv_cmd .. <instruction if false>\n");
\r
311 print(" sv_cmd .. <instruction if false>\n");
\r
312 print(" sv_cmd .. fi\n");
\r
313 print("Conditions: a=b, a>b, a<b, a\t\t(spaces not allowed)\n");
\r
314 print(" Values in conditions can be numbers, cvars in the form cvar.cvar_string or special fields\n");
\r
315 print("Fields: health, speed, flagcarrier\n");
\r
316 print("Examples: if health>50; if health>cvar.g_balance_laser_primary_damage; if flagcarrier;");
\r
318 case BOT_CMD_RESETAIM:
\r
319 print("Points the aim to the coordinates x,y 0,0");
\r
322 print("Move the aim x/y (horizontal/vertical) degrees relatives to the bot\n");
\r
323 print("There is a 3rd optional parameter telling in how many seconds the aim has to reach the new position\n");
\r
324 print("Examples: aim \"90 0\" // Turn 90 degrees inmediately (positive numbers move to the left/up)\n");
\r
325 print(" aim \"0 90 2\" // Will gradually look to the sky in the next two seconds");
\r
327 case BOT_CMD_PRESSKEY:
\r
328 print("Press one of the following keys: forward, backward, left, right, jump, crouch, attack1, attack2, use\n");
\r
329 print("Multiple keys can be pressed at time (with many presskey calls) and it will remain pressed until the command \"releasekey\" is called");
\r
330 print("Note: The script will not return the control to the bot ai until all keys are released");
\r
332 case BOT_CMD_RELEASEKEY:
\r
333 print("Release previoulsy used keys. Use the parameter \"all\" to release all keys");
\r
336 print("This command has no description yet.");
\r
343 void bot_list_commands()
\r
346 local string ptype;
\r
348 if(!bot_cmds_initialized)
\r
349 bot_commands_init();
\r
351 print("List of all available commands:\n");
\r
352 print(" Command\t\t\t\tParameter Type\n");
\r
354 for(i=1;i<BOT_CMD_COUNTER;++i)
\r
356 switch(bot_cmd_parm_type[i])
\r
358 case BOT_CMD_PARAMETER_FLOAT:
\r
359 ptype = "float number";
\r
361 case BOT_CMD_PARAMETER_STRING:
\r
364 case BOT_CMD_PARAMETER_VECTOR:
\r
371 print(strcat(" ",bot_cmd_string[i],"\t\t\t\t<",ptype,"> \n"));
\r
376 .float bot_exec_status;
\r
378 #define BOT_EXEC_STATUS_IDLE 0
\r
379 #define BOT_EXEC_STATUS_PAUSED 1
\r
380 #define BOT_EXEC_STATUS_WAITING 2
\r
382 #define CMD_STATUS_EXECUTING 0
\r
383 #define CMD_STATUS_FINISHED 1
\r
384 #define CMD_STATUS_ERROR 2
\r
388 clientcommand(self,bot_cmd.bot_cmd_parm_string);
\r
389 return CMD_STATUS_FINISHED;
\r
392 float bot_cmd_impulse()
\r
394 self.impulse = bot_cmd.bot_cmd_parm_float;
\r
395 return CMD_STATUS_FINISHED;
\r
398 float bot_cmd_continue()
\r
400 self.bot_exec_status &~= BOT_EXEC_STATUS_PAUSED;
\r
401 return CMD_STATUS_FINISHED;
\r
404 .float bot_cmd_wait_time;
\r
405 float bot_cmd_wait()
\r
407 if(self.bot_exec_status & BOT_EXEC_STATUS_WAITING)
\r
409 if(time>=self.bot_cmd_wait_time)
\r
411 self.bot_exec_status &~= BOT_EXEC_STATUS_WAITING;
\r
412 return CMD_STATUS_FINISHED;
\r
415 return CMD_STATUS_EXECUTING;
\r
418 self.bot_cmd_wait_time = time + bot_cmd.bot_cmd_parm_float;
\r
419 self.bot_exec_status |= BOT_EXEC_STATUS_WAITING;
\r
420 return CMD_STATUS_EXECUTING;
\r
423 float bot_cmd_turn()
\r
425 self.v_angle_y = self.v_angle_y + bot_cmd.bot_cmd_parm_float;
\r
426 self.v_angle_y = self.v_angle_y - floor(self.v_angle_y / 360) * 360;
\r
427 return CMD_STATUS_FINISHED;
\r
430 float bot_cmd_select_weapon()
\r
434 id = bot_cmd.bot_cmd_parm_float;
\r
436 if(id < WEP_FIRST || id > WEP_LAST)
\r
437 return CMD_STATUS_ERROR;
\r
439 if(client_hasweapon(self, id, TRUE, FALSE))
\r
440 self.switchweapon = id;
\r
442 return CMD_STATUS_FINISHED;
\r
445 .float bot_cmd_condition_status;
\r
447 #define CMD_CONDITION_NONE 0
\r
448 #define CMD_CONDITION_TRUE 1
\r
449 #define CMD_CONDITION_FALSE 2
\r
450 #define CMD_CONDITION_TRUE_BLOCK 4
\r
451 #define CMD_CONDITION_FALSE_BLOCK 8
\r
453 float bot_cmd_eval(string expr)
\r
455 // Search for numbers
\r
456 if(strstrofs("0123456789", substring(expr, 0, 1), 0) >= 0)
\r
461 // Search for cvars
\r
462 if(substring(expr, 0, 5)=="cvar.")
\r
464 return cvar(substring(expr, 5, strlen(expr)));
\r
467 // Search for fields
\r
471 return self.health;
\r
473 return vlen(self.velocity);
\r
474 case "flagcarrier":
\r
475 return ((self.flagcarried!=world));
\r
478 print(strcat("ERROR: Unable to convert the expression '",expr,"' into a numeric value\n"));
\r
484 local string expr, val_a, val_b;
\r
485 local float cmpofs;
\r
487 if(self.bot_cmd_condition_status != CMD_CONDITION_NONE)
\r
489 // Only one "if" block is allowed at time
\r
490 print("ERROR: Only one conditional block can be processed at time");
\r
492 return CMD_STATUS_ERROR;
\r
495 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE_BLOCK;
\r
497 // search for operators
\r
498 expr = bot_cmd.bot_cmd_parm_string;
\r
500 cmpofs = strstrofs(expr,"=",0);
\r
504 val_a = substring(expr,0,cmpofs);
\r
505 val_b = substring(expr,cmpofs+1,strlen(expr));
\r
507 if(bot_cmd_eval(val_a)==bot_cmd_eval(val_b))
\r
508 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
\r
510 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
\r
512 return CMD_STATUS_FINISHED;
\r
515 cmpofs = strstrofs(expr,">",0);
\r
519 val_a = substring(expr,0,cmpofs);
\r
520 val_b = substring(expr,cmpofs+1,strlen(expr));
\r
522 if(bot_cmd_eval(val_a)>bot_cmd_eval(val_b))
\r
523 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
\r
525 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
\r
527 return CMD_STATUS_FINISHED;
\r
530 cmpofs = strstrofs(expr,"<",0);
\r
534 val_a = substring(expr,0,cmpofs);
\r
535 val_b = substring(expr,cmpofs+1,strlen(expr));
\r
537 if(bot_cmd_eval(val_a)<bot_cmd_eval(val_b))
\r
538 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
\r
540 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
\r
542 return CMD_STATUS_FINISHED;
\r
545 if(bot_cmd_eval(expr))
\r
546 self.bot_cmd_condition_status |= CMD_CONDITION_TRUE;
\r
548 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE;
\r
550 return CMD_STATUS_FINISHED;
\r
553 float bot_cmd_else()
\r
555 self.bot_cmd_condition_status &~= CMD_CONDITION_TRUE_BLOCK;
\r
556 self.bot_cmd_condition_status |= CMD_CONDITION_FALSE_BLOCK;
\r
557 return CMD_STATUS_FINISHED;
\r
562 self.bot_cmd_condition_status = CMD_CONDITION_NONE;
\r
563 return CMD_STATUS_FINISHED;
\r
566 float bot_cmd_resetaim()
\r
568 self.v_angle = '0 0 0';
\r
569 return CMD_STATUS_FINISHED;
\r
572 .float bot_cmd_aim_begintime;
\r
573 .float bot_cmd_aim_endtime;
\r
574 .vector bot_cmd_aim_begin;
\r
575 .vector bot_cmd_aim_end;
\r
577 float bot_cmd_aim()
\r
579 // Current direction
\r
580 if(self.bot_cmd_aim_endtime)
\r
582 local float progress;
\r
584 progress = min(1 - (self.bot_cmd_aim_endtime - time) / (self.bot_cmd_aim_endtime - self.bot_cmd_aim_begintime),1);
\r
585 self.v_angle = self.bot_cmd_aim_begin + ((self.bot_cmd_aim_end - self.bot_cmd_aim_begin) * progress);
\r
587 if(time>=self.bot_cmd_aim_endtime)
\r
589 self.bot_cmd_aim_endtime = 0;
\r
590 return CMD_STATUS_FINISHED;
\r
593 return CMD_STATUS_EXECUTING;
\r
596 // New aiming direction
\r
597 local string parms;
\r
598 local float tokens, step;
\r
600 parms = bot_cmd.bot_cmd_parm_string;
\r
602 tokens = tokenizebyseparator(parms, " ");
\r
606 self.v_angle_x -= stof(argv(1));
\r
607 self.v_angle_y += stof(argv(0));
\r
608 return CMD_STATUS_FINISHED;
\r
611 if(tokens<1||tokens>3)
\r
612 return CMD_STATUS_ERROR;
\r
614 step = stof(argv(2));
\r
616 self.bot_cmd_aim_begin = self.v_angle;
\r
618 self.bot_cmd_aim_end_x = self.v_angle_x - stof(argv(1));
\r
619 self.bot_cmd_aim_end_y = self.v_angle_y + stof(argv(0));
\r
620 self.bot_cmd_aim_end_z = 0;
\r
622 self.bot_cmd_aim_begintime = time;
\r
623 self.bot_cmd_aim_endtime = time + step;
\r
625 return CMD_STATUS_EXECUTING;
\r
628 .float bot_cmd_keys;
\r
630 #define BOT_CMD_KEY_NONE 0
\r
631 #define BOT_CMD_KEY_FORWARD 1
\r
632 #define BOT_CMD_KEY_BACKWARD 2
\r
633 #define BOT_CMD_KEY_RIGHT 4
\r
634 #define BOT_CMD_KEY_LEFT 8
\r
635 #define BOT_CMD_KEY_JUMP 16
\r
636 #define BOT_CMD_KEY_ATTACK1 32
\r
637 #define BOT_CMD_KEY_ATTACK2 64
\r
638 #define BOT_CMD_KEY_USE 128
\r
639 #define BOT_CMD_KEY_HOOK 256
\r
640 #define BOT_CMD_KEY_CROUCH 512
\r
642 float bot_presskeys()
\r
644 self.movement = '0 0 0';
\r
646 if(self.bot_cmd_keys == BOT_CMD_KEY_NONE)
\r
649 if(self.bot_cmd_keys & BOT_CMD_KEY_FORWARD)
\r
650 self.movement_x = cvar("sv_maxspeed");
\r
651 else if(self.bot_cmd_keys & BOT_CMD_KEY_BACKWARD)
\r
652 self.movement_x = -cvar("sv_maxspeed");
\r
654 if(self.bot_cmd_keys & BOT_CMD_KEY_RIGHT)
\r
655 self.movement_y = cvar("sv_maxspeed");
\r
656 else if(self.bot_cmd_keys & BOT_CMD_KEY_LEFT)
\r
657 self.movement_y = -cvar("sv_maxspeed");
\r
659 if(self.bot_cmd_keys & BOT_CMD_KEY_JUMP)
\r
660 self.BUTTON_JUMP = TRUE;
\r
662 if(self.bot_cmd_keys & BOT_CMD_KEY_CROUCH)
\r
663 self.BUTTON_CROUCH = TRUE;
\r
665 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK1)
\r
666 self.BUTTON_ATCK = TRUE;
\r
668 if(self.bot_cmd_keys & BOT_CMD_KEY_ATTACK2)
\r
669 self.BUTTON_ATCK2 = TRUE;
\r
671 if(self.bot_cmd_keys & BOT_CMD_KEY_USE)
\r
672 self.BUTTON_USE = TRUE;
\r
678 float bot_cmd_keypress_handler(string key, float enabled)
\r
684 self.bot_cmd_keys = power2of(20) - 1; // >:)
\r
686 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
\r
690 self.bot_cmd_keys |= BOT_CMD_KEY_FORWARD;
\r
691 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
\r
694 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
\r
699 self.bot_cmd_keys |= BOT_CMD_KEY_BACKWARD;
\r
700 self.bot_cmd_keys &~= BOT_CMD_KEY_FORWARD;
\r
703 self.bot_cmd_keys &~= BOT_CMD_KEY_BACKWARD;
\r
708 self.bot_cmd_keys |= BOT_CMD_KEY_LEFT;
\r
709 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
\r
712 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
\r
717 self.bot_cmd_keys |= BOT_CMD_KEY_RIGHT;
\r
718 self.bot_cmd_keys &~= BOT_CMD_KEY_LEFT;
\r
721 self.bot_cmd_keys &~= BOT_CMD_KEY_RIGHT;
\r
725 self.bot_cmd_keys |= BOT_CMD_KEY_JUMP;
\r
727 self.bot_cmd_keys &~= BOT_CMD_KEY_JUMP;
\r
731 self.bot_cmd_keys |= BOT_CMD_KEY_CROUCH;
\r
733 self.bot_cmd_keys &~= BOT_CMD_KEY_CROUCH;
\r
737 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK1;
\r
739 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK1;
\r
743 self.bot_cmd_keys |= BOT_CMD_KEY_ATTACK2;
\r
745 self.bot_cmd_keys &~= BOT_CMD_KEY_ATTACK2;
\r
749 self.bot_cmd_keys |= BOT_CMD_KEY_USE;
\r
751 self.bot_cmd_keys &~= BOT_CMD_KEY_USE;
\r
757 return CMD_STATUS_FINISHED;
\r
760 float bot_cmd_presskey()
\r
764 key = bot_cmd.bot_cmd_parm_string;
\r
766 bot_cmd_keypress_handler(key,TRUE);
\r
768 return CMD_STATUS_FINISHED;
\r
771 float bot_cmd_releasekey()
\r
775 key = bot_cmd.bot_cmd_parm_string;
\r
777 return bot_cmd_keypress_handler(key,FALSE);
\r
780 float bot_cmd_pause()
\r
784 self.BUTTON_USE = 0;
\r
785 self.BUTTON_ATCK = 0;
\r
786 self.BUTTON_JUMP = 0;
\r
787 self.BUTTON_HOOK = 0;
\r
788 self.BUTTON_CHAT = 0;
\r
789 self.BUTTON_ATCK2 = 0;
\r
790 self.BUTTON_CROUCH = 0;
\r
792 self.movement = '0 0 0';
\r
793 self.bot_cmd_keys = BOT_CMD_KEY_NONE;
\r
795 self.bot_exec_status = self.bot_exec_status | BOT_EXEC_STATUS_PAUSED;
\r
796 return CMD_STATUS_FINISHED;
\r
799 float bot_cmd_moveto()
801 return self.cmd_moveto(bot_cmd.bot_cmd_parm_vector);
804 float bot_cmd_resetgoal()
806 return self.cmd_resetgoal();
809 void bot_command_executed(float rm)
\r
815 self.bot_cmd_execution_index++;
\r
819 if(bot_cmd_parm_type[cmd.bot_cmd_type]==BOT_CMD_PARAMETER_STRING)
\r
821 strunzone(cmd.bot_cmd_parm_string);
\r
827 cmd.bot_cmd_execution_counter++;
\r
830 void bot_setcurrentcommand()
\r
836 if(self.bot_cmd_execution_index==0)
\r
837 self.bot_cmd_execution_index=1;
\r
839 for (cmd = findchainfloat(bot_cmd_index, self.bot_cmd_execution_index); cmd; cmd = cmd.chain)
\r
841 if(cmd.owner==self)
\r
849 // This function should be (the only) called directly from the bot ai loop
\r
850 // It maps commands to functions and deal with complex interactions between commands and execution states
\r
851 // NOTE: Of course you need to include your commands here too :)
\r
852 float bot_execute_commands()
\r
854 local float status, ispressingkey;
\r
857 bot_setcurrentcommand();
\r
859 // Keep pressing keys raised by the "presskey" command
\r
860 ispressingkey = bot_presskeys();
\r
863 return ispressingkey;
\r
865 // Ignore all commands except continue when the bot is paused
\r
866 if(self.bot_exec_status & BOT_EXEC_STATUS_PAUSED)
\r
867 if(bot_cmd.bot_cmd_type!=BOT_CMD_CONTINUE)
\r
869 if(bot_cmd.bot_cmd_type!=BOT_CMD_NULL)
\r
871 bot_command_executed(TRUE);
\r
872 print( "WARNING: Commands are ignored while the bot is paused. Use the command 'continue' instead.\n");
\r
877 // Handle conditions
\r
878 if not(bot_cmd.bot_cmd_type==BOT_CMD_FI||bot_cmd.bot_cmd_type==BOT_CMD_ELSE)
\r
879 if(self.bot_cmd_condition_status & CMD_CONDITION_TRUE && self.bot_cmd_condition_status & CMD_CONDITION_FALSE_BLOCK)
\r
881 bot_command_executed(TRUE);
\r
884 else if(self.bot_cmd_condition_status & CMD_CONDITION_FALSE && self.bot_cmd_condition_status & CMD_CONDITION_TRUE_BLOCK)
\r
886 bot_command_executed(TRUE);
\r
890 // Map commands to functions
\r
891 switch(bot_cmd.bot_cmd_type)
\r
894 return ispressingkey;
\r
896 case BOT_CMD_PAUSE:
\r
897 status = bot_cmd_pause();
\r
899 case BOT_CMD_CONTINUE:
\r
900 status = bot_cmd_continue();
\r
903 status = bot_cmd_wait();
\r
906 status = bot_cmd_turn();
\r
908 case BOT_CMD_MOVETO:
\r
909 status = bot_cmd_moveto();
\r
911 case BOT_CMD_RESETGOAL:
\r
912 status = bot_cmd_resetgoal();
\r
915 status = bot_cmd_cc();
\r
918 status = bot_cmd_if();
\r
921 status = bot_cmd_else();
\r
924 status = bot_cmd_fi();
\r
926 case BOT_CMD_RESETAIM:
\r
927 status = bot_cmd_resetaim();
\r
930 status = bot_cmd_aim();
\r
932 case BOT_CMD_PRESSKEY:
\r
933 status = bot_cmd_presskey();
\r
935 case BOT_CMD_RELEASEKEY:
\r
936 status = bot_cmd_releasekey();
\r
938 case BOT_CMD_SELECTWEAPON:
\r
939 status = bot_cmd_select_weapon();
\r
941 case BOT_CMD_IMPULSE:
\r
942 status = bot_cmd_impulse();
\r
945 print(strcat("ERROR: Invalid command on queue with id '",ftos(bot_cmd.bot_cmd_type),"'\n"));
\r
949 if (status==CMD_STATUS_ERROR)
\r
950 print(strcat("ERROR: The command '",bot_cmd_string[bot_cmd.bot_cmd_type],"' returned an error status\n"));
\r
952 // Move execution pointer
\r
953 if not(status==CMD_STATUS_EXECUTING)
\r
955 if(cvar("g_debug_bot_commands"))
\r
957 local string parms;
\r
959 switch(bot_cmd_parm_type[bot_cmd.bot_cmd_type])
\r
961 case BOT_CMD_PARAMETER_FLOAT:
\r
962 parms = ftos(bot_cmd.bot_cmd_parm_float);
\r
964 case BOT_CMD_PARAMETER_STRING:
\r
965 parms = bot_cmd.bot_cmd_parm_string;
\r
967 case BOT_CMD_PARAMETER_VECTOR:
\r
968 parms = vtos(bot_cmd.bot_cmd_parm_vector);
\r
974 clientcommand(self,strcat("say ^7", bot_cmd_string[bot_cmd.bot_cmd_type]," ",parms,"\n"));
\r
977 bot_command_executed(TRUE);
\r