/*
 * ============================================================================
 *
 *  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 <http://www.gnu.org/licenses/>.
 *
 * ============================================================================
 */

/**
 * @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"
#define ZMARKET_COOKIE_RANDOMIZE "zr_zmarket_randomize"
/**
 * @endsection
 */

/**
 * Slots saved for auto-rebuy
 */
#define ZMARKET_REBUY_WEAPONS_SLOTS_MAX 1


/**
 * 2026 randomization of zmarket guns for round start.
*/
new Handle:g_hZMarketRandomizeCookie = INVALID_HANDLE;
new bool:g_bZMarketRandomize[MAXPLAYERS + 1];
new String:g_sZMarketRandomHistoryPrimary[MAXPLAYERS + 1][3][WEAPONS_MAX_LENGTH];

/**
 * 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);
        }
    }

    // Randomize toggle cookie.
    if (g_hZMarketRandomizeCookie == INVALID_HANDLE)
    {
        g_hZMarketRandomizeCookie = RegClientCookie(ZMARKET_COOKIE_RANDOMIZE, "Whether weapon randomization is enabled", 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;

    // Clear randomize weapon history.
    for (new i = 0; i < 3; i++)
    {
        g_sZMarketRandomHistoryPrimary[client][i][0] = '\0';
    }
}

/**
 * Called once a client's saved cookies have been loaded from the database.
 *
 * @param client        Client index.
 */
ZMarketOnCookiesCached(client)
{
    decl String:value[4];
    GetClientCookie(client, g_hZMarketRandomizeCookie, value, sizeof(value));
    g_bZMarketRandomize[client] = (value[0] == '1');

    // 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];
    decl String:randomize[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");
    Format(randomize, sizeof(randomize), "Randomize Weapons: %s", g_bZMarketRandomize[client] ? "ON" : "OFF");

    // 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);
    AddMenuItem(menu_zmarket_main, "Randomize", randomize);

    // 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);
            }
            case 4:
            {
                // Toggle randomize.
                g_bZMarketRandomize[client] = !g_bZMarketRandomize[client];

                decl String:value[4];
                Format(value, sizeof(value), "%d", g_bZMarketRandomize[client] ? 1 : 0);
                SetClientCookie(client, g_hZMarketRandomizeCookie, value);
                PrintToChat(client, "Weapons zmarket randomize toggled: %s", g_bZMarketRandomize[client] ? "ON" : "OFF");

                ZMarketMenuMain(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:
    if(!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);
        }
        else if (StrEqual(weaponentity, "item_assaultsuit"))
        {
            SetEntProp(client, Prop_Send, "m_ArmorValue", 100);
            SetEntProp(client, Prop_Send, "m_bHasHelmet", 1);
        }
        else if (StrEqual(weaponentity, "item_defuser"))
        {
            SetEntProp(client, Prop_Send, "m_bHasDefuser", 1);
        }
        else if (StrEqual(weaponentity, "item_nvgs"))
        {
            SetEntProp(client, Prop_Send, "m_bHasNightVision", 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);
}

/**
 * Picks a random weapon name from the given slot, avoiding the client's
 * last 3 picks for the primiary slot.
 *
 * @param client    The client index.
 * @param slot      Slot_Primary
 * @param buffer    Output buffer for the weapon name.
 * @param maxlen    Size of buffer.
 */
stock ZMarketGetRandomWeaponForSlot(client, WeaponsSlot:slot, String:buffer[], maxlen)
{
    new Handle:candidates = CreateArray(WEAPONS_MAX_LENGTH);

    new size = GetArraySize(arrayWeapons);
    decl String:weaponname[WEAPONS_MAX_LENGTH];

    for (new i = 0; i < size; i++)
    {
        if (WeaponsGetSlot(i) != slot)
            continue;

        WeaponsGetName(i, weaponname, sizeof(weaponname));

        // Skip if restricted.
        if (RestrictIsWeaponRestricted(i))
            continue;

        // Skip if in the client's last-3 history for this slot.
        new bool:inHistory = false;
        for (new h = 0; h < 3; h++)
        {
            decl String:histEntry[WEAPONS_MAX_LENGTH];
            if (slot == Slot_Primary)
                strcopy(histEntry, sizeof(histEntry), g_sZMarketRandomHistoryPrimary[client][h]);
            if (StrEqual(histEntry, weaponname))
            {
                inHistory = true;
                break;
            }
        }

        if (inHistory)
            continue;

        PushArrayString(candidates, weaponname);
    }

    new candidateCount = GetArraySize(candidates);

    if (candidateCount == 0)
    {
        buffer[0] = '\0';
        CloseHandle(candidates);
        return;
    }

    new pick = Math_GetRandomInt(0, candidateCount - 1);
    GetArrayString(candidates, pick, buffer, maxlen);
    CloseHandle(candidates);

    // Push into history (shift, then insert at front).
    if (slot == Slot_Primary)
    {
        strcopy(g_sZMarketRandomHistoryPrimary[client][2], WEAPONS_MAX_LENGTH, g_sZMarketRandomHistoryPrimary[client][1]);
        strcopy(g_sZMarketRandomHistoryPrimary[client][1], WEAPONS_MAX_LENGTH, g_sZMarketRandomHistoryPrimary[client][0]);
        strcopy(g_sZMarketRandomHistoryPrimary[client][0], WEAPONS_MAX_LENGTH, buffer);
    }
}

/**
 * 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 randomize is enabled, override any saved loadout for primary/secondary.
        if (g_bZMarketRandomize[client] && (x == Slot_Primary || x == Slot_Secondary))
        {
            ZMarketGetRandomWeaponForSlot(client, WeaponsSlot:x, rebuyweapons[x], sizeof(rebuyweapons[]));
        }
        else if (!rebuyweapons[x][0])
        {
            // No saved loadout, fall back to cvar default.
            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;
}
