extensions/sdktools/voice.cpp
author Fyren <fyrenmoo@gmail.com>
Mon May 11 18:46:19 2009 -0700 (2009-05-11)
changeset 2710 3bf47c5fa143
parent 2289 44045ead61cd
child 2711 858723415154
permissions -rw-r--r--
Some sdktools string and style changes (r=pred)
     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 <extension.h>
    33 
    34 #define SPEAK_NORMAL		0
    35 #define SPEAK_MUTED			1
    36 #define SPEAK_ALL			2
    37 #define SPEAK_LISTENALL		4
    38 #define SPEAK_TEAM			8
    39 #define SPEAK_LISTENTEAM	16
    40 #define LISTEN_DEFAULT		0
    41 #define LISTEN_NO			1
    42 #define LISTEN_YES			2
    43 
    44 size_t g_VoiceFlags[65];
    45 size_t g_VoiceHookCount = 0;
    46 int g_VoiceMap[65][65];
    47 
    48 SH_DECL_HOOK3(IVoiceServer, SetClientListening, SH_NOATTRIB, 0, bool, int, int, bool);
    49 
    50 bool DecHookCount(int amount = 1);
    51 bool DecHookCount(int amount)
    52 {
    53 	g_VoiceHookCount -= amount;
    54 	if (g_VoiceHookCount == 0)
    55 	{
    56 		SH_REMOVE_HOOK_MEMFUNC(IVoiceServer, SetClientListening, voiceserver, &g_SdkTools, &SDKTools::OnSetClientListening, false);
    57 		return true;
    58 	}
    59 
    60 	return false;
    61 }
    62 
    63 void IncHookCount()
    64 {
    65 	if (!g_VoiceHookCount++)
    66 	{
    67 		SH_ADD_HOOK_MEMFUNC(IVoiceServer, SetClientListening, voiceserver, &g_SdkTools, &SDKTools::OnSetClientListening, false);
    68 	}
    69 }
    70 
    71 void SDKTools::VoiceInit()
    72 {
    73 	memset(g_VoiceMap, 0, sizeof(g_VoiceMap));
    74 }
    75 
    76 bool SDKTools::OnSetClientListening(int iReceiver, int iSender, bool bListen)
    77 {
    78 	if (g_VoiceMap[iReceiver][iSender] == LISTEN_NO)
    79 	{
    80 		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false));
    81 	}
    82 	else if (g_VoiceMap[iReceiver][iSender] == LISTEN_YES)
    83 	{
    84 		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
    85 	}
    86 
    87 	if (g_VoiceFlags[iSender] & SPEAK_MUTED)
    88 	{
    89 		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, false));
    90 	}
    91 
    92 	if ((g_VoiceFlags[iSender] & SPEAK_ALL) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENALL))
    93 	{
    94 		RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
    95 	}
    96 
    97 	if ((g_VoiceFlags[iSender] & SPEAK_TEAM) || (g_VoiceFlags[iReceiver] & SPEAK_LISTENTEAM))
    98 	{
    99 		IGamePlayer *pReceiver = playerhelpers->GetGamePlayer(iReceiver);
   100 		IGamePlayer *pSender = playerhelpers->GetGamePlayer(iSender);
   101 
   102 		if (pReceiver && pSender && pReceiver->IsInGame() && pSender->IsInGame())
   103 		{
   104 			IPlayerInfo *pRInfo = pReceiver->GetPlayerInfo();
   105 			IPlayerInfo *pSInfo = pSender->GetPlayerInfo();
   106 
   107 			if (pRInfo && pSInfo && pRInfo->GetTeamIndex() == pSInfo->GetTeamIndex())
   108 			{
   109 				RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVoiceServer::SetClientListening, (iReceiver, iSender, true));
   110 			}
   111 		}
   112 	}
   113 
   114 	RETURN_META_VALUE(MRES_IGNORED, bListen);
   115 }
   116 
   117 void SDKTools::OnClientDisconnecting(int client)
   118 {
   119 	int max_clients = playerhelpers->GetMaxClients();
   120 
   121 	if (g_VoiceHookCount == 0)
   122 	{
   123 		return;
   124 	}
   125 
   126 	/* This can probably be optimized more, but I doubt it's that much 
   127 	 * of an actual bottleneck.
   128 	 */
   129 
   130 	/* Reset clients who receive from us */
   131 	for (int i = 1; i <= max_clients; i++)
   132 	{
   133 		if (i == client)
   134 		{
   135 			continue;
   136 		}
   137 
   138 		if (g_VoiceMap[i][client] != LISTEN_DEFAULT)
   139 		{
   140 			g_VoiceMap[i][client] = LISTEN_DEFAULT;
   141 			if (DecHookCount())
   142 			{
   143 				return;
   144 			}
   145 		}
   146 	}
   147 
   148 	/* Reset clients who send to us.  I'm shoving a count in the 0 index! */
   149 	if (g_VoiceMap[client][0] > 0)
   150 	{
   151 		DecHookCount(g_VoiceMap[client][0]);
   152 		memset(&g_VoiceMap[client], 0, sizeof(int) * 65);
   153 	}
   154 
   155 	if (g_VoiceFlags[client])
   156 	{
   157 		g_VoiceFlags[client] = 0;
   158 		DecHookCount();
   159 	}
   160 }
   161 
   162 static cell_t SetClientListeningFlags(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   165 	if (player == NULL)
   166 	{
   167 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   168 	}
   169 	else if (!player->IsConnected())
   170 	{
   171 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   172 	}
   173 
   174 	if (!params[2] && g_VoiceFlags[params[1]])
   175 	{
   176 		DecHookCount();
   177 	}
   178 	else if (!g_VoiceFlags[params[1]] && params[2])
   179 	{
   180 		IncHookCount();
   181 	}
   182 
   183 	g_VoiceFlags[params[1]] = params[2];
   184 
   185 	return 1;
   186 }
   187 
   188 static cell_t GetClientListeningFlags(IPluginContext *pContext, const cell_t *params)
   189 {
   190 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   191 	if (player == NULL)
   192 	{
   193 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   194 	}
   195 	else if (!player->IsConnected())
   196 	{
   197 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   198 	}
   199 
   200 	return g_VoiceFlags[params[1]];
   201 }
   202 
   203 static cell_t SetClientListening(IPluginContext *pContext, const cell_t *params)
   204 {
   205 	int r, s;
   206 	IGamePlayer *player;
   207 	
   208 	player = playerhelpers->GetGamePlayer(params[1]);
   209 	if (player == NULL)
   210 	{
   211 		return pContext->ThrowNativeError("(Receiver) client index %d is invalid", params[1]);
   212 	}
   213 	else if (!player->IsConnected())
   214 	{
   215 		return pContext->ThrowNativeError("(Receiver) client %d is not connected", params[1]);
   216 	}
   217 
   218 	player = playerhelpers->GetGamePlayer(params[2]);
   219 	if (player == NULL)
   220 	{
   221 		return pContext->ThrowNativeError("(Sender) client index %d is invalid", params[2]);
   222 	}
   223 	else if (!player->IsConnected())
   224 	{
   225 		return pContext->ThrowNativeError("(Sender) client %d is not connected", params[2]);
   226 	}
   227 
   228 	r = params[1];
   229 	s = params[2];
   230 	
   231 	if (g_VoiceMap[r][s] == LISTEN_DEFAULT && params[3] != LISTEN_DEFAULT)
   232 	{
   233 		g_VoiceMap[r][s] = params[3];
   234 		g_VoiceMap[r][0]++;
   235 		IncHookCount();
   236 	}
   237 	else if (g_VoiceMap[r][s] != LISTEN_DEFAULT && params[3] == LISTEN_DEFAULT)
   238 	{
   239 		g_VoiceMap[r][s] = params[3];
   240 		g_VoiceMap[r][0]--;
   241 		DecHookCount();
   242 	}
   243 	else
   244 	{
   245 		g_VoiceMap[r][s] = params[3];
   246 	}
   247 
   248 	return 1;
   249 }
   250 
   251 static cell_t GetClientListening(IPluginContext *pContext, const cell_t *params)
   252 {
   253 	IGamePlayer *player;
   254 
   255 	player = playerhelpers->GetGamePlayer(params[1]);
   256 	if (player == NULL)
   257 	{
   258 		return pContext->ThrowNativeError("(Receiver) client index %d is invalid", params[1]);
   259 	}
   260 	else if (!player->IsConnected())
   261 	{
   262 		return pContext->ThrowNativeError("(Receiver) client %d is not connected", params[1]);
   263 	}
   264 
   265 	player = playerhelpers->GetGamePlayer(params[2]);
   266 	if (player == NULL)
   267 	{
   268 		return pContext->ThrowNativeError("(Sender) client index %d is invalid", params[2]);
   269 	}
   270 	else if (!player->IsConnected())
   271 	{
   272 		return pContext->ThrowNativeError("(Sender) client %d is not connected", params[2]);
   273 	}
   274 
   275 	return g_VoiceMap[params[1]][params[2]];
   276 }
   277 
   278 sp_nativeinfo_t g_VoiceNatives[] =
   279 {
   280 	{"SetClientListeningFlags",		SetClientListeningFlags},
   281 	{"GetClientListeningFlags",		GetClientListeningFlags},
   282 	{"SetClientListening",			SetClientListening},
   283 	{"GetClientListening",			GetClientListening},
   284 	{NULL,							NULL},
   285 };