// Return the number of bots following the given player int GetBotFollowCount(CBasePlayer *pLeader) { int count = 0; for (int i = 1; i <= gpGlobals->maxClients; i++) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); if (!pPlayer) continue; if (FNullEnt(pPlayer->pev)) continue; if (FStrEq(STRING(pPlayer->pev->netname), "")) continue; if (!pPlayer->IsBot()) continue; if (!pPlayer->IsAlive()) continue; CCSBot *pBot = static_cast<CCSBot *>(pPlayer); if (pBot->IsBot() && pBot->GetFollowLeader() == pLeader) count++; } return count; }
int GetBotFollowCount(CBasePlayer *leader) { int count = 0; for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBaseEntity *entity = UTIL_PlayerByIndex(i); if (entity == NULL) continue; if (FNullEnt(entity->pev)) continue; if (FStrEq(STRING(entity->pev->netname), "")) continue; CBasePlayer *player = static_cast<CBasePlayer *>(entity); if (!player->IsBot()) continue; if (!player->IsAlive()) continue; CCSBot *bot = dynamic_cast<CCSBot *>(player); if (bot != NULL && bot->GetFollowLeader() == leader) ++count; } return count; }
/* <36b5fa> ../cstrike/dlls/bot/cs_bot_manager.cpp:415 */ void CCSBotManager::__MAKE_VHOOK(ClientDisconnect)(CBasePlayer *pPlayer) { if (!pPlayer || !pPlayer->IsBot()) return; CCSBot *pBot = static_cast<CCSBot *>(pPlayer); entvars_t *temp = VARS(pPlayer->edict()); pBot->Disconnect(); if (pPlayer->pev->classname) RemoveEntityHashValue(pPlayer->pev, STRING(pPlayer->pev->classname), CLASSNAME); FREE_PRIVATE(pPlayer->edict()); CBasePlayer *player = GetClassPtr((CBasePlayer *)temp); AddEntityHashValue(player->pev, STRING(player->pev->classname), CLASSNAME); player->pev->flags = FL_DORMANT; }
/* <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 } }
CBasePlayer *CCSBot::FindMostDangerousThreat() { // maximum number of simulataneously attendable threats enum { MAX_THREATS = 16 }; struct CloseInfo { CBasePlayer *enemy; float range; } threat[ MAX_THREATS ]; int threatCount = 0; m_bomber = NULL; m_closestVisibleFriend = NULL; float closeFriendRange = 99999999999.9f; m_closestVisibleHumanFriend = NULL; float closeHumanFriendRange = 99999999999.9f; int i; { for (i = 1; i <= gpGlobals->maxClients; ++i) { CBasePlayer *player = UTIL_PlayerByIndex(i); if (player == NULL) continue; if (FNullEnt(player->pev)) continue; // is it a player? if (!player->IsPlayer()) continue; // ignore self if (player->entindex() == entindex()) continue; // is it alive? if (!player->IsAlive()) continue; // is it an enemy? if (player->m_iTeam == m_iTeam) { TraceResult result; UTIL_TraceLine(GetEyePosition(), player->pev->origin, ignore_monsters, ignore_glass, edict(), &result); if (result.flFraction == 1.0f) { // update watch timestamp int idx = player->entindex() - 1; m_watchInfo[idx].timestamp = gpGlobals->time; m_watchInfo[idx].isEnemy = false; // keep track of our closest friend Vector to = pev->origin - player->pev->origin; float rangeSq = to.LengthSquared(); if (rangeSq < closeFriendRange) { m_closestVisibleFriend = player; closeFriendRange = rangeSq; } // keep track of our closest human friend if (!player->IsBot() && rangeSq < closeHumanFriendRange) { m_closestVisibleHumanFriend = player; closeHumanFriendRange = rangeSq; } } continue; } // check if this enemy is fully if (!IsVisible(player, CHECK_FOV)) continue; // update watch timestamp int idx = player->entindex() - 1; m_watchInfo[idx].timestamp = gpGlobals->time; m_watchInfo[idx].isEnemy = true; // note if we see the bomber if (player->IsBombGuy()) { m_bomber = player; } // keep track of all visible threats Vector d = pev->origin - player->pev->origin; float distSq = d.LengthSquared(); // maintain set of visible threats, sorted by increasing distance if (threatCount == 0) { threat[0].enemy = player; threat[0].range = distSq; threatCount = 1; } else { // find insertion point int j; for (j = 0; j < threatCount; ++j) { if (distSq < threat[j].range) break; } // shift lower half down a notch for (int k = threatCount - 1; k >= j; --k) threat[k + 1] = threat[k]; // insert threat into sorted list threat[j].enemy = player; threat[j].range = distSq; if (threatCount < MAX_THREATS) ++threatCount; } } } { // track the maximum enemy and friend counts we've seen recently int prevEnemies = m_nearbyEnemyCount; int prevFriends = m_nearbyFriendCount; m_nearbyEnemyCount = 0; m_nearbyFriendCount = 0; for (i = 0; i < MAX_CLIENTS; ++i) { if (m_watchInfo[i].timestamp <= 0.0f) continue; const float recentTime = 3.0f; if (gpGlobals->time - m_watchInfo[i].timestamp < recentTime) { if (m_watchInfo[i].isEnemy) ++m_nearbyEnemyCount; else ++m_nearbyFriendCount; } } // note when we saw this batch of enemies if (prevEnemies == 0 && m_nearbyEnemyCount > 0) { m_firstSawEnemyTimestamp = gpGlobals->time; } if (prevEnemies != m_nearbyEnemyCount || prevFriends != m_nearbyFriendCount) { PrintIfWatched("Nearby friends = %d, enemies = %d\n", m_nearbyFriendCount, m_nearbyEnemyCount); } } { // Track the place where we saw most of our enemies struct PlaceRank { unsigned int place; int count; }; static PlaceRank placeRank[ MAX_PLACES_PER_MAP ]; int locCount = 0; PlaceRank common; common.place = 0; common.count = 0; for (i = 0; i < threatCount; ++i) { // find the area the player/bot is standing on CNavArea *area; CCSBot *bot = dynamic_cast<CCSBot *>(threat[i].enemy); if (bot != NULL && bot->IsBot()) { area = bot->GetLastKnownArea(); } else { area = TheNavAreaGrid.GetNearestNavArea(&threat[i].enemy->pev->origin); } if (area == NULL) continue; unsigned int threatLoc = area->GetPlace(); if (!threatLoc) continue; // if place is already in set, increment count int j; for (j = 0; j < locCount; ++j) { if (placeRank[j].place == threatLoc) break; } if (j == locCount) { // new place if (locCount < MAX_PLACES_PER_MAP) { placeRank[ locCount ].place = threatLoc; placeRank[ locCount ].count = 1; if (common.count == 0) common = placeRank[locCount]; ++locCount; } } else { // others are in that place, increment ++placeRank[j].count; // keep track of the most common place if (placeRank[j].count > common.count) common = placeRank[j]; } } // remember most common place m_enemyPlace = common.place; } { if (threatCount == 0) return NULL; // otherwise, find the closest threat that without using shield int t; for (t = 0; t < threatCount; ++t) { if (!threat[t].enemy->IsProtectedByShield()) { return threat[t].enemy; } } } // return closest threat return threat[0].enemy; }