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->client) {
01238                     BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
01239                     BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWME);
01240                 }
01241                 else {
01242                     BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
01243                     BotSayVoiceTeamOrder(bs, other, VOICECHAT_FOLLOWFLAGCARRIER);
01244                 }
01245                 BotSayTeamOrder(bs, other);
01246                 break;
01247             }
01248             default:
01249             {
01250                 //20% will defend the base
01251                 defenders = (int) (float) numteammates * 0.2 + 0.5;
01252                 if (defenders > 2) defenders = 2;
01253                 //80% accompanies the flag carrier
01254                 attackers = (int) (float) numteammates * 0.8 + 0.5;
01255                 if (attackers > 8) attackers = 8;
01256                 for (i = 0; i < defenders; i++) {
01257                     //
01258                     if (teammates[i] == bs->flagcarrier) {
01259                         continue;
01260                     }
01261                     ClientName(teammates[i], name, sizeof(name));
01262                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01263                     BotSayTeamOrder(bs, teammates[i]);
01264                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01265                 }
01266                 ClientName(bs->flagcarrier, carriername, sizeof(carriername));
01267                 for (i = 0; i < attackers; i++) {
01268                     //
01269                     if (teammates[numteammates - i - 1] == bs->flagcarrier) {
01270                         continue;
01271                     }
01272                     //
01273                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01274                     if (bs->flagcarrier == bs->client) {
01275                         BotAI_BotInitialChat(bs, "cmd_accompanyme", name, NULL);
01276                         BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWME);
01277                     }
01278                     else {
01279                         BotAI_BotInitialChat(bs, "cmd_accompany", name, carriername, NULL);
01280                         BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_FOLLOWFLAGCARRIER);
01281                     }
01282                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01283                 }
01284                 //
01285                 break;
01286             }
01287         }
01288     }
01289 }
01290 
01291 /*
01292 ==================
01293 Bot1FCTFOrders_EnemyHasFlag
01294 
01295   X% defend the base, Y% towards neutral flag
01296 ==================
01297 */
01298 void Bot1FCTFOrders_EnemyHasFlag(bot_state_t *bs) {
01299     int numteammates, defenders, attackers, i;
01300     int teammates[MAX_CLIENTS];
01301     char name[MAX_NETNAME];
01302 
01303     //sort team mates by travel time to base
01304     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
01305     //sort team mates by CTF preference
01306     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
01307     //passive strategy
01308     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
01309         //different orders based on the number of team mates
01310         switch(numteammates) {
01311             case 1: break;
01312             case 2:
01313             {
01314                 //both defend the base
01315                 ClientName(teammates[0], name, sizeof(name));
01316                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01317                 BotSayTeamOrder(bs, teammates[0]);
01318                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01319                 //
01320                 ClientName(teammates[1], name, sizeof(name));
01321                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01322                 BotSayTeamOrder(bs, teammates[1]);
01323                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01324                 break;
01325             }
01326             case 3:
01327             {
01328                 //the one closest to the base will defend the base
01329                 ClientName(teammates[0], name, sizeof(name));
01330                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01331                 BotSayTeamOrder(bs, teammates[0]);
01332                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01333                 //the second one closest to the base will defend the base
01334                 ClientName(teammates[1], name, sizeof(name));
01335                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01336                 BotSayTeamOrder(bs, teammates[1]);
01337                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01338                 //the other will also defend the base
01339                 ClientName(teammates[2], name, sizeof(name));
01340                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01341                 BotSayTeamOrder(bs, teammates[2]);
01342                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_DEFEND);
01343                 break;
01344             }
01345             default:
01346             {
01347                 //80% will defend the base
01348                 defenders = (int) (float) numteammates * 0.8 + 0.5;
01349                 if (defenders > 8) defenders = 8;
01350                 //10% will try to return the flag
01351                 attackers = (int) (float) numteammates * 0.1 + 0.5;
01352                 if (attackers > 2) attackers = 2;
01353                 for (i = 0; i < defenders; i++) {
01354                     //
01355                     ClientName(teammates[i], name, sizeof(name));
01356                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01357                     BotSayTeamOrder(bs, teammates[i]);
01358                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01359                 }
01360                 for (i = 0; i < attackers; i++) {
01361                     //
01362                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01363                     BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
01364                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01365                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01366                 }
01367                 //
01368                 break;
01369             }
01370         }
01371     }
01372     else { //agressive
01373         //different orders based on the number of team mates
01374         switch(numteammates) {
01375             case 1: break;
01376             case 2:
01377             {
01378                 //the one closest to the base will defend the base
01379                 ClientName(teammates[0], name, sizeof(name));
01380                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01381                 BotSayTeamOrder(bs, teammates[0]);
01382                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01383                 //the other will get the flag
01384                 ClientName(teammates[1], name, sizeof(name));
01385                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01386                 BotSayTeamOrder(bs, teammates[1]);
01387                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01388                 break;
01389             }
01390             case 3:
01391             {
01392                 //the one closest to the base will defend the base
01393                 ClientName(teammates[0], name, sizeof(name));
01394                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01395                 BotSayTeamOrder(bs, teammates[0]);
01396                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01397                 //the others should go for the enemy flag
01398                 ClientName(teammates[1], name, sizeof(name));
01399                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01400                 BotSayTeamOrder(bs, teammates[1]);
01401                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01402                 //
01403                 ClientName(teammates[2], name, sizeof(name));
01404                 BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
01405                 BotSayTeamOrder(bs, teammates[2]);
01406                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
01407                 break;
01408             }
01409             default:
01410             {
01411                 //70% defend the base
01412                 defenders = (int) (float) numteammates * 0.7 + 0.5;
01413                 if (defenders > 8) defenders = 8;
01414                 //20% try to return the flag
01415                 attackers = (int) (float) numteammates * 0.2 + 0.5;
01416                 if (attackers > 2) attackers = 2;
01417                 for (i = 0; i < defenders; i++) {
01418                     //
01419                     ClientName(teammates[i], name, sizeof(name));
01420                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01421                     BotSayTeamOrder(bs, teammates[i]);
01422                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01423                 }
01424                 for (i = 0; i < attackers; i++) {
01425                     //
01426                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01427                     BotAI_BotInitialChat(bs, "cmd_returnflag", name, NULL);
01428                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01429                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01430                 }
01431                 //
01432                 break;
01433             }
01434         }
01435     }
01436 }
01437 
01438 /*
01439 ==================
01440 Bot1FCTFOrders_EnemyDroppedFlag
01441 
01442   X% defend the base, Y% get the flag
01443 ==================
01444 */
01445 void Bot1FCTFOrders_EnemyDroppedFlag(bot_state_t *bs) {
01446     int numteammates, defenders, attackers, i;
01447     int teammates[MAX_CLIENTS];
01448     char name[MAX_NETNAME];
01449 
01450     //sort team mates by travel time to base
01451     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
01452     //sort team mates by CTF preference
01453     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
01454     //passive strategy
01455     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
01456         //different orders based on the number of team mates
01457         switch(numteammates) {
01458             case 1: break;
01459             case 2:
01460             {
01461                 //the one closest to the base will defend the base
01462                 ClientName(teammates[0], name, sizeof(name));
01463                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01464                 BotSayTeamOrder(bs, teammates[0]);
01465                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01466                 //the other will get the flag
01467                 ClientName(teammates[1], name, sizeof(name));
01468                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01469                 BotSayTeamOrder(bs, teammates[1]);
01470                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
01471                 break;
01472             }
01473             case 3:
01474             {
01475                 //the one closest to the base will defend the base
01476                 ClientName(teammates[0], name, sizeof(name));
01477                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01478                 BotSayTeamOrder(bs, teammates[0]);
01479                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01480                 //the second one closest to the base will defend the base
01481                 ClientName(teammates[1], name, sizeof(name));
01482                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01483                 BotSayTeamOrder(bs, teammates[1]);
01484                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01485                 //the other will get the flag
01486                 ClientName(teammates[2], name, sizeof(name));
01487                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01488                 BotSayTeamOrder(bs, teammates[2]);
01489                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
01490                 break;
01491             }
01492             default:
01493             {
01494                 //50% defend the base
01495                 defenders = (int) (float) numteammates * 0.5 + 0.5;
01496                 if (defenders > 5) defenders = 5;
01497                 //40% get the flag
01498                 attackers = (int) (float) numteammates * 0.4 + 0.5;
01499                 if (attackers > 4) attackers = 4;
01500                 for (i = 0; i < defenders; i++) {
01501                     //
01502                     ClientName(teammates[i], name, sizeof(name));
01503                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01504                     BotSayTeamOrder(bs, teammates[i]);
01505                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01506                 }
01507                 for (i = 0; i < attackers; i++) {
01508                     //
01509                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01510                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01511                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01512                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_GETFLAG);
01513                 }
01514                 //
01515                 break;
01516             }
01517         }
01518     }
01519     else { //agressive
01520         //different orders based on the number of team mates
01521         switch(numteammates) {
01522             case 1: break;
01523             case 2:
01524             {
01525                 //the one closest to the base will defend the base
01526                 ClientName(teammates[0], name, sizeof(name));
01527                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01528                 BotSayTeamOrder(bs, teammates[0]);
01529                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01530                 //the other will get the flag
01531                 ClientName(teammates[1], name, sizeof(name));
01532                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01533                 BotSayTeamOrder(bs, teammates[1]);
01534                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
01535                 break;
01536             }
01537             case 3:
01538             {
01539                 //the one closest to the base will defend the base
01540                 ClientName(teammates[0], name, sizeof(name));
01541                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01542                 BotSayTeamOrder(bs, teammates[0]);
01543                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01544                 //the others should go for the enemy flag
01545                 ClientName(teammates[1], name, sizeof(name));
01546                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01547                 BotSayTeamOrder(bs, teammates[1]);
01548                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_GETFLAG);
01549                 //
01550                 ClientName(teammates[2], name, sizeof(name));
01551                 BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01552                 BotSayTeamOrder(bs, teammates[2]);
01553                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_GETFLAG);
01554                 break;
01555             }
01556             default:
01557             {
01558                 //30% defend the base
01559                 defenders = (int) (float) numteammates * 0.3 + 0.5;
01560                 if (defenders > 3) defenders = 3;
01561                 //60% get the flag
01562                 attackers = (int) (float) numteammates * 0.6 + 0.5;
01563                 if (attackers > 6) attackers = 6;
01564                 for (i = 0; i < defenders; i++) {
01565                     //
01566                     ClientName(teammates[i], name, sizeof(name));
01567                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01568                     BotSayTeamOrder(bs, teammates[i]);
01569                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01570                 }
01571                 for (i = 0; i < attackers; i++) {
01572                     //
01573                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01574                     BotAI_BotInitialChat(bs, "cmd_getflag", name, NULL);
01575                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01576                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_DEFEND);
01577                 }
01578                 //
01579                 break;
01580             }
01581         }
01582     }
01583 }
01584 
01585 /*
01586 ==================
01587 Bot1FCTFOrders
01588 ==================
01589 */
01590 void Bot1FCTFOrders(bot_state_t *bs) {
01591     switch(bs->neutralflagstatus) {
01592         case 0: Bot1FCTFOrders_FlagAtCenter(bs); break;
01593         case 1: Bot1FCTFOrders_TeamHasFlag(bs); break;
01594         case 2: Bot1FCTFOrders_EnemyHasFlag(bs); break;
01595         case 3: Bot1FCTFOrders_EnemyDroppedFlag(bs); break;
01596     }
01597 }
01598 
01599 /*
01600 ==================
01601 BotObeliskOrders
01602 
01603   X% in defence Y% in offence
01604 ==================
01605 */
01606 void BotObeliskOrders(bot_state_t *bs) {
01607     int numteammates, defenders, attackers, i;
01608     int teammates[MAX_CLIENTS];
01609     char name[MAX_NETNAME];
01610 
01611     //sort team mates by travel time to base
01612     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
01613     //sort team mates by CTF preference
01614     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
01615     //passive strategy
01616     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
01617         //different orders based on the number of team mates
01618         switch(numteammates) {
01619             case 1: break;
01620             case 2:
01621             {
01622                 //the one closest to the base will defend the base
01623                 ClientName(teammates[0], name, sizeof(name));
01624                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01625                 BotSayTeamOrder(bs, teammates[0]);
01626                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01627                 //the other will attack the enemy base
01628                 ClientName(teammates[1], name, sizeof(name));
01629                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01630                 BotSayTeamOrder(bs, teammates[1]);
01631                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01632                 break;
01633             }
01634             case 3:
01635             {
01636                 //the one closest to the base will defend the base
01637                 ClientName(teammates[0], name, sizeof(name));
01638                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01639                 BotSayTeamOrder(bs, teammates[0]);
01640                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01641                 //the one second closest to the base also defends the base
01642                 ClientName(teammates[1], name, sizeof(name));
01643                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01644                 BotSayTeamOrder(bs, teammates[1]);
01645                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01646                 //the other one attacks the enemy base
01647                 ClientName(teammates[2], name, sizeof(name));
01648                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01649                 BotSayTeamOrder(bs, teammates[2]);
01650                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
01651                 break;
01652             }
01653             default:
01654             {
01655                 //50% defend the base
01656                 defenders = (int) (float) numteammates * 0.5 + 0.5;
01657                 if (defenders > 5) defenders = 5;
01658                 //40% attack the enemy base
01659                 attackers = (int) (float) numteammates * 0.4 + 0.5;
01660                 if (attackers > 4) attackers = 4;
01661                 for (i = 0; i < defenders; i++) {
01662                     //
01663                     ClientName(teammates[i], name, sizeof(name));
01664                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01665                     BotSayTeamOrder(bs, teammates[i]);
01666                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01667                 }
01668                 for (i = 0; i < attackers; i++) {
01669                     //
01670                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01671                     BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01672                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01673                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
01674                 }
01675                 //
01676                 break;
01677             }
01678         }
01679     }
01680     else {
01681         //different orders based on the number of team mates
01682         switch(numteammates) {
01683             case 1: break;
01684             case 2:
01685             {
01686                 //the one closest to the base will defend the base
01687                 ClientName(teammates[0], name, sizeof(name));
01688                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01689                 BotSayTeamOrder(bs, teammates[0]);
01690                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01691                 //the other will attack the enemy base
01692                 ClientName(teammates[1], name, sizeof(name));
01693                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01694                 BotSayTeamOrder(bs, teammates[1]);
01695                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01696                 break;
01697             }
01698             case 3:
01699             {
01700                 //the one closest to the base will defend the base
01701                 ClientName(teammates[0], name, sizeof(name));
01702                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01703                 BotSayTeamOrder(bs, teammates[0]);
01704                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01705                 //the others attack the enemy base
01706                 ClientName(teammates[1], name, sizeof(name));
01707                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01708                 BotSayTeamOrder(bs, teammates[1]);
01709                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01710                 //
01711                 ClientName(teammates[2], name, sizeof(name));
01712                 BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01713                 BotSayTeamOrder(bs, teammates[2]);
01714                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
01715                 break;
01716             }
01717             default:
01718             {
01719                 //30% defend the base
01720                 defenders = (int) (float) numteammates * 0.3 + 0.5;
01721                 if (defenders > 3) defenders = 3;
01722                 //70% attack the enemy base
01723                 attackers = (int) (float) numteammates * 0.7 + 0.5;
01724                 if (attackers > 7) attackers = 7;
01725                 for (i = 0; i < defenders; i++) {
01726                     //
01727                     ClientName(teammates[i], name, sizeof(name));
01728                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01729                     BotSayTeamOrder(bs, teammates[i]);
01730                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01731                 }
01732                 for (i = 0; i < attackers; i++) {
01733                     //
01734                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01735                     BotAI_BotInitialChat(bs, "cmd_attackenemybase", name, NULL);
01736                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01737                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
01738                 }
01739                 //
01740                 break;
01741             }
01742         }
01743     }
01744 }
01745 
01746 /*
01747 ==================
01748 BotHarvesterOrders
01749 
01750   X% defend the base, Y% harvest
01751 ==================
01752 */
01753 void BotHarvesterOrders(bot_state_t *bs) {
01754     int numteammates, defenders, attackers, i;
01755     int teammates[MAX_CLIENTS];
01756     char name[MAX_NETNAME];
01757 
01758     //sort team mates by travel time to base
01759     numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates));
01760     //sort team mates by CTF preference
01761     BotSortTeamMatesByTaskPreference(bs, teammates, numteammates);
01762     //passive strategy
01763     if (!(bs->ctfstrategy & CTFS_AGRESSIVE)) {
01764         //different orders based on the number of team mates
01765         switch(numteammates) {
01766             case 1: break;
01767             case 2:
01768             {
01769                 //the one closest to the base will defend the base
01770                 ClientName(teammates[0], name, sizeof(name));
01771                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01772                 BotSayTeamOrder(bs, teammates[0]);
01773                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01774                 //the other will harvest
01775                 ClientName(teammates[1], name, sizeof(name));
01776                 BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01777                 BotSayTeamOrder(bs, teammates[1]);
01778                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01779                 break;
01780             }
01781             case 3:
01782             {
01783                 //the one closest to the base will defend the base
01784                 ClientName(teammates[0], name, sizeof(name));
01785                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01786                 BotSayTeamOrder(bs, teammates[0]);
01787                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01788                 //the one second closest to the base also defends the base
01789                 ClientName(teammates[1], name, sizeof(name));
01790                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01791                 BotSayTeamOrder(bs, teammates[1]);
01792                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_DEFEND);
01793                 //the other one goes harvesting
01794                 ClientName(teammates[2], name, sizeof(name));
01795                 BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01796                 BotSayTeamOrder(bs, teammates[2]);
01797                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
01798                 break;
01799             }
01800             default:
01801             {
01802                 //50% defend the base
01803                 defenders = (int) (float) numteammates * 0.5 + 0.5;
01804                 if (defenders > 5) defenders = 5;
01805                 //40% goes harvesting
01806                 attackers = (int) (float) numteammates * 0.4 + 0.5;
01807                 if (attackers > 4) attackers = 4;
01808                 for (i = 0; i < defenders; i++) {
01809                     //
01810                     ClientName(teammates[i], name, sizeof(name));
01811                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01812                     BotSayTeamOrder(bs, teammates[i]);
01813                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01814                 }
01815                 for (i = 0; i < attackers; i++) {
01816                     //
01817                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01818                     BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01819                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01820                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
01821                 }
01822                 //
01823                 break;
01824             }
01825         }
01826     }
01827     else {
01828         //different orders based on the number of team mates
01829         switch(numteammates) {
01830             case 1: break;
01831             case 2:
01832             {
01833                 //the one closest to the base will defend the base
01834                 ClientName(teammates[0], name, sizeof(name));
01835                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01836                 BotSayTeamOrder(bs, teammates[0]);
01837                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01838                 //the other will harvest
01839                 ClientName(teammates[1], name, sizeof(name));
01840                 BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01841                 BotSayTeamOrder(bs, teammates[1]);
01842                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01843                 break;
01844             }
01845             case 3:
01846             {
01847                 //the one closest to the base will defend the base
01848                 ClientName(teammates[0], name, sizeof(name));
01849                 BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01850                 BotSayTeamOrder(bs, teammates[0]);
01851                 BotSayVoiceTeamOrder(bs, teammates[0], VOICECHAT_DEFEND);
01852                 //the others go harvesting
01853                 ClientName(teammates[1], name, sizeof(name));
01854                 BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01855                 BotSayTeamOrder(bs, teammates[1]);
01856                 BotSayVoiceTeamOrder(bs, teammates[1], VOICECHAT_OFFENSE);
01857                 //
01858                 ClientName(teammates[2], name, sizeof(name));
01859                 BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01860                 BotSayTeamOrder(bs, teammates[2]);
01861                 BotSayVoiceTeamOrder(bs, teammates[2], VOICECHAT_OFFENSE);
01862                 break;
01863             }
01864             default:
01865             {
01866                 //30% defend the base
01867                 defenders = (int) (float) numteammates * 0.3 + 0.5;
01868                 if (defenders > 3) defenders = 3;
01869                 //70% go harvesting
01870                 attackers = (int) (float) numteammates * 0.7 + 0.5;
01871                 if (attackers > 7) attackers = 7;
01872                 for (i = 0; i < defenders; i++) {
01873                     //
01874                     ClientName(teammates[i], name, sizeof(name));
01875                     BotAI_BotInitialChat(bs, "cmd_defendbase", name, NULL);
01876                     BotSayTeamOrder(bs, teammates[i]);
01877                     BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND);
01878                 }
01879                 for (i = 0; i < attackers; i++) {
01880                     //
01881                     ClientName(teammates[numteammates - i - 1], name, sizeof(name));
01882                     BotAI_BotInitialChat(bs, "cmd_harvest", name, NULL);
01883                     BotSayTeamOrder(bs, teammates[numteammates - i - 1]);
01884                     BotSayVoiceTeamOrder(bs, teammates[numteammates - i - 1], VOICECHAT_OFFENSE);
01885                 }
01886                 //
01887                 break;
01888             }
01889         }
01890     }
01891 }
01892 #endif
01893 
01894 /*
01895 ==================
01896 FindHumanTeamLeader
01897 ==================
01898 */
01899 int FindHumanTeamLeader(bot_state_t *bs) {
01900     int i;
01901 
01902     for (i = 0; i < MAX_CLIENTS; i++) {
01903         if ( g_entities[i].inuse ) {
01904             // if this player is not a bot
01905             if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
01906                 // if this player is ok with being the leader
01907                 if (!notleader[i]) {
01908                     // if this player is on the same team
01909                     if ( BotSameTeam(bs, i) ) {
01910                         ClientName(i, bs->teamleader, sizeof(bs->teamleader));
01911                         // if not yet ordered to do anything
01912                         if ( !BotSetLastOrderedTask(bs) ) {
01913                             // go on defense by default
01914                             BotVoiceChat_Defend(bs, i, SAY_TELL);
01915                         }
01916                         return qtrue;
01917                     }
01918                 }
01919             }
01920         }
01921     }
01922     return qfalse;
01923 }
01924 
01925 /*
01926 ==================
01927 BotTeamAI
01928 ==================
01929 */
01930 void BotTeamAI(bot_state_t *bs) {
01931     int numteammates;
01932     char netname[MAX_NETNAME];
01933 
01934     //
01935     if ( gametype < GT_TEAM  )
01936         return;
01937     // make sure we've got a valid team leader
01938     if (!BotValidTeamLeader(bs)) {
01939         //
01940         if (!FindHumanTeamLeader(bs)) {
01941             //
01942             if (!bs->askteamleader_time && !bs->becometeamleader_time) {
01943                 if (bs->entergame_time + 10 > FloatTime()) {
01944                     bs->askteamleader_time = FloatTime() + 5 + random() * 10;
01945                 }
01946                 else {
01947                     bs->becometeamleader_time = FloatTime() + 5 + random() * 10;
01948                 }
01949             }
01950             if (bs->askteamleader_time && bs->askteamleader_time < FloatTime()) {
01951                 // if asked for a team leader and no response
01952                 BotAI_BotInitialChat(bs, "whoisteamleader", NULL);
01953                 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
01954                 bs->askteamleader_time = 0;
01955                 bs->becometeamleader_time = FloatTime() + 8 + random() * 10;
01956             }
01957             if (bs->becometeamleader_time && bs->becometeamleader_time < FloatTime()) {
01958                 BotAI_BotInitialChat(bs, "iamteamleader", NULL);
01959                 trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
01960                 BotSayVoiceTeamOrder(bs, -1, VOICECHAT_STARTLEADER);
01961                 ClientName(bs->client, netname, sizeof(netname));
01962                 strncpy(bs->teamleader, netname, sizeof(bs->teamleader));
01963                 bs->teamleader[sizeof(bs->teamleader)] = '\0';
01964                 bs->becometeamleader_time = 0;
01965             }
01966             return;
01967         }
01968     }
01969     bs->askteamleader_time = 0;
01970     bs->becometeamleader_time = 0;
01971 
01972     //return if this bot is NOT the team leader
01973     ClientName(bs->client, netname, sizeof(netname));
01974     if (Q_stricmp(netname, bs->teamleader) != 0) return;
01975     //
01976     numteammates = BotNumTeamMates(bs);
01977     //give orders
01978     switch(gametype) {
01979         case GT_TEAM:
01980         {
01981             if (bs->numteammates != numteammates || bs->forceorders) {
01982                 bs->teamgiveorders_time = FloatTime();
01983                 bs->numteammates = numteammates;
01984                 bs->forceorders = qfalse;
01985             }
01986             //if it's time to give orders
01987             if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
01988                 BotTeamOrders(bs);
01989                 //give orders again after 120 seconds
01990                 bs->teamgiveorders_time = FloatTime() + 120;
01991             }
01992             break;
01993         }
01994         case GT_CTF:
01995         {
01996             //if the number of team mates changed or the flag status changed
01997             //or someone wants to know what to do
01998             if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
01999                 bs->teamgiveorders_time = FloatTime();
02000                 bs->numteammates = numteammates;
02001                 bs->flagstatuschanged = qfalse;
02002                 bs->forceorders = qfalse;
02003             }
02004             //if there were no flag captures the last 3 minutes
02005             if (bs->lastflagcapture_time < FloatTime() - 240) {
02006                 bs->lastflagcapture_time = FloatTime();
02007                 //randomly change the CTF strategy
02008                 if (random() < 0.4) {
02009                     bs->ctfstrategy ^= CTFS_AGRESSIVE;
02010                     bs->teamgiveorders_time = FloatTime();
02011                 }
02012             }
02013             //if it's time to give orders
02014             if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) {
02015                 BotCTFOrders(bs);
02016                 //
02017                 bs->teamgiveorders_time = 0;
02018             }
02019             break;
02020         }
02021 #ifdef MISSIONPACK
02022         case GT_1FCTF:
02023         {
02024             if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) {
02025                 bs->teamgiveorders_time = FloatTime();
02026                 bs->numteammates = numteammates;
02027                 bs->flagstatuschanged = qfalse;
02028                 bs->forceorders = qfalse;
02029             }
02030             //if there were no flag captures the last 4 minutes
02031             if (bs->lastflagcapture_time < FloatTime() - 240) {
02032                 bs->lastflagcapture_time = FloatTime();
02033                 //randomly change the CTF strategy
02034                 if (random() < 0.4) {
02035                     bs->ctfstrategy ^= CTFS_AGRESSIVE;
02036                     bs->teamgiveorders_time = FloatTime();
02037                 }
02038             }
02039             //if it's time to give orders
02040             if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 2) {
02041                 Bot1FCTFOrders(bs);
02042                 //
02043                 bs->teamgiveorders_time = 0;
02044             }
02045             break;
02046         }
02047         case GT_OBELISK:
02048         {
02049             if (bs->numteammates != numteammates || bs->forceorders) {
02050                 bs->teamgiveorders_time = FloatTime();
02051                 bs->numteammates = numteammates;
02052                 bs->forceorders = qfalse;
02053             }
02054             //if it's time to give orders
02055             if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
02056                 BotObeliskOrders(bs);
02057                 //give orders again after 30 seconds
02058                 bs->teamgiveorders_time = FloatTime() + 30;
02059             }
02060             break;
02061         }
02062         case GT_HARVESTER:
02063         {
02064             if (bs->numteammates != numteammates || bs->forceorders) {
02065                 bs->teamgiveorders_time = FloatTime();
02066                 bs->numteammates = numteammates;
02067                 bs->forceorders = qfalse;
02068             }
02069             //if it's time to give orders
02070             if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 5) {
02071                 BotHarvesterOrders(bs);
02072                 //give orders again after 30 seconds
02073                 bs->teamgiveorders_time = FloatTime() + 30;
02074             }
02075             break;
02076         }
02077 #endif
02078     }
02079 }
02080 

Generated on Thu Aug 25 12:37:29 2005 for Quake III Arena by  doxygen 1.3.9.1