Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ai_team.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 
00024 /*****************************************************************************
00025  * name:        ai_team.c
00026  *
00027  * desc:        Quake3 bot AI
00028  *
00029  * $Archive: /MissionPack/code/game/ai_team.c $
00030  *
00031  *****************************************************************************/
00032 
00033 #include "g_local.h"
00034 #include "botlib.h"
00035 #include "be_aas.h"
00036 #include "be_ea.h"
00037 #include "be_ai_char.h"
00038 #include "be_ai_chat.h"
00039 #include "be_ai_gen.h"
00040 #include "be_ai_goal.h"
00041 #include "be_ai_move.h"
00042 #include "be_ai_weap.h"
00043 //
00044 #include "ai_main.h"
00045 #include "ai_dmq3.h"
00046 #include "ai_chat.h"
00047 #include "ai_cmd.h"
00048 #include "ai_dmnet.h"
00049 #include "ai_team.h"
00050 #include "ai_vcmd.h"
00051 
00052 #include "match.h"
00053 
00054 // for the voice chats
00055 #include "../../ui/menudef.h"
00056 
00057 //ctf task preferences for a client
00058 typedef struct bot_ctftaskpreference_s
00059 {
00060     char        name[36];
00061     int         preference;
00062 } bot_ctftaskpreference_t;
00063 
00064 bot_ctftaskpreference_t ctftaskpreferences[MAX_CLIENTS];
00065 
00066 
00067 /*
00068 ==================
00069 BotValidTeamLeader
00070 ==================
00071 */
00072 int BotValidTeamLeader(bot_state_t *bs) {
00073     if (!strlen(bs->teamleader)) return qfalse;
00074     if (ClientFromName(bs->teamleader) == -1) return qfalse;
00075     return qtrue;
00076 }
00077 
00078 /*
00079 ==================
00080 BotNumTeamMates
00081 ==================
00082 */
00083 int BotNumTeamMates(bot_state_t *bs) {
00084     int i, numplayers;
00085     char buf[MAX_INFO_STRING];
00086     static int maxclients;
00087 
00088     if (!maxclients)
00089         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00090 
00091     numplayers = 0;
00092     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00093         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00094         //if no config string or no name
00095         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00096         //skip spectators
00097         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00098         //
00099         if (BotSameTeam(bs, i)) {
00100             numplayers++;
00101         }
00102     }
00103     return numplayers;
00104 }
00105 
00106 /*
00107 ==================
00108 BotClientTravelTimeToGoal
00109 ==================
00110 */
00111 int BotClientTravelTimeToGoal(int client, bot_goal_t *goal) {
00112     playerState_t ps;
00113     int areanum;
00114 
00115     BotAI_GetClientState(client, &ps);
00116     areanum = BotPointAreaNum(ps.origin);
00117     if (!areanum) return 1;
00118     return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
00119 }
00120 
00121 /*
00122 ==================
00123 BotSortTeamMatesByBaseTravelTime
00124 ==================
00125 */
00126 int BotSortTeamMatesByBaseTravelTime(bot_state_t *bs, int *teammates, int maxteammates) {
00127 
00128     int i, j, k, numteammates, traveltime;
00129     char buf[MAX_INFO_STRING];
00130     static int maxclients;
00131     int traveltimes[MAX_CLIENTS];
00132     bot_goal_t *goal = NULL;
00133 
00134     if (gametype == GT_CTF || gametype == GT_1FCTF) {
00135         if (BotTeam(bs) == TEAM_RED)
00136             goal = &ctf_redflag;
00137         else
00138             goal = &ctf_blueflag;
00139     }
00140 #ifdef MISSIONPACK
00141     else {
00142         if (BotTeam(bs) == TEAM_RED)
00143             goal = &redobelisk;
00144         else
00145             goal = &blueobelisk;
00146     }
00147 #endif
00148     if (!maxclients)
00149         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00150 
00151     numteammates = 0;
00152     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00153         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00154         //if no config string or no name
00155         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00156         //skip spectators
00157         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00158         //
00159         if (BotSameTeam(bs, i)) {
00160             //
00161             traveltime = BotClientTravelTimeToGoal(i, goal);
00162             //
00163             for (j = 0; j < numteammates; j++) {
00164                 if (traveltime < traveltimes[j]) {
00165                     for (k = numteammates; k > j; k--) {
00166                         traveltimes[k] = traveltimes[k-1];
00167                         teammates[k] = teammates[k-1];
00168                     }
00169                     break;
00170                 }
00171             }
00172             traveltimes[j] = traveltime;
00173             teammates[j] = i;
00174             numteammates++;
00175             if (numteammates >= maxteammates) break;
00176         }
00177     }
00178     return numteammates;
00179 }
00180 
00181 /*
00182 ==================
00183 BotSetTeamMateTaskPreference
00184 ==================
00185 */
00186 void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference) {
00187     char teammatename[MAX_NETNAME];
00188 
00189     ctftaskpreferences[teammate].preference = preference;
00190     ClientName(teammate, teammatename, sizeof(teammatename));
00191     strcpy(ctftaskpreferences[teammate].name, teammatename);
00192 }
00193 
00194 /*
00195 ==================
00196 BotGetTeamMateTaskPreference
00197 ==================
00198 */
00199 int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate) {
00200     char teammatename[MAX_NETNAME];
00201 
00202     if (!ctftaskpreferences[teammate].preference) return 0;
00203     ClientName(teammate, teammatename, sizeof(teammatename));
00204     if (Q_stricmp(teammatename, ctftaskpreferences[teammate].name)) return 0;
00205     return ctftaskpreferences[teammate].preference;
00206 }
00207 
00208 /*
00209 ==================
00210 BotSortTeamMatesByTaskPreference
00211 ==================
00212 */
00213 int BotSortTeamMatesByTaskPreference(bot_state_t *bs, int *teammates, int numteammates) {
00214     int defenders[MAX_CLIENTS], numdefenders;
00215     int attackers[MAX_CLIENTS], numattackers;
00216     int roamers[MAX_CLIENTS], numroamers;
00217     int i, preference;
00218 
00219     numdefenders = numattackers = numroamers = 0;
00220     for (i = 0; i < numteammates; i++) {
00221         preference = BotGetTeamMateTaskPreference(bs, teammates[i]);
00222         if (preference & TEAMTP_DEFENDER) {
00223             defenders[numdefenders++] = teammates[i];
00224         }
00225         else if (preference & TEAMTP_ATTACKER) {
00226             attackers[numattackers++] = teammates[i];
00227         }
00228         else {
00229             roamers[numroamers++] = teammates[i];
00230         }
00231     }
00232     numteammates = 0;
00233     //defenders at the front of the list
00234     memcpy(&teammates[numteammates], defenders, numdefenders * sizeof(int));
00235     numteammates += numdefenders;
00236     //roamers in the middle
00237     memcpy(&teammates[numteammates], roamers, numroamers * sizeof(int));
00238     numteammates += numroamers;
00239     //attacker in the back of the list
00240     memcpy(&teammates[numteammates], attackers, numattackers * sizeof(int));
00241     numteammates += numattackers;
00242 
00243     return numteammates;
00244 }
00245 
00246 /*
00247 ==================
00248 BotSayTeamOrders
00249 ==================
00250 */
00251 void BotSayTeamOrderAlways(bot_state_t *bs, int toclient) {
00252     char teamchat[MAX_MESSAGE_SIZE];
00253     char buf[MAX_MESSAGE_SIZE];
00254     char name[MAX_NETNAME];
00255 
00256     //if the bot is talking to itself
00257     if (bs->client == toclient) {
00258         //don't show the message just put it in the console message queue
00259         trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
00260         ClientName(bs->client, name, sizeof(name));
00261         Com_sprintf(teamchat, sizeof(teamchat), EC"(%s"EC")"EC": %s", name, buf);
00262         trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, teamchat);
00263     }
00264     else {
00265         trap_BotEnterChat(bs->cs, toclient, CHAT_TELL);
00266     }
00267 }
00268 
00269 /*
00270 ==================
00271 BotSayTeamOrders
00272 ==================
00273 */
00274 void BotSayTeamOrder(bot_state_t *bs, int toclient) {
00275 #ifdef MISSIONPACK
00276     // voice chats only
00277     char buf[MAX_MESSAGE_SIZE];
00278 
00279     trap_BotGetChatMessage(bs->cs, buf, sizeof(buf));
00280 #else
00281     BotSayTeamOrderAlways(bs, toclient);
00282 #endif
00283 }
00284 
00285 /*
00286 ==================
00287 BotVoiceChat
00288 ==================
00289 */
00290 void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat) {
00291 #ifdef MISSIONPACK
00292     if (toclient == -1)
00293         // voice only say team
00294         trap_EA_Command(bs->client, va("vsay_team %s", voicechat));
00295     else
00296         // voice only tell single player
00297         trap_EA_Command(bs->client, va("vtell %d %s", toclient, voicechat));
00298 #endif
00299 }
00300 
00301 /*
00302 ==================
00303 BotVoiceChatOnly
00304 ==================
00305 */
00306 void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat) {
00307 #ifdef MISSIONPACK
00308     if (toclient == -1)
00309         // voice only say team
00310         trap_EA_Command(bs->client, va("vosay_team %s", voicechat));
00311     else
00312         // voice only tell single player
00313         trap_EA_Command(bs->client, va("votell %d %s", toclient, voicechat));
00314 #endif
00315 }
00316 
00317 /*
00318 ==================
00319 BotSayVoiceTeamOrder
00320 ==================
00321 */
00322 void BotSayVoiceTeamOrder(bot_state_t *bs, int toclient, char *voicechat) {
00323 #ifdef MISSIONPACK
00324     BotVoiceChat(bs, toclient, voicechat);
00325 #endif
00326 }
00327 
00328 /*
00329 ==================
00330 BotCTFOrders
00331 ==================
00332 */
00333 void BotCTFOrders_BothFlagsNotAtBase(bot_state_t *bs) {
00334     int numteammates, defenders, attackers, i, other;
00335     int teammates[MAX_CLIENTS];
00336     char name[MAX_NETNAME], carriername[MAX_NETNAME];
00337 
00338     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
00339     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
00340     //different orders based on the number of team mates
00341     switch(bs->numteammates) {
00342         case 1: break;
00343         case 2:
00344         {
00345             //tell the one not carrying the flag to attack the enemy base
00346             if (teammates[0] != bs->flagcarrier) other = teammates[0];
00347             else other = teammates[1];
00348             ClientName(other, name, sizeof(name));
00349             BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00350             BotSayTeamOrder(bs, other);
00351             BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
00352             break;
00353         }
00354         case 3:
00355         {
00356             //tell the one closest to the base not carrying the flag to accompany the flag carrier
00357             if (teammates[0] != bs->flagcarrier) other = teammates[0];
00358             else other = teammates[1];
00359             ClientName(other, name, sizeof(name));
00360             if ( bs->flagcarrier != -1 ) {
00361                 ClientName(bs->flagcarrier, carriername, sizeof(carriername));
00362                 if (bs->flagcarrier == bs->client) {
00363                     BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
00364                     BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
00365                 }
00366                 else {
00367                     BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
00368                     BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
00369                 }
00370             }
00371             else {
00372                 //
00373                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00374                 BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
00375             }
00376             BotSayTeamOrder(bs, other);
00377             //tell the one furthest from the the base not carrying the flag to get the enemy flag
00378             if (teammates[2] != bs->flagcarrier) other = teammates[2];
00379             else other = teammates[1];
00380             ClientName(other, name, sizeof(name));
00381             BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00382             BotSayTeamOrder(bs, other);
00383             BotSayVoiceTeamOrder(bs, other, VOICECHAT_RETURNFLAG);
00384             break;
00385         }
00386         default:
00387         {
00388             defenders = (int) (float) numteammates * 0.4 + 0.5;
00389             if (defenders > 4) defenders = 4;
00390             attackers = (int) (float) numteammates * 0.5 + 0.5;
00391             if (attackers > 5) attackers = 5;
00392             if (bs->flagcarrier != -1) {
00393                 ClientName(bs->flagcarrier, carriername, sizeof(carriername));
00394                 for (i = 0; i < defenders; i++) {
00395                     //
00396                     if (teammates[i] == bs->flagcarrier) {
00397                         continue;
00398                     }
00399                     //
00400                     ClientName(teammates[i], name, sizeof(name));
00401                     if (bs->flagcarrier == bs->client) {
00402                         BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
00403                         BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWME);
00404                     }
00405                     else {
00406                         BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
00407                         BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_FOLLOWFLAGCARRIER);
00408                     }
00409                     BotSayTeamOrder(bs, teammates[i]);
00410                 }
00411             }
00412             else {
00413                 for (i = 0; i < defenders; i++) {
00414                     //
00415                     if (teammates[i] == bs->flagcarrier) {
00416                         continue;
00417                     }
00418                     //
00419                     ClientName(teammates[i], name, sizeof(name));
00420                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00421                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_GETFLAG);
00422                     BotSayTeamOrder(bs, teammates[i]);
00423                 }
00424             }
00425             for (i = 0; i < attackers; i++) {
00426                 //
00427                 if (teammates[numteammates - i - 1] == bs->flagcarrier) {
00428                     continue;
00429                 }
00430                 //
00431                 ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00432                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00433                 BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00434                 BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_RETURNFLAG);
00435             }
00436             //
00437             break;
00438         }
00439     }
00440 }
00441 
00442 /*
00443 ==================
00444 BotCTFOrders
00445 ==================
00446 */
00447 void BotCTFOrders_FlagNotAtBase(bot_state_t *bs) {
00448     int numteammates, defenders, attackers, i;
00449     int teammates[MAX_CLIENTS];
00450     char name[MAX_NETNAME];
00451 
00452     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
00453     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
00454     //passive strategy
00455     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
00456         //different orders based on the number of team mates
00457         switch(bs->numteammates) {
00458             case 1: break;
00459             case 2:
00460             {
00461                 //both will go for the enemy flag
00462                 ClientName(teammates[0], name, sizeof(name));
00463                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00464                 BotSayTeamOrder(bs, teammates[0]);
00465                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
00466                 //
00467                 ClientName(teammates[1], name, sizeof(name));
00468                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00469                 BotSayTeamOrder(bs, teammates[1]);
00470                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00471                 break;
00472             }
00473             case 3:
00474             {
00475                 //keep one near the base for when the flag is returned
00476                 ClientName(teammates[0], name, sizeof(name));
00477                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00478                 BotSayTeamOrder(bs, teammates[0]);
00479                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00480                 //the other two get the flag
00481                 ClientName(teammates[1], name, sizeof(name));
00482                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00483                 BotSayTeamOrder(bs, teammates[1]);
00484                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00485                 //
00486                 ClientName(teammates[2], name, sizeof(name));
00487                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00488                 BotSayTeamOrder(bs, teammates[2]);
00489                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
00490                 break;
00491             }
00492             default:
00493             {
00494                 //keep some people near the base for when the flag is returned
00495                 defenders = (int) (float) numteammates * 0.3 + 0.5;
00496                 if (defenders > 3) defenders = 3;
00497                 attackers = (int) (float) numteammates * 0.7 + 0.5;
00498                 if (attackers > 6) attackers = 6;
00499                 for (i = 0; i < defenders; i++) {
00500                     //
00501                     ClientName(teammates[i], name, sizeof(name));
00502                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00503                     BotSayTeamOrder(bs, teammates[i]);
00504                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
00505                 }
00506                 for (i = 0; i < attackers; i++) {
00507                     //
00508                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00509                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00510                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00511                     BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
00512                 }
00513                 //
00514                 break;
00515             }
00516         }
00517     }
00518     else {
00519         //different orders based on the number of team mates
00520         switch(bs->numteammates) {
00521             case 1: break;
00522             case 2:
00523             {
00524                 //both will go for the enemy flag
00525                 ClientName(teammates[0], name, sizeof(name));
00526                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00527                 BotSayTeamOrder(bs, teammates[0]);
00528                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
00529                 //
00530                 ClientName(teammates[1], name, sizeof(name));
00531                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00532                 BotSayTeamOrder(bs, teammates[1]);
00533                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00534                 break;
00535             }
00536             case 3:
00537             {
00538                 //everyone go for the flag
00539                 ClientName(teammates[0], name, sizeof(name));
00540                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00541                 BotSayTeamOrder(bs, teammates[0]);
00542                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_GETFLAG);
00543                 //
00544                 ClientName(teammates[1], name, sizeof(name));
00545                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00546                 BotSayTeamOrder(bs, teammates[1]);
00547                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00548                 //
00549                 ClientName(teammates[2], name, sizeof(name));
00550                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00551                 BotSayTeamOrder(bs, teammates[2]);
00552                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
00553                 break;
00554             }
00555             default:
00556             {
00557                 //keep some people near the base for when the flag is returned
00558                 defenders = (int) (float) numteammates * 0.2 + 0.5;
00559                 if (defenders > 2) defenders = 2;
00560                 attackers = (int) (float) numteammates * 0.7 + 0.5;
00561                 if (attackers > 7) attackers = 7;
00562                 for (i = 0; i < defenders; i++) {
00563                     //
00564                     ClientName(teammates[i], name, sizeof(name));
00565                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00566                     BotSayTeamOrder(bs, teammates[i]);
00567                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
00568                 }
00569                 for (i = 0; i < attackers; i++) {
00570                     //
00571                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00572                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00573                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00574                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
00575                 }
00576                 //
00577                 break;
00578             }
00579         }
00580     }
00581 }
00582 
00583 /*
00584 ==================
00585 BotCTFOrders
00586 ==================
00587 */
00588 void BotCTFOrders_EnemyFlagNotAtBase(bot_state_t *bs) {
00589     int numteammates, defenders, attackers, i, other;
00590     int teammates[MAX_CLIENTS];
00591     char name[MAX_NETNAME], carriername[MAX_NETNAME];
00592 
00593     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
00594     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
00595     //different orders based on the number of team mates
00596     switch(numteammates) {
00597         case 1: break;
00598         case 2:
00599         {
00600             //tell the one not carrying the flag to defend the base
00601             if (teammates[0] == bs->flagcarrier) other = teammates[1];
00602             else other = teammates[0];
00603             ClientName(other, name, sizeof(name));
00604             BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00605             BotSayTeamOrder(bs, other);
00606             BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
00607             break;
00608         }
00609         case 3:
00610         {
00611             //tell the one closest to the base not carrying the flag to defend the base
00612             if (teammates[0] != bs->flagcarrier) other = teammates[0];
00613             else other = teammates[1];
00614             ClientName(other, name, sizeof(name));
00615             BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00616             BotSayTeamOrder(bs, other);
00617             BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
00618             //tell the other also to defend the base
00619             if (teammates[2] != bs->flagcarrier) other = teammates[2];
00620             else other = teammates[1];
00621             ClientName(other, name, sizeof(name));
00622             BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00623             BotSayTeamOrder(bs, other);
00624             BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
00625             break;
00626         }
00627         default:
00628         {
00629             //60% will defend the base
00630             defenders = (int) (float) numteammates * 0.6 + 0.5;
00631             if (defenders > 6) defenders = 6;
00632             //30% accompanies the flag carrier
00633             attackers = (int) (float) numteammates * 0.3 + 0.5;
00634             if (attackers > 3) attackers = 3;
00635             for (i = 0; i < defenders; i++) {
00636                 //
00637                 if (teammates[i] == bs->flagcarrier) {
00638                     continue;
00639                 }
00640                 ClientName(teammates[i], name, sizeof(name));
00641                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00642                 BotSayTeamOrder(bs, teammates[i]);
00643                 BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
00644             }
00645             // if we have a flag carrier
00646             if ( bs->flagcarrier != -1 ) {
00647                 ClientName(bs->flagcarrier, carriername, sizeof(carriername));
00648                 for (i = 0; i < attackers; i++) {
00649                     //
00650                     if (teammates[numteammates - i - 1] == bs->flagcarrier) {
00651                         continue;
00652                     }
00653                     //
00654                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00655                     if (bs->flagcarrier == bs->client) {
00656                         BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
00657                         BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
00658                     }
00659                     else {
00660                         BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
00661                         BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
00662                     }
00663                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00664                 }
00665             }
00666             else {
00667                 for (i = 0; i < attackers; i++) {
00668                     //
00669                     if (teammates[numteammates - i - 1] == bs->flagcarrier) {
00670                         continue;
00671                     }
00672                     //
00673                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00674                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00675                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
00676                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00677                 }
00678             }
00679             //
00680             break;
00681         }
00682     }
00683 }
00684 
00685 
00686 /*
00687 ==================
00688 BotCTFOrders
00689 ==================
00690 */
00691 void BotCTFOrders_BothFlagsAtBase(bot_state_t *bs) {
00692     int numteammates, defenders, attackers, i;
00693     int teammates[MAX_CLIENTS];
00694     char name[MAX_NETNAME];
00695 
00696     //sort team mates by travel time to base
00697     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
00698     //sort team mates by CTF preference
00699     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
00700     //passive strategy
00701     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
00702         //different orders based on the number of team mates
00703         switch(numteammates) {
00704             case 1: break;
00705             case 2:
00706             {
00707                 //the one closest to the base will defend the base
00708                 ClientName(teammates[0], name, sizeof(name));
00709                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00710                 BotSayTeamOrder(bs, teammates[0]);
00711                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00712                 //the other will get the flag
00713                 ClientName(teammates[1], name, sizeof(name));
00714                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00715                 BotSayTeamOrder(bs, teammates[1]);
00716                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00717                 break;
00718             }
00719             case 3:
00720             {
00721                 //the one closest to the base will defend the base
00722                 ClientName(teammates[0], name, sizeof(name));
00723                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00724                 BotSayTeamOrder(bs, teammates[0]);
00725                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00726                 //the second one closest to the base will defend the base
00727                 ClientName(teammates[1], name, sizeof(name));
00728                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00729                 BotSayTeamOrder(bs, teammates[1]);
00730                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
00731                 //the other will get the flag
00732                 ClientName(teammates[2], name, sizeof(name));
00733                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00734                 BotSayTeamOrder(bs, teammates[2]);
00735                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
00736                 break;
00737             }
00738             default:
00739             {
00740                 defenders = (int) (float) numteammates * 0.5 + 0.5;
00741                 if (defenders > 5) defenders = 5;
00742                 attackers = (int) (float) numteammates * 0.4 + 0.5;
00743                 if (attackers > 4) attackers = 4;
00744                 for (i = 0; i < defenders; i++) {
00745                     //
00746                     ClientName(teammates[i], name, sizeof(name));
00747                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00748                     BotSayTeamOrder(bs, teammates[i]);
00749                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
00750                 }
00751                 for (i = 0; i < attackers; i++) {
00752                     //
00753                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00754                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00755                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00756                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
00757                 }
00758                 //
00759                 break;
00760             }
00761         }
00762     }
00763     else {
00764         //different orders based on the number of team mates
00765         switch(numteammates) {
00766             case 1: break;
00767             case 2:
00768             {
00769                 //the one closest to the base will defend the base
00770                 ClientName(teammates[0], name, sizeof(name));
00771                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00772                 BotSayTeamOrder(bs, teammates[0]);
00773                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00774                 //the other will get the flag
00775                 ClientName(teammates[1], name, sizeof(name));
00776                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00777                 BotSayTeamOrder(bs, teammates[1]);
00778                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00779                 break;
00780             }
00781             case 3:
00782             {
00783                 //the one closest to the base will defend the base
00784                 ClientName(teammates[0], name, sizeof(name));
00785                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00786                 BotSayTeamOrder(bs, teammates[0]);
00787                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00788                 //the others should go for the enemy flag
00789                 ClientName(teammates[1], name, sizeof(name));
00790                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00791                 BotSayTeamOrder(bs, teammates[1]);
00792                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00793                 //
00794                 ClientName(teammates[2], name, sizeof(name));
00795                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00796                 BotSayTeamOrder(bs, teammates[2]);
00797                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
00798                 break;
00799             }
00800             default:
00801             {
00802                 defenders = (int) (float) numteammates * 0.4 + 0.5;
00803                 if (defenders > 4) defenders = 4;
00804                 attackers = (int) (float) numteammates * 0.5 + 0.5;
00805                 if (attackers > 5) attackers = 5;
00806                 for (i = 0; i < defenders; i++) {
00807                     //
00808                     ClientName(teammates[i], name, sizeof(name));
00809                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00810                     BotSayTeamOrder(bs, teammates[i]);
00811                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
00812                 }
00813                 for (i = 0; i < attackers; i++) {
00814                     //
00815                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
00816                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00817                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
00818                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
00819                 }
00820                 //
00821                 break;
00822             }
00823         }
00824     }
00825 }
00826 
00827 /*
00828 ==================
00829 BotCTFOrders
00830 ==================
00831 */
00832 void BotCTFOrders(bot_state_t *bs) {
00833     int flagstatus;
00834 
00835     //
00836     if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
00837     else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
00838     //
00839     switch(flagstatus) {
00840         case 0: BotCTFOrders_BothFlagsAtBase(bs); break;
00841         case 1: BotCTFOrders_EnemyFlagNotAtBase(bs); break;
00842         case 2: BotCTFOrders_FlagNotAtBase(bs); break;
00843         case 3: BotCTFOrders_BothFlagsNotAtBase(bs); break;
00844     }
00845 }
00846 
00847 
00848 /*
00849 ==================
00850 BotCreateGroup
00851 ==================
00852 */
00853 void BotCreateGroup(bot_state_t *bs, int *teammates, int groupsize) {
00854     char name[MAX_NETNAME], leadername[MAX_NETNAME];
00855     int i;
00856 
00857     // the others in the group will follow the teammates[0]
00858     ClientName(teammates[0], leadername, sizeof(leadername));
00859     for (i = 1; i < groupsize; i++)
00860     {
00861         ClientName(teammates[i], name, sizeof(name));
00862         if (teammates[0] == bs->client) {
00863             BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
00864         }
00865         else {
00866             BotAI_BotInitialChat(bs, "cmd_accompany", name, leadername, NULL);
00867         }
00868         BotSayTeamOrderAlways(bs, teammates[i]);
00869     }
00870 }
00871 
00872 /*
00873 ==================
00874 BotTeamOrders
00875 
00876   FIXME: defend key areas?
00877 ==================
00878 */
00879 void BotTeamOrders(bot_state_t *bs) {
00880     int teammates[MAX_CLIENTS];
00881     int numteammates, i;
00882     char buf[MAX_INFO_STRING];
00883     static int maxclients;
00884 
00885     if (!maxclients)
00886         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00887 
00888     numteammates = 0;
00889     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00890         trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00891         //if no config string or no name
00892         if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00893         //skip spectators
00894         if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00895         //
00896         if (BotSameTeam(bs, i)) {
00897             teammates[numteammates] = i;
00898             numteammates++;
00899         }
00900     }
00901     //
00902     switch(numteammates) {
00903         case 1: break;
00904         case 2:
00905         {
00906             //nothing special
00907             break;
00908         }
00909         case 3:
00910         {
00911             //have one follow another and one free roaming
00912             BotCreateGroup(bs, teammates, 2);
00913             break;
00914         }
00915         case 4:
00916         {
00917             BotCreateGroup(bs, teammates, 2);       //a group of 2
00918             BotCreateGroup(bs, &teammates[2], 2);   //a group of 2
00919             break;
00920         }
00921         case 5:
00922         {
00923             BotCreateGroup(bs, teammates, 2);       //a group of 2
00924             BotCreateGroup(bs, &teammates[2], 3);   //a group of 3
00925             break;
00926         }
00927         default:
00928         {
00929             if (numteammates <= 10) {
00930                 for (i = 0; i < numteammates / 2; i++) {
00931                     BotCreateGroup(bs, &teammates[i*2], 2); //groups of 2
00932                 }
00933             }
00934             break;
00935         }
00936     }
00937 }
00938 
00939 #ifdef MISSIONPACK
00940 
00941 /*
00942 ==================
00943 Bot1FCTFOrders_FlagAtCenter
00944 
00945   X% defend the base, Y% get the flag
00946 ==================
00947 */
00948 void Bot1FCTFOrders_FlagAtCenter(bot_state_t *bs) {
00949     int numteammates, defenders, attackers, i;
00950     int teammates[MAX_CLIENTS];
00951     char name[MAX_NETNAME];
00952 
00953     //sort team mates by travel time to base
00954     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
00955     //sort team mates by CTF preference
00956     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
00957     //passive strategy
00958     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
00959         //different orders based on the number of team mates
00960         switch(numteammates) {
00961             case 1: break;
00962             case 2:
00963             {
00964                 //the one closest to the base will defend the base
00965                 ClientName(teammates[0], name, sizeof(name));
00966                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00967                 BotSayTeamOrder(bs, teammates[0]);
00968                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00969                 //the other will get the flag
00970                 ClientName(teammates[1], name, sizeof(name));
00971                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00972                 BotSayTeamOrder(bs, teammates[1]);
00973                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
00974                 break;
00975             }
00976             case 3:
00977             {
00978                 //the one closest to the base will defend the base
00979                 ClientName(teammates[0], name, sizeof(name));
00980                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00981                 BotSayTeamOrder(bs, teammates[0]);
00982                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00983                 //the second one closest to the base will defend the base
00984                 ClientName(teammates[1], name, sizeof(name));
00985                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
00986                 BotSayTeamOrder(bs, teammates[1]);
00987                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
00988                 //the other will get the flag
00989                 ClientName(teammates[2], name, sizeof(name));
00990                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
00991                 BotSayTeamOrder(bs, teammates[2]);
00992                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
00993                 break;
00994             }
00995             default:
00996             {
00997                 //50% defend the base
00998                 defenders = (int) (float) numteammates * 0.5 + 0.5;
00999                 if (defenders > 5) defenders = 5;
01000                 //40% get the flag
01001                 attackers = (int) (float) numteammates * 0.4 + 0.5;
01002                 if (attackers > 4) attackers = 4;
01003                 for (i = 0; i < defenders; i++) {
01004                     //
01005                     ClientName(teammates[i], name, sizeof(name));
01006                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01007                     BotSayTeamOrder(bs, teammates[i]);
01008                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01009                 }
01010                 for (i = 0; i < attackers; i++) {
01011                     //
01012                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01013                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01014                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01015                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01016                 }
01017                 //
01018                 break;
01019             }
01020         }
01021     }
01022     else { //agressive
01023         //different orders based on the number of team mates
01024         switch(numteammates) {
01025             case 1: break;
01026             case 2:
01027             {
01028                 //the one closest to the base will defend the base
01029                 ClientName(teammates[0], name, sizeof(name));
01030                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01031                 BotSayTeamOrder(bs, teammates[0]);
01032                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01033                 //the other will get the flag
01034                 ClientName(teammates[1], name, sizeof(name));
01035                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01036                 BotSayTeamOrder(bs, teammates[1]);
01037                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
01038                 break;
01039             }
01040             case 3:
01041             {
01042                 //the one closest to the base will defend the base
01043                 ClientName(teammates[0], name, sizeof(name));
01044                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01045                 BotSayTeamOrder(bs, teammates[0]);
01046                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01047                 //the others should go for the enemy flag
01048                 ClientName(teammates[1], name, sizeof(name));
01049                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01050                 BotSayTeamOrder(bs, teammates[1]);
01051                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
01052                 //
01053                 ClientName(teammates[2], name, sizeof(name));
01054                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01055                 BotSayTeamOrder(bs, teammates[2]);
01056                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
01057                 break;
01058             }
01059             default:
01060             {
01061                 //30% defend the base
01062                 defenders = (int) (float) numteammates * 0.3 + 0.5;
01063                 if (defenders > 3) defenders = 3;
01064                 //60% get the flag
01065                 attackers = (int) (float) numteammates * 0.6 + 0.5;
01066                 if (attackers > 6) attackers = 6;
01067                 for (i = 0; i < defenders; i++) {
01068                     //
01069                     ClientName(teammates[i], name, sizeof(name));
01070                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01071                     BotSayTeamOrder(bs, teammates[i]);
01072                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01073                 }
01074                 for (i = 0; i < attackers; i++) {
01075                     //
01076                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01077                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01078                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01079                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01080                 }
01081                 //
01082                 break;
01083             }
01084         }
01085     }
01086 }
01087 
01088 /*
01089 ==================
01090 Bot1FCTFOrders_TeamHasFlag
01091 
01092   X% towards neutral flag, Y% go towards enemy base and accompany flag carrier if visible
01093 ==================
01094 */
01095 void Bot1FCTFOrders_TeamHasFlag(bot_state_t *bs) {
01096     int numteammates, defenders, attackers, i, other;
01097     int teammates[MAX_CLIENTS];
01098     char name[MAX_NETNAME], carriername[MAX_NETNAME];
01099 
01100     //sort team mates by travel time to base
01101     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
01102     //sort team mates by CTF preference
01103     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
01104     //passive strategy
01105     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
01106         //different orders based on the number of team mates
01107         switch(numteammates) {
01108             case 1: break;
01109             case 2:
01110             {
01111                 //tell the one not carrying the flag to attack the enemy base
01112                 if (teammates[0] == bs->flagcarrier) other = teammates[1];
01113                 else other = teammates[0];
01114                 ClientName(other, name, sizeof(name));
01115                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01116                 BotSayTeamOrder(bs, other);
01117                 BotSayVoiceTeamOrder(bs, other, VOICECHAT_OFFENSE);
01118                 break;
01119             }
01120             case 3:
01121             {
01122                 //tell the one closest to the base not carrying the flag to defend the base
01123                 if (teammates[0] != bs->flagcarrier) other = teammates[0];
01124                 else other = teammates[1];
01125                 ClientName(other, name, sizeof(name));
01126                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01127                 BotSayTeamOrder(bs, other);
01128                 BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
01129                 //tell the one furthest from the base not carrying the flag to accompany the flag carrier
01130                 if (teammates[2] != bs->flagcarrier) other = teammates[2];
01131                 else other = teammates[1];
01132                 ClientName(other, name, sizeof(name));
01133                 if ( bs->flagcarrier != -1 ) {
01134                     ClientName(bs->flagcarrier, carriername, sizeof(carriername));
01135                     if (bs->flagcarrier == bs->client) {
01136                         BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
01137                         BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
01138                     }
01139                     else {
01140                         BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
01141                         BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
01142                     }
01143                 }
01144                 else {
01145                     //
01146                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01147                     BotSayVoiceTeamOrder(bs, other, VOICECHAT_GETFLAG);
01148                 }
01149                 BotSayTeamOrder(bs, other);
01150                 break;
01151             }
01152             default:
01153             {
01154                 //30% will defend the base
01155                 defenders = (int) (float) numteammates * 0.3 + 0.5;
01156                 if (defenders > 3) defenders = 3;
01157                 //70% accompanies the flag carrier
01158                 attackers = (int) (float) numteammates * 0.7 + 0.5;
01159                 if (attackers > 7) attackers = 7;
01160                 for (i = 0; i < defenders; i++) {
01161                     //
01162                     if (teammates[i] == bs->flagcarrier) {
01163                         continue;
01164                     }
01165                     ClientName(teammates[i], name, sizeof(name));
01166                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01167                     BotSayTeamOrder(bs, teammates[i]);
01168                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01169                 }
01170                 if (bs->flagcarrier != -1) {
01171                     ClientName(bs->flagcarrier, carriername, sizeof(carriername));
01172                     for (i = 0; i < attackers; i++) {
01173                         //
01174                         if (teammates[numteammates - i - 1] == bs->flagcarrier) {
01175                             continue;
01176                         }
01177                         //
01178                         ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01179                         if (bs->flagcarrier == bs->client) {
01180                             BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
01181                             BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
01182                         }
01183                         else {
01184                             BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
01185                             BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
01186                         }
01187                         BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01188                     }
01189                 }
01190                 else {
01191                     for (i = 0; i < attackers; i++) {
01192                         //
01193                         if (teammates[numteammates - i - 1] == bs->flagcarrier) {
01194                             continue;
01195                         }
01196                         //
01197                         ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01198                         BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01199                         BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01200                         BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01201                     }
01202                 }
01203                 //
01204                 break;
01205             }
01206         }
01207     }
01208     else { //agressive
01209         //different orders based on the number of team mates
01210         switch(numteammates) {
01211             case 1: break;
01212             case 2:
01213             {
01214                 //tell the one not carrying the flag to defend the base
01215                 if (teammates[0] == bs->flagcarrier) other = teammates[1];
01216                 else other = teammates[0];
01217                 ClientName(other, name, sizeof(name));
01218                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01219                 BotSayTeamOrder(bs, other);
01220                 BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
01221                 break;
01222             }
01223             case 3:
01224             {
01225                 //tell the one closest to the base not carrying the flag to defend the base
01226                 if (teammates[0] != bs->flagcarrier) other = teammates[0];
01227                 else other = teammates[1];
01228                 ClientName(other, name, sizeof(name));
01229                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01230                 BotSayTeamOrder(bs, other);
01231                 BotSayVoiceTeamOrder(bs, other, VOICECHAT_DEFEND);
01232                 //tell the one furthest from the base not carrying the flag to accompany the flag carrier
01233                 if (teammates[2] != bs->flagcarrier) other = teammates[2];
01234                 else other = teammates[1];
01235                 ClientName(other, name, sizeof(name));
01236                 ClientName(bs->flagcarrier, carriername, sizeof(carriername));
01237                 if (bs->flagcarrier == bs->