From 3363fe29dec1cad24dda9aaf8b4f95c14fd63200 Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Tue, 3 Mar 2026 00:11:30 -0700 Subject: [PATCH] Bots drop weapon when used if commanding disabled --- .../bot/behavior/neo_bot_scenario_monitor.cpp | 24 +++++++++--- .../neo_bot_throw_weapon_at_player.cpp | 7 ++++ .../behavior/neo_bot_throw_weapon_at_player.h | 3 ++ .../behavior/neo_bot_throw_weapon_at_user.h | 38 +++++++++++++++++++ src/game/server/neo/neo_player.cpp | 35 ++++++++--------- 5 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_user.h diff --git a/src/game/server/neo/bot/behavior/neo_bot_scenario_monitor.cpp b/src/game/server/neo/bot/behavior/neo_bot_scenario_monitor.cpp index cb0b348e02..eea1bc18e8 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_scenario_monitor.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_scenario_monitor.cpp @@ -9,15 +9,15 @@ #include "bot/behavior/nav_entities/neo_bot_nav_ent_destroy_entity.h" #include "bot/behavior/nav_entities/neo_bot_nav_ent_move_to.h" #include "bot/behavior/nav_entities/neo_bot_nav_ent_wait.h" -#include "bot/behavior/neo_bot_tactical_monitor.h" -#include "bot/behavior/neo_bot_retreat_to_cover.h" -#include "bot/behavior/neo_bot_get_health.h" -#include "bot/behavior/neo_bot_get_ammo.h" +#include "bot/behavior/neo_bot_attack.h" #include "bot/behavior/neo_bot_command_follow.h" +#include "bot/behavior/neo_bot_get_ammo.h" +#include "bot/behavior/neo_bot_get_health.h" #include "bot/behavior/neo_bot_pause.h" - -#include "bot/behavior/neo_bot_attack.h" +#include "bot/behavior/neo_bot_retreat_to_cover.h" #include "bot/behavior/neo_bot_seek_and_destroy.h" +#include "bot/behavior/neo_bot_tactical_monitor.h" +#include "bot/behavior/neo_bot_throw_weapon_at_user.h" #include "bot/behavior/neo_bot_scenario_monitor.h" @@ -85,6 +85,18 @@ ActionResult< CNEOBot > CNEOBotScenarioMonitor::Update( CNEOBot *me, float inter return SuspendFor(new CNEOBotPause, "Paused by debug convar sv_neo_bot_cmdr_debug_pause_uncommanded"); } } + else + { + if (me->m_hCommandingPlayer.Get()) + { + CNEO_Player* pCommander = me->m_hCommandingPlayer.Get(); + + if (CNEOBotThrowWeaponAtUser::ReadyAimToThrowWeapon(me, pCommander)) + { + return SuspendFor(new CNEOBotThrowWeaponAtUser(pCommander), "Throwing primary weapon to user"); + } + } + } return Continue(); } diff --git a/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.cpp b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.cpp index db94c88011..7947995cdc 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.cpp @@ -20,12 +20,19 @@ ActionResult< CNEOBot > CNEOBotThrowWeaponAtPlayer::OnStart( CNEOBot *me, Action return Done( "No target player to throw weapon at" ); } + m_expirationTimer.Start( 5.0f ); + return Continue(); } //--------------------------------------------------------------------------------------------- ActionResult< CNEOBot > CNEOBotThrowWeaponAtPlayer::Update( CNEOBot *me, float interval ) { + if ( m_expirationTimer.IsElapsed() ) + { + return Done( "Expiration timer elapsed" ); + } + CNEO_Player *pTarget = m_hTargetPlayer.Get(); if ( !pTarget || !pTarget->IsAlive() ) { diff --git a/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.h b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.h index 53e23cd93a..339d573437 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.h +++ b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_player.h @@ -19,6 +19,9 @@ class CNEOBotThrowWeaponAtPlayer : public Action< CNEOBot > virtual const char *GetName( void ) const override { return "ThrowWeaponAtPlayer"; }; +protected: + CountdownTimer m_expirationTimer; + private: CHandle m_hTargetPlayer; }; diff --git a/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_user.h b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_user.h new file mode 100644 index 0000000000..7b7b06c10e --- /dev/null +++ b/src/game/server/neo/bot/behavior/neo_bot_throw_weapon_at_user.h @@ -0,0 +1,38 @@ +#ifndef NEO_BOT_THROW_WEAPON_AT_USER_H +#define NEO_BOT_THROW_WEAPON_AT_USER_H +#pragma once + +#include "bot/behavior/neo_bot_throw_weapon_at_player.h" +#include "bot/neo_bot.h" +#include "neo_player.h" + +//----------------------------------------------------------------------------------------- +// If the bot command system is disabled, bots simply drop their weapon for the user +class CNEOBotThrowWeaponAtUser : public CNEOBotThrowWeaponAtPlayer +{ +public: + CNEOBotThrowWeaponAtUser(CNEO_Player* pTargetPlayer) : CNEOBotThrowWeaponAtPlayer(pTargetPlayer) {} + + virtual void OnEnd(CNEOBot* me, Action< CNEOBot >* nextAction) override + { + me->m_hCommandingPlayer = nullptr; + CNEOBotThrowWeaponAtPlayer::OnEnd(me, nextAction); + } + + virtual const char* GetName(void) const override { return "ThrowWeaponAtUser"; }; + + static bool ReadyAimToThrowWeapon(CNEOBot* me, CNEO_Player* pCommander) + { + me->GetBodyInterface()->AimHeadTowards(pCommander->GetAbsOrigin(), IBody::MANDATORY, 0.2f, nullptr, "Aiming at user's feet to throw weapon"); + + Vector vecToUserFeet = pCommander->GetAbsOrigin() - me->EyePosition(); + vecToUserFeet.NormalizeInPlace(); + + Vector vecBotFacing; + me->EyeVectors(&vecBotFacing); + + return (vecBotFacing.Dot(vecToUserFeet) > 0.95f); + } +}; + +#endif // NEO_BOT_THROW_WEAPON_AT_USER_H diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index d1d7091a82..0d248652a0 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -3280,16 +3280,13 @@ void CNEO_Player::SetTestMessageVisible(bool visible) void CNEO_Player::ResetBotCommandState() { - if (sv_neo_bot_cmdr_enable.GetBool()) + m_hLeadingPlayer = nullptr; + m_hCommandingPlayer = nullptr; + m_tBotPlayerPingCooldown.Invalidate(); + m_flBotDynamicFollowDistanceSq = 0.0f; + for (int i = 0; i < STAR__TOTAL; ++i) { - m_hLeadingPlayer = nullptr; - m_hCommandingPlayer = nullptr; - m_tBotPlayerPingCooldown.Invalidate(); - m_flBotDynamicFollowDistanceSq = 0.0f; - for (int i = 0; i < STAR__TOTAL; ++i) - { - m_vLastPingByStar.GetForModify(i) = VECTOR_INVALID_WAYPOINT; - } + m_vLastPingByStar.GetForModify(i) = VECTOR_INVALID_WAYPOINT; } } @@ -3362,11 +3359,6 @@ void CNEO_Player::PlayerUse( void ) { BaseClass::PlayerUse(); - if (!sv_neo_bot_cmdr_enable.GetBool()) - { - return; - } - if ( (m_afButtonPressed & IN_USE) && !FindUseEntity() ) { // Select bot under cursor to follow/unfollow. @@ -3384,9 +3376,18 @@ void CNEO_Player::PlayerUse( void ) CNEO_Player* pTargetPlayer = ToNEOPlayer(tr.m_pEnt); if ( pTargetPlayer && pTargetPlayer->IsBot()) { - // The hit entity is a bot! Now, toggle its follow state. - pTargetPlayer->ToggleBotFollowCommander( this ); - // TODO: Do we want to allow using players for some kind of communication? + if (sv_neo_bot_cmdr_enable.GetBool()) + { + // The hit entity is a bot! Now, toggle its follow state. + pTargetPlayer->ToggleBotFollowCommander( this ); + // TODO: Do we want to allow using players for some kind of communication? + } + else if (NEORules()->IsTeamplay() && pTargetPlayer->GetTeamNumber() == GetTeamNumber()) + { + // Alt: Triggers throwing primary weapon to user + // see neo_bot_scenario_monitor for behavior transition + pTargetPlayer->m_hCommandingPlayer = this; + } } } }