From 9fd32bfa3bd2487fec0dfae7f7e0777f0dd0f081 Mon Sep 17 00:00:00 2001 From: Greyscale Date: Thu, 4 Jun 2009 20:58:48 -0700 Subject: [PATCH] Finished ZMarket. Includes rebuy and auto-rebuy which can be disabled by cvar (and clients can disable auto-rebuy in-game) * "stock'd" a couple functions. --- .../addons/sourcemod/configs/zr/weapons.txt | 44 +- .../translations/zombiereloaded.phrases.txt | 83 ++- src/zr/account.inc | 14 +- src/zr/cvars.inc | 12 +- src/zr/event.inc | 4 +- src/zr/log.inc | 2 +- src/zr/menu.inc | 2 + src/zr/models.inc | 6 + src/zr/sayhooks.inc | 1 + src/zr/weapons/menu_weapons.inc | 56 +- src/zr/weapons/restrict.inc | 2 +- src/zr/weapons/weaponammo.inc | 6 +- src/zr/weapons/weapons.inc | 111 ++- src/zr/weapons/zmarket.inc | 635 +++++++++++++++++- 14 files changed, 904 insertions(+), 74 deletions(-) diff --git a/cstrike/addons/sourcemod/configs/zr/weapons.txt b/cstrike/addons/sourcemod/configs/zr/weapons.txt index b9b0bad..f06d5aa 100644 --- a/cstrike/addons/sourcemod/configs/zr/weapons.txt +++ b/cstrike/addons/sourcemod/configs/zr/weapons.txt @@ -11,13 +11,18 @@ // // Attribute: Values: Description: // ---------------------------------------------------------------------------- -// weapontype text The type of weapon it is. (List types, separate by ", " +// weapontype text The type of weapon it is. [List types, separate by ", "] +// weaponslot number The slot index the weapon resides in. (Don't change this) // restrictdefault yes/no The default restricted status of the weapon on map start. // toggleable yes/no Enable weapon to have restrictions toggled mid-game. // ammotype text Ammo entity that belongs to weapons. (Don't change this) // ammoprice number Price of ammo for this weapon. // knockback decimal The knockback multiplier for the weapon. ['0.5' = half knockback | 2.0 = double] -// zmarketprice number The price of the weapon in ZMarket. (Defaulted to CS:S buymenu price) +// zmarketprice number The price of the weapon in ZMarket. [Default: CS:S buymenu price] +// zmarketpurchasemax number The max number of purchases allowed per spawn for the weapon. +// +// Notes: +// * Omitting and option will disable the feature for the weapon. "weapons" // Counter-Strike: Source weapons { @@ -26,6 +31,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -51,6 +57,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -76,6 +83,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -102,6 +110,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -128,6 +137,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -154,6 +164,7 @@ // General "weapontype" "All, Pistol" + "weaponslot" "1" // Restrict (core) @@ -180,6 +191,7 @@ // General "weapontype" "All, Shotgun" + "weaponslot" "0" // Restrict (core) @@ -206,6 +218,7 @@ // General "weapontype" "All, Shotgun" + "weaponslot" "0" // Restrict (core) @@ -219,7 +232,7 @@ // Knockback (module) - "knockback" "0.8" // See above comment. + "knockback" "0.9" // See above comment. // ZMarket (module) @@ -232,6 +245,7 @@ // General "weapontype" "All, SMG" + "weaponslot" "0" // Restrict (core) @@ -257,6 +271,7 @@ // General "weapontype" "All, SMG" + "weaponslot" "0" // Restrict (core) @@ -282,6 +297,7 @@ // General "weapontype" "All, SMG" + "weaponslot" "0" // Restrict (core) @@ -307,6 +323,7 @@ // General "weapontype" "All, SMG" + "weaponslot" "0" // Restrict (core) @@ -332,6 +349,7 @@ // General "weapontype" "All, SMG" + "weaponslot" "0" // Restrict (core) @@ -357,6 +375,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -382,6 +401,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -407,6 +427,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -432,6 +453,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -457,6 +479,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -482,6 +505,7 @@ // General "weapontype" "All, Rifle" + "weaponslot" "0" // Restrict (core) @@ -507,6 +531,7 @@ // General "weapontype" "All, Sniper" + "weaponslot" "0" // Restrict (core) @@ -532,6 +557,7 @@ // General "weapontype" "All, Sniper" + "weaponslot" "0" // Restrict (core) @@ -557,6 +583,7 @@ // General "weapontype" "All, Sniper" + "weaponslot" "0" // Restrict (core) @@ -582,6 +609,7 @@ // General "weapontype" "All, Sniper" + "weaponslot" "0" // Restrict (core) @@ -607,6 +635,7 @@ // General "weapontype" "All, Machine Gun" + "weaponslot" "0" // Restrict (core) @@ -632,6 +661,7 @@ // General "weapontype" "All, Melee" + "weaponslot" "2" // Restrict (core) @@ -648,6 +678,7 @@ // General "weapontype" "All, Projectile" + "weaponslot" "3" // Restrict (core) @@ -661,6 +692,7 @@ // ZMarket (module) "zmarketprice" "300" + "zmarketpurchasemax" "1" } "Flashbang" @@ -668,6 +700,7 @@ // General "weapontype" "All, Projectile" + "weaponslot" "3" // Restrict (core) @@ -676,7 +709,8 @@ // ZMarket (module) - "zmarketprice" "300" + "zmarketprice" "200" + "zmarketpurchasemax" "1" } "Smokegrenade" @@ -684,6 +718,7 @@ // General "weapontype" "All, Projectile" + "weaponslot" "3" // Restrict (core) @@ -693,6 +728,7 @@ // ZMarket (module) "zmarketprice" "300" + "zmarketpurchasemax" "1" } "NVGs" diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index 3b72035..288f04b 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -34,6 +34,11 @@ "en" "This feature is currently disabled by the server host." } + "Not enough money" + { + "en" "You do not have enough money to buy this item." + } + "Must be player" { "en" "This feature is reserved for players only." @@ -267,14 +272,6 @@ "ru" "Зомби не могут использовать оружие!" } - // Market - - "Market out of buyzone" - { - "en" "You are not in a buyzone." - "ru" "Вы вне зоны покупки." - } - // Restrict "Restrict weapon" @@ -346,14 +343,21 @@ // ZMarket - "Market title" + "Weapons zmarket buyzone" { - "en" "" + "en" "You must be in a buyzone to use ZMarket." } - "Market rebuy" + "Weapons zmarket purchase" { - "en" "" + "#format" "{1:s}" + "en" "You have purchased weapon @green{1}. @defaultSelect item again to buy ammo if you are low." + } + + "Weapons zmarket purchase max" + { + "#format" "{1:s},{2:d}" + "en" "Weapon @green{1} @defaulthas a purchase limit of @green{2}@default. Wait until you respawn to try again." } // Commands @@ -368,57 +372,92 @@ "en" "Unrestricts a weapon or a weapon type. Usage: zr_unrestrict [weapon2|weapontype2] ..." } - // Menu + // Menu (Restrict) - "Weapons menu main title" + "Weapons menu restrict main title" { "en" "Weapons Management" } - "Weapons menu main restrict" + "Weapons menu restrict main restrict" { "en" "Weapon Restrictions" } - "Weapons menu main market" + "Weapons menu restrict main market" { "en" "ZMarket" } - "Weapons menu types title" + "Weapons menu restrict types title" { "en" "Weapon Restrictions\nSelect Weapon Type:" } - "Weapons menu types type title" + "Weapons menu restrict types weapon type title" { "#format" "{1:s}" "en" "Weapon Restrictions\nWeapon Type: {1}\n[] = Restricted" } - "Weapons menu types restrict all" + "Weapons menu restrict types restrict all" { "#format" "{1:s}" "en" "Restrict weapon type {1}" } - "Weapons menu types unrestrict all" + "Weapons menu restrict types unrestrict all" { "#format" "{1:s}" "en" "Unrestrict weapon type {1}\n " } - "Weapons menu zmarket title" + "Weapons menu restrict zmarket title" { "en" "ZMarket\nSelect Setting:" } - "Weapons menu zmarket buyzone" + "Weapons menu restrict zmarket buyzone" { "#format" "{1:s}" "en" "Buyzone Only - {1}" } + // Menu (ZMarket) + + "Weapons menu zmarket types title" + { + "en" "ZMarket\nSelect Weapon Type:" + } + + "Weapons menu zmarket types rebuy" + { + "en" "Rebuy (1 weapon per slot)" + } + + "Weapons menu zmarket types auto-rebuy" + { + "#format" "{1:s}" + "en" "Auto-Rebuy: {1}\n " + } + + "Weapons menu zmarket types weapon type title" + { + "#format" "{1:s}" + "en" "ZMarket\nWeapon Type: {1}\n[] = Restricted" + } + + "Weapons menu zmarket types weapon info" + { + "#format" "{1:s},{2:d},{3:d}" + "en" "{1} (${2})\nPurchases Left: {3}" + } + + "Weapons menu zmarket types weapon ammo" + { + "en" "Ammo" + } + // =========================== // Spawn Protect (module) // =========================== diff --git a/src/zr/account.inc b/src/zr/account.inc index 9ffdf0e..ec6b068 100644 --- a/src/zr/account.inc +++ b/src/zr/account.inc @@ -54,13 +54,25 @@ AccountOnClientSpawn(client) AccountSetClientCash(client, cash); } +/** + * Get's a client's account value (cash) + * + * @param client The client index. + * @return The client's current account value. + */ +stock AccountGetClientCash(client) +{ + // Set client's cash. + return GetEntData(client, g_iToolsAccount, 4); +} + /** * Set's a client's account value (cash) * * @param client The client index. * @param value The value to set to. */ -AccountSetClientCash(client, value) +stock AccountSetClientCash(client, value) { // If value if below 0, then set to 0. if (value < 0) diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index f977c58..c6cfa6d 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -49,6 +49,8 @@ enum CvarsList Handle:CVAR_WEAPONS_RESTRICT, Handle:CVAR_WEAPONS_ZMARKET, Handle:CVAR_WEAPONS_ZMARKET_BUYZONE, + Handle:CVAR_WEAPONS_ZMARKET_REBUY, + Handle:CVAR_WEAPONS_ZMARKET_REBUY_AUTO, Handle:CVAR_HITGROUPS, Handle:CVAR_DAMAGE_HITGROUPS, Handle:CVAR_DAMAGE_BLOCK_FF, @@ -252,14 +254,16 @@ CvarsCreate() // =========================== // General - g_hCvarsList[CVAR_WEAPONS] = CreateConVar("zr_weapons", "1", "Enable weapons module, disabling this will disable any weapons-related features. (weapon restrictions, weapon knockback multipliers, etc)"); + g_hCvarsList[CVAR_WEAPONS] = CreateConVar("zr_weapons", "1", "Enable weapons module, disabling this will disable any weapons-related features. (weapon restrictions, weapon knockback multipliers, etc)"); // Restrict - g_hCvarsList[CVAR_WEAPONS_RESTRICT] = CreateConVar("zr_weapons_restrict", "1", "Enable weapon restriction module, disabling this will disable weapon restriction commands."); + g_hCvarsList[CVAR_WEAPONS_RESTRICT] = CreateConVar("zr_weapons_restrict", "1", "Enable weapon restriction module, disabling this will disable weapon restriction commands."); // ZMarket - g_hCvarsList[CVAR_WEAPONS_ZMARKET] = CreateConVar("zr_weapons_zmarket", "1", "Allow player to buy from a list of weapons in the weapons config."); - g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE] = CreateConVar("zr_weapons_zmarket_buyzone", "1", "Requires player to be inside a buyzone to use ZMarket. [Dependency: zr_weapons_zmarket]"); + g_hCvarsList[CVAR_WEAPONS_ZMARKET] = CreateConVar("zr_weapons_zmarket", "1", "Allow player to buy from a list of weapons in the weapons config."); + g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE] = CreateConVar("zr_weapons_zmarket_buyzone", "1", "Requires player to be inside a buyzone to use ZMarket. [Dependency: zr_weapons_zmarket]"); + g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY] = CreateConVar("zr_weapons_zmarket_rebuy", "1", "Allow players to rebuy their previous weapons. [Dependency: zr_weapons_zmarket]"); + g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_AUTO] = CreateConVar("zr_weapons_zmarket_rebuy_auto", "1", "Allow players to automatically rebuy their previous weapons. [Dependency: zr_weapons_zmarket&zr_weapons_zmarket_rebuy]"); // =========================== diff --git a/src/zr/event.inc b/src/zr/event.inc index f671aa9..c0221d8 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -155,10 +155,10 @@ public Action:EventPlayerSpawn(Handle:event, const String:name[], bool:dontBroad // Forward event to modules. InfectOnClientSpawn(index); // Some modules depend on this to finish first. + AccountOnClientSpawn(index); // Some modules depend on this to finish first. ClassOnClientSpawn(index); - RestrictOnClientSpawn(index); + WeaponsOnClientSpawn(index); SEffectsOnClientSpawn(index); - AccountOnClientSpawn(index); SpawnProtectOnClientSpawn(index); RespawnOnClientSpawn(index); ZTeleOnClientSpawn(index); diff --git a/src/zr/log.inc b/src/zr/log.inc index ac8a5e0..6896beb 100644 --- a/src/zr/log.inc +++ b/src/zr/log.inc @@ -188,7 +188,7 @@ LogEvent(bool:isConsole = false, LogTypes:logType = LogType_Normal, eventType = // Format extra parameters into the log buffer. decl String:logbuffer[LOG_MAX_LENGTH_FILE]; - VFormat(logbuffer, sizeof(logbuffer), text, 5); + VFormat(logbuffer, sizeof(logbuffer), text, 7); // Get human readable module name. new String:modulename[64]; diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 2cb474b..58daedf 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -113,6 +113,8 @@ public MenuMainHandle(Handle:menu, MenuAction:action, client, slot) // Select zmarket. case 5: { + // Send ZMarket menu. + resend = !ZMarketMenuTypes(client); } } diff --git a/src/zr/models.inc b/src/zr/models.inc index 0382b3a..c97b63d 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -92,6 +92,12 @@ ModelsLoad() // Open dir containing model files. new Handle:modeldir = OpenDirectory(modelpath); + if (modeldir == INVALID_HANDLE) + { + LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Error opening model path directory: %s", modelpath); + continue; + } + // Reset model file count. modelfilecount = 0; diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index 5c80170..1252b2a 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -121,6 +121,7 @@ public Action:SayHooksCmdSay(client, argc) // Client triggered ZMarket flag. case SAYHOOKS_KEYWORD_FLAG_ZMARKET: { + success = ZMarketMenuTypes(client); } } diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index fa29242..c04212c 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -3,9 +3,24 @@ * * Zombie:Reloaded * - * File: menu_weapons.inc - * Type: Core - * Description: Handles weapons management menu. + * File: menu_weapons.inc + * Type: Core + * Description: Handles weapons management menu. + * + * Copyright (C) 2009 Greyscale, Richard Helgeby + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * * ============================================================================ */ @@ -13,7 +28,7 @@ /** * Array to store the client's current weapon type within menu. */ -new g_iCurWeaponType[MAXPLAYERS + 1]; +new g_iWeaponsCurType[MAXPLAYERS + 1]; /** * Sends main weapon menu to client. @@ -26,13 +41,13 @@ WeaponsMenuMain(client) SetGlobalTransTarget(client); - SetMenuTitle(menu_weapons_main, "%t\n ", "Weapons menu main title"); + SetMenuTitle(menu_weapons_main, "%t\n ", "Weapons menu restrict main title"); decl String:restrict[64]; decl String:zmarket[64]; - Format(restrict, sizeof(restrict), "%t", "Weapons menu main restrict"); - Format(zmarket, sizeof(zmarket), "%t", "Weapons menu main market"); + Format(restrict, sizeof(restrict), "%t", "Weapons menu restrict main restrict"); + Format(zmarket, sizeof(zmarket), "%t", "Weapons menu restrict main market"); // Draw items, make unselectable if module is disabled. AddMenuItem(menu_weapons_main, "restrict", restrict, MenuGetItemDraw(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_RESTRICT]))); @@ -98,8 +113,8 @@ WeaponsMenuTypes(client) SetGlobalTransTarget(client); - SetMenuTitle(menu_weapons_types, "%t\n ", "Weapons menu types title"); - + SetMenuTitle(menu_weapons_types, "%t\n ", "Weapons menu restrict types title"); + decl String:typename[WEAPONS_MAX_LENGTH]; // x = Array index. @@ -141,7 +156,7 @@ public WeaponsMenuTypesHandle(Handle:menu_weapons_types, MenuAction:action, clie if (action == MenuAction_Select) { // Menu slot index is = weapon type index. - g_iCurWeaponType[client] = slot; + g_iWeaponsCurType[client] = slot; // Send weapons of the selected type in a menu to client. WeaponsMenuTypeWeapons(client); @@ -172,26 +187,26 @@ WeaponsMenuTypeWeapons(client) new Handle:menu_weapons_typeweapons = CreateMenu(WeaponsMenuTypeWeaponsHandle); decl String:typename[WEAPONS_MAX_LENGTH]; - RestrictWeaponTypeGetName(g_iCurWeaponType[client], typename, sizeof(typename)); + RestrictWeaponTypeGetName(g_iWeaponsCurType[client], typename, sizeof(typename)); - SetMenuTitle(menu_weapons_typeweapons, "%t\n ", "Weapons menu types type title", typename); + SetMenuTitle(menu_weapons_typeweapons, "%t\n ", "Weapons menu restrict types weapon type title", typename); decl String:restrictall[64]; decl String:unrestrictall[64]; - Format(restrictall, sizeof(restrictall), "%t", "Weapons menu types restrict all", typename); - Format(unrestrictall, sizeof(unrestrictall), "%t", "Weapons menu types unrestrict all", typename); + Format(restrictall, sizeof(restrictall), "%t", "Weapons menu restrict types restrict all", typename); + Format(unrestrictall, sizeof(unrestrictall), "%t", "Weapons menu restrict types unrestrict all", typename); // Draw items as selectable only if not all weapons within the type are restricted or unrestricted. - AddMenuItem(menu_weapons_typeweapons, "restrictall", restrictall, MenuGetItemDraw(!RestrictIsTypeUniform(true, g_iCurWeaponType[client]))); - AddMenuItem(menu_weapons_typeweapons, "unrestrictall", unrestrictall, MenuGetItemDraw(!RestrictIsTypeUniform(false, g_iCurWeaponType[client]))); + AddMenuItem(menu_weapons_typeweapons, "restrictall", restrictall, MenuGetItemDraw(!RestrictIsTypeUniform(true, g_iWeaponsCurType[client]))); + AddMenuItem(menu_weapons_typeweapons, "unrestrictall", unrestrictall, MenuGetItemDraw(!RestrictIsTypeUniform(false, g_iWeaponsCurType[client]))); decl String:typeweapon[WEAPONS_MAX_LENGTH]; decl String:display[WEAPONS_MAX_LENGTH]; // Get an array populated with all weapons of the given type. new Handle:arrayTypeWeapons; - new count = RestrictGetTypeWeapons(g_iCurWeaponType[client], arrayTypeWeapons); + new count = RestrictGetTypeWeapons(g_iWeaponsCurType[client], arrayTypeWeapons); // x = Array index. for (new x = 0; x < count; x++) @@ -236,7 +251,7 @@ public WeaponsMenuTypeWeaponsHandle(Handle:menu_weapons_typeweapons, MenuAction: { // Get name of current weapon type. decl String:typename[WEAPONS_MAX_LENGTH]; - RestrictWeaponTypeGetName(g_iCurWeaponType[client], typename, sizeof(typename)); + RestrictWeaponTypeGetName(g_iWeaponsCurType[client], typename, sizeof(typename)); new RestrictQuery:query; new bool:single; @@ -270,6 +285,7 @@ public WeaponsMenuTypeWeaponsHandle(Handle:menu_weapons_typeweapons, MenuAction: if (weaponindex == -1) { CloseHandle(menu_weapons_typeweapons); + return; } // If weapon isn't restricted, then restrict it. @@ -321,7 +337,7 @@ WeaponsMenuZMarket(client) SetGlobalTransTarget(client); - SetMenuTitle(menu_weapons_market, "%t\n ", "Weapons menu zmarket title"); + SetMenuTitle(menu_weapons_market, "%t\n ", "Weapons menu restrict zmarket title"); decl String:buyzone[64]; decl String:buyzonesetting[8]; @@ -330,7 +346,7 @@ WeaponsMenuZMarket(client) ConfigBoolToSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), buyzonesetting, sizeof(buyzonesetting)); // Add options to menu. - Format(buyzone, sizeof(buyzone), "%t", "Weapons menu zmarket buyzone", buyzonesetting); + Format(buyzone, sizeof(buyzone), "%t", "Weapons menu restrict zmarket buyzone", buyzonesetting); AddMenuItem(menu_weapons_market, "buyzone", buyzone); // Create a "Back" button to the weapons main menu. diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index 165bac6..2189e68 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -72,7 +72,7 @@ RestrictLoad() decl String:weapontype[WEAPONS_MAX_LENGTH]; new String:weapontypes[WEAPONS_RESTRICT_MAX_TYPES][WEAPONS_MAX_LENGTH]; - // x = array index + // x = Array index. new size = GetArraySize(arrayWeapons); for (new x = 0; x < size; x++) { diff --git a/src/zr/weapons/weaponammo.inc b/src/zr/weapons/weaponammo.inc index 4232905..d9dab3d 100644 --- a/src/zr/weapons/weaponammo.inc +++ b/src/zr/weapons/weaponammo.inc @@ -47,7 +47,7 @@ WeaponAmmoOnOffsetsFound() * @param value The amount of ammo to set to. * @param add (Optional) If true, the value is added to the weapon's current ammo count. */ -stock WeaponAmmoSetClientAmmo(weapon, bool:clip, value, bool:add = false) +stock WeaponAmmoSetAmmo(weapon, bool:clip, value, bool:add = false) { // Set variable to offset we are changing. new ammooffset = clip ? g_iToolsClip1 : g_iToolsClip2; @@ -58,7 +58,7 @@ stock WeaponAmmoSetClientAmmo(weapon, bool:clip, value, bool:add = false) // If we are adding, then update variable with current ammo value. if (add) { - ammovalue = WeaponAmmoGetClientAmmo(weapon, clip); + ammovalue = WeaponAmmoGetAmmo(weapon, clip); } // Return ammo offset value. @@ -71,7 +71,7 @@ stock WeaponAmmoSetClientAmmo(weapon, bool:clip, value, bool:add = false) * @param weapon The weapon index. * @param clip True gets clip ammo, false gets reserve. */ -stock WeaponAmmoGetClientAmmo(weapon, bool:clip) +stock WeaponAmmoGetAmmo(weapon, bool:clip) { // Set variable to offset we are changing. new ammooffset = clip ? g_iToolsClip1 : g_iToolsClip2; diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index f3d1eba..198b742 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -27,12 +27,14 @@ enum WeaponsData { WEAPONS_DATA_NAME = 0, WEAPONS_DATA_TYPE, + WEAPONS_DATA_SLOT, WEAPONS_DATA_RESTRICTDEFAULT, WEAPONS_DATA_TOGGLEABLE, WEAPONS_DATA_AMMOTYPE, WEAPONS_DATA_AMMOPRICE, WEAPONS_DATA_KNOCKBACK, WEAPONS_DATA_ZMARKETPRICE, + WEAPONS_DATA_ZMARKETPURCHASEMAX, WEAPONS_DATA_RESTRICTED, } @@ -203,6 +205,7 @@ WeaponsCacheData() // General KvGetString(kvWeapons, "weapontype", weapontype, sizeof(weapontype)); + new WeaponsSlot:weaponslot = WeaponsSlot:KvGetNum(kvWeapons, "weaponslot", -1); // Restrict (core) new bool:restrictdefault = ConfigKvGetStringBool(kvWeapons, "restrictdefault", "no"); @@ -210,27 +213,30 @@ WeaponsCacheData() // Weapon Ammo (core) KvGetString(kvWeapons, "ammotype", ammotype, sizeof(ammotype)); - new ammoprice = KvGetNum(kvWeapons, "ammoprice"); + new ammoprice = KvGetNum(kvWeapons, "ammoprice", -1); // Knockback (module) new Float:knockback = KvGetFloat(kvWeapons, "knockback", 1.0); // ZMarket (module) new zmarketprice = KvGetNum(kvWeapons, "zmarketprice", -1); + new zmarketpurchasemax = KvGetNum(kvWeapons, "zmarketpurchasemax", 0); new Handle:arrayWeapon = GetArrayCell(arrayWeapons, x); // Push data into array. - PushArrayString(arrayWeapon, weapontype); // Index: 1 - PushArrayCell(arrayWeapon, restrictdefault); // Index: 2 - PushArrayCell(arrayWeapon, toggleable); // Index: 3 - PushArrayString(arrayWeapon, ammotype); // Index: 4 - PushArrayCell(arrayWeapon, ammoprice); // Index: 5 - PushArrayCell(arrayWeapon, knockback); // Index: 6 - PushArrayCell(arrayWeapon, zmarketprice); // Index: 7 + PushArrayString(arrayWeapon, weapontype); // Index: 1 + PushArrayCell(arrayWeapon, weaponslot); // Index: 2 + PushArrayCell(arrayWeapon, restrictdefault); // Index: 3 + PushArrayCell(arrayWeapon, toggleable); // Index: 4 + PushArrayString(arrayWeapon, ammotype); // Index: 5 + PushArrayCell(arrayWeapon, ammoprice); // Index: 6 + PushArrayCell(arrayWeapon, knockback); // Index: 7 + PushArrayCell(arrayWeapon, zmarketprice); // Index: 8 + PushArrayCell(arrayWeapon, zmarketpurchasemax); // Index: 9 // Initialize other stored weapon info here. - PushArrayCell(arrayWeapon, restrictdefault); // Index: 8 + PushArrayCell(arrayWeapon, restrictdefault); // Index: 10 } // We're done with this file now, so we can close it. @@ -253,21 +259,35 @@ public WeaponsOnConfigReload() */ WeaponsClientInit(client) { - // Forward event to sub-module. + // Forward event to sub-modules. RestrictClientInit(client); WeaponAlphaClientInit(client); + ZMarketClientInit(client); } /** * Client is leaving the server. * * @param client The client index. - */ + */ WeaponsOnClientDisconnect(client) { - // Forward event to sub-module. + // Forward event to sub-modules. RestrictOnClientDisconnect(client); WeaponAlphaOnClientDisconnect(client); + ZMarketOnClientDisconnect(client); +} + +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +WeaponsOnClientSpawn(client) +{ + // Forward event to sub-modules. + RestrictOnClientSpawn(client); + ZMarketOnClientSpawn(client); } /** @@ -375,6 +395,20 @@ stock WeaponsGetType(index, String:type[], maxlen) GetArrayString(arrayWeapon, _:WEAPONS_DATA_TYPE, type, maxlen); } +/** + * Gets the slot index of a weapon at a given index. + * @param index The weapon index. + * @return The slot index of the weapon. + */ +stock WeaponsSlot:WeaponsGetSlot(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return default restriction status. + return WeaponsSlot:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_SLOT); +} + /** * Gets if a weapon is restricted by default. * @param index The weapon index. @@ -415,7 +449,7 @@ stock WeaponsGetAmmoType(index, String:ammotype[], maxlen) new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); // Get ammo type of the weapon. - GetArrayString(arrayWeapon, _:WEAPONS_DATA_AMMOTYPE, type, maxlen); + GetArrayString(arrayWeapon, _:WEAPONS_DATA_AMMOTYPE, ammotype, maxlen); } /** @@ -460,10 +494,59 @@ stock WeaponsGetZMarketPrice(index) return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_ZMARKETPRICE); } +/** + * Gets the max purchases from ZMarket per round per client of a weapon. + * @param index The weapon index. + * @return The max purchases of the weapon. + */ +stock WeaponsGetZMarketPurchaseMax(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return the ZMarket price of the weapon. + return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_ZMARKETPURCHASEMAX); +} + /** * General weapon API. */ +/** + * Checks if a client has a specific weapon. + * + * @param client The client index. + * @param weapon The weapon classname. + */ +stock bool:WeaponsClientHasWeapon(client, const String:weapon[]) +{ + // Get all of client's current weapons. + new weapons[WeaponsSlot]; + WeaponsGetClientWeapons(client, weapons); + + decl String:classname[64]; + + // x = slot index + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + // If slot is empty, then stop. + if (weapons[x] == -1) + { + continue; + } + + // If the weapon's classname matches, then return true. + GetEdictClassname(weapons[x], classname, sizeof(classname)); + ReplaceString(classname, sizeof(classname), "weapon_", ""); + if (StrEqual(weapon, classname, false)) + { + return true; + } + } + + return false; +} + /** * Return an array that contains all client's weapon indexes. * @@ -473,7 +556,7 @@ stock WeaponsGetZMarketPrice(index) */ stock WeaponsGetClientWeapons(client, weapons[WeaponsSlot]) { - // x = weapon slot. + // x = Weapon slot. for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) { weapons[x] = GetPlayerWeaponSlot(client, x); diff --git a/src/zr/weapons/zmarket.inc b/src/zr/weapons/zmarket.inc index c7fbf1d..4c82345 100644 --- a/src/zr/weapons/zmarket.inc +++ b/src/zr/weapons/zmarket.inc @@ -3,18 +3,69 @@ * * Zombie:Reloaded * - * File: + * File: zmarket.inc * Type: Module - * Description: + * Description: ZMarket module, provides menu of weapons to buy from. + * + * Copyright (C) 2009 Greyscale, Richard Helgeby + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * * ============================================================================ */ +/* * Copyright (C) 2009 Greyscale, Richard Helgeby + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + /** * Variable to store buyzone offset value. */ new g_iToolsInBuyZone; +/** + * Array to store the client's current weapon type within menu. + */ +new g_iZMarketCurType[MAXPLAYERS + 1]; + +/** + * Array handle to store the amount of purchases left for a weapon. + */ +new Handle:g_hZMarketPurchaseCount[MAXPLAYERS + 1]; + +/** + * Array to store a weapon of each type last purchased from ZMarket. + */ +new String:g_strZMarketLastWeapon[MAXPLAYERS + 1][WeaponsSlot][WEAPONS_MAX_LENGTH]; + +/** + * Array to store clients' auto-rebuy setting. + */ +new bool:g_bZMarketAutoRebuy[MAXPLAYERS + 1]; + /** * Initialize market data. */ @@ -35,6 +86,586 @@ ZMarketOnOffsetsFound() } } +/** + * Client is joining the server. + * + * @param client The client index. + */ +ZMarketClientInit(client) +{ + // If purchase count data exists, then destroy before creating again. + if (g_hZMarketPurchaseCount[client] != INVALID_HANDLE) + { + CloseHandle(g_hZMarketPurchaseCount[client]); + } + + // Create a new array handle to store purchase count data for client. + g_hZMarketPurchaseCount[client] = CreateTrie(); + + // Initialize auto-rebuy data. + g_bZMarketAutoRebuy[client] = false; +} + +/** + * Client is leaving the server. + * + * @param client The client index. + */ +ZMarketOnClientDisconnect(client) +{ + // Destroy ZMarket array data for client. + CloseHandle(g_hZMarketPurchaseCount[client]); + g_hZMarketPurchaseCount[client] = INVALID_HANDLE; +} + +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +ZMarketOnClientSpawn(client) +{ + // Reset purchase counts for client. + ZMarketResetPurchaseCount(client); + + // If auto-rebuy is enabled, then force client to rebuy weapons. + if (g_bZMarketAutoRebuy[client]) + { + ZMarketRebuy(client); + } +} + +/** + * Reset the purchase count(s) for a client. + * + * @param client The client index. + */ +ZMarketResetPurchaseCount(client) +{ + // Clear out the trie of all data. + ClearTrie(g_hZMarketPurchaseCount[client]); +} + +/** + * Set the purchases left for a client of a weapon. + * + * @param client The client index. + * @param weapon The weapon name. + * @param value The amount of purchases left for the weapon. + */ +ZMarketSetPurchaseCount(client, const String:weapon[], value, bool:add = false) +{ + // Initialize variable (value is 0) + new purchasemax; + + // If we are adding, then update variable with current ammo value. + if (add) + { + purchasemax = ZMarketGetPurchaseCount(client, weapon); + } + + // Set value in client's trie. + SetTrieValue(g_hZMarketPurchaseCount[client], weapon, purchasemax + value); +} + +/** + * Get the purchases left for a client of a weapon. + * + * @param client The client index. + * @param weapon The weapon name. + * @param return The amount of purchases left for the weapon. + */ +ZMarketGetPurchaseCount(client, const String:weapon[]) +{ + // Get value in client's trie. + new value; + GetTrieValue(g_hZMarketPurchaseCount[client], weapon, value); + return value; +} + +/** + * Sends weapon type list to client. + * @param client The client index. + * @return True if the menu was sent successfully, false if not. + */ +bool:ZMarketMenuTypes(client) +{ + new bool:zmarket = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET]); + if (!zmarket) + { + // Telle client feature is disabled. + TranslationPrintToChat(client, "Feature is disabled"); + return false; + } + + // Create menu handle. + new Handle:menu_zmarket_types = CreateMenu(ZMarketMenuTypesHandle); + + // Set translation target as client. + SetGlobalTransTarget(client); + + // Set menu title. + SetMenuTitle(menu_zmarket_types, "%t\n ", "Weapons menu zmarket types title"); + + // If rebuy is enabled, then add it to the menu. + new bool:zmarketrebuy = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY]); + new bool:zmarketrebuyauto = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_AUTO]); + + // If rebuy or auto-rebuy is enabled, then add it to the menu. + if (zmarketrebuy || zmarketrebuyauto) + { + // Add "Rebuy" option. + decl String:rebuy[WEAPONS_MAX_LENGTH]; + Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket types rebuy"); + AddMenuItem(menu_zmarket_types, "Rebuy", rebuy); + } + + // If auto-rebuy is enabled, then add it to the menu. + if (zmarketrebuyauto) + { + // Get current auto-rebuy setting. + decl String:rebuyautosetting[8]; + ConfigBoolToSetting(g_bZMarketAutoRebuy[client], rebuyautosetting, sizeof(rebuyautosetting)); + + // Add "Auto-Rebuy" option. + decl String:rebuyauto[WEAPONS_MAX_LENGTH]; + Format(rebuyauto, sizeof(rebuyauto), "%t", "Weapons menu zmarket types auto-rebuy", rebuyautosetting); + AddMenuItem(menu_zmarket_types, "Auto-Rebuy", rebuyauto); + } + + decl String:typename[WEAPONS_MAX_LENGTH]; + + // x = Array index. + new size = GetArraySize(arrayWeaponTypes); + for (new x = 0; x < size; x++) + { + // Get name of type. + RestrictWeaponTypeGetName(x, typename, sizeof(typename)); + + // Add item to menu. + AddMenuItem(menu_zmarket_types, typename, typename); + } + + // If there are no weapons, add an "(Empty)" line. + if (size == 0) + { + decl String:empty[64]; + Format(empty, sizeof(empty), "%t", "Menu empty"); + + AddMenuItem(menu_zmarket_types, "empty", empty, ITEMDRAW_DISABLED); + } + + // Set exit back button. + SetMenuExitBackButton(menu_zmarket_types, true); + + DisplayMenu(menu_zmarket_types, client, MENU_TIME_FOREVER); + + // Menu sent successfully. + return true; +} + +/** + * Called when client selects option in the weapons list menu, and handles it. + * @param menu_zmarket_types Handle of the menu being used. + * @param action The action done on the menu (see menus.inc, enum MenuAction). + * @param client The client index. + * @param slot The slot index selected (starting from 0). + */ +public ZMarketMenuTypesHandle(Handle:menu_zmarket_types, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + decl String:weapontype[WEAPONS_MAX_LENGTH]; + GetMenuItem(menu_zmarket_types, slot, weapontype, sizeof(weapontype)); + + if (StrEqual(weapontype, "Rebuy")) + { + // Force client to rebuy weapons. + ZMarketRebuy(client); + + // Resend menu. + ZMarketMenuTypes(client); + + return; + } + + if (StrEqual(weapontype, "Auto-Rebuy")) + { + // Toggle rebuy. + g_bZMarketAutoRebuy[client] = !g_bZMarketAutoRebuy[client]; + + // Resend menu. + ZMarketMenuTypes(client); + + return; + } + + // Get weapon index. + new weapontypeindex = RestrictTypeToIndex(weapontype); + + // If weapon type index is -1, then something went very wrong. + if (weapontypeindex == -1) + { + // Resend menu. + ZMarketMenuTypes(client); + + return; + } + + // Menu slot index is = weapon type index. + g_iZMarketCurType[client] = weapontypeindex; + + // Send weapons of the selected type in a menu to client. + ZMarketMenuTypeWeapons(client); + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + MenuMain(client); + } + } + // Client hit "Exit" button. + else if (action == MenuAction_End) + { + CloseHandle(menu_zmarket_types); + } +} + +/** + * Sends a list of weapons of a certain type in a menu to the client. + * @param client The client index. + */ +ZMarketMenuTypeWeapons(client) +{ + // Create menu handle. + new Handle:menu_zmarket_typeweapons = CreateMenu(ZMarketMenuTypeWeaponsHandle); + + // Get name of current weapon type. + decl String:typename[WEAPONS_MAX_LENGTH]; + RestrictWeaponTypeGetName(g_iZMarketCurType[client], typename, sizeof(typename)); + + // Set menu title. + SetMenuTitle(menu_zmarket_typeweapons, "%t\n ", "Weapons menu zmarket types weapon type title", typename); + + decl String:typeweapon[WEAPONS_MAX_LENGTH]; + decl String:typeweapondisplay[WEAPONS_MAX_LENGTH]; + decl String:display[128]; + + // Get an array populated with all weapons of the given type. + new Handle:arrayTypeWeapons; + new count = RestrictGetTypeWeapons(g_iZMarketCurType[client], arrayTypeWeapons); + + // x = Array index. + for (new x = 0; x < count; x++) + { + // Get weapon index to check restricted status of. + new weaponindex = GetArrayCell(arrayTypeWeapons, x); + + // Get name of weapon. + WeaponsGetName(weaponindex, typeweapon, sizeof(typeweapon)); + + // Check if client is buying the weapon or ammo for it, and get the price of the item. + new bool:hasweapon = WeaponsClientHasWeapon(client, typeweapon); + + // DO ITEM PRICE STUFF HERE. + + new itemprice; + + // Do appropriate formatting for the type of item client is buying. + new WeaponsSlot:slot = WeaponsGetSlot(weaponindex); + if (!hasweapon || slot == Slot_Invalid || slot == Slot_Projectile) + { + // Get the weapon price. + itemprice = WeaponsGetZMarketPrice(weaponindex); + } + else + { + // Get the weapon's ammo price. + itemprice = WeaponsGetAmmoPrice(weaponindex); + + // Tell client they are buying ammo. + Format(typeweapondisplay, sizeof(typeweapondisplay), "%s %t", typeweapon, "Weapons menu zmarket types weapon ammo"); + } + + // If the itemprice is invalid, then set to known integer to be later replaced. + if (itemprice < 0) + { + itemprice = -1; + } + + // DO RESTRICTED WEAPON STUFF HERE. + + // Get restricted status on the weapon. + new bool:restricted = RestrictIsWeaponRestricted(weaponindex); + + // If weapon is restricted then format "[]" around it. + strcopy(typeweapondisplay, sizeof(typeweapondisplay), typeweapon); + if (restricted) + { + Format(typeweapondisplay, sizeof(typeweapondisplay), "[%s]", typeweapon); + } + + // DO PURCHASE MAX STUFF HERE. + + // Get the purchase count information for this weapon. + new purchasemax = WeaponsGetZMarketPurchaseMax(weaponindex); + new purchasecount = ZMarketGetPurchaseCount(client, typeweapon); + new purchasesleft = purchasemax - purchasecount; + + // If the purchases left for the weapon goes below 0, fix it. + if (purchasesleft < 0) + { + purchasesleft = 0; + } + + // If max purchases is disabled for the weapon, then set as known integer to be later replaced. + if (purchasemax <= 0) + { + purchasesleft = -1; + } + + // Format all the information together. + + // Format price onto the menu entry. + Format(display, sizeof(display), "%t", "Weapons menu zmarket types weapon info", typeweapondisplay, itemprice, purchasesleft); + + // Remove the known invalid number from the string, and replace with N/A, and remove currency symbol. + ReplaceString(display, sizeof(display), "$-1", "N/A"); + ReplaceString(display, sizeof(display), "-1", "N/A"); + + // Disable option if it isn't toggleable. + new bool:itemdraw = ((itemprice > -1) && !restricted && (purchasemax <= 0 || purchasesleft > 0)); + AddMenuItem(menu_zmarket_typeweapons, typeweapon, display, MenuGetItemDraw(itemdraw)); + } + + // Destroy the array handle. + CloseHandle(arrayTypeWeapons); + + // Set menu back button. + SetMenuExitBackButton(menu_zmarket_typeweapons, true); + + // Display menu to client. + DisplayMenu(menu_zmarket_typeweapons, client, MENU_TIME_FOREVER); +} + +/** + * Called when client selects option in the weapon group menu, and handles it. + * @param menu_zmarket_typeweapons Handle of the menu being used. + * @param action The action done on the menu (see menus.inc, enum MenuAction). + * @param client The client index. + * @param slot The slot index selected (starting from 0). + */ +public ZMarketMenuTypeWeaponsHandle(Handle:menu_zmarket_typeweapons, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + // Get name of current weapon type. + decl String:typename[WEAPONS_MAX_LENGTH]; + RestrictWeaponTypeGetName(g_iZMarketCurType[client], typename, sizeof(typename)); + + decl String:typeweapon[WEAPONS_MAX_LENGTH]; + GetMenuItem(menu_zmarket_typeweapons, slot, typeweapon, sizeof(typeweapon)); + + // Equip weapon on client. + ZMarketEquip(client, typeweapon); + + // Open types menu. + ZMarketMenuTypes(client); + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + ZMarketMenuTypes(client); + } + } + // Client hit "Exit" button. + else if (action == MenuAction_End) + { + CloseHandle(menu_zmarket_typeweapons); + } +} + +/** + * Equip a weapon on a client. + * + * @param client The client index. + * @param weapon The weapon to equip (must be in weapons config file) + * @param rebuy (Optional) If client is rebuying, ammo will be ignored. + */ +stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) +{ + // If client is a zombie, then stop. + if (InfectIsClientInfected(client)) + { + TranslationPrintToChat(client, "Must be human"); + return false; + } + + new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); + if (zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) + { + TranslationPrintToChat(client, "Weapons zmarket buyzone"); + return false; + } + + // Get weapon index. + new weaponindex = WeaponsNameToIndex(weapon); + + // If weapon index is -1, then something went very wrong. + if (weaponindex == -1) + { + return false; + } + + // Get slot index of the weapon being purchased. + new WeaponsSlot:slot = WeaponsGetSlot(weaponindex); + + // Get the appropriate price of the item being purchased. + new bool:hasweapon = WeaponsClientHasWeapon(client, weapon); + new itemprice = (hasweapon && slot != Slot_Invalid && slot != Slot_Projectile) ? WeaponsGetAmmoPrice(weaponindex) : WeaponsGetZMarketPrice(weaponindex); + + // If the weapon price is below 0, then something went wrong. + if (itemprice < 0) + { + return false; + } + + // Get client's current money. + new cash = AccountGetClientCash(client); + + // If client doesn't have enough money, tell them, resend menu, and then stop. + if (cash < itemprice) + { + TranslationPrintToChat(client, "Not enough money"); + return false; + } + + // Set client's new cash after purchase. + AccountSetClientCash(client, cash - itemprice); + + // Check to make sure the weapon isn't restricted. + new bool:restricted = RestrictIsWeaponRestricted(weaponindex); + if (restricted) + { + TranslationPrintToChat(client, "Weapon is restricted", weapon); + return false; + } + + // Get the purchase count information for this weapon. + new purchasemax = WeaponsGetZMarketPurchaseMax(weaponindex); + new purchasecount = ZMarketGetPurchaseCount(client, weapon); + new purchasesleft = purchasemax - purchasecount; + if (purchasemax > 0 && purchasesleft <= 0) + { + TranslationPrintToChat(client, "Weapons zmarket purchase max", weapon, purchasemax); + return false; + } + + // Get a list of the client's current weapons. + new weapons[WeaponsSlot]; + WeaponsGetClientWeapons(client, weapons); + + // Check if client is buying the weapon or ammo for it. + if (!hasweapon || slot == Slot_Invalid || slot == Slot_Projectile) + { + + // Check if the slot is valid and NOT a projectile (grenade). + if (slot != Slot_Invalid && slot != Slot_Projectile) + { + // If there is already a weapon in the slot, then force client to drop it. + if (weapons[slot] > -1) + { + // Force client to drop the weapon. + WeaponsForceClientDrop(client, weapons[slot]); + } + } + + // Format name into entity name. + decl String:weaponentity[WEAPONS_MAX_LENGTH]; + + // If the slot is invalid, this means the item is not a usable weapon, it's equipment. + if (slot == Slot_Invalid) + { + Format(weaponentity, sizeof(weaponentity), "item_%s", weapon); + } + else + { + Format(weaponentity, sizeof(weaponentity), "weapon_%s", weapon); + } + + // Give client the weapon. + GivePlayerItem(client, weaponentity); + + // Copy weapon to array for this slot. + strcopy(g_strZMarketLastWeapon[client][slot], sizeof(g_strZMarketLastWeapon), weapon); + + // Add 1 to the client's purchase count. + ZMarketSetPurchaseCount(client, weapon, 1, true); + + // Tell client they bought a weapon. + TranslationPrintToChat(client, "Weapons zmarket purchase", weapon); + } + else if (!rebuy) + { + // Get ammo type and stop if it's invalid. + decl String:weaponammo[WEAPONS_MAX_LENGTH]; + WeaponsGetAmmoType(weaponindex, weaponammo, sizeof(weaponammo)); + if (!weaponammo[0]) + { + return false; + } + + // Give ammo and preserve client's clip ammo value. + new clip = WeaponAmmoGetAmmo(weapons[slot], true); + GivePlayerItem(client, weaponammo); + WeaponAmmoSetAmmo(weapons[slot], true, clip); + } + + return true; +} + +/** + * Force a client to rebuy their weapons. + * + * @param client The client index. + */ +ZMarketRebuy(client) +{ + // If client is a zombie, then stop. + if (InfectIsClientInfected(client)) + { + TranslationPrintToChat(client, "Must be human"); + return; + } + + new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); + if (zmarketbuyzone && !ZMarketIsClientInBuyZone(client)) + { + TranslationPrintToChat(client, "Weapons zmarket buyzone"); + return; + } + + // x = Weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + new bool:equipped = ZMarketEquip(client, g_strZMarketLastWeapon[client][x], true); + + // Remove weapon from last weapons. + if (!equipped) + { + strcopy(g_strZMarketLastWeapon[client][x], sizeof(g_strZMarketLastWeapon), ""); + } + } +} + /** * Checks if a client is in a buyzone. *