[fork] Random Weapons WarmUP

fork Random Weapons WarmUP 2.4.9

Нет прав для скачивания
Сообщения
2,491
Реакции
2,794
Помог
61 раз(а)
GIT, FastDL это чисто ваша серверная настройка. Плагин никак не влияет на это.
 
Сообщения
215
Реакции
25
Помог
1 раз(а)
Обнаружен баг в плагине, Пример когда заходят два игрока на сервер 1 за T другой за CT , начинается разминочный раунд, тут тер начинает херной страдать прописывает в консоле kill во время разминочного раунда. Как бы начинается новый раунд , но таймер разминочного раунда идет не по секундам а вот так 40 37 38 35 31 27
 
Сообщения
96
Реакции
120
Помог
1 раз(а)
ade888, какая у вас версия? Не удалось воспроизвести баг
 
Сообщения
215
Реакции
25
Помог
1 раз(а)
@h1k3,h1k3, нету, вот если 1 зашел за СТ и другой за Т , потом террорист хочет сменить скин террориста , тоесть он нажимает во время разминки M 1 2 то тогда начинаеться этот баг
20 Янв 2018
ade888, https://yadi.sk/i/MnvLbhGl3RcXQx демострация
20 Янв 2018
h1k3, Вот сам исходник

Код:
#include <amxmodx>
#include <reapi>

#define TIME_RR     60    // Время разминки
#define NUM_RR        1    // Кол-во рестартов
#define LATENCY        1.5    // Задержка между рестартами
#define PROTECTED     2    // Сколько секунд действует защита после возрождения, 0 - отключить (актуально для DM_MODE)
// отключаемо //
//#define SOUND            // Музыка под час разминки
#define STOP_PLUGS        // Отключать плагины на время разминки
#define DM_MODE            // Бесконечный респавн на время разминки
#define OFF_RR            // Отключать этот плагин на указанных картах
//#define BLOCK           // Запрет поднятия оружия с земли [по умолчанию выкл.]

#if defined SOUND
new const soundRR[] = "sound/rr/RoundStart.mp3"; // Указывать путь и название файла, например sound/serv/music.mp3
#endif

#if defined STOP_PLUGS
    new g_arPlugins[][] =    // Указывать название плагинов, например test.amxx
    {
        "test.amxx",
        "test2.amxx"
    }
#endif
new g_iHudSync;
new g_szWeapon[32];
new g_iWp;
new HookChain:fwd_NewRound,
    HookChain:fwd_GiveC4,
#if defined BLOCK
    HookChain:fwd_BlockEntity,
#endif
#if defined DM_MODE
    HookChain:fwd_Killed,
#endif
    HookChain:fwd_Spawn;

const TASK_PROTECTION_ID = 33464;

public plugin_init()
{
    register_plugin("[ReAPI] Random Weapons WarmUP", "2.4.3a", "neugomon/h1k3");

    RegisterHookChain(RG_RoundEnd, "fwdRoundEnd", true);
    DisableHookChain(fwd_NewRound = RegisterHookChain(RG_CSGameRules_CheckMapConditions, "fwdRoundStart", true));
    DisableHookChain(fwd_Spawn    = RegisterHookChain(RG_CBasePlayer_Spawn, "fwdPlayerSpawnPost", true));
    DisableHookChain(fwd_GiveC4   = RegisterHookChain(RG_CSGameRules_GiveC4, "fwdGiveC4", false));
#if defined BLOCK
    DisableHookChain(fwd_BlockEntity = RegisterHookChain(RG_CBasePlayer_HasRestrictItem, "fwdHasRestrictItemPre", false));
#endif
#if defined DM_MODE
    DisableHookChain(fwd_Killed   = RegisterHookChain(RG_CBasePlayer_Killed, "fwdPlayerKilledPost", true));
    g_iHudSync    = CreateHudSyncObj();
    register_clcmd("joinclass", "clCmdJoinClass");
    register_clcmd("menuselect","clCmdJoinClass");
#endif
    state warmupOff;
   
    #if defined OFF_RR
    new sPref[][] = { "awp_", "aim_", "fy_", "$", "35hp" }; // Указывать префиксы карт
    new map[32]; get_mapname(map, charsmax(map));
    for(new i; i < sizeof sPref; i++)
    {
        if(containi(map, sPref) != -1)
        {
            pause("ad");
            return;
        }
    }    
    #endif    
}

#if defined BLOCK
public fwdHasRestrictItemPre() {
    SetHookChainReturn(ATYPE_INTEGER, true);
    return HC_SUPERCEDE;
}
#endif

public client_putinserver(id) 
{
    remove_task(id + TASK_PROTECTION_ID)
}

#if defined SOUND
public plugin_precache() 
{
        precache_generic(soundRR);
}
#endif

public fwdRoundEnd(WinStatus:status, ScenarioEventEndRound:event, Float:tmDelay)
    if(event == ROUND_GAME_COMMENCE)
        EnableHookChain(fwd_NewRound);

public fwdRoundStart()
{
    state warmupOn;
    
    #if defined SOUND
    client_cmd(0, "mp3 play ^"%s^"", soundRR);
    #endif
    
    DisableHookChain(fwd_NewRound);
    EnableHookChain(fwd_Spawn);
    EnableHookChain(fwd_GiveC4);
    set_cvar_string("mp_round_infinite", "efg");
#if defined BLOCK
    EnableHookChain(fwd_BlockEntity);
#endif
#if defined DM_MODE    
    EnableHookChain(fwd_Killed);
#endif    
#if defined STOP_PLUGS    
    PluginController(1);
#endif
    switch((g_iWp = random(2)))
    {
        case 0: formatex(g_szWeapon, charsmax(g_szWeapon), "M4A1");
        case 1: formatex(g_szWeapon, charsmax(g_szWeapon), "AK-47");
    }
    set_task(1.0, "ShowTimer", .flags = "a", .repeat = TIME_RR);
}
#if defined DM_MODE
public clCmdJoinClass(id) <warmupOff>
    return;
    
public clCmdJoinClass(id) <warmupOn>
    if(get_member(id, m_iMenu) == Menu_ChooseAppearance)
        set_task(0.5, "SpawnPlayer", id);
#endif
public fwdPlayerSpawnPost(const id)
{
    if(!is_user_alive(id))
        return;

    SetProtection(id)
    rg_remove_all_items(id);
    set_member_game(m_bMapHasBuyZone, true);
    BuyZone_ToogleSolid(SOLID_NOT);

    switch(g_iWp)
    {
        case 0:
        {
            rg_give_item(id, "weapon_m4a1");
            rg_set_user_bpammo(id, WEAPON_M4A1, 90);
            rg_give_item(id, "weapon_knife");
        }
        case 1:
        {
            rg_give_item(id, "weapon_ak47");
            rg_set_user_bpammo(id, WEAPON_AK47, 90);
            rg_give_item(id, "weapon_knife");
        }    
    }    
}
#if defined DM_MODE
public fwdPlayerKilledPost(pVictim)
    set_task(1.0, "SpawnPlayer", pVictim);
#endif

public fwdGiveC4()
{
    return HC_SUPERCEDE
}

public ShowTimer()
{
    static timer = -1; 
    if(timer == -1) timer = TIME_RR;
    
    switch(--timer)
    {
        case 0: 
        {
            state warmupOff;
            
            BuyZone_ToogleSolid(SOLID_TRIGGER);
            DisableHookChain(fwd_Spawn);
            DisableHookChain(fwd_GiveC4);
            set_cvar_string("mp_round_infinite", "0");
        #if defined BLOCK
            DisableHookChain(fwd_BlockEntity);
        #endif
        #if defined DM_MODE    
            DisableHookChain(fwd_Killed);
        #endif
        #if defined STOP_PLUGS    
            PluginController(0);
        #endif    
        #if NUM_RR > 1        
            set_task(LATENCY, "SV_Restart", .flags = "a", .repeat = NUM_RR);
        #else
            SV_Restart();
        #endif
            timer = -1;
        }
        default:
        {
            set_hudmessage(255, 255, 255, .x = -1.0, .y = 0.9, .holdtime = 0.9, .channel = -1);
            ShowSyncHudMsg(0, g_iHudSync, "[ Разминка на %s! [%d] ]", g_szWeapon, timer);
        }
    }
}

public SV_Restart()
    set_cvar_num("sv_restart", 1);
#if defined DM_MODE    
public SpawnPlayer(id)
{
    if(!is_user_connected(id))
        return;
    if(is_user_alive(id))
        return;
    
    switch(get_member(id, m_iTeam))
    {
        case 1, 2: rg_round_respawn(id);
    }
}
#endif

public SetProtection(id)
{
    set_entvar(id, var_takedamage, DAMAGE_NO)

    switch(get_member(id, m_iTeam))
    {
        case TEAM_TERRORIST: rg_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, 10);
        case TEAM_CT: rg_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, 10);
    }

    remove_task(TASK_PROTECTION_ID + id)
    set_task( PROTECTED.0, "EndProtection", TASK_PROTECTION_ID + id)
}

public EndProtection(TaskID)
{
    new id = TaskID - TASK_PROTECTION_ID

    if(!is_user_connected(id)) 
        return

    set_entvar(id, var_takedamage, DAMAGE_AIM)
    rg_set_rendering(id)
}

stock rg_set_rendering(index, fx = kRenderFxNone, r=255, g=255, b=255, amount=16) 
{
    new Float:RenderColor[3]
    RenderColor[0] = float(r)
    RenderColor[1] = float(g)
    RenderColor[2] = float(b)
    
    set_entvar(index, var_renderfx, fx)
    set_entvar(index, var_rendercolor, RenderColor)
    set_entvar(index, var_renderamt, float(amount))
}

stock PluginController(stop)
{
    for(new i; i < sizeof g_arPlugins; i++)
    {
        if(stop)pause  ("ac", g_arPlugins);
        else    unpause("ac", g_arPlugins);
    }    
}

stock BuyZone_ToogleSolid(const solid)
{
    new entityIndex = 0;
    while ((entityIndex = rg_find_ent_by_class(entityIndex, "func_buyzone")))
        set_entvar(entityIndex, var_solid, solid);
}
20 Янв 2018
h1k3, вам удалось воспроизвести баг?
 
Последнее редактирование модератором:
Сообщения
957
Реакции
1,185
Помог
52 раз(а)
ade888, попробуйте заменить

Diff:
-set_cvar_string("mp_round_infinite", "efg");
+set_cvar_string("mp_round_infinite", "1");
 
  • Нравится
Реакции: h1k3
Сообщения
96
Реакции
120
Помог
1 раз(а)
h1k3 обновил(а) ресурс [fork] Random Weapons WarmUP новой записью:

Random Weapons WarmUP 2.4.4

  • Запрет дропа оружия при #define BLOCK
  • Фикс блокировки конца раунда
  • Отключение статистики на время разминки (Работает только с измененным CSStatsX SQL by serfreeman1337, в архиве присутствует)
  • Вывод сообщения о конце разминки
Узнать больше об этом обновлении...
 
Сообщения
342
Реакции
65
Помог
6 раз(а)
Обратите внимание, если вы хотите заключить сделку с этим пользователем, он заблокирован
а что за измененная стата? что там изменено?
 
Сообщения
96
Реакции
120
Помог
1 раз(а)
Код:
/*
*    CSStatsX SQL                  v. 0.7.4
*    by serfreeman1337              http://1337.uz/
*/

#include <amxmodx>
#include <sqlx>

#include <fakemeta>
#include <hamsandwich>

#define PLUGIN "CSStatsX SQL"
#define VERSION "0.7.4"
#define AUTHOR "serfreeman1337"    // AKA SerSQL1337

#define LASTUPDATE "06, July (07), 2016"

#if AMXX_VERSION_NUM < 183
    #define MAX_PLAYERS 32
    #define MAX_NAME_LENGTH 32
    new MaxClients
#endif

/* - SQL - */

new Handle:sql
new Handle:sql_con

/* -  КОНСТАНТЫ - */

enum _:sql_que_type    // тип sql запроса
{
    SQL_DUMMY,
    SQL_INITDB,    // автоматическое созданием таблиц
    SQL_LOAD,    // загрузка статистики
    SQL_UPDATE,    // обновление
    SQL_INSERT,    // внесение новой записи
    SQL_UPDATERANK,    // получение ранков игроков,
    SQL_GETSTATS,    // потоквый запрос на get_stats
    
    // 0.7
    SQL_GETWSTATS,    // статистика по оружию
    SQL_GETSESSID,    // id сессии статистики за карту
    SQL_GETSESTATS,    // статистика по картам
    SQL_AUTOCLEAR    // чистка БД от неактивных записей
}

enum _:load_state_type    // состояние получение статистики
{
    LOAD_NO,    // данных нет
    LOAD_WAIT,    // ожидание данных
    LOAD_NEWWAIT,    // новая запись, ждем ответа
    LOAD_UPDATE,    // перезагрузить после обновления
    LOAD_NEW,    // новая запись
    LOAD_OK        // есть данные
}

enum _:row_ids        // столбцы таблицы
{
    ROW_ID,
    ROW_STEAMID,
    ROW_NAME,
    ROW_IP,
    ROW_SKILL,
    ROW_KILLS,
    ROW_DEATHS,
    ROW_HS,
    ROW_TKS,
    ROW_SHOTS,
    ROW_HITS,
    ROW_DMG,
    ROW_BOMBDEF,
    ROW_BOMBDEFUSED,
    ROW_BOMBPLANTS,
    ROW_BOMBEXPLOSIONS,
    ROW_H0,
    ROW_H1,
    ROW_H2,
    ROW_H3,
    ROW_H4,
    ROW_H5,
    ROW_H6,
    ROW_H7,
    ROW_ONLINETIME,
    
    // 0.7
    ROW_CONNECTS,
    ROW_ROUNDT,
    ROW_WINT,
    ROW_ROUNDCT,
    ROW_WINCT,
    
    // 0.7.2
    ROW_ASSISTS,
    
    ROW_FIRSTJOIN,
    ROW_LASTJOIN,
    
    // 0.7
    ROW_SESSIONID,
    ROW_SESSIONNAME
}

new const row_names[row_ids][] = // имена столбцов
{
    "id",
    "steamid",
    "name",
    "ip",
    "skill",
    "kills",
    "deaths",
    "hs",
    "tks",
    "shots",
    "hits",
    "dmg",
    "bombdef",
    "bombdefused",
    "bombplants",
    "bombexplosions",
    "h_0",
    "h_1",
    "h_2",
    "h_3",
    "h_4",
    "h_5",
    "h_6",
    "h_7",
    "connection_time",
    
    // 0.7
    "connects",
    "roundt",
    "wint",
    "roundct",
    "winct",
    
    // 0.7.2
    "assists",
    
    "first_join",
    "last_join",
    
    // 0.7
    "session_id",
    "session_map"
}

enum _:STATS
{
    STATS_KILLS,
    STATS_DEATHS,
    STATS_HS,
    STATS_TK,
    STATS_SHOTS,
    STATS_HITS,
    STATS_DMG,
    
    STATS_END
}

enum _:KILL_EVENT
{
    NORMAL,
    SUICIDE,
    WORLD,
    WORLDSPAWN
}

const QUERY_LENGTH =    1472    // размер переменной sql запроса

#define STATS2_DEFAT    0
#define STATS2_DEFOK    1
#define STATS2_PLAAT    2
#define STATS2_PLAOK    3
#define STATS2_END    4

new const task_rankupdate    =    31337
new const task_confin        =    21337
new const task_flush        =    11337

#define MAX_CWEAPONS        6
#define MAX_WEAPONS        CSW_P90 + 1 + MAX_CWEAPONS
#define HIT_END            HIT_RIGHTLEG + 1

// 0.7

enum _:row_weapons_ids        // столбцы таблицы
{
    ROW_WEAPON_ID,
    ROW_WEAPON_PLAYER,
    ROW_WEAPON_NAME,
    ROW_WEAPON_KILLS,
    ROW_WEAPON_DEATHS,
    ROW_WEAPON_HS,
    ROW_WEAPON_TKS,
    ROW_WEAPON_SHOTS,
    ROW_WEAPON_HITS,
    ROW_WEAPON_DMG,
    ROW_WEAPON_H0,
    ROW_WEAPON_H1,
    ROW_WEAPON_H2,
    ROW_WEAPON_H3,
    ROW_WEAPON_H4,
    ROW_WEAPON_H5,
    ROW_WEAPON_H6,
    ROW_WEAPON_H7
}

new const row_weapons_names[row_weapons_ids][] = // имена столбцов
{
    "id",
    "player_id",
    "weapon",
    "kills",
    "deaths",
    "hs",
    "tks",
    "shots",
    "hits",
    "dmg",
    "h_0",
    "h_1",
    "h_2",
    "h_3",
    "h_4",
    "h_5",
    "h_6",
    "h_7"
}

enum _:row_maps_ids
{
    ROW_MAP_ID,
    ROW_MAP_SESSID,
    ROW_MAP_PLRID,
    ROW_MAP_MAP,
    ROW_MAP_SKILL,
    ROW_MAP_KILLS,
    ROW_MAP_DEATHS,
    ROW_MAP_HS,
    ROW_MAP_TKS,
    ROW_MAP_SHOTS,
    ROW_MAP_HITS,
    ROW_MAP_DMG,
    ROW_MAP_BOMBDEF,
    ROW_MAP_BOMBDEFUSED,
    ROW_MAP_BOMBPLANTS,
    ROW_MAP_BOMBEXPLOSIONS,
    ROW_MAP_H0,
    ROW_MAP_H1,
    ROW_MAP_H2,
    ROW_MAP_H3,
    ROW_MAP_H4,
    ROW_MAP_H5,
    ROW_MAP_H6,
    ROW_MAP_H7,
    ROW_MAP_ONLINETIME,
    ROW_MAP_CONNECTS,
    ROW_MAP_ROUNDT,
    ROW_MAP_WINT,
    ROW_MAP_ROUNDCT,
    ROW_MAP_WINCT,
    ROW_MAP_ASSISTS,
    ROW_MAP_FIRSTJOIN,
    ROW_MAP_LASTJOIN,
}

/* - СТРУКТУРА ДАННЫХ - */

// 0.7
enum _:STATS3_END
{
    STATS3_CURRENTTEAM,    // тек. команда игрока (определяется в начале раунда)
    
    STATS3_CONNECT,        // подключения к серверу
    STATS3_ROUNDT,        // раунды за теров
    STATS3_WINT,        // побед за теров
    STATS3_ROUNDCT,        // раунды за спецов
    STATS3_WINCT,        // побед за спецов
    
    // 0.7.2
    STATS3_ASSIST        // помощь в убийстве
}


enum _:sestats_array_struct
{
    SESTATS_ID,
    SESTATS_PLAYERID,
    SESTATS_MAP[MAX_NAME_LENGTH],
    SESTATS_STATS[8],
    SESTATS_HITS[8],
    SESTATS_STATS2[4],
    SESTATS_STATS3[STATS3_END],
    Float:SESTATS_SKILL,
    SESTATS_ONLINETIME,
    SESTATS_FIRSTJOIN,
    SESTATS_LASTJOIN
}

enum _:player_data_struct
{
    PLAYER_ID,            // ид игрока в базе данных
    PLAYER_LOADSTATE,        // состояние загрузки статистики игрока
    PLAYER_RANK,            // ранк игрока
    PLAYER_STATS[STATS_END],    // статистика игрока
    PLAYER_STATSLAST[STATS_END],    // разница в статистики
    PLAYER_HITS[HIT_END],        // статистика попаданий
    PLAYER_HITSLAST[HIT_END],    // разница в статистике попаданий
    PLAYER_STATS2[4],        // статистика cstrike
    PLAYER_STATS2LAST[4],        // разница
    Float:PLAYER_SKILL,        // скилл
    PLAYER_ONLINE,            // время онлайна
    // я не помню чо за diff и last, но без этого не работает XD
    Float:PLAYER_SKILLLAST,
    PLAYER_ONLINEDIFF,
    PLAYER_ONLINELAST,
    
    PLAYER_NAME[MAX_NAME_LENGTH * 3],
    PLAYER_STEAMID[30],
    PLAYER_IP[16],
    
    // 0.7
    PLAYER_STATS3[STATS3_END],    // stast3
    PLAYER_STATS3LAST[STATS3_END],    // stast3
    PLAYER_FIRSTJOIN,
    PLAYER_LASTJOIN
}

enum _:stats_cache_struct    // кеширование для get_stats
{
    CACHE_NAME[32],
    CACHE_STEAMID[30],
    CACHE_STATS[8],
    CACHE_HITS[8],
    CACHE_SKILL,
    bool:CACHE_LAST,
    
    // 0.5.1
    CACHE_ID,
    CACHE_TIME,
    
    // 0.7
    CACHE_STATS2[4],
    CACHE_STATS3[STATS3_END],
    CACHE_FIRSTJOIN,
    CACHE_LASTJOIN
}

enum _:cvar_set
{
    CVAR_SQL_HOST,
    CVAR_SQL_USER,
    CVAR_SQL_PASS,
    CVAR_SQL_DB,
    CVAR_SQL_TABLE,
    CVAR_SQL_TYPE,
    CVAR_SQL_CREATE_DB,
    
    CVAR_UPDATESTYLE,
    CVAR_RANK,
    CVAR_RANKFORMULA,
    CVAR_SKILLFORMULA,
    CVAR_RANKBOTS,
    CVAR_USEFORWARDS,
    
    // 0.7
    CVAR_WEAPONSTATS,
    CVAR_MAPSTATS,
    
    CVAR_AUTOCLEAR,
    CVAR_CACHETIME,
    CVAR_AUTOCLEAR_DAY,
    
    // 0.7.2
    CVAR_ASSISTHP
}


// 0.7
enum _:stats_cache_queue_struct
{
    CACHE_QUE_START,
    CACHE_QUE_TOP,
}

#define    MAX_DATA_PARAMS    32

/* - ПЕРЕМЕННЫЕ - */

// 0.7
new session_id,session_map[MAX_NAME_LENGTH]

new player_data[MAX_PLAYERS + 1][player_data_struct]
new flush_que[QUERY_LENGTH * 3],flush_que_len
new statsnum

//
 // Общая стата по оружию
 //
// 1ый STATS_END + HIT_END - текущая общая статистика по оружию игрока
// 2ой STATS_END + HIT_END - последнее значение player_wstats, использует для расчета разницы
// последний индекс - определяет INSERT или UPDATE для запроса
//
new player_awstats[MAX_PLAYERS + 1][MAX_WEAPONS][((STATS_END + HIT_END) * 2) + 1]

new cvar[cvar_set]

new Trie:stats_cache_trie    // дерево кеша для get_stats // ключ - ранг

new tbl_name[32]

/* - CSSTATS CORE - */

 #pragma dynamic 32768

// wstats
new player_wstats[MAX_PLAYERS + 1][MAX_WEAPONS][STATS_END + HIT_END]

// wstats2
new player_wstats2[MAX_PLAYERS + 1][STATS2_END]

// wrstats rstats
new player_wrstats[MAX_PLAYERS + 1][MAX_WEAPONS][STATS_END + HIT_END]

// vstats
new player_vstats[MAX_PLAYERS + 1][MAX_PLAYERS + 1][STATS_END + HIT_END + MAX_NAME_LENGTH]

// astats
new player_astats[MAX_PLAYERS + 1][MAX_PLAYERS + 1][STATS_END + HIT_END + MAX_NAME_LENGTH]

new FW_Death
new FW_Damage
new FW_BPlanting
new FW_BPlanted
new FW_BExplode
new FW_BDefusing
new FW_BDefused
new FW_GThrow

// 0.7.2
new FW_Assist

// 0.7.3
new FW_Initialized

new dummy_ret

// осталось монитор прихуярить

new g_planter
new g_defuser

#define WEAPON_INFO_SIZE        1 + (MAX_NAME_LENGTH * 2)

new Array:weapons_data            // массив с инфой по оружию
new Trie:log_ids_trie            // дерево для быстрого определения id оружия по лог-коду

// 0.7
new Array:stats_cache_queue

// 0.7.1
new bool:weapon_stats_enabled,bool:map_stats_enabled

// 0.7.3
new init_seq = -1
new bool:is_ready = false
+new bool:gSaveStats = true

// макрос для помощи реагистрации инфы по оружию
#define REG_INFO(%0,%1,%2)\
    weapon_info[0] = %0;\
    copy(weapon_info[1],MAX_NAME_LENGTH,%1);\
    copy(weapon_info[MAX_NAME_LENGTH ],MAX_NAME_LENGTH,%2);\
    ArrayPushArray(weapons_data,weapon_info);\
    TrieSetCell(log_ids_trie,%2,ArraySize(weapons_data) - 1)

public plugin_precache()
{
    register_plugin(PLUGIN,VERSION,AUTHOR)
    register_cvar("csstatsx_sql", VERSION, FCVAR_SERVER | FCVAR_SPONLY | FCVAR_UNLOGGED)
    
    /*
    * хост mysql
    */
    cvar[CVAR_SQL_HOST] = register_cvar("csstats_sql_host","192.168.101.206",FCVAR_UNLOGGED|FCVAR_PROTECTED)
    
    /*
    * пользователь mysql
    */
    cvar[CVAR_SQL_USER] = register_cvar("csstats_sql_user","u4666",FCVAR_UNLOGGED|FCVAR_PROTECTED)
    
    /*
    * пароль mysql
    */
    cvar[CVAR_SQL_PASS] = register_cvar("csstats_sql_pass","6NcIGDeEMs",FCVAR_UNLOGGED|FCVAR_PROTECTED)
    
    /*
    * название БД mysql или sqlite
    */
    cvar[CVAR_SQL_DB] = register_cvar("csstats_sql_db","u4666_1",FCVAR_UNLOGGED|FCVAR_PROTECTED)
    
    /*
    * название таблицы в БД
    */
    cvar[CVAR_SQL_TABLE] = register_cvar("csstats_sql_table","csstats",FCVAR_UNLOGGED|FCVAR_PROTECTED)
    
    /*
    * тип бд
    *    mysql - база данных MySQL
    *    sqlite - локальная база данных SQLite
    */
    cvar[CVAR_SQL_TYPE] = register_cvar("csstats_sql_type","mysql")
    
    /*
    * отправка запроса на создание таблицы
    *    0 - не отправлять запрос
    *    1 - отправлять запрос при загрузке карты
    */
    cvar[CVAR_SQL_CREATE_DB] = register_cvar("csstats_sql_create_db","1")
    
    /*
    * как вести учет игроков
    *    -1            - не учитывать
    *    0            - по нику
    *    1            - по steamid
    *    2            - по ip
    */
    cvar[CVAR_RANK] = get_cvar_pointer("csstats_rank")
    
    if(!cvar[CVAR_RANK])
        cvar[CVAR_RANK] = register_cvar("csstats_rank","1")
        
    /*
    * запись статистики ботов
    *    0            - не записывать
    *    1            - записывать0
    */
    cvar[CVAR_RANKBOTS] = get_cvar_pointer("csstats_rankbots")
    
    if(!cvar[CVAR_RANKBOTS])
        cvar[CVAR_RANKBOTS] = register_cvar("csstats_rankbots","1")
    
    /*
    * как обновлять статистику игрока в БД
    *    -2             - при смерти и дисконнекте
    *    -1            - в конце раунда и дисконнекте
    *    0             - при дисконнекте
    *    значение больше 0     - через указанное кол-во секунд и дисконнекте
    */
    cvar[CVAR_UPDATESTYLE] = register_cvar("csstats_sql_update","-1")
    
    /*
    * включить собственные форварды для client_death, client_damage
    *    0            - выключить
    *    1            - включить, небоходимо, если csstats_sql используется в качестве замены модуля
    */
    cvar[CVAR_USEFORWARDS] = register_cvar("csstats_sql_forwards","0")
    
    /*
    * формула расчета ранга
    *    0            - убйиства - смерти - тк
    *    1            - убийства
    *    2            - убийства + хедшоты
    *    3            - скилл
    *    4            - время онлайн
    */
    cvar[CVAR_RANKFORMULA] = register_cvar("csstats_sql_rankformula","0")
    
    /*
    * формула расчета скилла
    *    0            - The ELO Method (http://fastcup.net/rating.html)
    */
    cvar[CVAR_SKILLFORMULA] = register_cvar("csstats_sql_skillformula","0")
    
    // 0.7
    
    /*
    * ведение статистики по оружию
    */
    cvar[CVAR_WEAPONSTATS] = register_cvar("csstats_sql_weapons","0")
    
    /*
    * ведение статистики по картам
    */
    cvar[CVAR_MAPSTATS] = register_cvar("csstats_sql_maps","0")
    
    /*
    * автоматическое удаление неактвиных игроков в БД
    */
    cvar[CVAR_AUTOCLEAR] = register_cvar("csstats_sql_autoclear","60")
    
    /*
    * использование кеша для get_stats
    *    -1 - обновлять в конце раунда или по времени csstats_sql_update
    *    0 - отключить использование кеша
    */
    cvar[CVAR_CACHETIME] = register_cvar("csstats_sql_cachetime","-1")

    /*
    * автоматическая очистка всей игровой статистики в БД в определенный день
    */                               
    cvar[CVAR_AUTOCLEAR_DAY] = register_cvar("csstats_sql_autoclear_day","0")
    
    /*
    * урон для засчитывания ассиста
    */
    cvar[CVAR_ASSISTHP] = register_cvar("csstats_sql_assisthp","50")
    
    #if AMXX_VERSION_NUM < 183
        MaxClients = get_maxplayers()
    #endif
}

public plugin_init()
{
    register_logevent("LogEventHooK_RoundEnd", 2, "1=Round_End")
    register_logevent("LogEventHooK_RoundStart", 2, "1=Round_Start")
    
    register_event("CurWeapon","EventHook_CurWeapon","b","1=1")
    register_event("Damage","EventHook_Damage","b","2!0")
    register_event("BarTime","EventHook_BarTime","be")
    register_event("SendAudio","EventHook_SendAudio","a")
    register_event("TextMsg","EventHook_TextMsg","a")
    
    register_srvcmd("csstats_sql_reset","SrvCmd_DBReset")
    
    new weapon_info[WEAPON_INFO_SIZE]
    
    //
    log_ids_trie = TrieCreate()
    //                    is_meele  + название +   логнейм
    weapons_data = ArrayCreate(WEAPON_INFO_SIZE)
    
    REG_INFO(false,"","")
    REG_INFO(false,"p228","p228")
    REG_INFO(false,"","")
    REG_INFO(false,"scout","scout")
    REG_INFO(false,"hegrenade","grenade")
    REG_INFO(false,"xm1014","xm1014")
    REG_INFO(false,"c4","weapon_c4")
    REG_INFO(false,"mac10","mac10")
    REG_INFO(false,"aug","aug")
    REG_INFO(false,"sgrenade","grenade")
    REG_INFO(false,"elite","elite")
    REG_INFO(false,"fiveseven","fiveseven")
    REG_INFO(false,"ump45","ump45")
    REG_INFO(false,"sg550","sg550")
    REG_INFO(false,"galil","galil")
    REG_INFO(false,"famas","famas")
    REG_INFO(false,"usp","usp")
    REG_INFO(false,"glock18","glock18")
    REG_INFO(false,"awp","awp")
    REG_INFO(false,"mp5navy","mp5navy")
    REG_INFO(false,"m249","m249")
    REG_INFO(false,"m3","m3")
    REG_INFO(false,"m4a1","m4a1")
    REG_INFO(false,"tmp","tmp")
    REG_INFO(false,"g3sg1","g3sg1")
    REG_INFO(false,"flashbang","flashbang")
    REG_INFO(false,"deagle","deagle")
    REG_INFO(false,"sg552","sg552")
    REG_INFO(false,"ak47","ak47")
    REG_INFO(true,"knife","knife")
    REG_INFO(false,"p90","p90")
    
    RegisterHam(Ham_Spawn,"player","HamHook_PlayerSpawn",true)
}

#if AMXX_VERSION_NUM < 183
    public plugin_cfg()
#else
    public OnAutoConfigsBuffered()
#endif
{
    #if AMXX_VERSION_NUM < 183
        // форсируем выполнение exec addons/amxmodx/configs/amxx.cfg
        server_exec()
    #endif
    
    // читаем квары на подключение
    new host[128],user[64],pass[64],db[64],type[10]
    get_pcvar_string(cvar[CVAR_SQL_HOST],host,charsmax(host))
    get_pcvar_string(cvar[CVAR_SQL_USER],user,charsmax(user))
    get_pcvar_string(cvar[CVAR_SQL_PASS],pass,charsmax(pass))
    get_pcvar_string(cvar[CVAR_SQL_DB],db,charsmax(db))
    get_pcvar_string(cvar[CVAR_SQL_TABLE],tbl_name,charsmax(tbl_name))
    get_pcvar_string(cvar[CVAR_SQL_TYPE],type,charsmax(type))
    
    // и снова здравствуй wopox3
    if(!SQL_SetAffinity(type))
    {
        new error_msg[128]
        formatex(error_msg,charsmax(error_msg),"failed to use ^"%s^" for db driver",
            error_msg)
            
        set_fail_state(error_msg)
        
        return
    }
    
    sql = SQL_MakeDbTuple(host,user,pass,db)
    
    // для поддержки utf8 ников требуется AMXX 1.8.3-dev-git3799 или выше
    
    #if AMXX_VERSION_NUM >= 183
        SQL_SetCharset(sql,"utf8")
    #endif
    
    weapon_stats_enabled = get_pcvar_num(cvar[CVAR_WEAPONSTATS]) == 1? true : false
    map_stats_enabled = get_pcvar_num(cvar[CVAR_MAPSTATS]) == 1 ? true : false
    
    new query[QUERY_LENGTH * 2],que_len
    
    new sql_data[1]
    sql_data[0] = SQL_INITDB

    // запрос на создание таблицы
    if(get_pcvar_num(cvar[CVAR_SQL_CREATE_DB]))
    {
        // запрос для mysql
        if(strcmp(type,"mysql") == 0)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                CREATE TABLE IF NOT EXISTS `%s` (\
                    `%s` int(11) NOT NULL AUTO_INCREMENT,\
                    `%s` varchar(30) NOT NULL,\
                    `%s` varchar(32) NOT NULL,\
                    `%s` varchar(16) NOT NULL,\
                    `%s` float NOT NULL DEFAULT '0.0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',",
                    
                    tbl_name,
                    
                    row_names[ROW_ID],
                    row_names[ROW_STEAMID],
                    row_names[ROW_NAME],
                    row_names[ROW_IP],
                    row_names[ROW_SKILL],
                    row_names[ROW_KILLS],
                    row_names[ROW_DEATHS],
                    row_names[ROW_HS]
            )
            
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',",
                    
                    row_names[ROW_TKS],
                    row_names[ROW_SHOTS],
                    row_names[ROW_HITS],
                    row_names[ROW_DMG],
                    row_names[ROW_BOMBDEF],
                    row_names[ROW_BOMBDEFUSED],
                    row_names[ROW_BOMBPLANTS],
                    row_names[ROW_BOMBEXPLOSIONS],
                    row_names[ROW_H0]
            )
            
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',",
                    
                    row_names[ROW_H1],
                    row_names[ROW_H2],
                    row_names[ROW_H3],
                    row_names[ROW_H4],
                    row_names[ROW_H5],
                    row_names[ROW_H6],
                    row_names[ROW_H7],
                    row_names[ROW_ONLINETIME]
            )
            
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',\
                    `%s` int(11) NOT NULL DEFAULT '0',",
                    
                    row_names[ROW_CONNECTS],
                    row_names[ROW_ROUNDT],
                    row_names[ROW_WINT],
                    row_names[ROW_ROUNDCT],
                    row_names[ROW_WINCT],
                    row_names[ROW_ASSISTS]
            )
            
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\
                `%s` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\
                `%s` int(11) DEFAULT NULL,\
                `%s` varchar(32) DEFAULT NULL,\
                    PRIMARY KEY (%s),\
                    KEY `%s` (`%s`(16)),\
                    KEY `%s` (`%s`(16)),\
                    KEY `%s` (`%s`)\
                ) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;",
                
                row_names[ROW_FIRSTJOIN],
                row_names[ROW_LASTJOIN],
                
                row_names[ROW_SESSIONID],
                row_names[ROW_SESSIONNAME],
                
                row_names[ROW_ID],
                row_names[ROW_STEAMID],row_names[ROW_STEAMID],
                row_names[ROW_NAME],row_names[ROW_NAME],
                row_names[ROW_IP],row_names[ROW_IP]
            )
        }
        // запрос для sqlite
        else if(strcmp(type,"sqlite") == 0)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                CREATE TABLE IF NOT EXISTS `%s` (\
                    `%s` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
                    `%s`    TEXT NOT NULL,\
                    `%s`    TEXT NOT NULL,\
                    `%s`    TEXT NOT NULL,\
                    `%s`    REAL NOT NULL DEFAULT 0.0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,",
                    
                    tbl_name,
                    
                    row_names[ROW_ID],
                    row_names[ROW_STEAMID],
                    row_names[ROW_NAME],
                    row_names[ROW_IP],
                    row_names[ROW_SKILL],
                    row_names[ROW_KILLS],
                    row_names[ROW_DEATHS]
            )
                
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,",
                    
                    row_names[ROW_HS],
                    row_names[ROW_TKS],
                    row_names[ROW_SHOTS],
                    row_names[ROW_HITS],
                    row_names[ROW_DMG],
                    row_names[ROW_BOMBDEF],
                    row_names[ROW_BOMBDEFUSED],
                    row_names[ROW_BOMBPLANTS],
                    row_names[ROW_BOMBEXPLOSIONS]
            )
                    
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,",
                    
                    row_names[ROW_H0],
                    row_names[ROW_H1],
                    row_names[ROW_H2],
                    row_names[ROW_H3],
                    row_names[ROW_H4],
                    row_names[ROW_H5],
                    row_names[ROW_H6],
                    row_names[ROW_H7]
            )
                    
            // 0.7
            
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,\
                    `%s`    INTEGER NOT NULL DEFAULT 0,",
                    
                    row_names[ROW_ONLINETIME],
                    row_names[ROW_CONNECTS],
                    row_names[ROW_ROUNDT],
                    row_names[ROW_WINT],
                    row_names[ROW_ROUNDCT],
                    row_names[ROW_WINCT],
                    row_names[ROW_ASSISTS]
            )
                    
            que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\
                    `%s`    TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',\
                    `%s`    INTEGER,\
                    `%s`    TEXT\
                );",
                
                row_names[ROW_FIRSTJOIN],
                row_names[ROW_LASTJOIN],
                row_names[ROW_SESSIONID],
                row_names[ROW_SESSIONNAME]
            )
        }
        else
        {
            set_fail_state("invalid ^"csstats_sql_type^" cvar value")
        }
        
        DB_AddInitSeq()
        SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
        
        if(weapon_stats_enabled)
        {
            que_len = 0
            
            // запрос для mysql
            if(strcmp(type,"mysql") == 0)
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    CREATE TABLE IF NOT EXISTS `%s_weapons` (\
                        `%s` int(11) NOT NULL AUTO_INCREMENT,\
                        `%s` int(11) NOT NULL,\
                        `%s` varchar(32) NOT NULL,\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',",
                        
                        tbl_name,
                        row_weapons_names[ROW_WEAPON_ID],
                        row_weapons_names[ROW_WEAPON_PLAYER],
                        row_weapons_names[ROW_WEAPON_NAME],
                        row_weapons_names[ROW_WEAPON_KILLS],
                        row_weapons_names[ROW_WEAPON_DEATHS],
                        row_weapons_names[ROW_WEAPON_HS]
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',",
                        
                        row_weapons_names[ROW_WEAPON_TKS],
                        row_weapons_names[ROW_WEAPON_SHOTS],
                        row_weapons_names[ROW_WEAPON_HITS],
                        row_weapons_names[ROW_WEAPON_DMG]   
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',\
                        `%s` int(11) NOT NULL DEFAULT '0',",
                        
                        row_weapons_names[ROW_WEAPON_H0],
                        row_weapons_names[ROW_WEAPON_H1],
                        row_weapons_names[ROW_WEAPON_H2],
                        row_weapons_names[ROW_WEAPON_H3],
                        row_weapons_names[ROW_WEAPON_H4],
                        row_weapons_names[ROW_WEAPON_H5],
                        row_weapons_names[ROW_WEAPON_H6],
                        row_weapons_names[ROW_WEAPON_H7]
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                        PRIMARY KEY (%s),\
                        KEY `%s` (`%s`(16))\
                    ) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;",
                    
                    row_weapons_names[ROW_WEAPON_ID],
                    row_weapons_names[ROW_WEAPON_NAME],
                    row_weapons_names[ROW_WEAPON_NAME]
                )
            }
            // запрос для sqlite
            else if(strcmp(type,"sqlite") == 0)
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    CREATE TABLE IF NOT EXISTS `%s_weapons` (\
                        `%s` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
                        `%s`    INTEGER NOT NULL,\
                        `%s`    TEXT NOT NULL,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,",
                        
                        tbl_name,
                        row_weapons_names[ROW_WEAPON_ID],
                        row_weapons_names[ROW_WEAPON_PLAYER],
                        row_weapons_names[ROW_WEAPON_NAME],
                        row_weapons_names[ROW_WEAPON_KILLS],
                        row_weapons_names[ROW_WEAPON_DEATHS]
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,",
                        
                        row_weapons_names[ROW_WEAPON_HS],
                        row_weapons_names[ROW_WEAPON_TKS],
                        row_weapons_names[ROW_WEAPON_SHOTS],
                        row_weapons_names[ROW_WEAPON_HITS],
                        row_weapons_names[ROW_WEAPON_DMG]
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0,\
                        `%s`    INTEGER NOT NULL DEFAULT 0",
                        
                        row_weapons_names[ROW_WEAPON_H0],
                        row_weapons_names[ROW_WEAPON_H1],
                        row_weapons_names[ROW_WEAPON_H2],
                        row_weapons_names[ROW_WEAPON_H3],
                        row_weapons_names[ROW_WEAPON_H4],
                        row_weapons_names[ROW_WEAPON_H5],
                        row_weapons_names[ROW_WEAPON_H6],
                        row_weapons_names[ROW_WEAPON_H7]
                )
                que_len += formatex(query[que_len],charsmax(query) - que_len,");")
            }
            else
            {
                set_fail_state("invalid ^"csstats_sql_type^" cvar value")
            }
            
            if(que_len)
            {
                DB_AddInitSeq()
                SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
            }
        }
    }
    
    DB_AutoClearOpt()
    
    // обновление статистики в БД каждые n сек
    if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) > 0)
    {
        set_task(
            float(get_pcvar_num(cvar[CVAR_UPDATESTYLE])),
            "DB_SaveAll",
            .flags = "b"
        )
    }
    
    if(get_pcvar_num(cvar[CVAR_USEFORWARDS]))
    {    FW_Death =  CreateMultiForward("client_death",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL)
        FW_Damage = CreateMultiForward("client_damage",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL)
        FW_BPlanting = CreateMultiForward("bomb_planting",ET_IGNORE,FP_CELL)
        FW_BPlanted = CreateMultiForward("bomb_planted",ET_IGNORE,FP_CELL)
        FW_BExplode = CreateMultiForward("bomb_explode",ET_IGNORE,FP_CELL,FP_CELL)
        FW_BDefusing = CreateMultiForward("bomb_defusing",ET_IGNORE,FP_CELL)
        FW_BDefused = CreateMultiForward("bomb_defused",ET_IGNORE,FP_CELL)
        FW_GThrow = CreateMultiForward("grenade_throw",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL)
        
        register_forward(FM_SetModel,"FMHook_SetModel",true)
    }
    
    // 0.7.2
    FW_Assist = CreateMultiForward("client_assist_sql",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL)
    
    // 0.7.3
    FW_Initialized = CreateMultiForward("csxsql_initialized",ET_IGNORE)
    
    // 0.7
    
    //
    // запрос на получение ID сессии статистики за карту
    //
    if(map_stats_enabled)
    {
        new query[128],sql_data[1] = SQL_GETSESSID
        
        formatex(query,charsmax(query),"SELECT MAX(`session_id`) FROM `%s_maps`",
            tbl_name
        )
        
        DB_AddInitSeq()
        SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
    }
    
    // защита от ретардов, которые не читаю README
    if(
        (get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -2) ||
        (get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == 0)
    )
    {
        // выключаем кеширование
        set_pcvar_num(cvar[CVAR_CACHETIME],0)
    }
    
    DB_InitSeq()
}

//
// последовательность перед началом работы плагина
//
DB_AddInitSeq()
{
    init_seq --
}

//
// проверяем выполнение последовательности инициализации
//
DB_InitSeq()
{
    if(init_seq ==0)
    {
        log_amx("!?!?!?!?!?")
        return
    }
    
    init_seq ++
    
    // все выполнено, начинаем работу
    if(init_seq == 0)
    {
        ExecuteForward(FW_Initialized,dummy_ret)
    }
}

//
// Функция очистки БД от неактивных игроков
//
DB_AutoClearOpt()
{
    // 0.7
    new autoclear_days = get_pcvar_num(cvar[CVAR_AUTOCLEAR])
    
    if(autoclear_days > 0)
    {
        DB_ClearTables(autoclear_days)
    }
    
    // полные сброс статистики в определенный день
    autoclear_days = get_pcvar_num(cvar[CVAR_AUTOCLEAR_DAY])
    
    if(autoclear_days > 0)
    {
          new s_data[10]
          get_time("%d",s_data,charsmax(s_data))
          
          if(str_to_num(s_data) == autoclear_days)
          {
              s_data[0] = 0
              get_vaultdata("csxsql_clear",s_data,charsmax(s_data))
            
            // проверяем не было ли сброса
            if(!str_to_num(s_data))
            {
                set_vaultdata("csxsql_clear","1")
                DB_ClearTables(-1)
            }
          }
          /// очищяем проверку на сброс
          else
          {
              set_vaultdata("csxsql_clear","0")
          }
    }
}

//
// Начало работы с БД
//
public csxsql_initialized()
{
    is_ready = true
    
    new players[MAX_PLAYERS],pnum
    get_players(players,pnum)
    
    // загружаем стату игроков
    for(new i ; i < pnum ; i++)
    {
        client_putinserver(players[i])
    }
}

public SrvCmd_DBReset()
{
    DB_ClearTables(-1)
}

//
// Очистка таблиц от неактивных записей
//
DB_ClearTables(by_days)
{
    if(by_days == -1)
    {
        log_amx("database reset")
    }
    
    new query[QUERY_LENGTH],que_len
    
    new type[10]
    get_pcvar_string(cvar[CVAR_SQL_TYPE],type,charsmax(type))
        
    if(strcmp(type,"mysql") == 0)
    {
        que_len += formatex(query[que_len],charsmax(query) - que_len,"DELETE `%s`",
            tbl_name
        )
        
        if(weapon_stats_enabled)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,",`%s_weapons`",tbl_name)
        }
        
        if(map_stats_enabled)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,",`%s_maps`",tbl_name)
        }
        
        que_len += formatex(query[que_len],charsmax(query) - que_len," FROM `%s`",
            tbl_name
        )
        
        if(weapon_stats_enabled)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                LEFT JOIN `%s_weapons` ON `%s`.`%s` = `%s_weapons`.`%s`",
                tbl_name,
                tbl_name,row_names[ROW_ID],
                tbl_name,row_weapons_names[ROW_WEAPON_PLAYER]
            )
        }
        
        if(map_stats_enabled)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                LEFT JOIN `%s_maps` ON `%s`.`%s` = `%s_maps`.`%s`",
                tbl_name,
                tbl_name,row_names[ROW_ID],
                tbl_name,row_weapons_names[ROW_WEAPON_PLAYER]
            )
        }
        
        if(by_days > 0)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"WHERE `%s`.`%s` <= DATE_SUB(NOW(),INTERVAL %d DAY);",
                tbl_name,row_names[ROW_LASTJOIN],by_days
            )
        }
        else
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"WHERE 1")
        }
    }
    else if(strcmp(type,"sqlite") == 0)
    {
        if(weapon_stats_enabled)
        {
            if(by_days > 0)
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                        DELETE FROM `%s_weapons` WHERE `%s` IN (\
                            SELECT `%s` FROM `%s` WHERE `%s` <= DATETIME('now','-%d day')\
                        );",
                        tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
                        row_names[ROW_ID],tbl_name,row_names[ROW_LASTJOIN],
                        by_days
                )
            }
            else
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                        DELETE FROM `%s_weapons` WHERE `%s` IN (\
                            SELECT `%s` FROM `%s` WHERE 1\
                        );",
                        tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
                        row_names[ROW_ID],tbl_name
                    )
            }
        }
        
        if(map_stats_enabled)
        {
            if(by_days > 0)
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    DELETE FROM `%s_maps` WHERE `%s` IN (\
                        SELECT `%s` FROM `%s` WHERE `%s` <= DATETIME('now','-%d day')\
                    );",
                    tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
                    row_names[ROW_ID],tbl_name,row_names[ROW_LASTJOIN],
                    by_days
                )
            }
            else
            {
                que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    DELETE FROM `%s_maps` WHERE `%s` IN (\
                        SELECT `%s` FROM `%s` WHERE 1\
                    );",
                    tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
                    row_names[ROW_ID],tbl_name
                )
            }
        }
        
        if(by_days > 0)
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    DELETE FROM `%s` WHERE `%s` <= DATETIME('now','-%d day');",
                    tbl_name,row_names[ROW_LASTJOIN],by_days
            )
        }
        else
        {
            que_len += formatex(query[que_len],charsmax(query) - que_len,"\
                    DELETE FROM `%s` WHERE 1;",tbl_name
            )
        }
    }
    
    new sql_data[1]
    sql_data[0] = SQL_AUTOCLEAR
    
    DB_AddInitSeq()
    SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
}

public plugin_end()
{
    // выполняем накопившиеся запросы при смене карты или выключении серваре
    DB_FlushQuery()
    
    SQL_FreeHandle(sql)
    
    if(sql_con != Empty_Handle)
    {
        SQL_FreeHandle(sql_con)
    }
    
    if(stats_cache_trie)
    {
        TrieDestroy(stats_cache_trie)
    }
    
    TrieDestroy(log_ids_trie)
    ArrayDestroy(weapons_data)
}

/*
* загружаем статистику при подключении
*/
public client_putinserver(id)
{
    // ждем начала работы с БД
    if(!is_ready)
    {
        return PLUGIN_CONTINUE
    }
    
    reset_user_allstats(id)
    reset_user_wstats(id)
    
    arrayset(player_data[id],0,player_data_struct)
    
    for(new wpn ; wpn < MAX_WEAPONS ; wpn ++)
    {
        arrayset(player_awstats[id][wpn],0,sizeof player_awstats[][])
    }
    
    DB_LoadPlayerData(id)
    
    return PLUGIN_CONTINUE
}

/*
* сохраняем статистику при дисконнекте
*/
#if AMXX_VERSION_NUM < 183
public client_disconnect(id)
#else
public client_disconnected(id)
#endif
{
    DB_SavePlayerData(id)
}

public HamHook_PlayerSpawn(id)
{
    reset_user_wstats(id)
}

//
// Регистрация выстрелов
//
public EventHook_CurWeapon(player)
{
    #define LASTWEAPON     0    // id посл. оружия
    #define LASTCLIP    1    // кол-во потронов посл. оружия
    
    static event_tmp[MAX_PLAYERS + 1][LASTCLIP + 1]    // помним послед
    static weapon_id; weapon_id = read_data(2)
    static clip_ammo; clip_ammo = read_data(3)
    
    if(event_tmp[player][LASTWEAPON] != weapon_id) // оружие было изменено, запоминаем новое кол-во патронов
    {
        event_tmp[player][LASTWEAPON] = weapon_id
        event_tmp[player][LASTCLIP] = clip_ammo
    }
    else if(event_tmp[player][LASTCLIP] > clip_ammo) // кол-во патронов в магазине уменьшилось, регистрируем выстрел
    {
        Stats_SaveShot(player,weapon_id)
+        if (!gSaveStats) return;
        event_tmp[player][LASTCLIP] = clip_ammo
    }
}

//
// Регистрация попадания
//
public EventHook_Damage(player)
{
    static damage_take;damage_take = read_data(2)
    static dmg_inflictor;dmg_inflictor = pev(player,pev_dmg_inflictor)
    
    if(pev_valid(dmg_inflictor) != 2)
    {
        return PLUGIN_CONTINUE
    }
    
    if(!(0 < dmg_inflictor <= MaxClients))
    {
        // урон с гранаты на данным момент не учитывается
        
        return PLUGIN_CONTINUE
    }
    
    static weapon_id,last_hit,attacker
    attacker = get_user_attacker(player,weapon_id,last_hit)
    
    if(0 <= last_hit < HIT_END)
    {
        Stats_SaveHit(dmg_inflictor,player,damage_take,weapon_id,last_hit)
+        if (!gSaveStats) return 0
    }
    
    if(!is_user_alive(player))
    {
        if(is_user_connected(attacker))
        {
            Stats_SaveKill(attacker,player,weapon_id,last_hit)
+            if (!gSaveStats) return 0
        }
    }
    
    return PLUGIN_CONTINUE
}

//
// Регистрация установки и дефьюза бомбы
//
public EventHook_BarTime(player)
{
    new duration = read_data(1)
    
    if(!duration)
    {
        return PLUGIN_CONTINUE
    }
    
    if(duration == 3)
    {
        g_planter = player
        g_defuser = 0
        
        if(FW_BPlanting)
            ExecuteForward(FW_BPlanting,dummy_ret,player)
    }
    else
    {
        g_defuser = player
        
        Stats_SaveBDefusing(player)
+        if (!gSaveStats) return 0
    }
    
    return PLUGIN_CONTINUE
}

public EventHook_SendAudio(player)
{
    new audio_code[16]
    read_data(2,audio_code,charsmax(audio_code))
    
    if (!player && audio_code[7] == 'B')
    {
        if (audio_code[11]=='P' && g_planter)
        {
            Stats_SaveBPlanted(g_planter)
 +           if (!gSaveStats) return;
        }
        else if (audio_code[11] =='D' && g_defuser)
        {
            Stats_SaveBDefused(g_defuser)
+            if (!gSaveStats) return;
            
            Event_CTWin()
        }
    }
}

public EventHook_TextMsg(player)
{
    new message[16]
    read_data(2,message,charsmax(message))
    
    if (!player)
    {
        // #Target_Bombed
        if ((message[1]=='T' && message[8] == 'B') && g_planter)
        {
            Stats_SaveBExplode(g_planter)
 +           if (!gSaveStats) return;
            
            g_planter = 0
            g_defuser = 0
            
            Event_TWin()
        }
        // #Terrorists_Win -- #Hostages_Not_R
        else if(
            (message[2] == 'e' && message[12] == 'W') ||
            (message[1] == 'H' && message[14] == 'R')
        )
        {
            Event_TWin()
        }
        // #Target_Saved -- #CTs_Win -- #All_Hostages_R
        else if(
            (message[1] == 'T' && message[8] == 'S') ||
            (message[2] == 'T' && message[5] == 'W') ||
            (message[1] == 'A' && message[14] == 'R')
        )
        {
            Event_CTWin()
        }
        
    }
}

//
// Победа TERRORIST
//
Event_TWin()
{
    new players[MAX_PLAYERS],pnum
    get_players(players,pnum)
    
    for(new i,player ; i < pnum ; i++)
    {
        player = players[i]
        
        // считаем статистику побед по командам
        if(player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] == 1)
        {
            player_data[player][PLAYER_STATS3][STATS3_WINT] ++
        }
    }
}

//
// Победа CT
//
Event_CTWin()
{
    new players[MAX_PLAYERS],pnum
    get_players(players,pnum)
    
    for(new i,player ; i < pnum ; i++)
    {
        player = players[i]
        
        // считаем статистику побед по командам
        if(player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] == 2)
        {
            player_data[player][PLAYER_STATS3][STATS3_WINCT] ++
        }
    }
}

//
// Форвард grenade_throw
//
public FMHook_SetModel(ent,model[])
{
    new owner = pev(ent,pev_owner)
    
    new Float:dmg_time
    pev(ent,pev_dmgtime,dmg_time)
    
    if(dmg_time <= 0.0 || !is_user_connected(owner))
    {
        return FMRES_IGNORED
    }
    
    new classname[32]
    pev(ent,pev_classname,classname,charsmax(classname))
    
    if(strcmp(classname,"grenade") != 0) // реагируем только на гранаты
    {
        return FMRES_IGNORED
    }
    
    new wId
    
    if(model[9] == 'h') // модель хеешки
    {
        wId = CSW_HEGRENADE
    }
    else if(model[9] == 'f') // модель флешки
    {
        wId = CSW_FLASHBANG
    }
    else if(model[9] == 's') // модель смока
    {
        wId = CSW_SMOKEGRENADE
    }
    
    ExecuteForward(FW_GThrow,dummy_ret,owner,ent,wId)
    
    return FMRES_IGNORED
}

//
// Учет ассистов
//
Stats_SaveAssist(player,victim,assisted)
{
+    if (!gSaveStats) return 0
    player_data[player][PLAYER_STATS3][STATS3_ASSIST] ++
    
    ExecuteForward(FW_Assist,dummy_ret,player,victim,assisted)
    
    return true
}

//
// Учет выстрелов
//
Stats_SaveShot(player,wpn_id)
{
+    if (!gSaveStats) return 0
    player_wstats[player][0][STATS_SHOTS] ++
    player_wstats[player][wpn_id][STATS_SHOTS] ++
    
    player_wrstats[player][0][STATS_SHOTS] ++
    player_wrstats[player][wpn_id][STATS_SHOTS] ++
    
    return true
}

//
// Учет попадания
//
Stats_SaveHit(attacker,victim,damage,wpn_id,hit_place)
{
+    if (!gSaveStats) return 0
    player_wstats[attacker][0][STATS_HITS] ++
    player_wstats[attacker][0][STATS_DMG] += damage
    player_wstats[attacker][0][hit_place + STATS_END] ++
    
    player_wrstats[attacker][0][STATS_HITS] ++
    player_wrstats[attacker][0][STATS_DMG] += damage
    player_wrstats[attacker][0][hit_place + STATS_END] ++
    
    player_wstats[attacker][wpn_id][STATS_DMG] += damage
    player_wrstats[attacker][wpn_id][STATS_DMG] += damage
    player_wstats[attacker][wpn_id][STATS_HITS] ++
    player_wrstats[attacker][wpn_id][STATS_HITS] ++
    player_wstats[attacker][wpn_id][hit_place + STATS_END] ++
    player_wrstats[attacker][wpn_id][hit_place + STATS_END] ++
    
    player_vstats[attacker][victim][STATS_HITS] ++
    player_vstats[attacker][victim][STATS_DMG] += damage
    player_vstats[attacker][victim][hit_place + STATS_END] ++
    player_astats[victim][attacker][STATS_HITS] ++
    player_astats[victim][attacker][STATS_DMG] += damage
    player_astats[victim][attacker][hit_place + STATS_END] ++
    player_vstats[attacker][0][STATS_HITS] ++
    player_vstats[attacker][0][STATS_DMG] += damage
    player_vstats[attacker][0][hit_place + STATS_END] ++
    player_astats[victim][0][STATS_HITS] ++
    player_astats[victim][0][STATS_DMG] += damage
    player_astats[victim][0][hit_place + STATS_END] ++
    
    // оружие, с которого убил для astats, vstats
    new weapon_info[WEAPON_INFO_SIZE]
    ArrayGetArray(weapons_data,wpn_id,weapon_info)
    
    copy(player_vstats[attacker][victim][STATS_END + HIT_END],
        MAX_NAME_LENGTH - 1,
        weapon_info[1]
    )
    
    copy(player_astats[victim][attacker][STATS_END + HIT_END],
        MAX_NAME_LENGTH - 1,
        weapon_info[1]
    )
    
    if(FW_Damage)
        ExecuteForward(FW_Damage,dummy_ret,attacker,victim,damage,wpn_id,hit_place,is_tk(attacker,victim))
        
    return true
}

//
// Учет смертей
//
Stats_SaveKill(killer,victim,wpn_id,hit_place)
{
+    if (!gSaveStats) return 0
    if(killer == victim) // не учитываем суицид
    {
        return false
    }
    
    if(!is_tk(killer,victim))
    {
        player_wstats[killer][0][STATS_KILLS] ++
        player_wstats[killer][wpn_id][STATS_KILLS] ++
            
        player_wrstats[killer][0][STATS_KILLS] ++
        player_wrstats[killer][wpn_id][STATS_KILLS] ++
            
        player_vstats[killer][victim][STATS_KILLS] ++
        player_astats[victim][killer][STATS_KILLS] ++
        player_vstats[killer][0][STATS_KILLS] ++
        player_astats[victim][0][STATS_KILLS] ++
            
        if(hit_place == HIT_HEAD)
        {
            player_wstats[killer][0][STATS_HS] ++
            player_wstats[killer][wpn_id][STATS_HS] ++
                
            player_wrstats[killer][0][STATS_HS] ++
            player_wrstats[killer][wpn_id][STATS_HS] ++
                
            player_vstats[killer][victim][STATS_HS] ++
            player_astats[victim][killer][STATS_HS] ++
            player_vstats[killer][0][STATS_HS] ++
            player_astats[victim][0][STATS_HS] ++
        }
    }
    else
    {
        player_wstats[killer][0][STATS_TK] ++
        player_wstats[killer][wpn_id][STATS_TK] ++
        
        player_wrstats[killer][0][STATS_TK] ++
        player_wrstats[killer][wpn_id][STATS_TK] ++
        
        player_vstats[killer][victim][STATS_TK] ++
        player_astats[victim][killer][STATS_TK] ++
        player_vstats[killer][0][STATS_TK] ++
        player_astats[victim][0][STATS_TK] ++
    }
        
    player_wstats[victim][0][STATS_DEATHS] ++
    player_wrstats[victim][0][STATS_DEATHS] ++
    
    // смотрим ассисты
    for(new i = 1,assist_hp = get_pcvar_num(cvar[CVAR_ASSISTHP]); (assist_hp) && (i <= MAX_PLAYERS) ; i++)
    {
        if(i == killer)
        {
            continue
        }
        
        if(player_astats[victim][i][STATS_DMG] >= assist_hp)
        {
            Stats_SaveAssist(i,victim,killer)
+            if (!gSaveStats) return 0
        }
    }
    
    new victim_wpn_id = get_user_weapon(victim)
    
    if(victim_wpn_id)
    {
        player_wstats[victim][victim_wpn_id][STATS_DEATHS] ++
        player_wrstats[victim][victim_wpn_id][STATS_DEATHS] ++
    }
    
    if(FW_Death)
        ExecuteForward(FW_Death,dummy_ret,killer,victim,wpn_id,hit_place,is_tk(killer,victim))
    
    if(player_data[killer][PLAYER_LOADSTATE] == LOAD_OK && player_data[victim][PLAYER_LOADSTATE] == LOAD_OK) // скилл расчитывается только при наличии статистики из БД
    {
        switch(get_pcvar_num(cvar[CVAR_SKILLFORMULA])) // расчет скилла
        {
            case 0: // The ELO Method (http://fastcup.net/rating.html)
            {
                new Float:delta = 1.0 / (1.0 + floatpower(10.0,(player_data[killer][PLAYER_SKILL] - player_data[victim][PLAYER_SKILL]) / 100.0))
                new Float:koeff = 0.0
                
                if(player_data[killer][PLAYER_STATS][STATS_KILLS] < 100)
                {
                    koeff = 2.0
                }
                else
                {
                    koeff = 1.5
                }
                
                player_data[killer][PLAYER_SKILL] += (koeff * delta)
                player_data[victim][PLAYER_SKILL] -= (koeff * delta)
            }
        }
    }
    
    
    // обновляем статистику в БД при смерти
    if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -2)
    {
        DB_SavePlayerData(victim)
    }
    
    
    
    return true
}

//
// Учет статистики по бомба
//
Stats_SaveBDefusing(id)
{
+    if (!gSaveStats) return 0
    player_wstats2[id][STATS2_DEFAT] ++

    if(FW_BDefusing)
        ExecuteForward(FW_BDefusing,dummy_ret,id)

    return true
}

Stats_SaveBDefused(id)
{
+    if (!gSaveStats) return 0
    player_wstats2[id][STATS2_DEFOK] ++

    if(FW_BDefused)
        ExecuteForward(FW_BDefused,dummy_ret,id)

    return true
}

Stats_SaveBPlanted(id)
{
+    if (!gSaveStats) return 0
    player_wstats2[id][STATS2_PLAAT] ++

    if(FW_BPlanted)
        ExecuteForward(FW_BPlanted,dummy_ret,id)

    return true
}

Stats_SaveBExplode(id)
{
+    if (!gSaveStats) return 0
    player_wstats2[id][STATS2_PLAOK] ++
    
    if(FW_BExplode)
        ExecuteForward(FW_BExplode,dummy_ret,id,g_defuser)

    return true
}

/*
* изменение ника игрока
*/
public client_infochanged(id)
{
    new cur_name[MAX_NAME_LENGTH],new_name[MAX_NAME_LENGTH]
    get_user_name(id,cur_name,charsmax(cur_name))
    get_user_info(id,"name",new_name,charsmax(new_name))
    
    if(strcmp(cur_name,new_name) != 0)
    {
        copy(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]),new_name)
        mysql_escape_string(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
        
        if(get_pcvar_num(cvar[CVAR_RANK]) == 0)
        {
            DB_SavePlayerData(id,true)
        }
    }
}

/*
* сбрасываем astats,vstats статистику в начале раунда
*/
public LogEventHooK_RoundStart()
{
    // сбрасываем wrstats, vstats, astats в начале раунда
    new players[32],pnum
    get_players(players,pnum)
    
    for(new i,player ; i < pnum ; i++)
    {
        player = players[i]
        
        // определяем в какой команде игрок
        switch(get_user_team(player))
        {
            // статистика сыгранных раундов по командам
            case 1:
            {
                player_data[player][PLAYER_STATS3][STATS3_ROUNDT] ++
                player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] = 1
            }
            case 2:
            {
                player_data[player][PLAYER_STATS3][STATS3_ROUNDCT] ++
                player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] = 2
            }
        }
    }

    
}

//
// сохраняем статистику в конце раунда
//
public LogEventHooK_RoundEnd()
{
    if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -1)
    {
        DB_SaveAll()
    }
}

/*
* загрузка статистики игрока из базы данных
*/
DB_LoadPlayerData(id)
{
    // пропускаем HLTV
    if(is_user_hltv(id))
    {
        return false
    }
    
    // пропускаем ботов, если отключена запись статистики ботов
    if( is_user_bot(id) && !get_pcvar_num(cvar[CVAR_RANKBOTS]))
    {
        return false
    }
    
    get_user_info(id,"name",player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
    mysql_escape_string(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
    
    get_user_authid(id,player_data[id][PLAYER_STEAMID],charsmax(player_data[][PLAYER_STEAMID]))
    get_user_ip(id,player_data[id][PLAYER_IP],charsmax(player_data[][PLAYER_IP]),true)
    
    // формируем SQL запрос
    new query[QUERY_LENGTH],len,sql_data[2]
    
    sql_data[0] = SQL_LOAD
    sql_data[1] = id
    player_data[id][PLAYER_LOADSTATE] = LOAD_WAIT
    
    len += formatex(query[len],charsmax(query)-len,"SELECT *,(")
    len += DB_QueryBuildScore(query[len],charsmax(query)-len)
    len += formatex(query[len],charsmax(query)-len,"),(")
    len += DB_QueryBuildStatsnum(query[len],charsmax(query)-len)
    len += formatex(query[len],charsmax(query)-len,")")
    
    switch(get_pcvar_num(cvar[CVAR_RANK]))
    {
        case 0: // статистика по нику
        {
            len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `name` = '%s'",
                tbl_name,player_data[id][PLAYER_NAME]
            )
        }
        case 1: // статистика по steamid
        {
            len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `steamid` = '%s'",
                tbl_name,player_data[id][PLAYER_STEAMID]
            )
        }
        case 2: // статистика по ip
        {
            len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `ip` = '%s'",
                tbl_name,player_data[id][PLAYER_IP]
            )
        }
        default:
        {
            return false
        }
    }
    
    // отправка потокового запроса
    SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
    
    return true
}

//
// Загрузка статистики по оружию
//
DB_LoadPlayerWstats(id)
{
    if(!player_data[id][PLAYER_ID])
    {
        return false
    }
    
    new query[QUERY_LENGTH],sql_data[2]
    
    sql_data[0] = SQL_GETWSTATS
    sql_data[1] = id
    
    formatex(query,charsmax(query),"SELECT * FROM `%s_weapons` WHERE `player_id` = '%d'",
        tbl_name,player_data[id][PLAYER_ID]
    )
    
    SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
    
    return true
        
}

/*
* сохранение статистики игрока
*/
DB_SavePlayerData(id,bool:reload = false)
{
    if(player_data[id][PLAYER_LOADSTATE] < LOAD_NEW) // игрок не загрузился
    {
        return false
    }
    
    new query[QUERY_LENGTH],i,len
    new sql_data[2]
    
    sql_data[1] = id
    
    new stats[8],stats2[4],hits[8]
    get_user_wstats(id,0,stats,hits)
    get_user_stats2(id,stats2)
    
    switch(player_data[id][PLAYER_LOADSTATE])
    {
        case LOAD_OK: // обновление данных
        {
            if(reload)
            {
                player_data[id][PLAYER_LOADSTATE] = LOAD_UPDATE
            }
            
            sql_data[0] = SQL_UPDATE
            
            new diffstats[sizeof player_data[][PLAYER_STATS]]
            new diffstats2[sizeof player_data[][PLAYER_STATS2]]
            new diffhits[sizeof player_data[][PLAYER_HITS]]
            new to_save
            
            len += formatex(query[len],charsmax(query) - len,"UPDATE `%s` SET",tbl_name)
            
            // обновляем по разнице с предедущими данными
            for(i = 0 ; i < sizeof player_data[][PLAYER_STATS] ; i++)
            {
                diffstats[i] = stats[i] - player_data[id][PLAYER_STATSLAST][i] // узнаем разницу
                player_data[id][PLAYER_STATSLAST][i] = stats[i]
                
                if(diffstats[i])
                {
                    len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
                        !to_save ? " " : ",",
                        row_names[i + ROW_KILLS],
                        row_names[i + ROW_KILLS],
                        diffstats[i]
                    )
                    
                    to_save ++
                }
            }
            
            // обновляем по разнице с предедущими данными
            for(i = 0 ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
            {
                diffstats2[i] = stats2[i] - player_data[id][PLAYER_STATS2LAST][i] // узнаем разницу
                player_data[id][PLAYER_STATS2LAST][i] = stats2[i]
                
                if(diffstats2[i])
                {
                    len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
                        !to_save ? " " : ",",
                        row_names[i + ROW_BOMBDEF],
                        row_names[i + ROW_BOMBDEF],
                        diffstats2[i]
                    )
                    
                    to_save ++
                }
            }
        
            
            new Float:diffskill = player_data[id][PLAYER_SKILL] - player_data[id][PLAYER_SKILLLAST]
            player_data[id][PLAYER_SKILLLAST] = _:player_data[id][PLAYER_SKILL]
            
            if(diffskill != 0.0)
            {
                len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %.2f",
                    !to_save ? " " : ",",
                    row_names[ROW_SKILL],
                    row_names[ROW_SKILL],
                    diffskill
                )
                    
                to_save ++
            }
            
            if(stats[STATS_HITS])
            {
                // запрос на сохранение мест попаданий
                for(i = 0; i < sizeof player_data[][PLAYER_HITS] ; i++)
                {
                    diffhits[i] = hits[i] - player_data[id][PLAYER_HITSLAST][i] // узнаем разницу
                    player_data[id][PLAYER_HITSLAST][i] = hits[i]
                    
                    if(diffhits[i])
                    {
                        len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
                            !to_save ? " " : ",",
                            row_names[i + ROW_H0],row_names[i + ROW_H0],
                            diffhits[i]
                        )
                    }
                }
            }
            
            // 0.7
            new diffstats3[STATS3_END]
            
            for(i = STATS3_CONNECT ; i < sizeof player_data[][PLAYER_STATS3] ; i++)
            {
                diffstats3[i] = player_data[id][PLAYER_STATS3][i] - player_data[id][PLAYER_STATS3LAST][i]
                player_data[id][PLAYER_STATS3LAST][i] = player_data[id][PLAYER_STATS3][i]
                
                if(diffstats3[i])
                {
                    len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
                        !to_save ? " " : ",",
                        row_names[(i - 1) + ROW_CONNECTS],row_names[(i - 1) + ROW_CONNECTS],
                        diffstats3[i]
                    )
                    
                    to_save ++
                }
            }
            
            // не сохраняем только подключения
            to_save --
            
            // 0.7 задаем поля для тригерром статистики по картам
            if(session_id)
            {
                len += formatex(query[len],charsmax(query) - len,"%s`%s` = '%d',`%s` = '%s'",
                        to_save <= 0 ? " " : ",",
                        row_names[ROW_SESSIONID],session_id,
                        row_names[ROW_SESSIONNAME],session_map
                )
            }
            
            //
            player_data[id][PLAYER_ONLINE] += get_user_time(id) - player_data[id][PLAYER_ONLINEDIFF]
            player_data[id][PLAYER_ONLINEDIFF] = get_user_time(id)
            
            new diffonline = player_data[id][PLAYER_ONLINE]- player_data[id][PLAYER_ONLINELAST]
            player_data[id][PLAYER_ONLINELAST] = player_data[id][PLAYER_ONLINE]
            
            if(diffonline)
            {
                len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
                    to_save <= 0 ? " " : ",",
                    row_names[ROW_ONLINETIME],
                    row_names[ROW_ONLINETIME],
                    diffonline
                )
                
                //to_save ++
            }
            
            // обновляем время последнего подключения, ник, ип и steamid
            len += formatex(query[len],charsmax(query) - len,",\
                `last_join` = CURRENT_TIMESTAMP,\
                `%s` = '%s',\
                `%s` = '%s'",
                
                
                row_names[ROW_STEAMID],player_data[id][PLAYER_STEAMID],
                row_names[ROW_IP],player_data[id][PLAYER_IP],
                
                row_names[ROW_ID],player_data[id][PLAYER_ID]
            )
            
            if(!reload) // не обновляем ник при его смене
            {
                len += formatex(query[len],charsmax(query) - len,",`%s` = '%s'",
                    row_names[ROW_NAME],player_data[id][PLAYER_NAME]
                )
            }
            
            len += formatex(query[len],charsmax(query) - len,"WHERE `%s` = '%d'",row_names[ROW_ID],player_data[id][PLAYER_ID])
            
            if(to_save <= 0) // нечего сохранять
            {
                if(player_data[id][PLAYER_LOADSTATE] == LOAD_UPDATE) // релоад для обновления ника
                {
                    player_data[id][PLAYER_LOADSTATE] = LOAD_NO
                    DB_LoadPlayerData(id)
                }
                
                return false
            }
            else
            {
                //
                // Сравниваем статистику
                //
                for(new i ; i < sizeof player_data[][PLAYER_STATS] ; i++)
                {
                    player_data[id][PLAYER_STATS][i] += diffstats[i]
                }
                
                for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
                {
                    player_data[id][PLAYER_HITS][i] += diffhits[i]
                }
                
                for(new i ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
                {
                    player_data[id][PLAYER_STATS2][i] += diffstats2[i]
                }
            }
        }
        case LOAD_NEW: // запрос на добавление новой записи
        {
            sql_data[0] = SQL_INSERT
            
            new Float:skill
            
            switch(get_pcvar_num(cvar[CVAR_SKILLFORMULA]))
            {
                case 0: skill = 100.0
            }
            
            formatex(query,charsmax(query),"INSERT INTO `%s` \
                            (`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`)\
                            VALUES('%s','%s','%s','%.2f','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d',CURRENT_TIMESTAMP)\
                            ",tbl_name,
                            
                    row_names[ROW_STEAMID],
                    row_names[ROW_NAME],
                    row_names[ROW_IP],
                    row_names[ROW_SKILL],
                    row_names[ROW_KILLS],
                    row_names[ROW_DEATHS],
                    row_names[ROW_HS],
                    row_names[ROW_TKS],
                    row_names[ROW_SHOTS],
                    row_names[ROW_HITS],
                    row_names[ROW_DMG],
                    row_names[ROW_BOMBDEF],
                    row_names[ROW_BOMBDEFUSED],
                    row_names[ROW_BOMBPLANTS],
                    row_names[ROW_BOMBEXPLOSIONS],
                    row_names[ROW_LASTJOIN],
                    
                    player_data[id][PLAYER_STEAMID],
                    player_data[id][PLAYER_NAME],
                    player_data[id][PLAYER_IP],
                    
                    skill,
                    
                    stats[STATS_KILLS],
                    stats[STATS_DEATHS],
                    stats[STATS_HS],
                    stats[STATS_TK],
                    stats[STATS_SHOTS],
                    stats[STATS_HITS],
                    stats[STATS_DMG],
                    
                    stats2[STATS2_DEFAT],
                    stats2[STATS2_DEFOK],
                    stats2[STATS2_PLAAT],
                    stats2[STATS2_PLAOK]
            )
            
            //
            // Сравниваем статистику
            //
            for(new i ; i < sizeof player_data[][PLAYER_STATS] ; i++)
            {
                player_data[id][PLAYER_STATS][i] = stats[i]
            }
                
            for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
            {
                player_data[id][PLAYER_HITS][i] = hits[i]
            }
                
            for(new i ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
            {
                player_data[id][PLAYER_STATS2][i] = stats2[i]
            }
                
            player_data[id][PLAYER_SKILL] = _:player_data[id][PLAYER_SKILLLAST] = _:skill
            
            if(reload)
            {
                player_data[id][PLAYER_LOADSTATE] = LOAD_UPDATE
            }
            else
            {
                player_data[id][PLAYER_LOADSTATE] = LOAD_NEWWAIT
            }
        }
    }
    
    if(query[0])
    {
        if(weapon_stats_enabled)
        {
            DB_SavePlayerWstats(id)
        }
        
        switch(sql_data[0])
        {
            // накапливаем запросы
            case SQL_UPDATE:
            {
                // запросов достаточно, сбрасываем их
                DB_AddQuery(query,len)
                
                return true
            }
        }
        
        SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
    }
    
    return true
}

//
// Сохранение статистики по оружию
//
public DB_SavePlayerWstats(id)
{
    if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // игрок не загрузился
    {
        return false
    }
    
    new query[QUERY_LENGTH],len,log[MAX_NAME_LENGTH],wpn,stats_index,stats_index_last,to_save
    new diff[STATS_END + HIT_END]
    
    const load_index = sizeof player_awstats[][] - 1
    
    // по всем оружиям
    for(wpn = 0; wpn < MAX_WEAPONS ; wpn++)
    {
        Info_Weapon_GetLog(wpn,log,charsmax(log))
        
        if(!log[0])
        {
            continue
        }
        
        to_save = 0
        len = 0
        
        // расчитываем разницу статисткии
        for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
        {
            stats_index_last = stats_index + (STATS_END + HIT_END)
            
            diff[stats_index] = player_wstats[id][wpn][stats_index] - player_awstats[id][wpn][stats_index_last]
            player_awstats[id][wpn][stats_index_last] = player_wstats[id][wpn][stats_index]
        }
        
        switch(player_awstats[id][wpn][load_index])
        {
            // новая статистика оружия
            case LOAD_NEW:
            {
                new id_row
                
                // строим запрос
                len += formatex(query[len],charsmax(query) - len,"INSERT INTO `%s_weapons` (`%s`,`%s`",
                    tbl_name,
                    
                    row_weapons_names[ROW_WEAPON_PLAYER],
                    row_weapons_names[ROW_WEAPON_NAME]
                )
                
                for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
                {
                    id_row = ROW_WEAPON_KILLS + stats_index
                    
                    if(diff[stats_index])
                    {
                        len += formatex(query[len],charsmax(query) - len,",`%s`",
                            row_weapons_names[id_row]
                        )
                        
                        to_save ++
                    }
                }
                
                if(to_save)
                {
                    len += formatex(query[len],charsmax(query) - len,") VALUES('%d','%s'",
                        player_data[id][PLAYER_ID],
                        log
                    )
                    
                    for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
                    {
                        id_row = ROW_WEAPON_KILLS + stats_index
                        
                        if(diff[stats_index])
                        {
                            len += formatex(query[len],charsmax(query) - len,",'%d'",
                                diff[stats_index]
                            )
                        }
                    }
                    
                    len += formatex(query[len],charsmax(query) - len,")")
                    player_awstats[id][wpn][load_index]  = _:LOAD_OK
                }
                
                
            }
            // обновляем статистику
            case LOAD_OK:
            {
                new id_row
                
                // строим запрос
                len += formatex(query[len],charsmax(query) - len,"UPDATE `%s_weapons` SET",tbl_name)
                
                for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
                {
                    id_row = ROW_WEAPON_KILLS + stats_index
                    
                    if(diff[stats_index])
                    {
                        len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
                            to_save ? "," : "",
                            row_weapons_names[id_row],
                            row_weapons_names[id_row],
                            diff[stats_index]
                        )
                        
                        to_save ++
                    }
                }
                
                len += formatex(query[len],charsmax(query) - len,"WHERE `%s` = '%s' AND `%s` = '%d'",
                    row_weapons_names[ROW_WEAPON_NAME],log,
                    row_weapons_names[ROW_WEAPON_PLAYER],player_data[id][PLAYER_ID]
                )
            }   
        }
        
        if(to_save)
        {
            DB_AddQuery(query,len)
        }
    }
    
    return true
}

DB_AddQuery(query[],len)
{
    if((flush_que_len + len + 1) > charsmax(flush_que))
    {
        DB_FlushQuery()
    }
    
    flush_que_len += formatex(
        flush_que[flush_que_len],
        charsmax(flush_que) - flush_que_len,
        "%s%s",flush_que_len ? ";" : "",
        query
    )
        
    // задание на сброс накопленных запросов
    remove_task(task_flush)
    set_task(0.1,"DB_FlushQuery",task_flush)
}

//
// Сброс накопленных запросов
//
public DB_FlushQuery()
{
    if(flush_que_len)
    {
        new sql_data[1] = SQL_UPDATE
        SQL_ThreadQuery(sql,"SQL_Handler",flush_que,sql_data,sizeof sql_data)
        
        flush_que_len = 0
    }
}

#define falos false

/*
* получение новых позиции в топе игроков
*/
public DB_GetPlayerRanks()
{
    new players[32],pnum
    get_players(players,pnum)
    
    new query[QUERY_LENGTH],len
    
    // строим SQL запрос
    len += formatex(query[len],charsmax(query) - len,"SELECT `id`,(")
    len += DB_QueryBuildScore(query[len],charsmax(query) - len)
    len += formatex(query[len],charsmax(query) - len,") FROM `%s` as `a` WHERE `id` IN(",tbl_name)
    
    new bool:letsgo
    
    for(new i,player,bool:y  ; i < pnum ; i++)
    {
        player = players[i]
        
        if(player_data[player][PLAYER_ID])
        {
            len += formatex(query[len],charsmax(query) - len,"%s'%d'",y ? "," : "",player_data[player][PLAYER_ID])
            y = true
            letsgo = true
        }
    }
    
    len += formatex(query[len],charsmax(query) - len,")")
    
    if(letsgo)
    {
        new data[1] = SQL_UPDATERANK
        SQL_ThreadQuery(sql,"SQL_Handler",query,data,sizeof data)
    }
}

new bool:update_cache = false

/*
* сохранение статистики всех игроков
*/
public DB_SaveAll()
{
    new players[32],pnum
    get_players(players,pnum)
    
    if(get_pcvar_num(cvar[CVAR_CACHETIME]) == -1)
    {
        update_cache = true
    }
    
    for(new i ; i < pnum ; i++)
    {
        DB_SavePlayerData(players[i])
    }
}

/*
* запрос на просчет ранка
*/
DB_QueryBuildScore(sql_que[] = "",sql_que_len = 0,bool:only_rows = falos,overide_order = 0)
{
    // стандартная формула csstats (убийства-смерти-tk)
    
    if(only_rows)
    {
        switch(overide_order ? overide_order : get_pcvar_num(cvar[CVAR_RANKFORMULA]))
        {
            case 1: return formatex(sql_que,sql_que_len,"`kills`")
            case 2: return formatex(sql_que,sql_que_len,"`kills`+`hs`")
            case 3: return formatex(sql_que,sql_que_len,"`skill`")
            case 4: return formatex(sql_que,sql_que_len,"`connection_time`")
            default: return formatex(sql_que,sql_que_len,"`kills`-`deaths`-`tks`")
        }
    }
    else
    {
        switch(overide_order ? overide_order : get_pcvar_num(cvar[CVAR_RANKFORMULA]))
        {
            case 1: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills)>=(a.kills)",tbl_name)
            case 2: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills+hs)>=(a.kills+a.hs)",tbl_name)
            case 3: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (skill)>=(a.skill)",tbl_name)
            case 4: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (connection_time)>=(a.connection_time)",tbl_name)
            default: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills-deaths-tks)>=(a.kills-a.deaths-a.tks)",tbl_name)
        }
    
    
    }
    
    return 0
}

/*
* запрос на общее кол-во записей в БД
*/
DB_QueryBuildStatsnum(sql_que[] = "",sql_que_len = 0)
{
    return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE 1",tbl_name)
}

/*
* запрос на выборку статистики по позиции
*    index - начальная позиция
*    index_count - кол-во выбираемых записей
*/
DB_QueryBuildGetstats(query[],query_max,len = 0,index,index_count = 2,overide_order = 0)
{
    // строим запрос
    len += formatex(query[len],query_max-len,"SELECT *")
    
    // запрос на ранк
    len += formatex(query[len],query_max-len,",(")
    len += DB_QueryBuildScore(query[len],query_max-len,true,overide_order)
    len += formatex(query[len],query_max-len,") as `rank`")
    
    // запрашиваем следующию запись
    // если есть, то возврашаем нативом index + 1
    len += formatex(query[len],query_max-len," FROM `%s` as `a` ORDER BY `rank` DESC LIMIT %d,%d",
        tbl_name,index,index_count
    )
    
    return len
}

/*
* чтение результата get_stats запроса
*/
DB_ReadGetStats(Handle:sqlQue,name[] = "",name_len = 0,authid[] = "",authid_len = 0,stats[8] = 0,hits[8] = 0,stats2[4] = 0,stats3[STATS3_END] = 0,&stats_count = 0,index)
{
    stats_count = SQL_NumResults(sqlQue)
    
    if(!stats_count)
    {
        return false
    }
    
    new stats_cache[stats_cache_struct]
    
    switch(get_pcvar_num(cvar[CVAR_RANK]))
    {
        case 0: SQL_ReadResult(sqlQue,ROW_NAME,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
        case 1: SQL_ReadResult(sqlQue,ROW_STEAMID,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
        case 2: SQL_ReadResult(sqlQue,ROW_IP,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
    }
    
    SQL_ReadResult(sqlQue,ROW_NAME,stats_cache[CACHE_NAME],charsmax(stats_cache[CACHE_NAME]))
    
    copy(name,name_len,stats_cache[CACHE_NAME])
    copy(authid,authid_len,stats_cache[CACHE_STEAMID])
    
    new i
    
    for(i = ROW_SKILL ; i <= ROW_LASTJOIN ; i++)
    {
        switch(i)
        {
            case ROW_SKILL: SQL_ReadResult(sqlQue,i,stats_cache[CACHE_SKILL])
            case ROW_KILLS..ROW_DMG:
            {
                stats_cache[CACHE_STATS][i - ROW_KILLS] = stats[i - ROW_KILLS] = SQL_ReadResult(sqlQue,i)
            }
            case ROW_BOMBDEF..ROW_BOMBEXPLOSIONS:
            {
                stats_cache[CACHE_STATS2][i - ROW_BOMBDEF] = stats2[i - ROW_BOMBDEF] = SQL_ReadResult(sqlQue,i)
            }
            case ROW_H0..ROW_H7:
            {
                stats_cache[CACHE_HITS][i - ROW_H0] = hits[i - ROW_H0] = SQL_ReadResult(sqlQue,i)
            }
            // 0.7
            case ROW_CONNECTS..ROW_ASSISTS:
            {
                stats_cache[CACHE_STATS3][((i - ROW_CONNECTS) + 1)] = stats3[((i - ROW_CONNECTS) + 1)] = SQL_ReadResult(sqlQue,i)
            }
            case ROW_FIRSTJOIN..ROW_LASTJOIN:
            {
                new date_str[32]
                SQL_ReadResult(sqlQue,i,date_str,charsmax(date_str))
                            
                stats_cache[(CACHE_FIRSTJOIN + (i - ROW_FIRSTJOIN))] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
            }
        }
        
    }
    
    // кеширование данных
    if(!stats_cache_trie)
    {
        stats_cache_trie = TrieCreate()
    }
    
    stats_cache[CACHE_LAST] = SQL_NumResults(sqlQue) <= 1
    SQL_ReadResult(sqlQue,ROW_SKILL,stats_cache[CACHE_SKILL])
    stats_cache[CACHE_ID] = SQL_ReadResult(sqlQue,ROW_ID)
    stats_cache[CACHE_TIME] = SQL_ReadResult(sqlQue,ROW_ONLINETIME)
    
    new index_str[10]
    num_to_str(index,index_str,charsmax(index_str))
    
    TrieSetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct)
    // кешироавние данных
    
    SQL_NextRow(sqlQue)
    
    return SQL_MoreResults(sqlQue)
}

//
// Задаем очередь для обновления кеша
//
Cache_Stats_SetQueue(start_index,top)
{
    // очередь уже создана
    if(Cache_Stats_CheckQueue(start_index,top))
    {
        return false
    }
    
    if(!stats_cache_queue)
    {
        stats_cache_queue = ArrayCreate(stats_cache_queue_struct)
    }
    
    new length = ArraySize(stats_cache_queue)
    
    new cache_queue_info[stats_cache_queue_struct]
    cache_queue_info[CACHE_QUE_START] = start_index
    cache_queue_info[CACHE_QUE_TOP] = top
    
    if(!length) // новая очередь
    {
        ArrayPushArray(stats_cache_queue,cache_queue_info)
    }
    else // в топ
    {
        ArrayInsertArrayBefore(stats_cache_queue,0,cache_queue_info)
    }
    
    length ++
    
    if(length > 5) // максимум 5 заданий в очереди
    {
        ArrayDeleteItem(stats_cache_queue,5)
        length --
    }
    
    return true
}

//
// Обновление кеша через очередь
//
Cache_Stats_UpdateQueue()
{
    if(!stats_cache_queue)
    {
        return false
    }
    
    for(new i,length = ArraySize(stats_cache_queue),cache_queue_info[stats_cache_queue_struct] ; i < length ; i++)
    {
        ArrayGetArray(stats_cache_queue,i,cache_queue_info)
        DB_QueryTop15(0,-1,-1,-1,cache_queue_info[CACHE_QUE_START],cache_queue_info[CACHE_QUE_TOP],-1)
    }
    
    return true
}

Cache_Stats_CheckQueue(start_index,top)
{
    if(!stats_cache_queue)
    {
        return false
    }
    
    for(new i,length = ArraySize(stats_cache_queue),cache_queue_info[stats_cache_queue_struct] ; i < length ; i++)
    {
        ArrayGetArray(stats_cache_queue,i,cache_queue_info)
        
        if(start_index == cache_queue_info[0] &&
            top == cache_queue_info[1]
        )
        {
            return true
        }
    }
    
    return false
}

//
// Потоковый запрос на Top15
//
DB_QueryTop15(id,plugin_id,func_id,position,start_index,top,params)
{
    // кеширование
    if((get_pcvar_num(cvar[CVAR_CACHETIME]) != 0) && stats_cache_trie)
    {
        Cache_Stats_SetQueue(start_index,top)
        
        new bool:use_cache = true
        
        // проверяем что требуемые данные есть в кеше
        for(new i =  start_index,index_str[10]; i < (start_index + top) ; i++)
        {
            num_to_str(i,index_str,charsmax(index_str))
            
            if(!TrieKeyExists(stats_cache_trie,index_str))
            {
                use_cache = false
            }
        }
        
        // юзаем кеш
        if(use_cache)
        {
            // вызываем хандлер другого плагина
            
            if(func_id > -1)
            {
                if(callfunc_begin_i(func_id,plugin_id))
                {
                    callfunc_push_int(id)
                    callfunc_push_int(position)
                    callfunc_end()
                }
            }
            
            return true
        }
    }
    // кеширование
    
    // строим новый запрос
    new query[QUERY_LENGTH]
    
    if(params == 5)
    {
        DB_QueryBuildGetstats(query,charsmax(query),.index = start_index,.index_count = top,.overide_order = get_param(5))
    }
    else
    {
        DB_QueryBuildGetstats(query,charsmax(query),.index = start_index,.index_count = top)
    }
    
    new sql_data[6]
    
    sql_data[0] = SQL_GETSTATS
    sql_data[1] = id
    sql_data[2] = plugin_id
    sql_data[3] = func_id
    sql_data[4] = position
    sql_data[5] = start_index
    
    SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
    
    return true
}

/*
* обновляем кеш для get_stats
*/
Cache_Stats_Update()
{
    if(!stats_cache_trie)
        return false
    
    TrieClear(stats_cache_trie)
    
    return true
}

/*
* обработка ответов на SQL запросы
*/
public SQL_Handler(failstate,Handle:sqlQue,err[],errNum,data[],dataSize){
    // есть ошибки
    switch(failstate)
    {
        case TQUERY_CONNECT_FAILED:  // ошибка соединения с mysql сервером
        {
            log_amx("SQL connection failed")
            log_amx("[ %d ] %s",errNum,err)
            
            return PLUGIN_HANDLED
        }
        case TQUERY_QUERY_FAILED:  // ошибка SQL запроса
        {
            new lastQue[QUERY_LENGTH]
            SQL_GetQueryString(sqlQue,lastQue,charsmax(lastQue)) // узнаем последний SQL запрос
            
            log_amx("SQL query failed")
            log_amx("[ %d ] %s",errNum,err)
            log_amx("[ SQL ] %s",lastQue)
            
            return PLUGIN_HANDLED
        }
    }
    
    switch(data[0])
    {
        case SQL_INITDB:
        {
            DB_InitSeq()
        }
        case SQL_LOAD: // загрзука статистики игрока
        {
            new id = data[1]
        
            if(!is_user_connected(id))
            {
                return PLUGIN_HANDLED
            }
            
            if(SQL_NumResults(sqlQue)) // считываем статистику
            {
                player_data[id][PLAYER_LOADSTATE] = LOAD_OK
                player_data[id][PLAYER_ID] = SQL_ReadResult(sqlQue,ROW_ID)
                
                // общая статистика
                player_data[id][PLAYER_STATS][STATS_KILLS] = SQL_ReadResult(sqlQue,ROW_KILLS)
                player_data[id][PLAYER_STATS][STATS_DEATHS] = SQL_ReadResult(sqlQue,ROW_DEATHS)
                player_data[id][PLAYER_STATS][STATS_HS] = SQL_ReadResult(sqlQue,ROW_HS)
                player_data[id][PLAYER_STATS][STATS_TK] = SQL_ReadResult(sqlQue,ROW_TKS)
                player_data[id][PLAYER_STATS][STATS_SHOTS] = SQL_ReadResult(sqlQue,ROW_SHOTS)
                player_data[id][PLAYER_STATS][STATS_HITS] = SQL_ReadResult(sqlQue,ROW_HITS)
                player_data[id][PLAYER_STATS][STATS_DMG] = SQL_ReadResult(sqlQue,ROW_DMG)
                
                // статистика cstrike
                player_data[id][PLAYER_STATS2][STATS2_DEFAT] = SQL_ReadResult(sqlQue,ROW_BOMBDEF)
                player_data[id][PLAYER_STATS2][STATS2_DEFOK] = SQL_ReadResult(sqlQue,ROW_BOMBDEFUSED)
                player_data[id][PLAYER_STATS2][STATS2_PLAAT] = SQL_ReadResult(sqlQue,ROW_BOMBPLANTS)
                player_data[id][PLAYER_STATS2][STATS2_PLAOK] = SQL_ReadResult(sqlQue,ROW_BOMBEXPLOSIONS)
                
                // время онлайн
                player_data[id][PLAYER_ONLINE] = player_data[id][PLAYER_ONLINELAST] = SQL_ReadResult(sqlQue,ROW_ONLINETIME)
                
                // скилл
                SQL_ReadResult(sqlQue,ROW_SKILL,player_data[id][PLAYER_SKILL])
                player_data[id][PLAYER_SKILLLAST] = _:player_data[id][PLAYER_SKILL]
                
                // посл подключение и первое подкчлючение
                new date_str[32]
                
                SQL_ReadResult(sqlQue,ROW_FIRSTJOIN,date_str,charsmax(date_str))
                player_data[id][PLAYER_FIRSTJOIN] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
                SQL_ReadResult(sqlQue,ROW_LASTJOIN,date_str,charsmax(date_str))
                player_data[id][PLAYER_LASTJOIN] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
                
                // доп. запросы
                player_data[id][PLAYER_RANK] = SQL_ReadResult(sqlQue,row_ids)    // ранк игрока
                statsnum = SQL_ReadResult(sqlQue,row_ids + 1)            // общее кол-во игроков в БД
                
                // статистика попаданий
                for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
                {
                    player_data[id][PLAYER_HITS][i] = SQL_ReadResult(sqlQue,ROW_H0 + i)
                }
                
                // 0.7
                for(new i = STATS3_CONNECT ; i < sizeof player_data[][PLAYER_STATS3] ; i++)
                {
                    player_data[id][PLAYER_STATS3][i] = player_data[id][PLAYER_STATS3LAST][i] = SQL_ReadResult(sqlQue,(i - 1) + ROW_CONNECTS)
                    
                    // плюсуем стату подключений
                    if(i == STATS3_CONNECT)
                    {
                        player_data[id][PLAYER_STATS3][i] ++
                    }
                }
                
                if(weapon_stats_enabled)
                {
                    DB_LoadPlayerWstats(id)
                }
            }
            else // помечаем как нового игрока
            {
                player_data[id][PLAYER_LOADSTATE] = LOAD_NEW
                
                DB_SavePlayerData(id) // добавляем запись в базу данных
            }
        }
        case SQL_INSERT:    // запись новых данных
        {
            new id = data[1]
            
            if(is_user_connected(id))
            {
                if(player_data[id][PLAYER_LOADSTATE] == LOAD_UPDATE)
                {
                    player_data[id][PLAYER_LOADSTATE] = LOAD_NO
                    DB_LoadPlayerData(id)
                    
                    return PLUGIN_HANDLED
                }
                
                player_data[id][PLAYER_ID] = SQL_GetInsertId(sqlQue)    // первичный ключ
                player_data[id][PLAYER_LOADSTATE] = LOAD_OK        // данные загружены
                
                // я упрлся 0)0)0
                
                // обновляем счетчик общего кол-ва записей
                statsnum++
                
                if(weapon_stats_enabled)
                {
                    DB_LoadPlayerWstats(id)
                }
            }
            
            // обновляем позици игроков
            // действие с задержкой, что-бы учесть изменения при множественном обновлении данных
            if(!task_exists(task_rankupdate))
            {
                set_task(1.0,"DB_GetPlayerRanks",task_rankupdate)
            }
        }
        case SQL_UPDATE: // обновление данных
        {
            // обновляем позици игроков
            // действие с задержкой, что-бы учесть изменения при множественном обновлении данных
            if(!task_exists(task_rankupdate))
            {
                set_task(0.1,"DB_GetPlayerRanks",task_rankupdate)
            }
            
            new players[MAX_PLAYERS],pnum
            get_players(players,pnum)
            
            for(new i,player ; i < pnum ; i++)
            {
                player = players[i]
                
                if(player_data[player][PLAYER_LOADSTATE] == LOAD_UPDATE)
                {
                    player_data[player][PLAYER_LOADSTATE] = LOAD_NO
                    DB_LoadPlayerData(player)
                }
            }
            
            if(update_cache)
            {
                update_cache = false
                
                Cache_Stats_Update()
                Cache_Stats_UpdateQueue()
            }
        }
        case SQL_UPDATERANK:
        {
            while(SQL_MoreResults(sqlQue))
            {
                new pK =  SQL_ReadResult(sqlQue,0)
                new rank = SQL_ReadResult(sqlQue,1)
                
                for(new i ; i < MAX_PLAYERS ; i++)
                {
                    if(player_data[i][PLAYER_ID] == pK)    // задаем ранк по первичному ключу
                    {
                        player_data[i][PLAYER_RANK] = rank
                    }
                }
                
                SQL_NextRow(sqlQue)
            }
        }
        case SQL_GETSTATS: // потоковый get_stats
        {
            new id = data[1]
            
            if(id && !is_user_connected(id))
            {
                return PLUGIN_HANDLED
            }
            
            new index = data[5]
            new name[32],authid[30]
            
            // кешируем ответ
            while(DB_ReadGetStats(sqlQue,name,charsmax(name),authid,charsmax(authid),.index = index ++))
            {
            }
            
            if(data[3] > -1)
            {
                // вызываем хандлер другого плагина
                if(callfunc_begin_i(data[3],data[2]))
                {
                    callfunc_push_int(id)
                    callfunc_push_int(data[4])
                    callfunc_end()
                }
            }
        }
        
        // 0.7
        case SQL_GETWSTATS:
        {
            new id = data[1]
            
            if(!is_user_connected(id))
            {
                return PLUGIN_HANDLED
            }
            
            const load_index = sizeof player_awstats[][] - 1
            
            // загружаем статистику по оружию
            while(SQL_MoreResults(sqlQue))
            {
                new log[MAX_NAME_LENGTH]
                SQL_ReadResult(sqlQue,ROW_WEAPON_NAME,log,charsmax(log))
                
                new wpn = Info_Weapon_GetId(log)
                
                if(wpn == -1)
                {
                    continue
                }
                
                for(new i ; i < STATS_END + HIT_END ; i++)
                {
                    player_awstats[id][wpn][i] = SQL_ReadResult(sqlQue,i + ROW_WEAPON_KILLS)
                }
                
                player_awstats[id][wpn][load_index] = _:LOAD_OK
                    
                SQL_NextRow(sqlQue)
            }
            
            // помечаем статистику по другим оружиям как новую
            for(new wpn ; wpn < MAX_WEAPONS ; wpn++)
            {
                if(_:player_awstats[id][wpn][load_index] != _:LOAD_OK)
                {
                    player_awstats[id][wpn][load_index] = _:LOAD_NEW
                }
            }
        }
        case SQL_GETSESSID:
        {
            session_id = SQL_ReadResult(sqlQue,0) + 1
            get_mapname(session_map,charsmax(session_map))
            
            DB_InitSeq()
        }
        // get_sestats_thread_sql
        case SQL_GETSESTATS:
        {
            new Array:sestats_array = ArrayCreate(sestats_array_struct)
            new sestats_data[sestats_array_struct]
            
            while(SQL_MoreResults(sqlQue))
            {
                arrayset(sestats_data,0,sestats_array_struct)
                
                // заполняем массив со статой сессии
                for(new i = ROW_MAP_ID ; i <= ROW_MAP_LASTJOIN ; i++)
                {
                    switch(i)
                    {
                        case ROW_MAP_ID: sestats_data[SESTATS_ID] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_PLRID: sestats_data[SESTATS_PLAYERID] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_MAP: SQL_ReadResult(sqlQue,i,sestats_data[SESTATS_MAP],charsmax(sestats_data[SESTATS_MAP]))
                        case ROW_MAP_SKILL: SQL_ReadResult(sqlQue,i,sestats_data[SESTATS_SKILL])
                        case ROW_MAP_KILLS..ROW_MAP_DMG: sestats_data[SESTATS_STATS][(i - ROW_MAP_KILLS)] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_H0..ROW_MAP_H7: sestats_data[SESTATS_HITS][(i - ROW_MAP_H0)] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_BOMBDEF..ROW_MAP_BOMBEXPLOSIONS: sestats_data[SESTATS_STATS2][(i - ROW_MAP_BOMBDEF)] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_ROUNDT..ROW_MAP_ASSISTS: sestats_data[SESTATS_STATS3][((i - ROW_MAP_ROUNDT) + 1)] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_ONLINETIME: sestats_data[SESTATS_ONLINETIME] = SQL_ReadResult(sqlQue,i)
                        case ROW_MAP_FIRSTJOIN,ROW_LASTJOIN:
                        {
                            new date_str[32]
                            SQL_ReadResult(sqlQue,i,date_str,charsmax(date_str))
                            
                            sestats_data[(SESTATS_FIRSTJOIN + (i - ROW_MAP_FIRSTJOIN))] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
                        }
                    }
                }
                
                ArrayPushArray(sestats_array,sestats_data)
                
                SQL_NextRow(sqlQue)
            }
            
            new func_id = data[1]
            new plugin_id = data[2]
            
            if(callfunc_begin_i(func_id,plugin_id))
            {
                callfunc_push_int(int:sestats_array)
                
                // передаваемые данные
                if(dataSize > 3)
                {
                    new cb_data[MAX_DATA_PARAMS]
                    
                    for(new i ; i < (dataSize - 3) ; i++)
                    {
                        cb_data[i] = data[(3 + i)]
                    }
                    
                    callfunc_push_array(cb_data,(dataSize - 3))
                    callfunc_push_int((dataSize - 3))
                }
                
                callfunc_end()
            }
            else
            {
                log_amx("get_sestats_thread_sql callback function failed")
            }
        }
        case SQL_AUTOCLEAR:
        {
            if(SQL_AffectedRows(sqlQue))
            {
                log_amx("deleted %d inactive entries",
                    SQL_AffectedRows(sqlQue)
                )
            }
            
            DB_InitSeq()
        }
    }

    return PLUGIN_HANDLED
}

//
// Поиск ID оружия по его лог коду
//
Info_Weapon_GetId(weapon[])
{
    new weapon_info[WEAPON_INFO_SIZE]
    new length = ArraySize(weapons_data)
    
    for(new i ; i < length; i++)
    {
        ArrayGetArray(weapons_data,i,weapon_info)
        
        new weapon_name[MAX_NAME_LENGTH]
        copy(weapon_name,charsmax(weapon_name),weapon_info[MAX_NAME_LENGTH])
        
        if(strcmp(weapon_name,weapon) == 0)
        {
            return i
        }
    }
    
    return -1
}

//
// Поиск лог кода по ID оружия
//
Info_Weapon_GetLog(wpn_id,weapon_name[],len)
{
    if(!(0 < wpn_id < ArraySize(weapons_data)))
    {
        formatex(weapon_name,len,"")
        return
    }
    
    new weapon_info[WEAPON_INFO_SIZE]
    ArrayGetArray(weapons_data,wpn_id,weapon_info)
    
    copy(weapon_name,len,weapon_info[MAX_NAME_LENGTH])
}

/*
*
* API
*
*/

#define CHECK_PLAYER(%1) \
    if (%1 < 1 || %1 > MaxClients) { \
        log_error(AMX_ERR_NATIVE, "Player out of range (%d)", %1); \
        return 0; \
    } else { \
        if (!is_user_connected(%1) || pev_valid(%1) != 2) { \
            log_error(AMX_ERR_NATIVE, "Invalid player %d", %1); \
            return 0; \
        } \
    }
    
#define CHECK_PLAYERRANGE(%1) \
    if(%1 < 0 || %1 > MaxClients) {\
        log_error(AMX_ERR_NATIVE,"Player out of range (%d)",%1);\
        return 0;\
    }
    
#define CHECK_WEAPON(%1) \
    if(!(0 <= %1 < ArraySize(weapons_data))){\
        log_error(AMX_ERR_NATIVE,"Invalid weapon id %d",%1);\
        return 0;\
    }
    
public plugin_natives()
{
    // default csstats
    register_library("xstats")
    
    register_native("get_user_wstats","native_get_user_wstats")
    register_native("get_user_wrstats","native_get_user_wrstats")
    register_native("get_user_stats","native_get_user_stats")
    register_native("get_user_rstats","native_get_user_rstats")
    register_native("get_user_vstats","native_get_user_vstats")
    register_native("get_user_astats","native_get_user_astats")
    register_native("reset_user_wstats","native_reset_user_wstats")
    register_native("get_stats","native_get_stats")
    register_native("get_statsnum","native_get_statsnum")
    register_native("get_user_stats2","native_get_user_stats2")
    register_native("get_stats2","native_get_stats2")
    
    register_native("xmod_is_melee_wpn","native_xmod_is_melee_wpn")
    register_native("xmod_get_wpnname","native_xmod_get_wpnname")
    register_native("xmod_get_wpnlogname","native_xmod_get_wpnlogname")
    register_native("xmod_get_maxweapons","native_xmod_get_maxweapons")
    register_native("xmod_get_stats_size","native_get_statsnum")
    register_native("get_map_objectives","native_get_map_objectives")
    
    register_native("custom_weapon_add","native_custom_weapon_add")
    register_native("custom_weapon_dmg","native_custom_weapon_dmg")
    register_native("custom_weapon_shot","native_custom_weapon_shot")
    
    register_library("csstatsx_sql")
    
    // csstats mysql
    register_native("get_statsnum_sql","native_get_statsnum")
    register_native("get_user_stats_sql","native_get_user_stats")
    register_native("get_stats_sql","native_get_stats")
    register_native("get_stats_sql_thread","native_get_stats_thread")
    register_native("get_stats2_sql","native_get_stats2")
    register_native("get_user_skill","native_get_user_skill")
    register_native("get_skill","native_get_skill")
    
    // 0.5.1
    register_native("get_user_gametime","native_get_user_gametime")
    register_native("get_stats_gametime","native_get_stats_gametime")
    register_native("get_user_stats_id","native_get_user_stats_id")
    register_native("get_stats_id","native_get_stats_id")
    register_native("update_stats_cache","native_update_stats_cache")
    
    // 0.7
    register_native("get_user_stats3_sql","native_get_user_stats3")
    register_native("get_stats3_sql","native_get_stats3")
    register_native("get_user_wstats_sql","native_get_user_wstats_sql")
    register_native("get_sestats_thread_sql","native_get_sestats_thread_sql")
    register_native("get_sestats_read_count","native_get_sestats_read_count")
    register_native("get_sestats_read_stats","native_get_sestats_read_stats")
    register_native("get_sestats_read_stats2","native_get_sestats_read_stats2")
    register_native("get_sestats_read_stats3","native_get_sestats_read_stats3")
    register_native("get_sestats_read_online","native_get_sestats_read_online")
    register_native("get_sestats_read_skill","native_get_sestats_read_skill")
    register_native("get_sestats_read_map","native_get_sestats_read_map")
    register_native("get_sestats_read_stime","native_get_sestats_read_stime")
    register_native("get_sestats_read_etime","native_get_sestats_read_etime")
    register_native("get_sestats_free","native_get_sestats_free")
    register_native("get_user_firstjoin_sql","native_get_user_firstjoin_sql")
    register_native("get_user_lastjoin_sql","native_get_user_lastjoin_sql")
    
    // 0.7.2
    register_native("xmod_get_maxweapons_sql","native_xmod_get_maxweapons")
+    register_native("stats_set_enabled", "native_enabled", 0);
}

+public native_enabled(plugin_id, params_num)
+{
+    gSaveStats = bool:get_param(1)
+}

public native_get_user_firstjoin_sql(plugin_id,params)
{
    new id = get_param(1)
    CHECK_PLAYERRANGE(id)
    
    if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
    {
        return -1
    }
    
    return player_data[id][PLAYER_FIRSTJOIN]
}

public native_get_user_lastjoin_sql(plugin_id,params)
{
    new id = get_param(1)
    CHECK_PLAYERRANGE(id)
    
    if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
    {
        return -1
    }
    
    return player_data[id][PLAYER_LASTJOIN]
}

public native_get_sestats_read_stime(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    return sestats_data[SESTATS_FIRSTJOIN]
}

public native_get_sestats_read_etime(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    return sestats_data[SESTATS_LASTJOIN]
}

public native_get_sestats_free(plugin_id,params)
{
    new sestats = get_param_byref(1)
    ArrayDestroy(Array:sestats)
    set_param_byref(1,0)
    return true
}

public native_get_sestats_read_map(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    new length = get_param(4)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    return set_string(3,sestats_data[SESTATS_MAP],length)
}

public Float:native_get_sestats_read_skill(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0.0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    return sestats_data[SESTATS_SKILL]
}

public native_get_sestats_read_online(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    return sestats_data[SESTATS_ONLINETIME]
}

public native_get_sestats_read_stats(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    set_array(3,sestats_data[SESTATS_STATS],8)
    set_array(4,sestats_data[SESTATS_HITS],8)
    
    index ++
    
    return (index >= sestats_size) ? 0 : index
}

public native_get_sestats_read_stats2(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 <= index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    set_array(3,sestats_data[SESTATS_STATS2],4)
    
    index ++
    
    return (index >= sestats_size) ? 0 : index
}

public native_get_sestats_read_stats3(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    new index = get_param(2)
    
    new sestats_size = ArraySize(sestats)
    
    if(!(0 < index < sestats_size))
    {
        log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
        return 0
    }
    
    new sestats_data[sestats_array_struct]
    ArrayGetArray(sestats,index,sestats_data)
    
    set_array(3,sestats_data[SESTATS_STATS3],STATS3_END)
    
    index ++
    
    return (index >= sestats_size) ? 0 : index
}

public native_get_sestats_read_count(plugin_id,params)
{
    new Array:sestats = Array:get_param(1)
    
    return ArraySize(sestats)
}

public native_get_sestats_thread_sql(plugin_id,params)
{
    // статистика по картам выключена
    if(session_id == 0)
    {
        return false
    }
    
    new callback_func[32]
    get_string(2,callback_func,charsmax(callback_func))
    
    new func_id = get_func_id(callback_func,plugin_id)
    
    // функция ответа не найдена
    if(func_id == -1)
    {
        log_error(AMX_ERR_NATIVE,"Callback function ^"%s^" not found",callback_func)
        return false
    }
    
    new data_size = get_param(4)
    
    if(data_size > MAX_DATA_PARAMS)
    {
        log_error(AMX_ERR_NATIVE,"Max data size %d reached.",MAX_DATA_PARAMS)
        return false
    }
    
    // подготавливаем данные
    new sql_data[3 + MAX_DATA_PARAMS],data_array[MAX_DATA_PARAMS]
    
    sql_data[0] = SQL_GETSESTATS
    sql_data[1] = func_id
    sql_data[2] = plugin_id
    
    // передаваемые данные
    if(data_size)
    {
        get_array(3,data_array,data_size)
        
        for(new i ; i < data_size ; i++)
        {
            sql_data[i + 3] = data_array[i]
        }
    }
    
    new player_db_id = get_param(1)    // ищем по ID игрока
    new limit = get_param(5)        // лимит на выборку
    
    new query[QUERY_LENGTH]
    
    formatex(query,charsmax(query),"SELECT * FROM `%s_maps` WHERE `%s` = '%d' ORDER BY `%s` DESC LIMIT %d",
        tbl_name,
        row_weapons_names[ROW_WEAPON_PLAYER],player_db_id,
        row_names[ROW_FIRSTJOIN],limit
    )
    SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,3 + data_size)
    
    return true
}

public native_get_user_wstats_sql(plugin_id,params)
{
    if(params != 4)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
        
        return false
    }
    
    if(!weapon_stats_enabled)
    {
        return -1
    }
    
    new player_id = get_param(1)
    CHECK_PLAYERRANGE(player_id)
    
    new weapon_id = get_param(2)
    CHECK_WEAPON(weapon_id)
    
    new stats[8],bh[8]
    
    const stats_index_last = (STATS_END + HIT_END)
    
    for(new i ; i < STATS_END ; i++)
    {
        stats[i] = player_awstats[player_id][weapon_id][i] + player_awstats[player_id][weapon_id][i + stats_index_last]
    }
    
    // игрок не пользовался этим оружием
    if(!stats[STATS_DEATHS] &&  !stats[STATS_SHOTS])
    {
        return false
    }
    
    for(new i = STATS_END ; i < (STATS_END + HIT_END) ; i ++)
    {
        bh[(i - STATS_END)] = player_awstats[player_id][weapon_id][i] + player_awstats[player_id][weapon_id][i + stats_index_last]
    }
    
    set_array(3,stats,sizeof stats)
    set_array(4,bh,sizeof bh)
    
    return true
}

public native_update_stats_cache()
{
    return Cache_Stats_Update()
}

/*
* Функция возвращает онлайн время игрока
*
* native get_user_gametime(id)
*/
public native_get_user_gametime(plugin_id,params)
{
    new id = get_param(1)
    CHECK_PLAYERRANGE(id)
    
    if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
    {
        return -1
    }
    
    return player_data[id][PLAYER_ONLINE]
}

/*
* Получение времени по позиции
*
* native get_stats_gametime(index,&game_time)
*/
public native_get_stats_gametime(plugin_id,params)
{
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_param_byref(2,stats_cache[CACHE_TIME])
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    return 0
}


/*
* Функция возрващает ID игрока в БД
*
* native get_user_stats_id(id)
*/
public native_get_user_stats_id(plugin_id,params)
{
    new id = get_param(1)
    CHECK_PLAYERRANGE(id)
    
    return player_data[id][PLAYER_ID]
}

/*
* Получение ID по позиции
*
* native get_stats_id(index,&db_id)
*/
public native_get_stats_id(plugin_id,params)
{
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_param_byref(2,stats_cache[CACHE_ID])
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    return 0
}

/*
* Функция возрващает скилл игрока
*
* native get_user_skill(player,&Float:skill)
*/
public native_get_user_skill(plugin_id,params)
{
    new id = get_param(1)
    CHECK_PLAYERRANGE(id)
    
    set_float_byref(2,player_data[id][PLAYER_SKILL])
    
    return true
}


/*
* Получение скилла по позиции
*
* native get_skill(index,&Float:skill)
*/
public native_get_skill(plugin_id,params)
{
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    
    if(index < 0)
        index = 0
    
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_float_byref(2,Float:stats_cache[CACHE_SKILL])
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    return 0
}

/*
* Добавление кастомного оружия для статистики
*
* native custom_weapon_add(const wpnname[], melee = 0, const logname[] = "")
*/
public native_custom_weapon_add(plugin_id,params)
{
    if(ArraySize(weapons_data) >= MAX_WEAPONS)
    {
        return 0
    }
    
    new weapon_name[MAX_NAME_LENGTH],weapon_log[MAX_NAME_LENGTH],is_melee
    get_string(1,weapon_name,charsmax(weapon_name))
    
    if(params >= 2) // задан флаг is_melee
        is_melee = get_param(2)
        
    if(params == 3) // указан лог код
    {
        get_string(3,weapon_log,charsmax(weapon_log))
    }
    else // копируем название оружия для лог кода
    {
        copy(weapon_log,charsmax(weapon_log),weapon_name)
    }
    
    // регистриурем
    new weapon_info[WEAPON_INFO_SIZE]
    REG_INFO(is_melee,weapon_name,weapon_info)
    
    return ArraySize(weapons_data) - 1
}

/*
* Учет урона кастомного оружия
*
* native custom_weapon_dmg(weapon, att, vic, damage, hitplace = 0)
*/
public native_custom_weapon_dmg(plugin_id,params)
{
    new weapon_id = get_param(1)
    
    CHECK_WEAPON(weapon_id)
    
    new att = get_param(2)
    
    CHECK_PLAYERRANGE(att)
    
    new vic = get_param(3)
    
    CHECK_PLAYERRANGE(vic)
    
    new dmg = get_param(4)
    
    if(dmg < 1)
    {
        log_error(AMX_ERR_NATIVE,"Invalid damage %d", dmg)
        
        return 0
    }
    
    new hit_place = get_param(5)
    
    return Stats_SaveHit(att,vic,dmg,weapon_id,hit_place)
}

/*
* Регистрация выстрела кастомного оружия
*
* native custom_weapon_shot(weapon, index)
*/
public native_custom_weapon_shot(plugin_id,params)
{
    new weapon_id = get_param(1)
    
    CHECK_WEAPON(weapon_id)
    
    new id = get_param(2)
    
    CHECK_PLAYERRANGE(id)
    
    return Stats_SaveShot(id,weapon_id)
}

/*
* Возвращает true, если оружие рукопашного боя
*
* native xmod_is_melee_wpn(wpnindex)
*/
public native_xmod_is_melee_wpn(plugin_id,params)
{
    new wpn_id = get_param(1)
    
    CHECK_WEAPON(wpn_id)
    
    new weapon_info[WEAPON_INFO_SIZE]
    ArrayGetArray(weapons_data,wpn_id,weapon_info)
    
    return weapon_info[0]
}

/*
* Получение полного названия оружия
*
* native xmod_get_wpnname(wpnindex, name[], len)
*/
public native_xmod_get_wpnname(plugin_id,params)
{
    new wpn_id = get_param(1)
    
    CHECK_WEAPON(wpn_id)
    
    new weapon_info[WEAPON_INFO_SIZE]
    ArrayGetArray(weapons_data,wpn_id,weapon_info)
    
    new weapon_name[MAX_NAME_LENGTH]
    copy(weapon_name,charsmax(weapon_name),weapon_info[1])
    
    set_string(2,weapon_name,get_param(3))
    
    return strlen(weapon_name)
}

/*
* Получение лог кода для оружия
*
* native xmod_get_wpnlogname(wpnindex, name[], len)
*/
public native_xmod_get_wpnlogname(plugin_id,params)
{
    new wpn_id = get_param(1)
    CHECK_WEAPON(wpn_id)
    
    new weapon_name[MAX_NAME_LENGTH]
    Info_Weapon_GetLog(wpn_id,weapon_name,get_param(3))
    
    set_string(2,weapon_name,get_param(3))
    
    return strlen(weapon_name)
}

/*
* Возврашение общего количества оружия для статистики
*
* native xmod_get_maxweapons()
*/
public native_xmod_get_maxweapons(plugin_id,params)
{
    return ArraySize(weapons_data)
}

public native_get_map_objectives(plugin_id,params)
{
    return false
}

/*
* Статистика за текущую сессию
*
* native get_user_wstats(index, wpnindex, stats[8], bodyhits[8])
*/
public native_get_user_wstats(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    new wpn_id = get_param(2)
    
    CHECK_WEAPON(wpn_id)
    
    new stats[8],bh[8]
    get_user_wstats(id,wpn_id,stats,bh)
    
    set_array(3,stats,STATS_END)
    set_array(4,bh,HIT_END)
    
    return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
}

/*
* Статистика за текущий раунд
*
* native get_user_wrstats(index, wpnindex, stats[8], bodyhits[8])
*/
public native_get_user_wrstats(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    new wpn_id = get_param(2)
    
    CHECK_WEAPON(wpn_id)
    
    if(wpn_id != 0 && !(0 < wpn_id < MAX_WEAPONS))
    {
        log_error(AMX_ERR_NATIVE,"Weapon index out of bounds (%d)",id)
        
        return false
    }
    
    new stats[8],bh[8]
    get_user_wrstats(id,wpn_id,stats,bh)
    
    set_array(3,stats,STATS_END)
    set_array(4,bh,HIT_END)
    
    return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
}


/*
* Получение статистики игрока
*
* native get_user_stats(index, stats[8], bodyhits[8])
*/
public native_get_user_stats(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // данные отсутствуют
    {
        return 0
    }
    
    set_array(2,player_data[id][PLAYER_STATS],8)
    set_array(3,player_data[id][PLAYER_HITS],8)
    
    return player_data[id][PLAYER_RANK]
}

/*
* Статистика за текущий раунд
*
* native get_user_rstats(index, stats[8], bodyhits[8])
*/
public native_get_user_rstats(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    new stats[8],bh[8]
    get_user_rstats(id,stats,bh)
    
    set_array(2,stats,STATS_END)
    set_array(3,bh,HIT_END)
    
    return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
}
/*
* Статистика по жертвам
*
* native get_user_vstats(index, victim, stats[8], bodyhits[8], wpnname[] = "", len = 0);
*/
public native_get_user_vstats(plugin_id,params)
{
    if(params != 6)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 6, passed %d",params)
        
        return false
    }
    
    new id = get_param(1)
    new victim = get_param(2)
    
    CHECK_PLAYERRANGE(id)
    CHECK_PLAYERRANGE(victim)
    
    new stats[STATS_END],hits[HIT_END],wname[MAX_NAME_LENGTH]
    unpack_vstats(id,victim,stats,hits,wname,charsmax(wname))
    
    set_array(3,stats,STATS_END)
    set_array(4,hits,HIT_END)
    set_string(5,wname,get_param(6))
    
    return (stats[STATS_KILLS] || stats[STATS_HITS])
}


unpack_vstats(killer,victim,stats[STATS_END],hits[HIT_END],vname[],vname_len)
{
    new i,stats_i
    
    for(i = 0; i < STATS_END ; i++,stats_i++)
    {
        stats[i]= player_vstats[killer][victim][stats_i]
    }
    
    for(i = 0; i < HIT_END ; i++,stats_i++)
    {
        hits[i]= player_vstats[killer][victim][stats_i]
    }
    
    copy(vname,vname_len,player_vstats[killer][victim][stats_i])
}

unpack_astats(attacker,victim,stats[STATS_END],hits[HIT_END],vname[],vname_len)
{
    new i,stats_i
    
    for(i = 0; i < STATS_END ; i++,stats_i++)
    {
        stats[i]= player_astats[victim][attacker][stats_i]
    }
    
    for(i = 0; i < HIT_END ; i++,stats_i++)
    {
        hits[i]= player_astats[victim][attacker][stats_i]
    }
    
    copy(vname,vname_len,player_astats[victim][attacker][stats_i])
}

/*
* Статистика по врагам
*
* native get_user_astats(index, victim, stats[8], bodyhits[8], wpnname[] = "", len = 0);
*/
public native_get_user_astats(plugin_id,params)
{
    if(params != 6)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 6, passed %d",params)
        
        return false
    }
    
    new id = get_param(1)
    new attacker = get_param(2)
    
    CHECK_PLAYERRANGE(id)
    CHECK_PLAYERRANGE(attacker)
    
    new stats[STATS_END],hits[HIT_END],wname[MAX_NAME_LENGTH]
    unpack_astats(attacker,id,stats,hits,wname,charsmax(wname))
    
    set_array(3,stats,STATS_END)
    set_array(4,hits,HIT_END)
    set_string(5,wname,get_param(6))
    
    return (stats[STATS_KILLS] || stats[STATS_HITS])
}

public native_reset_user_wstats()
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    return reset_user_wstats(id)
}

/*
* Возвращает общее количество записей в базе данных
*
* native get_statsnum()
*/
public native_get_statsnum(plugin_id,params)
{
    return statsnum
}

/*
* Получение статистик по позиции
*
* native get_stats(index, stats[8], bodyhits[8], name[], len, authid[] = "", authidlen = 0);
*/
public native_get_stats(plugin_id,params)
{
    // ждем начала работы с БД
    if(!is_ready)
    {
        return 0
    }
    
    if(params < 5)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 5, passed %d",params)
        
        return 0
    }
    else if(params > 5 && params != 7)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 7, passed %d",params)
        
        return 0
    }
    
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_array(2,stats_cache[CACHE_STATS],sizeof stats_cache[CACHE_STATS])
        set_array(3,stats_cache[CACHE_HITS],sizeof stats_cache[CACHE_HITS])
        set_string(4,stats_cache[CACHE_NAME],get_param(5))
        
        if(params == 7)
        {
            set_string(6,stats_cache[CACHE_STEAMID],get_param(7))
        }
    
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    /*
    * прямой запрос в БД, в случае если нету данных в кеше
    */
    
    // открываем соединение с БД для получения актуальных данных
    if(!DB_OpenConnection())
    {
        return false    // ошибка открытия соединения
    }
    else
    {
        // задание на сброс содеинения
        // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
        if(!task_exists(task_confin))
        {
            set_task(0.1,"DB_CloseConnection",task_confin)
        }
    }
    
    // подготавливаем запрос в БД
    new query[QUERY_LENGTH]
    DB_QueryBuildGetstats(query,charsmax(query),.index = index)
    new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
    
    // ошибка выполнения запроса
    if(!SQL_Execute(sqlQue))
    {
        new errNum,err[256]
        errNum = SQL_QueryError(sqlQue,err,charsmax(err))
        
        log_amx("SQL query failed")
        log_amx("[ %d ] %s",errNum,err)
        log_amx("[ SQL ] %s",query)
        
        SQL_FreeHandle(sqlQue)
        
        return 0
    }
    
    // читаем результат
    new name[32],steamid[30],stats[8],hits[8],stats_count
        
    DB_ReadGetStats(sqlQue,
        name,charsmax(name),
        steamid,charsmax(steamid),
        stats,
        hits,
        .stats_count = stats_count,
        .index = index
    )
    
    // статистики нет
    if(!stats_count)
    {
        return false
    }
    
    SQL_FreeHandle(sqlQue)
    
    // возвращаем данные натива
    set_array(2,stats,sizeof player_data[][PLAYER_STATS])
    set_array(3,hits,sizeof player_data[][PLAYER_HITS])
    set_string(4,name,get_param(5))
        
    if(params == 7)
    {
        set_string(6,steamid,get_param(7))
    }
    
    return stats_count > 1 ? index + 1 : 0
}

/*
* Получение статистик по позиции
*
* native get_stats2_sql(index, stats[4], authid[] = "", authidlen = 0)
*/
public native_get_stats2(plugin_id,params)
{
    // ждем начала работы с БД
    if(!is_ready)
    {
        return 0
    }
    
    if(params < 2)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 2, passed %d",params)
        
        return false
    }
    else if(params > 2 && params != 4)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
        
        return false
    }
    
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_array(2,stats_cache[CACHE_STATS2],sizeof stats_cache[CACHE_STATS2])
        
        if(params == 4)
        {
            set_string(3,stats_cache[CACHE_STEAMID],get_param(4))
        }
        
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    /*
    * прямой запрос в БД, в случае если нету данных в кеше
    */
    
    // открываем соединение с БД для получения актуальных данных
    if(!DB_OpenConnection())
    {
        return false    // ошибка открытия соединения
    }
    else
    {
        // задание на сброс содеинения
        // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
        if(!task_exists(task_confin))
        {
            set_task(0.1,"DB_CloseConnection",task_confin)
        }
    }
    
    // подготавливаем запрос в БД
    new query[QUERY_LENGTH]
    DB_QueryBuildGetstats(query,charsmax(query),.index = index)
    new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
    
    // ошибка выполнения запроса
    if(!SQL_Execute(sqlQue))
    {
        new errNum,err[256]
        errNum = SQL_QueryError(sqlQue,err,charsmax(err))
        
        log_amx("SQL query failed")
        log_amx("[ %d ] %s",errNum,err)
        log_amx("[ SQL ] %s",query)
        
        SQL_FreeHandle(sqlQue)
        
        return 0
    }
    
    // читаем результат
    new name[32],steamid[30],stats2[4],stats_count
        
    DB_ReadGetStats(sqlQue,
        name,charsmax(name),
        steamid,charsmax(steamid),
        .stats2 = stats2,
        .stats_count = stats_count,
        .index = index
    )
    
    // статистики нет
    if(!stats_count)
    {
        return false
    }
    
    SQL_FreeHandle(sqlQue)
    
    // возвращаем данные натива
    set_array(2,stats2,sizeof player_data[][PLAYER_STATS2])
        
    if(params == 4)
    {
        set_string(3,steamid,get_param(4))
    }
    
    return stats_count > 1 ? index + 1 : 0
}

/*
* Потоковый запрос на получение статистик по позиции
*    id - для кого мы запрашиваем
*    position - позиция
*    top - кол-во
*    callback[] - хандлер ответа
*
* native get_stats_sql_thread(id,position,top,callback[]);
*/
public native_get_stats_thread(plugin_id,params)
{
    // ждем начала работы с БД
    if(!is_ready)
    {
        return false
    }
    
    if(params < 4)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
        
        return false
    }
    
    new id = get_param(1)
    new position = min(statsnum,get_param(2))
    new top = get_param(3)
    new start_index = max((position - top),0)
    
    new callback[20]
    get_string(4,callback,charsmax(callback))
    
    new func_id = get_func_id(callback,plugin_id)
    
    if(func_id == -1)
    {
        log_error(AMX_ERR_NATIVE,"Unable to locate ^"%s^" handler.",callback)
        
        return false
    }
    
    return DB_QueryTop15(id,plugin_id,func_id,position,start_index,top,params)
}

// 0.7
/*
* Получение статистик по позиции
*
* native get_stats3_sql(index, stats3[STATS3_END], authid[] = "", authidlen = 0)
*/
public native_get_stats3(plugin_id,params)
{
    // ждем начала работы с БД
    if(!is_ready)
    {
        return 0
    }
    
    if(params < 2)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 2, passed %d",params)
        
        return false
    }
    else if(params > 2 && params != 4)
    {
        log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
        
        return false
    }
    
    new index = get_param(1)    // индекс в статистике
    
    // кеширование
    new index_str[10],stats_cache[stats_cache_struct]
    num_to_str(index,index_str,charsmax(index_str))
    
    // есть информация в кеше
    if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
    {
        set_array(2,stats_cache[CACHE_STATS3],sizeof stats_cache[CACHE_STATS3])
        
        if(params == 4)
        {
            set_string(3,stats_cache[CACHE_STEAMID],get_param(4))
        }
        
        return !stats_cache[CACHE_LAST] ? index + 1 : 0
    }
    // кеширование
    
    /*
    * прямой запрос в БД, в случае если нету данных в кеше
    */
    
    // открываем соединение с БД для получения актуальных данных
    if(!DB_OpenConnection())
    {
        return false    // ошибка открытия соединения
    }
    else
    {
        // задание на сброс содеинения
        // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
        if(!task_exists(task_confin))
        {
            set_task(0.1,"DB_CloseConnection",task_confin)
        }
    }
    
    // подготавливаем запрос в БД
    new query[QUERY_LENGTH]
    DB_QueryBuildGetstats(query,charsmax(query),.index = index)
    new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
    
    // ошибка выполнения запроса
    if(!SQL_Execute(sqlQue))
    {
        new errNum,err[256]
        errNum = SQL_QueryError(sqlQue,err,charsmax(err))
        
        log_amx("SQL query failed")
        log_amx("[ %d ] %s",errNum,err)
        log_amx("[ SQL ] %s",query)
        
        SQL_FreeHandle(sqlQue)
        
        return 0
    }
    
    // читаем результат
    new name[32],steamid[30],stats3[STATS3_END],stats_count
        
    DB_ReadGetStats(sqlQue,
        name,charsmax(name),
        steamid,charsmax(steamid),
        .stats3 = stats3,
        .stats_count = stats_count,
        .index = index
    )
    
    // статистики нет
    if(!stats_count)
    {
        return false
    }
    
    SQL_FreeHandle(sqlQue)
    
    // возвращаем данные натива
    set_array(2,stats3,sizeof player_data[][PLAYER_STATS3])
        
    if(params == 4)
    {
        set_string(3,steamid,get_param(4))
    }
    
    return stats_count > 1 ? index + 1 : 0
}

/*
* Получение статистик по позиции
*
* native get_user_stats3_sql(id,stats3[STATS3_END])
*/
public native_get_user_stats3(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // данные отсутствуют
    {
        return 0
    }
    
    set_array(2,player_data[id][PLAYER_STATS3],STATS3_END)
    
    return player_data[id][PLAYER_RANK]
}

public native_get_user_stats2(plugin_id,params)
{
    new id = get_param(1)
    
    CHECK_PLAYERRANGE(id)
    
    set_array(2,player_data[id][PLAYER_STATS2],sizeof player_data[][PLAYER_STATS2])
    
    return true
}

/*
*
* ВСЯКАЯ ХРЕНЬ ДЛЯ САМОСТОЯТЕЛЬНОГО ПРОСЧЕТА СТАТИСТИКИ
*
*/

is_tk(killer,victim)
{
    if(killer == victim)
        return true   
    
    return false
}

get_user_wstats(index, wpnindex, stats[8], bh[8])
{
    for(new i ; i < STATS_END ; i++)
    {
        stats[i] = player_wstats[index][wpnindex][i]
    }
    
    #define krisa[%1] player_wstats[index][wpnindex][STATS_END + %1]
    
    for(new i ; i < HIT_END ; i++)
    {
        bh[i] = krisa[i]
    }
}

get_user_wrstats(index, wpnindex, stats[8], bh[8])
{
    for(new i ; i < STATS_END ; i++)
    {
        stats[i] = player_wrstats[index][wpnindex][i]
    }
    
    for(new i ; i < HIT_END ; i++)
    {
        bh[i] = player_wrstats[index][wpnindex][STATS_END + i]
    }
}

get_user_rstats(index, stats[8], bh[8])
{
    for(new i ; i < STATS_END ; i++)
    {
        stats[i] = player_wrstats[index][0][i]
    }
    
    for(new i ; i < HIT_END ; i++)
    {
        bh[i] = player_wrstats[index][0][STATS_END + i]
    }
}

get_user_stats2(index, stats[4])
{
    for(new i ; i < STATS2_END ; i++)
    {
        stats[i] = player_wstats2[index][i]
    }
    
    return true
}

reset_user_wstats(index)
{
    for(new i ; i < MAX_WEAPONS ; i++)
    {
        arrayset(player_wrstats[index][i],0,sizeof player_wrstats[][])
    }
    
    for(new i ; i < MAX_PLAYERS + 1 ;i++)
    {
        arrayset(player_vstats[index][i],0,sizeof player_vstats[][])
        arrayset(player_astats[index][i],0,sizeof player_astats[][])
    }
    
    return true
}

reset_user_allstats(index)
{
    for(new i ; i < MAX_WEAPONS ; i++)
    {
        arrayset(player_wstats[index][i],0,sizeof player_wstats[][])
    }
    
    arrayset(player_wstats2[index],0,sizeof player_wstats2[])
    
    return true
}

public DB_OpenConnection()
{
    if(!is_ready)
    {
        return false
    }
    
    if(sql_con != Empty_Handle)
    {
        return true
    }
    
    new errNum,err[256]
    sql_con = SQL_Connect(sql,errNum,err,charsmax(err))
    
    #if AMXX_VERSION_NUM >= 183
    SQL_SetCharset(sql_con,"utf8")
    #endif
    
    if(errNum)
    {
        log_amx("SQL query failed")
        log_amx("[ %d ] %s",errNum,err)
            
        return false
    }
    
    return true
}

public DB_CloseConnection()
{
    if(sql_con != Empty_Handle)
    {
        SQL_FreeHandle(sql_con)
        sql_con = Empty_Handle
    }
}

/*********    mysql escape functions     ************/
mysql_escape_string(dest[],len)
{
    //copy(dest, len, source);
    replace_all(dest,len,"\\","\\\\");
    replace_all(dest,len,"\0","\\0");
    replace_all(dest,len,"\n","\\n");
    replace_all(dest,len,"\r","\\r");
    replace_all(dest,len,"\x1a","\Z");
    replace_all(dest,len,"'","''");
    replace_all(dest,len,"^"","^"^"");
}
 

GIT

Сообщения
82
Реакции
6
Помог
2 раз(а)
h1k3, Cтату обязательно ставить?
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
GIT, если хочешь, чтобы статистика не велась во время вармапа, то нужен форк CSStatsX SQL by serfreeman1337, либо вручную переписывай под иную статистику. Если плевать на то, что игроки могут набить статистику во время разминки, то ничего не трогай. Все будет нормально работать и не нужно ничего ставить.
 

GIT

Сообщения
82
Реакции
6
Помог
2 раз(а)
Minni, Хорошо я понял и еще вопрос чтобы сделать на ножах, так?
case 2: formatex(g_szWeapon, charsmax(g_szWeapon), "Knife");

case 2:
{
rg_give_item(id, "weapon_knife");
set_entvar(id, var_health, 35.0);
}
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
GIT, да, только еще поправь:

Код:
-switch((g_iWp = random(2)))
+switch((g_iWp = random(3)))
21 Янв 2018
Тут вообще можно вот так сделать:

Код:
rg_remove_all_items(id);
set_member_game(m_bMapHasBuyZone, true);
+rg_give_item(id, "weapon_knife");

switch(g_iWp)
{
    case 0:
    {
        rg_give_item(id, "weapon_m4a1");
        rg_set_user_bpammo(id, WEAPON_M4A1, 90);
-        rg_give_item(id, "weapon_knife");
    }
    case 1:
    {
        rg_give_item(id, "weapon_ak47");
        rg_set_user_bpammo(id, WEAPON_AK47, 90);
-        rg_give_item(id, "weapon_knife");
    }
    case 2:
    {
        set_entvar(id, var_health, 35.0);
    } 
}
 

GIT

Сообщения
82
Реакции
6
Помог
2 раз(а)
Minni, Подскажи, а как броню добавить ?
case 2: formatex(g_szWeapon, charsmax(g_szWeapon), "Ножи"); Прочтет ли так или нужно на английском Knife?
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
Прочтет ли так или нужно на английском Knife?
Это формирование части строки, которая будет показывать игрокам тип запущенной разминки. Можно писать все, что угодно, правда в пределах размера массива.
 
Сообщения
2,143
Реакции
1,225
Помог
44 раз(а)
fantom, можно юзать оба варианта, но твой будет более правильным, т.к. в нем можно указывать количество, а в его варианте - просто выдача итема со стандартным значением (100), как бай в шопе.
 

GIT

Сообщения
82
Реакции
6
Помог
2 раз(а)
h1k3, Есть проблема, карта aim_usp после того как разминка закончилась на ак-47 идет рестарт и после рестарта у кого-то остался калаш, как убрать это?
23 Янв 2018
GIT, zss.PNG
Код:
#include <amxmodx>
#include <reapi>

#define TIME_RR     45    // Время разминки
#define NUM_RR        1    // Кол-во рестартов
#define LATENCY        1.5    // Задержка между рестартами
#define PROTECTED     5    // Сколько секунд действует защита после возрождения, 0 - отключить (актуально для DM_MODE)
// отключаемо //
#define SOUND            // Музыка под час разминки
//#define STOP_PLUGS        // Отключать плагины на время разминки
#define DM_MODE            // Бесконечный респавн на время разминки
//#define OFF_RR            // Отключать этот плагин на указанных картах
#define BLOCK           // Запрет поднятия оружия с земли [по умолчанию выкл.]
#define STOP_STATS      // Отключать запись статистики на время разминки (Работает только с измененным CSStatsX SQL by serfreeman1337) [по умолчанию выкл.]

#if defined SOUND
new const soundRR[] = "sound/rr/RoundStart.mp3"; // Указывать путь и название файла, например sound/serv/music.mp3
#endif
#if defined STOP_STATS
native stats_set_enabled(params_num)
#endif
#if defined STOP_PLUGS
    new g_arPlugins[][] =    // Указывать название плагинов, например test.amxx
    {
        "test.amxx",
        "test2.amxx"
    }
#endif
new g_iHudSync;
new g_szWeapon[32];
new g_iWp;
new HookChain:fwd_NewRound,
    HookChain:fwd_Spawn,
    HookChain:fwd_GiveC4,
#if defined BLOCK
    HookChain:fwd_BlockEntity,
#endif
#if defined DM_MODE
    HookChain:fwd_Killed;
#endif

const TASK_PROTECTION_ID = 33464;

public plugin_init()
{
    register_plugin("[ReAPI] Random Weapons WarmUP", "2.4.4", "neugomon");

    RegisterHookChain(RG_RoundEnd, "fwdRoundEnd", true);
    DisableHookChain(fwd_NewRound = RegisterHookChain(RG_CSGameRules_CheckMapConditions, "fwdRoundStart", true));
    DisableHookChain(fwd_Spawn    = RegisterHookChain(RG_CBasePlayer_Spawn, "fwdPlayerSpawnPost", true));
    DisableHookChain(fwd_GiveC4   = RegisterHookChain(RG_CSGameRules_GiveC4, "fwdGiveC4", false));
#if defined BLOCK
    DisableHookChain(fwd_BlockEntity = RegisterHookChain(RG_CBasePlayer_HasRestrictItem, "fwdHasRestrictItemPre", false));
    register_clcmd("drop", "ClCmd_Drop");
#endif
#if defined DM_MODE
    DisableHookChain(fwd_Killed   = RegisterHookChain(RG_CBasePlayer_Killed, "fwdPlayerKilledPost", true));
    g_iHudSync    = CreateHudSyncObj();
    register_clcmd("joinclass", "clCmdJoinClass");
    register_clcmd("menuselect","clCmdJoinClass");
#endif
    state warmupOff;   
#if defined OFF_RR
    new sPref[][] = { "awp_", "aim_", "fy_", "$", "cs_", "35hp" }; // Указывать префиксы карт
    new map[32]; get_mapname(map, charsmax(map));
    for(new i; i < sizeof sPref; i++)
    {
        if(containi(map, sPref[i]) != -1)
        {
            pause("ad");
            return;
        }
    }   
#endif   
}
#if defined BLOCK
public fwdHasRestrictItemPre() {
    SetHookChainReturn(ATYPE_INTEGER, true);
    return HC_SUPERCEDE;
}

public ClCmd_Drop() <warmupOff>
    return PLUGIN_CONTINUE;
    
public ClCmd_Drop() <warmupOn>
    return PLUGIN_HANDLED;
#endif
public client_putinserver(id)
{
    remove_task(id + TASK_PROTECTION_ID)
}
#if defined SOUND
public plugin_precache()
{
        precache_generic(soundRR);
}
#endif
public fwdRoundEnd(WinStatus:status, ScenarioEventEndRound:event, Float:tmDelay)
    if(event == ROUND_GAME_COMMENCE)
        EnableHookChain(fwd_NewRound);

public fwdRoundStart()
{
    state warmupOn;
    
#if defined SOUND
    client_cmd(0, "mp3 play ^"%s^"", soundRR);
#endif
    
    DisableHookChain(fwd_NewRound);
    EnableHookChain(fwd_Spawn);
    EnableHookChain(fwd_GiveC4);
#if defined STOP_STATS
    stats_set_enabled(0);
#endif
    set_cvar_string("mp_round_infinite", "1");
#if defined BLOCK
    EnableHookChain(fwd_BlockEntity);
#endif
#if defined DM_MODE   
    EnableHookChain(fwd_Killed);
#endif   
#if defined STOP_PLUGS   
    PluginController(1);
#endif
    switch((g_iWp = random(3)))
    {
        case 0: formatex(g_szWeapon, charsmax(g_szWeapon), "M4A1");
        case 1: formatex(g_szWeapon, charsmax(g_szWeapon), "AK-47");
        case 2: formatex(g_szWeapon, charsmax(g_szWeapon), "Ножах");
    }
    set_task(1.0, "ShowTimer", .flags = "a", .repeat = TIME_RR);
}
#if defined DM_MODE
public clCmdJoinClass(id) <warmupOff>
    return;
    
public clCmdJoinClass(id) <warmupOn>
    if(get_member(id, m_iMenu) == Menu_ChooseAppearance)
        set_task(0.5, "SpawnPlayer", id);
#endif
public fwdPlayerSpawnPost(const id)
{
    if(!is_user_alive(id))
        return;

    BuyZone_ToogleSolid(SOLID_NOT);
    SetProtection(id)
    rg_remove_all_items(id);
    set_member_game(m_bMapHasBuyZone, true);
    rg_give_item(id, "weapon_knife");

    switch(g_iWp)
    {
        case 0:
        {
            rg_give_item(id, "weapon_m4a1");
            rg_set_user_bpammo(id, WEAPON_M4A1, 90);
            rg_set_user_armor(id, 100, ARMOR_VESTHELM);
        }
        case 1:
        {
            rg_give_item(id, "weapon_ak47");
            rg_set_user_bpammo(id, WEAPON_AK47, 90);
            rg_set_user_armor(id, 100, ARMOR_VESTHELM);
        }
        case 2:
        {
            set_entvar(id, var_health, 35.0);
            rg_set_user_armor(id, 100, ARMOR_VESTHELM);
        }
    }   
}
#if defined DM_MODE
public fwdPlayerKilledPost(pVictim)
    set_task(1.0, "SpawnPlayer", pVictim);
#endif
public fwdGiveC4()
{
    return HC_SUPERCEDE
}

public ShowTimer()
{
    static timer = -1;
    if(timer == -1) timer = TIME_RR;
    
    switch(--timer)
    {
        case 0:
        {
            state warmupOff;
            
            BuyZone_ToogleSolid(SOLID_TRIGGER);
            DisableHookChain(fwd_Spawn);
            DisableHookChain(fwd_GiveC4);
        #if defined STOP_STATS
            stats_set_enabled(1);
        #endif
            set_cvar_string("mp_round_infinite", "0");
        #if defined BLOCK
            DisableHookChain(fwd_BlockEntity);
        #endif
        #if defined DM_MODE   
            DisableHookChain(fwd_Killed);
        #endif
        #if defined STOP_PLUGS   
            PluginController(0);
        #endif   
        #if NUM_RR > 1       
            set_task(LATENCY, "SV_Restart", .flags = "a", .repeat = NUM_RR);
        #else
            SV_Restart();
        #endif
            timer = -1;
        }
        default:
        {
        #if defined STOP_STATS
            set_hudmessage(255, 0, 0, .x = -1.0, .y = 0.55, .holdtime = 0.9, .channel = -1);
            show_hudmessage(0, "[Статистика Отключена]");
        #endif
            set_hudmessage(135, 206, 235, .x = -1.0, .y = 0.60, .holdtime = 0.9, .channel = -1);
            ShowSyncHudMsg(0, g_iHudSync, "Разминка на %s!^nРестарт через %d сек", g_szWeapon, timer);
        }
    }
}

public SV_Restart()
{
    set_cvar_num("sv_restart", 1);
    set_task(2.0, "End_RR");
}

public End_RR()
{
#if defined STOP_STATS
    set_hudmessage(255, 0, 0, .x = -1.0, .y = 0.55, .holdtime = 5.0, .channel = -1);
    show_hudmessage(0, "[Статистика Включена]");
#endif
    set_hudmessage(135, 206, 235, .x = -1.0, .y = 0.60, .holdtime = 5.0, .channel = -1);
    show_hudmessage(0, "Разминка окончена! Приятной игры!");
}
#if defined DM_MODE   
public SpawnPlayer(id)
{
    if(!is_user_connected(id))
        return;
    if(is_user_alive(id))
        return;
    
    switch(get_member(id, m_iTeam))
    {
        case 1, 2: rg_round_respawn(id);
    }
}
#endif

public SetProtection(id)
{
    set_entvar(id, var_takedamage, DAMAGE_NO)

    switch(get_member(id, m_iTeam))
    {
        case TEAM_TERRORIST: rg_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, 10);
        case TEAM_CT: rg_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, 10);
    }

    remove_task(TASK_PROTECTION_ID + id)
    set_task( PROTECTED.0, "EndProtection", TASK_PROTECTION_ID + id)
}

public EndProtection(TaskID)
{
    new id = TaskID - TASK_PROTECTION_ID

    if(!is_user_connected(id))
        return

    set_entvar(id, var_takedamage, DAMAGE_AIM)
    rg_set_rendering(id)
}

stock rg_set_rendering(index, fx = kRenderFxNone, r=255, g=255, b=255, amount=16)
{
    new Float:RenderColor[3]
    RenderColor[0] = float(r)
    RenderColor[1] = float(g)
    RenderColor[2] = float(b)
    
    set_entvar(index, var_renderfx, fx)
    set_entvar(index, var_rendercolor, RenderColor)
    set_entvar(index, var_renderamt, float(amount))
}

stock PluginController(stop)
{
    for(new i; i < sizeof g_arPlugins; i++)
    {
        if(stop)pause  ("ac", g_arPlugins[i]);
        else    unpause("ac", g_arPlugins[i]);
    }   
}

stock BuyZone_ToogleSolid(const solid)
{
    new entityIndex = 0;
    while ((entityIndex = rg_find_ent_by_class(entityIndex, "func_buyzone")))
        set_entvar(entityIndex, var_solid, solid);
}
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу