Иконка ресурса

Ultimate Parachute 1.0

Нет прав для скачивания
Код:
/*
    Максимально прокаченный парашют с огромными возможностями и гибкими настройками.
    Автор: MaXaoH
*/
#include <amxmodx>
#include <fakemeta>
#include <engine>
#include <fun>
#include <hamsandwich>
#include <nvault>
#include <cstrike>
#pragma semicolon 1
#define PLUGIN      "Ultimate Parachute"
#define VERSION     "1.0"
#define AUTHOR      "MaXaoH"
#define cm(%0)      ( sizeof(%0) - 1 )
const XO_PLAYER            = 5;
const m_flFallVelocity     = 251;
#define MAX_SPEEDS   32
#define MAX_MODELS   64
#define MAX_TRAILS         64
#define MAX_TRAIL_COLORS   32
#define MAX_TRAIL_LENGTHS  32
enum
{
    DEPLOY_HOLD = 0,
    DEPLOY_TAP  = 1,
    DEPLOY_AUTO = 2
};
new const g_szDeployModeName[3][] = { "Удержание", "Нажатие (повторно - закрыть)", "Автоматически (нажатие - закрыть)" };
new const PARA_CLASS[] = "parachute";
#define TE_BEAMFOLLOW 22
#define TE_KILLBEAM   99
new g_szCfgPath[256];
new g_szAccessFlags[32];
new g_iAccessBits;
new g_iAccessTeamTT;
new g_iAccessTeamCT;
new g_iWeaponUsage;
new g_iDeployModeAccess;
new g_iDeployModeDefault;
new g_iFallSpeedAccess;
new g_szFallSpeedDefault[32];
new g_iThirdAccess;
new g_iThirdDefault;
new g_iModelAccess;
new g_szModelDefault[128];
new Float:g_flAutoThreshold;
new g_iDeploysPerRound;
new g_szDeploySound[128];
new g_iSpeedsNum;
new g_szSpeedName[MAX_SPEEDS][32];
new Float:g_flSpeedValue[MAX_SPEEDS];
new g_iModelsNum;
new g_szModelPath[MAX_MODELS][128];
new g_szModelName[MAX_MODELS][48];
new g_iTrailAccess;
new g_szTrailDefault[128];
new g_iTrailColorAccess;
new g_szTrailColorDefault[32];
new g_iTrailLengthAccess;
new g_szTrailLengthDefault[16];
new g_iTrailsNum;
new g_szTrailPath[MAX_TRAILS][128];
new g_szTrailName[MAX_TRAILS][48];
new g_iTrailSpriteIdx[MAX_TRAILS];
new g_iTrailColorsNum;
new g_szTrailColorName[MAX_TRAIL_COLORS][48];
new g_iTrailColorRGB[MAX_TRAIL_COLORS][3];
new g_iTrailLengthsNum;
new g_szTrailLengthName[MAX_TRAIL_LENGTHS][48];
new g_iTrailLengthVal[MAX_TRAIL_LENGTHS];
new g_iDefaultTrailIndex;
new g_iDefaultTrailColorIndex;
new g_iDefaultTrailLengthIndex;
new g_iTrailWidth = 10;
new g_iTrailIndex[33];
new g_iTrailColorIndex[33];
new g_iTrailLengthIndex[33];
new g_iTrailMenuPage[33];
new g_iTrailColorMenuPage[33];
new g_iTrailLengthMenuPage[33];
new bool:g_bTrailActive[33];
new g_iDefaultSpeedIndex;
new g_iDefaultModelIndex;
new g_iVault;
new g_iParaEnt[33];
new bool:g_bParaDeployed[33];
new g_iDeployMode[33];
new g_iSpeedIndex[33];
new bool:g_bThird[33];
new g_iModelIndex[33];
new g_iModelMenuPage[33];
new g_iLastWeapon[33];
new g_iDeploysUsed[33];
public plugin_precache()
{
    precache_model("models/rpgrocket.mdl");
    BuildConfigPath();
    LoadConfig(true);
}
public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR);
    register_clcmd("say /parachute", "Cmd_Menu");
    register_clcmd("say_team /parachute", "Cmd_Menu");
    RegisterHam(Ham_Player_PreThink, "player", "OnPreThink", 0);
    RegisterHam(Ham_Spawn, "player", "OnSpawnPost", 1);
    RegisterHam(Ham_Killed, "player", "OnKilledPost", 1);
    register_logevent("OnRoundStart", 2, "1=Round_Start");
}
public plugin_cfg()
{
    BuildConfigPath();
    LoadConfig(false);
    g_iVault = nvault_open("ultimate_parachute");
    if (g_iVault == INVALID_HANDLE)
        set_fail_state("Error opening nVault (ultimate_parachute)");
}
public plugin_end()
{
    if (g_iVault != INVALID_HANDLE)
        nvault_close(g_iVault);
}
public OnSpawnPost(id)
{
    if(!is_user_connected(id)) return;
    RemoveParachute(id, true);
    g_iDeploysUsed[id] = 0;
    LoadPlayerData(id);
}
public OnKilledPost(victim, attacker, shouldgib)
{
    if(!is_user_connected(victim)) return;
    RemoveParachute(victim, true);
}
public OnRoundStart()
{
    for(new id=1; id<=32; id++)
    {
        g_iDeploysUsed[id] = 0;
        if(is_user_connected(id))
            RemoveParachute(id, true);
    }
}
public client_putinserver(id)
{
    ResetPlayerState(id);
}
public client_disconnected(id)
{
    SavePlayerData(id);
    ResetPlayerState(id);
}
public OnPreThink(id)
{
    if(!is_user_alive(id))
        return;
    if(!HasParachuteAccess(id))
    {
        RemoveParachute(id, false);
        return;
    }
    if(pev(id, pev_movetype) == MOVETYPE_FLY)
    {
        RemoveParachute(id, false);
        return;
    }
    new buttons = pev(id, pev_button);
    new oldbuttons = pev(id, pev_oldbuttons);
    new flags = pev(id, pev_flags);
    static Float:vel[3];
    pev(id, pev_velocity, vel);
    new bool:bDescending = (vel[2] < 0.0);
    switch(g_iDeployMode[id])
    {
        case DEPLOY_HOLD:
        {
            if( (buttons & IN_USE) && !(flags & FL_ONGROUND) && bDescending )
            {
                    if(!g_bParaDeployed[id])
                    {
                        if(!TryStartDeploy(id))
                        {
                            RemoveParachute(id, false);
                            return;
                        }
                        g_bParaDeployed[id] = true;
                    StartTrailIfNeeded(id);
                    }
                    EnsureEntity(id);
                    ApplyParachute(id, vel);
            }
            else
            {
                RemoveParachute(id, false);
            }
        }
        case DEPLOY_TAP:
        {
            if( (buttons & IN_USE) && !(oldbuttons & IN_USE) && !(flags & FL_ONGROUND) && bDescending )
            {
                if(!g_bParaDeployed[id])
                {
                        if(!TryStartDeploy(id))
                            return;
                    EnsureEntity(id);
                    g_bParaDeployed[id] = true;
                    StartTrailIfNeeded(id);
                }
                else
                {
                    RemoveParachute(id, false);
                }
            }
            if(g_bParaDeployed[id] && !(flags & FL_ONGROUND) && bDescending)
            {
                EnsureEntity(id);
                ApplyParachute(id, vel);
            }
            else if(flags & FL_ONGROUND)
            {
                RemoveParachute(id, false);
            }
        }
        case DEPLOY_AUTO:
        {
            static Float:fallvel;
            fallvel = get_pdata_float(id, m_flFallVelocity, XO_PLAYER);
                if(!g_bParaDeployed[id] && bDescending && fallvel >= g_flAutoThreshold && !(flags & FL_ONGROUND))
            {
                    if(!TryStartDeploy(id))
                        return;
                EnsureEntity(id);
                g_bParaDeployed[id] = true;
                StartTrailIfNeeded(id);
            }
            if(g_bParaDeployed[id] && !(flags & FL_ONGROUND) && bDescending)
            {
                EnsureEntity(id);
                ApplyParachute(id, vel);
            }
            else if(flags & FL_ONGROUND)
            {
                RemoveParachute(id, false);
            }
            if(g_bParaDeployed[id] && (buttons & IN_USE) && !(oldbuttons & IN_USE) && !(flags & FL_ONGROUND))
            {
                RemoveParachute(id, false);
            }
        }
    }
    if(!(buttons & IN_USE) && (oldbuttons & IN_USE))
    {
        RestoreGravityIfNeeded(id);
    }
}
public Cmd_Menu(id)
{
    if(!is_user_connected(id)) return PLUGIN_HANDLED;
    if(!HasParachuteAccess(id))
    {
        client_print(id, print_chat, "[Ultimate Parachute] У вас нет доступа к парашюту.");
        return PLUGIN_HANDLED;
    }
    if(g_bParaDeployed[id] || g_iParaEnt[id] > 0)
        return PLUGIN_HANDLED;
    new menu = menu_create("Настройки парашюта", "Menu_Handler");
    new sz[192];
    if(g_iDeployModeAccess)
    {
        formatex(sz, cm(sz), "Режим раскрытия: \y%s", g_szDeployModeName[g_iDeployMode[id]]);
        menu_additem(menu, sz, "0");
    }
    else
    {
        formatex(sz, cm(sz), "Режим раскрытия: \d%s", g_szDeployModeName[g_iDeployMode[id]]);
        menu_additem(menu, sz, "0");
    }
    if(g_iThirdAccess)
    {
        formatex(sz, cm(sz), "Вид: \y%s", g_bThird[id] ? "от 3 лица" : "от 1 лица");
        menu_additem(menu, sz, "1");
    }
    else
    {
        formatex(sz, cm(sz), "Вид: \d%s", g_bThird[id] ? "от 3 лица" : "от 1 лица");
        menu_additem(menu, sz, "1");
    }
    if(g_iFallSpeedAccess && g_iSpeedsNum > 0)
    {
        formatex(sz, cm(sz), "Скорость падения: \y%s", g_szSpeedName[g_iSpeedIndex[id]]);
        menu_additem(menu, sz, "2");
    }
    else
    {
        formatex(sz, cm(sz), "Скорость падения: \d%s", (g_iSpeedsNum > 0) ? g_szSpeedName[g_iSpeedIndex[id]] : "нет списка");
        menu_additem(menu, sz, "2");
    }
    if(g_iModelsNum > 0)
    {
        new const szRandom[] = "Меняющаяся модель";
        if(g_iModelIndex[id] == -1)
            formatex(sz, cm(sz), "Модель: \y%s", szRandom);
        else
            formatex(sz, cm(sz), "Модель: \y%s", g_szModelName[g_iModelIndex[id]]);
        if(!g_iModelAccess)
            replace(sz, cm(sz), "\y", "\d");
        menu_additem(menu, sz, "3");
    }
    else
    {
        formatex(sz, cm(sz), "Модель: \dнет списка");
        menu_additem(menu, sz, "3");
    }
    if(g_iTrailsNum > 0)
    {
        new const szRandomTrail[] = "Меняющийся хвост";
        if(g_iTrailIndex[id] == -1)
            formatex(sz, cm(sz), "Хвост: \y%s", szRandomTrail);
        else
            formatex(sz, cm(sz), "Хвост: \y%s", g_szTrailName[g_iTrailIndex[id]]);
        if(!g_iTrailAccess)
            replace(sz, cm(sz), "\y", "\d");
        menu_additem(menu, sz, "4");
    }
    else
    {
        formatex(sz, cm(sz), "Хвост: \dнет списка");
        menu_additem(menu, sz, "4");
    }
    if(g_iTrailColorsNum > 0)
    {
        new const szRandomColor[] = "Случайный";
        if(g_iTrailColorIndex[id] == -1)
            formatex(sz, cm(sz), "Цвет хвоста: \y%s", szRandomColor);
        else
            formatex(sz, cm(sz), "Цвет хвоста: \y%s", g_szTrailColorName[g_iTrailColorIndex[id]]);
        if(!g_iTrailColorAccess || !g_iTrailAccess)
            replace(sz, cm(sz), "\y", "\d");
        menu_additem(menu, sz, "5");
    }
    else
    {
        formatex(sz, cm(sz), "Цвет хвоста: \dнет списка");
        menu_additem(menu, sz, "5");
    }
    if(g_iTrailLengthsNum > 0)
    {
        new const szRandomLen[] = "Случайная";
        if(g_iTrailLengthIndex[id] == -1)
            formatex(sz, cm(sz), "Длина хвоста: \y%s", szRandomLen);
        else
            formatex(sz, cm(sz), "Длина хвоста: \y%s", g_szTrailLengthName[g_iTrailLengthIndex[id]]);
        if(!g_iTrailLengthAccess || !g_iTrailAccess)
            replace(sz, cm(sz), "\y", "\d");
        menu_additem(menu, sz, "6");
    }
    else
    {
        formatex(sz, cm(sz), "Длина хвоста: \dнет списка");
        menu_additem(menu, sz, "6");
    }
    menu_setprop(menu, MPROP_EXIT, MEXIT_ALL);
    menu_display(id, menu);
    return PLUGIN_HANDLED;
}
public Menu_Handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        SavePlayerData(id);
        return PLUGIN_HANDLED;
    }
    new info[8], access, callback;
    menu_item_getinfo(menu, item, access, info, cm(info), _, _, callback);
    new key = str_to_num(info);
    switch(key)
    {
        case 0:
        {
            if(g_iDeployModeAccess)
            {
                g_iDeployMode[id]++;
                if(g_iDeployMode[id] > DEPLOY_AUTO) g_iDeployMode[id] = DEPLOY_HOLD;
            }
        }
        case 1:
        {
            if(g_iThirdAccess)
            {
                g_bThird[id] = !g_bThird[id];
                if(!g_bThird[id]) set_view(id, CAMERA_NONE);
            }
        }
        case 2:
        {
            if(g_iFallSpeedAccess && g_iSpeedsNum > 0)
            {
                g_iSpeedIndex[id]++;
                if(g_iSpeedIndex[id] >= g_iSpeedsNum) g_iSpeedIndex[id] = 0;
            }
        }
        case 3:
        {
            if(g_iModelAccess && g_iModelsNum > 0)
            {
                menu_destroy(menu);
                ShowModelMenu(id, 0);
                return PLUGIN_HANDLED;
            }
        }
        case 4:
        {
            if(g_iTrailAccess && g_iTrailsNum > 0)
            {
                menu_destroy(menu);
                ShowTrailMenu(id, 0);
                return PLUGIN_HANDLED;
            }
        }
        case 5:
        {
            if(g_iTrailAccess && g_iTrailColorAccess && g_iTrailColorsNum > 0)
            {
                menu_destroy(menu);
                ShowTrailColorMenu(id, 0);
                return PLUGIN_HANDLED;
            }
        }
        case 6:
        {
            if(g_iTrailAccess && g_iTrailLengthAccess && g_iTrailLengthsNum > 0)
            {
                menu_destroy(menu);
                ShowTrailLengthMenu(id, 0);
                return PLUGIN_HANDLED;
            }
        }
    }
    menu_destroy(menu);
    Cmd_Menu(id);
    SavePlayerData(id);
    return PLUGIN_HANDLED;
}
stock ShowModelMenu(id, page)
{
    if(!is_user_connected(id)) return;
    new const perPage = 7;
    new totalItems = g_iModelsNum + 1;
    new maxPage = 0;
    if(totalItems > 0)
        maxPage = (totalItems - 1) / perPage;
    if(page < 0) page = 0;
    if(page > maxPage) page = maxPage;
    g_iModelMenuPage[id] = page;
    new menu = menu_create("Выбор модели", "ModelMenu_Handler");
    menu_additem(menu, "Меняющаяся модель", "R");
    new sz[96], info[12];
    for(new i = 0; i < g_iModelsNum; i++)
    {
        formatex(sz, charsmax(sz), "%s", g_szModelName);
        formatex(info, charsmax(info), "%d", i);
        menu_additem(menu, sz, info);
    }
    menu_setprop(menu, MPROP_PERPAGE, perPage);
    menu_setprop(menu, MPROP_BACKNAME, "Назад");
    menu_setprop(menu, MPROP_NEXTNAME, "Вперед");
    menu_setprop(menu, MPROP_EXITNAME, "Выход");
    menu_display(id, menu, page);
}
public ModelMenu_Handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        Cmd_Menu(id);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_BACK)
    {
        menu_destroy(menu);
        ShowModelMenu(id, g_iModelMenuPage[id] - 1);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_MORE)
    {
        menu_destroy(menu);
        ShowModelMenu(id, g_iModelMenuPage[id] + 1);
        return PLUGIN_HANDLED;
    }
    new info[12], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback);
    if(info[0] == 'R')
    {
        g_iModelIndex[id] = -1;
    }
    else
    {
        new idx = str_to_num(info);
        if(idx >= 0 && idx < g_iModelsNum)
            g_iModelIndex[id] = idx;
    }
    menu_destroy(menu);
    SavePlayerData(id);
    Cmd_Menu(id);
    return PLUGIN_HANDLED;
}
stock bool:TryStartDeploy(id)
{
    if(g_iDeploysPerRound > 0 && g_iDeploysUsed[id] >= g_iDeploysPerRound)
        return false;
    g_iDeploysUsed[id]++;
    if(g_szDeploySound[0])
        emit_sound(id, CHAN_ITEM, g_szDeploySound, 1.0, ATTN_NORM, 0, PITCH_NORM);
    if(!g_iWeaponUsage)
        DenyWeapons(id);
    if(g_bThird[id])
        set_view(id, CAMERA_3RDPERSON);
    set_pev(id, pev_gravity, 0.1);
    return true;
}
stock EnsureEntity(id)
{
    if(g_iParaEnt[id] > 0 && is_valid_ent(g_iParaEnt[id]))
        return;
    new ent = create_entity("info_target");
    if(ent <= 0) return;
    entity_set_string(ent, EV_SZ_classname, PARA_CLASS);
    if(g_iModelsNum > 0)
    {
        new mdlIndex = g_iModelIndex[id];
        if(mdlIndex < 0) mdlIndex = random_num(0, g_iModelsNum - 1);
        entity_set_model(ent, g_szModelPath[mdlIndex]);
    }
    entity_set_int(ent, EV_INT_movetype, MOVETYPE_FOLLOW);
    entity_set_int(ent, EV_INT_solid, SOLID_NOT);
    entity_set_edict(ent, EV_ENT_aiment, id);
    entity_set_edict(ent, EV_ENT_owner, id);
    entity_set_int(ent, EV_INT_sequence, 0);
    entity_set_int(ent, EV_INT_gaitsequence, 1);
    entity_set_float(ent, EV_FL_frame, 0.0);
    entity_set_float(ent, EV_FL_fuser1, 0.0);
    g_iParaEnt[id] = ent;
}
stock ShowTrailMenu(id, page)
{
    if(!is_user_connected(id)) return;
    new const perPage = 7;
    new totalItems = g_iTrailsNum + 1;
    new maxPage = 0;
    if(totalItems > 0)
        maxPage = (totalItems - 1) / perPage;
    if(page < 0) page = 0;
    if(page > maxPage) page = maxPage;
    g_iTrailMenuPage[id] = page;
    new menu = menu_create("Выбор хвоста", "TrailMenu_Handler");
    menu_additem(menu, "Меняющийся хвост", "R");
    new sz[96], info[12];
    for(new i = 0; i < g_iTrailsNum; i++)
    {
        formatex(sz, charsmax(sz), "%s", g_szTrailName);
        formatex(info, charsmax(info), "%d", i);
        menu_additem(menu, sz, info);
    }
    menu_setprop(menu, MPROP_PERPAGE, perPage);
    menu_setprop(menu, MPROP_BACKNAME, "Назад");
    menu_setprop(menu, MPROP_NEXTNAME, "Вперед");
    menu_setprop(menu, MPROP_EXITNAME, "Выход");
    menu_display(id, menu, page);
}
public TrailMenu_Handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        Cmd_Menu(id);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_BACK)
    {
        menu_destroy(menu);
        ShowTrailMenu(id, g_iTrailMenuPage[id] - 1);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_MORE)
    {
        menu_destroy(menu);
        ShowTrailMenu(id, g_iTrailMenuPage[id] + 1);
        return PLUGIN_HANDLED;
    }
    new info[12], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback);
    if(info[0] == 'R')
    {
        g_iTrailIndex[id] = -1;
    }
    else
    {
        new idx = str_to_num(info);
        if(idx >= 0 && idx < g_iTrailsNum)
            g_iTrailIndex[id] = idx;
    }
    menu_destroy(menu);
    SavePlayerData(id);
    Cmd_Menu(id);
    return PLUGIN_HANDLED;
}
stock ShowTrailColorMenu(id, page)
{
    if(!is_user_connected(id)) return;
    new const perPage = 7;
    new totalItems = g_iTrailColorsNum + 1;
    new maxPage = 0;
    if(totalItems > 0)
        maxPage = (totalItems - 1) / perPage;
    if(page < 0) page = 0;
    if(page > maxPage) page = maxPage;
    g_iTrailColorMenuPage[id] = page;
    new menu = menu_create("Выбор цвета хвоста", "TrailColorMenu_Handler");
    menu_additem(menu, "Случайный", "R");
    new sz[96], info[12];
    for(new i = 0; i < g_iTrailColorsNum; i++)
    {
        formatex(sz, charsmax(sz), "%s", g_szTrailColorName);
        formatex(info, charsmax(info), "%d", i);
        menu_additem(menu, sz, info);
    }
    menu_setprop(menu, MPROP_PERPAGE, perPage);
    menu_setprop(menu, MPROP_BACKNAME, "Назад");
    menu_setprop(menu, MPROP_NEXTNAME, "Вперед");
    menu_setprop(menu, MPROP_EXITNAME, "Выход");
    menu_display(id, menu, page);
}
public TrailColorMenu_Handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        Cmd_Menu(id);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_BACK)
    {
        menu_destroy(menu);
        ShowTrailColorMenu(id, g_iTrailColorMenuPage[id] - 1);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_MORE)
    {
        menu_destroy(menu);
        ShowTrailColorMenu(id, g_iTrailColorMenuPage[id] + 1);
        return PLUGIN_HANDLED;
    }
    new info[12], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback);
    if(info[0] == 'R')
    {
        g_iTrailColorIndex[id] = -1;
    }
    else
    {
        new idx = str_to_num(info);
        if(idx >= 0 && idx < g_iTrailColorsNum)
            g_iTrailColorIndex[id] = idx;
    }
    menu_destroy(menu);
    SavePlayerData(id);
    Cmd_Menu(id);
    return PLUGIN_HANDLED;
}

stock ShowTrailLengthMenu(id, page)
{
    if(!is_user_connected(id)) return;
    new const perPage = 7;
    new totalItems = g_iTrailLengthsNum + 1;
    new maxPage = 0;
    if(totalItems > 0)
        maxPage = (totalItems - 1) / perPage;
    if(page < 0) page = 0;
    if(page > maxPage) page = maxPage;
    g_iTrailLengthMenuPage[id] = page;
    new menu = menu_create("Выбор длины хвоста", "TrailLengthMenu_Handler");
    menu_additem(menu, "Случайная", "R");
    new sz[96], info[12];
    for(new i = 0; i < g_iTrailLengthsNum; i++)
    {
        formatex(sz, charsmax(sz), "%s", g_szTrailLengthName);
        formatex(info, charsmax(info), "%d", i);
        menu_additem(menu, sz, info);
    }
    menu_setprop(menu, MPROP_PERPAGE, perPage);
    menu_setprop(menu, MPROP_BACKNAME, "Назад");
    menu_setprop(menu, MPROP_NEXTNAME, "Вперед");
    menu_setprop(menu, MPROP_EXITNAME, "Выход");
    menu_display(id, menu, page);
}
public TrailLengthMenu_Handler(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        Cmd_Menu(id);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_BACK)
    {
        menu_destroy(menu);
        ShowTrailLengthMenu(id, g_iTrailLengthMenuPage[id] - 1);
        return PLUGIN_HANDLED;
    }
    if(item == MENU_MORE)
    {
        menu_destroy(menu);
        ShowTrailLengthMenu(id, g_iTrailLengthMenuPage[id] + 1);
        return PLUGIN_HANDLED;
    }
    new info[12], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback);
    if(info[0] == 'R')
    {
        g_iTrailLengthIndex[id] = -1;
    }
    else
    {
        new idx = str_to_num(info);
        if(idx >= 0 && idx < g_iTrailLengthsNum)
            g_iTrailLengthIndex[id] = idx;
    }
    menu_destroy(menu);
    SavePlayerData(id);
    Cmd_Menu(id);
    return PLUGIN_HANDLED;
}
stock ApplyParachute(id, Float:vel[3])
{
    set_pev(id, pev_gravity, 0.1);
    if(g_iSpeedsNum > 0)
    {
        new i = g_iSpeedIndex[id];
        new Float:target = g_flSpeedValue;
        vel[2] = (vel[2] + 40.0 < target) ? (vel[2] + 40.0) : target;
        set_pev(id, pev_velocity, vel);
    }
    new ent = g_iParaEnt[id];
    if(ent > 0 && is_valid_ent(ent))
    {
        new Float:frame;
        if(entity_get_int(ent, EV_INT_sequence) == 0)
        {
            frame = entity_get_float(ent, EV_FL_fuser1) + 1.0;
            entity_set_float(ent, EV_FL_fuser1, frame);
            entity_set_float(ent, EV_FL_frame, frame);
            if(frame > 100.0)
            {
                entity_set_float(ent, EV_FL_animtime, 0.0);
                entity_set_float(ent, EV_FL_framerate, 0.4);
                entity_set_int(ent, EV_INT_sequence, 1);
                entity_set_int(ent, EV_INT_gaitsequence, 1);
                entity_set_float(ent, EV_FL_frame, 0.0);
                entity_set_float(ent, EV_FL_fuser1, 0.0);
            }
        }
    }
}
stock RemoveParachute(id, bool:bForce)
{
    if(g_iParaEnt[id] > 0)
    {
        if(is_valid_ent(g_iParaEnt[id]))
            remove_entity(g_iParaEnt[id]);
        g_iParaEnt[id] = 0;
    }
    if(g_bParaDeployed[id] || bForce)
    {
        g_bParaDeployed[id] = false;
        KillTrail(id);
        set_view(id, CAMERA_NONE);
        if(!g_iWeaponUsage)
            RestoreWeapon(id);
        RestoreGravityIfNeeded(id);
    }
}
stock RestoreGravityIfNeeded(id)
{
    if(!is_user_alive(id)) return;
    static Float:gr;
    pev(id, pev_gravity, gr);
    if(gr == 0.1)
        set_pev(id, pev_gravity, 1.0);
}
stock KillTrail(id)
{
    if(!g_bTrailActive[id])
        return;
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_KILLBEAM);
    write_short(id);
    message_end();
    g_bTrailActive[id] = false;
}
stock StartTrailIfNeeded(id)
{
    if(!g_bParaDeployed[id])
        return;
    if(!g_iTrailAccess || g_iTrailsNum <= 0 || g_iTrailLengthsNum <= 0)
        return;
    new iLenIdx = g_iTrailLengthIndex[id];
    if(iLenIdx == -1 && g_iTrailLengthsNum > 0)
        iLenIdx = random_num(0, g_iTrailLengthsNum - 1);
    if(iLenIdx < 0 || iLenIdx >= g_iTrailLengthsNum)
        return;
    new life = g_iTrailLengthVal[iLenIdx];
    if(life <= 0)
    {
        KillTrail(id);
        return;
    }
    new iTrailIdx = g_iTrailIndex[id];
    if(iTrailIdx == -1 && g_iTrailsNum > 0)
        iTrailIdx = random_num(0, g_iTrailsNum - 1);
    if(iTrailIdx < 0 || iTrailIdx >= g_iTrailsNum)
        return;
    new sprite = g_iTrailSpriteIdx[iTrailIdx];
    if(sprite <= 0)
        return;
    new iColorIdx = g_iTrailColorIndex[id];
    if(iColorIdx == -1 && g_iTrailColorsNum > 0)
        iColorIdx = random_num(0, g_iTrailColorsNum - 1);
    new r = 255, g = 255, b = 255;
    if(iColorIdx >= 0 && iColorIdx < g_iTrailColorsNum)
    {
        r = g_iTrailColorRGB[iColorIdx][0];
        g = g_iTrailColorRGB[iColorIdx][1];
        b = g_iTrailColorRGB[iColorIdx][2];
    }
    KillTrail(id);
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
    write_byte(TE_BEAMFOLLOW);
    write_short(id);
    write_short(sprite);
    write_byte(clamp(life, 0, 255));
    write_byte(g_iTrailWidth);
    write_byte(r);
    write_byte(g);
    write_byte(b);
    write_byte(255);
    message_end();
    g_bTrailActive[id] = true;
}
stock DenyWeapons(id)
{
    new weapon = get_user_weapon(id);
    if(weapon != CSW_KNIFE)
    {
        g_iLastWeapon[id] = weapon;
        engclient_cmd(id, "weapon_knife");
    }
    new buttons = pev(id, pev_button);
    buttons &= ~IN_ATTACK;
    buttons &= ~IN_ATTACK2;
    set_pev(id, pev_button, buttons);
}
stock RestoreWeapon(id)
{
    if(g_iLastWeapon[id] <= 0) return;
    new szWpn[32];
    get_weaponname(g_iLastWeapon[id], szWpn, cm(szWpn));
    engclient_cmd(id, szWpn);
    g_iTrailIndex[id] = (g_iTrailsNum > 0) ? g_iDefaultTrailIndex : 0;
    g_iTrailColorIndex[id] = (g_iTrailColorsNum > 0) ? g_iDefaultTrailColorIndex : 0;
    g_iTrailLengthIndex[id] = (g_iTrailLengthsNum > 0) ? g_iDefaultTrailLengthIndex : 0;
    g_bTrailActive[id] = false;
g_iLastWeapon[id] = 0;
}
stock BuildConfigPath()
{
    new cfgdir[128];
    get_localinfo("amxx_configsdir", cfgdir, cm(cfgdir));
    formatex(g_szCfgPath, cm(g_szCfgPath), "%s/ultimate_parachute.ini", cfgdir);
}
stock LoadConfig(bool:bPrecacheOnly)
{
    g_szAccessFlags[0] = 0;
    g_iAccessBits = 0;
    g_iAccessTeamTT = 1;
    g_iAccessTeamCT = 1;
    g_iWeaponUsage = 1;
    g_iDeployModeAccess = 1;
    g_iDeployModeDefault = DEPLOY_HOLD;
    g_flAutoThreshold = 350.0;
    g_iDeploysPerRound = 0;
    g_iFallSpeedAccess = 1;
    g_szFallSpeedDefault[0] = 0;
    g_iThirdAccess = 1;
    g_iThirdDefault = 0;
    g_iModelAccess = 1;
    g_szModelDefault[0] = 0;
    g_szDeploySound[0] = 0;
    g_iSpeedsNum = 0;
    g_iModelsNum = 0;
    g_iTrailAccess = 1;
    g_szTrailDefault[0] = 0;
    g_iTrailColorAccess = 1;
    g_szTrailColorDefault[0] = 0;
    g_iTrailLengthAccess = 1;
    g_szTrailLengthDefault[0] = 0;
    g_iTrailsNum = 0;
    g_iTrailColorsNum = 0;
    g_iTrailLengthsNum = 0;
    g_iDefaultSpeedIndex = 0;
    g_iDefaultModelIndex = 0;
    g_iDefaultTrailIndex = -1;
    g_iDefaultTrailColorIndex = -1;
    g_iDefaultTrailLengthIndex = 0;
    if(!file_exists(g_szCfgPath))
    {
        return;
    }
    new line[256], section[32];
    section[0] = 0;
    new fp = fopen(g_szCfgPath, "rt");
    if(!fp) return;
    while(!feof(fp))
    {
        fgets(fp, line, cm(line));
        trim(line);
        if(!line[0]) continue;
        if(line[0] == ';') continue;
        if(line[0] == '/' && line[1] == '/') continue;
        if(line[0] == '[')
        {
            new iEnd = contain(line, "]");
            if(iEnd > 1)
            {
                new j = 0;
                for(new i = 1; i < iEnd && j < cm(section); i++)
                    section[j++] = line;
                section[j] = 0;
                strtolower(section);
            }
            continue;
        }
        if(equali(section, "settings"))
        {
            new k[64], v[192];
            k[0]=0; v[0]=0;
            parse(line, k, cm(k), v, cm(v));
            strtolower(k);
            StripQuotes(v);
            if(equali(k, "access_flags"))
            {
                copy(g_szAccessFlags, cm(g_szAccessFlags), v);
                g_iAccessBits = read_flags(g_szAccessFlags);
            }
            else if(equali(k, "access_team_tt"))
            {
                g_iAccessTeamTT = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "access_team_ct"))
            {
                g_iAccessTeamCT = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "weapon_usage"))
            {
                g_iWeaponUsage = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "deploy_mode_access"))
            {
                g_iDeployModeAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "deploy_mode_default"))
            {
                g_iDeployModeDefault = clamp(str_to_num(v), 0, 2);
            }
            else if(equali(k, "autodeploy_threshold"))
            {
                g_flAutoThreshold = floatclamp(str_to_float(v), 0.0, 9999.0);
            }
            else if(equali(k, "deploys_per_round"))
            {
                g_iDeploysPerRound = max(0, str_to_num(v));
            }
            else if(equali(k, "fall_speed_access"))
            {
                g_iFallSpeedAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "fall_speed_default"))
            {
                copy(g_szFallSpeedDefault, cm(g_szFallSpeedDefault), v);
            }
            else if(equali(k, "3rd_person_view_access"))
            {
                g_iThirdAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "3rd_person_view_default"))
            {
                g_iThirdDefault = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "model_access"))
            {
                g_iModelAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "model_default"))
            {
                copy(g_szModelDefault, cm(g_szModelDefault), v);
            }
            else if(equali(k, "trail_access"))
            {
                g_iTrailAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "trail_default"))
            {
                copy(g_szTrailDefault, cm(g_szTrailDefault), v);
            }
            else if(equali(k, "trail_color_access"))
            {
                g_iTrailColorAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "trail_color_default"))
            {
                copy(g_szTrailColorDefault, cm(g_szTrailColorDefault), v);
            }
            else if(equali(k, "trail_length_access"))
            {
                g_iTrailLengthAccess = clamp(str_to_num(v), 0, 1);
            }
            else if(equali(k, "trail_length_default"))
            {
                copy(g_szTrailLengthDefault, cm(g_szTrailLengthDefault), v);
            }
            else if(equali(k, "trail_width"))
            {
                g_iTrailWidth = clamp(str_to_num(v), 0, 255);
            }
            else if(equali(k, "deploy_sound"))
            {
                copy(g_szDeploySound, cm(g_szDeploySound), v);
            }
        }
        else if(equali(section, "speeds"))
        {
            if(g_iSpeedsNum >= MAX_SPEEDS) continue;
            new sSpeed[32], sName[64];
            sSpeed[0]=0; sName[0]=0;
            parse(line, sSpeed, cm(sSpeed), sName, cm(sName));
            StripQuotes(sSpeed);
            StripQuotes(sName);
            if(!sSpeed[0] || !sName[0]) continue;
            copy(g_szSpeedName[g_iSpeedsNum], cm(g_szSpeedName[]), sName);
            g_flSpeedValue[g_iSpeedsNum] = str_to_float(sSpeed);
            g_iSpeedsNum++;
        }
        else if(equali(section, "models"))
        {
            if(g_iModelsNum >= MAX_MODELS) continue;
            new path[160], name[64];
            path[0]=0; name[0]=0;
            parse(line, path, cm(path), name, cm(name));
            StripQuotes(path);
            StripQuotes(name);
            if(!path[0]) continue;
            copy(g_szModelPath[g_iModelsNum], cm(g_szModelPath[]), path);
            if(name[0])
                copy(g_szModelName[g_iModelsNum], cm(g_szModelName[]), name);
            else
                formatex(g_szModelName[g_iModelsNum], cm(g_szModelName[]), "Модель %d", g_iModelsNum + 1);
            if(bPrecacheOnly)
            {
                if(containi(path, ".mdl") != -1)
                    precache_model(path);
            }
            g_iModelsNum++;
        }
        else if(equali(section, "trails"))
        {
            if(g_iTrailsNum >= MAX_TRAILS) continue;
            new path[160], name[64];
            path[0]=0; name[0]=0;
            parse(line, path, cm(path), name, cm(name));
            StripQuotes(path);
            StripQuotes(name);
            if(!path[0]) continue;
            copy(g_szTrailPath[g_iTrailsNum], cm(g_szTrailPath[]), path);
            if(name[0])
                copy(g_szTrailName[g_iTrailsNum], cm(g_szTrailName[]), name);
            else
                formatex(g_szTrailName[g_iTrailsNum], cm(g_szTrailName[]), "Хвост %d", g_iTrailsNum + 1);
            if(bPrecacheOnly)
            {
                if(containi(path, ".spr") != -1)
                    g_iTrailSpriteIdx[g_iTrailsNum] = precache_model(path);
            }
            else
            {
                g_iTrailSpriteIdx[g_iTrailsNum] = engfunc(EngFunc_ModelIndex, path);
            }
            g_iTrailsNum++;
        }
        else if(equali(section, "trail_colors"))
        {
            if(g_iTrailColorsNum >= MAX_TRAIL_COLORS) continue;
            new rgb[32], name[64];
            rgb[0]=0; name[0]=0;
            parse(line, rgb, cm(rgb), name, cm(name));
            StripQuotes(rgb);
            StripQuotes(name);
            if(!rgb[0]) continue;
            new sr[8], sg[8], sb[8];
            sr[0]=sg[0]=sb[0]=0;
            parse(rgb, sr, cm(sr), sg, cm(sg), sb, cm(sb));
            new r = clamp(str_to_num(sr), 0, 255);
            new g = clamp(str_to_num(sg), 0, 255);
            new b = clamp(str_to_num(sb), 0, 255);
            g_iTrailColorRGB[g_iTrailColorsNum][0] = r;
            g_iTrailColorRGB[g_iTrailColorsNum][1] = g;
            g_iTrailColorRGB[g_iTrailColorsNum][2] = b;
            if(name[0])
                copy(g_szTrailColorName[g_iTrailColorsNum], cm(g_szTrailColorName[]), name);
            else
                formatex(g_szTrailColorName[g_iTrailColorsNum], cm(g_szTrailColorName[]), "Цвет %d", g_iTrailColorsNum + 1);
            g_iTrailColorsNum++;
        }
        else if(equali(section, "trail_lengths"))
        {
            if(g_iTrailLengthsNum >= MAX_TRAIL_LENGTHS) continue;
            new lenStr[16], name[64];
            lenStr[0]=0; name[0]=0;
            parse(line, lenStr, cm(lenStr), name, cm(name));
            StripQuotes(lenStr);
            StripQuotes(name);
            if(!lenStr[0]) continue;
            g_iTrailLengthVal[g_iTrailLengthsNum] = max(0, str_to_num(lenStr));
            if(name[0])
                copy(g_szTrailLengthName[g_iTrailLengthsNum], cm(g_szTrailLengthName[]), name);
            else
                formatex(g_szTrailLengthName[g_iTrailLengthsNum], cm(g_szTrailLengthName[]), "Длина %d", g_iTrailLengthsNum + 1);
            g_iTrailLengthsNum++;
        }
    }
    fclose(fp);
    ResolveDefaults();
    NormalizeDeploySound(bPrecacheOnly);
}
stock ResolveDefaults()
{
    g_iDefaultSpeedIndex = 0;
    if(g_iSpeedsNum > 0)
    {
        if(g_szFallSpeedDefault[0])
        {
            new bool:isIndex = true;
            for(new j=0; g_szFallSpeedDefault[j]; j++)
            {
                if(g_szFallSpeedDefault[j] == '-' || g_szFallSpeedDefault[j] == '.' )
                {
                    isIndex = false;
                    break;
                }
            }
            if(isIndex)
            {
                new idx = str_to_num(g_szFallSpeedDefault);
                if(idx >= 0 && idx < g_iSpeedsNum)
                    g_iDefaultSpeedIndex = idx;
            }
            else
            {
                new Float:f = str_to_float(g_szFallSpeedDefault);
                for(new i=0;i<g_iSpeedsNum;i++)
                {
                    if(floatabs(g_flSpeedValue - f) < 0.01)
                    {
                        g_iDefaultSpeedIndex = i;
                        break;
                    }
                }
            }
        }
        else
        {
            for(new i=0;i<g_iSpeedsNum;i++)
            {
                if(floatabs(g_flSpeedValue - (-100.0)) < 0.01)
                {
                    g_iDefaultSpeedIndex = i;
                    break;
                }
            }
        }
    }
    g_iDefaultModelIndex = -1;
    if(g_iModelsNum > 0)
    {
        if(g_szModelDefault[0])
        {
            for(new i=0;i<g_iModelsNum;i++)
            {
                if(equali(g_szModelPath, g_szModelDefault))
                {
                    g_iDefaultModelIndex = i;
                    break;
                }
            }
        }
    }
    g_iDefaultTrailIndex = -1;
    if(g_iTrailsNum > 0)
    {
        if(g_szTrailDefault[0])
        {
            for(new i=0;i<g_iTrailsNum;i++)
            {
                if(equali(g_szTrailPath, g_szTrailDefault))
                {
                    g_iDefaultTrailIndex = i;
                    break;
                }
            }
        }
    }
    g_iDefaultTrailColorIndex = -1;
    if(g_iTrailColorsNum > 0)
    {
        if(g_szTrailColorDefault[0])
        {
            new sr[8], sg[8], sb[8];
            sr[0]=sg[0]=sb[0]=0;
            parse(g_szTrailColorDefault, sr, cm(sr), sg, cm(sg), sb, cm(sb));
            new dr = clamp(str_to_num(sr), 0, 255);
            new dg = clamp(str_to_num(sg), 0, 255);
            new db = clamp(str_to_num(sb), 0, 255);
            for(new i=0;i<g_iTrailColorsNum;i++)
            {
                if(g_iTrailColorRGB[0] == dr && g_iTrailColorRGB[1] == dg && g_iTrailColorRGB[2] == db)
                {
                    g_iDefaultTrailColorIndex = i;
                    break;
                }
            }
        }
    }
    g_iDefaultTrailLengthIndex = 0;
    if(g_iTrailLengthsNum > 0)
    {
        if(g_szTrailLengthDefault[0])
        {
            new dl = max(0, str_to_num(g_szTrailLengthDefault));
            for(new i=0;i<g_iTrailLengthsNum;i++)
            {
                if(g_iTrailLengthVal == dl)
                {
                    g_iDefaultTrailLengthIndex = i;
                    break;
                }
            }
        }
        if(g_iDefaultTrailLengthIndex >= g_iTrailLengthsNum)
            g_iDefaultTrailLengthIndex = 0;
    }
}
stock NormalizeDeploySound(bool:bPrecacheOnly)
{
    if(!g_szDeploySound[0])
        return;
    if(containi(g_szDeploySound, "sound/") == 0)
    {
        new tmp[128];
        copy(tmp, cm(tmp), g_szDeploySound[6]);
        copy(g_szDeploySound, cm(g_szDeploySound), tmp);
    }
    else if(containi(g_szDeploySound, "sound\\") == 0)
    {
        new tmp2[128];
        copy(tmp2, cm(tmp2), g_szDeploySound[6]);
        copy(g_szDeploySound, cm(g_szDeploySound), tmp2);
    }
    if(bPrecacheOnly)
        precache_sound(g_szDeploySound);
}
stock ResetPlayerState(id)
{
    g_iParaEnt[id] = 0;
    g_bParaDeployed[id] = false;
    g_iDeployMode[id] = g_iDeployModeDefault;
    g_iSpeedIndex[id] = g_iDefaultSpeedIndex;
    g_bThird[id] = (g_iThirdDefault != 0);
    if(g_iModelsNum > 0)
    {
        g_iModelIndex[id] = g_iDefaultModelIndex;
        if(g_iModelIndex[id] >= g_iModelsNum) g_iModelIndex[id] = -1;
    }
    else
    {
        g_iModelIndex[id] = 0;
    }
    g_iLastWeapon[id] = 0;
}
stock HasParachuteAccess(id)
{
    if(g_szAccessFlags[0] && (get_user_flags(id) & g_iAccessBits) == 0)
        return false;
    new CsTeams:t = cs_get_user_team(id);
    if(t == CS_TEAM_T && !g_iAccessTeamTT) return false;
    if(t == CS_TEAM_CT && !g_iAccessTeamCT) return false;
    return true;
}
stock GetVaultKey(id, key[], keylen)
{
    new auth[32];
    get_user_authid(id, auth, cm(auth));
    if(equali(auth, "BOT") || equali(auth, "HLTV") || equali(auth, "STEAM_ID_LAN") || equali(auth, "VALVE_ID_LAN") || equali(auth, "STEAM_ID_PENDING"))
    {
        new ip[32];
        get_user_ip(id, ip, cm(ip), 1);
        formatex(key, keylen, "IP_%s", ip);
        return;
    }
    formatex(key, keylen, "SID_%s", auth);
}
stock LoadPlayerData(id)
{
    ResetPlayerState(id);
    if(g_iVault == INVALID_HANDLE)
        return;
    new key[64];
    GetVaultKey(id, key, cm(key));
    new data[128];
    if(!nvault_get(g_iVault, key, data, cm(data)))
        return;
    new s1[8], s2[8], s3[8], s4[8], s5[8], s6[8], s7[8];
    s1[0]=s2[0]=s3[0]=s4[0]=s5[0]=s6[0]=s7[0]=0;
    parse(data, s1, cm(s1), s2, cm(s2), s3, cm(s3), s4, cm(s4), s5, cm(s5), s6, cm(s6), s7, cm(s7));
    new m = str_to_num(s1);
    new sp = str_to_num(s2);
    new th = str_to_num(s3);
    new md = str_to_num(s4);
    new tr = str_to_num(s5);
    new tc = str_to_num(s6);
    new tl = str_to_num(s7);
    g_iDeployMode[id] = clamp(m, 0, 2);
    if(g_iSpeedsNum > 0)
        g_iSpeedIndex[id] = clamp(sp, 0, g_iSpeedsNum-1);
    else
        g_iSpeedIndex[id] = 0;
    g_bThird[id] = (th != 0);
    if(g_iModelsNum > 0)
    {
        if(md < 0)
            g_iModelIndex[id] = -1;
        else
            g_iModelIndex[id] = clamp(md, 0, g_iModelsNum-1);
    }
    else
    {
        g_iModelIndex[id] = 0;
    }
    if(g_iTrailsNum > 0)
    {
        if(tr < 0)
            g_iTrailIndex[id] = -1;
        else
            g_iTrailIndex[id] = clamp(tr, 0, g_iTrailsNum-1);
    }
    else
    {
        g_iTrailIndex[id] = 0;
    }
    if(g_iTrailColorsNum > 0)
    {
        if(tc < 0)
            g_iTrailColorIndex[id] = -1;
        else
            g_iTrailColorIndex[id] = clamp(tc, 0, g_iTrailColorsNum-1);
    }
    else
    {
        g_iTrailColorIndex[id] = 0;
    }
    if(g_iTrailLengthsNum > 0)
    {
        if(tl < 0)
            g_iTrailLengthIndex[id] = -1;
        else
            g_iTrailLengthIndex[id] = clamp(tl, 0, g_iTrailLengthsNum-1);
    }
    else
    {
        g_iTrailLengthIndex[id] = 0;
    }
}
stock SavePlayerData(id)
{
    if(!is_user_connected(id)) return;
    if(!HasParachuteAccess(id)) return;
    if(g_iVault == INVALID_HANDLE) return;
    new key[64];
    GetVaultKey(id, key, cm(key));
    new data[128];
    formatex(data, cm(data), "%d %d %d %d %d %d %d",
        g_iDeployMode[id],
        g_iSpeedIndex[id],
        g_bThird[id] ? 1 : 0,
        g_iModelIndex[id],
        g_iTrailIndex[id],
        g_iTrailColorIndex[id],
        g_iTrailLengthIndex[id]
    );
    nvault_set(g_iVault, key, data);
}
stock StripQuotes(str[])
{
    if(!str[0]) return;
    new len = strlen(str);
    if(len >= 2 && str[0] == '"' && str[len-1] == '"')
    {
        str[len-1] = 0;
        for(new i=0; i<len; i++)
            str = str[i+1];
    }
}
Назад
Верх