44#include " bot/behavior/neo_bot_attack.h"
55#include " bot/behavior/neo_bot_ctg_capture.h"
66#include " bot/behavior/neo_bot_ctg_lone_wolf.h"
7+ #include " bot/behavior/neo_bot_ctg_lone_wolf_ambush.h"
78#include " bot/behavior/neo_bot_seek_weapon.h"
89#include " bot/behavior/neo_bot_retreat_to_cover.h"
910#include " bot/neo_bot_path_compute.h"
1011#include " neo_gamerules.h"
1112#include " neo_ghost_cap_point.h"
13+ #include " weapon_detpack.h"
1214#include " weapon_ghost.h"
1315
1416
@@ -17,7 +19,6 @@ CNEOBotCtgLoneWolf::CNEOBotCtgLoneWolf( void )
1719{
1820 m_hGhost = nullptr ;
1921 m_bPursuingDropThreat = false ;
20- m_bHasRetreatedFromGhost = false ;
2122 m_vecDropThreatPos = CNEO_Player::VECTOR_INVALID_WAYPOINT;
2223 m_closestCapturePoint = CNEO_Player::VECTOR_INVALID_WAYPOINT;
2324}
@@ -26,7 +27,7 @@ CNEOBotCtgLoneWolf::CNEOBotCtgLoneWolf( void )
2627ActionResult< CNEOBot > CNEOBotCtgLoneWolf::OnStart ( CNEOBot *me, Action< CNEOBot > *priorAction )
2728{
2829 m_hGhost = nullptr ;
29- m_bHasRetreatedFromGhost = false ;
30+ m_hPursueTarget = nullptr ;
3031 m_bPursuingDropThreat = false ;
3132 m_useAttemptTimer.Invalidate ();
3233 m_lookAroundTimer.Invalidate ();
@@ -35,7 +36,6 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::OnStart( CNEOBot *me, Action< CNEOBo
3536 m_capPointUpdateTimer.Invalidate ();
3637 m_vecDropThreatPos = CNEO_Player::VECTOR_INVALID_WAYPOINT;
3738 m_closestCapturePoint = CNEO_Player::VECTOR_INVALID_WAYPOINT;
38- m_hPursueTarget = nullptr ;
3939
4040 return Continue ();
4141}
@@ -87,42 +87,15 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::Update( CNEOBot *me, float interval
8787 }
8888
8989 // Always need to find the ghost to act on it
90- if (!m_hGhost)
91- {
92- m_hGhost = dynamic_cast <CWeaponGhost*>( gEntList .FindEntityByClassname (nullptr , " weapon_ghost" ) );
93- }
94-
95- if (!m_hGhost)
90+ if ( !UpdateGhostHandle ( me ) )
9691 {
9792 return Done ( " Ghost not found" );
9893 }
9994
10095 // Occasionally reconsider which cap zone is our goal
10196 if ( !m_capPointUpdateTimer.HasStarted () || m_capPointUpdateTimer.IsElapsed () )
10297 {
103- m_closestCapturePoint = CNEO_Player::VECTOR_INVALID_WAYPOINT;
104- float flNearestCapDistSq = FLT_MAX;
105-
106- if ( NEORules ()->m_pGhostCaps .Count () > 0 )
107- {
108- const Vector& vecStart = me->IsCarryingGhost () ? me->GetAbsOrigin () : m_hGhost->GetAbsOrigin ();
109-
110- for ( int i=0 ; i<NEORules ()->m_pGhostCaps .Count (); ++i )
111- {
112- CNEOGhostCapturePoint *pCapPoint = dynamic_cast <CNEOGhostCapturePoint*>( UTIL_EntityByIndex ( NEORules ()->m_pGhostCaps [i] ) );
113- if ( !pCapPoint ) continue ;
114-
115- if ( pCapPoint->owningTeamAlternate () == me->GetTeamNumber () )
116- {
117- float distSq = vecStart.DistToSqr ( pCapPoint->GetAbsOrigin () );
118- if ( distSq < flNearestCapDistSq )
119- {
120- flNearestCapDistSq = distSq;
121- m_closestCapturePoint = pCapPoint->GetAbsOrigin ();
122- }
123- }
124- }
125- }
98+ m_closestCapturePoint = GetNearestCapturePoint ( me, false );
12699 m_capPointUpdateTimer.Start ( RandomFloat ( 0 .5f , 1 .0f ) );
127100 }
128101
@@ -294,11 +267,20 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::Update( CNEOBot *me, float interval
294267 // Ghost is free for taking
295268 if ( bSafeToCap || (bIs1v1 && m_stalemateTimer.HasStarted () && m_stalemateTimer.IsElapsed ()) )
296269 {
297- // Try to cap before enemy can stop us.
298270 float flDistToGhostSq = me->GetAbsOrigin ().DistToSqr (m_hGhost->GetAbsOrigin ());
299- if ( flDistToGhostSq < 100 .0f * 100 .0f )
271+ float flAmbushDistSq = CNEOBotCtgLoneWolf::GetDetpackDeployDistanceSq ( me );
272+
273+ if ( flDistToGhostSq < flAmbushDistSq)
300274 {
301- return SuspendFor (new CNEOBotCtgCapture (m_hGhost.Get ()), " Picking up ghost to make a run for it!" );
275+ if ( !bSafeToCap && me->Weapon_OwnsThisType (" weapon_remotedet" ) )
276+ {
277+ return ChangeTo (new CNEOBotCtgLoneWolfAmbush (), " Setting up detpack ambush at ghost" );
278+ }
279+ else
280+ {
281+ // Try to cap before enemy can stop us.
282+ return SuspendFor (new CNEOBotCtgCapture (m_hGhost.Get ()), " Picking up ghost to make a run for it!" );
283+ }
302284 }
303285
304286 if ( !m_repathTimer.HasStarted () || m_repathTimer.IsElapsed () )
@@ -323,40 +305,27 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::Update( CNEOBot *me, float interval
323305 m_stalemateTimer.Start ( RandomFloat ( 10 .0f , 20 .0f ) );
324306 }
325307
326- if ( m_bHasRetreatedFromGhost )
308+ // Hide out of sight of ghost to ambush anyone that picks up the ghost
309+ float flDistToGhostSq = me->GetAbsOrigin ().DistToSqr (m_hGhost->GetAbsOrigin ());
310+ float flAmbushDistSq = CNEOBotCtgLoneWolf::GetDetpackDeployDistanceSq ( me );
311+ if (flDistToGhostSq < flAmbushDistSq)
327312 {
328- // Waiting in ambush/cover
329- if (threat && me->IsLineOfFireClear ( threat->GetEntity ()->WorldSpaceCenter (), CNEOBot::LINE_OF_FIRE_FLAGS_DEFAULT ))
330- {
331- me->EnableCloak ( 3 .0f );
332- return SuspendFor (new CNEOBotAttack, " Ambushing enemy near ghost!" );
333- }
334- return UpdateLookAround ( me, m_hGhost->GetAbsOrigin () );
313+ return ChangeTo (new CNEOBotCtgLoneWolfAmbush (), " Setting up ambush near the ghost" );
335314 }
336315 else
337316 {
338- // Hide out of sight of ghost to ambush anyone that picks up the ghost
339- float flDistToGhostSq = me->GetAbsOrigin ().DistToSqr (m_hGhost->GetAbsOrigin ());
340- if (flDistToGhostSq < 300 .0f * 300 .0f )
317+ // Get near the ghost first before surveying hiding spots
318+ if ( !m_repathTimer.HasStarted () || m_repathTimer.IsElapsed () )
341319 {
342- m_bHasRetreatedFromGhost = true ;
343- return SuspendFor (new CNEOBotRetreatToCover (), " Finding a hiding spot near the ghost" );
320+ CNEOBotPathCompute (me, m_path, m_hGhost->GetAbsOrigin (), FASTEST_ROUTE);
321+ m_path.Update (me);
322+ m_repathTimer.Start ( RandomFloat ( 0 .5f , 1 .0f ) );
344323 }
345324 else
346325 {
347- // Get near the ghost first before surveying hiding spots
348- if ( !m_repathTimer.HasStarted () || m_repathTimer.IsElapsed () )
349- {
350- CNEOBotPathCompute (me, m_path, m_hGhost->GetAbsOrigin (), FASTEST_ROUTE);
351- m_path.Update (me);
352- m_repathTimer.Start ( RandomFloat ( 0 .5f , 1 .0f ) );
353- }
354- else
355- {
356- m_path.Update (me);
357- }
358- return Continue ();
326+ m_path.Update (me);
359327 }
328+ return Continue ();
360329 }
361330 }
362331 }
@@ -417,7 +386,50 @@ EventDesiredResult< CNEOBot > CNEOBotCtgLoneWolf::OnMoveToFailure( CNEOBot *me,
417386 return TryContinue ();
418387}
419388
389+ // ---------------------------------------------------------------------------------------------
390+ Vector CNEOBotCtgLoneWolf::GetNearestCapturePoint ( CNEOBot *me, bool bEnemyCapPoint )
391+ {
392+ Vector vecBestCapPoint = CNEO_Player::VECTOR_INVALID_WAYPOINT;
393+ float flNearestCapDistSq = FLT_MAX;
394+
395+ if ( NEORules ()->m_pGhostCaps .Count () > 0 )
396+ {
397+ const Vector& vecStart = me->IsCarryingGhost () ? me->GetAbsOrigin () : ( m_hGhost.Get () ? m_hGhost->GetAbsOrigin () : me->GetAbsOrigin () );
398+
399+ for ( int i=0 ; i<NEORules ()->m_pGhostCaps .Count (); ++i )
400+ {
401+ CNEOGhostCapturePoint *pCapPoint = dynamic_cast <CNEOGhostCapturePoint*>( UTIL_EntityByIndex ( NEORules ()->m_pGhostCaps [i] ) );
402+ if ( !pCapPoint ) continue ;
403+
404+ bool bValidTeam = (pCapPoint->owningTeamAlternate () == me->GetTeamNumber ());
405+ if ( bEnemyCapPoint )
406+ {
407+ bValidTeam = (pCapPoint->owningTeamAlternate () != me->GetTeamNumber ());
408+ }
420409
410+ if ( bValidTeam )
411+ {
412+ float distSq = vecStart.DistToSqr ( pCapPoint->GetAbsOrigin () );
413+ if ( distSq < flNearestCapDistSq )
414+ {
415+ flNearestCapDistSq = distSq;
416+ vecBestCapPoint = pCapPoint->GetAbsOrigin ();
417+ }
418+ }
419+ }
420+ }
421+
422+ return vecBestCapPoint;
423+ }
424+
425+ // ---------------------------------------------------------------------------------------------
426+ float CNEOBotCtgLoneWolf::GetDetpackDeployDistanceSq ( CNEOBot *me )
427+ {
428+ float flArmingTime = CWeaponDetpack::GetArmingTime ();
429+ return Square ( MAX ( 100 .0f , flArmingTime * me->GetNormSpeed () ) );
430+ }
431+
432+ // ---------------------------------------------------------------------------------------------
421433// Helper for "UpdateLookAround" - inspired from how CNavArea CollectPotentiallyVisibleAreas works
422434class CCollectPotentiallyVisibleAreas
423435{
@@ -437,7 +449,18 @@ class CCollectPotentiallyVisibleAreas
437449};
438450
439451// ---------------------------------------------------------------------------------------------
440- ActionResult< CNEOBot > CNEOBotCtgLoneWolf::UpdateLookAround ( CNEOBot *me, const Vector &anchorPos )
452+ bool CNEOBotCtgLoneWolf::UpdateGhostHandle ( CNEOBot *me )
453+ {
454+ if ( !m_hGhost )
455+ {
456+ m_hGhost = dynamic_cast <CWeaponGhost*>( gEntList .FindEntityByClassname ( nullptr , " weapon_ghost" ) );
457+ }
458+
459+ return ( m_hGhost != nullptr );
460+ }
461+
462+ // ---------------------------------------------------------------------------------------------
463+ ActionResult< CNEOBot > CNEOBotCtgLoneWolf::UpdateLookAround ( CNEOBot *me )
441464{
442465 if ( !m_lookAroundTimer.HasStarted () || m_lookAroundTimer.IsElapsed () )
443466 {
0 commit comments