Bots avoid grenade related hazard areas#2020
Conversation
| else | ||
| { | ||
| // Fallback if GetLastKnownArea is null, try finding nearest nav area | ||
| CNavArea *nearestArea = TheNavMesh->GetNearestNavArea( me->GetAbsOrigin() ); |
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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 | ||
| } | ||
| } |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
The rest of this file was getting rid of one level of indentation inherited from copying CSimpleBotPathCost, by getting rid of this else.
|
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
left a comment
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
If a bot gets stuck, sometimes the chosen cover area is the culprit, so look for another random cover area to reset.
056f199 to
75814a1
Compare
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
75814a1 to
0134d13
Compare
There was a problem hiding this comment.
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 ) ); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
if nb_debug path is enabled, then the areas that are considered hazardous will be highlighted as red floor tiles:
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" ); |
There was a problem hiding this comment.
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()) |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
Description
Bots avoid hazard areas:
Toolchain