csgo-2018-source/game/server/sound.cpp
2021-07-24 21:11:47 -07:00

333 lines
8.8 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Entities relating to in-level sound effects.
//
// env_speaker: used for public address announcements over loudspeakers.
// This tries not to drown out talking NPCs.
//
// env_soundscape: controls what sound script an area uses.
//
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "mathlib/mathlib.h"
#include "ai_speech.h"
#include "stringregistry.h"
#include "gamerules.h"
#include "game.h"
#include <ctype.h>
#include "entitylist.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ndebugoverlay.h"
#include "soundscape.h"
#include "igamesystem.h"
#include "keyvalues.h"
#include "filesystem.h"
#include "ambientgeneric.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// =================== ROOM SOUND FX ==========================================
// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ======================================
int fSentencesInit = false;
// ===================== SENTENCE GROUPS, MAIN ROUTINES ========================
// given sentence group index, play random sentence for given entity.
// returns sentenceIndex - which sentence was picked
// Ipick is only needed if you plan on stopping the sound before playback is done (see SENTENCEG_Stop).
// sentenceIndex can be used to find the name/length of the sentence
int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg,
float volume, soundlevel_t soundlevel, int flags, int pitch)
{
char name[64];
int ipick;
if (!fSentencesInit)
return -1;
name[0] = 0;
ipick = engine->SentenceGroupPick( isentenceg, name, sizeof( name ) );
if (ipick > 0 && name)
{
int sentenceIndex = SENTENCEG_Lookup( name );
CPASAttenuationFilter filter( GetContainingEntity( entity ), soundlevel );
CBaseEntity::EmitSentenceByIndex( filter, ENTINDEX(entity), CHAN_VOICE, sentenceIndex, volume, soundlevel, flags, pitch );
return sentenceIndex;
}
return -1;
}
//-----------------------------------------------------------------------------
// Picks a sentence, but doesn't play it
//-----------------------------------------------------------------------------
int SENTENCEG_PickRndSz(const char *szgroupname)
{
char name[64];
int ipick;
int isentenceg;
if (!fSentencesInit)
return -1;
name[0] = 0;
isentenceg = engine->SentenceGroupIndexFromName(szgroupname);
if (isentenceg < 0)
{
Warning( "No such sentence group %s\n", szgroupname );
return -1;
}
ipick = engine->SentenceGroupPick(isentenceg, name, sizeof( name ));
if (ipick >= 0 && name[0])
{
return SENTENCEG_Lookup( name );
}
return -1;
}
//-----------------------------------------------------------------------------
// Plays a sentence by sentence index
//-----------------------------------------------------------------------------
void SENTENCEG_PlaySentenceIndex( edict_t *entity, int iSentenceIndex, float volume, soundlevel_t soundlevel, int flags, int pitch )
{
if ( iSentenceIndex >= 0 )
{
CPASAttenuationFilter filter( GetContainingEntity( entity ), soundlevel );
CBaseEntity::EmitSentenceByIndex( filter, ENTINDEX(entity), CHAN_VOICE, iSentenceIndex, volume, soundlevel, flags, pitch );
}
}
int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname,
float volume, soundlevel_t soundlevel, int flags, int pitch)
{
char name[64];
int ipick;
int isentenceg;
if (!fSentencesInit)
return -1;
name[0] = 0;
isentenceg = engine->SentenceGroupIndexFromName(szgroupname);
if (isentenceg < 0)
{
Warning( "No such sentence group %s\n", szgroupname );
return -1;
}
ipick = engine->SentenceGroupPick(isentenceg, name, sizeof( name ));
if (ipick >= 0 && name[0])
{
int sentenceIndex = SENTENCEG_Lookup( name );
CPASAttenuationFilter filter( GetContainingEntity( entity ), soundlevel );
CBaseEntity::EmitSentenceByIndex( filter, ENTINDEX(entity), CHAN_VOICE, sentenceIndex, volume, soundlevel, flags, pitch );
return sentenceIndex;
}
return -1;
}
// play sentences in sequential order from sentence group. Reset after last sentence.
int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname,
float volume, soundlevel_t soundlevel, int flags, int pitch, int ipick, int freset)
{
char name[64];
int ipicknext;
int isentenceg;
if (!fSentencesInit)
return -1;
name[0] = 0;
isentenceg = engine->SentenceGroupIndexFromName(szgroupname);
if (isentenceg < 0)
return -1;
ipicknext = engine->SentenceGroupPickSequential(isentenceg, name, sizeof( name ), ipick, freset);
if (ipicknext >= 0 && name[0])
{
int sentenceIndex = SENTENCEG_Lookup( name );
CPASAttenuationFilter filter( GetContainingEntity( entity ), soundlevel );
CBaseEntity::EmitSentenceByIndex( filter, ENTINDEX(entity), CHAN_VOICE, sentenceIndex, volume, soundlevel, flags, pitch );
return sentenceIndex;
}
return -1;
}
#if 0
// for this entity, for the given sentence within the sentence group, stop
// the sentence.
void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick)
{
char buffer[64];
char sznum[8];
if (!fSentencesInit)
return;
if (isentenceg < 0 || ipick < 0)
return;
Q_snprintf(buffer,sizeof(buffer),"!%s%d", engine->SentenceGroupNameFromIndex( isentenceg ), ipick );
UTIL_StopSound(entity, CHAN_VOICE, buffer);
}
#endif
// open sentences.txt, scan for groups, build rgsentenceg
// Should be called from world spawn, only works on the
// first call and is ignored subsequently.
void SENTENCEG_Init()
{
if (fSentencesInit)
return;
engine->PrecacheSentenceFile( "scripts/sentences.txt" );
fSentencesInit = true;
}
// convert sentence (sample) name to !sentencenum, return !sentencenum
int SENTENCEG_Lookup(const char *sample)
{
return engine->SentenceIndexFromName( sample + 1 );
}
int SENTENCEG_GetIndex(const char *szrootname)
{
return engine->SentenceGroupIndexFromName( szrootname );
}
void UTIL_RestartAmbientSounds( void )
{
CAmbientGeneric *pAmbient = NULL;
while ( ( pAmbient = (CAmbientGeneric*) gEntList.FindEntityByClassname( pAmbient, "ambient_generic" ) ) != NULL )
{
if (pAmbient->m_fActive )
{
if ( strstr( STRING( pAmbient->m_iszSound ), "mp3" ) )
{
pAmbient->SendSound( SND_CHANGE_VOL ); // fake a change, so we don't create 2 sounds
}
pAmbient->SendSound( SND_CHANGE_VOL ); // fake a change, so we don't create 2 sounds
}
}
}
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename
void UTIL_EmitSoundSuit(edict_t *entity, const char *sample)
{
float fvol;
int pitch = PITCH_NORM;
fvol = suitvolume.GetFloat();
if (random->RandomInt(0,1))
pitch = random->RandomInt(0,6) + 98;
// If friendlies are talking, reduce the volume of the suit
if ( !g_AIFriendliesTalkSemaphore.IsAvailable( GetContainingEntity( entity ) ) )
{
fvol *= 0.3;
}
if (fvol > 0.05)
{
CPASAttenuationFilter filter( GetContainingEntity( entity ) );
filter.MakeReliable();
EmitSound_t ep;
ep.m_nChannel = CHAN_STATIC;
ep.m_pSoundName = sample;
ep.m_flVolume = fvol;
ep.m_SoundLevel = SNDLVL_NORM;
ep.m_nPitch = pitch;
CBaseEntity::EmitSound( filter, ENTINDEX(entity), ep );
}
}
// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker
int UTIL_EmitGroupIDSuit(edict_t *entity, int isentenceg)
{
float fvol;
int pitch = PITCH_NORM;
int sentenceIndex = -1;
fvol = suitvolume.GetFloat();
if (random->RandomInt(0,1))
pitch = random->RandomInt(0,6) + 98;
// If friendlies are talking, reduce the volume of the suit
if ( !g_AIFriendliesTalkSemaphore.IsAvailable( GetContainingEntity( entity ) ) )
{
fvol *= 0.3;
}
if (fvol > 0.05)
sentenceIndex = SENTENCEG_PlayRndI(entity, isentenceg, fvol, SNDLVL_NORM, 0, pitch);
return sentenceIndex;
}
// play a sentence, randomly selected from the passed in groupname
int UTIL_EmitGroupnameSuit(edict_t *entity, const char *groupname)
{
float fvol;
int pitch = PITCH_NORM;
int sentenceIndex = -1;
fvol = suitvolume.GetFloat();
if (random->RandomInt(0,1))
pitch = random->RandomInt(0,6) + 98;
// If friendlies are talking, reduce the volume of the suit
if ( !g_AIFriendliesTalkSemaphore.IsAvailable( GetContainingEntity( entity ) ) )
{
fvol *= 0.3;
}
if (fvol > 0.05)
sentenceIndex = SENTENCEG_PlayRndSz(entity, groupname, fvol, SNDLVL_NORM, 0, pitch);
return sentenceIndex;
}
// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ========================
//
// Used to detect the texture the player is standing on, map the
// texture name to a material type. Play footstep sound based
// on material type.
char TEXTURETYPE_Find( trace_t *ptr )
{
const surfacedata_t *psurfaceData = physprops->GetSurfaceData( ptr->surface.surfaceProps );
return psurfaceData->game.material;
}