11#include " cbase.h"
22#include " bot/behavior/neo_bot_jgr_capture.h"
33#include " bot/behavior/neo_bot_retreat_to_cover.h"
4+ #include " bot/behavior/neo_bot_attack.h"
45#include " bot/neo_bot_path_compute.h"
56#include " neo_gamerules.h"
67#include " neo_juggernaut.h"
78
9+ static const float JGR_CAPTURE_FACING_DOT = 0 .9f ;
10+ static const float JGR_CAPTURE_LOCKED_RETREAT_TIME = 2 .0f ;
11+ static const float JGR_CAPTURE_MAX_REPATH_DELAY = 5 .0f ;
12+ static const float JGR_CAPTURE_MIN_REPATH_DELAY = 1 .0f ;
13+ static const float JGR_CAPTURE_REPOSITION_RATIO = 0 .7f ;
14+ static const float JGR_CAPTURE_TIMER_BUFFER = 1 .0f ;
15+
16+ // ---------------------------------------------------------------------------------------------
17+ void CNEOBotJgrCapture::StopMoving ( CNEOBot *me )
18+ {
19+ m_path.Invalidate ();
20+ me->ReleaseForwardButton ();
21+ me->ReleaseBackwardButton ();
22+ me->ReleaseLeftButton ();
23+ me->ReleaseRightButton ();
24+ }
25+
826// ---------------------------------------------------------------------------------------------
927CNEOBotJgrCapture::CNEOBotJgrCapture ( CNEO_Juggernaut *pObjective )
1028{
@@ -17,6 +35,7 @@ ActionResult<CNEOBot> CNEOBotJgrCapture::OnStart( CNEOBot *me, Action<CNEOBot> *
1735 m_useAttemptTimer.Invalidate ();
1836 m_path.Invalidate ();
1937 m_repathTimer.Invalidate ();
38+ m_bStrafeRight = ( RandomInt ( 0 , 1 ) == 1 );
2039
2140 if ( !m_hObjective )
2241 {
@@ -35,6 +54,7 @@ ActionResult<CNEOBot> CNEOBotJgrCapture::OnStart( CNEOBot *me, Action<CNEOBot> *
3554
3655 // Ignore enemies while capturing juggernaut
3756 me->StopLookingAroundForEnemies ();
57+ me->SetAttribute ( CNEOBot::IGNORE_ENEMIES );
3858 me->ReloadIfLowClip (); // might as well as we're preoccupied
3959 return Continue ();
4060}
@@ -44,24 +64,21 @@ void CNEOBotJgrCapture::OnEnd( CNEOBot *me, Action<CNEOBot> *nextAction )
4464{
4565 me->ReleaseUseButton ();
4666 me->StartLookingAroundForEnemies ();
67+ me->ClearAttribute ( CNEOBot::IGNORE_ENEMIES );
4768}
4869
4970// ---------------------------------------------------------------------------------------------
5071ActionResult<CNEOBot> CNEOBotJgrCapture::OnSuspend ( CNEOBot *me, Action<CNEOBot> *interruptingAction )
5172{
52- // CNEOBotTacticalMonitor -> CNEOBotRetreatToCover will handle reacting to enemies if under fire
53- // Debatably, maybe bots should just ignore enemies, but that would require a change to CNEOBotTacticalMonitor
54- // Also it might be more fun for humans if they can interrupt bots from taking the Juggernaut.
55- me->ReleaseUseButton ();
56- me->StartLookingAroundForEnemies ();
57- return Continue ();
73+ // Situation around juggernaut is possibly stale, reevaluate
74+ return Done ( " OnSuspend: Reevaluating capture situation" );
5875}
5976
6077// ---------------------------------------------------------------------------------------------
6178ActionResult<CNEOBot> CNEOBotJgrCapture::OnResume ( CNEOBot *me, Action<CNEOBot> *interruptingAction )
6279{
63- me-> StopLookingAroundForEnemies ();
64- return Continue ( );
80+ // Situation around juggernaut is possibly stale, reevaluate
81+ return Done ( " OnResume: Reevaluating capture situation " );
6582}
6683
6784// ---------------------------------------------------------------------------------------------
@@ -92,6 +109,29 @@ ActionResult<CNEOBot> CNEOBotJgrCapture::Update( CNEOBot *me, float interval )
92109 }
93110 }
94111
112+ CBasePlayer *pActivatingPlayer = m_hObjective->GetActivatingPlayer ();
113+ if ( pActivatingPlayer )
114+ {
115+ if ( !me->InSameTeam ( pActivatingPlayer ) )
116+ {
117+ return SuspendFor ( new CNEOBotAttack, " Attacking enemy capturing the juggernaut" );
118+ }
119+ else if ( pActivatingPlayer != me )
120+ {
121+ if ( me->GetVisionInterface ()->GetPrimaryKnownThreat () )
122+ {
123+ return SuspendFor ( new CNEOBotAttack, " Defending teammate capturing the juggernaut" );
124+ }
125+
126+ // Look away from the juggernaut to watch for threats
127+ CNEOBotJgrCapture::LookAwayFrom ( me, m_hObjective );
128+
129+ me->ReleaseUseButton ();
130+ m_useAttemptTimer.Invalidate ();
131+ return Continue ();
132+ }
133+ }
134+
95135 if ( me->GetAbsOrigin ().DistToSqr ( m_hObjective->GetAbsOrigin () ) < CNEO_Juggernaut::GetUseDistanceSquared () )
96136 {
97137 if ( NEORules ()->IsJuggernautLocked () )
@@ -101,47 +141,76 @@ ActionResult<CNEOBot> CNEOBotJgrCapture::Update( CNEOBot *me, float interval )
101141 Assert ( NEORules ()->IsJuggernautLocked () == (pJuggernaut && pJuggernaut->m_bLocked ) );
102142#endif
103143 me->ReleaseUseButton ();
104- return SuspendFor ( new CNEOBotRetreatToCover ( 2 .0f ), " Juggernaut is locked, taking cover to wait for it to unlock" );
144+ m_useAttemptTimer.Invalidate ();
145+
146+ // Look away from the juggernaut while it's locked to watch for threats
147+ CNEOBotJgrCapture::LookAwayFrom ( me, m_hObjective );
105148 }
106-
107- // Stop moving while using
108- m_path.Invalidate ();
109- me->ReleaseForwardButton ();
110- me->ReleaseBackwardButton ();
111- me->ReleaseLeftButton ();
112- me->ReleaseRightButton ();
113149
114150 const Vector vecObjectiveCenter = m_hObjective->WorldSpaceCenter ();
151+ me->GetBodyInterface ()->AimHeadTowards ( vecObjectiveCenter, IBody::MANDATORY, 0 .1f , nullptr , " Focusing on Juggernaut objective" );
152+
153+ // Check if we are facing juggernaut and have a clear line of sight
115154 Vector vecToTargetDir = vecObjectiveCenter - me->EyePosition ();
116155 vecToTargetDir.NormalizeInPlace ();
117156
118- // Ensure we are facing the target before attempting to use
119157 Vector vecEyeDirection;
120158 me->EyeVectors ( &vecEyeDirection );
121159 const float flDot = vecEyeDirection.Dot ( vecToTargetDir );
122- const bool bIsFacing = flDot > 0 . 9f ;
160+ const bool bIsFacing = flDot > JGR_CAPTURE_FACING_DOT ;
123161
124- me->GetBodyInterface ()->AimHeadTowards ( vecObjectiveCenter, IBody::CRITICAL, 0 .1f , NULL , " Looking at Juggernaut objective to use" );
162+ trace_t trace;
163+ UTIL_TraceLine ( me->EyePosition (), vecObjectiveCenter, MASK_PLAYERSOLID, me, COLLISION_GROUP_NONE, &trace );
125164
126- if ( m_useAttemptTimer. HasStarted () )
165+ if ( trace. m_pEnt == m_hObjective )
127166 {
128- if ( m_useAttemptTimer. IsElapsed () )
167+ if ( bIsFacing && me-> GetBodyInterface ()-> IsHeadAimingOnTarget () )
129168 {
130- return Done ( " Use timer elapsed, failed to capture" );
169+ if ( !m_useAttemptTimer.HasStarted () )
170+ {
171+ m_useAttemptTimer.Start ( CNEO_Juggernaut::GetUseDuration () + JGR_CAPTURE_TIMER_BUFFER );
172+ }
173+
174+ me->PressUseButton ();
175+ StopMoving ( me );
176+
177+ if ( m_useAttemptTimer.IsElapsed () )
178+ {
179+ return Done ( " Activation attempt expired" );
180+ }
131181 }
132182 }
133- else if ( bIsFacing && me-> GetBodyInterface ()-> IsHeadAimingOnTarget () )
183+ else
134184 {
135- m_useAttemptTimer.Start ( CNEO_Juggernaut::GetUseDuration () + 1 .0f );
136- me->PressUseButton ( CNEO_Juggernaut::GetUseDuration () + 1 .0f );
185+ // Trace blocked (usually by teammate), reposition to get a better angle
186+ me->ReleaseUseButton ();
187+ m_useAttemptTimer.Invalidate ();
188+ m_path.Invalidate ();
189+
190+ const float flRepositionDistSqr = JGR_CAPTURE_REPOSITION_RATIO * CNEO_Juggernaut::GetUseDistanceSquared ();
191+ if ( me->GetAbsOrigin ().DistToSqr ( m_hObjective->GetAbsOrigin () ) > flRepositionDistSqr )
192+ {
193+ me->PressForwardButton ( 0 .2f );
194+ }
195+
196+ if ( m_bStrafeRight )
197+ {
198+ me->PressRightButton ( 1 .0f );
199+ me->ReleaseLeftButton ();
200+ }
201+ else
202+ {
203+ me->PressLeftButton ( 1 .0f );
204+ me->ReleaseRightButton ();
205+ }
137206 }
138207 }
139208 else
140209 {
141- // Objective is farther than we can reach for cpature
142- if ( m_repathTimer.IsElapsed () )
210+ // Objective is farther than we can reach for capture
211+ if ( !m_repathTimer. HasStarted () || m_repathTimer.IsElapsed () )
143212 {
144- m_repathTimer.Start ( RandomFloat ( 1 . 0f , 5 . 0f ) );
213+ m_repathTimer.Start ( RandomFloat ( JGR_CAPTURE_MIN_REPATH_DELAY, JGR_CAPTURE_MAX_REPATH_DELAY ) );
145214 if ( !CNEOBotPathCompute ( me, m_path, m_hObjective->GetAbsOrigin (), FASTEST_ROUTE ) )
146215 {
147216 return Done ( " Unable to find a path to the Juggernaut objective" );
@@ -152,3 +221,19 @@ ActionResult<CNEOBot> CNEOBotJgrCapture::Update( CNEOBot *me, float interval )
152221
153222 return Continue ();
154223}
224+
225+ // ---------------------------------------------------------------------------------------------
226+ void CNEOBotJgrCapture::LookAwayFrom ( CNEOBot *me, CBaseEntity *pTarget )
227+ {
228+ if ( !pTarget )
229+ {
230+ return ;
231+ }
232+
233+ Vector vecAwayFromTarget = me->GetAbsOrigin () - pTarget->GetAbsOrigin ();
234+ Vector2D vecLookDir2D = vecAwayFromTarget.AsVector2D ();
235+ vecLookDir2D.NormalizeInPlace ();
236+
237+ const Vector vecLookPos = me->EyePosition () + Vector ( vecLookDir2D.x , vecLookDir2D.y , 0 .0f ) * 500 .0f ;
238+ me->GetBodyInterface ()->AimHeadTowards ( vecLookPos, IBody::IMPORTANT, 0 .1f , nullptr , " Facing away from target to watch for threats" );
239+ }
0 commit comments