nav: fallback to whole map search if buckets fails
bot: improved breakable destroying aim: improved short-range firing ctrl: prevent commands execution while disconnected from server build: fix cmake for apple silicon builds
This commit is contained in:
parent
7238fe76f5
commit
5eab5dfb3c
12 changed files with 100 additions and 90 deletions
|
|
@ -7,7 +7,6 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
project(yapb VERSION 4.5 LANGUAGES CXX)
|
project(yapb VERSION 4.5 LANGUAGES CXX)
|
||||||
|
|
||||||
if(NOT ANDROID)
|
if(NOT ANDROID)
|
||||||
|
|
@ -61,19 +60,23 @@ if(GIT_FOUND)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE VERSION_GENERATED)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE VERSION_GENERATED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm64")
|
||||||
|
set(BUILD_X86 true)
|
||||||
|
endif()
|
||||||
|
|
||||||
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MSVC)
|
if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MSVC)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -flto=auto -fno-exceptions -fno-rtti -fno-threadsafe-statics -pthread)
|
target_compile_options(${PROJECT_NAME} PRIVATE -flto=auto -fno-exceptions -fno-rtti -fno-threadsafe-statics -pthread)
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -march=armv8-a+fp+simd)
|
target_compile_options(${PROJECT_NAME} PRIVATE -march=armv8-a+fp+simd)
|
||||||
elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc")
|
elseif(BUILD_X86)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -mmmx -msse -msse2 -msse3 -mfpmath=sse)
|
target_compile_options(${PROJECT_NAME} PRIVATE -mmmx -msse -msse2 -msse3 -mfpmath=sse)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -funroll-loops -fomit-frame-pointer -fno-stack-protector -fvisibility=hidden -fvisibility-inlines-hidden -fno-math-errno)
|
target_compile_options(${PROJECT_NAME} PRIVATE -funroll-loops -fomit-frame-pointer -fno-stack-protector -fvisibility=hidden -fvisibility-inlines-hidden -fno-math-errno)
|
||||||
|
|
||||||
if(NOT WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm" AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc")
|
if(BUILD_X86)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -fdata-sections -ffunction-sections -fcf-protection=none -fno-plt)
|
target_compile_options(${PROJECT_NAME} PRIVATE -fdata-sections -ffunction-sections -fcf-protection=none -fno-plt)
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/ext/ldscripts/version.lds -Wl,--gc-sections)
|
target_link_options(${PROJECT_NAME} PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/ext/ldscripts/version.lds -Wl,--gc-sections)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -434,7 +434,7 @@ namespace TaskPri {
|
||||||
constexpr auto kInfiniteDistance = 9999999.0f;
|
constexpr auto kInfiniteDistance = 9999999.0f;
|
||||||
constexpr auto kInvalidLightLevel = kInfiniteDistance;
|
constexpr auto kInvalidLightLevel = kInfiniteDistance;
|
||||||
constexpr auto kGrenadeCheckTime = 0.6f;
|
constexpr auto kGrenadeCheckTime = 0.6f;
|
||||||
constexpr auto kSprayDistance = 360.0f;
|
constexpr auto kSprayDistance = 272.0f;
|
||||||
constexpr auto kSprayDistanceX2 = kSprayDistance * 2;
|
constexpr auto kSprayDistanceX2 = kSprayDistance * 2;
|
||||||
constexpr auto kMaxChatterRepeatInterval = 99.0f;
|
constexpr auto kMaxChatterRepeatInterval = 99.0f;
|
||||||
constexpr auto kViewFrameUpdate = 1.0f / 25.0f;
|
constexpr auto kViewFrameUpdate = 1.0f / 25.0f;
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ private:
|
||||||
bool m_rapidOutput {};
|
bool m_rapidOutput {};
|
||||||
bool m_isMenuFillCommand {};
|
bool m_isMenuFillCommand {};
|
||||||
bool m_ignoreTranslate {};
|
bool m_ignoreTranslate {};
|
||||||
|
bool m_denyCommands {};
|
||||||
|
|
||||||
int m_menuServerFillTeam {};
|
int m_menuServerFillTeam {};
|
||||||
int m_interMenuData[4] = { 0, };
|
int m_interMenuData[4] = { 0, };
|
||||||
|
|
@ -185,6 +186,10 @@ public:
|
||||||
m_rapidOutput = force;
|
m_rapidOutput = force;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDenyCommands (bool deny) {
|
||||||
|
m_denyCommands = deny;
|
||||||
|
}
|
||||||
|
|
||||||
void setIssuer (edict_t *ent) {
|
void setIssuer (edict_t *ent) {
|
||||||
m_ent = ent;
|
m_ent = ent;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@ private:
|
||||||
IntArray m_sniperPoints {};
|
IntArray m_sniperPoints {};
|
||||||
IntArray m_rescuePoints {};
|
IntArray m_rescuePoints {};
|
||||||
IntArray m_visitedGoals {};
|
IntArray m_visitedGoals {};
|
||||||
|
IntArray m_nodeNumbers {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SmallArray <Path> m_paths {};
|
SmallArray <Path> m_paths {};
|
||||||
|
|
@ -350,6 +351,11 @@ public:
|
||||||
memcpy (&m_graphHeader, hdr, sizeof (StorageHeader));
|
memcpy (&m_graphHeader, hdr, sizeof (StorageHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gets the node numbers
|
||||||
|
const IntArray &getNodeNumbers () {
|
||||||
|
return m_nodeNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// graph helper for sending message to correct channel
|
// graph helper for sending message to correct channel
|
||||||
template <typename ...Args> void msg (const char *fmt, Args &&...args);
|
template <typename ...Args> void msg (const char *fmt, Args &&...args);
|
||||||
|
|
|
||||||
|
|
@ -760,6 +760,7 @@ public:
|
||||||
bool hasShield ();
|
bool hasShield ();
|
||||||
bool isShieldDrawn ();
|
bool isShieldDrawn ();
|
||||||
bool findNextBestNode ();
|
bool findNextBestNode ();
|
||||||
|
bool findNextBestNodeEx (const IntArray &data, bool returnFailure);
|
||||||
bool seesEntity (const Vector &dest, bool fromBody = false);
|
bool seesEntity (const Vector &dest, bool fromBody = false);
|
||||||
|
|
||||||
int getAmmo ();
|
int getAmmo ();
|
||||||
|
|
|
||||||
|
|
@ -161,8 +161,10 @@ void Bot::checkBreakable (edict_t *touch) {
|
||||||
m_breakableEntity = lookupBreakable ();
|
m_breakableEntity = lookupBreakable ();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_breakableEntity = touch;
|
if (m_breakableEntity != touch) {
|
||||||
m_breakableOrigin = game.getEntityOrigin (touch);
|
m_breakableEntity = touch;
|
||||||
|
m_breakableOrigin = game.getEntityOrigin (touch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-check from previous steps
|
// re-check from previous steps
|
||||||
|
|
@ -177,6 +179,7 @@ void Bot::checkBreakablesAround () {
|
||||||
if (!m_buyingFinished
|
if (!m_buyingFinished
|
||||||
|| !cv_destroy_breakables_around
|
|| !cv_destroy_breakables_around
|
||||||
|| usesKnife ()
|
|| usesKnife ()
|
||||||
|
|| usesSniper ()
|
||||||
|| rg.chance (25)
|
|| rg.chance (25)
|
||||||
|| !game.hasBreakables ()
|
|| !game.hasBreakables ()
|
||||||
|| m_seeEnemyTime + 4.0f > game.time ()
|
|| m_seeEnemyTime + 4.0f > game.time ()
|
||||||
|
|
@ -208,7 +211,7 @@ void Bot::checkBreakablesAround () {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &origin = game.getEntityOrigin (breakable);
|
const auto &origin = game.getEntityOrigin (breakable);
|
||||||
const auto distanceToObstacleSq = origin.distanceSq (pev->origin);
|
const auto distanceToObstacleSq = origin.distanceSq2d (pev->origin);
|
||||||
|
|
||||||
// too far, skip it
|
// too far, skip it
|
||||||
if (distanceToObstacleSq > cr::sqrf (radius)) {
|
if (distanceToObstacleSq > cr::sqrf (radius)) {
|
||||||
|
|
@ -221,7 +224,7 @@ void Bot::checkBreakablesAround () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe time to give up?
|
// maybe time to give up?
|
||||||
if (m_lastBreakable == breakable && m_breakableTime + 1.0f < game.time ()) {
|
if (m_lastBreakable == breakable && m_breakableTime + 1.5f < game.time ()) {
|
||||||
m_ignoredBreakable.emplace (breakable);
|
m_ignoredBreakable.emplace (breakable);
|
||||||
m_breakableOrigin.clear ();
|
m_breakableOrigin.clear ();
|
||||||
|
|
||||||
|
|
@ -250,6 +253,12 @@ void Bot::checkBreakablesAround () {
|
||||||
edict_t *Bot::lookupBreakable () {
|
edict_t *Bot::lookupBreakable () {
|
||||||
// this function checks if bot is blocked by a shoot able breakable in his moving direction
|
// this function checks if bot is blocked by a shoot able breakable in his moving direction
|
||||||
|
|
||||||
|
// we're got something already
|
||||||
|
if (util.isBreakableEntity (m_breakableEntity)) {
|
||||||
|
return m_breakableEntity;
|
||||||
|
}
|
||||||
|
const float detectBreakableDistance = (usesKnife () || isOnLadder ()) ? 32.0f : rg (72.0f, 256.0f);
|
||||||
|
|
||||||
auto doLookup = [&] (const Vector &start, const Vector &end, const float dist) -> edict_t * {
|
auto doLookup = [&] (const Vector &start, const Vector &end, const float dist) -> edict_t * {
|
||||||
TraceResult tr {};
|
TraceResult tr {};
|
||||||
game.testLine (start, start + (end - start).normalize_apx () * dist, TraceIgnore::None, ent (), &tr);
|
game.testLine (start, start + (end - start).normalize_apx () * dist, TraceIgnore::None, ent (), &tr);
|
||||||
|
|
@ -267,56 +276,18 @@ edict_t *Bot::lookupBreakable () {
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
|
auto hit = doLookup (pev->origin, m_destOrigin, detectBreakableDistance);
|
||||||
|
|
||||||
// got recipe from KWo
|
if (!game.isNullEntity (hit)) {
|
||||||
for (auto i = 0; i < 5; ++i) {
|
return hit;
|
||||||
if (i == 1 && game.isNullEntity (m_breakableEntity)) {
|
}
|
||||||
continue;
|
hit = doLookup (getEyesPos (), m_destOrigin, detectBreakableDistance);
|
||||||
}
|
|
||||||
Vector end = m_pathOrigin;
|
|
||||||
Vector start = getEyesPos ();
|
|
||||||
|
|
||||||
if (graph.exists (m_currentNodeIndex)) {
|
if (!game.isNullEntity (hit)) {
|
||||||
end = graph[m_currentNodeIndex].origin;
|
return hit;
|
||||||
}
|
|
||||||
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
if (graph.exists (m_previousNodes[0])) {
|
|
||||||
start = graph[m_previousNodes[0]].origin;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
start = getEyesPos ();
|
|
||||||
end = game.getEntityOrigin (m_breakableEntity);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
start = pev->origin;
|
|
||||||
end = m_destOrigin;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
start = getEyesPos ();
|
|
||||||
end = m_destOrigin;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
start = getEyesPos ();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto hit = doLookup (start, end, (usesKnife () || isOnLadder ()) ? 32.0f : rg (72.0f, 256.0f));
|
|
||||||
|
|
||||||
if (!game.isNullEntity (hit)) {
|
|
||||||
return hit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_breakableEntity = nullptr;
|
m_breakableEntity = nullptr;
|
||||||
m_breakableOrigin.clear ();
|
m_breakableOrigin = nullptr;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1076,7 +1076,7 @@ bool Bot::checkZoom (float distance) {
|
||||||
return zoomChange;
|
return zoomChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::selectWeapons (float distance, int index, int id, int choosen) {
|
void Bot::selectWeapons (float distance, int, int id, int choosen) {
|
||||||
const auto tab = conf.getRawWeapons ();
|
const auto tab = conf.getRawWeapons ();
|
||||||
|
|
||||||
// we want to fire weapon, don't reload now
|
// we want to fire weapon, don't reload now
|
||||||
|
|
@ -1150,7 +1150,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
|
||||||
const float timeDelta = game.time () - m_frameInterval;
|
const float timeDelta = game.time () - m_frameInterval;
|
||||||
|
|
||||||
// need to care for burst fire?
|
// need to care for burst fire?
|
||||||
if (distance < kSprayDistance || m_blindTime > game.time () || usesKnife ()) {
|
if ((distance < kSprayDistance && !isRecoilHigh ()) || m_blindTime > game.time () || usesKnife ()) {
|
||||||
if (id == Weapon::Knife) {
|
if (id == Weapon::Knife) {
|
||||||
if (distance < 64.0f) {
|
if (distance < 64.0f) {
|
||||||
const auto primaryAttackChance = (m_oldButtons & IN_ATTACK2) ? 80 : 40;
|
const auto primaryAttackChance = (m_oldButtons & IN_ATTACK2) ? 80 : 40;
|
||||||
|
|
@ -1165,7 +1165,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// if automatic weapon press attack
|
// if automatic weapon press attack
|
||||||
if (tab[choosen].primaryFireHold && getAmmoInClip () > tab[index].minPrimaryAmmo) {
|
if (tab[choosen].primaryFireHold) {
|
||||||
pev->button |= IN_ATTACK;
|
pev->button |= IN_ATTACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2207,6 +2207,10 @@ BotControl::BotControl () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotControl::handleEngineCommands () {
|
void BotControl::handleEngineCommands () {
|
||||||
|
if (m_denyCommands) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
collectArgs ();
|
collectArgs ();
|
||||||
setIssuer (game.getLocalEntity ());
|
setIssuer (game.getLocalEntity ());
|
||||||
|
|
||||||
|
|
@ -2215,6 +2219,10 @@ void BotControl::handleEngineCommands () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotControl::handleClientSideCommandsWrapper (edict_t *ent, bool isMenus) {
|
bool BotControl::handleClientSideCommandsWrapper (edict_t *ent, bool isMenus) {
|
||||||
|
if (m_denyCommands) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
collectArgs ();
|
collectArgs ();
|
||||||
setIssuer (ent);
|
setIssuer (ent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ void Game::precache () {
|
||||||
void Game::levelInitialize (edict_t *entities, int max) {
|
void Game::levelInitialize (edict_t *entities, int max) {
|
||||||
// this function precaches needed models and initialize class variables
|
// this function precaches needed models and initialize class variables
|
||||||
|
|
||||||
|
// enable command handling
|
||||||
|
ctrl.setDenyCommands (false);
|
||||||
|
|
||||||
// re-initialize bot's array
|
// re-initialize bot's array
|
||||||
bots.destroy ();
|
bots.destroy ();
|
||||||
|
|
||||||
|
|
@ -215,6 +218,10 @@ void Game::levelShutdown () {
|
||||||
|
|
||||||
// suspend any analyzer tasks
|
// suspend any analyzer tasks
|
||||||
analyzer.suspend ();
|
analyzer.suspend ();
|
||||||
|
|
||||||
|
// disable command handling
|
||||||
|
ctrl.setDenyCommands (true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type) {
|
void Game::drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type) {
|
||||||
|
|
@ -761,7 +768,7 @@ bool Game::loadCSBinary () {
|
||||||
|
|
||||||
// lookup for x64 binaries first
|
// lookup for x64 binaries first
|
||||||
if (plat.x64) {
|
if (plat.x64) {
|
||||||
libs.insert (0, { "mp_amd64", "cs_amd64" });
|
libs.insert (0, { "mp_amd64", "mp_arm64", "cs_arm64", "cs_amd64" });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto libCheck = [&] (StringRef mod, StringRef dll) {
|
auto libCheck = [&] (StringRef mod, StringRef dll) {
|
||||||
|
|
|
||||||
|
|
@ -1663,6 +1663,7 @@ void BotGraph::populateNodes () {
|
||||||
m_rescuePoints.clear ();
|
m_rescuePoints.clear ();
|
||||||
m_sniperPoints.clear ();
|
m_sniperPoints.clear ();
|
||||||
m_visitedGoals.clear ();
|
m_visitedGoals.clear ();
|
||||||
|
m_nodeNumbers.clear ();
|
||||||
|
|
||||||
for (const auto &path : m_paths) {
|
for (const auto &path : m_paths) {
|
||||||
if (path.flags & NodeFlag::TerroristOnly) {
|
if (path.flags & NodeFlag::TerroristOnly) {
|
||||||
|
|
@ -1683,6 +1684,7 @@ void BotGraph::populateNodes () {
|
||||||
else if (path.flags & NodeFlag::Rescue) {
|
else if (path.flags & NodeFlag::Rescue) {
|
||||||
m_rescuePoints.push (path.number);
|
m_rescuePoints.push (path.number);
|
||||||
}
|
}
|
||||||
|
m_nodeNumbers.push (path.number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2275,7 +2277,7 @@ void BotGraph::frame () {
|
||||||
|
|
||||||
// draw the radius circle
|
// draw the radius circle
|
||||||
Vector origin = (path.flags & NodeFlag::Crouch) ? path.origin : path.origin - Vector (0.0f, 0.0f, 18.0f);
|
Vector origin = (path.flags & NodeFlag::Crouch) ? path.origin : path.origin - Vector (0.0f, 0.0f, 18.0f);
|
||||||
Color radiusColor { 36, 36, 255 };
|
static Color radiusColor { 36, 36, 255 };
|
||||||
|
|
||||||
// if radius is nonzero, draw a full circle
|
// if radius is nonzero, draw a full circle
|
||||||
if (path.radius > 0.0f) {
|
if (path.radius > 0.0f) {
|
||||||
|
|
@ -2805,13 +2807,6 @@ BotGraph::BotGraph () {
|
||||||
m_facingAtIndex = kInvalidNodeIndex;
|
m_facingAtIndex = kInvalidNodeIndex;
|
||||||
m_isOnLadder = false;
|
m_isOnLadder = false;
|
||||||
|
|
||||||
m_terrorPoints.clear ();
|
|
||||||
m_ctPoints.clear ();
|
|
||||||
m_goalPoints.clear ();
|
|
||||||
m_campPoints.clear ();
|
|
||||||
m_rescuePoints.clear ();
|
|
||||||
m_sniperPoints.clear ();
|
|
||||||
|
|
||||||
m_editFlags = 0;
|
m_editFlags = 0;
|
||||||
|
|
||||||
m_pathDisplayTime = 0.0f;
|
m_pathDisplayTime = 0.0f;
|
||||||
|
|
|
||||||
|
|
@ -1751,7 +1751,24 @@ bool Bot::findNextBestNode () {
|
||||||
// this function find a node in the near of the bot if bot had lost his path of pathfinder needs
|
// this function find a node in the near of the bot if bot had lost his path of pathfinder needs
|
||||||
// to be restarted over again.
|
// to be restarted over again.
|
||||||
|
|
||||||
int busyIndex = kInvalidNodeIndex;
|
const auto &origin = pev->origin + Vector { pev->velocity.x, pev->velocity.y, 0.0f } * m_frameInterval;
|
||||||
|
const auto &bucket = graph.getNodesInBucket (origin);
|
||||||
|
|
||||||
|
// maximum number of nodes to recheck without buckets
|
||||||
|
constexpr auto kNearestRecheckThreshold = 1200;
|
||||||
|
|
||||||
|
// try to search in buckets first
|
||||||
|
if (!findNextBestNodeEx (bucket, graph.length () < kNearestRecheckThreshold ? true : false)) {
|
||||||
|
|
||||||
|
// fallback to nearest search instead
|
||||||
|
return findNextBestNodeEx (graph.getNodeNumbers (), false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bot::findNextBestNodeEx (const IntArray &data, bool returnFailure) {
|
||||||
|
// this function find a node in the near of the bot if bot had lost his path of pathfinder needs
|
||||||
|
// to be restarted over again.
|
||||||
|
|
||||||
float lessDist[3] {};
|
float lessDist[3] {};
|
||||||
int lessIndex[3] {};
|
int lessIndex[3] {};
|
||||||
|
|
@ -1760,12 +1777,9 @@ bool Bot::findNextBestNode () {
|
||||||
lessDist[i] = kInfiniteDistance;
|
lessDist[i] = kInfiniteDistance;
|
||||||
lessIndex[i] = kInvalidNodeIndex;
|
lessIndex[i] = kInvalidNodeIndex;
|
||||||
}
|
}
|
||||||
|
const auto &numToSkip = returnFailure ? 0 : cr::clamp (rg (0, 2), 0, static_cast <int> (data.length () / 2));
|
||||||
|
|
||||||
const auto &origin = pev->origin + pev->velocity * m_frameInterval;
|
for (const auto &i : data) {
|
||||||
const auto &bucket = graph.getNodesInBucket (origin);
|
|
||||||
const auto &numToSkip = cr::clamp (rg (0, 2), 0, static_cast <int> (bucket.length () / 2));
|
|
||||||
|
|
||||||
for (const auto &i : bucket) {
|
|
||||||
const auto &path = graph[i];
|
const auto &path = graph[i];
|
||||||
|
|
||||||
if (!graph.exists (path.number)) {
|
if (!graph.exists (path.number)) {
|
||||||
|
|
@ -1801,12 +1815,6 @@ bool Bot::findNextBestNode () {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if node is already used by another bot...
|
|
||||||
if (bots.getRoundStartTime () + 5.0f < game.time () && isOccupiedNode (path.number)) {
|
|
||||||
busyIndex = path.number;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore non-reacheable nodes...
|
// ignore non-reacheable nodes...
|
||||||
if (!isReachableNode (path.number)) {
|
if (!isReachableNode (path.number)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1845,13 +1853,11 @@ bool Bot::findNextBestNode () {
|
||||||
}
|
}
|
||||||
selected = lessIndex[index];
|
selected = lessIndex[index];
|
||||||
|
|
||||||
// if we're still have no node and have busy one (by other bot) pick it up
|
|
||||||
if (selected == kInvalidNodeIndex && busyIndex != kInvalidNodeIndex) {
|
|
||||||
selected = busyIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// worst case... find at least something
|
// worst case... find at least something
|
||||||
if (selected == kInvalidNodeIndex) {
|
if (selected == kInvalidNodeIndex) {
|
||||||
|
if (returnFailure) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
selected = findNearestNode ();
|
selected = findNearestNode ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1977,7 +1983,7 @@ int Bot::findNearestNode () {
|
||||||
// try to search ANYTHING that can be reached
|
// try to search ANYTHING that can be reached
|
||||||
if (!graph.exists (index)) {
|
if (!graph.exists (index)) {
|
||||||
nearestDistanceSq = cr::sqrf (kMaxDistance);
|
nearestDistanceSq = cr::sqrf (kMaxDistance);
|
||||||
const auto &nearestNodes = graph.getNearestInRadius (kMaxDistance, pev->origin);
|
const auto &nearestNodes = graph.getNodeNumbers ();
|
||||||
|
|
||||||
for (const auto &i : nearestNodes) {
|
for (const auto &i : nearestNodes) {
|
||||||
const auto &path = graph[i];
|
const auto &path = graph[i];
|
||||||
|
|
|
||||||
|
|
@ -1460,13 +1460,13 @@ void Bot::escapeFromBomb_ () {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::shootBreakable_ () {
|
void Bot::shootBreakable_ () {
|
||||||
m_aimFlags |= AimFlags::Override;
|
|
||||||
|
|
||||||
// breakable destroyed?
|
// breakable destroyed?
|
||||||
if (!util.isBreakableEntity (m_breakableEntity)) {
|
if (!util.isBreakableEntity (m_breakableEntity)) {
|
||||||
completeTask ();
|
completeTask ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_aimFlags |= AimFlags::Override;
|
||||||
pev->button |= m_campButtons;
|
pev->button |= m_campButtons;
|
||||||
|
|
||||||
m_checkTerrain = false;
|
m_checkTerrain = false;
|
||||||
|
|
@ -1475,19 +1475,27 @@ void Bot::shootBreakable_ () {
|
||||||
m_navTimeset = game.time ();
|
m_navTimeset = game.time ();
|
||||||
m_lookAtSafe = m_breakableOrigin;
|
m_lookAtSafe = m_breakableOrigin;
|
||||||
|
|
||||||
// is bot facing the breakable?
|
const float distToObstacle = pev->origin.distanceSq (m_lookAtSafe);
|
||||||
if (util.getConeDeviation (ent (), m_lookAtSafe) >= 0.95f) {
|
|
||||||
m_aimFlags |= AimFlags::Override;
|
|
||||||
|
|
||||||
|
// is bot facing the breakable?
|
||||||
|
if (util.getConeDeviation (ent (), m_lookAtSafe) >= 0.90f) {
|
||||||
m_moveSpeed = 0.0f;
|
m_moveSpeed = 0.0f;
|
||||||
m_strafeSpeed = 0.0f;
|
m_strafeSpeed = 0.0f;
|
||||||
|
|
||||||
m_wantsToFire = true;
|
m_wantsToFire = true;
|
||||||
m_shootTime = game.time ();
|
m_shootTime = game.time ();
|
||||||
|
|
||||||
|
// enforce shooting
|
||||||
|
if (!usesKnife () && !m_isReloading && !(pev->button & IN_RELOAD) && getAmmoInClip () > 0) {
|
||||||
|
if (!(m_oldButtons & IN_ATTACK)) {
|
||||||
|
pev->button |= IN_ATTACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if with knife with no ammo, recompute breakable distance
|
||||||
if (!hasAnyAmmoInClip ()
|
if (!hasAnyAmmoInClip ()
|
||||||
&& usesKnife ()
|
&& usesKnife ()
|
||||||
&& pev->origin.distanceSq (m_lookAtSafe) > cr::sqrf (72.0f)) {
|
&& distToObstacle > cr::sqrf (72.0f)) {
|
||||||
|
|
||||||
completeTask ();
|
completeTask ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue