extensions/cstrike/natives.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 15 21:22:24 2014 -0400 (2014-05-15)
changeset 4362 8a15e967d983
parent 4252 e665928a4dba
permissions -rw-r--r--
Update gamedata for CS:S update.
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>
drifter01620@4246
    37
#include <iplayerinfo.h>
faluco@1441
    38
rgr_02@3519
    39
int g_iPriceOffset = -1;
rgr_02@3519
    40
faluco@1441
    41
#define REGISTER_NATIVE_ADDR(name, code) \
faluco@1441
    42
	void *addr; \
rgr_02@3313
    43
	if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
faluco@1441
    44
	{ \
faluco@1441
    45
		return pContext->ThrowNativeError("Failed to locate function"); \
faluco@1441
    46
	} \
faluco@1441
    47
	code; \
faluco@1441
    48
	g_RegNatives.Register(pWrapper);
faluco@1441
    49
drifter01620@4237
    50
#define GET_MEMSIG(name) \
drifter01620@4237
    51
	if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
drifter01620@4237
    52
	{ \
drifter01620@4237
    53
		return pContext->ThrowNativeError("Failed to locate function"); \
drifter01620@4237
    54
	}
drifter01620@4237
    55
faluco@1441
    56
inline CBaseEntity *GetCBaseEntity(int num, bool isplayer)
faluco@1441
    57
{
rgr_02@3519
    58
	edict_t *pEdict = gamehelpers->EdictOfIndex(num);
faluco@1441
    59
	if (!pEdict || pEdict->IsFree())
faluco@1441
    60
	{
faluco@1441
    61
		return NULL;
faluco@1441
    62
	}
faluco@1441
    63
dvander@1857
    64
	if (num > 0 && num <= playerhelpers->GetMaxClients())
faluco@1441
    65
	{
faluco@1441
    66
		IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(pEdict);
faluco@1441
    67
		if (!pPlayer || !pPlayer->IsConnected())
faluco@1441
    68
		{
faluco@1441
    69
			return NULL;
faluco@1441
    70
		}
dvander@1857
    71
	}
dvander@1857
    72
	else if (isplayer) 
dvander@1857
    73
	{
faluco@1441
    74
		return NULL;
faluco@1441
    75
	}
faluco@1441
    76
faluco@1441
    77
	IServerUnknown *pUnk;
faluco@1441
    78
	if ((pUnk=pEdict->GetUnknown()) == NULL)
faluco@1441
    79
	{
faluco@1441
    80
		return NULL;
faluco@1441
    81
	}
faluco@1441
    82
faluco@1441
    83
	return pUnk->GetBaseEntity();
faluco@1441
    84
}
faluco@1441
    85
rgr_02@3313
    86
bool UTIL_FindDataTable(SendTable *pTable, const char *name, sm_sendprop_info_t *info, unsigned int offset)
rgr_02@3313
    87
{
rgr_02@3313
    88
	const char *pname;
rgr_02@3313
    89
	int props = pTable->GetNumProps();
rgr_02@3313
    90
	SendProp *prop;
rgr_02@3313
    91
	SendTable *table;
rgr_02@3313
    92
rgr_02@3313
    93
	for (int i=0; i<props; i++)
rgr_02@3313
    94
	{
rgr_02@3313
    95
		prop = pTable->GetProp(i);
rgr_02@3313
    96
rgr_02@3313
    97
		if ((table = prop->GetDataTable()) != NULL)
rgr_02@3313
    98
		{
rgr_02@3313
    99
			pname = table->GetName();
rgr_02@3313
   100
			if (pname && strcmp(name, pname) == 0)
rgr_02@3313
   101
			{
rgr_02@3313
   102
				info->prop = prop;
rgr_02@3313
   103
				info->actual_offset = offset + info->prop->GetOffset();
rgr_02@3313
   104
				return true;
rgr_02@3313
   105
			}
rgr_02@3313
   106
rgr_02@3313
   107
			if (UTIL_FindDataTable(table, 
rgr_02@3313
   108
				name,
rgr_02@3313
   109
				info,
rgr_02@3313
   110
				offset + prop->GetOffset())
rgr_02@3313
   111
				)
rgr_02@3313
   112
			{
rgr_02@3313
   113
				return true;
rgr_02@3313
   114
			}
rgr_02@3313
   115
		}
rgr_02@3313
   116
	}
rgr_02@3313
   117
rgr_02@3313
   118
	return false;
rgr_02@3313
   119
}
rgr_02@3313
   120
rgr_02@3313
   121
//Taken From Sourcemod Core
rgr_02@3313
   122
unsigned int strncopy(char *dest, const char *src, size_t count)
rgr_02@3313
   123
{
rgr_02@3313
   124
	if (!count)
rgr_02@3313
   125
	{
rgr_02@3313
   126
		return 0;
rgr_02@3313
   127
	}
rgr_02@3313
   128
rgr_02@3313
   129
	char *start = dest;
rgr_02@3313
   130
	while ((*src) && (--count))
rgr_02@3313
   131
	{
rgr_02@3313
   132
		*dest++ = *src++;
rgr_02@3313
   133
	}
rgr_02@3313
   134
	*dest = '\0';
rgr_02@3313
   135
rgr_02@3313
   136
	return (dest - start);
rgr_02@3313
   137
}
rgr_02@3313
   138
faluco@1441
   139
static cell_t CS_RespawnPlayer(IPluginContext *pContext, const cell_t *params)
faluco@1441
   140
{
faluco@1441
   141
	static ICallWrapper *pWrapper = NULL;
faluco@1441
   142
	if (!pWrapper)
faluco@1441
   143
	{
faluco@1441
   144
		REGISTER_NATIVE_ADDR("RoundRespawn", 
faluco@1441
   145
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0));
faluco@1441
   146
	}
faluco@1441
   147
faluco@1441
   148
	CBaseEntity *pEntity;
faluco@1441
   149
	if (!(pEntity=GetCBaseEntity(params[1], true)))
faluco@1441
   150
	{
faluco@1441
   151
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
faluco@1441
   152
	}
faluco@1441
   153
	pWrapper->Execute(&pEntity, NULL);
faluco@1441
   154
faluco@1441
   155
	return 1;
faluco@1441
   156
}
faluco@1441
   157
faluco@1441
   158
static cell_t CS_SwitchTeam(IPluginContext *pContext, const cell_t *params)
faluco@1441
   159
{
drifter01620@4237
   160
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
faluco@1441
   161
	static ICallWrapper *pWrapper = NULL;
faluco@1441
   162
	if (!pWrapper)
faluco@1441
   163
	{
faluco@1441
   164
		REGISTER_NATIVE_ADDR("SwitchTeam", 
faluco@1441
   165
			PassInfo pass[1]; \
faluco@1441
   166
			pass[0].flags = PASSFLAG_BYVAL; \
faluco@1441
   167
			pass[0].size = sizeof(int); \
faluco@1441
   168
			pass[0].type = PassType_Basic; \
faluco@1441
   169
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 1))
faluco@1441
   170
	}
faluco@1441
   171
faluco@1441
   172
	CBaseEntity *pEntity;
faluco@1441
   173
	if (!(pEntity=GetCBaseEntity(params[1], true)))
faluco@1441
   174
	{
faluco@1441
   175
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
faluco@1441
   176
	}
faluco@1441
   177
faluco@1441
   178
	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(int)];
faluco@1441
   179
	unsigned char *vptr = vstk;
faluco@1441
   180
faluco@1441
   181
	*(CBaseEntity **)vptr = pEntity;
faluco@1441
   182
	vptr += sizeof(CBaseEntity *);
faluco@1441
   183
	*(int *)vptr = params[2];
faluco@1441
   184
	pWrapper->Execute(vstk, NULL);
drifter01620@4237
   185
#else
drifter01620@4237
   186
	if (g_pSDKTools == NULL)
drifter01620@4237
   187
	{
drifter01620@4238
   188
		return pContext->ThrowNativeError("SDKTools interface not found. SwitchTeam native disabled.");
drifter01620@4237
   189
	}
drifter01620@4237
   190
drifter01620@4237
   191
	static void *addr = NULL;
drifter01620@4237
   192
	if(!addr)
drifter01620@4237
   193
	{
drifter01620@4237
   194
		GET_MEMSIG("SwitchTeam");
drifter01620@4237
   195
	}
drifter01620@4237
   196
drifter01620@4237
   197
	void *gamerules = g_pSDKTools->GetGameRules();
drifter01620@4237
   198
	if (gamerules == NULL)
drifter01620@4237
   199
	{
drifter01620@4237
   200
		return pContext->ThrowNativeError("GameRules not available. SwitchTeam native disabled.");
drifter01620@4237
   201
	}
drifter01620@4237
   202
drifter01620@4237
   203
	CBaseEntity *pEntity;
drifter01620@4237
   204
	if (!(pEntity=GetCBaseEntity(params[1], true)))
drifter01620@4237
   205
	{
drifter01620@4237
   206
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
drifter01620@4237
   207
	}
drifter01620@4237
   208
drifter01620@4237
   209
	int team = params[2];
drifter01620@4237
   210
drifter01620@4237
   211
	__asm
drifter01620@4237
   212
	{
drifter01620@4237
   213
		push team
drifter01620@4237
   214
		mov ecx, pEntity
drifter01620@4237
   215
		mov ebx, gamerules
drifter01620@4237
   216
 
drifter01620@4237
   217
		call addr
drifter01620@4237
   218
	}
drifter01620@4237
   219
#endif
faluco@1441
   220
faluco@1441
   221
	return 1;
faluco@1441
   222
}
faluco@1441
   223
rgr_02@3313
   224
static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   225
{
rgr_02@3313
   226
	static ICallWrapper *pWrapper = NULL;
rgr_02@3313
   227
	if (!pWrapper)
rgr_02@3313
   228
	{
rgr_02@3313
   229
		REGISTER_NATIVE_ADDR("CSWeaponDrop",
rgr_02@3313
   230
			PassInfo pass[3]; \
rgr_02@3313
   231
			pass[0].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   232
			pass[0].type  = PassType_Basic; \
rgr_02@3313
   233
			pass[0].size  = sizeof(CBaseEntity *); \
rgr_02@3313
   234
			pass[1].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   235
			pass[1].type  = PassType_Basic; \
rgr_02@3313
   236
			pass[1].size  = sizeof(bool); \
rgr_02@3313
   237
			pass[2].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   238
			pass[2].type  = PassType_Basic; \
rgr_02@3313
   239
			pass[2].size  = sizeof(bool); \
rgr_02@3313
   240
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 3))
rgr_02@3313
   241
	}
rgr_02@3313
   242
rgr_02@3313
   243
	CBaseEntity *pEntity;
rgr_02@3313
   244
	if (!(pEntity = GetCBaseEntity(params[1], true)))
rgr_02@3313
   245
	{
rgr_02@3313
   246
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3313
   247
	}
rgr_02@3313
   248
rgr_02@3313
   249
	CBaseEntity *pWeapon;
rgr_02@3313
   250
	if (!(pWeapon = GetCBaseEntity(params[2], false)))
rgr_02@3313
   251
	{
rgr_02@3313
   252
		return pContext->ThrowNativeError("Weapon index %d is not valid", params[2]);
rgr_02@3313
   253
	}
rgr_02@3313
   254
rgr_02@3313
   255
	//Psychonic is awesome for this
kyle@3634
   256
	sm_sendprop_info_t spi;
rgr_02@3313
   257
	IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
rgr_02@3313
   258
	IServerNetworkable *pNet = pUnk->GetNetworkable();
rgr_02@3313
   259
kyle@3634
   260
	if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", &spi, 0))
rgr_02@3313
   261
		return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);
rgr_02@3313
   262
kyle@3634
   263
	if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", &spi))
rgr_02@3313
   264
		return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
rgr_02@3313
   265
kyle@3634
   266
	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + spi.actual_offset);
skamonkey@3710
   267
	if (params[1] != hndl.GetEntryIndex() || hndl != ((IServerEntity *)pEntity)->GetRefEHandle())
rgr_02@3313
   268
		return pContext->ThrowNativeError("Weapon %d is not owned by client %d", params[2], params[1]);
rgr_02@3313
   269
rgr_02@3313
   270
	if (params[4] == 1 && g_pCSWeaponDropDetoured)
rgr_02@3313
   271
		g_pIgnoreCSWeaponDropDetour = true;
rgr_02@3313
   272
rgr_02@3313
   273
	unsigned char vstk[sizeof(CBaseEntity *) * 2 + sizeof(bool) * 2];
rgr_02@3313
   274
	unsigned char *vptr = vstk;
rgr_02@3313
   275
rgr_02@3313
   276
	// <psychonic> first one is always false. second is true to toss, false to just drop
rgr_02@3313
   277
	*(CBaseEntity **)vptr = pEntity;
rgr_02@3313
   278
	vptr += sizeof(CBaseEntity *);
rgr_02@3313
   279
	*(CBaseEntity **)vptr = pWeapon;
rgr_02@3313
   280
	vptr += sizeof(CBaseEntity *);
rgr_02@3313
   281
	*(bool *)vptr = false;
rgr_02@3313
   282
	vptr += sizeof(bool);
rgr_02@3313
   283
	*(bool *)vptr = (params[3]) ? true : false;
rgr_02@3313
   284
rgr_02@3313
   285
 	pWrapper->Execute(vstk, NULL);
rgr_02@3313
   286
rgr_02@3313
   287
	return 1;
rgr_02@3313
   288
}
rgr_02@3313
   289
rgr_02@3313
   290
static cell_t CS_TerminateRound(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   291
{
rgr_02@3313
   292
	if (g_pSDKTools == NULL)
rgr_02@3313
   293
	{
drifter01620@4237
   294
		return pContext->ThrowNativeError("SDKTools interface not found. TerminateRound native disabled.");
rgr_02@3313
   295
	}
rgr_02@3313
   296
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3313
   297
	{
rgr_02@3313
   298
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3313
   299
		return pContext->ThrowNativeError("SDKTools interface is outdated. TerminateRound native disabled.");
rgr_02@3313
   300
	}
rgr_02@3313
   301
drifter01620@4237
   302
	void *gamerules = g_pSDKTools->GetGameRules();
drifter01620@4237
   303
	if (gamerules == NULL)
drifter01620@4237
   304
	{
drifter01620@4237
   305
		return pContext->ThrowNativeError("GameRules not available. TerminateRound native disabled.");
drifter01620@4237
   306
	}
drifter01620@4237
   307
drifter01620@4237
   308
#if SOURCE_ENGINE != SE_CSGO || !defined(WIN32)
rgr_02@3313
   309
	static ICallWrapper *pWrapper = NULL;
rgr_02@3313
   310
rgr_02@3313
   311
	if (!pWrapper)
rgr_02@3313
   312
	{
rgr_02@3313
   313
		REGISTER_NATIVE_ADDR("TerminateRound",
rgr_02@3313
   314
			PassInfo pass[2]; \
rgr_02@3313
   315
			pass[0].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   316
			pass[0].type = PassType_Basic; \
rgr_02@3313
   317
			pass[0].size = sizeof(float); \
rgr_02@3313
   318
			pass[1].flags = PASSFLAG_BYVAL; \
rgr_02@3313
   319
			pass[1].type = PassType_Basic; \
rgr_02@3313
   320
			pass[1].size = sizeof(int); \
rgr_02@3313
   321
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
rgr_02@3313
   322
	}
rgr_02@3313
   323
rgr_02@3313
   324
	if (params[3] == 1 && g_pTerminateRoundDetoured)
rgr_02@3313
   325
		g_pIgnoreTerminateDetour = true;
rgr_02@3313
   326
rgr_02@3313
   327
	unsigned char vstk[sizeof(void *) + sizeof(float)+ sizeof(int)];
rgr_02@3313
   328
	unsigned char *vptr = vstk;
rgr_02@3313
   329
rgr_02@3313
   330
	*(void **)vptr = gamerules;
rgr_02@3313
   331
	vptr += sizeof(void *);
rgr_02@3313
   332
	*(float *)vptr = sp_ctof(params[1]);
rgr_02@3313
   333
	vptr += sizeof(float);
rgr_02@3313
   334
	*(int*)vptr = params[2];
rgr_02@3313
   335
rgr_02@3313
   336
	pWrapper->Execute(vstk, NULL);
drifter01620@4237
   337
#else
drifter01620@4237
   338
	static void *addr = NULL;
rgr_02@3313
   339
drifter01620@4237
   340
	if(!addr)
drifter01620@4237
   341
	{
drifter01620@4237
   342
		GET_MEMSIG("TerminateRound");
drifter01620@4237
   343
	}
drifter01620@4237
   344
drifter01620@4237
   345
	if (params[3] == 1 && g_pTerminateRoundDetoured)
drifter01620@4237
   346
		g_pIgnoreTerminateDetour = true;
drifter01620@4237
   347
drifter01620@4237
   348
	float delay = sp_ctof(params[1]);
drifter01620@4237
   349
	int reason = params[2];
drifter01620@4237
   350
	signed int unknown = 1;//We might want to find what this is?
drifter01620@4237
   351
	__asm
drifter01620@4237
   352
	{
drifter01620@4237
   353
		push reason
drifter01620@4237
   354
		movss xmm1, delay
drifter01620@4237
   355
		mov edi, unknown
drifter01620@4237
   356
		mov ecx, gamerules
drifter01620@4237
   357
		call addr
drifter01620@4237
   358
	}
drifter01620@4237
   359
drifter01620@4237
   360
#endif
rgr_02@3313
   361
	return 1;
rgr_02@3313
   362
}
rgr_02@3313
   363
kyle@3702
   364
static cell_t CS_WeaponIDToAlias(IPluginContext *pContext, const cell_t *params)
kyle@3702
   365
{
drifter01620@3965
   366
	if (!IsValidWeaponID(params[1]))
drifter01620@3965
   367
		return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
drifter01620@3965
   368
kyle@3702
   369
	char *dest;
kyle@3702
   370
kyle@3702
   371
	pContext->LocalToString(params[2], &dest);
kyle@3702
   372
kyle@3702
   373
	const char *ret = WeaponIDToAlias(params[1]);
kyle@3702
   374
	
kyle@3702
   375
	if (ret == NULL)
kyle@3702
   376
	{
kyle@3702
   377
		return 0;
kyle@3702
   378
	}
kyle@3702
   379
	
kyle@3702
   380
	return strncopy(dest, ret, params[3]);
kyle@3702
   381
}
kyle@3702
   382
rgr_02@3313
   383
static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t *params)
rgr_02@3313
   384
{
rgr_02@3519
   385
	char *weapon;
rgr_02@3519
   386
	char *dest;
rgr_02@3313
   387
rgr_02@3313
   388
	pContext->LocalToString(params[2], &dest);
rgr_02@3313
   389
	pContext->LocalToString(params[1], &weapon);
rgr_02@3313
   390
rgr_02@3519
   391
	const char *ret = GetTranslatedWeaponAlias(weapon);
rgr_02@3313
   392
	strncopy(dest, ret, params[3]);
rgr_02@3313
   393
	
rgr_02@3313
   394
	return 1;
rgr_02@3313
   395
}
skamonkey@3405
   396
rgr_02@3324
   397
static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params)
rgr_02@3324
   398
{
drifter01620@3965
   399
	if (!IsValidWeaponID(params[2]))
drifter01620@3965
   400
		return pContext->ThrowNativeError("Invalid WeaponID passed for this game");
drifter01620@3964
   401
drifter01620@3964
   402
	int id = GetRealWeaponID(params[2]);
drifter01620@3964
   403
rgr_02@3359
   404
	//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
rgr_02@3519
   405
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   406
	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
drifter01620@3964
   407
		return 0;
rgr_02@3519
   408
#else
rgr_02@3519
   409
 	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_SHIELD)
rgr_02@3359
   410
		return 0;
drifter01620@3964
   411
	else if (id == WEAPON_KEVLAR)
rgr_02@3359
   412
		return 650;
drifter01620@3964
   413
	else if (id == WEAPON_ASSAULTSUIT)
rgr_02@3359
   414
		return 1000;
drifter01620@3964
   415
#endif
drifter01620@3964
   416
	else if (id == WEAPON_NIGHTVISION)
rgr_02@3359
   417
		return 1250;
rgr_02@3519
   418
#if SOURCE_ENGINE == SE_CSGO
drifter01620@3964
   419
	else if (id == WEAPON_DEFUSER)
drifter01620@3964
   420
		return 400;
rgr_02@3519
   421
#endif
rgr_02@3359
   422
drifter01620@4016
   423
	void *info = GetWeaponInfo(id);
drifter01620@4016
   424
		
drifter01620@4016
   425
	if (!info)
drifter01620@4016
   426
	{
drifter01620@4016
   427
		return pContext->ThrowNativeError("Failed to get weaponinfo");
drifter01620@4016
   428
	}
drifter01620@4016
   429
drifter01620@4246
   430
	CBaseEntity *pEntity;
drifter01620@4246
   431
	if (!(pEntity = GetCBaseEntity(params[1], true)))
drifter01620@4246
   432
	{
drifter01620@4246
   433
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
drifter01620@4246
   434
	}
drifter01620@4016
   435
#if SOURCE_ENGINE == SE_CSGO
drifter01620@4016
   436
	static ICallWrapper *pWrapper = NULL;
drifter01620@4016
   437
drifter01620@4016
   438
	if (!pWrapper)
drifter01620@4016
   439
	{
drifter01620@4016
   440
		REGISTER_NATIVE_ADDR("GetAttributeInt",
drifter01620@4016
   441
		PassInfo pass[2]; \
drifter01620@4016
   442
		PassInfo ret; \
drifter01620@4016
   443
		pass[0].flags = PASSFLAG_BYVAL; \
drifter01620@4016
   444
		pass[0].type = PassType_Basic; \
drifter01620@4016
   445
		pass[0].size = sizeof(char *); \
drifter01620@4016
   446
		pass[1].flags = PASSFLAG_BYVAL; \
drifter01620@4016
   447
		pass[1].type = PassType_Basic; \
drifter01620@4016
   448
		pass[1].size = sizeof(CEconItemView *); \
drifter01620@4016
   449
		ret.flags = PASSFLAG_BYVAL; \
drifter01620@4016
   450
		ret.type = PassType_Basic; \
drifter01620@4016
   451
		ret.size = sizeof(int); \
drifter01620@4016
   452
		pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &ret, pass, 2))
drifter01620@4016
   453
	}
drifter01620@4016
   454
drifter01620@4246
   455
	// Get a CEconItemView for the m4
drifter01620@4246
   456
	// Found in CCSPlayer::HandleCommand_Buy_Internal
drifter01620@4246
   457
	// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot:
drifter01620@4246
   458
	// v4 = *(int (__cdecl **)(_DWORD, _DWORD, _DWORD))(*(_DWORD *)(a1 + 9492) + 36); // offset 9
drifter01620@4246
   459
	// v6 = v4(a1 + 9492, v5, a3);
drifter01620@4246
   460
	// Windows v5 - CCSPlayer *pEntity a4 -  ItemLoadoutSlot -1 use default loadoutslot:
drifter01620@4246
   461
	// v8 = (*(int (__stdcall **)(_DWORD, int))(*(_DWORD *)(v5 + 9472) + 32))(*(_DWORD *)(v5 + 760), a4); // offset 8
drifter01620@4246
   462
	// The function is CCSPlayerInventory::GetItemInLoadout(int, int)
drifter01620@4246
   463
	// We can pass NULL view to the GetAttribute to use default loadoutslot.
drifter01620@4246
   464
	// We only really care about m4a1/m4a4 as price differs between them
drifter01620@4246
   465
	// thisPtrOffset = 9472/9492
drifter01620@4246
   466
drifter01620@4246
   467
	static ICallWrapper *pGetView = NULL;
drifter01620@4246
   468
	static int thisPtrOffset = -1;
drifter01620@4246
   469
	CEconItemView *view = NULL;
drifter01620@4246
   470
drifter01620@4246
   471
	if(!pGetView)
drifter01620@4246
   472
	{
drifter01620@4246
   473
		int offset = -1;
drifter01620@4246
   474
		int byteOffset = -1;
drifter01620@4246
   475
		void *pHandleCommandBuy = NULL;
drifter01620@4246
   476
		if (!g_pGameConf->GetOffset("GetItemInLoadout", &offset) || offset == -1)
drifter01620@4246
   477
		{
drifter01620@4246
   478
			smutils->LogError(myself, "Failed to get GetItemInLoadout offset. Reverting to NULL ItemView");
drifter01620@4246
   479
		}
drifter01620@4246
   480
		else if (!g_pGameConf->GetOffset("CCSPlayerInventoryOffset", &byteOffset) || byteOffset == -1)
drifter01620@4246
   481
		{
drifter01620@4246
   482
			smutils->LogError(myself, "Failed to get CCSPlayerInventoryOffset offset. Reverting to NULL ItemView");
drifter01620@4246
   483
		}
drifter01620@4246
   484
		else if (!g_pGameConf->GetMemSig("HandleCommand_Buy_Internal", &pHandleCommandBuy) || !pHandleCommandBuy)
drifter01620@4246
   485
		{
drifter01620@4246
   486
			smutils->LogError(myself, "Failed to get HandleCommand_Buy_Internal function. Reverting to NULL ItemView");
drifter01620@4246
   487
		}
drifter01620@4246
   488
		else
drifter01620@4246
   489
		{
drifter01620@4246
   490
			thisPtrOffset = *(int *)((intptr_t)pHandleCommandBuy + byteOffset);
drifter01620@4246
   491
drifter01620@4246
   492
			PassInfo pass[2];
drifter01620@4246
   493
			PassInfo ret;
drifter01620@4246
   494
			pass[0].flags = PASSFLAG_BYVAL;
drifter01620@4246
   495
			pass[0].type  = PassType_Basic;
drifter01620@4246
   496
			pass[0].size  = sizeof(int);
drifter01620@4246
   497
			pass[1].flags = PASSFLAG_BYVAL;
drifter01620@4246
   498
			pass[1].type  = PassType_Basic;
drifter01620@4246
   499
			pass[1].size  = sizeof(int);
drifter01620@4246
   500
drifter01620@4246
   501
			ret.flags = PASSFLAG_BYVAL;
drifter01620@4246
   502
			ret.type = PassType_Basic;
drifter01620@4246
   503
			ret.size = sizeof(void *);
drifter01620@4246
   504
Dr!fter@4247
   505
			pGetView = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
drifter01620@4246
   506
			g_RegNatives.Register(pGetView);
drifter01620@4246
   507
		}
drifter01620@4246
   508
	}
drifter01620@4246
   509
drifter01620@4246
   510
	IPlayerInfo *playerinfo = playerhelpers->GetGamePlayer(params[1])->GetPlayerInfo();
drifter01620@4246
   511
	if(pGetView && thisPtrOffset != -1 && playerinfo)
drifter01620@4246
   512
	{
drifter01620@4246
   513
		//If the gun isnt an M4 we ignore this as M4 is the only one that differs in price based on Loadout item.
drifter01620@4246
   514
		int iLoadoutSlot = -1;
drifter01620@4246
   515
		if(id == WEAPON_M4)
drifter01620@4246
   516
		{
drifter01620@4246
   517
			iLoadoutSlot = 15;
drifter01620@4246
   518
		}
drifter01620@4246
   519
drifter01620@4246
   520
		unsigned char vstk_view[sizeof(void *) + sizeof(int) * 2];
drifter01620@4246
   521
		unsigned char *vptr_view = vstk_view;
drifter01620@4246
   522
drifter01620@4246
   523
		*(void **)vptr_view = (void *)((intptr_t)pEntity + thisPtrOffset);
drifter01620@4246
   524
		vptr_view += sizeof(void *);
drifter01620@4246
   525
		*(int *)vptr_view = playerinfo->GetTeamIndex();
drifter01620@4246
   526
		vptr_view += sizeof(int);
drifter01620@4246
   527
		*(int *)vptr_view = iLoadoutSlot;
drifter01620@4246
   528
drifter01620@4246
   529
		pGetView->Execute(vstk_view, &view);
drifter01620@4246
   530
	}
drifter01620@4246
   531
drifter01620@4016
   532
	unsigned char vstk[sizeof(void *) * 2 + sizeof(char *)];
drifter01620@4016
   533
	unsigned char *vptr = vstk;
drifter01620@4016
   534
drifter01620@4016
   535
	*(void **)vptr = info;
drifter01620@4016
   536
	vptr += sizeof(void *);
drifter01620@4237
   537
	*(const char **)vptr = "in game price";
drifter01620@4246
   538
	vptr += sizeof(const char *);
drifter01620@4246
   539
	*(CEconItemView **)vptr = view;
drifter01620@4016
   540
drifter01620@4016
   541
	int price = 0;
drifter01620@4016
   542
 	pWrapper->Execute(vstk, &price);
drifter01620@4016
   543
#else
rgr_02@3519
   544
	if (g_iPriceOffset == -1)
rgr_02@3324
   545
	{
rgr_02@3519
   546
		if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset))
rgr_02@3324
   547
		{
rgr_02@3519
   548
			g_iPriceOffset = -1;
rgr_02@3324
   549
			return pContext->ThrowNativeError("Failed to get WeaponPrice offset");
rgr_02@3324
   550
		}
rgr_02@3324
   551
	}
rgr_02@3324
   552
drifter01620@4016
   553
	int price = *(int *)((intptr_t)info + g_iPriceOffset);
drifter01620@4016
   554
#endif
drifter01620@4016
   555
rgr_02@3324
   556
	if (params[3] || weaponNameOffset == -1)
rgr_02@3324
   557
		return price;
rgr_02@3324
   558
rgr_02@3324
   559
	const char *weapon_name = (const char *)((intptr_t)info + weaponNameOffset);
rgr_02@3324
   560
rgr_02@3324
   561
	return CallPriceForward(params[1], weapon_name, price);
rgr_02@3324
   562
}
rgr_02@3313
   563
skamonkey@3405
   564
static cell_t CS_GetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   565
{
skamonkey@3405
   566
	static void *addr;
skamonkey@3405
   567
	if (!addr)
skamonkey@3405
   568
	{
skamonkey@3405
   569
		if (!g_pGameConf->GetMemSig("SetClanTag", &addr) || !addr)
skamonkey@3405
   570
		{
skamonkey@3405
   571
			return pContext->ThrowNativeError("Failed to locate function");
skamonkey@3405
   572
		}
skamonkey@3405
   573
	}
skamonkey@3405
   574
skamonkey@3405
   575
	CBaseEntity *pEntity;
skamonkey@3405
   576
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   577
	{
skamonkey@3405
   578
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   579
	}
skamonkey@3405
   580
skamonkey@3405
   581
	static int tagOffsetOffset = -1;
skamonkey@3405
   582
	static int tagOffset;
skamonkey@3405
   583
skamonkey@3405
   584
	if (tagOffsetOffset == -1)
skamonkey@3405
   585
	{
skamonkey@3405
   586
		if (!g_pGameConf->GetOffset("ClanTagOffset", &tagOffsetOffset))
skamonkey@3405
   587
		{
skamonkey@3405
   588
			tagOffsetOffset = -1;
skamonkey@3405
   589
			return pContext->ThrowNativeError("Unable to find ClanTagOffset gamedata");
skamonkey@3405
   590
		}
skamonkey@3405
   591
skamonkey@3405
   592
		tagOffset = *(int *)((intptr_t)addr + tagOffsetOffset);
skamonkey@3405
   593
	}
skamonkey@3405
   594
skamonkey@3405
   595
	size_t len;
skamonkey@3405
   596
skamonkey@3405
   597
	const char *src = (char *)((intptr_t)pEntity + tagOffset);
skamonkey@3405
   598
	pContext->StringToLocalUTF8(params[2], params[3], src, &len);
skamonkey@3405
   599
skamonkey@3405
   600
	return len;
skamonkey@3405
   601
}
skamonkey@3405
   602
skamonkey@3405
   603
static cell_t CS_SetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   604
{
skamonkey@3405
   605
	static ICallWrapper *pWrapper = NULL;
skamonkey@3405
   606
skamonkey@3405
   607
	if (!pWrapper)
skamonkey@3405
   608
	{
skamonkey@3405
   609
		REGISTER_NATIVE_ADDR("SetClanTag",
skamonkey@3405
   610
			PassInfo pass[2]; \
skamonkey@3405
   611
			pass[0].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   612
			pass[0].type  = PassType_Basic; \
skamonkey@3405
   613
			pass[0].size  = sizeof(CBaseEntity *); \
skamonkey@3405
   614
			pass[1].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   615
			pass[1].type  = PassType_Basic; \
skamonkey@3405
   616
			pass[1].size  = sizeof(char *); \
skamonkey@3405
   617
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
skamonkey@3405
   618
	}
skamonkey@3405
   619
skamonkey@3405
   620
	CBaseEntity *pEntity;
skamonkey@3405
   621
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   622
	{
skamonkey@3405
   623
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   624
	}
skamonkey@3405
   625
skamonkey@3405
   626
	char *szNewTag;
skamonkey@3405
   627
	pContext->LocalToString(params[2], &szNewTag);
skamonkey@3405
   628
skamonkey@3405
   629
	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(char *)];
skamonkey@3405
   630
	unsigned char *vptr = vstk;
skamonkey@3405
   631
skamonkey@3405
   632
	*(CBaseEntity **)vptr = pEntity;
skamonkey@3405
   633
	vptr += sizeof(CBaseEntity *);
skamonkey@3405
   634
	*(char **)vptr = szNewTag;
skamonkey@3405
   635
skamonkey@3405
   636
	pWrapper->Execute(vstk, NULL);
skamonkey@3405
   637
skamonkey@3405
   638
	return 1;
rgr_02@3519
   639
}
rgr_02@3519
   640
rgr_02@3519
   641
static cell_t CS_AliasToWeaponID(IPluginContext *pContext, const cell_t *params)
rgr_02@3519
   642
{
rgr_02@3519
   643
	char *weapon;
rgr_02@3519
   644
rgr_02@3519
   645
	pContext->LocalToString(params[1], &weapon);
rgr_02@3519
   646
drifter01620@4016
   647
#if SOURCE_ENGINE == SE_CSGO
drifter01620@4016
   648
	if (strstr(weapon, "usp_silencer") != NULL)
drifter01620@4016
   649
	{
drifter01620@4016
   650
		return SMCSWeapon_HKP2000;
drifter01620@4016
   651
	}
drifter01620@4252
   652
	else if(strstr(weapon, "cz75a") != NULL)
drifter01620@4252
   653
	{
drifter01620@4252
   654
		return SMCSWeapon_P250;
drifter01620@4252
   655
	}
drifter01620@4016
   656
#endif
drifter01620@4016
   657
drifter01620@3965
   658
	int id = GetFakeWeaponID(AliasToWeaponID(weapon));
drifter01620@3965
   659
drifter01620@3965
   660
	if (!IsValidWeaponID(id))
drifter01620@3965
   661
		return SMCSWeapon_NONE;
drifter01620@3965
   662
drifter01620@3965
   663
	return id;
skamonkey@3405
   664
}
skamonkey@3405
   665
rgr_02@3530
   666
static cell_t CS_SetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   667
{
rgr_02@3530
   668
	if (g_pSDKTools == NULL)
rgr_02@3530
   669
	{
rgr_02@3530
   670
		smutils->LogError(myself, "SDKTools interface not found. CS_SetTeamScore native disabled.");
rgr_02@3530
   671
	}
rgr_02@3530
   672
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   673
	{
rgr_02@3530
   674
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   675
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_SetTeamScore native disabled.");
rgr_02@3530
   676
	}
rgr_02@3530
   677
rgr_02@3530
   678
	static void *addr;
rgr_02@3530
   679
	if (!addr)
rgr_02@3530
   680
	{
rgr_02@3530
   681
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   682
		{
rgr_02@3530
   683
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   684
		}
rgr_02@3530
   685
	}
rgr_02@3530
   686
rgr_02@3530
   687
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   688
	static int ctTeamOffset;
rgr_02@3530
   689
rgr_02@3530
   690
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   691
	static int tTeamOffset;
rgr_02@3530
   692
rgr_02@3530
   693
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   694
	{
rgr_02@3530
   695
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   696
		{
rgr_02@3530
   697
			ctTeamOffsetOffset = -1;
rgr_02@3530
   698
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   699
		}
rgr_02@3530
   700
rgr_02@3530
   701
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   702
	}
rgr_02@3530
   703
rgr_02@3530
   704
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   705
	{
rgr_02@3530
   706
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   707
		{
rgr_02@3530
   708
			tTeamOffsetOffset = -1;
rgr_02@3530
   709
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   710
		}
rgr_02@3530
   711
rgr_02@3530
   712
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   713
	}
rgr_02@3530
   714
rgr_02@3530
   715
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   716
	if (gamerules == NULL)
rgr_02@3530
   717
	{
rgr_02@3530
   718
		return pContext->ThrowNativeError("GameRules not available. CS_SetTeamScore native disabled.");
rgr_02@3530
   719
	}
rgr_02@3530
   720
rgr_02@3530
   721
	if (params[1] == 3)
rgr_02@3530
   722
	{
rgr_02@3530
   723
		*(int16_t *)((intptr_t)gamerules+ctTeamOffset) = params[2];
rgr_02@3530
   724
		return 1;
rgr_02@3530
   725
	}
rgr_02@3530
   726
	else if (params[1] == 2)
rgr_02@3530
   727
	{
rgr_02@3530
   728
		*(int16_t *)((intptr_t)gamerules+tTeamOffset) = params[2];
rgr_02@3530
   729
		return 1;
rgr_02@3530
   730
	}
rgr_02@3530
   731
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   732
}
rgr_02@3530
   733
rgr_02@3530
   734
static cell_t CS_GetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   735
{
rgr_02@3530
   736
	if (g_pSDKTools == NULL)
rgr_02@3530
   737
	{
rgr_02@3530
   738
		smutils->LogError(myself, "SDKTools interface not found. CS_GetTeamScore native disabled.");
rgr_02@3530
   739
	}
rgr_02@3530
   740
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   741
	{
rgr_02@3530
   742
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   743
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_GetTeamScore native disabled.");
rgr_02@3530
   744
	}
rgr_02@3530
   745
rgr_02@3530
   746
	static void *addr;
rgr_02@3530
   747
	if (!addr)
rgr_02@3530
   748
	{
rgr_02@3530
   749
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   750
		{
rgr_02@3530
   751
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   752
		}
rgr_02@3530
   753
	}
rgr_02@3530
   754
rgr_02@3530
   755
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   756
	static int ctTeamOffset;
rgr_02@3530
   757
rgr_02@3530
   758
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   759
	static int tTeamOffset;
rgr_02@3530
   760
rgr_02@3530
   761
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   762
	{
rgr_02@3530
   763
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   764
		{
rgr_02@3530
   765
			ctTeamOffsetOffset = -1;
rgr_02@3530
   766
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   767
		}
rgr_02@3530
   768
rgr_02@3530
   769
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   770
	}
rgr_02@3530
   771
rgr_02@3530
   772
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   773
	{
rgr_02@3530
   774
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   775
		{
rgr_02@3530
   776
			tTeamOffsetOffset = -1;
rgr_02@3530
   777
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   778
		}
rgr_02@3530
   779
rgr_02@3530
   780
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   781
	}
rgr_02@3530
   782
rgr_02@3530
   783
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   784
	if (gamerules == NULL)
rgr_02@3530
   785
	{
rgr_02@3530
   786
		return pContext->ThrowNativeError("GameRules not available. CS_GetTeamScore native disabled.");
rgr_02@3530
   787
	}
rgr_02@3530
   788
rgr_02@3530
   789
	if (params[1] == 3)
rgr_02@3530
   790
	{
rgr_02@3530
   791
		return *(int16_t *)((intptr_t)gamerules+ctTeamOffset);
rgr_02@3530
   792
	}
rgr_02@3530
   793
	else if (params[1] == 2)
rgr_02@3530
   794
	{
rgr_02@3530
   795
		return *(int16_t *)((intptr_t)gamerules+tTeamOffset);
rgr_02@3530
   796
	}
rgr_02@3530
   797
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   798
}
rgr_02@3530
   799
drifter01620@3965
   800
static cell_t CS_IsValidWeaponID(IPluginContext *pContext, const cell_t *params)
drifter01620@3965
   801
{
drifter01620@3965
   802
	return IsValidWeaponID(params[1]) ? 1 : 0;
drifter01620@3965
   803
}
drifter01620@3965
   804
skamonkey@3706
   805
template <typename T>
skamonkey@3706
   806
static inline T *GetPlayerVarAddressOrError(const char *pszGamedataName, IPluginContext *pContext, CBaseEntity *pPlayerEntity)
rgr_02@3530
   807
{
skamonkey@3706
   808
	char szBaseName[128];
skamonkey@3706
   809
	g_pSM->Format(szBaseName, sizeof(szBaseName), "%sBase", pszGamedataName);
skamonkey@3706
   810
skamonkey@3706
   811
	const char *pszBaseVar = g_pGameConf->GetKeyValue(szBaseName);
skamonkey@3706
   812
	if (pszBaseVar == NULL)
skamonkey@3706
   813
	{
skamonkey@3706
   814
		pContext->ThrowNativeError("Failed to locate %s key in gamedata", szBaseName);
skamonkey@3706
   815
		return NULL;
skamonkey@3706
   816
	}
skamonkey@3706
   817
skamonkey@3706
   818
	int interimOffset = 0;
skamonkey@3706
   819
	sm_sendprop_info_t info;
skamonkey@3706
   820
	if (gamehelpers->FindSendPropInfo("CCSPlayer", pszBaseVar, &info))
rgr_02@3530
   821
	{
skamonkey@3706
   822
		interimOffset = info.actual_offset;
skamonkey@3706
   823
	}
skamonkey@3706
   824
	else
skamonkey@3706
   825
	{
skamonkey@3706
   826
		datamap_t *pMap = gamehelpers->GetDataMap(pPlayerEntity);
skamonkey@3706
   827
		typedescription_t *td = gamehelpers->FindInDataMap(pMap, pszBaseVar);
skamonkey@3706
   828
		if (td)
rgr_02@3530
   829
		{
skamonkey@3706
   830
#if SOURCE_ENGINE >= SE_LEFT4DEAD
skamonkey@3706
   831
			interimOffset = td->fieldOffset;
skamonkey@3706
   832
#else
skamonkey@3706
   833
			interimOffset = td->fieldOffset[TD_OFFSET_NORMAL];
skamonkey@3706
   834
#endif
rgr_02@3530
   835
		}
rgr_02@3530
   836
	}
rgr_02@3530
   837
skamonkey@3706
   838
	if (interimOffset == 0)
skamonkey@3706
   839
	{
skamonkey@3706
   840
		pContext->ThrowNativeError("Failed to find property \"%s\" on player.", pszBaseVar);
skamonkey@3706
   841
		return NULL;
skamonkey@3706
   842
	}
skamonkey@3706
   843
		
skamonkey@3706
   844
skamonkey@3706
   845
	int tempOffset;
skamonkey@3706
   846
	if (!g_pGameConf->GetOffset(pszGamedataName, &tempOffset))
skamonkey@3706
   847
	{
skamonkey@3706
   848
		pContext->ThrowNativeError("Failed to locate %s offset in gamedata", pszGamedataName);
skamonkey@3706
   849
		return NULL;
skamonkey@3706
   850
	}
skamonkey@3706
   851
skamonkey@3706
   852
	return (T *)((intptr_t)pPlayerEntity + interimOffset + tempOffset);
skamonkey@3706
   853
}
skamonkey@3706
   854
skamonkey@3706
   855
template <typename T>
skamonkey@3706
   856
static inline cell_t GetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   857
{
skamonkey@3706
   858
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   859
	if (!pPlayer)
rgr_02@3530
   860
	{
rgr_02@3530
   861
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3530
   862
	}
rgr_02@3530
   863
skamonkey@3706
   864
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   865
	if (pVar)
skamonkey@3706
   866
	{	
skamonkey@3706
   867
		return (cell_t)*pVar;
rgr_02@3530
   868
	}
rgr_02@3530
   869
skamonkey@3706
   870
	return 0;
skamonkey@3706
   871
}
skamonkey@3706
   872
skamonkey@3706
   873
template <typename T>
skamonkey@3706
   874
static inline cell_t SetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   875
{
skamonkey@3706
   876
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   877
	if (!pPlayer)
skamonkey@3706
   878
	{
skamonkey@3706
   879
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3706
   880
	}
rgr_02@3530
   881
skamonkey@3706
   882
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   883
	if (pVar)
skamonkey@3706
   884
	{
skamonkey@3706
   885
		*pVar = (T)params[2];
skamonkey@3706
   886
	}
skamonkey@3706
   887
skamonkey@3706
   888
	return 0;
skamonkey@3706
   889
}
skamonkey@3706
   890
skamonkey@3706
   891
static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   892
{
skamonkey@3706
   893
	return SetPlayerVar<int>(pContext, params, "MVPs");
rgr_02@3530
   894
}
rgr_02@3530
   895
rgr_02@3530
   896
static cell_t CS_GetMVPCount(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   897
{
skamonkey@3706
   898
	return GetPlayerVar<int>(pContext, params, "MVPs");
skamonkey@3706
   899
}
rgr_02@3530
   900
skamonkey@3706
   901
static cell_t CS_SetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   902
{
skamonkey@3706
   903
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   904
	return SetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   905
#else
skamonkey@3706
   906
	return pContext->ThrowNativeError("SetClientContributionScore is not supported on this game");
skamonkey@3706
   907
#endif
skamonkey@3706
   908
}
rgr_02@3530
   909
skamonkey@3706
   910
static cell_t CS_GetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   911
{
skamonkey@3706
   912
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   913
	return GetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   914
#else
skamonkey@3706
   915
	return pContext->ThrowNativeError("GetClientContributionScore is not supported on this game");
skamonkey@3706
   916
#endif
skamonkey@3706
   917
}
rgr_02@3530
   918
skamonkey@3706
   919
static cell_t CS_SetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   920
{
skamonkey@3706
   921
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   922
	return SetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   923
#else
skamonkey@3706
   924
	return pContext->ThrowNativeError("SetClientAssists is not supported on this game");
skamonkey@3706
   925
#endif
skamonkey@3706
   926
}
rgr_02@3530
   927
skamonkey@3706
   928
static cell_t CS_GetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   929
{
skamonkey@3706
   930
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   931
	return GetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   932
#else
skamonkey@3706
   933
	return pContext->ThrowNativeError("GetClientAssists is not supported on this game");
skamonkey@3706
   934
#endif
rgr_02@3530
   935
}
rgr_02@3530
   936
drifter01620@4121
   937
static cell_t CS_UpdateClientModel(IPluginContext *pContext, const cell_t *params)
drifter01620@4121
   938
{
drifter01620@4121
   939
	static ICallWrapper *pWrapper = NULL;
drifter01620@4121
   940
	if (!pWrapper)
drifter01620@4121
   941
	{
drifter01620@4121
   942
		REGISTER_NATIVE_ADDR("SetModelFromClass", 
drifter01620@4121
   943
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0));
drifter01620@4121
   944
	}
drifter01620@4121
   945
drifter01620@4121
   946
	CBaseEntity *pEntity;
drifter01620@4121
   947
	if (!(pEntity=GetCBaseEntity(params[1], true)))
drifter01620@4121
   948
	{
drifter01620@4121
   949
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
drifter01620@4121
   950
	}
drifter01620@4121
   951
drifter01620@4121
   952
	pWrapper->Execute(&pEntity, NULL);
drifter01620@4121
   953
drifter01620@4121
   954
	return 1;
drifter01620@4121
   955
}
faluco@1441
   956
sp_nativeinfo_t g_CSNatives[] = 
faluco@1441
   957
{
faluco@1441
   958
	{"CS_RespawnPlayer",			CS_RespawnPlayer}, 
rgr_02@3313
   959
	{"CS_SwitchTeam",				CS_SwitchTeam},
rgr_02@3313
   960
	{"CS_DropWeapon",				CS_DropWeapon},
rgr_02@3313
   961
	{"CS_TerminateRound",			CS_TerminateRound},
rgr_02@3313
   962
	{"CS_GetTranslatedWeaponAlias",	CS_GetTranslatedWeaponAlias},
rgr_02@3324
   963
	{"CS_GetWeaponPrice",			CS_GetWeaponPrice},
skamonkey@3405
   964
	{"CS_GetClientClanTag",			CS_GetClientClanTag},
skamonkey@3405
   965
	{"CS_SetClientClanTag",			CS_SetClientClanTag},
rgr_02@3519
   966
	{"CS_AliasToWeaponID",			CS_AliasToWeaponID},
rgr_02@3530
   967
	{"CS_GetTeamScore",				CS_GetTeamScore},
rgr_02@3530
   968
	{"CS_SetTeamScore",				CS_SetTeamScore},
rgr_02@3530
   969
	{"CS_GetMVPCount",				CS_GetMVPCount},
rgr_02@3530
   970
	{"CS_SetMVPCount",				CS_SetMVPCount},
kyle@3702
   971
	{"CS_WeaponIDToAlias",			CS_WeaponIDToAlias},
skamonkey@3706
   972
	{"CS_GetClientContributionScore",	CS_GetClientContributionScore},
skamonkey@3706
   973
	{"CS_SetClientContributionScore",	CS_SetClientContributionScore},
skamonkey@3706
   974
	{"CS_GetClientAssists",			CS_GetClientAssists},
skamonkey@3706
   975
	{"CS_SetClientAssists",			CS_SetClientAssists},
drifter01620@4121
   976
	{"CS_UpdateClientModel",		CS_UpdateClientModel},
drifter01620@3965
   977
	{"CS_IsValidWeaponID",			CS_IsValidWeaponID},
faluco@1441
   978
	{NULL,							NULL}
faluco@1441
   979
};
dvander@1692
   980