-
Notifications
You must be signed in to change notification settings - Fork 23
Bots avoid hazard areas #2020
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Bots avoid hazard areas #2020
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,7 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor | |
| m_threatArea = threat->GetLastKnownArea(); | ||
| m_goalArea = goalArea ? goalArea : m_threatArea; // prioritize movement towards input goal area or threat | ||
| m_myDistToGoalSq = m_goalArea ? ( m_goalArea->GetCenter() - m_me->GetAbsOrigin() ).LengthSqr() : 0; | ||
| m_onStuckPenalty = neo_bot_path_reservation_onstuck_penalty.GetFloat(); | ||
| } | ||
|
|
||
| virtual bool operator() ( CNavArea *baseArea, CNavArea *priorArea, float travelDistanceSoFar ) | ||
|
|
@@ -79,10 +80,18 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor | |
| return true; // skip our starting area | ||
| } | ||
|
|
||
| if ( neo_bot_path_reservation_enable.GetBool() && | ||
| ( CNEOBotPathReservations()->GetAreaAvoidPenalty(area->GetID()) > 0 ) ) | ||
| // Skip areas that are hazardous or where bots get stuck | ||
| if ( neo_bot_path_reservation_enable.GetBool() ) | ||
| { | ||
| return true; // skip areas that have had navigation hiccups | ||
| int navAreaId = area->GetID(); | ||
| if (CNEOBotPathReservations()->IsAreaHazardous(navAreaId, m_me)) | ||
| { | ||
| return true; | ||
| } | ||
| if (CNEOBotPathReservations()->GetAreaAvoidPenalty(navAreaId) >= m_onStuckPenalty) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| if ( m_attackCoverArea ) | ||
|
|
@@ -199,6 +208,7 @@ class CSearchForAttackCover : public ISearchSurroundingAreasFunctor | |
| const CNavArea *m_myArea; // reference point of myself | ||
| const CNavArea *m_threatArea; // reference point of the threat | ||
| float m_myDistToGoalSq; // the bot's current distance to the threat | ||
| float m_onStuckPenalty; // cache onstuck penalty | ||
| }; | ||
|
|
||
|
|
||
|
|
@@ -452,11 +462,6 @@ QueryResultType CNEOBotAttack::ShouldRetreat( const INextBot *me ) const | |
| return ANSWER_UNDEFINED; | ||
| } | ||
|
|
||
| if ( m_goalArea && m_attackCoverArea ) | ||
| { | ||
| return ANSWER_NO; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
|
|
||
| return ANSWER_UNDEFINED; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,8 @@ | |
| #include "bot/behavior/neo_bot_tactical_monitor.h" | ||
| #include "weapons/weapon_balc.h" | ||
|
|
||
| extern ConVar sv_neo_grenade_fuse_timer; | ||
|
|
||
| ConVar neo_bot_path_lookahead_range( "neo_bot_path_lookahead_range", "300" ); | ||
| ConVar neo_bot_sniper_aim_error( "neo_bot_sniper_aim_error", "0.01", FCVAR_CHEAT ); | ||
| ConVar neo_bot_sniper_aim_steady_rate( "neo_bot_sniper_aim_steady_rate", "10", FCVAR_CHEAT ); | ||
|
|
@@ -195,16 +197,14 @@ EventDesiredResult<CNEOBot> CNEOBotMainAction::OnKilled( CNEOBot *me, const CTak | |
| // Intended to add some variance to pathing for similar starting scenarios | ||
| if ( const CNavArea *navArea = me->GetLastKnownArea() ) | ||
| { | ||
| CNEOBotPathReservations()->IncrementAreaAvoidPenalty( navArea->GetID(), neo_bot_path_reservation_killed_penalty.GetFloat() ); | ||
| } | ||
| else | ||
| { | ||
| // Fallback if GetLastKnownArea is null, try finding nearest nav area | ||
| CNavArea *nearestArea = TheNavMesh->GetNearestNavArea( me->GetAbsOrigin() ); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| if ( nearestArea ) | ||
| { | ||
| CNEOBotPathReservations()->IncrementAreaAvoidPenalty( nearestArea->GetID(), neo_bot_path_reservation_killed_penalty.GetFloat() ); | ||
| } | ||
| int areaId = navArea->GetID(); | ||
| int teamId = me->GetTeamNumber(); | ||
| CNEOBotPathReservations()->IncrementAreaAvoidPenalty( areaId, neo_bot_path_reservation_killed_penalty.GetFloat() ); | ||
|
|
||
| // Discourage friendlies from stepping out into recent danger zone | ||
| // Use grenade fuse timer so that we don't need to compare expiration times with previous entries | ||
| // where the frag grenade timer is the usual time input into AddFragHazard | ||
| CNEOBotPathReservations()->AddDeadlyHazard(areaId, gpGlobals->curtime + sv_neo_grenade_fuse_timer.GetFloat(), teamId); | ||
| } | ||
|
|
||
| return TryChangeTo( new CNEOBotDead, RESULT_CRITICAL, "I died!" ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,8 @@ | |
| #include "bot/behavior/neo_bot_retreat_from_grenade.h" | ||
| #include "bot/behavior/neo_bot_retreat_to_cover.h" | ||
| #include "bot/neo_bot_path_compute.h" | ||
| #include "bot/neo_bot_path_reservation.h" | ||
| #include "nav_mesh.h" | ||
| #include "sdk/sdk_basegrenade_projectile.h" | ||
|
|
||
| // memdbgon must be the last include file in a .cpp file!!! | ||
|
|
@@ -72,6 +74,7 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor | |
| { | ||
| m_me = me; | ||
| m_grenade = grenade; | ||
| m_onStuckPenalty = neo_bot_path_reservation_onstuck_penalty.GetFloat(); | ||
| m_pGrenadeStats = dynamic_cast<CBaseGrenadeProjectile *>( grenade ); | ||
| m_safeRadiusSqr = m_pGrenadeStats ? Square(m_pGrenadeStats->m_DmgRadius * sv_neo_bot_grenade_frag_safety_range_multiplier.GetFloat()) : 0.0f; | ||
|
|
||
|
|
@@ -91,6 +94,20 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor | |
| return false; // can't search if there's no threat source | ||
| } | ||
|
|
||
| // Skip areas that are hazardous or where bots get stuck | ||
| if ( neo_bot_path_reservation_enable.GetBool() ) | ||
| { | ||
| int navAreaId = area->GetID(); | ||
| if (CNEOBotPathReservations()->IsAreaHazardous(navAreaId, m_me)) | ||
| { | ||
| return true; | ||
| } | ||
| if (CNEOBotPathReservations()->GetAreaAvoidPenalty(navAreaId) >= m_onStuckPenalty) | ||
| { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| if ( m_pGrenadeStats ) | ||
| { | ||
| if ( ( area->GetCenter() - m_pGrenadeStats->GetAbsOrigin() ).LengthSqr() < m_safeRadiusSqr * 2 ) | ||
|
|
@@ -138,6 +155,7 @@ class CSearchForCoverFromGrenade : public ISearchSurroundingAreasFunctor | |
| CNEOBot *m_me; | ||
| CBaseEntity *m_grenade; | ||
| CBaseGrenadeProjectile *m_pGrenadeStats; | ||
| float m_onStuckPenalty; | ||
| float m_safeRadiusSqr; | ||
| CUtlVector< CNavArea * > m_coverAreaVector; | ||
| }; | ||
|
|
@@ -181,6 +199,19 @@ ActionResult< CNEOBot > CNEOBotRetreatFromGrenade::OnStart( CNEOBot *me, Action< | |
| m_grenade = FindDangerousGrenade( me ); | ||
| } | ||
|
|
||
| if ( !m_grenade ) // not a duplicate, check FindDangerousGrenade result | ||
| { | ||
| return Done("No grenade found"); | ||
| } | ||
|
|
||
| // Register explosive hazard for the bot's team at the grenade's initial position | ||
| CNavArea *grenadeArea = TheNavMesh->GetNearestNavArea( m_grenade->GetAbsOrigin() ); | ||
| if (grenadeArea) | ||
| { | ||
| int team = me->GetTeamNumber(); | ||
| CNEOBotPathReservations()->AddFragHazard(grenadeArea->GetID(), gpGlobals->curtime + sv_neo_grenade_fuse_timer.GetFloat(), team); | ||
| } | ||
|
|
||
| // Sometimes grenades can be in a bad limbo state, so force exit eventually | ||
| m_expiryTimer.Start( sv_neo_grenade_fuse_timer.GetFloat() ); | ||
|
|
||
|
|
@@ -247,6 +278,9 @@ ActionResult< CNEOBot > CNEOBotRetreatFromGrenade::Update( CNEOBot *me, float in | |
| //--------------------------------------------------------------------------------------------- | ||
| EventDesiredResult< CNEOBot > CNEOBotRetreatFromGrenade::OnStuck( CNEOBot *me ) | ||
| { | ||
| 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()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| return TryContinue(); | ||
| } | ||
|
|
||
|
|
@@ -261,6 +295,9 @@ EventDesiredResult< CNEOBot > CNEOBotRetreatFromGrenade::OnMoveToSuccess( CNEOBo | |
| //--------------------------------------------------------------------------------------------- | ||
| EventDesiredResult< CNEOBot > CNEOBotRetreatFromGrenade::OnMoveToFailure( CNEOBot *me, const Path *path, MoveToFailureType reason ) | ||
| { | ||
| 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()); | ||
| return TryContinue(); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
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.