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