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:
jeefo 2021-09-20 13:50:00 +03:00 committed by GitHub
commit 6f912eb056
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 214 additions and 177 deletions

View file

@ -386,6 +386,15 @@ int BotGraph::clearConnections (int index) {
return numFixedLinks;
}
int BotGraph::getBspSize () {
MemFile file (strings.format ("maps/%s.bsp", game.getMapName ()));
if (file) {
return static_cast <int> (file.length ());
}
return 0;
}
void BotGraph::addPath (int addIndex, int pathIndex, float distance) {
if (!exists (addIndex) || !exists (pathIndex)) {
return;
@ -437,7 +446,7 @@ int BotGraph::getFarest (const Vector &origin, float maxDistance) {
maxDistance = cr::square (maxDistance);
for (const auto &path : m_paths) {
float distance = (path.origin - origin).lengthSq ();
float distance = path.origin.distanceSq (origin);
if (distance > maxDistance) {
index = path.number;
@ -458,7 +467,7 @@ int BotGraph::getNearestNoBuckets (const Vector &origin, float minDistance, int
if (flags != -1 && !(path.flags & flags)) {
continue; // if flag not -1 and node has no this flag, skip node
}
float distance = (path.origin - origin).lengthSq ();
float distance = path.origin.distanceSq (origin);
if (distance < minDistance) {
index = path.number;
@ -491,7 +500,7 @@ int BotGraph::getNearest (const Vector &origin, float minDistance, int flags) {
if (flags != -1 && !(m_paths[at].flags & flags)) {
continue; // if flag not -1 and node has no this flag, skip node
}
float distance = (m_paths[at].origin - origin).lengthSq ();
float distance = origin.distanceSq (m_paths[at].origin);
if (distance < minDistanceSq) {
index = at;
@ -523,7 +532,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun
break;
}
if ((m_paths[at].origin - origin).lengthSq () < radius) {
if (origin.distanceSq (m_paths[at].origin) < radius) {
result.push (at);
}
}
@ -548,7 +557,7 @@ void BotGraph::add (int type, const Vector &pos) {
m_hasChanged = true;
switch (type) {
case 5:
case NodeAddFlag::Camp:
index = getEditorNeareset ();
if (index != kInvalidNodeIndex) {
@ -564,7 +573,7 @@ void BotGraph::add (int type, const Vector &pos) {
}
break;
case 6:
case NodeAddFlag::CampEnd:
index = getEditorNeareset ();
if (index != kInvalidNodeIndex) {
@ -581,11 +590,11 @@ void BotGraph::add (int type, const Vector &pos) {
}
return;
case 9:
case NodeAddFlag::JumpStart:
index = getEditorNeareset ();
if (index != kInvalidNodeIndex && m_paths[index].number >= 0) {
float distance = (m_paths[index].origin - m_editor->v.origin).length ();
float distance = m_editor->v.origin.distance (m_paths[index].origin);
if (distance < 50.0f) {
addNewNode = false;
@ -599,11 +608,11 @@ void BotGraph::add (int type, const Vector &pos) {
}
break;
case 10:
case NodeAddFlag::JumpEnd:
index = getEditorNeareset ();
if (index != kInvalidNodeIndex && m_paths[index].number >= 0) {
float distance = (m_paths[index].origin - m_editor->v.origin).length ();
float distance = m_editor->v.origin.distance (m_paths[index].origin);
if (distance < 50.0f) {
addNewNode = false;
@ -627,7 +636,7 @@ void BotGraph::add (int type, const Vector &pos) {
auto nearest = getEditorNeareset ();
// do not allow to place waypoints "inside" waypoints, make at leat 10 units range
if (exists (nearest) && (m_paths[nearest].origin - newOrigin).lengthSq () < cr::square (10.0f)) {
if (exists (nearest) && newOrigin.distanceSq (m_paths[nearest].origin) < cr::square (10.0f)) {
ctrl.msg ("Can't add node. It's way to near to %d node. Please move some units anywhere.", nearest);
return;
}
@ -666,11 +675,11 @@ void BotGraph::add (int type, const Vector &pos) {
m_lastNode = m_editor->v.origin;
}
if (type == 9) {
if (type == NodeAddFlag::JumpStart) {
m_lastJumpNode = index;
}
else if (type == 10) {
float distance = (m_paths[m_lastJumpNode].origin - m_editor->v.origin).length ();
else if (type == NodeAddFlag::JumpEnd) {
float distance = m_paths[m_lastJumpNode].origin.distance (m_editor->v.origin);
addPath (m_lastJumpNode, index, distance);
for (auto &link : m_paths[m_lastJumpNode].links) {
@ -701,32 +710,32 @@ void BotGraph::add (int type, const Vector &pos) {
}
switch (type) {
case 1:
case NodeAddFlag::TOnly:
path->flags |= NodeFlag::Crossing;
path->flags |= NodeFlag::TerroristOnly;
break;
case 2:
case NodeAddFlag::CTOnly:
path->flags |= NodeFlag::Crossing;
path->flags |= NodeFlag::CTOnly;
break;
case 3:
case NodeAddFlag::NoHostage:
path->flags |= NodeFlag::NoHostage;
break;
case 4:
case NodeAddFlag::Rescue:
path->flags |= NodeFlag::Rescue;
break;
case 5:
case NodeAddFlag::Camp:
path->flags |= NodeFlag::Crossing;
path->flags |= NodeFlag::Camp;
path->start = m_editor->v.v_angle;
break;
case 100:
case NodeAddFlag::Goal:
path->flags |= NodeFlag::Goal;
break;
}
@ -750,7 +759,7 @@ void BotGraph::add (int type, const Vector &pos) {
game.testLine (newOrigin, calc.origin, TraceIgnore::Monsters, m_editor, &tr);
if (cr::fequal (tr.flFraction, 1.0f) && cr::abs (newOrigin.x - calc.origin.x) < 64.0f && cr::abs (newOrigin.y - calc.origin.y) < 64.0f && cr::abs (newOrigin.z - calc.origin.z) < m_autoPathDistance) {
float distance = (calc.origin - newOrigin).length ();
float distance = newOrigin.distance (calc.origin);
addPath (index, calc.number, distance);
addPath (calc.number, index, distance);
@ -759,7 +768,7 @@ void BotGraph::add (int type, const Vector &pos) {
else {
// check if the node is reachable from the new one
if (isNodeReacheable (newOrigin, calc.origin) || isNodeReacheable (calc.origin, newOrigin)) {
float distance = (calc.origin - newOrigin).length ();
float distance = newOrigin.distance (calc.origin);
if (distance < minDistance) {
destIndex = calc.number;
@ -772,12 +781,12 @@ void BotGraph::add (int type, const Vector &pos) {
if (exists (destIndex)) {
// check if the node is reachable from the new one (one-way)
if (isNodeReacheable (newOrigin, m_paths[destIndex].origin)) {
addPath (index, destIndex, (m_paths[destIndex].origin - newOrigin).length ());
addPath (index, destIndex, newOrigin.distance (m_paths[destIndex].origin));
}
// check if the new one is reachable from the node (other way)
if (isNodeReacheable (m_paths[destIndex].origin, newOrigin)) {
addPath (destIndex, index, (m_paths[destIndex].origin - newOrigin).length ());
addPath (destIndex, index, newOrigin.distance (m_paths[destIndex].origin));
}
}
}
@ -790,12 +799,12 @@ void BotGraph::add (int type, const Vector &pos) {
// check if the node is reachable from the new one (one-way)
if (isNodeReacheable (newOrigin, calc.origin)) {
addPath (index, calc.number, (calc.origin - newOrigin).length ());
addPath (index, calc.number, calc.origin.distance (newOrigin));
}
// check if the new one is reachable from the node (other way)
if (isNodeReacheable (calc.origin, newOrigin)) {
addPath (calc.number, index, (calc.origin - newOrigin).length ());
addPath (calc.number, index, calc.origin.distance (newOrigin));
}
}
clearConnections (index);
@ -975,7 +984,7 @@ void BotGraph::pathCreate (char dir) {
return;
}
float distance = (m_paths[nodeTo].origin - m_paths[nodeFrom].origin).length ();
float distance = m_paths[nodeFrom].origin.distance (m_paths[nodeTo].origin);
if (dir == PathConnection::Outgoing) {
addPath (nodeFrom, nodeTo, distance);
@ -1787,7 +1796,7 @@ bool BotGraph::loadGraphData () {
loadPractice ();
if (exten.mapSize > 0) {
int mapSize = engfuncs.pfnGetFileSize (strings.format ("maps/%s.bsp", game.getMapName ()));
int mapSize = getBspSize ();
if (mapSize != exten.mapSize) {
ctrl.msg ("Warning: Graph data is probably not for this map. Please check bots behaviour.");
@ -1829,7 +1838,7 @@ bool BotGraph::saveGraphData () {
ExtenHeader exten {};
strings.copy (exten.author, author.chars (), cr::bufsize (exten.author));
exten.mapSize = engfuncs.pfnGetFileSize (strings.format ("maps/%s.bsp", game.getMapName ()));
exten.mapSize = getBspSize ();
// ensure narrow places saved into file
m_narrowChecked = false;
@ -1883,13 +1892,13 @@ const char *BotGraph::getOldFormatGraphName (bool isMemoryFile) {
float BotGraph::calculateTravelTime (float maxSpeed, const Vector &src, const Vector &origin) {
// this function returns 2D traveltime to a position
return (origin - src).length2d () / maxSpeed;
return origin.distance2d (src) / maxSpeed;
}
bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
TraceResult tr {};
float distance = (destination - src).length ();
float distance = destination.distance (src);
// is the destination not close enough?
if (distance > m_autoPathDistance) {
@ -1945,7 +1954,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
game.testLine (check, down, TraceIgnore::Monsters, m_editor, &tr);
float lastHeight = tr.flFraction * 1000.0f; // height from ground
distance = (destination - check).length (); // distance from goal
distance = destination.distance (check); // distance from goal
while (distance > 10.0f) {
// move 10 units closer to the goal...
@ -1963,7 +1972,7 @@ bool BotGraph::isNodeReacheable (const Vector &src, const Vector &destination) {
return false; // can't get there without jumping...
}
lastHeight = height;
distance = (destination - check).length (); // distance from goal
distance = destination.distance (check); // distance from goal
}
return true;
}
@ -2115,7 +2124,7 @@ void BotGraph::frame () {
if (m_jumpLearnNode) {
if (!m_endJumpPoint) {
if (m_editor->v.button & IN_JUMP) {
add (9);
add (NodeAddFlag::JumpStart);
m_timeJumpStarted = game.time ();
m_endJumpPoint = true;
@ -2126,7 +2135,7 @@ void BotGraph::frame () {
}
}
else if (((m_editor->v.flags & FL_ONGROUND) || m_editor->v.movetype == MOVETYPE_FLY) && m_timeJumpStarted + 0.1f < game.time () && m_endJumpPoint) {
add (10);
add (NodeAddFlag::JumpEnd);
m_jumpLearnNode = false;
m_endJumpPoint = false;
@ -2136,13 +2145,13 @@ void BotGraph::frame () {
// check if it's a auto-add-node mode enabled
if (hasEditFlag (GraphEdit::Auto) && (m_editor->v.flags & (FL_ONGROUND | FL_PARTIALGROUND))) {
// find the distance from the last used node
float distance = (m_lastNode - m_editor->v.origin).lengthSq ();
float distance = m_lastNode.distanceSq (m_editor->v.origin);
if (distance > cr::square (128.0f)) {
// check that no other reachable nodes are nearby...
for (const auto &path : m_paths) {
if (isNodeReacheable (m_editor->v.origin, path.origin)) {
distance = (path.origin - m_editor->v.origin).lengthSq ();
distance = path.origin.distanceSq (m_editor->v.origin);
if (distance < nearestDistance) {
nearestDistance = distance;
@ -2152,7 +2161,7 @@ void BotGraph::frame () {
// make sure nearest node is far enough away...
if (nearestDistance >= cr::square (128.0f)) {
add (GraphAdd::Normal); // place a node here
add (NodeAddFlag::Normal); // place a node here
}
}
}
@ -2163,7 +2172,7 @@ void BotGraph::frame () {
// now iterate through all nodes in a map, and draw required ones
for (auto &path : m_paths) {
float distance = (path.origin - m_editor->v.origin).length ();
float distance = path.origin.distance (m_editor->v.origin);
// check if node is whitin a distance, and is visible
if (distance < 512.0f && ((util.isVisible (path.origin, m_editor) && util.isInViewCone (path.origin, m_editor)) || !util.isAlive (m_editor) || distance < 128.0f)) {
@ -2705,7 +2714,7 @@ void BotGraph::addBasic () {
do {
if (getNearestNoBuckets (point, 50.0f) == kInvalidNodeIndex) {
add (3, point);
add (NodeAddFlag::NoHostage, point);
}
point.z += 160;
} while (point.z < down.z - 40.0f);
@ -2713,7 +2722,7 @@ void BotGraph::addBasic () {
point = down + Vector (0.0f, 0.0f, 38.0f);
if (getNearestNoBuckets (point, 50.0f) == kInvalidNodeIndex) {
add (3, point);
add (NodeAddFlag::NoHostage, point);
}
m_isOnLadder = false;
@ -2731,31 +2740,30 @@ void BotGraph::addBasic () {
});
};
autoCreateForEntity (0, "info_player_deathmatch"); // then terrortist spawnpoints
autoCreateForEntity (0, "info_player_start"); // then add ct spawnpoints
autoCreateForEntity (0, "info_vip_start"); // then vip spawnpoint
autoCreateForEntity (0, "armoury_entity"); // weapons on the map ?
autoCreateForEntity (NodeAddFlag::Normal, "info_player_deathmatch"); // then terrortist spawnpoints
autoCreateForEntity (NodeAddFlag::Normal, "info_player_start"); // then add ct spawnpoints
autoCreateForEntity (NodeAddFlag::Normal, "info_vip_start"); // then vip spawnpoint
autoCreateForEntity (NodeAddFlag::Normal, "armoury_entity"); // weapons on the map ?
autoCreateForEntity (4, "func_hostage_rescue"); // hostage rescue zone
autoCreateForEntity (4, "info_hostage_rescue"); // hostage rescue zone (same as above)
autoCreateForEntity (NodeAddFlag::Rescue, "func_hostage_rescue"); // hostage rescue zone
autoCreateForEntity (NodeAddFlag::Rescue, "info_hostage_rescue"); // hostage rescue zone (same as above)
autoCreateForEntity (100, "func_bomb_target"); // bombspot zone
autoCreateForEntity (100, "info_bomb_target"); // bombspot zone (same as above)
autoCreateForEntity (100, "hostage_entity"); // hostage entities
autoCreateForEntity (100, "func_vip_safetyzone"); // vip rescue (safety) zone
autoCreateForEntity (100, "func_escapezone"); // terrorist escape zone
autoCreateForEntity (NodeAddFlag::Goal, "func_bomb_target"); // bombspot zone
autoCreateForEntity (NodeAddFlag::Goal, "info_bomb_target"); // bombspot zone (same as above)
autoCreateForEntity (NodeAddFlag::Goal, "hostage_entity"); // hostage entities
autoCreateForEntity (NodeAddFlag::Goal, "func_vip_safetyzone"); // vip rescue (safety) zone
autoCreateForEntity (NodeAddFlag::Goal, "func_escapezone"); // terrorist escape zone
}
void BotGraph::eraseFromDisk () {
// this function removes graph file from the hard disk
StringArray forErase;
bots.kickEveryone (true);
auto map = game.getMapName ();
auto data = getDataDirectory ();
bots.kickEveryone (true);
// if we're delete graph, delete all corresponding to it files
forErase.push (strings.format ("%spwf/%s.pwf", data, map)); // graph itself
forErase.push (strings.format ("%strain/%s.prc", data, map)); // corresponding to practice