diff --git a/src/game/server/NextBot/Player/NextBotPlayer.h b/src/game/server/NextBot/Player/NextBotPlayer.h index e6a775d49..2a90a830e 100644 --- a/src/game/server/NextBot/Player/NextBotPlayer.h +++ b/src/game/server/NextBot/Player/NextBotPlayer.h @@ -145,6 +145,11 @@ class INextBotPlayerInput // This is just an "alias" to PressWalkButton virtual void PressRunButton( float duration = -1.0f ) = 0; virtual void ReleaseRunButton( void ) = 0; + + // This is an alias for +walk because PressWalkButton is already taken + void PressSneakButton( float duration = -1.0f ); + void ReleaseSneakButton( void ); + bool IsSneakButtonDown( void ) const; #endif // NEO virtual void SetButtonScale( float forward, float right ) = 0; @@ -256,6 +261,10 @@ class NextBotPlayer : public PlayerType, public INextBot, public INextBotPlayerI virtual void PressRunButton( float duration = -1.0f ); virtual void ReleaseRunButton( void ); + void PressSneakButton( float duration = -1.0f ); + void ReleaseSneakButton( void ); + bool IsSneakButtonDown( void ) const; + void PressLeanLeftButton( float duration = -1.0f ); void ReleaseLeanLeftButton( void ); @@ -307,6 +316,7 @@ class NextBotPlayer : public PlayerType, public INextBot, public INextBotPlayerI CountdownTimer m_moveUpButtonTimer; CountdownTimer m_moveDownButtonTimer; CountdownTimer m_dropButtonTimer; + CountdownTimer m_sneakButtonTimer; CountdownTimer m_thermopticButtonTimer; CountdownTimer m_leanLeftButtonTimer; CountdownTimer m_leanRightButtonTimer; @@ -565,6 +575,26 @@ inline void NextBotPlayer< PlayerType >::ReleaseRunButton( void ) return NextBotPlayer::ReleaseWalkButton(); } +template < typename PlayerType > +inline void NextBotPlayer< PlayerType >::PressSneakButton( float duration ) +{ + m_inputButtons |= IN_WALK; + m_sneakButtonTimer.Start( duration ); +} + +template < typename PlayerType > +inline void NextBotPlayer< PlayerType >::ReleaseSneakButton( void ) +{ + m_inputButtons &= ~IN_WALK; + m_sneakButtonTimer.Invalidate(); +} + +template < typename PlayerType > +inline bool NextBotPlayer< PlayerType >::IsSneakButtonDown( void ) const +{ + return !m_sneakButtonTimer.IsElapsed(); +} + template < typename PlayerType > inline void NextBotPlayer< PlayerType >::PressLeanLeftButton( float duration ) { @@ -704,6 +734,7 @@ inline void NextBotPlayer< PlayerType >::Spawn( void ) m_moveUpButtonTimer.Invalidate(); m_moveDownButtonTimer.Invalidate(); m_dropButtonTimer.Invalidate(); + m_sneakButtonTimer.Invalidate(); m_thermopticButtonTimer.Invalidate(); m_leanLeftButtonTimer.Invalidate(); m_leanRightButtonTimer.Invalidate(); @@ -842,6 +873,9 @@ inline void NextBotPlayer< PlayerType >::PhysicsSimulate( void ) m_inputButtons |= IN_SPEED; #ifdef NEO + if ( !m_sneakButtonTimer.IsElapsed() ) + m_inputButtons |= IN_WALK; + if ( !m_dropButtonTimer.IsElapsed() ) m_inputButtons |= IN_DROP; 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 599ffff6f..6994076f3 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_behavior.cpp @@ -370,6 +370,11 @@ Vector CNEOBotMainAction::SelectTargetPoint( const INextBot *meBot, const CBaseC //----------------------------------------------------------------------------------------- void CNEOBotMainAction::ReconConsiderSuperJump( CNEOBot *me ) { + if (me->IsSneakButtonDown()) + { + return; + } + if ( me->GetClass() != NEO_CLASS_RECON ) { return; @@ -704,7 +709,17 @@ QueryResultType CNEOBotMainAction::ShouldWalk(const CNEOBot *me, const QueryResu // Walk if reloading or firing CNEOBaseCombatWeapon *myWeapon = static_cast(me->GetActiveWeapon()); - return (myWeapon && (myWeapon->m_bInReload || me->m_bOnTarget || me->IsFiring())) ? ANSWER_YES : ANSWER_NO; + if (myWeapon && (myWeapon->m_bInReload || me->m_bOnTarget || me->IsFiring())) + { + return ANSWER_YES; + } + + if (me->IsSneakButtonDown()) + { + return ANSWER_YES; + } + + return ANSWER_NO; } QueryResultType CNEOBotMainAction::ShouldAim(const CNEOBot *me, const bool bWepHasClip) const diff --git a/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp b/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp index d4f433c2e..77987a796 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_command_follow.cpp @@ -203,6 +203,15 @@ bool CNEOBotCommandFollow::FollowCommandChain(CNEOBot* me) { me->ReleaseCrouchButton(); } + + if (pPlayerToMirror->IsWalking()) + { + me->PressSneakButton(0.5f); + } + else + { + me->ReleaseSneakButton(); + } } // Calibrate dynamic follow distance @@ -226,6 +235,7 @@ bool CNEOBotCommandFollow::FollowCommandChain(CNEOBot* me) // Use sv_neo_bot_cmdr_stop_distance_sq for consistent bot collection range // follow_stop_distance_sq would be confusing if player doesn't know about distance tuning me->m_hLeadingPlayer = pCommander; + m_bSneakWhenFollowingPing = false; // watch commander's stance m_vGoalPos = CNEO_Player::VECTOR_INVALID_WAYPOINT; pCommander->m_vLastPingByStar.GetForModify(me->GetStar()) = CNEO_Player::VECTOR_INVALID_WAYPOINT; } @@ -236,6 +246,7 @@ bool CNEOBotCommandFollow::FollowCommandChain(CNEOBot* me) if (pCommander->m_vLastPingByStar.Get(me->GetStar()) != me->m_vLastPingByStar.Get(me->GetStar())) { me->m_hLeadingPlayer = nullptr; // Stop following and start travelling to ping + m_bSneakWhenFollowingPing = pCommander->IsWalking(); m_vGoalPos = pCommander->m_vLastPingByStar.Get(me->GetStar()); me->m_vLastPingByStar.GetForModify(me->GetStar()) = pCommander->m_vLastPingByStar.Get(me->GetStar()); @@ -248,10 +259,16 @@ bool CNEOBotCommandFollow::FollowCommandChain(CNEOBot* me) else { me->m_hLeadingPlayer = pCommander; // fallback to following commander + m_bSneakWhenFollowingPing = false; // watch commander's stance // continue with leader following logic below } } + if (m_bSneakWhenFollowingPing) + { + me->PressSneakButton(0.3f); + } + if (FanOutAndCover(me, m_vGoalPos)) { // FanOutAndCover true: arrived at destination and settled, so don't recompute path @@ -266,6 +283,7 @@ bool CNEOBotCommandFollow::FollowCommandChain(CNEOBot* me) else { me->m_hLeadingPlayer = pCommander; // fallback to following commander + m_bSneakWhenFollowingPing = false; // react to enemies at full speed // continue with leader following logic below } } diff --git a/src/game/server/neo/bot/behavior/neo_bot_command_follow.h b/src/game/server/neo/bot/behavior/neo_bot_command_follow.h index fe2afab06..997625c7b 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_command_follow.h +++ b/src/game/server/neo/bot/behavior/neo_bot_command_follow.h @@ -29,6 +29,7 @@ class CNEOBotCommandFollow : public Action< CNEOBot > CNEOBotGhostEquipmentHandler m_ghostEquipmentHandler; IntervalTimer m_commanderLookingAtMeTimer; + bool m_bSneakWhenFollowingPing = false; bool m_bWasCommanderLookingAtMe = false; EHANDLE m_hTargetEntity;