diff --git a/src/game/server/neo/bot/behavior/neo_bot_ctg_capture.cpp b/src/game/server/neo/bot/behavior/neo_bot_ctg_capture.cpp index d6ee9d542..b0647673b 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_ctg_capture.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_ctg_capture.cpp @@ -3,6 +3,7 @@ #include "bot/behavior/neo_bot_ctg_lone_wolf_seek.h" #include "bot/behavior/neo_bot_seek_weapon.h" #include "bot/neo_bot_path_compute.h" +#include "neo_detpack.h" #include "weapon_ghost.h" @@ -68,6 +69,31 @@ ActionResult CNEOBotCtgCapture::Update( CNEOBot *me, float interval ) m_captureAttemptTimer.Start( 3.0f ); } + // Check if there is a detpack that risks exploding if I pick up the ghost + // NEO Jank: It may be more proper to check for line of sight, + // but triggering an entity search at the last moment may involve fewer overall calculations + // with the lampshade explanation as the bot being able to notice the detpack along the path + // even if we didn't check constantly along the same path + CBaseEntity *pEnts[256]; + int numEnts = UTIL_EntitiesInSphere( pEnts, 256, me->GetAbsOrigin(), NEO_DETPACK_DAMAGE_RADIUS, 0 ); + bool bDetpackNear = false; + for ( int i = 0; i < numEnts; ++i ) + { + if ( pEnts[i] && FClassnameIs( pEnts[i], "neo_deployed_detpack" ) ) + { + bDetpackNear = true; + break; + } + } + + if ( bDetpackNear ) + { + // NEO JANK: Putting the bot into seek mode will have it search the map for enemies for the rest of the round + // but for now this could be fine as it may indicate an entrenched enemy + // or a friendly that is setting up an ambush, where either scenario indicates ghost capture is too dangerous + return ChangeTo( new CNEOBotCtgLoneWolfSeek(), "Found detpack: skipping ghost capture to search for enemies" ); + } + CBaseCombatWeapon *pPrimary = me->Weapon_GetSlot( 0 ); if ( pPrimary ) { diff --git a/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf_seek.cpp b/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf_seek.cpp index b5f40b25e..1e3213667 100644 --- a/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf_seek.cpp +++ b/src/game/server/neo/bot/behavior/neo_bot_ctg_lone_wolf_seek.cpp @@ -158,7 +158,27 @@ ActionResult< CNEOBot > CNEOBotCtgLoneWolfSeek::Update( CNEOBot *me, float inter } } - const Vector& currentGhostPos = NEORules()->GetGhostPos(); + Vector vecSoundPos = me->GetAudibleEnemySoundPos(); + if ( vecSoundPos != CNEO_Player::VECTOR_INVALID_WAYPOINT ) + { + // Don't veer path for sound if waypoint is not that far off + if ( m_vecSearchWaypoint.DistToSqr( vecSoundPos ) > Square( 200.0f ) ) + { + m_vecSearchWaypoint = vecSoundPos; + m_path.Invalidate(); + m_repathTimer.Invalidate(); // path to sound next tick + + CNavArea *soundArea = TheNavMesh->GetNearestNavArea( vecSoundPos ); + if ( soundArea ) + { + m_iExplorationTargetId = (int)soundArea->GetID(); + // Mark sound area as not explored + m_exploredAreaIds.Remove( m_iExplorationTargetId ); + } + } + } + + const Vector currentGhostPos = NEORules()->GetGhostPos(); if ( !m_pCachedGhostArea || currentGhostPos.DistToSqr( m_vecLastGhostPos ) > Square( 64.0f ) ) { CNavArea *pLastGhostArea = m_pCachedGhostArea; diff --git a/src/game/server/neo/bot/neo_bot.cpp b/src/game/server/neo/bot/neo_bot.cpp index 1931b3415..dbd883e12 100644 --- a/src/game/server/neo/bot/neo_bot.cpp +++ b/src/game/server/neo/bot/neo_bot.cpp @@ -21,6 +21,8 @@ #include "neo_weapon_loadout.h" #include "behavior/neo_bot_behavior.h" #include "neo_crosshair.h" +#include "recipientfilter.h" +#include "soundent.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); @@ -2939,5 +2941,80 @@ QueryResultType CNEOBotBehavior::ShouldAim(const CNEOBot *me, const bool bWepHas return result; } +//--------------------------------------------------------------------------------------------- +Vector CNEOBot::GetAudibleEnemySoundPos(const Vector& vecReferencePos, float flMaxRangeSq) const +{ + CSound *pSound = nullptr; + for ( int iSound = CSoundEnt::ActiveList(); iSound != SOUNDLIST_EMPTY; iSound = pSound->NextSound() ) + { + pSound = CSoundEnt::SoundPointerForIndex( iSound ); + if ( !pSound ) + { + break; + } + + // If a reference position and range are provided, check distance first + if ( vecReferencePos != CNEO_Player::VECTOR_INVALID_WAYPOINT && flMaxRangeSq > 0.0f ) + { + if ( pSound->GetSoundOrigin().DistToSqr( vecReferencePos ) > flMaxRangeSq ) + { + continue; + } + } + + if ( ( pSound->SoundType() & ( SOUND_COMBAT | SOUND_PLAYER ) ) == 0 ) + { + continue; + } + + CBaseEntity *pOwner = pSound->m_hOwner.Get(); + + // Ignore non-player sounds and sounds I was responsible for + if ( !pOwner || !pOwner->IsPlayer() || pOwner == GetEntity() ) + { + continue; + } + + // Only care about sounds from the enemy + if ( InSameTeam( pOwner ) ) + { + continue; + } + + // Check if I can hear the sound + bool bCanHearEnemy = false; + CPASFilter soundFilter( pSound->GetSoundOrigin() ); + for ( int i = 0; i < soundFilter.GetRecipientCount(); ++i ) + { + if ( soundFilter.GetRecipientIndex( i ) == entindex() ) + { + bCanHearEnemy = true; + break; + } + } + + if ( !bCanHearEnemy ) + { + // Check if I can hear the shooter + CPASFilter shooterFilter( pOwner->GetAbsOrigin() ); + for ( int i = 0; i < shooterFilter.GetRecipientCount(); ++i ) + { + if ( shooterFilter.GetRecipientIndex( i ) == entindex() ) + { + bCanHearEnemy = true; + break; + } + } + } + + if ( bCanHearEnemy ) + { + return pSound->GetSoundOrigin(); + } + } + + return CNEO_Player::VECTOR_INVALID_WAYPOINT; +} + diff --git a/src/game/server/neo/bot/neo_bot.h b/src/game/server/neo/bot/neo_bot.h index eef55c4c8..b88feac77 100644 --- a/src/game/server/neo/bot/neo_bot.h +++ b/src/game/server/neo/bot/neo_bot.h @@ -172,6 +172,7 @@ class CNEOBot : public NextBotPlayer< CNEO_Player >, public CGameEventListener bool IsQuietWeapon(CNEOBaseCombatWeapon* weapon) const; // return true if given weapon doesn't make much sound when used (ie: spy knife, etc) bool IsEnvironmentNoisy(void) const; // return true if there are/have been loud noises (ie: non-quiet weapons) nearby very recently + Vector GetAudibleEnemySoundPos(const Vector& vecReferencePos = CNEO_Player::VECTOR_INVALID_WAYPOINT, float flMaxRangeSq = -1.0f) const; bool IsEnemy(const CBaseEntity* them) const OVERRIDE;