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:
parent
590471d94c
commit
286e1c8621
10 changed files with 155 additions and 114 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue