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

be_ai_char.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_char.c
00025  *
00026  * desc:        bot characters
00027  *
00028  * $Archive: /MissionPack/code/botlib/be_ai_char.c $
00029  *
00030  *****************************************************************************/
00031 
00032 #include "../game/q_shared.h"
00033 #include "l_log.h"
00034 #include "l_memory.h"
00035 #include "l_utils.h"
00036 #include "l_script.h"
00037 #include "l_precomp.h"
00038 #include "l_struct.h"
00039 #include "l_libvar.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 "../game/be_ai_char.h"
00046 
00047 #define MAX_CHARACTERISTICS     80
00048 
00049 #define CT_INTEGER              1
00050 #define CT_FLOAT                2
00051 #define CT_STRING               3
00052 
00053 #define DEFAULT_CHARACTER       "bots/default_c.c"
00054 
00055 //characteristic value
00056 union cvalue
00057 {
00058     int integer;
00059     float _float;
00060     char *string;
00061 };
00062 //a characteristic
00063 typedef struct bot_characteristic_s
00064 {
00065     char type;                      //characteristic type
00066     union cvalue value;             //characteristic value
00067 } bot_characteristic_t;
00068 
00069 //a bot character
00070 typedef struct bot_character_s
00071 {
00072     char filename[MAX_QPATH];
00073     float skill;
00074     bot_characteristic_t c[1];      //variable sized
00075 } bot_character_t;
00076 
00077 bot_character_t *botcharacters[MAX_CLIENTS + 1];
00078 
00079 //========================================================================
00080 //
00081 // Parameter:           -
00082 // Returns:             -
00083 // Changes Globals:     -
00084 //========================================================================
00085 bot_character_t *BotCharacterFromHandle(int handle)
00086 {
00087     if (handle <= 0 || handle > MAX_CLIENTS)
00088     {
00089         botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle);
00090         return NULL;
00091     } //end if
00092     if (!botcharacters[handle])
00093     {
00094         botimport.Print(PRT_FATAL, "invalid character %d\n", handle);
00095         return NULL;
00096     } //end if
00097     return botcharacters[handle];
00098 } //end of the function BotCharacterFromHandle
00099 //===========================================================================
00100 //
00101 // Parameter:           -
00102 // Returns:             -
00103 // Changes Globals:     -
00104 //===========================================================================
00105 void BotDumpCharacter(bot_character_t *ch)
00106 {
00107     int i;
00108 
00109     Log_Write("%s", ch->filename);
00110     Log_Write("skill %d\n", ch->skill);
00111     Log_Write("{\n");
00112     for (i = 0; i < MAX_CHARACTERISTICS; i++)
00113     {
00114         switch(ch->c[i].type)
00115         {
00116             case CT_INTEGER: Log_Write(" %4d %d\n", i, ch->c[i].value.integer); break;
00117             case CT_FLOAT: Log_Write(" %4d %f\n", i, ch->c[i].value._float); break;
00118             case CT_STRING: Log_Write(" %4d %s\n", i, ch->c[i].value.string); break;
00119         } //end case
00120     } //end for
00121     Log_Write("}\n");
00122 } //end of the function BotDumpCharacter
00123 //========================================================================
00124 //
00125 // Parameter:           -
00126 // Returns:             -
00127 // Changes Globals:     -
00128 //========================================================================
00129 void BotFreeCharacterStrings(bot_character_t *ch)
00130 {
00131     int i;
00132 
00133     for (i = 0; i < MAX_CHARACTERISTICS; i++)
00134     {
00135         if (ch->c[i].type == CT_STRING)
00136         {
00137             FreeMemory(ch->c[i].value.string);
00138         } //end if
00139     } //end for
00140 } //end of the function BotFreeCharacterStrings
00141 //========================================================================
00142 //
00143 // Parameter:           -
00144 // Returns:             -
00145 // Changes Globals:     -
00146 //========================================================================
00147 void BotFreeCharacter2(int handle)
00148 {
00149     if (handle <= 0 || handle > MAX_CLIENTS)
00150     {
00151         botimport.Print(PRT_FATAL, "character handle %d out of range\n", handle);
00152         return;
00153     } //end if
00154     if (!botcharacters[handle])
00155     {
00156         botimport.Print(PRT_FATAL, "invalid character %d\n", handle);
00157         return;
00158     } //end if
00159     BotFreeCharacterStrings(botcharacters[handle]);
00160     FreeMemory(botcharacters[handle]);
00161     botcharacters[handle] = NULL;
00162 } //end of the function BotFreeCharacter2
00163 //========================================================================
00164 //
00165 // Parameter:           -
00166 // Returns:             -
00167 // Changes Globals:     -
00168 //========================================================================
00169 void BotFreeCharacter(int handle)
00170 {
00171     if (!LibVarGetValue("bot_reloadcharacters")) return;
00172     BotFreeCharacter2(handle);
00173 } //end of the function BotFreeCharacter
00174 //===========================================================================
00175 //
00176 // Parameter:           -
00177 // Returns:             -
00178 // Changes Globals:     -
00179 //===========================================================================
00180 void BotDefaultCharacteristics(bot_character_t *ch, bot_character_t *defaultch)
00181 {
00182     int i;
00183 
00184     for (i = 0; i < MAX_CHARACTERISTICS; i++)
00185     {
00186         if (ch->c[i].type) continue;
00187         //
00188         if (defaultch->c[i].type == CT_FLOAT)
00189         {
00190             ch->c[i].type = CT_FLOAT;
00191             ch->c[i].value._float = defaultch->c[i].value._float;
00192         } //end if
00193         else if (defaultch->c[i].type == CT_INTEGER)
00194         {
00195             ch->c[i].type = CT_INTEGER;
00196             ch->c[i].value.integer = defaultch->c[i].value.integer;
00197         } //end else if
00198         else if (defaultch->c[i].type == CT_STRING)
00199         {
00200             ch->c[i].type = CT_STRING;
00201             ch->c[i].value.string = (char *) GetMemory(strlen(defaultch->c[i].value.string)+1);
00202             strcpy(ch->c[i].value.string, defaultch->c[i].value.string);
00203         } //end else if
00204     } //end for
00205 } //end of the function BotDefaultCharacteristics
00206 //===========================================================================
00207 //
00208 // Parameter:           -
00209 // Returns:             -
00210 // Changes Globals:     -
00211 //===========================================================================
00212 bot_character_t *BotLoadCharacterFromFile(char *charfile, int skill)
00213 {
00214     int indent, index, foundcharacter;
00215     bot_character_t *ch;
00216     source_t *source;
00217     token_t token;
00218 
00219     foundcharacter = qfalse;
00220     //a bot character is parsed in two phases
00221     PC_SetBaseFolder(BOTFILESBASEFOLDER);
00222     source = LoadSourceFile(charfile);
00223     if (!source)
00224     {
00225         botimport.Print(PRT_ERROR, "counldn't load %s\n", charfile);
00226         return NULL;
00227     } //end if
00228     ch = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +
00229                     MAX_CHARACTERISTICS * sizeof(bot_characteristic_t));
00230     strcpy(ch->filename, charfile);
00231     while(PC_ReadToken(source, &token))
00232     {
00233         if (!strcmp(token.string, "skill"))
00234         {
00235             if (!PC_ExpectTokenType(source, TT_NUMBER, 0, &token))
00236             {
00237                 FreeSource(source);
00238                 BotFreeCharacterStrings(ch);
00239                 FreeMemory(ch);
00240                 return NULL;
00241             } //end if
00242             if (!PC_ExpectTokenString(source, "{"))
00243             {
00244                 FreeSource(source);
00245                 BotFreeCharacterStrings(ch);
00246                 FreeMemory(ch);
00247                 return NULL;
00248             } //end if
00249             //if it's the correct skill
00250             if (skill < 0 || token.intvalue == skill)
00251             {
00252                 foundcharacter = qtrue;
00253                 ch->skill = token.intvalue;
00254                 while(PC_ExpectAnyToken(source, &token))
00255                 {
00256                     if (!strcmp(token.string, "}")) break;
00257                     if (token.type != TT_NUMBER || !(token.subtype & TT_INTEGER))
00258                     {
00259                         SourceError(source, "expected integer index, found %s\n", token.string);
00260                         FreeSource(source);
00261                         BotFreeCharacterStrings(ch);
00262                         FreeMemory(ch);
00263                         return NULL;
00264                     } //end if
00265                     index = token.intvalue;
00266                     if (index < 0 || index > MAX_CHARACTERISTICS)
00267                     {
00268                         SourceError(source, "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS);
00269                         FreeSource(source);
00270                         BotFreeCharacterStrings(ch);
00271                         FreeMemory(ch);
00272                         return NULL;
00273                     } //end if
00274                     if (ch->c[index].type)
00275                     {
00276                         SourceError(source, "characteristic %d already initialized\n", index);
00277                         FreeSource(source);
00278                         BotFreeCharacterStrings(ch);
00279                         FreeMemory(ch);
00280                         return NULL;
00281                     } //end if
00282                     if (!PC_ExpectAnyToken(source, &token))
00283                     {
00284                         FreeSource(source);
00285                         BotFreeCharacterStrings(ch);
00286                         FreeMemory(ch);
00287                         return NULL;
00288                     } //end if
00289                     if (token.type == TT_NUMBER)
00290                     {
00291                         if (token.subtype & TT_FLOAT)
00292                         {
00293                             ch->c[index].value._float = token.floatvalue;
00294                             ch->c[index].type = CT_FLOAT;
00295                         } //end if
00296                         else
00297                         {
00298                             ch->c[index].value.integer = token.intvalue;
00299                             ch->c[index].type = CT_INTEGER;
00300                         } //end else
00301                     } //end if
00302                     else if (token.type == TT_STRING)
00303                     {
00304                         StripDoubleQuotes(token.string);
00305                         ch->c[index].value.string = GetMemory(strlen(token.string)+1);
00306                         strcpy(ch->c[index].value.string, token.string);
00307                         ch->c[index].type = CT_STRING;
00308                     } //end else if
00309                     else
00310                     {
00311                         SourceError(source, "expected integer, float or string, found %s\n", token.string);
00312                         FreeSource(source);
00313                         BotFreeCharacterStrings(ch);
00314                         FreeMemory(ch);
00315                         return NULL;
00316                     } //end else
00317                 } //end if
00318                 break;
00319             } //end if
00320             else
00321             {
00322                 indent = 1;
00323                 while(indent)
00324                 {
00325                     if (!PC_ExpectAnyToken(source, &token))
00326                     {
00327                         FreeSource(source);
00328                         BotFreeCharacterStrings(ch);
00329                         FreeMemory(ch);
00330                         return NULL;
00331                     } //end if
00332                     if (!strcmp(token.string, "{")) indent++;
00333                     else if (!strcmp(token.string, "}")) indent--;
00334                 } //end while
00335             } //end else
00336         } //end if
00337         else
00338         {
00339             SourceError(source, "unknown definition %s\n", token.string);
00340             FreeSource(source);
00341             BotFreeCharacterStrings(ch);
00342             FreeMemory(ch);
00343             return NULL;
00344         } //end else
00345     } //end while
00346     FreeSource(source);
00347     //
00348     if (!foundcharacter)
00349     {
00350         BotFreeCharacterStrings(ch);
00351         FreeMemory(ch);
00352         return NULL;
00353     } //end if
00354     return ch;
00355 } //end of the function BotLoadCharacterFromFile
00356 //===========================================================================
00357 //
00358 // Parameter:           -
00359 // Returns:             -
00360 // Changes Globals:     -
00361 //===========================================================================
00362 int BotFindCachedCharacter(char *charfile, float skill)
00363 {
00364     int handle;
00365 
00366     for (handle = 1; handle <= MAX_CLIENTS; handle++)
00367     {
00368         if ( !botcharacters[handle] ) continue;
00369         if ( strcmp( botcharacters[handle]->filename, charfile ) == 0 &&
00370             (skill < 0 || fabs(botcharacters[handle]->skill - skill) < 0.01) )
00371         {
00372             return handle;
00373         } //end if
00374     } //end for
00375     return 0;
00376 } //end of the function BotFindCachedCharacter
00377 //===========================================================================
00378 //
00379 // Parameter:           -
00380 // Returns:             -
00381 // Changes Globals:     -
00382 //===========================================================================
00383 int BotLoadCachedCharacter(char *charfile, float skill, int reload)
00384 {
00385     int handle, cachedhandle, intskill;
00386     bot_character_t *ch = NULL;
00387 #ifdef DEBUG
00388     int starttime;
00389 
00390     starttime = Sys_MilliSeconds();
00391 #endif //DEBUG
00392 
00393     //find a free spot for a character
00394     for (handle = 1; handle <= MAX_CLIENTS; handle++)
00395     {
00396         if (!botcharacters[handle]) break;
00397     } //end for
00398     if (handle > MAX_CLIENTS) return 0;
00399     //try to load a cached character with the given skill
00400     if (!reload)
00401     {
00402         cachedhandle = BotFindCachedCharacter(charfile, skill);
00403         if (cachedhandle)
00404         {
00405             botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile);
00406             return cachedhandle;
00407         } //end if
00408     } //end else
00409     //
00410     intskill = (int) (skill + 0.5);
00411     //try to load the character with the given skill
00412     ch = BotLoadCharacterFromFile(charfile, intskill);
00413     if (ch)
00414     {
00415         botcharacters[handle] = ch;
00416         //
00417         botimport.Print(PRT_MESSAGE, "loaded skill %d from %s\n", intskill, charfile);
00418 #ifdef DEBUG
00419         if (bot_developer)
00420         {
00421             botimport.Print(PRT_MESSAGE, "skill %d loaded in %d msec from %s\n", intskill, Sys_MilliSeconds() - starttime, charfile);
00422         } //end if
00423 #endif //DEBUG
00424         return handle;
00425     } //end if
00426     //
00427     botimport.Print(PRT_WARNING, "couldn't find skill %d in %s\n", intskill, charfile);
00428     //
00429     if (!reload)
00430     {
00431         //try to load a cached default character with the given skill
00432         cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, skill);
00433         if (cachedhandle)
00434         {
00435             botimport.Print(PRT_MESSAGE, "loaded cached default skill %d from %s\n", intskill, charfile);
00436             return cachedhandle;
00437         } //end if
00438     } //end if
00439     //try to load the default character with the given skill
00440     ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, intskill);
00441     if (ch)
00442     {
00443         botcharacters[handle] = ch;
00444         botimport.Print(PRT_MESSAGE, "loaded default skill %d from %s\n", intskill, charfile);
00445         return handle;
00446     } //end if
00447     //
00448     if (!reload)
00449     {
00450         //try to load a cached character with any skill
00451         cachedhandle = BotFindCachedCharacter(charfile, -1);
00452         if (cachedhandle)
00453         {
00454             botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile);
00455             return cachedhandle;
00456         } //end if
00457     } //end if
00458     //try to load a character with any skill
00459     ch = BotLoadCharacterFromFile(charfile, -1);
00460     if (ch)
00461     {
00462         botcharacters[handle] = ch;
00463         botimport.Print(PRT_MESSAGE, "loaded skill %f from %s\n", ch->skill, charfile);
00464         return handle;
00465     } //end if
00466     //
00467     if (!reload)
00468     {
00469         //try to load a cached character with any skill
00470         cachedhandle = BotFindCachedCharacter(DEFAULT_CHARACTER, -1);
00471         if (cachedhandle)
00472         {
00473             botimport.Print(PRT_MESSAGE, "loaded cached default skill %f from %s\n", botcharacters[cachedhandle]->skill, charfile);
00474             return cachedhandle;
00475         } //end if
00476     } //end if
00477     //try to load a character with any skill
00478     ch = BotLoadCharacterFromFile(DEFAULT_CHARACTER, -1);
00479     if (ch)
00480     {
00481         botcharacters[handle] = ch;
00482         botimport.Print(PRT_MESSAGE, "loaded default skill %f from %s\n", ch->skill, charfile);
00483         return handle;
00484     } //end if
00485     //
00486     botimport.Print(PRT_WARNING, "couldn't load any skill from %s\n", charfile);
00487     //couldn't load any character
00488     return 0;
00489 } //end of the function BotLoadCachedCharacter
00490 //===========================================================================
00491 //
00492 // Parameter:           -
00493 // Returns:             -
00494 // Changes Globals:     -
00495 //===========================================================================
00496 int BotLoadCharacterSkill(char *charfile, float skill)
00497 {
00498     int ch, defaultch;
00499 
00500     defaultch = BotLoadCachedCharacter(DEFAULT_CHARACTER, skill, qfalse);
00501     ch = BotLoadCachedCharacter(charfile, skill, LibVarGetValue("bot_reloadcharacters"));
00502 
00503     if (defaultch && ch)
00504     {
00505         BotDefaultCharacteristics(botcharacters[ch], botcharacters[defaultch]);
00506     } //end if
00507 
00508     return ch;
00509 } //end of the function BotLoadCharacterSkill
00510 //===========================================================================
00511 //
00512 // Parameter:           -
00513 // Returns:             -
00514 // Changes Globals:     -
00515 //===========================================================================
00516 int BotInterpolateCharacters(int handle1, int handle2, float desiredskill)
00517 {
00518     bot_character_t *ch1, *ch2, *out;
00519     int i, handle;
00520     float scale;
00521 
00522     ch1 = BotCharacterFromHandle(handle1);
00523     ch2 = BotCharacterFromHandle(handle2);
00524     if (!ch1 || !ch2)
00525         return 0;
00526     //find a free spot for a character
00527     for (handle = 1; handle <= MAX_CLIENTS; handle++)
00528     {
00529         if (!botcharacters[handle]) break;
00530     } //end for
00531     if (handle > MAX_CLIENTS) return 0;
00532     out = (bot_character_t *) GetClearedMemory(sizeof(bot_character_t) +
00533                     MAX_CHARACTERISTICS * sizeof(bot_characteristic_t));
00534     out->skill = desiredskill;
00535     strcpy(out->filename, ch1->filename);
00536     botcharacters[handle] = out;
00537 
00538     scale = (float) (desiredskill - ch1->skill) / (ch2->skill - ch1->skill);
00539     for (i = 0; i < MAX_CHARACTERISTICS; i++)
00540     {
00541         //
00542         if (ch1->c[i].type == CT_FLOAT && ch2->c[i].type == CT_FLOAT)
00543         {
00544             out->c[i].type = CT_FLOAT;
00545             out->c[i].value._float = ch1->c[i].value._float +
00546                                 (ch2->c[i].value._float - ch1->c[i].value._float) * scale;
00547         } //end if
00548         else if (ch1->c[i].type == CT_INTEGER)
00549         {
00550             out->c[i].type = CT_INTEGER;
00551             out->c[i].value.integer = ch1->c[i].value.integer;
00552         } //end else if
00553         else if (ch1->c[i].type == CT_STRING)
00554         {
00555             out->c[i].type = CT_STRING;
00556             out->c[i].value.string = (char *) GetMemory(strlen(ch1->c[i].value.string)+1);
00557             strcpy(out->c[i].value.string, ch1->c[i].value.string);
00558         } //end else if
00559     } //end for
00560     return handle;
00561 } //end of the function BotInterpolateCharacters
00562 //===========================================================================
00563 //
00564 // Parameter:           -
00565 // Returns:             -
00566 // Changes Globals:     -
00567 //===========================================================================
00568 int BotLoadCharacter(char *charfile, float skill)
00569 {
00570     int firstskill, secondskill, handle;
00571 
00572     //make sure the skill is in the valid range
00573     if (skill < 1.0) skill = 1.0;
00574     else if (skill > 5.0) skill = 5.0;
00575     //skill 1, 4 and 5 should be available in the character files
00576     if (skill == 1.0 || skill == 4.0 || skill == 5.0)
00577     {
00578         return BotLoadCharacterSkill(charfile, skill);
00579     } //end if
00580     //check if there's a cached skill
00581     handle = BotFindCachedCharacter(charfile, skill);
00582     if (handle)
00583     {
00584         botimport.Print(PRT_MESSAGE, "loaded cached skill %f from %s\n", skill, charfile);
00585         return handle;
00586     } //end if
00587     if (skill < 4.0)
00588     {
00589         //load skill 1 and 4
00590         firstskill = BotLoadCharacterSkill(charfile, 1);
00591         if (!firstskill) return 0;
00592         secondskill = BotLoadCharacterSkill(charfile, 4);
00593         if (!secondskill) return firstskill;
00594     } //end if
00595     else
00596     {
00597         //load skill 4 and 5
00598         firstskill = BotLoadCharacterSkill(charfile, 4);
00599         if (!firstskill) return 0;
00600         secondskill = BotLoadCharacterSkill(charfile, 5);
00601         if (!secondskill) return firstskill;
00602     } //end else
00603     //interpolate between the two skills
00604     handle = BotInterpolateCharacters(firstskill, secondskill, skill);
00605     if (!handle) return 0;
00606     //write the character to the log file
00607     BotDumpCharacter(botcharacters[handle]);
00608     //
00609     return handle;
00610 } //end of the function BotLoadCharacter
00611 //===========================================================================
00612 //
00613 // Parameter:           -
00614 // Returns:             -
00615 // Changes Globals:     -
00616 //===========================================================================
00617 int CheckCharacteristicIndex(int character, int index)
00618 {
00619     bot_character_t *ch;
00620 
00621     ch = BotCharacterFromHandle(character);
00622     if (!ch) return qfalse;
00623     if (index < 0 || index >= MAX_CHARACTERISTICS)
00624     {
00625         botimport.Print(PRT_ERROR, "characteristic %d does not exist\n", index);
00626         return qfalse;
00627     } //end if
00628     if (!ch->c[index].type)
00629     {
00630         botimport.Print(PRT_ERROR, "characteristic %d is not initialized\n", index);
00631         return qfalse;
00632     } //end if
00633     return qtrue;
00634 } //end of the function CheckCharacteristicIndex
00635 //===========================================================================
00636 //
00637 // Parameter:           -
00638 // Returns:             -
00639 // Changes Globals:     -
00640 //===========================================================================
00641 float Characteristic_Float(int character, int index)
00642 {
00643     bot_character_t *ch;
00644 
00645     ch = BotCharacterFromHandle(character);
00646     if (!ch) return 0;
00647     //check if the index is in range
00648     if (!CheckCharacteristicIndex(character, index)) return 0;
00649     //an integer will be converted to a float
00650     if (ch->c[index].type == CT_INTEGER)
00651     {
00652         return (float) ch->c[index].value.integer;
00653     } //end if
00654     //floats are just returned
00655     else if (ch->c[index].type == CT_FLOAT)
00656     {
00657         return ch->c[index].value._float;
00658     } //end else if
00659     //cannot convert a string pointer to a float
00660     else
00661     {
00662         botimport.Print(PRT_ERROR, "characteristic %d is not a float\n", index);
00663         return 0;
00664     } //end else if
00665 //  return 0;
00666 } //end of the function Characteristic_Float
00667 //===========================================================================
00668 //
00669 // Parameter:               -
00670 // Returns:                 -
00671 // Changes Globals:     -
00672 //===========================================================================
00673 float Characteristic_BFloat(int character, int index, float min, float max)
00674 {
00675     float value;
00676     bot_character_t *ch;
00677 
00678     ch = BotCharacterFromHandle(character);
00679     if (!ch) return 0;
00680     if (min > max)
00681     {
00682         botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %f and %f\n", index, min, max);
00683         return 0;
00684     } //end if
00685     value = Characteristic_Float(character, index);
00686     if (value < min) return min;
00687     if (value > max) return max;
00688     return value;
00689 } //end of the function Characteristic_BFloat
00690 //===========================================================================
00691 //
00692 // Parameter:           -
00693 // Returns:             -
00694 // Changes Globals:     -
00695 //===========================================================================
00696 int Characteristic_Integer(int character, int index)
00697 {
00698     bot_character_t *ch;
00699 
00700     ch = BotCharacterFromHandle(character);
00701     if (!ch) return 0;
00702     //check if the index is in range
00703     if (!CheckCharacteristicIndex(character, index)) return 0;
00704     //an integer will just be returned
00705     if (ch->c[index].type == CT_INTEGER)
00706     {
00707         return ch->c[index].value.integer;
00708     } //end if
00709     //floats are casted to integers
00710     else if (ch->c[index].type == CT_FLOAT)
00711     {
00712         return (int) ch->c[index].value._float;
00713     } //end else if
00714     else
00715     {
00716         botimport.Print(PRT_ERROR, "characteristic %d is not a integer\n", index);
00717         return 0;
00718     } //end else if
00719 //  return 0;
00720 } //end of the function Characteristic_Integer
00721 //===========================================================================
00722 //
00723 // Parameter:           -
00724 // Returns:             -
00725 // Changes Globals:     -
00726 //===========================================================================
00727 int Characteristic_BInteger(int character, int index, int min, int max)
00728 {
00729     int value;
00730     bot_character_t *ch;
00731 
00732     ch = BotCharacterFromHandle(character);
00733     if (!ch) return 0;
00734     if (min > max)
00735     {
00736         botimport.Print(PRT_ERROR, "cannot bound characteristic %d between %d and %d\n", index, min, max);
00737         return 0;
00738     } //end if
00739     value = Characteristic_Integer(character, index);
00740     if (value < min) return min;
00741     if (value > max) return max;
00742     return value;
00743 } //end of the function Characteristic_BInteger
00744 //===========================================================================
00745 //
00746 // Parameter:           -
00747 // Returns:             -
00748 // Changes Globals:     -
00749 //===========================================================================
00750 void Characteristic_String(int character, int index, char *buf, int size)
00751 {
00752     bot_character_t *ch;
00753 
00754     ch = BotCharacterFromHandle(character);
00755     if (!ch) return;
00756     //check if the index is in range
00757     if (!CheckCharacteristicIndex(character, index)) return;
00758     //an integer will be converted to a float
00759     if (ch->c[index].type == CT_STRING)
00760     {
00761         strncpy(buf, ch->c[index].value.string, size-1);
00762         buf[size-1] = '\0';
00763         return;
00764     } //end if
00765     else
00766     {
00767         botimport.Print(PRT_ERROR, "characteristic %d is not a string\n", index);
00768         return;
00769     } //end else if
00770     return;
00771 } //end of the function Characteristic_String
00772 //===========================================================================
00773 //
00774 // Parameter:           -
00775 // Returns:             -
00776 // Changes Globals:     -
00777 //===========================================================================
00778 void BotShutdownCharacters(void)
00779 {
00780     int handle;
00781 
00782     for (handle = 1; handle <= MAX_CLIENTS; handle++)
00783     {
00784         if (botcharacters[handle])
00785         {
00786             BotFreeCharacter2(handle);
00787         } //end if
00788     } //end for
00789 } //end of the function BotShutdownCharacters
00790 

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