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