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

sv_bot.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 // sv_bot.c
00023 
00024 #include "server.h"
00025 #include "../game/botlib.h"
00026 
00027 typedef struct bot_debugpoly_s
00028 {
00029     int inuse;
00030     int color;
00031     int numPoints;
00032     vec3_t points[128];
00033 } bot_debugpoly_t;
00034 
00035 static bot_debugpoly_t *debugpolygons;
00036 int bot_maxdebugpolys;
00037 
00038 extern botlib_export_t  *botlib_export;
00039 int bot_enable;
00040 
00041 
00042 /*
00043 ==================
00044 SV_BotAllocateClient
00045 ==================
00046 */
00047 int SV_BotAllocateClient(void) {
00048     int         i;
00049     client_t    *cl;
00050 
00051     // find a client slot
00052     for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) {
00053         if ( cl->state == CS_FREE ) {
00054             break;
00055         }
00056     }
00057 
00058     if ( i == sv_maxclients->integer ) {
00059         return -1;
00060     }
00061 
00062     cl->gentity = SV_GentityNum( i );
00063     cl->gentity->s.number = i;
00064     cl->state = CS_ACTIVE;
00065     cl->lastPacketTime = svs.time;
00066     cl->netchan.remoteAddress.type = NA_BOT;
00067     cl->rate = 16384;
00068 
00069     return i;
00070 }
00071 
00072 /*
00073 ==================
00074 SV_BotFreeClient
00075 ==================
00076 */
00077 void SV_BotFreeClient( int clientNum ) {
00078     client_t    *cl;
00079 
00080     if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) {
00081         Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum );
00082     }
00083     cl = &svs.clients[clientNum];
00084     cl->state = CS_FREE;
00085     cl->name[0] = 0;
00086     if ( cl->gentity ) {
00087         cl->gentity->r.svFlags &= ~SVF_BOT;
00088     }
00089 }
00090 
00091 /*
00092 ==================
00093 BotDrawDebugPolygons
00094 ==================
00095 */
00096 void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) {
00097     static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea;
00098     bot_debugpoly_t *poly;
00099     int i, parm0;
00100 
00101     if (!debugpolygons)
00102         return;
00103     //bot debugging
00104     if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0);
00105     //
00106     if (bot_enable && bot_debug->integer) {
00107         //show reachabilities
00108         if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0);
00109         //show ground faces only
00110         if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0);
00111         //get the hightlight area
00112         if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0);
00113         //
00114         parm0 = 0;
00115         if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1;
00116         if (bot_reachability->integer) parm0 |= 2;
00117         if (bot_groundonly->integer) parm0 |= 4;
00118         botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string);
00119         botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, 
00120             svs.clients[0].gentity->r.currentAngles);
00121     } //end if
00122     //draw all debug polys
00123     for (i = 0; i < bot_maxdebugpolys; i++) {
00124         poly = &debugpolygons[i];
00125         if (!poly->inuse) continue;
00126         drawPoly(poly->color, poly->numPoints, (float *) poly->points);
00127         //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints);
00128     }
00129 }
00130 
00131 /*
00132 ==================
00133 BotImport_Print
00134 ==================
00135 */
00136 void QDECL BotImport_Print(int type, char *fmt, ...)
00137 {
00138     char str[2048];
00139     va_list ap;
00140 
00141     va_start(ap, fmt);
00142     vsprintf(str, fmt, ap);
00143     va_end(ap);
00144 
00145     switch(type) {
00146         case PRT_MESSAGE: {
00147             Com_Printf("%s", str);
00148             break;
00149         }
00150         case PRT_WARNING: {
00151             Com_Printf(S_COLOR_YELLOW "Warning: %s", str);
00152             break;
00153         }
00154         case PRT_ERROR: {
00155             Com_Printf(S_COLOR_RED "Error: %s", str);
00156             break;
00157         }
00158         case PRT_FATAL: {
00159             Com_Printf(S_COLOR_RED "Fatal: %s", str);
00160             break;
00161         }
00162         case PRT_EXIT: {
00163             Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str);
00164             break;
00165         }
00166         default: {
00167             Com_Printf("unknown print type\n");
00168             break;
00169         }
00170     }
00171 }
00172 
00173 /*
00174 ==================
00175 BotImport_Trace
00176 ==================
00177 */
00178 void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) {
00179     trace_t trace;
00180 
00181     SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse);
00182     //copy the trace information
00183     bsptrace->allsolid = trace.allsolid;
00184     bsptrace->startsolid = trace.startsolid;
00185     bsptrace->fraction = trace.fraction;
00186     VectorCopy(trace.endpos, bsptrace->endpos);
00187     bsptrace->plane.dist = trace.plane.dist;
00188     VectorCopy(trace.plane.normal, bsptrace->plane.normal);
00189     bsptrace->plane.signbits = trace.plane.signbits;
00190     bsptrace->plane.type = trace.plane.type;
00191     bsptrace->surface.value = trace.surfaceFlags;
00192     bsptrace->ent = trace.entityNum;
00193     bsptrace->exp_dist = 0;
00194     bsptrace->sidenum = 0;
00195     bsptrace->contents = 0;
00196 }
00197 
00198 /*
00199 ==================
00200 BotImport_EntityTrace
00201 ==================
00202 */
00203 void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) {
00204     trace_t trace;
00205 
00206     SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse);
00207     //copy the trace information
00208     bsptrace->allsolid = trace.allsolid;
00209     bsptrace->startsolid = trace.startsolid;
00210     bsptrace->fraction = trace.fraction;
00211     VectorCopy(trace.endpos, bsptrace->endpos);
00212     bsptrace->plane.dist = trace.plane.dist;
00213     VectorCopy(trace.plane.normal, bsptrace->plane.normal);
00214     bsptrace->plane.signbits = trace.plane.signbits;
00215     bsptrace->plane.type = trace.plane.type;
00216     bsptrace->surface.value = trace.surfaceFlags;
00217     bsptrace->ent = trace.entityNum;
00218     bsptrace->exp_dist = 0;
00219     bsptrace->sidenum = 0;
00220     bsptrace->contents = 0;
00221 }
00222 
00223 
00224 /*
00225 ==================
00226 BotImport_PointContents
00227 ==================
00228 */
00229 int BotImport_PointContents(vec3_t point) {
00230     return SV_PointContents(point, -1);
00231 }
00232 
00233 /*
00234 ==================
00235 BotImport_inPVS
00236 ==================
00237 */
00238 int BotImport_inPVS(vec3_t p1, vec3_t p2) {
00239     return SV_inPVS (p1, p2);
00240 }
00241 
00242 /*
00243 ==================
00244 BotImport_BSPEntityData
00245 ==================
00246 */
00247 char *BotImport_BSPEntityData(void) {
00248     return CM_EntityString();
00249 }
00250 
00251 /*
00252 ==================
00253 BotImport_BSPModelMinsMaxsOrigin
00254 ==================
00255 */
00256 void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) {
00257     clipHandle_t h;
00258     vec3_t mins, maxs;
00259     float max;
00260     int i;
00261 
00262     h = CM_InlineModel(modelnum);
00263     CM_ModelBounds(h, mins, maxs);
00264     //if the model is rotated
00265     if ((angles[0] || angles[1] || angles[2])) {
00266         // expand for rotation
00267 
00268         max = RadiusFromBounds(mins, maxs);
00269         for (i = 0; i < 3; i++) {
00270             mins[i] = -max;
00271             maxs[i] = max;
00272         }
00273     }
00274     if (outmins) VectorCopy(mins, outmins);
00275     if (outmaxs) VectorCopy(maxs, outmaxs);
00276     if (origin) VectorClear(origin);
00277 }
00278 
00279 /*
00280 ==================
00281 BotImport_GetMemory
00282 ==================
00283 */
00284 void *BotImport_GetMemory(int size) {
00285     void *ptr;
00286 
00287     ptr = Z_TagMalloc( size, TAG_BOTLIB );
00288     return ptr;
00289 }
00290 
00291 /*
00292 ==================
00293 BotImport_FreeMemory
00294 ==================
00295 */
00296 void BotImport_FreeMemory(void *ptr) {
00297     Z_Free(ptr);
00298 }
00299 
00300 /*
00301 =================
00302 BotImport_HunkAlloc
00303 =================
00304 */
00305 void *BotImport_HunkAlloc( int size ) {
00306     if( Hunk_CheckMark() ) {
00307         Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" );
00308     }
00309     return Hunk_Alloc( size, h_high );
00310 }
00311 
00312 /*
00313 ==================
00314 BotImport_DebugPolygonCreate
00315 ==================
00316 */
00317 int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
00318     bot_debugpoly_t *poly;
00319     int i;
00320 
00321     if (!debugpolygons)
00322         return 0;
00323 
00324     for (i = 1; i < bot_maxdebugpolys; i++)     {
00325         if (!debugpolygons[i].inuse)
00326             break;
00327     }
00328     if (i >= bot_maxdebugpolys)
00329         return 0;
00330     poly = &debugpolygons[i];
00331     poly->inuse = qtrue;
00332     poly->color = color;
00333     poly->numPoints = numPoints;
00334     Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));
00335     //
00336     return i;
00337 }
00338 
00339 /*
00340 ==================
00341 BotImport_DebugPolygonShow
00342 ==================
00343 */
00344 void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) {
00345     bot_debugpoly_t *poly;
00346 
00347     if (!debugpolygons) return;
00348     poly = &debugpolygons[id];
00349     poly->inuse = qtrue;
00350     poly->color = color;
00351     poly->numPoints = numPoints;
00352     Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t));
00353 }
00354 
00355 /*
00356 ==================
00357 BotImport_DebugPolygonDelete
00358 ==================
00359 */
00360 void BotImport_DebugPolygonDelete(int id)
00361 {
00362     if (!debugpolygons) return;
00363     debugpolygons[id].inuse = qfalse;
00364 }
00365 
00366 /*
00367 ==================
00368 BotImport_DebugLineCreate
00369 ==================
00370 */
00371 int BotImport_DebugLineCreate(void) {
00372     vec3_t points[1];
00373     return BotImport_DebugPolygonCreate(0, 0, points);
00374 }
00375 
00376 /*
00377 ==================
00378 BotImport_DebugLineDelete
00379 ==================
00380 */
00381 void BotImport_DebugLineDelete(int line) {
00382     BotImport_DebugPolygonDelete(line);
00383 }
00384 
00385 /*
00386 ==================
00387 BotImport_DebugLineShow
00388 ==================
00389 */
00390 void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) {
00391     vec3_t points[4], dir, cross, up = {0, 0, 1};
00392     float dot;
00393 
00394     VectorCopy(start, points[0]);
00395     VectorCopy(start, points[1]);
00396     //points[1][2] -= 2;
00397     VectorCopy(end, points[2]);
00398     //points[2][2] -= 2;
00399     VectorCopy(end, points[3]);
00400 
00401 
00402     VectorSubtract(end, start, dir);
00403     VectorNormalize(dir);
00404     dot = DotProduct(dir, up);
00405     if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);
00406     else CrossProduct(dir, up, cross);
00407 
00408     VectorNormalize(cross);
00409 
00410     VectorMA(points[0], 2, cross, points[0]);
00411     VectorMA(points[1], -2, cross, points[1]);
00412     VectorMA(points[2], -2, cross, points[2]);
00413     VectorMA(points[3], 2, cross, points[3]);
00414 
00415     BotImport_DebugPolygonShow(line, color, 4, points);
00416 }
00417 
00418 /*
00419 ==================
00420 SV_BotClientCommand
00421 ==================
00422 */
00423 void BotClientCommand( int client, char *command ) {
00424     SV_ExecuteClientCommand( &svs.clients[client], command, qtrue );
00425 }
00426 
00427 /*
00428 ==================
00429 SV_BotFrame
00430 ==================
00431 */
00432 void SV_BotFrame( int time ) {
00433     if (!bot_enable) return;
00434     //NOTE: maybe the game is already shutdown
00435     if (!gvm) return;
00436     VM_Call( gvm, BOTAI_START_FRAME, time );
00437 }
00438 
00439 /*
00440 ===============
00441 SV_BotLibSetup
00442 ===============
00443 */
00444 int SV_BotLibSetup( void ) {
00445     if (!bot_enable) {
00446         return 0;
00447     }
00448 
00449     if ( !botlib_export ) {
00450         Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" );
00451         return -1;
00452     }
00453 
00454     return botlib_export->BotLibSetup();
00455 }
00456 
00457 /*
00458 ===============
00459 SV_ShutdownBotLib
00460 
00461 Called when either the entire server is being killed, or
00462 it is changing to a different game directory.
00463 ===============
00464 */
00465 int SV_BotLibShutdown( void ) {
00466 
00467     if ( !botlib_export ) {
00468         return -1;
00469     }
00470 
00471     return botlib_export->BotLibShutdown();
00472 }
00473 
00474 /*
00475 ==================
00476 SV_BotInitCvars
00477 ==================
00478 */
00479 void SV_BotInitCvars(void) {
00480 
00481     Cvar_Get("bot_enable", "1", 0);                     //enable the bot
00482     Cvar_Get("bot_developer", "0", CVAR_CHEAT);         //bot developer mode
00483     Cvar_Get("bot_debug", "0", CVAR_CHEAT);             //enable bot debugging
00484     Cvar_Get("bot_maxdebugpolys", "2", 0);              //maximum number of debug polys
00485     Cvar_Get("bot_groundonly", "1", 0);                 //only show ground faces of areas
00486     Cvar_Get("bot_reachability", "0", 0);               //show all reachabilities to other areas
00487     Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads
00488     Cvar_Get("bot_forceclustering", "0", 0);            //force cluster calculations
00489     Cvar_Get("bot_forcereachability", "0", 0);          //force reachability calculations
00490     Cvar_Get("bot_forcewrite", "0", 0);                 //force writing aas file
00491     Cvar_Get("bot_aasoptimize", "0", 0);                //no aas file optimisation
00492     Cvar_Get("bot_saveroutingcache", "0", 0);           //save routing cache
00493     Cvar_Get("bot_thinktime", "100", CVAR_CHEAT);       //msec the bots thinks
00494     Cvar_Get("bot_reloadcharacters", "0", 0);           //reload the bot characters each time
00495     Cvar_Get("bot_testichat", "0", 0);                  //test ichats
00496     Cvar_Get("bot_testrchat", "0", 0);                  //test rchats
00497     Cvar_Get("bot_testsolid", "0", CVAR_CHEAT);         //test for solid areas
00498     Cvar_Get("bot_testclusters", "0", CVAR_CHEAT);      //test the AAS clusters
00499     Cvar_Get("bot_fastchat", "0", 0);                   //fast chatting bots
00500     Cvar_Get("bot_nochat", "0", 0);                     //disable chats
00501     Cvar_Get("bot_pause", "0", CVAR_CHEAT);             //pause the bots thinking
00502     Cvar_Get("bot_report", "0", CVAR_CHEAT);            //get a full report in ctf
00503     Cvar_Get("bot_grapple", "0", 0);                    //enable grapple
00504     Cvar_Get("bot_rocketjump", "1", 0);                 //enable rocket jumping
00505     Cvar_Get("bot_challenge", "0", 0);                  //challenging bot
00506     Cvar_Get("bot_minplayers", "0", 0);                 //minimum players in a team or the game
00507     Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT);     //bot character used for interbreeding
00508     Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT);   //number of bots used for interbreeding
00509     Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT);  //bot interbreeding cycle
00510     Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT);    //write interbreeded bots to this file
00511 }
00512 
00513 /*
00514 ==================
00515 SV_BotInitBotLib
00516 ==================
00517 */
00518 void SV_BotInitBotLib(void) {
00519     botlib_import_t botlib_import;
00520 
00521     if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) {
00522         Com_Error( ERR_NEED_CD, "Game CD not in drive" );
00523     }
00524 
00525     if (debugpolygons) Z_Free(debugpolygons);
00526     bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys");
00527     debugpolygons = Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys);
00528 
00529     botlib_import.Print = BotImport_Print;
00530     botlib_import.Trace = BotImport_Trace;
00531     botlib_import.EntityTrace = BotImport_EntityTrace;
00532     botlib_import.PointContents = BotImport_PointContents;
00533     botlib_import.inPVS = BotImport_inPVS;
00534     botlib_import.BSPEntityData = BotImport_BSPEntityData;
00535     botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;
00536     botlib_import.BotClientCommand = BotClientCommand;
00537 
00538     //memory management
00539     botlib_import.GetMemory = BotImport_GetMemory;
00540     botlib_import.FreeMemory = BotImport_FreeMemory;
00541     botlib_import.AvailableMemory = Z_AvailableMemory;
00542     botlib_import.HunkAlloc = BotImport_HunkAlloc;
00543 
00544     // file system access
00545     botlib_import.FS_FOpenFile = FS_FOpenFileByMode;
00546     botlib_import.FS_Read = FS_Read2;
00547     botlib_import.FS_Write = FS_Write;
00548     botlib_import.FS_FCloseFile = FS_FCloseFile;
00549     botlib_import.FS_Seek = FS_Seek;
00550 
00551     //debug lines
00552     botlib_import.DebugLineCreate = BotImport_DebugLineCreate;
00553     botlib_import.DebugLineDelete = BotImport_DebugLineDelete;
00554     botlib_import.DebugLineShow = BotImport_DebugLineShow;
00555 
00556     //debug polygons
00557     botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate;
00558     botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete;
00559 
00560     botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import );
00561     assert(botlib_export);  // bk001129 - somehow we end up with a zero import.
00562 }
00563 
00564 
00565 //
00566 //  * * * BOT AI CODE IS BELOW THIS POINT * * *
00567 //
00568 
00569 /*
00570 ==================
00571 SV_BotGetConsoleMessage
00572 ==================
00573 */
00574 int SV_BotGetConsoleMessage( int client, char *buf, int size )
00575 {
00576     client_t    *cl;
00577     int         index;
00578 
00579     cl = &svs.clients[client];
00580     cl->lastPacketTime = svs.time;
00581 
00582     if ( cl->reliableAcknowledge == cl->reliableSequence ) {
00583         return qfalse;
00584     }
00585 
00586     cl->reliableAcknowledge++;
00587     index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 );
00588 
00589     if ( !cl->reliableCommands[index][0] ) {
00590         return qfalse;
00591     }
00592 
00593     Q_strncpyz( buf, cl->reliableCommands[index], size );
00594     return qtrue;
00595 }
00596 
00597 #if 0
00598 /*
00599 ==================
00600 EntityInPVS
00601 ==================
00602 */
00603 int EntityInPVS( int client, int entityNum ) {
00604     client_t            *cl;
00605     clientSnapshot_t    *frame;
00606     int                 i;
00607 
00608     cl = &svs.clients[client];
00609     frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];
00610     for ( i = 0; i < frame->num_entities; i++ ) {
00611         if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) {
00612             return qtrue;
00613         }
00614     }
00615     return qfalse;
00616 }
00617 #endif
00618 
00619 /*
00620 ==================
00621 SV_BotGetSnapshotEntity
00622 ==================
00623 */
00624 int SV_BotGetSnapshotEntity( int client, int sequence ) {
00625     client_t            *cl;
00626     clientSnapshot_t    *frame;
00627 
00628     cl = &svs.clients[client];
00629     frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK];
00630     if (sequence < 0 || sequence >= frame->num_entities) {
00631         return -1;
00632     }
00633     return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number;
00634 }
00635 

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