extensions/sdktools/vnatives.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Wed May 25 13:31:14 2011 -0400 (2011-05-25)
changeset 3285 065beec73902
parent 3280 7aea1316eff7
child 3292 f428ffc8a3fe
permissions -rw-r--r--
Backed out changeset: 65eb3df32b1c
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools Extension
     5 * Copyright (C) 2004-2010 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 <stdlib.h>
    33 #include <sh_string.h>
    34 #include "extension.h"
    35 #include "vcallbuilder.h"
    36 #include "vnatives.h"
    37 #include "vhelpers.h"
    38 #include "vglobals.h"
    39 #include "CellRecipientFilter.h"
    40 #include <inetchannel.h>
    41 #include <iclient.h>
    42 #include "iserver.h"
    43 #include <iserverentity.h>
    44 
    45 SourceHook::List<ValveCall *> g_RegCalls;
    46 SourceHook::List<ICallWrapper *> g_CallWraps;
    47 
    48 inline void InitPass(ValvePassInfo &info, ValveType vtype, PassType type, unsigned int flags, unsigned int decflags=0)
    49 {
    50 	info.decflags = decflags;
    51 	info.encflags = 0;
    52 	info.flags = flags;
    53 	info.type = type;
    54 	info.vtype = vtype;
    55 }
    56 
    57 #define START_CALL() \
    58 	unsigned char *vptr = pCall->stk_get();
    59 
    60 #define FINISH_CALL_SIMPLE(vret) \
    61 	pCall->call->Execute(vptr, vret); \
    62 	pCall->stk_put(vptr);
    63 
    64 #define ENCODE_VALVE_PARAM(num, which, vnum) \
    65 	if (EncodeValveParam(pContext, \
    66 			params[num], \
    67 			pCall, \
    68 			&pCall->which[vnum], \
    69 			vptr) \
    70 		== Data_Fail) \
    71 	{ \
    72 		return 0; \
    73 	}
    74 
    75 #define DECODE_VALVE_PARAM(num, which, vnum) \
    76 	if (DecodeValveParam(pContext, \
    77 			params[num], \
    78 			pCall, \
    79 			&pCall->which[vnum], \
    80 			vptr) \
    81 		== Data_Fail) \
    82 	{ \
    83 		return 0; \
    84 	}
    85 
    86 bool CreateBaseCall(const char *name,
    87 						  ValveCallType vcalltype,
    88 						  const ValvePassInfo *retinfo,
    89 						  const ValvePassInfo params[],
    90 						  unsigned int numParams,
    91 						  ValveCall **vaddr)
    92 {
    93 	int offset;
    94 	ValveCall *call;
    95 	if (g_pGameConf->GetOffset(name, &offset))
    96 	{
    97 		call = CreateValveVCall(offset, vcalltype, retinfo, params, numParams);
    98 		if (call)
    99 		{
   100 			g_RegCalls.push_back(call);
   101 		}
   102 		*vaddr = call;
   103 		return true;
   104 	} else {
   105 		void *addr = NULL;
   106 		if (g_pGameConf->GetMemSig(name, &addr) && addr != NULL)
   107 		{
   108 			call = CreateValveCall(addr, vcalltype, retinfo, params, numParams);
   109 			if (call)
   110 			{
   111 				g_RegCalls.push_back(call);
   112 			}
   113 			*vaddr = call;
   114 			return true;
   115 		}
   116 	}
   117 	return false;
   118 }
   119 
   120 static cell_t RemovePlayerItem(IPluginContext *pContext, const cell_t *params)
   121 {
   122 	static ValveCall *pCall = NULL;
   123 	if (!pCall)
   124 	{
   125 		ValvePassInfo pass[2];
   126 		InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   127 		InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   128 		if (!CreateBaseCall("RemovePlayerItem", ValveCall_Player, &pass[1], pass, 1, &pCall))
   129 		{
   130 			return pContext->ThrowNativeError("\"RemovePlayerItem\" not supported by this mod");
   131 		} else if (!pCall) {
   132 			return pContext->ThrowNativeError("\"RemovePlayerItem\" wrapper failed to initialize");
   133 		}
   134 	}
   135 
   136 	bool ret;
   137 	START_CALL();
   138 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   139 	DECODE_VALVE_PARAM(2, vparams, 0);
   140 	FINISH_CALL_SIMPLE(&ret);
   141 	return ret ? 1 : 0;
   142 }
   143 
   144 static cell_t GiveNamedItem(IPluginContext *pContext, const cell_t *params)
   145 {
   146 	static ValveCall *pCall = NULL;
   147 	if (!pCall)
   148 	{
   149 		ValvePassInfo pass[3];
   150 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   151 		InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   152 		InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   153 		if (!CreateBaseCall("GiveNamedItem", ValveCall_Player, &pass[2], pass, 2, &pCall))
   154 		{
   155 			return pContext->ThrowNativeError("\"GiveNamedItem\" not supported by this mod");
   156 		} else if (!pCall) {
   157 			return pContext->ThrowNativeError("\"GiveNamedItem\" wrapper failed to initialize");
   158 		}
   159 	}
   160 
   161 	CBaseEntity *pEntity = NULL;
   162 	START_CALL();
   163 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   164 	DECODE_VALVE_PARAM(2, vparams, 0);
   165 	DECODE_VALVE_PARAM(3, vparams, 1);
   166 	FINISH_CALL_SIMPLE(&pEntity);
   167 
   168 	return gamehelpers->EntityToBCompatRef(pEntity);
   169 }
   170 
   171 static cell_t GetPlayerWeaponSlot(IPluginContext *pContext, const cell_t *params)
   172 {
   173 	static ValveCall *pCall = NULL;
   174 	if (!pCall)
   175 	{
   176 		ValvePassInfo pass[2];
   177 		InitPass(pass[0], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   178 		InitPass(pass[1], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   179 		if (!CreateBaseCall("Weapon_GetSlot", ValveCall_Player, &pass[1], pass, 1, &pCall))
   180 		{
   181 			return pContext->ThrowNativeError("\"Weapon_GetSlot\" not supported by this mod");
   182 		} else if (!pCall) {
   183 			return pContext->ThrowNativeError("\"Weapon_GetSlot\" wrapper failed to initialize");
   184 		}
   185 	}
   186 
   187 	CBaseEntity *pEntity;
   188 	START_CALL();
   189 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   190 	DECODE_VALVE_PARAM(2, vparams, 0);
   191 	FINISH_CALL_SIMPLE(&pEntity);
   192 
   193 	return gamehelpers->EntityToBCompatRef(pEntity);
   194 }
   195 
   196 #if SOURCE_ENGINE != SE_DARKMESSIAH
   197 static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
   198 {
   199 	static ValveCall *pCall = NULL;
   200 	if (!pCall)
   201 	{
   202 		ValvePassInfo pass[4];
   203 		InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
   204 		InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   205 		InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
   206 		InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   207 		if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 4, &pCall))
   208 		{
   209 			return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
   210 		} else if (!pCall) {
   211 			return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialize");
   212 		}
   213 	}
   214 
   215 	START_CALL();
   216 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   217 	DECODE_VALVE_PARAM(2, vparams, 0);
   218 	DECODE_VALVE_PARAM(3, vparams, 1);
   219 	DECODE_VALVE_PARAM(4, vparams, 2);
   220 	DECODE_VALVE_PARAM(5, vparams, 3);
   221 	FINISH_CALL_SIMPLE(NULL);
   222 
   223 	return 1;
   224 }
   225 #else
   226 /* Dark Messiah specific version */
   227 static cell_t IgniteEntity(IPluginContext *pContext, const cell_t *params)
   228 {
   229 	static ValveCall *pCall = NULL;
   230 	if (!pCall)
   231 	{
   232 		ValvePassInfo pass[6];
   233 		InitPass(pass[0], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
   234 		InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   235 		InitPass(pass[2], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
   236 		InitPass(pass[3], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   237 		InitPass(pass[4], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   238 		InitPass(pass[5], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   239 		if (!CreateBaseCall("Ignite", ValveCall_Entity, NULL, pass, 6, &pCall))
   240 		{
   241 			return pContext->ThrowNativeError("\"Ignite\" not supported by this mod");
   242 		} else if (!pCall) {
   243 			return pContext->ThrowNativeError("\"Ignite\" wrapper failed to initialize");
   244 		}
   245 	}
   246 
   247 	START_CALL();
   248 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   249 	DECODE_VALVE_PARAM(2, vparams, 0);
   250 	DECODE_VALVE_PARAM(3, vparams, 1);
   251 	DECODE_VALVE_PARAM(4, vparams, 2);
   252 	DECODE_VALVE_PARAM(5, vparams, 3);
   253 	/* Not sure what these params do, but they appear to be the default values */
   254 	*(int *)(vptr + 14) = 3;
   255 	*(int *)(vptr + 18) = 0;
   256 	FINISH_CALL_SIMPLE(NULL);
   257 
   258 	return 1;
   259 }
   260 #endif
   261 
   262 static cell_t ExtinguishEntity(IPluginContext *pContext, const cell_t *params)
   263 {
   264 	static ValveCall *pCall = NULL;
   265 	if (!pCall)
   266 	{
   267 		if (!CreateBaseCall("Extinguish", ValveCall_Entity, NULL, NULL, 0, &pCall))
   268 		{
   269 			return pContext->ThrowNativeError("\"Extinguish\" not supported by this mod");
   270 		} else if (!pCall) {
   271 			return pContext->ThrowNativeError("\"Extinguish\" wrapper failed to initialize");
   272 		}
   273 	}
   274 
   275 	START_CALL();
   276 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   277 	FINISH_CALL_SIMPLE(NULL);
   278 
   279 	return 1;
   280 }
   281 
   282 static cell_t TeleportEntity(IPluginContext *pContext, const cell_t *params)
   283 {
   284 	static ValveCall *pCall = NULL;
   285 	if (!pCall)
   286 	{
   287 		ValvePassInfo pass[3];
   288 		InitPass(pass[0], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
   289 		InitPass(pass[1], Valve_QAngle, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
   290 		InitPass(pass[2], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL);
   291 		if (!CreateBaseCall("Teleport", ValveCall_Entity, NULL, pass, 3, &pCall))
   292 		{
   293 			return pContext->ThrowNativeError("\"Teleport\" not supported by this mod");
   294 		} else if (!pCall) {
   295 			return pContext->ThrowNativeError("\"Teleport\" wrapper failed to initialize");
   296 		}
   297 	}
   298 
   299 	START_CALL();
   300 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   301 	DECODE_VALVE_PARAM(2, vparams, 0);
   302 	DECODE_VALVE_PARAM(3, vparams, 1);
   303 	DECODE_VALVE_PARAM(4, vparams, 2);
   304 	FINISH_CALL_SIMPLE(NULL);
   305 
   306 	return 1;
   307 }
   308 
   309 #if SOURCE_ENGINE >= SE_ORANGEBOX
   310 /* :TODO: This is Team Fortress 2 specific */
   311 static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
   312 {
   313 	static ValveCall *pCall = NULL;
   314 	if (!pCall)
   315 	{
   316 		ValvePassInfo pass[2];
   317 		InitPass(pass[0], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   318 		InitPass(pass[1], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   319 		if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, pass, 2, &pCall))
   320 		{
   321 			return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
   322 		}
   323 		else if (!pCall)
   324 		{
   325 			return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialize");
   326 		}
   327 	}
   328 
   329 	START_CALL();
   330 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   331 	*(bool *)(vptr + 4) = false;
   332 	*(bool *)(vptr + 5) = false;
   333 	FINISH_CALL_SIMPLE(NULL);
   334 
   335 	return 1;
   336 }
   337 #else
   338 static cell_t ForcePlayerSuicide(IPluginContext *pContext, const cell_t *params)
   339 {
   340 	static ValveCall *pCall = NULL;
   341 	if (!pCall)
   342 	{
   343 		if (!CreateBaseCall("CommitSuicide", ValveCall_Player, NULL, NULL, 0, &pCall))
   344 		{
   345 			return pContext->ThrowNativeError("\"CommitSuicide\" not supported by this mod");
   346 		} else if (!pCall) {
   347 			return pContext->ThrowNativeError("\"CommitSuicide\" wrapper failed to initialize");
   348 		}
   349 	}
   350 
   351 	START_CALL();
   352 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   353 	FINISH_CALL_SIMPLE(NULL);
   354 
   355 	return 1;
   356 }
   357 #endif
   358 
   359 static cell_t SetClientViewEntity(IPluginContext *pContext, const cell_t *params)
   360 {
   361 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   362 	if (player == NULL)
   363 	{
   364 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   365 	}
   366 	if (!player->IsInGame())
   367 	{
   368 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   369 	}
   370 
   371 	edict_t *pEdict = PEntityOfEntIndex(gamehelpers->ReferenceToIndex(params[2]));
   372 	if (!pEdict || pEdict->IsFree())
   373 	{
   374 		return pContext->ThrowNativeError("Entity %d is not valid", params[2]);
   375 	}
   376 
   377 	engine->SetView(player->GetEdict(), pEdict);
   378 
   379 	return 1;
   380 }
   381 
   382 static SourceHook::String *g_lightstyle[MAX_LIGHTSTYLES] = {NULL};
   383 static cell_t SetLightStyle(IPluginContext *pContext, const cell_t *params)
   384 {
   385 	int style = params[1];
   386 	if (style >= MAX_LIGHTSTYLES)
   387 	{
   388 		return pContext->ThrowNativeError("Light style %d is invalid (range: 0-%d)", style, MAX_LIGHTSTYLES - 1);
   389 	}
   390 
   391 	if (g_lightstyle[style] == NULL)
   392 	{
   393 		/* We allocate and never free this because the Engine wants to hold onto it :\
   394 		 * in theory we could hook light style and know whether we're supposed to free 
   395 		 * this or not on shutdown, but for ~4K of memory MAX, it doesn't seem worth it yet.
   396 		 * So, it's a :TODO:!
   397 		 */
   398 		g_lightstyle[style] = new SourceHook::String();
   399 	}
   400 
   401 	char *str;
   402 	pContext->LocalToString(params[2], &str);
   403 
   404 	g_lightstyle[style]->assign(str);
   405 
   406 	engine->LightStyle(style, g_lightstyle[style]->c_str());
   407 
   408 	return 1;
   409 }
   410 
   411 static cell_t SlapPlayer(IPluginContext *pContext, const cell_t *params)
   412 {
   413 	static bool s_slap_supported = false;
   414 	static bool s_slap_setup = false;
   415 	static ICallWrapper *s_teleport = NULL;
   416 	static int s_health_offs = 0;
   417 	static int s_sound_count = 0;
   418 	static int s_frag_offs = 0;
   419 
   420 	if (!s_slap_setup)
   421 	{
   422 		int tries = 0;
   423 
   424 		s_slap_setup = true;
   425 
   426 		if (IsTeleportSupported())
   427 		{
   428 			tries++;
   429 		}
   430 		if (IsGetVelocitySupported())
   431 		{
   432 			tries++;
   433 		}
   434 
   435 		/* Setup health */
   436 		if (g_pGameConf->GetOffset("m_iHealth", &s_health_offs) && s_health_offs)
   437 		{
   438 			tries++;
   439 		}
   440 
   441 		if (tries == 3)
   442 		{
   443 			s_slap_supported = true;
   444 
   445 			const char *key;
   446 			if ((key = g_pGameConf->GetKeyValue("SlapSoundCount")) != NULL)
   447 			{
   448 				s_sound_count = atoi(key);
   449 			}
   450 		}
   451 	}
   452 
   453 	if (!s_slap_supported)
   454 	{
   455 		return pContext->ThrowNativeError("This function is not supported on this mod");
   456 	}
   457 
   458 	/* First check if the client is valid */
   459 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   460 	if (!player)
   461 	{
   462 		return pContext->ThrowNativeError("Client %d is not valid", params[1]);
   463 	} else if (!player->IsInGame()) {
   464 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   465 	}
   466 
   467 	edict_t *pEdict = player->GetEdict();
   468 	CBaseEntity *pEntity = pEdict->GetUnknown()->GetBaseEntity();
   469 
   470 	/* See if we should be taking away health */
   471 	bool should_slay = false;
   472 	if (params[2])
   473 	{
   474 #if SOURCE_ENGINE != SE_DARKMESSIAH
   475 		int *health = (int *)((char *)pEntity + s_health_offs);
   476 
   477 		if (*health - params[2] <= 0)
   478 		{
   479 			*health = 1;
   480 			should_slay = true;
   481 		} else {
   482 			*health -= params[2];
   483 		}
   484 #else
   485 		float *health = (float *)((char *)pEntity + s_health_offs);
   486 
   487 		if (*health - (float)params[2] <= 0)
   488 		{
   489 			*health = 1.0f;
   490 			should_slay = true;
   491 		} else {
   492 			*health -= (float)params[2];
   493 		}
   494 #endif
   495 	}
   496 
   497 	/* Teleport in a random direction - thank you, Mani!*/
   498 	Vector velocity;
   499 	GetVelocity(pEntity, &velocity, NULL);
   500 	velocity.x += ((rand() % 180) + 50) * (((rand() % 2) == 1) ?  -1 : 1);
   501 	velocity.y += ((rand() % 180) + 50) * (((rand() % 2) == 1) ?  -1 : 1);
   502 	velocity.z += rand() % 200 + 100;
   503 	Teleport(pEntity, NULL, NULL, &velocity);
   504 
   505 	/* Play a random sound */
   506 	if (params[3] && s_sound_count > 0)
   507 	{
   508 		char name[48];
   509 		const char *sound_name;
   510 		cell_t player_list[256], total_players = 0;
   511 		int maxClients = playerhelpers->GetMaxClients();
   512 
   513 		int r = (rand() % s_sound_count) + 1;
   514 		snprintf(name, sizeof(name), "SlapSound%d", r);
   515 
   516 		if ((sound_name = g_pGameConf->GetKeyValue(name)) != NULL)
   517 		{
   518 			IGamePlayer *other;
   519 			for (int i=1; i<=maxClients; i++)
   520 			{
   521 				other = playerhelpers->GetGamePlayer(i);
   522 				if (other->IsInGame())
   523 				{
   524 					player_list[total_players++] = i;
   525 				}
   526 			}
   527 
   528 			const Vector & pos = pEdict->GetCollideable()->GetCollisionOrigin();
   529 			CellRecipientFilter rf;
   530 			rf.SetToReliable(true);
   531 			rf.Initialize(player_list, total_players);
   532 			engsound->EmitSound(rf, params[1], CHAN_AUTO, sound_name, VOL_NORM, ATTN_NORM, 0, PITCH_NORM, &pos);
   533 		}
   534 	}
   535 
   536 	if (!s_frag_offs)
   537 	{
   538 		const char *frag_prop = g_pGameConf->GetKeyValue("m_iFrags");
   539 		if (frag_prop)
   540 		{
   541 			datamap_t *pMap = gamehelpers->GetDataMap(pEntity);
   542 			typedescription_t *pType = gamehelpers->FindInDataMap(pMap, frag_prop);
   543 			if (pType != NULL)
   544 			{
   545 				s_frag_offs = GetTypeDescOffs(pType);
   546 			}
   547 		}
   548 		if (!s_frag_offs)
   549 		{
   550 			s_frag_offs = -1;
   551 		}
   552 	}
   553 
   554 	int old_frags = 0;
   555 	if (s_frag_offs > 0)
   556 	{
   557 		old_frags = *(int *)((char *)pEntity + s_frag_offs);
   558 	}
   559 	
   560 	/* Force suicide */
   561 	if (should_slay)
   562 	{
   563 		pluginhelpers->ClientCommand(pEdict, "kill\n");
   564 	}
   565 
   566 	if (s_frag_offs > 0)
   567 	{
   568 		*(int *)((char *)pEntity + s_frag_offs) = old_frags;
   569 	}
   570 
   571 	return 1;
   572 }
   573 
   574 static cell_t GetClientEyePosition(IPluginContext *pContext, const cell_t *params)
   575 {
   576 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   577 	if (player == NULL)
   578 	{
   579 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   580 	}
   581 	if (!player->IsInGame())
   582 	{
   583 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   584 	}
   585 
   586 	Vector pos;
   587 	serverClients->ClientEarPosition(player->GetEdict(), &pos);
   588 
   589 	cell_t *addr;
   590 	pContext->LocalToPhysAddr(params[2], &addr);
   591 	addr[0] = sp_ftoc(pos.x);
   592 	addr[1] = sp_ftoc(pos.y);
   593 	addr[2] = sp_ftoc(pos.z);
   594 
   595 	return 1;
   596 }
   597 
   598 static cell_t GetClientEyeAngles(IPluginContext *pContext, const cell_t *params)
   599 {
   600 	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
   601 
   602 	if (!pPlayer)
   603 	{
   604 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   605 	}
   606 	else if (!pPlayer->IsInGame())
   607 	{
   608 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   609 	}
   610 
   611 	edict_t *pEdict = pPlayer->GetEdict();
   612 	CBaseEntity *pEntity = pEdict->GetUnknown() ? pEdict->GetUnknown()->GetBaseEntity() : NULL;
   613 
   614 	/* We always set the angles for backwards compatibility -- 
   615 	 * The original function had no return value.
   616 	 */
   617 	QAngle angles;
   618 	bool got_angles = false;
   619 
   620 	if (pEntity != NULL)
   621 	{
   622 		got_angles = GetEyeAngles(pEntity, &angles);
   623 	}
   624 	
   625 	cell_t *addr;
   626 	pContext->LocalToPhysAddr(params[2], &addr);
   627 	addr[0] = sp_ftoc(angles.x);
   628 	addr[1] = sp_ftoc(angles.y);
   629 	addr[2] = sp_ftoc(angles.z);
   630 
   631 	return got_angles ? 1 : 0;
   632 }
   633 
   634 #if SOURCE_ENGINE >= SE_ORANGEBOX
   635 static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
   636 {
   637 	char *searchname;
   638 	CBaseEntity *pEntity;
   639 
   640 	if (params[1] == -1)
   641 	{
   642 		pEntity = (CBaseEntity *)servertools->FirstEntity();
   643 	}
   644 	else
   645 	{
   646 		pEntity = gamehelpers->ReferenceToEntity(params[1]);
   647 		if (!pEntity)
   648 		{
   649 			return pContext->ThrowNativeError("Entity %d (%d) is invalid",
   650 				gamehelpers->ReferenceToIndex(params[1]),
   651 				params[1]);
   652 		}
   653 	}
   654 
   655 	pContext->LocalToString(params[2], &searchname);
   656 
   657 	char buffer[128];
   658 	const char *classname = buffer;
   659 	int lastcharpos;
   660 	bool ismatch = false;
   661 
   662 	while (pEntity)
   663 	{
   664 		if (!servertools->GetKeyValue(pEntity, "classname", buffer, sizeof(buffer)))
   665 		{
   666 			pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
   667 			continue;
   668 		}
   669 
   670 		lastcharpos = strlen(searchname);
   671 		if (searchname[lastcharpos-1] == '*')
   672 		{
   673 			if (strncasecmp(searchname, classname, lastcharpos-1) == 0)
   674 			{
   675 				ismatch = true;
   676 			}
   677 		}
   678 		else if (strcasecmp(searchname, classname) == 0)
   679 		{
   680 			ismatch = true;
   681 		}
   682 
   683 		if (ismatch)
   684 		{
   685 			return gamehelpers->EntityToBCompatRef(pEntity);
   686 		}
   687 
   688 		pEntity = (CBaseEntity *)servertools->NextEntity(pEntity);
   689 	}
   690 
   691 	return -1;
   692 }
   693 #else
   694 static cell_t FindEntityByClassname(IPluginContext *pContext, const cell_t *params)
   695 {
   696 	static ValveCall *pCall = NULL;
   697 	if (!pCall)
   698 	{
   699 		ValvePassInfo pass[3];
   700 		InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL, VDECODE_FLAG_ALLOWNULL|VDECODE_FLAG_ALLOWWORLD);
   701 		InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   702 		InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   703 		if (!CreateBaseCall("FindEntityByClassname", ValveCall_EntityList, &pass[2], pass, 2, &pCall))
   704 		{
   705 			return pContext->ThrowNativeError("\"FindEntityByClassname\" not supported by this mod");
   706 		} else if (!pCall) {
   707 			return pContext->ThrowNativeError("\"FindEntityByClassname\" wrapper failed to initialize");
   708 		}
   709 	}
   710 
   711 	CBaseEntity *pEntity;
   712 	START_CALL();
   713 	*(void **)vptr = g_EntList; 
   714 	DECODE_VALVE_PARAM(1, vparams, 0);
   715 	DECODE_VALVE_PARAM(2, vparams, 1);
   716 	FINISH_CALL_SIMPLE(&pEntity);
   717 
   718 	return gamehelpers->EntityToBCompatRef(pEntity);
   719 }
   720 #endif
   721 
   722 #if SOURCE_ENGINE >= SE_ORANGEBOX
   723 static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
   724 {
   725 	char *classname;
   726 	pContext->LocalToString(params[1], &classname);
   727 	CBaseEntity *pEntity = (CBaseEntity *)servertools->CreateEntityByName(classname);
   728 	return gamehelpers->EntityToBCompatRef(pEntity);
   729 }
   730 #else
   731 static cell_t CreateEntityByName(IPluginContext *pContext, const cell_t *params)
   732 {
   733 	static ValveCall *pCall = NULL;
   734 	if (!pCall)
   735 	{
   736 		ValvePassInfo pass[3];
   737 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   738 		InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   739 		InitPass(pass[2], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   740 		if (!CreateBaseCall("CreateEntityByName", ValveCall_Static, &pass[2], pass, 2, &pCall))
   741 		{
   742 			return pContext->ThrowNativeError("\"CreateEntityByName\" not supported by this mod");
   743 		} else if (!pCall) {
   744 			return pContext->ThrowNativeError("\"CreateEntityByName\" wrapper failed to initialize");
   745 		}
   746 	}
   747 
   748 	CBaseEntity *pEntity = NULL;
   749 	START_CALL();
   750 	DECODE_VALVE_PARAM(1, vparams, 0);
   751 	DECODE_VALVE_PARAM(2, vparams, 1);
   752 	FINISH_CALL_SIMPLE(&pEntity);
   753 
   754 	return gamehelpers->EntityToBCompatRef(pEntity);
   755 }
   756 #endif
   757 
   758 #if SOURCE_ENGINE >= SE_ORANGEBOX
   759 static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
   760 {
   761 	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   762 	if (!pEntity)
   763 	{
   764 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   765 	}
   766 
   767 	servertools->DispatchSpawn(pEntity);
   768 
   769 	return 1;
   770 }
   771 #else
   772 static cell_t DispatchSpawn(IPluginContext *pContext, const cell_t *params)
   773 {
   774 	static ValveCall *pCall = NULL;
   775 	if (!pCall)
   776 	{
   777 		ValvePassInfo pass[2];
   778 		InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
   779 		InitPass(pass[1], Valve_POD, PassType_Basic, PASSFLAG_BYVAL);
   780 		if (!CreateBaseCall("DispatchSpawn", ValveCall_Static, &pass[1], pass, 1, &pCall))
   781 		{
   782 			return pContext->ThrowNativeError("\"DispatchSpawn\" not supported by this mod");
   783 		} else if (!pCall) {
   784 			return pContext->ThrowNativeError("\"DispatchSpawn\" wrapper failed to initialize");
   785 		}
   786 	}
   787 
   788 	int ret;
   789 	START_CALL();
   790 	DECODE_VALVE_PARAM(1, vparams, 0);
   791 	FINISH_CALL_SIMPLE(&ret);
   792 
   793 	return (ret == -1) ? 0 : 1;
   794 }
   795 #endif
   796 
   797 #if SOURCE_ENGINE >= SE_ORANGEBOX
   798 static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
   799 {
   800 	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   801 	if (!pEntity)
   802 	{
   803 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   804 	}
   805 
   806 	char *key;
   807 	char *value;
   808 	pContext->LocalToString(params[2], &key);
   809 	pContext->LocalToString(params[3], &value);
   810 
   811 	return (servertools->SetKeyValue(pEntity, key, value) ? 1 : 0);
   812 }
   813 #else
   814 static cell_t DispatchKeyValue(IPluginContext *pContext, const cell_t *params)
   815 {
   816 	static ValveCall *pCall = NULL;
   817 	if (!pCall)
   818 	{
   819 		ValvePassInfo pass[3];
   820 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   821 		InitPass(pass[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   822 		InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   823 		if (!CreateBaseCall("DispatchKeyValue", ValveCall_Entity, &pass[2], pass, 2, &pCall))
   824 		{
   825 			return pContext->ThrowNativeError("\"DispatchKeyValue\" not supported by this mod");
   826 		} else if (!pCall) {
   827 			return pContext->ThrowNativeError("\"DispatchKeyValue\" wrapper failed to initialize");
   828 		}
   829 	}
   830 
   831 	bool ret;
   832 	START_CALL();
   833 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   834 	DECODE_VALVE_PARAM(2, vparams, 0);
   835 	DECODE_VALVE_PARAM(3, vparams, 1);
   836 	FINISH_CALL_SIMPLE(&ret);
   837 
   838 	return ret ? 1 : 0;
   839 }
   840 #endif
   841 
   842 #if SOURCE_ENGINE >= SE_ORANGEBOX
   843 static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
   844 {
   845 	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   846 	if (!pEntity)
   847 	{
   848 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   849 	}
   850 
   851 	char *key;
   852 	pContext->LocalToString(params[2], &key);
   853 	
   854 	float value = sp_ctof(params[3]);
   855 
   856 	return (servertools->SetKeyValue(pEntity, key, value) ? 1 : 0);
   857 }
   858 #else
   859 static cell_t DispatchKeyValueFloat(IPluginContext *pContext, const cell_t *params)
   860 {
   861 	static ValveCall *pCall = NULL;
   862 	if (!pCall)
   863 	{
   864 		ValvePassInfo pass[3];
   865 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   866 		InitPass(pass[1], Valve_Float, PassType_Float, PASSFLAG_BYVAL);
   867 		InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   868 		if (!CreateBaseCall("DispatchKeyValueFloat", ValveCall_Entity, &pass[2], pass, 2, &pCall))
   869 		{
   870 			return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" not supported by this mod");
   871 		} else if (!pCall) {
   872 			return pContext->ThrowNativeError("\"DispatchKeyValueFloat\" wrapper failed to initialize");
   873 		}
   874 	}
   875 
   876 	bool ret;
   877 	START_CALL();
   878 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   879 	DECODE_VALVE_PARAM(2, vparams, 0);
   880 	DECODE_VALVE_PARAM(3, vparams, 1);
   881 	FINISH_CALL_SIMPLE(&ret);
   882 
   883 	return ret ? 1 : 0;
   884 }
   885 #endif
   886 
   887 #if SOURCE_ENGINE >= SE_ORANGEBOX
   888 static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
   889 {
   890 	CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(params[1]);
   891 	if (!pEntity)
   892 	{
   893 		return pContext->ThrowNativeError("Entity %d (%d) is invalid", gamehelpers->ReferenceToIndex(params[1]), params[1]);
   894 	}
   895 
   896 	char *key;
   897 	pContext->LocalToString(params[2], &key);
   898 	
   899 	cell_t *vec;
   900 	pContext->LocalToPhysAddr(params[3], &vec);
   901 
   902 	const Vector *v = new Vector(
   903 		sp_ctof(vec[0]),
   904 		sp_ctof(vec[1]),
   905 		sp_ctof(vec[2]));
   906 
   907 	return (servertools->SetKeyValue(pEntity, key, *v) ? 1 : 0);
   908 }
   909 #else
   910 static cell_t DispatchKeyValueVector(IPluginContext *pContext, const cell_t *params)
   911 {
   912 	static ValveCall *pCall = NULL;
   913 	if (!pCall)
   914 	{
   915 		ValvePassInfo pass[3];
   916 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   917 #if SOURCE_ENGINE >= SE_ORANGEBOX
   918 		InitPass(pass[1], Valve_Vector, PassType_Basic, PASSFLAG_BYVAL);
   919 #else
   920 		InitPass(pass[1], Valve_Vector, PassType_Object, PASSFLAG_BYVAL|PASSFLAG_OCTOR|PASSFLAG_OASSIGNOP);
   921 #endif
   922 		InitPass(pass[2], Valve_Bool, PassType_Basic, PASSFLAG_BYVAL);
   923 		if (!CreateBaseCall("DispatchKeyValueVector", ValveCall_Entity, &pass[2], pass, 2, &pCall))
   924 		{
   925 			return pContext->ThrowNativeError("\"DispatchKeyValueVector\" not supported by this mod");
   926 		} else if (!pCall) {
   927 			return pContext->ThrowNativeError("\"DispatchKeyValueVector\" wrapper failed to initialize");
   928 		}
   929 	}
   930 
   931 	bool ret;
   932 	START_CALL();
   933 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   934 	DECODE_VALVE_PARAM(2, vparams, 0);
   935 	DECODE_VALVE_PARAM(3, vparams, 1);
   936 	FINISH_CALL_SIMPLE(&ret);
   937 
   938 	return ret ? 1 : 0;
   939 }
   940 #endif
   941 
   942 static cell_t sm_GetClientAimTarget(IPluginContext *pContext, const cell_t *params)
   943 {
   944 	IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
   945 
   946 	if (!pPlayer)
   947 	{
   948 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   949 	}
   950 	else if (!pPlayer->IsInGame())
   951 	{
   952 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   953 	}
   954 
   955 	return GetClientAimTarget(pPlayer->GetEdict(), params[2] ? true : false);
   956 }
   957 
   958 static cell_t sm_SetEntityModel(IPluginContext *pContext, const cell_t *params)
   959 {
   960 	static ValveCall *pCall = NULL;
   961 	if (!pCall)
   962 	{
   963 		ValvePassInfo pass[1];
   964 		InitPass(pass[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
   965 		if (!CreateBaseCall("SetEntityModel", ValveCall_Entity, NULL, pass, 1, &pCall))
   966 		{
   967 			return pContext->ThrowNativeError("\"SetEntityModel\" not supported by this mod");
   968 		} else if (!pCall) {
   969 			return pContext->ThrowNativeError("\"SetEntityModel\" wrapper failed to initialize");
   970 		}
   971 	}
   972 
   973 	START_CALL();
   974 	DECODE_VALVE_PARAM(1, thisinfo, 0);
   975 	DECODE_VALVE_PARAM(2, vparams, 0);
   976 	FINISH_CALL_SIMPLE(NULL);
   977 
   978 	return 1;
   979 }
   980 
   981 static cell_t GetPlayerDecalFile(IPluginContext *pContext, const cell_t *params)
   982 {
   983 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
   984 	if (player == NULL)
   985 	{
   986 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
   987 	}
   988 	if (!player->IsInGame())
   989 	{
   990 		return pContext->ThrowNativeError("Client %d is not in game", params[1]);
   991 	}
   992 
   993 	player_info_t info;
   994 	char *buffer;
   995 
   996 	if (!GetPlayerInfo(params[1], &info) || !info.customFiles[0])
   997 	{
   998 		return 0;
   999 	}
  1000 
  1001 	pContext->LocalToString(params[2], &buffer);
  1002 	Q_binarytohex((byte *)&info.customFiles[0], sizeof(info.customFiles[0]), buffer, params[3]);
  1003 
  1004 	return 1;
  1005 }
  1006 
  1007 static cell_t GetServerNetStats(IPluginContext *pContext, const cell_t *params)
  1008 {
  1009 	if (iserver == NULL)
  1010 	{
  1011 		return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
  1012 	}
  1013 
  1014 	float in, out;
  1015 	cell_t *pIn, *pOut;
  1016 
  1017 	pContext->LocalToPhysAddr(params[1], &pIn);
  1018 	pContext->LocalToPhysAddr(params[2], &pOut);
  1019 	iserver->GetNetStats(in, out);
  1020 
  1021 	*pIn = sp_ftoc(in);
  1022 	*pOut = sp_ftoc(out);
  1023 
  1024 	return 1;
  1025 }
  1026 
  1027 static cell_t WeaponEquip(IPluginContext *pContext, const cell_t *params)
  1028 {
  1029 	static ValveCall *pCall = NULL;
  1030 	if (!pCall)
  1031 	{
  1032 		ValvePassInfo pass[1];
  1033 		InitPass(pass[0], Valve_CBaseEntity, PassType_Basic, PASSFLAG_BYVAL);
  1034 		if (!CreateBaseCall("WeaponEquip", ValveCall_Player, NULL, pass, 1, &pCall))
  1035 		{
  1036 			return pContext->ThrowNativeError("\"WeaponEquip\" not supported by this mod");
  1037 		} else if (!pCall) {
  1038 			return pContext->ThrowNativeError("\"WeaponEquip\" wrapper failed to initialize");
  1039 		}
  1040 	}
  1041 
  1042 	START_CALL();
  1043 	DECODE_VALVE_PARAM(1, thisinfo, 0);
  1044 	DECODE_VALVE_PARAM(2, vparams, 0);
  1045 	FINISH_CALL_SIMPLE(NULL);
  1046 
  1047 	return 1;
  1048 }
  1049 
  1050 static cell_t ActivateEntity(IPluginContext *pContext, const cell_t *params)
  1051 {
  1052 	static ValveCall *pCall = NULL;
  1053 	if (!pCall)
  1054 	{
  1055 		if (!CreateBaseCall("Activate", ValveCall_Entity, NULL, NULL, 0, &pCall))
  1056 		{
  1057 			return pContext->ThrowNativeError("\"Activate\" not supported by this mod");
  1058 		}
  1059 		else if (!pCall)
  1060 		{
  1061 			return pContext->ThrowNativeError("\"Activate\" wrapper failed to initialize");
  1062 		}
  1063 	}
  1064 
  1065 	START_CALL();
  1066 	DECODE_VALVE_PARAM(1, thisinfo, 0);
  1067 	FINISH_CALL_SIMPLE(NULL);
  1068 
  1069 	return 1;
  1070 }
  1071 
  1072 static cell_t SetClientInfo(IPluginContext *pContext, const cell_t *params)
  1073 {
  1074 	if (iserver == NULL)
  1075 	{
  1076 		return pContext->ThrowNativeError("IServer interface not supported, file a bug report.");
  1077 	}
  1078 
  1079 	IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
  1080 	IClient *pClient = iserver->GetClient(params[1] - 1);
  1081 
  1082 	if (player == NULL || pClient == NULL)
  1083 	{
  1084 		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
  1085 	}
  1086 	if (!player->IsConnected())
  1087 	{
  1088 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1089 	}
  1090 
  1091 	static ValveCall *pCall = NULL;
  1092 	if (!pCall)
  1093 	{
  1094 		ValvePassInfo params[2];
  1095 		InitPass(params[0], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
  1096 		InitPass(params[1], Valve_String, PassType_Basic, PASSFLAG_BYVAL);
  1097 
  1098 		if (!CreateBaseCall("SetUserCvar", ValveCall_Entity, NULL, params, 2, &pCall))
  1099 		{
  1100 			return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
  1101 		}
  1102 		else if (!pCall)
  1103 		{
  1104 			return pContext->ThrowNativeError("\"SetUserCvar\" wrapper failed to initialize");
  1105 		}
  1106 	}
  1107 
  1108 /* TODO: Use UpdateUserSettings function for all engines */
  1109 #if SOURCE_ENGINE == SE_DARKMESSIAH
  1110 	static ValveCall *pUpdateSettings = NULL;
  1111 	if (!pUpdateSettings)
  1112 	{
  1113 		if (!CreateBaseCall("UpdateUserSettings", ValveCall_Entity, NULL, NULL, 0, &pUpdateSettings))
  1114 		{
  1115 			return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
  1116 		}
  1117 		else if (!pUpdateSettings)
  1118 		{
  1119 			return pContext->ThrowNativeError("\"SetUserCvar\" wrapper failed to initialize");
  1120 		}
  1121 	}
  1122 #else
  1123 	static int changedOffset = -1;
  1124 
  1125 	if (changedOffset == -1)
  1126 	{	
  1127 		if (!g_pGameConf->GetOffset("InfoChanged", &changedOffset))
  1128 		{
  1129 			return pContext->ThrowNativeError("\"SetUserCvar\" not supported by this mod");
  1130 		}
  1131 	}
  1132 #endif
  1133 
  1134 	unsigned char *CGameClient = (unsigned char *)pClient - 4;
  1135 
  1136 	START_CALL();
  1137 	/* Not really a CBaseEntity* but this works */
  1138 	CBaseEntity **ebuf = (CBaseEntity **)vptr;
  1139 	*ebuf = (CBaseEntity *)CGameClient;
  1140 	DECODE_VALVE_PARAM(2, vparams, 0);
  1141 	DECODE_VALVE_PARAM(3, vparams, 1);
  1142 	FINISH_CALL_SIMPLE(NULL);
  1143 
  1144 #if SOURCE_ENGINE == SE_DARKMESSIAH
  1145 	unsigned char *args = pUpdateSettings->stk_get();
  1146 	*(void **)args = CGameClient;
  1147 	pUpdateSettings->call->Execute(args, NULL);
  1148 	pUpdateSettings->stk_put(args);
  1149 #else
  1150 	uint8_t* changed = (uint8_t *)(CGameClient + changedOffset);
  1151 	*changed = 1;
  1152 #endif
  1153 
  1154 	return 1;
  1155 }
  1156 
  1157 sp_nativeinfo_t g_Natives[] = 
  1158 {
  1159 	{"ExtinguishEntity",		ExtinguishEntity},
  1160 	{"ForcePlayerSuicide",		ForcePlayerSuicide},
  1161 	{"GivePlayerItem",			GiveNamedItem},
  1162 	{"GetPlayerWeaponSlot",		GetPlayerWeaponSlot},
  1163 	{"IgniteEntity",			IgniteEntity},
  1164 	{"RemovePlayerItem",		RemovePlayerItem},
  1165 	{"TeleportEntity",			TeleportEntity},
  1166 	{"SetClientViewEntity",		SetClientViewEntity},
  1167 	{"SetLightStyle",			SetLightStyle},
  1168 	{"SlapPlayer",				SlapPlayer},
  1169 	{"GetClientEyePosition",	GetClientEyePosition},
  1170 	{"GetClientEyeAngles",		GetClientEyeAngles},
  1171 	{"FindEntityByClassname",	FindEntityByClassname},
  1172 	{"CreateEntityByName",		CreateEntityByName},
  1173 	{"DispatchSpawn",			DispatchSpawn},
  1174 	{"DispatchKeyValue",		DispatchKeyValue},
  1175 	{"DispatchKeyValueFloat",	DispatchKeyValueFloat},
  1176 	{"DispatchKeyValueVector",	DispatchKeyValueVector},
  1177 	{"GetClientAimTarget",		sm_GetClientAimTarget},
  1178 	{"SetEntityModel",			sm_SetEntityModel},
  1179 	{"GetPlayerDecalFile",		GetPlayerDecalFile},
  1180 	{"GetServerNetStats",		GetServerNetStats},
  1181 	{"EquipPlayerWeapon",		WeaponEquip},
  1182 	{"ActivateEntity",			ActivateEntity},
  1183 	{"SetClientInfo",			SetClientInfo},
  1184 	{NULL,						NULL},
  1185 };