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

ai_cmd.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_cmd.c
00026  *
00027  * desc:        Quake3 bot AI
00028  *
00029  * $Archive: /MissionPack/code/game/ai_cmd.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 //
00051 #include "chars.h"              //characteristics
00052 #include "inv.h"                //indexes into the inventory
00053 #include "syn.h"                //synonyms
00054 #include "match.h"              //string matching types and vars
00055 
00056 // for the voice chats
00057 #include "../../ui/menudef.h"
00058 
00059 int notleader[MAX_CLIENTS];
00060 
00061 #ifdef DEBUG
00062 /*
00063 ==================
00064 BotPrintTeamGoal
00065 ==================
00066 */
00067 void BotPrintTeamGoal(bot_state_t *bs) {
00068     char netname[MAX_NETNAME];
00069     float t;
00070 
00071     ClientName(bs->client, netname, sizeof(netname));
00072     t = bs->teamgoal_time - FloatTime();
00073     switch(bs->ltgtype) {
00074         case LTG_TEAMHELP:
00075         {
00076             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna help a team mate for %1.0f secs\n", netname, t);
00077             break;
00078         }
00079         case LTG_TEAMACCOMPANY:
00080         {
00081             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna accompany a team mate for %1.0f secs\n", netname, t);
00082             break;
00083         }
00084         case LTG_GETFLAG:
00085         {
00086             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get the flag for %1.0f secs\n", netname, t);
00087             break;
00088         }
00089         case LTG_RUSHBASE:
00090         {
00091             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna rush to the base for %1.0f secs\n", netname, t);
00092             break;
00093         }
00094         case LTG_RETURNFLAG:
00095         {
00096             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna try to return the flag for %1.0f secs\n", netname, t);
00097             break;
00098         }
00099 #ifdef MISSIONPACK
00100         case LTG_ATTACKENEMYBASE:
00101         {
00102             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna attack the enemy base for %1.0f secs\n", netname, t);
00103             break;
00104         }
00105         case LTG_HARVEST:
00106         {
00107             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna harvest for %1.0f secs\n", netname, t);
00108             break;
00109         }
00110 #endif
00111         case LTG_DEFENDKEYAREA:
00112         {
00113             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a key area for %1.0f secs\n", netname, t);
00114             break;
00115         }
00116         case LTG_GETITEM:
00117         {
00118             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna get an item for %1.0f secs\n", netname, t);
00119             break;
00120         }
00121         case LTG_KILL:
00122         {
00123             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna kill someone for %1.0f secs\n", netname, t);
00124             break;
00125         }
00126         case LTG_CAMP:
00127         case LTG_CAMPORDER:
00128         {
00129             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna camp for %1.0f secs\n", netname, t);
00130             break;
00131         }
00132         case LTG_PATROL:
00133         {
00134             BotAI_Print(PRT_MESSAGE, "%s: I'm gonna patrol for %1.0f secs\n", netname, t);
00135             break;
00136         }
00137         default:
00138         {
00139             if (bs->ctfroam_time > FloatTime()) {
00140                 t = bs->ctfroam_time - FloatTime();
00141                 BotAI_Print(PRT_MESSAGE, "%s: I'm gonna roam for %1.0f secs\n", netname, t);
00142             }
00143             else {
00144                 BotAI_Print(PRT_MESSAGE, "%s: I've got a regular goal\n", netname);
00145             }
00146         }
00147     }
00148 }
00149 #endif //DEBUG
00150 
00151 /*
00152 ==================
00153 BotGetItemTeamGoal
00154 
00155 FIXME: add stuff like "upper rocket launcher"
00156 "the rl near the railgun", "lower grenade launcher" etc.
00157 ==================
00158 */
00159 int BotGetItemTeamGoal(char *goalname, bot_goal_t *goal) {
00160     int i;
00161 
00162     if (!strlen(goalname)) return qfalse;
00163     i = -1;
00164     do {
00165         i = trap_BotGetLevelItemGoal(i, goalname, goal);
00166         if (i > 0) {
00167             //do NOT defend dropped items
00168             if (goal->flags & GFL_DROPPED)
00169                 continue;
00170             return qtrue;
00171         }
00172     } while(i > 0);
00173     return qfalse;
00174 }
00175 
00176 /*
00177 ==================
00178 BotGetMessageTeamGoal
00179 ==================
00180 */
00181 int BotGetMessageTeamGoal(bot_state_t *bs, char *goalname, bot_goal_t *goal) {
00182     bot_waypoint_t *cp;
00183 
00184     if (BotGetItemTeamGoal(goalname, goal)) return qtrue;
00185 
00186     cp = BotFindWayPoint(bs->checkpoints, goalname);
00187     if (cp) {
00188         memcpy(goal, &cp->goal, sizeof(bot_goal_t));
00189         return qtrue;
00190     }
00191     return qfalse;
00192 }
00193 
00194 /*
00195 ==================
00196 BotGetTime
00197 ==================
00198 */
00199 float BotGetTime(bot_match_t *match) {
00200     bot_match_t timematch;
00201     char timestring[MAX_MESSAGE_SIZE];
00202     float t;
00203 
00204     //if the matched string has a time
00205     if (match->subtype & ST_TIME) {
00206         //get the time string
00207         trap_BotMatchVariable(match, TIME, timestring, MAX_MESSAGE_SIZE);
00208         //match it to find out if the time is in seconds or minutes
00209         if (trap_BotFindMatch(timestring, &timematch, MTCONTEXT_TIME)) {
00210             if (timematch.type == MSG_FOREVER) {
00211                 t = 99999999.0f;
00212             }
00213             else if (timematch.type == MSG_FORAWHILE) {
00214                 t = 10 * 60; // 10 minutes
00215             }
00216             else if (timematch.type == MSG_FORALONGTIME) {
00217                 t = 30 * 60; // 30 minutes
00218             }
00219             else {
00220                 trap_BotMatchVariable(&timematch, TIME, timestring, MAX_MESSAGE_SIZE);
00221                 if (timematch.type == MSG_MINUTES) t = atof(timestring) * 60;
00222                 else if (timematch.type == MSG_SECONDS) t = atof(timestring);
00223                 else t = 0;
00224             }
00225             //if there's a valid time
00226             if (t > 0) return FloatTime() + t;
00227         }
00228     }
00229     return 0;
00230 }
00231 
00232 /*
00233 ==================
00234 FindClientByName
00235 ==================
00236 */
00237 int FindClientByName(char *name) {
00238     int i;
00239     char buf[MAX_INFO_STRING];
00240     static int maxclients;
00241 
00242     if (!maxclients)
00243         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00244     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00245         ClientName(i, buf, sizeof(buf));
00246         if (!Q_stricmp(buf, name)) return i;
00247     }
00248     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00249         ClientName(i, buf, sizeof(buf));
00250         if (stristr(buf, name)) return i;
00251     }
00252     return -1;
00253 }
00254 
00255 /*
00256 ==================
00257 FindEnemyByName
00258 ==================
00259 */
00260 int FindEnemyByName(bot_state_t *bs, char *name) {
00261     int i;
00262     char buf[MAX_INFO_STRING];
00263     static int maxclients;
00264 
00265     if (!maxclients)
00266         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00267     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00268         if (BotSameTeam(bs, i)) continue;
00269         ClientName(i, buf, sizeof(buf));
00270         if (!Q_stricmp(buf, name)) return i;
00271     }
00272     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00273         if (BotSameTeam(bs, i)) continue;
00274         ClientName(i, buf, sizeof(buf));
00275         if (stristr(buf, name)) return i;
00276     }
00277     return -1;
00278 }
00279 
00280 /*
00281 ==================
00282 NumPlayersOnSameTeam
00283 ==================
00284 */
00285 int NumPlayersOnSameTeam(bot_state_t *bs) {
00286     int i, num;
00287     char buf[MAX_INFO_STRING];
00288     static int maxclients;
00289 
00290     if (!maxclients)
00291         maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00292 
00293     num = 0;
00294     for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00295         trap_GetConfigstring(CS_PLAYERS+i, buf, MAX_INFO_STRING);
00296         if (strlen(buf)) {
00297             if (BotSameTeam(bs, i+1)) num++;
00298         }
00299     }
00300     return num;
00301 }
00302 
00303 /*
00304 ==================
00305 TeamPlayIsOn
00306 ==================
00307 */
00308 int BotGetPatrolWaypoints(bot_state_t *bs, bot_match_t *match) {
00309     char keyarea[MAX_MESSAGE_SIZE];
00310     int patrolflags;
00311     bot_waypoint_t *wp, *newwp, *newpatrolpoints;
00312     bot_match_t keyareamatch;
00313     bot_goal_t goal;
00314 
00315     newpatrolpoints = NULL;
00316     patrolflags = 0;
00317     //
00318     trap_BotMatchVariable(match, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
00319     //
00320     while(1) {
00321         if (!trap_BotFindMatch(keyarea, &keyareamatch, MTCONTEXT_PATROLKEYAREA)) {
00322             trap_EA_SayTeam(bs->client, "what do you say?");
00323             BotFreeWaypoints(newpatrolpoints);
00324             bs->patrolpoints = NULL;
00325             return qfalse;
00326         }
00327         trap_BotMatchVariable(&keyareamatch, KEYAREA, keyarea, MAX_MESSAGE_SIZE);
00328         if (!BotGetMessageTeamGoal(bs, keyarea, &goal)) {
00329             //BotAI_BotInitialChat(bs, "cannotfind", keyarea, NULL);
00330             //trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
00331             BotFreeWaypoints(newpatrolpoints);
00332             bs->patrolpoints = NULL;
00333             return qfalse;
00334         }
00335         //create a new waypoint
00336         newwp = BotCreateWayPoint(keyarea, goal.origin, goal.areanum);
00337         if (!newwp)
00338             break;
00339         //add the waypoint to the patrol points
00340         newwp->next = NULL;
00341         for (wp = newpatrolpoints; wp && wp->next; wp = wp->next);
00342         if (!wp) {
00343             newpatrolpoints = newwp;
00344             newwp->prev = NULL;
00345         }
00346         else {
00347             wp->next = newwp;
00348             newwp->prev = wp;
00349         }
00350         //
00351         if (keyareamatch.subtype & ST_BACK) {
00352             patrolflags = PATROL_LOOP;
00353             break;
00354         }
00355         else if (keyareamatch.subtype & ST_REVERSE) {
00356             patrolflags = PATROL_REVERSE;
00357             break;
00358         }
00359         else if (keyareamatch.subtype & ST_MORE) {
00360             trap_BotMatchVariable(&keyareamatch, MORE, keyarea, MAX_MESSAGE_SIZE);
00361         }
00362         else {
00363             break;
00364         }
00365     }
00366     //
00367     if (!newpatrolpoints || !newpatrolpoints->next) {
00368         trap_EA_SayTeam(bs->client, "I need more key points to patrol\n");
00369         BotFreeWaypoints(newpatrolpoints);
00370         newpatrolpoints = NULL;
00371         return qfalse;
00372     }
00373     //
00374     BotFreeWaypoints(bs->patrolpoints);
00375     bs->patrolpoints = newpatrolpoints;
00376     //
00377     bs->curpatrolpoint = bs->patrolpoints;
00378     bs->patrolflags = patrolflags;
00379     //
00380     return qtrue;
00381 }
00382 
00383 /*
00384 ==================
00385 BotAddressedToBot
00386 ==================
00387 */
00388 int BotAddressedToBot(bot_state_t *bs, bot_match_t *match) {
00389     char addressedto[MAX_MESSAGE_SIZE];
00390     char netname[MAX_MESSAGE_SIZE];
00391     char name[MAX_MESSAGE_SIZE];
00392     char botname[128];
00393     int client;
00394     bot_match_t addresseematch;
00395 
00396     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00397     client = ClientOnSameTeamFromName(bs, netname);
00398     if (client < 0) return qfalse;
00399     //if the message is addressed to someone
00400     if (match->subtype & ST_ADDRESSED) {
00401         trap_BotMatchVariable(match, ADDRESSEE, addressedto, sizeof(addressedto));
00402         //the name of this bot
00403         ClientName(bs->client, botname, 128);
00404         //
00405         while(trap_BotFindMatch(addressedto, &addresseematch, MTCONTEXT_ADDRESSEE)) {
00406             if (addresseematch.type == MSG_EVERYONE) {
00407                 return qtrue;
00408             }
00409             else if (addresseematch.type == MSG_MULTIPLENAMES) {
00410                 trap_BotMatchVariable(&addresseematch, TEAMMATE, name, sizeof(name));
00411                 if (strlen(name)) {
00412                     if (stristr(botname, name)) return qtrue;
00413                     if (stristr(bs->subteam, name)) return qtrue;
00414                 }
00415                 trap_BotMatchVariable(&addresseematch, MORE, addressedto, MAX_MESSAGE_SIZE);
00416             }
00417             else {
00418                 trap_BotMatchVariable(&addresseematch, TEAMMATE, name, MAX_MESSAGE_SIZE);
00419                 if (strlen(name)) {
00420                     if (stristr(botname, name)) return qtrue;
00421                     if (stristr(bs->subteam, name)) return qtrue;
00422                 }
00423                 break;
00424             }
00425         }
00426         //Com_sprintf(buf, sizeof(buf), "not addressed to me but %s", addressedto);
00427         //trap_EA_Say(bs->client, buf);
00428         return qfalse;
00429     }
00430     else {
00431         bot_match_t tellmatch;
00432 
00433         tellmatch.type = 0;
00434         //if this message wasn't directed solely to this bot
00435         if (!trap_BotFindMatch(match->string, &tellmatch, MTCONTEXT_REPLYCHAT) ||
00436                 tellmatch.type != MSG_CHATTELL) {
00437             //make sure not everyone reacts to this message
00438             if (random() > (float ) 1.0 / (NumPlayersOnSameTeam(bs)-1)) return qfalse;
00439         }
00440     }
00441     return qtrue;
00442 }
00443 
00444 /*
00445 ==================
00446 BotGPSToPosition
00447 ==================
00448 */
00449 int BotGPSToPosition(char *buf, vec3_t position) {
00450     int i, j = 0;
00451     int num, sign;
00452 
00453     for (i = 0; i < 3; i++) {
00454         num = 0;
00455         while(buf[j] == ' ') j++;
00456         if (buf[j] == '-') {
00457             j++;
00458             sign = -1;
00459         }
00460         else {
00461             sign = 1;
00462         }
00463         while (buf[j]) {
00464             if (buf[j] >= '0' && buf[j] <= '9') {
00465                 num = num * 10 + buf[j] - '0';
00466                 j++;
00467             }
00468             else {
00469                 j++;
00470                 break;
00471             }
00472         }
00473         BotAI_Print(PRT_MESSAGE, "%d\n", sign * num);
00474         position[i] = (float) sign * num;
00475     }
00476     return qtrue;
00477 }
00478 
00479 /*
00480 ==================
00481 BotMatch_HelpAccompany
00482 ==================
00483 */
00484 void BotMatch_HelpAccompany(bot_state_t *bs, bot_match_t *match) {
00485     int client, other, areanum;
00486     char teammate[MAX_MESSAGE_SIZE];
00487     char netname[MAX_MESSAGE_SIZE];
00488     char itemname[MAX_MESSAGE_SIZE];
00489     bot_match_t teammatematch;
00490     aas_entityinfo_t entinfo;
00491 
00492     if (!TeamPlayIsOn()) return;
00493     //if not addressed to this bot
00494     if (!BotAddressedToBot(bs, match)) return;
00495     //get the team mate name
00496     trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
00497     //get the client to help
00498     if (trap_BotFindMatch(teammate, &teammatematch, MTCONTEXT_TEAMMATE) &&
00499             //if someone asks for him or herself
00500             teammatematch.type == MSG_ME) {
00501         //get the netname
00502         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00503         client = ClientFromName(netname);
00504         other = qfalse;
00505     }
00506     else {
00507         //asked for someone else
00508         client = FindClientByName(teammate);
00509         //if this is the bot self
00510         if (client == bs->client) {
00511             other = qfalse;
00512         }
00513         else if (!BotSameTeam(bs, client)) {
00514             //FIXME: say "I don't help the enemy"
00515             return;
00516         }
00517         else {
00518             other = qtrue;
00519         }
00520     }
00521     //if the bot doesn't know who to help (FindClientByName returned -1)
00522     if (client < 0) {
00523         if (other) BotAI_BotInitialChat(bs, "whois", teammate, NULL);
00524         else BotAI_BotInitialChat(bs, "whois", netname, NULL);
00525         client = ClientFromName(netname);
00526         trap_BotEnterChat(bs->cs, client, CHAT_TELL);
00527         return;
00528     }
00529     //don't help or accompany yourself
00530     if (client == bs->client) {
00531         return;
00532     }
00533     //
00534     bs->teamgoal.entitynum = -1;
00535     BotEntityInfo(client, &entinfo);
00536     //if info is valid (in PVS)
00537     if (entinfo.valid) {
00538         areanum = BotPointAreaNum(entinfo.origin);
00539         if (areanum) {// && trap_AAS_AreaReachability(areanum)) {
00540             bs->teamgoal.entitynum = client;
00541             bs->teamgoal.areanum = areanum;
00542             VectorCopy(entinfo.origin, bs->teamgoal.origin);
00543             VectorSet(bs->teamgoal.mins, -8, -8, -8);
00544             VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00545         }
00546     }
00547     //if no teamgoal yet
00548     if (bs->teamgoal.entitynum < 0) {
00549         //if near an item
00550         if (match->subtype & ST_NEARITEM) {
00551             //get the match variable
00552             trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
00553             //
00554             if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00555                 //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
00556                 //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
00557                 return;
00558             }
00559         }
00560     }
00561     //
00562     if (bs->teamgoal.entitynum < 0) {
00563         if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
00564         else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
00565         client = ClientFromName(netname);
00566         trap_BotEnterChat(bs->cs, client, CHAT_TEAM);
00567         return;
00568     }
00569     //the team mate
00570     bs->teammate = client;
00571     //
00572     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00573     //
00574     client = ClientFromName(netname);
00575     //the team mate who ordered
00576     bs->decisionmaker = client;
00577     bs->ordered = qtrue;
00578     bs->order_time = FloatTime();
00579     //last time the team mate was assumed visible
00580     bs->teammatevisible_time = FloatTime();
00581     //set the time to send a message to the team mates
00582     bs->teammessage_time = FloatTime() + 2 * random();
00583     //get the team goal time
00584     bs->teamgoal_time = BotGetTime(match);
00585     //set the ltg type
00586     if (match->type == MSG_HELP) {
00587         bs->ltgtype = LTG_TEAMHELP;
00588         if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HELP_TIME;
00589     }
00590     else {
00591         bs->ltgtype = LTG_TEAMACCOMPANY;
00592         if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
00593         bs->formation_dist = 3.5 * 32;      //3.5 meter
00594         bs->arrive_time = 0;
00595         //
00596         BotSetTeamStatus(bs);
00597         // remember last ordered task
00598         BotRememberLastOrderedTask(bs);
00599     }
00600 #ifdef DEBUG
00601     BotPrintTeamGoal(bs);
00602 #endif //DEBUG
00603 }
00604 
00605 /*
00606 ==================
00607 BotMatch_DefendKeyArea
00608 ==================
00609 */
00610 void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) {
00611     char itemname[MAX_MESSAGE_SIZE];
00612     char netname[MAX_MESSAGE_SIZE];
00613     int client;
00614 
00615     if (!TeamPlayIsOn()) return;
00616     //if not addressed to this bot
00617     if (!BotAddressedToBot(bs, match)) return;
00618     //get the match variable
00619     trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
00620     //
00621     if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00622         //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
00623         //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
00624         return;
00625     }
00626     //
00627     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00628     //
00629     client = ClientFromName(netname);
00630     //the team mate who ordered
00631     bs->decisionmaker = client;
00632     bs->ordered = qtrue;
00633     bs->order_time = FloatTime();
00634     //set the time to send a message to the team mates
00635     bs->teammessage_time = FloatTime() + 2 * random();
00636     //set the ltg type
00637     bs->ltgtype = LTG_DEFENDKEYAREA;
00638     //get the team goal time
00639     bs->teamgoal_time = BotGetTime(match);
00640     //set the team goal time
00641     if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
00642     //away from defending
00643     bs->defendaway_time = 0;
00644     //
00645     BotSetTeamStatus(bs);
00646     // remember last ordered task
00647     BotRememberLastOrderedTask(bs);
00648 #ifdef DEBUG
00649     BotPrintTeamGoal(bs);
00650 #endif //DEBUG
00651 }
00652 
00653 /*
00654 ==================
00655 BotMatch_GetItem
00656 ==================
00657 */
00658 void BotMatch_GetItem(bot_state_t *bs, bot_match_t *match) {
00659     char itemname[MAX_MESSAGE_SIZE];
00660     char netname[MAX_MESSAGE_SIZE];
00661     int client;
00662 
00663     if (!TeamPlayIsOn()) return;
00664     //if not addressed to this bot
00665     if (!BotAddressedToBot(bs, match)) return;
00666     //get the match variable
00667     trap_BotMatchVariable(match, ITEM, itemname, sizeof(itemname));
00668     //
00669     if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00670         //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
00671         //trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
00672         return;
00673     }
00674     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00675     client = ClientOnSameTeamFromName(bs, netname);
00676     //
00677     bs->decisionmaker = client;
00678     bs->ordered = qtrue;
00679     bs->order_time = FloatTime();
00680     //set the time to send a message to the team mates
00681     bs->teammessage_time = FloatTime() + 2 * random();
00682     //set the ltg type
00683     bs->ltgtype = LTG_GETITEM;
00684     //set the team goal time
00685     bs->teamgoal_time = FloatTime() + TEAM_GETITEM_TIME;
00686     //
00687     BotSetTeamStatus(bs);
00688 #ifdef DEBUG
00689     BotPrintTeamGoal(bs);
00690 #endif //DEBUG
00691 }
00692 
00693 /*
00694 ==================
00695 BotMatch_Camp
00696 ==================
00697 */
00698 void BotMatch_Camp(bot_state_t *bs, bot_match_t *match) {
00699     int client, areanum;
00700     char netname[MAX_MESSAGE_SIZE];
00701     char itemname[MAX_MESSAGE_SIZE];
00702     aas_entityinfo_t entinfo;
00703 
00704     if (!TeamPlayIsOn()) return;
00705     //if not addressed to this bot
00706     if (!BotAddressedToBot(bs, match)) return;
00707     //
00708     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00709     //asked for someone else
00710     client = FindClientByName(netname);
00711     //if there's no valid client with this name
00712     if (client < 0) {
00713         BotAI_BotInitialChat(bs, "whois", netname, NULL);
00714         trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
00715         return;
00716     }
00717     //get the match variable
00718     trap_BotMatchVariable(match, KEYAREA, itemname, sizeof(itemname));
00719     //in CTF it could be the base
00720     if (match->subtype & ST_THERE) {
00721         //camp at the spot the bot is currently standing
00722         bs->teamgoal.entitynum = bs->entitynum;
00723         bs->teamgoal.areanum = bs->areanum;
00724         VectorCopy(bs->origin, bs->teamgoal.origin);
00725         VectorSet(bs->teamgoal.mins, -8, -8, -8);
00726         VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00727     }
00728     else if (match->subtype & ST_HERE) {
00729         //if this is the bot self
00730         if (client == bs->client) return;
00731         //
00732         bs->teamgoal.entitynum = -1;
00733         BotEntityInfo(client, &entinfo);
00734         //if info is valid (in PVS)
00735         if (entinfo.valid) {
00736             areanum = BotPointAreaNum(entinfo.origin);
00737             if (areanum) {// && trap_AAS_AreaReachability(areanum)) {
00738                 //NOTE: just assume the bot knows where the person is
00739                 //if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {
00740                     bs->teamgoal.entitynum = client;
00741                     bs->teamgoal.areanum = areanum;
00742                     VectorCopy(entinfo.origin, bs->teamgoal.origin);
00743                     VectorSet(bs->teamgoal.mins, -8, -8, -8);
00744                     VectorSet(bs->teamgoal.maxs, 8, 8, 8);
00745                 //}
00746             }
00747         }
00748         //if the other is not visible
00749         if (bs->teamgoal.entitynum < 0) {
00750             BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
00751             client = ClientFromName(netname);
00752             trap_BotEnterChat(bs->cs, client, CHAT_TELL);
00753             return;
00754         }
00755     }
00756     else if (!BotGetMessageTeamGoal(bs, itemname, &bs->teamgoal)) {
00757         //BotAI_BotInitialChat(bs, "cannotfind", itemname, NULL);
00758         //client = ClientFromName(netname);
00759         //trap_BotEnterChat(bs->cs, client, CHAT_TELL);
00760         return;
00761     }
00762     //
00763     bs->decisionmaker = client;
00764     bs->ordered = qtrue;
00765     bs->order_time = FloatTime();
00766     //set the time to send a message to the team mates
00767     bs->teammessage_time = FloatTime() + 2 * random();
00768     //set the ltg type
00769     bs->ltgtype = LTG_CAMPORDER;
00770     //get the team goal time
00771     bs->teamgoal_time = BotGetTime(match);
00772     //set the team goal time
00773     if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
00774     //not arrived yet
00775     bs->arrive_time = 0;
00776     //
00777     BotSetTeamStatus(bs);
00778     // remember last ordered task
00779     BotRememberLastOrderedTask(bs);
00780 #ifdef DEBUG
00781     BotPrintTeamGoal(bs);
00782 #endif //DEBUG
00783 }
00784 
00785 /*
00786 ==================
00787 BotMatch_Patrol
00788 ==================
00789 */
00790 void BotMatch_Patrol(bot_state_t *bs, bot_match_t *match) {
00791     char netname[MAX_MESSAGE_SIZE];
00792     int client;
00793 
00794     if (!TeamPlayIsOn()) return;
00795     //if not addressed to this bot
00796     if (!BotAddressedToBot(bs, match)) return;
00797     //get the patrol waypoints
00798     if (!BotGetPatrolWaypoints(bs, match)) return;
00799     //
00800     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00801     //
00802     client = FindClientByName(netname);
00803     //
00804     bs->decisionmaker = client;
00805     bs->ordered = qtrue;
00806     bs->order_time = FloatTime();
00807     //set the time to send a message to the team mates
00808     bs->teammessage_time = FloatTime() + 2 * random();
00809     //set the ltg type
00810     bs->ltgtype = LTG_PATROL;
00811     //get the team goal time
00812     bs->teamgoal_time = BotGetTime(match);
00813     //set the team goal time if not set already
00814     if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_PATROL_TIME;
00815     //
00816     BotSetTeamStatus(bs);
00817     // remember last ordered task
00818     BotRememberLastOrderedTask(bs);
00819 #ifdef DEBUG
00820     BotPrintTeamGoal(bs);
00821 #endif //DEBUG
00822 }
00823 
00824 /*
00825 ==================
00826 BotMatch_GetFlag
00827 ==================
00828 */
00829 void BotMatch_GetFlag(bot_state_t *bs, bot_match_t *match) {
00830     char netname[MAX_MESSAGE_SIZE];
00831     int client;
00832 
00833     if (gametype == GT_CTF) {
00834         if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
00835             return;
00836     }
00837 #ifdef MISSIONPACK
00838     else if (gametype == GT_1FCTF) {
00839         if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
00840             return;
00841     }
00842 #endif
00843     else {
00844         return;
00845     }
00846     //if not addressed to this bot
00847     if (!BotAddressedToBot(bs, match)) return;
00848     //
00849     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00850     //
00851     client = FindClientByName(netname);
00852     //
00853     bs->decisionmaker = client;
00854     bs->ordered = qtrue;
00855     bs->order_time = FloatTime();
00856     //set the time to send a message to the team mates
00857     bs->teammessage_time = FloatTime() + 2 * random();
00858     //set the ltg type
00859     bs->ltgtype = LTG_GETFLAG;
00860     //set the team goal time
00861     bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
00862     // get an alternate route in ctf
00863     if (gametype == GT_CTF) {
00864         //get an alternative route goal towards the enemy base
00865         BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00866     }
00867     //
00868     BotSetTeamStatus(bs);
00869     // remember last ordered task
00870     BotRememberLastOrderedTask(bs);
00871 #ifdef DEBUG
00872     BotPrintTeamGoal(bs);
00873 #endif //DEBUG
00874 }
00875 
00876 /*
00877 ==================
00878 BotMatch_AttackEnemyBase
00879 ==================
00880 */
00881 void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) {
00882     char netname[MAX_MESSAGE_SIZE];
00883     int client;
00884 
00885     if (gametype == GT_CTF) {
00886         BotMatch_GetFlag(bs, match);
00887     }
00888 #ifdef MISSIONPACK
00889     else if (gametype == GT_1FCTF || gametype == GT_OBELISK || gametype == GT_HARVESTER) {
00890         if (!redobelisk.areanum || !blueobelisk.areanum)
00891             return;
00892     }
00893 #endif
00894     else {
00895         return;
00896     }
00897     //if not addressed to this bot
00898     if (!BotAddressedToBot(bs, match)) return;
00899     //
00900     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00901     //
00902     client = FindClientByName(netname);
00903     //
00904     bs->decisionmaker = client;
00905     bs->ordered = qtrue;
00906     bs->order_time = FloatTime();
00907     //set the time to send a message to the team mates
00908     bs->teammessage_time = FloatTime() + 2 * random();
00909     //set the ltg type
00910     bs->ltgtype = LTG_ATTACKENEMYBASE;
00911     //set the team goal time
00912     bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
00913     bs->attackaway_time = 0;
00914     //
00915     BotSetTeamStatus(bs);
00916     // remember last ordered task
00917     BotRememberLastOrderedTask(bs);
00918 #ifdef DEBUG
00919     BotPrintTeamGoal(bs);
00920 #endif //DEBUG
00921 }
00922 
00923 #ifdef MISSIONPACK
00924 /*
00925 ==================
00926 BotMatch_Harvest
00927 ==================
00928 */
00929 void BotMatch_Harvest(bot_state_t *bs, bot_match_t *match) {
00930     char netname[MAX_MESSAGE_SIZE];
00931     int client;
00932 
00933     if (gametype == GT_HARVESTER) {
00934         if (!neutralobelisk.areanum || !redobelisk.areanum || !blueobelisk.areanum)
00935             return;
00936     }
00937     else {
00938         return;
00939     }
00940     //if not addressed to this bot
00941     if (!BotAddressedToBot(bs, match)) return;
00942     //
00943     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00944     //
00945     client = FindClientByName(netname);
00946     //
00947     bs->decisionmaker = client;
00948     bs->ordered = qtrue;
00949     bs->order_time = FloatTime();
00950     //set the time to send a message to the team mates
00951     bs->teammessage_time = FloatTime() + 2 * random();
00952     //set the ltg type
00953     bs->ltgtype = LTG_HARVEST;
00954     //set the team goal time
00955     bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
00956     bs->harvestaway_time = 0;
00957     //
00958     BotSetTeamStatus(bs);
00959     // remember last ordered task
00960     BotRememberLastOrderedTask(bs);
00961 #ifdef DEBUG
00962     BotPrintTeamGoal(bs);
00963 #endif //DEBUG
00964 }
00965 #endif
00966 
00967 /*
00968 ==================
00969 BotMatch_RushBase
00970 ==================
00971 */
00972 void BotMatch_RushBase(bot_state_t *bs, bot_match_t *match) {
00973     char netname[MAX_MESSAGE_SIZE];
00974     int client;
00975 
00976     if (gametype == GT_CTF) {
00977         if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
00978             return;
00979     }
00980 #ifdef MISSIONPACK
00981     else if (gametype == GT_1FCTF || gametype == GT_HARVESTER) {
00982         if (!redobelisk.areanum || !blueobelisk.areanum)
00983             return;
00984     }
00985 #endif
00986     else {
00987         return;
00988     }
00989     //if not addressed to this bot
00990     if (!BotAddressedToBot(bs, match)) return;
00991     //
00992     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
00993     //
00994     client = FindClientByName(netname);
00995     //
00996     bs->decisionmaker = client;
00997     bs->ordered = qtrue;
00998     bs->order_time = FloatTime();
00999     //set the time to send a message to the team mates
01000     bs->teammessage_time = FloatTime() + 2 * random();
01001     //set the ltg type
01002     bs->ltgtype = LTG_RUSHBASE;
01003     //set the team goal time
01004     bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
01005     bs->rushbaseaway_time = 0;
01006     //
01007     BotSetTeamStatus(bs);
01008 #ifdef DEBUG
01009     BotPrintTeamGoal(bs);
01010 #endif //DEBUG
01011 }
01012 
01013 /*
01014 ==================
01015 BotMatch_TaskPreference
01016 ==================
01017 */
01018 void BotMatch_TaskPreference(bot_state_t *bs, bot_match_t *match) {
01019     char netname[MAX_NETNAME];
01020     char teammatename[MAX_MESSAGE_SIZE];
01021     int teammate, preference;
01022 
01023     ClientName(bs->client, netname, sizeof(netname));
01024     if (Q_stricmp(netname, bs->teamleader) != 0) return;
01025 
01026     trap_BotMatchVariable(match, NETNAME, teammatename, sizeof(teammatename));
01027     teammate = ClientFromName(teammatename);
01028     if (teammate < 0) return;
01029 
01030     preference = BotGetTeamMateTaskPreference(bs, teammate);
01031     switch(match->subtype)
01032     {
01033         case ST_DEFENDER:
01034         {
01035             preference &= ~TEAMTP_ATTACKER;
01036             preference |= TEAMTP_DEFENDER;
01037             break;
01038         }
01039         case ST_ATTACKER:
01040         {
01041             preference &= ~TEAMTP_DEFENDER;
01042             preference |= TEAMTP_ATTACKER;
01043             break;
01044         }
01045         case ST_ROAMER:
01046         {
01047             preference &= ~(TEAMTP_ATTACKER|TEAMTP_DEFENDER);
01048             break;
01049         }
01050     }
01051     BotSetTeamMateTaskPreference(bs, teammate, preference);
01052     //
01053     EasyClientName(teammate, teammatename, sizeof(teammatename));
01054     BotAI_BotInitialChat(bs, "keepinmind", teammatename, NULL);
01055     trap_BotEnterChat(bs->cs, teammate, CHAT_TELL);
01056     BotVoiceChatOnly(bs, teammate, VOICECHAT_YES);
01057     trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
01058 }
01059 
01060 /*
01061 ==================
01062 BotMatch_ReturnFlag
01063 ==================
01064 */
01065 void BotMatch_ReturnFlag(bot_state_t *bs, bot_match_t *match) {
01066     char netname[MAX_MESSAGE_SIZE];
01067     int client;
01068 
01069     //if not in CTF mode
01070     if (
01071         gametype != GT_CTF
01072 #ifdef MISSIONPACK
01073         && gametype != GT_1FCTF
01074 #endif
01075         )
01076         return;
01077     //if not addressed to this bot
01078     if (!BotAddressedToBot(bs, match))
01079         return;
01080     //
01081     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01082     //
01083     client = FindClientByName(netname);
01084     //
01085     bs->decisionmaker = client;
01086     bs->ordered = qtrue;
01087     bs->order_time = FloatTime();
01088     //set the time to send a message to the team mates
01089     bs->teammessage_time = FloatTime() + 2 * random();
01090     //set the ltg type
01091     bs->ltgtype = LTG_RETURNFLAG;
01092     //set the team goal time
01093     bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
01094     bs->rushbaseaway_time = 0;
01095     //
01096     BotSetTeamStatus(bs);
01097 #ifdef DEBUG
01098     BotPrintTeamGoal(bs);
01099 #endif //DEBUG
01100 }
01101 
01102 /*
01103 ==================
01104 BotMatch_JoinSubteam
01105 ==================
01106 */
01107 void BotMatch_JoinSubteam(bot_state_t *bs, bot_match_t *match) {
01108     char teammate[MAX_MESSAGE_SIZE];
01109     char netname[MAX_MESSAGE_SIZE];
01110     int client;
01111 
01112     if (!TeamPlayIsOn()) return;
01113     //if not addressed to this bot
01114     if (!BotAddressedToBot(bs, match)) return;
01115     //get the sub team name
01116     trap_BotMatchVariable(match, TEAMNAME, teammate, sizeof(teammate));
01117     //set the sub team name
01118     strncpy(bs->subteam, teammate, 32);
01119     bs->subteam[31] = '\0';
01120     //
01121     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01122     BotAI_BotInitialChat(bs, "joinedteam", teammate, NULL);
01123     client = ClientFromName(netname);
01124     trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01125 }
01126 
01127 /*
01128 ==================
01129 BotMatch_LeaveSubteam
01130 ==================
01131 */
01132 void BotMatch_LeaveSubteam(bot_state_t *bs, bot_match_t *match) {
01133     char netname[MAX_MESSAGE_SIZE];
01134     int client;
01135 
01136     if (!TeamPlayIsOn()) return;
01137     //if not addressed to this bot
01138     if (!BotAddressedToBot(bs, match)) return;
01139     //
01140     if (strlen(bs->subteam))
01141     {
01142         BotAI_BotInitialChat(bs, "leftteam", bs->subteam, NULL);
01143         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01144         client = ClientFromName(netname);
01145         trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01146     } //end if
01147     strcpy(bs->subteam, "");
01148 }
01149 
01150 /*
01151 ==================
01152 BotMatch_LeaveSubteam
01153 ==================
01154 */
01155 void BotMatch_WhichTeam(bot_state_t *bs, bot_match_t *match) {
01156     if (!TeamPlayIsOn()) return;
01157     //if not addressed to this bot
01158     if (!BotAddressedToBot(bs, match)) return;
01159     //
01160     if (strlen(bs->subteam)) {
01161         BotAI_BotInitialChat(bs, "inteam", bs->subteam, NULL);
01162     }
01163     else {
01164         BotAI_BotInitialChat(bs, "noteam", NULL);
01165     }
01166     trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01167 }
01168 
01169 /*
01170 ==================
01171 BotMatch_CheckPoint
01172 ==================
01173 */
01174 void BotMatch_CheckPoint(bot_state_t *bs, bot_match_t *match) {
01175     int areanum, client;
01176     char buf[MAX_MESSAGE_SIZE];
01177     char netname[MAX_MESSAGE_SIZE];
01178     vec3_t position;
01179     bot_waypoint_t *cp;
01180 
01181     if (!TeamPlayIsOn()) return;
01182     //
01183     trap_BotMatchVariable(match, POSITION, buf, MAX_MESSAGE_SIZE);
01184     VectorClear(position);
01185     //
01186     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01187     client = ClientFromName(netname);
01188     //BotGPSToPosition(buf, position);
01189     sscanf(buf, "%f %f %f", &position[0], &position[1], &position[2]);
01190     position[2] += 0.5;
01191     areanum = BotPointAreaNum(position);
01192     if (!areanum) {
01193         if (BotAddressedToBot(bs, match)) {
01194             BotAI_BotInitialChat(bs, "checkpoint_invalid", NULL);
01195             trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01196         }
01197         return;
01198     }
01199     //
01200     trap_BotMatchVariable(match, NAME, buf, MAX_MESSAGE_SIZE);
01201     //check if there already exists a checkpoint with this name
01202     cp = BotFindWayPoint(bs->checkpoints, buf);
01203     if (cp) {
01204         if (cp->next) cp->next->prev = cp->prev;
01205         if (cp->prev) cp->prev->next = cp->next;
01206         else bs->checkpoints = cp->next;
01207         cp->inuse = qfalse;
01208     }
01209     //create a new check point
01210     cp = BotCreateWayPoint(buf, position, areanum);
01211     //add the check point to the bot's known chech points
01212     cp->next = bs->checkpoints;
01213     if (bs->checkpoints) bs->checkpoints->prev = cp;
01214     bs->checkpoints = cp;
01215     //
01216     if (BotAddressedToBot(bs, match)) {
01217         Com_sprintf(buf, sizeof(buf), "%1.0f %1.0f %1.0f", cp->goal.origin[0],
01218                                                     cp->goal.origin[1],
01219                                                     cp->goal.origin[2]);
01220 
01221         BotAI_BotInitialChat(bs, "checkpoint_confirm", cp->name, buf, NULL);
01222         trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01223     }
01224 }
01225 
01226 /*
01227 ==================
01228 BotMatch_FormationSpace
01229 ==================
01230 */
01231 void BotMatch_FormationSpace(bot_state_t *bs, bot_match_t *match) {
01232     char buf[MAX_MESSAGE_SIZE];
01233     float space;
01234 
01235     if (!TeamPlayIsOn()) return;
01236     //if not addressed to this bot
01237     if (!BotAddressedToBot(bs, match)) return;
01238     //
01239     trap_BotMatchVariable(match, NUMBER, buf, MAX_MESSAGE_SIZE);
01240     //if it's the distance in feet
01241     if (match->subtype & ST_FEET) space = 0.3048 * 32 * atof(buf);
01242     //else it's in meters
01243     else space = 32 * atof(buf);
01244     //check if the formation intervening space is valid
01245     if (space < 48 || space > 500) space = 100;
01246     bs->formation_dist = space;
01247 }
01248 
01249 /*
01250 ==================
01251 BotMatch_Dismiss
01252 ==================
01253 */
01254 void BotMatch_Dismiss(bot_state_t *bs, bot_match_t *match) {
01255     char netname[MAX_MESSAGE_SIZE];
01256     int client;
01257 
01258     if (!TeamPlayIsOn()) return;
01259     //if not addressed to this bot
01260     if (!BotAddressedToBot(bs, match)) return;
01261     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01262     client = ClientFromName(netname);
01263     //
01264     bs->decisionmaker = client;
01265     //
01266     bs->ltgtype = 0;
01267     bs->lead_time = 0;
01268     bs->lastgoal_ltgtype = 0;
01269     //
01270     BotAI_BotInitialChat(bs, "dismissed", NULL);
01271     trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01272 }
01273 
01274 /*
01275 ==================
01276 BotMatch_Suicide
01277 ==================
01278 */
01279 void BotMatch_Suicide(bot_state_t *bs, bot_match_t *match) {
01280     char netname[MAX_MESSAGE_SIZE];
01281     int client;
01282 
01283     if (!TeamPlayIsOn()) return;
01284     //if not addressed to this bot
01285     if (!BotAddressedToBot(bs, match)) return;
01286     //
01287     trap_EA_Command(bs->client, "kill");
01288     //
01289     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01290     client = ClientFromName(netname);
01291     //
01292     BotVoiceChat(bs, client, VOICECHAT_TAUNT);
01293     trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
01294 }
01295 
01296 /*
01297 ==================
01298 BotMatch_StartTeamLeaderShip
01299 ==================
01300 */
01301 void BotMatch_StartTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
01302     int client;
01303     char teammate[MAX_MESSAGE_SIZE];
01304 
01305     if (!TeamPlayIsOn()) return;
01306     //if chats for him or herself
01307     if (match->subtype & ST_I) {
01308         //get the team mate that will be the team leader
01309         trap_BotMatchVariable(match, NETNAME, teammate, sizeof(teammate));
01310         strncpy(bs->teamleader, teammate, sizeof(bs->teamleader));
01311         bs->teamleader[sizeof(bs->teamleader)] = '\0';
01312     }
01313     //chats for someone else
01314     else {
01315         //get the team mate that will be the team leader
01316         trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01317         client = FindClientByName(teammate);
01318         if (client >= 0) ClientName(client, bs->teamleader, sizeof(bs->teamleader));
01319     }
01320 }
01321 
01322 /*
01323 ==================
01324 BotMatch_StopTeamLeaderShip
01325 ==================
01326 */
01327 void BotMatch_StopTeamLeaderShip(bot_state_t *bs, bot_match_t *match) {
01328     int client;
01329     char teammate[MAX_MESSAGE_SIZE];
01330     char netname[MAX_MESSAGE_SIZE];
01331 
01332     if (!TeamPlayIsOn()) return;
01333     //get the team mate that stops being the team leader
01334     trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01335     //if chats for him or herself
01336     if (match->subtype & ST_I) {
01337         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01338         client = FindClientByName(netname);
01339     }
01340     //chats for someone else
01341     else {
01342         client = FindClientByName(teammate);
01343     } //end else
01344     if (client >= 0) {
01345         if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
01346             bs->teamleader[0] = '\0';
01347             notleader[client] = qtrue;
01348         }
01349     }
01350 }
01351 
01352 /*
01353 ==================
01354 BotMatch_WhoIsTeamLeader
01355 ==================
01356 */
01357 void BotMatch_WhoIsTeamLeader(bot_state_t *bs, bot_match_t *match) {
01358     char netname[MAX_MESSAGE_SIZE];
01359 
01360     if (!TeamPlayIsOn()) return;
01361 
01362     ClientName(bs->client, netname, sizeof(netname));
01363     //if this bot IS the team leader
01364     if (!Q_stricmp(netname, bs->teamleader)) {
01365         trap_EA_SayTeam(bs->client, "I'm the team leader\n");
01366     }
01367 }
01368 
01369 /*
01370 ==================
01371 BotMatch_WhatAreYouDoing
01372 ==================
01373 */
01374 void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) {
01375     char netname[MAX_MESSAGE_SIZE];
01376     char goalname[MAX_MESSAGE_SIZE];
01377     int client;
01378 
01379     //if not addressed to this bot
01380     if (!BotAddressedToBot(bs, match)) return;
01381     //
01382     switch(bs->ltgtype) {
01383         case LTG_TEAMHELP:
01384         {
01385             EasyClientName(bs->teammate, netname, sizeof(netname));
01386             BotAI_BotInitialChat(bs, "helping", netname, NULL);
01387             break;
01388         }
01389         case LTG_TEAMACCOMPANY:
01390         {
01391             EasyClientName(bs->teammate, netname, sizeof(netname));
01392             BotAI_BotInitialChat(bs, "accompanying", netname, NULL);
01393             break;
01394         }
01395         case LTG_DEFENDKEYAREA:
01396         {
01397             trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
01398             BotAI_BotInitialChat(bs, "defending", goalname, NULL);
01399             break;
01400         }
01401         case LTG_GETITEM:
01402         {
01403             trap_BotGoalName(bs->teamgoal.number, goalname, sizeof(goalname));
01404             BotAI_BotInitialChat(bs, "gettingitem", goalname, NULL);
01405             break;
01406         }
01407         case LTG_KILL:
01408         {
01409             ClientName(bs->teamgoal.entitynum, netname, sizeof(netname));
01410             BotAI_BotInitialChat(bs, "killing", netname, NULL);
01411             break;
01412         }
01413         case LTG_CAMP:
01414         case LTG_CAMPORDER:
01415         {
01416             BotAI_BotInitialChat(bs, "camping", NULL);
01417             break;
01418         }
01419         case LTG_PATROL:
01420         {
01421             BotAI_BotInitialChat(bs, "patrolling", NULL);
01422             break;
01423         }
01424         case LTG_GETFLAG:
01425         {
01426             BotAI_BotInitialChat(bs, "capturingflag", NULL);
01427             break;
01428         }
01429         case LTG_RUSHBASE:
01430         {
01431             BotAI_BotInitialChat(bs, "rushingbase", NULL);
01432             break;
01433         }
01434         case LTG_RETURNFLAG:
01435         {
01436             BotAI_BotInitialChat(bs, "returningflag", NULL);
01437             break;
01438         }
01439 #ifdef MISSIONPACK
01440         case LTG_ATTACKENEMYBASE:
01441         {
01442             BotAI_BotInitialChat(bs, "attackingenemybase", NULL);
01443             break;
01444         }
01445         case LTG_HARVEST:
01446         {
01447             BotAI_BotInitialChat(bs, "harvesting", NULL);
01448             break;
01449         }
01450 #endif
01451         default:
01452         {
01453             BotAI_BotInitialChat(bs, "roaming", NULL);
01454             break;
01455         }
01456     }
01457     //chat what the bot is doing
01458     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01459     client = ClientFromName(netname);
01460     trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01461 }
01462 
01463 /*
01464 ==================
01465 BotMatch_WhatIsMyCommand
01466 ==================
01467 */
01468 void BotMatch_WhatIsMyCommand(bot_state_t *bs, bot_match_t *match) {
01469     char netname[MAX_NETNAME];
01470 
01471     ClientName(bs->client, netname, sizeof(netname));
01472     if (Q_stricmp(netname, bs->teamleader) != 0) return;
01473     bs->forceorders = qtrue;
01474 }
01475 
01476 /*
01477 ==================
01478 BotNearestVisibleItem
01479 ==================
01480 */
01481 float BotNearestVisibleItem(bot_state_t *bs, char *itemname, bot_goal_t *goal) {
01482     int i;
01483     char name[64];
01484     bot_goal_t tmpgoal;
01485     float dist, bestdist;
01486     vec3_t dir;
01487     bsp_trace_t trace;
01488 
01489     bestdist = 999999;
01490     i = -1;
01491     do {
01492         i = trap_BotGetLevelItemGoal(i, itemname, &tmpgoal);
01493         trap_BotGoalName(tmpgoal.number, name, sizeof(name));
01494         if (Q_stricmp(itemname, name) != 0)
01495             continue;
01496         VectorSubtract(tmpgoal.origin, bs->origin, dir);
01497         dist = VectorLength(dir);
01498         if (dist < bestdist) {
01499             //trace from start to end
01500             BotAI_Trace(&trace, bs->eye, NULL, NULL, tmpgoal.origin, bs->client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
01501             if (trace.fraction >= 1.0) {
01502                 bestdist = dist;
01503                 memcpy(goal, &tmpgoal, sizeof(bot_goal_t));
01504             }
01505         }
01506     } while(i > 0);
01507     return bestdist;
01508 }
01509 
01510 /*
01511 ==================
01512 BotMatch_WhereAreYou
01513 ==================
01514 */
01515 void BotMatch_WhereAreYou(bot_state_t *bs, bot_match_t *match) {
01516     float dist, bestdist;
01517     int i, bestitem, redtt, bluett, client;
01518     bot_goal_t goal;
01519     char netname[MAX_MESSAGE_SIZE];
01520     char *nearbyitems[] = {
01521         "Shotgun",
01522         "Grenade Launcher",
01523         "Rocket Launcher",
01524         "Plasmagun",
01525         "Railgun",
01526         "Lightning Gun",
01527         "BFG10K",
01528         "Quad Damage",
01529         "Regeneration",
01530         "Battle Suit",
01531         "Speed",
01532         "Invisibility",
01533         "Flight",
01534         "Armor",
01535         "Heavy Armor",
01536         "Red Flag",
01537         "Blue Flag",
01538 #ifdef MISSIONPACK
01539         "Nailgun",
01540         "Prox Launcher",
01541         "Chaingun",
01542         "Scout",
01543         "Guard",
01544         "Doubler",
01545         "Ammo Regen",
01546         "Neutral Flag",
01547         "Red Obelisk",
01548         "Blue Obelisk",
01549         "Neutral Obelisk",
01550 #endif
01551         NULL
01552     };
01553     //
01554     if (!TeamPlayIsOn())
01555         return;
01556     //if not addressed to this bot
01557     if (!BotAddressedToBot(bs, match))
01558         return;
01559 
01560     bestitem = -1;
01561     bestdist = 999999;
01562     for (i = 0; nearbyitems[i]; i++) {
01563         dist = BotNearestVisibleItem(bs, nearbyitems[i], &goal);
01564         if (dist < bestdist) {
01565             bestdist = dist;
01566             bestitem = i;
01567         }
01568     }
01569     if (bestitem != -1) {
01570         if (gametype == GT_CTF
01571 #ifdef MISSIONPACK
01572             || gametype == GT_1FCTF
01573 #endif
01574             ) {
01575             redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_redflag.areanum, TFL_DEFAULT);
01576             bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, ctf_blueflag.areanum, TFL_DEFAULT);
01577             if (redtt < (redtt + bluett) * 0.4) {
01578                 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
01579             }
01580             else if (bluett < (redtt + bluett) * 0.4) {
01581                 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
01582             }
01583             else {
01584                 BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01585             }
01586         }
01587 #ifdef MISSIONPACK
01588         else if (gametype == GT_OBELISK || gametype == GT_HARVESTER) {
01589             redtt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, redobelisk.areanum, TFL_DEFAULT);
01590             bluett = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, blueobelisk.areanum, TFL_DEFAULT);
01591             if (redtt < (redtt + bluett) * 0.4) {
01592                 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "red", NULL);
01593             }
01594             else if (bluett < (redtt + bluett) * 0.4) {
01595                 BotAI_BotInitialChat(bs, "teamlocation", nearbyitems[bestitem], "blue", NULL);
01596             }
01597             else {
01598                 BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01599             }
01600         }
01601 #endif
01602         else {
01603             BotAI_BotInitialChat(bs, "location", nearbyitems[bestitem], NULL);
01604         }
01605         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01606         client = ClientFromName(netname);
01607         trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01608     }
01609 }
01610 
01611 /*
01612 ==================
01613 BotMatch_LeadTheWay
01614 ==================
01615 */
01616 void BotMatch_LeadTheWay(bot_state_t *bs, bot_match_t *match) {
01617     aas_entityinfo_t entinfo;
01618     char netname[MAX_MESSAGE_SIZE], teammate[MAX_MESSAGE_SIZE];
01619     int client, areanum, other;
01620 
01621     if (!TeamPlayIsOn()) return;
01622     //if not addressed to this bot
01623     if (!BotAddressedToBot(bs, match)) return;
01624     //if someone asks for someone else
01625     if (match->subtype & ST_SOMEONE) {
01626         //get the team mate name
01627         trap_BotMatchVariable(match, TEAMMATE, teammate, sizeof(teammate));
01628         client = FindClientByName(teammate);
01629         //if this is the bot self
01630         if (client == bs->client) {
01631             other = qfalse;
01632         }
01633         else if (!BotSameTeam(bs, client)) {
01634             //FIXME: say "I don't help the enemy"
01635             return;
01636         }
01637         else {
01638             other = qtrue;
01639         }
01640     }
01641     else {
01642         //get the netname
01643         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01644         client = ClientFromName(netname);
01645         other = qfalse;
01646     }
01647     //if the bot doesn't know who to help (FindClientByName returned -1)
01648     if (client < 0) {
01649         BotAI_BotInitialChat(bs, "whois", netname, NULL);
01650         trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01651         return;
01652     }
01653     //
01654     bs->lead_teamgoal.entitynum = -1;
01655     BotEntityInfo(client, &entinfo);
01656     //if info is valid (in PVS)
01657     if (entinfo.valid) {
01658         areanum = BotPointAreaNum(entinfo.origin);
01659         if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
01660             bs->lead_teamgoal.entitynum = client;
01661             bs->lead_teamgoal.areanum = areanum;
01662             VectorCopy(entinfo.origin, bs->lead_teamgoal.origin);
01663             VectorSet(bs->lead_teamgoal.mins, -8, -8, -8);
01664             VectorSet(bs->lead_teamgoal.maxs, 8, 8, 8);
01665         }
01666     }
01667 
01668     if (bs->teamgoal.entitynum < 0) {
01669         if (other) BotAI_BotInitialChat(bs, "whereis", teammate, NULL);
01670         else BotAI_BotInitialChat(bs, "whereareyou", netname, NULL);
01671         trap_BotEnterChat(bs->cs, bs->client, CHAT_TEAM);
01672         return;
01673     }
01674     bs->lead_teammate = client;
01675     bs->lead_time = FloatTime() + TEAM_LEAD_TIME;
01676     bs->leadvisible_time = 0;
01677     bs->leadmessage_time = -(FloatTime() + 2 * random());
01678 }
01679 
01680 /*
01681 ==================
01682 BotMatch_Kill
01683 ==================
01684 */
01685 void BotMatch_Kill(bot_state_t *bs, bot_match_t *match) {
01686     char enemy[MAX_MESSAGE_SIZE];
01687     char netname[MAX_MESSAGE_SIZE];
01688     int client;
01689 
01690     if (!TeamPlayIsOn()) return;
01691     //if not addressed to this bot
01692     if (!BotAddressedToBot(bs, match)) return;
01693 
01694     trap_BotMatchVariable(match, ENEMY, enemy, sizeof(enemy));
01695     //
01696     client = FindEnemyByName(bs, enemy);
01697     if (client < 0) {
01698         BotAI_BotInitialChat(bs, "whois", enemy, NULL);
01699         trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01700         client = ClientFromName(netname);
01701         trap_BotEnterChat(bs->cs, client, CHAT_TELL);
01702         return;
01703     }
01704     bs->teamgoal.entitynum = client;
01705     //set the time to send a message to the team mates
01706     bs->teammessage_time = FloatTime() + 2 * random();
01707     //set the ltg type
01708     bs->ltgtype = LTG_KILL;
01709     //set the team goal time
01710     bs->teamgoal_time = FloatTime() + TEAM_KILL_SOMEONE;
01711     //
01712     BotSetTeamStatus(bs);
01713 #ifdef DEBUG
01714     BotPrintTeamGoal(bs);
01715 #endif //DEBUG
01716 }
01717 
01718 /*
01719 ==================
01720 BotMatch_CTF
01721 ==================
01722 */
01723 void BotMatch_CTF(bot_state_t *bs, bot_match_t *match) {
01724 
01725     char flag[128], netname[MAX_NETNAME];
01726 
01727     if (gametype == GT_CTF) {
01728         trap_BotMatchVariable(match, FLAG, flag, sizeof(flag));
01729         if (match->subtype & ST_GOTFLAG) {
01730             if (!Q_stricmp(flag, "red")) {
01731                 bs->redflagstatus = 1;
01732                 if (BotTeam(bs) == TEAM_BLUE) {
01733                     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01734                     bs->flagcarrier = ClientFromName(netname);
01735                 }
01736             }
01737             else {
01738                 bs->blueflagstatus = 1;
01739                 if (BotTeam(bs) == TEAM_RED) {
01740                     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01741                     bs->flagcarrier = ClientFromName(netname);
01742                 }
01743             }
01744             bs->flagstatuschanged = 1;
01745             bs->lastflagcapture_time = FloatTime();
01746         }
01747         else if (match->subtype & ST_CAPTUREDFLAG) {
01748             bs->redflagstatus = 0;
01749             bs->blueflagstatus = 0;
01750             bs->flagcarrier = 0;
01751             bs->flagstatuschanged = 1;
01752         }
01753         else if (match->subtype & ST_RETURNEDFLAG) {
01754             if (!Q_stricmp(flag, "red")) bs->redflagstatus = 0;
01755             else bs->blueflagstatus = 0;
01756             bs->flagstatuschanged = 1;
01757         }
01758     }
01759 #ifdef MISSIONPACK
01760     else if (gametype == GT_1FCTF) {
01761         if (match->subtype & ST_1FCTFGOTFLAG) {
01762             trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01763             bs->flagcarrier = ClientFromName(netname);
01764         }
01765     }
01766 #endif
01767 }
01768 
01769 void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) {
01770     int client;
01771     char netname[MAX_NETNAME];
01772 
01773     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01774     client = FindClientByName(netname);
01775     if (client >= 0) {
01776         notleader[client] = qfalse;
01777     }
01778     //NOTE: eliza chats will catch this
01779     //Com_sprintf(buf, sizeof(buf), "heya %s", netname);
01780     //EA_Say(bs->client, buf);
01781 }
01782 
01783 void BotMatch_NewLeader(bot_state_t *bs, bot_match_t *match) {
01784     int client;
01785     char netname[MAX_NETNAME];
01786 
01787     trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname));
01788     client = FindClientByName(netname);
01789     if (!BotSameTeam(bs, client))
01790         return;
01791     Q_strncpyz(bs->teamleader, netname, sizeof(bs->teamleader));
01792 }
01793 
01794 /*
01795 ==================
01796 BotMatchMessage
01797 ==================
01798 */
01799 int BotMatchMessage(bot_state_t *bs, char *message) {
01800     bot_match_t match;
01801 
01802     match.type = 0;
01803     //if it is an unknown message
01804     if (!trap_BotFindMatch(message, &match, MTCONTEXT_MISC
01805                                             |MTCONTEXT_INITIALTEAMCHAT
01806                                             |MTCONTEXT_CTF)) {
01807         return qfalse;
01808     }
01809     //react to the found message
01810     switch(match.type)
01811     {
01812         case MSG_HELP:                  //someone calling for help
01813         case MSG_ACCOMPANY:             //someone calling for company
01814         {
01815             BotMatch_HelpAccompany(bs, &match);
01816             break;
01817         }
01818         case MSG_DEFENDKEYAREA:         //teamplay defend a key area
01819         {
01820             BotMatch_DefendKeyArea(bs, &match);
01821             break;
01822         }
01823         case MSG_CAMP:                  //camp somewhere
01824         {
01825             BotMatch_Camp(bs, &match);
01826             break;
01827         }
01828         case MSG_PATROL:                //patrol between several key areas
01829         {
01830             BotMatch_Patrol(bs, &match);
01831             break;
01832         }
01833         //CTF & 1FCTF
01834         case MSG_GETFLAG:               //ctf get the enemy flag
01835         {
01836             BotMatch_GetFlag(bs, &match);
01837             break;
01838         }
01839 #ifdef MISSIONPACK
01840         //CTF & 1FCTF & Obelisk & Harvester
01841         case MSG_ATTACKENEMYBASE:
01842         {
01843             BotMatch_AttackEnemyBase(bs, &match);
01844             break;
01845         }
01846         //Harvester
01847         case MSG_HARVEST:
01848         {
01849             BotMatch_Harvest(bs, &match);
01850             break;
01851         }
01852 #endif
01853         //CTF & 1FCTF & Harvester
01854         case MSG_RUSHBASE:              //ctf rush to the base
01855         {
01856             BotMatch_RushBase(bs, &match);
01857             break;
01858         }
01859         //CTF & 1FCTF
01860         case MSG_RETURNFLAG:
01861         {
01862             BotMatch_ReturnFlag(bs, &match);
01863             break;
01864         }
01865         //CTF & 1FCTF & Obelisk & Harvester
01866         case MSG_TASKPREFERENCE:
01867         {
01868             BotMatch_TaskPreference(bs, &match);
01869             break;
01870         }
01871         //CTF & 1FCTF
01872         case MSG_CTF:
01873         {
01874             BotMatch_CTF(bs, &match);
01875             break;
01876         }
01877         case MSG_GETITEM:
01878         {
01879             BotMatch_GetItem(bs, &match);
01880             break;
01881         }
01882         case MSG_JOINSUBTEAM:           //join a sub team
01883         {
01884             BotMatch_JoinSubteam(bs, &match);
01885             break;
01886         }
01887         case MSG_LEAVESUBTEAM:          //leave a sub team
01888         {
01889             BotMatch_LeaveSubteam(bs, &match);
01890             break;
01891         }
01892         case MSG_WHICHTEAM:
01893         {
01894             BotMatch_WhichTeam(bs, &match);
01895             break;
01896         }
01897         case MSG_CHECKPOINT:            //remember a check point
01898         {
01899             BotMatch_CheckPoint(bs, &match);
01900             break;
01901         }
01902         case MSG_CREATENEWFORMATION:    //start the creation of a new formation
01903         {
01904             trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
01905             break;
01906         }
01907         case MSG_FORMATIONPOSITION:     //tell someone his/her position in the formation
01908         {
01909             trap_EA_SayTeam(bs->client, "the part of my brain to create formations has been damaged");
01910             break;
01911         }
01912         case MSG_FORMATIONSPACE:        //set the formation space
01913         {
01914             BotMatch_FormationSpace(bs, &match);
01915             break;
01916         }
01917         case MSG_DOFORMATION:           //form a certain formation
01918         {
01919             break;
01920         }
01921         case MSG_DISMISS:               //dismiss someone
01922         {
01923             BotMatch_Dismiss(bs, &match);
01924             break;
01925         }
01926         case MSG_STARTTEAMLEADERSHIP:   //someone will become the team leader
01927         {
01928             BotMatch_StartTeamLeaderShip(bs, &match);
01929             break;
01930         }
01931         case MSG_STOPTEAMLEADERSHIP:    //someone will stop being the team leader
01932         {
01933             BotMatch_StopTeamLeaderShip(bs, &match);
01934             break;
01935         }
01936         case MSG_WHOISTEAMLAEDER:
01937         {
01938             BotMatch_WhoIsTeamLeader(bs, &match);
01939             break;
01940         }
01941         case MSG_WHATAREYOUDOING:       //ask a bot what he/she is doing
01942         {
01943             BotMatch_WhatAreYouDoing(bs, &match);
01944             break;
01945         }
01946         case MSG_WHATISMYCOMMAND:
01947         {
01948             BotMatch_WhatIsMyCommand(bs, &match);
01949             break;
01950         }
01951         case MSG_WHEREAREYOU:
01952         {
01953             BotMatch_WhereAreYou(bs, &match);
01954             break;
01955         }
01956         case MSG_LEADTHEWAY:
01957         {
01958             BotMatch_LeadTheWay(bs, &match);
01959             break;
01960         }
01961         case MSG_KILL:
01962         {
01963             BotMatch_Kill(bs, &match);
01964             break;
01965         }
01966         case MSG_ENTERGAME:             //someone entered the game
01967         {
01968             BotMatch_EnterGame(bs, &match);
01969             break;
01970         }
01971         case MSG_NEWLEADER:
01972         {
01973             BotMatch_NewLeader(bs, &match);
01974             break;
01975         }
01976         case MSG_WAIT:
01977         {
01978             break;
01979         }
01980         case MSG_SUICIDE:
01981         {
01982             BotMatch_Suicide(bs, &match);
01983             break;
01984         }
01985         default:
01986         {
01987             BotAI_Print(PRT_MESSAGE, "unknown match type\n");
01988             break;
01989         }
01990     }
01991     return qtrue;
01992 }

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