extensions/cstrike/natives.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Mon Dec 17 14:34:44 2012 -0500 (2012-12-17)
changeset 3710 5559ea22b6b5
parent 3706 54f55b538cb2
child 3964 8052afb00b69
permissions -rw-r--r--
Validate entity in GameRules_GetPropEnt and in CS_DropWeapon safety checks.
faluco@1441
     1
/**
faluco@1441
     2
 * vim: set ts=4 :
faluco@1441
     3
 * =============================================================================
faluco@1441
     4
 * SourceMod Counter-Strike:Source Extension
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
faluco@1441
     6
 * =============================================================================
faluco@1441
     7
 *
faluco@1441
     8
 * This program is free software; you can redistribute it and/or modify it under
faluco@1441
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
faluco@1441
    10
 * Free Software Foundation.
faluco@1441
    11
 * 
faluco@1441
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
faluco@1441
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
faluco@1441
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
faluco@1441
    15
 * details.
faluco@1441
    16
 *
faluco@1441
    17
 * You should have received a copy of the GNU General Public License along with
faluco@1441
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
faluco@1441
    19
 *
faluco@1441
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
faluco@1441
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
faluco@1441
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
faluco@1441
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
faluco@1441
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
faluco@1441
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
faluco@1441
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
faluco@1441
    27
 * or <http://www.sourcemod.net/license.php>.
faluco@1441
    28
 *
faluco@1441
    29
 * Version: $Id$
faluco@1441
    30
 */
faluco@1441
    31
faluco@1441
    32
#include "extension.h"
faluco@1441
    33
#include "RegNatives.h"
rgr_02@3519
    34
#include "forwards.h"
rgr_02@3519
    35
#include "util_cstrike.h"
rgr_02@3313
    36
#include <server_class.h>
faluco@1441
    37
rgr_02@3519
    38
int g_iPriceOffset = -1;
rgr_02@3519
    39
faluco@1441
    40
#define REGISTER_NATIVE_ADDR(name, code) \
faluco@1441
    41
	void *addr; \
rgr_02@3313
    42
	if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
faluco@1441
    43
	{ \
faluco@1441
    44
		return pContext->ThrowNativeError("Failed to locate function"); \
faluco@1441
    45
	} \
faluco@1441
    46
	code; \
faluco@1441
    47
	g_RegNatives.Register(pWrapper);
faluco@1441
    48
faluco@1441
    49
inline CBaseEntity *GetCBaseEntity(int num, bool isplayer)
faluco@1441
    50
{
rgr_02@3519
    51
	edict_t *pEdict = gamehelpers->EdictOfIndex(num);
faluco@1441
    52
	if (!pEdict || pEdict->IsFree())
faluco@1441
    53
	{
faluco@1441
    54
		return NULL;
faluco@1441
    55
	}
faluco@1441
    56
dvander@1857
    57
	if (num > 0 && num <= playerhelpers->GetMaxClients())
faluco@1441
    58
	{
faluco@1441
    59
		IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(pEdict);
faluco@1441
    60
		if (!pPlayer || !pPlayer->IsConnected())
faluco@1441
    61
		{
faluco@1441
    62
			return NULL;
faluco@1441
    63
		}
dvander@1857
    64
	}
dvander@1857
    65
	else if (isplayer) 
dvander@1857
    66
	{
faluco@1441
    67
		return NULL;
faluco@1441
    68
	}
faluco@1441
    69
faluco@1441
    70
	IServerUnknown *pUnk;
faluco@1441
    71
	if ((pUnk=pEdict->GetUnknown()) == NULL)
faluco@1441
    72
	{
faluco@1441
    73
		return NULL;
faluco@1441
    74
	}
faluco@1441
    75
faluco@1441
    76
	return pUnk->GetBaseEntity();
faluco@1441
    77
}
faluco@1441
    78
rgr_02@3313
    79
bool UTIL_FindDataTable(SendTable *pTable, const char *name, sm_sendprop_info_t *info, unsigned int offset)
rgr_02@3313
    80
{
rgr_02@3313
    81
	const char *pname;
rgr_02@3313
    82
	int props = pTable->GetNumProps();
rgr_02@3313
    83
	SendProp *prop;
rgr_02@3313
    84
	SendTable *table;
rgr_02@3313
    85
rgr_02@3313
    86
	for (int i=0; i<props; i++)
rgr_02@3313
    87
	{
rgr_02@3313
    88
		prop = pTable->GetProp(i);
rgr_02@3313
    89
rgr_02@3313
    90
		if ((table = prop->GetDataTable()) != NULL)
rgr_02@3313
    91
		{
rgr_02@3313
    92
			pname = table->GetName();
rgr_02@3313
    93
			if (pname && strcmp(name, pname) == 0)
rgr_02@3313
    94
			{
rgr_02@3313
    95
				info->prop = prop;
rgr_02@3313
    96
				info->actual_offset = offset + info->prop->GetOffset();
rgr_02@3313
    97
				return true;
rgr_02@3313
    98
			}
rgr_02@3313
    99
rgr_02@3313
   100
			if (UTIL_FindDataTable(table, 
rgr_02@3313
   101
				name,
rgr_02@3313
   102
				info,
rgr_02@3313
   103
				offset + prop->GetOffset())
rgr_02@3313
   104
				)
rgr_02@3313
   105
			{
rgr_02@3313
   106
				return true;
rgr_02@3313
   107
			}
rgr_02@3313
   108
		}
rgr_02@3313
   109
	}
rgr_02@3313
   110
rgr_02@3313
   111
	return false;
rgr_02@3313
   112
}
rgr_02@3313
   113
rgr_02@3313
   114
//Taken From Sourcemod Core
rgr_02@3313
   115
unsigned int strncopy(char *dest, const char *src, size_t count)
rgr_02@3313
   116
{
rgr_02@3313
   117
	if (!count)
rgr_02@3313
   118
	{
rgr_02@3313
   119
		return 0;
rgr_02@3313
   120
	}
rgr_02@3313
   121
rgr_02@3313
   122
	char *start = dest;
rgr_02@3313
   123
	while ((*src) && (--count))
rgr_02@3313
   124
	{
rgr_02@3313
   125
		*dest++ = *src++;
rgr_02@3313
   126
	}
rgr_02@3313
   127
	*dest = '\0';
rgr_02@3313
   128
rgr_02@3313
   129
	return (dest - start);
rgr_02@3313
   130
}
rgr_02@3313
   131
faluco@1441
   132
static cell_t CS_RespawnPlayer(IPluginContext *pContext, const cell_t *params)
faluco@1441
   133
{
faluco@1441
   134
	static ICallWrapper *pWrapper = NULL;
faluco@1441
   135
	if (!pWrapper)
faluco@1441
   136
	{
faluco@1441
   137
		REGISTER_NATIVE_ADDR("RoundRespawn", 
faluco@1441
   138
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0));
faluco@1441
   139
	}
faluco@1441
   140
faluco@1441
   141
	CBaseEntity *pEntity;
faluco@1441
   142
	if (!(pEntity=GetCBaseEntity(params[1], true)))
faluco@1441
   143
	{
faluco@1441
   144
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
faluco@1441
   145
	}
faluco@1441
   146
	pWrapper->Execute(&pEntity, NULL);
faluco@1441
   147
faluco@1441
   148
	return 1;
faluco@1441
   149
}
faluco@1441
   150
faluco@1441
   151
static cell_t CS_SwitchTeam(IPluginContext *pContext, const cell_t *params)
faluco@1441
   152
{
faluco@1441
   153
	static ICallWrapper *pWrapper = NULL;
faluco@1441
   154
	if (!pWrapper)
faluco@1441
   155
	{
faluco@1441
   156
		REGISTER_NATIVE_ADDR("SwitchTeam", 
faluco@1441
   157
			PassInfo pass[1]; \
faluco@1441
   158
			pass[0].flags = PASSFLAG_BYVAL; \
faluco@1441
   159
			pass[0].size = sizeof(int); \
faluco@1441
   160
			pass[0].type = PassType_Basic; \
faluco@1441
   161
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
faluco@1441
   162
	}
faluco@1441
   163
faluco@1441
   164
	CBaseEntity *pEntity;
faluco@1441
   165
	if (!(pEntity=GetCBaseEntity(params[1], true)))
faluco@1441
   166
	{
faluco@1441
   167
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
faluco@1441
   168
	}
faluco@1441
   169
faluco@1441
   170
	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(int)];
faluco@1441
   171
	unsigned char *vptr = vstk;
faluco@1441
   172
faluco@1441
   173
	*(CBaseEntity **)vptr = pEntity;
faluco@1441
   174
	vptr += sizeof(CBaseEntity *);
faluco@1441
   175
	*(int *)vptr = params[2];
faluco@1441
   176
	pWrapper->Execute(vstk, NULL);
faluco@1441
   177
faluco@1441
   178
	return 1;
faluco@1441
   179
}
faluco@1441
   180
rgr_02@3313
   181
static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   182
{
rgr_02@3313
   183
	static ICallWrapper *pWrapper = NULL;
rgr_02@3313
   184
	if (!pWrapper)
rgr_02@3313
   185
	{
rgr_02@3313
   186
		REGISTER_NATIVE_ADDR("CSWeaponDrop",
rgr_02@3313
   187
			PassInfo pass[3]; \
rgr_02@3313
   188
			pass[0].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   189
			pass[0].type  = PassType_Basic; \
rgr_02@3313
   190
			pass[0].size  = sizeof(CBaseEntity *); \
rgr_02@3313
   191
			pass[1].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   192
			pass[1].type  = PassType_Basic; \
rgr_02@3313
   193
			pass[1].size  = sizeof(bool); \
rgr_02@3313
   194
			pass[2].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   195
			pass[2].type  = PassType_Basic; \
rgr_02@3313
   196
			pass[2].size  = sizeof(bool); \
rgr_02@3313
   197
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
rgr_02@3313
   198
	}
rgr_02@3313
   199
rgr_02@3313
   200
	CBaseEntity *pEntity;
rgr_02@3313
   201
	if (!(pEntity = GetCBaseEntity(params[1], true)))
rgr_02@3313
   202
	{
rgr_02@3313
   203
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3313
   204
	}
rgr_02@3313
   205
rgr_02@3313
   206
	CBaseEntity *pWeapon;
rgr_02@3313
   207
	if (!(pWeapon = GetCBaseEntity(params[2], false)))
rgr_02@3313
   208
	{
rgr_02@3313
   209
		return pContext->ThrowNativeError("Weapon index %d is not valid", params[2]);
rgr_02@3313
   210
	}
rgr_02@3313
   211
rgr_02@3313
   212
	//Psychonic is awesome for this
kyle@3634
   213
	sm_sendprop_info_t spi;
rgr_02@3313
   214
	IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
rgr_02@3313
   215
	IServerNetworkable *pNet = pUnk->GetNetworkable();
rgr_02@3313
   216
kyle@3634
   217
	if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", &spi, 0))
rgr_02@3313
   218
		return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);
rgr_02@3313
   219
kyle@3634
   220
	if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", &spi))
rgr_02@3313
   221
		return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
rgr_02@3313
   222
kyle@3634
   223
	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + spi.actual_offset);
skamonkey@3710
   224
	if (params[1] != hndl.GetEntryIndex() || hndl != ((IServerEntity *)pEntity)->GetRefEHandle())
rgr_02@3313
   225
		return pContext->ThrowNativeError("Weapon %d is not owned by client %d", params[2], params[1]);
rgr_02@3313
   226
rgr_02@3313
   227
	if (params[4] == 1 && g_pCSWeaponDropDetoured)
rgr_02@3313
   228
		g_pIgnoreCSWeaponDropDetour = true;
rgr_02@3313
   229
rgr_02@3313
   230
	unsigned char vstk[sizeof(CBaseEntity *) * 2 + sizeof(bool) * 2];
rgr_02@3313
   231
	unsigned char *vptr = vstk;
rgr_02@3313
   232
rgr_02@3313
   233
	// <psychonic> first one is always false. second is true to toss, false to just drop
rgr_02@3313
   234
	*(CBaseEntity **)vptr = pEntity;
rgr_02@3313
   235
	vptr += sizeof(CBaseEntity *);
rgr_02@3313
   236
	*(CBaseEntity **)vptr = pWeapon;
rgr_02@3313
   237
	vptr += sizeof(CBaseEntity *);
rgr_02@3313
   238
	*(bool *)vptr = false;
rgr_02@3313
   239
	vptr += sizeof(bool);
rgr_02@3313
   240
	*(bool *)vptr = (params[3]) ? true : false;
rgr_02@3313
   241
rgr_02@3313
   242
 	pWrapper->Execute(vstk, NULL);
rgr_02@3313
   243
rgr_02@3313
   244
	return 1;
rgr_02@3313
   245
}
rgr_02@3313
   246
rgr_02@3313
   247
static cell_t CS_TerminateRound(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   248
{
rgr_02@3313
   249
	if (g_pSDKTools == NULL)
rgr_02@3313
   250
	{
rgr_02@3313
   251
		smutils->LogError(myself, "SDKTools interface not found. TerminateRound native disabled.");
rgr_02@3313
   252
	}
rgr_02@3313
   253
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3313
   254
	{
rgr_02@3313
   255
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3313
   256
		return pContext->ThrowNativeError("SDKTools interface is outdated. TerminateRound native disabled.");
rgr_02@3313
   257
	}
rgr_02@3313
   258
rgr_02@3313
   259
	static ICallWrapper *pWrapper = NULL;
rgr_02@3313
   260
rgr_02@3313
   261
	if (!pWrapper)
rgr_02@3313
   262
	{
rgr_02@3313
   263
		REGISTER_NATIVE_ADDR("TerminateRound",
rgr_02@3313
   264
			PassInfo pass[2]; \
rgr_02@3313
   265
			pass[0].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   266
			pass[0].type = PassType_Basic; \
rgr_02@3313
   267
			pass[0].size = sizeof(float); \
rgr_02@3313
   268
			pass[1].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   269
			pass[1].type = PassType_Basic; \
rgr_02@3313
   270
			pass[1].size = sizeof(int); \
rgr_02@3313
   271
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
rgr_02@3313
   272
	}
rgr_02@3313
   273
rgr_02@3313
   274
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3313
   275
	if (gamerules == NULL)
rgr_02@3313
   276
	{
rgr_02@3313
   277
		return pContext->ThrowNativeError("GameRules not available. TerminateRound native disabled.");
rgr_02@3313
   278
	}
rgr_02@3313
   279
rgr_02@3313
   280
	if (params[3] == 1 && g_pTerminateRoundDetoured)
rgr_02@3313
   281
		g_pIgnoreTerminateDetour = true;
rgr_02@3313
   282
rgr_02@3313
   283
	unsigned char vstk[sizeof(void *) + sizeof(float)+ sizeof(int)];
rgr_02@3313
   284
	unsigned char *vptr = vstk;
rgr_02@3313
   285
rgr_02@3313
   286
	*(void **)vptr = gamerules;
rgr_02@3313
   287
	vptr += sizeof(void *);
rgr_02@3313
   288
	*(float *)vptr = sp_ctof(params[1]);
rgr_02@3313
   289
	vptr += sizeof(float);
rgr_02@3313
   290
	*(int*)vptr = params[2];
rgr_02@3313
   291
rgr_02@3313
   292
	pWrapper->Execute(vstk, NULL);
rgr_02@3313
   293
rgr_02@3313
   294
	return 1;
rgr_02@3313
   295
}
rgr_02@3313
   296
kyle@3702
   297
static cell_t CS_WeaponIDToAlias(IPluginContext *pContext, const cell_t *params)
kyle@3702
   298
{
kyle@3702
   299
	char *dest;
kyle@3702
   300
kyle@3702
   301
	pContext->LocalToString(params[2], &dest);
kyle@3702
   302
kyle@3702
   303
	const char *ret = WeaponIDToAlias(params[1]);
kyle@3702
   304
	
kyle@3702
   305
	if (ret == NULL)
kyle@3702
   306
	{
kyle@3702
   307
		return 0;
kyle@3702
   308
	}
kyle@3702
   309
	
kyle@3702
   310
	return strncopy(dest, ret, params[3]);
kyle@3702
   311
}
kyle@3702
   312
rgr_02@3313
   313
static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   314
{
rgr_02@3519
   315
	char *weapon;
rgr_02@3519
   316
	char *dest;
rgr_02@3313
   317
rgr_02@3313
   318
	pContext->LocalToString(params[2], &dest);
rgr_02@3313
   319
	pContext->LocalToString(params[1], &weapon);
rgr_02@3313
   320
rgr_02@3519
   321
	const char *ret = GetTranslatedWeaponAlias(weapon);
rgr_02@3313
   322
	strncopy(dest, ret, params[3]);
rgr_02@3313
   323
	
rgr_02@3313
   324
	return 1;
rgr_02@3313
   325
}
skamonkey@3405
   326
rgr_02@3324
   327
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
rgr_02@3324
   328
{
rgr_02@3359
   329
	//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
rgr_02@3519
   330
	int id = GetRealWeaponID(params[2]);
rgr_02@3519
   331
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   332
	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
rgr_02@3519
   333
#else
rgr_02@3519
   334
 	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_SHIELD)
rgr_02@3519
   335
#endif
rgr_02@3359
   336
		return 0;
rgr_02@3519
   337
	if (id == WEAPON_KEVLAR)
rgr_02@3359
   338
		return 650;
rgr_02@3519
   339
	if (id == WEAPON_ASSAULTSUIT)
rgr_02@3359
   340
		return 1000;
rgr_02@3519
   341
	if (id == WEAPON_NIGHTVISION)
rgr_02@3359
   342
		return 1250;
rgr_02@3519
   343
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   344
	if (id == WEAPON_DEFUSER)
rgr_02@3519
   345
		return 200;
rgr_02@3519
   346
#endif
rgr_02@3519
   347
	if (id == 0)
rgr_02@3519
   348
		return 0;
rgr_02@3359
   349
rgr_02@3519
   350
	if (g_iPriceOffset == -1)
rgr_02@3324
   351
	{
rgr_02@3519
   352
		if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset))
rgr_02@3324
   353
		{
rgr_02@3519
   354
			g_iPriceOffset = -1;
rgr_02@3324
   355
			return pContext->ThrowNativeError("Failed to get WeaponPrice offset");
rgr_02@3324
   356
		}
rgr_02@3324
   357
	}
rgr_02@3324
   358
rgr_02@3324
   359
	CBaseEntity *pEntity;
rgr_02@3324
   360
	if (!(pEntity = GetCBaseEntity(params[1], true)))
rgr_02@3324
   361
	{
rgr_02@3324
   362
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3324
   363
	}
rgr_02@3324
   364
rgr_02@3560
   365
	void *info = GetWeaponInfo(id);
rgr_02@3324
   366
	if (!info)
rgr_02@3324
   367
		return pContext->ThrowNativeError("Failed to get weaponinfo");
rgr_02@3324
   368
rgr_02@3519
   369
	int price = *(int *)((intptr_t)info + g_iPriceOffset);
rgr_02@3324
   370
rgr_02@3324
   371
	if (params[3] || weaponNameOffset == -1)
rgr_02@3324
   372
		return price;
rgr_02@3324
   373
rgr_02@3324
   374
	const char *weapon_name = (const char *)((intptr_t)info + weaponNameOffset);
rgr_02@3324
   375
rgr_02@3519
   376
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   377
	return CallPriceForwardCSGO(params[1], weapon_name, price);
rgr_02@3519
   378
#else
rgr_02@3324
   379
	return CallPriceForward(params[1], weapon_name, price);
rgr_02@3519
   380
#endif
rgr_02@3324
   381
}
rgr_02@3313
   382
skamonkey@3405
   383
static cell_t CS_GetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   384
{
skamonkey@3405
   385
	static void *addr;
skamonkey@3405
   386
	if (!addr)
skamonkey@3405
   387
	{
skamonkey@3405
   388
		if (!g_pGameConf->GetMemSig("SetClanTag", &addr) || !addr)
skamonkey@3405
   389
		{
skamonkey@3405
   390
			return pContext->ThrowNativeError("Failed to locate function");
skamonkey@3405
   391
		}
skamonkey@3405
   392
	}
skamonkey@3405
   393
skamonkey@3405
   394
	CBaseEntity *pEntity;
skamonkey@3405
   395
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   396
	{
skamonkey@3405
   397
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   398
	}
skamonkey@3405
   399
skamonkey@3405
   400
	static int tagOffsetOffset = -1;
skamonkey@3405
   401
	static int tagOffset;
skamonkey@3405
   402
skamonkey@3405
   403
	if (tagOffsetOffset == -1)
skamonkey@3405
   404
	{
skamonkey@3405
   405
		if (!g_pGameConf->GetOffset("ClanTagOffset", &tagOffsetOffset))
skamonkey@3405
   406
		{
skamonkey@3405
   407
			tagOffsetOffset = -1;
skamonkey@3405
   408
			return pContext->ThrowNativeError("Unable to find ClanTagOffset gamedata");
skamonkey@3405
   409
		}
skamonkey@3405
   410
skamonkey@3405
   411
		tagOffset = *(int *)((intptr_t)addr + tagOffsetOffset);
skamonkey@3405
   412
	}
skamonkey@3405
   413
skamonkey@3405
   414
	size_t len;
skamonkey@3405
   415
skamonkey@3405
   416
	const char *src = (char *)((intptr_t)pEntity + tagOffset);
skamonkey@3405
   417
	pContext->StringToLocalUTF8(params[2], params[3], src, &len);
skamonkey@3405
   418
skamonkey@3405
   419
	return len;
skamonkey@3405
   420
}
skamonkey@3405
   421
skamonkey@3405
   422
static cell_t CS_SetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   423
{
skamonkey@3405
   424
	static ICallWrapper *pWrapper = NULL;
skamonkey@3405
   425
skamonkey@3405
   426
	if (!pWrapper)
skamonkey@3405
   427
	{
skamonkey@3405
   428
		REGISTER_NATIVE_ADDR("SetClanTag",
skamonkey@3405
   429
			PassInfo pass[2]; \
skamonkey@3405
   430
			pass[0].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   431
			pass[0].type  = PassType_Basic; \
skamonkey@3405
   432
			pass[0].size  = sizeof(CBaseEntity *); \
skamonkey@3405
   433
			pass[1].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   434
			pass[1].type  = PassType_Basic; \
skamonkey@3405
   435
			pass[1].size  = sizeof(char *); \
skamonkey@3405
   436
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
skamonkey@3405
   437
	}
skamonkey@3405
   438
skamonkey@3405
   439
	CBaseEntity *pEntity;
skamonkey@3405
   440
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   441
	{
skamonkey@3405
   442
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   443
	}
skamonkey@3405
   444
skamonkey@3405
   445
	char *szNewTag;
skamonkey@3405
   446
	pContext->LocalToString(params[2], &szNewTag);
skamonkey@3405
   447
skamonkey@3405
   448
	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(char *)];
skamonkey@3405
   449
	unsigned char *vptr = vstk;
skamonkey@3405
   450
skamonkey@3405
   451
	*(CBaseEntity **)vptr = pEntity;
skamonkey@3405
   452
	vptr += sizeof(CBaseEntity *);
skamonkey@3405
   453
	*(char **)vptr = szNewTag;
skamonkey@3405
   454
skamonkey@3405
   455
	pWrapper->Execute(vstk, NULL);
skamonkey@3405
   456
skamonkey@3405
   457
	return 1;
rgr_02@3519
   458
}
rgr_02@3519
   459
rgr_02@3519
   460
static cell_t CS_AliasToWeaponID(IPluginContext *pContext, const cell_t *params)
rgr_02@3519
   461
{
rgr_02@3519
   462
	char *weapon;
rgr_02@3519
   463
rgr_02@3519
   464
	pContext->LocalToString(params[1], &weapon);
rgr_02@3519
   465
rgr_02@3519
   466
	return GetFakeWeaponID(AliasToWeaponID(weapon));
skamonkey@3405
   467
}
skamonkey@3405
   468
rgr_02@3530
   469
static cell_t CS_SetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   470
{
rgr_02@3530
   471
	if (g_pSDKTools == NULL)
rgr_02@3530
   472
	{
rgr_02@3530
   473
		smutils->LogError(myself, "SDKTools interface not found. CS_SetTeamScore native disabled.");
rgr_02@3530
   474
	}
rgr_02@3530
   475
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   476
	{
rgr_02@3530
   477
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   478
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_SetTeamScore native disabled.");
rgr_02@3530
   479
	}
rgr_02@3530
   480
rgr_02@3530
   481
	static void *addr;
rgr_02@3530
   482
	if (!addr)
rgr_02@3530
   483
	{
rgr_02@3530
   484
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   485
		{
rgr_02@3530
   486
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   487
		}
rgr_02@3530
   488
	}
rgr_02@3530
   489
rgr_02@3530
   490
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   491
	static int ctTeamOffset;
rgr_02@3530
   492
rgr_02@3530
   493
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   494
	static int tTeamOffset;
rgr_02@3530
   495
rgr_02@3530
   496
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   497
	{
rgr_02@3530
   498
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   499
		{
rgr_02@3530
   500
			ctTeamOffsetOffset = -1;
rgr_02@3530
   501
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   502
		}
rgr_02@3530
   503
rgr_02@3530
   504
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   505
	}
rgr_02@3530
   506
rgr_02@3530
   507
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   508
	{
rgr_02@3530
   509
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   510
		{
rgr_02@3530
   511
			tTeamOffsetOffset = -1;
rgr_02@3530
   512
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   513
		}
rgr_02@3530
   514
rgr_02@3530
   515
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   516
	}
rgr_02@3530
   517
rgr_02@3530
   518
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   519
	if (gamerules == NULL)
rgr_02@3530
   520
	{
rgr_02@3530
   521
		return pContext->ThrowNativeError("GameRules not available. CS_SetTeamScore native disabled.");
rgr_02@3530
   522
	}
rgr_02@3530
   523
rgr_02@3530
   524
	if (params[1] == 3)
rgr_02@3530
   525
	{
rgr_02@3530
   526
		*(int16_t *)((intptr_t)gamerules+ctTeamOffset) = params[2];
rgr_02@3530
   527
		return 1;
rgr_02@3530
   528
	}
rgr_02@3530
   529
	else if (params[1] == 2)
rgr_02@3530
   530
	{
rgr_02@3530
   531
		*(int16_t *)((intptr_t)gamerules+tTeamOffset) = params[2];
rgr_02@3530
   532
		return 1;
rgr_02@3530
   533
	}
rgr_02@3530
   534
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   535
}
rgr_02@3530
   536
rgr_02@3530
   537
static cell_t CS_GetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   538
{
rgr_02@3530
   539
	if (g_pSDKTools == NULL)
rgr_02@3530
   540
	{
rgr_02@3530
   541
		smutils->LogError(myself, "SDKTools interface not found. CS_GetTeamScore native disabled.");
rgr_02@3530
   542
	}
rgr_02@3530
   543
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   544
	{
rgr_02@3530
   545
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   546
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_GetTeamScore native disabled.");
rgr_02@3530
   547
	}
rgr_02@3530
   548
rgr_02@3530
   549
	static void *addr;
rgr_02@3530
   550
	if (!addr)
rgr_02@3530
   551
	{
rgr_02@3530
   552
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   553
		{
rgr_02@3530
   554
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   555
		}
rgr_02@3530
   556
	}
rgr_02@3530
   557
rgr_02@3530
   558
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   559
	static int ctTeamOffset;
rgr_02@3530
   560
rgr_02@3530
   561
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   562
	static int tTeamOffset;
rgr_02@3530
   563
rgr_02@3530
   564
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   565
	{
rgr_02@3530
   566
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   567
		{
rgr_02@3530
   568
			ctTeamOffsetOffset = -1;
rgr_02@3530
   569
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   570
		}
rgr_02@3530
   571
rgr_02@3530
   572
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   573
	}
rgr_02@3530
   574
rgr_02@3530
   575
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   576
	{
rgr_02@3530
   577
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   578
		{
rgr_02@3530
   579
			tTeamOffsetOffset = -1;
rgr_02@3530
   580
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   581
		}
rgr_02@3530
   582
rgr_02@3530
   583
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   584
	}
rgr_02@3530
   585
rgr_02@3530
   586
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   587
	if (gamerules == NULL)
rgr_02@3530
   588
	{
rgr_02@3530
   589
		return pContext->ThrowNativeError("GameRules not available. CS_GetTeamScore native disabled.");
rgr_02@3530
   590
	}
rgr_02@3530
   591
rgr_02@3530
   592
	if (params[1] == 3)
rgr_02@3530
   593
	{
rgr_02@3530
   594
		return *(int16_t *)((intptr_t)gamerules+ctTeamOffset);
rgr_02@3530
   595
	}
rgr_02@3530
   596
	else if (params[1] == 2)
rgr_02@3530
   597
	{
rgr_02@3530
   598
		return *(int16_t *)((intptr_t)gamerules+tTeamOffset);
rgr_02@3530
   599
	}
rgr_02@3530
   600
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   601
}
rgr_02@3530
   602
skamonkey@3706
   603
template <typename T>
skamonkey@3706
   604
static inline T *GetPlayerVarAddressOrError(const char *pszGamedataName, IPluginContext *pContext, CBaseEntity *pPlayerEntity)
rgr_02@3530
   605
{
skamonkey@3706
   606
	char szBaseName[128];
skamonkey@3706
   607
	g_pSM->Format(szBaseName, sizeof(szBaseName), "%sBase", pszGamedataName);
skamonkey@3706
   608
skamonkey@3706
   609
	const char *pszBaseVar = g_pGameConf->GetKeyValue(szBaseName);
skamonkey@3706
   610
	if (pszBaseVar == NULL)
skamonkey@3706
   611
	{
skamonkey@3706
   612
		pContext->ThrowNativeError("Failed to locate %s key in gamedata", szBaseName);
skamonkey@3706
   613
		return NULL;
skamonkey@3706
   614
	}
skamonkey@3706
   615
skamonkey@3706
   616
	int interimOffset = 0;
skamonkey@3706
   617
	sm_sendprop_info_t info;
skamonkey@3706
   618
	if (gamehelpers->FindSendPropInfo("CCSPlayer", pszBaseVar, &info))
rgr_02@3530
   619
	{
skamonkey@3706
   620
		interimOffset = info.actual_offset;
skamonkey@3706
   621
	}
skamonkey@3706
   622
	else
skamonkey@3706
   623
	{
skamonkey@3706
   624
		datamap_t *pMap = gamehelpers->GetDataMap(pPlayerEntity);
skamonkey@3706
   625
		typedescription_t *td = gamehelpers->FindInDataMap(pMap, pszBaseVar);
skamonkey@3706
   626
		if (td)
rgr_02@3530
   627
		{
skamonkey@3706
   628
#if SOURCE_ENGINE >= SE_LEFT4DEAD
skamonkey@3706
   629
			interimOffset = td->fieldOffset;
skamonkey@3706
   630
#else
skamonkey@3706
   631
			interimOffset = td->fieldOffset[TD_OFFSET_NORMAL];
skamonkey@3706
   632
#endif
rgr_02@3530
   633
		}
rgr_02@3530
   634
	}
rgr_02@3530
   635
skamonkey@3706
   636
	if (interimOffset == 0)
skamonkey@3706
   637
	{
skamonkey@3706
   638
		pContext->ThrowNativeError("Failed to find property \"%s\" on player.", pszBaseVar);
skamonkey@3706
   639
		return NULL;
skamonkey@3706
   640
	}
skamonkey@3706
   641
		
skamonkey@3706
   642
skamonkey@3706
   643
	int tempOffset;
skamonkey@3706
   644
	if (!g_pGameConf->GetOffset(pszGamedataName, &tempOffset))
skamonkey@3706
   645
	{
skamonkey@3706
   646
		pContext->ThrowNativeError("Failed to locate %s offset in gamedata", pszGamedataName);
skamonkey@3706
   647
		return NULL;
skamonkey@3706
   648
	}
skamonkey@3706
   649
skamonkey@3706
   650
	return (T *)((intptr_t)pPlayerEntity + interimOffset + tempOffset);
skamonkey@3706
   651
}
skamonkey@3706
   652
skamonkey@3706
   653
template <typename T>
skamonkey@3706
   654
static inline cell_t GetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   655
{
skamonkey@3706
   656
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   657
	if (!pPlayer)
rgr_02@3530
   658
	{
rgr_02@3530
   659
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3530
   660
	}
rgr_02@3530
   661
skamonkey@3706
   662
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   663
	if (pVar)
skamonkey@3706
   664
	{	
skamonkey@3706
   665
		return (cell_t)*pVar;
rgr_02@3530
   666
	}
rgr_02@3530
   667
skamonkey@3706
   668
	return 0;
skamonkey@3706
   669
}
skamonkey@3706
   670
skamonkey@3706
   671
template <typename T>
skamonkey@3706
   672
static inline cell_t SetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   673
{
skamonkey@3706
   674
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   675
	if (!pPlayer)
skamonkey@3706
   676
	{
skamonkey@3706
   677
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3706
   678
	}
rgr_02@3530
   679
skamonkey@3706
   680
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   681
	if (pVar)
skamonkey@3706
   682
	{
skamonkey@3706
   683
		*pVar = (T)params[2];
skamonkey@3706
   684
	}
skamonkey@3706
   685
skamonkey@3706
   686
	return 0;
skamonkey@3706
   687
}
skamonkey@3706
   688
skamonkey@3706
   689
static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   690
{
skamonkey@3706
   691
	return SetPlayerVar<int>(pContext, params, "MVPs");
rgr_02@3530
   692
}
rgr_02@3530
   693
rgr_02@3530
   694
static cell_t CS_GetMVPCount(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   695
{
skamonkey@3706
   696
	return GetPlayerVar<int>(pContext, params, "MVPs");
skamonkey@3706
   697
}
rgr_02@3530
   698
skamonkey@3706
   699
static cell_t CS_SetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   700
{
skamonkey@3706
   701
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   702
	return SetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   703
#else
skamonkey@3706
   704
	return pContext->ThrowNativeError("SetClientContributionScore is not supported on this game");
skamonkey@3706
   705
#endif
skamonkey@3706
   706
}
rgr_02@3530
   707
skamonkey@3706
   708
static cell_t CS_GetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   709
{
skamonkey@3706
   710
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   711
	return GetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   712
#else
skamonkey@3706
   713
	return pContext->ThrowNativeError("GetClientContributionScore is not supported on this game");
skamonkey@3706
   714
#endif
skamonkey@3706
   715
}
rgr_02@3530
   716
skamonkey@3706
   717
static cell_t CS_SetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   718
{
skamonkey@3706
   719
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   720
	return SetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   721
#else
skamonkey@3706
   722
	return pContext->ThrowNativeError("SetClientAssists is not supported on this game");
skamonkey@3706
   723
#endif
skamonkey@3706
   724
}
rgr_02@3530
   725
skamonkey@3706
   726
static cell_t CS_GetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   727
{
skamonkey@3706
   728
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   729
	return GetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   730
#else
skamonkey@3706
   731
	return pContext->ThrowNativeError("GetClientAssists is not supported on this game");
skamonkey@3706
   732
#endif
rgr_02@3530
   733
}
rgr_02@3530
   734
faluco@1441
   735
sp_nativeinfo_t g_CSNatives[] = 
faluco@1441
   736
{
faluco@1441
   737
	{"CS_RespawnPlayer",			CS_RespawnPlayer}, 
rgr_02@3313
   738
	{"CS_SwitchTeam",				CS_SwitchTeam},
rgr_02@3313
   739
	{"CS_DropWeapon",				CS_DropWeapon},
rgr_02@3313
   740
	{"CS_TerminateRound",			CS_TerminateRound},
rgr_02@3313
   741
	{"CS_GetTranslatedWeaponAlias",	CS_GetTranslatedWeaponAlias},
rgr_02@3324
   742
	{"CS_GetWeaponPrice",			CS_GetWeaponPrice},
skamonkey@3405
   743
	{"CS_GetClientClanTag",			CS_GetClientClanTag},
skamonkey@3405
   744
	{"CS_SetClientClanTag",			CS_SetClientClanTag},
rgr_02@3519
   745
	{"CS_AliasToWeaponID",			CS_AliasToWeaponID},
rgr_02@3530
   746
	{"CS_GetTeamScore",				CS_GetTeamScore},
rgr_02@3530
   747
	{"CS_SetTeamScore",				CS_SetTeamScore},
rgr_02@3530
   748
	{"CS_GetMVPCount",				CS_GetMVPCount},
rgr_02@3530
   749
	{"CS_SetMVPCount",				CS_SetMVPCount},
kyle@3702
   750
	{"CS_WeaponIDToAlias",			CS_WeaponIDToAlias},
skamonkey@3706
   751
	{"CS_GetClientContributionScore",	CS_GetClientContributionScore},
skamonkey@3706
   752
	{"CS_SetClientContributionScore",	CS_SetClientContributionScore},
skamonkey@3706
   753
	{"CS_GetClientAssists",			CS_GetClientAssists},
skamonkey@3706
   754
	{"CS_SetClientAssists",			CS_SetClientAssists},
faluco@1441
   755
	{NULL,							NULL}
faluco@1441
   756
};
dvander@1692
   757