nav: more fixes to ladder navigation

refactor: bot difficulty data and add graph refresh command
combat: fixes for smoke grenades (ref #743)
engine: fixes to spawn management (ref #744)
This commit is contained in:
jeefo 2025-11-12 21:31:23 +03:00
commit 17ed252b60
No known key found for this signature in database
GPG key ID: D696786B81B667C8
26 changed files with 506 additions and 408 deletions

View file

@ -230,7 +230,11 @@ void Bot::updateLookAngles () {
float angleDiffYaw = cr::anglesDifference (direction.y, m_idealAngles.y);
// prevent reverse facing angles when navigating normally
if (m_moveToGoal && !importantAimFlags && !m_pathOrigin.empty ()) {
if (m_moveToGoal
&& !importantAimFlags
&& !m_pathOrigin.empty ()
&& !isOnLadder ()) {
const float forward = (m_lookAt - pev->origin).yaw ();
if (!cr::fzero (forward)) {
@ -436,7 +440,7 @@ void Bot::setAimDirection () {
|| (m_currentTravelFlags & PathFlag::Jump)) {
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
m_canChooseAimDirection = false;
m_canSetAimDirection = false;
}
// don't switch view right away after loosing focus with current enemy
@ -532,7 +536,8 @@ void Bot::setAimDirection () {
}
const float distToPredictNodeSq = graph[predictNode].origin.distanceSq (pev->origin);
if (distToPredictNodeSq >= cr::sqrf (2048.0f)) {
if (distToPredictNodeSq >= cr::sqrf (2048.0f) ||
distToPredictNodeSq <= cr::sqrf (256.0f)) {
return false;
}
@ -542,7 +547,8 @@ void Bot::setAimDirection () {
return false;
}
return isNodeValidForPredict (predictNode) && pathLength < cv_max_nodes_for_predict.as <int> ();
return isNodeValidForPredict (predictNode) && pathLength < cv_max_nodes_for_predict.as <int> ()
&& numEnemiesNear (graph[predictNode].origin, 1024.0f) > 0;
};
if (changePredictedEnemy) {
@ -573,47 +579,21 @@ void Bot::setAimDirection () {
const auto &destOrigin = m_destOrigin + pev->view_ofs;
m_lookAt = destOrigin;
const bool horizontalMovement = (m_pathFlags & NodeFlag::Ladder) || isOnLadder ();
if (!horizontalMovement && m_moveToGoal && m_seeEnemyTime + 4.0f < game.time ()
&& !m_isStuck && !(pev->button & IN_DUCK)
&& m_currentNodeIndex != kInvalidNodeIndex
&& !(m_pathFlags & (NodeFlag::Ladder | NodeFlag::Crouch))
&& m_pathWalk.hasNext () && !isOnLadder ()
&& pev->origin.distanceSq (destOrigin) < cr::sqrf (512.0f)) {
const auto nextPathIndex = m_pathWalk.next ();
const auto nextPathX2 = m_pathWalk.nextX2 ();
if (vistab.visible (m_currentNodeIndex, nextPathX2)) {
const auto &gn = graph[nextPathX2];
m_lookAt = gn.origin + pev->view_ofs;
}
else if (vistab.visible (m_currentNodeIndex, nextPathIndex)) {
const auto &gn = graph[nextPathIndex];
m_lookAt = gn.origin + pev->view_ofs;
}
else {
m_lookAt = pev->origin + pev->view_ofs + pev->v_angle.forward () * 300.0f;
}
}
else {
m_lookAt = destOrigin;
}
const bool verticalMove = (m_pathFlags & NodeFlag::Ladder) || isOnLadder () || isPreviousLadder () || pev->velocity.z > 16.0f;
if (m_numEnemiesLeft > 0
&& m_canChooseAimDirection
&& m_canSetAimDirection
&& m_seeEnemyTime + 4.0f < game.time ()
&& m_currentNodeIndex != kInvalidNodeIndex
&& !horizontalMovement) {
&& graph.exists (m_currentNodeIndex)
&& !(m_aimFlags & AimFlags::PredictPath)) {
const auto dangerIndex = practice.getIndex (m_team, m_currentNodeIndex, m_currentNodeIndex);
if (graph.exists (dangerIndex)
&& vistab.visible (m_currentNodeIndex, dangerIndex)
&& vistab.visibleBothSides (m_currentNodeIndex, dangerIndex)
&& !(graph[dangerIndex].flags & NodeFlag::Crouch)) {
if (pev->origin.distanceSq (graph[dangerIndex].origin) < cr::sqrf (512.0f)) {
if (pev->origin.distanceSq (graph[dangerIndex].origin) < cr::sqrf (240.0f)) {
m_lookAt = destOrigin;
}
else {
@ -624,24 +604,56 @@ void Bot::setAimDirection () {
}
}
}
else if (!verticalMove
&& m_moveToGoal
&& m_canSetAimDirection
&& isOnFloor ()
&& !isDucking ()
&& graph.exists (m_currentNodeIndex)
&& m_pathWalk.hasNext ()
&& pev->origin.distanceSq (destOrigin) < cr::sqrf (384.0f)
&& m_path->radius >= 16.0f
&& m_path->flags == 0 && graph[m_pathWalk.next ()].flags == 0) {
const auto nextPathIndex = m_pathWalk.next ();
const auto isNarrowPlace = isInNarrowPlace ();
if (graph.exists (nextPathIndex)
&& cr::abs (graph[nextPathIndex].origin.z - m_pathOrigin.z) < 8.0f) {
if (m_pathWalk.length () > 2 && !isNarrowPlace) {
const auto nextPathIndexX2 = m_pathWalk.nextX2 ();
if (vistab.visibleBothSides (m_currentNodeIndex, nextPathIndexX2)) {
m_lookAt = graph[nextPathIndexX2].origin + pev->view_ofs;
}
}
else if (!isNarrowPlace && vistab.visibleBothSides (m_currentNodeIndex, nextPathIndex)) {
m_lookAt = graph[nextPathIndex].origin + pev->view_ofs;
}
else {
m_lookAt = destOrigin;
}
}
else {
m_lookAt = destOrigin;
}
}
// try look at next node if on ladder
if (horizontalMovement
&& m_pathWalk.hasNext ()
&& !(m_currentTravelFlags & PathFlag::Jump)) {
if (verticalMove && m_pathWalk.hasNext ()) {
const auto &nextPath = graph[m_pathWalk.next ()];
if ((nextPath.flags & NodeFlag::Ladder)
&& m_destOrigin.distanceSq (pev->origin) < cr::sqrf (64.0f)
&& nextPath.origin.z > m_pathOrigin.z + 30.0f) {
&& m_destOrigin.distanceSq (pev->origin) < cr::sqrf (96.0f)
&& nextPath.origin.z > m_pathOrigin.z + 26.0f) {
m_lookAt = nextPath.origin;
m_lookAt = nextPath.origin + pev->view_ofs;
}
}
// don't look at bottom of node, if reached it
if (m_lookAt == destOrigin && !horizontalMovement) {
if (m_lookAt == destOrigin && !verticalMove) {
m_lookAt.z = getEyesPos ().z;
}