core/smn_player.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Tue Jan 22 23:18:27 2013 -0500 (2013-01-22)
changeset 3749 4dc3d723c490
parent 3696 9588d737efe0
child 3808 b5f4ea4d3736
permissions -rw-r--r--
Triggering build against new mac libprotobuf.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     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 "PlayerManager.h"
    33 #include "AdminCache.h"
    34 #include "sm_stringutil.h"
    35 #include "HalfLife2.h"
    36 #include "sourcemod.h"
    37 #include "ChatTriggers.h"
    38 #include <inetchannel.h>
    39 #include <iclient.h>
    40 
    41 ConVar sm_show_activity("sm_show_activity", "13", FCVAR_SPONLY, "Activity display setting (see sourcemod.cfg)");
    42 
    43 static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params)
    44 {
    45 	if (params[1])
    46 	{
    47 		return g_Players.NumPlayers();
    48 	}
    49 
    50 	int maxplayers = g_Players.MaxClients();
    51 	int count = 0;
    52 	for (int i=1; i<=maxplayers; ++i)
    53 	{
    54 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
    55 		if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame()))
    56 		{
    57 			count++;
    58 		}
    59 	}
    60 
    61 	return (g_Players.NumPlayers() + count);
    62 }
    63 
    64 static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params)
    65 {
    66 	return g_Players.MaxClients();
    67 }
    68 
    69 static cell_t sm_GetMaxHumanPlayers(IPluginContext *pCtx, const cell_t *params)
    70 {
    71 	int maxHumans = -1;
    72 
    73 #if SOURCE_ENGINE >= SE_LEFT4DEAD
    74 	maxHumans = serverClients->GetMaxHumanPlayers();
    75 #endif
    76 
    77 	if( maxHumans == -1 )
    78 	{
    79 		return g_Players.MaxClients();
    80 	}
    81 	
    82 	return maxHumans;
    83 }
    84 
    85 static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params)
    86 {
    87 	int index = params[1];
    88 
    89 	if (index == 0)
    90 	{
    91 		static ConVar *hostname = NULL;
    92 		if (!hostname)
    93 		{
    94 			hostname = icvar->FindVar("hostname");
    95 			if (!hostname)
    96 			{
    97 				return pCtx->ThrowNativeError("Could not find \"hostname\" cvar");
    98 			}
    99 		}
   100 		pCtx->StringToLocalUTF8(params[2], static_cast<size_t>(params[3]), hostname->GetString(), NULL);
   101 		return 1;
   102 	}
   103 
   104 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   105 	{
   106 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   107 	}
   108 
   109 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   110 	if (!pPlayer->IsConnected())
   111 	{
   112 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   113 	}
   114 
   115 	pCtx->StringToLocalUTF8(params[2], static_cast<size_t>(params[3]), pPlayer->GetName(), NULL);
   116 	return 1;
   117 }
   118 
   119 static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params)
   120 {
   121 	int index = params[1];
   122 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   123 	{
   124 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   125 	}
   126 
   127 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   128 	if (!pPlayer->IsConnected())
   129 	{
   130 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   131 	}
   132 
   133 	char buf[64], *ptr;
   134 	strcpy(buf, pPlayer->GetIPAddress());
   135 
   136 	if (params[4] && (ptr = strchr(buf, ':')))
   137 	{
   138 		*ptr = '\0';
   139 	}
   140 
   141 	pCtx->StringToLocal(params[2], static_cast<size_t>(params[3]), buf);
   142 	return 1;
   143 }
   144 
   145 static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
   146 {
   147 	int index = params[1];
   148 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   149 	{
   150 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   151 	}
   152 
   153 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   154 	if (!pPlayer->IsConnected())
   155 	{
   156 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   157 	}
   158 
   159 	if (!pPlayer->IsAuthorized())
   160 	{
   161 		return 0;
   162 	}
   163 
   164 	pCtx->StringToLocal(params[2], static_cast<size_t>(params[3]), pPlayer->GetAuthString());
   165 
   166 	return 1;
   167 }
   168 
   169 static cell_t sm_IsClientConnected(IPluginContext *pCtx, const cell_t *params)
   170 {
   171 	int index = params[1];
   172 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   173 	{
   174 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   175 	}
   176 
   177 	return (g_Players.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0;
   178 }
   179 
   180 static cell_t sm_IsClientInGame(IPluginContext *pCtx, const cell_t *params)
   181 {
   182 	int index = params[1];
   183 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   184 	{
   185 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   186 	}
   187 
   188 	return (g_Players.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0;
   189 }
   190 
   191 static cell_t sm_IsClientAuthorized(IPluginContext *pCtx, const cell_t *params)
   192 {
   193 	int index = params[1];
   194 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   195 	{
   196 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   197 	}
   198 
   199 	return (g_Players.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0;
   200 }
   201 
   202 static cell_t sm_IsClientFakeClient(IPluginContext *pCtx, const cell_t *params)
   203 {
   204 	int index = params[1];
   205 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   206 	{
   207 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   208 	}
   209 
   210 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   211 	if (!pPlayer->IsConnected())
   212 	{
   213 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   214 	}
   215 
   216 	return (pPlayer->IsFakeClient()) ? 1 : 0;
   217 }
   218 
   219 static cell_t sm_IsClientSourceTV(IPluginContext *pCtx, const cell_t *params)
   220 {
   221 	int index = params[1];
   222 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   223 	{
   224 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   225 	}
   226 
   227 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   228 	if (!pPlayer->IsConnected())
   229 	{
   230 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   231 	}
   232 
   233 	return (pPlayer->IsSourceTV()) ? 1 : 0;
   234 }
   235 
   236 static cell_t sm_IsClientReplay(IPluginContext *pCtx, const cell_t *params)
   237 {
   238 	int index = params[1];
   239 	if ((index < 1) || (index > g_Players.GetMaxClients()))
   240 	{
   241 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   242 	}
   243 
   244 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
   245 	if (!pPlayer->IsConnected())
   246 	{
   247 		return pCtx->ThrowNativeError("Client %d is not connected", index);
   248 	}
   249 
   250 	return (pPlayer->IsReplay()) ? 1 : 0;
   251 }
   252 
   253 static cell_t IsClientObserver(IPluginContext *pContext, const cell_t *params)
   254 {
   255 	int client = params[1];
   256 
   257 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   258 	if (!pPlayer)
   259 	{
   260 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   261 	} else if (!pPlayer->IsInGame()) {
   262 		return pContext->ThrowNativeError("Client %d is not in game", client);
   263 	}
   264 
   265 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   266 	if (!pInfo)
   267 	{
   268 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   269 	}
   270 
   271 	return pInfo->IsObserver() ? 1 : 0;
   272 }
   273 
   274 static cell_t sm_GetClientInfo(IPluginContext *pContext, const cell_t *params)
   275 {
   276 	int client = params[1];
   277 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   278 	if (!pPlayer)
   279 	{
   280 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   281 	}
   282 	if (!pPlayer->IsConnected())
   283 	{
   284 		return pContext->ThrowNativeError("Client %d is not connected", client);
   285 	}
   286 
   287 	char *key;
   288 	pContext->LocalToString(params[2], &key);
   289 
   290 	const char *val = engine->GetClientConVarValue(client, key);
   291 	if (!val)
   292 	{
   293 		return false;
   294 	}
   295 
   296 	pContext->StringToLocalUTF8(params[3], params[4], val, NULL);
   297 	return 1;
   298 }
   299 
   300 static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params)
   301 {
   302 	int client = params[1];
   303 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   304 	if (!pPlayer)
   305 	{
   306 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   307 	}
   308 	if (!pPlayer->IsConnected())
   309 	{
   310 		return pContext->ThrowNativeError("Client %d is not connected", client);
   311 	}
   312 	if (!g_Admins.IsValidAdmin(params[2]) && params[2] != INVALID_ADMIN_ID)
   313 	{
   314 		return pContext->ThrowNativeError("AdminId %x is invalid", params[2]);
   315 	}
   316 
   317 	pPlayer->SetAdminId(params[2], params[3] ? true : false);
   318 
   319 	return 1;
   320 }
   321 
   322 static cell_t GetUserAdmin(IPluginContext *pContext, const cell_t *params)
   323 {
   324 	int client = params[1];
   325 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   326 	if (!pPlayer)
   327 	{
   328 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   329 	}
   330 	if (!pPlayer->IsConnected())
   331 	{
   332 		return pContext->ThrowNativeError("Client %d is not connected", client);
   333 	}
   334 
   335 	return pPlayer->GetAdminId();
   336 }
   337 
   338 static cell_t AddUserFlags(IPluginContext *pContext, const cell_t *params)
   339 {
   340 	int client = params[1];
   341 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   342 	if (!pPlayer)
   343 	{
   344 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   345 	}
   346 	if (!pPlayer->IsConnected())
   347 	{
   348 		return pContext->ThrowNativeError("Client %d is not connected", client);
   349 	}
   350 
   351 	AdminId id;
   352 	if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID)
   353 	{
   354 		id = g_Admins.CreateAdmin(NULL);
   355 		pPlayer->SetAdminId(id, true);
   356 	}
   357 
   358 	cell_t *addr;
   359 	for (int i=2; i<=params[0]; i++)
   360 	{
   361 		pContext->LocalToPhysAddr(params[i], &addr);
   362 		g_Admins.SetAdminFlag(id, (AdminFlag)*addr, true);
   363 	}
   364 
   365 	return 1;
   366 }
   367 
   368 static cell_t RemoveUserFlags(IPluginContext *pContext, const cell_t *params)
   369 {
   370 	int client = params[1];
   371 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   372 	if (!pPlayer)
   373 	{
   374 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   375 	}
   376 	if (!pPlayer->IsConnected())
   377 	{
   378 		return pContext->ThrowNativeError("Client %d is not connected", client);
   379 	}
   380 	
   381 	AdminId id;
   382 	if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID)
   383 	{
   384 		return 0;
   385 	}
   386 
   387 	cell_t *addr;
   388 	for (int i=2; i<=params[0]; i++)
   389 	{
   390 		pContext->LocalToPhysAddr(params[i], &addr);
   391 		g_Admins.SetAdminFlag(id, (AdminFlag)*addr, false);
   392 	}
   393 
   394 	return 1;
   395 }
   396 
   397 static cell_t SetUserFlagBits(IPluginContext *pContext, const cell_t *params)
   398 {
   399 	int client = params[1];
   400 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   401 	if (!pPlayer)
   402 	{
   403 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   404 	}
   405 	if (!pPlayer->IsConnected())
   406 	{
   407 		return pContext->ThrowNativeError("Client %d is not connected", client);
   408 	}
   409 
   410 	AdminId id;
   411 	if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID)
   412 	{
   413 		id = g_Admins.CreateAdmin(NULL);
   414 		pPlayer->SetAdminId(id, true);
   415 	}
   416 
   417 	g_Admins.SetAdminFlags(id, Access_Effective, params[2]);
   418 
   419 	return 1;
   420 }
   421 
   422 static cell_t GetUserFlagBits(IPluginContext *pContext, const cell_t *params)
   423 {
   424 	int client = params[1];
   425 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   426 	if (!pPlayer)
   427 	{
   428 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   429 	}
   430 	if (!pPlayer->IsConnected())
   431 	{
   432 		return pContext->ThrowNativeError("Client %d is not connected", client);
   433 	}
   434 
   435 	AdminId id;
   436 	if ((id=pPlayer->GetAdminId()) == INVALID_ADMIN_ID)
   437 	{
   438 		return 0;
   439 	}
   440 
   441 	return g_Admins.GetAdminFlags(id, Access_Effective);
   442 }
   443 
   444 static cell_t GetClientUserId(IPluginContext *pContext, const cell_t *params)
   445 {
   446 	int client = params[1];
   447 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   448 	if (!pPlayer)
   449 	{
   450 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   451 	}
   452 	if (!pPlayer->IsConnected())
   453 	{
   454 		return pContext->ThrowNativeError("Client %d is not connected", client);
   455 	}
   456 
   457 	return engine->GetPlayerUserId(pPlayer->GetEdict());
   458 }
   459 
   460 static cell_t CanUserTarget(IPluginContext *pContext, const cell_t *params)
   461 {
   462 	int client = params[1];
   463 	int target = params[2];
   464 
   465 	if (client == 0)
   466 	{
   467 		return 1;
   468 	}
   469 
   470 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   471 	if (!pPlayer)
   472 	{
   473 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   474 	} else if (!pPlayer->IsConnected()) {
   475 		return pContext->ThrowNativeError("Client %d is not connected", client);
   476 	}
   477 
   478 	CPlayer *pTarget = g_Players.GetPlayerByIndex(target);
   479 	if (!pTarget)
   480 	{
   481 		return pContext->ThrowNativeError("Client index %d is invalid", target);
   482 	} else if (!pTarget->IsConnected()) {
   483 		return pContext->ThrowNativeError("Client %d is not connected", target);
   484 	}
   485 
   486 	return g_Admins.CanAdminTarget(pPlayer->GetAdminId(), pTarget->GetAdminId()) ? 1 : 0;
   487 }
   488 
   489 static cell_t GetClientTeam(IPluginContext *pContext, const cell_t *params)
   490 {
   491 	int client = params[1];
   492 
   493 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   494 	if (!pPlayer)
   495 	{
   496 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   497 	} else if (!pPlayer->IsInGame()) {
   498 		return pContext->ThrowNativeError("Client %d is not in game", client);
   499 	}
   500 
   501 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   502 	if (!pInfo)
   503 	{
   504 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   505 	}
   506 
   507 	return pInfo->GetTeamIndex();
   508 }
   509 
   510 static cell_t GetFragCount(IPluginContext *pContext, const cell_t *params)
   511 {
   512 	int client = params[1];
   513 
   514 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   515 	if (!pPlayer)
   516 	{
   517 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   518 	} else if (!pPlayer->IsInGame()) {
   519 		return pContext->ThrowNativeError("Client %d is not in game", client);
   520 	}
   521 
   522 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   523 	if (!pInfo)
   524 	{
   525 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   526 	}
   527 
   528 	return pInfo->GetFragCount();
   529 }
   530 
   531 static cell_t GetDeathCount(IPluginContext *pContext, const cell_t *params)
   532 {
   533 	int client = params[1];
   534 
   535 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   536 	if (!pPlayer)
   537 	{
   538 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   539 	} else if (!pPlayer->IsInGame()) {
   540 		return pContext->ThrowNativeError("Client %d is not in game", client);
   541 	}
   542 
   543 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   544 	if (!pInfo)
   545 	{
   546 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   547 	}
   548 
   549 	return pInfo->GetDeathCount();
   550 }
   551 
   552 static cell_t GetArmorValue(IPluginContext *pContext, const cell_t *params)
   553 {
   554 	int client = params[1];
   555 
   556 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   557 	if (!pPlayer)
   558 	{
   559 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   560 	} else if (!pPlayer->IsInGame()) {
   561 		return pContext->ThrowNativeError("Client %d is not in game", client);
   562 	}
   563 
   564 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   565 	if (!pInfo)
   566 	{
   567 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   568 	}
   569 
   570 	return pInfo->GetArmorValue();
   571 }
   572 
   573 static cell_t GetAbsOrigin(IPluginContext *pContext, const cell_t *params)
   574 {
   575 	int client = params[1];
   576 
   577 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   578 	if (!pPlayer)
   579 	{
   580 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   581 	} else if (!pPlayer->IsInGame()) {
   582 		return pContext->ThrowNativeError("Client %d is not in game", client);
   583 	}
   584 
   585 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   586 	if (!pInfo)
   587 	{
   588 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   589 	}
   590 
   591 	cell_t *pVec;
   592 	pContext->LocalToPhysAddr(params[2], &pVec);
   593 
   594 	Vector vec = pInfo->GetAbsOrigin();
   595 	pVec[0] = sp_ftoc(vec.x);
   596 	pVec[1] = sp_ftoc(vec.y);
   597 	pVec[2] = sp_ftoc(vec.z);
   598 
   599 	return 1;
   600 }
   601 
   602 static cell_t GetAbsAngles(IPluginContext *pContext, const cell_t *params)
   603 {
   604 	int client = params[1];
   605 
   606 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   607 	if (!pPlayer)
   608 	{
   609 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   610 	} else if (!pPlayer->IsInGame()) {
   611 		return pContext->ThrowNativeError("Client %d is not in game", client);
   612 	}
   613 
   614 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   615 	if (!pInfo)
   616 	{
   617 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   618 	}
   619 
   620 	cell_t *pAng;
   621 	pContext->LocalToPhysAddr(params[2], &pAng);
   622 
   623 	QAngle ang = pInfo->GetAbsAngles();
   624 	pAng[0] = sp_ftoc(ang.x);
   625 	pAng[1] = sp_ftoc(ang.y);
   626 	pAng[2] = sp_ftoc(ang.z);
   627 
   628 	return 1;
   629 }
   630 
   631 static cell_t GetPlayerMins(IPluginContext *pContext, const cell_t *params)
   632 {
   633 	int client = params[1];
   634 
   635 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   636 	if (!pPlayer)
   637 	{
   638 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   639 	} else if (!pPlayer->IsInGame()) {
   640 		return pContext->ThrowNativeError("Client %d is not in game", client);
   641 	}
   642 
   643 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   644 	if (!pInfo)
   645 	{
   646 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   647 	}
   648 
   649 	cell_t *pVec;
   650 	pContext->LocalToPhysAddr(params[2], &pVec);
   651 
   652 	Vector vec = pInfo->GetPlayerMins();
   653 	pVec[0] = sp_ftoc(vec.x);
   654 	pVec[1] = sp_ftoc(vec.y);
   655 	pVec[2] = sp_ftoc(vec.z);
   656 
   657 	return 1;
   658 }
   659 
   660 static cell_t GetPlayerMaxs(IPluginContext *pContext, const cell_t *params)
   661 {
   662 	int client = params[1];
   663 
   664 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   665 	if (!pPlayer)
   666 	{
   667 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   668 	} else if (!pPlayer->IsInGame()) {
   669 		return pContext->ThrowNativeError("Client %d is not in game", client);
   670 	}
   671 
   672 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   673 	if (!pInfo)
   674 	{
   675 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   676 	}
   677 
   678 	cell_t *pVec;
   679 	pContext->LocalToPhysAddr(params[2], &pVec);
   680 
   681 	Vector vec = pInfo->GetPlayerMaxs();
   682 	pVec[0] = sp_ftoc(vec.x);
   683 	pVec[1] = sp_ftoc(vec.y);
   684 	pVec[2] = sp_ftoc(vec.z);
   685 
   686 	return 1;
   687 }
   688 
   689 static cell_t GetWeaponName(IPluginContext *pContext, const cell_t *params)
   690 {
   691 	int client = params[1];
   692 
   693 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   694 	if (!pPlayer)
   695 	{
   696 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   697 	} else if (!pPlayer->IsInGame()) {
   698 		return pContext->ThrowNativeError("Client %d is not in game", client);
   699 	}
   700 
   701 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   702 	if (!pInfo)
   703 	{
   704 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   705 	}
   706 
   707 	const char *weapon = pInfo->GetWeaponName();
   708 	pContext->StringToLocalUTF8(params[2], static_cast<size_t>(params[3]), weapon ? weapon : "", NULL);
   709 
   710 	return 1;
   711 }
   712 
   713 static cell_t GetModelName(IPluginContext *pContext, const cell_t *params)
   714 {
   715 	int client = params[1];
   716 
   717 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   718 	if (!pPlayer)
   719 	{
   720 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   721 	} else if (!pPlayer->IsInGame()) {
   722 		return pContext->ThrowNativeError("Client %d is not in game", client);
   723 	}
   724 
   725 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   726 	if (!pInfo)
   727 	{
   728 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   729 	}
   730 
   731 	const char *model = pInfo->GetModelName();
   732 	pContext->StringToLocalUTF8(params[2], static_cast<size_t>(params[3]), model ? model : "", NULL);
   733 
   734 	return 1;
   735 }
   736 
   737 static cell_t GetHealth(IPluginContext *pContext, const cell_t *params)
   738 {
   739 	int client = params[1];
   740 
   741 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   742 	if (!pPlayer)
   743 	{
   744 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   745 	} else if (!pPlayer->IsInGame()) {
   746 		return pContext->ThrowNativeError("Client %d is not in game", client);
   747 	}
   748 
   749 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
   750 	if (!pInfo)
   751 	{
   752 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
   753 	}
   754 
   755 	return pInfo->GetHealth();
   756 }
   757 
   758 static cell_t GetTimeConnected(IPluginContext *pContext, const cell_t *params)
   759 {
   760 	int client = params[1];
   761 
   762 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   763 	if (!pPlayer)
   764 	{
   765 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   766 	} else if (!pPlayer->IsInGame()) {
   767 		return pContext->ThrowNativeError("Client %d is not in game", client);
   768 	} else if (pPlayer->IsFakeClient()) {
   769 		return pContext->ThrowNativeError("Client %d is a bot", client);
   770 	}
   771 
   772 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   773 	if (pInfo == NULL)
   774 	{
   775 		return 0;
   776 	}
   777 
   778 	return sp_ftoc(pInfo->GetTimeConnected());
   779 }
   780 
   781 static cell_t GetDataRate(IPluginContext *pContext, const cell_t *params)
   782 {
   783 	int client = params[1];
   784 
   785 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   786 	if (!pPlayer)
   787 	{
   788 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   789 	} else if (!pPlayer->IsInGame()) {
   790 		return pContext->ThrowNativeError("Client %d is not in game", client);
   791 	} else if (pPlayer->IsFakeClient()) {
   792 		return pContext->ThrowNativeError("Client %d is a bot", client);
   793 	}
   794 
   795 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   796 	if (pInfo == NULL)
   797 	{
   798 		return 0;
   799 	}
   800 
   801 	return pInfo->GetDataRate();
   802 }
   803 
   804 static cell_t IsTimingOut(IPluginContext *pContext, const cell_t *params)
   805 {
   806 	int client = params[1];
   807 
   808 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   809 	if (!pPlayer)
   810 	{
   811 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   812 	} else if (!pPlayer->IsInGame()) {
   813 		return pContext->ThrowNativeError("Client %d is not in game", client);
   814 	} else if (pPlayer->IsFakeClient()) {
   815 		return pContext->ThrowNativeError("Client %d is a bot", client);
   816 	}
   817 
   818 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   819 	if (pInfo == NULL)
   820 	{
   821 		return 1;
   822 	}
   823 
   824 	return pInfo->IsTimingOut() ? 1 : 0;
   825 }
   826 
   827 static cell_t GetLatency(IPluginContext *pContext, const cell_t *params)
   828 {
   829 	int client = params[1];
   830 	float value;
   831 
   832 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   833 	if (!pPlayer)
   834 	{
   835 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   836 	}
   837 	else if (!pPlayer->IsInGame())
   838 	{
   839 		return pContext->ThrowNativeError("Client %d is not in game", client);
   840 	}
   841 	else if (pPlayer->IsFakeClient())
   842 	{
   843 		return pContext->ThrowNativeError("Client %d is a bot", client);
   844 	}
   845 
   846 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   847 	if (pInfo == NULL)
   848 	{
   849 		return sp_ftoc(-1);
   850 	}
   851 
   852 	if (params[2] == MAX_FLOWS)
   853 	{
   854 		value = pInfo->GetLatency(FLOW_INCOMING) + pInfo->GetLatency(FLOW_OUTGOING);
   855 	}
   856 	else
   857 	{
   858 		value = pInfo->GetLatency(params[2]);
   859 	}
   860 
   861 	return sp_ftoc(value);
   862 }
   863 
   864 static cell_t GetAvgLatency(IPluginContext *pContext, const cell_t *params)
   865 {
   866 	int client = params[1];
   867 	float value;
   868 
   869 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   870 	if (!pPlayer)
   871 	{
   872 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   873 	}
   874 	else if (!pPlayer->IsInGame())
   875 	{
   876 		return pContext->ThrowNativeError("Client %d is not in game", client);
   877 	}
   878 	else if (pPlayer->IsFakeClient())
   879 	{
   880 		return pContext->ThrowNativeError("Client %d is a bot", client);
   881 	}
   882 
   883 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   884 	if (pInfo == NULL)
   885 	{
   886 		return sp_ftoc(-1);
   887 	}
   888 
   889 	if (params[2] == MAX_FLOWS)
   890 	{
   891 		value = pInfo->GetAvgLatency(FLOW_INCOMING) + pInfo->GetAvgLatency(FLOW_OUTGOING);
   892 	}
   893 	else
   894 	{
   895 		value = pInfo->GetAvgLatency(params[2]);
   896 	}
   897 
   898 	return sp_ftoc(value);
   899 }
   900 
   901 static cell_t GetAvgLoss(IPluginContext *pContext, const cell_t *params)
   902 {
   903 	int client = params[1];
   904 	float value;
   905 
   906 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   907 	if (!pPlayer)
   908 	{
   909 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   910 	}
   911 	else if (!pPlayer->IsInGame())
   912 	{
   913 		return pContext->ThrowNativeError("Client %d is not in game", client);
   914 	}
   915 	else if (pPlayer->IsFakeClient())
   916 	{
   917 		return pContext->ThrowNativeError("Client %d is a bot", client);
   918 	}
   919 
   920 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   921 	if (pInfo == NULL)
   922 	{
   923 		return sp_ftoc(-1);
   924 	}
   925 
   926 	if (params[2] == MAX_FLOWS)
   927 	{
   928 		value = pInfo->GetAvgLoss(FLOW_INCOMING) + pInfo->GetAvgLoss(FLOW_OUTGOING);
   929 	}
   930 	else
   931 	{
   932 		value = pInfo->GetAvgLoss(params[2]);
   933 	}
   934 
   935 	return sp_ftoc(value);
   936 }
   937 
   938 static cell_t GetAvgChoke(IPluginContext *pContext, const cell_t *params)
   939 {
   940 	int client = params[1];
   941 	float value;
   942 
   943 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   944 	if (!pPlayer)
   945 	{
   946 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   947 	}
   948 	else if (!pPlayer->IsInGame())
   949 	{
   950 		return pContext->ThrowNativeError("Client %d is not in game", client);
   951 	}
   952 	else if (pPlayer->IsFakeClient())
   953 	{
   954 		return pContext->ThrowNativeError("Client %d is a bot", client);
   955 	}
   956 
   957 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   958 	if (pInfo == NULL)
   959 	{
   960 		return sp_ftoc(-1);
   961 	}
   962 
   963 	if (params[2] == MAX_FLOWS)
   964 	{
   965 		value = pInfo->GetAvgChoke(FLOW_INCOMING) + pInfo->GetAvgChoke(FLOW_OUTGOING);
   966 	}
   967 	else
   968 	{
   969 		value = pInfo->GetAvgChoke(params[2]);
   970 	}
   971 
   972 	return sp_ftoc(value);
   973 }
   974 
   975 static cell_t GetAvgData(IPluginContext *pContext, const cell_t *params)
   976 {
   977 	int client = params[1];
   978 	float value;
   979 
   980 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   981 	if (!pPlayer)
   982 	{
   983 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   984 	}
   985 	else if (!pPlayer->IsInGame())
   986 	{
   987 		return pContext->ThrowNativeError("Client %d is not in game", client);
   988 	}
   989 	else if (pPlayer->IsFakeClient())
   990 	{
   991 		return pContext->ThrowNativeError("Client %d is a bot", client);
   992 	}
   993 
   994 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   995 	if (pInfo == NULL)
   996 	{
   997 		return 0;
   998 	}
   999 
  1000 	if (params[2] == MAX_FLOWS)
  1001 	{
  1002 		value = pInfo->GetAvgData(FLOW_INCOMING) + pInfo->GetAvgData(FLOW_OUTGOING);
  1003 	}
  1004 	else
  1005 	{
  1006 		value = pInfo->GetAvgData(params[2]);
  1007 	}
  1008 
  1009 	return sp_ftoc(value);
  1010 }
  1011 
  1012 static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
  1013 {
  1014 	int client = params[1];
  1015 	float value;
  1016 
  1017 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1018 	if (!pPlayer)
  1019 	{
  1020 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1021 	}
  1022 	else if (!pPlayer->IsInGame())
  1023 	{
  1024 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1025 	}
  1026 	else if (pPlayer->IsFakeClient())
  1027 	{
  1028 		return pContext->ThrowNativeError("Client %d is a bot", client);
  1029 	}
  1030 
  1031 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
  1032 
  1033 	if (pInfo == NULL)
  1034 	{
  1035 		return 0;
  1036 	}
  1037 
  1038 	if (params[2] == MAX_FLOWS)
  1039 	{
  1040 		value = pInfo->GetAvgPackets(FLOW_INCOMING) + pInfo->GetAvgPackets(FLOW_OUTGOING);
  1041 	}
  1042 	else
  1043 	{
  1044 		value = pInfo->GetAvgPackets(params[2]);
  1045 	}
  1046 
  1047 	return sp_ftoc(value);
  1048 }
  1049 
  1050 static cell_t GetClientOfUserId(IPluginContext *pContext, const cell_t *params)
  1051 {
  1052 	return g_Players.GetClientOfUserId(params[1]);
  1053 }
  1054 
  1055 static cell_t _ShowActivity(IPluginContext *pContext,
  1056 							const cell_t *params,
  1057 							const char *tag,
  1058 							cell_t fmt_param)
  1059 {
  1060 	char message[255];
  1061 	char buffer[255];
  1062 	int value = sm_show_activity.GetInt();
  1063 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
  1064 	int client = params[1];
  1065 
  1066 	const char *name = "Console";
  1067 	const char *sign = "ADMIN";
  1068 	bool display_in_chat = false;
  1069 	if (client != 0)
  1070 	{
  1071 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1072 		if (!pPlayer || !pPlayer->IsConnected())
  1073 		{
  1074 			return pContext->ThrowNativeError("Client index %d is invalid", client);
  1075 		}
  1076 		name = pPlayer->GetName();
  1077 		AdminId id = pPlayer->GetAdminId();
  1078 		if (id == INVALID_ADMIN_ID
  1079 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1080 		{
  1081 			sign = "PLAYER";
  1082 		}
  1083 
  1084 		/* Display the message to the client? */
  1085 		if (replyto == SM_REPLY_CONSOLE)
  1086 		{
  1087 			g_SourceMod.SetGlobalTarget(client);
  1088 			g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1089 
  1090 			if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1091 			{
  1092 				return 0;
  1093 			}
  1094 
  1095 			UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1096 			engine->ClientPrintf(pPlayer->GetEdict(), message);
  1097 			display_in_chat = true;
  1098 		}
  1099 	}
  1100 	else
  1101 	{
  1102 		g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
  1103 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1104 
  1105 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1106 		{
  1107 			return 0;
  1108 		}
  1109 
  1110 		UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1111 		META_CONPRINT(message);
  1112 	}
  1113 
  1114 	if (!value)
  1115 	{
  1116 		return 1;
  1117 	}
  1118 
  1119 	int maxClients = g_Players.GetMaxClients();
  1120 	for (int i=1; i<=maxClients; i++)
  1121 	{
  1122 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
  1123 		if (!pPlayer->IsInGame() 
  1124 			|| pPlayer->IsFakeClient()
  1125 			|| (display_in_chat && i == client))
  1126 		{
  1127 			continue;
  1128 		}
  1129 		AdminId id = pPlayer->GetAdminId();
  1130 		g_SourceMod.SetGlobalTarget(i);
  1131 		if (id == INVALID_ADMIN_ID
  1132 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1133 		{
  1134 			/* Treat this as a normal user */
  1135 			if ((value & 1) || (value & 2))
  1136 			{
  1137 				const char *newsign = sign;
  1138 				if ((value & 2) || (i == client))
  1139 				{
  1140 					newsign = name;
  1141 				}
  1142 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1143 
  1144 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1145 				{
  1146 					return 0;
  1147 				}
  1148 
  1149 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1150 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1151 			}
  1152 		}
  1153 		else
  1154 		{
  1155 			/* Treat this as an admin user */
  1156 			bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
  1157 			if ((value & 4) 
  1158 				|| (value & 8)
  1159 				|| ((value & 16) && is_root))
  1160 			{
  1161 				const char *newsign = sign;
  1162 				if ((value & 8) || ((value & 16) && is_root) || (i == client))
  1163 				{
  1164 					newsign = name;
  1165 				}
  1166 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1167 
  1168 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1169 				{
  1170 					return 0;
  1171 				}
  1172 
  1173 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1174 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1175 			}
  1176 		}
  1177 	}
  1178 
  1179 	return 1;
  1180 }
  1181 
  1182 static cell_t _ShowActivity2(IPluginContext *pContext,
  1183 							 const cell_t *params,
  1184 							 const char *tag,
  1185 							 cell_t fmt_param)
  1186 {
  1187 	char message[255];
  1188 	char buffer[255];
  1189 	int value = sm_show_activity.GetInt();
  1190 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
  1191 	int client = params[1];
  1192 
  1193 	const char *name = "Console";
  1194 	const char *sign = "ADMIN";
  1195 	if (client != 0)
  1196 	{
  1197 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1198 		if (!pPlayer || !pPlayer->IsConnected())
  1199 		{
  1200 			return pContext->ThrowNativeError("Client index %d is invalid", client);
  1201 		}
  1202 		name = pPlayer->GetName();
  1203 		AdminId id = pPlayer->GetAdminId();
  1204 		if (id == INVALID_ADMIN_ID
  1205 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1206 		{
  1207 			sign = "PLAYER";
  1208 		}
  1209 
  1210 		g_SourceMod.SetGlobalTarget(client);
  1211 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1212 
  1213 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1214 		{
  1215 			return 0;
  1216 		}
  1217 
  1218 		/* We don't display directly to the console because the chat text 
  1219 		 * simply gets added to the console, so we don't want it to print 
  1220 		 * twice.
  1221 		 */
  1222 		if (replyto == SM_REPLY_CONSOLE)
  1223 		{
  1224 #if 0
  1225 			UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1226 			engine->ClientPrintf(pPlayer->GetEdict(), message);
  1227 #endif
  1228 			UTIL_Format(message, sizeof(message), "%s%s", tag, buffer);
  1229 			g_HL2.TextMsg(client, HUD_PRINTTALK, message);
  1230 		}
  1231 		else
  1232 		{
  1233 			UTIL_Format(message, sizeof(message), "%s%s", tag, buffer);
  1234 			g_HL2.TextMsg(client, HUD_PRINTTALK, message);
  1235 		}
  1236 	}
  1237 	else
  1238 	{
  1239 		g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
  1240 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1241 
  1242 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1243 		{
  1244 			return 0;
  1245 		}
  1246 
  1247 		UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1248 		META_CONPRINT(message);
  1249 	}
  1250 
  1251 	if (!value)
  1252 	{
  1253 		return 1;
  1254 	}
  1255 
  1256 	int maxClients = g_Players.GetMaxClients();
  1257 	for (int i=1; i<=maxClients; i++)
  1258 	{
  1259 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
  1260 		if (!pPlayer->IsInGame() 
  1261 			|| pPlayer->IsFakeClient()
  1262 			|| i == client)
  1263 		{
  1264 			continue;
  1265 		}
  1266 		AdminId id = pPlayer->GetAdminId();
  1267 		g_SourceMod.SetGlobalTarget(i);
  1268 		if (id == INVALID_ADMIN_ID
  1269 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1270 		{
  1271 			/* Treat this as a normal user */
  1272 			if ((value & 1) || (value & 2))
  1273 			{
  1274 				const char *newsign = sign;
  1275 				if ((value & 2))
  1276 				{
  1277 					newsign = name;
  1278 				}
  1279 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1280 
  1281 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1282 				{
  1283 					return 0;
  1284 				}
  1285 
  1286 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1287 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1288 			}
  1289 		}
  1290 		else
  1291 		{
  1292 			/* Treat this as an admin user */
  1293 			bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
  1294 			if ((value & 4) 
  1295 				|| (value & 8)
  1296 				|| ((value & 16) && is_root))
  1297 			{
  1298 				const char *newsign = sign;
  1299 				if ((value & 8) || ((value & 16) && is_root))
  1300 				{
  1301 					newsign = name;
  1302 				}
  1303 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1304 
  1305 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1306 				{
  1307 					return 0;
  1308 				}
  1309 
  1310 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1311 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1312 			}
  1313 		}
  1314 	}
  1315 
  1316 	return 1;
  1317 }
  1318 
  1319 static cell_t ShowActivity(IPluginContext *pContext, const cell_t *params)
  1320 {
  1321 	return _ShowActivity(pContext, params, "[SM] ", 2);
  1322 }
  1323 
  1324 static cell_t ShowActivityEx(IPluginContext *pContext, const cell_t *params)
  1325 {
  1326 	char *str;
  1327 	pContext->LocalToString(params[2], &str);
  1328 
  1329 	return _ShowActivity(pContext, params, str, 3);
  1330 }
  1331 
  1332 static cell_t ShowActivity2(IPluginContext *pContext, const cell_t *params)
  1333 {
  1334 	char *str;
  1335 	pContext->LocalToString(params[2], &str);
  1336 
  1337 	return _ShowActivity2(pContext, params, str, 3);
  1338 }
  1339 
  1340 static cell_t KickClient(IPluginContext *pContext, const cell_t *params)
  1341 {
  1342 	int client = params[1];
  1343 
  1344 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1345 	if (!pPlayer)
  1346 	{
  1347 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1348 	}
  1349 	else if (!pPlayer->IsConnected())
  1350 	{
  1351 		return pContext->ThrowNativeError("Client %d is not connected", client);
  1352 	}
  1353 
  1354 	/* Ignore duplicate kicks */
  1355 	if (pPlayer->IsInKickQueue())
  1356 	{
  1357 		return 1;
  1358 	}
  1359 
  1360 	g_SourceMod.SetGlobalTarget(client);
  1361 
  1362 	char buffer[256];
  1363 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1364 
  1365 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1366 	{
  1367 		return 0;
  1368 	}
  1369 
  1370 	if (pPlayer->IsFakeClient())
  1371 	{
  1372 		// Kick uses the kickid command for bots. It is already delayed
  1373 		// until the next frame unless someone flushes command buffer
  1374 		pPlayer->Kick(buffer);
  1375 		return 1;
  1376 	}
  1377 
  1378 	pPlayer->MarkAsBeingKicked();
  1379 	g_HL2.AddDelayedKick(client, pPlayer->GetUserId(), buffer);
  1380 
  1381 	return 1;
  1382 }
  1383 
  1384 static cell_t KickClientEx(IPluginContext *pContext, const cell_t *params)
  1385 {
  1386 	int client = params[1];
  1387 
  1388 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1389 	if (!pPlayer)
  1390 	{
  1391 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1392 	}
  1393 	else if (!pPlayer->IsConnected())
  1394 	{
  1395 		return pContext->ThrowNativeError("Client %d is not connected", client);
  1396 	}
  1397 
  1398 	g_SourceMod.SetGlobalTarget(client);
  1399 
  1400 	char buffer[256];
  1401 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1402 
  1403 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1404 	{
  1405 		return 0;
  1406 	}
  1407 
  1408 	pPlayer->Kick(buffer);
  1409 
  1410 	return 1;
  1411 }
  1412 
  1413 static cell_t ChangeClientTeam(IPluginContext *pContext, const cell_t *params)
  1414 {
  1415 	int client = params[1];
  1416 
  1417 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1418 	if (!pPlayer)
  1419 	{
  1420 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1421 	}
  1422 	else if (!pPlayer->IsInGame())
  1423 	{
  1424 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1425 	}
  1426 
  1427 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
  1428 	if (!pInfo)
  1429 	{
  1430 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
  1431 	}
  1432 
  1433 	pInfo->ChangeTeam(params[2]);
  1434 
  1435 	return 1;
  1436 }
  1437 
  1438 static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
  1439 {
  1440 	int client = params[1];
  1441 
  1442 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1443 	if (!pPlayer)
  1444 	{
  1445 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1446 	}
  1447 	else if (!pPlayer->IsInGame())
  1448 	{
  1449 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1450 	}
  1451 	else if (!pPlayer->IsAuthorized())
  1452 	{
  1453 		return pContext->ThrowNativeError("Client %d is not authorized", client);
  1454 	}
  1455 
  1456 	AdminId id = pPlayer->GetAdminId();
  1457 	pPlayer->DoBasicAdminChecks();
  1458 
  1459 	return (id != pPlayer->GetAdminId()) ? 1 : 0;
  1460 }
  1461 
  1462 static cell_t NotifyPostAdminCheck(IPluginContext *pContext, const cell_t *params)
  1463 {
  1464 	int client = params[1];
  1465 
  1466 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1467 	if (!pPlayer)
  1468 	{
  1469 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1470 	}
  1471 	else if (!pPlayer->IsInGame()) {
  1472 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1473 	}
  1474 	else if (!pPlayer->IsAuthorized())
  1475 	{
  1476 		return pContext->ThrowNativeError("Client %d is not authorized", client);
  1477 	}
  1478 
  1479 	pPlayer->NotifyPostAdminChecks();
  1480 
  1481 	return 1;
  1482 }
  1483 
  1484 static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params)
  1485 {
  1486 	int client = params[1];
  1487 
  1488 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1489 
  1490 	if (!pPlayer)
  1491 	{
  1492 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1493 	}
  1494 	else if (!pPlayer->IsConnected())
  1495 	{
  1496 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1497 	}
  1498 
  1499 	return pPlayer->IsInKickQueue() ? 1 : 0;
  1500 }
  1501 
  1502 static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
  1503 {
  1504 	cmd_target_info_t info;
  1505 
  1506 	pContext->LocalToString(params[1], (char **)&info.pattern);
  1507 	info.admin = params[2];
  1508 	pContext->LocalToPhysAddr(params[3], &info.targets);
  1509 	info.max_targets = params[4];
  1510 	info.flags = params[5];
  1511 	pContext->LocalToString(params[6], &info.target_name);
  1512 	info.target_name_maxlength = params[7];
  1513 
  1514 	cell_t *tn_is_ml;
  1515 	pContext->LocalToPhysAddr(params[8], &tn_is_ml);
  1516 
  1517 	g_Players.ProcessCommandTarget(&info);
  1518 
  1519 	if (info.target_name_style == COMMAND_TARGETNAME_ML)
  1520 	{
  1521 		*tn_is_ml = 1;
  1522 	}
  1523 	else
  1524 	{
  1525 		*tn_is_ml = 0;
  1526 	}
  1527 
  1528 	if (info.num_targets == 0)
  1529 	{
  1530 		return info.reason;
  1531 	}
  1532 	else
  1533 	{
  1534 		return info.num_targets;
  1535 	}
  1536 }
  1537 
  1538 static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
  1539 {
  1540 	int value;
  1541 	int client;
  1542 	int target;
  1543 	CPlayer *pTarget;
  1544 	AdminId aidTarget;
  1545 	const char *identity[2] = {"Console", "ADMIN"};
  1546 
  1547 	client = params[1];
  1548 	target = params[2];
  1549 
  1550 	if ((pTarget = g_Players.GetPlayerByIndex(target)) == NULL)
  1551 	{
  1552 		return pContext->ThrowNativeError("Invalid client index %d", target);
  1553 	}
  1554 	if (!pTarget->IsConnected())
  1555 	{
  1556 		return pContext->ThrowNativeError("Client %d not connected", target);
  1557 	}
  1558 
  1559 	value = sm_show_activity.GetInt();
  1560 
  1561 	if (client != 0)
  1562 	{
  1563 		CPlayer *pPlayer;
  1564 
  1565 		if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
  1566 		{
  1567 			return pContext->ThrowNativeError("Invalid client index %d", client);
  1568 		}
  1569 		if (!pPlayer->IsConnected())
  1570 		{
  1571 			return pContext->ThrowNativeError("Client %d not connected", client);
  1572 		}
  1573 
  1574 		identity[0] = pPlayer->GetName();
  1575 
  1576 		AdminId id = pPlayer->GetAdminId();
  1577 		if (id == INVALID_ADMIN_ID
  1578 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1579 		{
  1580 			identity[1] = "PLAYER";
  1581 		}
  1582 	}
  1583 
  1584 	int mode = 1;
  1585 	bool bShowActivity = false;
  1586 
  1587 	if ((aidTarget = pTarget->GetAdminId()) == INVALID_ADMIN_ID
  1588 		|| !g_Admins.GetAdminFlag(aidTarget, Admin_Generic, Access_Effective))
  1589 	{
  1590 		/* Treat this as a normal user */
  1591 		if ((value & 1) || (value & 2))
  1592 		{
  1593 			if ((value & 2) || (target == client))
  1594 			{
  1595 				mode = 0;
  1596 			}
  1597 			bShowActivity = true;
  1598 		}
  1599 	}
  1600 	else
  1601 	{
  1602 		/* Treat this as an admin user */
  1603 		bool is_root = g_Admins.GetAdminFlag(aidTarget, Admin_Root, Access_Effective);
  1604 		if ((value & 4) 
  1605 			|| (value & 8)
  1606 			|| ((value & 16) && is_root))
  1607 		{
  1608 			if ((value & 8) || ((value & 16) && is_root) || (target == client))
  1609 			{
  1610 				mode = 0;
  1611 			}
  1612 			bShowActivity = true;
  1613 		}
  1614 	}
  1615 
  1616 	/* Otherwise, send it back to the script. */
  1617 	pContext->StringToLocalUTF8(params[3], params[4], identity[mode], NULL);
  1618 
  1619 	return bShowActivity ? 1 : 0;
  1620 }
  1621 
  1622 static cell_t sm_GetClientSerial(IPluginContext *pContext, const cell_t *params)
  1623 {
  1624 	int client = params[1];
  1625 
  1626 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1627 	if (!pPlayer)
  1628 	{
  1629 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1630 	}
  1631 
  1632 	return pPlayer->GetSerial();
  1633 }
  1634 
  1635 static cell_t sm_GetClientFromSerial(IPluginContext *pContext, const cell_t *params)
  1636 {
  1637 	return g_Players.GetClientFromSerial(params[1]);
  1638 }
  1639 
  1640 REGISTER_NATIVES(playernatives)
  1641 {
  1642 	{"AddUserFlags",			AddUserFlags},
  1643 	{"CanUserTarget",			CanUserTarget},
  1644 	{"ChangeClientTeam",		ChangeClientTeam},
  1645 	{"GetClientAuthString",		sm_GetClientAuthStr},
  1646 	{"GetClientCount",			sm_GetClientCount},
  1647 	{"GetClientInfo",			sm_GetClientInfo},
  1648 	{"GetClientIP",				sm_GetClientIP},
  1649 	{"GetClientName",			sm_GetClientName},
  1650 	{"GetClientTeam",			GetClientTeam},
  1651 	{"GetClientUserId",			GetClientUserId},
  1652 	{"GetMaxClients",			sm_GetMaxClients},
  1653 	{"GetMaxHumanPlayers",		sm_GetMaxHumanPlayers},
  1654 	{"GetUserAdmin",			GetUserAdmin},
  1655 	{"GetUserFlagBits",			GetUserFlagBits},
  1656 	{"IsClientAuthorized",		sm_IsClientAuthorized},
  1657 	{"IsClientConnected",		sm_IsClientConnected},
  1658 	{"IsFakeClient",			sm_IsClientFakeClient},
  1659 	{"IsClientSourceTV",		sm_IsClientSourceTV},
  1660 	{"IsClientReplay",			sm_IsClientReplay},
  1661 	{"IsClientInGame",			sm_IsClientInGame},
  1662 	{"IsClientObserver",		IsClientObserver},
  1663 	{"RemoveUserFlags",			RemoveUserFlags},
  1664 	{"SetUserAdmin",			SetUserAdmin},
  1665 	{"SetUserFlagBits",			SetUserFlagBits},
  1666 	{"GetClientDeaths",			GetDeathCount},
  1667 	{"GetClientFrags",			GetFragCount},
  1668 	{"GetClientArmor",			GetArmorValue},
  1669 	{"GetClientAbsOrigin",		GetAbsOrigin},
  1670 	{"GetClientAbsAngles",		GetAbsAngles},
  1671 	{"GetClientMins",			GetPlayerMins},
  1672 	{"GetClientMaxs",			GetPlayerMaxs},
  1673 	{"GetClientWeapon",			GetWeaponName},
  1674 	{"GetClientModel",			GetModelName},
  1675 	{"GetClientHealth",			GetHealth},
  1676 	{"GetClientTime",			GetTimeConnected},
  1677 	{"GetClientDataRate",		GetDataRate},
  1678 	{"IsClientTimingOut",		IsTimingOut},
  1679 	{"GetClientLatency",		GetLatency},
  1680 	{"GetClientAvgLatency",		GetAvgLatency},
  1681 	{"GetClientAvgLoss",		GetAvgLoss},
  1682 	{"GetClientAvgChoke",		GetAvgChoke},
  1683 	{"GetClientAvgData",		GetAvgData},
  1684 	{"GetClientAvgPackets",		GetAvgPackets},
  1685 	{"GetClientOfUserId",		GetClientOfUserId},
  1686 	{"ShowActivity",			ShowActivity},
  1687 	{"ShowActivityEx",			ShowActivityEx},
  1688 	{"ShowActivity2",			ShowActivity2},
  1689 	{"KickClient",				KickClient},
  1690 	{"KickClientEx",			KickClientEx},
  1691 	{"RunAdminCacheChecks",		RunAdminCacheChecks},
  1692 	{"NotifyPostAdminCheck",	NotifyPostAdminCheck},
  1693 	{"IsClientInKickQueue",		IsClientInKickQueue},
  1694 	{"ProcessTargetString",		ProcessTargetString},
  1695 	{"FormatActivitySource",	FormatActivitySource},
  1696 	{"GetClientSerial",			sm_GetClientSerial},
  1697 	{"GetClientFromSerial",		sm_GetClientFromSerial},
  1698 	{NULL,						NULL}
  1699 };
  1700