2013-12-03 07:31:46 +04:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements an entity that measures sound volume at a point in a map.
//
// This entity listens as though it is an NPC, meaning it will only
// hear sounds that were emitted using the CSound::InsertSound function.
//
// It does not hear danger sounds since they are not technically sounds.
//
//=============================================================================
# include "cbase.h"
# include "entityinput.h"
# include "entityoutput.h"
# include "eventqueue.h"
# include "mathlib/mathlib.h"
# include "soundent.h"
# include "envmicrophone.h"
# include "soundflags.h"
# include "engine/IEngineSound.h"
# include "filters.h"
2021-04-27 18:59:39 +03:00
# ifdef MAPBASE
# include "fmtstr.h"
# endif
2013-12-03 07:31:46 +04:00
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
//#define DEBUG_MICROPHONE
const float MICROPHONE_SETTLE_EPSILON = 0.005 ;
2021-04-27 18:59:39 +03:00
# ifdef MAPBASE
static ConVar sv_microphones_always_pickup_sentences ( " sv_microphones_always_pickup_sentences " , " 0 " , FCVAR_NONE , " Allows env_microphones to always detect and play back sentences, regardless of their keyvalues. " ) ;
# endif
2013-12-03 07:31:46 +04:00
// List of env_microphones who want to be told whenever a sound is started
static CUtlVector < CHandle < CEnvMicrophone > > s_Microphones ;
LINK_ENTITY_TO_CLASS ( env_microphone , CEnvMicrophone ) ;
BEGIN_DATADESC ( CEnvMicrophone )
DEFINE_KEYFIELD ( m_bDisabled , FIELD_BOOLEAN , " StartDisabled " ) ,
DEFINE_FIELD ( m_hMeasureTarget , FIELD_EHANDLE ) ,
DEFINE_KEYFIELD ( m_nSoundMask , FIELD_INTEGER , " SoundMask " ) ,
DEFINE_KEYFIELD ( m_flSensitivity , FIELD_FLOAT , " Sensitivity " ) ,
DEFINE_KEYFIELD ( m_flSmoothFactor , FIELD_FLOAT , " SmoothFactor " ) ,
DEFINE_KEYFIELD ( m_iszSpeakerName , FIELD_STRING , " SpeakerName " ) ,
DEFINE_KEYFIELD ( m_iszListenFilter , FIELD_STRING , " ListenFilter " ) ,
DEFINE_FIELD ( m_hListenFilter , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_hSpeaker , FIELD_EHANDLE ) ,
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
DEFINE_KEYFIELD ( m_iszLandmarkName , FIELD_STRING , " landmark " ) ,
DEFINE_FIELD ( m_hLandmark , FIELD_EHANDLE ) ,
Mapbase v3.0
- Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing *
- Added support for regular expression matching
- Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp
- Fixed env_global_light brightness
- Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro)
- New UnZoomWithRate and SetZoomRate inputs on env_zoom
- New "Don't change target's angles" flag on logic_measure_movement
- Fixed logic_measure_movement not using ignore origin flags correctly
- Fixed filter_damage_mod secondary filter not recognizing mode correctly
- Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code
- Added SetEntityName input for setting an entity's targetname
- Added "SetTarget" support to point_posecontroller
- Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health
- Added ignore flags and several direction-related inputs to math_vector
- Added pose parameter stuff to logic_modelinfo
- Fixed ChangeWeapon not changing during combat
- Fixed holster/unholster on NPCs without holster/unholster animations
- Fixed func_tank and other "player in the way" code ignoring notarget
- Added SetPoseParameter input to animating entities
- Introduced an experimental chapter system which allows for custom chapter title/restriction management
- Added SetChapterTitle input to worldspawn for dynamic title changing
- Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues
- Fixed mapbase_rpc_enabled not actually affecting RPC
- Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users
- Fixed some problems with the new shared activities
- Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity
- Added env_microphone pitch scale for scaling the pitch of transmitted sounds
- Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT
- Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing
- Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders
- Areaportal leaks now stop compilation in leaktest
- Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
2020-02-05 22:08:49 +03:00
DEFINE_KEYFIELD ( m_flPitchScale , FIELD_FLOAT , " PitchScale " ) ,
2021-03-14 21:49:10 +03:00
DEFINE_KEYFIELD ( m_flVolumeScale , FIELD_FLOAT , " VolumeScale " ) ,
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
DEFINE_KEYFIELD ( m_nChannel , FIELD_INTEGER , " channel " ) ,
2019-08-31 22:28:20 +03:00
# endif
2013-12-03 07:31:46 +04:00
// DEFINE_FIELD(m_bAvoidFeedback, FIELD_BOOLEAN), // DONT SAVE
DEFINE_KEYFIELD ( m_iSpeakerDSPPreset , FIELD_INTEGER , " speaker_dsp_preset " ) ,
DEFINE_KEYFIELD ( m_flMaxRange , FIELD_FLOAT , " MaxRange " ) ,
DEFINE_AUTO_ARRAY ( m_szLastSound , FIELD_CHARACTER ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " Enable " , InputEnable ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " Disable " , InputDisable ) ,
DEFINE_INPUTFUNC ( FIELD_STRING , " SetSpeakerName " , InputSetSpeakerName ) ,
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
DEFINE_INPUTFUNC ( FIELD_INTEGER , " SetDSPPreset " , InputSetDSPPreset ) ,
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
DEFINE_INPUTFUNC ( FIELD_FLOAT , " SetPitchScale " , InputSetPitchScale ) ,
2021-03-14 21:49:10 +03:00
DEFINE_INPUTFUNC ( FIELD_FLOAT , " SetVolumeScale " , InputSetVolumeScale ) ,
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
DEFINE_INPUTFUNC ( FIELD_INTEGER , " SetChannel " , InputSetChannel ) ,
2019-08-31 22:28:20 +03:00
# endif
2013-12-03 07:31:46 +04:00
DEFINE_OUTPUT ( m_SoundLevel , " SoundLevel " ) ,
DEFINE_OUTPUT ( m_OnRoutedSound , " OnRoutedSound " ) ,
DEFINE_OUTPUT ( m_OnHeardSound , " OnHeardSound " ) ,
END_DATADESC ( )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvMicrophone : : ~ CEnvMicrophone ( void )
{
s_Microphones . FindAndRemove ( this ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Called before spawning, after keyvalues have been handled.
//-----------------------------------------------------------------------------
void CEnvMicrophone : : Spawn ( void )
{
//
// Build our sound type mask from our spawnflags.
//
static int nFlags [ ] [ 2 ] =
{
{ SF_MICROPHONE_SOUND_COMBAT , SOUND_COMBAT } ,
{ SF_MICROPHONE_SOUND_WORLD , SOUND_WORLD } ,
{ SF_MICROPHONE_SOUND_PLAYER , SOUND_PLAYER } ,
{ SF_MICROPHONE_SOUND_BULLET_IMPACT , SOUND_BULLET_IMPACT } ,
{ SF_MICROPHONE_SOUND_EXPLOSION , SOUND_CONTEXT_EXPLOSION } ,
} ;
for ( int i = 0 ; i < sizeof ( nFlags ) / sizeof ( nFlags [ 0 ] ) ; i + + )
{
if ( m_spawnflags & nFlags [ i ] [ 0 ] )
{
m_nSoundMask | = nFlags [ i ] [ 1 ] ;
}
}
if ( m_flSensitivity = = 0 )
{
//
// Avoid a divide by zero in CanHearSound.
//
m_flSensitivity = 1 ;
}
else if ( m_flSensitivity > 10 )
{
m_flSensitivity = 10 ;
}
m_flSmoothFactor = clamp ( m_flSmoothFactor , 0.f , 0.9f ) ;
if ( ! m_bDisabled )
{
SetNextThink ( gpGlobals - > curtime + 0.1f ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Called after all entities have spawned and after a load game.
// Finds the reference point at which to measure sound level.
//-----------------------------------------------------------------------------
void CEnvMicrophone : : Activate ( void )
{
BaseClass : : Activate ( ) ;
// Get a handle to my filter entity if there is one
if ( m_iszListenFilter ! = NULL_STRING )
{
m_hListenFilter = dynamic_cast < CBaseFilter * > ( gEntList . FindEntityByName ( NULL , m_iszListenFilter ) ) ;
}
if ( m_target ! = NULL_STRING )
{
m_hMeasureTarget = gEntList . FindEntityByName ( NULL , STRING ( m_target ) ) ;
//
// If we were given a bad measure target, just measure sound where we are.
//
if ( ( m_hMeasureTarget = = NULL ) | | ( m_hMeasureTarget - > edict ( ) = = NULL ) )
{
// We've decided to disable this warning since this seems to be the 90% case.
//Warning( "EnvMicrophone - Measure target not found or measure target with no origin. Using Self.!\n");
m_hMeasureTarget = this ;
}
}
else
{
m_hMeasureTarget = this ;
}
ActivateSpeaker ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvMicrophone : : OnRestore ( void )
{
BaseClass : : OnRestore ( ) ;
ActivateSpeaker ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: If we've got a speaker, add ourselves to the list of microphones that want to listen
//-----------------------------------------------------------------------------
void CEnvMicrophone : : ActivateSpeaker ( void )
{
// If we're enabled, set the dsp_speaker preset to my specified one
if ( ! m_bDisabled )
{
ConVarRef dsp_speaker ( " dsp_speaker " ) ;
if ( dsp_speaker . IsValid ( ) )
{
int iDSPPreset = m_iSpeakerDSPPreset ;
if ( ! iDSPPreset )
{
// Reset it to the default
iDSPPreset = atoi ( dsp_speaker . GetDefault ( ) ) ;
}
DevMsg ( 2 , " Microphone %s set dsp_speaker to %d. \n " , STRING ( GetEntityName ( ) ) , iDSPPreset ) ;
dsp_speaker . SetValue ( m_iSpeakerDSPPreset ) ;
}
}
if ( m_iszSpeakerName ! = NULL_STRING )
{
// We've got a speaker to play heard sounds through. To do this, we need to add ourselves
// to the list of microphones who want to be told whenever a sound is played.
if ( s_Microphones . Find ( this ) = = - 1 )
{
s_Microphones . AddToTail ( this ) ;
}
}
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
if ( m_iszLandmarkName ! = NULL_STRING )
{
m_hLandmark = gEntList . FindEntityByName ( NULL , m_iszLandmarkName , this , NULL , NULL ) ;
}
# endif
2013-12-03 07:31:46 +04:00
}
//-----------------------------------------------------------------------------
// Purpose: Stops the microphone from sampling the sound level and firing the
// SoundLevel output.
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputEnable ( inputdata_t & inputdata )
{
if ( m_bDisabled )
{
m_bDisabled = false ;
SetNextThink ( gpGlobals - > curtime + 0.1f ) ;
ActivateSpeaker ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Resumes sampling the sound level and firing the SoundLevel output.
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputDisable ( inputdata_t & inputdata )
{
m_bDisabled = true ;
if ( m_hSpeaker )
{
2021-04-27 18:59:39 +03:00
# ifdef MAPBASE
CBaseEntity : : StopSound ( m_hSpeaker - > entindex ( ) , m_nChannel , m_szLastSound ) ;
# else
2013-12-03 07:31:46 +04:00
CBaseEntity : : StopSound ( m_hSpeaker - > entindex ( ) , CHAN_STATIC , m_szLastSound ) ;
2021-04-27 18:59:39 +03:00
# endif
2013-12-03 07:31:46 +04:00
m_szLastSound [ 0 ] = 0 ;
// Remove ourselves from the list of active mics
s_Microphones . FindAndRemove ( this ) ;
}
SetNextThink ( TICK_NEVER_THINK ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputSetSpeakerName ( inputdata_t & inputdata )
{
SetSpeakerName ( inputdata . value . StringID ( ) ) ;
}
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputSetDSPPreset ( inputdata_t & inputdata )
{
m_iSpeakerDSPPreset = inputdata . value . Int ( ) ;
ActivateSpeaker ( ) ;
}
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputSetPitchScale ( inputdata_t & inputdata )
{
m_flPitchScale = inputdata . value . Float ( ) ;
}
2021-03-14 21:49:10 +03:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputSetVolumeScale ( inputdata_t & inputdata )
{
m_flVolumeScale = inputdata . value . Float ( ) ;
}
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CEnvMicrophone : : InputSetChannel ( inputdata_t & inputdata )
{
m_nChannel = inputdata . value . Int ( ) ;
}
2019-08-31 22:28:20 +03:00
# endif
2013-12-03 07:31:46 +04:00
//-----------------------------------------------------------------------------
// Purpose: Checks whether this microphone can hear a given sound, and at what
// relative volume level.
// Input : pSound - Sound to test.
// flVolume - Returns with the relative sound volume from 0 - 1.
// Output : Returns true if the sound could be heard at the sample point, false if not.
//-----------------------------------------------------------------------------
bool CEnvMicrophone : : CanHearSound ( CSound * pSound , float & flVolume )
{
flVolume = 0 ;
if ( m_bDisabled )
{
return false ;
}
// Cull out sounds except from specific entities
CBaseFilter * pFilter = m_hListenFilter . Get ( ) ;
if ( pFilter )
{
CBaseEntity * pSoundOwner = pSound - > m_hOwner . Get ( ) ;
if ( ! pSoundOwner | | ! pFilter - > PassesFilter ( this , pSoundOwner ) )
{
return false ;
}
}
float flDistance = ( pSound - > GetSoundOrigin ( ) - m_hMeasureTarget - > GetAbsOrigin ( ) ) . Length ( ) ;
if ( flDistance = = 0 )
{
flVolume = 1.0 ;
return true ;
}
// Over our max range?
if ( m_flMaxRange & & flDistance > m_flMaxRange )
{
return false ;
}
if ( flDistance < = pSound - > Volume ( ) * m_flSensitivity )
{
flVolume = 1 - ( flDistance / ( pSound - > Volume ( ) * m_flSensitivity ) ) ;
flVolume = clamp ( flVolume , 0.f , 1.f ) ;
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if the microphone can hear the specified sound
//-----------------------------------------------------------------------------
bool CEnvMicrophone : : CanHearSound ( int entindex , soundlevel_t soundlevel , float & flVolume , const Vector * pOrigin )
{
if ( m_bDisabled )
{
flVolume = 0 ;
return false ;
}
if ( ( m_spawnflags & SF_MICROPHONE_IGNORE_NONATTENUATED ) & & soundlevel = = SNDLVL_NONE )
{
return false ;
}
// Sound might be coming from an origin or from an entity.
CBaseEntity * pEntity = NULL ;
if ( entindex )
{
pEntity = CBaseEntity : : Instance ( engine - > PEntityOfEntIndex ( entindex ) ) ;
}
// Cull out sounds except from specific entities
CBaseFilter * pFilter = m_hListenFilter . Get ( ) ;
if ( pFilter )
{
if ( ! pEntity | | ! pFilter - > PassesFilter ( this , pEntity ) )
{
flVolume = 0 ;
return false ;
}
}
float flDistance = 0 ;
if ( pOrigin )
{
flDistance = pOrigin - > DistTo ( m_hMeasureTarget - > GetAbsOrigin ( ) ) ;
}
else if ( pEntity )
{
flDistance = pEntity - > WorldSpaceCenter ( ) . DistTo ( m_hMeasureTarget - > GetAbsOrigin ( ) ) ;
}
// Over our max range?
if ( m_flMaxRange & & flDistance > m_flMaxRange )
{
# ifdef DEBUG_MICROPHONE
Msg ( " OUT OF RANGE. \n " ) ;
# endif
return false ;
}
# ifdef DEBUG_MICROPHONE
Msg ( " flVolume %f " , flVolume ) ;
# endif
// Reduce the volume by the amount it fell to get to the microphone
float gain = enginesound - > GetDistGainFromSoundLevel ( soundlevel , flDistance ) ;
flVolume * = gain ;
# ifdef DEBUG_MICROPHONE
Msg ( " dist %2f, soundlevel %d: gain %f " , flDistance , ( int ) soundlevel , gain ) ;
if ( ! flVolume )
{
Msg ( " : REJECTED \n " ) ;
}
else
{
Msg ( " : SENT \n " ) ;
}
# endif
return ( flVolume > 0 ) ;
}
void CEnvMicrophone : : SetSensitivity ( float flSensitivity )
{
m_flSensitivity = flSensitivity ;
}
void CEnvMicrophone : : SetSpeakerName ( string_t iszSpeakerName )
{
m_iszSpeakerName = iszSpeakerName ;
// Set the speaker to null. This will force it to find the speaker next time a sound is routed.
m_hSpeaker = NULL ;
ActivateSpeaker ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Listens for sounds and updates the value of the SoundLevel output.
//-----------------------------------------------------------------------------
void CEnvMicrophone : : Think ( void )
{
int nSound = CSoundEnt : : ActiveList ( ) ;
bool fHearSound = false ;
float flMaxVolume = 0 ;
//
// Find the loudest sound that this microphone cares about.
//
while ( nSound ! = SOUNDLIST_EMPTY )
{
CSound * pCurrentSound = CSoundEnt : : SoundPointerForIndex ( nSound ) ;
if ( pCurrentSound )
{
if ( m_nSoundMask & pCurrentSound - > SoundType ( ) )
{
float flVolume = 0 ;
if ( CanHearSound ( pCurrentSound , flVolume ) & & ( flVolume > flMaxVolume ) )
{
flMaxVolume = flVolume ;
fHearSound = true ;
}
}
}
nSound = pCurrentSound - > NextSound ( ) ;
}
if ( fHearSound )
{
m_OnHeardSound . FireOutput ( this , this ) ;
}
if ( flMaxVolume ! = m_SoundLevel . Get ( ) )
{
//
// Don't smooth if we are within an epsilon. This allows the output to stop firing
// much more quickly.
//
if ( fabs ( flMaxVolume - m_SoundLevel . Get ( ) ) < MICROPHONE_SETTLE_EPSILON )
{
m_SoundLevel . Set ( flMaxVolume , this , this ) ;
}
else
{
m_SoundLevel . Set ( flMaxVolume * ( 1 - m_flSmoothFactor ) + m_SoundLevel . Get ( ) * m_flSmoothFactor , this , this ) ;
}
}
SetNextThink ( gpGlobals - > curtime + 0.1f ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Hook for the sound system to tell us when a sound's been played
//-----------------------------------------------------------------------------
MicrophoneResult_t CEnvMicrophone : : SoundPlayed ( int entindex , const char * soundname , soundlevel_t soundlevel , float flVolume , int iFlags , int iPitch , const Vector * pOrigin , float soundtime , CUtlVector < Vector > & soundorigins )
{
if ( m_bAvoidFeedback )
return MicrophoneResult_Ok ;
// Don't hear sounds that have already been heard by a microphone to avoid feedback!
if ( iFlags & SND_SPEAKER )
return MicrophoneResult_Ok ;
# ifdef DEBUG_MICROPHONE
Msg ( " %s heard %s: " , STRING ( GetEntityName ( ) ) , soundname ) ;
# endif
if ( ! CanHearSound ( entindex , soundlevel , flVolume , pOrigin ) )
return MicrophoneResult_Ok ;
// We've heard it. Play it out our speaker. If our speaker's gone away, we're done.
if ( ! m_hSpeaker )
{
// First time, find our speaker. Done here, because finding it in Activate() wouldn't
// find players, and we need to be able to specify !player for a speaker.
if ( m_iszSpeakerName ! = NULL_STRING )
{
m_hSpeaker = gEntList . FindEntityByName ( NULL , STRING ( m_iszSpeakerName ) ) ;
if ( ! m_hSpeaker )
{
Warning ( " EnvMicrophone %s specifies a non-existent speaker name: %s \n " , STRING ( GetEntityName ( ) ) , STRING ( m_iszSpeakerName ) ) ;
m_iszSpeakerName = NULL_STRING ;
}
}
if ( ! m_hSpeaker )
{
return MicrophoneResult_Remove ;
}
}
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
// Something similar to trigger_teleport landmarks for sounds transmitting to speaker
Vector vecOrigin = m_hSpeaker - > GetAbsOrigin ( ) ;
if ( m_hLandmark )
{
Vector vecSoundPos ;
if ( pOrigin )
vecSoundPos = * pOrigin ;
else if ( CBaseEntity * pEntity = CBaseEntity : : Instance ( engine - > PEntityOfEntIndex ( entindex ) ) )
vecSoundPos = pEntity - > GetAbsOrigin ( ) ;
vecOrigin + = ( vecSoundPos - m_hLandmark - > GetAbsOrigin ( ) ) ;
}
# endif
2013-12-03 07:31:46 +04:00
m_bAvoidFeedback = true ;
// Add the speaker flag. Detected at playback and applies the speaker filter.
iFlags | = SND_SPEAKER ;
CPASAttenuationFilter filter ( m_hSpeaker ) ;
EmitSound_t ep ;
2021-04-27 18:59:39 +03:00
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
# ifdef MAPBASE
2021-04-27 18:59:39 +03:00
if ( m_bHearingSentence )
{
CBaseEntity : : EmitSentenceByIndex ( filter , m_hSpeaker - > entindex ( ) , m_nChannel , atoi ( soundname ) , flVolume , soundlevel , 0 , iPitch , & vecOrigin , NULL , true , soundtime ,
m_iSpeakerDSPPreset , entindex ) ;
}
else
Mapbase v3.1
- Fixed filter_damage_mod blocking all damage which doesn't match the secondary filter regardless of secondary filter mode
- Fixed impulse 101 and other give-related commands leaving behind weapons with occupied slots
- Fixed a crash with scripted_sound's PlaySoundOnEntity when the entity doesn't exist
- Added OnSoundFinished output to ambient_generic
- Added the ability to use custom models/nuggets with item_grubnugget
- Fixed a crash with citizen medics healing nonexistent targets
- Added "SetDistLook" and "SetDistTooFar" inputs for NPCs, allowing manual adjustment of NPC sight distance
- Added keyvalue and input to env_microphone for utilizing a different audio channel
- Added "SetPitchScale" input to env_microphone
- Fixed info_player_view_proxy not using angles
- Fixed dirt variant elite model not being recognized as elite
- Made headcrab hints properly register the start of use (for hint outputs)
- Made RPG use a more realistic firing rate for NPCs which aren't constrained by slow RPG animations, like soldiers
- Added spawnflag for func_breakable_surf to correctly play the break sound
- Added keyvalue for using cheaper warn sound code for combine_mines
- Added "OnSpawnNPC" output for npc_combinedropship when it spawns a soldier, rollermine, or strider
- Added signal gesture activities
- Fixed stunstick not using metrocop knockout/stun code correctly
- Fixed a possible crash involving a NPC's weapon being removed during alt-fire
- Fixed(?) flashlight shadow filters
- Added support for multiple look entities in trigger_look
- Added npc_metropolice alt-firing
- Fixed npc_metropolice using pistol burst firing on weapon_357
- Fixed npc_metropolice not deploying manhacks/throwing grenades in standoffs
- Fixed npc_metropolice not recognizing some crouch activities correctly
- Changed weapon_357 so it runs a tracer each shot from NPCs
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass
- Added "SetSpeedModifier" to NPCs, based on 1upD's shadow walker code
- Made game_convar_mod much more reliable
- Fixed non-mirrored npc_turret_lab refusing to die
- Made npc_turret_lab use SMG1 ammo instead of AR2 ammo
- Fixed block LOS brushes sometimes not working with players (and possibly similar issues)
- Raised maximum renderable entities from 4096 to 16384, based on ficool2's limit research
- Added SDK_ShatteredGlass, a Mapbase version of ShatteredGlass. Can display parallax corrected cubemaps from its unbroken form
- Fixed VBSP breaking func_breakable_surf, etc. when using parallax corrected cubemaps
- Raised maximum VBSP entities from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP worldlights from 8192 to 65536, based on ficool2's limit research
- Raised maximum VBSP overlays from 512 to 8192, based on ficool2's limit research
- Other misc. fixes
2020-05-02 05:06:02 +03:00
# endif
2021-04-27 18:59:39 +03:00
{
2019-08-31 22:28:20 +03:00
# ifdef MAPBASE
2021-04-27 18:59:39 +03:00
ep . m_nChannel = m_nChannel ;
if ( m_flVolumeScale ! = 1.0f )
ep . m_flVolume = ( flVolume * m_flVolumeScale ) ;
else
ep . m_flVolume = flVolume ;
if ( m_flPitchScale ! = 1.0f )
ep . m_nPitch = ( int ) ( ( float ) iPitch * m_flPitchScale ) ;
else
ep . m_nPitch = iPitch ;
ep . m_pOrigin = & vecOrigin ;
2019-08-31 22:28:20 +03:00
# else
2021-04-27 18:59:39 +03:00
ep . m_nChannel = CHAN_STATIC ;
ep . m_flVolume = flVolume ;
ep . m_nPitch = iPitch ;
ep . m_pOrigin = & m_hSpeaker - > GetAbsOrigin ( ) ;
2019-08-31 22:28:20 +03:00
# endif
2021-04-27 18:59:39 +03:00
ep . m_pSoundName = soundname ;
ep . m_SoundLevel = soundlevel ;
ep . m_nFlags = iFlags ;
ep . m_flSoundTime = soundtime ;
ep . m_nSpeakerEntity = entindex ;
2013-12-03 07:31:46 +04:00
2021-04-27 18:59:39 +03:00
CBaseEntity : : EmitSound ( filter , m_hSpeaker - > entindex ( ) , ep ) ;
}
2013-12-03 07:31:46 +04:00
Q_strncpy ( m_szLastSound , soundname , sizeof ( m_szLastSound ) ) ;
m_OnRoutedSound . FireOutput ( this , this , 0 ) ;
m_bAvoidFeedback = false ;
// Copy emitted origin to soundorigins array
for ( int i = 0 ; i < ep . m_UtlVecSoundOrigin . Count ( ) ; + + i )
{
soundorigins . AddToTail ( ep . m_UtlVecSoundOrigin [ i ] ) ;
}
// Do we want to allow the original sound to play?
if ( m_spawnflags & SF_MICROPHONE_SWALLOW_ROUTED_SOUNDS )
{
return MicrophoneResult_Swallow ;
}
return MicrophoneResult_Ok ;
}
//-----------------------------------------------------------------------------
// Purpose: Called by the sound system whenever a sound is played so that
// active microphones can have a chance to pick up the sound.
// Output : Returns whether or not the sound was swallowed by the microphone.
// Swallowed sounds should not be played by the sound system.
//-----------------------------------------------------------------------------
bool CEnvMicrophone : : OnSoundPlayed ( int entindex , const char * soundname , soundlevel_t soundlevel , float flVolume , int iFlags , int iPitch , const Vector * pOrigin , float soundtime , CUtlVector < Vector > & soundorigins )
{
bool bSwallowed = false ;
// Loop through all registered microphones and tell them the sound was just played
int iCount = s_Microphones . Count ( ) ;
if ( iCount > 0 )
{
// Iterate backwards because we might be deleting microphones.
for ( int i = iCount - 1 ; i > = 0 ; i - - )
{
if ( s_Microphones [ i ] )
{
MicrophoneResult_t eResult = s_Microphones [ i ] - > SoundPlayed (
entindex ,
soundname ,
soundlevel ,
flVolume ,
iFlags ,
iPitch ,
pOrigin ,
soundtime ,
soundorigins ) ;
if ( eResult = = MicrophoneResult_Swallow )
{
// Microphone told us to swallow it
bSwallowed = true ;
}
else if ( eResult = = MicrophoneResult_Remove )
{
s_Microphones . FastRemove ( i ) ;
}
}
}
}
return bSwallowed ;
}
2021-04-27 18:59:39 +03:00
# ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Called by the sound system whenever a sentence is played so that
// active microphones can have a chance to pick up the sound.
// Output : Returns whether or not the sentence was swallowed by the microphone.
// Swallowed sentences should not be played by the sound system.
//-----------------------------------------------------------------------------
bool CEnvMicrophone : : OnSentencePlayed ( int entindex , int sentenceIndex , soundlevel_t soundlevel , float flVolume , int iFlags , int iPitch , const Vector * pOrigin , float soundtime , CUtlVector < Vector > & soundorigins )
{
bool bSwallowed = false ;
// Loop through all registered microphones and tell them the sound was just played
int iCount = s_Microphones . Count ( ) ;
if ( iCount > 0 )
{
CNumStr szSentenceStr ( sentenceIndex ) ;
// Iterate backwards because we might be deleting microphones.
for ( int i = iCount - 1 ; i > = 0 ; i - - )
{
if ( s_Microphones [ i ] & & ( s_Microphones [ i ] - > ShouldHearSentences ( ) | | sv_microphones_always_pickup_sentences . GetBool ( ) ) )
{
// HACKHACK: Don't want to duplicate all of the code, so just use the same function with a new member variable
s_Microphones [ i ] - > ToggleHearingSentence ( true ) ;
MicrophoneResult_t eResult = s_Microphones [ i ] - > SoundPlayed (
entindex ,
szSentenceStr ,
soundlevel ,
flVolume ,
iFlags ,
iPitch ,
pOrigin ,
soundtime ,
soundorigins ) ;
s_Microphones [ i ] - > ToggleHearingSentence ( false ) ;
if ( eResult = = MicrophoneResult_Swallow )
{
// Microphone told us to swallow it
bSwallowed = true ;
}
else if ( eResult = = MicrophoneResult_Remove )
{
s_Microphones . FastRemove ( i ) ;
}
}
}
}
return bSwallowed ;
}
# endif