Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 84 additions & 32 deletions src/game/server/neo/bot/behavior/neo_bot_grenade_throw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ ConVar sv_neo_bot_grenade_search_range("sv_neo_bot_grenade_search_range", "1000"
//---------------------------------------------------------------------------------------------
CNEOBotGrenadeThrow::CNEOBotGrenadeThrow( CNEOBaseCombatWeapon *pWeapon, const CKnownEntity *threat )
{
m_bFocusedOnThrow = false;
m_bPinPulled = false;
m_hGrenadeWeapon = pWeapon;
m_bVantagePointBlocked = false;
m_vantageArea = nullptr;
Expand Down Expand Up @@ -132,20 +134,17 @@ class CFindVantagePointTargetPos : public ISearchSurroundingAreasFunctor

float flRadius = sv_neo_grenade_blast_radius.GetFloat() * sv_neo_bot_grenade_frag_safety_range_multiplier.GetFloat();
m_flSafetyRadiusSq = flRadius * flRadius;

m_flSearchRange = sv_neo_bot_grenade_search_range.GetFloat();
}

virtual bool operator() ( CNavArea* baseArea, CNavArea* priorArea, float travelDistanceSoFar )
{
CNavArea* area = (CNavArea*)baseArea;

if (!m_targetArea)
{
return false; // can't search
}

if ( area->IsPotentiallyVisible( m_targetArea ) )
if ( area->IsCompletelyVisible( m_targetArea ) )
{
// nearby area from which we can see the last known position
// nearby area from which we have a full view of the last known position
m_vantageArea = area;
return false; // stop searching
}
Expand All @@ -156,7 +155,7 @@ class CFindVantagePointTargetPos : public ISearchSurroundingAreasFunctor
// return true if 'adjArea' should be included in the ongoing search
virtual bool ShouldSearch( CNavArea *adjArea, CNavArea *currentArea, float travelDistanceSoFar )
{
if ( travelDistanceSoFar > sv_neo_bot_grenade_search_range.GetFloat() )
if ( travelDistanceSoFar > m_flSearchRange )
{
return false;
}
Expand Down Expand Up @@ -194,22 +193,70 @@ class CFindVantagePointTargetPos : public ISearchSurroundingAreasFunctor
CNavArea *m_vantageArea;
const CNavArea *m_threatArea;
float m_flSafetyRadiusSq;
float m_flSearchRange;
};


//---------------------------------------------------------------------------------------------
ActionResult< CNEOBot > CNEOBotGrenadeThrow::OnStart( CNEOBot *me, Action< CNEOBot > *priorAction )
// Search outwards from the bot for the nearest reachable area with a full view of the
// threat's last known position. Returns nullptr if the last known position is off the nav
// mesh, or if there is no such area within range.
CNavArea *CNEOBotGrenadeThrow::FindVantageArea( CNEOBot *me )
{
CNEOBaseCombatWeapon *pWep = m_hGrenadeWeapon.Get();
if ( pWep )
CFindVantagePointTargetPos find( me, m_vecThreatLastKnownPos, m_hThreatGrenadeTarget.Get() );
if ( !find.m_targetArea )
{
Assert( ( pWep->GetNeoWepBits() & NEO_WEP_FRAG_GRENADE ) || ( pWep->GetNeoWepBits() & NEO_WEP_SMOKE_GRENADE ) );
me->PushRequiredWeapon( m_hGrenadeWeapon );
// The last known position isn't on the nav mesh, so there is nothing to get a view of
return nullptr;
}
else

SearchSurroundingAreas( me->GetLastKnownArea(), find, find.m_flSearchRange );
return find.m_vantageArea;
}

//---------------------------------------------------------------------------------------------
// Take over the bot's weapon handling and looking while the throw is in progress.
// Paired with EndThrowFocus - anything added here needs its inverse added there.
void CNEOBotGrenadeThrow::BeginThrowFocus( CNEOBot *me )
{
m_bFocusedOnThrow = true;

// Swap to the grenade
me->PushRequiredWeapon( m_hGrenadeWeapon );

// Stop distracting looking or weapon handling behavior that could interrupt the throw
me->StopLookingAroundForEnemies(); // reduce distractions for manual look aiming
me->SetAttribute( CNEOBot::IGNORE_ENEMIES ); // suppress reaction to swap back to firearm
}

//---------------------------------------------------------------------------------------------
// Undo BeginThrowFocus. Safe to call unconditionally, because the behavior framework
// runs OnEnd even when OnStart returns Done before ever committing to the throw.
void CNEOBotGrenadeThrow::EndThrowFocus( CNEOBot *me )
{
if ( !m_bFocusedOnThrow )
{
return;
}
m_bFocusedOnThrow = false;

// Restore looking and weapon handling behaviors
me->PopRequiredWeapon();
me->StartLookingAroundForEnemies();
me->ClearAttribute( CNEOBot::IGNORE_ENEMIES );
const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
me->EquipBestWeaponForThreat( threat );
}

//---------------------------------------------------------------------------------------------
ActionResult< CNEOBot > CNEOBotGrenadeThrow::OnStart( CNEOBot *me, Action< CNEOBot > *priorAction )
{
CNEOBaseCombatWeapon *pWep = m_hGrenadeWeapon.Get();
if ( !pWep )
{
return Done( "Grenade input invalid" );
}
Assert( ( pWep->GetNeoWepBits() & NEO_WEP_FRAG_GRENADE ) || ( pWep->GetNeoWepBits() & NEO_WEP_SMOKE_GRENADE ) );

if ( !m_hThreatGrenadeTarget.Get() )
{
Expand All @@ -220,19 +267,30 @@ ActionResult< CNEOBot > CNEOBotGrenadeThrow::OnStart( CNEOBot *me, Action< CNEOB
{
return Done( "Targeted threat is dead" );
}

m_giveUpTimer.Start( sv_neo_bot_grenade_give_up_time.GetFloat() );
m_bPinPulled = false;

m_PathFollower.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
if ( m_vecThreatLastKnownPos != vec3_invalid )
if ( m_vecThreatLastKnownPos == vec3_invalid )
{
CNEOBotPathCompute( me, m_PathFollower, m_vecThreatLastKnownPos, FASTEST_ROUTE );
return Done( "Targeted threat position invalid" );
}

// Stop distracting looking or weapon handling behavior that could interrupt the throw
me->StopLookingAroundForEnemies(); // reduce distractions for manual look aiming
me->SetAttribute( CNEOBot::IGNORE_ENEMIES ); // suppress reaction to swap back to firearm
// Smoke grenades don't need vantage point planning since they don't have unsafe radius.
if ( !( pWep->GetNeoWepBits() & NEO_WEP_SMOKE_GRENADE ) )
{
m_vantageArea = FindVantageArea( me );
if ( !m_vantageArea )
{
return Done( "No viable vantage point for grenade throw" );
}
}

// We have decided to commit to the throw by this point
BeginThrowFocus( me );

m_giveUpTimer.Start( sv_neo_bot_grenade_give_up_time.GetFloat() );
m_bPinPulled = false;

m_PathFollower.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
CNEOBotPathCompute( me, m_PathFollower, m_vantageArea ? m_vantageArea->GetCenter() : m_vecThreatLastKnownPos, FASTEST_ROUTE );

return Continue();
}
Expand Down Expand Up @@ -416,9 +474,7 @@ ActionResult< CNEOBot > CNEOBotGrenadeThrow::Update( CNEOBot *me, float interval

if ( !m_vantageArea && !m_bVantagePointBlocked )
{
CFindVantagePointTargetPos find( me, m_vecThreatLastKnownPos, m_hThreatGrenadeTarget.Get() );
SearchSurroundingAreas( me->GetLastKnownArea(), find, sv_neo_bot_grenade_search_range.GetFloat() );
m_vantageArea = find.m_vantageArea;
m_vantageArea = FindVantageArea( me );

if ( !m_vantageArea )
{
Expand Down Expand Up @@ -500,12 +556,8 @@ void CNEOBotGrenadeThrow::OnEnd( CNEOBot *me, Action< CNEOBot > *nextAction )
return;
}

// Restore looking and weapon handling behaviors
me->PopRequiredWeapon();
me->StartLookingAroundForEnemies();
me->ClearAttribute( CNEOBot::IGNORE_ENEMIES );
const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
me->EquipBestWeaponForThreat( threat );
// No-ops if OnStart bailed out before committing to the throw
EndThrowFocus( me );
}

//---------------------------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/game/server/neo/bot/behavior/neo_bot_grenade_throw.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CNEOBotGrenadeThrow : public Action< CNEOBot >
CountdownTimer m_repathTimer;
PathFollower m_PathFollower;

bool m_bFocusedOnThrow; // indicates if grenade prep behavior needs to be cleaned up by EndThrowFocus
bool m_bPinPulled;
bool m_bVantagePointBlocked;

Expand All @@ -44,6 +45,13 @@ class CNEOBotGrenadeThrow : public Action< CNEOBot >
THROW_TARGET_WAIT = 1,
};

// Matched push/pop pair where BeginThrowFocus pushes the required weapon,
// which must be balanced by EndThrowFocus.
void BeginThrowFocus( CNEOBot *me );
void EndThrowFocus( CNEOBot *me );

CNavArea *FindVantageArea( CNEOBot *me );

static const Vector& FindEmergencePointAlongPath( const CNEOBot *me, const Vector &familiarPos, const Vector &obscuredPos );

virtual ThrowTargetResult UpdateGrenadeTargeting( CNEOBot *me, CNEOBaseCombatWeapon *pWeapon ) = 0;
Expand Down