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

ai_dmq3.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_dmq3.c
00026  *
00027  * desc:        Quake3 bot AI
00028  *
00029  * $Archive: /MissionPack/code/game/ai_dmq3.c $
00030  *
00031  *****************************************************************************/
00032 
00033 
00034 #include "g_local.h"
00035 #include "botlib.h"
00036 #include "be_aas.h"
00037 #include "be_ea.h"
00038 #include "be_ai_char.h"
00039 #include "be_ai_chat.h"
00040 #include "be_ai_gen.h"
00041 #include "be_ai_goal.h"
00042 #include "be_ai_move.h"
00043 #include "be_ai_weap.h"
00044 //
00045 #include "ai_main.h"
00046 #include "ai_dmq3.h"
00047 #include "ai_chat.h"
00048 #include "ai_cmd.h"
00049 #include "ai_dmnet.h"
00050 #include "ai_team.h"
00051 //
00052 #include "chars.h"              //characteristics
00053 #include "inv.h"                //indexes into the inventory
00054 #include "syn.h"                //synonyms
00055 #include "match.h"              //string matching types and vars
00056 
00057 // for the voice chats
00058 #include "../../ui/menudef.h" // sos001205 - for q3_ui also
00059 
00060 // from aasfile.h
00061 #define AREACONTENTS_MOVER              1024
00062 #define AREACONTENTS_MODELNUMSHIFT      24
00063 #define AREACONTENTS_MAXMODELNUM        0xFF
00064 #define AREACONTENTS_MODELNUM           (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
00065 
00066 #define IDEAL_ATTACKDIST            140
00067 
00068 #define MAX_WAYPOINTS       128
00069 //
00070 bot_waypoint_t botai_waypoints[MAX_WAYPOINTS];
00071 bot_waypoint_t *botai_freewaypoints;
00072 
00073 //NOTE: not using a cvars which can be updated because the game should be reloaded anyway
00074 int gametype;       //game type
00075 int maxclients;     //maximum number of clients
00076 
00077 vmCvar_t bot_grapple;
00078 vmCvar_t bot_rocketjump;
00079 vmCvar_t bot_fastchat;
00080 vmCvar_t bot_nochat;
00081 vmCvar_t bot_testrchat;
00082 vmCvar_t bot_challenge;
00083 vmCvar_t bot_predictobstacles;
00084 vmCvar_t g_spSkill;
00085 
00086 extern vmCvar_t bot_developer;
00087 
00088 vec3_t lastteleport_origin;     //last teleport event origin
00089 float lastteleport_time;        //last teleport event time
00090 int max_bspmodelindex;          //maximum BSP model index
00091 
00092 //CTF flag goals
00093 bot_goal_t ctf_redflag;
00094 bot_goal_t ctf_blueflag;
00095 #ifdef MISSIONPACK
00096 bot_goal_t ctf_neutralflag;
00097 bot_goal_t redobelisk;
00098 bot_goal_t blueobelisk;
00099 bot_goal_t neutralobelisk;
00100 #endif
00101 
00102 #define MAX_ALTROUTEGOALS       32
00103 
00104 int altroutegoals_setup;
00105 aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];
00106 int red_numaltroutegoals;
00107 aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];
00108 int blue_numaltroutegoals;
00109 
00110 
00111 /*
00112 ==================
00113 BotSetUserInfo
00114 ==================
00115 */
00116 void BotSetUserInfo(bot_state_t *bs, char *key, char *value) {
00117     char userinfo[MAX_INFO_STRING];
00118 
00119     trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
00120     Info_SetValueForKey(userinfo, key, value);
00121     trap_SetUserinfo(bs->client, userinfo);
00122     ClientUserinfoChanged( bs->client );
00123 }
00124 
00125 /*
00126 ==================
00127 BotCTFCarryingFlag
00128 ==================
00129 */
00130 int BotCTFCarryingFlag(bot_state_t *bs) {
00131     if (gametype != GT_CTF) return CTF_FLAG_NONE;
00132 
00133     if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;
00134     else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;
00135     return CTF_FLAG_NONE;
00136 }
00137 
00138 /*
00139 ==================
00140 BotTeam
00141 ==================
00142 */
00143 int BotTeam(bot_state_t *bs) {
00144     char info[1024];
00145 
00146     if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
00147         //BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n");
00148         return qfalse;
00149     }
00150     trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info));
00151     //
00152     if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return TEAM_RED;
00153     else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return TEAM_BLUE;
00154     return TEAM_FREE;
00155 }
00156 
00157 /*
00158 ==================
00159 BotOppositeTeam
00160 ==================
00161 */
00162 int BotOppositeTeam(bot_state_t *bs) {
00163     switch(BotTeam(bs)) {
00164         case TEAM_RED: return TEAM_BLUE;
00165         case TEAM_BLUE: return TEAM_RED;
00166         default: return TEAM_FREE;
00167     }
00168 }
00169 
00170 /*
00171 ==================
00172 BotEnemyFlag
00173 ==================
00174 */
00175 bot_goal_t *BotEnemyFlag(bot_state_t *bs) {
00176     if (BotTeam(bs) == TEAM_RED) {
00177         return &ctf_blueflag;
00178     }
00179     else {
00180         return &ctf_redflag;
00181     }
00182 }
00183 
00184 /*
00185 ==================
00186 BotTeamFlag
00187 ==================
00188 */
00189 bot_goal_t *BotTeamFlag(bot_state_t *bs) {
00190     if (BotTeam(bs) == TEAM_RED) {
00191         return &ctf_redflag;
00192     }
00193     else {
00194         return &ctf_blueflag;
00195     }
00196 }
00197 
00198 
00199 /*
00200 ==================
00201 EntityIsDead
00202 ==================
00203 */
00204 qboolean EntityIsDead(aas_entityinfo_t *entinfo) {
00205     playerState_t ps;
00206 
00207     if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
00208         //retrieve the current client state
00209         BotAI_GetClientState( entinfo->number, &ps );
00210         if (ps.pm_type != PM_NORMAL) return qtrue;
00211     }
00212     return qfalse;
00213 }
00214 
00215 /*
00216 ==================
00217 EntityCarriesFlag
00218 ==================
00219 */
00220 qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {
00221     if ( entinfo->powerups & ( 1 << PW_REDFLAG ) )
00222         return qtrue;
00223     if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )
00224         return qtrue;
00225 #ifdef MISSIONPACK
00226     if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) )
00227         return qtrue;
00228 #endif
00229     return qfalse;
00230 }
00231 
00232 /*
00233 ==================
00234 EntityIsInvisible
00235 ==================
00236 */
00237 qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {
00238     // the flag is always visible
00239     if (EntityCarriesFlag(entinfo)) {
00240         return qfalse;
00241     }
00242     if (entinfo->powerups & (1 << PW_INVIS)) {
00243         return qtrue;
00244     }
00245     return qfalse;
00246 }
00247 
00248 /*
00249 ==================
00250 EntityIsShooting
00251 ==================
00252 */
00253 qboolean EntityIsShooting(aas_entityinfo_t *entinfo) {
00254     if (entinfo->flags & EF_FIRING) {
00255         return qtrue;
00256     }
00257     return qfalse;
00258 }
00259 
00260 /*
00261 ==================
00262 EntityIsChatting
00263 ==================
00264 */
00265 qboolean EntityIsChatting(aas_entityinfo_t *entinfo) {
00266     if (entinfo->flags & EF_TALK) {
00267         return qtrue;
00268     }
00269     return qfalse;
00270 }
00271 
00272 /*
00273 ==================
00274 EntityHasQuad
00275 ==================
00276 */
00277 qboolean EntityHasQuad(aas_entityinfo_t *entinfo) {
00278     if (entinfo->powerups & (1 << PW_QUAD)) {
00279         return qtrue;
00280     }
00281     return qfalse;
00282 }
00283 
00284 #ifdef MISSIONPACK
00285 /*
00286 ==================
00287 EntityHasKamikze
00288 ==================
00289 */
00290 qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) {
00291     if (entinfo->flags & EF_KAMIKAZE) {
00292         return qtrue;
00293     }
00294     return qfalse;
00295 }
00296 
00297 /*
00298 ==================
00299 EntityCarriesCubes
00300 ==================
00301 */
00302 qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) {
00303     entityState_t state;
00304 
00305     if (gametype != GT_HARVESTER)
00306         return qfalse;
00307     //FIXME: get this info from the aas_entityinfo_t ?
00308     BotAI_GetEntityState(entinfo->number, &state);
00309     if (state.generic1 > 0)
00310         return qtrue;
00311     return qfalse;
00312 }
00313 
00314 /*
00315 ==================
00316 Bot1FCTFCarryingFlag
00317 ==================
00318 */
00319 int Bot1FCTFCarryingFlag(bot_state_t *bs) {
00320     if (gametype != GT_1FCTF) return qfalse;
00321 
00322     if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue;
00323     return qfalse;
00324 }
00325 
00326 /*
00327 ==================
00328 BotHarvesterCarryingCubes
00329 ==================
00330 */
00331 int BotHarvesterCarryingCubes(bot_state_t *bs) {
00332     if (gametype != GT_HARVESTER) return qfalse;
00333 
00334     if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue;
00335     if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue;
00336     return qfalse;
00337 }
00338 #endif
00339 
00340 /*
00341 ==================
00342 BotRememberLastOrderedTask
00343 ==================
00344 */
00345 void BotRememberLastOrderedTask(bot_state_t *bs) {
00346     if (!bs->ordered) {
00347         return;
00348     }
00349     bs->lastgoal_decisionmaker = bs->decisionmaker;
00350     bs->lastgoal_ltgtype = bs->ltgtype;
00351     memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));
00352     bs->lastgoal_teammate = bs->teammate;
00353 }
00354 
00355 /*
00356 ==================
00357 BotSetTeamStatus
00358 ==================
00359 */
00360 void BotSetTeamStatus(bot_state_t *bs) {
00361 #ifdef MISSIONPACK
00362     int teamtask;
00363     aas_entityinfo_t entinfo;
00364 
00365     teamtask = TEAMTASK_PATROL;
00366 
00367     switch(bs->ltgtype) {
00368         case LTG_TEAMHELP:
00369             break;
00370         case LTG_TEAMACCOMPANY:
00371             BotEntityInfo(bs->teammate, &entinfo);
00372             if ( ( (gametype == GT_CTF || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo))
00373                 || ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) {
00374                 teamtask = TEAMTASK_ESCORT;
00375             }
00376             else {
00377                 teamtask = TEAMTASK_FOLLOW;
00378             }
00379             break;
00380         case LTG_DEFENDKEYAREA:
00381             teamtask = TEAMTASK_DEFENSE;
00382             break;
00383         case LTG_GETFLAG:
00384             teamtask = TEAMTASK_OFFENSE;
00385             break;
00386         case LTG_RUSHBASE:
00387             teamtask = TEAMTASK_DEFENSE;
00388             break;
00389         case LTG_RETURNFLAG:
00390             teamtask = TEAMTASK_RETRIEVE;
00391             break;
00392         case LTG_CAMP:
00393         case LTG_CAMPORDER:
00394             teamtask = TEAMTASK_CAMP;
00395             break;
00396         case LTG_PATROL:
00397             teamtask = TEAMTASK_PATROL;
00398             break;
00399         case LTG_GETITEM:
00400             teamtask = TEAMTASK_PATROL;
00401             break;
00402         case LTG_KILL:
00403             teamtask = TEAMTASK_PATROL;
00404             break;
00405         case LTG_HARVEST:
00406             teamtask = TEAMTASK_OFFENSE;
00407             break;
00408         case LTG_ATTACKENEMYBASE:
00409             teamtask = TEAMTASK_OFFENSE;
00410             break;
00411         default:
00412             teamtask = TEAMTASK_PATROL;
00413             break;
00414     }
00415     BotSetUserInfo(bs, "teamtask", va("%d", teamtask));
00416 #endif
00417 }
00418 
00419 /*
00420 ==================
00421 BotSetLastOrderedTask
00422 ==================
00423 */
00424 int BotSetLastOrderedTask(bot_state_t *bs) {
00425 
00426     if (gametype == GT_CTF) {
00427         // don't go back to returning the flag if it's at the base
00428         if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {
00429             if ( BotTeam(bs) == TEAM_RED ) {
00430                 if ( bs->redflagstatus == 0 ) {
00431                     bs->lastgoal_ltgtype = 0;
00432                 }
00433             }
00434             else {
00435                 if ( bs->blueflagstatus == 0 ) {
00436                     bs->lastgoal_ltgtype = 0;
00437                 }
00438             }
00439         }
00440     }
00441 
00442     if ( bs->lastgoal_ltgtype ) {
00443         bs->decisionmaker = bs->lastgoal_decisionmaker;
00444         bs->ordered = qtrue;
00445         bs->ltgtype = bs->lastgoal_ltgtype;
00446         memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));
00447         bs->teammate = bs->lastgoal_teammate;
00448         bs->teamgoal_time = FloatTime() + 300;
00449         BotSetTeamStatus(bs);
00450         //
00451         if ( gametype == GT_CTF ) {
00452             if ( bs->ltgtype == LTG_GETFLAG ) {
00453                 bot_goal_t *tb, *eb;
00454                 int tt, et;
00455 
00456                 tb = BotTeamFlag(bs);
00457                 eb = BotEnemyFlag(bs);
00458                 tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);
00459                 et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);
00460                 // if the travel time towards the enemy base is larger than towards our base
00461                 if (et > tt) {
00462                     //get an alternative route goal towards the enemy base
00463                     BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00464                 }
00465             }
00466         }
00467         return qtrue;
00468     }
00469     return qfalse;
00470 }
00471 
00472 /*
00473 ==================
00474 BotRefuseOrder
00475 ==================
00476 */
00477 void BotRefuseOrder(bot_state_t *bs) {
00478     if (!bs->ordered)
00479         return;
00480     // if the bot was ordered to do something
00481     if ( bs->order_time && bs->order_time > FloatTime() - 10 ) {
00482         trap_EA_Action(bs->client, ACTION_NEGATIVE);
00483         BotVoiceChat(bs, bs->decisionmaker, VOICECHAT_NO);
00484         bs->order_time = 0;
00485     }
00486 }
00487 
00488 /*
00489 ==================
00490 BotCTFSeekGoals
00491 ==================
00492 */
00493 void BotCTFSeekGoals(bot_state_t *bs) {
00494     float rnd, l1, l2;
00495     int flagstatus, c;
00496     vec3_t dir;
00497     aas_entityinfo_t entinfo;
00498 
00499     //when carrying a flag in ctf the bot should rush to the base
00500     if (BotCTFCarryingFlag(bs)) {
00501         //if not already rushing to the base
00502         if (bs->ltgtype != LTG_RUSHBASE) {
00503             BotRefuseOrder(bs);
00504             bs->ltgtype = LTG_RUSHBASE;
00505             bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
00506             bs->rushbaseaway_time = 0;
00507             bs->decisionmaker = bs->client;
00508             bs->ordered = qfalse;
00509             //
00510             switch(BotTeam(bs)) {
00511                 case TEAM_RED: VectorSubtract(bs->origin, ctf_blueflag.origin, dir); break;
00512                 case TEAM_BLUE: VectorSubtract(bs->origin, ctf_redflag.origin, dir); break;
00513                 default: VectorSet(dir, 999, 999, 999); break;
00514             }
00515             // if the bot picked up the flag very close to the enemy base
00516             if ( VectorLength(dir) < 128 ) {
00517                 // get an alternative route goal through the enemy base
00518                 BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00519             } else {
00520                 // don't use any alt route goal, just get the hell out of the base
00521                 bs->altroutegoal.areanum = 0;
00522             }
00523             BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_OFFENSE));
00524             BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
00525         }
00526         else if (bs->rushbaseaway_time > FloatTime()) {
00527             if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus;
00528             else flagstatus = bs->blueflagstatus;
00529             //if the flag is back
00530             if (flagstatus == 0) {
00531                 bs->rushbaseaway_time = 0;
00532             }
00533         }
00534         return;
00535     }
00536     // if the bot decided to follow someone
00537     if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
00538         // if the team mate being accompanied no longer carries the flag
00539         BotEntityInfo(bs->teammate, &entinfo);
00540         if (!EntityCarriesFlag(&entinfo)) {
00541             bs->ltgtype = 0;
00542         }
00543     }
00544     //
00545     if (BotTeam(bs) == TEAM_RED) flagstatus = bs->redflagstatus * 2 + bs->blueflagstatus;
00546     else flagstatus = bs->blueflagstatus * 2 + bs->redflagstatus;
00547     //if our team has the enemy flag and our flag is at the base
00548     if (flagstatus == 1) {
00549         //
00550         if (bs->owndecision_time < FloatTime()) {
00551             //if Not defending the base already
00552             if (!(bs->ltgtype == LTG_DEFENDKEYAREA &&
00553                     (bs->teamgoal.number == ctf_redflag.number ||
00554                     bs->teamgoal.number == ctf_blueflag.number))) {
00555                 //if there is a visible team mate flag carrier
00556                 c = BotTeamFlagCarrierVisible(bs);
00557                 if (c >= 0 &&
00558                         // and not already following the team mate flag carrier
00559                         (bs->ltgtype != LTG_TEAMACCOMPANY || bs->teammate != c)) {
00560                     //
00561                     BotRefuseOrder(bs);
00562                     //follow the flag carrier
00563                     bs->decisionmaker = bs->client;
00564                     bs->ordered = qfalse;
00565                     //the team mate
00566                     bs->teammate = c;
00567                     //last time the team mate was visible
00568                     bs->teammatevisible_time = FloatTime();
00569                     //no message
00570                     bs->teammessage_time = 0;
00571                     //no arrive message
00572                     bs->arrive_time = 1;
00573                     //
00574                     BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
00575                     //get the team goal time
00576                     bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
00577                     bs->ltgtype = LTG_TEAMACCOMPANY;
00578                     bs->formation_dist = 3.5 * 32;      //3.5 meter
00579                     BotSetTeamStatus(bs);
00580                     bs->owndecision_time = FloatTime() + 5;
00581                 }
00582             }
00583         }
00584         return;
00585     }
00586     //if the enemy has our flag
00587     else if (flagstatus == 2) {
00588         //
00589         if (bs->owndecision_time < FloatTime()) {
00590             //if enemy flag carrier is visible
00591             c = BotEnemyFlagCarrierVisible(bs);
00592             if (c >= 0) {
00593                 //FIXME: fight enemy flag carrier
00594             }
00595             //if not already doing something important
00596             if (bs->ltgtype != LTG_GETFLAG &&
00597                 bs->ltgtype != LTG_RETURNFLAG &&
00598                 bs->ltgtype != LTG_TEAMHELP &&
00599                 bs->ltgtype != LTG_TEAMACCOMPANY &&
00600                 bs->ltgtype != LTG_CAMPORDER &&
00601                 bs->ltgtype != LTG_PATROL &&
00602                 bs->ltgtype != LTG_GETITEM) {
00603 
00604                 BotRefuseOrder(bs);
00605                 bs->decisionmaker = bs->client;
00606                 bs->ordered = qfalse;
00607                 //
00608                 if (random() < 0.5) {
00609                     //go for the enemy flag
00610                     bs->ltgtype = LTG_GETFLAG;
00611                 }
00612                 else {
00613                     bs->ltgtype = LTG_RETURNFLAG;
00614                 }
00615                 //no team message
00616                 bs->teammessage_time = 0;
00617                 //set the time the bot will stop getting the flag
00618                 bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
00619                 //get an alternative route goal towards the enemy base
00620                 BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00621                 //
00622                 BotSetTeamStatus(bs);
00623                 bs->owndecision_time = FloatTime() + 5;
00624             }
00625         }
00626         return;
00627     }
00628     //if both flags Not at their bases
00629     else if (flagstatus == 3) {
00630         //
00631         if (bs->owndecision_time < FloatTime()) {
00632             // if not trying to return the flag and not following the team flag carrier
00633             if ( bs->ltgtype != LTG_RETURNFLAG && bs->ltgtype != LTG_TEAMACCOMPANY ) {
00634                 //
00635                 c = BotTeamFlagCarrierVisible(bs);
00636                 // if there is a visible team mate flag carrier
00637                 if (c >= 0) {
00638                     BotRefuseOrder(bs);
00639                     //follow the flag carrier
00640                     bs->decisionmaker = bs->client;
00641                     bs->ordered = qfalse;
00642                     //the team mate
00643                     bs->teammate = c;
00644                     //last time the team mate was visible
00645                     bs->teammatevisible_time = FloatTime();
00646                     //no message
00647                     bs->teammessage_time = 0;
00648                     //no arrive message
00649                     bs->arrive_time = 1;
00650                     //
00651                     BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
00652                     //get the team goal time
00653                     bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
00654                     bs->ltgtype = LTG_TEAMACCOMPANY;
00655                     bs->formation_dist = 3.5 * 32;      //3.5 meter
00656                     //
00657                     BotSetTeamStatus(bs);
00658                     bs->owndecision_time = FloatTime() + 5;
00659                 }
00660                 else {
00661                     BotRefuseOrder(bs);
00662                     bs->decisionmaker = bs->client;
00663                     bs->ordered = qfalse;
00664                     //get the enemy flag
00665                     bs->teammessage_time = FloatTime() + 2 * random();
00666                     //get the flag
00667                     bs->ltgtype = LTG_RETURNFLAG;
00668                     //set the time the bot will stop getting the flag
00669                     bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
00670                     //get an alternative route goal towards the enemy base
00671                     BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00672                     //
00673                     BotSetTeamStatus(bs);
00674                     bs->owndecision_time = FloatTime() + 5;
00675                 }
00676             }
00677         }
00678         return;
00679     }
00680     // don't just do something wait for the bot team leader to give orders
00681     if (BotTeamLeader(bs)) {
00682         return;
00683     }
00684     // if the bot is ordered to do something
00685     if ( bs->lastgoal_ltgtype ) {
00686         bs->teamgoal_time += 60;
00687     }
00688     // if the bot decided to do something on it's own and has a last ordered goal
00689     if ( !bs->ordered && bs->lastgoal_ltgtype ) {
00690         bs->ltgtype = 0;
00691     }
00692     //if already a CTF or team goal
00693     if (bs->ltgtype == LTG_TEAMHELP ||
00694             bs->ltgtype == LTG_TEAMACCOMPANY ||
00695             bs->ltgtype == LTG_DEFENDKEYAREA ||
00696             bs->ltgtype == LTG_GETFLAG ||
00697             bs->ltgtype == LTG_RUSHBASE ||
00698             bs->ltgtype == LTG_RETURNFLAG ||
00699             bs->ltgtype == LTG_CAMPORDER ||
00700             bs->ltgtype == LTG_PATROL ||
00701             bs->ltgtype == LTG_GETITEM ||
00702             bs->ltgtype == LTG_MAKELOVE_UNDER ||
00703             bs->ltgtype == LTG_MAKELOVE_ONTOP) {
00704         return;
00705     }
00706     //
00707     if (BotSetLastOrderedTask(bs))
00708         return;
00709     //
00710     if (bs->owndecision_time > FloatTime())
00711         return;;
00712     //if the bot is roaming
00713     if (bs->ctfroam_time > FloatTime())
00714         return;
00715     //if the bot has anough aggression to decide what to do
00716     if (BotAggression(bs) < 50)
00717         return;
00718     //set the time to send a message to the team mates
00719     bs->teammessage_time = FloatTime() + 2 * random();
00720     //
00721     if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
00722         if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
00723             l1 = 0.7f;
00724         }
00725         else {
00726             l1 = 0.2f;
00727         }
00728         l2 = 0.9f;
00729     }
00730     else {
00731         l1 = 0.4f;
00732         l2 = 0.7f;
00733     }
00734     //get the flag or defend the base
00735     rnd = random();
00736     if (rnd < l1 && ctf_redflag.areanum && ctf_blueflag.areanum) {
00737         bs->decisionmaker = bs->client;
00738         bs->ordered = qfalse;
00739         bs->ltgtype = LTG_GETFLAG;
00740         //set the time the bot will stop getting the flag
00741         bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
00742         //get an alternative route goal towards the enemy base
00743         BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00744         BotSetTeamStatus(bs);
00745     }
00746     else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
00747         bs->decisionmaker = bs->client;
00748         bs->ordered = qfalse;
00749         //
00750         if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
00751         else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
00752         //set the ltg type
00753         bs->ltgtype = LTG_DEFENDKEYAREA;
00754         //set the time the bot stops defending the base
00755         bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
00756         bs->defendaway_time = 0;
00757         BotSetTeamStatus(bs);
00758     }
00759     else {
00760         bs->ltgtype = 0;
00761         //set the time the bot will stop roaming
00762         bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
00763         BotSetTeamStatus(bs);
00764     }
00765     bs->owndecision_time = FloatTime() + 5;
00766 #ifdef DEBUG
00767     BotPrintTeamGoal(bs);
00768 #endif //DEBUG
00769 }
00770 
00771 /*
00772 ==================
00773 BotCTFRetreatGoals
00774 ==================
00775 */
00776 void BotCTFRetreatGoals(bot_state_t *bs) {
00777     //when carrying a flag in ctf the bot should rush to the base
00778     if (BotCTFCarryingFlag(bs)) {
00779         //if not already rushing to the base
00780         if (bs->ltgtype != LTG_RUSHBASE) {
00781             BotRefuseOrder(bs);
00782             bs->ltgtype = LTG_RUSHBASE;
00783             bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
00784             bs->rushbaseaway_time = 0;
00785             bs->decisionmaker = bs->client;
00786             bs->ordered = qfalse;
00787             BotSetTeamStatus(bs);
00788         }
00789     }
00790 }
00791 
00792 #ifdef MISSIONPACK
00793 /*
00794 ==================
00795 Bot1FCTFSeekGoals
00796 ==================
00797 */
00798 void Bot1FCTFSeekGoals(bot_state_t *bs) {
00799     aas_entityinfo_t entinfo;
00800     float rnd, l1, l2;
00801     int c;
00802 
00803     //when carrying a flag in ctf the bot should rush to the base
00804     if (Bot1FCTFCarryingFlag(bs)) {
00805         //if not already rushing to the base
00806         if (bs->ltgtype != LTG_RUSHBASE) {
00807             BotRefuseOrder(bs);
00808             bs->ltgtype = LTG_RUSHBASE;
00809             bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
00810             bs->rushbaseaway_time = 0;
00811             bs->decisionmaker = bs->client;
00812             bs->ordered = qfalse;
00813             //get an alternative route goal towards the enemy base
00814             BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
00815             //
00816             BotSetTeamStatus(bs);
00817             BotVoiceChat(bs, -1, VOICECHAT_IHAVEFLAG);
00818         }
00819         return;
00820     }
00821     // if the bot decided to follow someone
00822     if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
00823         // if the team mate being accompanied no longer carries the flag
00824         BotEntityInfo(bs->teammate, &entinfo);
00825         if (!EntityCarriesFlag(&entinfo)) {
00826             bs->ltgtype = 0;
00827         }
00828     }
00829     //our team has the flag
00830     if (bs->neutralflagstatus == 1) {
00831         if (bs->owndecision_time < FloatTime()) {
00832             // if not already following someone
00833             if (bs->ltgtype != LTG_TEAMACCOMPANY) {
00834                 //if there is a visible team mate flag carrier
00835                 c = BotTeamFlagCarrierVisible(bs);
00836                 if (c >= 0) {
00837                     BotRefuseOrder(bs);
00838                     //follow the flag carrier
00839                     bs->decisionmaker = bs->client;
00840                     bs->ordered = qfalse;
00841                     //the team mate
00842                     bs->teammate = c;
00843                     //last time the team mate was visible
00844                     bs->teammatevisible_time = FloatTime();
00845                     //no message
00846                     bs->teammessage_time = 0;
00847                     //no arrive message
00848                     bs->arrive_time = 1;
00849                     //
00850                     BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
00851                     //get the team goal time
00852                     bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
00853                     bs->ltgtype = LTG_TEAMACCOMPANY;
00854                     bs->formation_dist = 3.5 * 32;      //3.5 meter
00855                     BotSetTeamStatus(bs);
00856                     bs->owndecision_time = FloatTime() + 5;
00857                     return;
00858                 }
00859             }
00860             //if already a CTF or team goal
00861             if (bs->ltgtype == LTG_TEAMHELP ||
00862                     bs->ltgtype == LTG_TEAMACCOMPANY ||
00863                     bs->ltgtype == LTG_DEFENDKEYAREA ||
00864                     bs->ltgtype == LTG_GETFLAG ||
00865                     bs->ltgtype == LTG_RUSHBASE ||
00866                     bs->ltgtype == LTG_CAMPORDER ||
00867                     bs->ltgtype == LTG_PATROL ||
00868                     bs->ltgtype == LTG_ATTACKENEMYBASE ||
00869                     bs->ltgtype == LTG_GETITEM ||
00870                     bs->ltgtype == LTG_MAKELOVE_UNDER ||
00871                     bs->ltgtype == LTG_MAKELOVE_ONTOP) {
00872                 return;
00873             }
00874             //if not already attacking the enemy base
00875             if (bs->ltgtype != LTG_ATTACKENEMYBASE) {
00876                 BotRefuseOrder(bs);
00877                 bs->decisionmaker = bs->client;
00878                 bs->ordered = qfalse;
00879                 //
00880                 if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
00881                 else memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
00882                 //set the ltg type
00883                 bs->ltgtype = LTG_ATTACKENEMYBASE;
00884                 //set the time the bot will stop getting the flag
00885                 bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
00886                 BotSetTeamStatus(bs);
00887                 bs->owndecision_time = FloatTime() + 5;
00888             }
00889         }
00890         return;
00891     }
00892     //enemy team has the flag
00893     else if (bs->neutralflagstatus == 2) {
00894         if (bs->owndecision_time < FloatTime()) {
00895             c = BotEnemyFlagCarrierVisible(bs);
00896             if (c >= 0) {
00897                 //FIXME: attack enemy flag carrier
00898             }
00899             //if already a CTF or team goal
00900             if (bs->ltgtype == LTG_TEAMHELP ||
00901                     bs->ltgtype == LTG_TEAMACCOMPANY ||
00902                     bs->ltgtype == LTG_CAMPORDER ||
00903                     bs->ltgtype == LTG_PATROL ||
00904                     bs->ltgtype == LTG_GETITEM) {
00905                 return;
00906             }
00907             // if not already defending the base
00908             if (bs->ltgtype != LTG_DEFENDKEYAREA) {
00909                 BotRefuseOrder(bs);
00910                 bs->decisionmaker = bs->client;
00911                 bs->ordered = qfalse;
00912                 //
00913                 if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
00914                 else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
00915                 //set the ltg type
00916                 bs->ltgtype = LTG_DEFENDKEYAREA;
00917                 //set the time the bot stops defending the base
00918                 bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
00919                 bs->defendaway_time = 0;
00920                 BotSetTeamStatus(bs);
00921                 bs->owndecision_time = FloatTime() + 5;
00922             }
00923         }
00924         return;
00925     }
00926     // don't just do something wait for the bot team leader to give orders
00927     if (BotTeamLeader(bs)) {
00928         return;
00929     }
00930     // if the bot is ordered to do something
00931     if ( bs->lastgoal_ltgtype ) {
00932         bs->teamgoal_time += 60;
00933     }
00934     // if the bot decided to do something on it's own and has a last ordered goal
00935     if ( !bs->ordered && bs->lastgoal_ltgtype ) {
00936         bs->ltgtype = 0;
00937     }
00938     //if already a CTF or team goal
00939     if (bs->ltgtype == LTG_TEAMHELP ||
00940             bs->ltgtype == LTG_TEAMACCOMPANY ||
00941             bs->ltgtype == LTG_DEFENDKEYAREA ||
00942             bs->ltgtype == LTG_GETFLAG ||
00943             bs->ltgtype == LTG_RUSHBASE ||
00944             bs->ltgtype == LTG_RETURNFLAG ||
00945             bs->ltgtype == LTG_CAMPORDER ||
00946             bs->ltgtype == LTG_PATROL ||
00947             bs->ltgtype == LTG_ATTACKENEMYBASE ||
00948             bs->ltgtype == LTG_GETITEM ||
00949             bs->ltgtype == LTG_MAKELOVE_UNDER ||
00950             bs->ltgtype == LTG_MAKELOVE_ONTOP) {
00951         return;
00952     }
00953     //
00954     if (BotSetLastOrderedTask(bs))
00955         return;
00956     //
00957     if (bs->owndecision_time > FloatTime())
00958         return;;
00959     //if the bot is roaming
00960     if (bs->ctfroam_time > FloatTime())
00961         return;
00962     //if the bot has anough aggression to decide what to do
00963     if (BotAggression(bs) < 50)
00964         return;
00965     //set the time to send a message to the team mates
00966     bs->teammessage_time = FloatTime() + 2 * random();
00967     //
00968     if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
00969         if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
00970             l1 = 0.7f;
00971         }
00972         else {
00973             l1 = 0.2f;
00974         }
00975         l2 = 0.9f;
00976     }
00977     else {
00978         l1 = 0.4f;
00979         l2 = 0.7f;
00980     }
00981     //get the flag or defend the base
00982     rnd = random();
00983     if (rnd < l1 && ctf_neutralflag.areanum) {
00984         bs->decisionmaker = bs->client;
00985         bs->ordered = qfalse;
00986         bs->ltgtype = LTG_GETFLAG;
00987         //set the time the bot will stop getting the flag
00988         bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
00989         BotSetTeamStatus(bs);
00990     }
00991     else if (rnd < l2 && ctf_redflag.areanum && ctf_blueflag.areanum) {
00992         bs->decisionmaker = bs->client;
00993         bs->ordered = qfalse;
00994         //
00995         if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t));
00996         else memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t));
00997         //set the ltg type
00998         bs->ltgtype = LTG_DEFENDKEYAREA;
00999         //set the time the bot stops defending the base
01000         bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
01001         bs->defendaway_time = 0;
01002         BotSetTeamStatus(bs);
01003     }
01004     else {
01005         bs->ltgtype = 0;
01006         //set the time the bot will stop roaming
01007         bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
01008         BotSetTeamStatus(bs);
01009     }
01010     bs->owndecision_time = FloatTime() + 5;
01011 #ifdef DEBUG
01012     BotPrintTeamGoal(bs);
01013 #endif //DEBUG
01014 }
01015 
01016 /*
01017 ==================
01018 Bot1FCTFRetreatGoals
01019 ==================
01020 */
01021 void Bot1FCTFRetreatGoals(bot_state_t *bs) {
01022     //when carrying a flag in ctf the bot should rush to the enemy base
01023     if (Bot1FCTFCarryingFlag(bs)) {
01024         //if not already rushing to the base
01025         if (bs->ltgtype != LTG_RUSHBASE) {
01026             BotRefuseOrder(bs);
01027             bs->ltgtype = LTG_RUSHBASE;
01028             bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
01029             bs->rushbaseaway_time = 0;
01030             bs->decisionmaker = bs->client;
01031             bs->ordered = qfalse;
01032             //get an alternative route goal towards the enemy base
01033             BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
01034             BotSetTeamStatus(bs);
01035         }
01036     }
01037 }
01038 
01039 /*
01040 ==================
01041 BotObeliskSeekGoals
01042 ==================
01043 */
01044 void BotObeliskSeekGoals(bot_state_t *bs) {
01045     float rnd, l1, l2;
01046 
01047     // don't just do something wait for the bot team leader to give orders
01048     if (BotTeamLeader(bs)) {
01049         return;
01050     }
01051     // if the bot is ordered to do something
01052     if ( bs->lastgoal_ltgtype ) {
01053         bs->teamgoal_time += 60;
01054     }
01055     //if already a team goal
01056     if (bs->ltgtype == LTG_TEAMHELP ||
01057             bs->ltgtype == LTG_TEAMACCOMPANY ||
01058             bs->ltgtype == LTG_DEFENDKEYAREA ||
01059             bs->ltgtype == LTG_GETFLAG ||
01060             bs->ltgtype == LTG_RUSHBASE ||
01061             bs->ltgtype == LTG_RETURNFLAG ||
01062             bs->ltgtype == LTG_CAMPORDER ||
01063             bs->ltgtype == LTG_PATROL ||
01064             bs->ltgtype == LTG_ATTACKENEMYBASE ||
01065             bs->ltgtype == LTG_GETITEM ||
01066             bs->ltgtype == LTG_MAKELOVE_UNDER ||
01067             bs->ltgtype == LTG_MAKELOVE_ONTOP) {
01068         return;
01069     }
01070     //
01071     if (BotSetLastOrderedTask(bs))
01072         return;
01073     //if the bot is roaming
01074     if (bs->ctfroam_time > FloatTime())
01075         return;
01076     //if the bot has anough aggression to decide what to do
01077     if (BotAggression(bs) < 50)
01078         return;
01079     //set the time to send a message to the team mates
01080     bs->teammessage_time = FloatTime() + 2 * random();
01081     //
01082     if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
01083         if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
01084             l1 = 0.7f;
01085         }
01086         else {
01087             l1 = 0.2f;
01088         }
01089         l2 = 0.9f;
01090     }
01091     else {
01092         l1 = 0.4f;
01093         l2 = 0.7f;
01094     }
01095     //get the flag or defend the base
01096     rnd = random();
01097     if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
01098         bs->decisionmaker = bs->client;
01099         bs->ordered = qfalse;
01100         //
01101         if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
01102         else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
01103         //set the ltg type
01104         bs->ltgtype = LTG_ATTACKENEMYBASE;
01105         //set the time the bot will stop attacking the enemy base
01106         bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
01107         //get an alternate route goal towards the enemy base
01108         BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
01109         BotSetTeamStatus(bs);
01110     }
01111     else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
01112         bs->decisionmaker = bs->client;
01113         bs->ordered = qfalse;
01114         //
01115         if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
01116         else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
01117         //set the ltg type
01118         bs->ltgtype = LTG_DEFENDKEYAREA;
01119         //set the time the bot stops defending the base
01120         bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
01121         bs->defendaway_time = 0;
01122         BotSetTeamStatus(bs);
01123     }
01124     else {
01125         bs->ltgtype = 0;
01126         //set the time the bot will stop roaming
01127         bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME;
01128         BotSetTeamStatus(bs);
01129     }
01130 }
01131 
01132 /*
01133 ==================
01134 BotGoHarvest
01135 ==================
01136 */
01137 void BotGoHarvest(bot_state_t *bs) {
01138     //
01139     if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t));
01140     else memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
01141     //set the ltg type
01142     bs->ltgtype = LTG_HARVEST;
01143     //set the time the bot will stop harvesting
01144     bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
01145     bs->harvestaway_time = 0;
01146     BotSetTeamStatus(bs);
01147 }
01148 
01149 /*
01150 ==================
01151 BotObeliskRetreatGoals
01152 ==================
01153 */
01154 void BotObeliskRetreatGoals(bot_state_t *bs) {
01155     //nothing special
01156 }
01157 
01158 /*
01159 ==================
01160 BotHarvesterSeekGoals
01161 ==================
01162 */
01163 void BotHarvesterSeekGoals(bot_state_t *bs) {
01164     aas_entityinfo_t entinfo;
01165     float rnd, l1, l2;
01166     int c;
01167 
01168     //when carrying cubes in harvester the bot should rush to the base
01169     if (BotHarvesterCarryingCubes(bs)) {
01170         //if not already rushing to the base
01171         if (bs->ltgtype != LTG_RUSHBASE) {
01172             BotRefuseOrder(bs);
01173             bs->ltgtype = LTG_RUSHBASE;
01174             bs->teamgoal_time = FloatTime() + CTF_RUSHBASE_TIME;
01175             bs->rushbaseaway_time = 0;
01176             bs->decisionmaker = bs->client;
01177             bs->ordered = qfalse;
01178             //get an alternative route goal towards the enemy base
01179             BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
01180             //
01181             BotSetTeamStatus(bs);
01182         }
01183         return;
01184     }
01185     // don't just do something wait for the bot team leader to give orders
01186     if (BotTeamLeader(bs)) {
01187         return;
01188     }
01189     // if the bot decided to follow someone
01190     if ( bs->ltgtype == LTG_TEAMACCOMPANY && !bs->ordered ) {
01191         // if the team mate being accompanied no longer carries the flag
01192         BotEntityInfo(bs->teammate, &entinfo);
01193         if (!EntityCarriesCubes(&entinfo)) {
01194             bs->ltgtype = 0;
01195         }
01196     }
01197     // if the bot is ordered to do something
01198     if ( bs->lastgoal_ltgtype ) {
01199         bs->teamgoal_time += 60;
01200     }
01201     //if not yet doing something
01202     if (bs->ltgtype == LTG_TEAMHELP ||
01203             bs->ltgtype == LTG_TEAMACCOMPANY ||
01204             bs->ltgtype == LTG_DEFENDKEYAREA ||
01205             bs->ltgtype == LTG_GETFLAG ||
01206             bs->ltgtype == LTG_CAMPORDER ||
01207             bs->ltgtype == LTG_PATROL ||
01208             bs->ltgtype == LTG_ATTACKENEMYBASE ||
01209             bs->ltgtype == LTG_HARVEST ||
01210             bs->ltgtype == LTG_GETITEM ||
01211             bs->ltgtype == LTG_MAKELOVE_UNDER ||
01212             bs->ltgtype == LTG_MAKELOVE_ONTOP) {
01213         return;
01214     }
01215     //
01216     if (BotSetLastOrderedTask(bs))
01217         return;
01218     //if the bot is roaming
01219     if (bs->ctfroam_time > FloatTime())
01220         return;
01221     //if the bot has anough aggression to decide what to do
01222     if (BotAggression(bs) < 50)
01223         return;
01224     //set the time to send a message to the team mates
01225     bs->teammessage_time = FloatTime() + 2 * random();
01226     //
01227     c = BotEnemyCubeCarrierVisible(bs);
01228     if (c >= 0) {
01229         //FIXME: attack enemy cube carrier
01230     }
01231     if (bs->ltgtype != LTG_TEAMACCOMPANY) {
01232         //if there is a visible team mate carrying cubes
01233         c = BotTeamCubeCarrierVisible(bs);
01234         if (c >= 0) {
01235             //follow the team mate carrying cubes
01236             bs->decisionmaker = bs->client;
01237             bs->ordered = qfalse;
01238             //the team mate
01239             bs->teammate = c;
01240             //last time the team mate was visible
01241             bs->teammatevisible_time = FloatTime();
01242             //no message
01243             bs->teammessage_time = 0;
01244             //no arrive message
01245             bs->arrive_time = 1;
01246             //
01247             BotVoiceChat(bs, bs->teammate, VOICECHAT_ONFOLLOW);
01248             //get the team goal time
01249             bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
01250             bs->ltgtype = LTG_TEAMACCOMPANY;
01251             bs->formation_dist = 3.5 * 32;      //3.5 meter
01252             BotSetTeamStatus(bs);
01253             return;
01254         }
01255     }
01256     //
01257     if (bs->teamtaskpreference & (TEAMTP_ATTACKER|TEAMTP_DEFENDER)) {
01258         if (bs->teamtaskpreference & TEAMTP_ATTACKER) {
01259             l1 = 0.7f;
01260         }
01261         else {
01262             l1 = 0.2f;
01263         }
01264         l2 = 0.9f;
01265     }
01266     else {
01267         l1 = 0.4f;
01268         l2 = 0.7f;
01269     }
01270     //
01271     rnd = random();
01272     if (rnd < l1 && redobelisk.areanum && blueobelisk.areanum) {
01273         bs->decisionmaker = bs->client;
01274         bs->ordered = qfalse;
01275         BotGoHarvest(bs);
01276     }
01277     else if (rnd < l2 && redobelisk.areanum && blueobelisk.areanum) {
01278         bs->decisionmaker = bs->client;
01279         bs->ordered = qfalse;
01280         //
01281         if (BotTeam(bs) == TEAM_RED) memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t));
01282         else memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot