Skip to content

Bots avoid grenade related hazard areas#2020

Open
sunzenshen wants to merge 1 commit into
NeotokyoRebuild:masterfrom
sunzenshen:bot-avoid-smoke
Open

Bots avoid grenade related hazard areas#2020
sunzenshen wants to merge 1 commit into
NeotokyoRebuild:masterfrom
sunzenshen:bot-avoid-smoke

Conversation

@sunzenshen

@sunzenshen sunzenshen commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Description

Bots avoid hazard areas:

  • areas that are in line of sight of a smoke cloud
  • areas that are in line of sight of a grenade trajectory

Toolchain

  • Windows MSVC VS2022

else
{
// Fallback if GetLastKnownArea is null, try finding nearest nav area
CNavArea *nearestArea = TheNavMesh->GetNearestNavArea( me->GetAbsOrigin() );

@sunzenshen sunzenshen Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided that if for some reason the situation was bugged enough that we don't know the GetLastKnownArea of a bot, we shouldn't bother trying to search for GetNearestNavArea. GetNearestNavArea is a bit more expensive and, if the situation is glitched, might not even return an appropriate navarea.

@sunzenshen sunzenshen left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of this PR was to have bots avoid areas that were visible from smoked areas, if they do not have thermal vision. Before this PR, bots tended to disregard smoke and would fall victim to either Support bots or humans that know to spray into the smoke. This PR introduces a time-expiring hazard area marking lookup for smoke and general hazardous areas.

Along with support for smoke, I added hazard area marking for grenades and death locations. The thinking for bot grenade trajectories is that they are so erratic that it's safer to assume that any place along the trajectory towards the target and beyond is a dangerous area. For marking death areas of friendly bots, it's mostly to have bots pause towards running into a fatal funnel if the room is narrow enough to be blocked by the bot death locations.

return -1.0f;
return -1.0f; // attempt to route around hazards
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff on this file is kind of ugly, but this hazard avoidance marking is the new change. A return value of -1.0 is considered an impassable navarea. The assumption is that this impassability applies only when a bot is not in a hazard area, and if a bot was in a hazard area, then they will check that in tactical monitor and try to exit the hazard area.

// first area in path, no cost
return 0.0f;
}
else

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of this file was getting rid of one level of indentation inherited from copying CSimpleBotPathCost, by getting rid of this else.

@sunzenshen
sunzenshen requested a review from a team July 14, 2026 05:03
@sunzenshen sunzenshen added the Bots Related to bot players label Jul 14, 2026
@sunzenshen

Copy link
Copy Markdown
Contributor Author

Demo example of bots moving out of a room with smoke coverage, into one where there is no exposed smoke:

bot-avoid-smoke-demo.mp4

@sunzenshen sunzenshen left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot that I also incremented OnStuck area avoidance penalties for bot death areas, not just for bots getting stuck so here's another set of adjustments when testing the allowance of bot death areas as candidates for where to escape a hazard.

{
return true;
}
if (CNEOBotPathReservations()->GetAreaAvoidPenalty(navAreaId) >= m_onStuckPenalty)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot I added avoidance penalties for areas where a bot died, so I made the threshold under which a bot got stuck in a location, allowing to minor penalty for death areas to be used as candidates if under the OnStuck threshold.


if ( m_goalArea && m_attackCoverArea )
{
return ANSWER_NO;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While preventing the bots from retreating when they are rushing for a cover area was okay for proving out #2000, it made the bots a bit suicidal when their chosen advancing cover was too exposed, so I think it's better to retreat when there's any incoming fire.

This also encourages more grenade throw attempts which is helpful for viewing the smoke and grenade avoidance behavior.

{
m_coverArea = FindCoverArea( me );
CNEOBotPathCompute(me, m_path, m_coverArea->GetCenter(), FASTEST_ROUTE);
CNEOBotPathReservations()->IncrementAreaAvoidPenalty(me->GetLastKnownArea()->GetID(), neo_bot_path_reservation_onstuck_penalty.GetFloat());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a bot gets stuck, sometimes the chosen cover area is the culprit, so look for another random cover area to reset.

@sunzenshen
sunzenshen removed the request for review from a team July 15, 2026 03:30
@sunzenshen
sunzenshen marked this pull request as draft July 15, 2026 03:30
@sunzenshen
sunzenshen force-pushed the bot-avoid-smoke branch 4 times, most recently from 056f199 to 75814a1 Compare July 18, 2026 00:28
Bots avoid hazard areas:
- areas that are in line of sight of a smoke cloud
- areas that are in line of sight of a grenade trajectory
@sunzenshen sunzenshen changed the title Bots avoid hazard areas Bots avoid grenade related hazard areas Jul 18, 2026
@sunzenshen
sunzenshen marked this pull request as ready for review July 18, 2026 00:34
@sunzenshen
sunzenshen requested a review from a team July 18, 2026 00:34

@sunzenshen sunzenshen left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally figured out why bots completely stop when blocked by a hazard area, and implemented partial pathing up to hazard area boundaries.

Opening up this PR for review again.

Here's the script I used to set up observation of bot behavior:

sv_neo_preround_freeze_time 2;

mp_chattime 2; 
cl_neo_grenade_show_path 1; sv_neo_grenade_show_path 1;

sv_neo_bot_grenade_polite_smoke 0;
sv_neo_bot_grenade_polite_frag 0;

nb_debug path;


CNEOBotPathCompute( me, m_path, vecMoveTarget, SAFEST_ROUTE );
m_repathTimer.Start( RandomFloat( 1.0f, 2.0f ) );
m_repathTimer.Start( RandomFloat( 5.0f, 10.0f ) );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excessively short repath timers can cause bots to indecisively fail to move towards a position, so I increased these timers to allow some movement towards a goal.

#include "weapon_smokegrenade.h"

ConVar sv_neo_bot_grenade_polite_frag("sv_neo_bot_grenade_polite_frag", "1", FCVAR_NONE, "Force bots to consider teammates when throwing frag grenades.", true, 0, true, 1);
ConVar sv_neo_bot_grenade_polite_smoke("sv_neo_bot_grenade_polite_smoke", "1", FCVAR_NONE, "Force bots to consider teammates when throwing smoke grenades.", true, 0, true, 1);

@sunzenshen sunzenshen Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be rare to see a smoke deployment with the default bot deployment decisions, so I added a ConVar to induce bots to throw grenades more readily. This helps observe the hazard avoidance behavior more frequently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing logic below should be mostly the same despite the indentation changes that caused many diff line changes.

if (area)
{
int team = me->GetTeamNumber();
CNEOBotPathReservations()->AddFragHazard(area->GetID(), gpGlobals->curtime + sv_neo_grenade_fuse_timer.GetFloat(), team);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expanding the hazard area around grenades by adjacent Potentially Visible Set is intended as a shorthand for avoid the area along the line through the target, as well as avoid the radiating circle around the idea detonation zone, with some leeway for the trajectory to be off as it usually is.

{
if ( m_me->IsDebugging( NEXTBOT_PATH ) )
{
baseArea->DrawFilled(255, 0, 0, MIN(255, candidateHazardTime), candidateHazardTime);

@sunzenshen sunzenshen Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if nb_debug path is enabled, then the areas that are considered hazardous will be highlighted as red floor tiles:

Image

One existing feature of nb_debug path is that arrows are drawn from the point a bot tried to make a full path and where the goal was, when the path ended up being blocked. With this PR, this also happens when bots try to path to a position that is marked blocked by the hazard areas.

I tweaked the default path computation API to allow for partial paths that are as close as possible to the goal without crossing the artificially blocked areas. This side effect should only affect the debug overlay, while encouraging bots to hide out of view of a smoke cloud.

{
if ( CNEOBotPathReservations()->IsAreaHazardous( myArea->GetID(), me ) )
{
return SuspendFor( new CNEOBotRetreatFromHazardArea( ), "Avoiding hazard area" );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allow bot commanders to micromanage where they will go instead of having bots cower from smoke clouds.

cost_without_reservations.m_bIgnoreReservations = true;
if (path.Compute(bot, goal, cost_without_reservations, maxPathLength, includeGoalIfPathFails, requireGoalArea) && path.IsValid())
path.Compute(bot, goal, cost_without_reservations, maxPathLength, includeGoalIfPathFails, requireGoalArea);
if (path.IsValid())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By allowing path.Compute to return false, we can allow bots to create partial paths closer to their goal areas, even if the path is blocked by a banned area. I use this to allow bots to wander around the edge of a hazard area until a smoke cloud dissipates.

RouteType route,
float maxPathLength = PATH_NO_LENGTH_LIMIT,
bool includeGoalIfPathFails = PATH_TRUNCATE_INCOMPLETE_PATH,
bool includeGoalIfPathFails = true, // return incomplete path if full path not found by default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, allow bots to plan partial routes to a goal even if the goal is blocked off from the bot's navigable area.

m_flGhostLastHeld = 0;

#ifdef GAME_DLL
CNEOBotPathReservations()->ClearRound();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If sv_neo_preround_freeze_time and mp_chattime are set too low, the round reset won't leave enough time for smoke hazard areas to reset. It's also probably cleaner to clear out the bot path reservations as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bots Related to bot players

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant