Do not throw grenades in narrow places.
Removed displaying of "CROSSING" flag for nodes, as it's not used anymore. Do not aim last / predict enemy in narrow places (like tunnels, when crouching).
This commit is contained in:
parent
d7ee3ae35a
commit
2aba34a24b
9 changed files with 121 additions and 16 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -34,8 +34,8 @@ Icon
|
||||||
# Files that might appear on external disk
|
# Files that might appear on external disk
|
||||||
.Spotlight-V100
|
.Spotlight-V100
|
||||||
.Trashes
|
.Trashes
|
||||||
/project/#Verone
|
|
||||||
/project/.vs
|
/project/.vs
|
||||||
|
/project/enc_temp_folder
|
||||||
/.vs
|
/.vs
|
||||||
|
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ CR_DECLARE_SCOPED_ENUM (NodeFlag,
|
||||||
Camp = cr::bit (7), // node is a camping point
|
Camp = cr::bit (7), // node is a camping point
|
||||||
NoHostage = cr::bit (8), // only use this node if no hostage
|
NoHostage = cr::bit (8), // only use this node if no hostage
|
||||||
DoubleJump = cr::bit (9), // bot help's another bot (requster) to get somewhere (using djump)
|
DoubleJump = cr::bit (9), // bot help's another bot (requster) to get somewhere (using djump)
|
||||||
|
Narrow = cr::bit (10), // node is inside some small space (corridor or such)
|
||||||
Sniper = cr::bit (28), // it's a specific sniper point
|
Sniper = cr::bit (28), // it's a specific sniper point
|
||||||
TerroristOnly = cr::bit (29), // it's a specific terrorist point
|
TerroristOnly = cr::bit (29), // it's a specific terrorist point
|
||||||
CTOnly = cr::bit (30), // it's a specific ct point
|
CTOnly = cr::bit (30), // it's a specific ct point
|
||||||
|
|
@ -255,6 +256,7 @@ private:
|
||||||
bool m_jumpLearnNode;
|
bool m_jumpLearnNode;
|
||||||
bool m_hasChanged;
|
bool m_hasChanged;
|
||||||
bool m_needsVisRebuild;
|
bool m_needsVisRebuild;
|
||||||
|
bool m_narrowChecked;
|
||||||
|
|
||||||
Vector m_learnVelocity;
|
Vector m_learnVelocity;
|
||||||
Vector m_learnPosition;
|
Vector m_learnPosition;
|
||||||
|
|
@ -321,6 +323,7 @@ public:
|
||||||
void loadVisibility ();
|
void loadVisibility ();
|
||||||
void initNodesTypes ();
|
void initNodesTypes ();
|
||||||
void initLightLevels ();
|
void initLightLevels ();
|
||||||
|
void initNarrowPlaces ();
|
||||||
void addPath (int addIndex, int pathIndex, float distance);
|
void addPath (int addIndex, int pathIndex, float distance);
|
||||||
void add (int type, const Vector &pos = nullptr);
|
void add (int type, const Vector &pos = nullptr);
|
||||||
void erase (int target);
|
void erase (int target);
|
||||||
|
|
|
||||||
|
|
@ -872,6 +872,10 @@ private:
|
||||||
return pev->waterlevel >= 2;
|
return pev->waterlevel >= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isInNarrowPlace () const {
|
||||||
|
return (m_pathFlags & NodeFlag::Narrow);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
entvars_t *pev;
|
entvars_t *pev;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,14 +117,14 @@ bool Bot::seesEntity (const Vector &dest, bool fromBody) {
|
||||||
void Bot::checkGrenadesThrow () {
|
void Bot::checkGrenadesThrow () {
|
||||||
|
|
||||||
// do not check cancel if we have grenade in out hands
|
// do not check cancel if we have grenade in out hands
|
||||||
bool checkTasks = getCurrentTaskId () == Task::PlantBomb || getCurrentTaskId () == Task::DefuseBomb;
|
bool preventibleTasks = getCurrentTaskId () == Task::PlantBomb || getCurrentTaskId () == Task::DefuseBomb;
|
||||||
|
|
||||||
auto clearThrowStates = [] (uint32 &states) {
|
auto clearThrowStates = [] (uint32 &states) {
|
||||||
states &= ~(Sense::ThrowExplosive | Sense::ThrowFlashbang | Sense::ThrowSmoke);
|
states &= ~(Sense::ThrowExplosive | Sense::ThrowFlashbang | Sense::ThrowSmoke);
|
||||||
};
|
};
|
||||||
|
|
||||||
// check if throwing a grenade is a good thing to do...
|
// check if throwing a grenade is a good thing to do...
|
||||||
if (checkTasks || yb_ignore_enemies.bool_ () || m_isUsingGrenade || m_grenadeRequested || m_isReloading || yb_jasonmode.bool_ () || m_grenadeCheckTime >= game.time ()) {
|
if (preventibleTasks || isInNarrowPlace () || yb_ignore_enemies.bool_ () || m_isUsingGrenade || m_grenadeRequested || m_isReloading || yb_jasonmode.bool_ () || m_grenadeCheckTime >= game.time ()) {
|
||||||
clearThrowStates (m_states);
|
clearThrowStates (m_states);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2692,7 +2692,11 @@ void Bot::updateAimDir () {
|
||||||
|
|
||||||
// don't allow bot to look at danger positions under certain circumstances
|
// don't allow bot to look at danger positions under certain circumstances
|
||||||
if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) {
|
if (!(flags & (AimFlags::Grenade | AimFlags::Enemy | AimFlags::Entity))) {
|
||||||
if (isOnLadder () || isInWater () || (m_pathFlags & NodeFlag::Ladder) || (m_currentTravelFlags & PathFlag::Jump)) {
|
|
||||||
|
// check if narrow place and we're duck, do not predict enemies in that situation
|
||||||
|
const bool duckedInNarrowPlace = isInNarrowPlace () && ((m_pathFlags & NodeFlag::Crouch) || (pev->button & IN_DUCK));
|
||||||
|
|
||||||
|
if (duckedInNarrowPlace || isOnLadder () || isInWater () || (m_pathFlags & NodeFlag::Ladder) || (m_currentTravelFlags & PathFlag::Jump)) {
|
||||||
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
flags &= ~(AimFlags::LastEnemy | AimFlags::PredictPath);
|
||||||
m_canChooseAimDirection = false;
|
m_canChooseAimDirection = false;
|
||||||
}
|
}
|
||||||
|
|
@ -2761,6 +2765,7 @@ void Bot::updateAimDir () {
|
||||||
if (!m_camp.empty ()) {
|
if (!m_camp.empty ()) {
|
||||||
m_lookAt = m_camp;
|
m_lookAt = m_camp;
|
||||||
}
|
}
|
||||||
|
m_timeNextTracking = game.time () + 2.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2771,8 +2776,15 @@ void Bot::updateAimDir () {
|
||||||
m_lookAt = m_camp;
|
m_lookAt = m_camp;
|
||||||
}
|
}
|
||||||
else if (flags & AimFlags::Nav) {
|
else if (flags & AimFlags::Nav) {
|
||||||
if (m_moveToGoal && !m_isStuck && m_currentNodeIndex != kInvalidNodeIndex && !(m_path->flags & NodeFlag::Ladder) && m_pathWalk.hasNext () && (pev->origin - m_destOrigin).lengthSq () < cr::square (52.0f)) {
|
if (m_moveToGoal && !m_isStuck && !(pev->button & IN_DUCK) && m_currentNodeIndex != kInvalidNodeIndex && !(m_path->flags & (NodeFlag::Ladder | NodeFlag::Crouch)) && m_pathWalk.hasNext () && (pev->origin - m_destOrigin).lengthSq () < cr::square (52.0f)) {
|
||||||
m_lookAt = graph[m_pathWalk.next ()].origin + pev->view_ofs;
|
int nextPath = m_pathWalk.next ();
|
||||||
|
|
||||||
|
if (graph.isVisible (m_currentNodeIndex, nextPath)) {
|
||||||
|
m_lookAt = graph[nextPath].origin + pev->view_ofs;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_lookAt = m_destOrigin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_lookAt = m_destOrigin;
|
m_lookAt = m_destOrigin;
|
||||||
|
|
|
||||||
|
|
@ -529,6 +529,9 @@ float Bot::getEnemyBodyOffsetCorrection (float distance) {
|
||||||
result = -4.5f;
|
result = -4.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
result = -5.6f;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -848,6 +848,9 @@ void Game::slowFrame () {
|
||||||
// initialize light levels
|
// initialize light levels
|
||||||
graph.initLightLevels ();
|
graph.initLightLevels ();
|
||||||
|
|
||||||
|
// initialize corridors
|
||||||
|
graph.initNarrowPlaces ();
|
||||||
|
|
||||||
// detect csdm
|
// detect csdm
|
||||||
applyGameModes ();
|
applyGameModes ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ void BotGraph::initGraph () {
|
||||||
m_arrowDisplayTime = 0.0f;
|
m_arrowDisplayTime = 0.0f;
|
||||||
m_autoPathDistance = 250.0f;
|
m_autoPathDistance = 250.0f;
|
||||||
m_hasChanged = false;
|
m_hasChanged = false;
|
||||||
|
m_narrowChecked = false;
|
||||||
|
|
||||||
// reset highest recorded damage
|
// reset highest recorded damage
|
||||||
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||||
|
|
@ -1296,6 +1297,83 @@ void BotGraph::initLightLevels () {
|
||||||
}
|
}
|
||||||
// disable lightstyle animations on finish (will be auto-enabled on mapchange)
|
// disable lightstyle animations on finish (will be auto-enabled on mapchange)
|
||||||
illum.enableAnimation (false);
|
illum.enableAnimation (false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BotGraph::initNarrowPlaces () {
|
||||||
|
// this function checks all nodes if they are inside narrow places. this is used to prevent
|
||||||
|
// bots to track hidden enemies in narrow places and prevent bots from throwing flashbangs or
|
||||||
|
// other grenades inside bad places.
|
||||||
|
|
||||||
|
// no nodes ?
|
||||||
|
if (m_paths.empty () || m_narrowChecked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TraceResult tr;
|
||||||
|
|
||||||
|
const auto distance = 178.0f;
|
||||||
|
const auto worldspawn = game.getStartEntity ();
|
||||||
|
const auto offset = Vector (0.0f, 0.0f, 16.0f);
|
||||||
|
|
||||||
|
// check olny paths that have not too much connections
|
||||||
|
for (auto &path : m_paths) {
|
||||||
|
|
||||||
|
// skip any goals and camp points
|
||||||
|
if (path.flags & (NodeFlag::Camp | NodeFlag::Goal)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int linkCount = 0;
|
||||||
|
|
||||||
|
for (const auto &link : path.links) {
|
||||||
|
if (link.index == kInvalidNodeIndex || link.index == path.number) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++linkCount > kMaxNodeLinks / 2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip nodes with too much connections, this indicated we're not in narrow place
|
||||||
|
if (linkCount > kMaxNodeLinks / 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int accumWeight = 0;
|
||||||
|
|
||||||
|
// we could use this one!
|
||||||
|
for (const auto &link : path.links) {
|
||||||
|
if (link.index == kInvalidNodeIndex || link.index == path.number) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Vector &ang = ((path.origin - m_paths[link.index].origin).normalize () * distance).angles ();
|
||||||
|
|
||||||
|
Vector forward, right, upward;
|
||||||
|
ang.angleVectors (&forward, &right, &upward);
|
||||||
|
|
||||||
|
// helper lambda
|
||||||
|
auto directionCheck = [&] (const Vector &to, int weight) {
|
||||||
|
game.testLine (path.origin + offset, to, TraceIgnore::None, nullptr, &tr);
|
||||||
|
|
||||||
|
// check if we're hit worldspawn entity
|
||||||
|
if (tr.pHit == worldspawn && tr.flFraction < 1.0f) {
|
||||||
|
accumWeight += weight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
directionCheck (-forward * distance, 1);
|
||||||
|
|
||||||
|
directionCheck (right * distance, 1);
|
||||||
|
directionCheck (-right * distance, 1);
|
||||||
|
|
||||||
|
directionCheck (upward * distance, 1);
|
||||||
|
}
|
||||||
|
path.flags &= ~NodeFlag::Narrow;
|
||||||
|
|
||||||
|
if (accumWeight > 1) {
|
||||||
|
path.flags |= NodeFlag::Narrow;
|
||||||
|
}
|
||||||
|
accumWeight = 0;
|
||||||
|
}
|
||||||
|
m_narrowChecked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotGraph::initNodesTypes () {
|
void BotGraph::initNodesTypes () {
|
||||||
|
|
@ -1336,7 +1414,8 @@ bool BotGraph::convertOldFormat () {
|
||||||
plat.bzero (&header, sizeof (header));
|
plat.bzero (&header, sizeof (header));
|
||||||
|
|
||||||
// save for faster access
|
// save for faster access
|
||||||
const char *map = game.getMapName ();
|
auto map = game.getMapName ();
|
||||||
|
|
||||||
if (fp) {
|
if (fp) {
|
||||||
|
|
||||||
if (fp.read (&header, sizeof (header)) == 0) {
|
if (fp.read (&header, sizeof (header)) == 0) {
|
||||||
|
|
@ -2216,7 +2295,7 @@ void BotGraph::frame () {
|
||||||
}
|
}
|
||||||
|
|
||||||
static String buffer;
|
static String buffer;
|
||||||
buffer.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags == 0 && !jumpPoint) ? " (none)" : "", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Crossing) ? " CROSSING" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
|
buffer.assignf ("%s%s%s%s%s%s%s%s%s%s%s%s%s", (path.flags == 0 && !jumpPoint) ? " (none)" : "", (path.flags & NodeFlag::Lift) ? " LIFT" : "", (path.flags & NodeFlag::Crouch) ? " CROUCH" : "", (path.flags & NodeFlag::Camp) ? " CAMP" : "", (path.flags & NodeFlag::TerroristOnly) ? " TERRORIST" : "", (path.flags & NodeFlag::CTOnly) ? " CT" : "", (path.flags & NodeFlag::Sniper) ? " SNIPER" : "", (path.flags & NodeFlag::Goal) ? " GOAL" : "", (path.flags & NodeFlag::Ladder) ? " LADDER" : "", (path.flags & NodeFlag::Rescue) ? " RESCUE" : "", (path.flags & NodeFlag::DoubleJump) ? " JUMPHELP" : "", (path.flags & NodeFlag::NoHostage) ? " NOHOSTAGE" : "", jumpPoint ? " JUMP" : "");
|
||||||
|
|
||||||
// return the message buffer
|
// return the message buffer
|
||||||
return buffer.chars ();
|
return buffer.chars ();
|
||||||
|
|
|
||||||
|
|
@ -642,9 +642,9 @@ bool Bot::updateNavigation () {
|
||||||
findValidNode ();
|
findValidNode ();
|
||||||
m_pathOrigin = m_path->origin;
|
m_pathOrigin = m_path->origin;
|
||||||
|
|
||||||
// if wayzone radios non zero vary origin a bit depending on the body angles
|
// if wayzone radius non zero vary origin a bit depending on the body angles
|
||||||
if (m_path->radius > 0.0f) {
|
if (m_path->radius > 0.0f) {
|
||||||
m_pathOrigin = m_pathOrigin + Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0, m_path->radius);
|
m_pathOrigin = m_pathOrigin + Vector (pev->angles.x, cr::normalizeAngles (pev->angles.y + rg.float_ (-90.0f, 90.0f)), 0.0f).forward () * rg.float_ (0.0f, m_path->radius);
|
||||||
}
|
}
|
||||||
m_navTimeset = game.time ();
|
m_navTimeset = game.time ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -652,10 +652,12 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
|
||||||
const auto send = [&] (const Twin <const uint8 *, size_t> &msg) -> int32 {
|
const auto send = [&] (const Twin <const uint8 *, size_t> &msg) -> int32 {
|
||||||
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);
|
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto packet = reinterpret_cast <const uint8 *> (message);
|
auto packet = reinterpret_cast <const uint8 *> (message);
|
||||||
|
|
||||||
// player replies response
|
// player replies response
|
||||||
if (length > 5 && packet[0] == 0xff && packet[1] == 0xff && packet[2] == 0xff && packet[3] == 0xff) {
|
if (length > 5 && packet[0] == 0xff && packet[1] == 0xff && packet[2] == 0xff && packet[3] == 0xff) {
|
||||||
|
|
||||||
if (packet[4] == 'D') {
|
if (packet[4] == 'D') {
|
||||||
QueryBuffer buffer (packet, length, 5);
|
QueryBuffer buffer (packet, length, 5);
|
||||||
auto count = buffer.read <uint8> ();
|
auto count = buffer.read <uint8> ();
|
||||||
|
|
@ -681,7 +683,6 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
|
||||||
buffer.skipString ();
|
buffer.skipString ();
|
||||||
}
|
}
|
||||||
buffer.skip <short> (); // steam app id
|
buffer.skip <short> (); // steam app id
|
||||||
|
|
||||||
buffer.skip <uint8> (); // players
|
buffer.skip <uint8> (); // players
|
||||||
buffer.skip <uint8> (); // maxplayers
|
buffer.skip <uint8> (); // maxplayers
|
||||||
buffer.skip <uint8> (); // bots
|
buffer.skip <uint8> (); // bots
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue