hlsdk-xash3d/dlls/bot/hl_bot_listen.cpp

211 lines
5.5 KiB
C++

#include "bot_common.h"
// Listen for enemy noises, and determine if we should react to them.
// Returns true if heard a noise and should move to investigate.
bool CHLBot::ShouldInvestigateNoise(float *retNoiseDist)
{
if (m_isNoiseTravelRangeChecked)
return false;
// don't investigate noises during safe time
if (!IsWellPastSafe())
return false;
// if our disposition is not to investigate, dont investigate
if (GetDisposition() != ENGAGE_AND_INVESTIGATE)
return false;
// listen for enemy noises
if (IsNoiseHeard() && gpGlobals->time - m_noiseCheckTimestamp >= 0.25f)
{
m_noiseCheckTimestamp = gpGlobals->time;
Vector toNoise = m_noisePosition - pev->origin;
float noiseDist = toNoise.Length();
float const oneStoreyHeight = 120.0f;
if (abs(int64(toNoise.z)) > oneStoreyHeight)
{
PathCost pc(this);
float travelDistToNoise = NavAreaTravelDistance(m_lastKnownArea, m_noiseArea, pc);
m_isNoiseTravelRangeChecked = true;
const float tooFar = 1500.0f;
if (travelDistToNoise < 0.0f || travelDistToNoise > tooFar)
return false;
if (noiseDist <= travelDistToNoise)
noiseDist = travelDistToNoise;
}
// if we are hiding, only react to noises very nearby, depending on how aggressive we are
if (IsAtHidingSpot() && noiseDist > 100.0f + 400.0f * GetProfile()->GetAggression())
return false;
// chance of investigating is inversely proportional to distance
const float maxNoiseDist = 2000.0f;
float chance = (1.0f - (noiseDist / maxNoiseDist));
// modify chance by number of friends remaining
// if we have lots of friends, presumably one of them is closer and will check it out
if (GetFriendsRemaining() >= 3)
{
float friendFactor = 0.05f * GetFriendsRemaining();
if (friendFactor > 0.5f)
friendFactor = 0.5f;
chance -= friendFactor;
}
if (RANDOM_FLOAT(0.0f, 1.0f) <= chance)
{
if (retNoiseDist)
*retNoiseDist = noiseDist;
return true;
}
}
return false;
}
// Return true if we hear nearby threatening enemy gunfire within given range
// -1 == infinite range
bool CHLBot::CanHearNearbyEnemyGunfire(float range) const
{
// only attend to noise if it just happened
if (gpGlobals->time - m_noiseTimestamp > 0.5f)
return false;
// gunfire is high priority
if (m_noisePriority < PRIORITY_HIGH)
return false;
// check noise range
if (range > 0.0f && (pev->origin - m_noisePosition).IsLengthGreaterThan(range))
return false;
// if we dont have line of sight, it's not threatening (cant get shot)
if (!CanSeeNoisePosition())
return false;
if (IsAttacking() && m_enemy != NULL)
{
// gunfire is only threatening if it is closer than our current enemy
float gunfireDistSq = (m_noisePosition - pev->origin).LengthSquared();
float enemyDistSq = (m_enemy->pev->origin - pev->origin).LengthSquared();
const float muchCloserSq = 100.0f * 100.0f;
if (gunfireDistSq > enemyDistSq - muchCloserSq)
return false;
}
return true;
}
// Return true if we directly see where we think the noise came from
// NOTE: Dont check FOV, since this is used to determine if we should turn our head to look at the noise
// NOTE: Dont use IsVisible(), because smoke shouldnt cause us to not look toward noises
bool CHLBot::CanSeeNoisePosition() const
{
TraceResult result;
UTIL_TraceLine(GetEyePosition(), m_noisePosition + Vector(0, 0, HalfHumanHeight), ignore_monsters, ignore_glass, ENT(pev), &result);
if (result.flFraction == 1.0f)
{
// we can see the source of the noise
return true;
}
return false;
}
// Return true if we decided to look towards the most recent noise source
// Assumes m_noisePosition is valid.
bool CHLBot::UpdateLookAtNoise()
{
// make sure a noise exists
if (!IsNoiseHeard() || gpGlobals->time - m_noiseTimestamp > 0.5f)
return false;
bool nearbyThreat = false;
float const recentThreatTime = 5.0f;
if (GetTimeSinceLastSawEnemy() < recentThreatTime)
{
const float closeThreatRange = 750.0f;
if ((pev->origin - m_lastEnemyPosition).IsLengthLessThan(closeThreatRange))
{
nearbyThreat = true;
}
}
Vector spot;
// if we have clear line of sight to noise position, look directly at it
if ((!IsAtHidingSpot() && nearbyThreat) || CanSeeNoisePosition())
{
// TODO: adjust noise Z to keep consistent with current height while fighting
spot = m_noisePosition + Vector(0, 0, HalfHumanHeight);
}
else
{
// line of sight is blocked, bend it
if (m_approachPointCount == 0)
return false;
int nearIdx = -1;
float nearRangeSq = 9.9999998e10f;
for (int i = 0; i < m_approachPointCount; ++i)
{
float distanceSq = (m_approachPoint[i] - m_noisePosition).LengthSquared();
if (distanceSq < nearRangeSq)
{
nearRangeSq = distanceSq;
nearIdx = i;
}
}
if (nearIdx != -1)
{
// line of sight is blocked, bend it
if (BendLineOfSight(&pev->origin, &m_approachPoint[nearIdx], &spot) == false)
return false;
spot.z += HalfHumanHeight;
}
else
{
// prior bend failed
return false;
}
}
// it's always important to look at enemy noises, because they come from ... enemies!
PriorityType pri = (GetNoisePriority() == PRIORITY_HIGH) ? PRIORITY_HIGH : PRIORITY_MEDIUM;
// look longer if we're hiding
if (IsAtHidingSpot())
{
// if there is only one enemy left, look for a long time
if (GetEnemiesRemaining() == 1)
{
SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(5.0f, 15.0f), true);
}
else
{
SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(2.0f, 5.0f), true);
}
}
else
{
SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(1.0f, 2.0f), true);
}
return true;
}