extensions/sdktools/vsound.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Tue May 06 18:40:35 2014 -0700 (2014-05-06)
changeset 4344 c445c3266192
parent 4209 1621324faee5
permissions -rw-r--r--
Unify Maximum supported clients, raised SDKTools limit (bug 5964, r=psychonic).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "vsound.h"
    33 #include <IForwardSys.h>
    34 
    35 #if SOURCE_ENGINE == SE_DOTA
    36 SH_DECL_HOOK8_void(IVEngineServer, EmitAmbientSound, SH_NOATTRIB, 0, CEntityIndex, const Vector &, const char *, float, soundlevel_t, int, int, float);
    37 #else
    38 SH_DECL_HOOK8_void(IVEngineServer, EmitAmbientSound, SH_NOATTRIB, 0, int, const Vector &, const char *, float, soundlevel_t, int, int, float);
    39 #endif
    40 
    41 #if SOURCE_ENGINE >= SE_PORTAL2
    42 SH_DECL_HOOK17(IEngineSound, EmitSound, SH_NOATTRIB, 0, int, IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, float, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    43 SH_DECL_HOOK17(IEngineSound, EmitSound, SH_NOATTRIB, 1, int, IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    44 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
    45 SH_DECL_HOOK15_void(IEngineSound, EmitSound, SH_NOATTRIB, 0, IRecipientFilter &, int, int, const char *, float, float, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    46 SH_DECL_HOOK15_void(IEngineSound, EmitSound, SH_NOATTRIB, 1, IRecipientFilter &, int, int, const char *, float, soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    47 #else
    48 SH_DECL_HOOK14_void(IEngineSound, EmitSound, SH_NOATTRIB, 0, IRecipientFilter &, int, int, const char *, float, float, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    49 SH_DECL_HOOK14_void(IEngineSound, EmitSound, SH_NOATTRIB, 1, IRecipientFilter &, int, int, const char *, float, soundlevel_t, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int);
    50 #endif
    51 
    52 bool g_InSoundHook = false;
    53 
    54 /***************************
    55 *                          *
    56 * Sound Related Hook Class *
    57 *                          *
    58 ****************************/
    59 
    60 cell_t SoundReferenceToIndex(cell_t ref)
    61 {
    62 	if (ref == 0 || ref == -1 || ref == -2)
    63 	{
    64 		return ref;
    65 	}
    66 
    67 	return gamehelpers->ReferenceToIndex(ref);
    68 }
    69 
    70 size_t SoundHooks::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
    71 {
    72 	size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
    73 
    74 	for (size_t i=0; i<size; i++)
    75 	{
    76 		int index;
    77 #if SOURCE_ENGINE == SE_DOTA
    78 		index = pFilter->GetRecipientIndex(i).Get();
    79 #else
    80 		index = pFilter->GetRecipientIndex(i);
    81 #endif
    82 		pl_array[i] = index;
    83 	}
    84 
    85 	return size;
    86 }
    87 
    88 void SoundHooks::_IncRefCounter(int type)
    89 {
    90 	if (type == NORMAL_SOUND_HOOK)
    91 	{
    92 		if (m_NormalCount++ == 0)
    93 		{
    94 			SH_ADD_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound), false);
    95 			SH_ADD_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound2), false);
    96 		}
    97 	}
    98 	else if (type == AMBIENT_SOUND_HOOK)
    99 	{
   100 		if (m_AmbientCount++ == 0)
   101 		{
   102 			SH_ADD_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
   103 		}
   104 	}
   105 }
   106 
   107 void SoundHooks::_DecRefCounter(int type)
   108 {
   109 	if (type == NORMAL_SOUND_HOOK)
   110 	{
   111 		if (--m_NormalCount == 0)
   112 		{
   113 			SH_REMOVE_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound), false);
   114 			SH_REMOVE_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound2), false);
   115 		}
   116 	}
   117 	else if (type == AMBIENT_SOUND_HOOK)
   118 	{
   119 		if (--m_AmbientCount == 0)
   120 		{
   121 			SH_REMOVE_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
   122 		}
   123 	}
   124 }
   125 
   126 void SoundHooks::Initialize()
   127 {
   128 	plsys->AddPluginsListener(this);
   129 }
   130 
   131 void SoundHooks::Shutdown()
   132 {
   133 	plsys->RemovePluginsListener(this);
   134 	if (m_NormalCount)
   135 	{
   136 		SH_REMOVE_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound), false);
   137 		SH_REMOVE_HOOK(IEngineSound, EmitSound, engsound, SH_MEMBER(this, &SoundHooks::OnEmitSound2), false);
   138 	}
   139 	if (m_AmbientCount)
   140 	{
   141 		SH_REMOVE_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
   142 	}
   143 }
   144 
   145 void SoundHooks::OnPluginUnloaded(IPlugin *plugin)
   146 {
   147 	SoundHookIter iter;
   148 	IPluginContext *pContext = plugin->GetBaseContext();
   149 
   150 	if (m_AmbientCount)
   151 	{
   152 		for (iter=m_AmbientFuncs.begin(); iter!=m_AmbientFuncs.end(); )
   153 		{
   154 			if ((*iter)->GetParentContext() == pContext)
   155 			{
   156 				iter = m_AmbientFuncs.erase(iter);
   157 				_DecRefCounter(AMBIENT_SOUND_HOOK);
   158 			}
   159 			else
   160 			{
   161 				iter++;
   162 			}
   163 		}
   164 	}
   165 	if (m_NormalCount)
   166 	{
   167 		for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); )
   168 		{
   169 			if ((*iter)->GetParentContext() == pContext)
   170 			{
   171 				iter = m_NormalFuncs.erase(iter);
   172 				_DecRefCounter(NORMAL_SOUND_HOOK);
   173 			}
   174 			else
   175 			{
   176 				iter++;
   177 			}
   178 		}
   179 	}
   180 }
   181 
   182 void SoundHooks::AddHook(int type, IPluginFunction *pFunc)
   183 {
   184 	if (type == NORMAL_SOUND_HOOK)
   185 	{
   186 		m_NormalFuncs.push_back(pFunc);
   187 		_IncRefCounter(NORMAL_SOUND_HOOK);
   188 	}
   189 	else if (type == AMBIENT_SOUND_HOOK)
   190 	{
   191 		m_AmbientFuncs.push_back(pFunc);
   192 		_IncRefCounter(AMBIENT_SOUND_HOOK);
   193 	}
   194 }
   195 
   196 bool SoundHooks::RemoveHook(int type, IPluginFunction *pFunc)
   197 {
   198 	SoundHookIter iter;
   199 	if (type == NORMAL_SOUND_HOOK)
   200 	{
   201 		if ((iter=m_NormalFuncs.find(pFunc)) != m_NormalFuncs.end())
   202 		{
   203 			m_NormalFuncs.erase(iter);
   204 			_DecRefCounter(NORMAL_SOUND_HOOK);
   205 			return true;
   206 		}
   207 		else
   208 		{
   209 			return false;
   210 		}
   211 	}
   212 	else if (type == AMBIENT_SOUND_HOOK)
   213 	{
   214 		if ((iter=m_AmbientFuncs.find(pFunc)) != m_AmbientFuncs.end())
   215 		{
   216 			m_AmbientFuncs.erase(iter);
   217 			_DecRefCounter(AMBIENT_SOUND_HOOK);
   218 			return true;
   219 		}
   220 		else
   221 		{
   222 			return false;
   223 		}
   224 	}
   225 
   226 	return false;
   227 }
   228 
   229 #if SOURCE_ENGINE == SE_DOTA
   230 void SoundHooks::OnEmitAmbientSound(CEntityIndex index, const Vector &pos, const char *samp, float vol, 
   231 									soundlevel_t soundlevel, int fFlags, int pitch, float delay)
   232 {
   233 	int entindex = index.Get();
   234 #else
   235 void SoundHooks::OnEmitAmbientSound(int entindex, const Vector &pos, const char *samp, float vol, 
   236 									soundlevel_t soundlevel, int fFlags, int pitch, float delay)
   237 {
   238 #endif
   239 	SoundHookIter iter;
   240 	IPluginFunction *pFunc;
   241 	cell_t vec[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
   242 	cell_t res = static_cast<ResultType>(Pl_Continue);
   243 	char buffer[PLATFORM_MAX_PATH];
   244 	strcpy(buffer, samp);
   245 
   246 	for (iter=m_AmbientFuncs.begin(); iter!=m_AmbientFuncs.end(); iter++)
   247 	{
   248 		pFunc = (*iter);
   249 		pFunc->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   250 		pFunc->PushCellByRef(&entindex);
   251 		pFunc->PushFloatByRef(&vol);
   252 		pFunc->PushCellByRef(reinterpret_cast<cell_t *>(&soundlevel));
   253 		pFunc->PushCellByRef(&pitch);
   254 		pFunc->PushArray(vec, 3, SM_PARAM_COPYBACK);
   255 		pFunc->PushCellByRef(&fFlags);
   256 		pFunc->PushFloatByRef(&delay);
   257 		g_InSoundHook = true;
   258 		pFunc->Execute(&res);
   259 		g_InSoundHook = false;
   260 
   261 		switch (res)
   262 		{
   263 		case Pl_Handled:
   264 		case Pl_Stop:
   265 			{
   266 				RETURN_META(MRES_SUPERCEDE);
   267 			}
   268 		case Pl_Changed:
   269 			{
   270 				Vector vec2;
   271 				vec2.x = sp_ctof(vec[0]);
   272 				vec2.y = sp_ctof(vec[1]);
   273 				vec2.z = sp_ctof(vec[2]);
   274 #if SOURCE_ENGINE == SE_DOTA
   275 				RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::EmitAmbientSound, 
   276 										(CEntityIndex(entindex), vec2, buffer, vol, soundlevel, fFlags, pitch, delay));
   277 #else
   278 				RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::EmitAmbientSound,
   279 										(entindex, vec2, buffer, vol, soundlevel, fFlags, pitch, delay));
   280 #endif
   281 			}
   282 		}
   283 	}
   284 }
   285 
   286 #if SOURCE_ENGINE >= SE_PORTAL2
   287 int SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSoundEntry, unsigned int nSoundEntryHash, const char *pSample, 
   288 							 float flVolume, soundlevel_t iSoundlevel, int nSeed, int iFlags, int iPitch, const Vector *pOrigin, 
   289 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   290 							 float soundtime, int speakerentity)
   291 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   292 void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   293 							 float flVolume, soundlevel_t iSoundlevel, int iFlags, int iPitch, int iSpecialDSP, const Vector *pOrigin, 
   294 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   295 							 float soundtime, int speakerentity)
   296 #else
   297 void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   298 							 float flVolume, soundlevel_t iSoundlevel, int iFlags, int iPitch, const Vector *pOrigin, 
   299 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   300 							 float soundtime, int speakerentity)
   301 #endif
   302 {
   303 	SoundHookIter iter;
   304 	IPluginFunction *pFunc;
   305 	cell_t res = static_cast<ResultType>(Pl_Continue);
   306 	char buffer[PLATFORM_MAX_PATH];
   307 	strcpy(buffer, pSample);
   308 
   309 	for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
   310 	{
   311 		int players[SM_MAXPLAYERS], size;
   312 		size = _FillInPlayers(players, &filter);
   313 		pFunc = (*iter);
   314 
   315 		pFunc->PushArray(players, SM_ARRAYSIZE(players), SM_PARAM_COPYBACK);
   316 		pFunc->PushCellByRef(&size);
   317 		pFunc->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   318 		pFunc->PushCellByRef(&iEntIndex);
   319 		pFunc->PushCellByRef(&iChannel);
   320 		pFunc->PushFloatByRef(&flVolume);
   321 		pFunc->PushCellByRef(reinterpret_cast<cell_t *>(&iSoundlevel));
   322 		pFunc->PushCellByRef(&iPitch);
   323 		pFunc->PushCellByRef(&iFlags);
   324 		g_InSoundHook = true;
   325 		pFunc->Execute(&res);
   326 		g_InSoundHook = false;
   327 
   328 		switch (res)
   329 		{
   330 		case Pl_Handled:
   331 		case Pl_Stop:
   332 			{
   333 #if SOURCE_ENGINE >= SE_PORTAL2
   334 				RETURN_META_VALUE(MRES_SUPERCEDE, -1);
   335 #else
   336 				RETURN_META(MRES_SUPERCEDE);
   337 #endif
   338 			}
   339 		case Pl_Changed:
   340 			{
   341 				/* Client validation */
   342 				for (int i = 0; i < size; i++)
   343 				{
   344 					int client = players[i];
   345 					IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
   346 
   347 					if (!pPlayer)
   348 					{
   349 						pFunc->GetParentContext()->ThrowNativeError("Client index %d is invalid", client);
   350 					} else if (!pPlayer->IsInGame()) {
   351 						pFunc->GetParentContext()->ThrowNativeError("Client %d is not connected", client);
   352 					} else {
   353 						continue;
   354 					}
   355 
   356 #if SOURCE_ENGINE >= SE_PORTAL2
   357 					RETURN_META_VALUE(MRES_IGNORED, -1 );
   358 #else
   359 					return;
   360 #endif
   361 				}
   362 
   363 				CellRecipientFilter crf;
   364 				crf.Initialize(players, size);
   365 #if SOURCE_ENGINE >= SE_PORTAL2
   366 				RETURN_META_VALUE_NEWPARAMS(
   367 					MRES_IGNORED,
   368 					-1,
   369 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, soundlevel_t, 
   370 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   371 					(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, iSoundlevel, nSeed, iFlags, iPitch, pOrigin, 
   372 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   373 					);
   374 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   375 				RETURN_META_NEWPARAMS(
   376 					MRES_IGNORED,
   377 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, soundlevel_t, 
   378 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   379 					(crf, iEntIndex, iChannel, buffer, flVolume, iSoundlevel, iFlags, iPitch, iSpecialDSP, pOrigin, 
   380 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   381 					);
   382 #else
   383 				RETURN_META_NEWPARAMS(
   384 					MRES_IGNORED,
   385 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, soundlevel_t, 
   386 					int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   387 					(crf, iEntIndex, iChannel, buffer, flVolume, iSoundlevel, iFlags, iPitch, pOrigin, 
   388 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   389 					);
   390 #endif
   391 			}
   392 		}
   393 	}
   394 
   395 #if SOURCE_ENGINE >= SE_PORTAL2
   396 	RETURN_META_VALUE(MRES_IGNORED, -1 );
   397 #endif
   398 }
   399 
   400 #if SOURCE_ENGINE >= SE_PORTAL2
   401 int SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSoundEntry, unsigned int nSoundEntryHash, const char *pSample, 
   402 							 float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch, const Vector *pOrigin, 
   403 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   404 							 float soundtime, int speakerentity)
   405 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   406 void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   407 							 float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP, const Vector *pOrigin, 
   408 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   409 							 float soundtime, int speakerentity)
   410 #else
   411 void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   412 							 float flVolume, float flAttenuation, int iFlags, int iPitch, const Vector *pOrigin, 
   413 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   414 							 float soundtime, int speakerentity)
   415 #endif
   416 {
   417 	SoundHookIter iter;
   418 	IPluginFunction *pFunc;
   419 	cell_t res = static_cast<ResultType>(Pl_Continue);
   420 	cell_t sndlevel = static_cast<cell_t>(ATTN_TO_SNDLVL(flAttenuation));
   421 	char buffer[PLATFORM_MAX_PATH];
   422 	strcpy(buffer, pSample);
   423 
   424 	for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
   425 	{
   426 		int players[SM_MAXPLAYERS], size;
   427 		size = _FillInPlayers(players, &filter);
   428 		pFunc = (*iter);
   429 
   430 		pFunc->PushArray(players, SM_ARRAYSIZE(players), SM_PARAM_COPYBACK);
   431 		pFunc->PushCellByRef(&size);
   432 		pFunc->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   433 		pFunc->PushCellByRef(&iEntIndex);
   434 		pFunc->PushCellByRef(&iChannel);
   435 		pFunc->PushFloatByRef(&flVolume);
   436 		pFunc->PushCellByRef(&sndlevel);
   437 		pFunc->PushCellByRef(&iPitch);
   438 		pFunc->PushCellByRef(&iFlags);
   439 		g_InSoundHook = true;
   440 		pFunc->Execute(&res);
   441 		g_InSoundHook = false;
   442 
   443 		switch (res)
   444 		{
   445 		case Pl_Handled:
   446 		case Pl_Stop:
   447 			{
   448 #if SOURCE_ENGINE >= SE_PORTAL2
   449 				RETURN_META_VALUE(MRES_SUPERCEDE, -1);
   450 #else
   451 				RETURN_META(MRES_SUPERCEDE);
   452 #endif
   453 			}
   454 		case Pl_Changed:
   455 			{
   456 				/* Client validation */
   457 				for (int i = 0; i < size; i++)
   458 				{
   459 					int client = players[i];
   460 					IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
   461 
   462 					if (!pPlayer)
   463 					{
   464 						pFunc->GetParentContext()->ThrowNativeError("Client index %d is invalid", client);
   465 					} else if (!pPlayer->IsInGame()) {
   466 						pFunc->GetParentContext()->ThrowNativeError("Client %d is not connected", client);
   467 					} else {
   468 						continue;
   469 					}
   470 
   471 #if SOURCE_ENGINE >= SE_PORTAL2
   472 					RETURN_META_VALUE(MRES_IGNORED, -1 );
   473 #else
   474 					return;
   475 #endif
   476 				}
   477 
   478 				CellRecipientFilter crf;
   479 				crf.Initialize(players, size);
   480 #if SOURCE_ENGINE >= SE_PORTAL2
   481 				RETURN_META_VALUE_NEWPARAMS(
   482 					MRES_IGNORED,
   483 					-1,
   484 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, float, 
   485 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   486 					(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   487 					nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   488 					);
   489 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   490 RETURN_META_NEWPARAMS(
   491 					MRES_IGNORED,
   492 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
   493 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   494 					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   495 					iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   496 					);
   497 #else
   498 				RETURN_META_NEWPARAMS(
   499 					MRES_IGNORED,
   500 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
   501 					int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   502 					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   503 					iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   504 					);
   505 #endif
   506 			}
   507 		}
   508 	}
   509 
   510 #if SOURCE_ENGINE >= SE_PORTAL2
   511 	RETURN_META_VALUE(MRES_IGNORED, -1 );
   512 #endif
   513 }
   514 
   515 /************************
   516 *                       *
   517 * Sound Related Natives *
   518 *                       *
   519 *************************/
   520 
   521 SoundHooks s_SoundHooks;
   522 
   523 static cell_t PrefetchSound(IPluginContext *pContext, const cell_t *params)
   524 {
   525 	char *name;
   526 	pContext->LocalToString(params[1], &name);
   527 
   528 	engsound->PrefetchSound(name);
   529 
   530 	return 1;
   531 }
   532 
   533 static cell_t GetSoundDuration(IPluginContext *pContext, const cell_t *params)
   534 {
   535 	char *name;
   536 	pContext->LocalToString(params[1], &name);
   537 
   538 	return sp_ftoc(engsound->GetSoundDuration(name));
   539 }
   540 
   541 static cell_t EmitAmbientSound(IPluginContext *pContext, const cell_t *params)
   542 {
   543 	cell_t entity;
   544 	Vector pos;
   545 	char *name;
   546 	float vol, delay;
   547 	int pitch, flags, level;
   548 
   549 	entity = SoundReferenceToIndex(params[3]);
   550 
   551 	cell_t *addr;
   552 	pContext->LocalToPhysAddr(params[2], &addr);
   553 	pos.x = sp_ctof(addr[0]);
   554 	pos.y = sp_ctof(addr[1]);
   555 	pos.z = sp_ctof(addr[2]);
   556 
   557 	pContext->LocalToString(params[1], &name);
   558 
   559 	vol = sp_ctof(params[6]);
   560 	level = params[4];
   561 	flags = params[5];
   562 	pitch = params[7];
   563 	delay = sp_ctof(params[8]);
   564 
   565 	if (g_InSoundHook)
   566 	{
   567 		ENGINE_CALL(EmitAmbientSound)(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
   568 	}
   569 	else
   570 	{
   571 		engine->EmitAmbientSound(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
   572 	}
   573 
   574 	return 1;
   575 }
   576 
   577 static cell_t FadeClientVolume(IPluginContext *pContext, const cell_t *params)
   578 {
   579 	int client = params[1];
   580 	if (client < 1 || client > playerhelpers->GetMaxClients())
   581 	{
   582 		return pContext->ThrowNativeError("Client index %d is not valid", client);
   583 	}
   584 
   585 	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
   586 	if (!player->IsInGame())
   587 	{
   588 		return pContext->ThrowNativeError("Client index %d is not in game", client);
   589 	}
   590 
   591 	engine->FadeClientVolume(
   592 #if SOURCE_ENGINE == SE_DOTA
   593 		player->GetIndex(),
   594 #else
   595 		player->GetEdict(),
   596 #endif
   597 		sp_ctof(params[2]),
   598 		sp_ctof(params[3]),
   599 		sp_ctof(params[4]),
   600 		sp_ctof(params[5]));
   601 
   602 	return 1;
   603 }
   604 
   605 static cell_t StopSound(IPluginContext *pContext, const cell_t *params)
   606 {
   607 	int entity = SoundReferenceToIndex(params[1]);
   608 	int channel = params[2];
   609 
   610 	char *name;
   611 	pContext->LocalToString(params[3], &name);
   612 
   613 #if SOURCE_ENGINE >= SE_PORTAL2
   614 	engsound->StopSound(entity, channel, name, -1);
   615 #else
   616 	engsound->StopSound(entity, channel, name);
   617 #endif
   618 
   619 	return 1;
   620 }
   621 
   622 static cell_t EmitSound(IPluginContext *pContext, const cell_t *params)
   623 {
   624 	cell_t *addr, *cl_array;
   625 	CellRecipientFilter crf;
   626 	unsigned int numClients;
   627 	int client;
   628 	IGamePlayer *pPlayer = NULL;
   629 
   630 	pContext->LocalToPhysAddr(params[1], &cl_array);
   631 	numClients = params[2];
   632 
   633 	/* Client validation */
   634 	for (unsigned int i = 0; i < numClients; i++)
   635 	{
   636 		client = cl_array[i];
   637 		pPlayer = playerhelpers->GetGamePlayer(client);
   638 
   639 		if (!pPlayer)
   640 		{
   641 			return pContext->ThrowNativeError("Client index %d is invalid", client);
   642 		} else if (!pPlayer->IsInGame()) {
   643 			return pContext->ThrowNativeError("Client %d is not connected", client);
   644 		}
   645 	}
   646 
   647 	crf.Initialize(cl_array, numClients);
   648 
   649 	char *sample;
   650 	pContext->LocalToString(params[3], &sample);
   651 	
   652 	int entity = SoundReferenceToIndex(params[4]);
   653 	int channel = params[5];
   654 	int level = params[6];
   655 	int flags = params[7];
   656 	float vol = sp_ctof(params[8]);
   657 	int pitch = params[9];
   658 	int speakerentity = params[10];
   659 
   660 	Vector *pOrigin = NULL, origin;
   661 	Vector *pDir = NULL, dir;
   662 
   663 	pContext->LocalToPhysAddr(params[11], &addr);
   664 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   665 	{
   666 		pOrigin = &origin;
   667 		origin.x = sp_ctof(addr[0]);
   668 		origin.y = sp_ctof(addr[1]);
   669 		origin.z = sp_ctof(addr[2]);
   670 	}
   671 
   672 	pContext->LocalToPhysAddr(params[12], &addr);
   673 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   674 	{
   675 		pDir = &dir;
   676 		dir.x = sp_ctof(addr[0]);
   677 		dir.y = sp_ctof(addr[1]);
   678 		dir.z = sp_ctof(addr[2]);
   679 	}
   680 
   681 	bool updatePos = params[13] ? true : false;
   682 	float soundtime = sp_ctof(params[14]);
   683 
   684 	CUtlVector<Vector> *pOrigVec = NULL;
   685 	CUtlVector<Vector> origvec;
   686 	if (params[0] > 14)
   687 	{
   688 		pOrigVec = &origvec;
   689 		for (cell_t i = 15; i <= params[0]; i++)
   690 		{
   691 			Vector vec;
   692 			pContext->LocalToPhysAddr(params[i], &addr);
   693 			vec.x = sp_ctof(addr[0]);
   694 			vec.y = sp_ctof(addr[1]);
   695 			vec.z = sp_ctof(addr[2]);
   696 			origvec.AddToTail(vec);
   697 		}
   698 	}
   699 
   700 	/* If we're going to a "local player" and this is a dedicated server,
   701 	 * intelligently redirect each sound.
   702 	 */
   703 
   704 	if (entity == -2 && engine->IsDedicatedServer())
   705 	{
   706 		for (unsigned int i = 0; i < numClients; i++)
   707 		{
   708 			cell_t player[1];
   709 			player[0] = cl_array[i];
   710 			crf.Reset();
   711 			crf.Initialize(player, 1);
   712 #if SOURCE_ENGINE >= SE_PORTAL2
   713 			if (g_InSoundHook)
   714 			{
   715 				SH_CALL(enginesoundPatch, 
   716 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, 
   717 					soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   718 
   719 					(&IEngineSound::EmitSound))
   720 					(crf, 
   721 					player[0], 
   722 					channel, 
   723 					sample, 
   724 					-1, 
   725 					sample, 
   726 					vol, 
   727 					(soundlevel_t)level, 
   728 					0, 
   729 					flags, 
   730 					pitch, 
   731 					pOrigin,
   732 					pDir,
   733 					pOrigVec,
   734 					updatePos,
   735 					soundtime,
   736 					speakerentity);
   737 			}
   738 			else
   739 			{
   740 				engsound->EmitSound(crf, 
   741 					player[0], 
   742 					channel, 
   743 					sample, 
   744 					-1, 
   745 					sample, 
   746 					vol, 
   747 					(soundlevel_t)level, 
   748 					0, 
   749 					flags, 
   750 					pitch, 
   751 					pOrigin,
   752 					pDir,
   753 					pOrigVec,
   754 					updatePos,
   755 					soundtime,
   756 					speakerentity);
   757 			}
   758 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   759 			if (g_InSoundHook)
   760 			{
   761 				SH_CALL(enginesoundPatch, 
   762 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   763 					soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   764 					(&IEngineSound::EmitSound))
   765 					(crf, 
   766 					player[0], 
   767 					channel, 
   768 					sample, 
   769 					vol, 
   770 					(soundlevel_t)level, 
   771 					flags, 
   772 					pitch, 
   773 					0, 
   774 					pOrigin,
   775 					pDir,
   776 					pOrigVec,
   777 					updatePos,
   778 					soundtime,
   779 					speakerentity);
   780 			}
   781 			else
   782 			{
   783 				engsound->EmitSound(crf, 
   784 					player[0], 
   785 					channel, 
   786 					sample, 
   787 					vol, 
   788 					(soundlevel_t)level, 
   789 					flags, 
   790 					pitch, 
   791 					0, 
   792 					pOrigin,
   793 					pDir,
   794 					pOrigVec,
   795 					updatePos,
   796 					soundtime,
   797 					speakerentity);
   798 			}
   799 #else
   800 			if (g_InSoundHook)
   801 			{
   802 				SH_CALL(enginesoundPatch, 
   803 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   804 					soundlevel_t, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   805 					(&IEngineSound::EmitSound))
   806 					(crf, 
   807 					player[0], 
   808 					channel, 
   809 					sample, 
   810 					vol, 
   811 					(soundlevel_t)level, 
   812 					flags, 
   813 					pitch, 
   814 					pOrigin,
   815 					pDir,
   816 					pOrigVec,
   817 					updatePos,
   818 					soundtime,
   819 					speakerentity);
   820 			}
   821 			else
   822 			{
   823 				engsound->EmitSound(crf, 
   824 					player[0], 
   825 					channel, 
   826 					sample, 
   827 					vol, 
   828 					(soundlevel_t)level, 
   829 					flags, 
   830 					pitch, 
   831 					pOrigin,
   832 					pDir,
   833 					pOrigVec,
   834 					updatePos,
   835 					soundtime,
   836 					speakerentity);
   837 			}
   838 #endif
   839 		}
   840 	} else {
   841 #if SOURCE_ENGINE >= SE_PORTAL2
   842 		if (g_InSoundHook)
   843 		{
   844 			SH_CALL(enginesoundPatch, 
   845 				static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, 
   846 				soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   847 				(&IEngineSound::EmitSound))
   848 				(crf, 
   849 				entity, 
   850 				channel, 
   851 				sample, 
   852 				-1, 
   853 				sample, 
   854 				vol, 
   855 				(soundlevel_t)level, 
   856 				0, 
   857 				flags, 
   858 				pitch, 
   859 				pOrigin,
   860 				pDir,
   861 				pOrigVec,
   862 				updatePos,
   863 				soundtime,
   864 				speakerentity);
   865 		}
   866 		else
   867 		{
   868 			engsound->EmitSound(crf, 
   869 				entity, 
   870 				channel, 
   871 				sample, 
   872 				-1, 
   873 				sample, 
   874 				vol, 
   875 				(soundlevel_t)level, 
   876 				0, 
   877 				flags, 
   878 				pitch, 
   879 				pOrigin,
   880 				pDir,
   881 				pOrigVec,
   882 				updatePos,
   883 				soundtime,
   884 				speakerentity);
   885 		}
   886 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
   887 		if (g_InSoundHook)
   888 		{
   889 			SH_CALL(enginesoundPatch, 
   890 				static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   891 				soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   892 				(&IEngineSound::EmitSound))
   893 				(crf, 
   894 				entity, 
   895 				channel, 
   896 				sample, 
   897 				vol, 
   898 				(soundlevel_t)level, 
   899 				flags, 
   900 				pitch, 
   901 				0, 
   902 				pOrigin,
   903 				pDir,
   904 				pOrigVec,
   905 				updatePos,
   906 				soundtime,
   907 				speakerentity);
   908 		}
   909 		else
   910 		{
   911 			engsound->EmitSound(crf, 
   912 				entity, 
   913 				channel, 
   914 				sample, 
   915 				vol, 
   916 				(soundlevel_t)level, 
   917 				flags, 
   918 				pitch, 
   919 				0, 
   920 				pOrigin,
   921 				pDir,
   922 				pOrigVec,
   923 				updatePos,
   924 				soundtime,
   925 				speakerentity);
   926 		}
   927 #else
   928 		if (g_InSoundHook)
   929 		{
   930 			SH_CALL(enginesoundPatch, 
   931 				static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   932 				soundlevel_t, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   933 				(&IEngineSound::EmitSound))
   934 				(crf, 
   935 				entity, 
   936 				channel, 
   937 				sample, 
   938 				vol, 
   939 				(soundlevel_t)level, 
   940 				flags, 
   941 				pitch, 
   942 				pOrigin,
   943 				pDir,
   944 				pOrigVec,
   945 				updatePos,
   946 				soundtime,
   947 				speakerentity);
   948 		}
   949 		else
   950 		{
   951 			engsound->EmitSound(crf, 
   952 				entity, 
   953 				channel, 
   954 				sample, 
   955 				vol, 
   956 				(soundlevel_t)level, 
   957 				flags, 
   958 				pitch, 
   959 				pOrigin,
   960 				pDir,
   961 				pOrigVec,
   962 				updatePos,
   963 				soundtime,
   964 				speakerentity);
   965 		}
   966 #endif
   967 	}
   968 
   969 	return 1;
   970 }
   971 
   972 static cell_t EmitSentence(IPluginContext *pContext, const cell_t *params)
   973 {
   974 	cell_t *addr;
   975 	CellRecipientFilter crf;
   976 	unsigned int numClients;
   977 	int client;
   978 	IGamePlayer *pPlayer = NULL;
   979 
   980 	pContext->LocalToPhysAddr(params[1], &addr);
   981 	numClients = params[2];
   982 
   983 	/* Client validation */
   984 	for (unsigned int i = 0; i < numClients; i++)
   985 	{
   986 		client = addr[i];
   987 		pPlayer = playerhelpers->GetGamePlayer(client);
   988 
   989 		if (!pPlayer)
   990 		{
   991 			return pContext->ThrowNativeError("Client index %d is invalid", client);
   992 		} else if (!pPlayer->IsInGame()) {
   993 			return pContext->ThrowNativeError("Client %d is not connected", client);
   994 		}
   995 	}
   996 
   997 	crf.Initialize(addr, numClients);
   998 
   999 	int sentence = params[3];
  1000 	int entity = SoundReferenceToIndex(params[4]);
  1001 	int channel = params[5];
  1002 	int level = params[6];
  1003 	int flags = params[7];
  1004 	float vol = sp_ctof(params[8]);
  1005 	int pitch = params[9];
  1006 	int speakerentity = params[10];
  1007 
  1008 	Vector *pOrigin = NULL, origin;
  1009 	Vector *pDir = NULL, dir;
  1010 
  1011 	pContext->LocalToPhysAddr(params[11], &addr);
  1012 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
  1013 	{
  1014 		pOrigin = &origin;
  1015 		origin.x = sp_ctof(addr[0]);
  1016 		origin.y = sp_ctof(addr[1]);
  1017 		origin.z = sp_ctof(addr[2]);
  1018 	}
  1019 
  1020 	pContext->LocalToPhysAddr(params[12], &addr);
  1021 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
  1022 	{
  1023 		pDir = &dir;
  1024 		dir.x = sp_ctof(addr[0]);
  1025 		dir.y = sp_ctof(addr[1]);
  1026 		dir.z = sp_ctof(addr[2]);
  1027 	}
  1028 
  1029 	bool updatePos = params[13] ? true : false;
  1030 	float soundtime = sp_ctof(params[14]);
  1031 
  1032 	CUtlVector<Vector> *pOrigVec = NULL;
  1033 	CUtlVector<Vector> origvec;
  1034 	if (params[0] > 14)
  1035 	{
  1036 		pOrigVec = &origvec;
  1037 		for (cell_t i = 15; i <= params[0]; i++)
  1038 		{
  1039 			Vector vec;
  1040 			pContext->LocalToPhysAddr(params[i], &addr);
  1041 			vec.x = sp_ctof(addr[0]);
  1042 			vec.y = sp_ctof(addr[1]);
  1043 			vec.z = sp_ctof(addr[2]);
  1044 			origvec.AddToTail(vec);
  1045 		}
  1046 	}
  1047 
  1048 	engsound->EmitSentenceByIndex(crf, 
  1049 		entity, 
  1050 		channel, 
  1051 		sentence, 
  1052 		vol, 
  1053 		(soundlevel_t)level, 
  1054 #if SOURCE_ENGINE >= SE_PORTAL2
  1055 		0, 
  1056 #endif
  1057 		flags, 
  1058 		pitch, 
  1059 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
  1060 		0, 
  1061 #endif
  1062 		pOrigin,
  1063 		pDir,
  1064 		pOrigVec,
  1065 		updatePos,
  1066 		soundtime,
  1067 		speakerentity);
  1068 
  1069 	return 1;
  1070 }
  1071 
  1072 static cell_t smn_AddAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
  1073 {
  1074 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1075 	if (!pFunc)
  1076 	{
  1077 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1078 	}
  1079 
  1080 	s_SoundHooks.AddHook(AMBIENT_SOUND_HOOK, pFunc);
  1081 
  1082 	return 1;
  1083 }
  1084 
  1085 static cell_t smn_AddNormalSoundHook(IPluginContext *pContext, const cell_t *params)
  1086 {
  1087 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1088 	if (!pFunc)
  1089 	{
  1090 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1091 	}
  1092 
  1093 	s_SoundHooks.AddHook(NORMAL_SOUND_HOOK, pFunc);
  1094 
  1095 	return 1;
  1096 }
  1097 
  1098 static cell_t smn_RemoveAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
  1099 {
  1100 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1101 	if (!pFunc)
  1102 	{
  1103 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1104 	}
  1105 
  1106 	if (!s_SoundHooks.RemoveHook(AMBIENT_SOUND_HOOK, pFunc))
  1107 	{
  1108 		return pContext->ThrowNativeError("Invalid hooked function");
  1109 	}
  1110 
  1111 	return 1;
  1112 }
  1113 
  1114 static cell_t smn_RemoveNormalSoundHook(IPluginContext *pContext, const cell_t *params)
  1115 {
  1116 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1117 	if (!pFunc)
  1118 	{
  1119 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1120 	}
  1121 
  1122 	if (!s_SoundHooks.RemoveHook(NORMAL_SOUND_HOOK, pFunc))
  1123 	{
  1124 		return pContext->ThrowNativeError("Invalid hooked function");
  1125 	}
  1126 
  1127 	return 1;
  1128 }
  1129 
  1130 static cell_t smn_GetDistGainFromSoundLevel(IPluginContext *pContext, const cell_t *params)
  1131 {
  1132 	int decibel = params[1];
  1133 	float distance = sp_ctof(params[2]);
  1134 
  1135 	return sp_ftoc(engsound->GetDistGainFromSoundLevel((soundlevel_t)decibel, distance));
  1136 }
  1137 
  1138 sp_nativeinfo_t g_SoundNatives[] = 
  1139 {
  1140 	{"EmitAmbientSound",		EmitAmbientSound},
  1141 	{"EmitSentence",			EmitSentence},
  1142 	{"EmitSound",				EmitSound},
  1143 	{"FadeClientVolume",		FadeClientVolume},
  1144 	{"GetSoundDuration",		GetSoundDuration},
  1145 	{"PrefetchSound",			PrefetchSound},
  1146 	{"StopSound",				StopSound},
  1147 	{"AddAmbientSoundHook",		smn_AddAmbientSoundHook},
  1148 	{"AddNormalSoundHook",		smn_AddNormalSoundHook},
  1149 	{"RemoveAmbientSoundHook",	smn_RemoveAmbientSoundHook},
  1150 	{"RemoveNormalSoundHook",	smn_RemoveNormalSoundHook},
  1151 	{"GetDistGainFromSoundLevel", smn_GetDistGainFromSoundLevel},
  1152 	{NULL,						NULL},
  1153 };