ai_vcmd.c (14355B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // 23 24 /***************************************************************************** 25 * name: ai_vcmd.c 26 * 27 * desc: Quake3 bot AI 28 * 29 * $Archive: /MissionPack/code/game/ai_vcmd.c $ 30 * 31 *****************************************************************************/ 32 33 #include "g_local.h" 34 #include "botlib.h" 35 #include "be_aas.h" 36 #include "be_ea.h" 37 #include "be_ai_char.h" 38 #include "be_ai_chat.h" 39 #include "be_ai_gen.h" 40 #include "be_ai_goal.h" 41 #include "be_ai_move.h" 42 #include "be_ai_weap.h" 43 // 44 #include "ai_main.h" 45 #include "ai_dmq3.h" 46 #include "ai_chat.h" 47 #include "ai_cmd.h" 48 #include "ai_dmnet.h" 49 #include "ai_team.h" 50 #include "ai_vcmd.h" 51 // 52 #include "chars.h" //characteristics 53 #include "inv.h" //indexes into the inventory 54 #include "syn.h" //synonyms 55 #include "match.h" //string matching types and vars 56 57 // for the voice chats 58 #include "../../ui/menudef.h" 59 60 61 typedef struct voiceCommand_s 62 { 63 char *cmd; 64 void (*func)(bot_state_t *bs, int client, int mode); 65 } voiceCommand_t; 66 67 /* 68 ================== 69 BotVoiceChat_GetFlag 70 ================== 71 */ 72 void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) { 73 // 74 if (gametype == GT_CTF) { 75 if (!ctf_redflag.areanum || !ctf_blueflag.areanum) 76 return; 77 } 78 #ifdef MISSIONPACK 79 else if (gametype == GT_1FCTF) { 80 if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum) 81 return; 82 } 83 #endif 84 else { 85 return; 86 } 87 // 88 bs->decisionmaker = client; 89 bs->ordered = qtrue; 90 bs->order_time = FloatTime(); 91 //set the time to send a message to the team mates 92 bs->teammessage_time = FloatTime() + 2 * random(); 93 //set the ltg type 94 bs->ltgtype = LTG_GETFLAG; 95 //set the team goal time 96 bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME; 97 // get an alternate route in ctf 98 if (gametype == GT_CTF) { 99 //get an alternative route goal towards the enemy base 100 BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs)); 101 } 102 // 103 BotSetTeamStatus(bs); 104 // remember last ordered task 105 BotRememberLastOrderedTask(bs); 106 #ifdef DEBUG 107 BotPrintTeamGoal(bs); 108 #endif //DEBUG 109 } 110 111 /* 112 ================== 113 BotVoiceChat_Offense 114 ================== 115 */ 116 void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) { 117 if ( gametype == GT_CTF 118 #ifdef MISSIONPACK 119 || gametype == GT_1FCTF 120 #endif 121 ) { 122 BotVoiceChat_GetFlag(bs, client, mode); 123 return; 124 } 125 #ifdef MISSIONPACK 126 if (gametype == GT_HARVESTER) { 127 // 128 bs->decisionmaker = client; 129 bs->ordered = qtrue; 130 bs->order_time = FloatTime(); 131 //set the time to send a message to the team mates 132 bs->teammessage_time = FloatTime() + 2 * random(); 133 //set the ltg type 134 bs->ltgtype = LTG_HARVEST; 135 //set the team goal time 136 bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME; 137 bs->harvestaway_time = 0; 138 // 139 BotSetTeamStatus(bs); 140 // remember last ordered task 141 BotRememberLastOrderedTask(bs); 142 } 143 else 144 #endif 145 { 146 // 147 bs->decisionmaker = client; 148 bs->ordered = qtrue; 149 bs->order_time = FloatTime(); 150 //set the time to send a message to the team mates 151 bs->teammessage_time = FloatTime() + 2 * random(); 152 //set the ltg type 153 bs->ltgtype = LTG_ATTACKENEMYBASE; 154 //set the team goal time 155 bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME; 156 bs->attackaway_time = 0; 157 // 158 BotSetTeamStatus(bs); 159 // remember last ordered task 160 BotRememberLastOrderedTask(bs); 161 } 162 #ifdef DEBUG 163 BotPrintTeamGoal(bs); 164 #endif //DEBUG 165 } 166 167 /* 168 ================== 169 BotVoiceChat_Defend 170 ================== 171 */ 172 void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) { 173 #ifdef MISSIONPACK 174 if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) { 175 // 176 switch(BotTeam(bs)) { 177 case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break; 178 case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break; 179 default: return; 180 } 181 } 182 else 183 #endif 184 if (gametype == GT_CTF 185 #ifdef MISSIONPACK 186 || gametype == GT_1FCTF 187 #endif 188 ) { 189 // 190 switch(BotTeam(bs)) { 191 case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break; 192 case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break; 193 default: return; 194 } 195 } 196 else { 197 return; 198 } 199 // 200 bs->decisionmaker = client; 201 bs->ordered = qtrue; 202 bs->order_time = FloatTime(); 203 //set the time to send a message to the team mates 204 bs->teammessage_time = FloatTime() + 2 * random(); 205 //set the ltg type 206 bs->ltgtype = LTG_DEFENDKEYAREA; 207 //get the team goal time 208 bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME; 209 //away from defending 210 bs->defendaway_time = 0; 211 // 212 BotSetTeamStatus(bs); 213 // remember last ordered task 214 BotRememberLastOrderedTask(bs); 215 #ifdef DEBUG 216 BotPrintTeamGoal(bs); 217 #endif //DEBUG 218 } 219 220 /* 221 ================== 222 BotVoiceChat_DefendFlag 223 ================== 224 */ 225 void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) { 226 BotVoiceChat_Defend(bs, client, mode); 227 } 228 229 /* 230 ================== 231 BotVoiceChat_Patrol 232 ================== 233 */ 234 void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) { 235 // 236 bs->decisionmaker = client; 237 // 238 bs->ltgtype = 0; 239 bs->lead_time = 0; 240 bs->lastgoal_ltgtype = 0; 241 // 242 BotAI_BotInitialChat(bs, "dismissed", NULL); 243 trap_BotEnterChat(bs->cs, client, CHAT_TELL); 244 BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL); 245 // 246 BotSetTeamStatus(bs); 247 #ifdef DEBUG 248 BotPrintTeamGoal(bs); 249 #endif //DEBUG 250 } 251 252 /* 253 ================== 254 BotVoiceChat_Camp 255 ================== 256 */ 257 void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) { 258 int areanum; 259 aas_entityinfo_t entinfo; 260 char netname[MAX_NETNAME]; 261 262 // 263 bs->teamgoal.entitynum = -1; 264 BotEntityInfo(client, &entinfo); 265 //if info is valid (in PVS) 266 if (entinfo.valid) { 267 areanum = BotPointAreaNum(entinfo.origin); 268 if (areanum) { // && trap_AAS_AreaReachability(areanum)) { 269 //NOTE: just assume the bot knows where the person is 270 //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) { 271 bs->teamgoal.entitynum = client; 272 bs->teamgoal.areanum = areanum; 273 VectorCopy(entinfo.origin, bs->teamgoal.origin); 274 VectorSet(bs->teamgoal.mins, -8, -8, -8); 275 VectorSet(bs->teamgoal.maxs, 8, 8, 8); 276 //} 277 } 278 } 279 //if the other is not visible 280 if (bs->teamgoal.entitynum < 0) { 281 BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); 282 trap_BotEnterChat(bs->cs, client, CHAT_TELL); 283 return; 284 } 285 // 286 bs->decisionmaker = client; 287 bs->ordered = qtrue; 288 bs->order_time = FloatTime(); 289 //set the time to send a message to the team mates 290 bs->teammessage_time = FloatTime() + 2 * random(); 291 //set the ltg type 292 bs->ltgtype = LTG_CAMPORDER; 293 //get the team goal time 294 bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME; 295 //the teammate that requested the camping 296 bs->teammate = client; 297 //not arrived yet 298 bs->arrive_time = 0; 299 // 300 BotSetTeamStatus(bs); 301 // remember last ordered task 302 BotRememberLastOrderedTask(bs); 303 #ifdef DEBUG 304 BotPrintTeamGoal(bs); 305 #endif //DEBUG 306 } 307 308 /* 309 ================== 310 BotVoiceChat_FollowMe 311 ================== 312 */ 313 void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) { 314 int areanum; 315 aas_entityinfo_t entinfo; 316 char netname[MAX_NETNAME]; 317 318 bs->teamgoal.entitynum = -1; 319 BotEntityInfo(client, &entinfo); 320 //if info is valid (in PVS) 321 if (entinfo.valid) { 322 areanum = BotPointAreaNum(entinfo.origin); 323 if (areanum) { // && trap_AAS_AreaReachability(areanum)) { 324 bs->teamgoal.entitynum = client; 325 bs->teamgoal.areanum = areanum; 326 VectorCopy(entinfo.origin, bs->teamgoal.origin); 327 VectorSet(bs->teamgoal.mins, -8, -8, -8); 328 VectorSet(bs->teamgoal.maxs, 8, 8, 8); 329 } 330 } 331 //if the other is not visible 332 if (bs->teamgoal.entitynum < 0) { 333 BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL); 334 trap_BotEnterChat(bs->cs, client, CHAT_TELL); 335 return; 336 } 337 // 338 bs->decisionmaker = client; 339 bs->ordered = qtrue; 340 bs->order_time = FloatTime(); 341 //the team mate 342 bs->teammate = client; 343 //last time the team mate was assumed visible 344 bs->teammatevisible_time = FloatTime(); 345 //set the time to send a message to the team mates 346 bs->teammessage_time = FloatTime() + 2 * random(); 347 //get the team goal time 348 bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME; 349 //set the ltg type 350 bs->ltgtype = LTG_TEAMACCOMPANY; 351 bs->formation_dist = 3.5 * 32; //3.5 meter 352 bs->arrive_time = 0; 353 // 354 BotSetTeamStatus(bs); 355 // remember last ordered task 356 BotRememberLastOrderedTask(bs); 357 #ifdef DEBUG 358 BotPrintTeamGoal(bs); 359 #endif //DEBUG 360 } 361 362 /* 363 ================== 364 BotVoiceChat_FollowFlagCarrier 365 ================== 366 */ 367 void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) { 368 int carrier; 369 370 carrier = BotTeamFlagCarrier(bs); 371 if (carrier >= 0) 372 BotVoiceChat_FollowMe(bs, carrier, mode); 373 #ifdef DEBUG 374 BotPrintTeamGoal(bs); 375 #endif //DEBUG 376 } 377 378 /* 379 ================== 380 BotVoiceChat_ReturnFlag 381 ================== 382 */ 383 void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) { 384 //if not in CTF mode 385 if ( 386 gametype != GT_CTF 387 #ifdef MISSIONPACK 388 && gametype != GT_1FCTF 389 #endif 390 ) { 391 return; 392 } 393 // 394 bs->decisionmaker = client; 395 bs->ordered = qtrue; 396 bs->order_time = FloatTime(); 397 //set the time to send a message to the team mates 398 bs->teammessage_time = FloatTime() + 2 * random(); 399 //set the ltg type 400 bs->ltgtype = LTG_RETURNFLAG; 401 //set the team goal time 402 bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME; 403 bs->rushbaseaway_time = 0; 404 BotSetTeamStatus(bs); 405 #ifdef DEBUG 406 BotPrintTeamGoal(bs); 407 #endif //DEBUG 408 } 409 410 /* 411 ================== 412 BotVoiceChat_StartLeader 413 ================== 414 */ 415 void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) { 416 ClientName(client, bs->teamleader, sizeof(bs->teamleader)); 417 } 418 419 /* 420 ================== 421 BotVoiceChat_StopLeader 422 ================== 423 */ 424 void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) { 425 char netname[MAX_MESSAGE_SIZE]; 426 427 if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) { 428 bs->teamleader[0] = '\0'; 429 notleader[client] = qtrue; 430 } 431 } 432 433 /* 434 ================== 435 BotVoiceChat_WhoIsLeader 436 ================== 437 */ 438 void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) { 439 char netname[MAX_MESSAGE_SIZE]; 440 441 if (!TeamPlayIsOn()) return; 442 443 ClientName(bs->client, netname, sizeof(netname)); 444 //if this bot IS the team leader 445 if (!Q_stricmp(netname, bs->teamleader)) { 446 BotAI_BotInitialChat(bs, "iamteamleader", NULL); 447 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); 448 BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER); 449 } 450 } 451 452 /* 453 ================== 454 BotVoiceChat_WantOnDefense 455 ================== 456 */ 457 void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) { 458 char netname[MAX_NETNAME]; 459 int preference; 460 461 preference = BotGetTeamMateTaskPreference(bs, client); 462 preference &= ~TEAMTP_ATTACKER; 463 preference |= TEAMTP_DEFENDER; 464 BotSetTeamMateTaskPreference(bs, client, preference); 465 // 466 EasyClientName(client, netname, sizeof(netname)); 467 BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); 468 trap_BotEnterChat(bs->cs, client, CHAT_TELL); 469 BotVoiceChatOnly(bs, client, VOICECHAT_YES); 470 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); 471 } 472 473 /* 474 ================== 475 BotVoiceChat_WantOnOffense 476 ================== 477 */ 478 void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) { 479 char netname[MAX_NETNAME]; 480 int preference; 481 482 preference = BotGetTeamMateTaskPreference(bs, client); 483 preference &= ~TEAMTP_DEFENDER; 484 preference |= TEAMTP_ATTACKER; 485 BotSetTeamMateTaskPreference(bs, client, preference); 486 // 487 EasyClientName(client, netname, sizeof(netname)); 488 BotAI_BotInitialChat(bs, "keepinmind", netname, NULL); 489 trap_BotEnterChat(bs->cs, client, CHAT_TELL); 490 BotVoiceChatOnly(bs, client, VOICECHAT_YES); 491 trap_EA_Action(bs->client, ACTION_AFFIRMATIVE); 492 } 493 494 void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) { 495 } 496 497 voiceCommand_t voiceCommands[] = { 498 {VOICECHAT_GETFLAG, BotVoiceChat_GetFlag}, 499 {VOICECHAT_OFFENSE, BotVoiceChat_Offense }, 500 {VOICECHAT_DEFEND, BotVoiceChat_Defend }, 501 {VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag }, 502 {VOICECHAT_PATROL, BotVoiceChat_Patrol }, 503 {VOICECHAT_CAMP, BotVoiceChat_Camp }, 504 {VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe }, 505 {VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier }, 506 {VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag }, 507 {VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader }, 508 {VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader }, 509 {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader }, 510 {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense }, 511 {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense }, 512 {NULL, BotVoiceChat_Dummy} 513 }; 514 515 int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) { 516 int i, voiceOnly, clientNum, color; 517 char *ptr, buf[MAX_MESSAGE_SIZE], *cmd; 518 519 if (!TeamPlayIsOn()) { 520 return qfalse; 521 } 522 523 if ( mode == SAY_ALL ) { 524 return qfalse; // don't do anything with voice chats to everyone 525 } 526 527 Q_strncpyz(buf, voiceChat, sizeof(buf)); 528 cmd = buf; 529 for (ptr = cmd; *cmd && *cmd > ' '; cmd++); 530 while (*cmd && *cmd <= ' ') *cmd++ = '\0'; 531 voiceOnly = atoi(ptr); 532 for (ptr = cmd; *cmd && *cmd > ' '; cmd++); 533 while (*cmd && *cmd <= ' ') *cmd++ = '\0'; 534 clientNum = atoi(ptr); 535 for (ptr = cmd; *cmd && *cmd > ' '; cmd++); 536 while (*cmd && *cmd <= ' ') *cmd++ = '\0'; 537 color = atoi(ptr); 538 539 if (!BotSameTeam(bs, clientNum)) { 540 return qfalse; 541 } 542 543 for (i = 0; voiceCommands[i].cmd; i++) { 544 if (!Q_stricmp(cmd, voiceCommands[i].cmd)) { 545 voiceCommands[i].func(bs, clientNum, mode); 546 return qtrue; 547 } 548 } 549 return qfalse; 550 }