Bot hearing started

This commit is contained in:
RGreenlees 2024-04-18 08:24:16 +01:00
parent d1da0553e8
commit 3073f7f60b
17 changed files with 319 additions and 19 deletions

View file

@ -25,6 +25,10 @@
#include "gamerules.h"
#include "../mod/AvHSpecials.h"
#ifdef AVH_SERVER
#include "../mod/AvHAIPlayerManager.h"
#endif
static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize );
@ -1429,7 +1433,9 @@ void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volu
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
}
else
{
EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch);
}
}
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename

View file

@ -804,6 +804,8 @@ typedef struct AVH_AI_PLAYER
float ServerUpdateDelta = 0.0f; // How long since we last called RunPlayerMove
float LastServerUpdateTime = 0.0f; // When we last called RunPlayerMove
float HearingThreshold = 0.0f; // How loud does a sound need to be before the bot detects it? This is set when hearing a sound so that louder sounds drown out quieter ones, and decrements quickly
} AvHAIPlayer;

View file

@ -1895,23 +1895,19 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot)
{
if (IsPlayerMarine(pBot->Edict)) { return; }
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY))
{
BotEvolveUpgrade(pBot, pBot->CurrentFloorPosition, ALIEN_EVOLUTION_TEN);
return;
}
pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot);
if (pBot->CurrentEnemy < 0)
if (pBot->CurrentEnemy >= 0)
{
MoveTo(pBot, AITAC_GetTeamStartingLocation(AIMGR_GetEnemyTeam(pBot->Player->GetTeam())), MOVESTYLE_NORMAL);
}
else
{
AlienCombatThink(pBot);
if (IsPlayerMarine(pBot->Edict))
{
MarineCombatThink(pBot);
}
else
{
AlienCombatThink(pBot);
}
}
}
@ -2005,11 +2001,35 @@ void UpdateAIPlayerDMRole(AvHAIPlayer* pBot)
}
void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy)
{
int heardIndex = ENTINDEX(HeardEnemy) - 1;
if (heardIndex < 0 || heardIndex >= 32 || HeardEnemy->v.team == pBot->Edict->v.team) { return; }
pBot->TrackedEnemies[heardIndex].LastSeenTime = gpGlobals->time;
// If the bot can't see the enemy (bCurrentlyVisible is false) then set the last seen location to a random point in the vicinity so the bot doesn't immediately know where they are
if (pBot->TrackedEnemies[heardIndex].bIsVisible || vDist2DSq(pBot->TrackedEnemies[heardIndex].EnemyEdict->v.origin, pBot->Edict->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
{
pBot->TrackedEnemies[heardIndex].LastSeenLocation = HeardEnemy->v.origin;
}
else
{
// The further the enemy is, the more inaccurate the bot's guess will be where they are
pBot->TrackedEnemies[heardIndex].LastSeenLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(SKULK_BASE_NAV_PROFILE), HeardEnemy->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
}
pBot->TrackedEnemies[heardIndex].bIsAwareOfPlayer = true;
}
void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor)
{
int aggressorIndex = ENTINDEX(aggressor) - 1;
if (aggressorIndex > -1 && aggressor->v.team != pBot->Edict->v.team && IsPlayerActiveInGame(aggressor))
if (aggressorIndex < 0 || aggressorIndex >= 32) { return; }
if (aggressor->v.team != pBot->Edict->v.team && IsPlayerActiveInGame(aggressor))
{
pBot->TrackedEnemies[aggressorIndex].LastSeenTime = gpGlobals->time;

View file

@ -153,6 +153,7 @@ void UpdateAIPlayerDMRole(AvHAIPlayer* pBot);
bool ShouldAIPlayerTakeCommand(AvHAIPlayer* pBot);
void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor);
void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy);
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);

View file

@ -8,6 +8,7 @@
#include "AvHAIHelper.h"
#include "AvHAICommander.h"
#include "AvHAIPlayerUtil.h"
#include "AvHAISoundQueue.h"
#include "AvHGamerules.h"
#include "../dlls/client.h"
#include <time.h>
@ -592,6 +593,8 @@ void AIMGR_UpdateAIPlayers()
AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f);
}
}
AIMGR_ProcessPendingSounds(FrameDelta);
}
int NumCommanders = AIMGR_GetNumAICommanders();
@ -709,7 +712,7 @@ AvHTeamNumber AIMGR_GetTeamANumber()
AvHTeamNumber AIMGR_GetTeamBNumber()
{
return GetGameRules()->GetTeamANumber();
return GetGameRules()->GetTeamBNumber();
}
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team)
@ -1450,4 +1453,92 @@ bool AIMGR_IsMatchPracticallyOver()
}
return false;
}
}
void AIMGR_ProcessPendingSounds(float FrameDelta)
{
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
{
it->HearingThreshold -= FrameDelta;
it->HearingThreshold = clampf(it->HearingThreshold, 0.0f, 1.0f);
}
AvHAISound Sound = AISND_PopSound();
AvHTeamNumber TeamANumber = AIMGR_GetTeamANumber();
AvHTeamNumber TeamBNumber = AIMGR_GetTeamBNumber();
while (Sound.SoundType != AI_SOUND_NONE)
{
edict_t* EmittingEntity = INDEXENT(Sound.EntIndex);
//string SoundType = "Unknown";
float MaxDist = 0.0f;
switch (Sound.SoundType)
{
case AI_SOUND_FOOTSTEP:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Footstep";
break;
case AI_SOUND_SHOOT:
MaxDist = UTIL_MetresToGoldSrcUnits(30.0f);
//SoundType = "Shoot";
break;
case AI_SOUND_VOICELINE:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Voiceline";
break;
case AI_SOUND_LANDING:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Landing";
break;
case AI_SOUND_OTHER:
default:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Other";
break;
}
MaxDist = sqrf(MaxDist);
if (!FNullEnt(EmittingEntity) && EmittingEntity->v.team != 0 && IsEdictPlayer(EmittingEntity) && IsPlayerActiveInGame(EmittingEntity))
{
AvHTeamNumber EmitterTeam = (AvHTeamNumber)EmittingEntity->v.team;
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
{
AvHTeamNumber ThisTeam = it->Player->GetTeam();
float Volume = Sound.Volume;
float HearingThresholdScalar = (ThisTeam != EmitterTeam || EmittingEntity == it->Edict) ? 1.0f : 0.5f;
if (EmitterTeam != ThisTeam)
{
float DistFromSound = vDist3DSq(Sound.SoundLocation, it->Edict->v.origin);
if (DistFromSound > MaxDist) { continue; }
Volume = Sound.Volume - (Sound.Volume * clampf((DistFromSound / MaxDist), 0.0f, 1.0f));
}
Volume = Volume * HearingThresholdScalar;
if (Volume > it->HearingThreshold)
{
it->HearingThreshold = Volume;
if (EmitterTeam != ThisTeam)
{
//char msg[64];
//sprintf(msg, "%s Sound: %f\n", SoundType.c_str(), Volume);
//UTIL_SayText(msg, CBaseEntity::Instance(INDEXENT(1)));
AIPlayerHearEnemy(&(*it), EmittingEntity);
}
}
}
}
Sound = AISND_PopSound();
}
}

View file

@ -126,4 +126,6 @@ bool AIMGR_HasMatchEnded();
bool AIMGR_IsMatchPracticallyOver();
void AIMGR_ProcessPendingSounds(float FrameDelta);
#endif

View file

@ -0,0 +1,35 @@
#include "AvHAISoundQueue.h"
#include "AvHAIPlayerManager.h"
std::vector<AvHAISound> PendingSounds;
void AISND_RegisterNewSound(int EntIndex, float* NewLocation, AvHAISoundType NewSoundType, float Volume)
{
if (!AIMGR_IsBotEnabled() || Volume < 0.01f) { return; }
AvHAISound NewSound;
NewSound.EntIndex = EntIndex;
NewSound.SoundLocation[0] = NewLocation[0];
NewSound.SoundLocation[1] = NewLocation[1];
NewSound.SoundLocation[2] = NewLocation[2];
NewSound.Volume = Volume;
NewSound.SoundType = NewSoundType;
PendingSounds.push_back(NewSound);
}
AvHAISound AISND_PopSound()
{
if (PendingSounds.size() == 0) { return AvHAISound(); }
AvHAISound Result = PendingSounds.back();
PendingSounds.pop_back();
return Result;
}
void AISND_ClearSounds()
{
PendingSounds.clear();
}

View file

@ -0,0 +1,35 @@
#ifndef AVH_AI_SOUND_QUEUE
#define AVH_AI_SOUND_QUEUE
#include <vector>
// Sound types affect how audible they are to bots, how easy it is to pinpoint the location of the sound etc
typedef enum _AVHAISOUNDTYPE
{
AI_SOUND_NONE = 0, // Blank sound
AI_SOUND_FOOTSTEP, // Footstep sound
AI_SOUND_LANDING, // Landing sound, THUD
AI_SOUND_SHOOT, // Pew pew
AI_SOUND_VOICELINE, // Player played a voice line (e.g. "Need a medpack")
AI_SOUND_OTHER // Miscellaneous sound e.g. building
} AvHAISoundType;
typedef struct _AVHAISOUND
{
int EntIndex = 0;
float SoundLocation[3] = {0.0f, 0.0f, 0.0f};
float Volume = 1.0f;
AvHAISoundType SoundType = AI_SOUND_NONE;
} AvHAISound;
void AISND_RegisterNewSound(int EntIndex, float* NewLocation, AvHAISoundType NewSoundType, float Volume = 1.0f);
AvHAISound AISND_PopSound();
void AISND_ClearSounds();
#endif

View file

@ -86,7 +86,7 @@ extern int g_runfuncs;
#ifdef AVH_SERVER
#include "AvHServerUtil.h"
#include "AvHGamerules.h"
#include "AvHAISoundQueue.h"
extern int gWelderConstEventID;
#endif
@ -1040,11 +1040,32 @@ void AvHBasePlayerWeapon::PrimaryAttack(bool fireOnAttackUp)
this->PlaybackEvent(this->mEvent, this->GetShootAnimation());
this->SetAnimationAndSound();
// If player is too close to a wall, don't actually fire the projectile
if(this->GetIsGunPositionValid())
{
this->FireProjectiles();
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->m_pPlayer->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->m_pPlayer->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
}
else
{

View file

@ -64,6 +64,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@ -221,6 +222,8 @@ void AvHBite::FireProjectiles(void)
{
theSoundToPlay = kBiteKillSound;
}
AISND_RegisterNewSound(this->m_pPlayer->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM);
}

View file

@ -70,6 +70,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@ -235,6 +236,8 @@ void AvHClaws::FireProjectiles(void)
float theForceScalar = theDamage*.2f;
CBaseEntity* theAttacker = this->m_pPlayer;
AvHSUExplosiveForce(pHurt->pev->origin, 100, theForceScalar, theAttacker, theAttacker);
AISND_RegisterNewSound(pHurt->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
// Played in event now
//EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM, 0, 100 + theAdrenalineFactor*30 + RANDOM_LONG(-3,3) );

View file

@ -119,6 +119,7 @@
#include "AvHHulls.h"
#include "AvHServerVariables.h"
//extern AvHKnife gKnife;
//extern AvHMachineGun gMachineGun;
//extern AvHPistol gPistol;

View file

@ -146,7 +146,10 @@
#include "AvHSiegeTurret.h"
#include "AvHHulls.h"
#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h"
#include "AvHAISoundQueue.h"
#endif
//LINK_ENTITY_TO_CLASS(kwMine, AvHMine);
//LINK_ENTITY_TO_CLASS(kwDeployedTurret, AvHDeployedTurret);
@ -1286,6 +1289,10 @@ void AvHPhaseGate::TeleportUse(CBaseEntity *pActivator, CBaseEntity *pCaller, US
this->SetTimeOfLastDeparture(gpGlobals->time);
AvHSUPlayPhaseInEffect(theFlags, this, thePlayer);
#ifdef AVH_SERVER
AISND_RegisterNewSound(thePlayer->entindex(), theOrigin, AI_SOUND_OTHER, 1.0f);
#endif
// AvHSUKillPlayersTouchingPlayer(thePlayer, this->pev);
AvHSUPushbackPlayersTouchingPlayer(thePlayer, this->pev);
KillBuildablesTouchingPlayer(thePlayer, this->pev);
@ -1978,11 +1985,13 @@ void AvHCommandStation::CommandUse( CBaseEntity* pActivator, CBaseEntity* pCalle
GetGameRules()->MarkDramaticEvent(kCCNewCommanderPriority, thePlayer, this);
#ifdef AVH_SERVER
// A human used the comm chair, let the AI know to keep away
if (!(thePlayer->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(theStationTeamNumber, gpGlobals->time + 20.0f);
}
#endif
}
else
{

View file

@ -255,7 +255,10 @@
#include "AvHNetworkMessages.h"
#include "AvHNexusServer.h"
#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h"
#include "AvHAISoundQueue.h"
#endif
std::string GetLogStringForPlayer( edict_t *pEntity );
@ -2309,6 +2312,26 @@ void AvHPlayer::StartLeap()
// Make sure player has leap
if(this->pev->iuser3 == AVH_USER3_ALIEN_PLAYER1)
{
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
this->mTimeLeapEnd = gpGlobals->time + kLeapDuration;
}
}
@ -4972,6 +4995,11 @@ bool AvHPlayer::PlaySaying(AvHMessageID inMessageID)
//int pitch = 95;// + RANDOM_LONG(0,29);
//EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, theSaying, 1, ATTN_NORM, 0, pitch);
gSoundListManager.PlaySoundInList(theSoundList, this, CHAN_VOICE, 1.0f);
#ifdef AVH_SERVER
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_VOICELINE, 1.0f);
#endif
thePlayedSaying = true;
}
@ -7033,6 +7061,28 @@ void AvHPlayer::InternalMovementThink()
}
}
else {
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
EMIT_SOUND_DYN(ENT(this->pev), CHAN_WEAPON, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, 100);
this->mTimeOfLastMovementSound = gpGlobals->time;
}
@ -9176,7 +9226,8 @@ int AvHPlayer::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa
{
CBasePlayer* inAttackingPlayer = dynamic_cast<CBasePlayer*>(CBaseEntity::Instance(ENT(pevAttacker)));
if (inAttackingPlayer)
#ifdef AVH_SERVER
if (inAttackingPlayer && AIMGR_IsBotEnabled())
{
AvHAIPlayer* VictimBot = AIMGR_GetBotRefFromPlayer(this);
@ -9185,7 +9236,7 @@ int AvHPlayer::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa
AIPlayerTakeDamage(VictimBot, flDamage, inAttackingPlayer->edict());
}
}
#endif
const char* inWeaponName = STRING(pevInflictor->classname);
if(inAttackingPlayer && inWeaponName)
{

View file

@ -123,6 +123,8 @@
#include "AvHHulls.h"
#include "AnimationUtil.h"
#include "AvHAISoundQueue.h"
int NS_PointContents(const hull_t *hull, int num, float p[3]);
float NS_TraceLineAgainstEntity(int inEntityIndex, float inTime, const float inRayOrigin[3], const float inRayDirection[3]);
@ -573,6 +575,8 @@ void AvHSUPlayRandomConstructionEffect(AvHPlayer* inPlayer, CBaseEntity* inConst
{
gSoundListManager.PlaySoundInList(kMarineConstructionSoundList, inConstructee, CHAN_BODY, theVolume);
AISND_RegisterNewSound(inPlayer->entindex(), inPlayer->pev->origin, AI_SOUND_OTHER, theVolume);
// Play sparks every other time
if(RANDOM_LONG(0, 1) == 1)
{

View file

@ -67,6 +67,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@ -254,6 +255,8 @@ void AvHSwipe::FireProjectiles(void)
ASSERT(theSoundToPlay);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM);
AISND_RegisterNewSound(pHurt->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
}
}

View file

@ -107,6 +107,9 @@
#include "../mod/CollisionUtil.h"
#include "../engine/studio.h"
#ifdef AVH_SERVER
#include "../mod/AvHAISoundQueue.h"
#endif
//#ifdef AVH_SERVER
#include "../engine/edict.h"
@ -2008,6 +2011,9 @@ void NS_PlayStepSound(int inMaterialType, int inSoundNumber, float inVolume)
// Play it at the specified volume
PM_NSPlaySound(CHAN_BODY, theFinalName, inVolume, theNorm, 0, PITCH_NORM);
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_FOOTSTEP, inVolume);
#endif
}
else
{
@ -4613,6 +4619,10 @@ bool PM_FlapMove()
theVolumeScalar = min(max(theVolumeScalar, 0.0f), 1.0f);
PM_NSPlaySound(CHAN_BODY, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, PITCH_NORM);
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_FOOTSTEP, theVolumeScalar);
#endif
}
pmove->oldbuttons |= IN_JUMP; // don't jump again until released
@ -5700,6 +5710,9 @@ void PM_CheckFalling( void )
//break;
//case 1:
PM_NSPlaySound( CHAN_VOICE, theFallPainSound, theFallPainVolume, ATTN_NORM, 0, PITCH_NORM );
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_LANDING, theFallPainVolume);
#endif
// break;
//}
fvol = 1.0;