extensions/sdktools/vsound.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Sun Jul 21 11:53:56 2013 -0400 (2013-07-21)
changeset 3961 0dc477c29792
parent 3942 7aaa00382627
child 4141 8ff66ae5ffcc
permissions -rw-r--r--
Split TF2, DoD:S, HL2:DM, and ND to separate binaries (bug 5813, r=asherkin).
     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_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_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[64], size;
   312 		size = _FillInPlayers(players, &filter);
   313 		pFunc = (*iter);
   314 
   315 		pFunc->PushArray(players, 64, 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 				CellRecipientFilter crf;
   342 				crf.Initialize(players, size);
   343 #if SOURCE_ENGINE >= SE_PORTAL2
   344 				RETURN_META_VALUE_NEWPARAMS(
   345 					MRES_IGNORED,
   346 					-1,
   347 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, soundlevel_t, 
   348 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   349 					(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, iSoundlevel, nSeed, iFlags, iPitch, pOrigin, 
   350 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   351 					);
   352 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
   353 				RETURN_META_NEWPARAMS(
   354 					MRES_IGNORED,
   355 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, soundlevel_t, 
   356 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   357 					(crf, iEntIndex, iChannel, buffer, flVolume, iSoundlevel, iFlags, iPitch, iSpecialDSP, pOrigin, 
   358 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   359 					);
   360 #else
   361 				RETURN_META_NEWPARAMS(
   362 					MRES_IGNORED,
   363 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, soundlevel_t, 
   364 					int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   365 					(crf, iEntIndex, iChannel, buffer, flVolume, iSoundlevel, iFlags, iPitch, pOrigin, 
   366 					pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   367 					);
   368 #endif
   369 			}
   370 		}
   371 	}
   372 
   373 #if SOURCE_ENGINE >= SE_PORTAL2
   374 	RETURN_META_VALUE(MRES_IGNORED, -1 );
   375 #endif
   376 }
   377 
   378 #if SOURCE_ENGINE >= SE_PORTAL2
   379 int SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSoundEntry, unsigned int nSoundEntryHash, const char *pSample, 
   380 							 float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch, const Vector *pOrigin, 
   381 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   382 							 float soundtime, int speakerentity)
   383 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
   384 void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   385 							 float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP, const Vector *pOrigin, 
   386 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   387 							 float soundtime, int speakerentity)
   388 #else
   389 void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
   390 							 float flVolume, float flAttenuation, int iFlags, int iPitch, const Vector *pOrigin, 
   391 							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
   392 							 float soundtime, int speakerentity)
   393 #endif
   394 {
   395 	SoundHookIter iter;
   396 	IPluginFunction *pFunc;
   397 	cell_t res = static_cast<ResultType>(Pl_Continue);
   398 	cell_t sndlevel = static_cast<cell_t>(ATTN_TO_SNDLVL(flAttenuation));
   399 	char buffer[PLATFORM_MAX_PATH];
   400 	strcpy(buffer, pSample);
   401 
   402 	for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
   403 	{
   404 		int players[64], size;
   405 		size = _FillInPlayers(players, &filter);
   406 		pFunc = (*iter);
   407 
   408 		pFunc->PushArray(players, 64, SM_PARAM_COPYBACK);
   409 		pFunc->PushCellByRef(&size);
   410 		pFunc->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
   411 		pFunc->PushCellByRef(&iEntIndex);
   412 		pFunc->PushCellByRef(&iChannel);
   413 		pFunc->PushFloatByRef(&flVolume);
   414 		pFunc->PushCellByRef(&sndlevel);
   415 		pFunc->PushCellByRef(&iPitch);
   416 		pFunc->PushCellByRef(&iFlags);
   417 		g_InSoundHook = true;
   418 		pFunc->Execute(&res);
   419 		g_InSoundHook = false;
   420 
   421 		switch (res)
   422 		{
   423 		case Pl_Handled:
   424 		case Pl_Stop:
   425 			{
   426 #if SOURCE_ENGINE >= SE_PORTAL2
   427 				RETURN_META_VALUE(MRES_SUPERCEDE, -1);
   428 #else
   429 				RETURN_META(MRES_SUPERCEDE);
   430 #endif
   431 			}
   432 		case Pl_Changed:
   433 			{
   434 				CellRecipientFilter crf;
   435 				crf.Initialize(players, size);
   436 #if SOURCE_ENGINE >= SE_PORTAL2
   437 				RETURN_META_VALUE_NEWPARAMS(
   438 					MRES_IGNORED,
   439 					-1,
   440 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, float, 
   441 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   442 					(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   443 					nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   444 					);
   445 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
   446 RETURN_META_NEWPARAMS(
   447 					MRES_IGNORED,
   448 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
   449 					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   450 					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   451 					iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   452 					);
   453 #else
   454 				RETURN_META_NEWPARAMS(
   455 					MRES_IGNORED,
   456 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
   457 					int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
   458 					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
   459 					iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
   460 					);
   461 #endif
   462 			}
   463 		}
   464 	}
   465 
   466 #if SOURCE_ENGINE >= SE_PORTAL2
   467 	RETURN_META_VALUE(MRES_IGNORED, -1 );
   468 #endif
   469 }
   470 
   471 /************************
   472 *                       *
   473 * Sound Related Natives *
   474 *                       *
   475 *************************/
   476 
   477 SoundHooks s_SoundHooks;
   478 
   479 static cell_t PrefetchSound(IPluginContext *pContext, const cell_t *params)
   480 {
   481 	char *name;
   482 	pContext->LocalToString(params[1], &name);
   483 
   484 	engsound->PrefetchSound(name);
   485 
   486 	return 1;
   487 }
   488 
   489 static cell_t GetSoundDuration(IPluginContext *pContext, const cell_t *params)
   490 {
   491 	char *name;
   492 	pContext->LocalToString(params[1], &name);
   493 
   494 	return sp_ftoc(engsound->GetSoundDuration(name));
   495 }
   496 
   497 static cell_t EmitAmbientSound(IPluginContext *pContext, const cell_t *params)
   498 {
   499 	cell_t entity;
   500 	Vector pos;
   501 	char *name;
   502 	float vol, delay;
   503 	int pitch, flags, level;
   504 
   505 	entity = SoundReferenceToIndex(params[3]);
   506 
   507 	cell_t *addr;
   508 	pContext->LocalToPhysAddr(params[2], &addr);
   509 	pos.x = sp_ctof(addr[0]);
   510 	pos.y = sp_ctof(addr[1]);
   511 	pos.z = sp_ctof(addr[2]);
   512 
   513 	pContext->LocalToString(params[1], &name);
   514 
   515 	vol = sp_ctof(params[6]);
   516 	level = params[4];
   517 	flags = params[5];
   518 	pitch = params[7];
   519 	delay = sp_ctof(params[8]);
   520 
   521 	if (g_InSoundHook)
   522 	{
   523 		ENGINE_CALL(EmitAmbientSound)(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
   524 	}
   525 	else
   526 	{
   527 		engine->EmitAmbientSound(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
   528 	}
   529 
   530 	return 1;
   531 }
   532 
   533 static cell_t FadeClientVolume(IPluginContext *pContext, const cell_t *params)
   534 {
   535 	int client = params[1];
   536 	if (client < 1 || client > playerhelpers->GetMaxClients())
   537 	{
   538 		return pContext->ThrowNativeError("Client index %d is not valid", client);
   539 	}
   540 
   541 	IGamePlayer *player = playerhelpers->GetGamePlayer(client);
   542 	if (!player->IsInGame())
   543 	{
   544 		return pContext->ThrowNativeError("Client index %d is not in game", client);
   545 	}
   546 
   547 	engine->FadeClientVolume(
   548 #if SOURCE_ENGINE == SE_DOTA
   549 		player->GetIndex(),
   550 #else
   551 		player->GetEdict(),
   552 #endif
   553 		sp_ctof(params[2]),
   554 		sp_ctof(params[3]),
   555 		sp_ctof(params[4]),
   556 		sp_ctof(params[5]));
   557 
   558 	return 1;
   559 }
   560 
   561 static cell_t StopSound(IPluginContext *pContext, const cell_t *params)
   562 {
   563 	int entity = SoundReferenceToIndex(params[1]);
   564 	int channel = params[2];
   565 
   566 	char *name;
   567 	pContext->LocalToString(params[3], &name);
   568 
   569 #if SOURCE_ENGINE >= SE_PORTAL2
   570 	engsound->StopSound(entity, channel, name, -1);
   571 #else
   572 	engsound->StopSound(entity, channel, name);
   573 #endif
   574 
   575 	return 1;
   576 }
   577 
   578 static cell_t EmitSound(IPluginContext *pContext, const cell_t *params)
   579 {
   580 	cell_t *addr, *cl_array;
   581 	CellRecipientFilter crf;
   582 	unsigned int numClients;
   583 	int client;
   584 	IGamePlayer *pPlayer = NULL;
   585 
   586 	pContext->LocalToPhysAddr(params[1], &cl_array);
   587 	numClients = params[2];
   588 
   589 	/* Client validation */
   590 	for (unsigned int i = 0; i < numClients; i++)
   591 	{
   592 		client = cl_array[i];
   593 		pPlayer = playerhelpers->GetGamePlayer(client);
   594 
   595 		if (!pPlayer)
   596 		{
   597 			return pContext->ThrowNativeError("Client index %d is invalid", client);
   598 		} else if (!pPlayer->IsInGame()) {
   599 			return pContext->ThrowNativeError("Client %d is not connected", client);
   600 		}
   601 	}
   602 
   603 	crf.Initialize(cl_array, numClients);
   604 
   605 	char *sample;
   606 	pContext->LocalToString(params[3], &sample);
   607 	
   608 	int entity = SoundReferenceToIndex(params[4]);
   609 	int channel = params[5];
   610 	int level = params[6];
   611 	int flags = params[7];
   612 	float vol = sp_ctof(params[8]);
   613 	int pitch = params[9];
   614 	int speakerentity = params[10];
   615 
   616 	Vector *pOrigin = NULL, origin;
   617 	Vector *pDir = NULL, dir;
   618 
   619 	pContext->LocalToPhysAddr(params[11], &addr);
   620 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   621 	{
   622 		pOrigin = &origin;
   623 		origin.x = sp_ctof(addr[0]);
   624 		origin.y = sp_ctof(addr[1]);
   625 		origin.z = sp_ctof(addr[2]);
   626 	}
   627 
   628 	pContext->LocalToPhysAddr(params[12], &addr);
   629 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   630 	{
   631 		pDir = &dir;
   632 		dir.x = sp_ctof(addr[0]);
   633 		dir.y = sp_ctof(addr[1]);
   634 		dir.z = sp_ctof(addr[2]);
   635 	}
   636 
   637 	bool updatePos = params[13] ? true : false;
   638 	float soundtime = sp_ctof(params[14]);
   639 
   640 	CUtlVector<Vector> *pOrigVec = NULL;
   641 	CUtlVector<Vector> origvec;
   642 	if (params[0] > 14)
   643 	{
   644 		pOrigVec = &origvec;
   645 		for (cell_t i = 15; i <= params[0]; i++)
   646 		{
   647 			Vector vec;
   648 			pContext->LocalToPhysAddr(params[i], &addr);
   649 			vec.x = sp_ctof(addr[0]);
   650 			vec.y = sp_ctof(addr[1]);
   651 			vec.z = sp_ctof(addr[2]);
   652 			origvec.AddToTail(vec);
   653 		}
   654 	}
   655 
   656 	/* If we're going to a "local player" and this is a dedicated server,
   657 	 * intelligently redirect each sound.
   658 	 */
   659 
   660 	if (entity == -2 && engine->IsDedicatedServer())
   661 	{
   662 		for (unsigned int i = 0; i < numClients; i++)
   663 		{
   664 			cell_t player[1];
   665 			player[0] = cl_array[i];
   666 			crf.Reset();
   667 			crf.Initialize(player, 1);
   668 #if SOURCE_ENGINE >= SE_PORTAL2
   669 			if (g_InSoundHook)
   670 			{
   671 				SH_CALL(enginesoundPatch, 
   672 					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, 
   673 					soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   674 
   675 					(&IEngineSound::EmitSound))
   676 					(crf, 
   677 					player[0], 
   678 					channel, 
   679 					sample, 
   680 					-1, 
   681 					sample, 
   682 					vol, 
   683 					(soundlevel_t)level, 
   684 					0, 
   685 					flags, 
   686 					pitch, 
   687 					pOrigin,
   688 					pDir,
   689 					pOrigVec,
   690 					updatePos,
   691 					soundtime,
   692 					speakerentity);
   693 			}
   694 			else
   695 			{
   696 				engsound->EmitSound(crf, 
   697 					player[0], 
   698 					channel, 
   699 					sample, 
   700 					-1, 
   701 					sample, 
   702 					vol, 
   703 					(soundlevel_t)level, 
   704 					0, 
   705 					flags, 
   706 					pitch, 
   707 					pOrigin,
   708 					pDir,
   709 					pOrigVec,
   710 					updatePos,
   711 					soundtime,
   712 					speakerentity);
   713 			}
   714 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
   715 			if (g_InSoundHook)
   716 			{
   717 				SH_CALL(enginesoundPatch, 
   718 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   719 					soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   720 					(&IEngineSound::EmitSound))
   721 					(crf, 
   722 					player[0], 
   723 					channel, 
   724 					sample, 
   725 					vol, 
   726 					(soundlevel_t)level, 
   727 					flags, 
   728 					pitch, 
   729 					0, 
   730 					pOrigin,
   731 					pDir,
   732 					pOrigVec,
   733 					updatePos,
   734 					soundtime,
   735 					speakerentity);
   736 			}
   737 			else
   738 			{
   739 				engsound->EmitSound(crf, 
   740 					player[0], 
   741 					channel, 
   742 					sample, 
   743 					vol, 
   744 					(soundlevel_t)level, 
   745 					flags, 
   746 					pitch, 
   747 					0, 
   748 					pOrigin,
   749 					pDir,
   750 					pOrigVec,
   751 					updatePos,
   752 					soundtime,
   753 					speakerentity);
   754 			}
   755 #else
   756 			if (g_InSoundHook)
   757 			{
   758 				SH_CALL(enginesoundPatch, 
   759 					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   760 					soundlevel_t, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   761 					(&IEngineSound::EmitSound))
   762 					(crf, 
   763 					player[0], 
   764 					channel, 
   765 					sample, 
   766 					vol, 
   767 					(soundlevel_t)level, 
   768 					flags, 
   769 					pitch, 
   770 					pOrigin,
   771 					pDir,
   772 					pOrigVec,
   773 					updatePos,
   774 					soundtime,
   775 					speakerentity);
   776 			}
   777 			else
   778 			{
   779 				engsound->EmitSound(crf, 
   780 					player[0], 
   781 					channel, 
   782 					sample, 
   783 					vol, 
   784 					(soundlevel_t)level, 
   785 					flags, 
   786 					pitch, 
   787 					pOrigin,
   788 					pDir,
   789 					pOrigVec,
   790 					updatePos,
   791 					soundtime,
   792 					speakerentity);
   793 			}
   794 #endif
   795 		}
   796 	} else {
   797 #if SOURCE_ENGINE >= SE_PORTAL2
   798 		if (g_InSoundHook)
   799 		{
   800 			SH_CALL(enginesoundPatch, 
   801 				static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, 
   802 				soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   803 				(&IEngineSound::EmitSound))
   804 				(crf, 
   805 				entity, 
   806 				channel, 
   807 				sample, 
   808 				-1, 
   809 				sample, 
   810 				vol, 
   811 				(soundlevel_t)level, 
   812 				0, 
   813 				flags, 
   814 				pitch, 
   815 				pOrigin,
   816 				pDir,
   817 				pOrigVec,
   818 				updatePos,
   819 				soundtime,
   820 				speakerentity);
   821 		}
   822 		else
   823 		{
   824 			engsound->EmitSound(crf, 
   825 				entity, 
   826 				channel, 
   827 				sample, 
   828 				-1, 
   829 				sample, 
   830 				vol, 
   831 				(soundlevel_t)level, 
   832 				0, 
   833 				flags, 
   834 				pitch, 
   835 				pOrigin,
   836 				pDir,
   837 				pOrigVec,
   838 				updatePos,
   839 				soundtime,
   840 				speakerentity);
   841 		}
   842 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
   843 		if (g_InSoundHook)
   844 		{
   845 			SH_CALL(enginesoundPatch, 
   846 				static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   847 				soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   848 				(&IEngineSound::EmitSound))
   849 				(crf, 
   850 				entity, 
   851 				channel, 
   852 				sample, 
   853 				vol, 
   854 				(soundlevel_t)level, 
   855 				flags, 
   856 				pitch, 
   857 				0, 
   858 				pOrigin,
   859 				pDir,
   860 				pOrigVec,
   861 				updatePos,
   862 				soundtime,
   863 				speakerentity);
   864 		}
   865 		else
   866 		{
   867 			engsound->EmitSound(crf, 
   868 				entity, 
   869 				channel, 
   870 				sample, 
   871 				vol, 
   872 				(soundlevel_t)level, 
   873 				flags, 
   874 				pitch, 
   875 				0, 
   876 				pOrigin,
   877 				pDir,
   878 				pOrigVec,
   879 				updatePos,
   880 				soundtime,
   881 				speakerentity);
   882 		}
   883 #else
   884 		if (g_InSoundHook)
   885 		{
   886 			SH_CALL(enginesoundPatch, 
   887 				static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char*, float, 
   888 				soundlevel_t, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
   889 				(&IEngineSound::EmitSound))
   890 				(crf, 
   891 				entity, 
   892 				channel, 
   893 				sample, 
   894 				vol, 
   895 				(soundlevel_t)level, 
   896 				flags, 
   897 				pitch, 
   898 				pOrigin,
   899 				pDir,
   900 				pOrigVec,
   901 				updatePos,
   902 				soundtime,
   903 				speakerentity);
   904 		}
   905 		else
   906 		{
   907 			engsound->EmitSound(crf, 
   908 				entity, 
   909 				channel, 
   910 				sample, 
   911 				vol, 
   912 				(soundlevel_t)level, 
   913 				flags, 
   914 				pitch, 
   915 				pOrigin,
   916 				pDir,
   917 				pOrigVec,
   918 				updatePos,
   919 				soundtime,
   920 				speakerentity);
   921 		}
   922 #endif
   923 	}
   924 
   925 	return 1;
   926 }
   927 
   928 static cell_t EmitSentence(IPluginContext *pContext, const cell_t *params)
   929 {
   930 	cell_t *addr;
   931 	CellRecipientFilter crf;
   932 	unsigned int numClients;
   933 	int client;
   934 	IGamePlayer *pPlayer = NULL;
   935 
   936 	pContext->LocalToPhysAddr(params[1], &addr);
   937 	numClients = params[2];
   938 
   939 	/* Client validation */
   940 	for (unsigned int i = 0; i < numClients; i++)
   941 	{
   942 		client = addr[i];
   943 		pPlayer = playerhelpers->GetGamePlayer(client);
   944 
   945 		if (!pPlayer)
   946 		{
   947 			return pContext->ThrowNativeError("Client index %d is invalid", client);
   948 		} else if (!pPlayer->IsInGame()) {
   949 			return pContext->ThrowNativeError("Client %d is not connected", client);
   950 		}
   951 	}
   952 
   953 	crf.Initialize(addr, numClients);
   954 
   955 	int sentence = params[3];
   956 	int entity = SoundReferenceToIndex(params[4]);
   957 	int channel = params[5];
   958 	int level = params[6];
   959 	int flags = params[7];
   960 	float vol = sp_ctof(params[8]);
   961 	int pitch = params[9];
   962 	int speakerentity = params[10];
   963 
   964 	Vector *pOrigin = NULL, origin;
   965 	Vector *pDir = NULL, dir;
   966 
   967 	pContext->LocalToPhysAddr(params[11], &addr);
   968 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   969 	{
   970 		pOrigin = &origin;
   971 		origin.x = sp_ctof(addr[0]);
   972 		origin.y = sp_ctof(addr[1]);
   973 		origin.z = sp_ctof(addr[2]);
   974 	}
   975 
   976 	pContext->LocalToPhysAddr(params[12], &addr);
   977 	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
   978 	{
   979 		pDir = &dir;
   980 		dir.x = sp_ctof(addr[0]);
   981 		dir.y = sp_ctof(addr[1]);
   982 		dir.z = sp_ctof(addr[2]);
   983 	}
   984 
   985 	bool updatePos = params[13] ? true : false;
   986 	float soundtime = sp_ctof(params[14]);
   987 
   988 	CUtlVector<Vector> *pOrigVec = NULL;
   989 	CUtlVector<Vector> origvec;
   990 	if (params[0] > 14)
   991 	{
   992 		pOrigVec = &origvec;
   993 		for (cell_t i = 15; i <= params[0]; i++)
   994 		{
   995 			Vector vec;
   996 			pContext->LocalToPhysAddr(params[i], &addr);
   997 			vec.x = sp_ctof(addr[0]);
   998 			vec.y = sp_ctof(addr[1]);
   999 			vec.z = sp_ctof(addr[2]);
  1000 			origvec.AddToTail(vec);
  1001 		}
  1002 	}
  1003 
  1004 	engsound->EmitSentenceByIndex(crf, 
  1005 		entity, 
  1006 		channel, 
  1007 		sentence, 
  1008 		vol, 
  1009 		(soundlevel_t)level, 
  1010 #if SOURCE_ENGINE >= SE_PORTAL2
  1011 		0, 
  1012 #endif
  1013 		flags, 
  1014 		pitch, 
  1015 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2
  1016 		0, 
  1017 #endif
  1018 		pOrigin,
  1019 		pDir,
  1020 		pOrigVec,
  1021 		updatePos,
  1022 		soundtime,
  1023 		speakerentity);
  1024 
  1025 	return 1;
  1026 }
  1027 
  1028 static cell_t smn_AddAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
  1029 {
  1030 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1031 	if (!pFunc)
  1032 	{
  1033 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1034 	}
  1035 
  1036 	s_SoundHooks.AddHook(AMBIENT_SOUND_HOOK, pFunc);
  1037 
  1038 	return 1;
  1039 }
  1040 
  1041 static cell_t smn_AddNormalSoundHook(IPluginContext *pContext, const cell_t *params)
  1042 {
  1043 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1044 	if (!pFunc)
  1045 	{
  1046 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1047 	}
  1048 
  1049 	s_SoundHooks.AddHook(NORMAL_SOUND_HOOK, pFunc);
  1050 
  1051 	return 1;
  1052 }
  1053 
  1054 static cell_t smn_RemoveAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
  1055 {
  1056 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1057 	if (!pFunc)
  1058 	{
  1059 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1060 	}
  1061 
  1062 	if (!s_SoundHooks.RemoveHook(AMBIENT_SOUND_HOOK, pFunc))
  1063 	{
  1064 		return pContext->ThrowNativeError("Invalid hooked function");
  1065 	}
  1066 
  1067 	return 1;
  1068 }
  1069 
  1070 static cell_t smn_RemoveNormalSoundHook(IPluginContext *pContext, const cell_t *params)
  1071 {
  1072 	IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
  1073 	if (!pFunc)
  1074 	{
  1075 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1076 	}
  1077 
  1078 	if (!s_SoundHooks.RemoveHook(NORMAL_SOUND_HOOK, pFunc))
  1079 	{
  1080 		return pContext->ThrowNativeError("Invalid hooked function");
  1081 	}
  1082 
  1083 	return 1;
  1084 }
  1085 
  1086 static cell_t smn_GetDistGainFromSoundLevel(IPluginContext *pContext, const cell_t *params)
  1087 {
  1088 	int decibel = params[1];
  1089 	float distance = sp_ctof(params[2]);
  1090 
  1091 	return sp_ftoc(engsound->GetDistGainFromSoundLevel((soundlevel_t)decibel, distance));
  1092 }
  1093 
  1094 sp_nativeinfo_t g_SoundNatives[] = 
  1095 {
  1096 	{"EmitAmbientSound",		EmitAmbientSound},
  1097 	{"EmitSentence",			EmitSentence},
  1098 	{"EmitSound",				EmitSound},
  1099 	{"FadeClientVolume",		FadeClientVolume},
  1100 	{"GetSoundDuration",		GetSoundDuration},
  1101 	{"PrefetchSound",			PrefetchSound},
  1102 	{"StopSound",				StopSound},
  1103 	{"AddAmbientSoundHook",		smn_AddAmbientSoundHook},
  1104 	{"AddNormalSoundHook",		smn_AddNormalSoundHook},
  1105 	{"RemoveAmbientSoundHook",	smn_RemoveAmbientSoundHook},
  1106 	{"RemoveNormalSoundHook",	smn_RemoveNormalSoundHook},
  1107 	{"GetDistGainFromSoundLevel", smn_GetDistGainFromSoundLevel},
  1108 	{NULL,						NULL},
  1109 };