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