Merge pull request #68 from Arkshine/feature-improve-client-buy

Improve client buy forward
This commit is contained in:
Vincent Herbet 2014-07-18 10:00:10 +02:00
commit 7d69a78d06
11 changed files with 318 additions and 109 deletions

View File

@ -3,6 +3,10 @@ import os.path
binary = AMXX.MetaModule(builder, 'cstrike')
binary.compiler.defines += [
'HAVE_STDINT_H',
]
binary.sources = [
'sdk/amxxmodule.cpp',
'amxx_api.cpp',

View File

@ -64,6 +64,7 @@
#define OFFSET_INTERNALMODEL 126 + EXTRAOFFSET
#define OFFSET_NVGOGGLES 129 + EXTRAOFFSET
#define OFFSET_DEFUSE_PLANT 193 + EXTRAOFFSET
#define OFFSET_MENU 205 + EXTRAOFFSET
#define OFFSET_VIP 209 + EXTRAOFFSET
#define OFFSET_TK 216 + EXTRAOFFSET // 040926
#define OFFSET_HOSTAGEKILLS 217 + EXTRAOFFSET
@ -162,19 +163,19 @@
* CS_OnBuy forward
*/
#if defined(__linux__)
#define CS_IDENT_CANBUYTHIS "_Z10CanBuyThisP11CBasePlayeri"
#define CS_IDENT_BUYITEM "_Z7BuyItemP11CBasePlayeri"
#define CS_IDENT_BUYGUNAMMO "_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
#define CS_IDENT_GIVENSHIELD "_ZN11CBasePlayer10GiveShieldEb"
#define CS_IDENT_GIVENAMEDITEM "_ZN11CBasePlayer13GiveNamedItemEPKc"
#define CS_IDENT_ADDACCOUNT "_ZN11CBasePlayer10AddAccountEib"
#define CS_IDENT_HIDDEN_STATE false
#elif defined(__APPLE__)
#define CS_IDENT_CANBUYTHIS "_Z10CanBuyThisP11CBasePlayeri"
#define CS_IDENT_BUYITEM "_Z7BuyItemP11CBasePlayeri"
#define CS_IDENT_BUYGUNAMMO "_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb"
#define CS_IDENT_GIVENSHIELD "_ZN11CBasePlayer10GiveShieldEb"
#define CS_IDENT_GIVENAMEDITEM "_ZN11CBasePlayer13GiveNamedItemEPKc"
#define CS_IDENT_ADDACCOUNT "_ZN11CBasePlayer10AddAccountEib"
#define CS_IDENT_HIDDEN_STATE true
#elif defined(WIN32)
#define CS_IDENT_CANBUYTHIS "\\x53\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x56\\x8B\\x2A\\x2A\\x2A\\x57"
#define CS_IDENT_BUYITEM "\\x53\\x56\\x8B\\x2A\\x2A\\x2A\\xBB\\x2A\\x2A\\x2A\\x2A\\x57\\x53"
#define CS_IDENT_BUYGUNAMMO "\\x56\\x57\\x8B\\x2A\\x2A\\x2A\\x6A\\x2A\\x8B\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x84\\x2A\\x0F"
#define CS_IDENT_GIVENSHIELD "\\x56\\x8B\\x2A\\x57\\x33\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\xB0"
#define CS_IDENT_GIVENAMEDITEM "\\x8B\\x2A\\x2A\\x2A\\x56\\x57\\x8B\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x2B"
#define CS_IDENT_ADDACCOUNT "\\x8B\\x2A\\x2A\\x2A\\x56\\x8B\\x2A\\x8B\\x2A\\x2A\\x2A\\x2A\\x2A\\x03"
#define CS_IDENT_HIDDEN_STATE false
#endif
@ -347,4 +348,24 @@ enum
CS_SET_AUGSG552_ZOOM,
};
typedef enum
{
Menu_OFF,
Menu_ChooseTeam,
Menu_IGChooseTeam,
Menu_ChooseAppearance,
Menu_Buy,
Menu_BuyPistol,
Menu_BuyRifle,
Menu_BuyMachineGun,
Menu_BuyShotgun,
Menu_BuySubMachineGun,
Menu_BuyItem,
Menu_Radio1,
Menu_Radio2,
Menu_Radio3,
Menu_ClientBuy
} Menu;
#endif // CSTRIKE_DATA_H

View File

@ -33,21 +33,27 @@
#include "CstrikeDatas.h"
#include "CstrikeUtils.h"
#include "CDetour/detours.h"
#include <sm_stringhashmap.h>
using namespace SourceMod; // hashmap
void CtrlDetours_ClientCommand(bool set);
void CtrlDetours_BuyCommands(bool set);
int g_CSCliCmdFwd = -1;
int g_CSBuyCmdFwd = -1;
int ForwardInternalCommand = -1;
int ForwardOnBuy = -1;
int ForwardOnBuyAttempt = -1;
int *g_UseBotArgs = NULL;
const char **g_BotArgs = NULL;
int *UseBotArgs = NULL;
const char **BotArgs = NULL;
CDetour *g_ClientCommandDetour = NULL;
CDetour *g_CanBuyThisDetour = NULL;
CDetour *g_BuyItemDetour = NULL;
CDetour *g_BuyGunAmmoDetour = NULL;
CDetour *ClientCommandDetour = NULL;
CDetour *GiveShieldDetour = NULL;
CDetour *GiveNamedItemDetour = NULL;
CDetour *AddAccountDetour = NULL;
int CurrentItemId = 0;
StringHashMap<int> ItemAliasList;
void InitializeHacks()
{
@ -65,76 +71,170 @@ void ShutdownHacks()
CtrlDetours_BuyCommands(false);
}
#undef CMD_ARGV
const char *CMD_ARGV(int i)
{
if (*UseBotArgs)
{
if (i < 4)
{
return BotArgs[i];
}
return NULL;
}
return g_engfuncs.pfnCmd_Argv(i);
}
DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity)
{
if (*g_UseBotArgs)
{
int client = ENTINDEX(pEdict);
const char *args = *g_BotArgs;
const char *command = CMD_ARGV(0);
if (MF_ExecuteForward(g_CSCliCmdFwd, static_cast<cell>(client), args) > 0)
// A new command is triggered, reset variable, always.
CurrentItemId = 0;
// Purpose is to retrieve an item id based on alias name or selected item from menu,
// to be used in OnBuy* forwards.
if ((ForwardOnBuyAttempt != -1 || ForwardOnBuy != -1) && command && *command)
{
// Just for safety.
command = UTIL_StringToLower((char *)command);
int itemId = 0;
// Handling buy via menu.
if (!strcmp(command, "menuselect"))
{
int slot = atoi(CMD_ARGV(1));
if (slot > 0 && slot < 9)
{
static const int menuItemsTe[][9] =
{
/* Menu_Buy */ { 0, 0, 0, 0, 0, 0, CSI_PRIMAMMO, CSI_SECAMMO, 0 },
/* Menu_BuyPistol */ { 0, CSI_GLOCK18, CSI_USP, CSI_P228, CSI_DEAGLE, CSI_ELITE, 0, 0, 0 },
/* Menu_BuyRifle */ { 0, CSI_GALI, CSI_AK47, CSI_SCOUT, CSI_SG552, CSI_AWP, CSI_G3SG1, 0, 0 },
/* Menu_BuyMachineGun */ { 0, CSI_M249, 0, 0, 0, 0, 0, 0, 0 },
/* Menu_BuyShotgun */ { 0, CSI_M3, CSI_XM1014, 0, 0, 0, 0, 0, 0 },
/* Menu_BuySubMachineGun */ { 0, CSI_MAC10, CSI_MP5NAVY, CSI_UMP45, CSI_P90, 0, 0, 0, 0 },
/* Menu_BuyItem */ { 0, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, 0, 0 }
};
static const int menuItemsCt[][9] =
{
/* Menu_Buy */ { 0, 0, 0, 0, 0, 0, CSI_PRIMAMMO, CSI_SECAMMO, 0 },
/* Menu_BuyPistol */ { 0, CSI_GLOCK18, CSI_USP, CSI_P228, CSI_DEAGLE, CSI_FIVESEVEN, 0, 0, 0 },
/* Menu_BuyRifle */ { 0, CSI_FAMAS, CSI_SCOUT, CSI_M4A1, CSI_AUG, CSI_SG550, CSI_AWP, 0, 0 },
/* Menu_BuyMachineGun */ { 0, CSI_M249, 0, 0, 0, 0, 0, 0, 0 },
/* Menu_BuyShotgun */ { 0, CSI_M3, CSI_XM1014, 0, 0, 0, 0, 0, 0 },
/* Menu_BuySubMachineGun */ { 0, CSI_TMP, CSI_MP5NAVY, CSI_UMP45, CSI_P90, 0, 0, 0, 0 },
/* Menu_BuyItem */ { 0, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, CSI_DEFUSER, CSI_SHIELDGUN }
};
int menuId = *((int *)pEdict->pvPrivateData + OFFSET_MENU);
if (menuId >= Menu_Buy && menuId <= Menu_BuyItem)
{
int team = *((int *)pEdict->pvPrivateData + OFFSET_TEAM);
switch (team)
{
case TEAM_T: itemId = menuItemsTe[menuId - 4][slot]; break; // -4 because array is zero-based and Menu_Buy* constants starts from 4.
case TEAM_CT:itemId = menuItemsCt[menuId - 4][slot]; break;
}
if (itemId)
{
CurrentItemId = itemId;
}
}
}
}
else // Handling buy via alias
{
if (ItemAliasList.retrieve(command, &itemId))
{
CurrentItemId = itemId;
}
}
}
int client = ENTINDEX(pEdict);
if (ForwardInternalCommand != -1 && *UseBotArgs)
{
const char *args = *BotArgs;
if (MF_ExecuteForward(ForwardInternalCommand, static_cast<cell>(client), args) > 0)
{
return;
}
}
if (ForwardOnBuyAttempt != -1 &&
CurrentItemId &&
MF_IsPlayerAlive(client) &&
MF_ExecuteForward(ForwardOnBuyAttempt, static_cast<cell>(client), static_cast<cell>(CurrentItemId)) > 0)
{
return;
}
DETOUR_STATIC_CALL(C_ClientCommand)(pEdict);
}
DETOUR_DECL_STATIC2(CanBuyThis, bool, void*, pvPlayer, int, weaponId) // bool CanBuyThis(CBasePlayer *pPlayer, int weaponId)
DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlayer::GiveNamedItem(const char *pszName)
{
if (weaponId != CSI_SHIELDGUN) // This will be handled before with BuyItem. Avoiding duplicated call.
// If the current item id is not null, this means player has triggers a buy command.
if (CurrentItemId)
{
int player = PrivateToIndex(pvPlayer);
int client = PrivateToIndex(this);
if (MF_IsPlayerAlive(player) && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(weaponId)) > 0)
{
return false;
}
}
return DETOUR_STATIC_CALL(CanBuyThis)(pvPlayer, weaponId);
}
DETOUR_DECL_STATIC2(BuyItem, void, void*, pvPlayer, int, iSlot) // void BuyItem(CBasePlayer *pPlayer, int iSlot)
{
int player = PrivateToIndex(pvPlayer);
if (MF_IsPlayerAlive(player))
{
static const int itemSlotToWeaponId[] = {-1, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, CSI_DEFUSER, CSI_SHIELDGUN};
if (iSlot >= 1 && iSlot <= 8 && MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(itemSlotToWeaponId[iSlot])) > 0)
if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast<cell>(client), static_cast<cell>(CurrentItemId)) > 0)
{
return;
}
}
DETOUR_STATIC_CALL(BuyItem)(pvPlayer, iSlot);
// From here, forward is not blocked, resetting this
// to ignore code in AddAccount which is called right after.
CurrentItemId = 0;
// Give me my item!
DETOUR_MEMBER_CALL(GiveNamedItem)(pszName);
}
DETOUR_DECL_STATIC3(BuyGunAmmo, bool, void*, pvPlayer, void*, pvWeapon, bool, bBlinkMoney) // bool BuyGunAmmo(CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney)
DETOUR_DECL_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire)
{
int player = PrivateToIndex(pvPlayer);
if (MF_IsPlayerAlive(player))
// Special case for shield. Game doesn't use GiveNamedItem() to give a shield.
if (CurrentItemId == CSI_SHIELDGUN)
{
edict_t *pWeapon = PrivateToEdict(pvWeapon);
int client = PrivateToIndex(this);
if (pWeapon)
if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast<cell>(client), CSI_SHIELDGUN) > 0)
{
int weaponId = *((int *)pWeapon->pvPrivateData + OFFSET_WEAPONTYPE);
int ammoId = (1<<weaponId & BITS_PISTOLS) ? CSI_SECAMMO : CSI_PRIMAMMO;
if (MF_ExecuteForward(g_CSBuyCmdFwd, static_cast<cell>(player), static_cast<cell>(ammoId)) > 0)
{
return false;
return;
}
}
// From here, forward is not blocked, resetting this
// to ignore code in AddAccount which is called right after.
CurrentItemId = 0;
// Give me my shield!
DETOUR_MEMBER_CALL(GiveShield)(bRetire);
}
DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void CBasePlayer::AddAccount(int amount, bool bTrackChange)
{
// No buy command or forward not blocked.
// Resuming game flow.
if (!CurrentItemId)
{
DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange);
}
return DETOUR_STATIC_CALL(BuyGunAmmo)(pvPlayer, pvWeapon, bBlinkMoney);
// Let's reset this right away to avoid issues.
CurrentItemId = 0;
}
@ -146,33 +246,88 @@ void CtrlDetours_ClientCommand(bool set)
#if defined(WIN32)
g_UseBotArgs = *(int **)((unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS);
g_BotArgs = (const char **)*(const char **)((unsigned char *)target + CS_CLICMD_OFFS_BOTARGS);
UseBotArgs = *(int **)((unsigned char *)target + CS_CLICMD_OFFS_USEBOTARGS);
BotArgs = (const char **)*(const char **)((unsigned char *)target + CS_CLICMD_OFFS_BOTARGS);
#elif defined(__linux__) || defined(__APPLE__)
g_UseBotArgs = (int *)UTIL_FindAddressFromEntry(CS_IDENT_USEBOTARGS, CS_IDENT_HIDDEN_STATE);
g_BotArgs = (const char **)UTIL_FindAddressFromEntry(CS_IDENT_BOTARGS, CS_IDENT_HIDDEN_STATE);
UseBotArgs = (int *)UTIL_FindAddressFromEntry(CS_IDENT_USEBOTARGS, CS_IDENT_HIDDEN_STATE);
BotArgs = (const char **)UTIL_FindAddressFromEntry(CS_IDENT_BOTARGS, CS_IDENT_HIDDEN_STATE);
#endif
g_ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, target);
ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, target);
if (g_ClientCommandDetour == NULL)
if (ClientCommandDetour == NULL)
{
MF_Log("No Client Commands detour could be initialized - Disabled Client Command forward.");
}
}
else
{
if (g_ClientCommandDetour)
g_ClientCommandDetour->Destroy();
if (ClientCommandDetour)
ClientCommandDetour->Destroy();
ItemAliasList.clear();
}
}
void ToggleDetour_ClientCommands(bool enable)
{
if (g_ClientCommandDetour)
(enable) ? g_ClientCommandDetour->EnableDetour() : g_ClientCommandDetour->DisableDetour();
if (ClientCommandDetour)
(enable) ? ClientCommandDetour->EnableDetour() : ClientCommandDetour->DisableDetour();
if (enable)
{
// Build the item alias list.
// Used in ClientCommand to check and get fastly item id from alias name.
typedef struct
{
const char *alias;
int id;
} itemBuyAliasInfo;
itemBuyAliasInfo aliasToId[] =
{
{ "p228" , CSI_P228 }, { "228compact" , CSI_P228 },
{ "scout" , CSI_SCOUT }, { "hegren" , CSI_HEGRENADE },
{ "xm1014" , CSI_XM1014 }, { "autoshotgun", CSI_XM1014 },
{ "mac10" , CSI_MAC10 }, { "aug" , CSI_AUG },
{ "bullpup" , CSI_AUG }, { "sgren" , CSI_SMOKEGRENADE },
{ "elites" , CSI_ELITE }, { "fn57" , CSI_FIVESEVEN },
{ "fiveseven" , CSI_FIVESEVEN }, { "ump45" , CSI_UMP45 },
{ "sg550" , CSI_SG550 }, { "krieg550" , CSI_SG550 },
{ "galil" , CSI_GALI }, { "defender" , CSI_GALI },
{ "famas" , CSI_FAMAS }, { "clarion" , CSI_FAMAS },
{ "usp" , CSI_USP }, { "km45" , CSI_USP },
{ "glock" , CSI_GLOCK18 }, { "9x19mm" , CSI_GLOCK18 },
{ "awp" , CSI_AWP }, { "magnum" , CSI_AWP },
{ "mp5" , CSI_MP5NAVY }, { "smg" , CSI_MP5NAVY },
{ "m249" , CSI_M249 }, { "m3" , CSI_M3 },
{ "12gauge" , CSI_M3 }, { "m4a1" , CSI_M4A1 },
{ "tmp" , CSI_TMP }, { "mp" , CSI_TMP },
{ "g3sg1" , CSI_G3SG1 }, { "d3au1" , CSI_G3SG1 },
{ "flash" , CSI_FLASHBANG }, { "deagle" , CSI_DEAGLE },
{ "nighthawk" , CSI_DEAGLE }, { "sg552" , CSI_SG552 },
{ "krieg552" , CSI_SG552 }, { "ak47" , CSI_AK47 },
{ "cv47" , CSI_AK47 }, { "p90" , CSI_P90 },
{ "c90" , CSI_P90 }, { "vest" , CSI_VEST },
{ "vesthelm" , CSI_VESTHELM }, { "defuser" , CSI_DEFUSER },
{ "nvgs" , CSI_NVGS }, { "shield" , CSI_SHIELDGUN },
{ "buyammo1" , CSI_PRIMAMMO }, { "primammo" , CSI_PRIMAMMO },
{ "buyammo2" , CSI_SECAMMO }, { "secammo" , CSI_SECAMMO },
{ NULL , 0 }
};
for (size_t i = 0; aliasToId[i].alias != NULL; ++i)
{
ItemAliasList.insert(aliasToId[i].alias, aliasToId[i].id);
}
}
else
{
ItemAliasList.clear();
}
}
@ -180,40 +335,42 @@ void CtrlDetours_BuyCommands(bool set)
{
if (set)
{
void *canBuyThisAddress = UTIL_FindAddressFromEntry(CS_IDENT_CANBUYTHIS, CS_IDENT_HIDDEN_STATE);
void *buyItemAddress = UTIL_FindAddressFromEntry(CS_IDENT_BUYITEM, CS_IDENT_HIDDEN_STATE);
void *buyGunAmmoAddress = UTIL_FindAddressFromEntry(CS_IDENT_BUYGUNAMMO, CS_IDENT_HIDDEN_STATE);
void *giveShieldAddress = UTIL_FindAddressFromEntry(CS_IDENT_GIVENSHIELD , CS_IDENT_HIDDEN_STATE);
void *giveNamedItemAddress = UTIL_FindAddressFromEntry(CS_IDENT_GIVENAMEDITEM, CS_IDENT_HIDDEN_STATE);
void *addAccountAddress = UTIL_FindAddressFromEntry(CS_IDENT_ADDACCOUNT , CS_IDENT_HIDDEN_STATE);
g_CanBuyThisDetour = DETOUR_CREATE_STATIC_FIXED(CanBuyThis, canBuyThisAddress);
g_BuyItemDetour = DETOUR_CREATE_STATIC_FIXED(BuyItem, buyItemAddress);
g_BuyGunAmmoDetour = DETOUR_CREATE_STATIC_FIXED(BuyGunAmmo, buyGunAmmoAddress);
GiveShieldDetour = DETOUR_CREATE_MEMBER_FIXED(GiveShield, giveShieldAddress);
GiveNamedItemDetour = DETOUR_CREATE_MEMBER_FIXED(GiveNamedItem, giveNamedItemAddress);
AddAccountDetour = DETOUR_CREATE_MEMBER_FIXED(AddAccount, addAccountAddress);
if (g_CanBuyThisDetour == NULL || g_BuyItemDetour == NULL || g_BuyGunAmmoDetour == NULL)
if (GiveNamedItemDetour == NULL || AddAccountDetour == NULL)
{
MF_Log("No Buy Commands detours could be initialized - Disabled Buy forward.");
}
}
else
{
if (g_CanBuyThisDetour)
g_CanBuyThisDetour->Destroy();
if (GiveShieldDetour)
GiveShieldDetour->Destroy();
if (g_BuyItemDetour)
g_BuyItemDetour->Destroy();
if (GiveNamedItemDetour)
GiveNamedItemDetour->Destroy();
if (g_BuyGunAmmoDetour)
g_BuyGunAmmoDetour->Destroy();
if (AddAccountDetour)
AddAccountDetour->Destroy();
ItemAliasList.clear();
}
}
void ToggleDetour_BuyCommands(bool enable)
{
if (g_CanBuyThisDetour)
(enable) ? g_CanBuyThisDetour->EnableDetour() : g_CanBuyThisDetour->DisableDetour();
if (GiveShieldDetour)
(enable) ? GiveShieldDetour->EnableDetour() : GiveShieldDetour->DisableDetour();
if (g_BuyItemDetour)
(enable) ? g_BuyItemDetour->EnableDetour() : g_BuyItemDetour->DisableDetour();
if (GiveNamedItemDetour)
(enable) ? GiveNamedItemDetour->EnableDetour() : GiveNamedItemDetour->DisableDetour();
if (g_BuyGunAmmoDetour)
(enable) ? g_BuyGunAmmoDetour->EnableDetour() : g_BuyGunAmmoDetour->DisableDetour();
if (AddAccountDetour)
(enable) ? AddAccountDetour->EnableDetour() : AddAccountDetour->DisableDetour();
}

View File

@ -1749,7 +1749,7 @@ static cell AMX_NATIVE_CALL not_on_64(AMX* amx, cell* params)
#endif
AMX_NATIVE_INFO cstrikeNatives[] = {
AMX_NATIVE_INFO CstrikeNatives[] = {
{"cs_set_user_money", cs_set_user_money},
{"cs_get_user_money", cs_get_user_money},
{"cs_get_user_deaths", cs_get_user_deaths},

View File

@ -3,14 +3,6 @@
//////////////////////////////////////////////////////////////////////
#include "CstrikePlayer.h"
#if defined _MSC_VER
#if _MSC_VER >= 1400
// MSVC8 - disable deprecation warnings for "unsafe" CRT functions
#define _CRT_SECURE_NO_DEPRECATE
#endif
#endif
#include <string.h> // strcpy()
//////////////////////////////////////////////////////////////////////

View File

@ -140,3 +140,14 @@ bool UTIL_CheckForPublic(const char *publicname)
return false;
}
char *UTIL_StringToLower(char *str)
{
char *p;
for (p = str; *p != '\0'; ++p)
{
*p = tolower(*p);
}
return str;
}

View File

@ -37,6 +37,7 @@ bool UTIL_IsPlayer(AMX* amx, edict_t* pPlayer);
void UTIL_TextMsg_Generic(edict_t* pPlayer, const char* message);
void *UTIL_FindAddressFromEntry(const char *entry, bool isHidden = false, const char *library = "mod");
bool UTIL_CheckForPublic(const char *publicname);
char *UTIL_StringToLower(char *str);
#define GETINFOKEYBUFFER (*g_engfuncs.pfnGetInfoKeyBuffer)
#define SETCLIENTKEYVALUE (*g_engfuncs.pfnSetClientKeyValue)

View File

@ -33,10 +33,11 @@
#include "amxxmodule.h"
#include "CstrikeUtils.h"
extern AMX_NATIVE_INFO cstrikeNatives[];
extern AMX_NATIVE_INFO CstrikeNatives[];
extern int g_CSCliCmdFwd;
extern int g_CSBuyCmdFwd;
extern int ForwardInternalCommand;
extern int ForwardOnBuy;
extern int ForwardOnBuyAttempt;
void InitializeHacks();
void ShutdownHacks();
@ -56,17 +57,25 @@ int AmxxCheckGame(const char *game)
void OnAmxxAttach()
{
MF_AddNatives(cstrikeNatives);
MF_AddNatives(CstrikeNatives);
InitializeHacks();
}
void OnPluginsLoaded()
{
g_CSCliCmdFwd = MF_RegisterForward("CS_InternalCommand", ET_STOP, FP_CELL, FP_STRING, FP_DONE);
g_CSBuyCmdFwd = MF_RegisterForward("CS_OnBuy", ET_STOP, FP_CELL, FP_CELL, FP_DONE);
ForwardInternalCommand = MF_RegisterForward("CS_InternalCommand", ET_STOP, FP_CELL, FP_STRING, FP_DONE);
ForwardOnBuy = MF_RegisterForward("CS_OnBuy" , ET_STOP, FP_CELL, FP_CELL, FP_DONE);
ForwardOnBuyAttempt = MF_RegisterForward("CS_OnBuyAttempt" , ET_STOP, FP_CELL, FP_CELL, FP_DONE);
ToggleDetour_ClientCommands(UTIL_CheckForPublic("CS_InternalCommand"));
ToggleDetour_BuyCommands(UTIL_CheckForPublic("CS_OnBuy"));
// Checking whether such public forwards are used in plugins.
// Resetting variable to -1 to avoid running unnecessary code in ClientCommand.
if (!UTIL_CheckForPublic("CS_InternalCommand")) { ForwardInternalCommand = -1; }
if (!UTIL_CheckForPublic("CS_OnBuy")) { ForwardOnBuy = -1; }
if (!UTIL_CheckForPublic("CS_OnBuyAttempt")) { ForwardOnBuyAttempt = -1; }
// And enable/disable detours when necessary.
ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuy != -1);
ToggleDetour_BuyCommands(ForwardOnBuy != -1);
}
void OnAmxxDetach()

View File

@ -63,7 +63,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\;..\..\..\..\public; ..\..\..\..\public\amtl;..\..\..\..\public\memtools;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HAVE_STDINT_H;_CRT_SECURE_NO_DEPRECATE;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
@ -106,7 +106,7 @@
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<AdditionalIncludeDirectories>..\;..\..\..\..\public; ..\..\..\..\public\amtl;..\..\..\..\public\memtools;..\sdk;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HAVE_STDINT_H;_CRT_SECURE_NO_DEPRECATE;CSTRIKE_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>

View File

@ -357,7 +357,7 @@ forward CS_InternalCommand(id, const cmd[]);
/**
* The following constants are used with CS_OnBuy forward.
* The following constants are used with CS_OnBuy[Attempt] forwards.
*/
#define CSI_P228 CSW_P228
#define CSI_SCOUT CSW_SCOUT
@ -397,7 +397,20 @@ forward CS_InternalCommand(id, const cmd[]);
/**
* Called when a player attempts to purchase an item.
* Return PLUGIN_CONTINUE to allow the purchase or return a higher action to deny.
* This is ususally called right away on buy commands issued by a player.
*
* @note Return PLUGIN_CONTINUE to allow the purchase or return a higher action to deny.
*
* @param index Player index.
* @param item Item index, see CSI_* constants.
*/
forward CS_OnBuyAttempt(index, item);
/**
* Called when a player purchases an item.
* This usually called right before a player gets the purchased item.
*
* @note Return PLUGIN_CONTINUE to allow the purchase or return a higher action to deny.
*
* @param index Player index.
* @param item Item index, see CSI_* constants.

View File

@ -136,6 +136,7 @@ ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name
#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
#define DETOUR_CREATE_MEMBER(name, gamedata, target) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata, target);
#define DETOUR_CREATE_MEMBER_FIXED(name, address) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), address);
#define DETOUR_CREATE_STATIC(name, gamedata, target) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata, target);
#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);