/* * ============================================================================ * * Zombie:Reloaded * * File: zmarket.inc * Type: Module * Description: ZMarket module, provides menu of weapons to buy from. * * Copyright (C) 2009-2013 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 . * * ============================================================================ */ /** * @section Name of the cookies for ZMarket rebuy/auto-rebuy data. */ #define ZMARKET_COOKIE_AUTOREBUY "zr_zmarket_autorebuy" #define ZMARKET_COOKIE_REBUY "zr_zmarket_rebuy" /** * @endsection */ /** * Slots saved for auto-rebuy */ #define ZMARKET_REBUY_WEAPONS_SLOTS_MAX 1 /** * 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]; /** * Whether weapons has been bought automatically. Used to prevent double rebuy * when cookies are loaded after the player was spawned. */ new bool:g_bZMarketWeaponsBought[MAXPLAYERS + 1]; /** * Cookie handle array for weapon loadouts. */ new Handle:g_hZMarketLoadoutCookie[ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1]; new bool:g_bZMarketCommandInitialized = false; /** * Create commands specific to ZMarket. */ ZMarketOnCommandsCreate() { // Register ZMarket command. RegConsoleCmd(SAYHOOKS_KEYWORD_ZMARKET, ZMarketCommand, "Opens custom buymenu."); g_bZMarketCommandInitialized = false; } ZMarketOnCookiesCreate() { decl String:rebuycookiename[32]; decl String:rebuycookiedesc[64]; // x = Weapon slot. for (new x = 0; x < ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1; x++) { // Format cookie name and description. Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); Format(rebuycookiedesc, sizeof(rebuycookiedesc), "Current loadout weapon for slot %d", x); // Create loadout cookie handle if it doesn't exist. if (g_hZMarketLoadoutCookie[x] == INVALID_HANDLE) { g_hZMarketLoadoutCookie[x] = RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Protected); } } } ZMarketLoad() { // Do not register commands multiple times if(g_bZMarketCommandInitialized) return; decl String:zmarketcommand[CONFIG_MAX_LENGTH]; decl String:weaponname[WEAPONS_MAX_LENGTH]; new size = GetArraySize(arrayWeapons); for (new weaponindex = 0; weaponindex < size; weaponindex++) { WeaponsGetZMarketCommand(weaponindex, zmarketcommand, sizeof(zmarketcommand)); if(zmarketcommand[0]) { WeaponsGetName(weaponindex, weaponname, sizeof(weaponname)); if (FindCharInString(zmarketcommand, ',') != -1) { int idx; int lastidx; while ((idx = FindCharInString(zmarketcommand[lastidx], ',')) != -1) { char out[16]; char fmt[8]; Format(fmt, sizeof(fmt), "%%.%ds", idx); Format(out, sizeof(out), fmt, zmarketcommand[lastidx]); RegConsoleCmd(out, ZMarketBuyCommand, weaponname); lastidx += ++idx; if (FindCharInString(zmarketcommand[lastidx], ',') == -1 && zmarketcommand[lastidx+1] != '\0') RegConsoleCmd(zmarketcommand[lastidx], ZMarketBuyCommand, weaponname); } } else { RegConsoleCmd(zmarketcommand, ZMarketBuyCommand, weaponname); } } } g_bZMarketCommandInitialized = true; } public Action:ZMarketBuyCommand(client, argc) { decl String:command[CONFIG_MAX_LENGTH]; decl String:zmarketcommand[CONFIG_MAX_LENGTH]; decl String:weaponname[WEAPONS_MAX_LENGTH]; GetCmdArg(0, command, sizeof(command)); new size = GetArraySize(arrayWeapons); for (new weaponindex = 0; weaponindex < size; weaponindex++) { WeaponsGetZMarketCommand(weaponindex, zmarketcommand, sizeof(zmarketcommand)); if (FindCharInString(zmarketcommand, ',') != -1) { int idx; int lastidx; while ((idx = FindCharInString(zmarketcommand[lastidx], ',')) != -1) { if (!strncmp(command, zmarketcommand[lastidx], idx)) { WeaponsGetName(weaponindex, weaponname, sizeof(weaponname)); ZMarketEquip(client, weaponname); return Plugin_Handled; } lastidx += ++idx; if (FindCharInString(zmarketcommand[lastidx], ',') == -1 && zmarketcommand[lastidx+1] != '\0') { if (!strncmp(command, zmarketcommand[lastidx], idx)) { WeaponsGetName(weaponindex, weaponname, sizeof(weaponname)); ZMarketEquip(client, weaponname); return Plugin_Handled; } } } } else { if(StrEqual(command, zmarketcommand)) { WeaponsGetName(weaponindex, weaponname, sizeof(weaponname)); ZMarketEquip(client, weaponname); return Plugin_Handled; } } } return Plugin_Handled; } /** * 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(); // No weapons bought automatically. g_bZMarketWeaponsBought[client] = false; } /** * Called once a client's saved cookies have been loaded from the database. * * @param client Client index. */ ZMarketOnCookiesCached(client) { // Rebuy wapons (if auto-rebuy is enabled, and not bought already). if (!g_bZMarketWeaponsBought[client]) { ZMarketCheckRebuy(client); } } /** * Client is leaving the server. * * @param client The client index. */ ZMarketOnClientDisconnect(client) { // Destroy ZMarket array data for client. if (g_hZMarketPurchaseCount[client] != INVALID_HANDLE) { CloseHandle(g_hZMarketPurchaseCount[client]); } // Reset handle. g_hZMarketPurchaseCount[client] = INVALID_HANDLE; } /** * Client is spawning into the game. * * @param client The client index. */ ZMarketOnClientSpawnPost(client) { // Reset purchase counts for client. ZMarketResetPurchaseCount(client); // Rebuy if auto-rebuy is enabled. ZMarketCheckRebuy(client); } /** * Rebuys weapons if auto-rebuy is enabled and player is a human (alive). * * @param client The client index. */ ZMarketCheckRebuy(client) { // If client hasn't spawned into the game yet, then stop. if (!IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client)) { return; } // If client is a zombie, then stop. if (InfectIsClientInfected(client)) { return; } // Give default/prefered spawn weapons ZMarketRebuy(client, true); g_bZMarketWeaponsBought[client] = true; } /** * Reset the purchase count(s) for a client. * * @param client The client index. */ ZMarketResetPurchaseCount(client) { // Clear out the trie of all data. if (g_hZMarketPurchaseCount[client] != INVALID_HANDLE) { 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 main ZMarket menu to client. * * @param client The client index. * @return True if the menu was sent successfully, false if not. */ bool:ZMarketMenuMain(client) { // If weapons module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); if (!weapons) { // Telle client feature is disabled. TranslationPrintToChat(client, "Feature is disabled"); return false; } // If ZMarket module is disabled, then stop. 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_main = CreateMenu(ZMarketMenuMainHandle); // Set translation target as client. SetGlobalTransTarget(client); // 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]); // Add "Get Current Loadout" option. decl String:title[MENU_LINE_TITLE_LENGTH]; decl String:getloadout[MENU_LINE_REG_LENGTH]; decl String:editloadout[MENU_LINE_REG_LENGTH]; decl String:rebuy[MENU_LINE_REG_LENGTH]; decl String:weaponslist[MENU_LINE_REG_LENGTH]; // Format menu options. Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket main title"); Format(getloadout, sizeof(getloadout), "%t", "Weapons menu zmarket main get loadout"); Format(editloadout, sizeof(editloadout), "%t", "Weapons menu zmarket main edit loadout"); Format(rebuy, sizeof(rebuy), "%t", "Weapons menu zmarket main rebuy"); Format(weaponslist, sizeof(weaponslist), "%t", "Weapons menu zmarket main weapons list"); // Add formatted options to menu. SetMenuTitle(menu_zmarket_main, title); AddMenuItem(menu_zmarket_main, "Get Loadout", getloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); AddMenuItem(menu_zmarket_main, "Edit Loadout", editloadout, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); AddMenuItem(menu_zmarket_main, "Rebuy", rebuy, MenuGetItemDraw(zmarketrebuy || zmarketrebuyauto)); AddMenuItem(menu_zmarket_main, "Weapons List", weaponslist); // Set exit back button. SetMenuExitBackButton(menu_zmarket_main, true); DisplayMenu(menu_zmarket_main, client, MENU_TIME_FOREVER); // Menu sent successfully. return true; } /** * Called when client selects option in the main ZMarket menu, and handles it. * * @param menu_zmarket_main 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 ZMarketMenuMainHandle(Handle:menu_zmarket_main, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { switch(slot) { // Get loadout. case 0: { // Gets a client's current loadout. ZMarketGetCurrentLoadout(client); // Resend menu. ZMarketMenuMain(client); } // Edit loadout. case 1: { // Send the weapon loadout edit menu. ZMarketMenuLoadout(client); } // Rebuy. case 2: { // Force client to rebuy weapons. ZMarketRebuy(client); // Resend menu. ZMarketMenuMain(client); } // Weapons list. case 3: { // Send the weapon types list. ZMarketMenuTypes(client); } } } // Client closed the menu. if (action == MenuAction_Cancel) { // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { ZMenuMain(client); } } // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_zmarket_main); } } /** * Sends list of weapons in a client's loadout to the client. * * @param client The client index. */ bool:ZMarketMenuLoadout(client) { // Create menu handle. new Handle:menu_zmarket_loadout = CreateMenu(ZMarketMenuLoadoutHandle); // Transfer cookie values into an array. new String:rebuyweapons[ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1][WEAPONS_MAX_LENGTH]; ZMarketCookiesToArray(client, rebuyweapons, sizeof(rebuyweapons), sizeof(rebuyweapons[])); SetGlobalTransTarget(client); // x = Rebuy weapon slot. for (new x = 0; x < sizeof(rebuyweapons); x++) { // If the client doesn't have a weapon in this slot, then set the weapon to the default translation. if (!rebuyweapons[x][0]) { // Get default weapon for this slot decl String:weaponname[WEAPONS_MAX_LENGTH]; switch(x) { case Slot_Primary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_PRIMARY], weaponname, sizeof(weaponname)); } case Slot_Secondary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_SECONDARY], weaponname, sizeof(weaponname)); } } Format(rebuyweapons[x], sizeof(rebuyweapons[]), "%t", "Weapons menu zmarket loadout default", weaponname); } } decl String:title[MENU_LINE_HUGE_LENGTH]; decl String:primary[MENU_LINE_REG_LENGTH]; decl String:secondary[MENU_LINE_REG_LENGTH]; // Format all the lines of the menu. Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket loadout title"); Format(primary, sizeof(primary), "%t", "Weapons menu zmarket loadout primary", rebuyweapons[Slot_Primary]); Format(secondary, sizeof(secondary), "%t", "Weapons menu zmarket loadout secondary", rebuyweapons[Slot_Secondary]); // Add formatted options to menu. SetMenuTitle(menu_zmarket_loadout, title); AddMenuItem(menu_zmarket_loadout, "0", primary); AddMenuItem(menu_zmarket_loadout, "1", secondary); // Set exit back button. SetMenuExitBackButton(menu_zmarket_loadout, true); // Send menu to client. DisplayMenu(menu_zmarket_loadout, client, MENU_TIME_FOREVER); } /** * Allow the user to press the "Back" button to go to main ZMarket menu. * * @param menu_zmarket_loadout 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 ZMarketMenuLoadoutHandle(Handle:menu_zmarket_loadout, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { // Open correct submenu for weapon type switch(slot) { case 0: { g_iZMarketCurType[client] = _:Slot_Primary; ZMarketMenuLoadoutWeapons(client, Slot_Primary); } case 1: { g_iZMarketCurType[client] = _:Slot_Secondary; ZMarketMenuLoadoutWeapons(client, Slot_Secondary); } } } // Client closed the menu. if (action == MenuAction_Cancel) { // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { ZMarketMenuMain(client); } } // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_zmarket_loadout); } } ZMarketMenuLoadoutWeapons(client, WeaponsSlot:slot) { // Create menu handle. new Handle:menu_zmarket_loadout_weapons = CreateMenu(ZMarketMenuLoadoutWeaponsHandle); // Set translation target as client. SetGlobalTransTarget(client); decl String:title[MENU_LINE_TITLE_LENGTH]; Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket loadout weapons title"); SetMenuTitle(menu_zmarket_loadout_weapons, title); decl String:weaponname[WEAPONS_MAX_LENGTH]; decl String:weapondisplay[MENU_LINE_REG_LENGTH]; // Get default weapon for this slot switch(slot) { case Slot_Primary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_PRIMARY], weaponname, sizeof(weaponname)); } case Slot_Secondary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_SECONDARY], weaponname, sizeof(weaponname)); } } // First item = Server default weapon Format(weapondisplay, sizeof(weapondisplay), "%t", "Weapons menu zmarket loadout default", weaponname); AddMenuItem(menu_zmarket_loadout_weapons, "", weapondisplay); new size = GetArraySize(arrayWeapons); for (new weaponindex = 0; weaponindex < size; weaponindex++) { // Get weapons slot new WeaponsSlot:wslot = WeaponsGetSlot(weaponindex); // Does it match with the slot we want? if(wslot != slot) continue; WeaponsGetName(weaponindex, weaponname, sizeof(weaponname), (g_Game == Game_CSGO)); // Get restricted status on the weapon. new bool:restricted = RestrictIsWeaponRestricted(weaponindex); // If weapon is restricted then format "[]" around it. strcopy(weapondisplay, sizeof(weapondisplay), weaponname); if (restricted) { Format(weapondisplay, sizeof(weapondisplay), "[%s]", weaponname); } // Disable weapon if it's restricted. AddMenuItem(menu_zmarket_loadout_weapons, weaponname, weapondisplay, MenuGetItemDraw(!restricted)); } // Set exit back button. SetMenuExitBackButton(menu_zmarket_loadout_weapons, true); DisplayMenu(menu_zmarket_loadout_weapons, client, MENU_TIME_FOREVER); } /** * Called when client selects a weapon in the loadout weapons menu, and handles it. * * @param menu_zmarket_loadout_weapons 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 ZMarketMenuLoadoutWeaponsHandle(Handle:menu_zmarket_loadout_weapons, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { // Get name of selected weapon. decl String:weapon[WEAPONS_MAX_LENGTH]; GetMenuItem(menu_zmarket_loadout_weapons, slot, weapon, sizeof(weapon)); // Update cookie with new weapon. ZMarketSetRebuyCookie(client, WeaponsSlot:g_iZMarketCurType[client], weapon); // Open loadout menu. ZMarketMenuLoadout(client); } // Client closed the menu. if (action == MenuAction_Cancel) { // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { ZMarketMenuLoadout(client); } } // Client hit "Exit" button. else if (action == MenuAction_End) { CloseHandle(menu_zmarket_loadout_weapons); } } /** * Sends weapon type list to client. * * @param client The client index. */ ZMarketMenuTypes(client) { // Create menu handle. new Handle:menu_zmarket_types = CreateMenu(ZMarketMenuTypesHandle); // Set translation target as client. SetGlobalTransTarget(client); decl String:title[MENU_LINE_TITLE_LENGTH]; Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket types title"); SetMenuTitle(menu_zmarket_types, title); 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) { SetGlobalTransTarget(client); decl String:empty[MENU_LINE_SMALL_LENGTH]; 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); } /** * 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)); // 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) { ZMarketMenuMain(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)); decl String:title[MENU_LINE_TITLE_LENGTH]; decl String:typeweapon[WEAPONS_MAX_LENGTH]; decl String:typeweapondisplay[MENU_LINE_REG_LENGTH]; decl String:typeweaponentity[WEAPONS_MAX_LENGTH]; decl String:display[MENU_LINE_BIG_LENGTH]; // Get an array populated with all weapons of the given type. new Handle:arrayTypeWeapons; new count = RestrictGetTypeWeapons(g_iZMarketCurType[client], arrayTypeWeapons); SetGlobalTransTarget(client); // 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), (g_Game == Game_CSGO)); // Get entity name of weapon. WeaponsGetEntity(weaponindex, typeweaponentity, sizeof(typeweaponentity)); // Check if client is buying the weapon or ammo for it, and get the price of the item. new bool:hasweapon = WeaponsClientHasWeapon(client, typeweaponentity); // 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_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)); } Format(title, sizeof(title), "%t\n ", "Weapons menu zmarket types weapon type title", typename); SetMenuTitle(menu_zmarket_typeweapons, title); // 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 and cash will be ignored. */ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) { // if zombie hasn't spawned yet we're always rebuying: new bool:zmarketfreespawn = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_FREESPAWN]); if(zmarketfreespawn && !InfectHasZombieSpawned()) rebuy = true; // Get weapon index. new weaponindex = WeaponsNameToIndex(weapon); // If weapon index is -1, then something went very wrong. if (weaponindex == -1) { LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Weapons, "ZMarket Equip", "Invalid weapon (%s) selected from the ZMarket menu.", weapon); return false; } // Get slot index of the weapon being purchased. new WeaponsSlot:slot = WeaponsGetSlot(weaponindex); // If client is dead, then stop. if (!IsPlayerAlive(client)) { TranslationPrintToChat(client, "Must be alive"); return 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 (!rebuy && zmarketbuyzone && !WeaponsIsClientInBuyZone(client)) { TranslationPrintToChat(client, "Must be in buyzone"); return false; } // Get entity name of the weapon. decl String:weaponentity[WEAPONS_MAX_LENGTH]; WeaponsGetEntity(weaponindex, weaponentity, sizeof(weaponentity)); // Get the appropriate price of the item being purchased. new bool:hasweapon = WeaponsClientHasWeapon(client, weaponentity); new itemprice = (hasweapon && slot != Slot_Projectile) ? WeaponsGetAmmoPrice(weaponindex) : WeaponsGetZMarketPrice(weaponindex); // If the weapon price is below 0, then something went wrong. if (itemprice < 0) { return false; } // Get the display name for the weapon. decl String:weapondisplay[WEAPONS_MAX_LENGTH]; WeaponsGetName(weaponindex, weapondisplay, sizeof(weapondisplay), (g_Game == Game_CSGO)); // Check to make sure the weapon isn't restricted. new bool:restricted = RestrictIsWeaponRestricted(weaponindex); if (restricted) { TranslationPrintToChat(client, "Weapon is restricted", weapondisplay); return false; } // Get the purchase count information for this weapon. new purchasemax = WeaponsGetZMarketPurchaseMax(weaponindex); new purchasecount = ZMarketGetPurchaseCount(client, weapon); new purchasesleft = purchasemax - purchasecount; if (!rebuy && purchasemax >= 0 && purchasesleft <= 0) { TranslationPrintToChat(client, "Weapons zmarket purchase max", weapondisplay, purchasemax); return false; } // If the slot is a projectile, then get information we need to compare later. if (slot == Slot_Projectile) { // Get the grenade type the client is trying to buy. new WeaponAmmoGrenadeType:grenadetype = WeaponAmmoEntityToGrenadeType(weaponentity); if (grenadetype == GrenadeType_Invalid) { LogEvent(false, LogType_Error, LOG_GAME_EVENTS, LogModule_Weapons, "Grenades", "Client \"%L\" attempted to buy weapon entity \"%s\" marked as a projectile. Check your weapon config.", client, weaponentity); return false; } // How many grenades does the client currently have? new grenadecount = WeaponAmmoGetGrenadeCount(client, grenadetype); // How many grenades can the client hold? new grenadelimit = WeaponAmmoGetGrenadeLimit(grenadetype); // If client is at, or exceeds the grenade limit, then stop. if (grenadecount >= grenadelimit) { // Client can't carry any more of this type of grenade. TranslationPrintToChat(client, "Weapons zmarket grenade max", grenadelimit); return false; } } if(!rebuy) { // 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, "Weapons zmarket not enough money"); return false; } // Set client's new cash after purchase. AccountSetClientCash(client, cash - itemprice); } // 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_Projectile || slot == Slot_NVGs) { int oldclip = -1; // If the item is a projectile or NVGs, then skip. if (slot != Slot_Projectile && slot != Slot_NVGs) { // If there is already a weapon in the slot, then force client to drop it. if (weapons[slot] > -1) { oldclip = GetEntProp(weapons[slot], Prop_Send, "m_iClip1"); if(rebuy) { // Kill weapon right away to decrease amount of entities on roundstart. RemoveEdict(weapons[slot]); } else { // Force client to drop the weapon. WeaponsForceClientDrop(client, weapons[slot]); } } } int entity = INVALID_ENT_REFERENCE; if (StrEqual(weaponentity, "item_kevlar")) { SetEntProp(client, Prop_Send, "m_ArmorValue", 100); SetEntProp(client, Prop_Send, "m_bHasHelmet", 1); } else { // Give client the weapon. entity = GivePlayerItem(client, weaponentity); } if (!rebuy) { // Add 1 to the client's purchase count. ZMarketSetPurchaseCount(client, weapon, 1, true); // If client isn't rebuying the weapon, then tell them the weapon has been purchased. TranslationPrintToChat(client, "Weapons zmarket purchase", weapondisplay); new bool:zmarketnorefill = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_NOREFILL]); if (IsValidEntity(entity) && !WeaponsIsClientInBuyZone(client) && zmarketnorefill) { int newclip = 0; if (oldclip != -1) { newclip = GetEntProp(entity, Prop_Send, "m_iClip1"); if(newclip > oldclip) newclip = oldclip; } SetEntProp(entity, Prop_Send, "m_iClip1", newclip); } } } 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; } // Prevent exploit by refilling ammo by re-buying weapon. // Current clip amounts are stored, ammo is refilled, and then clips are reset. new prim_clip; new sec_clip; if (weapons[Slot_Primary] > 0) { prim_clip = WeaponAmmoGetAmmo(weapons[Slot_Primary], true); } if (weapons[Slot_Secondary] > 0) { sec_clip = WeaponAmmoGetAmmo(weapons[Slot_Secondary], true); } GivePlayerItem(client, weaponammo); if (weapons[Slot_Primary] > 0) { WeaponAmmoSetAmmo(weapons[Slot_Primary], true, prim_clip); } if (weapons[Slot_Secondary] > 0) { WeaponAmmoSetAmmo(weapons[Slot_Secondary], true, sec_clip); } } return true; } /** * Gets the client's current weapons and puts them in the rebuy cache. * * @param client The client index. * @return True if the menu sent successfully, false if not. */ bool:ZMarketGetCurrentLoadout(client) { // If client is dead, then stop. if (!IsPlayerAlive(client)) { TranslationPrintToChat(client, "Must be alive"); return false; } // If client is a zombie, then stop. if (InfectIsClientInfected(client)) { TranslationPrintToChat(client, "Must be human"); return false; } // Get all of client's current weapons. new weapons[WeaponsSlot]; WeaponsGetClientWeapons(client, weapons); decl String:weaponname[WEAPONS_MAX_LENGTH]; decl String:weaponentity[WEAPONS_MAX_LENGTH]; // x = Weapon slot. for (new x = 0; x < ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1; x++) { // If slot is empty, then clear this slot in rebuy cache and stop. if (weapons[x] == -1) { // Empty rebuy slot. ZMarketSetRebuyCookie(client, WeaponsSlot:x, ""); continue; } // Get the name of the weapon. GetEdictClassname(weapons[x], weaponentity, sizeof(weaponentity)); // Get the entity name of the weapon. WeaponsEntityToDisplay(weaponentity, weaponname, sizeof(weaponname)); // Copy the name to the rebuy cache. ZMarketSetRebuyCookie(client, WeaponsSlot:x, weaponname); } // Tell client their loadout has been updated. TranslationPrintToChat(client, "Weapons zmarket get current loadout"); return true; } /** * Transfer array values to rebuy cookies. * * @param client The client index. * @param rebuyweapons The string array to copy results from. * @param maxweapons The max amount of weapons in the array. * @param maxlen The max length of each cookie result. */ stock ZMarketArrayToCookies(client, String:rebuyweapons[ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1][], maxweapons, maxlen) { decl String:rebuycookiename[32]; new Handle:rebuycookie; // x = Weapon slot. for (new x = 0; x < maxweapons; x++) { // Format cookie name. Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); // Find cookie handle, and retrieve its value. rebuycookie = FindClientCookie(rebuycookiename); SetClientCookie(client, rebuycookie, rebuyweapons[x]); CloseHandle(rebuycookie); } } /** * Transfer rebuy cookies to an array for easier access. * * @param client The client index. * @param rebuyweapons The string array to copy results to * @param maxweapons The max amount of weapons in the array. * @param maxlen The max length of each cookie result. */ stock ZMarketCookiesToArray(client, String:rebuyweapons[ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1][], maxweapons, maxlen) { decl String:rebuycookiename[32]; new Handle:rebuycookie; // x = Weapon slot. for (new x = 0; x < maxweapons; x++) { // Format cookie name. Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); // Find cookie handle, and retrieve its value. rebuycookie = FindClientCookie(rebuycookiename); GetClientCookie(client, rebuycookie, rebuyweapons[x], maxlen); CloseHandle(rebuycookie); } } /** * Set a weapon slot cookie given the slot and value. * * @param client The client index. * @param slot The weapon slot to set value to. * @param value The value (weaponname) of the slot. */ stock ZMarketSetRebuyCookie(client, WeaponsSlot:slot, const String:value[]) { // Format cookie name. decl String:rebuycookiename[32]; Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, _:slot); // Find cookie handle, and retrieve its value. new Handle:rebuycookie = FindClientCookie(rebuycookiename); if (rebuycookie == INVALID_HANDLE) { return; } // Set weapon to cookie. SetClientCookie(client, rebuycookie, value); CloseHandle(rebuycookie); } /** * Force a client to rebuy their weapons. * * @param client The client index. */ ZMarketRebuy(client, bool:autorebuy = false) { // If client is dead, then stop. if (!IsPlayerAlive(client)) { TranslationPrintToChat(client, "Must be alive"); return; } // 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 (!autorebuy && zmarketbuyzone && !WeaponsIsClientInBuyZone(client)) { TranslationPrintToChat(client, "Weapons zmarket buyzone"); return; } // Transfer cookie values into an array. new String:rebuyweapons[ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1][WEAPONS_MAX_LENGTH]; ZMarketCookiesToArray(client, rebuyweapons, sizeof(rebuyweapons), sizeof(rebuyweapons[])); // x = Weapon slot. for (new x = 0; x < ZMARKET_REBUY_WEAPONS_SLOTS_MAX + 1; x++) { // If slot is empty, then use the default value. if (!rebuyweapons[x][0]) { switch(x) { case Slot_Primary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_PRIMARY], rebuyweapons[x], sizeof(rebuyweapons[])); } case Slot_Secondary: { GetConVarString(g_hCvarsList[CVAR_WEAPONS_ZMARKET_REBUY_SECONDARY], rebuyweapons[x], sizeof(rebuyweapons[])); } } } if (!RestrictIsWeaponRestricted(WeaponsNameToIndex(rebuyweapons[x]))) ZMarketEquip(client, rebuyweapons[x], autorebuy); } if(autorebuy) { // Always equip kevlar and hegrenade if (!RestrictIsWeaponRestricted(WeaponsNameToIndex("Kevlar Vest"))) ZMarketEquip(client, "Kevlar Vest", autorebuy); if (!RestrictIsWeaponRestricted(WeaponsNameToIndex("HEGrenade"))) ZMarketEquip(client, "HEGrenade", autorebuy); if (!RestrictIsWeaponRestricted(WeaponsNameToIndex("Smokegrenade"))) ZMarketEquip(client, "Smokegrenade", autorebuy); if (g_Game == Game_CSGO) { if (!RestrictIsWeaponRestricted(WeaponsNameToIndex("Healthshot"))) ZMarketEquip(client, "Healthshot", autorebuy); if (!RestrictIsWeaponRestricted(WeaponsNameToIndex("TAGrenade"))) ZMarketEquip(client, "TAGrenade", autorebuy); } } } /** * Command callback (zmarket) * Opens custom buymenu. * * @param client The client index. * @param argc Argument count. */ public Action:ZMarketCommand(client, argc) { // If client is console, then stop and tell them this feature is for players only. if (ZRIsConsole(client)) { TranslationPrintToServer("Must be player"); return Plugin_Handled; } // Send ZMarket menu. ZMarketMenuMain(client); // This stops the "Unknown command" message in client's console. return Plugin_Handled; }