From d24cb94a2c61edc39ecc61ba7d4c5f4f38ec0084 Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Wed, 2 Sep 2026 20:49:34 -0600 Subject: [PATCH] More bot reload reliability tweaks --- .../neo/bot/behavior/neo_bot_behavior.cpp | 26 ++++++++++++++++--- src/game/server/neo/bot/neo_bot.cpp | 9 ++++--- 2 files changed, 28 insertions(+), 7 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 8420b14a4..a381f549a 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp @@ -683,7 +683,8 @@ QueryResultType CNEOBotMainAction::ShouldWalk(const CNEOBot *me, const QueryResu } // Walk until reload actually starts so sprint does not block the reload initiation - if (myWeapon && myWeapon->Clip1() <= 0 && !myWeapon->m_bInReload) + if (myWeapon && !myWeapon->m_bInReload && + (myWeapon->Clip1() <= 0 || (me->m_nButtons & IN_RELOAD))) { return ANSWER_YES; } @@ -716,7 +717,7 @@ QueryResultType CNEOBotMainAction::ShouldAim(const CNEOBot *me, const bool bWepH } const bool bIsPlayerStopped = - me->GetLocomotionInterface()->GetSpeed() == 0.0f && !(me->GetNeoFlags() & NEO_FL_FREEZETIME); + me->GetLocomotionInterface()->GetSpeed() < 10.0f && !(me->GetNeoFlags() & NEO_FL_FREEZETIME); const bool bIsScoped = pNeoWep->GetNeoWepBits() & NEO_WEP_SCOPEDWEAPON; const bool bIsNowFiring = me->IsFiring(); @@ -751,6 +752,12 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) if ( !myWeapon ) return; + // Check reload waiting edge case, potentially from weapon swaps + if ( m_isWaitingForFullReload && myWeapon->GetMaxClip1() > 0 && myWeapon->Clip1() >= myWeapon->GetMaxClip1() ) + { + m_isWaitingForFullReload = false; + } + if ( me->IsBarrageAndReloadWeapon( myWeapon ) ) { if ( me->HasAttribute( CNEOBot::HOLD_FIRE_UNTIL_FULL_RELOAD ) || neo_bot_always_full_reload.GetBool() ) @@ -882,6 +889,8 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) && !( myWeapon->GetNeoWepBits() & NEO_WEP_BALC ) && myWeapon->m_iClip1 <= 0 ) { + bool bShouldConsiderReload = false; + if (myWeapon->m_bInReload) { // passthrough: don't introduce decision jitter @@ -890,10 +899,21 @@ void CNEOBotMainAction::FireWeaponAtEnemy( CNEOBot *me ) { // intention is to swap to secondary if available me->EquipBestWeaponForThreat(threat, bNotPrimary); + + auto *pActive = static_cast( me->GetActiveWeapon() ); + if ( pActive && pActive->m_iClip1 <= 0 && !pActive->m_bInReload ) + { + bShouldConsiderReload = true; + } } else { - me->ReloadIfLowClip(true); + bShouldConsiderReload = true; + } + + if ( bShouldConsiderReload ) + { + me->ReloadIfLowClip( true ); m_isWaitingForFullReload = true; } return; diff --git a/src/game/server/neo/bot/neo_bot.cpp b/src/game/server/neo/bot/neo_bot.cpp index 175eb07c2..0c01621b9 100644 --- a/src/game/server/neo/bot/neo_bot.cpp +++ b/src/game/server/neo/bot/neo_bot.cpp @@ -1607,9 +1607,8 @@ void CNEOBot::EquipBestWeaponForThreat(const CKnownEntity* threat, const bool bN // Ideally for close range empty primary reaction else if ( secondaryWeapon && primaryWeapon->Clip1() <= 0 - && (secondaryWeapon->Clip1() > 0) - && threat->IsVisibleInFOVNow() - && (IsRangeLessThan(threat->GetLastKnownPosition(), 250.0f)) ) + && secondaryWeapon->Clip1() > 0 + && IsRangeLessThan(threat->GetLastKnownPosition(), 250.0f) ) { // passthrough } @@ -1710,7 +1709,9 @@ void CNEOBot::ReloadIfLowClip(bool bForceReload) } else if (myWeapon->Clip1() > 0) { - if (GetTimeSinceWeaponFired() < 3.0f) + const CKnownEntity *threat = GetVisionInterface()->GetPrimaryKnownThreat(); + const bool bAwareOfThreat = threat && threat->GetEntity() && threat->IsVisibleRecently(); + if (bAwareOfThreat) { return; // still in the middle of a fight }