nav: return to everything visible in finding the nearest node. (resolve previously solved problem #432)
nav: checks whether the robot is blocked in the direction of movement. (excluded in hostages)
This commit is contained in:
parent
9d48b19e62
commit
ece83734a1
6 changed files with 113 additions and 85 deletions
|
|
@ -298,6 +298,13 @@ yb_stab_close_enemies "1"
|
|||
//
|
||||
yb_use_engine_pvs_check "0"
|
||||
|
||||
//
|
||||
// Use hitbox-based enemy targeting, instead of offset based. Use with the yb_use_engine_pvs_check enabled to reduce CPU usage.
|
||||
// ---
|
||||
// Default: "0", Min: "0", Max: "1"
|
||||
//
|
||||
yb_use_hitbox_enemy_targeting "0"
|
||||
|
||||
//
|
||||
// Binds specified key for opening bots menu.
|
||||
// ---
|
||||
|
|
@ -662,6 +669,13 @@ yb_rotate_stay_max "3600.0"
|
|||
//
|
||||
yb_has_team_semiclip "0"
|
||||
|
||||
//
|
||||
// Determines the maximum slope height change between the current and next node to consider the current link as a jump link. Only for generated graphs.
|
||||
// ---
|
||||
// Default: "24.0", Min: "12.0", Max: "48.0"
|
||||
//
|
||||
yb_graph_slope_height "24.0"
|
||||
|
||||
//
|
||||
// Selects the heuristic function mode. For debug purposes only.
|
||||
// ---
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ public:
|
|||
int getFarest (const Vector &origin, const float maxRange = 32.0);
|
||||
int getForAnalyzer (const Vector &origin, const float maxRange);
|
||||
int getNearest (const Vector &origin, const float range = kInfiniteDistance, int flags = -1);
|
||||
int getNearestNoBuckets (const Vector &origin, const float range = kInfiniteDistance, int flags = -1);
|
||||
int getNearestNoBuckets (const Vector &origin, float nearestDistanceSq = kInfiniteDistance, int flags = -1);
|
||||
int getEditorNearest (const float maxRange = 50.0f);
|
||||
int clearConnections (int index);
|
||||
int getBspSize ();
|
||||
|
|
@ -264,7 +264,7 @@ public:
|
|||
void syncCollectOnline ();
|
||||
void collectOnline ();
|
||||
|
||||
IntArray getNearestInRadius (float radius, const Vector &origin, int maxCount = -1);
|
||||
IntArray getNearestInRadius (float radiusSq, const Vector &origin, int maxCount = -1);
|
||||
const IntArray &getNodesInBucket (const Vector &pos);
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -1658,10 +1658,10 @@ void Bot::overrideConditions () {
|
|||
|
||||
// special handling, if we have a knife in our hands
|
||||
if (isKnifeMode () && (util.isPlayer (m_enemy) || (cv_attack_monsters && util.isMonster (m_enemy)))) {
|
||||
const float distance2d = pev->origin.distance2d (m_enemy->v.origin);
|
||||
const float distanceSq2d = pev->origin.distanceSq2d (m_enemy->v.origin);
|
||||
|
||||
// do nodes movement if enemy is not reachable with a knife
|
||||
if (distance2d > 250.0f && (m_states & Sense::SeeingEnemy)) {
|
||||
if (distanceSq2d > cr::sqrf (250.0f) && (m_states & Sense::SeeingEnemy)) {
|
||||
const int nearestToEnemyPoint = graph.getNearest (m_enemy->v.origin);
|
||||
|
||||
if (nearestToEnemyPoint != kInvalidNodeIndex
|
||||
|
|
@ -1669,18 +1669,18 @@ void Bot::overrideConditions () {
|
|||
&& cr::abs (graph[nearestToEnemyPoint].origin.z - m_enemy->v.origin.z) < 16.0f) {
|
||||
|
||||
if (tid != Task::MoveToPosition && !cr::fequal (getTask ()->desire, TaskPri::Hide)) {
|
||||
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + distance2d / (m_moveSpeed * 2.0f), true);
|
||||
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + distanceSq2d / cr::sqrf (m_moveSpeed) * 2.0f, true);
|
||||
}
|
||||
else {
|
||||
if (tid == Task::MoveToPosition && getTask ()->data != nearestToEnemyPoint) {
|
||||
clearTask (Task::MoveToPosition);
|
||||
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + distance2d / (m_moveSpeed * 2.0f), true);
|
||||
startTask (Task::MoveToPosition, TaskPri::Hide, nearestToEnemyPoint, game.time () + distanceSq2d / cr::sqrf (m_moveSpeed) * 2.0f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (distance2d <= 250.0f && (m_states & Sense::SeeingEnemy) && tid == Task::MoveToPosition) {
|
||||
if (distanceSq2d <= cr::sqrf (250.0f) && (m_states & Sense::SeeingEnemy) && tid == Task::MoveToPosition) {
|
||||
clearTask (Task::MoveToPosition); // remove any move tasks
|
||||
}
|
||||
}
|
||||
|
|
@ -1756,7 +1756,7 @@ void Bot::syncUpdatePredictedIndex () {
|
|||
auto result = planner.find (destIndex, currentNodeIndex, [&] (int index) {
|
||||
++pathLength;
|
||||
|
||||
if (vistab.visible (currentNodeIndex, index) && botOrigin.distanceSq (graph[index].origin) > cr::sqrf (256.0f)) {
|
||||
if (vistab.visible (currentNodeIndex, index) && botOrigin.distanceSq (graph[index].origin) < cr::sqrf (2048.0f)) {
|
||||
bestIndex = index;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1786,7 +1786,7 @@ void Bot::refreshEnemyPredict () {
|
|||
if (game.isNullEntity (m_enemy) && !game.isNullEntity (m_lastEnemy) && !m_lastEnemyOrigin.empty ()) {
|
||||
const auto distanceToLastEnemySq = m_lastEnemyOrigin.distanceSq (pev->origin);
|
||||
|
||||
if (distanceToLastEnemySq > cr::sqrf (256.0f) && (distanceToLastEnemySq < cr::sqrf (2048.0f) || usesSniper ())) {
|
||||
if (distanceToLastEnemySq < cr::sqrf (2048.0f)) {
|
||||
m_aimFlags |= AimFlags::PredictPath;
|
||||
}
|
||||
const bool denyLastEnemy = pev->velocity.lengthSq2d () > 0.0f
|
||||
|
|
@ -1872,11 +1872,11 @@ void Bot::setConditions () {
|
|||
}
|
||||
}
|
||||
else {
|
||||
auto currentTime = game.time ();
|
||||
m_killsInterval = m_lastVictimTime - game.time ();
|
||||
|
||||
if (m_killsInterval <= 5.0f) {
|
||||
++m_killsCount;
|
||||
|
||||
m_killsInterval = currentTime - m_lastVictimTime;
|
||||
if (m_killsInterval <= 5) {
|
||||
m_killsCount++;
|
||||
if (m_killsCount > 2) {
|
||||
pushChatterMessage (Chatter::OnARoll);
|
||||
}
|
||||
|
|
@ -2037,7 +2037,7 @@ void Bot::filterTasks () {
|
|||
else if (m_isVIP || m_isReloading || (sniping && usesSniper ())) {
|
||||
ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading
|
||||
}
|
||||
else if (m_lastEnemyOrigin.distanceSq2d (pev->origin) < cr::sqrf (200.0f)) {
|
||||
else if (m_lastEnemyOrigin.distanceSq2d (pev->origin) < cr::sqrf (256.0f)) {
|
||||
ratio *= 3.0f;
|
||||
}
|
||||
else if (game.is (GameFlags::CSDM)) {
|
||||
|
|
@ -2277,7 +2277,7 @@ void Bot::completeTask () {
|
|||
}
|
||||
|
||||
bool Bot::isEnemyThreat () {
|
||||
if (game.isNullEntity (m_enemy) || getCurrentTaskId () == Task::SeekCover) {
|
||||
if (game.isNullEntity (m_enemy) || (m_states & Sense::SuspectEnemy) || getCurrentTaskId () == Task::SeekCover) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ bool Bot::checkBodyPartsWithOffsets (edict_t *target) {
|
|||
|
||||
bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
||||
const auto self = pev->pContainingEntity;
|
||||
const auto refersh = m_frameInterval * 1.5f;
|
||||
const auto refresh = m_frameInterval * 1.5f;
|
||||
|
||||
TraceResult result {};
|
||||
const auto &eyes = getEyesPos ();
|
||||
|
|
@ -240,7 +240,7 @@ bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
|||
|
||||
// get the stomach hitbox
|
||||
m_enemyParts = Visibility::None;
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Stomach, refersh), ignoreFlags, self, &result);
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Stomach, refresh), ignoreFlags, self, &result);
|
||||
|
||||
if (hitsTarget ()) {
|
||||
m_enemyParts |= Visibility::Body;
|
||||
|
|
@ -249,7 +249,7 @@ bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
|||
|
||||
// get the stomach hitbox
|
||||
m_enemyParts = Visibility::None;
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Head, refersh), ignoreFlags, self, &result);
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Head, refresh), ignoreFlags, self, &result);
|
||||
|
||||
if (hitsTarget ()) {
|
||||
m_enemyParts |= Visibility::Head;
|
||||
|
|
@ -262,7 +262,7 @@ bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
|||
|
||||
// get the left hitbox
|
||||
m_enemyParts = Visibility::None;
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::LeftArm, refersh), ignoreFlags, self, &result);
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::LeftArm, refresh), ignoreFlags, self, &result);
|
||||
|
||||
if (hitsTarget ()) {
|
||||
m_enemyParts |= Visibility::Other;
|
||||
|
|
@ -273,7 +273,7 @@ bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
|||
|
||||
// get the right hitbox
|
||||
m_enemyParts = Visibility::None;
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::RightArm, refersh), ignoreFlags, self, &result);
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::RightArm, refresh), ignoreFlags, self, &result);
|
||||
|
||||
if (hitsTarget ()) {
|
||||
m_enemyParts |= Visibility::Other;
|
||||
|
|
@ -284,7 +284,7 @@ bool Bot::checkBodyPartsWithHitboxes (edict_t *target) {
|
|||
|
||||
// get the feet spot
|
||||
m_enemyParts = Visibility::None;
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Feet, refersh), ignoreFlags, self, &result);
|
||||
game.testLine (eyes, m_hitboxEnumerator->get (target, PlayerPart::Feet, refresh), ignoreFlags, self, &result);
|
||||
|
||||
if (hitsTarget ()) {
|
||||
m_enemyParts |= Visibility::Other;
|
||||
|
|
@ -1373,7 +1373,7 @@ void Bot::attackMovement () {
|
|||
}
|
||||
|
||||
auto approach = 0;
|
||||
const auto distance = m_lookAt.distance (getEyesPos ()); // how far away is the enemy scum?
|
||||
const auto distanceSq = m_lookAt.distanceSq (getEyesPos ()); // how far away is the enemy scum?
|
||||
|
||||
if (usesKnife ()) {
|
||||
approach = 100;
|
||||
|
|
@ -1394,7 +1394,11 @@ void Bot::attackMovement () {
|
|||
|
||||
// only take cover when bomb is not planted and enemy can see the bot or the bot is VIP
|
||||
if (!game.is (GameFlags::CSDM)) {
|
||||
if ((m_states & Sense::SeeingEnemy) && approach < 30 && !bots.isBombPlanted () && (isInViewCone (m_enemy->v.origin) || m_isVIP)) {
|
||||
if ((m_states & Sense::SeeingEnemy)
|
||||
&& approach < 30
|
||||
&& !bots.isBombPlanted ()
|
||||
&& (isInViewCone (m_enemy->v.origin) || m_isVIP)) {
|
||||
|
||||
if (m_retreatTime < game.time ()) {
|
||||
startTask (Task::SeekCover, TaskPri::SeekCover, kInvalidNodeIndex, 0.0f, true);
|
||||
}
|
||||
|
|
@ -1419,10 +1423,10 @@ void Bot::attackMovement () {
|
|||
else if (usesRifle () || usesSubmachine () || usesHeavy ()) {
|
||||
const int rand = rg (1, 100);
|
||||
|
||||
if (distance < 768.0f) {
|
||||
if (distanceSq < cr::sqrf (768.0f)) {
|
||||
m_fightStyle = Fight::Strafe;
|
||||
}
|
||||
else if (distance < 1024.0f) {
|
||||
else if (distanceSq < cr::sqrf (1024.0f)) {
|
||||
if (isGroupOfEnemies (m_enemy->v.origin)) {
|
||||
m_fightStyle = Fight::Strafe;
|
||||
}
|
||||
|
|
@ -1460,14 +1464,14 @@ void Bot::attackMovement () {
|
|||
|
||||
// fire hurts friend value here is from previous frame, but acceptable, and saves us alot of cpu cycles
|
||||
if (approach < 30 || m_fireHurtsFriend || ((usesPistol () || usesShotgun ())
|
||||
&& distance < pistolStrafeDistance
|
||||
&& distanceSq < cr::sqrf (pistolStrafeDistance)
|
||||
&& isInViewCone (m_enemyOrigin))) {
|
||||
m_fightStyle = Fight::Strafe;
|
||||
}
|
||||
m_lastFightStyleCheck = game.time () + 3.0f;
|
||||
}
|
||||
|
||||
if (distance < 96.0f && !usesKnife ()) {
|
||||
if (distanceSq < cr::sqrf (96.0f) && !usesKnife ()) {
|
||||
m_moveSpeed = -pev->maxspeed;
|
||||
}
|
||||
|
||||
|
|
@ -1556,7 +1560,7 @@ void Bot::attackMovement () {
|
|||
if (alreadyDucking) {
|
||||
m_duckTime = game.time () + m_frameInterval * 3.0f;
|
||||
}
|
||||
else if ((distance > kSprayDistanceX2 && hasPrimaryWeapon ())
|
||||
else if ((distanceSq > cr::sqrf (kSprayDistanceX2) && hasPrimaryWeapon ())
|
||||
&& isFullView
|
||||
&& getCurrentTaskId () != Task::SeekCover
|
||||
&& getCurrentTaskId () != Task::Hunt) {
|
||||
|
|
@ -1573,7 +1577,7 @@ void Bot::attackMovement () {
|
|||
}
|
||||
|
||||
if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) {
|
||||
if (distance < kSprayDistanceX2) {
|
||||
if (distanceSq < cr::sqrf (kSprayDistanceX2)) {
|
||||
if (rg (0, 1000) < rg (5, 10) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) {
|
||||
pev->button |= IN_JUMP;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,12 +493,12 @@ int BotGraph::getForAnalyzer (const Vector &origin, const float maxRange) {
|
|||
return index;
|
||||
}
|
||||
|
||||
int BotGraph::getNearestNoBuckets (const Vector &origin, const float range, int flags) {
|
||||
int BotGraph::getNearestNoBuckets (const Vector &origin, float nearestDistanceSq, int flags) {
|
||||
// find the nearest node to that origin and return the index
|
||||
|
||||
// fallback and go thru wall the nodes...
|
||||
int index = kInvalidNodeIndex;
|
||||
float nearestDistanceSq = cr::sqrf (range);
|
||||
nearestDistanceSq = cr::sqrf (nearestDistanceSq);
|
||||
|
||||
for (const auto &path : m_paths) {
|
||||
if (flags != -1 && !(path.flags & flags)) {
|
||||
|
|
@ -555,15 +555,15 @@ int BotGraph::getNearest (const Vector &origin, const float range, int flags) {
|
|||
return index;
|
||||
}
|
||||
|
||||
IntArray BotGraph::getNearestInRadius (float radius, const Vector &origin, int maxCount) {
|
||||
IntArray BotGraph::getNearestInRadius (float radiusSq, const Vector &origin, int maxCount) {
|
||||
// returns all nodes within radius from position
|
||||
|
||||
const float radiusSq = cr::sqrf (radius);
|
||||
radiusSq = cr::sqrf (radiusSq);
|
||||
|
||||
IntArray result {};
|
||||
const auto &bucket = getNodesInBucket (origin);
|
||||
|
||||
if (bucket.length () < kMaxNodeLinks || radius > cr::sqrf (256.0f)) {
|
||||
if (bucket.length () < kMaxNodeLinks || radiusSq > cr::sqrf (256.0f)) {
|
||||
for (const auto &path : m_paths) {
|
||||
if (maxCount != -1 && static_cast <int> (result.length ()) > maxCount) {
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -370,10 +370,6 @@ void Bot::postProcessGoals (const IntArray &goals, int result[]) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!isOccupiedNode (index)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if historical goal
|
||||
for (const auto &hg : m_goalHist) {
|
||||
if (hg == index) {
|
||||
|
|
@ -874,7 +870,7 @@ void Bot::checkFall () {
|
|||
fixFall = true;
|
||||
}
|
||||
else if (m_currentNodeIndex != kInvalidNodeIndex) {
|
||||
if (pev->origin.distanceSq (m_checkFallPoint[1]) <= cr::sqrf (32.0f) && pev->origin.z + 16.0f < m_checkFallPoint[1].z) {
|
||||
if (pev->origin.distanceSq (m_checkFallPoint[1]) <= cr::sqrf (32.0f) && pev->origin.z + 64.0f < m_checkFallPoint[1].z) {
|
||||
fixFall = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1046,13 +1042,19 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
if (m_pathFlags & NodeFlag::Ladder) {
|
||||
const float ladderDistance = pev->origin.distance (m_pathOrigin);
|
||||
|
||||
if (m_pathOrigin.z >= pev->origin.z + 16.0f) {
|
||||
constexpr auto kLadderOffset = Vector (0.0f, 0.0f, 36.0f);
|
||||
|
||||
const auto prevNodeIndex = m_previousNodes[0];
|
||||
const float ladderDistance = pev->origin.distance (m_pathOrigin);
|
||||
|
||||
if (graph.exists (prevNodeIndex) && !(graph[prevNodeIndex].flags & NodeFlag::Ladder)) {
|
||||
if (m_pathOrigin.z >= pev->origin.z + 16.0f) {
|
||||
m_pathOrigin = m_path->origin + kLadderOffset;
|
||||
}
|
||||
else if (m_pathOrigin.z < pev->origin.z - 16.0f) {
|
||||
m_pathOrigin = m_path->origin - kLadderOffset;
|
||||
}
|
||||
}
|
||||
else if (m_pathOrigin.z < pev->origin.z + 16.0f && !isOnLadder () && isOnFloor () && !isDucking ()) {
|
||||
m_moveSpeed = ladderDistance;
|
||||
|
||||
|
|
@ -1063,7 +1065,6 @@ bool Bot::updateNavigation () {
|
|||
m_moveSpeed = pev->maxspeed;
|
||||
}
|
||||
}
|
||||
const auto prevNodeIndex = m_previousNodes[0];
|
||||
|
||||
// do a precise movement when very near
|
||||
if (graph.exists (prevNodeIndex) && !(graph[prevNodeIndex].flags & NodeFlag::Ladder) && ladderDistance < 64.0f) {
|
||||
|
|
@ -1082,42 +1083,35 @@ bool Bot::updateNavigation () {
|
|||
for (const auto &client : util.getClients ()) {
|
||||
if (!(client.flags & ClientFlags::Used)
|
||||
|| !(client.flags & ClientFlags::Alive)
|
||||
|| (client.ent->v.movetype != MOVETYPE_FLY)
|
||||
|| client.team != m_team
|
||||
|| client.ent == ent ()) {
|
||||
|
||||
continue;
|
||||
}
|
||||
TraceResult tr {};
|
||||
|
||||
if (client.ent->v.origin.distanceSq (m_pathOrigin) > cr::sqrf (64.0f)) {
|
||||
continue;
|
||||
}
|
||||
bool foundGround = false;
|
||||
int previousNode = 0;
|
||||
|
||||
// more than likely someone is already using our ladder...
|
||||
if (client.ent->v.origin.distanceSq (m_path->origin) < cr::sqrf (48.0f)) {
|
||||
game.testHull (getEyesPos (), m_pathOrigin, TraceIgnore::Monsters, isDucking () ? head_hull : human_hull, ent (), &tr);
|
||||
|
||||
// someone is above or below us and is using the ladder already
|
||||
if (tr.pHit == client.ent
|
||||
&& cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f
|
||||
&& (client.ent->v.movetype == MOVETYPE_FLY)) {
|
||||
|
||||
if (cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f && (client.ent->v.movetype == MOVETYPE_FLY)) {
|
||||
const auto numPreviousNode = rg (0, 2);
|
||||
|
||||
for (int i = 0; i < numPreviousNode; ++i) {
|
||||
if (graph.exists (m_previousNodes[i]) && (graph[m_previousNodes[i]].flags & NodeFlag::Ladder)) {
|
||||
if (graph.exists (prevNodeIndex) && (graph[prevNodeIndex].flags & NodeFlag::Ladder)) {
|
||||
foundGround = true;
|
||||
previousNode = m_previousNodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundGround) {
|
||||
changeNodeIndex (m_previousNodes[0]);
|
||||
findPath (m_previousNodes[0], previousNode, m_pathType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special lift handling (code merged from podbotmm)
|
||||
if (m_pathFlags & NodeFlag::Lift) {
|
||||
|
|
@ -1252,12 +1246,14 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
// needs precise placement - check if we get past the point
|
||||
if (desiredDistanceSq < cr::sqrf (22.0f)
|
||||
&& nodeDistanceSq < cr::sqrf (30.0f)
|
||||
&& m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) {
|
||||
|
||||
if (desiredDistanceSq < cr::sqrf (22.0f) && nodeDistanceSq < cr::sqrf (30.0f)) {
|
||||
if (m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= nodeDistanceSq) {
|
||||
desiredDistanceSq = nodeDistanceSq + 1.0f;
|
||||
}
|
||||
if (m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) <= desiredDistanceSq) {
|
||||
desiredDistanceSq = nodeDistanceSq + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// this allows us to prevent stupid bot behavior when he reaches almost end point of this route, but some one (other bot eg)
|
||||
// is sitting there, so the bot is unable to reach the node because of other player on it, and he starts to jumping and so on
|
||||
|
|
@ -1720,6 +1716,7 @@ bool Bot::findNextBestNode () {
|
|||
|
||||
const auto &origin = pev->origin + pev->velocity * m_frameInterval;
|
||||
const auto &bucket = graph.getNodesInBucket (origin);
|
||||
const auto &numToSkip = cr::clamp (rg (0, 2), 0, static_cast <int> (bucket.length () / 2));
|
||||
|
||||
for (const auto &i : bucket) {
|
||||
const auto &path = graph[i];
|
||||
|
|
@ -1729,9 +1726,17 @@ bool Bot::findNextBestNode () {
|
|||
}
|
||||
bool skip = !!(path.number == m_currentNodeIndex);
|
||||
|
||||
// skip the current node, if any
|
||||
if (skip && numToSkip > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip current or recent previous node
|
||||
if (path.number == m_previousNodes[0]) {
|
||||
for (int j = 0; j < numToSkip; ++j) {
|
||||
if (path.number == m_previousNodes[j]) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// skip node from recent list
|
||||
|
|
@ -2474,8 +2479,7 @@ bool Bot::advanceMovement () {
|
|||
bool willJump = false;
|
||||
float jumpDistanceSq = 0.0f;
|
||||
|
||||
Vector src {};
|
||||
Vector dst {};
|
||||
Vector src {}, dst {};
|
||||
|
||||
// try to find out about future connection flags
|
||||
if (m_pathWalk.hasNext ()) {
|
||||
|
|
@ -2536,16 +2540,17 @@ bool Bot::advanceMovement () {
|
|||
|
||||
void Bot::setPathOrigin () {
|
||||
constexpr int kMaxAlternatives = 5;
|
||||
const float radius = m_path->radius;
|
||||
|
||||
// if node radius non zero vary origin a bit depending on the body angles
|
||||
if (m_path->radius > 0.0f) {
|
||||
if (radius > 0.0f) {
|
||||
int nearestIndex = kInvalidNodeIndex;
|
||||
|
||||
if (!m_pathWalk.empty () && m_pathWalk.hasNext ()) {
|
||||
Vector orgs[kMaxAlternatives] {};
|
||||
|
||||
for (int i = 0; i < kMaxAlternatives; ++i) {
|
||||
orgs[i] = m_pathOrigin + Vector (rg (-m_path->radius, m_path->radius), rg (-m_path->radius, m_path->radius), 0.0f);
|
||||
orgs[i] = m_pathOrigin + Vector (rg (-radius, radius), rg (-radius, radius), 0.0f);
|
||||
}
|
||||
float nearestDistanceSq = kInfiniteDistance;
|
||||
|
||||
|
|
@ -2565,7 +2570,7 @@ void Bot::setPathOrigin () {
|
|||
}
|
||||
|
||||
if (nearestIndex == kInvalidNodeIndex) {
|
||||
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f).forward () * rg (0.0f, m_path->radius);
|
||||
m_pathOrigin += Vector (pev->angles.x, cr::wrapAngle (pev->angles.y + rg (-90.0f, 90.0f)), 0.0f).forward () * rg (0.0f, radius);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2599,12 +2604,17 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
return result->flFraction < 1.0f && !util.isDoorEntity (result->pHit);
|
||||
};
|
||||
|
||||
auto checkHostage = [&] (TraceResult *result) {
|
||||
return result->flFraction < 1.0f && m_team == Team::Terrorist && !util.isHostageEntity (result->pHit);
|
||||
};
|
||||
|
||||
// trace from the bot's eyes straight forward...
|
||||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (tr->flFraction < 1.0f) {
|
||||
if (game.mapIs (MapFlags::HasDoors) && util.isDoorEntity (tr->pHit)) {
|
||||
if ((game.mapIs (MapFlags::HasDoors) && util.isDoorEntity (tr->pHit))
|
||||
|| (m_team == Team::CT && util.isHostageEntity (tr->pHit))) {
|
||||
return false;
|
||||
}
|
||||
return true; // bot's head will hit something
|
||||
|
|
@ -2622,7 +2632,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
|
||||
|
|
@ -2634,7 +2644,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
|
||||
|
|
@ -2646,7 +2656,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
src = pev->origin;
|
||||
|
|
@ -2655,7 +2665,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
}
|
||||
|
|
@ -2671,7 +2681,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
|
||||
|
|
@ -2682,7 +2692,7 @@ bool Bot::isBlockedForward (const Vector &normal, TraceResult *tr) {
|
|||
game.testLine (src, forward, TraceIgnore::Monsters, ent (), tr);
|
||||
|
||||
// check if the trace hit something...
|
||||
if (checkDoor (tr)) {
|
||||
if (checkDoor (tr) || checkHostage (tr)) {
|
||||
return true; // bot's body will hit something
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue