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 Quake III Arena source code; 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_team.c
26  *
27  * desc:		Quake3 bot AI
28  *
29  * $Archive: /MissionPack/code/game/ai_team.c $
30  *
31  *****************************************************************************/
32 
33 #include "g_local.h"
34 #include "../botlib/botlib.h"
35 #include "../botlib/be_aas.h"
36 #include "../botlib/be_ea.h"
37 #include "../botlib/be_ai_char.h"
38 #include "../botlib/be_ai_chat.h"
39 #include "../botlib/be_ai_gen.h"
40 #include "../botlib/be_ai_goal.h"
41 #include "../botlib/be_ai_move.h"
42 #include "../botlib/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 "match.h"
53 
54 // for the voice chats
55 #include "../../ui/menudef.h"
56 
57 //ctf task preferences for a client
58 typedef struct bot_ctftaskpreference_s
59 {
60 	char		name[36];
61 	int			preference;
62 } bot_ctftaskpreference_t;
63 
64 bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];
65 
66 
67 /*
68 ==================
69 BotValidTeamLeader
70 ==================
71 */
BotValidTeamLeader(bot_state_t * bs)72 int BotValidTeamLeader(bot_state_t *bs) {
73 	if (!strlen(bs->teamleader)) return qfalse;
74 	if (ClientFromName(bs->teamleader) == -1) return qfalse;
75 	return qtrue;
76 }
77 
78 /*
79 ==================
80 BotNumTeamMates
81 ==================
82 */
BotNumTeamMates(bot_state_t * bs)83 int BotNumTeamMates(bot_state_t *bs) {
84 	int i, numplayers;
85 	char buf[MAX_INFO_STRING];
86 	static int maxclients;
87 
88 	if (!maxclients)
89 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
90 
91 	numplayers = 0;
92 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
93 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
94 		//if no config string or no name
95 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
96 		//skip spectators
97 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
98 		//
99 		if (BotSameTeam(bs, i)) {
100 			numplayers++;
101 		}
102 	}
103 	return numplayers;
104 }
105 
106 /*
107 ==================
108 BotClientTravelTimeToGoal
109 ==================
110 */
BotClientTravelTimeToGoal(int client,bot_goal_t * goal)111 int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {
112 	playerState_t ps;
113 	int areanum;
114 
115 	BotAI_GetClientState(client, &ps);
116 	areanum = BotPointAreaNum(ps.origin);
117 	if (!areanum) return 1;
118 	return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
119 }
120 
121 /*
122 ==================
123 BotSortTeamMatesByBaseTravelTime
124 ==================
125 */
BotSortTeamMatesByBaseTravelTime(bot_state_t * bs,int * teammates,int maxteammates)126 int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {
127 
128 	int i, j, k, numteammates, traveltime;
129 	char buf[MAX_INFO_STRING];
130 	static int maxclients;
131 	int traveltimes[MAX_CLIENTS];
132 	bot_goal_t *goal = NULL;
133 
134 	if (gametype == GT_CTF || gametype == GT_1FCTF) {
135 		if (BotTeam(bs) == TEAM_RED)
136 			goal = &ctf_redflag;
137 		else
138 			goal = &ctf_blueflag;
139 	}
140 #ifdef MISSIONPACK
141 	else {
142 		if (BotTeam(bs) == TEAM_RED)
143 			goal = &redobelisk;
144 		else
145 			goal = &blueobelisk;
146 	}
147 #endif
148 	if (!maxclients)
149 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
150 
151 	numteammates = 0;
152 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
153 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
154 		//if no config string or no name
155 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
156 		//skip spectators
157 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
158 		//
159 		if (BotSameTeam(bs, i)) {
160 			//
161 			traveltime = BotClientTravelTimeToGoal(i, goal);
162 			//
163 			for (j = 0; j < numteammates; j++) {
164 				if (traveltime < traveltimes[j]) {
165 					for (k = numteammates; k > j; k--) {
166 						traveltimes[k] = traveltimes[k-1];
167 						teammates[k] = teammates[k-1];
168 					}
169 					break;
170 				}
171 			}
172 			traveltimes[j] = traveltime;
173 			teammates[j] = i;
174 			numteammates++;
175 			if (numteammates >= maxteammates) break;
176 		}
177 	}
178 	return numteammates;
179 }
180 
181 /*
182 ==================
183 BotSetTeamMateTaskPreference
184 ==================
185 */
BotSetTeamMateTaskPreference(bot_state_t * bs,int teammate,int preference)186 void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {
187 	char teammatename[MAX_NETNAME];
188 
189 	ctftaskpreferences[teammate].preference = preference;
190 	ClientName(teammate, teammatename, sizeof(teammatename));
191 	strcpy(ctftaskpreferences[teammate].name, teammatename);
192 }
193 
194 /*
195 ==================
196 BotGetTeamMateTaskPreference
197 ==================
198 */
BotGetTeamMateTaskPreference(bot_state_t * bs,int teammate)199 int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {
200 	char teammatename[MAX_NETNAME];
201 
202 	if (!ctftaskpreferences[teammate].preference) return 0;
203 	ClientName(teammate, teammatename, sizeof(teammatename));
204 	if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;
205 	return ctftaskpreferences[teammate].preference;
206 }
207 
208 /*
209 ==================
210 BotSortTeamMatesByTaskPreference
211 ==================
212 */
BotSortTeamMatesByTaskPreference(bot_state_t * bs,int * teammates,int numteammates)213 int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {
214 	int defenders[MAX_CLIENTS], numdefenders;
215 	int attackers[MAX_CLIENTS], numattackers;
216 	int roamers[MAX_CLIENTS], numroamers;
217 	int i, preference;
218 
219 	numdefenders = numattackers = numroamers = 0;
220 	for (i = 0; i < numteammates; i++) {
221 		preference = BotGetTeamMateTaskPreference(bs, teammates[i]);
222 		if (preference & TEAMTP_DEFENDER) {
223 			defenders[numdefenders++] = teammates[i];
224 		}
225 		else if (preference & TEAMTP_ATTACKER) {
226 			attackers[numattackers++] = teammates[i];
227 		}
228 		else {
229 			roamers[numroamers++] = teammates[i];
230 		}
231 	}
232 	numteammates = 0;
233 	//defenders at the front of the list
234 	memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));
235 	numteammates += numdefenders;
236 	//roamers in the middle
237 	memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));
238 	numteammates += numroamers;
239 	//attacker in the back of the list
240 	memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));
241 	numteammates += numattackers;
242 
243 	return numteammates;
244 }
245 
246 /*
247 ==================
248 BotSayTeamOrders
249 ==================
250 */
BotSayTeamOrderAlways(bot_state_t * bs,int toclient)251 void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {
252 	char teamchat[MAX_MESSAGE_SIZE];
253 	char buf[MAX_MESSAGE_SIZE];
254 	char name[MAX_NETNAME];
255 
256 	//if the bot is talking to itself
257 	if (bs->client == toclient) {
258 		//don't show the message just put it in the console message queue
259 		trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
260 		ClientName(bs->client, name, sizeof(name));
261 		Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf);
262 		trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);
263 	}
264 	else {
265 		trap_BotEnterChat(bs->cs, toclient, CHAT_TELL);
266 	}
267 }
268 
269 /*
270 ==================
271 BotSayTeamOrders
272 ==================
273 */
BotSayTeamOrder(bot_state_t * bs,int toclient)274 void BotSayTeamOrder(bot_state_t *bs, int toclient) {
275 #ifdef MISSIONPACK
276 	// voice chats only
277 	char buf[MAX_MESSAGE_SIZE];
278 
279 	trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
280 #else
281 	BotSayTeamOrderAlways(bs, toclient);
282 #endif
283 }
284 
285 /*
286 ==================
287 BotVoiceChat
288 ==================
289 */
BotVoiceChat(bot_state_t * bs,int toclient,char * voicechat)290 void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {
291 #ifdef MISSIONPACK
292 	if (toclient == -1)
293 		// voice only say team
294 		trap_EA_Command(bs->client, va("vsay_team %s", voicechat));
295 	else
296 		// voice only tell single player
297 		trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat));
298 #endif
299 }
300 
301 /*
302 ==================
303 BotVoiceChatOnly
304 ==================
305 */
BotVoiceChatOnly(bot_state_t * bs,int toclient,char * voicechat)306 void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {
307 #ifdef MISSIONPACK
308 	if (toclient == -1)
309 		// voice only say team
310 		trap_EA_Command(bs->client, va("vosay_team %s", voicechat));
311 	else
312 		// voice only tell single player
313 		trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat));
314 #endif
315 }
316 
317 /*
318 ==================
319 BotSayVoiceTeamOrder
320 ==================
321 */
BotSayVoiceTeamOrder(bot_state_t * bs,int toclient,char * voicechat)322 void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {
323 #ifdef MISSIONPACK
324 	BotVoiceChat(bs, toclient, voicechat);
325 #endif
326 }
327 
328 /*
329 ==================
330 BotCTFOrders
331 ==================
332 */
BotCTFOrders_BothFlagsNotAtBase(bot_state_t * bs)333 void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {
334 	int numteammates, defenders, attackers, i, other;
335 	int teammates[MAX_CLIENTS];
336 	char name[MAX_NETNAME], carriername[MAX_NETNAME];
337 
338 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
339 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
340 	//different orders based on the number of team mates
341 	switch(bs->numteammates) {
342 		case 1: break;
343 		case 2:
344 		{
345 			//tell the one not carrying the flag to attack the enemy base
346 			if (teammates[0] != bs->flagcarrier) other = teammates[0];
347 			else other = teammates[1];
348 			ClientName(other, name, sizeof(name));
349 			BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
350 			BotSayTeamOrder(bs, other);
351 			BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
352 			break;
353 		}
354 		case 3:
355 		{
356 			//tell the one closest to the base not carrying the flag to accompany the flag carrier
357 			if (teammates[0] != bs->flagcarrier) other = teammates[0];
358 			else other = teammates[1];
359 			ClientName(other, name, sizeof(name));
360 			if ( bs->flagcarrier != -1 ) {
361 				ClientName(bs->flagcarrier, carriername, sizeof(carriername));
362 				if (bs->flagcarrier == bs->client) {
363 					BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
364 					BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
365 				}
366 				else {
367 					BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
368 					BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
369 				}
370 			}
371 			else {
372 				//
373 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
374 				BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
375 			}
376 			BotSayTeamOrder(bs, other);
377 			//tell the one furthest from the the base not carrying the flag to get the enemy flag
378 			if (teammates[2] != bs->flagcarrier) other = teammates[2];
379 			else other = teammates[1];
380 			ClientName(other, name, sizeof(name));
381 			BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
382 			BotSayTeamOrder(bs, other);
383 			BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);
384 			break;
385 		}
386 		default:
387 		{
388 			defenders = (int) (float) numteammates * 0.4 + 0.5;
389 			if (defenders > 4) defenders = 4;
390 			attackers = (int) (float) numteammates * 0.5 + 0.5;
391 			if (attackers > 5) attackers = 5;
392 			if (bs->flagcarrier != -1) {
393 				ClientName(bs->flagcarrier, carriername, sizeof(carriername));
394 				for (i = 0; i < defenders; i++) {
395 					//
396 					if (teammates[i] == bs->flagcarrier) {
397 						continue;
398 					}
399 					//
400 					ClientName(teammates[i], name, sizeof(name));
401 					if (bs->flagcarrier == bs->client) {
402 						BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
403 						BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);
404 					}
405 					else {
406 						BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
407 						BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);
408 					}
409 					BotSayTeamOrder(bs, teammates[i]);
410 				}
411 			}
412 			else {
413 				for (i = 0; i < defenders; i++) {
414 					//
415 					if (teammates[i] == bs->flagcarrier) {
416 						continue;
417 					}
418 					//
419 					ClientName(teammates[i], name, sizeof(name));
420 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
421 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
422 					BotSayTeamOrder(bs, teammates[i]);
423 				}
424 			}
425 			for (i = 0; i < attackers; i++) {
426 				//
427 				if (teammates[numteammates - i - 1] == bs->flagcarrier) {
428 					continue;
429 				}
430 				//
431 				ClientName(teammates[numteammates - i - 1], name, sizeof(name));
432 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
433 				BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
434 				BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);
435 			}
436 			//
437 			break;
438 		}
439 	}
440 }
441 
442 /*
443 ==================
444 BotCTFOrders
445 ==================
446 */
BotCTFOrders_FlagNotAtBase(bot_state_t * bs)447 void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {
448 	int numteammates, defenders, attackers, i;
449 	int teammates[MAX_CLIENTS];
450 	char name[MAX_NETNAME];
451 
452 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
453 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
454 	//passive strategy
455 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
456 		//different orders based on the number of team mates
457 		switch(bs->numteammates) {
458 			case 1: break;
459 			case 2:
460 			{
461 				//both will go for the enemy flag
462 				ClientName(teammates[0], name, sizeof(name));
463 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
464 				BotSayTeamOrder(bs, teammates[0]);
465 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
466 				//
467 				ClientName(teammates[1], name, sizeof(name));
468 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
469 				BotSayTeamOrder(bs, teammates[1]);
470 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
471 				break;
472 			}
473 			case 3:
474 			{
475 				//keep one near the base for when the flag is returned
476 				ClientName(teammates[0], name, sizeof(name));
477 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
478 				BotSayTeamOrder(bs, teammates[0]);
479 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
480 				//the other two get the flag
481 				ClientName(teammates[1], name, sizeof(name));
482 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
483 				BotSayTeamOrder(bs, teammates[1]);
484 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
485 				//
486 				ClientName(teammates[2], name, sizeof(name));
487 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
488 				BotSayTeamOrder(bs, teammates[2]);
489 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
490 				break;
491 			}
492 			default:
493 			{
494 				//keep some people near the base for when the flag is returned
495 				defenders = (int) (float) numteammates * 0.3 + 0.5;
496 				if (defenders > 3) defenders = 3;
497 				attackers = (int) (float) numteammates * 0.7 + 0.5;
498 				if (attackers > 6) attackers = 6;
499 				for (i = 0; i < defenders; i++) {
500 					//
501 					ClientName(teammates[i], name, sizeof(name));
502 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
503 					BotSayTeamOrder(bs, teammates[i]);
504 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
505 				}
506 				for (i = 0; i < attackers; i++) {
507 					//
508 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
509 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
510 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
511 					BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
512 				}
513 				//
514 				break;
515 			}
516 		}
517 	}
518 	else {
519 		//different orders based on the number of team mates
520 		switch(bs->numteammates) {
521 			case 1: break;
522 			case 2:
523 			{
524 				//both will go for the enemy flag
525 				ClientName(teammates[0], name, sizeof(name));
526 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
527 				BotSayTeamOrder(bs, teammates[0]);
528 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
529 				//
530 				ClientName(teammates[1], name, sizeof(name));
531 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
532 				BotSayTeamOrder(bs, teammates[1]);
533 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
534 				break;
535 			}
536 			case 3:
537 			{
538 				//everyone go for the flag
539 				ClientName(teammates[0], name, sizeof(name));
540 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
541 				BotSayTeamOrder(bs, teammates[0]);
542 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
543 				//
544 				ClientName(teammates[1], name, sizeof(name));
545 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
546 				BotSayTeamOrder(bs, teammates[1]);
547 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
548 				//
549 				ClientName(teammates[2], name, sizeof(name));
550 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
551 				BotSayTeamOrder(bs, teammates[2]);
552 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
553 				break;
554 			}
555 			default:
556 			{
557 				//keep some people near the base for when the flag is returned
558 				defenders = (int) (float) numteammates * 0.2 + 0.5;
559 				if (defenders > 2) defenders = 2;
560 				attackers = (int) (float) numteammates * 0.7 + 0.5;
561 				if (attackers > 7) attackers = 7;
562 				for (i = 0; i < defenders; i++) {
563 					//
564 					ClientName(teammates[i], name, sizeof(name));
565 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
566 					BotSayTeamOrder(bs, teammates[i]);
567 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
568 				}
569 				for (i = 0; i < attackers; i++) {
570 					//
571 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
572 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
573 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
574 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
575 				}
576 				//
577 				break;
578 			}
579 		}
580 	}
581 }
582 
583 /*
584 ==================
585 BotCTFOrders
586 ==================
587 */
BotCTFOrders_EnemyFlagNotAtBase(bot_state_t * bs)588 void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {
589 	int numteammates, defenders, attackers, i, other;
590 	int teammates[MAX_CLIENTS];
591 	char name[MAX_NETNAME], carriername[MAX_NETNAME];
592 
593 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
594 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
595 	//different orders based on the number of team mates
596 	switch(numteammates) {
597 		case 1: break;
598 		case 2:
599 		{
600 			//tell the one not carrying the flag to defend the base
601 			if (teammates[0] == bs->flagcarrier) other = teammates[1];
602 			else other = teammates[0];
603 			ClientName(other, name, sizeof(name));
604 			BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
605 			BotSayTeamOrder(bs, other);
606 			BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
607 			break;
608 		}
609 		case 3:
610 		{
611 			//tell the one closest to the base not carrying the flag to defend the base
612 			if (teammates[0] != bs->flagcarrier) other = teammates[0];
613 			else other = teammates[1];
614 			ClientName(other, name, sizeof(name));
615 			BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
616 			BotSayTeamOrder(bs, other);
617 			BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
618 			//tell the other also to defend the base
619 			if (teammates[2] != bs->flagcarrier) other = teammates[2];
620 			else other = teammates[1];
621 			ClientName(other, name, sizeof(name));
622 			BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
623 			BotSayTeamOrder(bs, other);
624 			BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
625 			break;
626 		}
627 		default:
628 		{
629 			//60% will defend the base
630 			defenders = (int) (float) numteammates * 0.6 + 0.5;
631 			if (defenders > 6) defenders = 6;
632 			//30% accompanies the flag carrier
633 			attackers = (int) (float) numteammates * 0.3 + 0.5;
634 			if (attackers > 3) attackers = 3;
635 			for (i = 0; i < defenders; i++) {
636 				//
637 				if (teammates[i] == bs->flagcarrier) {
638 					continue;
639 				}
640 				ClientName(teammates[i], name, sizeof(name));
641 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
642 				BotSayTeamOrder(bs, teammates[i]);
643 				BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
644 			}
645 			// if we have a flag carrier
646 			if ( bs->flagcarrier != -1 ) {
647 				ClientName(bs->flagcarrier, carriername, sizeof(carriername));
648 				for (i = 0; i < attackers; i++) {
649 					//
650 					if (teammates[numteammates - i - 1] == bs->flagcarrier) {
651 						continue;
652 					}
653 					//
654 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
655 					if (bs->flagcarrier == bs->client) {
656 						BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
657 						BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
658 					}
659 					else {
660 						BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
661 						BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
662 					}
663 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
664 				}
665 			}
666 			else {
667 				for (i = 0; i < attackers; i++) {
668 					//
669 					if (teammates[numteammates - i - 1] == bs->flagcarrier) {
670 						continue;
671 					}
672 					//
673 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
674 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
675 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
676 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
677 				}
678 			}
679 			//
680 			break;
681 		}
682 	}
683 }
684 
685 
686 /*
687 ==================
688 BotCTFOrders
689 ==================
690 */
BotCTFOrders_BothFlagsAtBase(bot_state_t * bs)691 void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {
692 	int numteammates, defenders, attackers, i;
693 	int teammates[MAX_CLIENTS];
694 	char name[MAX_NETNAME];
695 
696 	//sort team mates by travel time to base
697 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
698 	//sort team mates by CTF preference
699 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
700 	//passive strategy
701 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
702 		//different orders based on the number of team mates
703 		switch(numteammates) {
704 			case 1: break;
705 			case 2:
706 			{
707 				//the one closest to the base will defend the base
708 				ClientName(teammates[0], name, sizeof(name));
709 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
710 				BotSayTeamOrder(bs, teammates[0]);
711 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
712 				//the other will get the flag
713 				ClientName(teammates[1], name, sizeof(name));
714 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
715 				BotSayTeamOrder(bs, teammates[1]);
716 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
717 				break;
718 			}
719 			case 3:
720 			{
721 				//the one closest to the base will defend the base
722 				ClientName(teammates[0], name, sizeof(name));
723 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
724 				BotSayTeamOrder(bs, teammates[0]);
725 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
726 				//the second one closest to the base will defend the base
727 				ClientName(teammates[1], name, sizeof(name));
728 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
729 				BotSayTeamOrder(bs, teammates[1]);
730 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
731 				//the other will get the flag
732 				ClientName(teammates[2], name, sizeof(name));
733 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
734 				BotSayTeamOrder(bs, teammates[2]);
735 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
736 				break;
737 			}
738 			default:
739 			{
740 				defenders = (int) (float) numteammates * 0.5 + 0.5;
741 				if (defenders > 5) defenders = 5;
742 				attackers = (int) (float) numteammates * 0.4 + 0.5;
743 				if (attackers > 4) attackers = 4;
744 				for (i = 0; i < defenders; i++) {
745 					//
746 					ClientName(teammates[i], name, sizeof(name));
747 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
748 					BotSayTeamOrder(bs, teammates[i]);
749 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
750 				}
751 				for (i = 0; i < attackers; i++) {
752 					//
753 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
754 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
755 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
756 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
757 				}
758 				//
759 				break;
760 			}
761 		}
762 	}
763 	else {
764 		//different orders based on the number of team mates
765 		switch(numteammates) {
766 			case 1: break;
767 			case 2:
768 			{
769 				//the one closest to the base will defend the base
770 				ClientName(teammates[0], name, sizeof(name));
771 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
772 				BotSayTeamOrder(bs, teammates[0]);
773 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
774 				//the other will get the flag
775 				ClientName(teammates[1], name, sizeof(name));
776 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
777 				BotSayTeamOrder(bs, teammates[1]);
778 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
779 				break;
780 			}
781 			case 3:
782 			{
783 				//the one closest to the base will defend the base
784 				ClientName(teammates[0], name, sizeof(name));
785 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
786 				BotSayTeamOrder(bs, teammates[0]);
787 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
788 				//the others should go for the enemy flag
789 				ClientName(teammates[1], name, sizeof(name));
790 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
791 				BotSayTeamOrder(bs, teammates[1]);
792 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
793 				//
794 				ClientName(teammates[2], name, sizeof(name));
795 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
796 				BotSayTeamOrder(bs, teammates[2]);
797 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
798 				break;
799 			}
800 			default:
801 			{
802 				defenders = (int) (float) numteammates * 0.4 + 0.5;
803 				if (defenders > 4) defenders = 4;
804 				attackers = (int) (float) numteammates * 0.5 + 0.5;
805 				if (attackers > 5) attackers = 5;
806 				for (i = 0; i < defenders; i++) {
807 					//
808 					ClientName(teammates[i], name, sizeof(name));
809 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
810 					BotSayTeamOrder(bs, teammates[i]);
811 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
812 				}
813 				for (i = 0; i < attackers; i++) {
814 					//
815 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
816 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
817 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
818 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
819 				}
820 				//
821 				break;
822 			}
823 		}
824 	}
825 }
826 
827 /*
828 ==================
829 BotCTFOrders
830 ==================
831 */
BotCTFOrders(bot_state_t * bs)832 void BotCTFOrders(bot_state_t *bs) {
833 	int flagstatus;
834 
835 	//
836 	if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
837 	else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
838 	//
839 	switch(flagstatus) {
840 		case 0: BotCTFOrders_BothFlagsAtBase(bs); break;
841 		case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;
842 		case 2: BotCTFOrders_FlagNotAtBase(bs); break;
843 		case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;
844 	}
845 }
846 
847 
848 /*
849 ==================
850 BotCreateGroup
851 ==================
852 */
BotCreateGroup(bot_state_t * bs,int * teammates,int groupsize)853 void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {
854 	char name[MAX_NETNAME], leadername[MAX_NETNAME];
855 	int i;
856 
857 	// the others in the group will follow the teammates[0]
858 	ClientName(teammates[0], leadername, sizeof(leadername));
859 	for (i = 1; i < groupsize; i++)
860 	{
861 		ClientName(teammates[i], name, sizeof(name));
862 		if (teammates[0] == bs->client) {
863 			BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
864 		}
865 		else {
866 			BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL);
867 		}
868 		BotSayTeamOrderAlways(bs, teammates[i]);
869 	}
870 }
871 
872 /*
873 ==================
874 BotTeamOrders
875 
876   FIXME: defend key areas?
877 ==================
878 */
BotTeamOrders(bot_state_t * bs)879 void BotTeamOrders(bot_state_t *bs) {
880 	int teammates[MAX_CLIENTS];
881 	int numteammates, i;
882 	char buf[MAX_INFO_STRING];
883 	static int maxclients;
884 
885 	if (!maxclients)
886 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
887 
888 	numteammates = 0;
889 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
890 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
891 		//if no config string or no name
892 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
893 		//skip spectators
894 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
895 		//
896 		if (BotSameTeam(bs, i)) {
897 			teammates[numteammates] = i;
898 			numteammates++;
899 		}
900 	}
901 	//
902 	switch(numteammates) {
903 		case 1: break;
904 		case 2:
905 		{
906 			//nothing special
907 			break;
908 		}
909 		case 3:
910 		{
911 			//have one follow another and one free roaming
912 			BotCreateGroup(bs, teammates, 2);
913 			break;
914 		}
915 		case 4:
916 		{
917 			BotCreateGroup(bs, teammates, 2);		//a group of 2
918 			BotCreateGroup(bs, &teammates[2], 2);	//a group of 2
919 			break;
920 		}
921 		case 5:
922 		{
923 			BotCreateGroup(bs, teammates, 2);		//a group of 2
924 			BotCreateGroup(bs, &teammates[2], 3);	//a group of 3
925 			break;
926 		}
927 		default:
928 		{
929 			if (numteammates <= 10) {
930 				for (i = 0; i < numteammates / 2; i++) {
931 					BotCreateGroup(bs, &teammates[i*2], 2);	//groups of 2
932 				}
933 			}
934 			break;
935 		}
936 	}
937 }
938 
939 #ifdef MISSIONPACK
940 
941 /*
942 ==================
943 Bot1FCTFOrders_FlagAtCenter
944 
945   X% defend the base, Y% get the flag
946 ==================
947 */
Bot1FCTFOrders_FlagAtCenter(bot_state_t * bs)948 void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) {
949 	int numteammates, defenders, attackers, i;
950 	int teammates[MAX_CLIENTS];
951 	char name[MAX_NETNAME];
952 
953 	//sort team mates by travel time to base
954 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
955 	//sort team mates by CTF preference
956 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
957 	//passive strategy
958 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
959 		//different orders based on the number of team mates
960 		switch(numteammates) {
961 			case 1: break;
962 			case 2:
963 			{
964 				//the one closest to the base will defend the base
965 				ClientName(teammates[0], name, sizeof(name));
966 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
967 				BotSayTeamOrder(bs, teammates[0]);
968 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
969 				//the other will get the flag
970 				ClientName(teammates[1], name, sizeof(name));
971 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
972 				BotSayTeamOrder(bs, teammates[1]);
973 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
974 				break;
975 			}
976 			case 3:
977 			{
978 				//the one closest to the base will defend the base
979 				ClientName(teammates[0], name, sizeof(name));
980 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
981 				BotSayTeamOrder(bs, teammates[0]);
982 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
983 				//the second one closest to the base will defend the base
984 				ClientName(teammates[1], name, sizeof(name));
985 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
986 				BotSayTeamOrder(bs, teammates[1]);
987 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
988 				//the other will get the flag
989 				ClientName(teammates[2], name, sizeof(name));
990 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
991 				BotSayTeamOrder(bs, teammates[2]);
992 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
993 				break;
994 			}
995 			default:
996 			{
997 				//50% defend the base
998 				defenders = (int) (float) numteammates * 0.5 + 0.5;
999 				if (defenders > 5) defenders = 5;
1000 				//40% get the flag
1001 				attackers = (int) (float) numteammates * 0.4 + 0.5;
1002 				if (attackers > 4) attackers = 4;
1003 				for (i = 0; i < defenders; i++) {
1004 					//
1005 					ClientName(teammates[i], name, sizeof(name));
1006 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1007 					BotSayTeamOrder(bs, teammates[i]);
1008 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1009 				}
1010 				for (i = 0; i < attackers; i++) {
1011 					//
1012 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1013 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1014 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1015 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1016 				}
1017 				//
1018 				break;
1019 			}
1020 		}
1021 	}
1022 	else { //agressive
1023 		//different orders based on the number of team mates
1024 		switch(numteammates) {
1025 			case 1: break;
1026 			case 2:
1027 			{
1028 				//the one closest to the base will defend the base
1029 				ClientName(teammates[0], name, sizeof(name));
1030 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1031 				BotSayTeamOrder(bs, teammates[0]);
1032 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1033 				//the other will get the flag
1034 				ClientName(teammates[1], name, sizeof(name));
1035 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1036 				BotSayTeamOrder(bs, teammates[1]);
1037 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
1038 				break;
1039 			}
1040 			case 3:
1041 			{
1042 				//the one closest to the base will defend the base
1043 				ClientName(teammates[0], name, sizeof(name));
1044 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1045 				BotSayTeamOrder(bs, teammates[0]);
1046 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1047 				//the others should go for the enemy flag
1048 				ClientName(teammates[1], name, sizeof(name));
1049 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1050 				BotSayTeamOrder(bs, teammates[1]);
1051 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
1052 				//
1053 				ClientName(teammates[2], name, sizeof(name));
1054 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1055 				BotSayTeamOrder(bs, teammates[2]);
1056 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
1057 				break;
1058 			}
1059 			default:
1060 			{
1061 				//30% defend the base
1062 				defenders = (int) (float) numteammates * 0.3 + 0.5;
1063 				if (defenders > 3) defenders = 3;
1064 				//60% get the flag
1065 				attackers = (int) (float) numteammates * 0.6 + 0.5;
1066 				if (attackers > 6) attackers = 6;
1067 				for (i = 0; i < defenders; i++) {
1068 					//
1069 					ClientName(teammates[i], name, sizeof(name));
1070 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1071 					BotSayTeamOrder(bs, teammates[i]);
1072 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1073 				}
1074 				for (i = 0; i < attackers; i++) {
1075 					//
1076 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1077 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1078 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1079 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1080 				}
1081 				//
1082 				break;
1083 			}
1084 		}
1085 	}
1086 }
1087 
1088 /*
1089 ==================
1090 Bot1FCTFOrders_TeamHasFlag
1091 
1092   X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible
1093 ==================
1094 */
Bot1FCTFOrders_TeamHasFlag(bot_state_t * bs)1095 void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) {
1096 	int numteammates, defenders, attackers, i, other;
1097 	int teammates[MAX_CLIENTS];
1098 	char name[MAX_NETNAME], carriername[MAX_NETNAME];
1099 
1100 	//sort team mates by travel time to base
1101 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
1102 	//sort team mates by CTF preference
1103 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
1104 	//passive strategy
1105 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
1106 		//different orders based on the number of team mates
1107 		switch(numteammates) {
1108 			case 1: break;
1109 			case 2:
1110 			{
1111 				//tell the one not carrying the flag to attack the enemy base
1112 				if (teammates[0] == bs->flagcarrier) other = teammates[1];
1113 				else other = teammates[0];
1114 				ClientName(other, name, sizeof(name));
1115 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1116 				BotSayTeamOrder(bs, other);
1117 				BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE);
1118 				break;
1119 			}
1120 			case 3:
1121 			{
1122 				//tell the one closest to the base not carrying the flag to defend the base
1123 				if (teammates[0] != bs->flagcarrier) other = teammates[0];
1124 				else other = teammates[1];
1125 				ClientName(other, name, sizeof(name));
1126 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1127 				BotSayTeamOrder(bs, other);
1128 				BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
1129 				//tell the one furthest from the base not carrying the flag to accompany the flag carrier
1130 				if (teammates[2] != bs->flagcarrier) other = teammates[2];
1131 				else other = teammates[1];
1132 				ClientName(other, name, sizeof(name));
1133 				if ( bs->flagcarrier != -1 ) {
1134 					ClientName(bs->flagcarrier, carriername, sizeof(carriername));
1135 					if (bs->flagcarrier == bs->client) {
1136 						BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
1137 						BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
1138 					}
1139 					else {
1140 						BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
1141 						BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
1142 					}
1143 				}
1144 				else {
1145 					//
1146 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1147 					BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
1148 				}
1149 				BotSayTeamOrder(bs, other);
1150 				break;
1151 			}
1152 			default:
1153 			{
1154 				//30% will defend the base
1155 				defenders = (int) (float) numteammates * 0.3 + 0.5;
1156 				if (defenders > 3) defenders = 3;
1157 				//70% accompanies the flag carrier
1158 				attackers = (int) (float) numteammates * 0.7 + 0.5;
1159 				if (attackers > 7) attackers = 7;
1160 				for (i = 0; i < defenders; i++) {
1161 					//
1162 					if (teammates[i] == bs->flagcarrier) {
1163 						continue;
1164 					}
1165 					ClientName(teammates[i], name, sizeof(name));
1166 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1167 					BotSayTeamOrder(bs, teammates[i]);
1168 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1169 				}
1170 				if (bs->flagcarrier != -1) {
1171 					ClientName(bs->flagcarrier, carriername, sizeof(carriername));
1172 					for (i = 0; i < attackers; i++) {
1173 						//
1174 						if (teammates[numteammates - i - 1] == bs->flagcarrier) {
1175 							continue;
1176 						}
1177 						//
1178 						ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1179 						if (bs->flagcarrier == bs->client) {
1180 							BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
1181 							BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
1182 						}
1183 						else {
1184 							BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
1185 							BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
1186 						}
1187 						BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1188 					}
1189 				}
1190 				else {
1191 					for (i = 0; i < attackers; i++) {
1192 						//
1193 						if (teammates[numteammates - i - 1] == bs->flagcarrier) {
1194 							continue;
1195 						}
1196 						//
1197 						ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1198 						BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1199 						BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1200 						BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1201 					}
1202 				}
1203 				//
1204 				break;
1205 			}
1206 		}
1207 	}
1208 	else { //agressive
1209 		//different orders based on the number of team mates
1210 		switch(numteammates) {
1211 			case 1: break;
1212 			case 2:
1213 			{
1214 				//tell the one not carrying the flag to defend the base
1215 				if (teammates[0] == bs->flagcarrier) other = teammates[1];
1216 				else other = teammates[0];
1217 				ClientName(other, name, sizeof(name));
1218 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1219 				BotSayTeamOrder(bs, other);
1220 				BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
1221 				break;
1222 			}
1223 			case 3:
1224 			{
1225 				//tell the one closest to the base not carrying the flag to defend the base
1226 				if (teammates[0] != bs->flagcarrier) other = teammates[0];
1227 				else other = teammates[1];
1228 				ClientName(other, name, sizeof(name));
1229 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1230 				BotSayTeamOrder(bs, other);
1231 				BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
1232 				//tell the one furthest from the base not carrying the flag to accompany the flag carrier
1233 				if (teammates[2] != bs->flagcarrier) other = teammates[2];
1234 				else other = teammates[1];
1235 				ClientName(other, name, sizeof(name));
1236 				ClientName(bs->flagcarrier, carriername, sizeof(carriername));
1237 				if (bs->flagcarrier == bs->client) {
1238 					BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
1239 					BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
1240 				}
1241 				else {
1242 					BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
1243 					BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
1244 				}
1245 				BotSayTeamOrder(bs, other);
1246 				break;
1247 			}
1248 			default:
1249 			{
1250 				//20% will defend the base
1251 				defenders = (int) (float) numteammates * 0.2 + 0.5;
1252 				if (defenders > 2) defenders = 2;
1253 				//80% accompanies the flag carrier
1254 				attackers = (int) (float) numteammates * 0.8 + 0.5;
1255 				if (attackers > 8) attackers = 8;
1256 				for (i = 0; i < defenders; i++) {
1257 					//
1258 					if (teammates[i] == bs->flagcarrier) {
1259 						continue;
1260 					}
1261 					ClientName(teammates[i], name, sizeof(name));
1262 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1263 					BotSayTeamOrder(bs, teammates[i]);
1264 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1265 				}
1266 				ClientName(bs->flagcarrier, carriername, sizeof(carriername));
1267 				for (i = 0; i < attackers; i++) {
1268 					//
1269 					if (teammates[numteammates - i - 1] == bs->flagcarrier) {
1270 						continue;
1271 					}
1272 					//
1273 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1274 					if (bs->flagcarrier == bs->client) {
1275 						BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
1276 						BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
1277 					}
1278 					else {
1279 						BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
1280 						BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
1281 					}
1282 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1283 				}
1284 				//
1285 				break;
1286 			}
1287 		}
1288 	}
1289 }
1290 
1291 /*
1292 ==================
1293 Bot1FCTFOrders_EnemyHasFlag
1294 
1295   X% defend the base, Y% towards neutral flag
1296 ==================
1297 */
Bot1FCTFOrders_EnemyHasFlag(bot_state_t * bs)1298 void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) {
1299 	int numteammates, defenders, attackers, i;
1300 	int teammates[MAX_CLIENTS];
1301 	char name[MAX_NETNAME];
1302 
1303 	//sort team mates by travel time to base
1304 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
1305 	//sort team mates by CTF preference
1306 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
1307 	//passive strategy
1308 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
1309 		//different orders based on the number of team mates
1310 		switch(numteammates) {
1311 			case 1: break;
1312 			case 2:
1313 			{
1314 				//both defend the base
1315 				ClientName(teammates[0], name, sizeof(name));
1316 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1317 				BotSayTeamOrder(bs, teammates[0]);
1318 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1319 				//
1320 				ClientName(teammates[1], name, sizeof(name));
1321 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1322 				BotSayTeamOrder(bs, teammates[1]);
1323 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1324 				break;
1325 			}
1326 			case 3:
1327 			{
1328 				//the one closest to the base will defend the base
1329 				ClientName(teammates[0], name, sizeof(name));
1330 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1331 				BotSayTeamOrder(bs, teammates[0]);
1332 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1333 				//the second one closest to the base will defend the base
1334 				ClientName(teammates[1], name, sizeof(name));
1335 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1336 				BotSayTeamOrder(bs, teammates[1]);
1337 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1338 				//the other will also defend the base
1339 				ClientName(teammates[2], name, sizeof(name));
1340 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1341 				BotSayTeamOrder(bs, teammates[2]);
1342 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND);
1343 				break;
1344 			}
1345 			default:
1346 			{
1347 				//80% will defend the base
1348 				defenders = (int) (float) numteammates * 0.8 + 0.5;
1349 				if (defenders > 8) defenders = 8;
1350 				//10% will try to return the flag
1351 				attackers = (int) (float) numteammates * 0.1 + 0.5;
1352 				if (attackers > 2) attackers = 2;
1353 				for (i = 0; i < defenders; i++) {
1354 					//
1355 					ClientName(teammates[i], name, sizeof(name));
1356 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1357 					BotSayTeamOrder(bs, teammates[i]);
1358 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1359 				}
1360 				for (i = 0; i < attackers; i++) {
1361 					//
1362 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1363 					BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
1364 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1365 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1366 				}
1367 				//
1368 				break;
1369 			}
1370 		}
1371 	}
1372 	else { //agressive
1373 		//different orders based on the number of team mates
1374 		switch(numteammates) {
1375 			case 1: break;
1376 			case 2:
1377 			{
1378 				//the one closest to the base will defend the base
1379 				ClientName(teammates[0], name, sizeof(name));
1380 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1381 				BotSayTeamOrder(bs, teammates[0]);
1382 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1383 				//the other will get the flag
1384 				ClientName(teammates[1], name, sizeof(name));
1385 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1386 				BotSayTeamOrder(bs, teammates[1]);
1387 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1388 				break;
1389 			}
1390 			case 3:
1391 			{
1392 				//the one closest to the base will defend the base
1393 				ClientName(teammates[0], name, sizeof(name));
1394 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1395 				BotSayTeamOrder(bs, teammates[0]);
1396 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1397 				//the others should go for the enemy flag
1398 				ClientName(teammates[1], name, sizeof(name));
1399 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1400 				BotSayTeamOrder(bs, teammates[1]);
1401 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1402 				//
1403 				ClientName(teammates[2], name, sizeof(name));
1404 				BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
1405 				BotSayTeamOrder(bs, teammates[2]);
1406 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
1407 				break;
1408 			}
1409 			default:
1410 			{
1411 				//70% defend the base
1412 				defenders = (int) (float) numteammates * 0.7 + 0.5;
1413 				if (defenders > 8) defenders = 8;
1414 				//20% try to return the flag
1415 				attackers = (int) (float) numteammates * 0.2 + 0.5;
1416 				if (attackers > 2) attackers = 2;
1417 				for (i = 0; i < defenders; i++) {
1418 					//
1419 					ClientName(teammates[i], name, sizeof(name));
1420 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1421 					BotSayTeamOrder(bs, teammates[i]);
1422 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1423 				}
1424 				for (i = 0; i < attackers; i++) {
1425 					//
1426 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1427 					BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
1428 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1429 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1430 				}
1431 				//
1432 				break;
1433 			}
1434 		}
1435 	}
1436 }
1437 
1438 /*
1439 ==================
1440 Bot1FCTFOrders_EnemyDroppedFlag
1441 
1442   X% defend the base, Y% get the flag
1443 ==================
1444 */
Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t * bs)1445 void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) {
1446 	int numteammates, defenders, attackers, i;
1447 	int teammates[MAX_CLIENTS];
1448 	char name[MAX_NETNAME];
1449 
1450 	//sort team mates by travel time to base
1451 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
1452 	//sort team mates by CTF preference
1453 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
1454 	//passive strategy
1455 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
1456 		//different orders based on the number of team mates
1457 		switch(numteammates) {
1458 			case 1: break;
1459 			case 2:
1460 			{
1461 				//the one closest to the base will defend the base
1462 				ClientName(teammates[0], name, sizeof(name));
1463 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1464 				BotSayTeamOrder(bs, teammates[0]);
1465 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1466 				//the other will get the flag
1467 				ClientName(teammates[1], name, sizeof(name));
1468 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1469 				BotSayTeamOrder(bs, teammates[1]);
1470 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
1471 				break;
1472 			}
1473 			case 3:
1474 			{
1475 				//the one closest to the base will defend the base
1476 				ClientName(teammates[0], name, sizeof(name));
1477 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1478 				BotSayTeamOrder(bs, teammates[0]);
1479 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1480 				//the second one closest to the base will defend the base
1481 				ClientName(teammates[1], name, sizeof(name));
1482 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1483 				BotSayTeamOrder(bs, teammates[1]);
1484 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1485 				//the other will get the flag
1486 				ClientName(teammates[2], name, sizeof(name));
1487 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1488 				BotSayTeamOrder(bs, teammates[2]);
1489 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
1490 				break;
1491 			}
1492 			default:
1493 			{
1494 				//50% defend the base
1495 				defenders = (int) (float) numteammates * 0.5 + 0.5;
1496 				if (defenders > 5) defenders = 5;
1497 				//40% get the flag
1498 				attackers = (int) (float) numteammates * 0.4 + 0.5;
1499 				if (attackers > 4) attackers = 4;
1500 				for (i = 0; i < defenders; i++) {
1501 					//
1502 					ClientName(teammates[i], name, sizeof(name));
1503 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1504 					BotSayTeamOrder(bs, teammates[i]);
1505 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1506 				}
1507 				for (i = 0; i < attackers; i++) {
1508 					//
1509 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1510 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1511 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1512 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
1513 				}
1514 				//
1515 				break;
1516 			}
1517 		}
1518 	}
1519 	else { //agressive
1520 		//different orders based on the number of team mates
1521 		switch(numteammates) {
1522 			case 1: break;
1523 			case 2:
1524 			{
1525 				//the one closest to the base will defend the base
1526 				ClientName(teammates[0], name, sizeof(name));
1527 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1528 				BotSayTeamOrder(bs, teammates[0]);
1529 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1530 				//the other will get the flag
1531 				ClientName(teammates[1], name, sizeof(name));
1532 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1533 				BotSayTeamOrder(bs, teammates[1]);
1534 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
1535 				break;
1536 			}
1537 			case 3:
1538 			{
1539 				//the one closest to the base will defend the base
1540 				ClientName(teammates[0], name, sizeof(name));
1541 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1542 				BotSayTeamOrder(bs, teammates[0]);
1543 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1544 				//the others should go for the enemy flag
1545 				ClientName(teammates[1], name, sizeof(name));
1546 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1547 				BotSayTeamOrder(bs, teammates[1]);
1548 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
1549 				//
1550 				ClientName(teammates[2], name, sizeof(name));
1551 				BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1552 				BotSayTeamOrder(bs, teammates[2]);
1553 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
1554 				break;
1555 			}
1556 			default:
1557 			{
1558 				//30% defend the base
1559 				defenders = (int) (float) numteammates * 0.3 + 0.5;
1560 				if (defenders > 3) defenders = 3;
1561 				//60% get the flag
1562 				attackers = (int) (float) numteammates * 0.6 + 0.5;
1563 				if (attackers > 6) attackers = 6;
1564 				for (i = 0; i < defenders; i++) {
1565 					//
1566 					ClientName(teammates[i], name, sizeof(name));
1567 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1568 					BotSayTeamOrder(bs, teammates[i]);
1569 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1570 				}
1571 				for (i = 0; i < attackers; i++) {
1572 					//
1573 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1574 					BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
1575 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1576 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_DEFEND);
1577 				}
1578 				//
1579 				break;
1580 			}
1581 		}
1582 	}
1583 }
1584 
1585 /*
1586 ==================
1587 Bot1FCTFOrders
1588 ==================
1589 */
Bot1FCTFOrders(bot_state_t * bs)1590 void Bot1FCTFOrders(bot_state_t *bs) {
1591 	switch(bs->neutralflagstatus) {
1592 		case 0: Bot1FCTFOrders_FlagAtCenter(bs); break;
1593 		case 1: Bot1FCTFOrders_TeamHasFlag(bs); break;
1594 		case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break;
1595 		case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break;
1596 	}
1597 }
1598 
1599 /*
1600 ==================
1601 BotObeliskOrders
1602 
1603   X% in defence Y% in offence
1604 ==================
1605 */
BotObeliskOrders(bot_state_t * bs)1606 void BotObeliskOrders(bot_state_t *bs) {
1607 	int numteammates, defenders, attackers, i;
1608 	int teammates[MAX_CLIENTS];
1609 	char name[MAX_NETNAME];
1610 
1611 	//sort team mates by travel time to base
1612 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
1613 	//sort team mates by CTF preference
1614 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
1615 	//passive strategy
1616 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
1617 		//different orders based on the number of team mates
1618 		switch(numteammates) {
1619 			case 1: break;
1620 			case 2:
1621 			{
1622 				//the one closest to the base will defend the base
1623 				ClientName(teammates[0], name, sizeof(name));
1624 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1625 				BotSayTeamOrder(bs, teammates[0]);
1626 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1627 				//the other will attack the enemy base
1628 				ClientName(teammates[1], name, sizeof(name));
1629 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1630 				BotSayTeamOrder(bs, teammates[1]);
1631 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1632 				break;
1633 			}
1634 			case 3:
1635 			{
1636 				//the one closest to the base will defend the base
1637 				ClientName(teammates[0], name, sizeof(name));
1638 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1639 				BotSayTeamOrder(bs, teammates[0]);
1640 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1641 				//the one second closest to the base also defends the base
1642 				ClientName(teammates[1], name, sizeof(name));
1643 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1644 				BotSayTeamOrder(bs, teammates[1]);
1645 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1646 				//the other one attacks the enemy base
1647 				ClientName(teammates[2], name, sizeof(name));
1648 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1649 				BotSayTeamOrder(bs, teammates[2]);
1650 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
1651 				break;
1652 			}
1653 			default:
1654 			{
1655 				//50% defend the base
1656 				defenders = (int) (float) numteammates * 0.5 + 0.5;
1657 				if (defenders > 5) defenders = 5;
1658 				//40% attack the enemy base
1659 				attackers = (int) (float) numteammates * 0.4 + 0.5;
1660 				if (attackers > 4) attackers = 4;
1661 				for (i = 0; i < defenders; i++) {
1662 					//
1663 					ClientName(teammates[i], name, sizeof(name));
1664 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1665 					BotSayTeamOrder(bs, teammates[i]);
1666 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1667 				}
1668 				for (i = 0; i < attackers; i++) {
1669 					//
1670 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1671 					BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1672 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1673 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
1674 				}
1675 				//
1676 				break;
1677 			}
1678 		}
1679 	}
1680 	else {
1681 		//different orders based on the number of team mates
1682 		switch(numteammates) {
1683 			case 1: break;
1684 			case 2:
1685 			{
1686 				//the one closest to the base will defend the base
1687 				ClientName(teammates[0], name, sizeof(name));
1688 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1689 				BotSayTeamOrder(bs, teammates[0]);
1690 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1691 				//the other will attack the enemy base
1692 				ClientName(teammates[1], name, sizeof(name));
1693 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1694 				BotSayTeamOrder(bs, teammates[1]);
1695 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1696 				break;
1697 			}
1698 			case 3:
1699 			{
1700 				//the one closest to the base will defend the base
1701 				ClientName(teammates[0], name, sizeof(name));
1702 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1703 				BotSayTeamOrder(bs, teammates[0]);
1704 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1705 				//the others attack the enemy base
1706 				ClientName(teammates[1], name, sizeof(name));
1707 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1708 				BotSayTeamOrder(bs, teammates[1]);
1709 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1710 				//
1711 				ClientName(teammates[2], name, sizeof(name));
1712 				BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1713 				BotSayTeamOrder(bs, teammates[2]);
1714 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
1715 				break;
1716 			}
1717 			default:
1718 			{
1719 				//30% defend the base
1720 				defenders = (int) (float) numteammates * 0.3 + 0.5;
1721 				if (defenders > 3) defenders = 3;
1722 				//70% attack the enemy base
1723 				attackers = (int) (float) numteammates * 0.7 + 0.5;
1724 				if (attackers > 7) attackers = 7;
1725 				for (i = 0; i < defenders; i++) {
1726 					//
1727 					ClientName(teammates[i], name, sizeof(name));
1728 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1729 					BotSayTeamOrder(bs, teammates[i]);
1730 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1731 				}
1732 				for (i = 0; i < attackers; i++) {
1733 					//
1734 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1735 					BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
1736 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1737 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
1738 				}
1739 				//
1740 				break;
1741 			}
1742 		}
1743 	}
1744 }
1745 
1746 /*
1747 ==================
1748 BotHarvesterOrders
1749 
1750   X% defend the base, Y% harvest
1751 ==================
1752 */
BotHarvesterOrders(bot_state_t * bs)1753 void BotHarvesterOrders(bot_state_t *bs) {
1754 	int numteammates, defenders, attackers, i;
1755 	int teammates[MAX_CLIENTS];
1756 	char name[MAX_NETNAME];
1757 
1758 	//sort team mates by travel time to base
1759 	numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
1760 	//sort team mates by CTF preference
1761 	BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
1762 	//passive strategy
1763 	if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
1764 		//different orders based on the number of team mates
1765 		switch(numteammates) {
1766 			case 1: break;
1767 			case 2:
1768 			{
1769 				//the one closest to the base will defend the base
1770 				ClientName(teammates[0], name, sizeof(name));
1771 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1772 				BotSayTeamOrder(bs, teammates[0]);
1773 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1774 				//the other will harvest
1775 				ClientName(teammates[1], name, sizeof(name));
1776 				BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1777 				BotSayTeamOrder(bs, teammates[1]);
1778 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1779 				break;
1780 			}
1781 			case 3:
1782 			{
1783 				//the one closest to the base will defend the base
1784 				ClientName(teammates[0], name, sizeof(name));
1785 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1786 				BotSayTeamOrder(bs, teammates[0]);
1787 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1788 				//the one second closest to the base also defends the base
1789 				ClientName(teammates[1], name, sizeof(name));
1790 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1791 				BotSayTeamOrder(bs, teammates[1]);
1792 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
1793 				//the other one goes harvesting
1794 				ClientName(teammates[2], name, sizeof(name));
1795 				BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1796 				BotSayTeamOrder(bs, teammates[2]);
1797 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
1798 				break;
1799 			}
1800 			default:
1801 			{
1802 				//50% defend the base
1803 				defenders = (int) (float) numteammates * 0.5 + 0.5;
1804 				if (defenders > 5) defenders = 5;
1805 				//40% goes harvesting
1806 				attackers = (int) (float) numteammates * 0.4 + 0.5;
1807 				if (attackers > 4) attackers = 4;
1808 				for (i = 0; i < defenders; i++) {
1809 					//
1810 					ClientName(teammates[i], name, sizeof(name));
1811 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1812 					BotSayTeamOrder(bs, teammates[i]);
1813 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1814 				}
1815 				for (i = 0; i < attackers; i++) {
1816 					//
1817 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1818 					BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1819 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1820 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
1821 				}
1822 				//
1823 				break;
1824 			}
1825 		}
1826 	}
1827 	else {
1828 		//different orders based on the number of team mates
1829 		switch(numteammates) {
1830 			case 1: break;
1831 			case 2:
1832 			{
1833 				//the one closest to the base will defend the base
1834 				ClientName(teammates[0], name, sizeof(name));
1835 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1836 				BotSayTeamOrder(bs, teammates[0]);
1837 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1838 				//the other will harvest
1839 				ClientName(teammates[1], name, sizeof(name));
1840 				BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1841 				BotSayTeamOrder(bs, teammates[1]);
1842 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1843 				break;
1844 			}
1845 			case 3:
1846 			{
1847 				//the one closest to the base will defend the base
1848 				ClientName(teammates[0], name, sizeof(name));
1849 				BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1850 				BotSayTeamOrder(bs, teammates[0]);
1851 				BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
1852 				//the others go harvesting
1853 				ClientName(teammates[1], name, sizeof(name));
1854 				BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1855 				BotSayTeamOrder(bs, teammates[1]);
1856 				BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
1857 				//
1858 				ClientName(teammates[2], name, sizeof(name));
1859 				BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1860 				BotSayTeamOrder(bs, teammates[2]);
1861 				BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
1862 				break;
1863 			}
1864 			default:
1865 			{
1866 				//30% defend the base
1867 				defenders = (int) (float) numteammates * 0.3 + 0.5;
1868 				if (defenders > 3) defenders = 3;
1869 				//70% go harvesting
1870 				attackers = (int) (float) numteammates * 0.7 + 0.5;
1871 				if (attackers > 7) attackers = 7;
1872 				for (i = 0; i < defenders; i++) {
1873 					//
1874 					ClientName(teammates[i], name, sizeof(name));
1875 					BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
1876 					BotSayTeamOrder(bs, teammates[i]);
1877 					BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
1878 				}
1879 				for (i = 0; i < attackers; i++) {
1880 					//
1881 					ClientName(teammates[numteammates - i - 1], name, sizeof(name));
1882 					BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
1883 					BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
1884 					BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
1885 				}
1886 				//
1887 				break;
1888 			}
1889 		}
1890 	}
1891 }
1892 #endif
1893 
1894 /*
1895 ==================
1896 FindHumanTeamLeader
1897 ==================
1898 */
FindHumanTeamLeader(bot_state_t * bs)1899 int FindHumanTeamLeader(bot_state_t *bs) {
1900 	int i;
1901 
1902 	for (i = 0; i < MAX_CLIENTS; i++) {
1903 		if ( g_entities[i].inuse ) {
1904 			// if this player is not a bot
1905 			if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
1906 				// if this player is ok with being the leader
1907 				if (!notleader[i]) {
1908 					// if this player is on the same team
1909 					if ( BotSameTeam(bs, i) ) {
1910 						ClientName(i, bs->teamleader, sizeof(bs->teamleader));
1911 						// if not yet ordered to do anything
1912 						if ( !BotSetLastOrderedTask(bs) ) {
1913 							// go on defense by default
1914 							BotVoiceChat_Defend(bs, i, SAY_TELL);
1915 						}
1916 						return qtrue;
1917 					}
1918 				}
1919 			}
1920 		}
1921 	}
1922 	return qfalse;
1923 }
1924 
1925 /*
1926 ==================
1927 BotTeamAI
1928 ==================
1929 */
BotTeamAI(bot_state_t * bs)1930 void BotTeamAI(bot_state_t *bs) {
1931 	int numteammates;
1932 	char netname[MAX_NETNAME];
1933 
1934 	//
1935 	if ( gametype < GT_TEAM  )
1936 		return;
1937 	// make sure we've got a valid team leader
1938 	if (!BotValidTeamLeader(bs)) {
1939 		//
1940 		if (!FindHumanTeamLeader(bs)) {
1941 			//
1942 			if (!bs->askteamleader_time && !bs->becometeamleader_time) {
1943 				if (bs->entergame_time + 10 > FloatTime()) {
1944 					bs->askteamleader_time = FloatTime() + 5 + random() * 10;
1945 				}
1946 				else {
1947 					bs->becometeamleader_time = FloatTime() + 5 + random() * 10;
1948 				}
1949 			}
1950 			if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {
1951 				// if asked for a team leader and no response
1952 				BotAI_BotInitialChat(bs, "whoisteamleader", NULL);
1953 				trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
1954 				bs->askteamleader_time = 0;
1955 				bs->becometeamleader_time = FloatTime() + 8 + random() * 10;
1956 			}
1957 			if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {
1958 				BotAI_BotInitialChat(bs, "iamteamleader", NULL);
1959 				trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
1960 				BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);
1961 				ClientName(bs->client, netname, sizeof(netname));
1962 				strncpy(bs->teamleader, netname, sizeof(bs->teamleader));
1963 				bs->teamleader[sizeof(bs->teamleader)-1] = '\0';
1964 				bs->becometeamleader_time = 0;
1965 			}
1966 			return;
1967 		}
1968 	}
1969 	bs->askteamleader_time = 0;
1970 	bs->becometeamleader_time = 0;
1971 
1972 	//return if this bot is NOT the team leader
1973 	ClientName(bs->client, netname, sizeof(netname));
1974 	if (Q_stricmp(netname, bs->teamleader) != 0) return;
1975 	//
1976 	numteammates = BotNumTeamMates(bs);
1977 	//give orders
1978 	switch(gametype) {
1979 		case GT_TEAM:
1980 		{
1981 			if (bs->numteammates != numteammates || bs->forceorders) {
1982 				bs->teamgiveorders_time = FloatTime();
1983 				bs->numteammates = numteammates;
1984 				bs->forceorders = qfalse;
1985 			}
1986 			//if it's time to give orders
1987 			if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
1988 				BotTeamOrders(bs);
1989 				//give orders again after 120 seconds
1990 				bs->teamgiveorders_time = FloatTime() + 120;
1991 			}
1992 			break;
1993 		}
1994 		case GT_CTF:
1995 		{
1996 			//if the number of team mates changed or the flag status changed
1997 			//or someone wants to know what to do
1998 			if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
1999 				bs->teamgiveorders_time = FloatTime();
2000 				bs->numteammates = numteammates;
2001 				bs->flagstatuschanged = qfalse;
2002 				bs->forceorders = qfalse;
2003 			}
2004 			//if there were no flag captures the last 3 minutes
2005 			if (bs->lastflagcapture_time < FloatTime() - 240) {
2006 				bs->lastflagcapture_time = FloatTime();
2007 				//randomly change the CTF strategy
2008 				if (random() < 0.4) {
2009 					bs->ctfstrategy ^= CTFS_AGRESSIVE;
2010 					bs->teamgiveorders_time = FloatTime();
2011 				}
2012 			}
2013 			//if it's time to give orders
2014 			if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
2015 				BotCTFOrders(bs);
2016 				//
2017 				bs->teamgiveorders_time = 0;
2018 			}
2019 			break;
2020 		}
2021 #ifdef MISSIONPACK
2022 		case GT_1FCTF:
2023 		{
2024 			if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
2025 				bs->teamgiveorders_time = FloatTime();
2026 				bs->numteammates = numteammates;
2027 				bs->flagstatuschanged = qfalse;
2028 				bs->forceorders = qfalse;
2029 			}
2030 			//if there were no flag captures the last 4 minutes
2031 			if (bs->lastflagcapture_time < FloatTime() - 240) {
2032 				bs->lastflagcapture_time = FloatTime();
2033 				//randomly change the CTF strategy
2034 				if (random() < 0.4) {
2035 					bs->ctfstrategy ^= CTFS_AGRESSIVE;
2036 					bs->teamgiveorders_time = FloatTime();
2037 				}
2038 			}
2039 			//if it's time to give orders
2040 			if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) {
2041 				Bot1FCTFOrders(bs);
2042 				//
2043 				bs->teamgiveorders_time = 0;
2044 			}
2045 			break;
2046 		}
2047 		case GT_OBELISK:
2048 		{
2049 			if (bs->numteammates != numteammates || bs->forceorders) {
2050 				bs->teamgiveorders_time = FloatTime();
2051 				bs->numteammates = numteammates;
2052 				bs->forceorders = qfalse;
2053 			}
2054 			//if it's time to give orders
2055 			if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
2056 				BotObeliskOrders(bs);
2057 				//give orders again after 30 seconds
2058 				bs->teamgiveorders_time = FloatTime() + 30;
2059 			}
2060 			break;
2061 		}
2062 		case GT_HARVESTER:
2063 		{
2064 			if (bs->numteammates != numteammates || bs->forceorders) {
2065 				bs->teamgiveorders_time = FloatTime();
2066 				bs->numteammates = numteammates;
2067 				bs->forceorders = qfalse;
2068 			}
2069 			//if it's time to give orders
2070 			if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
2071 				BotHarvesterOrders(bs);
2072 				//give orders again after 30 seconds
2073 				bs->teamgiveorders_time = FloatTime() + 30;
2074 			}
2075 			break;
2076 		}
2077 #endif
2078 	}
2079 }
2080 
2081