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