584 lines
16 KiB
C++
584 lines
16 KiB
C++
/**
|
|
* vim: set ts=4 :
|
|
* =============================================================================
|
|
* SourceMod Counter-Strike:Source Extension
|
|
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
* =============================================================================
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
* or <http://www.sourcemod.net/license.php>.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#include "extension.h"
|
|
#include "util_cstrike.h"
|
|
#include "RegNatives.h"
|
|
#include <iplayerinfo.h>
|
|
#if SOURCE_ENGINE == SE_CSGO
|
|
#include "itemdef-hash.h"
|
|
|
|
ClassnameMap g_mapClassToDefIdx;
|
|
ItemIndexMap g_mapDefIdxToClass;
|
|
WeaponIDMap g_mapWeaponIDToDefIdx;
|
|
#endif
|
|
|
|
#define REGISTER_ADDR(name, defaultret, code) \
|
|
void *addr; \
|
|
if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
|
|
{ \
|
|
g_pSM->LogError(myself, "Failed to lookup %s signature.", name); \
|
|
return defaultret; \
|
|
} \
|
|
code; \
|
|
g_RegNatives.Register(pWrapper);
|
|
|
|
#define GET_MEMSIG(name, defaultret) \
|
|
if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \
|
|
{ \
|
|
g_pSM->LogError(myself, "Failed to lookup %s signature.", name); \
|
|
return defaultret;\
|
|
}
|
|
|
|
#if SOURCE_ENGINE == SE_CSGO
|
|
|
|
// Get a CEconItemView for the m4
|
|
// Found in CCSPlayer::HandleCommand_Buy_Internal
|
|
// Linux a1 - CCSPlayer *pEntity, v5 - Player Team, a3 - ItemLoadoutSlot -1 use default loadoutslot:
|
|
// v4 = *(int (__cdecl **)(_DWORD, _DWORD, _DWORD))(*(_DWORD *)(a1 + 9492) + 36); // offset 9
|
|
// v6 = v4(a1 + 9492, v5, a3);
|
|
// Windows v5 - CCSPlayer *pEntity a4 - ItemLoadoutSlot -1 use default loadoutslot:
|
|
// v8 = (*(int (__stdcall **)(_DWORD, int))(*(_DWORD *)(v5 + 9472) + 32))(*(_DWORD *)(v5 + 760), a4); // offset 8
|
|
// The function is CCSPlayerInventory::GetItemInLoadout(int, int)
|
|
// We can pass NULL view to the GetAttribute to use default loadoutslot.
|
|
// We only really care about m4a1/m4a4 as price differs between them
|
|
// thisPtrOffset = 9472/9492
|
|
|
|
CEconItemView *GetEconItemView(CBaseEntity *pEntity, int iSlot)
|
|
{
|
|
if (!pEntity)
|
|
return NULL;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
static int thisPtrOffset = -1;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
int offset = -1;
|
|
int byteOffset = -1;
|
|
void *pHandleCommandBuy = NULL;
|
|
if (!g_pGameConf->GetOffset("GetItemInLoadout", &offset) || offset == -1)
|
|
{
|
|
smutils->LogError(myself, "Failed to get GetItemInLoadout offset.");
|
|
return NULL;
|
|
}
|
|
else if (!g_pGameConf->GetOffset("CCSPlayerInventoryOffset", &byteOffset) || byteOffset == -1)
|
|
{
|
|
smutils->LogError(myself, "Failed to get CCSPlayerInventoryOffset offset.");
|
|
return NULL;
|
|
}
|
|
else if (!g_pGameConf->GetMemSig("HandleCommand_Buy_Internal", &pHandleCommandBuy) || !pHandleCommandBuy)
|
|
{
|
|
smutils->LogError(myself, "Failed to get HandleCommand_Buy_Internal function.");
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
thisPtrOffset = *(int *)((intptr_t)pHandleCommandBuy + byteOffset);
|
|
|
|
PassInfo pass[2];
|
|
PassInfo ret;
|
|
pass[0].flags = PASSFLAG_BYVAL;
|
|
pass[0].type = PassType_Basic;
|
|
pass[0].size = sizeof(int);
|
|
pass[1].flags = PASSFLAG_BYVAL;
|
|
pass[1].type = PassType_Basic;
|
|
pass[1].size = sizeof(int);
|
|
|
|
ret.flags = PASSFLAG_BYVAL;
|
|
ret.type = PassType_Basic;
|
|
ret.size = sizeof(CEconItemView *);
|
|
|
|
pWrapper = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 2);
|
|
g_RegNatives.Register(pWrapper);
|
|
}
|
|
}
|
|
|
|
int client = gamehelpers->EntityToBCompatRef(pEntity);
|
|
|
|
IPlayerInfo *playerinfo = playerhelpers->GetGamePlayer(client)->GetPlayerInfo();
|
|
|
|
if (!playerinfo)
|
|
return NULL;
|
|
|
|
int team = playerinfo->GetTeamIndex();
|
|
|
|
if (team != 2 && team != 3)
|
|
return NULL;
|
|
|
|
CEconItemView *ret;
|
|
unsigned char vstk[sizeof(void *) + sizeof(int) * 2];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(void **)vptr = (void *)((intptr_t)pEntity + thisPtrOffset);
|
|
vptr += sizeof(void *);
|
|
*(int *)vptr = team;
|
|
vptr += sizeof(int);
|
|
*(int *)vptr = iSlot;
|
|
|
|
pWrapper->Execute(vstk, &ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
CCSWeaponData *GetCCSWeaponData(CEconItemView *view)
|
|
{
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("GetCCSWeaponData", NULL,
|
|
PassInfo retpass; \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(CCSWeaponData *); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, &retpass, NULL, 0))
|
|
}
|
|
|
|
unsigned char vstk[sizeof(CEconItemView *)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(CEconItemView **)vptr = view;
|
|
|
|
CCSWeaponData *pWpnData = NULL;
|
|
|
|
pWrapper->Execute(vstk, &pWpnData);
|
|
|
|
return pWpnData;
|
|
}
|
|
|
|
CEconItemSchema *GetItemSchema()
|
|
{
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("GetItemSchema", NULL,
|
|
PassInfo retpass; \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(void *); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, NULL, 0))
|
|
}
|
|
|
|
void *pSchema = NULL;
|
|
pWrapper->Execute(NULL, &pSchema);
|
|
|
|
//In windows this is actually ItemSystem() + 4 is ItemSchema
|
|
#ifdef WIN32
|
|
return (CEconItemSchema *)((intptr_t)pSchema + 4);
|
|
#else
|
|
return (CEconItemSchema *)pSchema;
|
|
#endif
|
|
}
|
|
|
|
CEconItemDefinition *GetItemDefintionByName(const char *classname)
|
|
{
|
|
CEconItemSchema *pSchema = GetItemSchema();
|
|
|
|
if (!pSchema)
|
|
return NULL;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
int offset = -1;
|
|
|
|
if (!g_pGameConf->GetOffset("GetItemDefintionByName", &offset) || offset == -1)
|
|
{
|
|
smutils->LogError(myself, "Failed to get GetItemDefintionByName offset.");
|
|
return NULL;
|
|
}
|
|
|
|
PassInfo pass[1];
|
|
PassInfo ret;
|
|
pass[0].flags = PASSFLAG_BYVAL;
|
|
pass[0].type = PassType_Basic;
|
|
pass[0].size = sizeof(const char *);
|
|
|
|
ret.flags = PASSFLAG_BYVAL;
|
|
ret.type = PassType_Basic;
|
|
ret.size = sizeof(CEconItemDefinition *);
|
|
|
|
pWrapper = g_pBinTools->CreateVCall(offset, 0, 0, &ret, pass, 1);
|
|
|
|
g_RegNatives.Register(pWrapper);
|
|
}
|
|
|
|
unsigned char vstk[sizeof(void *) + sizeof(const char *)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(void **)vptr = pSchema;
|
|
vptr += sizeof(void *);
|
|
*(const char **)vptr = classname;
|
|
|
|
CEconItemDefinition *pItemDef = NULL;
|
|
pWrapper->Execute(vstk, &pItemDef);
|
|
|
|
return pItemDef;
|
|
}
|
|
|
|
void CreateHashMaps()
|
|
{
|
|
CEconItemSchema *pSchema = GetItemSchema();
|
|
|
|
if (!pSchema)
|
|
return;
|
|
|
|
static const char *pPriceKey = NULL;
|
|
|
|
if (!pPriceKey)
|
|
{
|
|
pPriceKey = g_pGameConf->GetKeyValue("PriceKey");
|
|
if (!pPriceKey)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
static int iHashMapOffset = -1;
|
|
|
|
if (iHashMapOffset == -1)
|
|
{
|
|
if (!g_pGameConf->GetOffset("ItemDefHashOffset", &iHashMapOffset) || iHashMapOffset == -1)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
g_mapClassToDefIdx.init();
|
|
g_mapDefIdxToClass.init();
|
|
g_mapWeaponIDToDefIdx.init();
|
|
|
|
CHashItemDef *map = (CHashItemDef *)((intptr_t)pSchema + iHashMapOffset);
|
|
|
|
for (int i = 0; i < map->currentElements; i++)
|
|
{
|
|
HashItemDef_Node node = map->pMem[i];
|
|
|
|
if (!node.pDef || !node.pDef->m_pKv)
|
|
continue;
|
|
|
|
KeyValues *pClassname = node.pDef->m_pKv->FindKey("name", false);
|
|
KeyValues *pAttributes = node.pDef->m_pKv->FindKey("attributes", false);
|
|
|
|
if (pClassname && pAttributes)
|
|
{
|
|
KeyValues *pPrice = pAttributes->FindKey(pPriceKey, false);
|
|
|
|
if (pPrice)
|
|
{
|
|
const char *classname = pClassname->GetString();
|
|
|
|
unsigned int price = pPrice->GetInt();
|
|
uint16_t iItemDefIdx = node.pDef->m_iDefinitionIndex;
|
|
SMCSWeapon iWeaponID = GetWeaponIdFromDefIdx(iItemDefIdx);
|
|
int iLoadoutslot = node.pDef->GetDefaultLoadoutSlot();
|
|
|
|
ClassnameMap::Insert i = g_mapClassToDefIdx.findForAdd(classname);
|
|
g_mapClassToDefIdx.add(i, ke::AString(classname), ItemDefHashValue(iLoadoutslot, price, iWeaponID, iItemDefIdx, classname));
|
|
|
|
ItemIndexMap::Insert x = g_mapDefIdxToClass.findForAdd(iItemDefIdx);
|
|
g_mapDefIdxToClass.add(x, iItemDefIdx, ItemDefHashValue(iLoadoutslot, price, iWeaponID, iItemDefIdx, classname));
|
|
|
|
WeaponIDMap::Insert t = g_mapWeaponIDToDefIdx.findForAdd(iWeaponID);
|
|
g_mapWeaponIDToDefIdx.add(t, iWeaponID, ItemDefHashValue(iLoadoutslot, price, iWeaponID, iItemDefIdx, classname));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ClearHashMaps()
|
|
{
|
|
g_mapClassToDefIdx.clear();
|
|
g_mapDefIdxToClass.clear();
|
|
g_mapWeaponIDToDefIdx.clear();
|
|
}
|
|
|
|
SMCSWeapon GetWeaponIdFromDefIdx(uint16_t iDefIdx)
|
|
{
|
|
//DEAR GOD THIS IS HIDEOUS
|
|
//None in the middle are weapons that dont exist.
|
|
//If they are added and use the same idx they should be changed to their respective ones
|
|
static SMCSWeapon weaponIDMap[SMCSWeapon_MAXWEAPONIDS] =
|
|
{
|
|
SMCSWeapon_NONE, SMCSWeapon_DEAGLE, SMCSWeapon_ELITE, SMCSWeapon_FIVESEVEN,
|
|
SMCSWeapon_GLOCK, SMCSWeapon_NONE, SMCSWeapon_NONE, SMCSWeapon_AK47,
|
|
SMCSWeapon_AUG, SMCSWeapon_AWP, SMCSWeapon_FAMAS, SMCSWeapon_G3SG1,
|
|
SMCSWeapon_NONE, SMCSWeapon_GALILAR, SMCSWeapon_M249, SMCSWeapon_NONE,
|
|
SMCSWeapon_M4A1, SMCSWeapon_MAC10, SMCSWeapon_NONE, SMCSWeapon_P90,
|
|
SMCSWeapon_NONE, SMCSWeapon_NONE, SMCSWeapon_NONE, SMCSWeapon_NONE,
|
|
SMCSWeapon_UMP45, SMCSWeapon_XM1014, SMCSWeapon_BIZON, SMCSWeapon_MAG7,
|
|
SMCSWeapon_NEGEV, SMCSWeapon_SAWEDOFF, SMCSWeapon_TEC9, SMCSWeapon_TASER,
|
|
SMCSWeapon_HKP2000, SMCSWeapon_MP7, SMCSWeapon_MP9, SMCSWeapon_NOVA,
|
|
SMCSWeapon_P250, SMCSWeapon_NONE, SMCSWeapon_SCAR20, SMCSWeapon_SG556,
|
|
SMCSWeapon_SSG08, SMCSWeapon_KNIFE_GG, SMCSWeapon_KNIFE, SMCSWeapon_FLASHBANG,
|
|
SMCSWeapon_HEGRENADE, SMCSWeapon_SMOKEGRENADE, SMCSWeapon_MOLOTOV, SMCSWeapon_DECOY,
|
|
SMCSWeapon_INCGRENADE, SMCSWeapon_C4, SMCSWeapon_KEVLAR, SMCSWeapon_ASSAULTSUIT,
|
|
SMCSWeapon_HEAVYASSAULTSUIT, SMCSWeapon_NONE, SMCSWeapon_NIGHTVISION, SMCSWeapon_DEFUSER
|
|
};
|
|
|
|
if (iDefIdx >= SMCSWeapon_MAXWEAPONIDS)
|
|
return (SMCSWeapon)iDefIdx;
|
|
else
|
|
return weaponIDMap[iDefIdx];
|
|
}
|
|
|
|
ItemDefHashValue *GetHashValueFromWeapon(const char *szWeapon)
|
|
{
|
|
char tempWeapon[MAX_WEAPON_NAME_LENGTH];
|
|
|
|
Q_strncpy(tempWeapon, szWeapon, sizeof(tempWeapon));
|
|
Q_strlower(tempWeapon);
|
|
|
|
if (strstr(tempWeapon, "weapon_") == NULL && strstr(tempWeapon, "item_") == NULL)
|
|
{
|
|
static const char *szClassPrefixs[] = { "weapon_", "item_" };
|
|
|
|
for (unsigned int i = 0; i < SM_ARRAYSIZE(szClassPrefixs); i++)
|
|
{
|
|
char classname[MAX_WEAPON_NAME_LENGTH];
|
|
Q_snprintf(classname, sizeof(classname), "%s%s", szClassPrefixs[i], tempWeapon);
|
|
|
|
ClassnameMap::Result res = g_mapClassToDefIdx.find(classname);
|
|
|
|
if (res.found())
|
|
return &res->value;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ClassnameMap::Result res = g_mapClassToDefIdx.find(tempWeapon);
|
|
|
|
if (res.found())
|
|
return &res->value;
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
#if SOURCE_ENGINE != SE_CSGO
|
|
void *GetWeaponInfo(int weaponID)
|
|
{
|
|
void *info;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("GetWeaponInfo", NULL,
|
|
PassInfo pass[1]; \
|
|
PassInfo retpass; \
|
|
pass[0].flags = PASSFLAG_BYVAL; \
|
|
pass[0].type = PassType_Basic; \
|
|
pass[0].size = sizeof(int); \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(void *); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, pass, 1))
|
|
}
|
|
|
|
unsigned char vstk[sizeof(int)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(int *)vptr = weaponID;
|
|
|
|
pWrapper->Execute(vstk, &info);
|
|
|
|
return info;
|
|
}
|
|
#endif
|
|
|
|
const char *GetWeaponNameFromClassname(const char *weapon)
|
|
{
|
|
char *szTemp = strstr((char *)weapon, "_");
|
|
|
|
if (!szTemp)
|
|
{
|
|
return weapon;
|
|
}
|
|
else
|
|
{
|
|
return (const char *)((intptr_t)szTemp + 1);
|
|
}
|
|
}
|
|
|
|
const char *GetTranslatedWeaponAlias(const char *weapon)
|
|
{
|
|
#if SOURCE_ENGINE != SE_CSGO
|
|
const char *alias = NULL;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("GetTranslatedWeaponAlias", weapon,
|
|
PassInfo pass[1]; \
|
|
PassInfo retpass; \
|
|
pass[0].flags = PASSFLAG_BYVAL; \
|
|
pass[0].type = PassType_Basic; \
|
|
pass[0].size = sizeof(const char *); \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(const char *); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, pass, 1))
|
|
}
|
|
|
|
unsigned char vstk[sizeof(const char *)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(const char **)vptr = GetWeaponNameFromClassname(weapon);
|
|
|
|
pWrapper->Execute(vstk, &alias);
|
|
return alias;
|
|
#else //this should work for both games maybe replace both?
|
|
static const char *szAliases[] =
|
|
{
|
|
"cv47", "ak47",
|
|
"magnum", "awp",
|
|
"d3au1", "g3sg1",
|
|
"clarion", "famas",
|
|
"bullpup", "aug",
|
|
"9x19mm", "glock",
|
|
"nighthawk", "deagle",
|
|
"elites", "elite",
|
|
"fn57", "fiveseven",
|
|
"autoshotgun", "xm1014",
|
|
"c90", "p90",
|
|
"vest", "kevlar",
|
|
"vesthelm", "assaultsuit",
|
|
"nvgs", "nightvision"
|
|
};
|
|
|
|
for (size_t i = 0; i < SM_ARRAYSIZE(szAliases) / 2; i++)
|
|
{
|
|
if (Q_stristr(GetWeaponNameFromClassname(weapon), szAliases[i * 2]) != 0)
|
|
return szAliases[i * 2 + 1];
|
|
}
|
|
|
|
return GetWeaponNameFromClassname(weapon);
|
|
#endif
|
|
}
|
|
|
|
int AliasToWeaponID(const char *weapon)
|
|
{
|
|
#if SOURCE_ENGINE != SE_CSGO
|
|
int weaponID = 0;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("AliasToWeaponID", 0,
|
|
PassInfo pass[1]; \
|
|
PassInfo retpass; \
|
|
pass[0].flags = PASSFLAG_BYVAL; \
|
|
pass[0].type = PassType_Basic; \
|
|
pass[0].size = sizeof(const char *); \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(int); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, pass, 1))
|
|
}
|
|
|
|
unsigned char vstk[sizeof(const char *)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(const char **)vptr = GetWeaponNameFromClassname(weapon);
|
|
|
|
pWrapper->Execute(vstk, &weaponID);
|
|
|
|
return weaponID;
|
|
#else
|
|
ItemDefHashValue *pHashValue = GetHashValueFromWeapon(weapon);
|
|
|
|
if (pHashValue)
|
|
return pHashValue->m_iWeaponID;
|
|
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
const char *WeaponIDToAlias(int weaponID)
|
|
{
|
|
#if SOURCE_ENGINE != SE_CSGO
|
|
const char *alias = NULL;
|
|
|
|
static ICallWrapper *pWrapper = NULL;
|
|
|
|
if (!pWrapper)
|
|
{
|
|
REGISTER_ADDR("WeaponIDToAlias", 0,
|
|
PassInfo pass[1]; \
|
|
PassInfo retpass; \
|
|
pass[0].flags = PASSFLAG_BYVAL; \
|
|
pass[0].type = PassType_Basic; \
|
|
pass[0].size = sizeof(int); \
|
|
retpass.flags = PASSFLAG_BYVAL; \
|
|
retpass.type = PassType_Basic; \
|
|
retpass.size = sizeof(const char *); \
|
|
pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass, pass, 1))
|
|
}
|
|
|
|
unsigned char vstk[sizeof(int)];
|
|
unsigned char *vptr = vstk;
|
|
|
|
*(int *)vptr = weaponID;
|
|
|
|
pWrapper->Execute(vstk, &alias);
|
|
|
|
return alias;
|
|
#else
|
|
WeaponIDMap::Result res = g_mapWeaponIDToDefIdx.find((SMCSWeapon)weaponID);
|
|
|
|
if (res.found())
|
|
return res->value.m_szItemName;
|
|
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
bool IsValidWeaponID(int id)
|
|
{
|
|
if (id <= (int)SMCSWeapon_NONE)
|
|
return false;
|
|
#if SOURCE_ENGINE == SE_CSGO
|
|
WeaponIDMap::Result res = g_mapWeaponIDToDefIdx.find((SMCSWeapon)id);
|
|
if (!res.found())
|
|
return false;
|
|
#else
|
|
else if (id > SMCSWeapon_NIGHTVISION || !GetWeaponInfo(id))
|
|
return false;
|
|
#endif
|
|
return true;
|
|
}
|