diff --git a/cfg/addons/yapb/conf/lang/chs_lang.cfg b/cfg/addons/yapb/conf/lang/chs_lang.cfg index fde55a3..4887c6a 100644 --- a/cfg/addons/yapb/conf/lang/chs_lang.cfg +++ b/cfg/addons/yapb/conf/lang/chs_lang.cfg @@ -1637,10 +1637,10 @@ Forces all the bot to vote to specified map. 强制所有人机投票给指定地图。 [ORIGINAL] -Sets the bots weapon mode to use +Sets the bots weapon mode to use. [TRANSLATED] -设置人机的武器模式 +设置人机的武器模式。 [ORIGINAL] Opens the main bot menu, or command menu if specified. diff --git a/cfg/addons/yapb/conf/lang/de_lang.cfg b/cfg/addons/yapb/conf/lang/de_lang.cfg index 92805af..4947630 100644 --- a/cfg/addons/yapb/conf/lang/de_lang.cfg +++ b/cfg/addons/yapb/conf/lang/de_lang.cfg @@ -1400,10 +1400,10 @@ Forces all the bot to vote to specified map. Zwingt alle Bots, für die angegebene Karte zu stimmen. [ORIGINAL] -Sets the bots weapon mode to use +Sets the bots weapon mode to use. [TRANSLATED] -Legt den zu verwendenden Waffenmodus des Bots fest +Legt den zu verwendenden Waffenmodus des Bots fest. [ORIGINAL] Opens the main bot menu, or command menu if specified. diff --git a/cfg/addons/yapb/conf/lang/en_names.cfg b/cfg/addons/yapb/conf/lang/en_names.cfg index a46f778..d959ce9 100644 --- a/cfg/addons/yapb/conf/lang/en_names.cfg +++ b/cfg/addons/yapb/conf/lang/en_names.cfg @@ -9,7 +9,6 @@ hoop -|NoS|- -Chrono bobjones dawgz The BiG SMUT diff --git a/cfg/addons/yapb/conf/lang/ru_lang.cfg b/cfg/addons/yapb/conf/lang/ru_lang.cfg index cf5e540..86af0a9 100644 --- a/cfg/addons/yapb/conf/lang/ru_lang.cfg +++ b/cfg/addons/yapb/conf/lang/ru_lang.cfg @@ -1636,10 +1636,10 @@ Forces all the bot to vote to specified map. Принуждает всех ботов голосовать за указанную карту. [ORIGINAL] -Sets the bots weapon mode to use +Sets the bots weapon mode to use. [TRANSLATED] -Настроить режим используемого ботами оружия +Настроить режим используемого ботами оружия. [ORIGINAL] Opens the main bot menu, or command menu if specified. diff --git a/inc/control.h b/inc/control.h index b7b8fdb..b11c602 100644 --- a/inc/control.h +++ b/inc/control.h @@ -157,10 +157,23 @@ private: int menuGraphPath (int item); int menuCampDirections (int item); int menuAutoPathDistance (int item); - int menuKickPage1 (int item); - int menuKickPage2 (int item); - int menuKickPage3 (int item); - int menuKickPage4 (int item); + + int menuKickPage1 (int item) { + return menuKickPage (1, item); + } + + int menuKickPage2 (int item) { + return menuKickPage (2, item); + } + + int menuKickPage3 (int item) { + return menuKickPage (3, item); + } + + int menuKickPage4 (int item) { + return menuKickPage (4, item); + } + int menuKickPage (int page, int item); private: void createMenus (); diff --git a/inc/fakeping.h b/inc/fakeping.h index 3d771ee..77e3220 100644 --- a/inc/fakeping.h +++ b/inc/fakeping.h @@ -77,9 +77,6 @@ public: // bot fakeping manager class BotFakePingManager final : public Singleton { -private: - mutable Mutex m_cs {}; - private: CountdownTimer m_recalcTime {}; PingBitMsg m_pbm {}; diff --git a/inc/manager.h b/inc/manager.h index 2a9f169..c2748f6 100644 --- a/inc/manager.h +++ b/inc/manager.h @@ -59,6 +59,8 @@ private: edict_t *m_killerEntity {}; // killer entity for bots BotTeamData m_teamData[kGameTeamNum] {}; // teams shared data + CountdownTimer m_holdQuotaManagementTimer {}; // prevent from running quota management for some time + protected: BotCreateResult create (StringRef name, int difficulty, int personality, int team, int skin); diff --git a/inc/planner.h b/inc/planner.h index a2b6184..e3c2ebf 100644 --- a/inc/planner.h +++ b/inc/planner.h @@ -275,6 +275,10 @@ public: return m_pathsCheckFailed; } + void setPathsCheckFailed (const bool value) { + m_pathsCheckFailed = value; + } + public: // do the pathfinding bool find (int srcIndex, int destIndex, NodeAdderFn onAddedNode, int *pathDistance = nullptr); diff --git a/inc/practice.h b/inc/practice.h index 0dc43c1..fff0bc1 100644 --- a/inc/practice.h +++ b/inc/practice.h @@ -124,7 +124,6 @@ public: } void setHighestDamageForTeam (int32_t team, int32_t value) { - MutexScopedLock lock (m_damageUpdateLock); m_teamHighestDamage[team] = value; } }; diff --git a/inc/product.h b/inc/product.h index 3151375..64abf32 100644 --- a/inc/product.h +++ b/inc/product.h @@ -58,7 +58,7 @@ public: ~Folders () = default; public: - CTS_BUILD_STR bot { "yapb" }; + CTS_BUILD_STR bot { product.nameLower }; CTS_BUILD_STR addons { "addons" }; CTS_BUILD_STR config { "conf" }; CTS_BUILD_STR data { "data" }; diff --git a/inc/yapb.h b/inc/yapb.h index a56826d..23c109d 100644 --- a/inc/yapb.h +++ b/inc/yapb.h @@ -730,7 +730,6 @@ public: Array m_goalHist {}; FrameDelay m_thinkTimer {}; - FrameDelay m_fullThinkTimer {}; public: Bot (edict_t *bot, int difficulty, int personality, int team, int skin); @@ -738,7 +737,6 @@ public: public: void logic (); /// the things that can be executed while skipping frames - void upkeep (); void spawned (); void takeBlind (int alpha); void takeDamage (edict_t *inflictor, int damage, int armor, int bits); diff --git a/meson.build b/meson.build index 0a733fa..9bbfd8a 100644 --- a/meson.build +++ b/meson.build @@ -149,12 +149,14 @@ if cxx == 'clang' or cxx == 'gcc' '-fdata-sections', '-ffunction-sections', '-fcf-protection=none', - '-fno-plt' + '-fno-plt', + '-Wa,--noexecstack' ] ldflags += [ '-Wl,--version-script=' + meson.project_source_root() + '/ext/ldscripts/version.lds', - '-Wl,--gc-sections' + '-Wl,--gc-sections', + '-Wl,-z,noexecstack' ] else cxxflags += ['-DLINKENT_STATIC'] @@ -177,7 +179,7 @@ if cxx == 'clang' or cxx == 'gcc' ] endif else - cxxflags += ['-g3', '-ggdb', '-DDEBUG', '-D_FORTIFY_SOURCE=2'] + cxxflags += ['-g3', '-ggdb', '-DDEBUG'] endif # special script for mingw-64 builds diff --git a/src/botlib.cpp b/src/botlib.cpp index f70f183..0b38c0f 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -3053,12 +3053,7 @@ void Bot::frame () { if (m_thinkTimer.time < game.time ()) { m_thinkTimer.time = game.time () + m_thinkTimer.interval; - if (m_fullThinkTimer.time < game.time ()) { - m_fullThinkTimer.time = game.time () + m_fullThinkTimer.interval; - - update (); - } - upkeep (); + update (); } if (m_slowFrameTimestamp > game.time ()) { @@ -3182,6 +3177,7 @@ void Bot::update () { else if (!m_botMovement) { resetMovement (); } + runMovement (); } void Bot::logicDuringFreezetime () { @@ -3199,7 +3195,7 @@ void Bot::logicDuringFreezetime () { if (rg.chance (15) && m_jumpTime < game.time ()) { pev->button |= IN_JUMP; - m_jumpTime = game.time () + rg (1.0f, 2.0f); + m_jumpTime = game.time () + rg (1.0f, 3.0f); } static Array players {}; players.clear (); @@ -3253,7 +3249,7 @@ void Bot::logicDuringFreezetime () { m_needToSendWelcomeChat = false; } } - m_changeViewTime = game.time () + rg (1.25f, 2.0f); + m_changeViewTime = game.time () + rg (1.25f, 3.0f); } void Bot::executeTasks () { @@ -3389,6 +3385,9 @@ void Bot::logic () { m_isUsingGrenade = false; executeTasks (); // execute current task + setAimDirection (); // choose aim direction + updateLookAngles (); // and turn to chosen aim direction + doFireWeapons (); // fire the weapons // check for reloading if (m_reloadCheckTime <= game.time ()) { @@ -3471,14 +3470,6 @@ void Bot::logic () { m_lastDamageType = -1; // reset damage } -void Bot::upkeep () { - setAimDirection (); - doFireWeapons (); - - updateLookAngles (); - runMovement (); -} - void Bot::spawned () { if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) { newRound (); diff --git a/src/config.cpp b/src/config.cpp index eb0927e..45998f0 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -352,6 +352,7 @@ void BotConfig::loadChatterConfig () { { "Chatter_Camp", Chatter::Camping, 10.0f }, { "Chatter_OnARoll", Chatter::OnARoll, kMaxChatterRepeatInterval}, }; + Array badFiles {}; while (file.getLine (line)) { line.trim (); @@ -393,7 +394,7 @@ void BotConfig::loadChatterConfig () { m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration); } else { - game.print ("Warning: Couldn't get duration of sound '%s.wav.", sound); + badFiles.push (sound); } } sentences.clear (); @@ -402,6 +403,10 @@ void BotConfig::loadChatterConfig () { } } file.close (); + + if (!badFiles.empty ()) { + game.print ("Warning: Couldn't get duration of next chatter sounds: %s.", String::join (badFiles, ",")); + } } else { cv_radio_mode.set (1); diff --git a/src/control.cpp b/src/control.cpp index 055dfba..3fd7604 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -1742,7 +1742,7 @@ int BotControl::menuAutoPathDistance (int item) { return BotCommandResult::Handled; } -int BotControl::menuKickPage1 (int item) { +int BotControl::menuKickPage (int page, int item) { closeMenu (); // reset menu display switch (item) { @@ -1754,93 +1754,21 @@ int BotControl::menuKickPage1 (int item) { case 6: case 7: case 8: - bots.kickBot (item - 1); - kickBotByMenu (1); + bots.kickBot (item + (page - 1) * 8 - 1); + kickBotByMenu (page); break; case 9: - kickBotByMenu (2); + kickBotByMenu (page + 1); break; case 10: - showMenu (Menu::Control); - break; - } - return BotCommandResult::Handled; -} - -int BotControl::menuKickPage2 (int item) { - closeMenu (); // reset menu display - - switch (item) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - bots.kickBot (item + 8 - 1); - kickBotByMenu (2); - break; - - case 9: - kickBotByMenu (3); - break; - - case 10: - kickBotByMenu (1); - break; - } - return BotCommandResult::Handled; -} - -int BotControl::menuKickPage3 (int item) { - closeMenu (); // reset menu display - - switch (item) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - bots.kickBot (item + 16 - 1); - kickBotByMenu (3); - break; - - case 9: - kickBotByMenu (4); - break; - - case 10: - kickBotByMenu (2); - break; - } - return BotCommandResult::Handled; -} - -int BotControl::menuKickPage4 (int item) { - closeMenu (); // reset menu display - - switch (item) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - bots.kickBot (item + 24 - 1); - kickBotByMenu (4); - break; - - case 10: - kickBotByMenu (3); + if (page == 1) { + showMenu (Menu::Control); + } + else { + kickBotByMenu (page - 1); + } break; } return BotCommandResult::Handled; @@ -2229,7 +2157,7 @@ BotControl::BotControl () { m_cmds.emplace ("kill/killbots/killall/kill_ct/kill_t", "kill [team] [silent]", "Kills the specified team / all the bots.", &BotControl::cmdKillBots); m_cmds.emplace ("fill/fillserver", "fill [team] [count] [difficulty] [personality]", "Fill the server (add bots) with specified parameters.", &BotControl::cmdFill); m_cmds.emplace ("vote/votemap", "vote [map_id]", "Forces all the bot to vote to specified map.", &BotControl::cmdVote); - m_cmds.emplace ("weapons/weaponmode", "weapons [knife|pistol|shotgun|smg|rifle|sniper|standard]", "Sets the bots weapon mode to use", &BotControl::cmdWeaponMode); + m_cmds.emplace ("weapons/weaponmode", "weapons [knife|pistol|shotgun|smg|rifle|sniper|standard]", "Sets the bots weapon mode to use.", &BotControl::cmdWeaponMode); m_cmds.emplace ("menu/botmenu", "menu [cmd]", "Opens the main bot menu, or command menu if specified.", &BotControl::cmdMenu); m_cmds.emplace ("version/ver/about", "version [no arguments]", "Displays version information about bot build.", &BotControl::cmdVersion); m_cmds.emplace ("graphmenu/wpmenu/wptmenu", "graphmenu [noarguments]", "Opens and displays bots graph editor.", &BotControl::cmdNodeMenu); diff --git a/src/engine.cpp b/src/engine.cpp index 78a8dee..44002e8 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -338,7 +338,7 @@ Vector Game::getEntityOrigin (edict_t *ent) { } if (ent->v.origin.empty ()) { - return ent->v.absmin + (ent->v.size * 0.5); + return ent->v.absmin + ent->v.size * 0.5; } return ent->v.origin; } @@ -935,7 +935,12 @@ bool Game::loadCSBinary () { } if (entity != nullptr) { - m_gameFlags |= (GameFlags::Modern | GameFlags::HasBotVoice | GameFlags::HasFakePings); + m_gameFlags |= (GameFlags::Modern | GameFlags::HasBotVoice); + + // no fake pings on xash3d + if (!(m_gameFlags & (GameFlags::Xash3D | GameFlags::Xash3DLegacy))) { + m_gameFlags |= GameFlags::HasFakePings; + } } else { m_gameFlags |= GameFlags::Legacy; diff --git a/src/fakeping.cpp b/src/fakeping.cpp index aa4b77f..9cfbe2b 100644 --- a/src/fakeping.cpp +++ b/src/fakeping.cpp @@ -40,8 +40,6 @@ void BotFakePingManager::reset (edict_t *to) { } void BotFakePingManager::syncCalculate () { - MutexScopedLock lock (m_cs); - int averagePing {}; if (cv_ping_count_real_players) { diff --git a/src/graph.cpp b/src/graph.cpp index 64314eb..dda415a 100644 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -576,7 +576,7 @@ IntArray BotGraph::getNearestInRadius (const float radius, const Vector &origin, if (bucket.length () < kMaxNodeLinks || radius > cr::sqrf (256.0f)) { for (const auto &path : m_paths) { - if (maxCount != -1 && static_cast (result.length ()) > maxCount) { + if (maxCount != -1 && result.length () > maxCount) { break; } @@ -588,7 +588,7 @@ IntArray BotGraph::getNearestInRadius (const float radius, const Vector &origin, } for (const auto &at : bucket) { - if (maxCount != -1 && static_cast (result.length ()) > maxCount) { + if (maxCount != -1 && result.length () > maxCount) { break; } @@ -1292,6 +1292,7 @@ void BotGraph::showFileInfo () { msg (" uncompressed_size: %dkB", info.uncompressed / 1024); msg (" options: %d", info.options); // display as string ? msg (" analyzed: %s", isAnalyzed () ? conf.translate ("yes") : conf.translate ("no")); // display as string ? + msg (" pathfinder: %s", planner.isPathsCheckFailed () ? "floyd" : "astar"); msg (""); diff --git a/src/linkage.cpp b/src/linkage.cpp index e516b48..139a71c 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -1023,15 +1023,15 @@ CR_EXPORT int Meta_Detach (PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { gpMetaUtilFuncs->pfnLogError (PLID, "%s: plugin NOT detaching (can't unload plugin right now)", Plugin_info.name); return HLFalse; // returning FALSE prevents metamod from unloading this plugin } + // stop the worker + worker.shutdown (); + // kick all bots off this server bots.kickEveryone (true); // save collected practice on shutdown practice.save (); - // stop the worker - worker.shutdown (); - // disable hooks fakequeries.disable (); diff --git a/src/manager.cpp b/src/manager.cpp index a243ada..1295985 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -348,6 +348,10 @@ void BotManager::maintainQuota () { // this function keeps number of bots up to date, and don't allow to maintain bot creation // while creation process in process. + if (!m_holdQuotaManagementTimer.elapsed ()) { + return; + } + if (graph.length () < 1 || graph.hasChanged ()) { if (cv_quota.as () > 0) { ctrl.msg ("There is no graph found. Cannot create bot."); @@ -707,8 +711,8 @@ void BotManager::kickBot (int index) { auto bot = findBotByIndex (index); if (bot) { - decrementQuota (); bot->kick (); + decrementQuota (); } } @@ -855,10 +859,15 @@ void BotManager::checkBotModel (edict_t *ent, char *infobuffer) { } void BotManager::checkNeedsToBeKicked () { + // this is called to check if bot is leaving server due to pathfinding error + // so this will cause to delay quota management stuff from executing for some time + for (const auto &bot : bots) { if (bot->m_kickMeFromServer) { + m_holdQuotaManagementTimer.start (10.0f); + m_addRequests.clear (); + bot->kick (); // kick bot from server if requested - break; } } } @@ -1118,6 +1127,8 @@ void BotManager::balanceBotDifficulties () { void BotManager::destroy () { // this function free all bots slots (used on server shutdown) + m_holdQuotaManagementTimer.invalidate (); // restart quota manager + for (auto &bot : m_bots) { bot->markStale (); } @@ -1739,15 +1750,12 @@ void Bot::newRound () { thinkInterval = 1.0f / 50.0f; // xash3d works acceptable at 50fps } } - auto fullThinkInterval = 1.0f / (thinkFps * 0.5f); // legacy games behaves strange, when this enabled, disable for xash3d as well if requested if (bots.isFrameSkipDisabled ()) { thinkInterval = 0.0f; - fullThinkInterval = 0.0f; } m_thinkTimer.interval = thinkInterval; - m_fullThinkTimer.interval = fullThinkInterval; } void Bot::resetPathSearchType () { @@ -1804,10 +1812,6 @@ void Bot::kick (bool silent) { } void Bot::markStale () { - // wait till threads tear down - MutexScopedLock lock1 (m_pathFindLock); - MutexScopedLock lock2 (m_predictLock); - // switch chatter icon off showChatterIcon (false, true); @@ -1817,6 +1821,10 @@ void Bot::markStale () { // mark bot as leaving m_isStale = true; + // wait till threads tear down + MutexScopedLock lock1 (m_pathFindLock); + MutexScopedLock lock2 (m_predictLock); + // clear the bot name conf.clearUsedName (this); @@ -2397,7 +2405,7 @@ bool BotManager::isLineBlockedBySmoke (const Vector &from, const Vector &to) { const float maxSmokedLength = 0.7f * kSmokeGrenadeRadius; // return true if the total length of smoke-covered line-of-sight is too much - return (totalSmokedLength > maxSmokedLength); + return totalSmokedLength > maxSmokedLength; } bool BotManager::isFrameSkipDisabled () { diff --git a/src/navigate.cpp b/src/navigate.cpp index ebd496c..f15b909 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -552,7 +552,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) { if (graph.exists (destIndex)) { findPath (m_currentNodeIndex, destIndex, other->m_pathType); - other->findPath (m_currentNodeIndex, destIndex); + other->findPath (m_currentNodeIndex, destIndex, m_pathType); } } } @@ -646,13 +646,6 @@ void Bot::checkTerrain (const Vector &dirNormal) { } } - if (m_probeTime >= game.time ()) { - m_isStuck = true; - } - else if (m_probeTime + randomProbeTime < game.time () && !cr::fzero (m_probeTime)) { - resetCollision (); // resets its collision state because it was too long time in probing state - } - // not stuck? if (!m_isStuck) { if (m_probeTime + randomProbeTime < game.time ()) { @@ -914,6 +907,15 @@ void Bot::checkFall () { return; } + // take in account node sequences levels to compensate surface inclining + if (m_previousNodes[0] != kInvalidNodeIndex) { + const auto &pn = graph[m_previousNodes[0]]; + + if (cr::abs (pn.origin.z - m_pathOrigin.z) < cv_graph_analyze_max_jump_height.as ()) { + return; + } + } + if (!m_checkFall) { if (isOnFloor ()) { m_checkFallPoint[0] = pev->origin; @@ -948,6 +950,7 @@ void Bot::checkFall () { && (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f) && baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) { fixFall = true; + } else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f && m_checkFallPoint[0].z > pev->origin.z + 128.0f) { @@ -1988,7 +1991,7 @@ float Bot::getEstimatedNodeReachTime () { } estimatedTime = cr::clamp (estimatedTime, 3.0f, longTermReachability ? 8.0f : 3.5f); } - return estimatedTime; + return estimatedTime += m_lastDamageTimestamp >= game.time () ? 1.0f : 0.0f; } void Bot::findValidNode () { @@ -3148,10 +3151,7 @@ bool Bot::checkWallOnLeft (float distance) { game.testLine (pev->origin, pev->origin - pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr); // check if the trace hit something... - if (tr.flFraction < 1.0f) { - return true; - } - return false; + return tr.flFraction < 1.0f; } bool Bot::checkWallOnRight (float distance) { @@ -3161,10 +3161,7 @@ bool Bot::checkWallOnRight (float distance) { game.testLine (pev->origin, pev->origin + pev->angles.right () * distance, TraceIgnore::Monsters, ent (), &tr); // check if the trace hit something... - if (tr.flFraction < 1.0f) { - return true; - } - return false; + return tr.flFraction < 1.0f; } bool Bot::checkWallOnBehind (float distance) { @@ -3174,10 +3171,7 @@ bool Bot::checkWallOnBehind (float distance) { game.testLine (pev->origin, pev->origin - pev->angles.forward () * distance, TraceIgnore::Monsters, ent (), &tr); // check if the trace hit something... - if (tr.flFraction < 1.0f) { - return true; - } - return false; + return tr.flFraction < 1.0f; } bool Bot::isDeadlyMove (const Vector &to) { @@ -3448,6 +3442,10 @@ bool Bot::isPreviousLadder () const { void Bot::findShortestPath (int srcIndex, int destIndex) { // this function finds the shortest path from source index to destination index + // stale bots shouldn't do pathfinding + if (m_isStale) { + return; + } clearSearchNodes (); m_chosenGoalIndex = srcIndex; @@ -3472,6 +3470,11 @@ void Bot::syncFindPath (int srcIndex, int destIndex, FindPath pathType) { } ScopedUnlock unlock (m_pathFindLock); + // stale bots shouldn't do pathfinding + if (m_isStale) { + return; + } + if (!graph.exists (srcIndex)) { srcIndex = changeNodeIndex (graph.getNearestNoBuckets (pev->origin, 256.0f)); diff --git a/src/planner.cpp b/src/planner.cpp index 2403ed4..f98eac6 100644 --- a/src/planner.cpp +++ b/src/planner.cpp @@ -274,6 +274,11 @@ AStarResult AStarAlgo::find (int botTeam, int srcIndex, int destIndex, NodeAdder // safes us from bad graph... if (m_routeQue.length () >= getMaxLength () - 1) { + m_routeQue.clear (); + + // infrom pathfinder to use floyds in that case + planner.setPathsCheckFailed (true); + return AStarResult::InternalError; } diff --git a/src/practice.cpp b/src/practice.cpp index 2e3b75e..4f51797 100644 --- a/src/practice.cpp +++ b/src/practice.cpp @@ -18,7 +18,6 @@ void BotPractice::setIndex (int32_t team, int32_t start, int32_t goal, int32_t v if (team != Team::Terrorist && team != Team::CT) { return; } - MutexScopedLock lock (m_damageUpdateLock); // reliability check if (!graph.exists (start) || !graph.exists (goal) || !graph.exists (value)) { @@ -38,7 +37,6 @@ void BotPractice::setValue (int32_t team, int32_t start, int32_t goal, int32_t v if (team != Team::Terrorist && team != Team::CT) { return; } - MutexScopedLock lock (m_damageUpdateLock); // reliability check if (!graph.exists (start) || !graph.exists (goal)) { @@ -58,7 +56,6 @@ void BotPractice::setDamage (int32_t team, int32_t start, int32_t goal, int32_t if (team != Team::Terrorist && team != Team::CT) { return; } - MutexScopedLock lock (m_damageUpdateLock); // reliability check if (!graph.exists (start) || !graph.exists (goal)) { @@ -72,6 +69,7 @@ float BotPractice::plannerGetDamage (int32_t team, int32_t start, int32_t goal, return 0.0f; } ScopedUnlock unlock (m_damageUpdateLock); + auto damage = static_cast (getDamage (team, start, goal)); if (addTeamHighestDamage) { @@ -97,6 +95,8 @@ void BotPractice::syncUpdate () { } auto adjustValues = false; + MutexScopedLock lock (m_damageUpdateLock); + // get the most dangerous node for this position for both teams for (int team = Team::Terrorist; team < kGameTeamNum; ++team) { auto bestIndex = kInvalidNodeIndex; // best index to store @@ -142,7 +142,6 @@ void BotPractice::syncUpdate () { } } } - MutexScopedLock lock (m_damageUpdateLock); for (int team = Team::Terrorist; team < kGameTeamNum; ++team) { m_teamHighestDamage[team] = cr::clamp (m_teamHighestDamage[team] - kHalfDamageVal, 1, kFullDamageVal); diff --git a/src/support.cpp b/src/support.cpp index 6ba2abc..04f0006 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -329,46 +329,37 @@ void BotSupport::checkWelcome () { } } -bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) { +bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, + bool needAlive, bool needDrawn, bool needBotWithC4) { + // this function finds nearest to to, player with set of parameters, like his // team, live status, search distance etc. if needBot is true, then pvHolder, will // be filled with bot pointer, else with edict pointer(!). searchDistance = cr::sqrf (searchDistance); - - edict_t *survive = nullptr; // pointer to temporally & survive entity - float nearestPlayer = 4096.0f; // nearest player - - const int toTeam = game.getTeam (to); + float nearestPlayerDistanceSq = cr::sqrf (4096.0f); // nearest player for (const auto &client : m_clients) { if (!(client.flags & ClientFlags::Used) || client.ent == to) { continue; } - if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & ClientFlags::Alive)) || (needBot && !bots[client.ent]) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) { + if ((sameTeam && client.team != game.getTeam (to)) + || (needAlive && !(client.flags & ClientFlags::Alive)) + || (needBot && !bots[client.ent]) + || (needDrawn && (client.ent->v.effects & EF_NODRAW)) + || (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) { + continue; // filter players with parameters } const float distanceSq = client.ent->v.origin.distanceSq (to->v.origin); - if (distanceSq < nearestPlayer && distanceSq < searchDistance) { - nearestPlayer = distanceSq; - survive = client.ent; + if (distanceSq < nearestPlayerDistanceSq && distanceSq < searchDistance) { + nearestPlayerDistanceSq = distanceSq; + *pvHolder = needBot ? reinterpret_cast (bots[client.ent]) : reinterpret_cast (client.ent); } } - - if (game.isNullEntity (survive)) { - return false; // nothing found - } - - // fill the holder - if (needBot) { - *pvHolder = reinterpret_cast (bots[survive]); - } - else { - *pvHolder = reinterpret_cast (survive); - } - return true; + return !!*pvHolder; } void BotSupport::updateClients () { diff --git a/src/vision.cpp b/src/vision.cpp index b4afe42..c1b9b6f 100644 --- a/src/vision.cpp +++ b/src/vision.cpp @@ -425,15 +425,24 @@ void Bot::setAimDirection () { if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) { // check if narrow place and we're duck, do not predict enemies in that situation - const bool duckedInNarrowPlace = isInNarrowPlace () && ((m_pathFlags & NodeFlag::Crouch) || (pev->button & IN_DUCK)); + const bool duckedInNarrowPlace = isInNarrowPlace () + && ((m_pathFlags & NodeFlag::Crouch) + || (pev->button & IN_DUCK)); + + if (duckedInNarrowPlace + || isOnLadder () + || isInWater () + || (m_pathFlags & NodeFlag::Ladder) + || (m_currentTravelFlags & PathFlag::Jump)) { - if (duckedInNarrowPlace || isOnLadder () || isInWater () || (m_pathFlags & NodeFlag::Ladder) || (m_currentTravelFlags & PathFlag::Jump)) { flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath); m_canChooseAimDirection = false; } // don't switch view right away after loosing focus with current enemy - if ((m_shootTime + rg (1.0f, 1.5f) > game.time () || m_seeEnemyTime + 1.5f > game.time ()) + if ((m_shootTime + rg (0.75f, 1.25f) > game.time () + || m_seeEnemyTime + 1.5f > game.time ()) + && m_forgetLastVictimTimer.elapsed () && !m_lastEnemyOrigin.empty () && util.isAlive (m_lastEnemy) @@ -619,7 +628,10 @@ void Bot::setAimDirection () { if (horizontalMovement && m_pathWalk.hasNext ()) { const auto &nextPath = graph[m_pathWalk.next ()]; - if ((nextPath.flags & NodeFlag::Ladder) && m_destOrigin.distanceSq (pev->origin) < cr::sqrf (128.0f) && nextPath.origin.z > m_pathOrigin.z + 26.0f) { + if ((nextPath.flags & NodeFlag::Ladder) + && m_destOrigin.distanceSq (pev->origin) < cr::sqrf (128.0f) + && nextPath.origin.z > m_pathOrigin.z + 26.0f) { + m_lookAt = nextPath.origin + pev->view_ofs; } } @@ -630,7 +642,10 @@ void Bot::setAimDirection () { } // try to look at last victim for a little, maybe there's some one else - if (game.isNullEntity (m_enemy) && m_difficulty >= Difficulty::Normal && !m_forgetLastVictimTimer.elapsed () && !m_lastVictimOrigin.empty ()) { + if (game.isNullEntity (m_enemy) && m_difficulty >= Difficulty::Normal + && !m_forgetLastVictimTimer.elapsed () + && !m_lastVictimOrigin.empty ()) { + m_lookAt = m_lastVictimOrigin + pev->view_ofs; } } diff --git a/vc/yapb.vcxproj b/vc/yapb.vcxproj index bc07e08..6fde8d5 100644 --- a/vc/yapb.vcxproj +++ b/vc/yapb.vcxproj @@ -324,7 +324,7 @@ true false stdcpp17 - ProgramDatabase + EditAndContinue NDEBUG;%(PreprocessorDefinitions)