From 5190ed8fdf616021f2d578cfb90580b5d84a8940 Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Sat, 12 Sep 2026 23:08:26 -0600 Subject: [PATCH] Bots don't avoid smoke grenades with a known thrower --- .../behavior/neo_bot_retreat_from_grenade.cpp | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/game/server/neo/bot/behavior/neo_bot_retreat_from_grenade.cpp b/src/game/server/neo/bot/behavior/neo_bot_retreat_from_grenade.cpp index 699b62ab3..204a01070 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_retreat_from_grenade.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_retreat_from_grenade.cpp @@ -19,6 +19,42 @@ ConVar neo_bot_debug_retreat_from_grenade( "neo_bot_debug_retreat_from_grenade", ConVar neo_bot_grenade_check_radius( "neo_bot_grenade_check_radius", "500", FCVAR_CHEAT ); +//--------------------------------------------------------------------------------------------- +// In flight a smoke looks like a frag, unless we know who threw it +static bool IsUnidentifiedSmoke( CNEOBot *me, CBaseEntity *grenade ) +{ + if ( !FClassnameIs( grenade, "neo_grenade_smoke" ) ) + { + return false; + } + + CBaseCombatCharacter *thrower = static_cast< CBaseGrenade * >( grenade )->GetThrower(); + if ( !thrower ) + { + return true; + } + + if ( thrower == me ) + { + return false; + } + + if ( NEORules()->IsTeamplay() && thrower->GetTeamNumber() == me->GetTeamNumber() ) + { + return false; + } + + const CKnownEntity *known = me->GetVisionInterface()->GetKnown( thrower ); + if ( !known || !known->WasEverVisible() ) + { + return true; + } + + CNEO_Player *pThrower = ToNEOPlayer( thrower ); + return !pThrower || pThrower->GetClass() != NEO_CLASS_SUPPORT; +} + + //--------------------------------------------------------------------------------------------- CBaseEntity *CNEOBotRetreatFromGrenade::FindDangerousGrenade( CNEOBot *me ) { @@ -41,7 +77,7 @@ CBaseEntity *CNEOBotRetreatFromGrenade::FindDangerousGrenade( CNEOBot *me ) CBaseEntity *pOwner = pSound->m_hOwner.Get(); // Use FClassnameIs to check if it's a generic base grenade or our specific ones // FClassnameIs is better than dynamic_cast inside a loop when possible - if ( pOwner && ( FClassnameIs( pOwner, pszGrenadeClass ) || FClassnameIs( pOwner, "neo_grenade_smoke" ) ) ) + if ( pOwner && ( FClassnameIs( pOwner, pszGrenadeClass ) || IsUnidentifiedSmoke( me, pOwner ) ) ) { // Found a dangerous grenade closestThreat = pOwner; @@ -240,14 +276,6 @@ ActionResult< CNEOBot > CNEOBotRetreatFromGrenade::Update( CNEOBot *me, float in } const CNavArea *grenadeArea = TheNavMesh->GetNavArea( m_grenade->GetAbsOrigin() ); - bool bIsExposed = false; - if ( grenadeArea && me->GetLastKnownArea() ) - { - if ( grenadeArea->IsPotentiallyVisible( me->GetLastKnownArea() ) ) - { - bIsExposed = true; - } - } // track projectile and relation to escape destination every update if ( !m_coverArea || ( grenadeArea && grenadeArea->IsPotentiallyVisible( m_coverArea ) ) ) @@ -268,16 +296,12 @@ ActionResult< CNEOBot > CNEOBotRetreatFromGrenade::Update( CNEOBot *me, float in return Done("Reacting to contact instead"); } - if ( me->GetLastKnownArea() != m_coverArea || !bIsExposed ) + if ( m_repathTimer.IsElapsed() || !m_path.IsValid() ) { - // not in cover yet - if ( m_repathTimer.IsElapsed() || !m_path.IsValid() ) - { - CNEOBotPathCompute( me, m_path, m_coverArea->GetCenter(), FASTEST_ROUTE ); - m_repathTimer.Start( 1.0f ); - } - m_path.Update( me ); + CNEOBotPathCompute( me, m_path, m_coverArea->GetCenter(), FASTEST_ROUTE ); + m_repathTimer.Start( 1.0f ); } + m_path.Update( me ); return Continue(); }