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