core/smn_player.cpp
author Peace-Maker <januk@freenet.de>
Wed Apr 23 08:55:09 2014 -0400 (2014-04-23)
changeset 4330 98726cea1607
parent 4300 cc206102001c
permissions -rw-r--r--
Mark CS:S as supporting HudMsg (bug 6108, r=psychonic).
     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 	}
   792 	else if (!pPlayer->IsConnected())
   793 	{
   794 		return pContext->ThrowNativeError("Client %d is not connected", client);
   795 	}
   796 	else if (pPlayer->IsFakeClient())
   797 	{
   798 		return pContext->ThrowNativeError("Client %d is a bot", client);
   799 	}
   800 
   801 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   802 	if (pInfo == NULL)
   803 	{
   804 		return 0;
   805 	}
   806 
   807 	return sp_ftoc(pInfo->GetTimeConnected());
   808 }
   809 
   810 static cell_t GetDataRate(IPluginContext *pContext, const cell_t *params)
   811 {
   812 	int client = params[1];
   813 
   814 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   815 	if (!pPlayer)
   816 	{
   817 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   818 	}
   819 	else if (!pPlayer->IsConnected())
   820 	{
   821 		return pContext->ThrowNativeError("Client %d is not connected", client);
   822 	}
   823 	else if (pPlayer->IsFakeClient())
   824 	{
   825 		return pContext->ThrowNativeError("Client %d is a bot", client);
   826 	}
   827 
   828 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   829 	if (pInfo == NULL)
   830 	{
   831 		return 0;
   832 	}
   833 
   834 	return pInfo->GetDataRate();
   835 }
   836 
   837 static cell_t IsTimingOut(IPluginContext *pContext, const cell_t *params)
   838 {
   839 	int client = params[1];
   840 
   841 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   842 	if (!pPlayer)
   843 	{
   844 		return pContext->ThrowNativeError("Client index %d is invalid", client);
   845 	}
   846 	else if (!pPlayer->IsConnected())
   847 	{
   848 		return pContext->ThrowNativeError("Client %d is not connected", client);
   849 	}
   850 	else if (pPlayer->IsFakeClient())
   851 	{
   852 		return pContext->ThrowNativeError("Client %d is a bot", client);
   853 	}
   854 
   855 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
   856 	if (pInfo == NULL)
   857 	{
   858 		return 1;
   859 	}
   860 
   861 	return pInfo->IsTimingOut() ? 1 : 0;
   862 }
   863 
   864 static cell_t GetLatency(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->IsConnected())
   875 	{
   876 		return pContext->ThrowNativeError("Client %d is not connected", 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->GetLatency(FLOW_INCOMING) + pInfo->GetLatency(FLOW_OUTGOING);
   892 	}
   893 	else
   894 	{
   895 		value = pInfo->GetLatency(params[2]);
   896 	}
   897 
   898 	return sp_ftoc(value);
   899 }
   900 
   901 static cell_t GetAvgLatency(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->IsConnected())
   912 	{
   913 		return pContext->ThrowNativeError("Client %d is not connected", 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->GetAvgLatency(FLOW_INCOMING) + pInfo->GetAvgLatency(FLOW_OUTGOING);
   929 	}
   930 	else
   931 	{
   932 		value = pInfo->GetAvgLatency(params[2]);
   933 	}
   934 
   935 	return sp_ftoc(value);
   936 }
   937 
   938 static cell_t GetAvgLoss(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->IsConnected())
   949 	{
   950 		return pContext->ThrowNativeError("Client %d is not connected", 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->GetAvgLoss(FLOW_INCOMING) + pInfo->GetAvgLoss(FLOW_OUTGOING);
   966 	}
   967 	else
   968 	{
   969 		value = pInfo->GetAvgLoss(params[2]);
   970 	}
   971 
   972 	return sp_ftoc(value);
   973 }
   974 
   975 static cell_t GetAvgChoke(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->IsConnected())
   986 	{
   987 		return pContext->ThrowNativeError("Client %d is not connected", 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 sp_ftoc(-1);
   998 	}
   999 
  1000 	if (params[2] == MAX_FLOWS)
  1001 	{
  1002 		value = pInfo->GetAvgChoke(FLOW_INCOMING) + pInfo->GetAvgChoke(FLOW_OUTGOING);
  1003 	}
  1004 	else
  1005 	{
  1006 		value = pInfo->GetAvgChoke(params[2]);
  1007 	}
  1008 
  1009 	return sp_ftoc(value);
  1010 }
  1011 
  1012 static cell_t GetAvgData(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->IsConnected())
  1023 	{
  1024 		return pContext->ThrowNativeError("Client %d is not connected", 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 	if (pInfo == NULL)
  1033 	{
  1034 		return 0;
  1035 	}
  1036 
  1037 	if (params[2] == MAX_FLOWS)
  1038 	{
  1039 		value = pInfo->GetAvgData(FLOW_INCOMING) + pInfo->GetAvgData(FLOW_OUTGOING);
  1040 	}
  1041 	else
  1042 	{
  1043 		value = pInfo->GetAvgData(params[2]);
  1044 	}
  1045 
  1046 	return sp_ftoc(value);
  1047 }
  1048 
  1049 static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
  1050 {
  1051 	int client = params[1];
  1052 	float value;
  1053 
  1054 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1055 	if (!pPlayer)
  1056 	{
  1057 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1058 	}
  1059 	else if (!pPlayer->IsConnected())
  1060 	{
  1061 		return pContext->ThrowNativeError("Client %d is not connected", client);
  1062 	}
  1063 	else if (pPlayer->IsFakeClient())
  1064 	{
  1065 		return pContext->ThrowNativeError("Client %d is a bot", client);
  1066 	}
  1067 
  1068 	INetChannelInfo *pInfo = engine->GetPlayerNetInfo(client);
  1069 	if (pInfo == NULL)
  1070 	{
  1071 		return 0;
  1072 	}
  1073 
  1074 	if (params[2] == MAX_FLOWS)
  1075 	{
  1076 		value = pInfo->GetAvgPackets(FLOW_INCOMING) + pInfo->GetAvgPackets(FLOW_OUTGOING);
  1077 	}
  1078 	else
  1079 	{
  1080 		value = pInfo->GetAvgPackets(params[2]);
  1081 	}
  1082 
  1083 	return sp_ftoc(value);
  1084 }
  1085 
  1086 static cell_t GetClientOfUserId(IPluginContext *pContext, const cell_t *params)
  1087 {
  1088 	return g_Players.GetClientOfUserId(params[1]);
  1089 }
  1090 
  1091 static cell_t _ShowActivity(IPluginContext *pContext,
  1092 							const cell_t *params,
  1093 							const char *tag,
  1094 							cell_t fmt_param)
  1095 {
  1096 	char message[255];
  1097 	char buffer[255];
  1098 	int value = sm_show_activity.GetInt();
  1099 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
  1100 	int client = params[1];
  1101 
  1102 	const char *name = "Console";
  1103 	const char *sign = "ADMIN";
  1104 	bool display_in_chat = false;
  1105 	if (client != 0)
  1106 	{
  1107 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1108 		if (!pPlayer || !pPlayer->IsConnected())
  1109 		{
  1110 			return pContext->ThrowNativeError("Client index %d is invalid", client);
  1111 		}
  1112 		name = pPlayer->GetName();
  1113 		AdminId id = pPlayer->GetAdminId();
  1114 		if (id == INVALID_ADMIN_ID
  1115 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1116 		{
  1117 			sign = "PLAYER";
  1118 		}
  1119 
  1120 		/* Display the message to the client? */
  1121 		if (replyto == SM_REPLY_CONSOLE)
  1122 		{
  1123 			g_SourceMod.SetGlobalTarget(client);
  1124 			g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1125 
  1126 			if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1127 			{
  1128 				return 0;
  1129 			}
  1130 
  1131 			UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1132 			pPlayer->PrintToConsole(message);
  1133 			display_in_chat = true;
  1134 		}
  1135 	}
  1136 	else
  1137 	{
  1138 		g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
  1139 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1140 
  1141 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1142 		{
  1143 			return 0;
  1144 		}
  1145 
  1146 		UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1147 		META_CONPRINT(message);
  1148 	}
  1149 
  1150 	if (!value)
  1151 	{
  1152 		return 1;
  1153 	}
  1154 
  1155 	int maxClients = g_Players.GetMaxClients();
  1156 	for (int i=1; i<=maxClients; i++)
  1157 	{
  1158 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
  1159 		if (!pPlayer->IsInGame() 
  1160 			|| pPlayer->IsFakeClient()
  1161 			|| (display_in_chat && i == client))
  1162 		{
  1163 			continue;
  1164 		}
  1165 		AdminId id = pPlayer->GetAdminId();
  1166 		g_SourceMod.SetGlobalTarget(i);
  1167 		if (id == INVALID_ADMIN_ID
  1168 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1169 		{
  1170 			/* Treat this as a normal user */
  1171 			if ((value & 1) || (value & 2))
  1172 			{
  1173 				const char *newsign = sign;
  1174 				if ((value & 2) || (i == client))
  1175 				{
  1176 					newsign = name;
  1177 				}
  1178 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1179 
  1180 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1181 				{
  1182 					return 0;
  1183 				}
  1184 
  1185 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1186 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1187 			}
  1188 		}
  1189 		else
  1190 		{
  1191 			/* Treat this as an admin user */
  1192 			bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
  1193 			if ((value & 4) 
  1194 				|| (value & 8)
  1195 				|| ((value & 16) && is_root))
  1196 			{
  1197 				const char *newsign = sign;
  1198 				if ((value & 8) || ((value & 16) && is_root) || (i == client))
  1199 				{
  1200 					newsign = name;
  1201 				}
  1202 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1203 
  1204 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1205 				{
  1206 					return 0;
  1207 				}
  1208 
  1209 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1210 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1211 			}
  1212 		}
  1213 	}
  1214 
  1215 	return 1;
  1216 }
  1217 
  1218 static cell_t _ShowActivity2(IPluginContext *pContext,
  1219 							 const cell_t *params,
  1220 							 const char *tag,
  1221 							 cell_t fmt_param)
  1222 {
  1223 	char message[255];
  1224 	char buffer[255];
  1225 	int value = sm_show_activity.GetInt();
  1226 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
  1227 	int client = params[1];
  1228 
  1229 	const char *name = "Console";
  1230 	const char *sign = "ADMIN";
  1231 	if (client != 0)
  1232 	{
  1233 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1234 		if (!pPlayer || !pPlayer->IsConnected())
  1235 		{
  1236 			return pContext->ThrowNativeError("Client index %d is invalid", client);
  1237 		}
  1238 		name = pPlayer->GetName();
  1239 		AdminId id = pPlayer->GetAdminId();
  1240 		if (id == INVALID_ADMIN_ID
  1241 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1242 		{
  1243 			sign = "PLAYER";
  1244 		}
  1245 
  1246 		g_SourceMod.SetGlobalTarget(client);
  1247 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1248 
  1249 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1250 		{
  1251 			return 0;
  1252 		}
  1253 
  1254 		/* We don't display directly to the console because the chat text 
  1255 		 * simply gets added to the console, so we don't want it to print 
  1256 		 * twice.
  1257 		 */
  1258 		UTIL_Format(message, sizeof(message), "%s%s", tag, buffer);
  1259 		g_HL2.TextMsg(client, HUD_PRINTTALK, message);
  1260 	}
  1261 	else
  1262 	{
  1263 		g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
  1264 		g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1265 
  1266 		if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1267 		{
  1268 			return 0;
  1269 		}
  1270 
  1271 		UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
  1272 		META_CONPRINT(message);
  1273 	}
  1274 
  1275 	if (!value)
  1276 	{
  1277 		return 1;
  1278 	}
  1279 
  1280 	int maxClients = g_Players.GetMaxClients();
  1281 	for (int i=1; i<=maxClients; i++)
  1282 	{
  1283 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
  1284 		if (!pPlayer->IsInGame() 
  1285 			|| pPlayer->IsFakeClient()
  1286 			|| i == client)
  1287 		{
  1288 			continue;
  1289 		}
  1290 		AdminId id = pPlayer->GetAdminId();
  1291 		g_SourceMod.SetGlobalTarget(i);
  1292 		if (id == INVALID_ADMIN_ID
  1293 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1294 		{
  1295 			/* Treat this as a normal user */
  1296 			if ((value & 1) || (value & 2))
  1297 			{
  1298 				const char *newsign = sign;
  1299 				if ((value & 2))
  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 		else
  1315 		{
  1316 			/* Treat this as an admin user */
  1317 			bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
  1318 			if ((value & 4) 
  1319 				|| (value & 8)
  1320 				|| ((value & 16) && is_root))
  1321 			{
  1322 				const char *newsign = sign;
  1323 				if ((value & 8) || ((value & 16) && is_root))
  1324 				{
  1325 					newsign = name;
  1326 				}
  1327 				g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
  1328 
  1329 				if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1330 				{
  1331 					return 0;
  1332 				}
  1333 
  1334 				UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
  1335 				g_HL2.TextMsg(i, HUD_PRINTTALK, message);
  1336 			}
  1337 		}
  1338 	}
  1339 
  1340 	return 1;
  1341 }
  1342 
  1343 static cell_t ShowActivity(IPluginContext *pContext, const cell_t *params)
  1344 {
  1345 	return _ShowActivity(pContext, params, "[SM] ", 2);
  1346 }
  1347 
  1348 static cell_t ShowActivityEx(IPluginContext *pContext, const cell_t *params)
  1349 {
  1350 	char *str;
  1351 	pContext->LocalToString(params[2], &str);
  1352 
  1353 	return _ShowActivity(pContext, params, str, 3);
  1354 }
  1355 
  1356 static cell_t ShowActivity2(IPluginContext *pContext, const cell_t *params)
  1357 {
  1358 	char *str;
  1359 	pContext->LocalToString(params[2], &str);
  1360 
  1361 	return _ShowActivity2(pContext, params, str, 3);
  1362 }
  1363 
  1364 static cell_t KickClient(IPluginContext *pContext, const cell_t *params)
  1365 {
  1366 	int client = params[1];
  1367 
  1368 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1369 	if (!pPlayer)
  1370 	{
  1371 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1372 	}
  1373 	else if (!pPlayer->IsConnected())
  1374 	{
  1375 		return pContext->ThrowNativeError("Client %d is not connected", client);
  1376 	}
  1377 
  1378 	/* Ignore duplicate kicks */
  1379 	if (pPlayer->IsInKickQueue())
  1380 	{
  1381 		return 1;
  1382 	}
  1383 
  1384 	g_SourceMod.SetGlobalTarget(client);
  1385 
  1386 	char buffer[256];
  1387 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1388 
  1389 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1390 	{
  1391 		return 0;
  1392 	}
  1393 
  1394 	if (pPlayer->IsFakeClient())
  1395 	{
  1396 		// Kick uses the kickid command for bots. It is already delayed
  1397 		// until the next frame unless someone flushes command buffer
  1398 		pPlayer->Kick(buffer);
  1399 		return 1;
  1400 	}
  1401 
  1402 	g_HL2.AddDelayedKick(client, pPlayer->GetUserId(), buffer);
  1403 
  1404 	return 1;
  1405 }
  1406 
  1407 static cell_t KickClientEx(IPluginContext *pContext, const cell_t *params)
  1408 {
  1409 	int client = params[1];
  1410 
  1411 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1412 	if (!pPlayer)
  1413 	{
  1414 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1415 	}
  1416 	else if (!pPlayer->IsConnected())
  1417 	{
  1418 		return pContext->ThrowNativeError("Client %d is not connected", client);
  1419 	}
  1420 
  1421 	g_SourceMod.SetGlobalTarget(client);
  1422 
  1423 	char buffer[256];
  1424 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1425 
  1426 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1427 	{
  1428 		return 0;
  1429 	}
  1430 
  1431 	pPlayer->Kick(buffer);
  1432 
  1433 	return 1;
  1434 }
  1435 
  1436 static cell_t ChangeClientTeam(IPluginContext *pContext, const cell_t *params)
  1437 {
  1438 	int client = params[1];
  1439 
  1440 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1441 	if (!pPlayer)
  1442 	{
  1443 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1444 	}
  1445 	else if (!pPlayer->IsInGame())
  1446 	{
  1447 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1448 	}
  1449 
  1450 	IPlayerInfo *pInfo = pPlayer->GetPlayerInfo();
  1451 	if (!pInfo)
  1452 	{
  1453 		return pContext->ThrowNativeError("IPlayerInfo not supported by game");
  1454 	}
  1455 
  1456 	pInfo->ChangeTeam(params[2]);
  1457 
  1458 	return 1;
  1459 }
  1460 
  1461 static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
  1462 {
  1463 	int client = params[1];
  1464 
  1465 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1466 	if (!pPlayer)
  1467 	{
  1468 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1469 	}
  1470 	else if (!pPlayer->IsInGame())
  1471 	{
  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 	AdminId id = pPlayer->GetAdminId();
  1480 	pPlayer->DoBasicAdminChecks();
  1481 
  1482 	return (id != pPlayer->GetAdminId()) ? 1 : 0;
  1483 }
  1484 
  1485 static cell_t NotifyPostAdminCheck(IPluginContext *pContext, const cell_t *params)
  1486 {
  1487 	int client = params[1];
  1488 
  1489 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1490 	if (!pPlayer)
  1491 	{
  1492 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1493 	}
  1494 	else if (!pPlayer->IsInGame()) {
  1495 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1496 	}
  1497 	else if (!pPlayer->IsAuthorized())
  1498 	{
  1499 		return pContext->ThrowNativeError("Client %d is not authorized", client);
  1500 	}
  1501 
  1502 	pPlayer->NotifyPostAdminChecks();
  1503 
  1504 	return 1;
  1505 }
  1506 
  1507 static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params)
  1508 {
  1509 	int client = params[1];
  1510 
  1511 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1512 
  1513 	if (!pPlayer)
  1514 	{
  1515 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1516 	}
  1517 	else if (!pPlayer->IsConnected())
  1518 	{
  1519 		return pContext->ThrowNativeError("Client %d is not in game", client);
  1520 	}
  1521 
  1522 	return pPlayer->IsInKickQueue() ? 1 : 0;
  1523 }
  1524 
  1525 static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
  1526 {
  1527 	cmd_target_info_t info;
  1528 
  1529 	pContext->LocalToString(params[1], (char **)&info.pattern);
  1530 	info.admin = params[2];
  1531 	pContext->LocalToPhysAddr(params[3], &info.targets);
  1532 	info.max_targets = params[4];
  1533 	info.flags = params[5];
  1534 	pContext->LocalToString(params[6], &info.target_name);
  1535 	info.target_name_maxlength = params[7];
  1536 
  1537 	cell_t *tn_is_ml;
  1538 	pContext->LocalToPhysAddr(params[8], &tn_is_ml);
  1539 
  1540 	g_Players.ProcessCommandTarget(&info);
  1541 
  1542 	if (info.target_name_style == COMMAND_TARGETNAME_ML)
  1543 	{
  1544 		*tn_is_ml = 1;
  1545 	}
  1546 	else
  1547 	{
  1548 		*tn_is_ml = 0;
  1549 	}
  1550 
  1551 	if (info.num_targets == 0)
  1552 	{
  1553 		return info.reason;
  1554 	}
  1555 	else
  1556 	{
  1557 		return info.num_targets;
  1558 	}
  1559 }
  1560 
  1561 static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
  1562 {
  1563 	int value;
  1564 	int client;
  1565 	int target;
  1566 	CPlayer *pTarget;
  1567 	AdminId aidTarget;
  1568 	const char *identity[2] = {"Console", "ADMIN"};
  1569 
  1570 	client = params[1];
  1571 	target = params[2];
  1572 
  1573 	if ((pTarget = g_Players.GetPlayerByIndex(target)) == NULL)
  1574 	{
  1575 		return pContext->ThrowNativeError("Invalid client index %d", target);
  1576 	}
  1577 	if (!pTarget->IsConnected())
  1578 	{
  1579 		return pContext->ThrowNativeError("Client %d not connected", target);
  1580 	}
  1581 
  1582 	value = sm_show_activity.GetInt();
  1583 
  1584 	if (client != 0)
  1585 	{
  1586 		CPlayer *pPlayer;
  1587 
  1588 		if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
  1589 		{
  1590 			return pContext->ThrowNativeError("Invalid client index %d", client);
  1591 		}
  1592 		if (!pPlayer->IsConnected())
  1593 		{
  1594 			return pContext->ThrowNativeError("Client %d not connected", client);
  1595 		}
  1596 
  1597 		identity[0] = pPlayer->GetName();
  1598 
  1599 		AdminId id = pPlayer->GetAdminId();
  1600 		if (id == INVALID_ADMIN_ID
  1601 			|| !g_Admins.GetAdminFlag(id, Admin_Generic, Access_Effective))
  1602 		{
  1603 			identity[1] = "PLAYER";
  1604 		}
  1605 	}
  1606 
  1607 	int mode = 1;
  1608 	bool bShowActivity = false;
  1609 
  1610 	if ((aidTarget = pTarget->GetAdminId()) == INVALID_ADMIN_ID
  1611 		|| !g_Admins.GetAdminFlag(aidTarget, Admin_Generic, Access_Effective))
  1612 	{
  1613 		/* Treat this as a normal user */
  1614 		if ((value & 1) || (value & 2))
  1615 		{
  1616 			if ((value & 2) || (target == client))
  1617 			{
  1618 				mode = 0;
  1619 			}
  1620 			bShowActivity = true;
  1621 		}
  1622 	}
  1623 	else
  1624 	{
  1625 		/* Treat this as an admin user */
  1626 		bool is_root = g_Admins.GetAdminFlag(aidTarget, Admin_Root, Access_Effective);
  1627 		if ((value & 4) 
  1628 			|| (value & 8)
  1629 			|| ((value & 16) && is_root))
  1630 		{
  1631 			if ((value & 8) || ((value & 16) && is_root) || (target == client))
  1632 			{
  1633 				mode = 0;
  1634 			}
  1635 			bShowActivity = true;
  1636 		}
  1637 	}
  1638 
  1639 	/* Otherwise, send it back to the script. */
  1640 	pContext->StringToLocalUTF8(params[3], params[4], identity[mode], NULL);
  1641 
  1642 	return bShowActivity ? 1 : 0;
  1643 }
  1644 
  1645 static cell_t sm_GetClientSerial(IPluginContext *pContext, const cell_t *params)
  1646 {
  1647 	int client = params[1];
  1648 
  1649 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
  1650 	if (!pPlayer)
  1651 	{
  1652 		return pContext->ThrowNativeError("Client index %d is invalid", client);
  1653 	}
  1654 
  1655 	return pPlayer->GetSerial();
  1656 }
  1657 
  1658 static cell_t sm_GetClientFromSerial(IPluginContext *pContext, const cell_t *params)
  1659 {
  1660 	return g_Players.GetClientFromSerial(params[1]);
  1661 }
  1662 
  1663 REGISTER_NATIVES(playernatives)
  1664 {
  1665 	{"AddUserFlags",			AddUserFlags},
  1666 	{"CanUserTarget",			CanUserTarget},
  1667 	{"ChangeClientTeam",		ChangeClientTeam},
  1668 	{"GetClientAuthString",		sm_GetClientAuthStr},
  1669 	{"GetSteamAccountID",		sm_GetSteamAccountID},
  1670 	{"GetClientCount",			sm_GetClientCount},
  1671 	{"GetClientInfo",			sm_GetClientInfo},
  1672 	{"GetClientIP",				sm_GetClientIP},
  1673 	{"GetClientName",			sm_GetClientName},
  1674 	{"GetClientTeam",			GetClientTeam},
  1675 	{"GetClientUserId",			GetClientUserId},
  1676 	{"GetMaxClients",			sm_GetMaxClients},
  1677 	{"GetMaxHumanPlayers",		sm_GetMaxHumanPlayers},
  1678 	{"GetUserAdmin",			GetUserAdmin},
  1679 	{"GetUserFlagBits",			GetUserFlagBits},
  1680 	{"IsClientAuthorized",		sm_IsClientAuthorized},
  1681 	{"IsClientConnected",		sm_IsClientConnected},
  1682 	{"IsFakeClient",			sm_IsClientFakeClient},
  1683 	{"IsClientSourceTV",		sm_IsClientSourceTV},
  1684 	{"IsClientReplay",			sm_IsClientReplay},
  1685 	{"IsClientInGame",			sm_IsClientInGame},
  1686 	{"IsClientObserver",		IsClientObserver},
  1687 	{"RemoveUserFlags",			RemoveUserFlags},
  1688 	{"SetUserAdmin",			SetUserAdmin},
  1689 	{"SetUserFlagBits",			SetUserFlagBits},
  1690 	{"GetClientDeaths",			GetDeathCount},
  1691 	{"GetClientFrags",			GetFragCount},
  1692 	{"GetClientArmor",			GetArmorValue},
  1693 	{"GetClientAbsOrigin",		GetAbsOrigin},
  1694 	{"GetClientAbsAngles",		GetAbsAngles},
  1695 	{"GetClientMins",			GetPlayerMins},
  1696 	{"GetClientMaxs",			GetPlayerMaxs},
  1697 	{"GetClientWeapon",			GetWeaponName},
  1698 	{"GetClientModel",			GetModelName},
  1699 	{"GetClientHealth",			GetHealth},
  1700 	{"GetClientTime",			GetTimeConnected},
  1701 	{"GetClientDataRate",		GetDataRate},
  1702 	{"IsClientTimingOut",		IsTimingOut},
  1703 	{"GetClientLatency",		GetLatency},
  1704 	{"GetClientAvgLatency",		GetAvgLatency},
  1705 	{"GetClientAvgLoss",		GetAvgLoss},
  1706 	{"GetClientAvgChoke",		GetAvgChoke},
  1707 	{"GetClientAvgData",		GetAvgData},
  1708 	{"GetClientAvgPackets",		GetAvgPackets},
  1709 	{"GetClientOfUserId",		GetClientOfUserId},
  1710 	{"ShowActivity",			ShowActivity},
  1711 	{"ShowActivityEx",			ShowActivityEx},
  1712 	{"ShowActivity2",			ShowActivity2},
  1713 	{"KickClient",				KickClient},
  1714 	{"KickClientEx",			KickClientEx},
  1715 	{"RunAdminCacheChecks",		RunAdminCacheChecks},
  1716 	{"NotifyPostAdminCheck",	NotifyPostAdminCheck},
  1717 	{"IsClientInKickQueue",		IsClientInKickQueue},
  1718 	{"ProcessTargetString",		ProcessTargetString},
  1719 	{"FormatActivitySource",	FormatActivitySource},
  1720 	{"GetClientSerial",			sm_GetClientSerial},
  1721 	{"GetClientFromSerial",		sm_GetClientFromSerial},
  1722 	{NULL,						NULL}
  1723 };
  1724