Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/game/server/NextBot/NextBotVisionInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,33 @@ void IVision::ForgetEntity( CBaseEntity *forgetMe )
}


#ifdef NEO
//------------------------------------------------------------------------------------------
// Update our knowledge of where an entity is, without asserting that we saw it ourselves.
// Needed because AddKnownEntity does not refresh already known entity position data.
void IVision::UpdateKnownEntityPosition( CBaseEntity *entity )
{
if ( !entity )
{
return;
}

FOR_EACH_VEC( m_knownEntityVector, it )
{
if ( m_knownEntityVector[ it ].Is( entity ) )
{
// Found already known entity
m_knownEntityVector[ it ].UpdatePosition();
return;
}
}

// We had no idea this entity existed until now
AddKnownEntity( entity );
}
#endif // NEO


//------------------------------------------------------------------------------------------
void IVision::ForgetAllKnownEntities( void )
{
Expand Down
4 changes: 4 additions & 0 deletions src/game/server/NextBot/NextBotVisionInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class IVision : public INextBotComponent
virtual void ForgetEntity( CBaseEntity *forgetMe ); // remove the given entity from our awareness (whether we know if it or not)
virtual void ForgetAllKnownEntities( void );

#ifdef NEO
virtual void UpdateKnownEntityPosition( CBaseEntity *entity );
#endif // NEO

//-- physical vision interface follows ------------------------------------------------------

/**
Expand Down
53 changes: 36 additions & 17 deletions src/game/server/neo/bot/behavior/neo_bot_ctg_carrier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,21 @@ void CNEOBotGhostEquipmentHandler::Update( CNEOBot *me )
m_enemyUpdateTimer.Start( GetUpdateInterval( me ) );
}

// Check if currently focused enemy has disappeared from beacon range
CBaseEntity *pFocus = m_hCurrentFocusEnemy.Get();
if ( !IsValidFocusEnemy( me, pFocus ) )
{
m_hCurrentFocusEnemy = nullptr;
pFocus = nullptr;
}

// Debug: Highlight the location of the enemy a bot ghost carrier is calling out
if ( neo_debug_ghost_carrier.GetBool() )
if ( neo_debug_ghost_carrier.GetBool() && pFocus && pFocus->IsPlayer() )
{
CBaseEntity *pFocus = m_hCurrentFocusEnemy.Get();
if ( pFocus && pFocus->IsPlayer() && pFocus->IsAlive() )
{
NDebugOverlay::Cross3D( pFocus->GetAbsOrigin(), 20.0f, 255, 0, 0, true, 0.1f );
}
NDebugOverlay::Cross3D( pFocus->GetAbsOrigin(), 20.0f, 255, 0, 0, true, 0.1f );
}

CBaseEntity *pFocus = m_hCurrentFocusEnemy.Get();
if ( pFocus && pFocus->IsAlive() )
if ( pFocus )
{
if ( bUpdateCallout )
{
Expand Down Expand Up @@ -125,12 +128,8 @@ void CNEOBotGhostEquipmentHandler::Update( CNEOBot *me )
// NEO Jank: Urge relevant teammate bots look at the enemy
pBot->GetBodyInterface()->AimHeadTowards( pFocus, IBody::IMPORTANT, 0.5f, nullptr, "Ghost carrier teammate look override" );
}
else
{
// Force updates to known but not visible entity by forgetting them first
pBot->GetVisionInterface()->ForgetEntity( pFocus );
}
pBot->GetVisionInterface()->AddKnownEntity( pFocus ); // keep after ForgetEntity

pBot->GetVisionInterface()->UpdateKnownEntityPosition( pFocus );
}
}

Expand Down Expand Up @@ -177,6 +176,21 @@ void CNEOBotGhostEquipmentHandler::EquipBestWeaponForGhoster( CNEOBot *me )
}
}

bool CNEOBotGhostEquipmentHandler::IsValidFocusEnemy( CNEOBot *me, CBaseEntity *pFocus ) const
{
if ( !pFocus || !pFocus->IsAlive() || pFocus->IsEffectActive( EF_NODRAW ) )
{
return false;
}

if ( !me->IsEnemy( pFocus ) )
{
return false;
}

return me->GetVisionInterface()->IsAbleToSee( pFocus, IVision::DISREGARD_FOV );
}

float CNEOBotGhostEquipmentHandler::GetUpdateInterval( CNEOBot *me ) const
{
switch ( me->GetDifficulty() )
Expand Down Expand Up @@ -338,6 +352,11 @@ void CNEOBotGhostEquipmentHandler::UpdateGhostCarrierCallout( CNEOBot *me, const
m_enemyLastPos[ idx ] = pBestCallout->GetAbsOrigin();
}
}
else
{
// Nobody is in beacon range or in sight
m_hCurrentFocusEnemy = nullptr;
}
}


Expand Down Expand Up @@ -516,8 +535,7 @@ void CNEOBotCtgCarrier::UpdateFollowPath( CNEOBot *me, const CUtlVector<CNEO_Pla
if ( bFoundGoal )
{
// We need to know where enemies are to determine if we are safe to cap
CWeaponGhost *pGhost = dynamic_cast<CWeaponGhost*>( me->Weapon_GetSlot( 0 ) );
if ( pGhost && pGhost->IsGhost() && pGhost->IsBootupCompleted() )
if ( me->GetBeaconingGhost() )
{
float flDistMeToGoalSq = me->GetAbsOrigin().DistToSqr( vecGoalPos );

Expand All @@ -526,7 +544,8 @@ void CNEOBotCtgCarrier::UpdateFollowPath( CNEOBot *me, const CUtlVector<CNEO_Pla
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CNEO_Player *pPlayer = ToNEOPlayer( UTIL_PlayerByIndex( i ) );
if ( pPlayer && pPlayer->IsAlive() && pPlayer->GetTeamNumber() != me->GetTeamNumber() )
if ( pPlayer && pPlayer->IsAlive() && pPlayer->GetTeamNumber() != me->GetTeamNumber()
&& me->GetVisionInterface()->IsAbleToSee( pPlayer, IVision::DISREGARD_FOV ) )
{
float dSq = pPlayer->GetAbsOrigin().DistToSqr( vecGoalPos );
if ( dSq <= flDistMeToGoalSq )
Expand Down
1 change: 1 addition & 0 deletions src/game/server/neo/bot/behavior/neo_bot_ctg_carrier.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class CNEOBotGhostEquipmentHandler
private:
void EquipBestWeaponForGhoster( CNEOBot *me );
float GetUpdateInterval( CNEOBot *me ) const;
bool IsValidFocusEnemy( CNEOBot *me, CBaseEntity *pFocus ) const;
void UpdateGhostCarrierCallout( CNEOBot *me, const CUtlVector<CNEO_Player*> &enemies );

EHANDLE m_hCurrentFocusEnemy{nullptr};
Expand Down
47 changes: 47 additions & 0 deletions src/game/server/neo/bot/neo_bot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "neo_weapon_loadout.h"
#include "behavior/neo_bot_behavior.h"
#include "neo_crosshair.h"
#include "neo/weapons/weapon_ghost.h"

ConVar neo_bot_notice_gunfire_range("neo_bot_notice_gunfire_range", "3000", FCVAR_GAMEDLL);
ConVar neo_bot_notice_quiet_gunfire_range("neo_bot_notice_quiet_gunfire_range", "500", FCVAR_GAMEDLL);
Expand All @@ -41,6 +42,7 @@ extern ConVar neo_bot_difficulty;
extern ConVar neo_bot_farthest_visible_theater_sample_count;
extern ConVar neo_bot_path_lookahead_range;
extern ConVar neo_bot_path_around_friendly_cooldown;
extern ConVar sv_neo_ctg_ghost_beacons_when_inactive;



Expand Down Expand Up @@ -1625,6 +1627,51 @@ void CNEOBot::EquipBestWeaponForThreat(const CKnownEntity* threat, const bool bN
}


//-----------------------------------------------------------------------------------------------------
// Return handle to ghost if it is beaconing for the bot player
// Also useful to get true beacon range from weapon implementation
CWeaponGhost *CNEOBot::GetBeaconingGhost( void ) const
{
if ( !IsCarryingGhost() )
{
return nullptr;
}

CBaseCombatWeapon *pCandidate = sv_neo_ctg_ghost_beacons_when_inactive.GetBool()
? Weapon_GetSlot( 0 )
: GetActiveWeapon();

CNEOBaseCombatWeapon *pNeoWeapon = dynamic_cast<CNEOBaseCombatWeapon *>( pCandidate );
if ( !pNeoWeapon || !pNeoWeapon->IsGhost() )
{
return nullptr;
}

CWeaponGhost *pGhost = assert_cast<CWeaponGhost *>( pNeoWeapon );
return pGhost->IsBootupCompleted() ? pGhost : nullptr;
}


//-----------------------------------------------------------------------------------------------------
// Returns whether the conditions are satisfied for the ghost revealing the subject
bool CNEOBot::IsRevealedByMyGhost( CBaseEntity *subject ) const
{
if ( !subject )
{
return false;
}

const CWeaponGhost *pGhost = GetBeaconingGhost();
if ( !pGhost )
{
return false;
}

float flDistIgnored;
return pGhost->BeaconRange( subject, flDistIgnored );
}


//-----------------------------------------------------------------------------------------------------
bool CNEOBot::DropGhost()
{
Expand Down
4 changes: 4 additions & 0 deletions src/game/server/neo/bot/neo_bot.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
class CNEOBotActionPoint;
class CNEOBotGenerator;
class CNEOBot;
class CWeaponGhost;

extern ConVar hl2_normspeed;

Expand Down Expand Up @@ -160,7 +161,10 @@ class CNEOBot : public NextBotPlayer< CNEO_Player >, public CGameEventListener
bool EquipRequiredWeapon(void); // if we're required to equip a specific weapon, do it.
void EquipBestWeaponForThreat(const CKnownEntity* threat, const bool bNotPrimary = false); // equip the best weapon we have to attack the given threat
void ReloadIfLowClip(bool bForceReload = false);

bool DropGhost();
CWeaponGhost *GetBeaconingGhost(void) const;
bool IsRevealedByMyGhost(CBaseEntity *subject) const;

void DropPrimaryWeapon(void);

Expand Down
11 changes: 2 additions & 9 deletions src/game/server/neo/bot/neo_bot_vision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,9 @@ bool CNEOBotVision::IsInFieldOfView( CBaseEntity *subject ) const
bool CNEOBotVision::IsAbleToSee(CBaseEntity *subject, FieldOfViewCheckType checkFOV, Vector *visibleSpot) const
{
CNEOBot *me = (CNEOBot *)GetBot()->GetEntity();
if (me && me->IsCarryingGhost())
if (me && me->IsRevealedByMyGhost(subject))
{
auto *pGhost = dynamic_cast<CWeaponGhost *>(me->GetActiveWeapon());
if (pGhost && pGhost->IsGhost() && pGhost->IsBootupCompleted())
{
if (me->GetAbsOrigin().DistToSqr(subject->GetAbsOrigin()) < Square(CWeaponGhost::GetGhostRangeInHammerUnits()))
{
return true;
}
}
return true;
}

return IVision::IsAbleToSee(subject, checkFOV, visibleSpot);
Expand Down