You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.1 KiB
231 lines
6.1 KiB
4 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
// Author: Michael S. Booth (mike@turtlerockstudios.com), 2003
|
||
|
|
||
|
#include "cbase.h"
|
||
|
#include "cs_bot.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------
|
||
|
bool CCSBot::IsNoiseHeard( void ) const
|
||
|
{
|
||
|
if (m_noiseTimestamp <= 0.0f)
|
||
|
return false;
|
||
|
|
||
|
// primitive reaction time simulation - cannot "hear" noise until reaction time has elapsed
|
||
|
if (gpGlobals->curtime - m_noiseTimestamp >= GetProfile()->GetReactionTime())
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------
|
||
|
/**
|
||
|
* Listen for enemy noises, and determine if we should react to them.
|
||
|
* Returns true if heard a noise and should move to investigate.
|
||
|
*/
|
||
|
bool CCSBot::HeardInterestingNoise( void )
|
||
|
{
|
||
|
if (IsBlind())
|
||
|
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())
|
||
|
{
|
||
|
// if we are hiding, only react to noises very nearby, depending on how aggressive we are
|
||
|
if (IsAtHidingSpot() && GetNoiseRange() > 100.0f + 400.0f * GetProfile()->GetAggression())
|
||
|
return false;
|
||
|
|
||
|
// chance of investigating is inversely proportional to distance
|
||
|
const float maxNoiseDist = 3000.0f;
|
||
|
float chance = 100.0f * (1.0f - (GetNoiseRange()/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 = 5.0f * GetFriendsRemaining();
|
||
|
if (friendFactor > 50.0f)
|
||
|
friendFactor = 50.0f;
|
||
|
|
||
|
chance -= friendFactor;
|
||
|
}
|
||
|
|
||
|
if (RandomFloat( 0.0f, 100.0f ) <= chance)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------------------------------------------
|
||
|
/**
|
||
|
* Return true if we hear nearby threatening enemy gunfire within given range
|
||
|
* -1 == infinite range
|
||
|
*/
|
||
|
bool CCSBot::CanHearNearbyEnemyGunfire( float range ) const
|
||
|
{
|
||
|
Vector myOrigin = GetCentroid( this );
|
||
|
|
||
|
// only attend to noise if it just happened
|
||
|
if (gpGlobals->curtime - m_noiseTimestamp > 0.5f)
|
||
|
return false;
|
||
|
|
||
|
// gunfire is high priority
|
||
|
if (m_noisePriority < PRIORITY_HIGH)
|
||
|
return false;
|
||
|
|
||
|
// check noise range
|
||
|
if (range > 0.0f && (myOrigin - 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 && GetTimeSinceLastSawEnemy() < 1.0f)
|
||
|
{
|
||
|
// gunfire is only threatening if it is closer than our current enemy
|
||
|
float gunfireDistSq = (m_noisePosition - myOrigin).LengthSqr();
|
||
|
float enemyDistSq = (GetCentroid( m_enemy ) - myOrigin).LengthSqr();
|
||
|
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 CCSBot::CanSeeNoisePosition( void ) const
|
||
|
{
|
||
|
trace_t result;
|
||
|
CTraceFilterNoNPCsOrPlayer traceFilter( this, COLLISION_GROUP_NONE );
|
||
|
UTIL_TraceLine( EyePositionConst(), m_noisePosition + Vector( 0, 0, HalfHumanHeight ), MASK_VISIBLE_AND_NPCS, &traceFilter, &result );
|
||
|
if (result.fraction == 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 CCSBot::UpdateLookAtNoise( void )
|
||
|
{
|
||
|
// make sure a noise exists
|
||
|
if (!IsNoiseHeard())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Vector spot;
|
||
|
|
||
|
// if we have clear line of sight to noise position, look directly at it
|
||
|
if (CanSeeNoisePosition())
|
||
|
{
|
||
|
/// @todo adjust noise Z to keep consistent with current height while fighting
|
||
|
spot = m_noisePosition + Vector( 0, 0, HalfHumanHeight );
|
||
|
|
||
|
// since we can see the noise spot, forget about it
|
||
|
ForgetNoise();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// line of sight is blocked, bend it
|
||
|
|
||
|
// the bending algorithm is very expensive, throttle how often it is done
|
||
|
if (m_noiseBendTimer.IsElapsed())
|
||
|
{
|
||
|
const float noiseBendLOSInterval = RandomFloat( 0.2f, 0.3f );
|
||
|
m_noiseBendTimer.Start( noiseBendLOSInterval );
|
||
|
|
||
|
// line of sight is blocked, bend it
|
||
|
if (BendLineOfSight( EyePosition(), m_noisePosition, &spot ) == false)
|
||
|
{
|
||
|
m_bendNoisePositionValid = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
m_bentNoisePosition = spot;
|
||
|
m_bendNoisePositionValid = true;
|
||
|
}
|
||
|
else if (m_bendNoisePositionValid)
|
||
|
{
|
||
|
// use result of prior bend computation
|
||
|
spot = m_bentNoisePosition;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// prior bend failed
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// it's always important to look at enemy noises, because they come from ... enemies!
|
||
|
PriorityType pri = PRIORITY_HIGH;
|
||
|
|
||
|
// 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, RandomFloat( 5.0f, 15.0f ), true );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLookAt( "Noise", spot, pri, RandomFloat( 3.0f, 5.0f ), true );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float closeRange = 500.0f;
|
||
|
if (GetNoiseRange() < closeRange)
|
||
|
{
|
||
|
// look at nearby enemy noises for a longer time
|
||
|
SetLookAt( "Noise", spot, pri, RandomFloat( 3.0f, 5.0f ), true );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLookAt( "Noise", spot, pri, RandomFloat( 1.0f, 2.0f ), true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|