From 2a6ca1d91426d823526edc75f511fa95622dd811 Mon Sep 17 00:00:00 2001 From: jeefo Date: Sat, 1 Feb 2025 16:17:11 +0300 Subject: [PATCH] fix: breakable problems on some maps nav: do not consider busy nodes as long-radii nav: more fixes to player avoidance --- src/botlib.cpp | 20 ++++++++++++++++---- src/navigate.cpp | 38 +++++++++++++++++++++----------------- src/tasks.cpp | 14 ++++++++++++++ 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/botlib.cpp b/src/botlib.cpp index 17f2d88..85fa92d 100644 --- a/src/botlib.cpp +++ b/src/botlib.cpp @@ -268,7 +268,7 @@ edict_t *Bot::lookupBreakable () { // check if this isn't a triggered (bomb) breakable and if it takes damage. if true, shoot the crap! if (util.isBreakableEntity (hit)) { - m_breakableOrigin = tr.vecEndPos; + m_breakableOrigin = game.getEntityOrigin (hit); m_breakableEntity = hit; return hit; @@ -276,14 +276,26 @@ edict_t *Bot::lookupBreakable () { } return nullptr; }; + + auto isGoodForUs = [&] (edict_t *ent) -> bool { + if (game.isNullEntity (ent)) { + return false; + } + for (const auto &br : m_ignoredBreakable) { + if (br == ent) { + return false; + } + } + return true; + }; auto hit = doLookup (pev->origin, m_destOrigin, detectBreakableDistance); - if (!game.isNullEntity (hit)) { + if (isGoodForUs (hit)) { return hit; } hit = doLookup (getEyesPos (), m_destOrigin, detectBreakableDistance); - if (!game.isNullEntity (hit)) { + if (isGoodForUs (hit)) { return hit; } m_breakableEntity = nullptr; @@ -4146,7 +4158,7 @@ void Bot::enteredBuyZone (int buyState) { // if bot is in buy zone, try to buy ammo for this weapon... if (m_seeEnemyTime + 12.0f < game.time () - && m_lastEquipTime + 15.0f < game.time () + && m_lastEquipTime + 30.0f < game.time () && m_inBuyZone && (bots.getRoundStartTime () + rg (10.0f, 20.0f) + mp_buytime.as () < game.time ()) && !bots.isBombPlanted () diff --git a/src/navigate.cpp b/src/navigate.cpp index 4086c9c..ab3b443 100644 --- a/src/navigate.cpp +++ b/src/navigate.cpp @@ -474,19 +474,26 @@ void Bot::doPlayerAvoidance (const Vector &normal) { return; // no player avoiding when with semiclip plugin } m_hindrance = nullptr; - float distanceSq = cr::sqrf (512.0f); + float distanceSq = cr::sqrf (pev->maxspeed); const auto ownPrio = bots.getPlayerPriority (ent ()); - auto clearCamp = [] (edict_t *ent) { + auto clearCamp = [&] (edict_t *ent) { auto bot = bots[ent]; if (bot) { - auto tid = bot->getCurrentTaskId (); + const auto tid = bot->getCurrentTaskId (); + const auto tid2 = getCurrentTaskId (); - if (tid == Task::Camp || tid == Task::Hide || tid == Task::Pause) { + if ((m_currentNodeIndex == bot->m_currentNodeIndex) + && (tid == Task::Camp || tid == Task::Hide || tid == Task::Pause)) { bot->completeTask (); } + if ((m_currentNodeIndex == bot->m_currentNodeIndex) + && tid2 == Task::Camp || tid2 == Task::Hide || tid2 == Task::Pause) { + completeTask (); + findValidNode (); + } } }; @@ -499,6 +506,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) { // give some priorities to bot avoidance if (ownPrio < otherPrio) { + clearCamp (client.ent); continue; } @@ -508,6 +516,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) { // ignore because we're already avoiding someone better if (avoidPrio < otherPrio) { + clearCamp (m_hindrance); continue; } } @@ -551,7 +560,10 @@ void Bot::doPlayerAvoidance (const Vector &normal) { const auto &dir = (pev->origin - m_hindrance->v.origin).normalize2d_apx (); // to start strafing, we have to first figure out if the target is on the left side or right side - if (m_avoidAction == Dodge::None && m_path->radius > 16.0f && !isInNarrowPlace ()) { + if ((m_avoidAction == Dodge::None + && m_path->radius > 16.0f + && !isInNarrowPlace ()) + || m_moveSpeed < 0.0f) { if ((dir | right.normalize2d_apx ()) > 0.0f) { m_avoidAction = Dodge::Left; @@ -565,16 +577,12 @@ void Bot::doPlayerAvoidance (const Vector &normal) { setStrafeSpeed (normal, -pev->maxspeed); } } - m_isStuck = false; m_navTimeset = game.time (); if (distanceSq < cr::sqrf (96.0f)) { if ((dir | forward.normalize2d_apx ()) < 0.0f) { m_moveSpeed = -pev->maxspeed; } - else { - m_moveSpeed = pev->maxspeed; - } } ignoreCollision (); } @@ -1316,12 +1324,6 @@ bool Bot::updateNavigation () { desiredDistanceSq = 0.0f; } - // always increase reachability distance for occupied nodes - if (!(graph[m_path->number].flags & NodeFlag::Crouch) && isOccupiedNode (m_path->number, pathHasFlags)) { - desiredDistanceSq = cr::sqrf (96.0f); - nodeDistanceSq *= 0.5f; - } - // needs precise placement - check if we get past the point if (desiredDistanceSq < cr::sqrf (20.0f) && nodeDistanceSq < cr::sqrf (30.0f)) { const auto predictRangeSq = m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval); @@ -1344,7 +1346,7 @@ bool Bot::updateNavigation () { return true; } - if (nodeDistanceSq <= desiredDistanceSq) { + if (nodeDistanceSq < desiredDistanceSq) { // did we reach a destination node? if (getTask ()->data == m_currentNodeIndex) { if (m_chosenGoalIndex != kInvalidNodeIndex) { @@ -1816,7 +1818,9 @@ bool Bot::findNextBestNodeEx (const IntArray &data, bool handleFails) { lessDist[i] = kInfiniteDistance; lessIndex[i] = kInvalidNodeIndex; } - const auto &numToSkip = handleFails ? 1 : rg (1, 4); + + // in case low node density do not skip previous ones, in case of fail reduce max nodes to skip + const auto &numToSkip = graph.length () < 512 ? 0 : (handleFails ? 1 : rg (1, 4)); for (const auto &i : data) { const auto &path = graph[i]; diff --git a/src/tasks.cpp b/src/tasks.cpp index 1532c94..ab2a5cf 100644 --- a/src/tasks.cpp +++ b/src/tasks.cpp @@ -1467,6 +1467,20 @@ void Bot::shootBreakable_ () { completeTask (); return; } + else { + TraceResult tr {}; + game.testLine (pev->origin, m_breakableOrigin, TraceIgnore::None, ent (), &tr); + + if (tr.pHit != m_breakableEntity || !util.isVisible (tr.vecEndPos, ent ())) { + m_ignoredBreakable.push (tr.pHit); + + m_breakableEntity = nullptr; + m_breakableOrigin = nullptr; + + completeTask (); + return; + } + } m_aimFlags |= AimFlags::Override; pev->button |= m_campButtons;