extensions/cstrike/natives.cpp
changeset 4246 6307fc19783f
parent 4238 bb02aa3e5b95
child 4247 1e76e5856e9d
     1.1 --- a/extensions/cstrike/natives.cpp	Mon Feb 10 21:04:01 2014 -0500
     1.2 +++ b/extensions/cstrike/natives.cpp	Wed Feb 12 19:03:14 2014 -0500
     1.3 @@ -34,6 +34,7 @@
     1.4  #include "forwards.h"
     1.5  #include "util_cstrike.h"
     1.6  #include <server_class.h>
     1.7 +#include <iplayerinfo.h>
     1.8  
     1.9  int g_iPriceOffset = -1;
    1.10  
    1.11 @@ -426,6 +427,11 @@
    1.12  		return pContext->ThrowNativeError("Failed to get weaponinfo");
    1.13  	}
    1.14  
    1.15 +	CBaseEntity *pEntity;
    1.16 +	if (!(pEntity = GetCBaseEntity(params[1], true)))
    1.17 +	{
    1.18 +		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
    1.19 +	}
    1.20  #if SOURCE_ENGINE == SE_CSGO
    1.21  	static ICallWrapper *pWrapper = NULL;
    1.22  
    1.23 @@ -446,14 +452,91 @@
    1.24  		pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &ret, pass, 2))
    1.25  	}
    1.26  
    1.27 +	// Get a CEconItemView for the m4
    1.28 +	// Found in CCSPlayer::HandleCommand_Buy_Internal
    1.29 +	// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot:
    1.30 +	// v4 = *(int (__cdecl **)(_DWORD, _DWORD, _DWORD))(*(_DWORD *)(a1 + 9492) + 36); // offset 9
    1.31 +	// v6 = v4(a1 + 9492, v5, a3);
    1.32 +	// Windows v5 - CCSPlayer *pEntity a4 -  ItemLoadoutSlot -1 use default loadoutslot:
    1.33 +	// v8 = (*(int (__stdcall **)(_DWORD, int))(*(_DWORD *)(v5 + 9472) + 32))(*(_DWORD *)(v5 + 760), a4); // offset 8
    1.34 +	// The function is CCSPlayerInventory::GetItemInLoadout(int, int)
    1.35 +	// We can pass NULL view to the GetAttribute to use default loadoutslot.
    1.36 +	// We only really care about m4a1/m4a4 as price differs between them
    1.37 +	// thisPtrOffset = 9472/9492
    1.38 +
    1.39 +	static ICallWrapper *pGetView = NULL;
    1.40 +	static int thisPtrOffset = -1;
    1.41 +	CEconItemView *view = NULL;
    1.42 +
    1.43 +	if(!pGetView)
    1.44 +	{
    1.45 +		int offset = -1;
    1.46 +		int byteOffset = -1;
    1.47 +		void *pHandleCommandBuy = NULL;
    1.48 +		if (!g_pGameConf->GetOffset("GetItemInLoadout", &offset) || offset == -1)
    1.49 +		{
    1.50 +			smutils->LogError(myself, "Failed to get GetItemInLoadout offset. Reverting to NULL ItemView");
    1.51 +		}
    1.52 +		else if (!g_pGameConf->GetOffset("CCSPlayerInventoryOffset", &byteOffset) || byteOffset == -1)
    1.53 +		{
    1.54 +			smutils->LogError(myself, "Failed to get CCSPlayerInventoryOffset offset. Reverting to NULL ItemView");
    1.55 +		}
    1.56 +		else if (!g_pGameConf->GetMemSig("HandleCommand_Buy_Internal", &pHandleCommandBuy) || !pHandleCommandBuy)
    1.57 +		{
    1.58 +			smutils->LogError(myself, "Failed to get HandleCommand_Buy_Internal function. Reverting to NULL ItemView");
    1.59 +		}
    1.60 +		else
    1.61 +		{
    1.62 +			thisPtrOffset = *(int *)((intptr_t)pHandleCommandBuy + byteOffset);
    1.63 +
    1.64 +			PassInfo pass[2];
    1.65 +			PassInfo ret;
    1.66 +			pass[0].flags = PASSFLAG_BYVAL;
    1.67 +			pass[0].type  = PassType_Basic;
    1.68 +			pass[0].size  = sizeof(int);
    1.69 +			pass[1].flags = PASSFLAG_BYVAL;
    1.70 +			pass[1].type  = PassType_Basic;
    1.71 +			pass[1].size  = sizeof(int);
    1.72 +
    1.73 +			ret.flags = PASSFLAG_BYVAL;
    1.74 +			ret.type = PassType_Basic;
    1.75 +			ret.size = sizeof(void *);
    1.76 +
    1.77 +			g_RegNatives.Register(pGetView);
    1.78 +			pGetView = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
    1.79 +		}
    1.80 +	}
    1.81 +
    1.82 +	IPlayerInfo *playerinfo = playerhelpers->GetGamePlayer(params[1])->GetPlayerInfo();
    1.83 +	if(pGetView && thisPtrOffset != -1 && playerinfo)
    1.84 +	{
    1.85 +		//If the gun isnt an M4 we ignore this as M4 is the only one that differs in price based on Loadout item.
    1.86 +		int iLoadoutSlot = -1;
    1.87 +		if(id == WEAPON_M4)
    1.88 +		{
    1.89 +			iLoadoutSlot = 15;
    1.90 +		}
    1.91 +
    1.92 +		unsigned char vstk_view[sizeof(void *) + sizeof(int) * 2];
    1.93 +		unsigned char *vptr_view = vstk_view;
    1.94 +
    1.95 +		*(void **)vptr_view = (void *)((intptr_t)pEntity + thisPtrOffset);
    1.96 +		vptr_view += sizeof(void *);
    1.97 +		*(int *)vptr_view = playerinfo->GetTeamIndex();
    1.98 +		vptr_view += sizeof(int);
    1.99 +		*(int *)vptr_view = iLoadoutSlot;
   1.100 +
   1.101 +		pGetView->Execute(vstk_view, &view);
   1.102 +	}
   1.103 +
   1.104  	unsigned char vstk[sizeof(void *) * 2 + sizeof(char *)];
   1.105  	unsigned char *vptr = vstk;
   1.106  
   1.107  	*(void **)vptr = info;
   1.108  	vptr += sizeof(void *);
   1.109  	*(const char **)vptr = "in game price";
   1.110 -	vptr += sizeof(const char **);
   1.111 -	*(CEconItemView **)vptr = NULL;
   1.112 +	vptr += sizeof(const char *);
   1.113 +	*(CEconItemView **)vptr = view;
   1.114  
   1.115  	int price = 0;
   1.116   	pWrapper->Execute(vstk, &price);
   1.117 @@ -470,12 +553,6 @@
   1.118  	int price = *(int *)((intptr_t)info + g_iPriceOffset);
   1.119  #endif
   1.120  
   1.121 -	CBaseEntity *pEntity;
   1.122 -	if (!(pEntity = GetCBaseEntity(params[1], true)))
   1.123 -	{
   1.124 -		return pContext->ThrowNativeError("Client index %d is not valid", params[1]);
   1.125 -	}
   1.126 -
   1.127  	if (params[3] || weaponNameOffset == -1)
   1.128  		return price;
   1.129