extensions/cstrike/natives.cpp
author Drifter <drifter01620@gmail.com>
Wed Jul 31 22:08:23 2013 -0400 (2013-07-31)
changeset 3964 8052afb00b69
parent 3710 5559ea22b6b5
child 3965 86dedf4462d8
permissions -rw-r--r--
Fixed incorrect return for some weapons in CS_GetWeaponPrice (bug 5562, r=psychonic).
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
{
drifter01620@3964
   329
	if (params[2] == (int)SMCSWeapon_NONE)
drifter01620@3964
   330
		return pContext->ThrowNativeError("Invalid Weapon ID passed");
drifter01620@3964
   331
drifter01620@3964
   332
	int id = GetRealWeaponID(params[2]);
drifter01620@3964
   333
rgr_02@3359
   334
	//Hard code return values for weapons that dont call GetWeaponPrice and always use default value.
rgr_02@3519
   335
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   336
	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_KNIFE_GG)
drifter01620@3964
   337
		return 0;
rgr_02@3519
   338
#else
rgr_02@3519
   339
 	if (id == WEAPON_C4 || id == WEAPON_KNIFE || id == WEAPON_SHIELD)
rgr_02@3359
   340
		return 0;
drifter01620@3964
   341
	else if (id == WEAPON_KEVLAR)
rgr_02@3359
   342
		return 650;
drifter01620@3964
   343
	else if (id == WEAPON_ASSAULTSUIT)
rgr_02@3359
   344
		return 1000;
drifter01620@3964
   345
#endif
drifter01620@3964
   346
	else if (id == WEAPON_NIGHTVISION)
rgr_02@3359
   347
		return 1250;
rgr_02@3519
   348
#if SOURCE_ENGINE == SE_CSGO
drifter01620@3964
   349
	else if (id == WEAPON_DEFUSER)
drifter01620@3964
   350
		return 400;
rgr_02@3519
   351
#endif
rgr_02@3359
   352
rgr_02@3519
   353
	if (g_iPriceOffset == -1)
rgr_02@3324
   354
	{
rgr_02@3519
   355
		if (!g_pGameConf->GetOffset("WeaponPrice", &g_iPriceOffset))
rgr_02@3324
   356
		{
rgr_02@3519
   357
			g_iPriceOffset = -1;
rgr_02@3324
   358
			return pContext->ThrowNativeError("Failed to get WeaponPrice offset");
rgr_02@3324
   359
		}
rgr_02@3324
   360
	}
rgr_02@3324
   361
rgr_02@3324
   362
	CBaseEntity *pEntity;
rgr_02@3324
   363
	if (!(pEntity = GetCBaseEntity(params[1], true)))
rgr_02@3324
   364
	{
rgr_02@3324
   365
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3324
   366
	}
rgr_02@3324
   367
rgr_02@3560
   368
	void *info = GetWeaponInfo(id);
rgr_02@3324
   369
	if (!info)
rgr_02@3324
   370
		return pContext->ThrowNativeError("Failed to get weaponinfo");
rgr_02@3324
   371
rgr_02@3519
   372
	int price = *(int *)((intptr_t)info + g_iPriceOffset);
rgr_02@3324
   373
rgr_02@3324
   374
	if (params[3] || weaponNameOffset == -1)
rgr_02@3324
   375
		return price;
rgr_02@3324
   376
rgr_02@3324
   377
	const char *weapon_name = (const char *)((intptr_t)info + weaponNameOffset);
rgr_02@3324
   378
rgr_02@3519
   379
#if SOURCE_ENGINE == SE_CSGO
rgr_02@3519
   380
	return CallPriceForwardCSGO(params[1], weapon_name, price);
rgr_02@3519
   381
#else
rgr_02@3324
   382
	return CallPriceForward(params[1], weapon_name, price);
rgr_02@3519
   383
#endif
rgr_02@3324
   384
}
rgr_02@3313
   385
skamonkey@3405
   386
static cell_t CS_GetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   387
{
skamonkey@3405
   388
	static void *addr;
skamonkey@3405
   389
	if (!addr)
skamonkey@3405
   390
	{
skamonkey@3405
   391
		if (!g_pGameConf->GetMemSig("SetClanTag", &addr) || !addr)
skamonkey@3405
   392
		{
skamonkey@3405
   393
			return pContext->ThrowNativeError("Failed to locate function");
skamonkey@3405
   394
		}
skamonkey@3405
   395
	}
skamonkey@3405
   396
skamonkey@3405
   397
	CBaseEntity *pEntity;
skamonkey@3405
   398
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   399
	{
skamonkey@3405
   400
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   401
	}
skamonkey@3405
   402
skamonkey@3405
   403
	static int tagOffsetOffset = -1;
skamonkey@3405
   404
	static int tagOffset;
skamonkey@3405
   405
skamonkey@3405
   406
	if (tagOffsetOffset == -1)
skamonkey@3405
   407
	{
skamonkey@3405
   408
		if (!g_pGameConf->GetOffset("ClanTagOffset", &tagOffsetOffset))
skamonkey@3405
   409
		{
skamonkey@3405
   410
			tagOffsetOffset = -1;
skamonkey@3405
   411
			return pContext->ThrowNativeError("Unable to find ClanTagOffset gamedata");
skamonkey@3405
   412
		}
skamonkey@3405
   413
skamonkey@3405
   414
		tagOffset = *(int *)((intptr_t)addr + tagOffsetOffset);
skamonkey@3405
   415
	}
skamonkey@3405
   416
skamonkey@3405
   417
	size_t len;
skamonkey@3405
   418
skamonkey@3405
   419
	const char *src = (char *)((intptr_t)pEntity + tagOffset);
skamonkey@3405
   420
	pContext->StringToLocalUTF8(params[2], params[3], src, &len);
skamonkey@3405
   421
skamonkey@3405
   422
	return len;
skamonkey@3405
   423
}
skamonkey@3405
   424
skamonkey@3405
   425
static cell_t CS_SetClientClanTag(IPluginContext *pContext, const cell_t *params)
skamonkey@3405
   426
{
skamonkey@3405
   427
	static ICallWrapper *pWrapper = NULL;
skamonkey@3405
   428
skamonkey@3405
   429
	if (!pWrapper)
skamonkey@3405
   430
	{
skamonkey@3405
   431
		REGISTER_NATIVE_ADDR("SetClanTag",
skamonkey@3405
   432
			PassInfo pass[2]; \
skamonkey@3405
   433
			pass[0].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   434
			pass[0].type  = PassType_Basic; \
skamonkey@3405
   435
			pass[0].size  = sizeof(CBaseEntity *); \
skamonkey@3405
   436
			pass[1].flags = PASSFLAG_BYVAL; \
skamonkey@3405
   437
			pass[1].type  = PassType_Basic; \
skamonkey@3405
   438
			pass[1].size  = sizeof(char *); \
skamonkey@3405
   439
			pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2))
skamonkey@3405
   440
	}
skamonkey@3405
   441
skamonkey@3405
   442
	CBaseEntity *pEntity;
skamonkey@3405
   443
	if (!(pEntity = GetCBaseEntity(params[1], true)))
skamonkey@3405
   444
	{
skamonkey@3405
   445
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3405
   446
	}
skamonkey@3405
   447
skamonkey@3405
   448
	char *szNewTag;
skamonkey@3405
   449
	pContext->LocalToString(params[2], &szNewTag);
skamonkey@3405
   450
skamonkey@3405
   451
	unsigned char vstk[sizeof(CBaseEntity *) + sizeof(char *)];
skamonkey@3405
   452
	unsigned char *vptr = vstk;
skamonkey@3405
   453
skamonkey@3405
   454
	*(CBaseEntity **)vptr = pEntity;
skamonkey@3405
   455
	vptr += sizeof(CBaseEntity *);
skamonkey@3405
   456
	*(char **)vptr = szNewTag;
skamonkey@3405
   457
skamonkey@3405
   458
	pWrapper->Execute(vstk, NULL);
skamonkey@3405
   459
skamonkey@3405
   460
	return 1;
rgr_02@3519
   461
}
rgr_02@3519
   462
rgr_02@3519
   463
static cell_t CS_AliasToWeaponID(IPluginContext *pContext, const cell_t *params)
rgr_02@3519
   464
{
rgr_02@3519
   465
	char *weapon;
rgr_02@3519
   466
rgr_02@3519
   467
	pContext->LocalToString(params[1], &weapon);
rgr_02@3519
   468
rgr_02@3519
   469
	return GetFakeWeaponID(AliasToWeaponID(weapon));
skamonkey@3405
   470
}
skamonkey@3405
   471
rgr_02@3530
   472
static cell_t CS_SetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   473
{
rgr_02@3530
   474
	if (g_pSDKTools == NULL)
rgr_02@3530
   475
	{
rgr_02@3530
   476
		smutils->LogError(myself, "SDKTools interface not found. CS_SetTeamScore native disabled.");
rgr_02@3530
   477
	}
rgr_02@3530
   478
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   479
	{
rgr_02@3530
   480
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   481
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_SetTeamScore native disabled.");
rgr_02@3530
   482
	}
rgr_02@3530
   483
rgr_02@3530
   484
	static void *addr;
rgr_02@3530
   485
	if (!addr)
rgr_02@3530
   486
	{
rgr_02@3530
   487
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   488
		{
rgr_02@3530
   489
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   490
		}
rgr_02@3530
   491
	}
rgr_02@3530
   492
rgr_02@3530
   493
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   494
	static int ctTeamOffset;
rgr_02@3530
   495
rgr_02@3530
   496
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   497
	static int tTeamOffset;
rgr_02@3530
   498
rgr_02@3530
   499
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   500
	{
rgr_02@3530
   501
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   502
		{
rgr_02@3530
   503
			ctTeamOffsetOffset = -1;
rgr_02@3530
   504
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   505
		}
rgr_02@3530
   506
rgr_02@3530
   507
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   508
	}
rgr_02@3530
   509
rgr_02@3530
   510
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   511
	{
rgr_02@3530
   512
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   513
		{
rgr_02@3530
   514
			tTeamOffsetOffset = -1;
rgr_02@3530
   515
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   516
		}
rgr_02@3530
   517
rgr_02@3530
   518
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   519
	}
rgr_02@3530
   520
rgr_02@3530
   521
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   522
	if (gamerules == NULL)
rgr_02@3530
   523
	{
rgr_02@3530
   524
		return pContext->ThrowNativeError("GameRules not available. CS_SetTeamScore native disabled.");
rgr_02@3530
   525
	}
rgr_02@3530
   526
rgr_02@3530
   527
	if (params[1] == 3)
rgr_02@3530
   528
	{
rgr_02@3530
   529
		*(int16_t *)((intptr_t)gamerules+ctTeamOffset) = params[2];
rgr_02@3530
   530
		return 1;
rgr_02@3530
   531
	}
rgr_02@3530
   532
	else if (params[1] == 2)
rgr_02@3530
   533
	{
rgr_02@3530
   534
		*(int16_t *)((intptr_t)gamerules+tTeamOffset) = params[2];
rgr_02@3530
   535
		return 1;
rgr_02@3530
   536
	}
rgr_02@3530
   537
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   538
}
rgr_02@3530
   539
rgr_02@3530
   540
static cell_t CS_GetTeamScore(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   541
{
rgr_02@3530
   542
	if (g_pSDKTools == NULL)
rgr_02@3530
   543
	{
rgr_02@3530
   544
		smutils->LogError(myself, "SDKTools interface not found. CS_GetTeamScore native disabled.");
rgr_02@3530
   545
	}
rgr_02@3530
   546
	else if (g_pSDKTools->GetInterfaceVersion() < 2)
rgr_02@3530
   547
	{
rgr_02@3530
   548
		//<psychonic> THIS ISN'T DA LIMBO STICK. LOW IS BAD
rgr_02@3530
   549
		return pContext->ThrowNativeError("SDKTools interface is outdated. CS_GetTeamScore native disabled.");
rgr_02@3530
   550
	}
rgr_02@3530
   551
rgr_02@3530
   552
	static void *addr;
rgr_02@3530
   553
	if (!addr)
rgr_02@3530
   554
	{
rgr_02@3530
   555
		if (!g_pGameConf->GetMemSig("CheckWinLimit", &addr) || !addr)
rgr_02@3530
   556
		{
rgr_02@3530
   557
			return pContext->ThrowNativeError("Failed to locate CheckWinLimit function");
rgr_02@3530
   558
		}
rgr_02@3530
   559
	}
rgr_02@3530
   560
rgr_02@3530
   561
	static int ctTeamOffsetOffset = -1;
rgr_02@3530
   562
	static int ctTeamOffset;
rgr_02@3530
   563
rgr_02@3530
   564
	static int tTeamOffsetOffset = -1;
rgr_02@3530
   565
	static int tTeamOffset;
rgr_02@3530
   566
rgr_02@3530
   567
	if (ctTeamOffsetOffset == -1)
rgr_02@3530
   568
	{
rgr_02@3530
   569
		if (!g_pGameConf->GetOffset("CTTeamScoreOffset", &ctTeamOffsetOffset))
rgr_02@3530
   570
		{
rgr_02@3530
   571
			ctTeamOffsetOffset = -1;
rgr_02@3530
   572
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   573
		}
rgr_02@3530
   574
rgr_02@3530
   575
		ctTeamOffset = *(int *)((intptr_t)addr + ctTeamOffsetOffset);
rgr_02@3530
   576
	}
rgr_02@3530
   577
rgr_02@3530
   578
	if (tTeamOffsetOffset == -1)
rgr_02@3530
   579
	{
rgr_02@3530
   580
		if (!g_pGameConf->GetOffset("TTeamScoreOffset", &tTeamOffsetOffset))
rgr_02@3530
   581
		{
rgr_02@3530
   582
			tTeamOffsetOffset = -1;
rgr_02@3530
   583
			return pContext->ThrowNativeError("Unable to find CTTeamOffset gamedata");
rgr_02@3530
   584
		}
rgr_02@3530
   585
rgr_02@3530
   586
		tTeamOffset = *(int *)((intptr_t)addr + tTeamOffsetOffset);
rgr_02@3530
   587
	}
rgr_02@3530
   588
rgr_02@3530
   589
	void *gamerules = g_pSDKTools->GetGameRules();
rgr_02@3530
   590
	if (gamerules == NULL)
rgr_02@3530
   591
	{
rgr_02@3530
   592
		return pContext->ThrowNativeError("GameRules not available. CS_GetTeamScore native disabled.");
rgr_02@3530
   593
	}
rgr_02@3530
   594
rgr_02@3530
   595
	if (params[1] == 3)
rgr_02@3530
   596
	{
rgr_02@3530
   597
		return *(int16_t *)((intptr_t)gamerules+ctTeamOffset);
rgr_02@3530
   598
	}
rgr_02@3530
   599
	else if (params[1] == 2)
rgr_02@3530
   600
	{
rgr_02@3530
   601
		return *(int16_t *)((intptr_t)gamerules+tTeamOffset);
rgr_02@3530
   602
	}
rgr_02@3530
   603
	return pContext->ThrowNativeError("Invalid team index passed (%i).", params[1]);
rgr_02@3530
   604
}
rgr_02@3530
   605
skamonkey@3706
   606
template <typename T>
skamonkey@3706
   607
static inline T *GetPlayerVarAddressOrError(const char *pszGamedataName, IPluginContext *pContext, CBaseEntity *pPlayerEntity)
rgr_02@3530
   608
{
skamonkey@3706
   609
	char szBaseName[128];
skamonkey@3706
   610
	g_pSM->Format(szBaseName, sizeof(szBaseName), "%sBase", pszGamedataName);
skamonkey@3706
   611
skamonkey@3706
   612
	const char *pszBaseVar = g_pGameConf->GetKeyValue(szBaseName);
skamonkey@3706
   613
	if (pszBaseVar == NULL)
skamonkey@3706
   614
	{
skamonkey@3706
   615
		pContext->ThrowNativeError("Failed to locate %s key in gamedata", szBaseName);
skamonkey@3706
   616
		return NULL;
skamonkey@3706
   617
	}
skamonkey@3706
   618
skamonkey@3706
   619
	int interimOffset = 0;
skamonkey@3706
   620
	sm_sendprop_info_t info;
skamonkey@3706
   621
	if (gamehelpers->FindSendPropInfo("CCSPlayer", pszBaseVar, &info))
rgr_02@3530
   622
	{
skamonkey@3706
   623
		interimOffset = info.actual_offset;
skamonkey@3706
   624
	}
skamonkey@3706
   625
	else
skamonkey@3706
   626
	{
skamonkey@3706
   627
		datamap_t *pMap = gamehelpers->GetDataMap(pPlayerEntity);
skamonkey@3706
   628
		typedescription_t *td = gamehelpers->FindInDataMap(pMap, pszBaseVar);
skamonkey@3706
   629
		if (td)
rgr_02@3530
   630
		{
skamonkey@3706
   631
#if SOURCE_ENGINE >= SE_LEFT4DEAD
skamonkey@3706
   632
			interimOffset = td->fieldOffset;
skamonkey@3706
   633
#else
skamonkey@3706
   634
			interimOffset = td->fieldOffset[TD_OFFSET_NORMAL];
skamonkey@3706
   635
#endif
rgr_02@3530
   636
		}
rgr_02@3530
   637
	}
rgr_02@3530
   638
skamonkey@3706
   639
	if (interimOffset == 0)
skamonkey@3706
   640
	{
skamonkey@3706
   641
		pContext->ThrowNativeError("Failed to find property \"%s\" on player.", pszBaseVar);
skamonkey@3706
   642
		return NULL;
skamonkey@3706
   643
	}
skamonkey@3706
   644
		
skamonkey@3706
   645
skamonkey@3706
   646
	int tempOffset;
skamonkey@3706
   647
	if (!g_pGameConf->GetOffset(pszGamedataName, &tempOffset))
skamonkey@3706
   648
	{
skamonkey@3706
   649
		pContext->ThrowNativeError("Failed to locate %s offset in gamedata", pszGamedataName);
skamonkey@3706
   650
		return NULL;
skamonkey@3706
   651
	}
skamonkey@3706
   652
skamonkey@3706
   653
	return (T *)((intptr_t)pPlayerEntity + interimOffset + tempOffset);
skamonkey@3706
   654
}
skamonkey@3706
   655
skamonkey@3706
   656
template <typename T>
skamonkey@3706
   657
static inline cell_t GetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   658
{
skamonkey@3706
   659
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   660
	if (!pPlayer)
rgr_02@3530
   661
	{
rgr_02@3530
   662
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
rgr_02@3530
   663
	}
rgr_02@3530
   664
skamonkey@3706
   665
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   666
	if (pVar)
skamonkey@3706
   667
	{	
skamonkey@3706
   668
		return (cell_t)*pVar;
rgr_02@3530
   669
	}
rgr_02@3530
   670
skamonkey@3706
   671
	return 0;
skamonkey@3706
   672
}
skamonkey@3706
   673
skamonkey@3706
   674
template <typename T>
skamonkey@3706
   675
static inline cell_t SetPlayerVar(IPluginContext *pContext, const cell_t *params, const char *varName)
skamonkey@3706
   676
{
skamonkey@3706
   677
	CBaseEntity *pPlayer = GetCBaseEntity(params[1], true);
skamonkey@3706
   678
	if (!pPlayer)
skamonkey@3706
   679
	{
skamonkey@3706
   680
		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
skamonkey@3706
   681
	}
rgr_02@3530
   682
skamonkey@3706
   683
	T *pVar = GetPlayerVarAddressOrError<T>(varName, pContext, pPlayer);
skamonkey@3706
   684
	if (pVar)
skamonkey@3706
   685
	{
skamonkey@3706
   686
		*pVar = (T)params[2];
skamonkey@3706
   687
	}
skamonkey@3706
   688
skamonkey@3706
   689
	return 0;
skamonkey@3706
   690
}
skamonkey@3706
   691
skamonkey@3706
   692
static cell_t CS_SetMVPCount(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   693
{
skamonkey@3706
   694
	return SetPlayerVar<int>(pContext, params, "MVPs");
rgr_02@3530
   695
}
rgr_02@3530
   696
rgr_02@3530
   697
static cell_t CS_GetMVPCount(IPluginContext *pContext, const cell_t *params)
rgr_02@3530
   698
{
skamonkey@3706
   699
	return GetPlayerVar<int>(pContext, params, "MVPs");
skamonkey@3706
   700
}
rgr_02@3530
   701
skamonkey@3706
   702
static cell_t CS_SetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   703
{
skamonkey@3706
   704
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   705
	return SetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   706
#else
skamonkey@3706
   707
	return pContext->ThrowNativeError("SetClientContributionScore is not supported on this game");
skamonkey@3706
   708
#endif
skamonkey@3706
   709
}
rgr_02@3530
   710
skamonkey@3706
   711
static cell_t CS_GetClientContributionScore(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   712
{
skamonkey@3706
   713
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   714
	return GetPlayerVar<int>(pContext, params, "CScore");
skamonkey@3706
   715
#else
skamonkey@3706
   716
	return pContext->ThrowNativeError("GetClientContributionScore is not supported on this game");
skamonkey@3706
   717
#endif
skamonkey@3706
   718
}
rgr_02@3530
   719
skamonkey@3706
   720
static cell_t CS_SetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   721
{
skamonkey@3706
   722
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   723
	return SetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   724
#else
skamonkey@3706
   725
	return pContext->ThrowNativeError("SetClientAssists is not supported on this game");
skamonkey@3706
   726
#endif
skamonkey@3706
   727
}
rgr_02@3530
   728
skamonkey@3706
   729
static cell_t CS_GetClientAssists(IPluginContext *pContext, const cell_t *params)
skamonkey@3706
   730
{
skamonkey@3706
   731
#if SOURCE_ENGINE == SE_CSGO
skamonkey@3706
   732
	return GetPlayerVar<int>(pContext, params, "Assists");
skamonkey@3706
   733
#else
skamonkey@3706
   734
	return pContext->ThrowNativeError("GetClientAssists is not supported on this game");
skamonkey@3706
   735
#endif
rgr_02@3530
   736
}
rgr_02@3530
   737
faluco@1441
   738
sp_nativeinfo_t g_CSNatives[] = 
faluco@1441
   739
{
faluco@1441
   740
	{"CS_RespawnPlayer",			CS_RespawnPlayer}, 
rgr_02@3313
   741
	{"CS_SwitchTeam",				CS_SwitchTeam},
rgr_02@3313
   742
	{"CS_DropWeapon",				CS_DropWeapon},
rgr_02@3313
   743
	{"CS_TerminateRound",			CS_TerminateRound},
rgr_02@3313
   744
	{"CS_GetTranslatedWeaponAlias",	CS_GetTranslatedWeaponAlias},
rgr_02@3324
   745
	{"CS_GetWeaponPrice",			CS_GetWeaponPrice},
skamonkey@3405
   746
	{"CS_GetClientClanTag",			CS_GetClientClanTag},
skamonkey@3405
   747
	{"CS_SetClientClanTag",			CS_SetClientClanTag},
rgr_02@3519
   748
	{"CS_AliasToWeaponID",			CS_AliasToWeaponID},
rgr_02@3530
   749
	{"CS_GetTeamScore",				CS_GetTeamScore},
rgr_02@3530
   750
	{"CS_SetTeamScore",				CS_SetTeamScore},
rgr_02@3530
   751
	{"CS_GetMVPCount",				CS_GetMVPCount},
rgr_02@3530
   752
	{"CS_SetMVPCount",				CS_SetMVPCount},
kyle@3702
   753
	{"CS_WeaponIDToAlias",			CS_WeaponIDToAlias},
skamonkey@3706
   754
	{"CS_GetClientContributionScore",	CS_GetClientContributionScore},
skamonkey@3706
   755
	{"CS_SetClientContributionScore",	CS_SetClientContributionScore},
skamonkey@3706
   756
	{"CS_GetClientAssists",			CS_GetClientAssists},
skamonkey@3706
   757
	{"CS_SetClientAssists",			CS_SetClientAssists},
faluco@1441
   758
	{NULL,							NULL}
faluco@1441
   759
};
dvander@1692
   760