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