Refactoring (#246)
add: yb_chat_percent, yb_camping_time_[min/max], yb_danger_factor[min/max], yb_chat_percent cvars fix: possible crash with difficulty 0 fix: debug_goal should not be used as last history fix: startup on old hlds, because of missing pfnGetFileSize fix: crash with out-bounds read change: again tweaked some aiming code change: player avoidance code so bots will jump less when stuck change: max followers is just /4 of max players refactor: redone distance between vectors refactor: remove magic numbers in graph.add function
This commit is contained in:
parent
6e83258c7d
commit
6f912eb056
10 changed files with 214 additions and 177 deletions
109
src/navigate.cpp
109
src/navigate.cpp
|
|
@ -8,7 +8,10 @@
|
|||
#include <yapb.h>
|
||||
|
||||
ConVar cv_whose_your_daddy ("yb_whose_your_daddy", "0", "Enables or disables extra hard difficulty for bots.");
|
||||
ConVar cv_debug_heuristic_type ("yb_debug_heuristic_type", "0", "Selects the heuristic function mode. For debug purposes only.", true, 0.0f, 4.0f);
|
||||
ConVar cv_path_heuristic_mode ("yb_path_heuristic_mode", "4", "Selects the heuristic function mode. For debug purposes only.", true, 0.0f, 4.0f);
|
||||
|
||||
ConVar cv_path_danger_factor_min ("yb_path_danger_factor_min", "200", "Lower bound of danger factor that used to add additional danger to path based on practice.", true, 100.0f, 2400.0f);
|
||||
ConVar cv_path_danger_factor_max ("yb_path_danger_factor_max", "400", "Upper bound of danger factor that used to add additional danger to path based on practice.", true, 200.0f, 4800.0f);
|
||||
|
||||
int Bot::findBestGoal () {
|
||||
|
||||
|
|
@ -180,7 +183,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
|
|||
int count = 0;
|
||||
|
||||
for (auto &point : graph.m_goalPoints) {
|
||||
float distance = (graph[point].origin - pev->origin).lengthSq ();
|
||||
float distance = graph[point].origin.distanceSq (pev->origin);
|
||||
|
||||
if (distance > cr::square (1024.0f)) {
|
||||
continue;
|
||||
|
|
@ -295,6 +298,10 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
edict_t *hindrance = nullptr;
|
||||
float distance = cr::square (300.0f);
|
||||
|
||||
if (getCurrentTaskId () == Task::Attack || getCurrentTaskId () == Task::SeekCover || isOnLadder ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// find nearest player to bot
|
||||
for (const auto &client : util.getClients ()) {
|
||||
|
||||
|
|
@ -312,7 +319,7 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
if (client.team != m_team || client.ent == ent ()) {
|
||||
continue;
|
||||
}
|
||||
auto nearest = (client.ent->v.origin - pev->origin).lengthSq ();
|
||||
auto nearest = client.ent->v.origin.distanceSq (pev->origin);
|
||||
|
||||
if (nearest < cr::square (pev->maxspeed) && nearest < distance) {
|
||||
hindrance = client.ent;
|
||||
|
|
@ -324,7 +331,7 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
if (!hindrance) {
|
||||
return false;
|
||||
}
|
||||
const float interval = getFrameInterval ();
|
||||
const float interval = getFrameInterval () * 4.0f;
|
||||
|
||||
// use our movement angles, try to predict where we should be next frame
|
||||
Vector right, forward;
|
||||
|
|
@ -335,8 +342,8 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
predict += right * m_strafeSpeed * interval;
|
||||
predict += pev->velocity * interval;
|
||||
|
||||
auto movedDistance = (hindrance->v.origin - predict).lengthSq ();
|
||||
auto nextFrameDistance = ((hindrance->v.origin + hindrance->v.velocity * interval) - pev->origin).lengthSq ();
|
||||
auto movedDistance = hindrance->v.origin.distanceSq (predict);
|
||||
auto nextFrameDistance = pev->origin.distanceSq (hindrance->v.origin + hindrance->v.velocity * interval);
|
||||
|
||||
// is player that near now or in future that we need to steer away?
|
||||
if (movedDistance <= cr::square (48.0f) || (distance <= cr::square (56.0f) && nextFrameDistance < distance)) {
|
||||
|
|
@ -349,13 +356,11 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
else {
|
||||
setStrafeSpeed (normal, -pev->maxspeed);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (distance < cr::square (56.0f)) {
|
||||
if ((dir | forward.get2d ()) < 0.0f)
|
||||
if ((dir | forward.get2d ()) < 0.0f) {
|
||||
m_moveSpeed = -pev->maxspeed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -365,9 +370,12 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
|||
|
||||
// if avoiding someone do not consider stuck
|
||||
TraceResult tr {};
|
||||
doPlayerAvoidance (dirNormal);
|
||||
m_isStuck = doPlayerAvoidance (dirNormal);
|
||||
|
||||
m_isStuck = false;
|
||||
if (m_isStuck) {
|
||||
resetCollision ();
|
||||
return;
|
||||
}
|
||||
|
||||
// Standing still, no need to check?
|
||||
// FIXME: doesn't care for ladder movement (handled separately) should be included in some way
|
||||
|
|
@ -655,7 +663,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
m_destOrigin = m_pathOrigin + pev->view_ofs;
|
||||
|
||||
float nodeDistance = (pev->origin - m_pathOrigin).length ();
|
||||
float nodeDistance = pev->origin.distance (m_pathOrigin);
|
||||
|
||||
// this node has additional travel flags - care about them
|
||||
if (m_currentTravelFlags & PathFlag::Jump) {
|
||||
|
|
@ -714,7 +722,7 @@ bool Bot::updateNavigation () {
|
|||
|
||||
if (!game.isNullEntity (tr.pHit) && game.isNullEntity (m_liftEntity) && strncmp (tr.pHit->v.classname.chars (), "func_door", 9) == 0) {
|
||||
// if the door is near enough...
|
||||
if ((game.getEntityOrigin (tr.pHit) - pev->origin).lengthSq () < 2500.0f) {
|
||||
if (pev->origin.distanceSq (game.getEntityOrigin (tr.pHit)) < 2500.0f) {
|
||||
ignoreCollision (); // don't consider being stuck
|
||||
|
||||
if (rg.chance (50)) {
|
||||
|
|
@ -795,7 +803,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
// needs precise placement - check if we get past the point
|
||||
if (desiredDistance < 22.0f && nodeDistance < 30.0f && (pev->origin + (pev->velocity * getFrameInterval ()) - m_pathOrigin).lengthSq () >= cr::square (nodeDistance)) {
|
||||
if (desiredDistance < 22.0f && nodeDistance < 30.0f && m_pathOrigin.distanceSq (pev->origin + pev->velocity * getFrameInterval ()) >= cr::square (nodeDistance)) {
|
||||
desiredDistance = nodeDistance + 1.0f;
|
||||
}
|
||||
|
||||
|
|
@ -837,7 +845,7 @@ bool Bot::updateNavigation () {
|
|||
|
||||
// bot within 'hearable' bomb tick noises?
|
||||
if (!bombOrigin.empty ()) {
|
||||
float distance = (bombOrigin - graph[taskTarget].origin).length ();
|
||||
float distance = bombOrigin.distance (graph[taskTarget].origin);
|
||||
|
||||
if (distance > 512.0f) {
|
||||
if (rg.chance (50) && !graph.isVisited (taskTarget)) {
|
||||
|
|
@ -930,7 +938,7 @@ bool Bot::updateLiftHandling () {
|
|||
m_destOrigin = m_liftTravelPos;
|
||||
|
||||
// check if we enough to destination
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
|
||||
// need to wait our following teammate ?
|
||||
|
|
@ -984,7 +992,7 @@ bool Bot::updateLiftHandling () {
|
|||
if (needWaitForTeammate) {
|
||||
m_destOrigin = m_liftTravelPos;
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1015,7 +1023,7 @@ bool Bot::updateLiftHandling () {
|
|||
m_liftState = LiftState::TravelingBy;
|
||||
m_liftUsageTime = game.time () + 14.0f;
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1025,7 +1033,7 @@ bool Bot::updateLiftHandling () {
|
|||
if (m_liftState == LiftState::TravelingBy) {
|
||||
m_destOrigin = Vector (m_liftTravelPos.x, m_liftTravelPos.y, pev->origin.z);
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1042,7 +1050,7 @@ bool Bot::updateLiftHandling () {
|
|||
m_destOrigin = pev->origin;
|
||||
}
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1075,7 +1083,7 @@ bool Bot::updateLiftHandling () {
|
|||
m_destOrigin = button->v.origin;
|
||||
}
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1106,7 +1114,7 @@ bool Bot::updateLiftHandling () {
|
|||
}
|
||||
}
|
||||
|
||||
if ((pev->origin - m_destOrigin).lengthSq () < cr::square (20.0f)) {
|
||||
if (pev->origin.distanceSq (m_destOrigin) < cr::square (20.0f)) {
|
||||
wait ();
|
||||
}
|
||||
}
|
||||
|
|
@ -1204,8 +1212,12 @@ void Bot::findShortestPath (int srcIndex, int destIndex) {
|
|||
void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath::Fast */) {
|
||||
// this function finds a path from srcIndex to destIndex
|
||||
|
||||
auto dangerFactor = [&] () -> float {
|
||||
return rg.get (cv_path_danger_factor_min.float_ (), cv_path_danger_factor_max.float_ ()) * 2.0f / cr::clamp (m_difficulty, 1, 3);
|
||||
};
|
||||
|
||||
// least kills and number of nodes to goal for a team
|
||||
auto gfunctionKillsDist = [] (int team, int currentIndex, int parentIndex) -> float {
|
||||
auto gfunctionKillsDist = [&dangerFactor] (int team, int currentIndex, int parentIndex) -> float {
|
||||
if (parentIndex == kInvalidNodeIndex) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
|
@ -1221,7 +1233,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
if (current.flags & NodeFlag::Crouch) {
|
||||
cost *= 1.5f;
|
||||
}
|
||||
return cost;
|
||||
return cost + dangerFactor ();
|
||||
};
|
||||
|
||||
// least kills and number of nodes to goal for a team
|
||||
|
|
@ -1238,7 +1250,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
};
|
||||
|
||||
// least kills to goal for a team
|
||||
auto gfunctionKills = [] (int team, int currentIndex, int) -> float {
|
||||
auto gfunctionKills = [&dangerFactor] (int team, int currentIndex, int) -> float {
|
||||
auto cost = static_cast <float> (graph.getDangerDamage (team, currentIndex, currentIndex));
|
||||
const auto ¤t = graph[currentIndex];
|
||||
|
||||
|
|
@ -1251,7 +1263,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
if (current.flags & NodeFlag::Crouch) {
|
||||
cost *= 1.5f;
|
||||
}
|
||||
return cost + 0.5f;
|
||||
return cost + dangerFactor () + 1.0f;
|
||||
};
|
||||
|
||||
// least kills to goal for a team
|
||||
|
|
@ -1310,7 +1322,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
float y = cr::abs (start.origin.y - goal.origin.y);
|
||||
float z = cr::abs (start.origin.z - goal.origin.z);
|
||||
|
||||
switch (cv_debug_heuristic_type.int_ ()) {
|
||||
switch (cv_path_heuristic_mode.int_ ()) {
|
||||
case 0:
|
||||
default:
|
||||
return cr::max (cr::max (x, y), z); // chebyshev distance
|
||||
|
|
@ -1326,7 +1338,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
// euclidean based distance
|
||||
float euclidean = cr::powf (cr::powf (x, 2.0f) + cr::powf (y, 2.0f) + cr::powf (z, 2.0f), 0.5f);
|
||||
|
||||
if (cv_debug_heuristic_type.int_ () == 4) {
|
||||
if (cv_path_heuristic_mode.int_ () == 4) {
|
||||
return 1000.0f * (cr::ceilf (euclidean) - euclidean);
|
||||
}
|
||||
return euclidean;
|
||||
|
|
@ -1343,7 +1355,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
|
||||
// none heuristic
|
||||
auto hfunctionNone = [&hfunctionPathDist] (int index, int startIndex, int goalIndex) -> float {
|
||||
return hfunctionPathDist (index, startIndex, goalIndex) / 128.0f * 10.0f;
|
||||
return hfunctionPathDist (index, startIndex, goalIndex) / (128.0f * 10.0f);
|
||||
};
|
||||
|
||||
if (!graph.exists (srcIndex)) {
|
||||
|
|
@ -1578,7 +1590,7 @@ bool Bot::findBestNearestNode () {
|
|||
}
|
||||
|
||||
// if we're still here, find some close nodes
|
||||
float distance = (pev->origin - graph[at].origin).lengthSq ();
|
||||
float distance = pev->origin.distanceSq (graph[at].origin);
|
||||
|
||||
if (distance < lessDist[0]) {
|
||||
lessDist[2] = lessDist[1];
|
||||
|
|
@ -1650,7 +1662,7 @@ float Bot::getReachTime () {
|
|||
|
||||
// calculate 'real' time that we need to get from one node to another
|
||||
if (graph.exists (m_currentNodeIndex) && graph.exists (m_previousNodes[0])) {
|
||||
float distance = (graph[m_previousNodes[0]].origin - graph[m_currentNodeIndex].origin).length ();
|
||||
float distance = graph[m_previousNodes[0]].origin.distance (graph[m_currentNodeIndex].origin);
|
||||
|
||||
// caclulate estimated time
|
||||
if (pev->maxspeed <= 0.0f) {
|
||||
|
|
@ -1735,7 +1747,7 @@ int Bot::findNearestNode () {
|
|||
if (at == m_currentNodeIndex) {
|
||||
continue;
|
||||
}
|
||||
float distance = (graph[at].origin - pev->origin).lengthSq ();
|
||||
float distance = graph[at].origin.distanceSq (pev->origin);
|
||||
|
||||
if (distance < minimum) {
|
||||
|
||||
|
|
@ -1763,7 +1775,7 @@ int Bot::findBombNode () {
|
|||
const auto &audible = isBombAudible ();
|
||||
|
||||
// take the nearest to bomb nodes instead of goal if close enough
|
||||
if ((pev->origin - bomb).lengthSq () < cr::square (96.0f)) {
|
||||
if (pev->origin.distanceSq (bomb) < cr::square (96.0f)) {
|
||||
int node = graph.getNearest (bomb, 420.0f);
|
||||
|
||||
m_bombSearchOverridden = true;
|
||||
|
|
@ -1786,7 +1798,7 @@ int Bot::findBombNode () {
|
|||
|
||||
// find nearest goal node either to bomb (if "heard" or player)
|
||||
for (auto &point : goals) {
|
||||
float distance = (graph[point].origin - bomb).lengthSq ();
|
||||
float distance = bomb.distanceSq (graph[point].origin);
|
||||
|
||||
// check if we got more close distance
|
||||
if (distance < lastDistance) {
|
||||
|
|
@ -1888,7 +1900,7 @@ int Bot::findDefendNode (const Vector &origin) {
|
|||
IntArray found;
|
||||
|
||||
for (int i = 0; i < graph.length (); ++i) {
|
||||
if ((graph[i].origin - origin).lengthSq () <= cr::square (1248.0f) && !graph.isVisible (i, posIndex) && !isOccupiedNode (i)) {
|
||||
if (origin.distanceSq (graph[i].origin) <= cr::square (1248.0f) && !graph.isVisible (i, posIndex) && !isOccupiedNode (i)) {
|
||||
found.push (i);
|
||||
}
|
||||
}
|
||||
|
|
@ -1911,7 +1923,7 @@ int Bot::findDefendNode (const Vector &origin) {
|
|||
int Bot::findCoverNode (float maxDistance) {
|
||||
// this function tries to find a good cover node if bot wants to hide
|
||||
|
||||
const float enemyMax = (m_lastEnemyOrigin - pev->origin).length ();
|
||||
const float enemyMax = m_lastEnemyOrigin.distance (pev->origin);
|
||||
|
||||
// do not move to a position near to the enemy
|
||||
if (maxDistance > enemyMax) {
|
||||
|
|
@ -2172,7 +2184,7 @@ bool Bot::advanceMovement () {
|
|||
src = path.origin;
|
||||
dst = next.origin;
|
||||
|
||||
jumpDistance = (path.origin - next.origin).length ();
|
||||
jumpDistance = path.origin.distance (next.origin);
|
||||
willJump = true;
|
||||
|
||||
break;
|
||||
|
|
@ -2661,7 +2673,7 @@ bool Bot::isDeadlyMove (const Vector &to) {
|
|||
}
|
||||
|
||||
float lastHeight = tr.flFraction * 1000.0f; // height from ground
|
||||
float distance = (to - check).length (); // distance from goal
|
||||
float distance = to.distance (check); // distance from goal
|
||||
|
||||
if (distance <= 30.0f && lastHeight > 150.0f) {
|
||||
return true;
|
||||
|
|
@ -2686,7 +2698,7 @@ bool Bot::isDeadlyMove (const Vector &to) {
|
|||
return true;
|
||||
}
|
||||
lastHeight = height;
|
||||
distance = (to - check).length (); // distance from goal
|
||||
distance = to.distance (check); // distance from goal
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2774,13 +2786,13 @@ int Bot::findCampingDirection () {
|
|||
if (count < 3) {
|
||||
indices[count] = i;
|
||||
|
||||
distTab[count] = (pev->origin - path.origin).lengthSq ();
|
||||
distTab[count] = pev->origin.distanceSq (path.origin);
|
||||
visibility[count] = path.vis.crouch + path.vis.stand;
|
||||
|
||||
++count;
|
||||
}
|
||||
else {
|
||||
float distance = (pev->origin - path.origin).lengthSq ();
|
||||
float distance = pev->origin.distanceSq (path.origin);
|
||||
uint16 visBits = path.vis.crouch + path.vis.stand;
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
|
|
@ -3005,14 +3017,14 @@ bool Bot::isOccupiedNode (int index, bool needZeroVelocity) {
|
|||
}
|
||||
|
||||
// do not check clients far away from us
|
||||
if ((pev->origin - client.origin).lengthSq () > cr::square (320.0f)) {
|
||||
if (pev->origin.distanceSq (client.origin) > cr::square (320.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needZeroVelocity && client.ent->v.velocity.length2d () > 0.0f) {
|
||||
continue;
|
||||
}
|
||||
auto length = (graph[index].origin - client.origin).lengthSq ();
|
||||
auto length = client.origin.distanceSq (graph[index].origin);
|
||||
|
||||
if (length < cr::clamp (cr::square (graph[index].radius), cr::square (60.0f), cr::square (90.0f))) {
|
||||
return true;
|
||||
|
|
@ -3049,7 +3061,7 @@ edict_t *Bot::lookupButton (const char *target) {
|
|||
|
||||
// check if this place safe
|
||||
if (!isDeadlyMove (pos)) {
|
||||
float distance = (pev->origin - pos).lengthSq ();
|
||||
float distance = pev->origin.distanceSq (pos);
|
||||
|
||||
// check if we got more close button
|
||||
if (distance <= nearest) {
|
||||
|
|
@ -3073,7 +3085,7 @@ bool Bot::isReachableNode (int index) {
|
|||
const Vector &dst = graph[index].origin;
|
||||
|
||||
// is the destination close enough?
|
||||
if ((dst - src).lengthSq () >= cr::square (320.0f)) {
|
||||
if (dst.distanceSq (src) >= cr::square (320.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3081,7 +3093,7 @@ bool Bot::isReachableNode (int index) {
|
|||
if (isOccupiedNode (index, true)) {
|
||||
return true;
|
||||
}
|
||||
float ladderDist = (dst - src).length2d ();
|
||||
float ladderDist = dst.distance2d (src);
|
||||
|
||||
TraceResult tr {};
|
||||
game.testLine (src, dst, TraceIgnore::Monsters, ent (), &tr);
|
||||
|
|
@ -3112,6 +3124,9 @@ bool Bot::isReachableNode (int index) {
|
|||
}
|
||||
|
||||
bool Bot::isBannedNode (int index) {
|
||||
if (graph.exists (cv_debug_goal.int_ ())) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &node : m_goalHistory) {
|
||||
if (node == index) {
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue