Added consistency check for graph files. Totally optional, but wiill notify user if graph file built not for loaded map.
Some minor cosmetic changes and refactoring. Fixed #70. Better now, than never. Implemented #121. Bots auto-kill delays. Bumb the year.
This commit is contained in:
parent
2aba34a24b
commit
d6150a8aba
22 changed files with 171 additions and 82 deletions
|
|
@ -484,7 +484,7 @@ void Bot::updatePickups () {
|
|||
}
|
||||
|
||||
auto &intresting = bots.searchIntrestingEntities ();
|
||||
const float radius = cr::square (320.0f);
|
||||
const float radius = cr::square (399.0f);
|
||||
|
||||
if (!game.isNullEntity (m_pickupItem)) {
|
||||
bool itemExists = false;
|
||||
|
|
@ -2176,7 +2176,7 @@ bool Bot::reactOnEnemy () {
|
|||
auto lineDist = (m_enemy->v.origin - pev->origin).length ();
|
||||
auto pathDist = static_cast <float> (graph.getPathDist (ownIndex, enemyIndex));
|
||||
|
||||
if (pathDist - lineDist > 112.0f) {
|
||||
if (pathDist - lineDist > 112.0f || isOnLadder ()) {
|
||||
m_isEnemyReachable = false;
|
||||
}
|
||||
else {
|
||||
|
|
@ -3444,11 +3444,6 @@ void Bot::attackEnemy_ () {
|
|||
|
||||
if (!game.isNullEntity (m_enemy)) {
|
||||
ignoreCollision ();
|
||||
|
||||
if (isOnLadder ()) {
|
||||
pev->button |= IN_JUMP;
|
||||
clearSearchNodes ();
|
||||
}
|
||||
attackMovement ();
|
||||
|
||||
if (m_currentWeapon == Weapon::Knife && !m_lastEnemyOrigin.empty ()) {
|
||||
|
|
@ -3796,7 +3791,17 @@ void Bot::defuseBomb_ () {
|
|||
|
||||
// exception: bomb has been defused
|
||||
if (bombPos.empty () || !pickupExists) {
|
||||
defuseError = true;
|
||||
|
||||
// fix for stupid behaviour of CT's when bot is defused
|
||||
for (const auto &bot : bots) {
|
||||
if (bot->m_team == m_team && bot->m_notKilled) {
|
||||
auto defendPoint = graph.getFarest (bot->pev->origin);
|
||||
|
||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, game.time () + rg.float_ (30.0f, 60.0f), true); // push camp task on to stack
|
||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, defendPoint, game.time () + rg.float_ (3.0f, 6.0f), true); // push move command
|
||||
}
|
||||
}
|
||||
graph.setBombOrigin (true);
|
||||
|
||||
if (m_numFriendsLeft != 0 && rg.chance (50)) {
|
||||
if (timeToBlowUp <= 3.0) {
|
||||
|
|
@ -3811,6 +3816,7 @@ void Bot::defuseBomb_ () {
|
|||
pushRadioMessage (Radio::SectorClear);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (defuseRemainingTime > timeToBlowUp) {
|
||||
defuseError = true;
|
||||
|
|
@ -3833,17 +3839,16 @@ void Bot::defuseBomb_ () {
|
|||
|
||||
// one of exceptions is thrown. finish task.
|
||||
if (defuseError) {
|
||||
m_checkTerrain = true;
|
||||
m_moveToGoal = true;
|
||||
|
||||
m_destOrigin = nullptr;
|
||||
m_entity = nullptr;
|
||||
|
||||
m_pickupItem = nullptr;
|
||||
m_pickupType = Pickup::None;
|
||||
|
||||
selectBestWeapon ();
|
||||
resetCollision ();
|
||||
|
||||
completeTask ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -917,7 +917,7 @@ void Bot::fireWeapons () {
|
|||
if (weapons & cr::bit (id)) {
|
||||
const auto &prop = conf.getWeaponProp (id);
|
||||
|
||||
if (prop.ammo1 != -1 && prop.ammo1 < 32 && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo) {
|
||||
if (prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo) {
|
||||
|
||||
// available ammo found, reload weapon
|
||||
if (m_reloadState == Reload::None || m_reloadCheckTime > game.time ()) {
|
||||
|
|
@ -945,7 +945,7 @@ bool Bot::isWeaponBadAtDistance (int weaponIndex, float distance) {
|
|||
|
||||
auto &info = conf.getWeapons ();
|
||||
|
||||
if (m_difficulty < 2) {
|
||||
if (m_difficulty < 2 || !hasSecondaryWeapon ()) {
|
||||
return false;
|
||||
}
|
||||
int wid = info[weaponIndex].id;
|
||||
|
|
@ -1415,7 +1415,7 @@ void Bot::selectBestWeapon () {
|
|||
const auto &prop = conf.getWeaponProp (id);
|
||||
|
||||
// is no ammo required for this weapon OR enough ammo available to fire
|
||||
if (prop.ammo1 < 0 || (prop.ammo1 < 32 && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo)) {
|
||||
if (prop.ammo1 < 0 || (prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] >= tab[selectIndex].minPrimaryAmmo)) {
|
||||
ammoLeft = true;
|
||||
}
|
||||
|
||||
|
|
@ -1607,7 +1607,7 @@ void Bot::checkReload () {
|
|||
}
|
||||
const auto &prop = conf.getWeaponProp (weaponIndex);
|
||||
|
||||
if (m_ammoInClip[weaponIndex] < conf.findWeaponById (weaponIndex).maxClip * 0.8f && prop.ammo1 != -1 && prop.ammo1 < 32 && m_ammo[prop.ammo1] > 0) {
|
||||
if (m_ammoInClip[weaponIndex] < conf.findWeaponById (weaponIndex).maxClip * 0.8f && prop.ammo1 != -1 && prop.ammo1 < kMaxWeapons && m_ammo[prop.ammo1] > 0) {
|
||||
if (m_currentWeapon != weaponIndex) {
|
||||
selectWeaponByName (prop.classname.chars ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,6 @@ void Game::precache () {
|
|||
}
|
||||
m_precached = true;
|
||||
|
||||
|
||||
|
||||
m_drawModels[DrawLine::Simple] = m_engineWrap.precacheModel ("sprites/laserbeam.spr");
|
||||
m_drawModels[DrawLine::Arrow] = m_engineWrap.precacheModel ("sprites/arrow1.spr");
|
||||
|
||||
|
|
@ -842,6 +840,9 @@ void Game::slowFrame () {
|
|||
// update bot difficulties to newly selected from cvar
|
||||
bots.updateBotDifficulties ();
|
||||
|
||||
// check if we're need to autokill bots
|
||||
bots.maintainAutoKill ();
|
||||
|
||||
// update client pings
|
||||
util.calculatePings ();
|
||||
|
||||
|
|
|
|||
|
|
@ -1473,7 +1473,7 @@ bool BotGraph::convertOldFormat () {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename U> bool BotGraph::saveStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, const SmallArray <U> &data, uint8 *blob) {
|
||||
template <typename U> bool BotGraph::saveStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten) {
|
||||
bool isGraph = (ext == "graph");
|
||||
|
||||
String filename;
|
||||
|
|
@ -1521,9 +1521,9 @@ template <typename U> bool BotGraph::saveStorage (const String &ext, const Strin
|
|||
file.write (&hdr, sizeof (StorageHeader));
|
||||
file.write (compressed.data (), sizeof (uint8), compressedLength);
|
||||
|
||||
// add creator
|
||||
if ((options & StorageOption::Author) && blob != nullptr) {
|
||||
file.write (blob, sizeof (uint8), 64);
|
||||
// add extension
|
||||
if ((options & StorageOption::Exten) && exten != nullptr) {
|
||||
file.write (exten, sizeof (ExtenHeader));
|
||||
}
|
||||
game.print ("Successfully saved Bots %s data.", name.chars ());
|
||||
}
|
||||
|
|
@ -1537,7 +1537,7 @@ template <typename U> bool BotGraph::saveStorage (const String &ext, const Strin
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename U> bool BotGraph::loadStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, SmallArray <U> &data, uint8 *blob, int32 *outOptions) {
|
||||
template <typename U> bool BotGraph::loadStorage (const String &ext, const String &name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions) {
|
||||
String filename;
|
||||
filename.assignf ("%s.%s", game.getMapName (), ext.chars ()).lowercase ();
|
||||
|
||||
|
|
@ -1614,11 +1614,11 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
|
|||
}
|
||||
|
||||
if (download ()) {
|
||||
return loadStorage <U> (ext, name, options, version, data, blob, outOptions);
|
||||
return loadStorage <U> (ext, name, options, version, data, exten, outOptions);
|
||||
}
|
||||
|
||||
if (convertOldFormat ()) {
|
||||
return loadStorage <U> (ext, name, options, version, data, blob, outOptions);
|
||||
return loadStorage <U> (ext, name, options, version, data, exten, outOptions);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
|
@ -1690,8 +1690,8 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
|
|||
}
|
||||
|
||||
// author of graph.. save
|
||||
if ((hdr.options & StorageOption::Author) && blob != nullptr) {
|
||||
file.read (blob, sizeof (uint8), 64);
|
||||
if ((hdr.options & StorageOption::Exten) && exten != nullptr) {
|
||||
file.read (exten, sizeof (ExtenHeader));
|
||||
}
|
||||
game.print ("Successfully loaded Bots %s data (%d/%.2fMB).", name.chars (), data.length (), static_cast <float> (data.capacity () * sizeof (U)) / 1024.0f / 1024.0f);
|
||||
file.close ();
|
||||
|
|
@ -1706,13 +1706,13 @@ template <typename U> bool BotGraph::loadStorage (const String &ext, const Strin
|
|||
}
|
||||
|
||||
bool BotGraph::loadGraphData () {
|
||||
uint8 blob[64];
|
||||
ExtenHeader exten {};
|
||||
int32 outOptions = 0;
|
||||
|
||||
m_paths.clear ();
|
||||
|
||||
// check if loaded
|
||||
bool dataLoaded = loadStorage <Path> ("graph", "Graph", StorageOption::Graph, StorageVersion::Graph, m_paths, reinterpret_cast <uint8 *> (blob), &outOptions);
|
||||
bool dataLoaded = loadStorage <Path> ("graph", "Graph", StorageOption::Graph, StorageVersion::Graph, m_paths, &exten, &outOptions);
|
||||
|
||||
if (dataLoaded) {
|
||||
initGraph ();
|
||||
|
|
@ -1723,17 +1723,24 @@ bool BotGraph::loadGraphData () {
|
|||
addToBucket (path.origin, path.number);
|
||||
}
|
||||
|
||||
if ((outOptions & StorageOption::Official) || memcmp (blob, "official", 8) == 0) {
|
||||
m_tempStrings.assign ("Using Official Graph File");
|
||||
if ((outOptions & StorageOption::Official) || strncmp (exten.author, "official", 8) == 0 || strlen (exten.author) < 2) {
|
||||
m_tempStrings.assign ("Using Official Navigation Graph");
|
||||
}
|
||||
else {
|
||||
m_tempStrings.assignf ("Using Graph File By: %s", blob);
|
||||
m_tempStrings.assignf ("Navigation Graph Authord By: %s", exten.author);
|
||||
}
|
||||
initNodesTypes ();
|
||||
loadPathMatrix ();
|
||||
loadVisibility ();
|
||||
loadPractice ();
|
||||
|
||||
if (exten.mapSize > 0) {
|
||||
int mapSize = engfuncs.pfnGetFileSize (strings.format ("maps/%s.bsp", game.getMapName ()));
|
||||
|
||||
if (mapSize != exten.mapSize) {
|
||||
game.print ("Warning: Graph data is probably not for this map. Please check bots behaviour.");
|
||||
}
|
||||
}
|
||||
extern ConVar yb_debug_goal;
|
||||
yb_debug_goal.set (kInvalidNodeIndex);
|
||||
|
||||
|
|
@ -1743,7 +1750,7 @@ bool BotGraph::loadGraphData () {
|
|||
}
|
||||
|
||||
bool BotGraph::saveGraphData () {
|
||||
auto options = StorageOption::Graph | StorageOption::Author;
|
||||
auto options = StorageOption::Graph | StorageOption::Exten;
|
||||
String author;
|
||||
|
||||
if (game.isNullEntity (m_editor) && !m_tempStrings.empty ()) {
|
||||
|
|
@ -1757,13 +1764,17 @@ bool BotGraph::saveGraphData () {
|
|||
else {
|
||||
author = "YAPB";
|
||||
}
|
||||
author.resize (64);
|
||||
|
||||
|
||||
// mark as official
|
||||
if (author.startsWith ("YAPB")) {
|
||||
options |= StorageOption::Official;
|
||||
}
|
||||
return saveStorage <Path> ("graph", "Graph", static_cast <StorageOption> (options), StorageVersion::Graph, m_paths, reinterpret_cast <uint8 *> (author.begin ()));
|
||||
|
||||
ExtenHeader exten {};
|
||||
strings.copy (exten.author, author.chars (), cr::bufsize (exten.author));
|
||||
exten.mapSize = engfuncs.pfnGetFileSize (strings.format ("maps/%s.bsp", game.getMapName ()));
|
||||
|
||||
return saveStorage <Path> ("graph", "Graph", static_cast <StorageOption> (options), StorageVersion::Graph, m_paths, &exten);
|
||||
}
|
||||
|
||||
void BotGraph::saveOldFormat () {
|
||||
|
|
@ -2673,16 +2684,18 @@ void BotGraph::eraseFromDisk () {
|
|||
// this function removes graph file from the hard disk
|
||||
|
||||
StringArray forErase;
|
||||
const char *map = game.getMapName ();
|
||||
|
||||
auto map = game.getMapName ();
|
||||
auto data = getDataDirectory ();
|
||||
|
||||
bots.kickEveryone (true);
|
||||
|
||||
// if we're delete graph, delete all corresponding to it files
|
||||
forErase.push (strings.format ("%s%s.pwf", getDataDirectory (), map)); // graph itself
|
||||
forErase.push (strings.format ("%slearned/%s.exp", getDataDirectory (), map)); // corresponding to practice
|
||||
forErase.push (strings.format ("%slearned/%s.vis", getDataDirectory (), map)); // corresponding to vistable
|
||||
forErase.push (strings.format ("%slearned/%s.pmx", getDataDirectory (), map)); // corresponding to matrix
|
||||
forErase.push (strings.format ("%sgraph/%s.graph", getDataDirectory (), map)); // new format graph
|
||||
forErase.push (strings.format ("%s%s.pwf", data, map)); // graph itself
|
||||
forErase.push (strings.format ("%slearned/%s.exp", data, map)); // corresponding to practice
|
||||
forErase.push (strings.format ("%slearned/%s.vis", data, map)); // corresponding to vistable
|
||||
forErase.push (strings.format ("%slearned/%s.pmx", data, map)); // corresponding to matrix
|
||||
forErase.push (strings.format ("%sgraph/%s.graph", data, map)); // new format graph
|
||||
|
||||
for (const auto &item : forErase) {
|
||||
if (File::exists (item)) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ ConVar yb_quota ("yb_quota", "0", "Specifies the number bots to be added to the
|
|||
ConVar yb_quota_mode ("yb_quota_mode", "normal", "Specifies the type of quota.\nAllowed values: 'normal', 'fill', and 'match'.\nIf 'fill', the server will adjust bots to keep N players in the game, where N is yb_quota.\nIf 'match', the server will maintain a 1:N ratio of humans to bots, where N is yb_quota_match.", false);
|
||||
ConVar yb_quota_match ("yb_quota_match", "0", "Number of players to match if yb_quota_mode set to 'match'", true, 0.0f, static_cast <float> (kGameMaxPlayers));
|
||||
ConVar yb_think_fps ("yb_think_fps", "30.0", "Specifies hou many times per second bot code will run.", true, 30.0f, 90.0f);
|
||||
ConVar yb_autokill_delay ("yb_autokill_delay", "0.0", "Specifies amount of time in seconds when bots will be killed if no humans left alive.", true, 0.0f, 90.0f);
|
||||
|
||||
ConVar yb_join_after_player ("yb_join_after_player", "0", "Sepcifies whether bots should join server, only when at least one human player in game.");
|
||||
ConVar yb_join_team ("yb_join_team", "any", "Forces all bots to join team specified here.", false);
|
||||
|
|
@ -45,9 +46,11 @@ BotManager::BotManager () {
|
|||
m_timeRoundMid = 0.0f;
|
||||
m_timeRoundEnd = 0.0f;
|
||||
|
||||
m_autoKillCheckTime = 0.0f;
|
||||
|
||||
m_bombPlanted = false;
|
||||
m_botsCanPause = false;
|
||||
m_roundEnded = false;
|
||||
m_roundOver = false;
|
||||
|
||||
m_bombSayStatus = BombPlantedSay::ChatSay | BombPlantedSay::Chatter;
|
||||
|
||||
|
|
@ -67,7 +70,7 @@ BotManager::BotManager () {
|
|||
}
|
||||
|
||||
void BotManager::createKillerEntity () {
|
||||
// this function creates single trigger_hurt for using in Bot::Kill, to reduce lags, when killing all the bots
|
||||
// this function creates single trigger_hurt for using in Bot::kill, to reduce lags, when killing all the bots
|
||||
|
||||
m_killerEntity = engfuncs.pfnCreateNamedEntity (MAKE_STRING ("trigger_hurt"));
|
||||
|
||||
|
|
@ -410,6 +413,52 @@ void BotManager::maintainQuota () {
|
|||
m_quotaMaintainTime = game.time () + 0.40f;
|
||||
}
|
||||
|
||||
void BotManager::maintainAutoKill () {
|
||||
const float killDelay = yb_autokill_delay.float_ ();
|
||||
|
||||
if (killDelay < 1.0f || m_roundOver) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we're reached the delay, so kill out bots
|
||||
if (!cr::fzero (m_autoKillCheckTime) && m_autoKillCheckTime < game.time ()) {
|
||||
killAllBots ();
|
||||
m_autoKillCheckTime = 0.0f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int aliveBots = 0;
|
||||
|
||||
// do not interrupt bomb-defuse scenario
|
||||
if (game.mapIs (MapFlags::Demolition) && isBombPlanted ()) {
|
||||
return;
|
||||
}
|
||||
int totalHumans = getHumansCount (true); // we're ignore spectators intentionally
|
||||
|
||||
// if we're have no humans in teams do not bother to proceed
|
||||
if (!totalHumans) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &bot : m_bots) {
|
||||
if (bot->m_notKilled) {
|
||||
++aliveBots;
|
||||
|
||||
// do not interrupt assassination scenario, if vip is a bot
|
||||
if (game.is (MapFlags::Assassination) && util.isPlayerVIP (bot->ent ())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
int aliveHumans = getAliveHumansCount ();
|
||||
|
||||
// check if we're have no alive players and some alive bots, and start autokill timer
|
||||
if (!aliveHumans && aliveBots > 0 && cr::fzero (m_autoKillCheckTime)) {
|
||||
m_autoKillCheckTime = game.time () + killDelay;
|
||||
}
|
||||
}
|
||||
|
||||
void BotManager::reset () {
|
||||
m_maintainTime = 0.0f;
|
||||
m_quotaMaintainTime = 0.0f;
|
||||
|
|
@ -621,6 +670,7 @@ bool BotManager::kickRandom (bool decQuota, Team fromTeam) {
|
|||
|
||||
void BotManager::setLastWinner (int winner) {
|
||||
m_lastWinner = winner;
|
||||
m_roundOver = true;
|
||||
|
||||
if (yb_radio_mode.int_ () != 2) {
|
||||
return;
|
||||
|
|
@ -702,7 +752,7 @@ float BotManager::getConnectionTime (int botId) {
|
|||
if (bot->index () == botId) {
|
||||
auto current = plat.seconds ();
|
||||
|
||||
if (current - bot->m_joinServerTime > bot->m_playServerTime || current - bot->m_joinServerTime <= 0) {
|
||||
if (current - bot->m_joinServerTime > bot->m_playServerTime || current - bot->m_joinServerTime <= 0.0f) {
|
||||
bot->m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f);
|
||||
bot->m_joinServerTime = current - bot->m_playServerTime * rg.float_ (0.2f, 0.8f);
|
||||
}
|
||||
|
|
@ -950,7 +1000,7 @@ int BotManager::getAliveHumansCount () {
|
|||
int count = 0;
|
||||
|
||||
for (const auto &client : util.getClients ()) {
|
||||
if ((client.flags & (ClientFlags::Used | ClientFlags::Alive)) && bots[client.ent] == nullptr && !(client.ent->v.flags & FL_FAKECLIENT)) {
|
||||
if ((client.flags & ClientFlags::Alive) && bots[client.ent] == nullptr && !(client.ent->v.flags & FL_FAKECLIENT)) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
|
@ -1288,6 +1338,10 @@ void Bot::kick () {
|
|||
void Bot::updateTeamJoin () {
|
||||
// this function handles the selection of teams & class
|
||||
|
||||
if (!m_notStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cs prior beta 7.0 uses hud-based motd, so press fire once
|
||||
if (game.is (GameFlags::Legacy)) {
|
||||
pev->button |= IN_ATTACK;
|
||||
|
|
@ -1302,8 +1356,8 @@ void Bot::updateTeamJoin () {
|
|||
}
|
||||
|
||||
// if bot was unable to join team, and no menus popups, check for stacked team
|
||||
if (m_startAction == BotMsg::None && ++m_retryJoin > 3) {
|
||||
if (bots.isTeamStacked (m_wantedTeam - 1)) {
|
||||
if (m_startAction == BotMsg::None) {
|
||||
if (++m_retryJoin > 3 && bots.isTeamStacked (m_wantedTeam - 1)) {
|
||||
m_retryJoin = 0;
|
||||
|
||||
ctrl.msg ("Could not add bot to the game: Team is stacked (to disable this check, set mp_limitteams and mp_autoteambalance to zero and restart the round).");
|
||||
|
|
@ -1417,6 +1471,10 @@ void BotManager::captureChatRadio (const char *cmd, const char *arg, edict_t *en
|
|||
void BotManager::notifyBombDefuse () {
|
||||
// notify all terrorists that CT is starting bomb defusing
|
||||
|
||||
if (!isBombPlanted ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &bot : bots) {
|
||||
if (bot->m_team == Team::Terrorist && bot->m_notKilled && bot->getCurrentTaskId () != Task::MoveToPosition) {
|
||||
bot->clearSearchNodes ();
|
||||
|
|
@ -1584,7 +1642,7 @@ void BotManager::selectLeaders (int team, bool reset) {
|
|||
void BotManager::initRound () {
|
||||
// this is called at the start of each round
|
||||
|
||||
m_roundEnded = false;
|
||||
m_roundOver = false;
|
||||
|
||||
// check team economics
|
||||
for (int team = 0; team < kGameTeamNum; ++team) {
|
||||
|
|
@ -1611,6 +1669,7 @@ void BotManager::initRound () {
|
|||
m_bombSayStatus = BombPlantedSay::ChatSay | BombPlantedSay::Chatter;
|
||||
m_timeBombPlanted = 0.0f;
|
||||
m_plantSearchUpdateTime = 0.0f;
|
||||
m_autoKillCheckTime = 0.0f;
|
||||
m_botsCanPause = false;
|
||||
|
||||
resetFilters ();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ void MessageDispatcher::netMsgTextMsg () {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// reset bomb position for all the bots
|
||||
const auto resetBombPosition = [] () -> void {
|
||||
if (game.mapIs (MapFlags::Demolition)) {
|
||||
|
|
@ -115,7 +114,12 @@ void MessageDispatcher::netMsgShowMenu () {
|
|||
if (m_args.length () < min || !m_bot) {
|
||||
return;
|
||||
}
|
||||
m_bot->m_startAction = m_showMenuCache[m_args[menu].chars_];
|
||||
auto cached = m_showMenuCache[m_args[menu].chars_];
|
||||
|
||||
// only assign if non-zero
|
||||
if (cached > 0) {
|
||||
m_bot->m_startAction = cached;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageDispatcher::netMsgWeaponList () {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue