From d3e5957215b7f3cb75aaffd92fd12529a4776c42 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Wed, 15 Jul 2015 22:57:57 +0200 Subject: [PATCH 01/15] Cstrike: Add cstrike_const.inc and move existing constants there --- .../cstrike/cstrike/msvc12/cstrike.vcxproj | 1 + .../cstrike/msvc12/cstrike.vcxproj.filters | 3 + plugins/include/cstrike.inc | 116 +-------------- plugins/include/cstrike_const.inc | 133 ++++++++++++++++++ support/PackageScript | 1 + 5 files changed, 139 insertions(+), 115 deletions(-) create mode 100644 plugins/include/cstrike_const.inc diff --git a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj index e50b7f14..f4fb687b 100644 --- a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj +++ b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj @@ -167,6 +167,7 @@ + diff --git a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters index 33e30dbe..d7d54327 100644 --- a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters +++ b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters @@ -99,5 +99,8 @@ Pawn Includes + + Pawn Includes + \ No newline at end of file diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 041d35d9..3649bd4a 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -21,121 +21,7 @@ #pragma loadlib cstrike #endif -/** - * @section Team and team model constants, used by cs_[get|set]_user_team(). - */ - -/** - * Internal Counter-Strike model id constants. - * - * @note Model ids starting with CZ_ are only valid in Condition Zero. - */ -enum CsInternalModel -{ - CS_NORESET = -1, - CS_DONTCHANGE = 0, - CS_CT_URBAN = 1, - CS_T_TERROR = 2, - CS_T_LEET = 3, - CS_T_ARCTIC = 4, - CS_CT_GSG9 = 5, - CS_CT_GIGN = 6, - CS_CT_SAS = 7, - CS_T_GUERILLA = 8, - CS_CT_VIP = 9, - CZ_T_MILITIA = 10, - CZ_CT_SPETSNAZ = 11, -}; - -/** - * Counter-Strike team id constants. - */ -enum CsTeams -{ - CS_TEAM_UNASSIGNED = 0, - CS_TEAM_T = 1, - CS_TEAM_CT = 2, - CS_TEAM_SPECTATOR = 3, -}; - -/** - * @endsection - */ - -/** - * Counter-Strike armor types for use with cs_[get|set]_user_armor(). - */ -enum CsArmorType -{ - CS_ARMOR_NONE = 0, // no armor - CS_ARMOR_KEVLAR = 1, // body vest only - CS_ARMOR_VESTHELM = 2, // vest and helmet -}; - -/** - * Map zone flags returned by cs_get_user_mapzones(). - */ -#define CS_MAPZONE_BUY (1<<0) // Buyzone -#define CS_MAPZONE_BOMBTARGET (1<<1) // Bomb target zone -#define CS_MAPZONE_HOSTAGE_RESCUE (1<<2) // Hostage rescue zone -#define CS_MAPZONE_ESCAPE (1<<3) // Terrorist escape zone -#define CS_MAPZONE_VIP_SAFETY (1<<4) // VIP escape zone - -/** - * Constants used for cs_[get|set]_user_zoom(). - */ -enum -{ - CS_RESET_ZOOM = 0, // Reset any zoom blocking (mode has no effect) - CS_SET_NO_ZOOM, // Disable any sort of zoom - CS_SET_FIRST_ZOOM, // Set first zoom level (AWP style) - CS_SET_SECOND_ZOOM, // Set second zoom level (AWP style) - CS_SET_AUGSG552_ZOOM, // Set AUG/SG552 zoom style -}; - -/** - * Constants used for the CS_OnBuy() and CS_OnBuyAttempt() forwards. - * - * @note While these mostly overlap with the CSW_* constants the CSI_* constants - * contain custom AMXX values that do not correspond to any real value in - * the game. The CSI_* constants should therefore be used for consistency. - */ -#define CSI_P228 CSW_P228 -#define CSI_SCOUT CSW_SCOUT -#define CSI_HEGRENADE CSW_HEGRENADE -#define CSI_XM1014 CSW_XM1014 -#define CSI_C4 CSW_C4 -#define CSI_MAC10 CSW_MAC10 -#define CSI_AUG CSW_AUG -#define CSI_SMOKEGRENADE CSW_SMOKEGRENADE -#define CSI_ELITE CSW_ELITE -#define CSI_FIVESEVEN CSW_FIVESEVEN -#define CSI_UMP45 CSW_UMP45 -#define CSI_SG550 CSW_SG550 -#define CSI_GALIL CSW_GALIL -#define CSI_FAMAS CSW_FAMAS -#define CSI_USP CSW_USP -#define CSI_GLOCK18 CSW_GLOCK18 -#define CSI_AWP CSW_AWP -#define CSI_MP5NAVY CSW_MP5NAVY -#define CSI_M249 CSW_M249 -#define CSI_M3 CSW_M3 -#define CSI_M4A1 CSW_M4A1 -#define CSI_TMP CSW_TMP -#define CSI_G3SG1 CSW_G3SG1 -#define CSI_FLASHBANG CSW_FLASHBANG -#define CSI_DEAGLE CSW_DEAGLE -#define CSI_SG552 CSW_SG552 -#define CSI_AK47 CSW_AK47 -#define CSI_P90 CSW_P90 -#define CSI_SHIELDGUN CSW_SHIELDGUN // The real CS value, use CSI_SHELD instead. -#define CSI_VEST CSW_VEST // Custom -#define CSI_VESTHELM CSW_VESTHELM // Custom -#define CSI_DEFUSER 33 // Custom -#define CSI_NVGS 34 // Custom -#define CSI_PRIAMMO 36 // Custom -#define CSI_SECAMMO 37 // Custom -#define CSI_SHIELD 38 // Custom - The value passed by the forward, more convenient for plugins. +#include /** * Returns client's deaths. diff --git a/plugins/include/cstrike_const.inc b/plugins/include/cstrike_const.inc new file mode 100644 index 00000000..46fb2772 --- /dev/null +++ b/plugins/include/cstrike_const.inc @@ -0,0 +1,133 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +// +// Counter-Strike Functions +// + +#if defined _cstrike_const_included + #endinput +#endif +#define _cstrike_const_included + +/** + * @section Team and team model constants, used by cs_[get|set]_user_team(). + */ + +/** + * Internal Counter-Strike model id constants. + * + * @note Model ids starting with CZ_ are only valid in Condition Zero. + */ +enum CsInternalModel +{ + CS_DONTCHANGE = 0, + CS_CT_URBAN = 1, + CS_T_TERROR = 2, + CS_T_LEET = 3, + CS_T_ARCTIC = 4, + CS_CT_GSG9 = 5, + CS_CT_GIGN = 6, + CS_CT_SAS = 7, + CS_T_GUERILLA = 8, + CS_CT_VIP = 9, + CZ_T_MILITIA = 10, + CZ_CT_SPETSNAZ = 11, +}; + +/** + * Counter-Strike team id constants. + */ +enum CsTeams +{ + CS_TEAM_UNASSIGNED = 0, + CS_TEAM_T = 1, + CS_TEAM_CT = 2, + CS_TEAM_SPECTATOR = 3, +}; + +/** + * @endsection + */ + +/** + * Counter-Strike armor types for use with cs_[get|set]_user_armor(). + */ +enum CsArmorType +{ + CS_ARMOR_NONE = 0, // no armor + CS_ARMOR_KEVLAR = 1, // body vest only + CS_ARMOR_VESTHELM = 2, // vest and helmet +}; + +/** + * Map zone flags returned by cs_get_user_mapzones(). + */ +#define CS_MAPZONE_BUY (1<<0) // Buyzone +#define CS_MAPZONE_BOMBTARGET (1<<1) // Bomb target zone +#define CS_MAPZONE_HOSTAGE_RESCUE (1<<2) // Hostage rescue zone +#define CS_MAPZONE_ESCAPE (1<<3) // Terrorist escape zone +#define CS_MAPZONE_VIP_SAFETY (1<<4) // VIP escape zone + +/** + * Constants used for cs_[get|set]_user_zoom(). + */ +enum +{ + CS_RESET_ZOOM = 0, // Reset any zoom blocking (mode has no effect) + CS_SET_NO_ZOOM, // Disable any sort of zoom + CS_SET_FIRST_ZOOM, // Set first zoom level (AWP style) + CS_SET_SECOND_ZOOM, // Set second zoom level (AWP style) + CS_SET_AUGSG552_ZOOM, // Set AUG/SG552 zoom style +}; + +/** + * Constants used for the CS_OnBuy() and CS_OnBuyAttempt() forwards. + * + * @note While these mostly overlap with the CSW_* constants the CSI_* constants + * contain custom AMXX values that do not correspond to any real value in + * the game. The CSI_* constants should therefore be used for consistency. + */ +#define CSI_P228 CSW_P228 +#define CSI_SCOUT CSW_SCOUT +#define CSI_HEGRENADE CSW_HEGRENADE +#define CSI_XM1014 CSW_XM1014 +#define CSI_C4 CSW_C4 +#define CSI_MAC10 CSW_MAC10 +#define CSI_AUG CSW_AUG +#define CSI_SMOKEGRENADE CSW_SMOKEGRENADE +#define CSI_ELITE CSW_ELITE +#define CSI_FIVESEVEN CSW_FIVESEVEN +#define CSI_UMP45 CSW_UMP45 +#define CSI_SG550 CSW_SG550 +#define CSI_GALIL CSW_GALIL +#define CSI_FAMAS CSW_FAMAS +#define CSI_USP CSW_USP +#define CSI_GLOCK18 CSW_GLOCK18 +#define CSI_AWP CSW_AWP +#define CSI_MP5NAVY CSW_MP5NAVY +#define CSI_M249 CSW_M249 +#define CSI_M3 CSW_M3 +#define CSI_M4A1 CSW_M4A1 +#define CSI_TMP CSW_TMP +#define CSI_G3SG1 CSW_G3SG1 +#define CSI_FLASHBANG CSW_FLASHBANG +#define CSI_DEAGLE CSW_DEAGLE +#define CSI_SG552 CSW_SG552 +#define CSI_AK47 CSW_AK47 +#define CSI_P90 CSW_P90 +#define CSI_SHIELDGUN CSW_SHIELDGUN // The real CS value, use CSI_SHELD instead. +#define CSI_VEST CSW_VEST // Custom +#define CSI_VESTHELM CSW_VESTHELM // Custom +#define CSI_DEFUSER 33 // Custom +#define CSI_NVGS 34 // Custom +#define CSI_PRIAMMO 36 // Custom +#define CSI_SECAMMO 37 // Custom +#define CSI_SHIELD 38 // Custom - The value passed by the forward, more convenient for plugins. + diff --git a/support/PackageScript b/support/PackageScript index 1d42f07e..314a861f 100644 --- a/support/PackageScript +++ b/support/PackageScript @@ -273,6 +273,7 @@ scripting_files = [ 'include/core.inc', 'include/csstats.inc', 'include/cstrike.inc', + 'include/cstrike_const.inc', 'include/csx.inc', 'include/cvars.inc', 'include/datapack.inc', From c6628f22ee69dcbba42eaa6d449fd745dba48e5e Mon Sep 17 00:00:00 2001 From: Arkshine Date: Thu, 16 Jul 2015 07:42:22 +0200 Subject: [PATCH 02/15] Cstrike: Add more known constants from game --- plugins/include/amxconst.inc | 3 + plugins/include/cstrike_const.inc | 246 ++++++++++++++++++++++++++++-- plugins/include/hlsdk_const.inc | 9 ++ 3 files changed, 242 insertions(+), 16 deletions(-) diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 2512f09f..90111042 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -121,6 +121,7 @@ public stock const Float:NULL_VECTOR[3]; /** * IDs of weapons in CS */ +#define CSW_NONE 0 #define CSW_P228 1 #define CSW_SCOUT 3 #define CSW_HEGRENADE 4 @@ -154,6 +155,7 @@ public stock const Float:NULL_VECTOR[3]; #define CSW_VEST 31 // Custom #define CSW_VESTHELM 32 // Custom #define CSW_SHIELDGUN 99 +#define CSW_ALLWEAPONS (~(1< Date: Fri, 24 Jul 2015 09:57:10 +0200 Subject: [PATCH 03/15] Cstrike: Add cs_get_item_id() and cs_get_translated_item_alias() natives --- gamedata/modules.games/game.cstrike.txt | 333 ++++++++++++++++++ modules/cstrike/cstrike/AMBuilder | 1 + modules/cstrike/cstrike/CstrikeDatas.h | 25 +- modules/cstrike/cstrike/CstrikeHacks.cpp | 66 +--- modules/cstrike/cstrike/CstrikeHacks.h | 1 + modules/cstrike/cstrike/CstrikeItemsInfos.cpp | 241 +++++++++++++ modules/cstrike/cstrike/CstrikeItemsInfos.h | 87 +++++ modules/cstrike/cstrike/CstrikeMain.cpp | 15 + modules/cstrike/cstrike/CstrikeNatives.cpp | 78 +++- .../cstrike/cstrike/CstrikeUserMessages.cpp | 44 ++- modules/cstrike/cstrike/CstrikeUserMessages.h | 1 + modules/cstrike/cstrike/moduleconfig.h | 4 +- .../cstrike/cstrike/msvc12/cstrike.vcxproj | 2 + .../cstrike/msvc12/cstrike.vcxproj.filters | 6 + plugins/include/cstrike.inc | 37 ++ plugins/include/cstrike_const.inc | 3 +- 16 files changed, 877 insertions(+), 67 deletions(-) create mode 100644 modules/cstrike/cstrike/CstrikeItemsInfos.cpp create mode 100644 modules/cstrike/cstrike/CstrikeItemsInfos.h diff --git a/gamedata/modules.games/game.cstrike.txt b/gamedata/modules.games/game.cstrike.txt index d1a0f7c0..fb44cd70 100644 --- a/gamedata/modules.games/game.cstrike.txt +++ b/gamedata/modules.games/game.cstrike.txt @@ -99,5 +99,338 @@ } } } + + "#default" + { + "CommandsAliases" + { + "Common" + { + "p228" + { + "itemid" "1" // CSW/I_P228 + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "scout" + { + "itemid" "3" // CSW/I_SCOUT + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "xm1014" + { + "itemid" "5" // CSW/I_XM1014 + "classid" "5" // CS_WEAPONCLASS_SHOTGUN + } + "mac10" + { + "itemid" "7" // CSW/I_MAC10 + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "aug" + { + "itemid" "8" // CSW/I_AUG + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "elites" + { + "itemid" "10" // CSW/I_ELITE + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "fn57" + { + "itemid" "11" // CSW/I_FIVESEVEN + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "ump45" + { + "itemid" "12" // CSW/I_UMP45 + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "sg550" + { + "itemid" "13" // CSW/I_SG550 + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "galil" + { + "itemid" "14" // CSW/I_GALIL + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "famas" + { + "itemid" "15" // CSW/I_FAMAS + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "usp" + { + "itemid" "16" // CSW/I_USP + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "glock" + { + "itemid" "17" // CSW/I_GLOCK18 + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "awp" + { + "itemid" "18" // CSW/I_AWP + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "mp5" + { + "itemid" "19" // CSW/I_MP5NAVY + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "m249" + { + "itemid" "20" // CSW/I_M249 + "classid" "6" // CS_WEAPONCLASS_MACHINEGUN + } + "m3" + { + "itemid" "21" // CSW/I_M3 + "classid" "5" // CS_WEAPONCLASS_SHOTGUN + } + "m4a1" + { + "itemid" "22" // CSW/I_M4A1 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "tmp" + { + "itemid" "23" // CSW/I_TMP + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "g3sg1" + { + "itemid" "24" // CSW/I_G3SG1 + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "deagle" + { + "itemid" "26" // CSW/I_DEAGLE + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "sg552" + { + "itemid" "27" // CSW/I_SG552 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "ak47" + { + "itemid" "28" // CSW/I_AK47 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "p90" + { + "itemid" "30" // CSW/I_P90 + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "fiveseven" + { + "itemid" "11" // CSW/I_FIVESEVEN + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + } + + "Weapon" + { + "grenade" + { + "itemid" "4" // CSW/I_HEGRENADE + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "hegrenade" + { + "itemid" "4" // CSW/I_HEGRENADE + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "c4" + { + "itemid" "6" // CSW/I_C4 + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "elite" + { + "itemid" "10" // CSW/I_ELITE + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "glock18" + { + "itemid" "17" // CSW/I_GLOCK18 + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "mp5navy" + { + "itemid" "19" // CSW/I_MP5NAVY + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "knife" + { + "itemid" "29" // CSW/I_KNIFE + "classid" "1" // CS_WEAPONCLASS_KNIFE + } + } + + "Buy" + { + "228compact" + { + "itemid" "1" // CSW/I_P228 + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "autoshotgun" + { + "itemid" "5" // CSW/I_XM1014 + "classid" "5" // CS_WEAPONCLASS_SHOTGUN + } + "bullpup" + { + "itemid" "8" // CSW/I_AUG + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "sg550" + { + "itemid" "13" // CSW/I_SG550 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "krieg550" + { + "itemid" "13" // CSW/I_SG550 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "defender" + { + "itemid" "14" // CSW/I_GALIL + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "clarion" + { + "itemid" "15" // CSW/I_FAMAS + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "km45" + { + "itemid" "16" // CSW/I_USP + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "9x19mm" + { + "itemid" "17" // CSW/I_GLOCK18 + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "magnum" + { + "itemid" "18" // CSW/I_AWP + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "smg" + { + "itemid" "19" // CSW/I_MP5NAVY + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "12gauge" + { + "itemid" "21" // CSW/I_M3 + "classid" "5" // CS_WEAPONCLASS_SHOTGUN + } + "mp" + { + "itemid" "23" // CSW/I_TMP + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + "d3au1" + { + "itemid" "24" // CSW/I_G3SG1 + "classid" "8" // CS_WEAPONCLASS_SNIPERRIFLE + } + "nighthawk" + { + "itemid" "26" // CSW/I_DEAGLE + "classid" "2" // CS_WEAPONCLASS_PISTOL + } + "krieg552" + { + "itemid" "27" // CSW/I_SG552 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "cv47" + { + "itemid" "28" // CSW/I_AK47 + "classid" "7" // CS_WEAPONCLASS_RIFLE + } + "c90" + { + "itemid" "30" // CSW/I_P90 + "classid" "4" // CS_WEAPONCLASS_SUBMACHINEGUN + } + } + + "BuyEquip" + { + "hegren" + { + "itemid" "4" // CSW/I_HEGRENADE + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "sgren" + { + "itemid" "9" // CSW/I_SMOKEGRENADE + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "flash" + { + "itemid" "25" // CSW/I_FLASHBANG + "classid" "3" // CS_WEAPONCLASS_GRENADE + } + "vest" + { + "itemid" "31" // CSW/I_VEST + "classname" "item_kevlar" + } + "vesthelm" + { + "itemid" "32" // CSW/I_VESTHELM + "classname" "item_assaultsuit" + } + "defuser" + { + "itemid" "33" // CSI_DEFUSER + "classname" "item_thighpack" + } + "nvgs" + { + "itemid" "34" // CSI_NVGS + + } + "shield" + { + "itemid" "35" // CSI_SHIELD + "classid" "2" // CS_WEAPONCLASS_PISTOL + "classname" "weapon_shield" + } + } + + "BuyAmmo" + { + "primammo" + { + "itemid" "36" // CSI_PRIAMMO + } + "secammo" + { + "itemid" "37" // CSI_SECAMMO + } + "buyammo1" + { + "itemid" "36" // CSI_PRIAMMO + } + "buyammo2" + { + "itemid" "37" // CSI_SECAMMO + } + } + } + } } diff --git a/modules/cstrike/cstrike/AMBuilder b/modules/cstrike/cstrike/AMBuilder index 0db59424..17ede82c 100644 --- a/modules/cstrike/cstrike/AMBuilder +++ b/modules/cstrike/cstrike/AMBuilder @@ -15,6 +15,7 @@ binary.sources = [ 'CstrikeHacks.cpp', 'CstrikeUtils.cpp', 'CstrikeUserMessages.cpp', + 'CstrikeitemsInfos.cpp', '../../../public/memtools/MemoryUtils.cpp', '../../../public/memtools/CDetour/detours.cpp', '../../../public/memtools/CDetour/asm/asm.c', diff --git a/modules/cstrike/cstrike/CstrikeDatas.h b/modules/cstrike/cstrike/CstrikeDatas.h index 6167f7f3..40b823ba 100644 --- a/modules/cstrike/cstrike/CstrikeDatas.h +++ b/modules/cstrike/cstrike/CstrikeDatas.h @@ -17,6 +17,7 @@ /** * Weapon Ids for use with CS_OnBuyAttempt(), CS_OnBuy(). */ +#define CSI_NONE CSW_NONE #define CSI_P228 CSW_P228 #define CSI_SCOUT CSW_SCOUT #define CSI_HEGRENADE CSW_HEGRENADE @@ -50,15 +51,17 @@ #define CSI_VESTHELM CSW_VESTHELM // Custom #define CSI_DEFUSER 33 // Custom #define CSI_NVGS 34 // Custom +#define CSI_SHIELD 35 // Custom - The value passed by the forward, more convenient for plugins. #define CSI_PRIAMMO 36 // Custom #define CSI_SECAMMO 37 // Custom -#define CSI_SHIELD 38 // Custom - The value passed by the forward, more convenient for plugins. +#define CSI_MAX_COUNT 38 #define BITS_PISTOLS (1< ItemAliasList; TypeDescription TeamDesc; TypeDescription MenuDesc; @@ -148,9 +149,11 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma } else // Handling buy via alias { - if (ItemAliasList.retrieve(command, &itemId)) + AliasInfo info; + + if (ItemsManager.GetAliasInfosFromBuy(command, &info)) { - CurrentItemId = itemId; + CurrentItemId = info.itemid; } } } @@ -319,8 +322,6 @@ void CtrlDetours_ClientCommand(bool set) { ClientCommandDetour->Destroy(); } - - ItemAliasList.clear(); } } @@ -330,59 +331,6 @@ void ToggleDetour_ClientCommands(bool enable) { (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_GALIL }, { "defender" , CSI_GALIL }, - { "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_PRIAMMO }, { "primammo" , CSI_PRIAMMO }, - { "buyammo2" , CSI_SECAMMO }, { "secammo" , CSI_SECAMMO }, - { nullptr , 0 } - }; - - for (size_t i = 0; aliasToId[i].alias != nullptr; ++i) - { - ItemAliasList.insert(aliasToId[i].alias, aliasToId[i].id); - } - } - else - { - ItemAliasList.clear(); - } } @@ -443,8 +391,6 @@ void CtrlDetours_BuyCommands(bool set) { AddAccountDetour->Destroy(); } - - ItemAliasList.clear(); } } @@ -550,4 +496,4 @@ void InitGlobalVars() { MF_Log("sv global variable is not available"); } -} \ No newline at end of file +} diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index c7d91474..13404784 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -18,6 +18,7 @@ #include #include #include +#include "CstrikeDatas.h" void InitializeHacks(); void InitGlobalVars(); diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp new file mode 100644 index 00000000..ad8c5532 --- /dev/null +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp @@ -0,0 +1,241 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +// +// Counter-Strike Module +// + +#include "CstrikeitemsInfos.h" + +CsItemInfo ItemsManager; + +#define PSTATE_NONE +#define PSTATE_ALIASES_TYPE 0 +#define PSTATE_ALIASES_ALIAS 1 +#define PSTATE_ALIASES_ALIAS_DEFS 2 + +CsItemInfo::CsItemInfo() + : + m_ParseState(0), + m_List(nullptr), + m_ListsRetrievedFromConfig(false) +{ +} + +CsItemInfo::~CsItemInfo() +{ + Clear(); +} + +void CsItemInfo::Clear() +{ + m_CommonAliasesList.clear(); + m_WeaponAliasesList.clear(); + m_BuyAliasesList.clear(); +} + +bool CsItemInfo::HasConfigError() +{ + return !m_ListsRetrievedFromConfig; +} + +SMCResult CsItemInfo::ReadSMC_NewSection(const SMCStates *states, const char *name) +{ + switch (m_ParseState) + { + case PSTATE_ALIASES_TYPE: + { + m_List = nullptr; + + if (!strcmp(name, "Common")) + { + m_List = &m_CommonAliasesList; + } + else if (!strcmp(name, "Weapon")) + { + m_List = &m_WeaponAliasesList; + } + else if (strstr(name, "Buy")) + { + m_List = &m_BuyAliasesList; + } + else + { + return SMCResult_HaltFail; + } + + m_ParseState = PSTATE_ALIASES_ALIAS; + break; + } + case PSTATE_ALIASES_ALIAS: + { + m_AliasInfo.clear(); + m_Alias = name; + + m_ParseState = PSTATE_ALIASES_ALIAS_DEFS; + break; + } + } + + return SMCResult_Continue; +} + +SMCResult CsItemInfo::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) +{ + switch (m_ParseState) + { + case PSTATE_ALIASES_ALIAS_DEFS: + { + if (!strcmp(key, "itemid")) + { + m_AliasInfo.itemid = atoi(value); + + if (m_AliasInfo.itemid < CSI_NONE || m_AliasInfo.itemid >= CSI_MAX_COUNT) + { + m_AliasInfo.itemid = CSI_NONE; + } + } + else if (!strcmp(key, "classid")) + { + m_AliasInfo.classid = atoi(value); + + if (m_AliasInfo.classid < CS_WEAPONCLASS_NONE || m_AliasInfo.classid >= CS_WEAPONCLASS_MAX_COUNT) + { + m_AliasInfo.classid = CS_WEAPONCLASS_NONE; + } + } + else if (!strcmp(key, "classname")) + { + m_AliasInfo.classname = value; + } + else + { + return SMCResult_HaltFail; + } + break; + } + } + + return SMCResult_Continue; +} + +SMCResult CsItemInfo::ReadSMC_LeavingSection(const SMCStates *states) +{ + switch (m_ParseState) + { + case PSTATE_ALIASES_ALIAS: + { + m_ParseState = PSTATE_ALIASES_TYPE; + break; + } + case PSTATE_ALIASES_ALIAS_DEFS: + { + m_List->replace(m_Alias.chars(), m_AliasInfo); + m_WeaponIdToClass[m_AliasInfo.itemid] = static_cast(m_AliasInfo.classid); + + m_AliasInfo.clear(); + + m_ParseState = PSTATE_ALIASES_ALIAS; + break; + } + } + + return SMCResult_Continue; +} + +void CsItemInfo::ReadSMC_ParseEnd(bool halted, bool failed) +{ + if (halted) + { + MF_Log("Invalid or missing key in \"%s\" section. Please check your gamedata files.", m_Alias.chars()); + return; + } + + m_ListsRetrievedFromConfig = true; +} + +bool CsItemInfo::GetAliasInfos(const char *alias, AliasInfo *info) +{ + if (GetAliasInfosFromBuy(alias, info) || m_WeaponAliasesList.retrieve(alias, info)) + { + return true; + } + + return false; +} + +bool CsItemInfo::GetAliasInfosFromBuy(const char *alias, AliasInfo *info) +{ + if (m_CommonAliasesList.retrieve(alias, info) || m_BuyAliasesList.retrieve(alias, info)) + { + return true; + } + + return false; +} + +bool CsItemInfo::GetAliasInfosFromName(const char *name, AliasInfo *info) +{ + static const char prefix_weapon[] = "weapon_"; + static const char prefix_item[] = "item_"; + + const char *alias = name; + + if (strstr(name, prefix_weapon) && strcmp(name + sizeof(prefix_weapon) - 1, "shield")) + { + for (size_t id = 0; id < ARRAYSIZE(WeaponNameList); ++id) + { + if (!strcmp(name, WeaponNameList[id])) + { + info->classname = name; + info->itemid = id; + info->classid = WeaponIdToClass(id); + + return true; + } + } + + alias = name + sizeof(prefix_weapon) - 1; + } + else if (strstr(name, prefix_item)) + { + for (auto iter = m_BuyAliasesList.iter(); !iter.empty(); iter.next()) + { + if (iter->value.classname.length() && !iter->value.classname.compare(name)) + { + *info = iter->value; + return true; + } + } + + alias = name + sizeof(prefix_item) - 1; + } + + if (GetAliasInfos(alias, info)) + { + return true; + } + + return false; +} + +CsWeaponClassType CsItemInfo::WeaponIdToClass(int id) +{ + if ((id > CSI_NONE && id <= CSI_P90) || id == CSI_SHIELD || id == CSI_SHIELDGUN) + { + if (id == CSI_SHIELDGUN) + { + id = CSI_SHIELD; + } + + return m_WeaponIdToClass[id]; + } + + return CS_WEAPONCLASS_NONE; +} \ No newline at end of file diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.h b/modules/cstrike/cstrike/CstrikeItemsInfos.h new file mode 100644 index 00000000..6df10eb1 --- /dev/null +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.h @@ -0,0 +1,87 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +// +// Counter-Strike Module +// + +#ifndef _CSTRIKE_WEAPONS_INFOS_H_ +#define _CSTRIKE_WEAPONS_INFOS_H_ + +#include "CstrikeDatas.h" +#include +#include + +struct AliasInfo +{ + AliasInfo() + { + clear(); + } + + void clear() + { + itemid = CSI_NONE; + classid = CS_WEAPONCLASS_NONE; + } + + int itemid; + int classid; + ke::AString classname; +}; + +class CsItemInfo : public ITextListener_SMC +{ + public: + + CsItemInfo(); + ~CsItemInfo(); + + public: + + void Clear(); + bool HasConfigError(); + + public: + + SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); + SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); + SMCResult ReadSMC_LeavingSection(const SMCStates *states); + void ReadSMC_ParseEnd(bool halted, bool failed); + + public: + + bool GetAliasInfos(const char *alias, AliasInfo *info); + bool GetAliasInfosFromBuy(const char *alias, AliasInfo *info); + bool GetAliasInfosFromName(const char *classname, AliasInfo *info); + + CsWeaponClassType WeaponIdToClass(int id); + + private: // Retrieved datas + + typedef StringHashMap AliasMap; + + AliasMap m_CommonAliasesList; + AliasMap m_WeaponAliasesList; + AliasMap m_BuyAliasesList; + + CsWeaponClassType m_WeaponIdToClass[CSI_MAX_COUNT]; + + private: // Config parsing + + int m_ParseState; + AliasMap* m_List; + ke::AString m_Alias; + AliasInfo m_AliasInfo; + bool m_ListsRetrievedFromConfig; +}; + +extern CsItemInfo ItemsManager; + +#endif // _CSTRIKE_WEAPONS_INFOS_H_ diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index 1313bc36..8339f60b 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -41,6 +41,8 @@ void OnAmxxAttach() char error[256]; error[0] = '\0'; + ConfigManager->AddUserConfigHook("CommandsAliases", &ItemsManager); + if (!ConfigManager->LoadGameConfigFile("modules.games", &MainConfig, error, sizeof(error)) && error[0] != '\0') { MF_Log("Could not read module.games gamedata: %s", error); @@ -83,8 +85,21 @@ void OnPluginsLoaded() g_pFunctionTable->pfnStartFrame = nullptr; } +void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +{ + // Used to catch WeaponList message at map change. + EnableMessageHooks(); +} + +void OnServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) +{ + DisableMessageHooks(); +} + void OnAmxxDetach() { + ConfigManager->RemoveUserConfigHook("CommandsAliases", &ItemsManager); + ConfigManager->CloseGameConfigFile(MainConfig); ConfigManager->CloseGameConfigFile(CommonConfig); diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index e1419a98..62015acb 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -20,6 +20,7 @@ #include bool NoKifesMode = false; +char WeaponNameList[MAX_WEAPONS][64]; // native cs_set_user_money(index, money, flash = 1); static cell AMX_NATIVE_CALL cs_set_user_money(AMX *amx, cell *params) @@ -1739,6 +1740,77 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_class(AMX* amx, cell* params) return 0; } +// native any:cs_get_item_id(const name[], &CsWeaponClassType:classid = CS_WEAPONCLASS_NONE); +static cell AMX_NATIVE_CALL cs_get_item_id(AMX* amx, cell* params) +{ + if (ItemsManager.HasConfigError()) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_item_id() is disabled"); + return 0; + } + + int length; + char *name = MF_GetAmxString(amx, params[1], 0, &length); + cell *classid = MF_GetAmxAddr(amx, params[2]); + + if (length) + { + AliasInfo info; + + if (ItemsManager.GetAliasInfosFromName(name, &info)) + { + *classid = info.classid; + return info.itemid; + } + } + + return CSI_NONE; +} + +// native bool:cs_get_translated_item_alias(const alias[], itemname[], maxlength); +static cell AMX_NATIVE_CALL cs_get_translated_item_alias(AMX* amx, cell* params) +{ + if (ItemsManager.HasConfigError()) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_translated_item_alias() is disabled"); + return 0; + } + + int length; + const char *alias = MF_GetAmxString(amx, params[1], 0, &length); + const char *name = alias; + AliasInfo info; + + if (length && ItemsManager.GetAliasInfos(alias, &info) && info.itemid != CSI_NONE) + { + switch (info.itemid) + { + case CSI_VEST: + case CSI_VESTHELM: + case CSI_DEFUSER: + case CSI_SHIELD: + { + // Special item_* defined in gamdata file as game + // doesn't give us really a way to know about their classname + // and I don't want to hard code them in module. + name = info.classname.chars(); + break; + } + default: + { + // weapon_* retrieved from WeaponList messages at map change. + name = WeaponNameList[info.itemid]; + break; + } + } + } + + MF_SetAmxString(amx, params[2], alias, params[3]); + + return info.itemid != CSI_NONE; +} + + AMX_NATIVE_INFO CstrikeNatives[] = { {"cs_set_user_money", cs_set_user_money}, @@ -1802,7 +1874,9 @@ AMX_NATIVE_INFO CstrikeNatives[] = {"cs_get_c4_defusing", cs_get_c4_defusing}, {"cs_set_c4_defusing", cs_set_c4_defusing}, {"cs_create_entity", cs_create_entity }, - {"cs_find_ent_by_class", cs_find_ent_by_class}, - + {"cs_find_ent_by_class", cs_find_ent_by_class}, + {"cs_get_item_id", cs_get_item_id}, + {"cs_get_translated_item_alias",cs_get_translated_item_alias}, + {"cs_get_weapon_info", cs_get_weapon_info}, {nullptr, nullptr} }; diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.cpp b/modules/cstrike/cstrike/CstrikeUserMessages.cpp index 00c368f6..b290713e 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.cpp +++ b/modules/cstrike/cstrike/CstrikeUserMessages.cpp @@ -16,9 +16,14 @@ #include "CstrikeUtils.h" #include "CstrikeHacks.h" #include "CstrikePlayer.h" +#include "CstrikeDatas.h" +#include bool ShouldBlock; bool ShouldBlockHLTV; +bool RetrieveWeaponName; +ke::AString CurrentWeaponName; +int ArgPosition; int MessageIdArmorType; int MessageIdHLTV; @@ -30,6 +35,7 @@ int MessageIdSetFOV; int MessageIdStatusIcon; int MessageIdTeamInfo; int MessageIdTextMsg; +int MessageIdWeaponList; struct UserMsg { @@ -49,6 +55,7 @@ UserMsg MessagesList[] = { "StatusIcon" , &MessageIdStatusIcon }, { "TeamInfo" , &MessageIdTeamInfo }, { "TextMsg" , &MessageIdTextMsg }, + { "WeaponList" , &MessageIdWeaponList }, { nullptr , nullptr } }; @@ -113,6 +120,13 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p } break; } + case MSG_INIT: + { + if (msg_type == MessageIdWeaponList) + { + RetrieveWeaponName = true; + } + } } if (ShouldBlockHLTV) @@ -123,12 +137,26 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p RETURN_META(MRES_IGNORED); } -void OnWriteByte(int iValue) +void OnWriteByte(int value) { if (ShouldBlock) { RETURN_META(MRES_SUPERCEDE); } + else if (RetrieveWeaponName && ++ArgPosition == 7 && value >= 0 && value < MAX_WEAPONS) + { + strncopy(WeaponNameList[value], CurrentWeaponName.chars(), sizeof(WeaponNameList[value])); + } + + RETURN_META(MRES_IGNORED); +} + +void OnWriteString(const char *value) +{ + if (RetrieveWeaponName) + { + CurrentWeaponName = value; + } RETURN_META(MRES_IGNORED); } @@ -140,6 +168,11 @@ void OnMessageEnd(void) ShouldBlock = false; RETURN_META(MRES_SUPERCEDE); } + else if (RetrieveWeaponName) + { + RetrieveWeaponName = false; + ArgPosition = 0; + } RETURN_META(MRES_IGNORED); } @@ -150,6 +183,15 @@ void EnableMessageHooks() { g_pengfuncsTable->pfnMessageBegin = OnMessageBegin; g_pengfuncsTable->pfnWriteByte = OnWriteByte; + g_pengfuncsTable->pfnWriteString = OnWriteString; g_pengfuncsTable->pfnMessageEnd = OnMessageEnd; } } + +void DisableMessageHooks() +{ + g_pengfuncsTable->pfnMessageBegin = nullptr; + g_pengfuncsTable->pfnWriteByte = nullptr; + g_pengfuncsTable->pfnWriteString = nullptr; + g_pengfuncsTable->pfnMessageEnd = nullptr; +} diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.h b/modules/cstrike/cstrike/CstrikeUserMessages.h index 7c1a66ac..7541ad1a 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.h +++ b/modules/cstrike/cstrike/CstrikeUserMessages.h @@ -26,5 +26,6 @@ extern int MessageIdTeamInfo; extern int MessageIdTextMsg; void EnableMessageHooks(); +void DisableMessageHooks(); #endif // CSTRIKE_USER_MESSAGES_H diff --git a/modules/cstrike/cstrike/moduleconfig.h b/modules/cstrike/cstrike/moduleconfig.h index 79b9eccd..6438f750 100644 --- a/modules/cstrike/cstrike/moduleconfig.h +++ b/modules/cstrike/cstrike/moduleconfig.h @@ -123,7 +123,7 @@ // #define FN_ClientPutInServer ClientPutInServer /* pfnClientPutInServer() (wd) Client is entering the game */ // #define FN_ClientCommand ClientCommand /* pfnClientCommand() (wd) Player has sent a command (typed or from a bind) */ // #define FN_ClientUserInfoChanged ClientUserInfoChanged /* pfnClientUserInfoChanged() (wd) Client has updated their setinfo structure */ -// #define FN_ServerActivate ServerActivate /* pfnServerActivate() (wd) Server is starting a new map */ +#define FN_ServerActivate OnServerActivate /* pfnServerActivate() (wd) Server is starting a new map */ // #define FN_ServerDeactivate ServerDeactivate /* pfnServerDeactivate() (wd) Server is leaving the map (shutdown or changelevel); SDK2 */ // #define FN_PlayerPreThink PlayerPreThink /* pfnPlayerPreThink() */ // #define FN_PlayerPostThink PlayerPostThink /* pfnPlayerPostThink() */ @@ -175,7 +175,7 @@ // #define FN_ClientPutInServer_Post ClientPutInServer_Post // #define FN_ClientCommand_Post ClientCommand_Post // #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post -// #define FN_ServerActivate_Post ServerActivate_Post +#define FN_ServerActivate_Post OnServerActivate_Post // #define FN_ServerDeactivate_Post ServerDeactivate_Post // #define FN_PlayerPreThink_Post PlayerPreThink_Post // #define FN_PlayerPostThink_Post PlayerPostThink_Post diff --git a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj index f4fb687b..e15df551 100644 --- a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj +++ b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj @@ -151,12 +151,14 @@ + + diff --git a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters index d7d54327..89db5505 100644 --- a/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters +++ b/modules/cstrike/cstrike/msvc12/cstrike.vcxproj.filters @@ -59,6 +59,9 @@ Source Files + + Source Files + @@ -94,6 +97,9 @@ Header Files + + Header Files + diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 3649bd4a..8c769f6f 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1025,6 +1025,43 @@ native cs_create_entity(const classname[]); */ native cs_find_ent_by_class(start_index, const classname[]); +/** + * Returns the item id associated with an item name and its aliases. + * + * @note The item name is case sensitive an can be with or without + * weapon_ and item_ prefixes. This can be a command alias as well. + * Values examples: ak47, weapon_ak47, kevlar, item_kevlar, vest, bullpup, ... + * + * @param name Alias or classname + * @param classid If item is a weapon, variable to store the associated + * weapon class id in (CS_WEAPONCLASS_* constants) + * + * @return Item id (CSI_* constants) + */ +native any:cs_get_item_id(const name[], &CsWeaponClassType:classid = CS_WEAPONCLASS_NONE); + +/** + * Returns an item name associated with a command alias. + * + * @note The alias is case sensitive. + * @note If not an alias to a weapon, buffer will be set with the original alias. + * + * @param alias Alias name + * @param itemname Buffer to store item name to + * @param maxlength Maximum buffer size + * + * @return True if alias is translated, false otherwise + */ +native bool:cs_get_translated_item_alias(const alias[], itemname[], maxlength); + +/** + * + */ +stock cs_get_weapon_class(weapon_id) +{ + +} + /** * Called when CS internally fires a command to a player. * diff --git a/plugins/include/cstrike_const.inc b/plugins/include/cstrike_const.inc index 8f2f46e6..6462997c 100644 --- a/plugins/include/cstrike_const.inc +++ b/plugins/include/cstrike_const.inc @@ -129,9 +129,10 @@ enum #define CSI_VESTHELM CSW_VESTHELM // Custom #define CSI_DEFUSER 33 // Custom #define CSI_NVGS 34 // Custom +#define CSI_SHIELD 35 // Custom - The value passed by the forward, more convenient for plugins. #define CSI_PRIAMMO 36 // Custom #define CSI_SECAMMO 37 // Custom -#define CSI_SHIELD 38 // Custom - The value passed by the forward, more convenient for plugins. +#define CSI_MAX_COUNT 38 /** * Player's movements constants. From cf2f753660c7a5d19746cb33b905d60e08ed0bcf Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sat, 25 Jul 2015 13:07:42 +0200 Subject: [PATCH 04/15] Cstrike: Fix CS_OnBuy called only on the first buying of primary/secondary ammos and not when game loops to give until max amount When game gives ammos, it loops until the max amount is reached, but it sill calls GiveNamedItem and AddAcount, so forward should be called for each of these ones. Code logic is simplified and more understandable. --- modules/cstrike/cstrike/CstrikeHacks.cpp | 70 +++++++++++------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 14810a76..7d1c883b 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -80,7 +80,7 @@ const char *CMD_ARGV(int i) void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) { - // If shield is blocked with CS_OnBuy, we need to block the pickup sound ("items/gunpickup2.wav") + // If shield is blocked with CS_OnBuy, we need to block the pickup sound ("items/gunpickup2.wav") // as well played right after. Why this sound is not contained in GiveShield()? g_pengfuncsTable->pfnEmitSound = nullptr; @@ -91,24 +91,23 @@ void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity) { const char *command = CMD_ARGV(0); - - // A new command is triggered, reset variable, always. - CurrentItemId = 0; + + CurrentItemId = CSI_NONE; // 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) { - int itemId = 0; - + int itemId = CSI_NONE; + // Handling buy via menu. - if (!strcmp(command, "menuselect")) + if (!strcmp(command, "menuselect")) { int slot = atoi(CMD_ARGV(1)); if (slot > 0 && slot < 9) { - static const int menuItemsTe[][9] = + static const int menuItemsTe[][9] = { /* Menu_Buy */ { 0, 0, 0, 0, 0, 0, CSI_PRIAMMO, CSI_SECAMMO, 0 }, /* Menu_BuyPistol */ { 0, CSI_GLOCK18, CSI_USP, CSI_P228, CSI_DEAGLE, CSI_ELITE, 0, 0, 0 }, @@ -119,7 +118,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma /* Menu_BuyItem */ { 0, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, 0, 0 } }; - static const int menuItemsCt[][9] = + static const int menuItemsCt[][9] = { /* Menu_Buy */ { 0, 0, 0, 0, 0, 0, CSI_PRIAMMO, CSI_SECAMMO, 0 }, /* Menu_BuyPistol */ { 0, CSI_GLOCK18, CSI_USP, CSI_P228, CSI_DEAGLE, CSI_FIVESEVEN, 0, 0, 0 }, @@ -170,15 +169,19 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma } } - if (ForwardOnBuyAttempt != -1 && - CurrentItemId && - MF_IsPlayerAlive(client) && + if (ForwardOnBuyAttempt != -1 && + CurrentItemId && + MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuyAttempt, static_cast(client), static_cast(CurrentItemId)) > 0) { return; } + TriggeredFromCommand = CurrentItemId != CSI_NONE; + DETOUR_STATIC_CALL(C_ClientCommand)(pEdict); + + TriggeredFromCommand = false; } edict_s* OnCreateNamedEntity(int classname) @@ -212,63 +215,52 @@ DETOUR_DECL_MEMBER0(GiveDefaultItems, void) // void CBasePlayer::GiveDefaultIte DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlayer::GiveNamedItem(const char *pszName) { - // If the current item id is not null, this means player has triggers a buy command. - if (CurrentItemId) + if (TriggeredFromCommand) { int client = TypeConversion.cbase_to_id(this); if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), static_cast(CurrentItemId)) > 0) { + // Reset this to not call AddAccount() called right after. + CurrentItemId = CSI_NONE; return; } } - // 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_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire) { - // Special case for shield. Game doesn't use GiveNamedItem() to give a shield. - if (CurrentItemId == CSI_SHIELDGUN) + if (TriggeredFromCommand && CurrentItemId == CSI_SHIELDGUN) { int client = TypeConversion.cbase_to_id(this); if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELDGUN) > 0) { + // If shield blocked, we need to hook EmitSound to block pickup sound played right after. + g_pengfuncsTable->pfnEmitSound = OnEmitSound; + + // Reset this to not call AddAccount() called right after. + CurrentItemId = CSI_NONE; 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) + if (TriggeredFromCommand) { - DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); - } - // Shield is blocked. - // We need to hook EmitSound to block pickup sound played right after. - else if (CurrentItemId == CSI_SHIELDGUN) - { - g_pengfuncsTable->pfnEmitSound = OnEmitSound; + if (CurrentItemId == CSI_NONE) + { + return; + } } - // Let's reset this right away to avoid issues. - CurrentItemId = 0; + DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); } @@ -354,7 +346,7 @@ void CtrlDetours_BuyCommands(bool set) { AddAccountDetour = DETOUR_CREATE_MEMBER_FIXED(AddAccount, address); } - + if (!GiveShieldDetour || !GiveNamedItemDetour || !AddAccountDetour) { if (!GiveShieldDetour) From 60cdbeb2198475e7fbbfbab3763165beb05487e6 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sat, 25 Jul 2015 13:33:30 +0200 Subject: [PATCH 05/15] Cstrike: Add CS_OnGetItemPrice forward to get/alter an item price on purchase --- modules/cstrike/cstrike/CstrikeHacks.cpp | 13 +++++++++++++ modules/cstrike/cstrike/CstrikeHacks.h | 1 + modules/cstrike/cstrike/CstrikeMain.cpp | 6 ++++-- plugins/include/cstrike.inc | 18 +++++++++++++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 7d1c883b..17911a16 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -23,6 +23,7 @@ void CtrlDetours_Natives(bool set); int ForwardInternalCommand = -1; int ForwardOnBuy = -1; int ForwardOnBuyAttempt = -1; +int ForwardOnGetItemPrice = -1; int *UseBotArgs; const char **BotArgs; @@ -258,6 +259,18 @@ DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void C { return; } + else if (ForwardOnGetItemPrice != -1) + { + int client = G_HL_TypeConversion.cbase_to_id(this); + + cell price[1]; *price = -amount; + cell preparedCell = MF_PrepareCellArrayA(price, sizeof(price), true); + + if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnGetItemPrice, client, CurrentItemId, preparedCell) > 0) + { + amount = -*price; + } + } } DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 13404784..64328016 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -34,6 +34,7 @@ extern IGameConfig *CommonConfig; extern int ForwardInternalCommand; extern int ForwardOnBuy; extern int ForwardOnBuyAttempt; +extern int ForwardOnGetItemPrice; typedef edict_t* (*CreateNamedEntityFunc)(string_t iszClassname); typedef void* (*UTIL_FindEntityByStringFunc)(void* pStartEntity, const char *szKeyword, const char *szValue); diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index 8339f60b..e08da9e0 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -65,16 +65,18 @@ void OnPluginsLoaded() 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); + ForwardOnGetItemPrice = MF_RegisterForward("CS_OnGetItemPrice" , ET_STOP, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); // 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; } + if (!UTIL_CheckForPublic("CS_OnGetItemPrice")) { ForwardOnGetItemPrice = -1; } // And enable/disable detours when necessary. - ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuyAttempt != -1); - ToggleDetour_BuyCommands(ForwardOnBuy != -1); + ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuyAttempt != -1 || ForwardOnGetItemPrice != -1); + ToggleDetour_BuyCommands(ForwardOnBuy != -1 || ForwardOnGetItemPrice != -1); // Search pev/vtable offset automatically. TypeConversion.init(); diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index 8c769f6f..fcbeb47b 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1104,4 +1104,20 @@ forward CS_OnBuyAttempt(index, item); * @return PLUGIN_CONTINUE to let the buy continue * PLUGIN_HANDLED to block the buy */ -forward CS_OnBuy(index, item); +forward CS_OnBuy(index, item, &price); + +/** + * Called when a client purchased an item and game is about to apply item's price. + * + * @note This is called right after the user received the item and before the + * money is deducted from their cash reserves. + * @note For a list of possible item ids see the CSI_* constants. + * + * @param index Client index + * @param item Item id + * @param price Item price or buffer to store a newly price to + * + * @return PLUGIN_CONTINUE to use the default price + * PLUGIN_HANDLED or higher to use a newly-set price + */ +forward CS_OnGetItemPrice(index, item, &price); From 600a15a57bfa649cba236703923f822b0a0ba838 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sat, 25 Jul 2015 16:17:50 +0200 Subject: [PATCH 06/15] Cstrike: Add cs_get_weapon_info() native --- gamedata/modules.games/game.cstrike.txt | 8 ++++ modules/cstrike/cstrike/CstrikeDatas.h | 30 +++++++++++++ modules/cstrike/cstrike/CstrikeHacks.cpp | 13 ++++++ modules/cstrike/cstrike/CstrikeHacks.h | 2 + modules/cstrike/cstrike/CstrikeNatives.cpp | 51 ++++++++++++++++++++++ plugins/include/cstrike.inc | 11 +++++ plugins/include/cstrike_const.inc | 10 +++++ 7 files changed, 125 insertions(+) diff --git a/gamedata/modules.games/game.cstrike.txt b/gamedata/modules.games/game.cstrike.txt index fb44cd70..744c7707 100644 --- a/gamedata/modules.games/game.cstrike.txt +++ b/gamedata/modules.games/game.cstrike.txt @@ -62,6 +62,14 @@ "linux" "@_Z23UTIL_FindEntityByStringP11CBaseEntityPKcS2_" "mac" "@_Z23UTIL_FindEntityByStringP11CBaseEntityPKcS2_" } + + "GetWeaponInfo" // WeaponInfoStruct *GetWeaponInfo(int id); + { + "library" "server" + "windows" "\x8B\x2A\x2A\x2A\x2A\x2A\x33\x2A\x85\x2A\x56\x74\x2A\x8B" + "linux" "@_Z13GetWeaponInfoi" + "mac" "@_Z13GetWeaponInfoi" + } } } diff --git a/modules/cstrike/cstrike/CstrikeDatas.h b/modules/cstrike/cstrike/CstrikeDatas.h index 40b823ba..a6777fb6 100644 --- a/modules/cstrike/cstrike/CstrikeDatas.h +++ b/modules/cstrike/cstrike/CstrikeDatas.h @@ -94,6 +94,7 @@ #define CSW_VEST 31 // Brand new invention! #define CSW_VESTHELM 32 // Brand new invention! #define CSW_SHIELDGUN 99 +#define CSW_LAST_WEAPON CSW_P90 /** * Armoury entity ids for use with cs_get/set_armoury_type(). @@ -299,6 +300,35 @@ enum CsWeaponClassType CS_WEAPONCLASS_MAX_COUNT = 9, }; +/** + * Weapon infos. + */ +typedef struct +{ + int id; + int cost; + int clipCost; + int buyClipSize; + int gunClipSize; + int maxRounds; + int ammoType; + char *entityName; +} +WeaponInfoStruct; + +/** + * Weapon infos for use with cs_get_weapon_info(). + */ +enum CsWeaponInfo +{ + CS_WEAPONINFO_COST = 0, + CS_WEAPONINFO_CLIP_COST = 1, + CS_WEAPONINFO_BUY_CLIP_SIZE = 2, + CS_WEAPONINFO_GUN_CLIP_SIZE = 3, + CS_WEAPONINFO_MAX_ROUNDS = 4, + CS_WEAPONINFO_AMMO_TYPE = 5, +}; + extern char WeaponNameList[MAX_WEAPONS][64]; #endif // CSTRIKE_DATA_H diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 17911a16..9e3923a7 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -36,6 +36,7 @@ CDetour *GiveDefaultItemsDetour; CreateNamedEntityFunc CS_CreateNamedEntity; UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString; +GetWeaponInfoFunc GetWeaponInfo; int CurrentItemId; @@ -433,6 +434,12 @@ void CtrlDetours_Natives(bool set) CS_UTIL_FindEntityByString = reinterpret_cast(address); } + if (MainConfig->GetMemSig("GetWeaponInfo", &address)) // cs_get_weapon_info() + { + GetWeaponInfo = reinterpret_cast(address); + } + + if (!CS_CreateNamedEntity) { MF_Log("CREATE_NAMED_ENITTY is not available - native cs_create_entity() has been disabled"); @@ -443,6 +450,12 @@ void CtrlDetours_Natives(bool set) MF_Log("UTIL_FindEntByString is not available - native cs_find_ent_by_class() has been disabled"); } + if (!GetWeaponInfo) + { + MF_Log("GetWeaponInfo is not available - native cs_get_weapon_info() has been disabled"); + } + + if (MainConfig->GetMemSig("GiveDefaultItems", &address)) { GiveDefaultItemsDetour = DETOUR_CREATE_MEMBER_FIXED(GiveDefaultItems, address); diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 64328016..b05f22b3 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -38,9 +38,11 @@ extern int ForwardOnGetItemPrice; typedef edict_t* (*CreateNamedEntityFunc)(string_t iszClassname); typedef void* (*UTIL_FindEntityByStringFunc)(void* pStartEntity, const char *szKeyword, const char *szValue); +typedef WeaponInfoStruct* (*GetWeaponInfoFunc)(int id); extern CreateNamedEntityFunc CS_CreateNamedEntity; extern UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString; +extern GetWeaponInfoFunc GetWeaponInfo; extern CDetour *GiveDefaultItemsDetour; extern enginefuncs_t *g_pengfuncsTable; diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 62015acb..06ae45a8 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1810,6 +1810,57 @@ static cell AMX_NATIVE_CALL cs_get_translated_item_alias(AMX* amx, cell* params) return info.itemid != CSI_NONE; } +// native cs_get_weapon_info(weapon_id, CsWeaponInfo:type); +static cell AMX_NATIVE_CALL cs_get_weapon_info(AMX* amx, cell* params) +{ + if (GetWeaponInfo <= 0) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_weapon_info() is disabled"); + return 0; + } + + int weapon_id = params[1]; + + if (weapon_id <= CSW_NONE || weapon_id == CSW_C4 || weapon_id == CSW_KNIFE || weapon_id > CSW_LAST_WEAPON) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id: %d", weapon_id); + return 0; + } + + int info_type = params[2]; + + switch (info_type) + { + case CS_WEAPONINFO_COST: + { + return GetWeaponInfo(weapon_id)->cost; + } + case CS_WEAPONINFO_CLIP_COST: + { + return GetWeaponInfo(weapon_id)->clipCost; + } + case CS_WEAPONINFO_BUY_CLIP_SIZE: + { + return GetWeaponInfo(weapon_id)->buyClipSize; + } + case CS_WEAPONINFO_GUN_CLIP_SIZE: + { + return GetWeaponInfo(weapon_id)->gunClipSize; + } + case CS_WEAPONINFO_MAX_ROUNDS: + { + return GetWeaponInfo(weapon_id)->maxRounds; + } + case CS_WEAPONINFO_AMMO_TYPE: + { + return GetWeaponInfo(weapon_id)->ammoType; + } + } + + MF_LogError(amx, AMX_ERR_NATIVE, "Invalid info type: %d", info_type); + return 0; +} + AMX_NATIVE_INFO CstrikeNatives[] = { diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index fcbeb47b..5e0a83eb 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1062,6 +1062,17 @@ stock cs_get_weapon_class(weapon_id) } +/** + * Returns some information about a weapon. + * + * @param weapon_id Weapon id, see CSW_* constants + * @param type Info type, see CS_WEAPONINFO_* constants + * + * @return Weapon information value + * @error If weapon_id and type are out of bound, an error will be thrown. + */ +native any:cs_get_weapon_info(weapon_id, CsWeaponInfo:type); + /** * Called when CS internally fires a command to a player. * diff --git a/plugins/include/cstrike_const.inc b/plugins/include/cstrike_const.inc index 6462997c..34c4e897 100644 --- a/plugins/include/cstrike_const.inc +++ b/plugins/include/cstrike_const.inc @@ -346,3 +346,13 @@ enum CsAmmoType CS_AMMO_57MM = 8, CS_AMMO_357SIG = 9, }; + +enum CsWeaponInfo +{ + CS_WEAPONINFO_COST = 0, + CS_WEAPONINFO_CLIP_COST = 1, + CS_WEAPONINFO_BUY_CLIP_SIZE = 2, + CS_WEAPONINFO_GUN_CLIP_SIZE = 3, + CS_WEAPONINFO_MAX_ROUNDS = 4, + CS_WEAPONINFO_AMMO_TYPE = 5, +}; From 23b045093898f17980517c508449067cda54efce Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sun, 26 Jul 2015 18:26:12 +0200 Subject: [PATCH 07/15] Cstrike: Add cs_get_weapon_class() stock (weapon id -> class id) Note: this has been modified a bit later in cs_is_valid_itemid() commit. --- modules/cstrike/cstrike/CstrikeDatas.h | 22 +++++++++- plugins/include/amxconst.inc | 13 +++++- plugins/include/cstrike.inc | 60 ++++++++++++++++++++++---- plugins/include/cstrike_const.inc | 13 ++++++ 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeDatas.h b/modules/cstrike/cstrike/CstrikeDatas.h index a6777fb6..eabf8083 100644 --- a/modules/cstrike/cstrike/CstrikeDatas.h +++ b/modules/cstrike/cstrike/CstrikeDatas.h @@ -56,7 +56,16 @@ #define CSI_SECAMMO 37 // Custom #define CSI_MAX_COUNT 38 -#define BITS_PISTOLS (1< Date: Sun, 26 Jul 2015 19:55:10 +0200 Subject: [PATCH 08/15] Cstrike: Add cs_find_ent_by_owner() native --- modules/cstrike/cstrike/CstrikeNatives.cpp | 37 ++++++++++++++++++++++ modules/cstrike/cstrike/CstrikeUtils.h | 11 +++++++ plugins/include/cstrike.inc | 20 ++++++++++++ 3 files changed, 68 insertions(+) diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 06ae45a8..1c62e6fe 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1740,6 +1740,42 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_class(AMX* amx, cell* params) return 0; } +// cs_find_ent_by_owner(start_index, const classname[], owner) +static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) +{ + if (CS_UTIL_FindEntityByString <= 0) + { + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_owner() is disabled"); + return 0; + } + + int owner = params[3]; + CHECK_ENTITY_SIMPLE(params[3]); + + int length; + void* pEntity = G_HL_TypeConversion.id_to_cbase(params[1]); + const char* value = MF_GetAmxString(amx, params[2], 0, &length); + + edict_t *pOwner = GETEDICT(owner); + + while ((pEntity = CS_UTIL_FindEntityByString(pEntity, "classname", value))) + { + edict_t *pev = G_HL_TypeConversion.cbase_to_edict(pEntity); + + if (!FNullEnt(pev) && pev->v.owner == pOwner) + { + int index = ENTINDEX(pev); + + if (index != -1) + { + return index; + }; + } + } + + return 0; +} + // native any:cs_get_item_id(const name[], &CsWeaponClassType:classid = CS_WEAPONCLASS_NONE); static cell AMX_NATIVE_CALL cs_get_item_id(AMX* amx, cell* params) { @@ -1926,6 +1962,7 @@ AMX_NATIVE_INFO CstrikeNatives[] = {"cs_set_c4_defusing", cs_set_c4_defusing}, {"cs_create_entity", cs_create_entity }, {"cs_find_ent_by_class", cs_find_ent_by_class}, + {"cs_find_ent_by_owner", cs_find_ent_by_owner}, {"cs_get_item_id", cs_get_item_id}, {"cs_get_translated_item_alias",cs_get_translated_item_alias}, {"cs_get_weapon_info", cs_get_weapon_info}, diff --git a/modules/cstrike/cstrike/CstrikeUtils.h b/modules/cstrike/cstrike/CstrikeUtils.h index ac94a113..f1a59c53 100644 --- a/modules/cstrike/cstrike/CstrikeUtils.h +++ b/modules/cstrike/cstrike/CstrikeUtils.h @@ -27,6 +27,17 @@ bool UTIL_CheckForPublic(const char *publicname); #define GETCLIENTKEYVALUE (*g_engfuncs.pfnInfoKeyValue) #define CREATENAMEDENTITY (*g_engfuncs.pfnCreateNamedEntity) +#define CHECK_ENTITY_SIMPLE(x) \ + if (x < 0 || x > gpGlobals->maxEntities) { \ + MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \ + return 0; \ + } else { \ + if (x != 0 && FNullEnt(INDEXENT(x))) { \ + MF_LogError(amx, AMX_ERR_NATIVE, "Invalid entity %d", x); \ + return 0; \ + } \ + } + #define CHECK_ENTITY(x) \ if (x < 0 || x > gpGlobals->maxEntities) { \ MF_LogError(amx, AMX_ERR_NATIVE, "Entity out of range (%d)", x); \ diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index b97d9400..d45fb904 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1025,6 +1025,26 @@ native cs_create_entity(const classname[]); */ native cs_find_ent_by_class(start_index, const classname[]); +/** + * Finds an entity in the world using Counter-Strike's custom FindEntityByString + * wrapper, matching by owner. + * + * @note Unlike other mods CS keeps track of entities using a custom hashtable. + * This function utilizes the hasthable and allows for considerably faster + * classname lookup compared to the default FindEntityByString (used by + * find_ent_by_owner() for example). + * @note This exclusively considers entities in the hashtable, created by the + * game itself or using cs_create_entity(). + * + * @param start_index Entity index to start searching from. -1 to start from + * the first entity + * @param classname Classname to search for + * @param owner Entity index to search for entity's owner + * + * @return Entity index > 0 if found, 0 otherwise + */ +native cs_find_ent_by_owner(start_index, const classname[], owner); + /** * Returns the item id associated with an item name and its aliases. * From 2c5cc4289e3f90362108e98d1744a1107aad9b61 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 27 Jul 2015 11:26:32 +0200 Subject: [PATCH 09/15] Cstrike: Add cs_is_valid_itemid() stock --- modules/cstrike/cstrike/CstrikeItemsInfos.cpp | 2 +- plugins/include/cstrike.inc | 105 ++++++++++++------ 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp index ad8c5532..41510368 100644 --- a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp @@ -11,7 +11,7 @@ // Counter-Strike Module // -#include "CstrikeitemsInfos.h" +#include "CstrikeItemsInfos.h" CsItemInfo ItemsManager; diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index d45fb904..a7324a19 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1096,47 +1096,86 @@ stock CsWeaponClassType:cs_get_weapon_class(weapon_id) { new CsWeaponClassType:type = CS_WEAPONCLASS_NONE; - if (CSI_NONE <= weapon_id <= CSI_LAST_WEAPON || weapon_id == CSI_SHIELDGUN || weapon_id == CSI_SHIELD) + if (cs_is_valid_itemid(weapon_id, .weapon_only = true) || weapon_id == CSI_SHIELD) { - new const bits = (1 << weapon_id); + switch (weapon_id) + { + case CSI_SHIELDGUN, CSI_SHIELD: + { + type = CS_WEAPONCLASS_PISTOL; + } + case CSI_KNIFE: + { + type = CS_WEAPONCLASS_KNIFE; + } + default: + { + new const bits = (1 << weapon_id); - if (bits & (1 << CSI_KNIFE)) - { - type = CS_WEAPONCLASS_KNIFE; - } - else if(bits & CSI_ALL_PISTOLS || weapon_id == CSI_SHIELDGUN || weapon_id == CSI_SHIELD) - { - type = CS_WEAPONCLASS_PISTOL; - } - else if(bits & CSI_ALL_GRENADES) - { - type = CS_WEAPONCLASS_GRENADE; - } - else if(bits & CSI_ALL_SMGS) - { - type = CS_WEAPONCLASS_SUBMACHINEGUN; - } - else if(bits & CSI_ALL_SHOTGUNS) - { - type = CS_WEAPONCLASS_SHOTGUN; - } - else if(bits & CSI_ALL_MACHINEGUNS) - { - type = CS_WEAPONCLASS_MACHINEGUN; - } - else if(bits & CSI_ALL_RIFLES) - { - type = CS_WEAPONCLASS_RIFLE; - } - else if(bits & CSI_ALL_SNIPERRIFLES) - { - type = CS_WEAPONCLASS_SNIPERRIFLE; + if(bits & CSI_ALL_PISTOLS) + { + type = CS_WEAPONCLASS_PISTOL; + } + else if(bits & CSI_ALL_GRENADES) + { + type = CS_WEAPONCLASS_GRENADE; + } + else if(bits & CSI_ALL_SMGS) + { + type = CS_WEAPONCLASS_SUBMACHINEGUN; + } + else if(bits & CSI_ALL_SHOTGUNS) + { + type = CS_WEAPONCLASS_SHOTGUN; + } + else if(bits & CSI_ALL_MACHINEGUNS) + { + type = CS_WEAPONCLASS_MACHINEGUN; + } + else if(bits & CSI_ALL_RIFLES) + { + type = CS_WEAPONCLASS_RIFLE; + } + else if(bits & CSI_ALL_SNIPERRIFLES) + { + type = CS_WEAPONCLASS_SNIPERRIFLE; + } + } } } return type; } +/** + * Checks whether an item id is not out of bounds. + * + * @param id Item id (CSI_* constants) + * @param weapon_only If true, only the real weapon ids will be checked, + * including shield as well + * + * @return True if item id is valid, false otherwise + */ +stock bool:cs_is_valid_itemid(id, bool:weapon_only = false) +{ + if (id <= CSI_NONE) + { + return false; + } + + if (id > CSI_LAST_WEAPON && id != CSI_SHIELDGUN && weapon_only) + { + return false; + } + + if (id >= CSI_MAX_COUNT) + { + return false; + } + + return true; +} + /** * Called when CS internally fires a command to a player. * From ffe8b7761e2cdd3fd3dc84db3cc0cb36102e3fd9 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sat, 5 Sep 2015 10:31:12 +0200 Subject: [PATCH 10/15] Cstrike: Move CSW_* constants from amxconst.inc to cstrike_const.inc --- amxmodx/msvc12/amxmodx_mm.vcxproj | 1 + amxmodx/msvc12/amxmodx_mm.vcxproj.filters | 3 ++ plugins/include/amxconst.inc | 52 +---------------------- plugins/include/cstrike_const.inc | 50 ++++++++++++++++++++++ 4 files changed, 56 insertions(+), 50 deletions(-) diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj b/amxmodx/msvc12/amxmodx_mm.vcxproj index c02bfdef..6ae2689b 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj @@ -382,6 +382,7 @@ + diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters index 86499225..07545eb8 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters @@ -600,6 +600,9 @@ Pawn Includes + + Pawn Includes + diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index 9d3f6696..96dfcd21 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -118,56 +118,6 @@ public stock const Float:NULL_VECTOR[3]; #define PLUGIN_HANDLED 1 /* stop other plugins */ #define PLUGIN_HANDLED_MAIN 2 /* to use in client_command(), continue all plugins but stop the command */ -/** - * IDs of weapons in CS - */ -#define CSW_NONE 0 -#define CSW_P228 1 -#define CSW_SCOUT 3 -#define CSW_HEGRENADE 4 -#define CSW_XM1014 5 -#define CSW_C4 6 -#define CSW_MAC10 7 -#define CSW_AUG 8 -#define CSW_SMOKEGRENADE 9 -#define CSW_ELITE 10 -#define CSW_FIVESEVEN 11 -#define CSW_UMP45 12 -#define CSW_SG550 13 -#define CSW_GALI 14 -#define CSW_GALIL 14 -#define CSW_FAMAS 15 -#define CSW_USP 16 -#define CSW_GLOCK18 17 -#define CSW_AWP 18 -#define CSW_MP5NAVY 19 -#define CSW_M249 20 -#define CSW_M3 21 -#define CSW_M4A1 22 -#define CSW_TMP 23 -#define CSW_G3SG1 24 -#define CSW_FLASHBANG 25 -#define CSW_DEAGLE 26 -#define CSW_SG552 27 -#define CSW_AK47 28 -#define CSW_KNIFE 29 -#define CSW_P90 30 -#define CSW_VEST 31 // Custom -#define CSW_VESTHELM 32 // Custom -#define CSW_SHIELDGUN 99 -#define CSW_LAST_WEAPON CSW_P90 - -stock const CSW_ALL_WEAPONS = (~(1< // To keep backward compatibility \ No newline at end of file diff --git a/plugins/include/cstrike_const.inc b/plugins/include/cstrike_const.inc index 0986245e..d188a6d8 100644 --- a/plugins/include/cstrike_const.inc +++ b/plugins/include/cstrike_const.inc @@ -16,6 +16,56 @@ #endif #define _cstrike_const_included +/** + * IDs of weapons in CS + */ +#define CSW_NONE 0 +#define CSW_P228 1 +#define CSW_SCOUT 3 +#define CSW_HEGRENADE 4 +#define CSW_XM1014 5 +#define CSW_C4 6 +#define CSW_MAC10 7 +#define CSW_AUG 8 +#define CSW_SMOKEGRENADE 9 +#define CSW_ELITE 10 +#define CSW_FIVESEVEN 11 +#define CSW_UMP45 12 +#define CSW_SG550 13 +#define CSW_GALI 14 +#define CSW_GALIL 14 +#define CSW_FAMAS 15 +#define CSW_USP 16 +#define CSW_GLOCK18 17 +#define CSW_AWP 18 +#define CSW_MP5NAVY 19 +#define CSW_M249 20 +#define CSW_M3 21 +#define CSW_M4A1 22 +#define CSW_TMP 23 +#define CSW_G3SG1 24 +#define CSW_FLASHBANG 25 +#define CSW_DEAGLE 26 +#define CSW_SG552 27 +#define CSW_AK47 28 +#define CSW_KNIFE 29 +#define CSW_P90 30 +#define CSW_VEST 31 // Custom +#define CSW_VESTHELM 32 // Custom +#define CSW_SHIELDGUN 99 +#define CSW_LAST_WEAPON CSW_P90 + +stock const CSW_ALL_WEAPONS = (~(1< Date: Sat, 5 Sep 2015 10:33:28 +0200 Subject: [PATCH 11/15] Cstrike: Remove CS_OnGetItemPrice forward (reverted from commit 33a7d74b6da2ca4dcb621e9b306c386ba040571e) This is actually not possible to have a proper system to allow this. This is two majors problems: - The item price text can't be changed, whatever old and VGUI menu (it's either harcoded in config file or in client binary) - Once you open VGUI menu, to know if user has enough money to select an item, client relies on the current HUD money value, this means, since we can't directly changed price, before opening the menu, money needs to be somehow faked and restored once closed. It's awful. Overall it can't work properly, and at the end current forward doesn't make sense. If an author wanted to have its own prices, the only only way would to force players to use old menu, then overwriting the whole buy menu, so you would be able to display what you want exactly. --- modules/cstrike/cstrike/CstrikeHacks.cpp | 13 ------------- modules/cstrike/cstrike/CstrikeHacks.h | 1 - modules/cstrike/cstrike/CstrikeMain.cpp | 6 ++---- plugins/include/cstrike.inc | 18 +----------------- 4 files changed, 3 insertions(+), 35 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 9e3923a7..f47c1041 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -23,7 +23,6 @@ void CtrlDetours_Natives(bool set); int ForwardInternalCommand = -1; int ForwardOnBuy = -1; int ForwardOnBuyAttempt = -1; -int ForwardOnGetItemPrice = -1; int *UseBotArgs; const char **BotArgs; @@ -260,18 +259,6 @@ DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void C { return; } - else if (ForwardOnGetItemPrice != -1) - { - int client = G_HL_TypeConversion.cbase_to_id(this); - - cell price[1]; *price = -amount; - cell preparedCell = MF_PrepareCellArrayA(price, sizeof(price), true); - - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnGetItemPrice, client, CurrentItemId, preparedCell) > 0) - { - amount = -*price; - } - } } DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index b05f22b3..52068f91 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -34,7 +34,6 @@ extern IGameConfig *CommonConfig; extern int ForwardInternalCommand; extern int ForwardOnBuy; extern int ForwardOnBuyAttempt; -extern int ForwardOnGetItemPrice; typedef edict_t* (*CreateNamedEntityFunc)(string_t iszClassname); typedef void* (*UTIL_FindEntityByStringFunc)(void* pStartEntity, const char *szKeyword, const char *szValue); diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index e08da9e0..8339f60b 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -65,18 +65,16 @@ void OnPluginsLoaded() 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); - ForwardOnGetItemPrice = MF_RegisterForward("CS_OnGetItemPrice" , ET_STOP, FP_CELL, FP_CELL, FP_ARRAY, FP_DONE); // 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; } - if (!UTIL_CheckForPublic("CS_OnGetItemPrice")) { ForwardOnGetItemPrice = -1; } // And enable/disable detours when necessary. - ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuyAttempt != -1 || ForwardOnGetItemPrice != -1); - ToggleDetour_BuyCommands(ForwardOnBuy != -1 || ForwardOnGetItemPrice != -1); + ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuyAttempt != -1); + ToggleDetour_BuyCommands(ForwardOnBuy != -1); // Search pev/vtable offset automatically. TypeConversion.init(); diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index a7324a19..70e3ade5 100755 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -1218,20 +1218,4 @@ forward CS_OnBuyAttempt(index, item); * @return PLUGIN_CONTINUE to let the buy continue * PLUGIN_HANDLED to block the buy */ -forward CS_OnBuy(index, item, &price); - -/** - * Called when a client purchased an item and game is about to apply item's price. - * - * @note This is called right after the user received the item and before the - * money is deducted from their cash reserves. - * @note For a list of possible item ids see the CSI_* constants. - * - * @param index Client index - * @param item Item id - * @param price Item price or buffer to store a newly price to - * - * @return PLUGIN_CONTINUE to use the default price - * PLUGIN_HANDLED or higher to use a newly-set price - */ -forward CS_OnGetItemPrice(index, item, &price); +forward CS_OnBuy(index, item); From b6910667a824ce1510b8b0ba5d59430841c9c2dc Mon Sep 17 00:00:00 2001 From: Arkshine Date: Sat, 5 Sep 2015 14:28:26 +0200 Subject: [PATCH 12/15] Cstrike: Remove parsing error and update native error message --- modules/cstrike/cstrike/CstrikeItemsInfos.cpp | 34 +++++++------------ modules/cstrike/cstrike/CstrikeItemsInfos.h | 13 +++---- modules/cstrike/cstrike/CstrikeMain.cpp | 11 +++--- modules/cstrike/cstrike/CstrikeNatives.cpp | 14 ++++---- 4 files changed, 31 insertions(+), 41 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp index 41510368..27b658fb 100644 --- a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp @@ -12,21 +12,20 @@ // #include "CstrikeItemsInfos.h" +#include CsItemInfo ItemsManager; -#define PSTATE_NONE #define PSTATE_ALIASES_TYPE 0 #define PSTATE_ALIASES_ALIAS 1 #define PSTATE_ALIASES_ALIAS_DEFS 2 -CsItemInfo::CsItemInfo() - : - m_ParseState(0), +CsItemInfo::CsItemInfo() + : + m_ParseState(PSTATE_ALIASES_TYPE), m_List(nullptr), m_ListsRetrievedFromConfig(false) -{ -} +{} CsItemInfo::~CsItemInfo() { @@ -61,16 +60,16 @@ SMCResult CsItemInfo::ReadSMC_NewSection(const SMCStates *states, const char *na { m_List = &m_WeaponAliasesList; } - else if (strstr(name, "Buy")) + else if (!strcmp(name, "Buy") || !strcmp(name, "BuyEquip") || !strcmp(name, "BuyAmmo")) { m_List = &m_BuyAliasesList; } - else + + if (m_List) { - return SMCResult_HaltFail; + m_ParseState = PSTATE_ALIASES_ALIAS; } - m_ParseState = PSTATE_ALIASES_ALIAS; break; } case PSTATE_ALIASES_ALIAS: @@ -114,10 +113,6 @@ SMCResult CsItemInfo::ReadSMC_KeyValue(const SMCStates *states, const char *key, { m_AliasInfo.classname = value; } - else - { - return SMCResult_HaltFail; - } break; } } @@ -138,7 +133,7 @@ SMCResult CsItemInfo::ReadSMC_LeavingSection(const SMCStates *states) { m_List->replace(m_Alias.chars(), m_AliasInfo); m_WeaponIdToClass[m_AliasInfo.itemid] = static_cast(m_AliasInfo.classid); - + m_AliasInfo.clear(); m_ParseState = PSTATE_ALIASES_ALIAS; @@ -151,13 +146,10 @@ SMCResult CsItemInfo::ReadSMC_LeavingSection(const SMCStates *states) void CsItemInfo::ReadSMC_ParseEnd(bool halted, bool failed) { - if (halted) + if (!halted && !failed) { - MF_Log("Invalid or missing key in \"%s\" section. Please check your gamedata files.", m_Alias.chars()); - return; + m_ListsRetrievedFromConfig = true; } - - m_ListsRetrievedFromConfig = true; } bool CsItemInfo::GetAliasInfos(const char *alias, AliasInfo *info) @@ -238,4 +230,4 @@ CsWeaponClassType CsItemInfo::WeaponIdToClass(int id) } return CS_WEAPONCLASS_NONE; -} \ No newline at end of file +} diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.h b/modules/cstrike/cstrike/CstrikeItemsInfos.h index 6df10eb1..b9fa8e3f 100644 --- a/modules/cstrike/cstrike/CstrikeItemsInfos.h +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.h @@ -16,6 +16,7 @@ #include "CstrikeDatas.h" #include +#include #include struct AliasInfo @@ -49,14 +50,14 @@ class CsItemInfo : public ITextListener_SMC bool HasConfigError(); public: - - SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name); - SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); - SMCResult ReadSMC_LeavingSection(const SMCStates *states); - void ReadSMC_ParseEnd(bool halted, bool failed); + + SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name) override; + SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) override; + SMCResult ReadSMC_LeavingSection(const SMCStates *states) override; + void ReadSMC_ParseEnd(bool halted, bool failed) override; public: - + bool GetAliasInfos(const char *alias, AliasInfo *info); bool GetAliasInfosFromBuy(const char *alias, AliasInfo *info); bool GetAliasInfosFromName(const char *classname, AliasInfo *info); diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index 8339f60b..f7148473 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -38,20 +38,17 @@ void OnAmxxAttach() ConfigManager = MF_GetConfigManager(); - char error[256]; - error[0] = '\0'; - + char error[256] = ""; ConfigManager->AddUserConfigHook("CommandsAliases", &ItemsManager); - if (!ConfigManager->LoadGameConfigFile("modules.games", &MainConfig, error, sizeof(error)) && error[0] != '\0') + if (!ConfigManager->LoadGameConfigFile("modules.games", &MainConfig, error, sizeof(error)) && *error) { MF_Log("Could not read module.games gamedata: %s", error); return; } - error[0] = '\0'; - - if (!ConfigManager->LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error)) && error[0] != '\0') + *error = '\0'; + if (!ConfigManager->LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error)) && *error) { MF_Log("Could not read common.games gamedata: %s", error); return; diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 1c62e6fe..71640b64 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1081,7 +1081,7 @@ static cell AMX_NATIVE_CALL cs_set_no_knives(AMX *amx, cell *params) { if (!GiveDefaultItemsDetour) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_set_no_knives() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_set_no_knives() is disabled. Check your amxx logs."); return 0; } @@ -1700,7 +1700,7 @@ static cell AMX_NATIVE_CALL cs_create_entity(AMX* amx, cell* params) { if (CS_CreateNamedEntity <= 0) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_create_entity() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_create_entity() is disabled. Check your amxx logs."); return 0; } @@ -1722,7 +1722,7 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_class(AMX* amx, cell* params) { if (CS_UTIL_FindEntityByString <= 0) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_class() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_class() is disabled. Check your amxx logs."); return 0; } @@ -1745,7 +1745,7 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) { if (CS_UTIL_FindEntityByString <= 0) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_owner() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_find_ent_by_owner() is disabled. Check your amxx logs."); return 0; } @@ -1781,7 +1781,7 @@ static cell AMX_NATIVE_CALL cs_get_item_id(AMX* amx, cell* params) { if (ItemsManager.HasConfigError()) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_item_id() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_item_id() is disabled disabled because of missing gamedata"); return 0; } @@ -1808,7 +1808,7 @@ static cell AMX_NATIVE_CALL cs_get_translated_item_alias(AMX* amx, cell* params) { if (ItemsManager.HasConfigError()) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_translated_item_alias() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_translated_item_alias() is disabled because of missing gamedata"); return 0; } @@ -1851,7 +1851,7 @@ static cell AMX_NATIVE_CALL cs_get_weapon_info(AMX* amx, cell* params) { if (GetWeaponInfo <= 0) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_weapon_info() is disabled"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_weapon_info() is disabled. Check your amxx logs."); return 0; } From eb0222455ac9202996a39e1053b8c66320f070cc Mon Sep 17 00:00:00 2001 From: Arkshine Date: Mon, 7 Sep 2015 11:52:29 +0200 Subject: [PATCH 13/15] Cstrike: Fix spaces/tabulations/typo --- gamedata/modules.games/game.cstrike.txt | 12 ++-- modules/cstrike/cstrike/CstrikeHacks.cpp | 3 +- modules/cstrike/cstrike/CstrikeNatives.cpp | 80 +++++++++++----------- 3 files changed, 48 insertions(+), 47 deletions(-) diff --git a/gamedata/modules.games/game.cstrike.txt b/gamedata/modules.games/game.cstrike.txt index 744c7707..bf5de7b2 100644 --- a/gamedata/modules.games/game.cstrike.txt +++ b/gamedata/modules.games/game.cstrike.txt @@ -107,7 +107,7 @@ } } } - + "#default" { "CommandsAliases" @@ -376,17 +376,17 @@ "BuyEquip" { - "hegren" + "hegren" { "itemid" "4" // CSW/I_HEGRENADE "classid" "3" // CS_WEAPONCLASS_GRENADE } - "sgren" + "sgren" { "itemid" "9" // CSW/I_SMOKEGRENADE "classid" "3" // CS_WEAPONCLASS_GRENADE } - "flash" + "flash" { "itemid" "25" // CSW/I_FLASHBANG "classid" "3" // CS_WEAPONCLASS_GRENADE @@ -394,7 +394,7 @@ "vest" { "itemid" "31" // CSW/I_VEST - "classname" "item_kevlar" + "classname" "item_kevlar" } "vesthelm" { @@ -436,7 +436,7 @@ "buyammo2" { "itemid" "37" // CSI_SECAMMO - } + } } } } diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index f47c1041..78867578 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -38,6 +38,7 @@ UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString; GetWeaponInfoFunc GetWeaponInfo; int CurrentItemId; +bool TriggeredFromCommand; StringHashMap ItemAliasList; TypeDescription TeamDesc; @@ -127,7 +128,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma /* 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 } + /* Menu_BuyItem */ { 0, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, CSI_DEFUSER, CSI_SHIELD } }; int menuId = get_pdata(pEdict, MenuDesc.fieldOffset); diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 71640b64..84dccfe5 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -258,7 +258,7 @@ static cell AMX_NATIVE_CALL cs_set_weapon_silenced(AMX *amx, cell *params) GET_OFFSET("CBasePlayerWeapon", m_flNextPrimaryAttack); char animExt[12]; - float time; + float time = 0.0f; switch (weaponType) { @@ -406,7 +406,7 @@ static cell AMX_NATIVE_CALL cs_set_user_armor(AMX *amx, cell *params) pPlayer->v.armorvalue = armor; set_pdata(pPlayer, m_iKevlar, type); - + if (type == CS_ARMOR_KEVLAR || type == CS_ARMOR_ASSAULTSUIT) { MESSAGE_BEGIN(MSG_ONE, MessageIdArmorType, nullptr, pPlayer); @@ -489,7 +489,7 @@ static cell AMX_NATIVE_CALL cs_set_user_vip(AMX *amx, cell *params) WRITE_BYTE(index); WRITE_BYTE(scoreattrib); MESSAGE_END(); - } + } return 1; } @@ -501,7 +501,7 @@ static cell AMX_NATIVE_CALL cs_get_user_team(AMX *amx, cell *params) GET_OFFSET("CBasePlayer", m_iTeam); int index = params[1]; - + CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); @@ -538,7 +538,7 @@ static cell AMX_NATIVE_CALL cs_set_user_team(AMX *amx, cell *params) { Players[index].ResetModel(pPlayer); } - + bool sendTeamInfo = true; if (*params / sizeof(cell) >= 4) @@ -579,7 +579,7 @@ static cell AMX_NATIVE_CALL cs_get_user_inside_buyzone(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - + if (get_pdata(pPlayer, m_signals).GetState() & SIGNAL_BUY) { return 1; @@ -635,7 +635,7 @@ static cell AMX_NATIVE_CALL cs_set_user_plant(AMX *amx, cell *params) if (plant) { - if (icon) + if (icon) { MESSAGE_BEGIN(MSG_ONE, MessageIdStatusIcon, nullptr, pPlayer); WRITE_BYTE(1); @@ -646,7 +646,7 @@ static cell AMX_NATIVE_CALL cs_set_user_plant(AMX *amx, cell *params) MESSAGE_END(); } } - else + else { MESSAGE_BEGIN(MSG_ONE, MessageIdStatusIcon, nullptr, pPlayer); WRITE_BYTE(0); @@ -685,14 +685,14 @@ static cell AMX_NATIVE_CALL cs_set_user_defusekit(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - + set_pdata(pPlayer, m_bHasDefuser, kit); pPlayer->v.body = kit ? 1 : 0; if (kit) { int colour[3] = {DEFUSER_COLOUR_R, DEFUSER_COLOUR_G, DEFUSER_COLOUR_B}; - + for (int i = 0; i < 3; i++) { if (params[i + 3] != -1) @@ -708,7 +708,7 @@ static cell AMX_NATIVE_CALL cs_set_user_defusekit(AMX *amx, cell *params) int length; icon = MF_GetAmxString(amx, params[6], 1, &length); } - + MESSAGE_BEGIN(MSG_ONE, MessageIdStatusIcon, nullptr, pPlayer); WRITE_BYTE(params[7] == 1 ? 2 : 1); WRITE_STRING(icon); @@ -717,7 +717,7 @@ static cell AMX_NATIVE_CALL cs_set_user_defusekit(AMX *amx, cell *params) WRITE_BYTE(colour[2]); MESSAGE_END(); } - else + else { MESSAGE_BEGIN(MSG_ONE, MessageIdStatusIcon, nullptr, pPlayer); WRITE_BYTE(0); @@ -763,7 +763,7 @@ static cell AMX_NATIVE_CALL cs_get_user_backpackammo(AMX *amx, cell *params) pItem = get_pdata(pItem, m_pNext); } } - + return 0; } @@ -804,7 +804,7 @@ static cell AMX_NATIVE_CALL cs_set_user_backpackammo(AMX *amx, cell *params) pItem = get_pdata(pItem, m_pNext); } } - + return 0; } @@ -869,7 +869,7 @@ static cell AMX_NATIVE_CALL cs_set_user_model(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - if (model == -1) + if (model == -1) { MF_LogError(amx, AMX_ERR_NATIVE, "Invalid model %d", params[2]); return 0; @@ -1101,7 +1101,7 @@ static cell AMX_NATIVE_CALL cs_set_no_knives(AMX *amx, cell *params) // native cs_get_user_tked(index); static cell AMX_NATIVE_CALL cs_get_user_tked(AMX *amx, cell *params) -{ +{ GET_OFFSET("CBasePlayer", m_bJustKilledTeammate); int index = params[1]; @@ -1119,7 +1119,7 @@ static cell AMX_NATIVE_CALL cs_get_user_tked(AMX *amx, cell *params) // native cs_set_user_tked(index, tk = 1, subtract = 1); static cell AMX_NATIVE_CALL cs_set_user_tked(AMX *amx, cell *params) -{ +{ GET_OFFSET("CBasePlayer", m_bJustKilledTeammate); GET_OFFSET("CBasePlayer", m_iTeam); GET_OFFSET("CBasePlayer", m_iDeaths); @@ -1134,7 +1134,7 @@ static cell AMX_NATIVE_CALL cs_set_user_tked(AMX *amx, cell *params) set_pdata(pPlayer, m_bJustKilledTeammate, tk != 0); if (subtract > 0) - { + { pPlayer->v.frags -= subtract; MESSAGE_BEGIN(MSG_ALL, MessageIdScoreInfo); @@ -1143,15 +1143,15 @@ static cell AMX_NATIVE_CALL cs_set_user_tked(AMX *amx, cell *params) WRITE_SHORT(get_pdata(pPlayer, m_iDeaths)); WRITE_SHORT(0); WRITE_SHORT(get_pdata(pPlayer, m_iTeam)); - MESSAGE_END(); - } + MESSAGE_END(); + } - return 1; + return 1; } // native cs_get_user_driving(index); static cell AMX_NATIVE_CALL cs_get_user_driving(AMX *amx, cell *params) -{ +{ GET_OFFSET("CBasePlayer", m_iTrain); int index = params[1]; @@ -1163,8 +1163,8 @@ static cell AMX_NATIVE_CALL cs_get_user_driving(AMX *amx, cell *params) } // native cs_get_user_stationary(index); -static cell AMX_NATIVE_CALL cs_get_user_stationary(AMX *amx, cell *params) -{ +static cell AMX_NATIVE_CALL cs_get_user_stationary(AMX *amx, cell *params) +{ GET_OFFSET("CBasePlayer", m_iClientHideHUD); int index = params[1]; @@ -1184,13 +1184,13 @@ static cell AMX_NATIVE_CALL cs_get_user_shield(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - + if (get_pdata(pPlayer, m_bOwnsShield)) { return 1; } - return 0; + return 0; } // native cs_user_spawn(player); @@ -1204,7 +1204,7 @@ static cell AMX_NATIVE_CALL cs_user_spawn(AMX *amx, cell *params) pPlayer->v.deadflag = DEAD_RESPAWNABLE; MDLL_Think(pPlayer); - if (MF_IsPlayerBot(index) && pPlayer->v.deadflag == DEAD_RESPAWNABLE) + if (MF_IsPlayerBot(index) && pPlayer->v.deadflag == DEAD_RESPAWNABLE) { MDLL_Spawn(pPlayer); } @@ -1222,7 +1222,7 @@ static cell AMX_NATIVE_CALL cs_get_armoury_type(AMX *amx, cell *params) CHECK_NONPLAYER(index); edict_t *pArmoury = INDEXENT(index); - if (strcmp(STRING(pArmoury->v.classname), "armoury_entity")) + if (strcmp(STRING(pArmoury->v.classname), "armoury_entity")) { MF_LogError(amx, AMX_ERR_NATIVE, "Not an armoury_entity! (%d)", index); return 0; @@ -1231,7 +1231,7 @@ static cell AMX_NATIVE_CALL cs_get_armoury_type(AMX *amx, cell *params) int weapontype = get_pdata(pArmoury, m_iItem);; int weapontype_out = 0; - switch (weapontype) + switch (weapontype) { case CSA_MP5NAVY: weapontype_out = CSW_MP5NAVY; break; case CSA_TMP: weapontype_out = CSW_TMP; break; @@ -1266,7 +1266,7 @@ static cell AMX_NATIVE_CALL cs_get_armoury_type(AMX *amx, cell *params) *MF_GetAmxAddr(amx, params[2]) = get_pdata(pArmoury, m_iCount); } - return weapontype_out; + return weapontype_out; } // native cs_set_armoury_type(index, type, count = -1); @@ -1357,7 +1357,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) int type = params[2]; int mode = params[3]; int weapon = *static_cast(MF_PlayerPropAddr(index, Player_CurrentWeapon)); - + Players[index].ResetZoom(); if (type == CS_RESET_ZOOM) @@ -1482,7 +1482,7 @@ static cell AMX_NATIVE_CALL cs_get_user_lastactivity(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - + return amx_ftoc(get_pdata(pPlayer, m_fLastMovement)); } @@ -1495,7 +1495,7 @@ static cell AMX_NATIVE_CALL cs_set_user_lastactivity(AMX *amx, cell *params) CHECK_PLAYER(index); edict_t *pPlayer = MF_GetPlayerEdict(index); - + set_pdata(pPlayer, m_fLastMovement, amx_ctof(params[2])); return 1; @@ -1536,12 +1536,12 @@ static cell AMX_NATIVE_CALL cs_get_hostage_lastuse(AMX *amx, cell *params) GET_OFFSET("CHostage", m_improv); int index = params[1]; - + CHECK_NONPLAYER(index); edict_t *pHostage = INDEXENT(index); CHECK_HOSTAGE(pHostage); - + void *pImprov = get_pdata(pHostage, m_improv); if (pImprov) // Specific to CZ @@ -1567,7 +1567,7 @@ static cell AMX_NATIVE_CALL cs_set_hostage_lastuse(AMX *amx, cell *params) edict_t *pHostage = INDEXENT(index); CHECK_HOSTAGE(pHostage); - + void *pImprov = get_pdata(pHostage, m_improv); if (pImprov) // Specific to CZ @@ -1594,7 +1594,7 @@ static cell AMX_NATIVE_CALL cs_get_hostage_nextuse(AMX* amx, cell* params) edict_t *pHostage = INDEXENT(index); CHECK_HOSTAGE(pHostage); - + return amx_ftoc(get_pdata(pHostage, m_flNextChange)); } @@ -1755,7 +1755,7 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) int length; void* pEntity = G_HL_TypeConversion.id_to_cbase(params[1]); const char* value = MF_GetAmxString(amx, params[2], 0, &length); - + edict_t *pOwner = GETEDICT(owner); while ((pEntity = CS_UTIL_FindEntityByString(pEntity, "classname", value))) @@ -1769,7 +1769,7 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) if (index != -1) { return index; - }; + } } } @@ -1898,7 +1898,7 @@ static cell AMX_NATIVE_CALL cs_get_weapon_info(AMX* amx, cell* params) } -AMX_NATIVE_INFO CstrikeNatives[] = +AMX_NATIVE_INFO CstrikeNatives[] = { {"cs_set_user_money", cs_set_user_money}, {"cs_get_user_money", cs_get_user_money}, From d08e1357dd8dab5d8cba2e3cbab5dbaee005f972 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Wed, 9 Sep 2015 01:06:54 +0200 Subject: [PATCH 14/15] Cstrike: Fix defuser/nvgs not being called with CS_OnBuy and fix wrong shield CSI constants --- modules/cstrike/cstrike/CstrikeHacks.cpp | 136 +++++++++++++++--- modules/cstrike/cstrike/CstrikeHacks.h | 1 + modules/cstrike/cstrike/CstrikeMain.cpp | 6 + modules/cstrike/cstrike/CstrikeNatives.cpp | 10 +- .../cstrike/cstrike/CstrikeUserMessages.cpp | 71 +++++++-- modules/cstrike/cstrike/CstrikeUserMessages.h | 2 +- modules/cstrike/cstrike/moduleconfig.h | 2 +- 7 files changed, 200 insertions(+), 28 deletions(-) diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index 78867578..f62813b7 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -40,10 +40,11 @@ GetWeaponInfoFunc GetWeaponInfo; int CurrentItemId; bool TriggeredFromCommand; -StringHashMap ItemAliasList; +// m_iTeam and m_iMenu from CBasePlayer. TypeDescription TeamDesc; TypeDescription MenuDesc; +// Engine global variables. server_static_t *ServerStatic; server_t *Server; @@ -80,16 +81,6 @@ const char *CMD_ARGV(int i) return g_engfuncs.pfnCmd_Argv(i); } -void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) -{ - // If shield is blocked with CS_OnBuy, we need to block the pickup sound ("items/gunpickup2.wav") - // as well played right after. Why this sound is not contained in GiveShield()? - - g_pengfuncsTable->pfnEmitSound = nullptr; - - RETURN_META(MRES_SUPERCEDE); -} - DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity) { const char *command = CMD_ARGV(0); @@ -97,7 +88,7 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma CurrentItemId = CSI_NONE; // Purpose is to retrieve an item id based on alias name or selected item from menu, - // to be used in OnBuy* forwards. + // to be used in CS_OnBuy* forwards. if ((ForwardOnBuyAttempt != -1 || ForwardOnBuy != -1) && command && *command) { int itemId = CSI_NONE; @@ -179,8 +170,41 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma return; } + // CS_OnBuy() + // - + // This forward should be called right before game gives the item. + // All items except shield, defuser and nvgs, games executes in the following order: + // GiveNamedItem -> AddAccount + // Forward is fired on GiveNamedItem. + // Shield only: + // GiveShield -> AddAccount -> EmitSound + // Forward is fired on GiveShield. + // Defusal kit only: + // m_bHasDefuser(true) -> StatusIcon -> pev_body(1) -> AddAccount -> EmitSound -> ItemStatus + // Forward is fired on StatusIcon. + // Nightvision only: + // EmitSound -> m_bHasNightVision(true) -> AddAccount -> ItemStatus + // Forward is fired on EmitSound. + TriggeredFromCommand = CurrentItemId != CSI_NONE; + if (TriggeredFromCommand) + { + if (CurrentItemId == CSI_NVGS) + { + g_pengfuncsTable->pfnEmitSound = OnEmitSound; + } + else if (CurrentItemId == CSI_DEFUSER) + { + GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasDefuser); + + if (!get_pdata(pEdict, m_bHasDefuser)) + { + EnableMessageHooks(); + } + } + } + DETOUR_STATIC_CALL(C_ClientCommand)(pEdict); TriggeredFromCommand = false; @@ -203,6 +227,69 @@ edict_s* OnCreateNamedEntity(int classname) RETURN_META_VALUE(MRES_IGNORED, 0); } +void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) +{ + if (TriggeredFromCommand) + { + switch (CurrentItemId) + { + case CSI_NVGS: + { + auto client = ENTINDEX(entity); + + if (!MF_IsPlayerAlive(client) || MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_NVGS) <= 0) + { + g_pengfuncsTable->pfnEmitSound = nullptr; + RETURN_META(MRES_IGNORED); + } + } + case CSI_DEFUSER: + case CSI_SHIELD: + { + g_pengfuncsTable->pfnEmitSound = nullptr; + RETURN_META(MRES_SUPERCEDE); + } + } + } + + RETURN_META(MRES_IGNORED); +} + +bool OnMessageItemStatus(edict_t *pPlayer) +{ + if (TriggeredFromCommand && (CurrentItemId == CSI_DEFUSER || CurrentItemId == CSI_NVGS)) + { + if (!g_pengfuncsTable->pfnEmitSound) + { + return true; // Block message + } + + DisableMessageHooks(); + } + + return false; +} + +bool OnMessageStatusIcon(edict_t *pPlayer) +{ + if (TriggeredFromCommand && CurrentItemId == CSI_DEFUSER) + { + auto client = ENTINDEX(pPlayer); + + if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_DEFUSER) > 0) + { + GET_OFFSET_NO_ERROR_RET("CBasePlayer", m_bHasDefuser); + set_pdata(pPlayer, m_bHasDefuser, false); + + return true; // Block message + } + + DisableMessageHooks(); + } + + return false; +} + DETOUR_DECL_MEMBER0(GiveDefaultItems, void) // void CBasePlayer::GiveDefaultItems(void) { if (NoKifesMode) @@ -234,11 +321,11 @@ DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlay DETOUR_DECL_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire) { - if (TriggeredFromCommand && CurrentItemId == CSI_SHIELDGUN) + if (TriggeredFromCommand && CurrentItemId == CSI_SHIELD) { int client = TypeConversion.cbase_to_id(this); - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELDGUN) > 0) + if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELD) > 0) { // If shield blocked, we need to hook EmitSound to block pickup sound played right after. g_pengfuncsTable->pfnEmitSound = OnEmitSound; @@ -256,9 +343,26 @@ DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void C { if (TriggeredFromCommand) { - if (CurrentItemId == CSI_NONE) + switch (CurrentItemId) { - return; + case CSI_DEFUSER: + { + G_HL_TypeConversion.cbase_to_entvar(this)->body = 0; + g_pengfuncsTable->pfnEmitSound = OnEmitSound; // To block pickup sound. + EnableMessageHooks(); // To block ItemStatus + break; + } + case CSI_NVGS: + { + GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasNightVision); + set_pdata(G_HL_TypeConversion.cbase_to_edict(this), m_bHasNightVision, false); + EnableMessageHooks(); // To block ItemStatus + break; + } + case CSI_NONE: + { + return; + } } } diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 52068f91..7ba53900 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -25,6 +25,7 @@ void InitGlobalVars(); void ShutdownHacks(); void ToggleDetour_ClientCommands(bool enable); void ToggleDetour_BuyCommands(bool enable); +void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); extern AMX_NATIVE_INFO CstrikeNatives[]; diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index f7148473..71648615 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -93,6 +93,12 @@ void OnServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) DisableMessageHooks(); } +void OnPluginsUnloaded() +{ + // Force to disable all hooks at map change. + DisableMessageHooks(true); +} + void OnAmxxDetach() { ConfigManager->RemoveUserConfigHook("CommandsAliases", &ItemsManager); diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index 84dccfe5..d9f5abfe 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -1358,7 +1358,13 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) int mode = params[3]; int weapon = *static_cast(MF_PlayerPropAddr(index, Player_CurrentWeapon)); - Players[index].ResetZoom(); + CPlayer& player = Players[index]; + + if (player.GetZoom()) + { + DisableMessageHooks(); + player.ResetZoom(); + } if (type == CS_RESET_ZOOM) { @@ -1406,7 +1412,7 @@ static cell AMX_NATIVE_CALL cs_set_user_zoom(AMX *amx, cell *params) if (!mode) { - Players[index].SetZoom(value); + player.SetZoom(value); EnableMessageHooks(); } diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.cpp b/modules/cstrike/cstrike/CstrikeUserMessages.cpp index b290713e..ee51a21d 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.cpp +++ b/modules/cstrike/cstrike/CstrikeUserMessages.cpp @@ -21,11 +21,13 @@ bool ShouldBlock; bool ShouldBlockHLTV; +bool ShouldDisableHooks; bool RetrieveWeaponName; ke::AString CurrentWeaponName; int ArgPosition; int MessageIdArmorType; +int MessageIdItemStatus; int MessageIdHLTV; int MessageIdMoney; int MessageIdResetHUD; @@ -37,6 +39,9 @@ int MessageIdTeamInfo; int MessageIdTextMsg; int MessageIdWeaponList; +extern bool OnMessageStatusIcon(edict_t *pPlayer); +extern bool OnMessageItemStatus(edict_t *pPlayer); + struct UserMsg { const char* name; @@ -46,6 +51,7 @@ struct UserMsg UserMsg MessagesList[] = { { "ArmorType" , &MessageIdArmorType }, + { "ItemStatus" , &MessageIdItemStatus }, { "HLTV" , &MessageIdHLTV }, { "Money" , &MessageIdMoney }, { "ResetHUD" , &MessageIdResetHUD }, @@ -105,7 +111,30 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p int index = ENTINDEX(pEntity); if (Players[index].GetZoom()) + { Players[index].ResetZoom(); + DisableMessageHooks(); + } + } + else if (msg_type == MessageIdStatusIcon) + { + if (OnMessageStatusIcon(pEntity)) + { + ShouldBlock = true; + ShouldDisableHooks = true; + + RETURN_META(MRES_SUPERCEDE); + } + } + else if (msg_type == MessageIdItemStatus) + { + if (OnMessageItemStatus(pEntity)) + { + ShouldBlock = true; + ShouldDisableHooks = true; + + RETURN_META(MRES_SUPERCEDE); + } } break; } @@ -139,11 +168,12 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p void OnWriteByte(int value) { - if (ShouldBlock) + if (ShouldBlock) { RETURN_META(MRES_SUPERCEDE); } - else if (RetrieveWeaponName && ++ArgPosition == 7 && value >= 0 && value < MAX_WEAPONS) + + if (RetrieveWeaponName && ++ArgPosition == 7 && value >= 0 && value < MAX_WEAPONS) { strncopy(WeaponNameList[value], CurrentWeaponName.chars(), sizeof(WeaponNameList[value])); } @@ -153,6 +183,11 @@ void OnWriteByte(int value) void OnWriteString(const char *value) { + if (ShouldBlock) + { + RETURN_META(MRES_SUPERCEDE); + } + if (RetrieveWeaponName) { CurrentWeaponName = value; @@ -166,9 +201,17 @@ void OnMessageEnd(void) if (ShouldBlock) { ShouldBlock = false; + + if (ShouldDisableHooks) + { + ShouldDisableHooks = false; + DisableMessageHooks(); + } + RETURN_META(MRES_SUPERCEDE); } - else if (RetrieveWeaponName) + + if (RetrieveWeaponName) { RetrieveWeaponName = false; ArgPosition = 0; @@ -177,8 +220,12 @@ void OnMessageEnd(void) RETURN_META(MRES_IGNORED); } +size_t RefCount; + void EnableMessageHooks() { + ++RefCount; + if (!g_pengfuncsTable->pfnMessageBegin) { g_pengfuncsTable->pfnMessageBegin = OnMessageBegin; @@ -188,10 +235,18 @@ void EnableMessageHooks() } } -void DisableMessageHooks() +void DisableMessageHooks(bool force) { - g_pengfuncsTable->pfnMessageBegin = nullptr; - g_pengfuncsTable->pfnWriteByte = nullptr; - g_pengfuncsTable->pfnWriteString = nullptr; - g_pengfuncsTable->pfnMessageEnd = nullptr; + if (force) + { + RefCount = 1; + } + + if (--RefCount == 0) + { + g_pengfuncsTable->pfnMessageBegin = nullptr; + g_pengfuncsTable->pfnWriteByte = nullptr; + g_pengfuncsTable->pfnWriteString = nullptr; + g_pengfuncsTable->pfnMessageEnd = nullptr; + } } diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.h b/modules/cstrike/cstrike/CstrikeUserMessages.h index 7541ad1a..eae0ed15 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.h +++ b/modules/cstrike/cstrike/CstrikeUserMessages.h @@ -26,6 +26,6 @@ extern int MessageIdTeamInfo; extern int MessageIdTextMsg; void EnableMessageHooks(); -void DisableMessageHooks(); +void DisableMessageHooks(bool force = false); #endif // CSTRIKE_USER_MESSAGES_H diff --git a/modules/cstrike/cstrike/moduleconfig.h b/modules/cstrike/cstrike/moduleconfig.h index 6438f750..adeeea39 100644 --- a/modules/cstrike/cstrike/moduleconfig.h +++ b/modules/cstrike/cstrike/moduleconfig.h @@ -80,7 +80,7 @@ //#define FN_AMXX_PLUGINSUNLOADING OnPluginsUnloading /** All plugins are now unloaded */ -//#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded +#define FN_AMXX_PLUGINSUNLOADED OnPluginsUnloaded /**** METAMOD ****/ From a445e806ea45bd9c09e2121c68d8d5273891ffa1 Mon Sep 17 00:00:00 2001 From: Arkshine Date: Thu, 8 Oct 2015 20:53:14 +0200 Subject: [PATCH 15/15] Cstrike: Refactor - Simplify forwards logic, fix and improve few things - The logic around CS_OnBuy forward has been simplified. Since there is no way to have a consistent way to hook/block for all items, the new logic is to have as less as possible code, especially in blocking mode where we want to avoid to do extra stuffs (e.g blocking sound, event, etc). * All guns + shield -> CanBuyThis() * Nvgs and Fefuser only -> CanPlayerBuy() * The others items -> GiveNamedItem() + AddAccount() * Ammos -> -> BuyGunAmmo() + GiveNamedItem() + AddAccount() - Fixed missing buyzone check when alias from console are used (CS_OnBUy* were incorrectly fired). - Fixed an infinite loop when buying of ammos are blocked. Sorted by hooking BuyGunAmmo(). - Fixed blocking mode for some items. Some game behaviors were not blocked (e.g. weapon drop). - Fixed forwards being triggered even though errors were found. Detours are now a destroyed and associated variables resetted when necessary. Toggling forwards state is now based on detours state. - Moved things in its own functions (game functions to execute, class members retrieval) - Renamed CommandAliases -> ItemInfos (more generic) --- gamedata/modules.games/game.cstrike.txt | 74 ++- modules/cstrike/cstrike/AMBuilder | 2 +- modules/cstrike/cstrike/CstrikeDatas.h | 64 +- modules/cstrike/cstrike/CstrikeHacks.cpp | 572 +++++++++--------- modules/cstrike/cstrike/CstrikeHacks.h | 26 +- modules/cstrike/cstrike/CstrikeItemsInfos.cpp | 52 +- modules/cstrike/cstrike/CstrikeItemsInfos.h | 22 +- modules/cstrike/cstrike/CstrikeMain.cpp | 44 +- modules/cstrike/cstrike/CstrikeNatives.cpp | 26 +- .../cstrike/cstrike/CstrikeUserMessages.cpp | 25 +- modules/cstrike/cstrike/CstrikeUtils.h | 7 +- plugins/include/cstrike_const.inc | 92 ++- public/HLTypeConversion.h | 5 + 13 files changed, 635 insertions(+), 376 deletions(-) diff --git a/gamedata/modules.games/game.cstrike.txt b/gamedata/modules.games/game.cstrike.txt index bf5de7b2..dbf6578c 100644 --- a/gamedata/modules.games/game.cstrike.txt +++ b/gamedata/modules.games/game.cstrike.txt @@ -15,6 +15,22 @@ { "Signatures" { + "CanPlayerBuy" // bool CBasePlayer::CanPlayerBuy(bool display) + { + "library" "server" + "windows" "\x51\x53\x55\x56\x57\x8B\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x8B\x2A\xFF" + "linux" "@_ZN11CBasePlayer12CanPlayerBuyEb" + "mac" "@_ZN11CBasePlayer12CanPlayerBuyEb" + } + + "CanBuyThis" // bool CanBuyThis(CBasePlayer *pPlayer, int weaponId) + { + "library" "server" + "windows" "\x53\x8B\x2A\x2A\x2A\x2A\x2A\x56\x8B\x2A\x2A\x2A\x57\x8B" + "linux" "@_Z10CanBuyThisP11CBasePlayeri" + "mac" "@_Z10CanBuyThisP11CBasePlayeri" + } + "AddAccount" // void CBasePlayer::AddAccount(int amount, bool bTrackChange) { "library" "server" @@ -70,6 +86,22 @@ "linux" "@_Z13GetWeaponInfoi" "mac" "@_Z13GetWeaponInfoi" } + + "GetAmmoIndex" // int CBasePlayer::GetAmmoIndex(const char *psz) + { + "library" "server" + "windows" "\x56\x57\x8B\x2A\x2A\x2A\x85\x2A\x74\x2A\xBE" + "linux" "@_ZN11CBasePlayer12GetAmmoIndexEPKc" + "mac" "@_ZN11CBasePlayer12GetAmmoIndexEPKc" + } + + "BuyGunAmmo" // bool BuyGunAmmo(CBasePlayer *player, CBasePlayerItem *weapon, bool bBlinkMoney) + { + "library" "server" + "windows" "\x56\x57\x8B\x2A\x2A\x2A\x6A\x2A\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x84\x2A\x0F" + "linux" "@_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb" + "mac" "@_Z10BuyGunAmmoR11CBasePlayerR15CBasePlayerItemb" + } } } @@ -110,9 +142,9 @@ "#default" { - "CommandsAliases" + "ItemInfos" { - "Common" + "CommonAlias" { "p228" { @@ -241,7 +273,7 @@ } } - "Weapon" + "WeaponAlias" { "grenade" { @@ -280,7 +312,7 @@ } } - "Buy" + "BuyAlias" { "228compact" { @@ -374,52 +406,58 @@ } } - "BuyEquip" + "BuyEquipAlias" { "hegren" { "itemid" "4" // CSW/I_HEGRENADE "classid" "3" // CS_WEAPONCLASS_GRENADE + "price" "300" } "sgren" { "itemid" "9" // CSW/I_SMOKEGRENADE "classid" "3" // CS_WEAPONCLASS_GRENADE + "price" "300" } "flash" { - "itemid" "25" // CSW/I_FLASHBANG + "itemid" "25" // CSW/I_FLASHBANG "classid" "3" // CS_WEAPONCLASS_GRENADE + "price" "200" } "vest" { - "itemid" "31" // CSW/I_VEST - "classname" "item_kevlar" + "itemid" "31" // CSW/I_VEST + "classname" "item_kevlar" + "price" "650" } "vesthelm" { - "itemid" "32" // CSW/I_VESTHELM - "classname" "item_assaultsuit" + "itemid" "32" // CSW/I_VESTHELM + "classname" "item_assaultsuit" + "price" "1000" } "defuser" { - "itemid" "33" // CSI_DEFUSER - "classname" "item_thighpack" + "itemid" "33" // CSI_DEFUSER + "classname" "item_thighpack" + "price" "200" } "nvgs" { - "itemid" "34" // CSI_NVGS - + "itemid" "34" // CSI_NVGS + "price" "1250" } "shield" { - "itemid" "35" // CSI_SHIELD - "classid" "2" // CS_WEAPONCLASS_PISTOL - "classname" "weapon_shield" + "itemid" "35" // CSI_SHIELD + "classid" "2" // CS_WEAPONCLASS_PISTOL + "classname" "weapon_shield" } } - "BuyAmmo" + "BuyAmmoAlias" { "primammo" { diff --git a/modules/cstrike/cstrike/AMBuilder b/modules/cstrike/cstrike/AMBuilder index 17ede82c..3c86c911 100644 --- a/modules/cstrike/cstrike/AMBuilder +++ b/modules/cstrike/cstrike/AMBuilder @@ -15,7 +15,7 @@ binary.sources = [ 'CstrikeHacks.cpp', 'CstrikeUtils.cpp', 'CstrikeUserMessages.cpp', - 'CstrikeitemsInfos.cpp', + 'CstrikeItemsInfos.cpp', '../../../public/memtools/MemoryUtils.cpp', '../../../public/memtools/CDetour/detours.cpp', '../../../public/memtools/CDetour/asm/asm.c', diff --git a/modules/cstrike/cstrike/CstrikeDatas.h b/modules/cstrike/cstrike/CstrikeDatas.h index eabf8083..607d7895 100644 --- a/modules/cstrike/cstrike/CstrikeDatas.h +++ b/modules/cstrike/cstrike/CstrikeDatas.h @@ -55,11 +55,12 @@ #define CSI_PRIAMMO 36 // Custom #define CSI_SECAMMO 37 // Custom #define CSI_MAX_COUNT 38 +#define CSI_LAST_WEAPON CSW_LAST_WEAPON -#define CSI_ALL_WEAPONS CSW_ALL_WEAPONS +#define CSI_ALL_WEAPONS CSW_ALL_WEAPONS #define CSI_ALL_PISTOLS CSW_ALL_PISTOLS #define CSI_ALL_SHOTGUNS CSW_ALL_SHOTGUNS -#define CSI_ALL_SMGS CSW_ALL_SMGS +#define CSI_ALL_SMGS CSW_ALL_SMGS #define CSI_ALL_RIFLES CSW_ALL_RIFLES #define CSI_ALL_SNIPERRIFLES CSW_ALL_SNIPERRIFLES #define CSI_ALL_MACHINEGUNS CSW_ALL_MACHINEGUNS @@ -107,12 +108,12 @@ #define CSW_ALL_WEAPONS (~(1 << CSW_VEST)) #define CSW_ALL_PISTOLS (1 << CSW_P228 | 1 << CSW_ELITE | 1 << CSW_FIVESEVEN | 1 << CSW_USP | 1 << CSW_GLOCK18 | 1 << CSW_DEAGLE) -#define CSW_ALL_SHOTGUNS (1 << CSW_M3 | 1 << CSW_XM1014)) -#define CSW_ALL_SMGS (1 << CSW_MAC10 | 1 << CSW_UMP45 | 1 << CSW_MP5NAVY | 1 << CSW_TMP | 1 << CSW_P90)) -#define CSW_ALL_RIFLES (1 << CSW_AUG | 1 << CSW_GALIL | 1 << CSW_FAMAS | 1 << CSW_M4A1 | 1 << CSW_AK47 | 1 << CSW_SG552)) -#define CSW_ALL_SNIPERRIFLES (1 << CSW_SCOUT | 1 << CSW_AWP | 1 << CSW_G3SG1 | 1 << CSW_SG550)) -#define CSW_ALL_MACHINEGUNS (1 << CSW_M249)) -#define CSW_ALL_GRENADES (1 << CSW_HEGRENADE | 1 << CSW_SMOKEGRENADE | 1 << CSW_FLASHBANG)) +#define CSW_ALL_SHOTGUNS (1 << CSW_M3 | 1 << CSW_XM1014) +#define CSW_ALL_SMGS (1 << CSW_MAC10 | 1 << CSW_UMP45 | 1 << CSW_MP5NAVY | 1 << CSW_TMP | 1 << CSW_P90) +#define CSW_ALL_RIFLES (1 << CSW_AUG | 1 << CSW_GALIL | 1 << CSW_FAMAS | 1 << CSW_M4A1 | 1 << CSW_AK47 | 1 << CSW_SG552) +#define CSW_ALL_SNIPERRIFLES (1 << CSW_SCOUT | 1 << CSW_AWP | 1 << CSW_G3SG1 | 1 << CSW_SG550) +#define CSW_ALL_MACHINEGUNS (1 << CSW_M249) +#define CSW_ALL_GRENADES (1 << CSW_HEGRENADE | 1 << CSW_SMOKEGRENADE | 1 << CSW_FLASHBANG) #define CSW_ALL_ARMORS (1 << CSW_VEST | 1 << CSW_VESTHELM) #define CSW_ALL_GUNS (CSW_ALL_PISTOLS | CSW_ALL_SHOTGUNS | CSW_ALL_SMGS | CSW_ALL_RIFLES | CSW_ALL_SNIPERRIFLES | CSW_ALL_MACHINEGUNS) @@ -349,6 +350,51 @@ enum CsWeaponInfo CS_WEAPONINFO_AMMO_TYPE = 5, }; -extern char WeaponNameList[MAX_WEAPONS][64]; +/** + * Weapon default cost. + */ +enum WeaponCostType +{ + AK47_PRICE = 2500, + AWP_PRICE = 4750, + DEAGLE_PRICE = 650, + G3SG1_PRICE = 5000, + SG550_PRICE = 4200, + GLOCK18_PRICE = 400, + M249_PRICE = 5750, + M3_PRICE = 1700, + M4A1_PRICE = 3100, + AUG_PRICE = 3500, + MP5NAVY_PRICE = 1500, + P228_PRICE = 600, + P90_PRICE = 2350, + UMP45_PRICE = 1700, + MAC10_PRICE = 1400, + SCOUT_PRICE = 2750, + SG552_PRICE = 3500, + TMP_PRICE = 1250, + USP_PRICE = 500, + ELITE_PRICE = 800, + FIVESEVEN_PRICE = 750, + XM1014_PRICE = 3000, + GALIL_PRICE = 2000, + FAMAS_PRICE = 2250, + SHIELDGUN_PRICE = 2200 +}; + +/** + * Equipment default cost. + */ +enum ItemCostType +{ + ASSAULTSUIT_PRICE = 1000, + FLASHBANG_PRICE = 200, + HEGRENADE_PRICE = 300, + SMOKEGRENADE_PRICE = 300, + KEVLAR_PRICE = 650, + HELMET_PRICE = 350, + NVG_PRICE = 1250, + DEFUSEKIT_PRICE = 200 +}; #endif // CSTRIKE_DATA_H diff --git a/modules/cstrike/cstrike/CstrikeHacks.cpp b/modules/cstrike/cstrike/CstrikeHacks.cpp index f62813b7..aadae09f 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.cpp +++ b/modules/cstrike/cstrike/CstrikeHacks.cpp @@ -14,16 +14,16 @@ #include "CstrikeDatas.h" #include "CstrikeUtils.h" #include "CstrikeHacks.h" -#include - -void CtrlDetours_ClientCommand(bool set); -void CtrlDetours_BuyCommands(bool set); -void CtrlDetours_Natives(bool set); +#include "CstrikeItemsInfos.h" int ForwardInternalCommand = -1; int ForwardOnBuy = -1; int ForwardOnBuyAttempt = -1; +bool HasInternalCommandForward; +bool HasOnBuyAttemptForward; +bool HasOnBuyForward; + int *UseBotArgs; const char **BotArgs; @@ -31,7 +31,10 @@ CDetour *ClientCommandDetour; CDetour *GiveShieldDetour; CDetour *GiveNamedItemDetour; CDetour *AddAccountDetour; +CDetour *CanPlayerBuyDetour; +CDetour *CanBuyThisDetour; CDetour *GiveDefaultItemsDetour; +CDetour *BuyGunAmmoDetour; CreateNamedEntityFunc CS_CreateNamedEntity; UTIL_FindEntityByStringFunc CS_UTIL_FindEntityByString; @@ -39,21 +42,36 @@ GetWeaponInfoFunc GetWeaponInfo; int CurrentItemId; bool TriggeredFromCommand; +bool BlockMoneyUpdate; +bool BlockAmmosUpdate; -// m_iTeam and m_iMenu from CBasePlayer. +// CBasePlayer members. TypeDescription TeamDesc; TypeDescription MenuDesc; +TypeDescription NvgsDesc; +TypeDescription DefuserDesc; +TypeDescription SignalsDesc; +TypeDescription MoneyDesc; + +// GameRules members. +TypeDescription BombTargetDesc; // Engine global variables. server_static_t *ServerStatic; server_t *Server; +// Mod global variable +void **GameRules; + + void InitializeHacks() { CtrlDetours_ClientCommand(true); CtrlDetours_BuyCommands(true); CtrlDetours_Natives(true); + InitFuncsAddresses(); + InitClassMembers(); InitGlobalVars(); } @@ -83,13 +101,13 @@ const char *CMD_ARGV(int i) DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientCommand(edict_t *pEntity) { - const char *command = CMD_ARGV(0); + auto command = CMD_ARGV(0); CurrentItemId = CSI_NONE; // Purpose is to retrieve an item id based on alias name or selected item from menu, // to be used in CS_OnBuy* forwards. - if ((ForwardOnBuyAttempt != -1 || ForwardOnBuy != -1) && command && *command) + if ((HasOnBuyAttemptForward || HasOnBuyForward) && command && *command) { int itemId = CSI_NONE; @@ -141,78 +159,40 @@ DETOUR_DECL_STATIC1(C_ClientCommand, void, edict_t*, pEdict) // void ClientComma } else // Handling buy via alias { - AliasInfo info; - - if (ItemsManager.GetAliasInfosFromBuy(command, &info)) + if (get_pdata(pEdict, SignalsDesc.fieldOffset).GetState() & SIGNAL_BUY) // Are we inside the buy zone? { - CurrentItemId = info.itemid; + AliasInfo info; + + if (ItemsManager.GetAliasInfosFromBuy(command, &info)) + { + CurrentItemId = info.itemid; + } } } } - int client = ENTINDEX(pEdict); + auto client = TypeConversion.edict_to_id(pEdict); - if (ForwardInternalCommand != -1 && *UseBotArgs) - { - const char *args = *BotArgs; - - if (MF_ExecuteForward(ForwardInternalCommand, static_cast(client), args) > 0) - { - return; - } - } - - if (ForwardOnBuyAttempt != -1 && - CurrentItemId && - MF_IsPlayerAlive(client) && - MF_ExecuteForward(ForwardOnBuyAttempt, static_cast(client), static_cast(CurrentItemId)) > 0) + if (HasInternalCommandForward && *UseBotArgs && MF_ExecuteForward(ForwardInternalCommand, client, *BotArgs) > 0) { return; } - // CS_OnBuy() - // - - // This forward should be called right before game gives the item. - // All items except shield, defuser and nvgs, games executes in the following order: - // GiveNamedItem -> AddAccount - // Forward is fired on GiveNamedItem. - // Shield only: - // GiveShield -> AddAccount -> EmitSound - // Forward is fired on GiveShield. - // Defusal kit only: - // m_bHasDefuser(true) -> StatusIcon -> pev_body(1) -> AddAccount -> EmitSound -> ItemStatus - // Forward is fired on StatusIcon. - // Nightvision only: - // EmitSound -> m_bHasNightVision(true) -> AddAccount -> ItemStatus - // Forward is fired on EmitSound. + if (HasOnBuyAttemptForward && CurrentItemId && MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuyAttempt, client, CurrentItemId) > 0) + { + return; + } TriggeredFromCommand = CurrentItemId != CSI_NONE; - if (TriggeredFromCommand) - { - if (CurrentItemId == CSI_NVGS) - { - g_pengfuncsTable->pfnEmitSound = OnEmitSound; - } - else if (CurrentItemId == CSI_DEFUSER) - { - GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasDefuser); - - if (!get_pdata(pEdict, m_bHasDefuser)) - { - EnableMessageHooks(); - } - } - } - DETOUR_STATIC_CALL(C_ClientCommand)(pEdict); - TriggeredFromCommand = false; + TriggeredFromCommand = BlockMoneyUpdate = BlockAmmosUpdate = false; } edict_s* OnCreateNamedEntity(int classname) { - if (NoKifesMode) + if (NoKnivesMode) { if (!strcmp(STRING(classname), "weapon_knife")) { @@ -224,75 +204,12 @@ edict_s* OnCreateNamedEntity(int classname) g_pengfuncsTable->pfnCreateNamedEntity = nullptr; } - RETURN_META_VALUE(MRES_IGNORED, 0); -} - -void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) -{ - if (TriggeredFromCommand) - { - switch (CurrentItemId) - { - case CSI_NVGS: - { - auto client = ENTINDEX(entity); - - if (!MF_IsPlayerAlive(client) || MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_NVGS) <= 0) - { - g_pengfuncsTable->pfnEmitSound = nullptr; - RETURN_META(MRES_IGNORED); - } - } - case CSI_DEFUSER: - case CSI_SHIELD: - { - g_pengfuncsTable->pfnEmitSound = nullptr; - RETURN_META(MRES_SUPERCEDE); - } - } - } - - RETURN_META(MRES_IGNORED); -} - -bool OnMessageItemStatus(edict_t *pPlayer) -{ - if (TriggeredFromCommand && (CurrentItemId == CSI_DEFUSER || CurrentItemId == CSI_NVGS)) - { - if (!g_pengfuncsTable->pfnEmitSound) - { - return true; // Block message - } - - DisableMessageHooks(); - } - - return false; -} - -bool OnMessageStatusIcon(edict_t *pPlayer) -{ - if (TriggeredFromCommand && CurrentItemId == CSI_DEFUSER) - { - auto client = ENTINDEX(pPlayer); - - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_DEFUSER) > 0) - { - GET_OFFSET_NO_ERROR_RET("CBasePlayer", m_bHasDefuser); - set_pdata(pPlayer, m_bHasDefuser, false); - - return true; // Block message - } - - DisableMessageHooks(); - } - - return false; + RETURN_META_VALUE(MRES_IGNORED, nullptr); } DETOUR_DECL_MEMBER0(GiveDefaultItems, void) // void CBasePlayer::GiveDefaultItems(void) { - if (NoKifesMode) + if (NoKnivesMode) { g_pengfuncsTable->pfnCreateNamedEntity = OnCreateNamedEntity; } @@ -302,133 +219,199 @@ DETOUR_DECL_MEMBER0(GiveDefaultItems, void) // void CBasePlayer::GiveDefaultIte g_pengfuncsTable->pfnCreateNamedEntity = nullptr; } +DETOUR_DECL_MEMBER1(CanPlayerBuy, bool, bool, display) // bool CBasePlayer::CanPlayerBuy(bool display) +{ + auto canBuy = DETOUR_MEMBER_CALL(CanPlayerBuy)(display); + + if (!canBuy || !TriggeredFromCommand || !(CurrentItemId == CSI_NVGS || CurrentItemId == CSI_DEFUSER)) + { + return canBuy; + } + + auto pPlayer = TypeConversion.cbase_to_edict(this); + auto playerId = TypeConversion.edict_to_id(pPlayer); + + if (!MF_IsPlayerAlive(playerId)) + { + return canBuy; + } + + auto allowedToBuy = false; + auto itemPrice = ItemsManager.GetItemPrice(CurrentItemId); + + switch (CurrentItemId) + { + case CSI_NVGS: + { + allowedToBuy = !get_pdata(pPlayer, NvgsDesc.fieldOffset) && + get_pdata(pPlayer, MoneyDesc.fieldOffset) >= itemPrice; + break; + } + case CSI_DEFUSER: + { + allowedToBuy = !get_pdata(pPlayer, DefuserDesc.fieldOffset) && + get_pdata(pPlayer, TeamDesc.fieldOffset) == TEAM_CT && + get_pdata(*GameRules, BombTargetDesc.fieldOffset) && + get_pdata(pPlayer, MoneyDesc.fieldOffset) >= itemPrice; + break; + } + } + + if (allowedToBuy && MF_ExecuteForward(ForwardOnBuy, playerId, CurrentItemId) > 0) + { + canBuy = false; + } + + return canBuy; +} + +DETOUR_DECL_STATIC2(CanBuyThis, bool, void*, pvPlayer, int, weaponId) // bool CanBuyThis(CBasePlayer *pPlayer, int weaponId) +{ + auto canBuy = DETOUR_STATIC_CALL(CanBuyThis)(pvPlayer, weaponId); + + if (!canBuy || !TriggeredFromCommand || !((1 << CurrentItemId & CSI_ALL_GUNS) || CurrentItemId == CSI_SHIELD)) + { + return canBuy; + } + + auto playerId = TypeConversion.cbase_to_id(pvPlayer); + + if (MF_IsPlayerAlive(playerId) && get_pdata(pvPlayer, MoneyDesc.fieldOffset) >= ItemsManager.GetItemPrice(CurrentItemId)) + { + if (MF_ExecuteForward(ForwardOnBuy, playerId, CurrentItemId) > 0) + { + canBuy = false; + } + } + + return canBuy; +} + +DETOUR_DECL_STATIC3(BuyGunAmmo, bool, void*, player, int, nSlot, bool, bBlinkMoney) // bool BuyGunAmmo(CBasePlayer *player, int nSlot, bool bBlinkMoney) +{ + auto result = DETOUR_STATIC_CALL(BuyGunAmmo)(player, nSlot, bBlinkMoney); + + if (result && BlockAmmosUpdate) + { + BlockAmmosUpdate = false; + return false; + } + + return result; +} + DETOUR_DECL_MEMBER1(GiveNamedItem, void, const char*, pszName) // void CBasePlayer::GiveNamedItem(const char *pszName) { if (TriggeredFromCommand) { - int client = TypeConversion.cbase_to_id(this); - - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), static_cast(CurrentItemId)) > 0) + switch (CurrentItemId) { - // Reset this to not call AddAccount() called right after. - CurrentItemId = CSI_NONE; - return; + case CSI_VEST: + case CSI_VESTHELM: + case CSI_FLASHBANG: + case CSI_HEGRENADE: + case CSI_SMOKEGRENADE: + case CSI_PRIAMMO: + case CSI_SECAMMO: + { + auto playerId = TypeConversion.cbase_to_id(this); + + if (MF_IsPlayerAlive(playerId) && MF_ExecuteForward(ForwardOnBuy, playerId, CurrentItemId) > 0) + { + BlockAmmosUpdate = CurrentItemId == CSI_PRIAMMO || CurrentItemId == CSI_SECAMMO; + BlockMoneyUpdate = true; + return; + } + } } } DETOUR_MEMBER_CALL(GiveNamedItem)(pszName); } -DETOUR_DECL_MEMBER1(GiveShield, void, bool, bRetire) // void CBasePlayer::GiveShield(bool bRetire) -{ - if (TriggeredFromCommand && CurrentItemId == CSI_SHIELD) - { - int client = TypeConversion.cbase_to_id(this); - - if (MF_IsPlayerAlive(client) && MF_ExecuteForward(ForwardOnBuy, static_cast(client), CSI_SHIELD) > 0) - { - // If shield blocked, we need to hook EmitSound to block pickup sound played right after. - g_pengfuncsTable->pfnEmitSound = OnEmitSound; - - // Reset this to not call AddAccount() called right after. - CurrentItemId = CSI_NONE; - return; - } - } - - DETOUR_MEMBER_CALL(GiveShield)(bRetire); -} - DETOUR_DECL_MEMBER2(AddAccount, void, int, amount, bool, bTrackChange) // void CBasePlayer::AddAccount(int amount, bool bTrackChange) { - if (TriggeredFromCommand) + if (BlockMoneyUpdate) { - switch (CurrentItemId) - { - case CSI_DEFUSER: - { - G_HL_TypeConversion.cbase_to_entvar(this)->body = 0; - g_pengfuncsTable->pfnEmitSound = OnEmitSound; // To block pickup sound. - EnableMessageHooks(); // To block ItemStatus - break; - } - case CSI_NVGS: - { - GET_OFFSET_NO_ERROR("CBasePlayer", m_bHasNightVision); - set_pdata(G_HL_TypeConversion.cbase_to_edict(this), m_bHasNightVision, false); - EnableMessageHooks(); // To block ItemStatus - break; - } - case CSI_NONE: - { - return; - } - } + BlockMoneyUpdate = false; + return; } DETOUR_MEMBER_CALL(AddAccount)(amount, bTrackChange); } +void ToggleDetour(CDetour *detour, bool enable) +{ + if (detour) + { + (enable) ? detour->EnableDetour() : detour->DisableDetour(); + } +} + +void DestroyDetour(CDetour *&detour) +{ + if (detour) + { + detour->Destroy(); + detour = nullptr; + } +} + + void CtrlDetours_ClientCommand(bool set) { if (set) { - void *base = reinterpret_cast(MDLL_ClientCommand); + auto base = reinterpret_cast(MDLL_ClientCommand); -#if defined(WIN32) +#if defined(KE_WINDOWS) TypeDescription type; if (MainConfig->GetOffset("UseBotArgs", &type)) { - UseBotArgs = get_pdata(base, type.fieldOffset); + UseBotArgs = get_pdata(base, type.fieldOffset); } if (MainConfig->GetOffset("BotArgs", &type)) { - BotArgs = get_pdata(base, type.fieldOffset); + BotArgs = get_pdata(base, type.fieldOffset); } - -#elif defined(__linux__) || defined(__APPLE__) - +#else void *address = nullptr; if (MainConfig->GetMemSig("UseBotArgs", &address)) { - UseBotArgs = reinterpret_cast(address); + UseBotArgs = reinterpret_cast(address); } if (MainConfig->GetMemSig("BotArgs", &address)) { - BotArgs = reinterpret_cast(address); + BotArgs = reinterpret_cast(address); } #endif ClientCommandDetour = DETOUR_CREATE_STATIC_FIXED(C_ClientCommand, base); - CommonConfig->GetOffsetByClass("CBasePlayer", "m_iTeam", &TeamDesc); - CommonConfig->GetOffsetByClass("CBasePlayer", "m_iMenu", &MenuDesc); - - if (!ClientCommandDetour || !UseBotArgs || !BotArgs || !TeamDesc.fieldOffset || !MenuDesc.fieldOffset) + if (!ClientCommandDetour) { - MF_Log("ClientCommand is not available - forward client_command has been disabled"); + MF_Log("ClientCommand is not available - forwards CS_InternalCommand and CS_OnBuy[Attempt] have been disabled"); + CtrlDetours_ClientCommand(false); + } + else if (!UseBotArgs || !BotArgs) + { + MF_Log("UseBotArgs or BotArgs is not available - forward CS_InternalCommand has been disabled"); } } else { - if (ClientCommandDetour) - { - ClientCommandDetour->Destroy(); - } + DestroyDetour(ClientCommandDetour); } } void ToggleDetour_ClientCommands(bool enable) { - if (ClientCommandDetour) - { - (enable) ? ClientCommandDetour->EnableDetour() : ClientCommandDetour->DisableDetour(); - } + ToggleDetour(ClientCommandDetour, enable); } @@ -438,9 +421,9 @@ void CtrlDetours_BuyCommands(bool set) { void *address = nullptr; - if (MainConfig->GetMemSig("GiveShield", &address)) + if (MainConfig->GetMemSig("BuyGunAmmo", &address)) { - GiveShieldDetour = DETOUR_CREATE_MEMBER_FIXED(GiveShield, address); + BuyGunAmmoDetour = DETOUR_CREATE_STATIC_FIXED(BuyGunAmmo, address); } if (MainConfig->GetMemSig("GiveNamedItem", &address)) @@ -453,11 +436,21 @@ void CtrlDetours_BuyCommands(bool set) AddAccountDetour = DETOUR_CREATE_MEMBER_FIXED(AddAccount, address); } - if (!GiveShieldDetour || !GiveNamedItemDetour || !AddAccountDetour) + if (MainConfig->GetMemSig("CanPlayerBuy", &address)) { - if (!GiveShieldDetour) + CanPlayerBuyDetour = DETOUR_CREATE_MEMBER_FIXED(CanPlayerBuy, address); + } + + if (MainConfig->GetMemSig("CanBuyThis", &address)) + { + CanBuyThisDetour = DETOUR_CREATE_STATIC_FIXED(CanBuyThis, address); + } + + if (!BuyGunAmmoDetour || !GiveNamedItemDetour || !AddAccountDetour || !CanPlayerBuyDetour || !CanBuyThisDetour) + { + if (!BuyGunAmmoDetour) { - MF_Log("GiveShield is not available"); + MF_Log("BuyGunAmmo is not available"); } if (!GiveNamedItemDetour) @@ -470,84 +463,46 @@ void CtrlDetours_BuyCommands(bool set) MF_Log("AddAccount is not available"); } - MF_Log("Some functions are not available - forward CS_OnBuyAttempt and CS_OnBuy have been disabled"); + if (!CanPlayerBuyDetour) + { + MF_Log("CanPlayerBuy is not available"); + } + + if (!CanBuyThisDetour) + { + MF_Log("CanBuyThis is not available"); + } + + MF_Log("Some functions are not available - forwards CS_OnBuy[Attempt] have been disabled"); + ToggleDetour_BuyCommands(false); } } else { - if (GiveShieldDetour) - { - GiveShieldDetour->Destroy(); - } - - if (GiveNamedItemDetour) - { - GiveNamedItemDetour->Destroy(); - } - - if (AddAccountDetour) - { - AddAccountDetour->Destroy(); - } + DestroyDetour(BuyGunAmmoDetour); + DestroyDetour(GiveNamedItemDetour); + DestroyDetour(AddAccountDetour); + DestroyDetour(CanPlayerBuyDetour); + DestroyDetour(CanBuyThisDetour); } } void ToggleDetour_BuyCommands(bool enable) { - if (GiveShieldDetour) - { - (enable) ? GiveShieldDetour->EnableDetour() : GiveShieldDetour->DisableDetour(); - } - - if (GiveNamedItemDetour) - { - (enable) ? GiveNamedItemDetour->EnableDetour() : GiveNamedItemDetour->DisableDetour(); - } - - if (AddAccountDetour) - { - (enable) ? AddAccountDetour->EnableDetour() : AddAccountDetour->DisableDetour(); - } + ToggleDetour(BuyGunAmmoDetour, enable); + ToggleDetour(GiveNamedItemDetour, enable); + ToggleDetour(AddAccountDetour, enable); + ToggleDetour(CanPlayerBuyDetour, enable); + ToggleDetour(CanBuyThisDetour, enable); } + void CtrlDetours_Natives(bool set) { if (set) { void *address = nullptr; - if (MainConfig->GetMemSig("CreateNamedEntity", &address)) // cs_create_entity() - { - CS_CreateNamedEntity = reinterpret_cast(address); - } - - if (MainConfig->GetMemSig("FindEntityByString", &address)) // cs_find_ent_by_class() - { - CS_UTIL_FindEntityByString = reinterpret_cast(address); - } - - if (MainConfig->GetMemSig("GetWeaponInfo", &address)) // cs_get_weapon_info() - { - GetWeaponInfo = reinterpret_cast(address); - } - - - if (!CS_CreateNamedEntity) - { - MF_Log("CREATE_NAMED_ENITTY is not available - native cs_create_entity() has been disabled"); - } - - if (!CS_UTIL_FindEntityByString) - { - MF_Log("UTIL_FindEntByString is not available - native cs_find_ent_by_class() has been disabled"); - } - - if (!GetWeaponInfo) - { - MF_Log("GetWeaponInfo is not available - native cs_get_weapon_info() has been disabled"); - } - - if (MainConfig->GetMemSig("GiveDefaultItems", &address)) { GiveDefaultItemsDetour = DETOUR_CREATE_MEMBER_FIXED(GiveDefaultItems, address); @@ -560,10 +515,66 @@ void CtrlDetours_Natives(bool set) } else { - if (GiveDefaultItemsDetour) - { - GiveDefaultItemsDetour->Destroy(); - } + DestroyDetour(GiveDefaultItemsDetour); + } +} + + +void InitFuncsAddresses() +{ + void *address = nullptr; + + if (MainConfig->GetMemSig("CreateNamedEntity", &address)) // cs_create_entity() + { + CS_CreateNamedEntity = reinterpret_cast(address); + } + + if (MainConfig->GetMemSig("FindEntityByString", &address)) // cs_find_ent_by_class() + { + CS_UTIL_FindEntityByString = reinterpret_cast(address); + } + + if (MainConfig->GetMemSig("GetWeaponInfo", &address)) // cs_get_weapon_info() + { + GetWeaponInfo = reinterpret_cast(address); + } + + + if (!CS_CreateNamedEntity) + { + MF_Log("CREATE_NAMED_ENITTY is not available - native cs_create_entity() has been disabled"); + } + + if (!CS_UTIL_FindEntityByString) + { + MF_Log("UTIL_FindEntByString is not available - native cs_find_ent_by_class() has been disabled"); + } + + if (!GetWeaponInfo) + { + MF_Log("GetWeaponInfo is not available - native cs_get_weapon_info() and forward CS_OnBuy have been disabled"); + CtrlDetours_BuyCommands(false); + } +} + +void InitClassMembers() +{ + CommonConfig->GetOffsetByClass("CBasePlayer", "m_iTeam" , &TeamDesc ); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_iMenu" , &MenuDesc ); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_bHasNightVision", &NvgsDesc ); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_bHasDefuser" , &DefuserDesc); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_signals" , &SignalsDesc); + CommonConfig->GetOffsetByClass("CBasePlayer", "m_iAccount" , &MoneyDesc ); + + if (!TeamDesc.fieldOffset || + !MenuDesc.fieldOffset || + !NvgsDesc.fieldOffset || + !DefuserDesc.fieldOffset || + !SignalsDesc.fieldOffset || + !MoneyDesc.fieldOffset) + { + MF_Log("Invalid or missing entity gamedata files - forwards CS_OnBuy[Attempt] have been disabled"); + CtrlDetours_BuyCommands(false); } } @@ -571,30 +582,43 @@ void InitGlobalVars() { void *address = nullptr; -#if defined(WIN32) +#if defined(KE_WINDOWS) TypeDescription typeDesc; if (CommonConfig->GetOffset("svs", &typeDesc)) { uintptr_t base = *reinterpret_cast(reinterpret_cast(g_engfuncs.pfnGetCurrentPlayer) + typeDesc.fieldOffset); - ServerStatic = reinterpret_cast(base - 4); + ServerStatic = reinterpret_cast(base - 4); } if (CommonConfig->GetAddress("sv", &address)) { - Server = *reinterpret_cast(address); + Server = *reinterpret_cast(address); } + + if (CommonConfig->GetAddress("g_pGameRules", &address)) + { + GameRules = *reinterpret_cast(address); + } + #else + if (CommonConfig->GetMemSig("svs", &address)) { - ServerStatic = reinterpret_cast(address); + ServerStatic = reinterpret_cast(address); } if (CommonConfig->GetMemSig("sv", &address)) { - Server = reinterpret_cast(address); + Server = reinterpret_cast(address); } + + if (CommonConfig->GetMemSig("g_pGameRules", &address)) + { + GameRules = reinterpret_cast(address); + } + #endif if (!ServerStatic) @@ -606,4 +630,10 @@ void InitGlobalVars() { MF_Log("sv global variable is not available"); } + + if (!GameRules) + { + MF_Log("g_pGameRules is not available - Forward CS_OnBuy has been disabled"); + CtrlDetours_BuyCommands(false); + } } diff --git a/modules/cstrike/cstrike/CstrikeHacks.h b/modules/cstrike/cstrike/CstrikeHacks.h index 7ba53900..743a7cb9 100644 --- a/modules/cstrike/cstrike/CstrikeHacks.h +++ b/modules/cstrike/cstrike/CstrikeHacks.h @@ -21,11 +21,17 @@ #include "CstrikeDatas.h" void InitializeHacks(); +void InitFuncsAddresses(); +void InitClassMembers(); void InitGlobalVars(); void ShutdownHacks(); + +void CtrlDetours_ClientCommand(bool set); +void CtrlDetours_BuyCommands(bool set); +void CtrlDetours_Natives(bool set); + void ToggleDetour_ClientCommands(bool enable); void ToggleDetour_BuyCommands(bool enable); -void OnEmitSound(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); extern AMX_NATIVE_INFO CstrikeNatives[]; @@ -36,6 +42,18 @@ extern int ForwardInternalCommand; extern int ForwardOnBuy; extern int ForwardOnBuyAttempt; +extern bool HasInternalCommandForward; +extern bool HasOnBuyAttemptForward; +extern bool HasOnBuyForward; + +extern CDetour *ClientCommandDetour; +extern CDetour *GiveNamedItemDetour; +extern CDetour *AddAccountDetour; +extern CDetour *CanPlayerBuyDetour; +extern CDetour *CanBuyThisDetour; +extern CDetour *GiveDefaultItemsDetour; +extern CDetour *BuyGunAmmoDetour; + typedef edict_t* (*CreateNamedEntityFunc)(string_t iszClassname); typedef void* (*UTIL_FindEntityByStringFunc)(void* pStartEntity, const char *szKeyword, const char *szValue); typedef WeaponInfoStruct* (*GetWeaponInfoFunc)(int id); @@ -47,9 +65,13 @@ extern GetWeaponInfoFunc GetWeaponInfo; extern CDetour *GiveDefaultItemsDetour; extern enginefuncs_t *g_pengfuncsTable; extern DLL_FUNCTIONS *g_pFunctionTable; -extern bool NoKifesMode; +extern bool NoKnivesMode; extern server_static_t *ServerStatic; extern server_t *Server; +extern void **GameRules; + +extern int *UseBotArgs; +extern const char **BotArgs; #endif // CSTRIKE_HACKS_H diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp index 27b658fb..40b83b41 100644 --- a/modules/cstrike/cstrike/CstrikeItemsInfos.cpp +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.cpp @@ -12,9 +12,10 @@ // #include "CstrikeItemsInfos.h" -#include +#include "CstrikeHacks.h" CsItemInfo ItemsManager; +char WeaponNameList[MAX_WEAPONS][64]; #define PSTATE_ALIASES_TYPE 0 #define PSTATE_ALIASES_ALIAS 1 @@ -52,15 +53,15 @@ SMCResult CsItemInfo::ReadSMC_NewSection(const SMCStates *states, const char *na { m_List = nullptr; - if (!strcmp(name, "Common")) + if (!strcmp(name, "CommonAlias")) { m_List = &m_CommonAliasesList; } - else if (!strcmp(name, "Weapon")) + else if (!strcmp(name, "WeaponAlias")) { m_List = &m_WeaponAliasesList; } - else if (!strcmp(name, "Buy") || !strcmp(name, "BuyEquip") || !strcmp(name, "BuyAmmo")) + else if (!strcmp(name, "BuyAlias") || !strcmp(name, "BuyEquipAlias") || !strcmp(name, "BuyAmmoAlias")) { m_List = &m_BuyAliasesList; } @@ -113,6 +114,21 @@ SMCResult CsItemInfo::ReadSMC_KeyValue(const SMCStates *states, const char *key, { m_AliasInfo.classname = value; } + else if (!strcmp(key, "price")) + { + static int equipmentsList[static_cast(Equipments::Count)] = + { + CSI_NONE, CSI_VEST, CSI_VESTHELM, CSI_FLASHBANG, CSI_HEGRENADE, CSI_SMOKEGRENADE, CSI_NVGS, CSI_DEFUSER + }; + + for (int i = 0; i < ARRAY_LENGTH(equipmentsList); ++i) + { + if (m_AliasInfo.itemid == equipmentsList[i]) + { + m_EquipmentsPrice[i] = atoi(value); + } + } + } break; } } @@ -231,3 +247,31 @@ CsWeaponClassType CsItemInfo::WeaponIdToClass(int id) return CS_WEAPONCLASS_NONE; } + +int CsItemInfo::GetItemPrice(int itemId) +{ + if (itemId <= CSI_NONE || itemId > CSI_SHIELD) + { + return 0; + } + + Equipments id = Equipments::None; + + switch (itemId) + { + case CSI_VEST: id = Equipments::Vest; break; + case CSI_VESTHELM: id = Equipments::Vesthelm; break; + case CSI_HEGRENADE: id = Equipments::HEGrenade; break; + case CSI_SMOKEGRENADE: id = Equipments::SmokeGrenade; break; + case CSI_FLASHBANG: id = Equipments::Flashbang; break; + case CSI_NVGS: id = Equipments::Nvg; break; + case CSI_DEFUSER: id = Equipments::Defuser; break; + } + + if (id != Equipments::None) + { + return m_EquipmentsPrice[static_cast(id)]; + } + + return GetWeaponInfo(itemId == CSI_SHIELD ? CSI_SHIELDGUN : itemId)->cost; +} diff --git a/modules/cstrike/cstrike/CstrikeItemsInfos.h b/modules/cstrike/cstrike/CstrikeItemsInfos.h index b9fa8e3f..2729f19f 100644 --- a/modules/cstrike/cstrike/CstrikeItemsInfos.h +++ b/modules/cstrike/cstrike/CstrikeItemsInfos.h @@ -14,9 +14,10 @@ #ifndef _CSTRIKE_WEAPONS_INFOS_H_ #define _CSTRIKE_WEAPONS_INFOS_H_ +#include #include "CstrikeDatas.h" #include -#include +#include #include struct AliasInfo @@ -37,12 +38,25 @@ struct AliasInfo ke::AString classname; }; +enum class Equipments +{ + None, + Vest, + Vesthelm, + Flashbang, + HEGrenade, + SmokeGrenade, + Nvg, + Defuser, + Count +}; + class CsItemInfo : public ITextListener_SMC { public: CsItemInfo(); - ~CsItemInfo(); + virtual ~CsItemInfo(); public: @@ -64,6 +78,8 @@ class CsItemInfo : public ITextListener_SMC CsWeaponClassType WeaponIdToClass(int id); + int GetItemPrice(int id); + private: // Retrieved datas typedef StringHashMap AliasMap; @@ -81,8 +97,10 @@ class CsItemInfo : public ITextListener_SMC ke::AString m_Alias; AliasInfo m_AliasInfo; bool m_ListsRetrievedFromConfig; + int m_EquipmentsPrice[static_cast(Equipments::Count)]; }; +extern char WeaponNameList[MAX_WEAPONS][64]; extern CsItemInfo ItemsManager; #endif // _CSTRIKE_WEAPONS_INFOS_H_ diff --git a/modules/cstrike/cstrike/CstrikeMain.cpp b/modules/cstrike/cstrike/CstrikeMain.cpp index 71648615..55a80286 100644 --- a/modules/cstrike/cstrike/CstrikeMain.cpp +++ b/modules/cstrike/cstrike/CstrikeMain.cpp @@ -14,6 +14,8 @@ #include "amxxmodule.h" #include "CstrikeUtils.h" #include "CstrikeHacks.h" +#include "CstrikeItemsInfos.h" +#include "CstrikeUserMessages.h" #include IGameConfig *MainConfig; @@ -39,7 +41,7 @@ void OnAmxxAttach() ConfigManager = MF_GetConfigManager(); char error[256] = ""; - ConfigManager->AddUserConfigHook("CommandsAliases", &ItemsManager); + ConfigManager->AddUserConfigHook("ItemInfos", &ItemsManager); if (!ConfigManager->LoadGameConfigFile("modules.games", &MainConfig, error, sizeof(error)) && *error) { @@ -48,6 +50,7 @@ void OnAmxxAttach() } *error = '\0'; + if (!ConfigManager->LoadGameConfigFile("common.games", &CommonConfig, error, sizeof(error)) && *error) { MF_Log("Could not read common.games gamedata: %s", error); @@ -59,27 +62,29 @@ void OnAmxxAttach() void OnPluginsLoaded() { + TypeConversion.init(); + 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); - // 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; } + if (!ClientCommandDetour) // All CS_* forwards requires ClientCommand. Unlikely to fail. + { + ToggleDetour_ClientCommands(false); + ToggleDetour_BuyCommands(false); - // And enable/disable detours when necessary. - ToggleDetour_ClientCommands(ForwardInternalCommand != -1 || ForwardOnBuy != -1 || ForwardOnBuyAttempt != -1); - ToggleDetour_BuyCommands(ForwardOnBuy != -1); + return; + } - // Search pev/vtable offset automatically. - TypeConversion.init(); + auto haveBotDetours = UseBotArgs && BotArgs; + auto haveBuyDetours = BuyGunAmmoDetour && GiveNamedItemDetour && AddAccountDetour && CanPlayerBuyDetour && CanBuyThisDetour; - // Used with model natives, enabled on demand. - g_pengfuncsTable->pfnSetClientKeyValue = nullptr; - g_pFunctionTable->pfnClientUserInfoChanged = nullptr; - g_pFunctionTable->pfnStartFrame = nullptr; + HasInternalCommandForward = haveBotDetours && UTIL_CheckForPublic("CS_InternalCommand"); + HasOnBuyAttemptForward = haveBuyDetours && UTIL_CheckForPublic("CS_OnBuyAttempt"); + HasOnBuyForward = haveBuyDetours && UTIL_CheckForPublic("CS_OnBuy"); + + ToggleDetour_ClientCommands(HasInternalCommandForward || HasOnBuyAttemptForward || HasOnBuyForward); + ToggleDetour_BuyCommands(HasOnBuyForward); } void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) @@ -95,13 +100,18 @@ void OnServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax) void OnPluginsUnloaded() { - // Force to disable all hooks at map change. + // Used with model natives, enabled on demand. + g_pengfuncsTable->pfnSetClientKeyValue = nullptr; + g_pFunctionTable->pfnClientUserInfoChanged = nullptr; + g_pFunctionTable->pfnStartFrame = nullptr; + + // Force to disable all event hooks at map change. DisableMessageHooks(true); } void OnAmxxDetach() { - ConfigManager->RemoveUserConfigHook("CommandsAliases", &ItemsManager); + ConfigManager->RemoveUserConfigHook("ItemInfos", &ItemsManager); ConfigManager->CloseGameConfigFile(MainConfig); ConfigManager->CloseGameConfigFile(CommonConfig); diff --git a/modules/cstrike/cstrike/CstrikeNatives.cpp b/modules/cstrike/cstrike/CstrikeNatives.cpp index d9f5abfe..143ec92d 100644 --- a/modules/cstrike/cstrike/CstrikeNatives.cpp +++ b/modules/cstrike/cstrike/CstrikeNatives.cpp @@ -16,11 +16,11 @@ #include "CstrikeUtils.h" #include "CstrikeHacks.h" #include "CstrikeUserMessages.h" +#include "CstrikeItemsInfos.h" #include #include -bool NoKifesMode = false; -char WeaponNameList[MAX_WEAPONS][64]; +bool NoKnivesMode = false; // native cs_set_user_money(index, money, flash = 1); static cell AMX_NATIVE_CALL cs_set_user_money(AMX *amx, cell *params) @@ -1073,7 +1073,7 @@ static cell AMX_NATIVE_CALL cs_get_user_hasprimary(AMX *amx, cell *params) // native cs_get_no_knives(); static cell AMX_NATIVE_CALL cs_get_no_knives(AMX *amx, cell *params) { - return NoKifesMode ? 1 : 0; + return NoKnivesMode ? 1 : 0; } // native cs_set_no_knives(noknives = 0); @@ -1085,9 +1085,9 @@ static cell AMX_NATIVE_CALL cs_set_no_knives(AMX *amx, cell *params) return 0; } - NoKifesMode = params[1] != 0; + NoKnivesMode = params[1] != 0; - if (NoKifesMode) + if (NoKnivesMode) { GiveDefaultItemsDetour->EnableDetour(); } @@ -1756,21 +1756,21 @@ static cell AMX_NATIVE_CALL cs_find_ent_by_owner(AMX* amx, cell* params) } int owner = params[3]; - CHECK_ENTITY_SIMPLE(params[3]); + CHECK_ENTITY_SIMPLE(owner); int length; - void* pEntity = G_HL_TypeConversion.id_to_cbase(params[1]); + void* pEntity = TypeConversion.id_to_cbase(params[1]); const char* value = MF_GetAmxString(amx, params[2], 0, &length); - edict_t *pOwner = GETEDICT(owner); + edict_t *pOwner = TypeConversion.id_to_edict(owner); while ((pEntity = CS_UTIL_FindEntityByString(pEntity, "classname", value))) { - edict_t *pev = G_HL_TypeConversion.cbase_to_edict(pEntity); + edict_t *pev = TypeConversion.cbase_to_edict(pEntity); if (!FNullEnt(pev) && pev->v.owner == pOwner) { - int index = ENTINDEX(pev); + int index = TypeConversion.edict_to_id(pev); if (index != -1) { @@ -1787,7 +1787,7 @@ static cell AMX_NATIVE_CALL cs_get_item_id(AMX* amx, cell* params) { if (ItemsManager.HasConfigError()) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_item_id() is disabled disabled because of missing gamedata"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_item_id() is disabled because of corrupted or missing gamedata"); return 0; } @@ -1814,7 +1814,7 @@ static cell AMX_NATIVE_CALL cs_get_translated_item_alias(AMX* amx, cell* params) { if (ItemsManager.HasConfigError()) { - MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_translated_item_alias() is disabled because of missing gamedata"); + MF_LogError(amx, AMX_ERR_NATIVE, "Native cs_get_translated_item_alias() is disabled because of corrupted or missing gamedata"); return 0; } @@ -1966,7 +1966,7 @@ AMX_NATIVE_INFO CstrikeNatives[] = {"cs_set_c4_explode_time", cs_set_c4_explode_time}, {"cs_get_c4_defusing", cs_get_c4_defusing}, {"cs_set_c4_defusing", cs_set_c4_defusing}, - {"cs_create_entity", cs_create_entity }, + {"cs_create_entity", cs_create_entity }, {"cs_find_ent_by_class", cs_find_ent_by_class}, {"cs_find_ent_by_owner", cs_find_ent_by_owner}, {"cs_get_item_id", cs_get_item_id}, diff --git a/modules/cstrike/cstrike/CstrikeUserMessages.cpp b/modules/cstrike/cstrike/CstrikeUserMessages.cpp index ee51a21d..4d646765 100644 --- a/modules/cstrike/cstrike/CstrikeUserMessages.cpp +++ b/modules/cstrike/cstrike/CstrikeUserMessages.cpp @@ -11,13 +11,12 @@ // Counter-Strike Module // -#include #include "CstrikeUserMessages.h" #include "CstrikeUtils.h" #include "CstrikeHacks.h" #include "CstrikePlayer.h" -#include "CstrikeDatas.h" -#include +#include "CstrikeItemsInfos.h" +#include bool ShouldBlock; bool ShouldBlockHLTV; @@ -116,26 +115,6 @@ void OnMessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *p DisableMessageHooks(); } } - else if (msg_type == MessageIdStatusIcon) - { - if (OnMessageStatusIcon(pEntity)) - { - ShouldBlock = true; - ShouldDisableHooks = true; - - RETURN_META(MRES_SUPERCEDE); - } - } - else if (msg_type == MessageIdItemStatus) - { - if (OnMessageItemStatus(pEntity)) - { - ShouldBlock = true; - ShouldDisableHooks = true; - - RETURN_META(MRES_SUPERCEDE); - } - } break; } case MSG_SPEC: diff --git a/modules/cstrike/cstrike/CstrikeUtils.h b/modules/cstrike/cstrike/CstrikeUtils.h index f1a59c53..7f6c635f 100644 --- a/modules/cstrike/cstrike/CstrikeUtils.h +++ b/modules/cstrike/cstrike/CstrikeUtils.h @@ -110,6 +110,7 @@ bool UTIL_CheckForPublic(const char *publicname); member = type.fieldOffset; \ } + class CUnifiedSignals { public: @@ -120,17 +121,17 @@ class CUnifiedSignals m_flSignal = 0; } - void Signal(int flags) + void Signal(int flags) { m_flSignal |= flags; } - int GetSignal(void) + int GetSignal(void) { return m_flSignal; } - int GetState(void) + int GetState(void) { return m_flState; } diff --git a/plugins/include/cstrike_const.inc b/plugins/include/cstrike_const.inc index d188a6d8..4478b9fb 100644 --- a/plugins/include/cstrike_const.inc +++ b/plugins/include/cstrike_const.inc @@ -55,16 +55,16 @@ #define CSW_SHIELDGUN 99 #define CSW_LAST_WEAPON CSW_P90 -stock const CSW_ALL_WEAPONS = (~(1<(cbase, m_PevOffset); } + edict_t* cbase_to_edict(void *cbase) + { + return entvar_to_edict(cbase_to_entvar(cbase)); + } + int cbase_to_id(void *cbase) { return entvars_to_id(cbase_to_entvar(cbase));