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