bot: perform a seek cover search mission to avoid infected creatures. (#707)

bot: perform a seek cover search mission to avoid infected creatures.
nav: several changes in controlling the terrain.
This commit is contained in:
commandcobra7 2025-08-06 15:44:07 +03:00 committed by GitHub
commit 286e1c8621
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 155 additions and 114 deletions

View file

@ -173,7 +173,10 @@ int Bot::findBestGoal () {
float campDesire = rg (0.0f, 100.0f) + defensive;
if (!usesCampGun ()) {
campDesire *= 0.5f;
campDesire = 0.0f;
}
else if (usesSniper ()) {
campDesire = rg (1.5f, 2.5f) * campDesire;
}
int tactic = GoalTactic::Defensive;
@ -285,14 +288,14 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offensive) {
else if (tactic == GoalTactic::Goal && !graph.m_goalPoints.empty ()) { // map goal node
// force bomber to select closest goal, if round-start goal was reset by something
if (m_hasC4 && bots.getRoundStartTime () + 20.0f < game.time ()) {
if (m_isVIP || (m_hasC4 && bots.getRoundStartTime () + 20.0f < game.time ())) {
float nearestDistanceSq = kInfiniteDistance;
int count = 0;
for (const auto &point : graph.m_goalPoints) {
const float distanceSq = graph[point].origin.distanceSq (pev->origin);
if (distanceSq > cr::sqrf (1024.0f)) {
if (distanceSq > cr::sqrf (1024.0f) || isGroupOfEnemies (graph[point].origin)) {
continue;
}
if (distanceSq < nearestDistanceSq) {
@ -589,7 +592,7 @@ void Bot::doPlayerAvoidance (const Vector &normal) {
}
}
void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
void Bot::checkTerrain (const Vector &dirNormal) {
// if avoiding someone do not consider stuck
TraceResult tr {};
@ -599,6 +602,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
// minimal speed for consider stuck
const float minimalSpeed = isDucking () ? kMinMovedDistance : kMinMovedDistance * 4;
const auto randomProbeTime = rg (0.75f, 1.15f);
// standing still, no need to check?
if ((cr::abs (m_moveSpeed) >= minimalSpeed || cr::abs (m_strafeSpeed) >= minimalSpeed)
@ -612,7 +616,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
m_firstCollideTime = 0.0f;
}
// didn't we move enough previously?
else if (movedDistance < kMinMovedDistance && m_prevSpeed > 20.0f) {
else if (m_movedDistance < kMinMovedDistance && (m_prevSpeed > 20.0f || m_prevVelocity < m_moveSpeed / 2)) {
m_prevTime = game.time (); // then consider being stuck
m_isStuck = true;
@ -642,9 +646,16 @@ void Bot::checkTerrain (float movedDistance, 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 + rg (0.75f, 1.15f) < game.time ()) {
if (m_probeTime + randomProbeTime < game.time ()) {
resetCollision (); // reset collision memory if not being stuck for 0.5 secs
}
else {
@ -845,7 +856,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
}
m_collideTime = game.time ();
m_probeTime = game.time () + 0.5f;
m_probeTime = game.time () + randomProbeTime;
m_collisionProbeBits = bits;
m_collisionState = CollisionState::Probing;
m_collStateIndex = 0;
@ -855,10 +866,9 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
if (m_collisionState == CollisionState::Probing) {
if (m_probeTime < game.time ()) {
m_collStateIndex++;
m_probeTime = game.time () + 0.5f;
m_probeTime = game.time () + randomProbeTime;
if (m_collStateIndex >= kMaxCollideMoves) {
m_navTimeset = game.time () - 5.0f;
resetCollision ();
}
}
@ -867,7 +877,13 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
switch (m_collideMoves[m_collStateIndex]) {
case CollisionState::Jump:
if ((isOnFloor () || isInWater ()) && !isOnLadder ()) {
pev->button |= IN_JUMP;
if (isInWater ()
|| !m_isCreature
|| m_lastDamageTimestamp < game.time ()
|| (m_currentTravelFlags & PathFlag::Jump)) {
pev->button |= IN_JUMP;
}
}
break;
@ -894,10 +910,8 @@ void Bot::checkFall () {
if (isPreviousLadder ()) {
return;
}
else if (graph.exists (m_currentNodeIndex)) {
if (graph[m_currentNodeIndex].flags & NodeFlag::Ladder) {
return;
}
else if ((m_pathFlags & NodeFlag::Ladder) && isPreviousLadder () && isOnLadder ()) {
return;
}
if (!m_checkFall) {
@ -905,7 +919,7 @@ void Bot::checkFall () {
m_checkFallPoint[0] = pev->origin;
if (!game.isNullEntity (m_enemy)) {
m_checkFallPoint[1] = game.getEntityOrigin (m_enemy);
m_checkFallPoint[1] = m_enemy->v.origin;
}
else if (m_currentNodeIndex != kInvalidNodeIndex) {
m_checkFallPoint[1] = m_pathOrigin;
@ -921,7 +935,7 @@ void Bot::checkFall () {
}
}
if (!m_checkFall || !isOnFloor () || !m_fixFallTimer.elapsed ()) {
if (!m_checkFall || !isOnFloor ()) {
return;
}
m_checkFall = false;
@ -931,25 +945,23 @@ void Bot::checkFall () {
const float nowDistanceSq = pev->origin.distanceSq (m_checkFallPoint[1]);
if (nowDistanceSq > baseDistanceSq
&& (nowDistanceSq > baseDistanceSq * 1.8f || nowDistanceSq > baseDistanceSq + 260.0f)
&& baseDistanceSq >= cr::sqrf (124.0f) && nowDistanceSq >= cr::sqrf (146.0f)) {
&& (nowDistanceSq > baseDistanceSq * 1.2f || nowDistanceSq > baseDistanceSq + 200.0f)
&& baseDistanceSq >= cr::sqrf (80.0f) && nowDistanceSq >= cr::sqrf (100.0f)) {
fixFall = true;
}
else if (cr::abs (m_checkFallPoint[1].z) > cr::abs (pev->origin.z) + 138.0f
|| cr::abs (m_checkFallPoint[0].z) > cr::abs (pev->origin.z) + 138.0f) {
else if (m_checkFallPoint[1].z > pev->origin.z + 128.0f
&& m_checkFallPoint[0].z > pev->origin.z + 128.0f) {
fixFall = true;
}
else if (m_currentNodeIndex != kInvalidNodeIndex
&& nowDistanceSq > cr::sqrf (32.0f)
&& cr::abs (m_checkFallPoint[1].z) > cr::abs (pev->origin.z) + 72.0f) {
&& nowDistanceSq > cr::sqrf (16.0f)
&& m_checkFallPoint[1].z > pev->origin.z + 62.0f) {
fixFall = true;
}
if (fixFall) {
m_currentNodeIndex = kInvalidNodeIndex;
findValidNode ();
m_fixFallTimer.start (1.0f);
}
}
@ -1295,8 +1307,8 @@ bool Bot::updateNavigation () {
const auto &dirToPoint = (pev->origin - origin).normalize2d_apx ();
const auto &forwardMove = m_moveAngles.forward ().normalize2d_apx ();
if (distanceSq < cr::sqrf (80.0f)) {
if ((dirToPoint | forwardMove) < 0.0f && !checkWallOnBehind ()) {
if (distanceSq < cr::sqrf (96.0f)) {
if ((dirToPoint | forwardMove) < 0.0f) {
m_moveSpeed = -pev->maxspeed;
}
}
@ -1308,7 +1320,7 @@ bool Bot::updateNavigation () {
}
float desiredDistanceSq = cr::sqrf (8.0f);
float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
const float nodeDistanceSq = pev->origin.distanceSq (m_pathOrigin);
// initialize the radius for a special node type, where the node is considered to be reached
if (m_pathFlags & NodeFlag::Lift) {
@ -1948,8 +1960,7 @@ bool Bot::findNextBestNodeEx (const IntArray &data, bool handleFails) {
float Bot::getEstimatedNodeReachTime () {
const bool longTermReachability = (m_pathFlags & NodeFlag::Crouch)
|| (m_pathFlags & NodeFlag::Ladder)
|| (pev->button & IN_DUCK)
|| (m_oldButtons & IN_DUCK);
|| ((pev->button | pev->oldbuttons) & IN_DUCK);
float estimatedTime = longTermReachability ? 8.5f : 3.5f;
@ -1958,6 +1969,10 @@ float Bot::getEstimatedNodeReachTime () {
return estimatedTime;
}
if (m_lastDamageTimestamp < game.time () && !cr::fzero (m_lastDamageTimestamp) && !m_isStuck && m_isCreature) {
return estimatedTime;
}
// calculate 'real' time that we need to get from one node to another
if (graph.exists (m_currentNodeIndex) && graph.exists (m_previousNodes[0])) {
const float distanceSq = graph[m_previousNodes[0]].origin.distanceSq (graph[m_currentNodeIndex].origin);
@ -3097,7 +3112,7 @@ bool Bot::isBlockedLeft () {
pev->angles.angleVectors (&forward, &right, nullptr);
// do a trace to the left...
game.testLine (pev->origin, forward * direction - right * 48.0f, TraceIgnore::Monsters, ent (), &tr);
game.testLine (pev->origin, pev->origin - forward * direction - right * 48.0f, TraceIgnore::Monsters, ent (), &tr);
// check if the trace hit something...
if (game.mapIs (MapFlags::HasDoors) && tr.flFraction < 1.0f && !util.isDoorEntity (tr.pHit)) {
@ -3110,8 +3125,8 @@ bool Bot::isBlockedRight () {
TraceResult tr {};
float direction = 48.0f;
if (m_moveSpeed < 0.0f) {
direction = -48.0f;
if (m_moveSpeed > 0.0f) {
direction = 48.0f;
}
Vector right {}, forward {};
pev->angles.angleVectors (&forward, &right, nullptr);