From 87b6a165278f01bff3b153ed6d8330ec34a5fb2c Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Wed, 7 Oct 2026 22:29:49 -0600 Subject: [PATCH] Skip breakable props bots cannot start clearing The clear-breakable action took any breakable the path's hull trace hit, props included, but its Update ends at once on a target that is not IsAlive(), and CBaseProp::IsAlive() is always false. On a breakable prop in the path (prop_physics_multiplayer, hp 50) the action started and ended every bot update, about every 0.13 s, switching to the knife and back each time while the bot walked on pushing the prop. Start the action only on a breakable that passes the same intact test Update uses. func_breakable and func_breakable_surf are unchanged: they never leave LIFE_ALIVE. Marketa, 4 matches a build: 236 start/end cycles on props before, 0 after; panes still broken (6 of 6, 1 of 1). --- .../bot/behavior/neo_bot_path_clear_breakable.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/game/server/neo/bot/behavior/neo_bot_path_clear_breakable.cpp b/src/game/server/neo/bot/behavior/neo_bot_path_clear_breakable.cpp index 03276cf9f8..625bc93ebf 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_path_clear_breakable.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_path_clear_breakable.cpp @@ -9,6 +9,14 @@ extern ConVar neo_bot_fire_weapon_allowed; ConVar neo_bot_fire_at_breakable_weapon_min_time( "neo_bot_fire_at_breakable_weapon_min_time", "0.2", FCVAR_CHEAT, "Minimum time to fire at breakables", true, 0.0f, true, 60.0f ); +//-------------------------------------------------------------------------------------------------------- +// A prop never counts as alive (CBaseProp::IsAlive), +// so the action ends on its first update for a breakable prop +static bool IsBreakableIntact( CBaseEntity *breakable ) +{ + return breakable && breakable->IsAlive() && breakable->GetHealth() > 0; +} + //-------------------------------------------------------------------------------------------------------- CBaseEntity *CNEOBotPathClearBreakable::GetBreakableInPath( CNEOBot *me ) { @@ -60,7 +68,8 @@ CBaseEntity *CNEOBotPathClearBreakable::GetBreakableInPath( CNEOBot *me ) if ( tr.DidHit() && tr.m_pEnt ) { - if ( me->IsAbleToBreak( tr.m_pEnt ) ) + // Only start on a breakable the action would not end on at once + if ( me->IsAbleToBreak( tr.m_pEnt ) && IsBreakableIntact( tr.m_pEnt ) ) { return tr.m_pEnt; } @@ -123,7 +132,7 @@ ActionResult< CNEOBot > CNEOBotPathClearBreakable::Update( CNEOBot *me, float in CBaseEntity *breakable = m_hBreakable.Get(); // If the breakable is destroyed or invalid, we're done - if ( !breakable || !breakable->IsAlive() || breakable->GetHealth() <= 0 ) + if ( !IsBreakableIntact( breakable ) ) { return Done( "Path is clear" ); }