diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/shared/SoundEmitterSystem.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/shared/SoundEmitterSystem.cpp')
| -rw-r--r-- | mp/src/game/shared/SoundEmitterSystem.cpp | 3048 |
1 files changed, 1524 insertions, 1524 deletions
diff --git a/mp/src/game/shared/SoundEmitterSystem.cpp b/mp/src/game/shared/SoundEmitterSystem.cpp index 2b665654..6d27fde9 100644 --- a/mp/src/game/shared/SoundEmitterSystem.cpp +++ b/mp/src/game/shared/SoundEmitterSystem.cpp @@ -1,1524 +1,1524 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "cbase.h"
-#include <ctype.h>
-#include <KeyValues.h>
-#include "engine/IEngineSound.h"
-#include "SoundEmitterSystem/isoundemittersystembase.h"
-#include "igamesystem.h"
-#include "soundchars.h"
-#include "filesystem.h"
-#include "tier0/vprof.h"
-#include "checksum_crc.h"
-#include "tier0/icommandline.h"
-
-#if defined( TF_CLIENT_DLL ) || defined( TF_DLL )
-#include "tf_shareddefs.h"
-#include "tf_classdata.h"
-#endif
-
-// NVNT haptic utils
-#include "haptics/haptic_utils.h"
-
-#ifndef CLIENT_DLL
-#include "envmicrophone.h"
-#include "sceneentity.h"
-#else
-#include <vgui_controls/Controls.h>
-#include <vgui/IVGui.h>
-#include "hud_closecaption.h"
-#define CRecipientFilter C_RecipientFilter
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-static ConVar sv_soundemitter_trace( "sv_soundemitter_trace", "0", FCVAR_REPLICATED, "Show all EmitSound calls including their symbolic name and the actual wave file they resolved to\n" );
-#ifdef STAGING_ONLY
-static ConVar sv_snd_filter( "sv_snd_filter", "", FCVAR_REPLICATED, "Filters out all sounds not containing the specified string before being emitted\n" );
-#endif // STAGING_ONLY
-
-extern ISoundEmitterSystemBase *soundemitterbase;
-static ConVar *g_pClosecaption = NULL;
-
-#ifdef _XBOX
-int LookupStringFromCloseCaptionToken( char const *token );
-const wchar_t *GetStringForIndex( int index );
-#endif
-static bool g_bPermitDirectSoundPrecache = false;
-
-#if !defined( CLIENT_DLL )
-
-void ClearModelSoundsCache();
-
-#endif // !CLIENT_DLL
-
-void WaveTrace( char const *wavname, char const *funcname )
-{
- if ( IsX360() && !IsDebug() )
- {
- return;
- }
-
- static CUtlSymbolTable s_WaveTrace;
-
- // Make sure we only show the message once
- if ( UTL_INVAL_SYMBOL == s_WaveTrace.Find( wavname ) )
- {
- DevMsg( "%s directly referenced wave %s (should use game_sounds.txt system instead)\n",
- funcname, wavname );
- s_WaveTrace.AddString( wavname );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &src -
-//-----------------------------------------------------------------------------
-EmitSound_t::EmitSound_t( const CSoundParameters &src )
-{
- m_nChannel = src.channel;
- m_pSoundName = src.soundname;
- m_flVolume = src.volume;
- m_SoundLevel = src.soundlevel;
- m_nFlags = 0;
- m_nPitch = src.pitch;
- m_nSpecialDSP = 0;
- m_pOrigin = 0;
- m_flSoundTime = ( src.delay_msec == 0 ) ? 0.0f : gpGlobals->curtime + ( (float)src.delay_msec / 1000.0f );
- m_pflSoundDuration = 0;
- m_bEmitCloseCaption = true;
- m_bWarnOnMissingCloseCaption = false;
- m_bWarnOnDirectWaveReference = false;
- m_nSpeakerEntity = -1;
-}
-
-void Hack_FixEscapeChars( char *str )
-{
- int len = Q_strlen( str ) + 1;
- char *i = str;
- char *o = (char *)_alloca( len );
- char *osave = o;
- while ( *i )
- {
- if ( *i == '\\' )
- {
- switch ( *( i + 1 ) )
- {
- case 'n':
- *o = '\n';
- ++i;
- break;
- default:
- *o = *i;
- break;
- }
- }
- else
- {
- *o = *i;
- }
-
- ++i;
- ++o;
- }
- *o = 0;
- Q_strncpy( str, osave, len );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-class CSoundEmitterSystem : public CBaseGameSystem
-{
-public:
- virtual char const *Name() { return "CSoundEmitterSystem"; }
-
-#if !defined( CLIENT_DLL )
- bool m_bLogPrecache;
- FileHandle_t m_hPrecacheLogFile;
- CUtlSymbolTable m_PrecachedScriptSounds;
-public:
- CSoundEmitterSystem( char const *pszName ) :
- m_bLogPrecache( false ),
- m_hPrecacheLogFile( FILESYSTEM_INVALID_HANDLE )
- {
- }
-
- void LogPrecache( char const *soundname )
- {
- if ( !m_bLogPrecache )
- return;
-
- // Make sure we only show the message once
- if ( UTL_INVAL_SYMBOL != m_PrecachedScriptSounds.Find( soundname ) )
- return;
-
- if (m_hPrecacheLogFile == FILESYSTEM_INVALID_HANDLE)
- {
- StartLog();
- }
-
- m_PrecachedScriptSounds.AddString( soundname );
-
- if (m_hPrecacheLogFile != FILESYSTEM_INVALID_HANDLE)
- {
- filesystem->Write("\"", 1, m_hPrecacheLogFile);
- filesystem->Write(soundname, Q_strlen(soundname), m_hPrecacheLogFile);
- filesystem->Write("\"\n", 2, m_hPrecacheLogFile);
- }
- else
- {
- Warning( "Disabling precache logging due to file i/o problem!!!\n" );
- m_bLogPrecache = false;
- }
- }
-
- void StartLog()
- {
- m_PrecachedScriptSounds.RemoveAll();
-
- if ( !m_bLogPrecache )
- return;
-
- if ( FILESYSTEM_INVALID_HANDLE != m_hPrecacheLogFile )
- {
- return;
- }
-
- filesystem->CreateDirHierarchy("reslists", "DEFAULT_WRITE_PATH");
-
- // open the new level reslist
- char path[_MAX_PATH];
- Q_snprintf(path, sizeof(path), "reslists\\%s.snd", gpGlobals->mapname.ToCStr() );
- m_hPrecacheLogFile = filesystem->Open(path, "wt", "GAME");
- }
-
- void FinishLog()
- {
- if ( FILESYSTEM_INVALID_HANDLE != m_hPrecacheLogFile )
- {
- filesystem->Close( m_hPrecacheLogFile );
- m_hPrecacheLogFile = FILESYSTEM_INVALID_HANDLE;
- }
-
- m_PrecachedScriptSounds.RemoveAll();
- }
-#else
- CSoundEmitterSystem( char const *name )
- {
- }
-
-#endif
-
- // IServerSystem stuff
- virtual bool Init()
- {
- Assert( soundemitterbase );
-#if !defined( CLIENT_DLL )
- m_bLogPrecache = CommandLine()->CheckParm( "-makereslists" ) ? true : false;
-#endif
- g_pClosecaption = cvar->FindVar("closecaption");
- Assert(g_pClosecaption);
- return soundemitterbase->ModInit();
- }
-
- virtual void Shutdown()
- {
- Assert( soundemitterbase );
-#if !defined( CLIENT_DLL )
- FinishLog();
-#endif
- soundemitterbase->ModShutdown();
- }
-
- void ReloadSoundEntriesInList( IFileList *pFilesToReload )
- {
- soundemitterbase->ReloadSoundEntriesInList( pFilesToReload );
- }
-
- virtual void TraceEmitSound( char const *fmt, ... )
- {
- if ( !sv_soundemitter_trace.GetBool() )
- return;
-
- va_list argptr;
- char string[256];
- va_start (argptr, fmt);
- Q_vsnprintf( string, sizeof( string ), fmt, argptr );
- va_end (argptr);
-
- // Spew to console
- Msg( "%s %s", CBaseEntity::IsServer() ? "(sv)" : "(cl)", string );
- }
-
- // Precache all wave files referenced in wave or rndwave keys
- virtual void LevelInitPreEntity()
- {
- char mapname[ 256 ];
-#if !defined( CLIENT_DLL )
- StartLog();
- Q_snprintf( mapname, sizeof( mapname ), "maps/%s", STRING( gpGlobals->mapname ) );
-#else
- Q_strncpy( mapname, engine->GetLevelName(), sizeof( mapname ) );
-#endif
-
- Q_FixSlashes( mapname );
- Q_strlower( mapname );
-
- // Load in any map specific overrides
- char scriptfile[ 512 ];
-#if defined( TF_CLIENT_DLL ) || defined( TF_DLL )
- if( V_stristr( mapname, "mvm" ) )
- {
- V_strncpy( scriptfile, "scripts/mvm_level_sounds.txt", sizeof( scriptfile ) );
- if ( filesystem->FileExists( "scripts/mvm_level_sounds.txt", "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( "scripts/mvm_level_sounds.txt" );
- }
- if ( filesystem->FileExists( "scripts/mvm_level_sound_tweaks.txt", "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( "scripts/mvm_level_sound_tweaks.txt" );
- }
- if ( filesystem->FileExists( "scripts/game_sounds_vo_mvm.txt", "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( "scripts/game_sounds_vo_mvm.txt", true );
- }
- if ( filesystem->FileExists( "scripts/game_sounds_vo_mvm_mighty.txt", "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( "scripts/game_sounds_vo_mvm_mighty.txt", true );
- }
- g_pTFPlayerClassDataMgr->AddAdditionalPlayerDeathSounds();
- }
- else
- {
- Q_StripExtension( mapname, scriptfile, sizeof( scriptfile ) );
- Q_strncat( scriptfile, "_level_sounds.txt", sizeof( scriptfile ), COPY_ALL_CHARACTERS );
- if ( filesystem->FileExists( scriptfile, "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( scriptfile );
- }
- }
-#else
- Q_StripExtension( mapname, scriptfile, sizeof( scriptfile ) );
- Q_strncat( scriptfile, "_level_sounds.txt", sizeof( scriptfile ), COPY_ALL_CHARACTERS );
-
- if ( filesystem->FileExists( scriptfile, "GAME" ) )
- {
- soundemitterbase->AddSoundOverrides( scriptfile );
- }
-#endif
-
-#if !defined( CLIENT_DLL )
- for ( int i=soundemitterbase->First(); i != soundemitterbase->InvalidIndex(); i=soundemitterbase->Next( i ) )
- {
- CSoundParametersInternal *pParams = soundemitterbase->InternalGetParametersForSound( i );
- if ( pParams->ShouldPreload() )
- {
- InternalPrecacheWaves( i );
- }
- }
-#endif
- }
-
- virtual void LevelInitPostEntity()
- {
- }
-
- virtual void LevelShutdownPostEntity()
- {
- soundemitterbase->ClearSoundOverrides();
-
-#if !defined( CLIENT_DLL )
- FinishLog();
-#endif
- }
-
- void InternalPrecacheWaves( int soundIndex )
- {
- CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( soundIndex );
- if ( !internal )
- return;
-
- int waveCount = internal->NumSoundNames();
- if ( !waveCount )
- {
- DevMsg( "CSoundEmitterSystem: sounds.txt entry '%s' has no waves listed under 'wave' or 'rndwave' key!!!\n",
- soundemitterbase->GetSoundName( soundIndex ) );
- }
- else
- {
- g_bPermitDirectSoundPrecache = true;
-
- for( int wave = 0; wave < waveCount; wave++ )
- {
- CBaseEntity::PrecacheSound( soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol ) );
- }
-
- g_bPermitDirectSoundPrecache = false;
- }
- }
-
- void InternalPrefetchWaves( int soundIndex )
- {
- CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( soundIndex );
- if ( !internal )
- return;
-
- int waveCount = internal->NumSoundNames();
- if ( !waveCount )
- {
- DevMsg( "CSoundEmitterSystem: sounds.txt entry '%s' has no waves listed under 'wave' or 'rndwave' key!!!\n",
- soundemitterbase->GetSoundName( soundIndex ) );
- }
- else
- {
- for( int wave = 0; wave < waveCount; wave++ )
- {
- CBaseEntity::PrefetchSound( soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol ) );
- }
- }
- }
-
- HSOUNDSCRIPTHANDLE PrecacheScriptSound( const char *soundname )
- {
- int soundIndex = soundemitterbase->GetSoundIndex( soundname );
- if ( !soundemitterbase->IsValidIndex( soundIndex ) )
- {
- if ( Q_stristr( soundname, ".wav" ) || Q_strstr( soundname, ".mp3" ) )
- {
- g_bPermitDirectSoundPrecache = true;
-
- CBaseEntity::PrecacheSound( soundname );
-
- g_bPermitDirectSoundPrecache = false;
- return SOUNDEMITTER_INVALID_HANDLE;
- }
-
-#if !defined( CLIENT_DLL )
- if ( soundname[ 0 ] )
- {
- static CUtlSymbolTable s_PrecacheScriptSoundFailures;
-
- // Make sure we only show the message once
- if ( UTL_INVAL_SYMBOL == s_PrecacheScriptSoundFailures.Find( soundname ) )
- {
- DevMsg( "PrecacheScriptSound '%s' failed, no such sound script entry\n", soundname );
- s_PrecacheScriptSoundFailures.AddString( soundname );
- }
- }
-#endif
- return (HSOUNDSCRIPTHANDLE)soundIndex;
- }
-#if !defined( CLIENT_DLL )
- LogPrecache( soundname );
-#endif
-
- InternalPrecacheWaves( soundIndex );
- return (HSOUNDSCRIPTHANDLE)soundIndex;
- }
-
- void PrefetchScriptSound( const char *soundname )
- {
- int soundIndex = soundemitterbase->GetSoundIndex( soundname );
- if ( !soundemitterbase->IsValidIndex( soundIndex ) )
- {
- if ( Q_stristr( soundname, ".wav" ) || Q_strstr( soundname, ".mp3" ) )
- {
- CBaseEntity::PrefetchSound( soundname );
- }
- return;
- }
-
- InternalPrefetchWaves( soundIndex );
- }
-public:
-
- void EmitSoundByHandle( IRecipientFilter& filter, int entindex, const EmitSound_t & ep, HSOUNDSCRIPTHANDLE& handle )
- {
- // Pull data from parameters
- CSoundParameters params;
-
- // Try to deduce the actor's gender
- gender_t gender = GENDER_NONE;
- CBaseEntity *ent = CBaseEntity::Instance( entindex );
- if ( ent )
- {
- char const *actorModel = STRING( ent->GetModelName() );
- gender = soundemitterbase->GetActorGender( actorModel );
- }
-
- if ( !soundemitterbase->GetParametersForSoundEx( ep.m_pSoundName, handle, params, gender, true ) )
- {
- return;
- }
-
- if ( !params.soundname[0] )
- return;
-
-#ifdef STAGING_ONLY
- if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( params.soundname, sv_snd_filter.GetString() ))
- {
- return;
- }
-#endif // STAGING_ONLY
-
- if ( !Q_strncasecmp( params.soundname, "vo", 2 ) &&
- !( params.channel == CHAN_STREAM ||
- params.channel == CHAN_VOICE ||
- params.channel == CHAN_VOICE2 ) )
- {
- DevMsg( "EmitSound: Voice wave file %s doesn't specify CHAN_VOICE, CHAN_VOICE2 or CHAN_STREAM for sound %s\n",
- params.soundname, ep.m_pSoundName );
- }
-
- // handle SND_CHANGEPITCH/SND_CHANGEVOL and other sound flags.etc.
- if( ep.m_nFlags & SND_CHANGE_PITCH )
- {
- params.pitch = ep.m_nPitch;
- }
-
-
- if( ep.m_nFlags & SND_CHANGE_VOL )
- {
- params.volume = ep.m_flVolume;
- }
-
-#if !defined( CLIENT_DLL )
- bool bSwallowed = CEnvMicrophone::OnSoundPlayed(
- entindex,
- params.soundname,
- params.soundlevel,
- params.volume,
- ep.m_nFlags,
- params.pitch,
- ep.m_pOrigin,
- ep.m_flSoundTime,
- ep.m_UtlVecSoundOrigin );
- if ( bSwallowed )
- return;
-#endif
-
-#if defined( _DEBUG ) && !defined( CLIENT_DLL )
- if ( !enginesound->IsSoundPrecached( params.soundname ) )
- {
- Msg( "Sound %s:%s was not precached\n", ep.m_pSoundName, params.soundname );
- }
-#endif
-
- float st = ep.m_flSoundTime;
- if ( !st &&
- params.delay_msec != 0 )
- {
- st = gpGlobals->curtime + (float)params.delay_msec / 1000.f;
- }
-
- enginesound->EmitSound(
- filter,
- entindex,
- params.channel,
- params.soundname,
- params.volume,
- (soundlevel_t)params.soundlevel,
- ep.m_nFlags,
- params.pitch,
- ep.m_nSpecialDSP,
- ep.m_pOrigin,
- NULL,
- &ep.m_UtlVecSoundOrigin,
- true,
- st,
- ep.m_nSpeakerEntity );
- if ( ep.m_pflSoundDuration )
- {
- *ep.m_pflSoundDuration = enginesound->GetSoundDuration( params.soundname );
- }
-
- TraceEmitSound( "EmitSound: '%s' emitted as '%s' (ent %i)\n",
- ep.m_pSoundName, params.soundname, entindex );
-
-
- // Don't caption modulations to the sound
- if ( !( ep.m_nFlags & ( SND_CHANGE_PITCH | SND_CHANGE_VOL ) ) )
- {
- EmitCloseCaption( filter, entindex, params, ep );
- }
-#if defined( WIN32 ) && !defined( _X360 )
- // NVNT notify the haptics system of this sound
- HapticProcessSound(ep.m_pSoundName, entindex);
-#endif
- }
-
- void EmitSound( IRecipientFilter& filter, int entindex, const EmitSound_t & ep )
- {
- VPROF( "CSoundEmitterSystem::EmitSound (calls engine)" );
-
-#ifdef STAGING_ONLY
- if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( ep.m_pSoundName, sv_snd_filter.GetString() ))
- {
- return;
- }
-#endif // STAGING_ONLY
-
- if ( ep.m_pSoundName &&
- ( Q_stristr( ep.m_pSoundName, ".wav" ) ||
- Q_stristr( ep.m_pSoundName, ".mp3" ) ||
- ep.m_pSoundName[0] == '!' ) )
- {
-#if !defined( CLIENT_DLL )
- bool bSwallowed = CEnvMicrophone::OnSoundPlayed(
- entindex,
- ep.m_pSoundName,
- ep.m_SoundLevel,
- ep.m_flVolume,
- ep.m_nFlags,
- ep.m_nPitch,
- ep.m_pOrigin,
- ep.m_flSoundTime,
- ep.m_UtlVecSoundOrigin );
- if ( bSwallowed )
- return;
-#endif
-
- if ( ep.m_bWarnOnDirectWaveReference &&
- Q_stristr( ep.m_pSoundName, ".wav" ) )
- {
- WaveTrace( ep.m_pSoundName, "Emitsound" );
- }
-
-#if defined( _DEBUG ) && !defined( CLIENT_DLL )
- if ( !enginesound->IsSoundPrecached( ep.m_pSoundName ) )
- {
- Msg( "Sound %s was not precached\n", ep.m_pSoundName );
- }
-#endif
- enginesound->EmitSound(
- filter,
- entindex,
- ep.m_nChannel,
- ep.m_pSoundName,
- ep.m_flVolume,
- ep.m_SoundLevel,
- ep.m_nFlags,
- ep.m_nPitch,
- ep.m_nSpecialDSP,
- ep.m_pOrigin,
- NULL,
- &ep.m_UtlVecSoundOrigin,
- true,
- ep.m_flSoundTime,
- ep.m_nSpeakerEntity );
- if ( ep.m_pflSoundDuration )
- {
- *ep.m_pflSoundDuration = enginesound->GetSoundDuration( ep.m_pSoundName );
- }
-
- TraceEmitSound( "EmitSound: Raw wave emitted '%s' (ent %i)\n",
- ep.m_pSoundName, entindex );
- return;
- }
-
- if ( ep.m_hSoundScriptHandle == SOUNDEMITTER_INVALID_HANDLE )
- {
- ep.m_hSoundScriptHandle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( ep.m_pSoundName );
- }
-
- if ( ep.m_hSoundScriptHandle == -1 )
- return;
-
- EmitSoundByHandle( filter, entindex, ep, ep.m_hSoundScriptHandle );
- }
-
- void EmitCloseCaption( IRecipientFilter& filter, int entindex, bool fromplayer, char const *token, CUtlVector< Vector >& originlist, float duration, bool warnifmissing /*= false*/ )
- {
- // No close captions in multiplayer...
- if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool()))
- {
- return;
- }
-
- // A negative duration means fill it in from the wav file if possible
- if ( duration < 0.0f )
- {
- char const *wav = soundemitterbase->GetWavFileForSound( token, GENDER_NONE );
- if ( wav )
- {
- duration = enginesound->GetSoundDuration( wav );
- }
- else
- {
- duration = 2.0f;
- }
- }
-
- char lowercase[ 256 ];
- Q_strncpy( lowercase, token, sizeof( lowercase ) );
- Q_strlower( lowercase );
- if ( Q_strstr( lowercase, "\\" ) )
- {
- Hack_FixEscapeChars( lowercase );
- }
-
- // NOTE: We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing
- // all players from it!!!!
- CRecipientFilter filterCopy;
- filterCopy.CopyFrom( (CRecipientFilter &)filter );
-
- // Remove any players who don't want close captions
- CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy );
-
-#if !defined( CLIENT_DLL )
- {
- // Defined in sceneentity.cpp
- bool AttenuateCaption( const char *token, const Vector& listener, CUtlVector< Vector >& soundorigins );
-
- if ( filterCopy.GetRecipientCount() > 0 )
- {
- int c = filterCopy.GetRecipientCount();
- for ( int i = c - 1 ; i >= 0; --i )
- {
- CBasePlayer *player = UTIL_PlayerByIndex( filterCopy.GetRecipientIndex( i ) );
- if ( !player )
- continue;
-
- Vector playerOrigin = player->GetAbsOrigin();
-
- if ( AttenuateCaption( lowercase, playerOrigin, originlist ) )
- {
- filterCopy.RemoveRecipient( player );
- }
- }
- }
- }
-#endif
- // Anyone left?
- if ( filterCopy.GetRecipientCount() > 0 )
- {
-
-#if !defined( CLIENT_DLL )
-
- byte byteflags = 0;
- if ( warnifmissing )
- {
- byteflags |= CLOSE_CAPTION_WARNIFMISSING;
- }
- if ( fromplayer )
- {
- byteflags |= CLOSE_CAPTION_FROMPLAYER;
- }
-
- CBaseEntity *pActor = CBaseEntity::Instance( entindex );
- if ( pActor )
- {
- char const *pszActorModel = STRING( pActor->GetModelName() );
- gender_t gender = soundemitterbase->GetActorGender( pszActorModel );
-
- if ( gender == GENDER_MALE )
- {
- byteflags |= CLOSE_CAPTION_GENDER_MALE;
- }
- else if ( gender == GENDER_FEMALE )
- {
- byteflags |= CLOSE_CAPTION_GENDER_FEMALE;
- }
- }
-
- // Send caption and duration hint down to client
- UserMessageBegin( filterCopy, "CloseCaption" );
- WRITE_STRING( lowercase );
- WRITE_SHORT( MIN( 255, (int)( duration * 10.0f ) ) ),
- WRITE_BYTE( byteflags ),
- MessageEnd();
-#else
- // Direct dispatch
- CHudCloseCaption *cchud = GET_HUDELEMENT( CHudCloseCaption );
- if ( cchud )
- {
- cchud->ProcessCaption( lowercase, duration, fromplayer );
- }
-#endif
- }
- }
-
- void EmitCloseCaption( IRecipientFilter& filter, int entindex, const CSoundParameters & params, const EmitSound_t & ep )
- {
- // No close captions in multiplayer...
- if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool()))
- {
- return;
- }
-
- if ( !ep.m_bEmitCloseCaption )
- {
- return;
- }
-
- // NOTE: We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing
- // all players from it!!!!
- CRecipientFilter filterCopy;
- filterCopy.CopyFrom( (CRecipientFilter &)filter );
-
- // Remove any players who don't want close captions
- CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy );
-
- // Anyone left?
- if ( filterCopy.GetRecipientCount() <= 0 )
- {
- return;
- }
-
- float duration = 0.0f;
- if ( ep.m_pflSoundDuration )
- {
- duration = *ep.m_pflSoundDuration;
- }
- else
- {
- duration = enginesound->GetSoundDuration( params.soundname );
- }
-
- bool fromplayer = false;
- CBaseEntity *ent = CBaseEntity::Instance( entindex );
- if ( ent )
- {
- while ( ent )
- {
- if ( ent->IsPlayer() )
- {
- fromplayer = true;
- break;
- }
-
- ent = ent->GetOwnerEntity();
- }
- }
- EmitCloseCaption( filter, entindex, fromplayer, ep.m_pSoundName, ep.m_UtlVecSoundOrigin, duration, ep.m_bWarnOnMissingCloseCaption );
- }
-
- void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, float flVolume, int iFlags, int iPitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
- {
- // Pull data from parameters
- CSoundParameters params;
-
- if ( !soundemitterbase->GetParametersForSound( soundname, params, GENDER_NONE ) )
- {
- return;
- }
-
-#ifdef STAGING_ONLY
- if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( params.soundname, sv_snd_filter.GetString() ))
- {
- return;
- }
-#endif // STAGING_ONLY
-
- if( iFlags & SND_CHANGE_PITCH )
- {
- params.pitch = iPitch;
- }
-
- if( iFlags & SND_CHANGE_VOL )
- {
- params.volume = flVolume;
- }
-
-#if defined( CLIENT_DLL )
- enginesound->EmitAmbientSound( params.soundname, params.volume, params.pitch, iFlags, soundtime );
-#else
- engine->EmitAmbientSound(entindex, origin, params.soundname, params.volume, params.soundlevel, iFlags, params.pitch, soundtime );
-#endif
-
- bool needsCC = !( iFlags & ( SND_STOP | SND_CHANGE_VOL | SND_CHANGE_PITCH ) );
-
- float soundduration = 0.0f;
-
- if ( duration || needsCC )
- {
- soundduration = enginesound->GetSoundDuration( params.soundname );
- if ( duration )
- {
- *duration = soundduration;
- }
- }
-
- TraceEmitSound( "EmitAmbientSound: '%s' emitted as '%s' (ent %i)\n",
- soundname, params.soundname, entindex );
-
- // We only want to trigger the CC on the start of the sound, not on any changes or halting of the sound
- if ( needsCC )
- {
- CRecipientFilter filter;
- filter.AddAllPlayers();
- filter.MakeReliable();
-
- CUtlVector< Vector > dummy;
- EmitCloseCaption( filter, entindex, false, soundname, dummy, soundduration, false );
- }
-
- }
-
- void StopSoundByHandle( int entindex, const char *soundname, HSOUNDSCRIPTHANDLE& handle )
- {
- if ( handle == SOUNDEMITTER_INVALID_HANDLE )
- {
- handle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( soundname );
- }
-
- if ( handle == SOUNDEMITTER_INVALID_HANDLE )
- return;
-
- CSoundParametersInternal *params;
-
- params = soundemitterbase->InternalGetParametersForSound( (int)handle );
- if ( !params )
- {
- return;
- }
-
- // HACK: we have to stop all sounds if there are > 1 in the rndwave section...
- int c = params->NumSoundNames();
- for ( int i = 0; i < c; ++i )
- {
- char const *wavename = soundemitterbase->GetWaveName( params->GetSoundNames()[ i ].symbol );
- Assert( wavename );
-
- enginesound->StopSound(
- entindex,
- params->GetChannel(),
- wavename );
-
- TraceEmitSound( "StopSound: '%s' stopped as '%s' (ent %i)\n",
- soundname, wavename, entindex );
- }
- }
-
- void StopSound( int entindex, const char *soundname )
- {
- HSOUNDSCRIPTHANDLE handle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( soundname );
- if ( handle == SOUNDEMITTER_INVALID_HANDLE )
- {
- return;
- }
-
- StopSoundByHandle( entindex, soundname, handle );
- }
-
-
- void StopSound( int iEntIndex, int iChannel, const char *pSample )
- {
- if ( pSample && ( Q_stristr( pSample, ".wav" ) || Q_stristr( pSample, ".mp3" ) || pSample[0] == '!' ) )
- {
- enginesound->StopSound( iEntIndex, iChannel, pSample );
-
- TraceEmitSound( "StopSound: Raw wave stopped '%s' (ent %i)\n",
- pSample, iEntIndex );
- }
- else
- {
- // Look it up in sounds.txt and ignore other parameters
- StopSound( iEntIndex, pSample );
- }
- }
-
- void EmitAmbientSound( int entindex, const Vector &origin, const char *pSample, float volume, soundlevel_t soundlevel, int flags, int pitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
- {
-#ifdef STAGING_ONLY
- if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( pSample, sv_snd_filter.GetString() ))
- {
- return;
- }
-#endif // STAGING_ONLY
-
-#if !defined( CLIENT_DLL )
- CUtlVector< Vector > dummyorigins;
-
- // Loop through all registered microphones and tell them the sound was just played
- // NOTE: This means that pitch shifts/sound changes on the original ambient will not be reflected in the re-broadcasted sound
- bool bSwallowed = CEnvMicrophone::OnSoundPlayed(
- entindex,
- pSample,
- soundlevel,
- volume,
- flags,
- pitch,
- &origin,
- soundtime,
- dummyorigins );
- if ( bSwallowed )
- return;
-#endif
-
- if ( pSample && ( Q_stristr( pSample, ".wav" ) || Q_stristr( pSample, ".mp3" )) )
- {
-#if defined( CLIENT_DLL )
- enginesound->EmitAmbientSound( pSample, volume, pitch, flags, soundtime );
-#else
- engine->EmitAmbientSound( entindex, origin, pSample, volume, soundlevel, flags, pitch, soundtime );
-#endif
-
- if ( duration )
- {
- *duration = enginesound->GetSoundDuration( pSample );
- }
-
- TraceEmitSound( "EmitAmbientSound: Raw wave emitted '%s' (ent %i)\n",
- pSample, entindex );
- }
- else
- {
- EmitAmbientSound( entindex, origin, pSample, volume, flags, pitch, soundtime, duration );
- }
- }
-};
-
-static CSoundEmitterSystem g_SoundEmitterSystem( "CSoundEmitterSystem" );
-
-IGameSystem *SoundEmitterSystem()
-{
- return &g_SoundEmitterSystem;
-}
-
-#if defined( CLIENT_DLL )
-void ReloadSoundEntriesInList( IFileList *pFilesToReload )
-{
- g_SoundEmitterSystem.ReloadSoundEntriesInList( pFilesToReload );
-}
-#endif
-
-void S_SoundEmitterSystemFlush( void )
-{
-#if !defined( CLIENT_DLL )
- if ( !UTIL_IsCommandIssuedByServerAdmin() )
- return;
-#endif
-
- // save the current soundscape
- // kill the system
- g_SoundEmitterSystem.Shutdown();
-
- // restart the system
- g_SoundEmitterSystem.Init();
-
-#if !defined( CLIENT_DLL )
- // Redo precache all wave files... (this should work now that we have dynamic string tables)
- g_SoundEmitterSystem.LevelInitPreEntity();
-
- // These store raw sound indices for faster precaching, blow them away.
- ClearModelSoundsCache();
-#endif
-
- // TODO: when we go to a handle system, we'll need to invalidate handles somehow
-}
-
-#if defined( CLIENT_DLL )
-CON_COMMAND_F( cl_soundemitter_flush, "Flushes the sounds.txt system (client only)", FCVAR_CHEAT )
-#else
-CON_COMMAND_F( sv_soundemitter_flush, "Flushes the sounds.txt system (server only)", FCVAR_DEVELOPMENTONLY )
-#endif
-{
- S_SoundEmitterSystemFlush( );
-}
-
-#if !defined(_RETAIL)
-
-#if !defined( CLIENT_DLL )
-
-#if !defined( _XBOX )
-
-CON_COMMAND_F( sv_soundemitter_filecheck, "Report missing wave files for sounds and game_sounds files.", FCVAR_DEVELOPMENTONLY )
-{
- if ( !UTIL_IsCommandIssuedByServerAdmin() )
- return;
-
- int missing = soundemitterbase->CheckForMissingWavFiles( true );
- DevMsg( "---------------------------\nTotal missing files %i\n", missing );
-}
-
-CON_COMMAND_F( sv_findsoundname, "Find sound names which reference the specified wave files.", FCVAR_DEVELOPMENTONLY )
-{
- if ( !UTIL_IsCommandIssuedByServerAdmin() )
- return;
-
- if ( args.ArgC() != 2 )
- return;
-
- int c = soundemitterbase->GetSoundCount();
- int i;
-
- char const *search = args[ 1 ];
- if ( !search )
- return;
-
- for ( i = 0; i < c; i++ )
- {
- CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( i );
- if ( !internal )
- continue;
-
- int waveCount = internal->NumSoundNames();
- if ( waveCount > 0 )
- {
- for( int wave = 0; wave < waveCount; wave++ )
- {
- char const *wavefilename = soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol );
-
- if ( Q_stristr( wavefilename, search ) )
- {
- char const *soundname = soundemitterbase->GetSoundName( i );
- char const *scriptname = soundemitterbase->GetSourceFileForSound( i );
-
- Msg( "Referenced by '%s:%s' -- %s\n", scriptname, soundname, wavefilename );
- }
- }
- }
- }
-}
-#endif // !_XBOX
-
-#else
-void Playgamesound_f( const CCommand &args )
-{
- CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if ( pPlayer )
- {
- if ( args.ArgC() > 2 )
- {
- Vector position = pPlayer->EyePosition();
- Vector forward;
- pPlayer->GetVectors( &forward, NULL, NULL );
- position += atof( args[2] ) * forward;
- CPASAttenuationFilter filter( pPlayer );
- EmitSound_t params;
- params.m_pSoundName = args[1];
- params.m_pOrigin = &position;
- params.m_flVolume = 0.0f;
- params.m_nPitch = 0;
- g_SoundEmitterSystem.EmitSound( filter, 0, params );
- }
- else
- {
- pPlayer->EmitSound( args[1] );
- }
- }
- else
- {
- Msg("Can't play until a game is started.\n");
- // UNDONE: Make something like this work?
- //CBroadcastRecipientFilter filter;
- //g_SoundEmitterSystem.EmitSound( filter, 1, args[1], 0.0, 0, 0, &vec3_origin, 0, NULL );
- }
-}
-
-static int GamesoundCompletion( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
-{
- int current = 0;
-
- const char *cmdname = "playgamesound";
- char *substring = NULL;
- int substringLen = 0;
- if ( Q_strstr( partial, cmdname ) && strlen(partial) > strlen(cmdname) + 1 )
- {
- substring = (char *)partial + strlen( cmdname ) + 1;
- substringLen = strlen(substring);
- }
-
- for ( int i = soundemitterbase->GetSoundCount()-1; i >= 0 && current < COMMAND_COMPLETION_MAXITEMS; i-- )
- {
- const char *pSoundName = soundemitterbase->GetSoundName( i );
- if ( pSoundName )
- {
- if ( !substring || !Q_strncasecmp( pSoundName, substring, substringLen ) )
- {
- Q_snprintf( commands[ current ], sizeof( commands[ current ] ), "%s %s", cmdname, pSoundName );
- current++;
- }
- }
- }
-
- return current;
-}
-
-static ConCommand Command_Playgamesound( "playgamesound", Playgamesound_f, "Play a sound from the game sounds txt file", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_SERVER_CAN_EXECUTE, GamesoundCompletion );
-#endif
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: Non-static override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. );
-// Input : *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( const char *soundname, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
- //VPROF( "CBaseEntity::EmitSound" );
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
- CPASAttenuationFilter filter( this, soundname );
-
- EmitSound_t params;
- params.m_pSoundName = soundname;
- params.m_flSoundTime = soundtime;
- params.m_pflSoundDuration = duration;
- params.m_bWarnOnDirectWaveReference = true;
-
- EmitSound( filter, entindex(), params );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Non-static override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. );
-// Input : *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
- // VPROF( "CBaseEntity::EmitSound" );
- CPASAttenuationFilter filter( this, soundname, handle );
-
- EmitSound_t params;
- params.m_pSoundName = soundname;
- params.m_flSoundTime = soundtime;
- params.m_pflSoundDuration = duration;
- params.m_bWarnOnDirectWaveReference = true;
-
- EmitSound( filter, entindex(), params, handle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : filter -
-// iEntIndex -
-// *soundname -
-// *pOrigin -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, const Vector *pOrigin /*= NULL*/, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
- if ( !soundname )
- return;
-
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
- // VPROF( "CBaseEntity::EmitSound" );
- EmitSound_t params;
- params.m_pSoundName = soundname;
- params.m_flSoundTime = soundtime;
- params.m_pOrigin = pOrigin;
- params.m_pflSoundDuration = duration;
- params.m_bWarnOnDirectWaveReference = true;
-
- EmitSound( filter, iEntIndex, params, params.m_hSoundScriptHandle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : filter -
-// iEntIndex -
-// *soundname -
-// *pOrigin -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, HSOUNDSCRIPTHANDLE& handle, const Vector *pOrigin /*= NULL*/, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
- //VPROF( "CBaseEntity::EmitSound" );
- EmitSound_t params;
- params.m_pSoundName = soundname;
- params.m_flSoundTime = soundtime;
- params.m_pOrigin = pOrigin;
- params.m_pflSoundDuration = duration;
- params.m_bWarnOnDirectWaveReference = true;
-
- EmitSound( filter, iEntIndex, params, handle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : filter -
-// iEntIndex -
-// params -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params )
-{
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
-#ifdef GAME_DLL
- CBaseEntity *pEntity = UTIL_EntityByIndex( iEntIndex );
-#else
- C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex );
-#endif
- if ( pEntity )
- {
- pEntity->ModifyEmitSoundParams( const_cast< EmitSound_t& >( params ) );
- }
-
- // VPROF( "CBaseEntity::EmitSound" );
- // Call into the sound emitter system...
- g_SoundEmitterSystem.EmitSound( filter, iEntIndex, params );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : filter -
-// iEntIndex -
-// params -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHANDLE& handle )
-{
- VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) );
-
-#ifdef GAME_DLL
- CBaseEntity *pEntity = UTIL_EntityByIndex( iEntIndex );
-#else
- C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex );
-#endif
- if ( pEntity )
- {
- pEntity->ModifyEmitSoundParams( const_cast< EmitSound_t& >( params ) );
- }
-
- // VPROF( "CBaseEntity::EmitSound" );
- // Call into the sound emitter system...
- g_SoundEmitterSystem.EmitSoundByHandle( filter, iEntIndex, params, handle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::StopSound( const char *soundname )
-{
-#if defined( CLIENT_DLL )
- if ( entindex() == -1 )
- {
- // If we're a clientside entity, we need to use the soundsourceindex instead of the entindex
- StopSound( GetSoundSourceIndex(), soundname );
- return;
- }
-#endif
-
- StopSound( entindex(), soundname );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::StopSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle )
-{
-#if defined( CLIENT_DLL )
- if ( entindex() == -1 )
- {
- // If we're a clientside entity, we need to use the soundsourceindex instead of the entindex
- StopSound( GetSoundSourceIndex(), soundname );
- return;
- }
-#endif
-
- g_SoundEmitterSystem.StopSoundByHandle( entindex(), soundname, handle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : iEntIndex -
-// *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::StopSound( int iEntIndex, const char *soundname )
-{
- g_SoundEmitterSystem.StopSound( iEntIndex, soundname );
-}
-
-void CBaseEntity::StopSound( int iEntIndex, int iChannel, const char *pSample )
-{
- g_SoundEmitterSystem.StopSound( iEntIndex, iChannel, pSample );
-}
-
-soundlevel_t CBaseEntity::LookupSoundLevel( const char *soundname )
-{
- return soundemitterbase->LookupSoundLevel( soundname );
-}
-
-
-soundlevel_t CBaseEntity::LookupSoundLevel( const char *soundname, HSOUNDSCRIPTHANDLE& handle )
-{
- return soundemitterbase->LookupSoundLevelByHandle( soundname, handle );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *entity -
-// origin -
-// flags -
-// *soundname -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
- g_SoundEmitterSystem.EmitAmbientSound( entindex, origin, soundname, 0.0, flags, 0, soundtime, duration );
-}
-
-// HACK HACK: Do we need to pull the entire SENTENCEG_* wrapper over to the client .dll?
-#if defined( CLIENT_DLL )
-int SENTENCEG_Lookup(const char *sample)
-{
- return engine->SentenceIndexFromName( sample + 1 );
-}
-#endif
-
-void UTIL_EmitAmbientSound( int entindex, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ )
-{
-#ifdef STAGING_ONLY
- if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( samp, sv_snd_filter.GetString() ))
- {
- return;
- }
-#endif // STAGING_ONLY
-
- if (samp && *samp == '!')
- {
- int sentenceIndex = SENTENCEG_Lookup(samp);
- if (sentenceIndex >= 0)
- {
- char name[32];
- Q_snprintf( name, sizeof(name), "!%d", sentenceIndex );
-#if !defined( CLIENT_DLL )
- engine->EmitAmbientSound( entindex, vecOrigin, name, vol, soundlevel, fFlags, pitch, soundtime );
-#else
- enginesound->EmitAmbientSound( name, vol, pitch, fFlags, soundtime );
-#endif
- if ( duration )
- {
- *duration = enginesound->GetSoundDuration( name );
- }
-
- g_SoundEmitterSystem.TraceEmitSound( "UTIL_EmitAmbientSound: Sentence emitted '%s' (ent %i)\n",
- name, entindex );
- }
- }
- else
- {
- g_SoundEmitterSystem.EmitAmbientSound( entindex, vecOrigin, samp, vol, soundlevel, fFlags, pitch, soundtime, duration );
- }
-}
-
-static const char *UTIL_TranslateSoundName( const char *soundname, const char *actormodel )
-{
- Assert( soundname );
-
- if ( Q_stristr( soundname, ".wav" ) || Q_stristr( soundname, ".mp3" ) )
- {
- if ( Q_stristr( soundname, ".wav" ) )
- {
- WaveTrace( soundname, "UTIL_TranslateSoundName" );
- }
- return soundname;
- }
-
- return soundemitterbase->GetWavFileForSound( soundname, actormodel );
-}
-
-void CBaseEntity::GenderExpandString( char const *in, char *out, int maxlen )
-{
- soundemitterbase->GenderExpandString( STRING( GetModelName() ), in, out, maxlen );
-}
-
-bool CBaseEntity::GetParametersForSound( const char *soundname, CSoundParameters ¶ms, const char *actormodel )
-{
- gender_t gender = soundemitterbase->GetActorGender( actormodel );
-
- return soundemitterbase->GetParametersForSound( soundname, params, gender );
-}
-
-bool CBaseEntity::GetParametersForSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, CSoundParameters ¶ms, const char *actormodel )
-{
- gender_t gender = soundemitterbase->GetActorGender( actormodel );
-
- return soundemitterbase->GetParametersForSoundEx( soundname, handle, params, gender );
-}
-
-HSOUNDSCRIPTHANDLE CBaseEntity::PrecacheScriptSound( const char *soundname )
-{
-#if !defined( CLIENT_DLL )
- return g_SoundEmitterSystem.PrecacheScriptSound( soundname );
-#else
- return soundemitterbase->GetSoundIndex( soundname );
-#endif
-}
-
-void CBaseEntity::PrefetchScriptSound( const char *soundname )
-{
- g_SoundEmitterSystem.PrefetchScriptSound( soundname );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *soundname -
-// Output : float
-//-----------------------------------------------------------------------------
-float CBaseEntity::GetSoundDuration( const char *soundname, char const *actormodel )
-{
- return enginesound->GetSoundDuration( PSkipSoundChars( UTIL_TranslateSoundName( soundname, actormodel ) ) );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : filter -
-// *token -
-// duration -
-// warnifmissing -
-//-----------------------------------------------------------------------------
-void CBaseEntity::EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigin, float duration, bool warnifmissing /*= false*/ )
-{
- bool fromplayer = false;
- CBaseEntity *ent = CBaseEntity::Instance( entindex );
- while ( ent )
- {
- if ( ent->IsPlayer() )
- {
- fromplayer = true;
- break;
- }
- ent = ent->GetOwnerEntity();
- }
-
- g_SoundEmitterSystem.EmitCloseCaption( filter, entindex, fromplayer, token, soundorigin, duration, warnifmissing );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *name -
-// preload -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CBaseEntity::PrecacheSound( const char *name )
-{
- if ( IsPC() && !g_bPermitDirectSoundPrecache )
- {
- Warning( "Direct precache of %s\n", name );
- }
-
- // If this is out of order, warn
- if ( !CBaseEntity::IsPrecacheAllowed() )
- {
- if ( !enginesound->IsSoundPrecached( name ) )
- {
- Assert( !"CBaseEntity::PrecacheSound: too late" );
-
- Warning( "Late precache of %s\n", name );
- }
- }
-
- bool bret = enginesound->PrecacheSound( name, true );
- return bret;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *name -
-//-----------------------------------------------------------------------------
-void CBaseEntity::PrefetchSound( const char *name )
-{
- enginesound->PrefetchSound( name );
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <ctype.h> +#include <KeyValues.h> +#include "engine/IEngineSound.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "igamesystem.h" +#include "soundchars.h" +#include "filesystem.h" +#include "tier0/vprof.h" +#include "checksum_crc.h" +#include "tier0/icommandline.h" + +#if defined( TF_CLIENT_DLL ) || defined( TF_DLL ) +#include "tf_shareddefs.h" +#include "tf_classdata.h" +#endif + +// NVNT haptic utils +#include "haptics/haptic_utils.h" + +#ifndef CLIENT_DLL +#include "envmicrophone.h" +#include "sceneentity.h" +#else +#include <vgui_controls/Controls.h> +#include <vgui/IVGui.h> +#include "hud_closecaption.h" +#define CRecipientFilter C_RecipientFilter +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static ConVar sv_soundemitter_trace( "sv_soundemitter_trace", "0", FCVAR_REPLICATED, "Show all EmitSound calls including their symbolic name and the actual wave file they resolved to\n" ); +#ifdef STAGING_ONLY +static ConVar sv_snd_filter( "sv_snd_filter", "", FCVAR_REPLICATED, "Filters out all sounds not containing the specified string before being emitted\n" ); +#endif // STAGING_ONLY + +extern ISoundEmitterSystemBase *soundemitterbase; +static ConVar *g_pClosecaption = NULL; + +#ifdef _XBOX +int LookupStringFromCloseCaptionToken( char const *token ); +const wchar_t *GetStringForIndex( int index ); +#endif +static bool g_bPermitDirectSoundPrecache = false; + +#if !defined( CLIENT_DLL ) + +void ClearModelSoundsCache(); + +#endif // !CLIENT_DLL + +void WaveTrace( char const *wavname, char const *funcname ) +{ + if ( IsX360() && !IsDebug() ) + { + return; + } + + static CUtlSymbolTable s_WaveTrace; + + // Make sure we only show the message once + if ( UTL_INVAL_SYMBOL == s_WaveTrace.Find( wavname ) ) + { + DevMsg( "%s directly referenced wave %s (should use game_sounds.txt system instead)\n", + funcname, wavname ); + s_WaveTrace.AddString( wavname ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &src - +//----------------------------------------------------------------------------- +EmitSound_t::EmitSound_t( const CSoundParameters &src ) +{ + m_nChannel = src.channel; + m_pSoundName = src.soundname; + m_flVolume = src.volume; + m_SoundLevel = src.soundlevel; + m_nFlags = 0; + m_nPitch = src.pitch; + m_nSpecialDSP = 0; + m_pOrigin = 0; + m_flSoundTime = ( src.delay_msec == 0 ) ? 0.0f : gpGlobals->curtime + ( (float)src.delay_msec / 1000.0f ); + m_pflSoundDuration = 0; + m_bEmitCloseCaption = true; + m_bWarnOnMissingCloseCaption = false; + m_bWarnOnDirectWaveReference = false; + m_nSpeakerEntity = -1; +} + +void Hack_FixEscapeChars( char *str ) +{ + int len = Q_strlen( str ) + 1; + char *i = str; + char *o = (char *)_alloca( len ); + char *osave = o; + while ( *i ) + { + if ( *i == '\\' ) + { + switch ( *( i + 1 ) ) + { + case 'n': + *o = '\n'; + ++i; + break; + default: + *o = *i; + break; + } + } + else + { + *o = *i; + } + + ++i; + ++o; + } + *o = 0; + Q_strncpy( str, osave, len ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CSoundEmitterSystem : public CBaseGameSystem +{ +public: + virtual char const *Name() { return "CSoundEmitterSystem"; } + +#if !defined( CLIENT_DLL ) + bool m_bLogPrecache; + FileHandle_t m_hPrecacheLogFile; + CUtlSymbolTable m_PrecachedScriptSounds; +public: + CSoundEmitterSystem( char const *pszName ) : + m_bLogPrecache( false ), + m_hPrecacheLogFile( FILESYSTEM_INVALID_HANDLE ) + { + } + + void LogPrecache( char const *soundname ) + { + if ( !m_bLogPrecache ) + return; + + // Make sure we only show the message once + if ( UTL_INVAL_SYMBOL != m_PrecachedScriptSounds.Find( soundname ) ) + return; + + if (m_hPrecacheLogFile == FILESYSTEM_INVALID_HANDLE) + { + StartLog(); + } + + m_PrecachedScriptSounds.AddString( soundname ); + + if (m_hPrecacheLogFile != FILESYSTEM_INVALID_HANDLE) + { + filesystem->Write("\"", 1, m_hPrecacheLogFile); + filesystem->Write(soundname, Q_strlen(soundname), m_hPrecacheLogFile); + filesystem->Write("\"\n", 2, m_hPrecacheLogFile); + } + else + { + Warning( "Disabling precache logging due to file i/o problem!!!\n" ); + m_bLogPrecache = false; + } + } + + void StartLog() + { + m_PrecachedScriptSounds.RemoveAll(); + + if ( !m_bLogPrecache ) + return; + + if ( FILESYSTEM_INVALID_HANDLE != m_hPrecacheLogFile ) + { + return; + } + + filesystem->CreateDirHierarchy("reslists", "DEFAULT_WRITE_PATH"); + + // open the new level reslist + char path[_MAX_PATH]; + Q_snprintf(path, sizeof(path), "reslists\\%s.snd", gpGlobals->mapname.ToCStr() ); + m_hPrecacheLogFile = filesystem->Open(path, "wt", "GAME"); + } + + void FinishLog() + { + if ( FILESYSTEM_INVALID_HANDLE != m_hPrecacheLogFile ) + { + filesystem->Close( m_hPrecacheLogFile ); + m_hPrecacheLogFile = FILESYSTEM_INVALID_HANDLE; + } + + m_PrecachedScriptSounds.RemoveAll(); + } +#else + CSoundEmitterSystem( char const *name ) + { + } + +#endif + + // IServerSystem stuff + virtual bool Init() + { + Assert( soundemitterbase ); +#if !defined( CLIENT_DLL ) + m_bLogPrecache = CommandLine()->CheckParm( "-makereslists" ) ? true : false; +#endif + g_pClosecaption = cvar->FindVar("closecaption"); + Assert(g_pClosecaption); + return soundemitterbase->ModInit(); + } + + virtual void Shutdown() + { + Assert( soundemitterbase ); +#if !defined( CLIENT_DLL ) + FinishLog(); +#endif + soundemitterbase->ModShutdown(); + } + + void ReloadSoundEntriesInList( IFileList *pFilesToReload ) + { + soundemitterbase->ReloadSoundEntriesInList( pFilesToReload ); + } + + virtual void TraceEmitSound( char const *fmt, ... ) + { + if ( !sv_soundemitter_trace.GetBool() ) + return; + + va_list argptr; + char string[256]; + va_start (argptr, fmt); + Q_vsnprintf( string, sizeof( string ), fmt, argptr ); + va_end (argptr); + + // Spew to console + Msg( "%s %s", CBaseEntity::IsServer() ? "(sv)" : "(cl)", string ); + } + + // Precache all wave files referenced in wave or rndwave keys + virtual void LevelInitPreEntity() + { + char mapname[ 256 ]; +#if !defined( CLIENT_DLL ) + StartLog(); + Q_snprintf( mapname, sizeof( mapname ), "maps/%s", STRING( gpGlobals->mapname ) ); +#else + Q_strncpy( mapname, engine->GetLevelName(), sizeof( mapname ) ); +#endif + + Q_FixSlashes( mapname ); + Q_strlower( mapname ); + + // Load in any map specific overrides + char scriptfile[ 512 ]; +#if defined( TF_CLIENT_DLL ) || defined( TF_DLL ) + if( V_stristr( mapname, "mvm" ) ) + { + V_strncpy( scriptfile, "scripts/mvm_level_sounds.txt", sizeof( scriptfile ) ); + if ( filesystem->FileExists( "scripts/mvm_level_sounds.txt", "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( "scripts/mvm_level_sounds.txt" ); + } + if ( filesystem->FileExists( "scripts/mvm_level_sound_tweaks.txt", "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( "scripts/mvm_level_sound_tweaks.txt" ); + } + if ( filesystem->FileExists( "scripts/game_sounds_vo_mvm.txt", "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( "scripts/game_sounds_vo_mvm.txt", true ); + } + if ( filesystem->FileExists( "scripts/game_sounds_vo_mvm_mighty.txt", "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( "scripts/game_sounds_vo_mvm_mighty.txt", true ); + } + g_pTFPlayerClassDataMgr->AddAdditionalPlayerDeathSounds(); + } + else + { + Q_StripExtension( mapname, scriptfile, sizeof( scriptfile ) ); + Q_strncat( scriptfile, "_level_sounds.txt", sizeof( scriptfile ), COPY_ALL_CHARACTERS ); + if ( filesystem->FileExists( scriptfile, "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( scriptfile ); + } + } +#else + Q_StripExtension( mapname, scriptfile, sizeof( scriptfile ) ); + Q_strncat( scriptfile, "_level_sounds.txt", sizeof( scriptfile ), COPY_ALL_CHARACTERS ); + + if ( filesystem->FileExists( scriptfile, "GAME" ) ) + { + soundemitterbase->AddSoundOverrides( scriptfile ); + } +#endif + +#if !defined( CLIENT_DLL ) + for ( int i=soundemitterbase->First(); i != soundemitterbase->InvalidIndex(); i=soundemitterbase->Next( i ) ) + { + CSoundParametersInternal *pParams = soundemitterbase->InternalGetParametersForSound( i ); + if ( pParams->ShouldPreload() ) + { + InternalPrecacheWaves( i ); + } + } +#endif + } + + virtual void LevelInitPostEntity() + { + } + + virtual void LevelShutdownPostEntity() + { + soundemitterbase->ClearSoundOverrides(); + +#if !defined( CLIENT_DLL ) + FinishLog(); +#endif + } + + void InternalPrecacheWaves( int soundIndex ) + { + CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( soundIndex ); + if ( !internal ) + return; + + int waveCount = internal->NumSoundNames(); + if ( !waveCount ) + { + DevMsg( "CSoundEmitterSystem: sounds.txt entry '%s' has no waves listed under 'wave' or 'rndwave' key!!!\n", + soundemitterbase->GetSoundName( soundIndex ) ); + } + else + { + g_bPermitDirectSoundPrecache = true; + + for( int wave = 0; wave < waveCount; wave++ ) + { + CBaseEntity::PrecacheSound( soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol ) ); + } + + g_bPermitDirectSoundPrecache = false; + } + } + + void InternalPrefetchWaves( int soundIndex ) + { + CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( soundIndex ); + if ( !internal ) + return; + + int waveCount = internal->NumSoundNames(); + if ( !waveCount ) + { + DevMsg( "CSoundEmitterSystem: sounds.txt entry '%s' has no waves listed under 'wave' or 'rndwave' key!!!\n", + soundemitterbase->GetSoundName( soundIndex ) ); + } + else + { + for( int wave = 0; wave < waveCount; wave++ ) + { + CBaseEntity::PrefetchSound( soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol ) ); + } + } + } + + HSOUNDSCRIPTHANDLE PrecacheScriptSound( const char *soundname ) + { + int soundIndex = soundemitterbase->GetSoundIndex( soundname ); + if ( !soundemitterbase->IsValidIndex( soundIndex ) ) + { + if ( Q_stristr( soundname, ".wav" ) || Q_strstr( soundname, ".mp3" ) ) + { + g_bPermitDirectSoundPrecache = true; + + CBaseEntity::PrecacheSound( soundname ); + + g_bPermitDirectSoundPrecache = false; + return SOUNDEMITTER_INVALID_HANDLE; + } + +#if !defined( CLIENT_DLL ) + if ( soundname[ 0 ] ) + { + static CUtlSymbolTable s_PrecacheScriptSoundFailures; + + // Make sure we only show the message once + if ( UTL_INVAL_SYMBOL == s_PrecacheScriptSoundFailures.Find( soundname ) ) + { + DevMsg( "PrecacheScriptSound '%s' failed, no such sound script entry\n", soundname ); + s_PrecacheScriptSoundFailures.AddString( soundname ); + } + } +#endif + return (HSOUNDSCRIPTHANDLE)soundIndex; + } +#if !defined( CLIENT_DLL ) + LogPrecache( soundname ); +#endif + + InternalPrecacheWaves( soundIndex ); + return (HSOUNDSCRIPTHANDLE)soundIndex; + } + + void PrefetchScriptSound( const char *soundname ) + { + int soundIndex = soundemitterbase->GetSoundIndex( soundname ); + if ( !soundemitterbase->IsValidIndex( soundIndex ) ) + { + if ( Q_stristr( soundname, ".wav" ) || Q_strstr( soundname, ".mp3" ) ) + { + CBaseEntity::PrefetchSound( soundname ); + } + return; + } + + InternalPrefetchWaves( soundIndex ); + } +public: + + void EmitSoundByHandle( IRecipientFilter& filter, int entindex, const EmitSound_t & ep, HSOUNDSCRIPTHANDLE& handle ) + { + // Pull data from parameters + CSoundParameters params; + + // Try to deduce the actor's gender + gender_t gender = GENDER_NONE; + CBaseEntity *ent = CBaseEntity::Instance( entindex ); + if ( ent ) + { + char const *actorModel = STRING( ent->GetModelName() ); + gender = soundemitterbase->GetActorGender( actorModel ); + } + + if ( !soundemitterbase->GetParametersForSoundEx( ep.m_pSoundName, handle, params, gender, true ) ) + { + return; + } + + if ( !params.soundname[0] ) + return; + +#ifdef STAGING_ONLY + if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( params.soundname, sv_snd_filter.GetString() )) + { + return; + } +#endif // STAGING_ONLY + + if ( !Q_strncasecmp( params.soundname, "vo", 2 ) && + !( params.channel == CHAN_STREAM || + params.channel == CHAN_VOICE || + params.channel == CHAN_VOICE2 ) ) + { + DevMsg( "EmitSound: Voice wave file %s doesn't specify CHAN_VOICE, CHAN_VOICE2 or CHAN_STREAM for sound %s\n", + params.soundname, ep.m_pSoundName ); + } + + // handle SND_CHANGEPITCH/SND_CHANGEVOL and other sound flags.etc. + if( ep.m_nFlags & SND_CHANGE_PITCH ) + { + params.pitch = ep.m_nPitch; + } + + + if( ep.m_nFlags & SND_CHANGE_VOL ) + { + params.volume = ep.m_flVolume; + } + +#if !defined( CLIENT_DLL ) + bool bSwallowed = CEnvMicrophone::OnSoundPlayed( + entindex, + params.soundname, + params.soundlevel, + params.volume, + ep.m_nFlags, + params.pitch, + ep.m_pOrigin, + ep.m_flSoundTime, + ep.m_UtlVecSoundOrigin ); + if ( bSwallowed ) + return; +#endif + +#if defined( _DEBUG ) && !defined( CLIENT_DLL ) + if ( !enginesound->IsSoundPrecached( params.soundname ) ) + { + Msg( "Sound %s:%s was not precached\n", ep.m_pSoundName, params.soundname ); + } +#endif + + float st = ep.m_flSoundTime; + if ( !st && + params.delay_msec != 0 ) + { + st = gpGlobals->curtime + (float)params.delay_msec / 1000.f; + } + + enginesound->EmitSound( + filter, + entindex, + params.channel, + params.soundname, + params.volume, + (soundlevel_t)params.soundlevel, + ep.m_nFlags, + params.pitch, + ep.m_nSpecialDSP, + ep.m_pOrigin, + NULL, + &ep.m_UtlVecSoundOrigin, + true, + st, + ep.m_nSpeakerEntity ); + if ( ep.m_pflSoundDuration ) + { + *ep.m_pflSoundDuration = enginesound->GetSoundDuration( params.soundname ); + } + + TraceEmitSound( "EmitSound: '%s' emitted as '%s' (ent %i)\n", + ep.m_pSoundName, params.soundname, entindex ); + + + // Don't caption modulations to the sound + if ( !( ep.m_nFlags & ( SND_CHANGE_PITCH | SND_CHANGE_VOL ) ) ) + { + EmitCloseCaption( filter, entindex, params, ep ); + } +#if defined( WIN32 ) && !defined( _X360 ) + // NVNT notify the haptics system of this sound + HapticProcessSound(ep.m_pSoundName, entindex); +#endif + } + + void EmitSound( IRecipientFilter& filter, int entindex, const EmitSound_t & ep ) + { + VPROF( "CSoundEmitterSystem::EmitSound (calls engine)" ); + +#ifdef STAGING_ONLY + if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( ep.m_pSoundName, sv_snd_filter.GetString() )) + { + return; + } +#endif // STAGING_ONLY + + if ( ep.m_pSoundName && + ( Q_stristr( ep.m_pSoundName, ".wav" ) || + Q_stristr( ep.m_pSoundName, ".mp3" ) || + ep.m_pSoundName[0] == '!' ) ) + { +#if !defined( CLIENT_DLL ) + bool bSwallowed = CEnvMicrophone::OnSoundPlayed( + entindex, + ep.m_pSoundName, + ep.m_SoundLevel, + ep.m_flVolume, + ep.m_nFlags, + ep.m_nPitch, + ep.m_pOrigin, + ep.m_flSoundTime, + ep.m_UtlVecSoundOrigin ); + if ( bSwallowed ) + return; +#endif + + if ( ep.m_bWarnOnDirectWaveReference && + Q_stristr( ep.m_pSoundName, ".wav" ) ) + { + WaveTrace( ep.m_pSoundName, "Emitsound" ); + } + +#if defined( _DEBUG ) && !defined( CLIENT_DLL ) + if ( !enginesound->IsSoundPrecached( ep.m_pSoundName ) ) + { + Msg( "Sound %s was not precached\n", ep.m_pSoundName ); + } +#endif + enginesound->EmitSound( + filter, + entindex, + ep.m_nChannel, + ep.m_pSoundName, + ep.m_flVolume, + ep.m_SoundLevel, + ep.m_nFlags, + ep.m_nPitch, + ep.m_nSpecialDSP, + ep.m_pOrigin, + NULL, + &ep.m_UtlVecSoundOrigin, + true, + ep.m_flSoundTime, + ep.m_nSpeakerEntity ); + if ( ep.m_pflSoundDuration ) + { + *ep.m_pflSoundDuration = enginesound->GetSoundDuration( ep.m_pSoundName ); + } + + TraceEmitSound( "EmitSound: Raw wave emitted '%s' (ent %i)\n", + ep.m_pSoundName, entindex ); + return; + } + + if ( ep.m_hSoundScriptHandle == SOUNDEMITTER_INVALID_HANDLE ) + { + ep.m_hSoundScriptHandle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( ep.m_pSoundName ); + } + + if ( ep.m_hSoundScriptHandle == -1 ) + return; + + EmitSoundByHandle( filter, entindex, ep, ep.m_hSoundScriptHandle ); + } + + void EmitCloseCaption( IRecipientFilter& filter, int entindex, bool fromplayer, char const *token, CUtlVector< Vector >& originlist, float duration, bool warnifmissing /*= false*/ ) + { + // No close captions in multiplayer... + if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool())) + { + return; + } + + // A negative duration means fill it in from the wav file if possible + if ( duration < 0.0f ) + { + char const *wav = soundemitterbase->GetWavFileForSound( token, GENDER_NONE ); + if ( wav ) + { + duration = enginesound->GetSoundDuration( wav ); + } + else + { + duration = 2.0f; + } + } + + char lowercase[ 256 ]; + Q_strncpy( lowercase, token, sizeof( lowercase ) ); + Q_strlower( lowercase ); + if ( Q_strstr( lowercase, "\\" ) ) + { + Hack_FixEscapeChars( lowercase ); + } + + // NOTE: We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing + // all players from it!!!! + CRecipientFilter filterCopy; + filterCopy.CopyFrom( (CRecipientFilter &)filter ); + + // Remove any players who don't want close captions + CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy ); + +#if !defined( CLIENT_DLL ) + { + // Defined in sceneentity.cpp + bool AttenuateCaption( const char *token, const Vector& listener, CUtlVector< Vector >& soundorigins ); + + if ( filterCopy.GetRecipientCount() > 0 ) + { + int c = filterCopy.GetRecipientCount(); + for ( int i = c - 1 ; i >= 0; --i ) + { + CBasePlayer *player = UTIL_PlayerByIndex( filterCopy.GetRecipientIndex( i ) ); + if ( !player ) + continue; + + Vector playerOrigin = player->GetAbsOrigin(); + + if ( AttenuateCaption( lowercase, playerOrigin, originlist ) ) + { + filterCopy.RemoveRecipient( player ); + } + } + } + } +#endif + // Anyone left? + if ( filterCopy.GetRecipientCount() > 0 ) + { + +#if !defined( CLIENT_DLL ) + + byte byteflags = 0; + if ( warnifmissing ) + { + byteflags |= CLOSE_CAPTION_WARNIFMISSING; + } + if ( fromplayer ) + { + byteflags |= CLOSE_CAPTION_FROMPLAYER; + } + + CBaseEntity *pActor = CBaseEntity::Instance( entindex ); + if ( pActor ) + { + char const *pszActorModel = STRING( pActor->GetModelName() ); + gender_t gender = soundemitterbase->GetActorGender( pszActorModel ); + + if ( gender == GENDER_MALE ) + { + byteflags |= CLOSE_CAPTION_GENDER_MALE; + } + else if ( gender == GENDER_FEMALE ) + { + byteflags |= CLOSE_CAPTION_GENDER_FEMALE; + } + } + + // Send caption and duration hint down to client + UserMessageBegin( filterCopy, "CloseCaption" ); + WRITE_STRING( lowercase ); + WRITE_SHORT( MIN( 255, (int)( duration * 10.0f ) ) ), + WRITE_BYTE( byteflags ), + MessageEnd(); +#else + // Direct dispatch + CHudCloseCaption *cchud = GET_HUDELEMENT( CHudCloseCaption ); + if ( cchud ) + { + cchud->ProcessCaption( lowercase, duration, fromplayer ); + } +#endif + } + } + + void EmitCloseCaption( IRecipientFilter& filter, int entindex, const CSoundParameters & params, const EmitSound_t & ep ) + { + // No close captions in multiplayer... + if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool())) + { + return; + } + + if ( !ep.m_bEmitCloseCaption ) + { + return; + } + + // NOTE: We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing + // all players from it!!!! + CRecipientFilter filterCopy; + filterCopy.CopyFrom( (CRecipientFilter &)filter ); + + // Remove any players who don't want close captions + CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy ); + + // Anyone left? + if ( filterCopy.GetRecipientCount() <= 0 ) + { + return; + } + + float duration = 0.0f; + if ( ep.m_pflSoundDuration ) + { + duration = *ep.m_pflSoundDuration; + } + else + { + duration = enginesound->GetSoundDuration( params.soundname ); + } + + bool fromplayer = false; + CBaseEntity *ent = CBaseEntity::Instance( entindex ); + if ( ent ) + { + while ( ent ) + { + if ( ent->IsPlayer() ) + { + fromplayer = true; + break; + } + + ent = ent->GetOwnerEntity(); + } + } + EmitCloseCaption( filter, entindex, fromplayer, ep.m_pSoundName, ep.m_UtlVecSoundOrigin, duration, ep.m_bWarnOnMissingCloseCaption ); + } + + void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, float flVolume, int iFlags, int iPitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) + { + // Pull data from parameters + CSoundParameters params; + + if ( !soundemitterbase->GetParametersForSound( soundname, params, GENDER_NONE ) ) + { + return; + } + +#ifdef STAGING_ONLY + if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( params.soundname, sv_snd_filter.GetString() )) + { + return; + } +#endif // STAGING_ONLY + + if( iFlags & SND_CHANGE_PITCH ) + { + params.pitch = iPitch; + } + + if( iFlags & SND_CHANGE_VOL ) + { + params.volume = flVolume; + } + +#if defined( CLIENT_DLL ) + enginesound->EmitAmbientSound( params.soundname, params.volume, params.pitch, iFlags, soundtime ); +#else + engine->EmitAmbientSound(entindex, origin, params.soundname, params.volume, params.soundlevel, iFlags, params.pitch, soundtime ); +#endif + + bool needsCC = !( iFlags & ( SND_STOP | SND_CHANGE_VOL | SND_CHANGE_PITCH ) ); + + float soundduration = 0.0f; + + if ( duration || needsCC ) + { + soundduration = enginesound->GetSoundDuration( params.soundname ); + if ( duration ) + { + *duration = soundduration; + } + } + + TraceEmitSound( "EmitAmbientSound: '%s' emitted as '%s' (ent %i)\n", + soundname, params.soundname, entindex ); + + // We only want to trigger the CC on the start of the sound, not on any changes or halting of the sound + if ( needsCC ) + { + CRecipientFilter filter; + filter.AddAllPlayers(); + filter.MakeReliable(); + + CUtlVector< Vector > dummy; + EmitCloseCaption( filter, entindex, false, soundname, dummy, soundduration, false ); + } + + } + + void StopSoundByHandle( int entindex, const char *soundname, HSOUNDSCRIPTHANDLE& handle ) + { + if ( handle == SOUNDEMITTER_INVALID_HANDLE ) + { + handle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( soundname ); + } + + if ( handle == SOUNDEMITTER_INVALID_HANDLE ) + return; + + CSoundParametersInternal *params; + + params = soundemitterbase->InternalGetParametersForSound( (int)handle ); + if ( !params ) + { + return; + } + + // HACK: we have to stop all sounds if there are > 1 in the rndwave section... + int c = params->NumSoundNames(); + for ( int i = 0; i < c; ++i ) + { + char const *wavename = soundemitterbase->GetWaveName( params->GetSoundNames()[ i ].symbol ); + Assert( wavename ); + + enginesound->StopSound( + entindex, + params->GetChannel(), + wavename ); + + TraceEmitSound( "StopSound: '%s' stopped as '%s' (ent %i)\n", + soundname, wavename, entindex ); + } + } + + void StopSound( int entindex, const char *soundname ) + { + HSOUNDSCRIPTHANDLE handle = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex( soundname ); + if ( handle == SOUNDEMITTER_INVALID_HANDLE ) + { + return; + } + + StopSoundByHandle( entindex, soundname, handle ); + } + + + void StopSound( int iEntIndex, int iChannel, const char *pSample ) + { + if ( pSample && ( Q_stristr( pSample, ".wav" ) || Q_stristr( pSample, ".mp3" ) || pSample[0] == '!' ) ) + { + enginesound->StopSound( iEntIndex, iChannel, pSample ); + + TraceEmitSound( "StopSound: Raw wave stopped '%s' (ent %i)\n", + pSample, iEntIndex ); + } + else + { + // Look it up in sounds.txt and ignore other parameters + StopSound( iEntIndex, pSample ); + } + } + + void EmitAmbientSound( int entindex, const Vector &origin, const char *pSample, float volume, soundlevel_t soundlevel, int flags, int pitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) + { +#ifdef STAGING_ONLY + if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( pSample, sv_snd_filter.GetString() )) + { + return; + } +#endif // STAGING_ONLY + +#if !defined( CLIENT_DLL ) + CUtlVector< Vector > dummyorigins; + + // Loop through all registered microphones and tell them the sound was just played + // NOTE: This means that pitch shifts/sound changes on the original ambient will not be reflected in the re-broadcasted sound + bool bSwallowed = CEnvMicrophone::OnSoundPlayed( + entindex, + pSample, + soundlevel, + volume, + flags, + pitch, + &origin, + soundtime, + dummyorigins ); + if ( bSwallowed ) + return; +#endif + + if ( pSample && ( Q_stristr( pSample, ".wav" ) || Q_stristr( pSample, ".mp3" )) ) + { +#if defined( CLIENT_DLL ) + enginesound->EmitAmbientSound( pSample, volume, pitch, flags, soundtime ); +#else + engine->EmitAmbientSound( entindex, origin, pSample, volume, soundlevel, flags, pitch, soundtime ); +#endif + + if ( duration ) + { + *duration = enginesound->GetSoundDuration( pSample ); + } + + TraceEmitSound( "EmitAmbientSound: Raw wave emitted '%s' (ent %i)\n", + pSample, entindex ); + } + else + { + EmitAmbientSound( entindex, origin, pSample, volume, flags, pitch, soundtime, duration ); + } + } +}; + +static CSoundEmitterSystem g_SoundEmitterSystem( "CSoundEmitterSystem" ); + +IGameSystem *SoundEmitterSystem() +{ + return &g_SoundEmitterSystem; +} + +#if defined( CLIENT_DLL ) +void ReloadSoundEntriesInList( IFileList *pFilesToReload ) +{ + g_SoundEmitterSystem.ReloadSoundEntriesInList( pFilesToReload ); +} +#endif + +void S_SoundEmitterSystemFlush( void ) +{ +#if !defined( CLIENT_DLL ) + if ( !UTIL_IsCommandIssuedByServerAdmin() ) + return; +#endif + + // save the current soundscape + // kill the system + g_SoundEmitterSystem.Shutdown(); + + // restart the system + g_SoundEmitterSystem.Init(); + +#if !defined( CLIENT_DLL ) + // Redo precache all wave files... (this should work now that we have dynamic string tables) + g_SoundEmitterSystem.LevelInitPreEntity(); + + // These store raw sound indices for faster precaching, blow them away. + ClearModelSoundsCache(); +#endif + + // TODO: when we go to a handle system, we'll need to invalidate handles somehow +} + +#if defined( CLIENT_DLL ) +CON_COMMAND_F( cl_soundemitter_flush, "Flushes the sounds.txt system (client only)", FCVAR_CHEAT ) +#else +CON_COMMAND_F( sv_soundemitter_flush, "Flushes the sounds.txt system (server only)", FCVAR_DEVELOPMENTONLY ) +#endif +{ + S_SoundEmitterSystemFlush( ); +} + +#if !defined(_RETAIL) + +#if !defined( CLIENT_DLL ) + +#if !defined( _XBOX ) + +CON_COMMAND_F( sv_soundemitter_filecheck, "Report missing wave files for sounds and game_sounds files.", FCVAR_DEVELOPMENTONLY ) +{ + if ( !UTIL_IsCommandIssuedByServerAdmin() ) + return; + + int missing = soundemitterbase->CheckForMissingWavFiles( true ); + DevMsg( "---------------------------\nTotal missing files %i\n", missing ); +} + +CON_COMMAND_F( sv_findsoundname, "Find sound names which reference the specified wave files.", FCVAR_DEVELOPMENTONLY ) +{ + if ( !UTIL_IsCommandIssuedByServerAdmin() ) + return; + + if ( args.ArgC() != 2 ) + return; + + int c = soundemitterbase->GetSoundCount(); + int i; + + char const *search = args[ 1 ]; + if ( !search ) + return; + + for ( i = 0; i < c; i++ ) + { + CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound( i ); + if ( !internal ) + continue; + + int waveCount = internal->NumSoundNames(); + if ( waveCount > 0 ) + { + for( int wave = 0; wave < waveCount; wave++ ) + { + char const *wavefilename = soundemitterbase->GetWaveName( internal->GetSoundNames()[ wave ].symbol ); + + if ( Q_stristr( wavefilename, search ) ) + { + char const *soundname = soundemitterbase->GetSoundName( i ); + char const *scriptname = soundemitterbase->GetSourceFileForSound( i ); + + Msg( "Referenced by '%s:%s' -- %s\n", scriptname, soundname, wavefilename ); + } + } + } + } +} +#endif // !_XBOX + +#else +void Playgamesound_f( const CCommand &args ) +{ + CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + if ( args.ArgC() > 2 ) + { + Vector position = pPlayer->EyePosition(); + Vector forward; + pPlayer->GetVectors( &forward, NULL, NULL ); + position += atof( args[2] ) * forward; + CPASAttenuationFilter filter( pPlayer ); + EmitSound_t params; + params.m_pSoundName = args[1]; + params.m_pOrigin = &position; + params.m_flVolume = 0.0f; + params.m_nPitch = 0; + g_SoundEmitterSystem.EmitSound( filter, 0, params ); + } + else + { + pPlayer->EmitSound( args[1] ); + } + } + else + { + Msg("Can't play until a game is started.\n"); + // UNDONE: Make something like this work? + //CBroadcastRecipientFilter filter; + //g_SoundEmitterSystem.EmitSound( filter, 1, args[1], 0.0, 0, 0, &vec3_origin, 0, NULL ); + } +} + +static int GamesoundCompletion( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) +{ + int current = 0; + + const char *cmdname = "playgamesound"; + char *substring = NULL; + int substringLen = 0; + if ( Q_strstr( partial, cmdname ) && strlen(partial) > strlen(cmdname) + 1 ) + { + substring = (char *)partial + strlen( cmdname ) + 1; + substringLen = strlen(substring); + } + + for ( int i = soundemitterbase->GetSoundCount()-1; i >= 0 && current < COMMAND_COMPLETION_MAXITEMS; i-- ) + { + const char *pSoundName = soundemitterbase->GetSoundName( i ); + if ( pSoundName ) + { + if ( !substring || !Q_strncasecmp( pSoundName, substring, substringLen ) ) + { + Q_snprintf( commands[ current ], sizeof( commands[ current ] ), "%s %s", cmdname, pSoundName ); + current++; + } + } + } + + return current; +} + +static ConCommand Command_Playgamesound( "playgamesound", Playgamesound_f, "Play a sound from the game sounds txt file", FCVAR_CLIENTCMD_CAN_EXECUTE | FCVAR_SERVER_CAN_EXECUTE, GamesoundCompletion ); +#endif + +#endif + +//----------------------------------------------------------------------------- +// Purpose: Non-static override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); +// Input : *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( const char *soundname, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ + //VPROF( "CBaseEntity::EmitSound" ); + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + + CPASAttenuationFilter filter( this, soundname ); + + EmitSound_t params; + params.m_pSoundName = soundname; + params.m_flSoundTime = soundtime; + params.m_pflSoundDuration = duration; + params.m_bWarnOnDirectWaveReference = true; + + EmitSound( filter, entindex(), params ); +} + +//----------------------------------------------------------------------------- +// Purpose: Non-static override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); +// Input : *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + + // VPROF( "CBaseEntity::EmitSound" ); + CPASAttenuationFilter filter( this, soundname, handle ); + + EmitSound_t params; + params.m_pSoundName = soundname; + params.m_flSoundTime = soundtime; + params.m_pflSoundDuration = duration; + params.m_bWarnOnDirectWaveReference = true; + + EmitSound( filter, entindex(), params, handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : filter - +// iEntIndex - +// *soundname - +// *pOrigin - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, const Vector *pOrigin /*= NULL*/, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ + if ( !soundname ) + return; + + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + + // VPROF( "CBaseEntity::EmitSound" ); + EmitSound_t params; + params.m_pSoundName = soundname; + params.m_flSoundTime = soundtime; + params.m_pOrigin = pOrigin; + params.m_pflSoundDuration = duration; + params.m_bWarnOnDirectWaveReference = true; + + EmitSound( filter, iEntIndex, params, params.m_hSoundScriptHandle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : filter - +// iEntIndex - +// *soundname - +// *pOrigin - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const char *soundname, HSOUNDSCRIPTHANDLE& handle, const Vector *pOrigin /*= NULL*/, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + + //VPROF( "CBaseEntity::EmitSound" ); + EmitSound_t params; + params.m_pSoundName = soundname; + params.m_flSoundTime = soundtime; + params.m_pOrigin = pOrigin; + params.m_pflSoundDuration = duration; + params.m_bWarnOnDirectWaveReference = true; + + EmitSound( filter, iEntIndex, params, handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : filter - +// iEntIndex - +// params - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params ) +{ + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + +#ifdef GAME_DLL + CBaseEntity *pEntity = UTIL_EntityByIndex( iEntIndex ); +#else + C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); +#endif + if ( pEntity ) + { + pEntity->ModifyEmitSoundParams( const_cast< EmitSound_t& >( params ) ); + } + + // VPROF( "CBaseEntity::EmitSound" ); + // Call into the sound emitter system... + g_SoundEmitterSystem.EmitSound( filter, iEntIndex, params ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : filter - +// iEntIndex - +// params - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHANDLE& handle ) +{ + VPROF_BUDGET( "CBaseEntity::EmitSound", _T( "CBaseEntity::EmitSound" ) ); + +#ifdef GAME_DLL + CBaseEntity *pEntity = UTIL_EntityByIndex( iEntIndex ); +#else + C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); +#endif + if ( pEntity ) + { + pEntity->ModifyEmitSoundParams( const_cast< EmitSound_t& >( params ) ); + } + + // VPROF( "CBaseEntity::EmitSound" ); + // Call into the sound emitter system... + g_SoundEmitterSystem.EmitSoundByHandle( filter, iEntIndex, params, handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::StopSound( const char *soundname ) +{ +#if defined( CLIENT_DLL ) + if ( entindex() == -1 ) + { + // If we're a clientside entity, we need to use the soundsourceindex instead of the entindex + StopSound( GetSoundSourceIndex(), soundname ); + return; + } +#endif + + StopSound( entindex(), soundname ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::StopSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle ) +{ +#if defined( CLIENT_DLL ) + if ( entindex() == -1 ) + { + // If we're a clientside entity, we need to use the soundsourceindex instead of the entindex + StopSound( GetSoundSourceIndex(), soundname ); + return; + } +#endif + + g_SoundEmitterSystem.StopSoundByHandle( entindex(), soundname, handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : iEntIndex - +// *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::StopSound( int iEntIndex, const char *soundname ) +{ + g_SoundEmitterSystem.StopSound( iEntIndex, soundname ); +} + +void CBaseEntity::StopSound( int iEntIndex, int iChannel, const char *pSample ) +{ + g_SoundEmitterSystem.StopSound( iEntIndex, iChannel, pSample ); +} + +soundlevel_t CBaseEntity::LookupSoundLevel( const char *soundname ) +{ + return soundemitterbase->LookupSoundLevel( soundname ); +} + + +soundlevel_t CBaseEntity::LookupSoundLevel( const char *soundname, HSOUNDSCRIPTHANDLE& handle ) +{ + return soundemitterbase->LookupSoundLevelByHandle( soundname, handle ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *entity - +// origin - +// flags - +// *soundname - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ + g_SoundEmitterSystem.EmitAmbientSound( entindex, origin, soundname, 0.0, flags, 0, soundtime, duration ); +} + +// HACK HACK: Do we need to pull the entire SENTENCEG_* wrapper over to the client .dll? +#if defined( CLIENT_DLL ) +int SENTENCEG_Lookup(const char *sample) +{ + return engine->SentenceIndexFromName( sample + 1 ); +} +#endif + +void UTIL_EmitAmbientSound( int entindex, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) +{ +#ifdef STAGING_ONLY + if ( sv_snd_filter.GetString()[ 0 ] && !V_stristr( samp, sv_snd_filter.GetString() )) + { + return; + } +#endif // STAGING_ONLY + + if (samp && *samp == '!') + { + int sentenceIndex = SENTENCEG_Lookup(samp); + if (sentenceIndex >= 0) + { + char name[32]; + Q_snprintf( name, sizeof(name), "!%d", sentenceIndex ); +#if !defined( CLIENT_DLL ) + engine->EmitAmbientSound( entindex, vecOrigin, name, vol, soundlevel, fFlags, pitch, soundtime ); +#else + enginesound->EmitAmbientSound( name, vol, pitch, fFlags, soundtime ); +#endif + if ( duration ) + { + *duration = enginesound->GetSoundDuration( name ); + } + + g_SoundEmitterSystem.TraceEmitSound( "UTIL_EmitAmbientSound: Sentence emitted '%s' (ent %i)\n", + name, entindex ); + } + } + else + { + g_SoundEmitterSystem.EmitAmbientSound( entindex, vecOrigin, samp, vol, soundlevel, fFlags, pitch, soundtime, duration ); + } +} + +static const char *UTIL_TranslateSoundName( const char *soundname, const char *actormodel ) +{ + Assert( soundname ); + + if ( Q_stristr( soundname, ".wav" ) || Q_stristr( soundname, ".mp3" ) ) + { + if ( Q_stristr( soundname, ".wav" ) ) + { + WaveTrace( soundname, "UTIL_TranslateSoundName" ); + } + return soundname; + } + + return soundemitterbase->GetWavFileForSound( soundname, actormodel ); +} + +void CBaseEntity::GenderExpandString( char const *in, char *out, int maxlen ) +{ + soundemitterbase->GenderExpandString( STRING( GetModelName() ), in, out, maxlen ); +} + +bool CBaseEntity::GetParametersForSound( const char *soundname, CSoundParameters ¶ms, const char *actormodel ) +{ + gender_t gender = soundemitterbase->GetActorGender( actormodel ); + + return soundemitterbase->GetParametersForSound( soundname, params, gender ); +} + +bool CBaseEntity::GetParametersForSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, CSoundParameters ¶ms, const char *actormodel ) +{ + gender_t gender = soundemitterbase->GetActorGender( actormodel ); + + return soundemitterbase->GetParametersForSoundEx( soundname, handle, params, gender ); +} + +HSOUNDSCRIPTHANDLE CBaseEntity::PrecacheScriptSound( const char *soundname ) +{ +#if !defined( CLIENT_DLL ) + return g_SoundEmitterSystem.PrecacheScriptSound( soundname ); +#else + return soundemitterbase->GetSoundIndex( soundname ); +#endif +} + +void CBaseEntity::PrefetchScriptSound( const char *soundname ) +{ + g_SoundEmitterSystem.PrefetchScriptSound( soundname ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *soundname - +// Output : float +//----------------------------------------------------------------------------- +float CBaseEntity::GetSoundDuration( const char *soundname, char const *actormodel ) +{ + return enginesound->GetSoundDuration( PSkipSoundChars( UTIL_TranslateSoundName( soundname, actormodel ) ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : filter - +// *token - +// duration - +// warnifmissing - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigin, float duration, bool warnifmissing /*= false*/ ) +{ + bool fromplayer = false; + CBaseEntity *ent = CBaseEntity::Instance( entindex ); + while ( ent ) + { + if ( ent->IsPlayer() ) + { + fromplayer = true; + break; + } + ent = ent->GetOwnerEntity(); + } + + g_SoundEmitterSystem.EmitCloseCaption( filter, entindex, fromplayer, token, soundorigin, duration, warnifmissing ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// preload - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseEntity::PrecacheSound( const char *name ) +{ + if ( IsPC() && !g_bPermitDirectSoundPrecache ) + { + Warning( "Direct precache of %s\n", name ); + } + + // If this is out of order, warn + if ( !CBaseEntity::IsPrecacheAllowed() ) + { + if ( !enginesound->IsSoundPrecached( name ) ) + { + Assert( !"CBaseEntity::PrecacheSound: too late" ); + + Warning( "Late precache of %s\n", name ); + } + } + + bool bret = enginesound->PrecacheSound( name, true ); + return bret; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +//----------------------------------------------------------------------------- +void CBaseEntity::PrefetchSound( const char *name ) +{ + enginesound->PrefetchSound( name ); +} + |