3 * =============================================================================
4 * SourceMod SDKTools Extension
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
33 #include <IForwardSys.h>
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);
38 SH_DECL_HOOK8_void(IVEngineServer, EmitAmbientSound, SH_NOATTRIB, 0, int, const Vector &, const char *, float, soundlevel_t, int, int, float);
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);
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);
52 bool g_InSoundHook = false;
54 /***************************
56 * Sound Related Hook Class *
58 ****************************/
60 cell_t SoundReferenceToIndex(cell_t ref)
62 if (ref == 0 || ref == -1 || ref == -2)
67 return gamehelpers->ReferenceToIndex(ref);
70 size_t SoundHooks::_FillInPlayers(int *pl_array, IRecipientFilter *pFilter)
72 size_t size = static_cast<size_t>(pFilter->GetRecipientCount());
74 for (size_t i=0; i<size; i++)
77 #if SOURCE_ENGINE == SE_DOTA
78 index = pFilter->GetRecipientIndex(i).Get();
80 index = pFilter->GetRecipientIndex(i);
88 void SoundHooks::_IncRefCounter(int type)
90 if (type == NORMAL_SOUND_HOOK)
92 if (m_NormalCount++ == 0)
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);
98 else if (type == AMBIENT_SOUND_HOOK)
100 if (m_AmbientCount++ == 0)
102 SH_ADD_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
107 void SoundHooks::_DecRefCounter(int type)
109 if (type == NORMAL_SOUND_HOOK)
111 if (--m_NormalCount == 0)
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);
117 else if (type == AMBIENT_SOUND_HOOK)
119 if (--m_AmbientCount == 0)
121 SH_REMOVE_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
126 void SoundHooks::Initialize()
128 plsys->AddPluginsListener(this);
131 void SoundHooks::Shutdown()
133 plsys->RemovePluginsListener(this);
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);
141 SH_REMOVE_HOOK(IVEngineServer, EmitAmbientSound, engine, SH_MEMBER(this, &SoundHooks::OnEmitAmbientSound), false);
145 void SoundHooks::OnPluginUnloaded(IPlugin *plugin)
148 IPluginContext *pContext = plugin->GetBaseContext();
152 for (iter=m_AmbientFuncs.begin(); iter!=m_AmbientFuncs.end(); )
154 if ((*iter)->GetParentContext() == pContext)
156 iter = m_AmbientFuncs.erase(iter);
157 _DecRefCounter(AMBIENT_SOUND_HOOK);
167 for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); )
169 if ((*iter)->GetParentContext() == pContext)
171 iter = m_NormalFuncs.erase(iter);
172 _DecRefCounter(NORMAL_SOUND_HOOK);
182 void SoundHooks::AddHook(int type, IPluginFunction *pFunc)
184 if (type == NORMAL_SOUND_HOOK)
186 m_NormalFuncs.push_back(pFunc);
187 _IncRefCounter(NORMAL_SOUND_HOOK);
189 else if (type == AMBIENT_SOUND_HOOK)
191 m_AmbientFuncs.push_back(pFunc);
192 _IncRefCounter(AMBIENT_SOUND_HOOK);
196 bool SoundHooks::RemoveHook(int type, IPluginFunction *pFunc)
199 if (type == NORMAL_SOUND_HOOK)
201 if ((iter=m_NormalFuncs.find(pFunc)) != m_NormalFuncs.end())
203 m_NormalFuncs.erase(iter);
204 _DecRefCounter(NORMAL_SOUND_HOOK);
212 else if (type == AMBIENT_SOUND_HOOK)
214 if ((iter=m_AmbientFuncs.find(pFunc)) != m_AmbientFuncs.end())
216 m_AmbientFuncs.erase(iter);
217 _DecRefCounter(AMBIENT_SOUND_HOOK);
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)
233 int entindex = index.Get();
235 void SoundHooks::OnEmitAmbientSound(int entindex, const Vector &pos, const char *samp, float vol,
236 soundlevel_t soundlevel, int fFlags, int pitch, float delay)
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);
246 for (iter=m_AmbientFuncs.begin(); iter!=m_AmbientFuncs.end(); 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;
266 RETURN_META(MRES_SUPERCEDE);
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));
278 RETURN_META_NEWPARAMS(MRES_IGNORED, &IVEngineServer::EmitAmbientSound,
279 (entindex, vec2, buffer, vol, soundlevel, fFlags, pitch, delay));
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)
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)
304 IPluginFunction *pFunc;
305 cell_t res = static_cast<ResultType>(Pl_Continue);
306 char buffer[PLATFORM_MAX_PATH];
307 strcpy(buffer, pSample);
309 for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
311 int players[SM_MAXPLAYERS], size;
312 size = _FillInPlayers(players, &filter);
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;
333 #if SOURCE_ENGINE >= SE_PORTAL2
334 RETURN_META_VALUE(MRES_SUPERCEDE, -1);
336 RETURN_META(MRES_SUPERCEDE);
341 /* Client validation */
342 for (int i = 0; i < size; i++)
344 int client = players[i];
345 IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
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);
356 #if SOURCE_ENGINE >= SE_PORTAL2
357 RETURN_META_VALUE(MRES_IGNORED, -1 );
363 CellRecipientFilter crf;
364 crf.Initialize(players, size);
365 #if SOURCE_ENGINE >= SE_PORTAL2
366 RETURN_META_VALUE_NEWPARAMS(
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)
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(
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)
383 RETURN_META_NEWPARAMS(
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)
395 #if SOURCE_ENGINE >= SE_PORTAL2
396 RETURN_META_VALUE(MRES_IGNORED, -1 );
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)
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)
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);
424 for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
426 int players[SM_MAXPLAYERS], size;
427 size = _FillInPlayers(players, &filter);
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;
448 #if SOURCE_ENGINE >= SE_PORTAL2
449 RETURN_META_VALUE(MRES_SUPERCEDE, -1);
451 RETURN_META(MRES_SUPERCEDE);
456 /* Client validation */
457 for (int i = 0; i < size; i++)
459 int client = players[i];
460 IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
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);
471 #if SOURCE_ENGINE >= SE_PORTAL2
472 RETURN_META_VALUE(MRES_IGNORED, -1 );
478 CellRecipientFilter crf;
479 crf.Initialize(players, size);
480 #if SOURCE_ENGINE >= SE_PORTAL2
481 RETURN_META_VALUE_NEWPARAMS(
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)
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(
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)
498 RETURN_META_NEWPARAMS(
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)
510 #if SOURCE_ENGINE >= SE_PORTAL2
511 RETURN_META_VALUE(MRES_IGNORED, -1 );
515 /************************
517 * Sound Related Natives *
519 *************************/
521 SoundHooks s_SoundHooks;
523 static cell_t PrefetchSound(IPluginContext *pContext, const cell_t *params)
526 pContext->LocalToString(params[1], &name);
528 engsound->PrefetchSound(name);
533 static cell_t GetSoundDuration(IPluginContext *pContext, const cell_t *params)
536 pContext->LocalToString(params[1], &name);
538 return sp_ftoc(engsound->GetSoundDuration(name));
541 static cell_t EmitAmbientSound(IPluginContext *pContext, const cell_t *params)
547 int pitch, flags, level;
549 entity = SoundReferenceToIndex(params[3]);
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]);
557 pContext->LocalToString(params[1], &name);
559 vol = sp_ctof(params[6]);
563 delay = sp_ctof(params[8]);
567 ENGINE_CALL(EmitAmbientSound)(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
571 engine->EmitAmbientSound(entity, pos, name, vol, (soundlevel_t)level, flags, pitch, delay);
577 static cell_t FadeClientVolume(IPluginContext *pContext, const cell_t *params)
579 int client = params[1];
580 if (client < 1 || client > playerhelpers->GetMaxClients())
582 return pContext->ThrowNativeError("Client index %d is not valid", client);
585 IGamePlayer *player = playerhelpers->GetGamePlayer(client);
586 if (!player->IsInGame())
588 return pContext->ThrowNativeError("Client index %d is not in game", client);
591 engine->FadeClientVolume(
592 #if SOURCE_ENGINE == SE_DOTA
605 static cell_t StopSound(IPluginContext *pContext, const cell_t *params)
607 int entity = SoundReferenceToIndex(params[1]);
608 int channel = params[2];
611 pContext->LocalToString(params[3], &name);
613 #if SOURCE_ENGINE >= SE_PORTAL2
614 engsound->StopSound(entity, channel, name, -1);
616 engsound->StopSound(entity, channel, name);
622 static cell_t EmitSound(IPluginContext *pContext, const cell_t *params)
624 cell_t *addr, *cl_array;
625 CellRecipientFilter crf;
626 unsigned int numClients;
628 IGamePlayer *pPlayer = NULL;
630 pContext->LocalToPhysAddr(params[1], &cl_array);
631 numClients = params[2];
633 /* Client validation */
634 for (unsigned int i = 0; i < numClients; i++)
636 client = cl_array[i];
637 pPlayer = playerhelpers->GetGamePlayer(client);
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);
647 crf.Initialize(cl_array, numClients);
650 pContext->LocalToString(params[3], &sample);
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];
660 Vector *pOrigin = NULL, origin;
661 Vector *pDir = NULL, dir;
663 pContext->LocalToPhysAddr(params[11], &addr);
664 if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
667 origin.x = sp_ctof(addr[0]);
668 origin.y = sp_ctof(addr[1]);
669 origin.z = sp_ctof(addr[2]);
672 pContext->LocalToPhysAddr(params[12], &addr);
673 if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
676 dir.x = sp_ctof(addr[0]);
677 dir.y = sp_ctof(addr[1]);
678 dir.z = sp_ctof(addr[2]);
681 bool updatePos = params[13] ? true : false;
682 float soundtime = sp_ctof(params[14]);
684 CUtlVector<Vector> *pOrigVec = NULL;
685 CUtlVector<Vector> origvec;
689 for (cell_t i = 15; i <= params[0]; i++)
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);
700 /* If we're going to a "local player" and this is a dedicated server,
701 * intelligently redirect each sound.
704 if (entity == -2 && engine->IsDedicatedServer())
706 for (unsigned int i = 0; i < numClients; i++)
709 player[0] = cl_array[i];
711 crf.Initialize(player, 1);
712 #if SOURCE_ENGINE >= SE_PORTAL2
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)>
719 (&IEngineSound::EmitSound))
740 engsound->EmitSound(crf,
758 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
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))
783 engsound->EmitSound(crf,
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))
823 engsound->EmitSound(crf,
841 #if SOURCE_ENGINE >= SE_PORTAL2
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))
868 engsound->EmitSound(crf,
886 #elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
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))
911 engsound->EmitSound(crf,
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))
951 engsound->EmitSound(crf,
972 static cell_t EmitSentence(IPluginContext *pContext, const cell_t *params)
975 CellRecipientFilter crf;
976 unsigned int numClients;
978 IGamePlayer *pPlayer = NULL;
980 pContext->LocalToPhysAddr(params[1], &addr);
981 numClients = params[2];
983 /* Client validation */
984 for (unsigned int i = 0; i < numClients; i++)
987 pPlayer = playerhelpers->GetGamePlayer(client);
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);
997 crf.Initialize(addr, numClients);
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];
1008 Vector *pOrigin = NULL, origin;
1009 Vector *pDir = NULL, dir;
1011 pContext->LocalToPhysAddr(params[11], &addr);
1012 if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
1015 origin.x = sp_ctof(addr[0]);
1016 origin.y = sp_ctof(addr[1]);
1017 origin.z = sp_ctof(addr[2]);
1020 pContext->LocalToPhysAddr(params[12], &addr);
1021 if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
1024 dir.x = sp_ctof(addr[0]);
1025 dir.y = sp_ctof(addr[1]);
1026 dir.z = sp_ctof(addr[2]);
1029 bool updatePos = params[13] ? true : false;
1030 float soundtime = sp_ctof(params[14]);
1032 CUtlVector<Vector> *pOrigVec = NULL;
1033 CUtlVector<Vector> origvec;
1036 pOrigVec = &origvec;
1037 for (cell_t i = 15; i <= params[0]; i++)
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);
1048 engsound->EmitSentenceByIndex(crf,
1053 (soundlevel_t)level,
1054 #if SOURCE_ENGINE >= SE_PORTAL2
1059 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
1072 static cell_t smn_AddAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
1074 IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
1077 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1080 s_SoundHooks.AddHook(AMBIENT_SOUND_HOOK, pFunc);
1085 static cell_t smn_AddNormalSoundHook(IPluginContext *pContext, const cell_t *params)
1087 IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
1090 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1093 s_SoundHooks.AddHook(NORMAL_SOUND_HOOK, pFunc);
1098 static cell_t smn_RemoveAmbientSoundHook(IPluginContext *pContext, const cell_t *params)
1100 IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
1103 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1106 if (!s_SoundHooks.RemoveHook(AMBIENT_SOUND_HOOK, pFunc))
1108 return pContext->ThrowNativeError("Invalid hooked function");
1114 static cell_t smn_RemoveNormalSoundHook(IPluginContext *pContext, const cell_t *params)
1116 IPluginFunction *pFunc = pContext->GetFunctionById(params[1]);
1119 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1122 if (!s_SoundHooks.RemoveHook(NORMAL_SOUND_HOOK, pFunc))
1124 return pContext->ThrowNativeError("Invalid hooked function");
1130 static cell_t smn_GetDistGainFromSoundLevel(IPluginContext *pContext, const cell_t *params)
1132 int decibel = params[1];
1133 float distance = sp_ctof(params[2]);
1135 return sp_ftoc(engsound->GetDistGainFromSoundLevel((soundlevel_t)decibel, distance));
1138 sp_nativeinfo_t g_SoundNatives[] =
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},