// Bot_weapons.cpp // #include "precompiled.h" #pragma hdrstop #include "../Game_local.h" idCVar bot_weaponsfile( "bot_weaponsfile", "weapons.c", CVAR_GAME | CVAR_CHEAT, "which file to load the weapons weights from" ); idBotWeaponInfoManager botWeaponInfoManager; /* ========================= idBotWeaponInfoManager::BotValidWeaponNumber ========================= */ int idBotWeaponInfoManager::BotValidWeaponNumber( int weaponnum ) { if( weaponnum < 0 || weaponnum >= BOT_MAX_WEAPONS ) { gameLocal.Error( "weapon number out of range\n" ); return false; } return true; } /* ========================= idBotWeaponInfoManager::BotWeaponStateFromHandle ========================= */ bot_weaponstate_t* idBotWeaponInfoManager::BotWeaponStateFromHandle( int handle ) { if( handle <= 0 || handle > MAX_CLIENTS ) { gameLocal.Error( "move state handle %d out of range\n", handle ); return NULL; } return &botweaponstates[handle]; } /* ======================== idBotWeaponInfoManager::ParseProjectileInfo ======================== */ void idBotWeaponInfoManager::ParseProjectileInfo( idParser& parser, projectileinfo_t& newProjectileInfo ) { idToken token; idToken valueToken; parser.ExpectTokenString( "{" ); while( true ) { if( !parser.ReadToken( &token ) ) { parser.Error( "Unexpected end of file found while parsing weaponinfo!" ); } if( token == "}" ) { break; } if( !parser.ReadToken( &valueToken ) ) { parser.Error( "Failed to read value token, encountered EOF parsing weapon info!" ); } if( token == "name" ) { newProjectileInfo.name = valueToken; // name of the projectile } else if( token == "model" ) { newProjectileInfo.model = valueToken; // model of the projectile } else if( token == "flags" ) { newProjectileInfo.flags = valueToken.GetIntValue(); // special flags } else if( token == "gravity" ) { newProjectileInfo.gravity = valueToken.GetFloatValue(); // amount of gravity applied to the projectile [0,1] } else if( token == "damage" ) { newProjectileInfo.damage = valueToken.GetIntValue(); // damage of the projectile } else if( token == "radius" ) { newProjectileInfo.radius = valueToken.GetFloatValue(); // radius of damage } else if( token == "visdamage" ) { newProjectileInfo.visdamage = valueToken.GetIntValue(); // damage of the projectile to visible entities } else if( token == "damagetype" ) { newProjectileInfo.damagetype = valueToken.GetIntValue(); // type of damage (combination of the DAMAGETYPE_? flags) } else if( token == "healthinc" ) { newProjectileInfo.healthinc = valueToken.GetIntValue(); // health increase the owner gets } else if( token == "push" ) { newProjectileInfo.push = valueToken.GetFloatValue(); // amount a player is pushed away from the projectile impact } else if( token == "detonation" ) { newProjectileInfo.detonation = valueToken.GetFloatValue(); // time before projectile explodes after fire pressed } else if( token == "bounce" ) { newProjectileInfo.bounce = valueToken.GetFloatValue(); // amount the projectile bounces } else if( token == "bouncefric" ) { newProjectileInfo.bouncefric = valueToken.GetFloatValue(); // amount the bounce decreases per bounce } else if( token == "bouncestop" ) { newProjectileInfo.bouncestop = valueToken.GetFloatValue(); // minimum bounce value before bouncing stops } else { parser.Error( "ParseProjectileInfo: Unexpected token %s\n", token.c_str() ); } } } /* ======================== idBotWeaponInfoManager::ParseWeaponInfo ======================== */ void idBotWeaponInfoManager::ParseWeaponInfo( idParser& parser, weaponinfo_t& newWeaponInfo ) { idToken token; idToken valueToken; parser.ExpectTokenString( "{" ); while( true ) { if( !parser.ReadToken( &token ) ) { parser.Error( "Unexpected end of file found while parsing weaponinfo!" ); } if( token == "}" ) { break; } if( !parser.ReadToken( &valueToken ) ) { parser.Error( "Failed to read value token, encountered EOF parsing weapon info!" ); } if( token == "number" ) { newWeaponInfo.number = valueToken.GetIntValue(); //weapon number } else if( token == "name" ) { newWeaponInfo.name = valueToken; //name of the weapon } else if( token == "level" ) { newWeaponInfo.level = valueToken.GetIntValue(); } else if( token == "model" ) { newWeaponInfo.model = valueToken; //model of the weapon } else if( token == "weaponindex" ) { newWeaponInfo.weaponindex = valueToken.GetIntValue(); //index of weapon in inventory } else if( token == "flags" ) { newWeaponInfo.flags = valueToken.GetIntValue(); //special flags } else if( token == "projectile" ) { newWeaponInfo.projectile = valueToken; //projectile used by the weapon } else if( token == "numprojectiles" ) { newWeaponInfo.numprojectiles = valueToken.GetIntValue(); //number of projectiles } else if( token == "hspread" ) { newWeaponInfo.hspread = valueToken.GetFloatValue(); //horizontal spread of projectiles (degrees from middle) } else if( token == "vspread" ) { newWeaponInfo.vspread = valueToken.GetFloatValue(); //vertical spread of projectiles (degrees from middle) } else if( token == "speed" ) { newWeaponInfo.speed = valueToken.GetFloatValue(); //speed of the projectile (0 = instant hit) } else { parser.Error( "ParseWeaponInfo: Unexpected token %s\n", token.c_str() ); } } } /* ======================== idBotWeaponInfoManager::LoadWeaponConfig ======================== */ void idBotWeaponInfoManager::LoadWeaponConfig( char* filename ) { idParser parser; idToken token; int j; if( !parser.LoadFile( filename ) ) { gameLocal.Error( "Failed to load bot weapon config %s\n", filename ); } while( parser.ReadToken( &token ) ) { if( token == "weaponinfo" ) { weaponinfo_t newWeaponInfo; ParseWeaponInfo( parser, newWeaponInfo ); if( newWeaponInfo.number < 0 || newWeaponInfo.number >= BOT_MAX_WEAPONS ) { parser.Error( "weapon info number %d out of range\n", newWeaponInfo.number ); return; } weaponinfo[newWeaponInfo.number] = newWeaponInfo; weaponinfo[newWeaponInfo.number].valid = true; } else if( token == "projectileinfo" ) { projectileinfo_t newProjectileInfo; ParseProjectileInfo( parser, newProjectileInfo ); projectileinfo.Append( newProjectileInfo ); } else { parser.Error( "LoadWeaponConfig: Unknown definintion %s", token.c_str() ); } } // fix up weapons. for( int i = 0; i < BOT_MAX_WEAPONS; i++ ) { if( !weaponinfo[i].valid ) { continue; } if( weaponinfo[i].name.Length() <= 0 ) { parser.Error( "weapon %d has no name\n", i ); return; } if( weaponinfo[i].projectile.Length() <= 0 ) { parser.Error( "weapon %s has no projectile\n", weaponinfo[i].name ); return; } //find the projectile info and copy it to the weapon info for( j = 0; j < projectileinfo.Num(); j++ ) { if( projectileinfo[j].name == weaponinfo[i].projectile ) { memcpy( &weaponinfo[i].proj, &projectileinfo[j], sizeof( projectileinfo_t ) ); break; } } if( j == projectileinfo.Num() ) { parser.Error( "weapon %s uses undefined projectile\n", weaponinfo[i].name.c_str() ); return; } } } /* ======================== idBotWeaponInfoManager::Init ======================== */ void idBotWeaponInfoManager::Init( void ) { rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER ); LoadWeaponConfig( ( char* )bot_weaponsfile.GetString() ); } /* ===================== WeaponWeightIndex ===================== */ void idBotWeaponInfoManager::WeaponWeightIndex( weightconfig_t* wwc, bot_weaponstate_t* weaponState ) { for( int i = 0; i < BOT_MAX_WEAPONS; i++ ) { weaponState->weaponweightindex[i] = botFuzzyWeightManager.FindFuzzyWeight( wwc, ( char* )weaponinfo[i].name.c_str() ); } } /* ===================== idBotWeaponInfoManager::WeaponWeightIndex ===================== */ void idBotWeaponInfoManager::BotFreeWeaponWeights( int weaponstate ) { bot_weaponstate_t* ws; ws = BotWeaponStateFromHandle( weaponstate ); if( !ws ) { return; } // if (ws->weaponweightconfig) // FreeWeightConfig(ws->weaponweightconfig); // if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex); } /* ===================== BotLoadWeaponWeights ===================== */ int idBotWeaponInfoManager::BotLoadWeaponWeights( int weaponstate, char* filename ) { bot_weaponstate_t* ws; ws = BotWeaponStateFromHandle( weaponstate ); if( !ws ) { return BLERR_CANNOTLOADWEAPONWEIGHTS; } BotFreeWeaponWeights( weaponstate ); ws->weaponweightconfig = botFuzzyWeightManager.ReadWeightConfig( filename ); if( !ws->weaponweightconfig ) { gameLocal.Error( "couldn't load weapon config %s\n", filename ); return BLERR_CANNOTLOADWEAPONWEIGHTS; } WeaponWeightIndex( ws->weaponweightconfig, ws ); return BLERR_NOERROR; } /* ===================== idBotWeaponInfoManager::BotGetWeaponInfo ===================== */ void idBotWeaponInfoManager::BotGetWeaponInfo( int weaponstate, int weapon, weaponinfo_t* weaponinfo ) { if( weaponinfo == NULL ) { return; } if( BotValidWeaponNumber( weapon ) && this->weaponinfo[weapon].valid ) { *weaponinfo = this->weaponinfo[weapon]; return; } // Fallback: return the first loaded weapon so callers never keep an // uninitialized weaponinfo_t when a bot has not picked a valid weapon yet. for( int i = 0; i < BOT_MAX_WEAPONS; i++ ) { if( this->weaponinfo[i].valid ) { *weaponinfo = this->weaponinfo[i]; return; } } } /* ===================== idBotWeaponInfoManager::BotChooseBestFightWeapon ===================== */ int idBotWeaponInfoManager::BotChooseBestFightWeapon( int weaponstate, int* inventory ) { int i, index, bestweapon; float weight, bestweight; bot_weaponstate_t* ws; ws = BotWeaponStateFromHandle( weaponstate ); if( !ws ) { return 0; } //if the bot has no weapon weight configuration if( !ws->weaponweightconfig ) { return 0; } bestweight = 0; bestweapon = 0; for( i = 0; i < BOT_MAX_WEAPONS; i++ ) { if( !weaponinfo[i].valid ) { continue; } index = ws->weaponweightindex[i]; if( index < 0 ) { continue; } weight = botFuzzyWeightManager.FuzzyWeight( inventory, ws->weaponweightconfig, index ); if( weight > bestweight ) { bestweight = weight; bestweapon = i; } } return bestweapon; } /* ===================== idBotWeaponInfoManager::BotResetWeaponState ===================== */ void idBotWeaponInfoManager::BotResetWeaponState( int weaponstate ) { weightconfig_t* weaponweightconfig; int* weaponweightindex; bot_weaponstate_t* ws; ws = BotWeaponStateFromHandle( weaponstate ); if( !ws ) { return; } weaponweightconfig = ws->weaponweightconfig; weaponweightindex = ws->weaponweightindex; //Com_Memset(ws, 0, sizeof(bot_weaponstate_t)); ws->weaponweightconfig = weaponweightconfig; memcpy( ws->weaponweightindex, weaponweightindex, sizeof( int ) * BOT_MAX_WEAPONS ); } /* ===================== idBotWeaponInfoManager::BotAllocWeaponState ===================== */ int idBotWeaponInfoManager::BotAllocWeaponState( void ) { int i; for( i = 1; i <= MAX_CLIENTS; i++ ) { if( !botweaponstates[i].inUse ) { botweaponstates[i].Reset(); botweaponstates[i].inUse = true; return i; } } return 0; } /* ===================== idBotWeaponInfoManager::BotAllocWeaponState ===================== */ void idBotWeaponInfoManager::BotFreeWeaponState( int ws ) { botweaponstates[ws].inUse = false; botweaponstates[ws].Reset(); }