Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

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 }