From 04111e473a800a967df5623f5e13162429b56e3f Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Wed, 19 Aug 2026 22:41:59 -0600 Subject: [PATCH] Bots force reload improvements when empty clip --- .../neo/bot/behavior/neo_bot_behavior.cpp | 66 +++++++++++++------ 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp b/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp index 32723f42c..8420b14a4 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp @@ -675,9 +675,15 @@ QueryResultType CNEOBotMainAction::ShouldWalk(const CNEOBot *me, const QueryResu } } - // Walk if reloading or firing + // Walk if firing or aiming on target CNEOBaseCombatWeapon *myWeapon = static_cast(me->GetActiveWeapon()); - if (myWeapon && (myWeapon->m_bInReload || me->m_bOnTarget || me->IsFiring())) + if (myWeapon && (me->m_bOnTarget || me->IsFiring())) + { + return ANSWER_YES; + } + + // Walk until reload actually starts so sprint does not block the reload initiation + if (myWeapon && myWeapon->Clip1() <= 0 && !myWeapon->m_bInReload) { return ANSWER_YES; } @@ -693,7 +699,18 @@ QueryResultType CNEOBotMainAction::ShouldWalk(const CNEOBot *me, const QueryResu QueryResultType CNEOBotMainAction::ShouldAim(const CNEOBot *me, const bool bWepHasClip) const { auto *pNeoWep = static_cast(me->GetActiveWeapon()); - if (!bWepHasClip || !pNeoWep) + + if (!pNeoWep) + { + return ANSWER_NO; + } + + if (!bWepHasClip) + { + return ANSWER_NO; + } + + if (pNeoWep->m_bInReload) { return ANSWER_NO; } @@ -749,6 +766,10 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) { if ( myWeapon->Clip1() < myWeapon->GetMaxClip1() ) { + if ( !myWeapon->m_bInReload ) + { + me->ReloadIfLowClip(true); + } return; } @@ -857,6 +878,27 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) me->EquipBestWeaponForThreat(threat, false); } + if ( myWeapon && me->IsCombatWeapon( myWeapon ) + && !( myWeapon->GetNeoWepBits() & NEO_WEP_BALC ) + && myWeapon->m_iClip1 <= 0 ) + { + if (myWeapon->m_bInReload) + { + // passthrough: don't introduce decision jitter + } + else if (IsImmediateThreat(me->GetEntity(), threat) && !m_isWaitingForFullReload) + { + // intention is to swap to secondary if available + me->EquipBestWeaponForThreat(threat, bNotPrimary); + } + else + { + me->ReloadIfLowClip(true); + m_isWaitingForFullReload = true; + } + return; + } + float threatRange = ( threat->GetEntity()->GetAbsOrigin() - me->GetAbsOrigin() ).Length(); // actual head aiming is handled elsewhere, just check if we're on target @@ -888,24 +930,6 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) FireBalcAtEnemy( me, myWeapon, threat, threatRange ); return; } - else if (myWeapon->m_iClip1 <= 0) - { - if (m_isWaitingForFullReload) - { - // passthrough: don't introduce decision jitter - } - else if (IsImmediateThreat(me->GetEntity(), threat) && !m_isWaitingForFullReload) - { - // intention is to swap to secondary if available - me->EquipBestWeaponForThreat(threat, bNotPrimary); - } - else - { - me->ReloadIfLowClip(true); - m_isWaitingForFullReload = true; - } - return; - } // Even if my weapon is unsuppressed, better than nothing me->EnableCloak(3.0f);