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

@ -157,7 +157,10 @@ void Bot::checkBreakable (edict_t *touch) {
}
if (game.isNullEntity (touch)) {
m_breakableEntity = lookupBreakable ();
auto breakable = lookupBreakable ();
m_breakableEntity = breakable;
m_breakableOrigin = game.getEntityOrigin (breakable);
}
else {
if (m_breakableEntity != touch) {
@ -225,7 +228,7 @@ void Bot::checkBreakablesAround () {
// maybe time to give up?
if (m_lastBreakable == breakable && m_breakableTime + 1.5f < game.time ()) {
m_ignoredBreakable.emplace (breakable);
m_ignoredBreakable.push (breakable);
m_breakableOrigin.clear ();
m_lastBreakable = nullptr;
@ -305,7 +308,7 @@ edict_t *Bot::lookupBreakable () {
return hit;
}
m_breakableEntity = nullptr;
m_breakableOrigin = nullptr;
m_breakableOrigin.clear ();
return nullptr;
}
@ -1702,7 +1705,7 @@ void Bot::overrideConditions () {
// then start escape from bomb immediate
startTask (Task::EscapeFromBomb, TaskPri::EscapeFromBomb, kInvalidNodeIndex, 0.0f, true);
}
float reachEnemyWikKnifeDistanceSq = cr::sqrf (128.0f);
float reachEnemyKnifeDistanceSq = cr::sqrf (128.0f);
// special handling, if we have a knife in our hands
if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters && util.isMonster (m_enemy)))) {
@ -1710,12 +1713,12 @@ void Bot::overrideConditions () {
const auto nearestToEnemyPoint = graph.getNearest (m_enemy->v.origin);
if (nearestToEnemyPoint != kInvalidNodeIndex && nearestToEnemyPoint != m_currentNodeIndex) {
reachEnemyWikKnifeDistanceSq = graph[nearestToEnemyPoint].origin.distanceSq (m_enemy->v.origin);
reachEnemyWikKnifeDistanceSq += cr::sqrf (48.0f);
reachEnemyKnifeDistanceSq = graph[nearestToEnemyPoint].origin.distanceSq (m_enemy->v.origin);
reachEnemyKnifeDistanceSq += cr::sqrf (48.0f);
}
// do nodes movement if enemy is not reachable with a knife
if (distanceSq2d > reachEnemyWikKnifeDistanceSq && (m_states & Sense::SeeingEnemy)) {
if (distanceSq2d > reachEnemyKnifeDistanceSq && (m_states & Sense::SeeingEnemy)) {
if (nearestToEnemyPoint != kInvalidNodeIndex
&& nearestToEnemyPoint != m_currentNodeIndex
&& cr::abs (graph[nearestToEnemyPoint].origin.z - m_enemy->v.origin.z) < 16.0f) {
@ -1725,22 +1728,18 @@ void Bot::overrideConditions () {
if (tid != Task::MoveToPosition && !cr::fequal (getTask ()->desire, TaskPri::Hide)) {
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, taskTime, true);
}
else {
if (tid == Task::MoveToPosition && getTask ()->data != nearestToEnemyPoint) {
clearTask (Task::MoveToPosition);
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, taskTime, true);
}
else if (tid == Task::MoveToPosition && getTask ()->data != nearestToEnemyPoint) {
clearTask (Task::MoveToPosition);
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, taskTime, true);
}
}
}
else {
if (!m_isCreature
&& distanceSq2d <= reachEnemyWikKnifeDistanceSq
&& (m_states & Sense::SeeingEnemy)
&& tid == Task::MoveToPosition) {
else if (!m_isCreature
&& distanceSq2d <= reachEnemyKnifeDistanceSq
&& (m_states & Sense::SeeingEnemy)
&& tid == Task::MoveToPosition) {
clearTask (Task::MoveToPosition); // remove any move tasks
}
clearTask (Task::MoveToPosition); // remove any move tasks
}
}
@ -1781,6 +1780,18 @@ void Bot::overrideConditions () {
m_navTimeset = game.time ();
}
}
// start searching for seek cover to avoid infected creatures
if (game.is (GameFlags::ZombieMod)
&& !m_isCreature
&& m_infectedEnemyTeam
&& util.isAlive (m_enemy)
&& m_retreatTime < game.time ()
&& pev->origin.distanceSq2d (m_enemy->v.origin) < cr::sqrf (512.0f)) {
completeTask ();
startTask (Task::SeekCover, TaskPri::SeekCover, kInvalidNodeIndex, 0.0f, true);
}
}
void Bot::syncUpdatePredictedIndex () {
@ -2332,8 +2343,21 @@ bool Bot::isEnemyThreat () {
return false;
}
auto isOnAttackDistance = [&] (edict_t *enemy, float distance) -> bool {
if (enemy->v.origin.distanceSq (pev->origin) < cr::sqrf (distance)) {
return true;
}
if (usesKnife ()) {
if (enemy->v.origin.distanceSq (pev->origin) < cr::sqrf (distance)) {
return true;
}
}
return false;
};
// if enemy is near or facing us directly
if (m_enemy->v.origin.distanceSq (pev->origin) < cr::sqrf (256.0f) || (!usesKnife () && isInViewCone (m_enemy->v.origin))) {
if (isOnAttackDistance (m_enemy, 256.0f) || (!usesKnife () && isInViewCone (m_enemy->v.origin))) {
return true;
}
return false;
@ -2350,7 +2374,7 @@ bool Bot::reactOnEnemy () {
if (m_isCreature && !game.isNullEntity (m_enemy)) {
m_isEnemyReachable = false;
if (pev->origin.distanceSq2d (m_enemy->v.origin) < cr::sqrf (118.0f)) {
if (pev->origin.distanceSq2d (m_enemy->v.origin) < cr::sqrf (128.0f)) {
m_navTimeset = game.time ();
m_isEnemyReachable = true;
}
@ -3043,7 +3067,7 @@ void Bot::update () {
m_canChooseAimDirection = true;
m_isAlive = util.isAlive (ent ());
m_team = game.getTeam (ent ());
m_healthValue = cr::clamp (pev->health, 0.0f, 100.0f);
m_healthValue = cr::clamp (pev->health, 0.0f, 99999.9f);
if (m_team == Team::Terrorist && game.mapIs (MapFlags::Demolition)) {
m_hasC4 = !!(pev->weapons & cr::bit (Weapon::C4));
@ -3060,6 +3084,11 @@ void Bot::update () {
}
m_isCreature = isCreature ();
// damage victim action
if (m_lastDamageTimestamp < game.time () && !cr::fzero (m_lastDamageTimestamp)) {
m_lastDamageTimestamp = 0.0f;
}
// is bot movement enabled
m_botMovement = false;
@ -3262,7 +3291,7 @@ void Bot::checkSpawnConditions () {
void Bot::logic () {
// this function gets called each frame and is the core of all bot ai. from here all other subroutines are called
float movedDistance = kMinMovedDistance; // length of different vector (distance bot moved)
m_movedDistance = kMinMovedDistance; // length of different vector (distance bot moved)
resetMovement ();
@ -3289,7 +3318,7 @@ void Bot::logic () {
// see how far bot has moved since the previous position...
if (m_checkTerrain) {
movedDistance = m_prevOrigin.distance (pev->origin);
m_movedDistance = m_prevOrigin.distance (pev->origin);
}
// save current position as previous
@ -3397,7 +3426,7 @@ void Bot::logic () {
checkBreakable (nullptr);
doPlayerAvoidance (dirNormal);
checkTerrain (movedDistance, dirNormal);
checkTerrain (dirNormal);
}
// if we have fallen from the place of move, the nearest point is allowed
@ -3443,7 +3472,7 @@ void Bot::logic () {
// save the previous speed (for checking if stuck)
m_prevSpeed = cr::abs (m_moveSpeed);
m_prevVelocity = pev->velocity;
m_prevVelocity = cr::abs (pev->velocity.length2d ());
m_lastDamageType = -1; // reset damage
}
@ -3953,7 +3982,7 @@ Vector Bot::isBombAudible () {
}
// we hear bomb if length greater than radius
if (cr::sqrf (desiredRadius) < pev->origin.distanceSq2d (bombOrigin)) {
if (pev->origin.distanceSq2d (bombOrigin) > cr::sqrf (desiredRadius)) {
return bombOrigin;
}
return nullptr;
@ -4306,9 +4335,7 @@ float Bot::getShiftSpeed () {
if (getCurrentTaskId () == Task::SeekCover
|| (m_aimFlags & AimFlags::Enemy)
|| isDucking ()
|| m_isCreature
|| (pev->button & IN_DUCK)
|| (m_oldButtons & IN_DUCK)
|| ((pev->button | pev->oldbuttons) & IN_DUCK)
|| (m_currentTravelFlags & PathFlag::Jump)
|| (m_pathFlags & NodeFlag::Ladder)
|| isOnLadder ()
@ -4337,9 +4364,10 @@ void Bot::refreshCreatureStatus (char *infobuffer) {
// if bot is on infected team, and zombie mode is active, assume bot is a creature/zombie
m_isOnInfectedTeam = game.getRealTeam (ent ()) == infectedTeam;
m_infectedEnemyTeam = game.getRealTeam (m_enemy) == infectedTeam;
// do not process next if already infected
if (m_isOnInfectedTeam) {
if (m_isOnInfectedTeam || m_infectedEnemyTeam) {
return;
}
}