extensions/sdktools/vnatives.cpp
author Scott Ehlert <ds@alliedmods.net>
Thu Jan 22 15:20:45 2009 -0600 (2009-01-22)
changeset 2535 b3bfd3c1ad9f
parent 2488 f7f1bbcc85e4
child 2583 d3b2571c378b
permissions -rw-r--r--
Fixed crash in GetClientInfo() native on L4D (bug 3569, r=me).

The CreateFakeClient signature (used for verification before retrieving the IServer interface pointer) changed in a recent update. The IServer pointer was therefore null and GetClientInfo() did not check for this.

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