void GameDLL_Version_f() { if (Q_stricmp(CMD_ARGV(1), "version") != 0) return; // print version CONSOLE_ECHO("ReGameDLL build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")\n"); CONSOLE_ECHO("ReGameDLL API version %i.%i\n", REGAMEDLL_API_VERSION_MAJOR, REGAMEDLL_API_VERSION_MINOR); CONSOLE_ECHO("Build from: " APP_COMMITS_URL APP_COMMIT_ID " " APP_COMMIT_AUTHOR "\n"); }
void CLocalNav::RequestNav(CHostage *pOwner) { if (nodeval > 17 || tot_inqueue) { if (tot_inqueue >= MAX_HOSTAGES) { CONSOLE_ECHO("queue full\n"); return; } int i = qptr; for (int j = 0; j < tot_inqueue; j++) { CHostage *pHostage = GetClassPtr((CHostage *)queue[i]->pev); if (pHostage == pOwner) return; if (++i == MAX_HOSTAGES) i = 0; } queue[i] = pOwner; tot_inqueue++; } else pOwner->NavReady(); }
/* <4f169d> ../game_shared/bot/nav_file.cpp:811 */ void LoadLocationFile(const char *filename) { char locFilename[256]; Q_strcpy(locFilename, filename); char *dot = Q_strchr(locFilename, '.'); if (dot) { Q_strcpy(dot, ".loc"); int locDataLength; char *locDataFile = (char *)LOAD_FILE_FOR_ME(const_cast<char *>(locFilename), &locDataLength); char *locData = locDataFile; if (locData) { CONSOLE_ECHO("Loading legacy 'location file' '%s'\n", locFilename); // read directory locData = MP_COM_Parse(locData); int dirSize = Q_atoi(MP_COM_GetToken()); if (dirSize) { std::vector<unsigned int> directory; directory.reserve(dirSize); for (int i = 0; i < dirSize; ++i) { locData = MP_COM_Parse(locData); directory.push_back(TheBotPhrases->NameToID(MP_COM_GetToken())); } // read places for each nav area unsigned int areaID, locDirIndex; while (true) { locData = MP_COM_Parse(locData); if (locData == NULL) break; areaID = Q_atoi(MP_COM_GetToken()); locData = MP_COM_Parse(locData); locDirIndex = Q_atoi(MP_COM_GetToken()); CNavArea *area = TheNavAreaGrid.GetNavAreaByID(areaID); unsigned int place = (locDirIndex > 0) ? directory[locDirIndex - 1] : UNDEFINED_PLACE; if (area) area->SetPlace(place); } } FREE_FILE(locDataFile); } } }
CLocalNav::CLocalNav(CHostage *pOwner) { m_pOwner = pOwner; m_pTargetEnt = NULL; m_nodeArr = new node_index_t[MAX_NODES]; #ifdef _DEBUG CONSOLE_ECHO("Allocated m_nodeArr: %d nodes, %lu bytes\n", MAX_NODES, sizeof(node_index_t) * MAX_NODES); #endif if (tot_hostages >= MAX_HOSTAGES) { #ifdef _DEBUG CONSOLE_ECHO("queue full (creation)\n"); #endif return; } hostages[tot_hostages++] = pOwner; }
/* <36b714> ../cstrike/dlls/bot/cs_bot_manager.cpp:464 */ void PrintAllEntities(void) { for (int i = 1; i < gpGlobals->maxEntities; i++) { edict_t *edict = INDEXENT(i); if (!edict || FStringNull(edict->v.classname)) continue; CONSOLE_ECHO(" %s\n", STRING(edict->v.classname)); } }
/* <3fd373> ../cstrike/dlls/bot/cs_gamestate.cpp:313 */ void CSGameState::UpdatePlantedBomb(const Vector *pos) { CCSBotManager *ctrl = TheCSBots(); const CCSBotManager::Zone *zone = ctrl->GetClosestZone(pos); if (zone == NULL) { CONSOLE_ECHO("ERROR: Bomb planted outside of a zone!\n"); m_plantedBombsite = UNKNOWN; } else { m_plantedBombsite = zone->m_index; } m_plantedBombPos = *pos; m_isPlantedBombPosKnown = true; SetBombState(PLANTED); }
int CLocalNav::PathClear(Vector &vecSource, Vector &vecDest, BOOL fNoMonsters, TraceResult &tr) { TRACE_MONSTER_HULL(m_pOwner->edict(), vecSource, vecDest, fNoMonsters, m_pOwner->edict(), &tr); if (tr.fStartSolid) return 0; if (tr.flFraction == 1) return 1; if (tr.pHit == m_pTargetEnt) { #ifdef _DEBUG CONSOLE_ECHO("target edict hit!\n"); #endif m_fTargetEntHit = TRUE; return 1; } return 0; }
/* <4f09b8> ../game_shared/bot/nav_file.cpp:212 */ void CNavArea::Save(int fd, unsigned int version) { // save ID Q_write(fd, &m_id, sizeof(unsigned int)); // save attribute flags Q_write(fd, &m_attributeFlags, sizeof(unsigned char)); // save extent of area Q_write(fd, &m_extent, 6 * sizeof(float)); // save heights of implicit corners Q_write(fd, &m_neZ, sizeof(float)); Q_write(fd, &m_swZ, sizeof(float)); // save connections to adjacent areas // in the enum order NORTH, EAST, SOUTH, WEST for (int d = 0; d < NUM_DIRECTIONS; ++d) { // save number of connections for this direction unsigned int count = m_connect[d].size(); Q_write(fd, &count, sizeof(unsigned int)); NavConnectList::const_iterator iter; for (iter = m_connect[d].begin(); iter != m_connect[d].end(); ++iter) { NavConnect connect = *iter; Q_write(fd, &connect.area->m_id, sizeof(unsigned int)); } } // Store hiding spots for this area unsigned char count; if (m_hidingSpotList.size() > 255) { count = 255; CONSOLE_ECHO("Warning: NavArea #%d: Truncated hiding spot list to 255\n", m_id); } else { count = m_hidingSpotList.size(); } Q_write(fd, &count, sizeof(unsigned char)); // store HidingSpot objects unsigned int saveCount = 0; for (HidingSpotList::iterator iter = m_hidingSpotList.begin(); iter != m_hidingSpotList.end(); ++iter) { HidingSpot *spot = *iter; spot->Save(fd, version); // overflow check if (++saveCount == count) break; } // Save the approach areas for this area // save number of approach areas Q_write(fd, &m_approachCount, sizeof(unsigned char)); if (cv_bot_debug.value > 0.0f) { CONSOLE_ECHO(" m_approachCount = %d\n", m_approachCount); } // save approach area info unsigned char type; unsigned int zero = 0; for (int a = 0; a < m_approachCount; ++a) { if (m_approach[a].here.area) Q_write(fd, &m_approach[a].here.area->m_id, sizeof(unsigned int)); else Q_write(fd, &zero, sizeof(unsigned int)); if (m_approach[a].prev.area) Q_write(fd, &m_approach[a].prev.area->m_id, sizeof(unsigned int)); else Q_write(fd, &zero, sizeof(unsigned int)); type = (unsigned char)m_approach[a].prevToHereHow; Q_write(fd, &type, sizeof(unsigned char)); if (m_approach[a].next.area) Q_write(fd, &m_approach[a].next.area->m_id, sizeof(unsigned int)); else Q_write(fd, &zero, sizeof(unsigned int)); type = (unsigned char)m_approach[a].hereToNextHow; Q_write(fd, &type, sizeof(unsigned char)); } // Save encounter spots for this area { // save number of encounter paths for this area unsigned int count = m_spotEncounterList.size(); Q_write(fd, &count, sizeof(unsigned int)); if (cv_bot_debug.value > 0.0f) CONSOLE_ECHO(" m_spotEncounterList.size() = %d\n", count); SpotEncounter *e; for (SpotEncounterList::iterator iter = m_spotEncounterList.begin(); iter != m_spotEncounterList.end(); ++iter) { e = &(*iter); if (e->from.area) Q_write(fd, &e->from.area->m_id, sizeof(unsigned int)); else Q_write(fd, &zero, sizeof(unsigned int)); unsigned char dir = e->fromDir; Q_write(fd, &dir, sizeof(unsigned char)); if (e->to.area) Q_write(fd, &e->to.area->m_id, sizeof(unsigned int)); else Q_write(fd, &zero, sizeof(unsigned int)); dir = e->toDir; Q_write(fd, &dir, sizeof(unsigned char)); // write list of spots along this path unsigned char spotCount; if (e->spotList.size() > 255) { spotCount = 255; CONSOLE_ECHO("Warning: NavArea #%d: Truncated encounter spot list to 255\n", m_id); } else { spotCount = e->spotList.size(); } Q_write(fd, &spotCount, sizeof(unsigned char)); saveCount = 0; for (SpotOrderList::iterator oiter = e->spotList.begin(); oiter != e->spotList.end(); ++oiter) { SpotOrder *order = &(*oiter); // order->spot may be NULL if we've loaded a nav mesh that has been edited but not re-analyzed unsigned int id = (order->spot) ? order->spot->GetID() : 0; Q_write(fd, &id, sizeof(unsigned int)); unsigned char t = 255 * order->t; Q_write(fd, &t, sizeof(unsigned char)); // overflow check if (++saveCount == spotCount) break; } } } // store place dictionary entry PlaceDirectory::EntryType entry = placeDirectory.GetEntry(GetPlace()); Q_write(fd, &entry, sizeof(entry)); }
/** * Load the bot profile database */ void BotProfileManager::Init( const char *filename, unsigned int *checksum ) { FileHandle_t file = filesystem->Open( filename, "r" ); if (!file) { if ( true ) // UTIL_IsGame( "czero" ) ) { CONSOLE_ECHO( "WARNING: Cannot access bot profile database '%s'\n", filename ); } return; } int dataLength = filesystem->Size( filename ); char *dataPointer = new char[ dataLength ]; int dataReadLength = filesystem->Read( dataPointer, dataLength, file ); filesystem->Close( file ); if ( dataReadLength > 0 ) { // NULL-terminate based on the length read in, since Read() can transform \r\n to \n and // return fewer bytes than we were expecting. dataPointer[ dataReadLength - 1 ] = 0; } const char *dataFile = dataPointer; // compute simple checksum if (checksum) { *checksum = 0; // ComputeSimpleChecksum( (const unsigned char *)dataPointer, dataLength ); } BotProfile defaultProfile; // // Parse the BotProfile.db into BotProfile instances // while( true ) { dataFile = SharedParse( dataFile ); if (!dataFile) break; char *token = SharedGetToken(); bool isDefault = (!stricmp( token, "Default" )); bool isTemplate = (!stricmp( token, "Template" )); bool isCustomSkin = (!stricmp( token, "Skin" )); if ( isCustomSkin ) { const int BufLen = 64; char skinName[BufLen]; // get skin name dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected skin name\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); Q_snprintf( skinName, sizeof( skinName ), "%s", token ); // get attribute name dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (stricmp( "Model", token )) { CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename ); delete [] dataPointer; return; } // eat '=' dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "=", token )) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } // get attribute value dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); const char *decoratedName = GetDecoratedSkinName( skinName, filename ); bool skinExists = GetCustomSkinIndex( decoratedName ) > 0; if ( m_nextSkin < NumCustomSkins && !skinExists ) { // decorate the name m_skins[ m_nextSkin ] = CloneString( decoratedName ); // construct the model filename m_skinModelnames[ m_nextSkin ] = CloneString( token ); m_skinFilenames[ m_nextSkin ] = new char[ strlen(token)*2 + strlen("models/player//.mdl") + 1 ]; Q_snprintf( m_skinFilenames[ m_nextSkin ], sizeof( m_skinFilenames[ m_nextSkin ] ), "models/player/%s/%s.mdl", token, token ); ++m_nextSkin; } // eat 'End' dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "End", token )) { CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename ); delete [] dataPointer; return; } continue; // it's just a custom skin - no need to do inheritance on a bot profile, etc. } // encountered a new profile BotProfile *profile; if (isDefault) { profile = &defaultProfile; } else { profile = new BotProfile; // always inherit from Default *profile = defaultProfile; } // do inheritance in order of appearance if (!isTemplate && !isDefault) { const BotProfile *inherit = NULL; // template names are separated by "+" while(true) { char *c = strchr( token, '+' ); if (c) *c = '\000'; // find the given template name FOR_EACH_LL( m_templateList, it ) { BotProfile *profile = m_templateList[ it ]; if (!stricmp( profile->GetName(), token )) { inherit = profile; break; } } if (inherit == NULL) { CONSOLE_ECHO( "Error parsing '%s' - invalid template reference '%s'\n", filename, token ); delete [] dataPointer; return; } // inherit the data profile->Inherit( inherit, &defaultProfile ); if (c == NULL) break; token = c+1; } } // get name of this profile if (!isDefault) { dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing '%s' - expected name\n", filename ); delete [] dataPointer; return; } profile->m_name = CloneString( SharedGetToken() ); /** * HACK HACK * Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's * preference towards silencers based on his name. */ if ( profile->m_name[0] % 2 ) { profile->m_prefersSilencer = true; } } // read attributes for this profile bool isFirstWeaponPref = true; while( true ) { // get next token dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); // check for End delimiter if (!stricmp( token, "End" )) break; // found attribute name - keep it char attributeName[64]; strcpy( attributeName, token ); // eat '=' dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "=", token )) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } // get attribute value dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); // store value in appropriate attribute if (!stricmp( "Aggression", attributeName )) { profile->m_aggression = (float)atof(token) / 100.0f; } else if (!stricmp( "Skill", attributeName )) { profile->m_skill = (float)atof(token) / 100.0f; } else if (!stricmp( "Skin", attributeName )) { profile->m_skin = atoi(token); if ( profile->m_skin == 0 ) { // atoi() failed - try to look up a custom skin by name profile->m_skin = GetCustomSkinIndex( token, filename ); } } else if (!stricmp( "Teamwork", attributeName )) { profile->m_teamwork = (float)atof(token) / 100.0f; } else if (!stricmp( "Cost", attributeName )) { profile->m_cost = atoi(token); } else if (!stricmp( "VoicePitch", attributeName )) { profile->m_voicePitch = atoi(token); } else if (!stricmp( "VoiceBank", attributeName )) { profile->m_voiceBank = FindVoiceBankIndex( token ); } else if (!stricmp( "WeaponPreference", attributeName )) { // weapon preferences override parent prefs if (isFirstWeaponPref) { isFirstWeaponPref = false; profile->m_weaponPreferenceCount = 0; } if (!stricmp( token, "none" )) { profile->m_weaponPreferenceCount = 0; } else { if (profile->m_weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS) { profile->m_weaponPreference[ profile->m_weaponPreferenceCount++ ] = AliasToWeaponID( token ); } } } else if (!stricmp( "ReactionTime", attributeName )) { profile->m_reactionTime = (float)atof(token); #ifndef GAMEUI_EXPORTS // subtract off latency due to "think" update rate. // In GameUI, we don't really care. //profile->m_reactionTime -= g_BotUpdateInterval; #endif } else if (!stricmp( "AttackDelay", attributeName )) { profile->m_attackDelay = (float)atof(token); } else if (!stricmp( "Difficulty", attributeName )) { // override inheritance profile->m_difficultyFlags = 0; // parse bit flags while(true) { char *c = strchr( token, '+' ); if (c) *c = '\000'; for( int i=0; i<NUM_DIFFICULTY_LEVELS; ++i ) if (!stricmp( BotDifficultyName[i], token )) profile->m_difficultyFlags |= (1 << i); if (c == NULL) break; token = c+1; } } else if (!stricmp( "Team", attributeName )) { if ( !stricmp( token, "T" ) ) { profile->m_teams = TEAM_TERRORIST; } else if ( !stricmp( token, "CT" ) ) { profile->m_teams = TEAM_CT; } else { profile->m_teams = TEAM_UNASSIGNED; } } else { CONSOLE_ECHO( "Error parsing %s - unknown attribute '%s'\n", filename, attributeName ); } } if (!isDefault) { if (isTemplate) { // add to template list m_templateList.AddToTail( profile ); } else { // add profile to the master list m_profileList.AddToTail( profile ); } } }
/* <4f19c7> ../game_shared/bot/nav_file.cpp:947 */ NavErrorType LoadNavigationMap() { // since the navigation map is destroyed on map change, // if it exists it has already been loaded for this map if (!TheNavAreaList.empty()) return NAV_OK; // nav filename is derived from map filename char filename[256]; Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname)); // free previous navigation map data DestroyNavigationMap(); placeDirectory.Reset(); IMPL_CLASS(CNavArea, m_nextID) = 1; SteamFile navFile(filename); if (!navFile.IsValid()) return NAV_CANT_ACCESS_FILE; // check magic number bool result; unsigned int magic; result = navFile.Read(&magic, sizeof(unsigned int)); if (!result || magic != NAV_MAGIC_NUMBER) { CONSOLE_ECHO("ERROR: Invalid navigation file '%s'.\n", filename); return NAV_INVALID_FILE; } // read file version number unsigned int version; result = navFile.Read(&version, sizeof(unsigned int)); if (!result || version > 5) { CONSOLE_ECHO("ERROR: Unknown navigation file version.\n"); return NAV_BAD_FILE_VERSION; } if (version >= 4) { // get size of source bsp file and verify that the bsp hasn't changed unsigned int saveBspSize; navFile.Read(&saveBspSize, sizeof(unsigned int)); // verify size char *bspFilename = GetBspFilename(filename); if (bspFilename == NULL) return NAV_INVALID_FILE; unsigned int bspSize = (unsigned int)GET_FILE_SIZE(bspFilename); if (bspSize != saveBspSize) { // this nav file is out of date for this bsp file char *msg = "*** WARNING ***\nThe AI navigation data is from a different version of this map.\nThe CPU players will likely not perform well.\n"; HintMessageToAllPlayers(msg); CONSOLE_ECHO("\n-----------------\n"); CONSOLE_ECHO(msg); CONSOLE_ECHO("-----------------\n\n"); } } // load Place directory if (version >= 5) { placeDirectory.Load(&navFile); } // get number of areas unsigned int count; result = navFile.Read(&count, sizeof(unsigned int)); Extent extent; extent.lo.x = 9999999999.9f; extent.lo.y = 9999999999.9f; extent.hi.x = -9999999999.9f; extent.hi.y = -9999999999.9f; // load the areas and compute total extent for (unsigned int i = 0; i < count; ++i) { CNavArea *area = new CNavArea; area->Load(&navFile, version); TheNavAreaList.push_back(area); const Extent *areaExtent = area->GetExtent(); // check validity of nav area if (areaExtent->lo.x >= areaExtent->hi.x || areaExtent->lo.y >= areaExtent->hi.y) CONSOLE_ECHO("WARNING: Degenerate Navigation Area #%d at ( %g, %g, %g )\n", area->GetID(), area->m_center.x, area->m_center.y, area->m_center.z); if (areaExtent->lo.x < extent.lo.x) extent.lo.x = areaExtent->lo.x; if (areaExtent->lo.y < extent.lo.y) extent.lo.y = areaExtent->lo.y; if (areaExtent->hi.x > extent.hi.x) extent.hi.x = areaExtent->hi.x; if (areaExtent->hi.y > extent.hi.y) extent.hi.y = areaExtent->hi.y; } // add the areas to the grid TheNavAreaGrid.Initialize(extent.lo.x, extent.hi.x, extent.lo.y, extent.hi.y); NavAreaList::iterator iter; for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) TheNavAreaGrid.AddNavArea(*iter); // allow areas to connect to each other, etc for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { CNavArea *area = *iter; area->PostLoad(); } // load legacy location file (Places) if (version < 5) { LoadLocationFile(filename); } // Set up all the ladders BuildLadders(); return NAV_OK; }
/* <36c3c2> ../cstrike/dlls/bot/cs_bot_manager.cpp:903 */ NOBODY bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole) { if (IMPLEMENT_ARRAY(m_isLearningMap) || ENG_CHECK_PARM("-nobots", NULL)) return false; const BotProfile *profile = NULL; if (!isFromConsole || CMD_ARGC() < 2) { if (team == BOT_TEAM_ANY) { // if team not specified, check cv_bot_join_team cvar for preference if (!Q_stricmp(cv_bot_join_team.string, "T")) team = BOT_TEAM_T; else if (!Q_stricmp(cv_bot_join_team.string, "CT")) team = BOT_TEAM_CT; else { TeamName defaultTeam = SelectDefaultTeam(); if (defaultTeam == TERRORIST) team = BOT_TEAM_T; else if (defaultTeam == CT) team = BOT_TEAM_CT; } } // try to add a bot by name profile = TheBotProfiles->GetRandomProfile(GetDifficultyLevel(), team); if (profile == NULL) { CONSOLE_ECHO("All bot profiles at this difficulty level are in use.\n"); return true; } } else { // in career, ignore humans bool ignoreHumans = false; CHalfLifeMultiplay *mp = g_pGameRules; if (mp && mp->IsCareer()) ignoreHumans = true; if (UTIL_IsNameTaken(CMD_ARGV(1), ignoreHumans)) { CONSOLE_ECHO("Error - %s is already in the game.\n", CMD_ARGV(1)); return true; } profile = TheBotProfiles->GetProfile(CMD_ARGV(1), team); if (profile == NULL) { CONSOLE_ECHO("Error - no profile for '%s' exists.\n", CMD_ARGV(1)); return true; } } // create the bot if (CCSBotManager::AddBot(profile, team)) // TODO: Reverse me { if (isFromConsole) { // increase the bot quota to account for manually added bot CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value + 1); } } return true; }
/* <36ace2> ../cstrike/dlls/bot/cs_bot_manager.cpp:484 */ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd) { if (!m_bServerActive || !UTIL_IsGame("czero")) return; char buffer[400]; const char *msg = CMD_ARGV(1); if (FStrEq(pcmd, "bot_about")) { Q_sprintf(buffer, "\n--------------------------------------------------------------------------\nThe Official Counter-Strike Bot V%d.%02d\nCreated by Michael S. Booth\nWeb: www.turtlerockstudios.com\\csbot\nE-mail: [email protected]\n--------------------------------------------------------------------------\n\n", CSBOT_VERSION_MAJOR, CSBOT_VERSION_MINOR); CONSOLE_ECHO(buffer); HintMessageToAllPlayers(buffer); } else if (FStrEq(pcmd, "bot_add")) { BotAddCommand(BOT_TEAM_ANY); } else if (FStrEq(pcmd, "bot_add_t")) { BotAddCommand(BOT_TEAM_T); } else if (FStrEq(pcmd, "bot_add_ct")) { BotAddCommand(BOT_TEAM_CT); } else if (FStrEq(pcmd, "bot_kill")) { bool killThemAll; if (CMD_ARGC() == 1 || FStrEq(msg, "all")) killThemAll = true; else killThemAll = false; for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) { CBasePlayer *pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(iIndex); if (pPlayer == NULL) continue; if (FNullEnt(pPlayer->pev)) continue; const char *name = STRING(pPlayer->pev->netname); if (FStrEq(name, "")) continue; if (pPlayer->IsBot()) { if (killThemAll || FStrEq(name, msg)) { pPlayer->TakeDamage(pPlayer->pev, pPlayer->pev, 9999.9f, DMG_CRUSH); } } } } else if (FStrEq(pcmd, "bot_kick")) { bool kickThemAll; if (CMD_ARGC() == 1 || FStrEq(msg, "all")) kickThemAll = true; else kickThemAll = false; for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) { CBasePlayer *pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(iIndex); if (pPlayer == NULL) continue; if (FNullEnt(pPlayer->pev)) continue; const char *name = STRING(pPlayer->pev->netname); if (FStrEq(name, "")) continue; if (pPlayer->IsBot()) { if (kickThemAll || FStrEq(name, msg)) { SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", name)); CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1); } } } if (kickThemAll || cv_bot_quota.value < 0.0f) { CVAR_SET_FLOAT("bot_quota", 0); } } else if (FStrEq(pcmd, "bot_knives_only")) { CVAR_SET_FLOAT("bot_allow_pistols", 0); CVAR_SET_FLOAT("bot_allow_shotguns", 0); CVAR_SET_FLOAT("bot_allow_sub_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_rifles", 0); CVAR_SET_FLOAT("bot_allow_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_grenades", 0); CVAR_SET_FLOAT("bot_allow_snipers", 0); CVAR_SET_FLOAT("bot_allow_shield", 0); } else if (FStrEq(pcmd, "bot_pistols_only")) { CVAR_SET_FLOAT("bot_allow_pistols", 1); CVAR_SET_FLOAT("bot_allow_shotguns", 0); CVAR_SET_FLOAT("bot_allow_sub_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_rifles", 0); CVAR_SET_FLOAT("bot_allow_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_grenades", 0); CVAR_SET_FLOAT("bot_allow_snipers", 0); CVAR_SET_FLOAT("bot_allow_shield", 0); } else if (FStrEq(pcmd, "bot_snipers_only")) { CVAR_SET_FLOAT("bot_allow_pistols", 1); CVAR_SET_FLOAT("bot_allow_shotguns", 0); CVAR_SET_FLOAT("bot_allow_sub_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_rifles", 0); CVAR_SET_FLOAT("bot_allow_machine_guns", 0); CVAR_SET_FLOAT("bot_allow_grenades", 0); CVAR_SET_FLOAT("bot_allow_snipers", 1); CVAR_SET_FLOAT("bot_allow_shield", 0); } else if (FStrEq(pcmd, "bot_all_weapons")) { CVAR_SET_FLOAT("bot_allow_pistols", 1); CVAR_SET_FLOAT("bot_allow_shotguns", 1); CVAR_SET_FLOAT("bot_allow_sub_machine_guns", 1); CVAR_SET_FLOAT("bot_allow_rifles", 1); CVAR_SET_FLOAT("bot_allow_machine_guns", 1); CVAR_SET_FLOAT("bot_allow_grenades", 1); CVAR_SET_FLOAT("bot_allow_snipers", 1); CVAR_SET_FLOAT("bot_allow_shield", 1); } else if (FStrEq(pcmd, "entity_dump")) { PrintAllEntities(); } else if (FStrEq(pcmd, "bot_nav_delete")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_DELETE; } else if (FStrEq(pcmd, "bot_nav_split")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_SPLIT; } else if (FStrEq(pcmd, "bot_nav_merge")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_MERGE; } else if (FStrEq(pcmd, "bot_nav_mark")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_MARK; } else if (FStrEq(pcmd, "bot_nav_begin_area")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_BEGIN_AREA; } else if (FStrEq(pcmd, "bot_nav_end_area")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_END_AREA; } else if (FStrEq(pcmd, "bot_nav_connect")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_CONNECT; } else if (FStrEq(pcmd, "bot_nav_disconnect")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_DISCONNECT; } else if (FStrEq(pcmd, "bot_nav_splice")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_SPLICE; } else if (FStrEq(pcmd, "bot_nav_crouch")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_CROUCH; } else if (FStrEq(pcmd, "bot_nav_jump")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_JUMP; } else if (FStrEq(pcmd, "bot_nav_precise")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_PRECISE; } else if (FStrEq(pcmd, "bot_nav_no_jump")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_NO_JUMP; } else if (FStrEq(pcmd, "bot_nav_analyze")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_isAnalysisRequested) = true; } else if (FStrEq(pcmd, "bot_nav_strip")) { StripNavigationAreas();// TODO: reverse me } else if (FStrEq(pcmd, "bot_nav_save")) { GET_GAME_DIR(buffer); buffer[ Q_strlen(buffer) ] = '\\'; Q_strcat(buffer, CBotManager::GetNavMapFilename()); if (SaveNavigationMap(buffer))// TODO: reverse me CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer); else CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer); } else if (FStrEq(pcmd, "bot_nav_load")) { ValidateMapData(); } else if (FStrEq(pcmd, "bot_nav_use_place")) { if (CMD_ARGC() == 1) { int i = 0; const BotPhraseList *placeList = TheBotPhrases->GetPlaceList(); for (BotPhraseList::const_iterator iter = placeList->begin(); iter != placeList->end(); ++iter, i++) { if ((*iter)->GetID() == GetNavPlace()) CONSOLE_ECHO("--> %-26s", (*iter)->GetName()); else CONSOLE_ECHO("%-30s", (*iter)->GetName()); if (!(i % 3)) CONSOLE_ECHO("\n"); } CONSOLE_ECHO("\n"); } else { const BotPhraseList *placeList = TheBotPhrases->GetPlaceList(); const BotPhrase *found = NULL; bool isAmbiguous = false; for (BotPhraseList::const_iterator iter = placeList->begin(); iter != placeList->end(); ++iter) { if (!Q_strnicmp((*iter)->GetName(), msg, Q_strlen(msg))) { if (!Q_strcmp((*iter)->GetName(), msg)) { found = (*iter); break; } if (found != NULL) isAmbiguous = true; else found = (*iter); } } if (isAmbiguous) { CONSOLE_ECHO("Ambiguous\n"); return; } if (found != NULL) { CONSOLE_ECHO("Current place set to '%s'\n", found->GetName()); m_navPlace = found->GetID(); } } } else if (FStrEq(pcmd, "bot_nav_toggle_place_mode")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_TOGGLE_PLACE_MODE; } else if (FStrEq(pcmd, "bot_nav_place_floodfill")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_PLACE_FLOODFILL; } else if (FStrEq(pcmd, "bot_nav_place_pick")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_PLACE_PICK; } else if (FStrEq(pcmd, "bot_nav_toggle_place_painting")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_TOGGLE_PLACE_PAINTING; } else if (FStrEq(pcmd, "bot_goto_mark")) { // tell the first bot we find to go to our marked area CNavArea *area = GetMarkedArea();// TODO: reverse me if (area != NULL) { CBaseEntity *pEntity = NULL; while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")) != NULL) { if (!pEntity->IsPlayer()) continue; if ((pEntity->pev->flags & FL_DORMANT) == FL_DORMANT) continue; CBasePlayer *playerOrBot = GetClassPtr((CBasePlayer *)pEntity->pev); if (playerOrBot->IsBot()) { CCSBot *bot = reinterpret_cast<CCSBot *>(playerOrBot); bot->MoveTo(&area->m_center, FASTEST_ROUTE);// TODO: reverse me return; } } } } else if (FStrEq(pcmd, "bot_memory_usage")) { CONSOLE_ECHO("Memory usage:\n"); CONSOLE_ECHO(" %d bytes per bot\b", sizeof(CCSBot)); CONSOLE_ECHO(" %d Navigation Areas @ %d bytes each = %d bytes\n", TheNavAreaGrid.GetNavAreaCount(), sizeof(CNavArea), TheNavAreaGrid.GetNavAreaCount() * sizeof(CNavArea)); CONSOLE_ECHO(" %d Hiding Spots @ %d bytes each = %d bytes\n", TheHidingSpotList.size(), sizeof(HidingSpot), sizeof(HidingSpot) * TheHidingSpotList.size()); unsigned int encounterMem = 0; for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { CNavArea *area = (*iter); for (SpotEncounterList::iterator siter = area->m_spotEncounterList.begin(); siter != area->m_spotEncounterList.end(); ++siter) { // TODO: Fix me, this is crashed in HOOK_GAMEDLL SpotEncounter se = (*siter); encounterMem += sizeof(SpotEncounter); encounterMem += sizeof(SpotOrder) * se.spotList.size(); } } CONSOLE_ECHO(" Encounter Spot data = %d bytes\n", encounterMem); } else if (FStrEq(pcmd, "bot_nav_mark_unnamed")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_MARK_UNNAMED; } else if (FStrEq(pcmd, "bot_nav_warp")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_WARP_TO_MARK; } else if (FStrEq(pcmd, "bot_nav_corner_select")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_SELECT_CORNER; } else if (FStrEq(pcmd, "bot_nav_corner_raise")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_RAISE_CORNER; } else if (FStrEq(pcmd, "bot_nav_corner_lower")) { IMPLEMENT_ARRAY_CLASS(CCSBotManager, m_editCmd) = EDIT_LOWER_CORNER; } else if (FStrEq(pcmd, "bot_nav_check_consistency")) { if (CMD_ARGC() != 2) { CONSOLE_ECHO("usage: bot_nav_check_consistency <filename>\n"); return; } SanityCheckNavigationMap(msg);// TODO: reverse me } }
/* <43c197> ../cstrike/dlls/hostage/states/hostage_idle.cpp:23 */ void HostageIdleState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { if (!UTIL_ActivePlayersInGame()) return; if (m_mustFlee || (improv->IsScared() && !improv->IsTerroristNearby() && m_moveState != Moving)) { if (!m_mustFlee && improv->GetScareIntensity() == CHostageImprov::TERRIFIED) m_mustFlee = true; if ((improv->GetScareIntensity() == CHostageImprov::TERRIFIED || m_mustFlee) || (m_fleeTimer.IsElapsed() && improv->GetScareIntensity() > CHostageImprov::NERVOUS)) { m_fleeTimer.Start(RANDOM_FLOAT(10, 20)); const float fleeChance = 33.3f; const float terroristRecentTime = 5.0f; if (!m_mustFlee && improv->GetTimeSinceLastSawPlayer(TERRORIST) > terroristRecentTime && RANDOM_FLOAT(0, 100) < fleeChance) m_mustFlee = true; if (m_mustFlee) { m_mustFlee = false; const Vector *spot = FindNearbyRetreatSpot(NULL, &improv->GetFeet(), improv->GetLastKnownArea(), 500.0, TERRORIST, false); if (spot != NULL) { improv->MoveTo(*spot); improv->Run(); m_moveState = Moving; if (improv->GetScareIntensity() == CHostageImprov::TERRIFIED) { improv->Frighten(CHostageImprov::SCARED); } return; } } } } if (m_moveState && improv->IsAtMoveGoal()) { m_moveState = NotMoving; improv->Stop(); improv->FaceOutwards(); const float crouchChance = 33.3f; if (improv->IsScared() && !improv->IsAtHome() && RANDOM_FLOAT(0, 100) <= crouchChance) { improv->Crouch(); } return; } if (m_moveState == Moving) { improv->Run(); return; } if (!improv->IsAtMoveGoal(75.0f)) { improv->Walk(); m_moveState = Moving; return; } CBasePlayer *rescuer = improv->GetClosestVisiblePlayer(CT); CBasePlayer *captor = improv->GetClosestVisiblePlayer(TERRORIST); if (rescuer != NULL) { improv->LookAt(rescuer->EyePosition()); improv->Stop(); if (captor != NULL) { const float attentionRange = 700.0f; float rangeT = (improv->GetCentroid() - captor->pev->origin).Length(); if (rangeT < attentionRange) { const float cosTolerance = 0.95f; if (improv->IsAnyPlayerLookingAtMe(TERRORIST, cosTolerance)) { improv->LookAt(captor->EyePosition()); } else { TraceResult result; UTIL_TraceLine(rescuer->pev->origin, captor->pev->origin, ignore_monsters, ignore_glass, captor->edict(), &result); if (result.flFraction != 1.0f && m_disagreeTimer.IsElapsed()) { improv->Disagree(); m_disagreeTimer.Start(RANDOM_FLOAT(2, 4)); } } return; } } else if (!TheCSBots()->IsRoundOver() && m_askTimer.IsElapsed()) { const float closeRange = 200.0f; if ((rescuer->pev->origin - improv->GetCentroid()).IsLengthLessThan(closeRange)) { if (improv->IsPlayerLookingAtMe(rescuer, 0.99)) { HostageChatterType say; if (improv->IsTerroristNearby()) say = HOSTAGE_CHATTER_WARN_NEARBY; else say = HOSTAGE_CHATTER_PLEASE_RESCUE_ME; improv->Chatter(say, false); m_askTimer.Start(RANDOM_FLOAT(3, 10)); } } } if (m_waveTimer.IsElapsed()) { CHostage *hostage = improv->GetEntity(); const float waveRange = 250.0f; if ((rescuer->pev->origin - hostage->pev->origin).IsLengthGreaterThan(waveRange)) { improv->Stop(); improv->Wave(); improv->LookAt(rescuer->EyePosition()); improv->Chatter(HOSTAGE_CHATTER_CALL_TO_RESCUER, false); m_moveState = NotMoving; m_waveTimer.Start(RANDOM_FLOAT(10, 20)); } } } else if (captor != NULL) { improv->LookAt(captor->EyePosition()); improv->Stop(); const float closeRange = 200.0f; if ((captor->pev->origin - improv->GetCentroid()).IsLengthLessThan(closeRange) && improv->IsPlayerLookingAtMe(captor, 0.99)) { if (!m_intimidatedTimer.HasStarted()) { m_intimidatedTimer.Start(); } if (!improv->IsScared()) { improv->Frighten(CHostageImprov::NERVOUS); } const float minThreatenTime = 1.0f; if ((!m_intimidatedTimer.HasStarted() || m_intimidatedTimer.IsGreaterThen(minThreatenTime)) && m_pleadTimer.IsElapsed()) { improv->Chatter(HOSTAGE_CHATTER_INTIMIDATED, true); m_pleadTimer.Start(RANDOM_FLOAT(10, 20)); } if (!improv->IsAtHome()) { improv->Chatter(HOSTAGE_CHATTER_RETREAT, true); improv->Retreat(); } } else { m_intimidatedTimer.Invalidate(); } } else { improv->ClearLookAt(); const float pushbackRange = 60.0f; if (pushbackRange - improv->GetAggression() * 5.0f < TheCSBots()->GetElapsedRoundTime() && m_escapeTimer.IsElapsed()) { const float stayHomeDuration = 5.0f; m_escapeTimer.Start(stayHomeDuration); float sightTimeT = improv->GetTimeSinceLastSawPlayer(TERRORIST); float sightTimeCT = improv->GetTimeSinceLastSawPlayer(CT); const float waitTime = 15.0f - improv->GetAggression() * 3.0f; if (sightTimeT > waitTime && sightTimeCT > waitTime) { if (improv->IsTerroristNearby()) { if (cv_hostage_debug.value > 0.0f) { CONSOLE_ECHO("Hostage: I want to escape, but a T is nearby\n"); } m_escapeTimer.Start(waitTime); } else { improv->Escape(); if (cv_hostage_debug.value > 0.0f) { CONSOLE_ECHO("Hostage: I'm escaping!\n"); } } } } } }
void CHostageImprov::__MAKE_VHOOK(OnTouch)(CBaseEntity *other) { const char *classname; Vector2D to; const float pushForce = 20.0f; classname = STRING(other->pev->classname); if (cv_hostage_debug.value != 0.0) { CONSOLE_ECHO("%5.1f: Hostage hit '%s'\n", gpGlobals->time, classname); } m_collisionTimer.Start(); if (FStrEq(classname, "worldspawn")) { const float lookAheadRange = 30.0f; float ground; Vector normal = Vector(0, 0, 1); Vector alongFloor; TraceResult result; bool isStep = false; UTIL_MakeVectors(m_hostage->pev->angles); if (!GetSimpleGroundHeightWithFloor(&GetEyes(), &ground, &normal)) return; if (cv_hostage_debug.value < 0.0) { UTIL_DrawBeamPoints(GetFeet() + normal * 50, GetFeet(), 2, 255, 255, 0); } alongFloor = CrossProduct(normal, gpGlobals->v_right); Vector pos = alongFloor * lookAheadRange; for (float_precision offset = 1.0f; offset <= 18.0f; offset += 3.0f) { Vector vecStart = GetFeet(); vecStart.z += offset; UTIL_TraceLine(vecStart, vecStart + pos, ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && result.vecPlaneNormal.z < MaxUnitZSlope) { isStep = true; break; } } if (isStep) { float stepAheadGround = pos.z; Vector stepAheadNormal = Vector(0, 0, stepAheadGround); m_inhibitObstacleAvoidance.Start(0.5); for (float range = 1.0f; range <= 30.5f; range += 5.0f) { Vector stepAhead = GetFeet() + alongFloor * range; stepAhead.z = GetEyes().z; if (GetSimpleGroundHeightWithFloor(&stepAhead, &stepAheadGround, &stepAheadNormal)) { float dz = stepAheadGround - GetFeet().z; if (dz > 0.0f && dz < 18.0f) { m_hostage->pev->origin.z = stepAheadGround + 3.0f; break; } } } } else if (!IsMoving() && !IsUsingLadder()) { bool isSeam = false; const float checkSeamRange = 50.0f; Vector posBehind; posBehind = GetEyes() - alongFloor * checkSeamRange; UTIL_TraceLine(posBehind, posBehind - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) { isSeam = true; } else { Vector posAhead = GetEyes() + alongFloor * checkSeamRange; UTIL_TraceLine(posAhead, posAhead - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) isSeam = true; } if (isSeam) { if (cv_hostage_debug.value != 0.0) { CONSOLE_ECHO("Hostage stuck on seam.\n"); } const float nudge = 3.0f; m_hostage->pev->origin.z += nudge; } } } else if (FStrEq(classname, "func_breakable")) { other->TakeDamage(m_hostage->pev, m_hostage->pev, 9999.9, DMG_BULLET); } else if (other->IsPlayer() || FClassnameIs(other->pev, "hostage_entity")) { to = (m_hostage->pev->origin - other->pev->origin).Make2D(); to.NormalizeInPlace(); m_vel.x += to.x * pushForce; m_vel.y += to.y * pushForce; } }
void EXT_FUNC GameDLLInit() { g_psv_gravity = CVAR_GET_POINTER("sv_gravity"); g_psv_aim = CVAR_GET_POINTER("sv_aim"); g_footsteps = CVAR_GET_POINTER("mp_footsteps"); g_psv_accelerate = CVAR_GET_POINTER("sv_accelerate"); g_psv_friction = CVAR_GET_POINTER("sv_friction"); g_psv_stopspeed = CVAR_GET_POINTER("sv_stopspeed"); CVAR_REGISTER(&displaysoundlist); CVAR_REGISTER(&timelimit); CVAR_REGISTER(&friendlyfire); CVAR_REGISTER(&flashlight); CVAR_REGISTER(&decalfrequency); CVAR_REGISTER(&allowmonsters); CVAR_REGISTER(&roundtime); CVAR_REGISTER(&buytime); CVAR_REGISTER(&freezetime); CVAR_REGISTER(&c4timer); CVAR_REGISTER(&ghostfrequency); CVAR_REGISTER(&autokick); CVAR_REGISTER(&autokick_timeout); CVAR_REGISTER(&restartround); CVAR_REGISTER(&sv_restart); CVAR_REGISTER(&limitteams); CVAR_REGISTER(&autoteambalance); CVAR_REGISTER(&tkpunish); CVAR_REGISTER(&hostagepenalty); CVAR_REGISTER(&mirrordamage); CVAR_REGISTER(&logmessages); CVAR_REGISTER(&forcecamera); CVAR_REGISTER(&forcechasecam); CVAR_REGISTER(&mapvoteratio); CVAR_REGISTER(&maxrounds); CVAR_REGISTER(&winlimit); CVAR_REGISTER(&windifference); CVAR_REGISTER(&fadetoblack); CVAR_REGISTER(&logdetail); CVAR_REGISTER(&startmoney); CVAR_REGISTER(&playerid); CVAR_REGISTER(&allow_spectators); CVAR_REGISTER(&mp_chattime); CVAR_REGISTER(&kick_percent); CVAR_REGISTER(&fragsleft); CVAR_REGISTER(&timeleft); CVAR_REGISTER(&humans_join_team); // Remove unused cvars #ifndef REGAMEDLL_FIXES CVAR_REGISTER(&sk_plr_9mm_bullet1); CVAR_REGISTER(&sk_plr_9mm_bullet2); CVAR_REGISTER(&sk_plr_9mm_bullet3); CVAR_REGISTER(&sk_plr_357_bullet1); CVAR_REGISTER(&sk_plr_357_bullet2); CVAR_REGISTER(&sk_plr_357_bullet3); CVAR_REGISTER(&sk_plr_9mmAR_bullet1); CVAR_REGISTER(&sk_plr_9mmAR_bullet2); CVAR_REGISTER(&sk_plr_9mmAR_bullet3); CVAR_REGISTER(&sk_plr_9mmAR_grenade1); CVAR_REGISTER(&sk_plr_9mmAR_grenade2); CVAR_REGISTER(&sk_plr_9mmAR_grenade3); CVAR_REGISTER(&sk_plr_buckshot1); CVAR_REGISTER(&sk_plr_buckshot2); CVAR_REGISTER(&sk_plr_buckshot3); CVAR_REGISTER(&sk_plr_rpg1); CVAR_REGISTER(&sk_plr_rpg2); CVAR_REGISTER(&sk_plr_rpg3); CVAR_REGISTER(&sk_12mm_bullet1); CVAR_REGISTER(&sk_12mm_bullet2); CVAR_REGISTER(&sk_12mm_bullet3); CVAR_REGISTER(&sk_9mmAR_bullet1); CVAR_REGISTER(&sk_9mmAR_bullet2); CVAR_REGISTER(&sk_9mmAR_bullet3); CVAR_REGISTER(&sk_9mm_bullet1); CVAR_REGISTER(&sk_9mm_bullet2); CVAR_REGISTER(&sk_9mm_bullet3); CVAR_REGISTER(&sk_suitcharger1); CVAR_REGISTER(&sk_suitcharger2); CVAR_REGISTER(&sk_suitcharger3); CVAR_REGISTER(&sk_battery1); CVAR_REGISTER(&sk_battery2); CVAR_REGISTER(&sk_battery3); CVAR_REGISTER(&sk_healthcharger1); CVAR_REGISTER(&sk_healthcharger2); CVAR_REGISTER(&sk_healthcharger3); CVAR_REGISTER(&sk_healthkit1); CVAR_REGISTER(&sk_healthkit2); CVAR_REGISTER(&sk_healthkit3); CVAR_REGISTER(&sk_scientist_heal1); CVAR_REGISTER(&sk_scientist_heal2); CVAR_REGISTER(&sk_scientist_heal3); #endif // REGAMEDLL_FIXES #ifdef REGAMEDLL_ADD ADD_SERVER_COMMAND("game", GameDLL_Version_f); ADD_SERVER_COMMAND("endround", GameDLL_EndRound_f); CVAR_REGISTER(&game_version); CVAR_REGISTER(&maxmoney); CVAR_REGISTER(&round_infinite); CVAR_REGISTER(&hegrenade_penetration); CVAR_REGISTER(&nadedrops); CVAR_REGISTER(&roundrespawn_time); CVAR_REGISTER(&auto_reload_weapons); CVAR_REGISTER(&refill_bpammo_weapons); // print version CONSOLE_ECHO("ReGameDLL build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")\n"); CONSOLE_ECHO("ReGameDLL API version %i.%i\n", REGAMEDLL_API_VERSION_MAJOR, REGAMEDLL_API_VERSION_MINOR); #endif // REGAMEDLL_ADD Bot_RegisterCvars(); Tutor_RegisterCVars(); Hostage_RegisterCVars(); }
/* <4f029e> ../game_shared/bot/nav_file.cpp:562 */ NavErrorType CNavArea::PostLoad() { NavErrorType error = NAV_OK; // connect areas together for (int d = 0; d < NUM_DIRECTIONS; ++d) { NavConnectList::iterator iter; for (iter = m_connect[d].begin(); iter != m_connect[d].end(); ++iter) { NavConnect *connect = &(*iter); unsigned int id = connect->id; connect->area = TheNavAreaGrid.GetNavAreaByID(id); if (id && connect->area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Cannot connect Navigation Areas.\n"); error = NAV_CORRUPT_DATA; } } } // resolve approach area IDs for (int a = 0; a < m_approachCount; ++a) { m_approach[a].here.area = TheNavAreaGrid.GetNavAreaByID(m_approach[a].here.id); if (m_approach[a].here.id && m_approach[a].here.area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing Approach Area (here).\n"); error = NAV_CORRUPT_DATA; } m_approach[a].prev.area = TheNavAreaGrid.GetNavAreaByID(m_approach[a].prev.id); if (m_approach[a].prev.id && m_approach[a].prev.area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing Approach Area (prev).\n"); error = NAV_CORRUPT_DATA; } m_approach[a].next.area = TheNavAreaGrid.GetNavAreaByID(m_approach[a].next.id); if (m_approach[a].next.id && m_approach[a].next.area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing Approach Area (next).\n"); error = NAV_CORRUPT_DATA; } } // resolve spot encounter IDs SpotEncounter *e; for (SpotEncounterList::iterator iter = m_spotEncounterList.begin(); iter != m_spotEncounterList.end(); ++iter) { e = &(*iter); e->from.area = TheNavAreaGrid.GetNavAreaByID(e->from.id); if (e->from.area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing \"from\" Navigation Area for Encounter Spot.\n"); error = NAV_CORRUPT_DATA; } e->to.area = TheNavAreaGrid.GetNavAreaByID(e->to.id); if (e->to.area == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing \"to\" Navigation Area for Encounter Spot.\n"); error = NAV_CORRUPT_DATA; } if (e->from.area && e->to.area) { // compute path float halfWidth; ComputePortal(e->to.area, e->toDir, &e->path.to, &halfWidth); ComputePortal(e->from.area, e->fromDir, &e->path.from, &halfWidth); const float eyeHeight = HalfHumanHeight; e->path.from.z = e->from.area->GetZ(&e->path.from) + eyeHeight; e->path.to.z = e->to.area->GetZ(&e->path.to) + eyeHeight; } // resolve HidingSpot IDs for (SpotOrderList::iterator oiter = e->spotList.begin(); oiter != e->spotList.end(); ++oiter) { SpotOrder *order = &(*oiter); order->spot = GetHidingSpotByID(order->id); if (order->spot == NULL) { CONSOLE_ECHO("ERROR: Corrupt navigation data. Missing Hiding Spot\n"); error = NAV_CORRUPT_DATA; } } } // build overlap list // TODO: Optimize this for (NavAreaList::iterator oiter = TheNavAreaList.begin(); oiter != TheNavAreaList.end(); ++oiter) { CNavArea *area = *oiter; if (area == this) continue; if (IsOverlapping(area)) m_overlapList.push_back(area); } return error; }
/* <4f3e47> ../game_shared/bot/nav_file.cpp:702 */ bool SaveNavigationMap(const char *filename) { if (filename == NULL) return false; // Store the NAV file COM_FixSlashes(const_cast<char *>(filename)); #ifdef WIN32 int fd = _open(filename, _O_BINARY | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE); #else int fd = creat(filename, S_IRUSR | S_IWUSR | S_IRGRP); #endif // WIN32 if (fd < 0) return false; // store "magic number" to help identify this kind of file unsigned int magic = NAV_MAGIC_NUMBER; Q_write(fd, &magic, sizeof(unsigned int)); // store version number of file // 1 = hiding spots as plain vector array // 2 = hiding spots as HidingSpot objects // 3 = Encounter spots use HidingSpot ID's instead of storing vector again // 4 = Includes size of source bsp file to verify nav data correlation // ---- Beta Release at V4 ----- // 5 = Added Place info unsigned int version = 5; Q_write(fd, &version, sizeof(unsigned int)); // get size of source bsp file and store it in the nav file // so we can test if the bsp changed since the nav file was made char *bspFilename = GetBspFilename(filename); if (bspFilename == NULL) return false; unsigned int bspSize = (unsigned int)GET_FILE_SIZE(bspFilename); CONSOLE_ECHO("Size of bsp file '%s' is %u bytes.\n", bspFilename, bspSize); Q_write(fd, &bspSize, sizeof(unsigned int)); // Build a directory of the Places in this map placeDirectory.Reset(); NavAreaList::iterator it; for (it = TheNavAreaList.begin(); it != TheNavAreaList.end(); ++it) { CNavArea *area = *it; Place place = area->GetPlace(); if (place) { placeDirectory.AddPlace(place); } } placeDirectory.Save(fd); // Store navigation areas // store number of areas unsigned int count = TheNavAreaList.size(); Q_write(fd, &count, sizeof(unsigned int)); // store each area for (it = TheNavAreaList.begin(); it != TheNavAreaList.end(); ++it) { CNavArea *area = *it; area->Save(fd, version); } Q_close(fd); #ifdef _WIN32 // output a simple Wavefront file to visualize the generated areas in 3DSMax FILE *fp = fopen("c:\\tmp\\nav.obj", "w"); if (fp) { for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { (*iter)->Save(fp); } fclose(fp); } #endif // _WIN32 return true; }
/* <36b780> ../cstrike/dlls/bot/cs_bot_manager.cpp:1109 */ void CCSBotManager::ValidateMapData(void) { if (IMPLEMENT_ARRAY(m_isMapDataLoaded) || !UTIL_IsGame("czero")) { return; } IMPLEMENT_ARRAY(m_isMapDataLoaded) = true; // TODO: Reverse me if (LoadNavigationMap()) { CONSOLE_ECHO("Failed to load navigation map.\n"); return; } CONSOLE_ECHO("Navigation map loaded.\n"); m_zoneCount = 0; m_gameScenario = SCENARIO_DEATHMATCH; // Search all entities in the map and set the game type and // store all zones (bomb target, etc). CBaseEntity *entity = NULL; int i; for (i = 1; i < gpGlobals->maxEntities; i++) { entity = CBaseEntity::Instance(INDEXENT(i)); if (entity == NULL) continue; bool found = false; bool isLegacy = false; if (FClassnameIs(entity->pev, "func_bomb_target")) { found = true; isLegacy = false; m_gameScenario = SCENARIO_DEFUSE_BOMB; } else if (FClassnameIs(entity->pev, "info_bomb_target")) { found = true; isLegacy = true; m_gameScenario = SCENARIO_DEFUSE_BOMB; } else if (FClassnameIs(entity->pev, "func_hostage_rescue")) { found = true; isLegacy = false; m_gameScenario = SCENARIO_RESCUE_HOSTAGES; } else if (FClassnameIs(entity->pev, "info_hostage_rescue")) { found = true; isLegacy = true; m_gameScenario = SCENARIO_RESCUE_HOSTAGES; } else if (FClassnameIs(entity->pev, "hostage_entity")) { // some very old maps (ie: cs_assault) use info_player_start // as rescue zones, so set the scenario if there are hostages // in the map m_gameScenario = SCENARIO_RESCUE_HOSTAGES; } else if (FClassnameIs(entity->pev, "func_vip_safetyzone")) { found = true; isLegacy = false; m_gameScenario = SCENARIO_ESCORT_VIP; } if (found) { if (m_zoneCount < MAX_ZONES) { if (isLegacy) m_zone[ m_zoneCount ].m_center = entity->pev->origin; else m_zone[ m_zoneCount ].m_center = (entity->pev->absmax + entity->pev->absmin) / 2.0f; m_zone[ m_zoneCount ].m_isLegacy = isLegacy; m_zone[ m_zoneCount ].m_index = m_zoneCount; m_zone[ m_zoneCount ].m_entity = entity; ++m_zoneCount; } else CONSOLE_ECHO("Warning: Too many zones, some will be ignored.\n"); } } // If there are no zones and the scenario is hostage rescue, // use the info_player_start entities as rescue zones. if (m_zoneCount == 0 && m_gameScenario == SCENARIO_RESCUE_HOSTAGES) { entity = NULL; while ((entity = UTIL_FindEntityByClassname(entity, "info_player_start")) != NULL) { if (FNullEnt(entity->edict())) break; if (m_zoneCount < MAX_ZONES) { m_zone[ m_zoneCount ].m_center = entity->pev->origin; m_zone[ m_zoneCount ].m_isLegacy = true; m_zone[ m_zoneCount ].m_index = m_zoneCount; m_zone[ m_zoneCount ].m_entity = entity; ++m_zoneCount; } else CONSOLE_ECHO("Warning: Too many zones, some will be ignored.\n"); } } // Collect nav areas that overlap each zone for (i = 0; i < m_zoneCount; i++) { Zone *zone = &m_zone[i]; if (zone->m_isLegacy) { const float legacyRange = 256.0f; zone->m_extent.lo.x = zone->m_center.x - legacyRange; zone->m_extent.lo.y = zone->m_center.y - legacyRange; zone->m_extent.lo.z = zone->m_center.z - legacyRange; zone->m_extent.hi.x = zone->m_center.x + legacyRange; zone->m_extent.hi.y = zone->m_center.y + legacyRange; zone->m_extent.hi.z = zone->m_center.z + legacyRange; } else { zone->m_extent.lo = zone->m_entity->pev->absmin; zone->m_extent.hi = zone->m_entity->pev->absmax; } // ensure Z overlap const float zFudge = 50.0f; zone->m_areaCount = 0; zone->m_extent.lo.z -= zFudge; zone->m_extent.hi.z += zFudge; // build a list of nav areas that overlap this zone for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { CNavArea *area = (*iter); const Extent *areaExtent = area->GetExtent(); if (areaExtent->hi.x >= zone->m_extent.lo.x && areaExtent->lo.x <= zone->m_extent.hi.x && areaExtent->hi.y >= zone->m_extent.lo.y && areaExtent->lo.y <= zone->m_extent.hi.y && areaExtent->hi.z >= zone->m_extent.lo.z && areaExtent->lo.z <= zone->m_extent.hi.z) { // area overlaps zone zone->m_area[ zone->m_areaCount++ ] = area; if (zone->m_areaCount == MAX_ZONE_NAV_AREAS) { break; } } } } }
/* <4f05c5> ../game_shared/bot/nav_file.cpp:876 */ void SanityCheckNavigationMap(const char *mapName) { if (!mapName) { CONSOLE_ECHO("ERROR: navigation file not specified.\n"); return; } // nav filename is derived from map filename const int BufLen = 4096; char bspFilename[BufLen]; char navFilename[BufLen]; Q_snprintf(bspFilename, BufLen, "maps\\%s.bsp", mapName); Q_snprintf(navFilename, BufLen, "maps\\%s.nav", mapName); SteamFile navFile(navFilename); if (!navFile.IsValid()) { CONSOLE_ECHO("ERROR: navigation file %s does not exist.\n", navFilename); return; } // check magic number bool result; unsigned int magic; result = navFile.Read(&magic, sizeof(unsigned int)); if (!result || magic != NAV_MAGIC_NUMBER) { CONSOLE_ECHO("ERROR: Invalid navigation file '%s'.\n", navFilename); return; } // read file version number unsigned int version; result = navFile.Read(&version, sizeof(unsigned int)); if (!result || version > 5) { CONSOLE_ECHO("ERROR: Unknown version in navigation file %s.\n", navFilename); return; } if (version >= 4) { // get size of source bsp file and verify that the bsp hasn't changed unsigned int saveBspSize; navFile.Read(&saveBspSize, sizeof(unsigned int)); // verify size if (bspFilename == NULL) { CONSOLE_ECHO("ERROR: No map corresponds to navigation file %s.\n", navFilename); return; } unsigned int bspSize = (unsigned int)GET_FILE_SIZE(bspFilename); if (bspSize != saveBspSize) { // this nav file is out of date for this bsp file CONSOLE_ECHO("ERROR: Out-of-date navigation data in navigation file %s.\n", navFilename); return; } } CONSOLE_ECHO("navigation file %s passes the sanity check.\n", navFilename); }
//-------------------------------------------------------------------------------------------------------------- void BuyState::OnUpdate( CCSBot *me ) { char cmdBuffer[256]; // wait for a Navigation Mesh if (!TheNavMesh->IsLoaded()) return; // apparently we cant buy things in the first few seconds, so wait a bit if (m_isInitialDelay) { const float waitToBuyTime = 0.25f; if (gpGlobals->curtime - me->GetStateTimestamp() < waitToBuyTime) return; m_isInitialDelay = false; } // if we're done buying and still in the freeze period, wait if (m_doneBuying) { if (CSGameRules()->IsMultiplayer() && CSGameRules()->IsFreezePeriod()) { // make sure we're locked and loaded me->EquipBestWeapon( MUST_EQUIP ); me->Reload(); me->ResetStuckMonitor(); return; } me->Idle(); return; } // If we're supposed to buy a specific weapon for debugging, do so and then bail const char *cheatWeaponString = bot_loadout.GetString(); if ( cheatWeaponString && *cheatWeaponString ) { CUtlVector<char*, CUtlMemory<char*> > loadout; Q_SplitString( cheatWeaponString, " ", loadout ); for ( int i=0; i<loadout.Count(); ++i ) { const char *item = loadout[i]; if ( FStrEq( item, "vest" ) ) { me->GiveNamedItem( "item_kevlar" ); } else if ( FStrEq( item, "vesthelm" ) ) { me->GiveNamedItem( "item_assaultsuit" ); } else if ( FStrEq( item, "defuser" ) ) { if ( me->GetTeamNumber() == TEAM_CT ) { me->GiveDefuser(); } } else if ( FStrEq( item, "nvgs" ) ) { me->m_bHasNightVision = true; } else if ( FStrEq( item, "primammo" ) ) { me->AttemptToBuyAmmo( 0 ); } else if ( FStrEq( item, "secammo" ) ) { me->AttemptToBuyAmmo( 1 ); } else { me->GiveWeapon( item ); } } m_doneBuying = true; return; } if (!me->IsInBuyZone()) { m_doneBuying = true; CONSOLE_ECHO( "%s bot spawned outside of a buy zone (%d, %d, %d)\n", (me->GetTeamNumber() == TEAM_CT) ? "CT" : "Terrorist", (int)me->GetAbsOrigin().x, (int)me->GetAbsOrigin().y, (int)me->GetAbsOrigin().z ); return; } // try to buy some weapons const float buyInterval = 0.02f; if (gpGlobals->curtime - me->GetStateTimestamp() > buyInterval) { me->m_stateTimestamp = gpGlobals->curtime; bool isPreferredAllDisallowed = true; // try to buy our preferred weapons first if (m_prefIndex < me->GetProfile()->GetWeaponPreferenceCount() && bot_randombuy.GetBool() == false ) { // need to retry because sometimes first buy fails?? const int maxPrefRetries = 2; if (m_prefRetries >= maxPrefRetries) { // try to buy next preferred weapon ++m_prefIndex; m_prefRetries = 0; return; } int weaponPreference = me->GetProfile()->GetWeaponPreference( m_prefIndex ); // don't buy it again if we still have one from last round char weaponPreferenceName[32]; Q_snprintf( weaponPreferenceName, sizeof(weaponPreferenceName), "weapon_%s", me->GetProfile()->GetWeaponPreferenceAsString( m_prefIndex ) ); if( me->Weapon_OwnsThisType(weaponPreferenceName) )//Prefs and buyalias use the short version, this uses the long { // done with buying preferred weapon m_prefIndex = 9999; return; } if (me->HasShield() && weaponPreference == WEAPON_SHIELDGUN) { // done with buying preferred weapon m_prefIndex = 9999; return; } const char *buyAlias = NULL; if (weaponPreference == WEAPON_SHIELDGUN) { if (TheCSBots()->AllowTacticalShield()) buyAlias = "shield"; } else { buyAlias = WeaponIDToAlias( weaponPreference ); WeaponType type = GetWeaponType( buyAlias ); switch( type ) { case PISTOL: if (!TheCSBots()->AllowPistols()) buyAlias = NULL; break; case SHOTGUN: if (!TheCSBots()->AllowShotguns()) buyAlias = NULL; break; case SUB_MACHINE_GUN: if (!TheCSBots()->AllowSubMachineGuns()) buyAlias = NULL; break; case RIFLE: if (!TheCSBots()->AllowRifles()) buyAlias = NULL; break; case MACHINE_GUN: if (!TheCSBots()->AllowMachineGuns()) buyAlias = NULL; break; case SNIPER_RIFLE: if (!TheCSBots()->AllowSnipers()) buyAlias = NULL; break; } } if (buyAlias) { Q_snprintf( cmdBuffer, 256, "buy %s\n", buyAlias ); CCommand args; args.Tokenize( cmdBuffer ); me->ClientCommand( args ); me->PrintIfWatched( "Tried to buy preferred weapon %s.\n", buyAlias ); isPreferredAllDisallowed = false; } ++m_prefRetries; // bail out so we dont waste money on other equipment // unless everything we prefer has been disallowed, then buy at random if (isPreferredAllDisallowed == false) return; } // if we have no preferred primary weapon (or everything we want is disallowed), buy at random if (!me->HasPrimaryWeapon() && (isPreferredAllDisallowed || !me->GetProfile()->HasPrimaryPreference())) { if (m_buyShield) { // buy a shield CCommand args; args.Tokenize( "buy shield" ); me->ClientCommand( args ); me->PrintIfWatched( "Tried to buy a shield.\n" ); } else { // build list of allowable weapons to buy BuyInfo *masterPrimary = (me->GetTeamNumber() == TEAM_TERRORIST) ? primaryWeaponBuyInfoT : primaryWeaponBuyInfoCT; BuyInfo *stockPrimary[ PRIMARY_WEAPON_BUY_COUNT ]; int stockPrimaryCount = 0; // dont choose sniper rifles as often const float sniperRifleChance = 50.0f; bool wantSniper = (RandomFloat( 0, 100 ) < sniperRifleChance) ? true : false; if ( bot_randombuy.GetBool() ) { wantSniper = true; } for( int i=0; i<PRIMARY_WEAPON_BUY_COUNT; ++i ) { if ((masterPrimary[i].type == SHOTGUN && TheCSBots()->AllowShotguns()) || (masterPrimary[i].type == SUB_MACHINE_GUN && TheCSBots()->AllowSubMachineGuns()) || (masterPrimary[i].type == RIFLE && TheCSBots()->AllowRifles()) || (masterPrimary[i].type == SNIPER_RIFLE && TheCSBots()->AllowSnipers() && wantSniper) || (masterPrimary[i].type == MACHINE_GUN && TheCSBots()->AllowMachineGuns())) { stockPrimary[ stockPrimaryCount++ ] = &masterPrimary[i]; } } if (stockPrimaryCount) { // buy primary weapon if we don't have one int which; // on hard difficulty levels, bots try to buy preferred weapons on the first pass if (m_retries == 0 && TheCSBots()->GetDifficultyLevel() >= BOT_HARD && bot_randombuy.GetBool() == false ) { // count up available preferred weapons int prefCount = 0; for( which=0; which<stockPrimaryCount; ++which ) if (stockPrimary[which]->preferred) ++prefCount; if (prefCount) { int whichPref = RandomInt( 0, prefCount-1 ); for( which=0; which<stockPrimaryCount; ++which ) if (stockPrimary[which]->preferred && whichPref-- == 0) break; } else { // no preferred weapons available, just pick randomly which = RandomInt( 0, stockPrimaryCount-1 ); } } else { which = RandomInt( 0, stockPrimaryCount-1 ); } Q_snprintf( cmdBuffer, 256, "buy %s\n", stockPrimary[ which ]->buyAlias ); CCommand args; args.Tokenize( cmdBuffer ); me->ClientCommand( args ); me->PrintIfWatched( "Tried to buy %s.\n", stockPrimary[ which ]->buyAlias ); } } } // // If we now have a weapon, or have tried for too long, we're done // if (me->HasPrimaryWeapon() || m_retries++ > 5) { // primary ammo CCommand args; if (me->HasPrimaryWeapon()) { args.Tokenize( "buy primammo" ); me->ClientCommand( args ); } // buy armor last, to make sure we bought a weapon first args.Tokenize( "buy vesthelm" ); me->ClientCommand( args ); args.Tokenize( "buy vest" ); me->ClientCommand( args ); // pistols - if we have no preferred pistol, buy at random if (TheCSBots()->AllowPistols() && !me->GetProfile()->HasPistolPreference()) { if (m_buyPistol) { int which = RandomInt( 0, SECONDARY_WEAPON_BUY_COUNT-1 ); const char *what = NULL; if (me->GetTeamNumber() == TEAM_TERRORIST) what = secondaryWeaponBuyInfoT[ which ].buyAlias; else what = secondaryWeaponBuyInfoCT[ which ].buyAlias; Q_snprintf( cmdBuffer, 256, "buy %s\n", what ); args.Tokenize( cmdBuffer ); me->ClientCommand( args ); // only buy one pistol m_buyPistol = false; } // make sure we have enough pistol ammo args.Tokenize( "buy secammo" ); me->ClientCommand( args ); } // buy a grenade if we wish, and we don't already have one if (m_buyGrenade && !me->HasGrenade()) { if (UTIL_IsTeamAllBots( me->GetTeamNumber() )) { // only allow Flashbangs if everyone on the team is a bot (dont want to blind our friendly humans) float rnd = RandomFloat( 0, 100 ); if (rnd < 10) { args.Tokenize( "buy smokegrenade" ); me->ClientCommand( args ); // smoke grenade } else if (rnd < 35) { args.Tokenize( "buy flashbang" ); me->ClientCommand( args ); // flashbang } else { args.Tokenize( "buy hegrenade" ); me->ClientCommand( args ); // he grenade } } else { if (RandomFloat( 0, 100 ) < 10) { args.Tokenize( "buy smokegrenade" ); // smoke grenade me->ClientCommand( args ); } else { args.Tokenize( "buy hegrenade" ); // he grenade me->ClientCommand( args ); } } } if (m_buyDefuseKit) { args.Tokenize( "buy defuser" ); me->ClientCommand( args ); } m_doneBuying = true; } } }
// Load the bot profile database void BotProfileManager::Init(const char *filename, unsigned int *checksum) { static const char *BotDifficultyName[] = { "EASY", "NORMAL", "HARD", "EXPERT", nullptr }; int dataLength; char *dataPointer = (char *)LOAD_FILE_FOR_ME(const_cast<char *>(filename), &dataLength); char *dataFile = dataPointer; if (!dataFile) { if (AreBotsAllowed()) { CONSOLE_ECHO("WARNING: Cannot access bot profile database '%s'\n", filename); } return; } // compute simple checksum if (checksum) { *checksum = ComputeSimpleChecksum((const unsigned char *)dataPointer, dataLength); } // keep list of templates used for inheritance BotProfileList templateList; BotProfile defaultProfile; // Parse the BotProfile.db into BotProfile instances while (true) { dataFile = SharedParse(dataFile); if (!dataFile) break; char *token = SharedGetToken(); bool isDefault = (!Q_stricmp(token, "Default")); bool isTemplate = (!Q_stricmp(token, "Template")); bool isCustomSkin = (!Q_stricmp(token, "Skin")); if (isCustomSkin) { const int BufLen = 64; char skinName[BufLen]; // get skin name dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected skin name\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); Q_snprintf(skinName, BufLen, "%s", token); // get attribute name dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_stricmp(token, "Model") != 0) { CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename); FREE_FILE(dataPointer); return; } // eat '=' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp(token, "=") != 0) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } // get attribute value dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); const char *decoratedName = GetDecoratedSkinName(skinName, filename); bool skinExists = GetCustomSkinIndex(decoratedName) > 0; if (m_nextSkin < NumCustomSkins && !skinExists) { // decorate the name m_skins[m_nextSkin] = CloneString(decoratedName); // construct the model filename m_skinModelnames[m_nextSkin] = CloneString(token); m_skinFilenames[m_nextSkin] = new char[Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1]; Q_sprintf(m_skinFilenames[m_nextSkin], "models/player/%s/%s.mdl", token, token); m_nextSkin++; } // eat 'End' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp(token, "End") != 0) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } // it's just a custom skin - no need to do inheritance on a bot profile, etc. continue; } // encountered a new profile BotProfile *profile; if (isDefault) { profile = &defaultProfile; } else { profile = new BotProfile; // always inherit from Default *profile = defaultProfile; } // do inheritance in order of appearance if (!isTemplate && !isDefault) { const BotProfile *inherit = nullptr; // template names are separated by "+" while (true) { char *c = Q_strchr(token, '+'); if (c) *c = '\0'; // find the given template name for (auto templates : templateList) { if (!Q_stricmp(templates->GetName(), token)) { inherit = templates; break; } } if (!inherit) { CONSOLE_ECHO("Error parsing '%s' - invalid template reference '%s'\n", filename, token); FREE_FILE(dataPointer); return; } // inherit the data profile->Inherit(inherit, &defaultProfile); if (c == nullptr) break; token = c + 1; } } // get name of this profile if (!isDefault) { dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing '%s' - expected name\n", filename); FREE_FILE(dataPointer); return; } profile->m_name = CloneString(SharedGetToken()); #ifdef REGAMEDLL_FIXES if (RANDOM_LONG(0, 2) == 2) #else // HACK HACK // Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's // preference towards silencers based on his name. if (profile->m_name[0] % 2) #endif { profile->m_prefersSilencer = true; } } // read attributes for this profile bool isFirstWeaponPref = true; while (true) { // get next token dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); // check for End delimiter if (!Q_stricmp(token, "End")) break; // found attribute name - keep it char attributeName[64]; Q_strcpy(attributeName, token); // eat '=' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp(token, "=") != 0) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } // get attribute value dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); // store value in appropriate attribute if (!Q_stricmp("Aggression", attributeName)) { profile->m_aggression = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Skill", attributeName)) { profile->m_skill = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Skin", attributeName)) { profile->m_skin = Q_atoi(token); if (profile->m_skin == 0) { // Q_atoi() failed - try to look up a custom skin by name profile->m_skin = GetCustomSkinIndex(token, filename); } } else if (!Q_stricmp("Teamwork", attributeName)) { profile->m_teamwork = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Cost", attributeName)) { profile->m_cost = Q_atoi(token); } else if (!Q_stricmp("VoicePitch", attributeName)) { profile->m_voicePitch = Q_atoi(token); } else if (!Q_stricmp("VoiceBank", attributeName)) { profile->m_voiceBank = FindVoiceBankIndex(token); } else if (!Q_stricmp("WeaponPreference", attributeName)) { // weapon preferences override parent prefs if (isFirstWeaponPref) { isFirstWeaponPref = false; profile->m_weaponPreferenceCount = 0; } if (!Q_stricmp(token, "none")) { profile->m_weaponPreferenceCount = 0; } else { if (profile->m_weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS) { profile->m_weaponPreference[profile->m_weaponPreferenceCount++] = AliasToWeaponID(token); } } } else if (!Q_stricmp("ReactionTime", attributeName)) { profile->m_reactionTime = Q_atof(token); #ifndef GAMEUI_EXPORTS // subtract off latency due to "think" update rate. // In GameUI, we don't really care. profile->m_reactionTime -= g_flBotFullThinkInterval; #endif } else if (!Q_stricmp("AttackDelay", attributeName)) { profile->m_attackDelay = Q_atof(token); } else if (!Q_stricmp("Difficulty", attributeName)) { // override inheritance profile->m_difficultyFlags = 0; // parse bit flags while (true) { char *c = Q_strchr(token, '+'); if (c) *c = '\0'; for (int i = 0; i < NUM_DIFFICULTY_LEVELS; i++) { if (!Q_stricmp(BotDifficultyName[i], token)) profile->m_difficultyFlags |= (1<<i); } if (c == nullptr) break; token = c + 1; } } else if (!Q_stricmp("Team", attributeName)) { if (!Q_stricmp(token, "T")) { profile->m_teams = BOT_TEAM_T; } else if (!Q_stricmp(token, "CT")) { profile->m_teams = BOT_TEAM_CT; } else { profile->m_teams = BOT_TEAM_ANY; } } else { CONSOLE_ECHO("Error parsing %s - unknown attribute '%s'\n", filename, attributeName); } } if (!isDefault) { if (isTemplate) { // add to template list templateList.push_back(profile); } else { // add profile to the master list m_profileList.push_back(profile); } } } FREE_FILE(dataPointer); // free the templates for (auto templates : templateList) delete templates; templateList.clear(); }
int CLocalNav::FindPath(Vector &vecStart, Vector &vecDest, float flTargetRadius, BOOL fNoMonsters) { int nIndexBest; node_index_t *node; Vector vecNodeLoc; float flDistToDest; #ifdef _DEBUG CONSOLE_ECHO("findpath: %f\n", gpGlobals->time); #endif nIndexBest = FindDirectPath(vecStart, vecDest, flTargetRadius, fNoMonsters); if (nIndexBest != -1) return nIndexBest; m_vecStartingLoc = vecStart; m_nindexAvailableNode = 0; AddPathNodes(-1, fNoMonsters); vecNodeLoc = vecStart; nIndexBest = GetBestNode(vecNodeLoc, vecDest); while (nIndexBest != -1) { node = GetNode(nIndexBest); vecNodeLoc = node->vecLoc; node->fSearched = TRUE; flDistToDest = (vecDest - node->vecLoc).Length2D(); if (flDistToDest <= flTargetRadius) break; if (flDistToDest <= HOSTAGE_STEPSIZE) break; if ((flDistToDest - flTargetRadius) > (MAX_NODES - m_nindexAvailableNode) * HOSTAGE_STEPSIZE || m_nindexAvailableNode == MAX_NODES) { nIndexBest = -1; break; } AddPathNodes(nIndexBest, fNoMonsters); nIndexBest = GetBestNode(vecNodeLoc, vecDest); } if (m_nindexAvailableNode <= 10) nodeval += 2; else if (m_nindexAvailableNode <= 20) nodeval += 4; else if (m_nindexAvailableNode <= 30) nodeval += 8; else if (m_nindexAvailableNode <= 40) nodeval += 13; else if (m_nindexAvailableNode <= 50) nodeval += 19; else if (m_nindexAvailableNode <= 60) nodeval += 26; else if (m_nindexAvailableNode <= 70) nodeval += 34; else if (m_nindexAvailableNode <= 80) nodeval += 43; else if (m_nindexAvailableNode <= 90) nodeval += 53; else if (m_nindexAvailableNode <= 100) nodeval += 64; else if (m_nindexAvailableNode <= 110) nodeval += 76; else if (m_nindexAvailableNode <= 120) nodeval += 89; else if (m_nindexAvailableNode <= 130) nodeval += 103; else if (m_nindexAvailableNode <= 140) nodeval += 118; else if (m_nindexAvailableNode <= 150) nodeval += 134; else if (m_nindexAvailableNode <= 160) nodeval += 151; else nodeval += 169; return nIndexBest; }