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

be_ai_weap.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  * name:        be_ai_weap.c
00025  *
00026  * desc:        weapon AI
00027  *
00028  * $Archive: /MissionPack/code/botlib/be_ai_weap.c $
00029  *
00030  *****************************************************************************/
00031 
00032 #include "../game/q_shared.h"
00033 #include "l_libvar.h"
00034 #include "l_log.h"
00035 #include "l_memory.h"
00036 #include "l_utils.h"
00037 #include "l_script.h"
00038 #include "l_precomp.h"
00039 #include "l_struct.h"
00040 #include "aasfile.h"
00041 #include "../game/botlib.h"
00042 #include "../game/be_aas.h"
00043 #include "be_aas_funcs.h"
00044 #include "be_interface.h"
00045 #include "be_ai_weight.h"       //fuzzy weights
00046 #include "../game/be_ai_weap.h"
00047 
00048 //#define DEBUG_AI_WEAP
00049 
00050 //structure field offsets
00051 #define WEAPON_OFS(x) (int)&(((weaponinfo_t *)0)->x)
00052 #define PROJECTILE_OFS(x) (int)&(((projectileinfo_t *)0)->x)
00053 
00054 //weapon definition // bk001212 - static
00055 static fielddef_t weaponinfo_fields[] =
00056 {
00057 {"number", WEAPON_OFS(number), FT_INT},                     //weapon number
00058 {"name", WEAPON_OFS(name), FT_STRING},                          //name of the weapon
00059 {"level", WEAPON_OFS(level), FT_INT},
00060 {"model", WEAPON_OFS(model), FT_STRING},                        //model of the weapon
00061 {"weaponindex", WEAPON_OFS(weaponindex), FT_INT},           //index of weapon in inventory
00062 {"flags", WEAPON_OFS(flags), FT_INT},                           //special flags
00063 {"projectile", WEAPON_OFS(projectile), FT_STRING},          //projectile used by the weapon
00064 {"numprojectiles", WEAPON_OFS(numprojectiles), FT_INT}, //number of projectiles
00065 {"hspread", WEAPON_OFS(hspread), FT_FLOAT},                 //horizontal spread of projectiles (degrees from middle)
00066 {"vspread", WEAPON_OFS(vspread), FT_FLOAT},                 //vertical spread of projectiles (degrees from middle)
00067 {"speed", WEAPON_OFS(speed), FT_FLOAT},                     //speed of the projectile (0 = instant hit)
00068 {"acceleration", WEAPON_OFS(acceleration), FT_FLOAT},       //"acceleration" * time (in seconds) + "speed" = projectile speed
00069 {"recoil", WEAPON_OFS(recoil), FT_FLOAT|FT_ARRAY, 3},       //amount of recoil the player gets from the weapon
00070 {"offset", WEAPON_OFS(offset), FT_FLOAT|FT_ARRAY, 3},       //projectile start offset relative to eye and view angles
00071 {"angleoffset", WEAPON_OFS(angleoffset), FT_FLOAT|FT_ARRAY, 3},//offset of the shoot angles relative to the view angles
00072 {"extrazvelocity", WEAPON_OFS(extrazvelocity), FT_FLOAT},//extra z velocity the projectile gets
00073 {"ammoamount", WEAPON_OFS(ammoamount), FT_INT},             //ammo amount used per shot
00074 {"ammoindex", WEAPON_OFS(ammoindex), FT_INT},               //index of ammo in inventory
00075 {"activate", WEAPON_OFS(activate), FT_FLOAT},               //time it takes to select the weapon
00076 {"reload", WEAPON_OFS(reload), FT_FLOAT},                       //time it takes to reload the weapon
00077 {"spinup", WEAPON_OFS(spinup), FT_FLOAT},                       //time it takes before first shot
00078 {"spindown", WEAPON_OFS(spindown), FT_FLOAT},               //time it takes before weapon stops firing
00079 {NULL, 0, 0, 0}
00080 };
00081 
00082 //projectile definition
00083 static fielddef_t projectileinfo_fields[] =
00084 {
00085 {"name", PROJECTILE_OFS(name), FT_STRING},                  //name of the projectile
00086 {"model", WEAPON_OFS(model), FT_STRING},                        //model of the projectile
00087 {"flags", PROJECTILE_OFS(flags), FT_INT},                       //special flags
00088 {"gravity", PROJECTILE_OFS(gravity), FT_FLOAT},             //amount of gravity applied to the projectile [0,1]
00089 {"damage", PROJECTILE_OFS(damage), FT_INT},                 //damage of the projectile
00090 {"radius", PROJECTILE_OFS(radius), FT_FLOAT},               //radius of damage
00091 {"visdamage", PROJECTILE_OFS(visdamage), FT_INT},           //damage of the projectile to visible entities
00092 {"damagetype", PROJECTILE_OFS(damagetype), FT_INT},     //type of damage (combination of the DAMAGETYPE_? flags)
00093 {"healthinc", PROJECTILE_OFS(healthinc), FT_INT},           //health increase the owner gets
00094 {"push", PROJECTILE_OFS(push), FT_FLOAT},                       //amount a player is pushed away from the projectile impact
00095 {"detonation", PROJECTILE_OFS(detonation), FT_FLOAT},       //time before projectile explodes after fire pressed
00096 {"bounce", PROJECTILE_OFS(bounce), FT_FLOAT},               //amount the projectile bounces
00097 {"bouncefric", PROJECTILE_OFS(bouncefric), FT_FLOAT},   //amount the bounce decreases per bounce
00098 {"bouncestop", PROJECTILE_OFS(bouncestop), FT_FLOAT},       //minimum bounce value before bouncing stops
00099 //recurive projectile definition??
00100 {NULL, 0, 0, 0}
00101 };
00102 
00103 static structdef_t weaponinfo_struct =
00104 {
00105     sizeof(weaponinfo_t), weaponinfo_fields
00106 };
00107 static structdef_t projectileinfo_struct =
00108 {
00109     sizeof(projectileinfo_t), projectileinfo_fields
00110 };
00111 
00112 //weapon configuration: set of weapons with projectiles
00113 typedef struct weaponconfig_s
00114 {
00115     int numweapons;
00116     int numprojectiles;
00117     projectileinfo_t *projectileinfo;
00118     weaponinfo_t *weaponinfo;
00119 } weaponconfig_t;
00120 
00121 //the bot weapon state
00122 typedef struct bot_weaponstate_s
00123 {
00124     struct weightconfig_s *weaponweightconfig;      //weapon weight configuration
00125     int *weaponweightindex;                         //weapon weight index
00126 } bot_weaponstate_t;
00127 
00128 static bot_weaponstate_t *botweaponstates[MAX_CLIENTS+1];
00129 static weaponconfig_t *weaponconfig;
00130 
00131 //========================================================================
00132 //
00133 // Parameter:               -
00134 // Returns:                 -
00135 // Changes Globals:     -
00136 //========================================================================
00137 int BotValidWeaponNumber(int weaponnum)
00138 {
00139     if (weaponnum <= 0 || weaponnum > weaponconfig->numweapons)
00140     {
00141         botimport.Print(PRT_ERROR, "weapon number out of range\n");
00142         return qfalse;
00143     } //end if
00144     return qtrue;
00145 } //end of the function BotValidWeaponNumber
00146 //========================================================================
00147 //
00148 // Parameter:               -
00149 // Returns:                 -
00150 // Changes Globals:     -
00151 //========================================================================
00152 bot_weaponstate_t *BotWeaponStateFromHandle(int handle)
00153 {
00154     if (handle <= 0 || handle > MAX_CLIENTS)
00155     {
00156         botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
00157         return NULL;
00158     } //end if
00159     if (!botweaponstates[handle])
00160     {
00161         botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
00162         return NULL;
00163     } //end if
00164     return botweaponstates[handle];
00165 } //end of the function BotWeaponStateFromHandle
00166 //===========================================================================
00167 //
00168 // Parameter:               -
00169 // Returns:                 -
00170 // Changes Globals:     -
00171 //===========================================================================
00172 #ifdef DEBUG_AI_WEAP
00173 void DumpWeaponConfig(weaponconfig_t *wc)
00174 {
00175     FILE *fp;
00176     int i;
00177 
00178     fp = Log_FileStruct();
00179     if (!fp) return;
00180     for (i = 0; i < wc->numprojectiles; i++)
00181     {
00182         WriteStructure(fp, &projectileinfo_struct, (char *) &wc->projectileinfo[i]);
00183         Log_Flush();
00184     } //end for
00185     for (i = 0; i < wc->numweapons; i++)
00186     {
00187         WriteStructure(fp, &weaponinfo_struct, (char *) &wc->weaponinfo[i]);
00188         Log_Flush();
00189     } //end for
00190 } //end of the function DumpWeaponConfig
00191 #endif //DEBUG_AI_WEAP
00192 //===========================================================================
00193 //
00194 // Parameter:               -
00195 // Returns:                 -
00196 // Changes Globals:     -
00197 //===========================================================================
00198 weaponconfig_t *LoadWeaponConfig(char *filename)
00199 {
00200     int max_weaponinfo, max_projectileinfo;
00201     token_t token;
00202     char path[MAX_PATH];
00203     int i, j;
00204     source_t *source;
00205     weaponconfig_t *wc;
00206     weaponinfo_t weaponinfo;
00207 
00208     max_weaponinfo = (int) LibVarValue("max_weaponinfo", "32");
00209     if (max_weaponinfo < 0)
00210     {
00211         botimport.Print(PRT_ERROR, "max_weaponinfo = %d\n", max_weaponinfo);
00212         max_weaponinfo = 32;
00213         LibVarSet("max_weaponinfo", "32");
00214     } //end if
00215     max_projectileinfo = (int) LibVarValue("max_projectileinfo", "32");
00216     if (max_projectileinfo < 0)
00217     {
00218         botimport.Print(PRT_ERROR, "max_projectileinfo = %d\n", max_projectileinfo);
00219         max_projectileinfo = 32;
00220         LibVarSet("max_projectileinfo", "32");
00221     } //end if
00222     strncpy(path, filename, MAX_PATH);
00223     PC_SetBaseFolder(BOTFILESBASEFOLDER);
00224     source = LoadSourceFile(path);
00225     if (!source)
00226     {
00227         botimport.Print(PRT_ERROR, "counldn't load %s\n", path);
00228         return NULL;
00229     } //end if
00230     //initialize weapon config
00231     wc = (weaponconfig_t *) GetClearedHunkMemory(sizeof(weaponconfig_t) +
00232                                         max_weaponinfo * sizeof(weaponinfo_t) +
00233                                         max_projectileinfo * sizeof(projectileinfo_t));
00234     wc->weaponinfo = (weaponinfo_t *) ((char *) wc + sizeof(weaponconfig_t));
00235     wc->projectileinfo = (projectileinfo_t *) ((char *) wc->weaponinfo +
00236                                         max_weaponinfo * sizeof(weaponinfo_t));
00237     wc->numweapons = max_weaponinfo;
00238     wc->numprojectiles = 0;
00239     //parse the source file
00240     while(PC_ReadToken(source, &token))
00241     {
00242         if (!strcmp(token.string, "weaponinfo"))
00243         {
00244             Com_Memset(&weaponinfo, 0, sizeof(weaponinfo_t));
00245             if (!ReadStructure(source, &weaponinfo_struct, (char *) &weaponinfo))
00246             {
00247                 FreeMemory(wc);
00248                 FreeSource(source);
00249                 return NULL;
00250             } //end if
00251             if (weaponinfo.number < 0 || weaponinfo.number >= max_weaponinfo)
00252             {
00253                 botimport.Print(PRT_ERROR, "weapon info number %d out of range in %s\n", weaponinfo.number, path);
00254                 FreeMemory(wc);
00255                 FreeSource(source);
00256                 return NULL;
00257             } //end if
00258             Com_Memcpy(&wc->weaponinfo[weaponinfo.number], &weaponinfo, sizeof(weaponinfo_t));
00259             wc->weaponinfo[weaponinfo.number].valid = qtrue;
00260         } //end if
00261         else if (!strcmp(token.string, "projectileinfo"))
00262         {
00263             if (wc->numprojectiles >= max_projectileinfo)
00264             {
00265                 botimport.Print(PRT_ERROR, "more than %d projectiles defined in %s\n", max_projectileinfo, path);
00266                 FreeMemory(wc);
00267                 FreeSource(source);
00268                 return NULL;
00269             } //end if
00270             Com_Memset(&wc->projectileinfo[wc->numprojectiles], 0, sizeof(projectileinfo_t));
00271             if (!ReadStructure(source, &projectileinfo_struct, (char *) &wc->projectileinfo[wc->numprojectiles]))
00272             {
00273                 FreeMemory(wc);
00274                 FreeSource(source);
00275                 return NULL;
00276             } //end if
00277             wc->numprojectiles++;
00278         } //end if
00279         else
00280         {
00281             botimport.Print(PRT_ERROR, "unknown definition %s in %s\n", token.string, path);
00282             FreeMemory(wc);
00283             FreeSource(source);
00284             return NULL;
00285         } //end else
00286     } //end while
00287     FreeSource(source);
00288     //fix up weapons
00289     for (i = 0; i < wc->numweapons; i++)
00290     {
00291         if (!wc->weaponinfo[i].valid) continue;
00292         if (!wc->weaponinfo[i].name[0])
00293         {
00294             botimport.Print(PRT_ERROR, "weapon %d has no name in %s\n", i, path);
00295             FreeMemory(wc);
00296             return NULL;
00297         } //end if
00298         if (!wc->weaponinfo[i].projectile[0])
00299         {
00300             botimport.Print(PRT_ERROR, "weapon %s has no projectile in %s\n", wc->weaponinfo[i].name, path);
00301             FreeMemory(wc);
00302             return NULL;
00303         } //end if
00304         //find the projectile info and copy it to the weapon info
00305         for (j = 0; j < wc->numprojectiles; j++)
00306         {
00307             if (!strcmp(wc->projectileinfo[j].name, wc->weaponinfo[i].projectile))
00308             {
00309                 Com_Memcpy(&wc->weaponinfo[i].proj, &wc->projectileinfo[j], sizeof(projectileinfo_t));
00310                 break;
00311             } //end if
00312         } //end for
00313         if (j == wc->numprojectiles)
00314         {
00315             botimport.Print(PRT_ERROR, "weapon %s uses undefined projectile in %s\n", wc->weaponinfo[i].name, path);
00316             FreeMemory(wc);
00317             return NULL;
00318         } //end if
00319     } //end for
00320     if (!wc->numweapons) botimport.Print(PRT_WARNING, "no weapon info loaded\n");
00321     botimport.Print(PRT_MESSAGE, "loaded %s\n", path);
00322     return wc;
00323 } //end of the function LoadWeaponConfig
00324 //===========================================================================
00325 //
00326 // Parameter:               -
00327 // Returns:                 -
00328 // Changes Globals:     -
00329 //===========================================================================
00330 int *WeaponWeightIndex(weightconfig_t *wwc, weaponconfig_t *wc)
00331 {
00332     int *index, i;
00333 
00334     //initialize item weight index
00335     index = (int *) GetClearedMemory(sizeof(int) * wc->numweapons);
00336 
00337     for (i = 0; i < wc->numweapons; i++)
00338     {
00339         index[i] = FindFuzzyWeight(wwc, wc->weaponinfo[i].name);
00340     } //end for
00341     return index;
00342 } //end of the function WeaponWeightIndex
00343 //===========================================================================
00344 //
00345 // Parameter:               -
00346 // Returns:                 -
00347 // Changes Globals:     -
00348 //===========================================================================
00349 void BotFreeWeaponWeights(int weaponstate)
00350 {
00351     bot_weaponstate_t *ws;
00352 
00353     ws = BotWeaponStateFromHandle(weaponstate);
00354     if (!ws) return;
00355     if (ws->weaponweightconfig) FreeWeightConfig(ws->weaponweightconfig);
00356     if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex);
00357 } //end of the function BotFreeWeaponWeights
00358 //===========================================================================
00359 //
00360 // Parameter:               -
00361 // Returns:                 -
00362 // Changes Globals:     -
00363 //===========================================================================
00364 int BotLoadWeaponWeights(int weaponstate, char *filename)
00365 {
00366     bot_weaponstate_t *ws;
00367 
00368     ws = BotWeaponStateFromHandle(weaponstate);
00369     if (!ws) return BLERR_CANNOTLOADWEAPONWEIGHTS;
00370     BotFreeWeaponWeights(weaponstate);
00371     //
00372     ws->weaponweightconfig = ReadWeightConfig(filename);
00373     if (!ws->weaponweightconfig)
00374     {
00375         botimport.Print(PRT_FATAL, "couldn't load weapon config %s\n", filename);
00376         return BLERR_CANNOTLOADWEAPONWEIGHTS;
00377     } //end if
00378     if (!weaponconfig) return BLERR_CANNOTLOADWEAPONCONFIG;
00379     ws->weaponweightindex = WeaponWeightIndex(ws->weaponweightconfig, weaponconfig);
00380     return BLERR_NOERROR;
00381 } //end of the function BotLoadWeaponWeights
00382 //===========================================================================
00383 //
00384 // Parameter:               -
00385 // Returns:                 -
00386 // Changes Globals:     -
00387 //===========================================================================
00388 void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo)
00389 {
00390     bot_weaponstate_t *ws;
00391 
00392     if (!BotValidWeaponNumber(weapon)) return;
00393     ws = BotWeaponStateFromHandle(weaponstate);
00394     if (!ws) return;
00395     if (!weaponconfig) return;
00396     Com_Memcpy(weaponinfo, &weaponconfig->weaponinfo[weapon], sizeof(weaponinfo_t));
00397 } //end of the function BotGetWeaponInfo
00398 //===========================================================================
00399 //
00400 // Parameter:               -
00401 // Returns:                 -
00402 // Changes Globals:     -
00403 //===========================================================================
00404 int BotChooseBestFightWeapon(int weaponstate, int *inventory)
00405 {
00406     int i, index, bestweapon;
00407     float weight, bestweight;
00408     weaponconfig_t *wc;
00409     bot_weaponstate_t *ws;
00410 
00411     ws = BotWeaponStateFromHandle(weaponstate);
00412     if (!ws) return 0;
00413     wc = weaponconfig;
00414     if (!weaponconfig) return 0;
00415 
00416     //if the bot has no weapon weight configuration
00417     if (!ws->weaponweightconfig) return 0;
00418 
00419     bestweight = 0;
00420     bestweapon = 0;
00421     for (i = 0; i < wc->numweapons; i++)
00422     {
00423         if (!wc->weaponinfo[i].valid) continue;
00424         index = ws->weaponweightindex[i];
00425         if (index < 0) continue;
00426         weight = FuzzyWeight(inventory, ws->weaponweightconfig, index);
00427         if (weight > bestweight)
00428         {
00429             bestweight = weight;
00430             bestweapon = i;
00431         } //end if
00432     } //end for
00433     return bestweapon;
00434 } //end of the function BotChooseBestFightWeapon
00435 //===========================================================================
00436 //
00437 // Parameter:               -
00438 // Returns:                 -
00439 // Changes Globals:     -
00440 //===========================================================================
00441 void BotResetWeaponState(int weaponstate)
00442 {
00443     struct weightconfig_s *weaponweightconfig;
00444     int *weaponweightindex;
00445     bot_weaponstate_t *ws;
00446 
00447     ws = BotWeaponStateFromHandle(weaponstate);
00448     if (!ws) return;
00449     weaponweightconfig = ws->weaponweightconfig;
00450     weaponweightindex = ws->weaponweightindex;
00451 
00452     //Com_Memset(ws, 0, sizeof(bot_weaponstate_t));
00453     ws->weaponweightconfig = weaponweightconfig;
00454     ws->weaponweightindex = weaponweightindex;
00455 } //end of the function BotResetWeaponState
00456 //========================================================================
00457 //
00458 // Parameter:               -
00459 // Returns:                 -
00460 // Changes Globals:     -
00461 //========================================================================
00462 int BotAllocWeaponState(void)
00463 {
00464     int i;
00465 
00466     for (i = 1; i <= MAX_CLIENTS; i++)
00467     {
00468         if (!botweaponstates[i])
00469         {
00470             botweaponstates[i] = GetClearedMemory(sizeof(bot_weaponstate_t));
00471             return i;
00472         } //end if
00473     } //end for
00474     return 0;
00475 } //end of the function BotAllocWeaponState
00476 //========================================================================
00477 //
00478 // Parameter:               -
00479 // Returns:                 -
00480 // Changes Globals:     -
00481 //========================================================================
00482 void BotFreeWeaponState(int handle)
00483 {
00484     if (handle <= 0 || handle > MAX_CLIENTS)
00485     {
00486         botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
00487         return;
00488     } //end if
00489     if (!botweaponstates[handle])
00490     {
00491         botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
00492         return;
00493     } //end if
00494     BotFreeWeaponWeights(handle);
00495     FreeMemory(botweaponstates[handle]);
00496     botweaponstates[handle] = NULL;
00497 } //end of the function BotFreeWeaponState
00498 //===========================================================================
00499 //
00500 // Parameter:               -
00501 // Returns:                 -
00502 // Changes Globals:     -
00503 //===========================================================================
00504 int BotSetupWeaponAI(void)
00505 {
00506     char *file;
00507 
00508     file = LibVarString("weaponconfig", "weapons.c");
00509     weaponconfig = LoadWeaponConfig(file);
00510     if (!weaponconfig)
00511     {
00512         botimport.Print(PRT_FATAL, "couldn't load the weapon config\n");
00513         return BLERR_CANNOTLOADWEAPONCONFIG;
00514     } //end if
00515 
00516 #ifdef DEBUG_AI_WEAP
00517     DumpWeaponConfig(weaponconfig);
00518 #endif //DEBUG_AI_WEAP
00519     //
00520     return BLERR_NOERROR;
00521 } //end of the function BotSetupWeaponAI
00522 //===========================================================================
00523 //
00524 // Parameter:               -
00525 // Returns:                 -
00526 // Changes Globals:     -
00527 //===========================================================================
00528 void BotShutdownWeaponAI(void)
00529 {
00530     int i;
00531 
00532     if (weaponconfig) FreeMemory(weaponconfig);
00533     weaponconfig = NULL;
00534 
00535     for (i = 1; i <= MAX_CLIENTS; i++)
00536     {
00537         if (botweaponstates[i])
00538         {
00539             BotFreeWeaponState(i);
00540         } //end if
00541     } //end for
00542 } //end of the function BotShutdownWeaponAI
00543 

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