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.
346 lines
9.2 KiB
346 lines
9.2 KiB
//========= 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 |
|
} |
|
} |
|
#ifdef INFESTED_DLL |
|
pAmbient = NULL; |
|
while ( ( pAmbient = (CAmbientGeneric*) gEntList.FindEntityByClassname( pAmbient, "asw_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 |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
|
|
// 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; |
|
}
|
|
|