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