diff --git a/extensions/cstrike/extension.h b/extensions/cstrike/extension.h index 778d0d584..a5f9e9d8e 100644 --- a/extensions/cstrike/extension.h +++ b/extensions/cstrike/extension.h @@ -42,6 +42,8 @@ #include #include +int CallPriceForward(int client, const char *weapon_name, int price); + /** * @brief Sample implementation of the SDK Extension. * Note: Uncomment one of the pre-defined virtual functions in order to use it. @@ -146,5 +148,6 @@ extern bool g_pIgnoreTerminateDetour; extern bool g_pIgnoreCSWeaponDropDetour; extern bool g_pTerminateRoundDetoured; extern bool g_pCSWeaponDropDetoured; +extern int weaponNameOffset; #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/cstrike/forwards.cpp b/extensions/cstrike/forwards.cpp index 81183064c..b725e6763 100644 --- a/extensions/cstrike/forwards.cpp +++ b/extensions/cstrike/forwards.cpp @@ -51,19 +51,7 @@ DETOUR_DECL_MEMBER0(DetourWeaponPrice, int) const char *weapon_name = reinterpret_cast(this+weaponNameOffset); - int original = price; - - cell_t result = Pl_Continue; - - g_pPriceForward->PushCell(lastclient); - g_pPriceForward->PushString(weapon_name); - g_pPriceForward->PushCellByRef(&price); - g_pPriceForward->Execute(&result); - - if (result == Pl_Continue) - return original; - - return price; + return CallPriceForward(lastclient, weapon_name, price); } DETOUR_DECL_MEMBER2(DetourTerminateRound, void, float, delay, int, reason) @@ -232,3 +220,19 @@ void RemoveCSWeaponDropDetour() } g_pCSWeaponDropDetoured = false; } +int CallPriceForward(int client, const char *weapon_name, int price) +{ + int changedprice = price; + + cell_t result = Pl_Continue; + + g_pPriceForward->PushCell(client); + g_pPriceForward->PushString(weapon_name); + g_pPriceForward->PushCellByRef(&changedprice); + g_pPriceForward->Execute(&result); + + if (result == Pl_Continue) + return price; + + return changedprice; +} diff --git a/extensions/cstrike/natives.cpp b/extensions/cstrike/natives.cpp index 813c94acf..0804b8480 100644 --- a/extensions/cstrike/natives.cpp +++ b/extensions/cstrike/natives.cpp @@ -325,6 +325,58 @@ static cell_t CS_GetTranslatedWeaponAlias(IPluginContext *pContext, const cell_t return 1; } +static cell_t CS_GetWeaponPrice(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + static int priceOffset = -1; + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("GetWeaponInfo", + PassInfo pass[1]; \ + PassInfo retpass[1]; \ + pass[0].flags = PASSFLAG_BYVAL; \ + pass[0].type = PassType_Basic; \ + pass[0].size = sizeof(int); \ + retpass[0].flags = PASSFLAG_BYVAL; \ + retpass[0].type = PassType_Basic; \ + retpass[0].size = sizeof(void *); \ + pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retpass[0], pass, 1)) + } + if (priceOffset == -1) + { + if (!g_pGameConf->GetOffset("WeaponPrice", &priceOffset)) + { + return pContext->ThrowNativeError("Failed to get WeaponPrice offset"); + } + } + + CBaseEntity *pEntity; + if (!(pEntity = GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *info; + + unsigned char vstk[sizeof(int)]; + unsigned char *vptr = vstk; + + *(int *)vptr = params[2]; + + pWrapper->Execute(vstk, &info); + + if (!info) + return pContext->ThrowNativeError("Failed to get weaponinfo"); + + int price = *(int *)((intptr_t)info + priceOffset); + + if (params[3] || weaponNameOffset == -1) + return price; + + const char *weapon_name = (const char *)((intptr_t)info + weaponNameOffset); + + return CallPriceForward(params[1], weapon_name, price); +} sp_nativeinfo_t g_CSNatives[] = { @@ -333,6 +385,7 @@ sp_nativeinfo_t g_CSNatives[] = {"CS_DropWeapon", CS_DropWeapon}, {"CS_TerminateRound", CS_TerminateRound}, {"CS_GetTranslatedWeaponAlias", CS_GetTranslatedWeaponAlias}, + {"CS_GetWeaponPrice", CS_GetWeaponPrice}, {NULL, NULL} }; diff --git a/gamedata/sm-cstrike.games.txt b/gamedata/sm-cstrike.games.txt index a42622805..2ad784bd6 100644 --- a/gamedata/sm-cstrike.games.txt +++ b/gamedata/sm-cstrike.games.txt @@ -22,6 +22,12 @@ "linux" "6" "mac" "6" } + "WeaponPrice" + { + "windows" "2224" + "linux" "2224" + "mac" "2224" + } } "Signatures" { @@ -74,6 +80,13 @@ "linux" "@_Z24GetTranslatedWeaponAliasPKc" "mac" "@_Z24GetTranslatedWeaponAliasPKc" } + "GetWeaponInfo" + { + "library" "server" + "windows" "\x8B\x4C\x2A\x2A\x85\xC9\x75\x2A\x33\xC0\xC3" + "linux" "@_Z13GetWeaponInfo10CSWeaponID" + "mac" "@_Z13GetWeaponInfo10CSWeaponID" + } } } } diff --git a/plugins/include/cstrike.inc b/plugins/include/cstrike.inc index f1dceaf8e..b1fed6977 100644 --- a/plugins/include/cstrike.inc +++ b/plugins/include/cstrike.inc @@ -65,6 +65,43 @@ enum CSRoundEndReason CSRoundEnd_GameStart // Game Commencing! }; +enum CSWeaponID +{ + CSWeapon_NONE, + CSWeapon_P228, + CSWeapon_GLOCK, + CSWeapon_SCOUT, + CSWeapon_HEGRENADE, + CSWeapon_XM1014, + CSWeapon_C4, + CSWeapon_MAC10, + CSWeapon_AUG, + CSWeapon_SMOKEGRENADE, + CSWeapon_ELITE, + CSWeapon_FIVESEVEN, + CSWeapon_UMP45, + CSWeapon_SG550, + CSWeapon_GALIL, + CSWeapon_FAMAS, + CSWeapon_USP, + CSWeapon_AWP, + CSWeapon_MP5NAVY, + CSWeapon_M249, + CSWeapon_M3, + CSWeapon_M4A1, + CSWeapon_TMP, + CSWeapon_G3SG1, + CSWeapon_FLASHBANG, + CSWeapon_DEAGLE, + CSWeapon_SG552, + CSWeapon_AK47, + CSWeapon_KNIFE, + CSWeapon_P90, + CSWeapon_SHIELD, + CSWeapon_KEVLAR, + CSWeapon_ASSAULTSUIT, + CSWeapon_NIGHTVISION +}; /** * Called when a player attempts to purchase an item. * Return Plugin_Continue to allow the purchase or return a @@ -166,6 +203,19 @@ native CS_DropWeapon(client, weaponIndex, bool:toss, bool:blockhook = false); */ native CS_GetTranslatedWeaponAlias(const String:alias[], String:weapon[], size); + /** + * Gets a weapon's price + * + * @param client Client to check weapon price for. + * @param id Weapon id for the weapon to check + * @param defaultprice Set to true to get defaultprice. + * @return Returns price of the weapon (even if modified) + * + * @error Invalid client, failing to get weapon info, or failing to get price offset. + * @note Not all "weapons" will return their default price. Example: c4, knife, vest, vest helmet, night vision. + */ + native CS_GetWeaponPrice(client, CSWeaponID:id, bool:defaultprice=false); + /** * Do not edit below this line! */ @@ -189,6 +239,7 @@ public __ext_cstrike_SetNTVOptional() MarkNativeAsOptional("CS_DropWeapon"); MarkNativeAsOptional("CS_TerminateRound"); MarkNativeAsOptional("CS_GetTranslatedWeaponAlias"); + MarkNativeAsOptional("CS_GetWeaponPrice"); } #endif