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:
jeefo 2020-01-08 18:29:28 +03:00
commit 2aba34a24b
9 changed files with 121 additions and 16 deletions

View file

@ -117,14 +117,14 @@ bool Bot::seesEntity (const Vector &dest, bool fromBody) {
void Bot::checkGrenadesThrow () {
// 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) {
states &= ~(Sense::ThrowExplosive | Sense::ThrowFlashbang | Sense::ThrowSmoke);
};
// 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);
return;
}
@ -2692,12 +2692,16 @@ void Bot::updateAimDir () {
// don't allow bot to look at danger positions under certain circumstances
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);
m_canChooseAimDirection = false;
}
}
if (flags & AimFlags::Override) {
m_lookAt = m_camp;
}
@ -2761,6 +2765,7 @@ void Bot::updateAimDir () {
if (!m_camp.empty ()) {
m_lookAt = m_camp;
}
m_timeNextTracking = game.time () + 2.5f;
}
}
else {
@ -2771,8 +2776,15 @@ void Bot::updateAimDir () {
m_lookAt = m_camp;
}
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)) {
m_lookAt = graph[m_pathWalk.next ()].origin + pev->view_ofs;
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)) {
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 {
m_lookAt = m_destOrigin;

View file

@ -529,6 +529,9 @@ float Bot::getEnemyBodyOffsetCorrection (float distance) {
result = -4.5f;
}
}
else {
result = -5.6f;
}
return result;
}

View file

@ -848,6 +848,9 @@ void Game::slowFrame () {
// initialize light levels
graph.initLightLevels ();
// initialize corridors
graph.initNarrowPlaces ();
// detect csdm
applyGameModes ();

View file

@ -17,14 +17,15 @@ void BotGraph::initGraph () {
m_loadAttempts = 0;
m_editFlags = 0;
m_learnVelocity= nullptr;
m_learnVelocity = nullptr;
m_learnPosition = nullptr;
m_lastNode= nullptr;
m_lastNode = nullptr;
m_pathDisplayTime = 0.0f;
m_arrowDisplayTime = 0.0f;
m_autoPathDistance = 250.0f;
m_hasChanged = false;
m_narrowChecked = false;
// reset highest recorded damage
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)
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 () {
@ -1336,7 +1414,8 @@ bool BotGraph::convertOldFormat () {
plat.bzero (&header, sizeof (header));
// save for faster access
const char *map = game.getMapName ();
auto map = game.getMapName ();
if (fp) {
if (fp.read (&header, sizeof (header)) == 0) {
@ -2216,7 +2295,7 @@ void BotGraph::frame () {
}
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 buffer.chars ();

View file

@ -642,9 +642,9 @@ bool Bot::updateNavigation () {
findValidNode ();
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) {
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 ();
}
@ -666,7 +666,7 @@ bool Bot::updateNavigation () {
m_jumpFinished = true;
m_checkTerrain = false;
m_desiredVelocity= nullptr;
m_desiredVelocity = nullptr;
}
}
else if (!yb_jasonmode.bool_ () && m_currentWeapon == Weapon::Knife && isOnFloor ()) {

View file

@ -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 {
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);
};
auto packet = reinterpret_cast <const uint8 *> (message);
// player replies response
if (length > 5 && packet[0] == 0xff && packet[1] == 0xff && packet[2] == 0xff && packet[3] == 0xff) {
if (packet[4] == 'D') {
QueryBuffer buffer (packet, length, 5);
auto count = buffer.read <uint8> ();
@ -675,13 +677,12 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
else if (packet[4] == 'I') {
QueryBuffer buffer (packet, length, 5);
buffer.skip <uint8> (); // protocol
// skip server name, folder, map game
for (size_t i = 0; i < 4; ++i) {
buffer.skipString ();
}
buffer.skip <short> (); // steam app id
buffer.skip <uint8> (); // players
buffer.skip <uint8> (); // maxplayers
buffer.skip <uint8> (); // bots