SHARE
TWEET

Untitled

a guest Nov 12th, 2017 174 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. *   CSStatsX SQL                v. 0.7.4.2
  3. *   by serfreeman1337            http://1337.uz/
  4. *   by Ge3eR edition 12.11.2017
  5. */
  6.  
  7. #include <amxmodx>
  8. #include <sqlx>
  9.  
  10. #include <fakemeta>
  11. #include <hamsandwich>
  12.  
  13. #define PLUGIN "CSStatsX SQL"
  14. #define VERSION "0.7.5a"
  15. #define AUTHOR "serfreeman1337" // AKA SerSQL1337
  16.  
  17. #define LASTUPDATE "12, November (11), 2017"
  18. //#define LASTUPDATE "06, July (07), 2016"
  19.  
  20. #if AMXX_VERSION_NUM < 183
  21.     #define MAX_PLAYERS 32
  22.     #define MAX_NAME_LENGTH 32
  23.     new MaxClients
  24. #endif
  25.  
  26. /* - SQL - */
  27.  
  28. new Handle:sql
  29. new Handle:sql_con
  30.  
  31. /* -  КОНСТАНТЫ - */
  32.  
  33. enum _:sql_que_type // тип sql запроса
  34. {
  35.     SQL_DUMMY,
  36.     SQL_INITDB, // автоматическое созданием таблиц
  37.     SQL_LOAD,   // загрузка статистики
  38.     SQL_UPDATE, // обновление
  39.     SQL_INSERT, // внесение новой записи
  40.     SQL_UPDATERANK, // получение ранков игроков,
  41.     SQL_GETSTATS,   // потоквый запрос на get_stats
  42.    
  43.     // 0.7
  44.     SQL_GETWSTATS,  // статистика по оружию
  45.     SQL_GETSESSID,  // id сессии статистики за карту
  46.     SQL_GETSESTATS, // статистика по картам
  47.     SQL_AUTOCLEAR   // чистка БД от неактивных записей
  48. }
  49.  
  50. enum _:load_state_type  // состояние получение статистики
  51. {
  52.     LOAD_NO,    // данных нет
  53.     LOAD_WAIT,  // ожидание данных
  54.     LOAD_NEWWAIT,   // новая запись, ждем ответа
  55.     LOAD_UPDATE,    // перезагрузить после обновления
  56.     LOAD_NEW,   // новая запись
  57.     LOAD_OK     // есть данные
  58. }
  59.  
  60. enum _:row_ids      // столбцы таблицы
  61. {
  62.     ROW_ID,
  63.     ROW_STEAMID,
  64.     ROW_NAME,
  65.     ROW_IP,
  66.     ROW_SKILL,
  67.     ROW_KILLS,
  68.     ROW_DEATHS,
  69.     ROW_HS,
  70.     ROW_TKS,
  71.     ROW_SHOTS,
  72.     ROW_HITS,
  73.     ROW_DMG,
  74.     ROW_BOMBDEF,
  75.     ROW_BOMBDEFUSED,
  76.     ROW_BOMBPLANTS,
  77.     ROW_BOMBEXPLOSIONS,
  78.     ROW_H0,
  79.     ROW_H1,
  80.     ROW_H2,
  81.     ROW_H3,
  82.     ROW_H4,
  83.     ROW_H5,
  84.     ROW_H6,
  85.     ROW_H7,
  86.     ROW_ONLINETIME,
  87.    
  88.     // 0.7
  89.     ROW_CONNECTS,
  90.     ROW_ROUNDT,
  91.     ROW_WINT,
  92.     ROW_ROUNDCT,
  93.     ROW_WINCT,
  94.    
  95.     // 0.7.2
  96.     ROW_ASSISTS,
  97.    
  98.     ROW_FIRSTJOIN,
  99.     ROW_LASTJOIN,
  100.    
  101.     // 0.7
  102.     ROW_SESSIONID,
  103.     ROW_SESSIONNAME
  104. }
  105.  
  106. new const row_names[row_ids][] = // имена столбцов
  107. {
  108.     "id",
  109.     "steamid",
  110.     "name",
  111.     "ip",
  112.     "skill",
  113.     "kills",
  114.     "deaths",
  115.     "hs",
  116.     "tks",
  117.     "shots",
  118.     "hits",
  119.     "dmg",
  120.     "bombdef",
  121.     "bombdefused",
  122.     "bombplants",
  123.     "bombexplosions",
  124.     "h_0",
  125.     "h_1",
  126.     "h_2",
  127.     "h_3",
  128.     "h_4",
  129.     "h_5",
  130.     "h_6",
  131.     "h_7",
  132.     "connection_time",
  133.    
  134.     // 0.7
  135.     "connects",
  136.     "roundt",
  137.     "wint",
  138.     "roundct",
  139.     "winct",
  140.    
  141.     // 0.7.2
  142.     "assists",
  143.    
  144.     "first_join",
  145.     "last_join",
  146.    
  147.     // 0.7
  148.     "session_id",
  149.     "session_map"
  150. }
  151.  
  152. enum _:STATS
  153. {
  154.     STATS_KILLS,
  155.     STATS_DEATHS,
  156.     STATS_HS,
  157.     STATS_TK,
  158.     STATS_SHOTS,
  159.     STATS_HITS,
  160.     STATS_DMG,
  161.    
  162.     STATS_END
  163. }
  164.  
  165. enum _:KILL_EVENT
  166. {
  167.     NORMAL,
  168.     SUICIDE,
  169.     WORLD,
  170.     WORLDSPAWN
  171. }
  172.  
  173. const QUERY_LENGTH =    1472    // размер переменной sql запроса
  174.  
  175. #define STATS2_DEFAT    0
  176. #define STATS2_DEFOK    1
  177. #define STATS2_PLAAT    2
  178. #define STATS2_PLAOK    3
  179. #define STATS2_END  4
  180.  
  181. new const task_rankupdate   =   31337
  182. new const task_confin       =   21337
  183. new const task_flush        =   11337
  184.  
  185. #define MAX_CWEAPONS        6
  186. #define MAX_WEAPONS     CSW_P90 + 1 + MAX_CWEAPONS
  187. #define HIT_END         HIT_RIGHTLEG + 1
  188.  
  189. // 0.7
  190.  
  191. enum _:row_weapons_ids      // столбцы таблицы
  192. {
  193.     ROW_WEAPON_ID,
  194.     ROW_WEAPON_PLAYER,
  195.     ROW_WEAPON_NAME,
  196.     ROW_WEAPON_KILLS,
  197.     ROW_WEAPON_DEATHS,
  198.     ROW_WEAPON_HS,
  199.     ROW_WEAPON_TKS,
  200.     ROW_WEAPON_SHOTS,
  201.     ROW_WEAPON_HITS,
  202.     ROW_WEAPON_DMG,
  203.     ROW_WEAPON_H0,
  204.     ROW_WEAPON_H1,
  205.     ROW_WEAPON_H2,
  206.     ROW_WEAPON_H3,
  207.     ROW_WEAPON_H4,
  208.     ROW_WEAPON_H5,
  209.     ROW_WEAPON_H6,
  210.     ROW_WEAPON_H7
  211. }
  212.  
  213. new const row_weapons_names[row_weapons_ids][] = // имена столбцов
  214. {
  215.     "id",
  216.     "player_id",
  217.     "weapon",
  218.     "kills",
  219.     "deaths",
  220.     "hs",
  221.     "tks",
  222.     "shots",
  223.     "hits",
  224.     "dmg",
  225.     "h_0",
  226.     "h_1",
  227.     "h_2",
  228.     "h_3",
  229.     "h_4",
  230.     "h_5",
  231.     "h_6",
  232.     "h_7"
  233. }
  234.  
  235. enum _:row_maps_ids
  236. {
  237.     ROW_MAP_ID,
  238.     ROW_MAP_SESSID,
  239.     ROW_MAP_PLRID,
  240.     ROW_MAP_MAP,
  241.     ROW_MAP_SKILL,
  242.     ROW_MAP_KILLS,
  243.     ROW_MAP_DEATHS,
  244.     ROW_MAP_HS,
  245.     ROW_MAP_TKS,
  246.     ROW_MAP_SHOTS,
  247.     ROW_MAP_HITS,
  248.     ROW_MAP_DMG,
  249.     ROW_MAP_BOMBDEF,
  250.     ROW_MAP_BOMBDEFUSED,
  251.     ROW_MAP_BOMBPLANTS,
  252.     ROW_MAP_BOMBEXPLOSIONS,
  253.     ROW_MAP_H0,
  254.     ROW_MAP_H1,
  255.     ROW_MAP_H2,
  256.     ROW_MAP_H3,
  257.     ROW_MAP_H4,
  258.     ROW_MAP_H5,
  259.     ROW_MAP_H6,
  260.     ROW_MAP_H7,
  261.     ROW_MAP_ONLINETIME,
  262.     ROW_MAP_CONNECTS,
  263.     ROW_MAP_ROUNDT,
  264.     ROW_MAP_WINT,
  265.     ROW_MAP_ROUNDCT,
  266.     ROW_MAP_WINCT,
  267.     ROW_MAP_ASSISTS,
  268.     ROW_MAP_FIRSTJOIN,
  269.     ROW_MAP_LASTJOIN,
  270. }
  271.  
  272. /* - СТРУКТУРА ДАННЫХ - */
  273.  
  274. // 0.7
  275. enum _:STATS3_END
  276. {
  277.     STATS3_CURRENTTEAM, // тек. команда игрока (определяется в начале раунда)
  278.    
  279.     STATS3_CONNECT,     // подключения к серверу
  280.     STATS3_ROUNDT,      // раунды за теров
  281.     STATS3_WINT,        // побед за теров
  282.     STATS3_ROUNDCT,     // раунды за спецов
  283.     STATS3_WINCT,       // побед за спецов
  284.    
  285.     // 0.7.2
  286.     STATS3_ASSIST       // помощь в убийстве
  287. }
  288.  
  289.  
  290. enum _:sestats_array_struct
  291. {
  292.     SESTATS_ID,
  293.     SESTATS_PLAYERID,
  294.     SESTATS_MAP[MAX_NAME_LENGTH],
  295.     SESTATS_STATS[8],
  296.     SESTATS_HITS[8],
  297.     SESTATS_STATS2[4],
  298.     SESTATS_STATS3[STATS3_END],
  299.     Float:SESTATS_SKILL,
  300.     SESTATS_ONLINETIME,
  301.     SESTATS_FIRSTJOIN,
  302.     SESTATS_LASTJOIN
  303. }
  304.  
  305. enum _:player_data_struct
  306. {
  307.     PLAYER_ID,          // ид игрока в базе данных
  308.     PLAYER_LOADSTATE,       // состояние загрузки статистики игрока
  309.     PLAYER_RANK,            // ранк игрока
  310.     PLAYER_STATS[STATS_END],    // статистика игрока
  311.     PLAYER_STATSLAST[STATS_END],    // разница в статистики
  312.     PLAYER_HITS[HIT_END],       // статистика попаданий
  313.     PLAYER_HITSLAST[HIT_END],   // разница в статистике попаданий
  314.     PLAYER_STATS2[4],       // статистика cstrike
  315.     PLAYER_STATS2LAST[4],       // разница
  316.     Float:PLAYER_SKILL,     // скилл
  317.     PLAYER_ONLINE,          // время онлайна
  318.     // я не помню чо за diff и last, но без этого не работает XD
  319.     Float:PLAYER_SKILLLAST,
  320.     PLAYER_ONLINEDIFF,
  321.     PLAYER_ONLINELAST,
  322.    
  323.     PLAYER_NAME[MAX_NAME_LENGTH * 3],
  324.     PLAYER_STEAMID[30],
  325.     PLAYER_IP[16],
  326.    
  327.     // 0.7
  328.     PLAYER_STATS3[STATS3_END]// stast3
  329.     PLAYER_STATS3LAST[STATS3_END]// stast3
  330.     PLAYER_FIRSTJOIN,
  331.     PLAYER_LASTJOIN
  332. }
  333.  
  334. enum _:stats_cache_struct   // кеширование для get_stats
  335. {
  336.     CACHE_NAME[32],
  337.     CACHE_STEAMID[30],
  338.     CACHE_STATS[8],
  339.     CACHE_HITS[8],
  340.     CACHE_SKILL,
  341.     bool:CACHE_LAST,
  342.    
  343.     // 0.5.1
  344.     CACHE_ID,
  345.     CACHE_TIME,
  346.    
  347.     // 0.7
  348.     CACHE_STATS2[4],
  349.     CACHE_STATS3[STATS3_END],
  350.     CACHE_FIRSTJOIN,
  351.     CACHE_LASTJOIN
  352. }
  353.  
  354. enum _:cvar_set
  355. {
  356.     CVAR_SQL_HOST,
  357.     CVAR_SQL_USER,
  358.     CVAR_SQL_PASS,
  359.     CVAR_SQL_DB,
  360.     CVAR_SQL_TABLE,
  361.     CVAR_SQL_TYPE,
  362.     CVAR_SQL_CREATE_DB,
  363.    
  364.     CVAR_UPDATESTYLE,
  365.     CVAR_RANK,
  366.     CVAR_RANKFORMULA,
  367.     CVAR_SKILLFORMULA,
  368.     CVAR_RANKBOTS,
  369.     CVAR_USEFORWARDS,
  370.    
  371.     // 0.7
  372.     CVAR_WEAPONSTATS,
  373.     CVAR_MAPSTATS,
  374.    
  375.     CVAR_AUTOCLEAR,
  376.     CVAR_CACHETIME,
  377.     CVAR_AUTOCLEAR_DAY,
  378.    
  379.     // 0.7.2
  380.     CVAR_ASSISTHP
  381. }
  382.  
  383.  
  384. // 0.7
  385. enum _:stats_cache_queue_struct
  386. {
  387.     CACHE_QUE_START,
  388.     CACHE_QUE_TOP,
  389. }
  390.  
  391. #define MAX_DATA_PARAMS 32
  392.  
  393. /* - ПЕРЕМЕННЫЕ - */
  394.  
  395. // 0.7
  396. new session_id,session_map[MAX_NAME_LENGTH]
  397.  
  398. new player_data[MAX_PLAYERS + 1][player_data_struct]
  399. new flush_que[QUERY_LENGTH * 3],flush_que_len
  400. new statsnum
  401.  
  402. //
  403.  // Общая стата по оружию
  404.  //
  405. // 1ый STATS_END + HIT_END - текущая общая статистика по оружию игрока
  406. // 2ой STATS_END + HIT_END - последнее значение player_wstats, использует для расчета разницы
  407. // последний индекс - определяет INSERT или UPDATE для запроса
  408. //
  409. new player_awstats[MAX_PLAYERS + 1][MAX_WEAPONS][((STATS_END + HIT_END) * 2) + 1]
  410.  
  411. new cvar[cvar_set]
  412.  
  413. new Trie:stats_cache_trie   // дерево кеша для get_stats // ключ - ранг
  414.  
  415. new tbl_name[32]
  416.  
  417. /* - CSSTATS CORE - */
  418.  
  419.  #pragma dynamic 32768
  420.  
  421. // wstats
  422. new player_wstats[MAX_PLAYERS + 1][MAX_WEAPONS][STATS_END + HIT_END]
  423.  
  424. // wstats2
  425. new player_wstats2[MAX_PLAYERS + 1][STATS2_END]
  426.  
  427. // wrstats rstats
  428. new player_wrstats[MAX_PLAYERS + 1][MAX_WEAPONS][STATS_END + HIT_END]
  429.  
  430. // vstats
  431. new player_vstats[MAX_PLAYERS + 1][MAX_PLAYERS + 1][STATS_END + HIT_END + MAX_NAME_LENGTH]
  432.  
  433. // astats
  434. new player_astats[MAX_PLAYERS + 1][MAX_PLAYERS + 1][STATS_END + HIT_END + MAX_NAME_LENGTH]
  435.  
  436. new FW_SQLRead
  437.  
  438. // 0.7.4
  439. new FW_Death
  440. new FW_Damage
  441. new FW_BPlanting
  442. new FW_BPlanted
  443. new FW_BExplode
  444. new FW_BDefusing
  445. new FW_BDefused
  446. new FW_GThrow
  447.  
  448. // 0.7.2
  449. new FW_Assist
  450.  
  451. // 0.7.3
  452. new FW_Initialized
  453.  
  454. new dummy_ret
  455.  
  456. // осталось монитор прихуярить
  457.  
  458. new g_planter
  459. new g_defuser
  460.  
  461. #define WEAPON_INFO_SIZE        1 + (MAX_NAME_LENGTH * 2)
  462.  
  463. new Array:weapons_data          // массив с инфой по оружию
  464. new Trie:log_ids_trie           // дерево для быстрого определения id оружия по лог-коду
  465.  
  466. // 0.7
  467. new Array:stats_cache_queue
  468.  
  469. // 0.7.1
  470. new bool:weapon_stats_enabled,bool:map_stats_enabled
  471.  
  472. // 0.7.3
  473. new init_seq = -1
  474. new bool:is_ready = false
  475.  
  476. // макрос для помощи реагистрации инфы по оружию
  477. #define REG_INFO(%0,%1,%2)\
  478.     weapon_info[0] = %0;\
  479.     copy(weapon_info[1],MAX_NAME_LENGTH,%1);\
  480.     copy(weapon_info[MAX_NAME_LENGTH ],MAX_NAME_LENGTH,%2);\
  481.     ArrayPushArray(weapons_data,weapon_info);\
  482.     TrieSetCell(log_ids_trie,%2,ArraySize(weapons_data) - 1)
  483.  
  484. public plugin_precache()
  485. {
  486.     register_plugin(PLUGIN,VERSION,AUTHOR)
  487.     register_cvar("csstatsx_sql", VERSION, FCVAR_SERVER | FCVAR_SPONLY | FCVAR_UNLOGGED)
  488.    
  489.     /*
  490.     * хост mysql
  491.     */
  492.     cvar[CVAR_SQL_HOST] = register_cvar("csstats_sql_host","oqde.mypcw.net",FCVAR_UNLOGGED|FCVAR_PROTECTED)
  493.    
  494.     /*
  495.     * пользователь mysql
  496.     */
  497.     cvar[CVAR_SQL_USER] = register_cvar("csstats_sql_user","oqde_oqde",FCVAR_UNLOGGED|FCVAR_PROTECTED)
  498.    
  499.     /*
  500.     * пароль mysql
  501.     */
  502.     cvar[CVAR_SQL_PASS] = register_cvar("csstats_sql_pass","A1qwerty",FCVAR_UNLOGGED|FCVAR_PROTECTED)
  503.    
  504.     /*
  505.     * название БД mysql или sqlite
  506.     */
  507.     cvar[CVAR_SQL_DB] = register_cvar("csstats_sql_db","oqde_admin_mixlike",FCVAR_UNLOGGED|FCVAR_PROTECTED)
  508.    
  509.     /*
  510.     * название таблицы в БД
  511.     */
  512.     cvar[CVAR_SQL_TABLE] = register_cvar("csstats_sql_table","csstats",FCVAR_UNLOGGED|FCVAR_PROTECTED)
  513.    
  514.     /*
  515.     * тип бд
  516.     *   mysql - база данных MySQL
  517.     *   sqlite - локальная база данных SQLite
  518.     */
  519.     cvar[CVAR_SQL_TYPE] = register_cvar("csstats_sql_type","mysql")
  520.    
  521.     /*
  522.     * отправка запроса на создание таблицы
  523.     *   0 - не отправлять запрос
  524.     *   1 - отправлять запрос при загрузке карты
  525.     */
  526.     cvar[CVAR_SQL_CREATE_DB] = register_cvar("csstats_sql_create_db","0")
  527.    
  528.     /*
  529.     * как вести учет игроков
  530.     *   -1          - не учитывать
  531.     *   0           - по нику
  532.     *   1           - по steamid
  533.     *   2           - по ip
  534.     */
  535.     cvar[CVAR_RANK] = get_cvar_pointer("csstats_rank")
  536.    
  537.     if(!cvar[CVAR_RANK])
  538.         cvar[CVAR_RANK] = register_cvar("csstats_rank","0")
  539.        
  540.     /*
  541.     * запись статистики ботов
  542.     *   0           - не записывать
  543.     *   1           - записывать0
  544.     */
  545.     cvar[CVAR_RANKBOTS] = get_cvar_pointer("csstats_rankbots")
  546.    
  547.     if(!cvar[CVAR_RANKBOTS])
  548.         cvar[CVAR_RANKBOTS] = register_cvar("csstats_rankbots","0")
  549.    
  550.     /*
  551.     * как обновлять статистику игрока в БД
  552.     *   -2          - при смерти и дисконнекте
  553.     *   -1          - в конце раунда и дисконнекте
  554.     *   0           - при дисконнекте
  555.     *   значение больше 0     - через указанное кол-во секунд и дисконнекте
  556.     */
  557.     cvar[CVAR_UPDATESTYLE] = register_cvar("csstats_sql_update","-1")
  558.    
  559.     /*
  560.     * включить собственные форварды для client_death, client_damage
  561.     *   0           - выключить
  562.     *   1           - включить, небоходимо, если csstats_sql используется в качестве замены модуля
  563.     */
  564.     cvar[CVAR_USEFORWARDS] = register_cvar("csstats_sql_forwards","1")
  565.    
  566.     /*
  567.     * формула расчета ранга
  568.     *   0           - убйиства - смерти - тк
  569.     *   1           - убийства
  570.     *   2           - убийства + хедшоты
  571.     *   3           - скилл
  572.     *   4           - время онлайн
  573.     */
  574.     cvar[CVAR_RANKFORMULA] = register_cvar("csstats_sql_rankformula","0")
  575.    
  576.     /*
  577.     * формула расчета скилла
  578.     *   0           - The ELO Method (http://fastcup.net/rating.html)
  579.     */
  580.     cvar[CVAR_SKILLFORMULA] = register_cvar("csstats_sql_skillformula","0")
  581.    
  582.     // 0.7
  583.    
  584.     /*
  585.     * ведение статистики по оружию
  586.     */
  587.     cvar[CVAR_WEAPONSTATS] = register_cvar("csstats_sql_weapons","0")
  588.    
  589.     /*
  590.     * ведение статистики по картам
  591.     */
  592.     cvar[CVAR_MAPSTATS] = register_cvar("csstats_sql_maps","0")
  593.    
  594.     /*
  595.     * автоматическое удаление неактвиных игроков в БД
  596.     */
  597.     cvar[CVAR_AUTOCLEAR] = register_cvar("csstats_sql_autoclear","0")
  598.    
  599.     /*
  600.     * использование кеша для get_stats
  601.     *   -1 - обновлять в конце раунда или по времени csstats_sql_update
  602.     *   0 - отключить использование кеша
  603.     */
  604.     cvar[CVAR_CACHETIME] = register_cvar("csstats_sql_cachetime","-1")
  605.  
  606.     /*
  607.     * автоматическая очистка всей игровой статистики в БД в определенный день
  608.     */                              
  609.     cvar[CVAR_AUTOCLEAR_DAY] = register_cvar("csstats_sql_autoclear_day","0")
  610.    
  611.     /*
  612.     * урон для засчитывания ассиста
  613.     */
  614.     cvar[CVAR_ASSISTHP] = register_cvar("csstats_sql_assisthp","50")
  615.    
  616.     #if AMXX_VERSION_NUM < 183
  617.         MaxClients = get_maxplayers()
  618.     #endif
  619. }
  620.  
  621. public plugin_init()
  622. {
  623.     register_logevent("LogEventHooK_RoundEnd", 2, "1=Round_End")
  624.     register_logevent("LogEventHooK_RoundStart", 2, "1=Round_Start")
  625.    
  626.     register_event("CurWeapon","EventHook_CurWeapon","b","1=1")
  627.     register_event("Damage","EventHook_Damage","b","2!0")
  628.     register_event("BarTime","EventHook_BarTime","be")
  629.     register_event("SendAudio","EventHook_SendAudio","a")
  630.     register_event("TextMsg","EventHook_TextMsg","a")
  631.    
  632.     register_srvcmd("csstats_sql_reset","SrvCmd_DBReset")
  633.    
  634.     new weapon_info[WEAPON_INFO_SIZE]
  635.    
  636.     //
  637.     log_ids_trie = TrieCreate()
  638.     //                 is_meele  + название +   логнейм
  639.     weapons_data = ArrayCreate(WEAPON_INFO_SIZE)
  640.    
  641.     REG_INFO(false,"","")
  642.     REG_INFO(false,"p228","p228")
  643.     REG_INFO(false,"","")
  644.     REG_INFO(false,"scout","scout")
  645.     REG_INFO(false,"hegrenade","grenade")
  646.     REG_INFO(false,"xm1014","xm1014")
  647.     REG_INFO(false,"c4","weapon_c4")
  648.     REG_INFO(false,"mac10","mac10")
  649.     REG_INFO(false,"aug","aug")
  650.     REG_INFO(false,"sgrenade","grenade")
  651.     REG_INFO(false,"elite","elite")
  652.     REG_INFO(false,"fiveseven","fiveseven")
  653.     REG_INFO(false,"ump45","ump45")
  654.     REG_INFO(false,"sg550","sg550")
  655.     REG_INFO(false,"galil","galil")
  656.     REG_INFO(false,"famas","famas")
  657.     REG_INFO(false,"usp","usp")
  658.     REG_INFO(false,"glock18","glock18")
  659.     REG_INFO(false,"awp","awp")
  660.     REG_INFO(false,"mp5navy","mp5navy")
  661.     REG_INFO(false,"m249","m249")
  662.     REG_INFO(false,"m3","m3")
  663.     REG_INFO(false,"m4a1","m4a1")
  664.     REG_INFO(false,"tmp","tmp")
  665.     REG_INFO(false,"g3sg1","g3sg1")
  666.     REG_INFO(false,"flashbang","flashbang")
  667.     REG_INFO(false,"deagle","deagle")
  668.     REG_INFO(false,"sg552","sg552")
  669.     REG_INFO(false,"ak47","ak47")
  670.     REG_INFO(true,"knife","knife")
  671.     REG_INFO(false,"p90","p90")
  672.    
  673.     RegisterHam(Ham_Spawn,"player","HamHook_PlayerSpawn",true)
  674. }
  675.  
  676. #if AMXX_VERSION_NUM < 183
  677.     public plugin_cfg()
  678. #else
  679.     public OnAutoConfigsBuffered()
  680. #endif
  681. {
  682.     #if AMXX_VERSION_NUM < 183
  683.         // форсируем выполнение exec addons/amxmodx/configs/amxx.cfg
  684.         server_exec()
  685.     #endif
  686.    
  687.     // читаем квары на подключение
  688.     new host[128],user[64],pass[64],db[64],type[10]
  689.     get_pcvar_string(cvar[CVAR_SQL_HOST],host,charsmax(host))
  690.     get_pcvar_string(cvar[CVAR_SQL_USER],user,charsmax(user))
  691.     get_pcvar_string(cvar[CVAR_SQL_PASS],pass,charsmax(pass))
  692.     get_pcvar_string(cvar[CVAR_SQL_DB],db,charsmax(db))
  693.     get_pcvar_string(cvar[CVAR_SQL_TABLE],tbl_name,charsmax(tbl_name))
  694.     get_pcvar_string(cvar[CVAR_SQL_TYPE],type,charsmax(type))
  695.    
  696.     // и снова здравствуй wopox3
  697.     if(!SQL_SetAffinity(type))
  698.     {
  699.         new error_msg[128]
  700.         formatex(error_msg,charsmax(error_msg),"failed to use ^"%s^" for db driver",
  701.             error_msg)
  702.            
  703.         set_fail_state(error_msg)
  704.        
  705.         return
  706.     }
  707.    
  708.     sql = SQL_MakeDbTuple(host,user,pass,db)
  709.    
  710.     // для поддержки utf8 ников требуется AMXX 1.8.3-dev-git3799 или выше
  711.    
  712.     #if AMXX_VERSION_NUM >= 183
  713.         SQL_SetCharset(sql,"utf8")
  714.     #endif
  715.    
  716.     weapon_stats_enabled = get_pcvar_num(cvar[CVAR_WEAPONSTATS]) == 1? true : false
  717.     map_stats_enabled = get_pcvar_num(cvar[CVAR_MAPSTATS]) == 1 ? true : false
  718.    
  719.     new query[QUERY_LENGTH * 2],que_len
  720.    
  721.     new sql_data[1]
  722.     sql_data[0] = SQL_INITDB
  723.  
  724.     // запрос на создание таблицы
  725.     if(get_pcvar_num(cvar[CVAR_SQL_CREATE_DB]))
  726.     {
  727.         // запрос для mysql
  728.         if(strcmp(type,"mysql") == 0)
  729.         {
  730.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  731.                 CREATE TABLE IF NOT EXISTS `%s` (\
  732.                     `%s` int(11) NOT NULL AUTO_INCREMENT,\
  733.                     `%s` varchar(30) NOT NULL,\
  734.                     `%s` varchar(32) NOT NULL,\
  735.                     `%s` varchar(16) NOT NULL,\
  736.                     `%s` decimal(9,6) NOT NULL DEFAULT '100.0',\
  737.                     `%s` int(11) NOT NULL DEFAULT '0',\
  738.                     `%s` int(11) NOT NULL DEFAULT '0',\
  739.                     `%s` int(11) NOT NULL DEFAULT '0',",
  740.                    
  741.                     tbl_name,
  742.                    
  743.                     row_names[ROW_ID],
  744.                     row_names[ROW_STEAMID],
  745.                     row_names[ROW_NAME],
  746.                     row_names[ROW_IP],
  747.                     row_names[ROW_SKILL],
  748.                     row_names[ROW_KILLS],
  749.                     row_names[ROW_DEATHS],
  750.                     row_names[ROW_HS]
  751.             )
  752.            
  753.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
  754.                     `%s` int(11) NOT NULL DEFAULT '0',\
  755.                     `%s` int(11) NOT NULL DEFAULT '0',\
  756.                     `%s` int(11) NOT NULL DEFAULT '0',\
  757.                     `%s` int(11) NOT NULL DEFAULT '0',\
  758.                     `%s` int(11) NOT NULL DEFAULT '0',\
  759.                     `%s` int(11) NOT NULL DEFAULT '0',\
  760.                     `%s` int(11) NOT NULL DEFAULT '0',\
  761.                     `%s` int(11) NOT NULL DEFAULT '0',",
  762.                    
  763.                     row_names[ROW_TKS],
  764.                     row_names[ROW_SHOTS],
  765.                     row_names[ROW_HITS],
  766.                     row_names[ROW_DMG],
  767.                     row_names[ROW_BOMBDEF],
  768.                     row_names[ROW_BOMBDEFUSED],
  769.                     row_names[ROW_BOMBPLANTS],
  770.                     row_names[ROW_BOMBEXPLOSIONS],
  771.                     row_names[ROW_H0]
  772.             )
  773.            
  774.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
  775.                     `%s` int(11) NOT NULL DEFAULT '0',\
  776.                     `%s` int(11) NOT NULL DEFAULT '0',\
  777.                     `%s` int(11) NOT NULL DEFAULT '0',\
  778.                     `%s` int(11) NOT NULL DEFAULT '0',\
  779.                     `%s` int(11) NOT NULL DEFAULT '0',\
  780.                     `%s` int(11) NOT NULL DEFAULT '0',\
  781.                     `%s` int(11) NOT NULL DEFAULT '0',",
  782.                    
  783.                     row_names[ROW_H1],
  784.                     row_names[ROW_H2],
  785.                     row_names[ROW_H3],
  786.                     row_names[ROW_H4],
  787.                     row_names[ROW_H5],
  788.                     row_names[ROW_H6],
  789.                     row_names[ROW_H7],
  790.                     row_names[ROW_ONLINETIME]
  791.             )
  792.            
  793.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
  794.                     `%s` int(11) NOT NULL DEFAULT '0',\
  795.                     `%s` int(11) NOT NULL DEFAULT '0',\
  796.                     `%s` int(11) NOT NULL DEFAULT '0',\
  797.                     `%s` int(11) NOT NULL DEFAULT '0',\
  798.                     `%s` int(11) NOT NULL DEFAULT '0',",
  799.                    
  800.                     row_names[ROW_CONNECTS],
  801.                     row_names[ROW_ROUNDT],
  802.                     row_names[ROW_WINT],
  803.                     row_names[ROW_ROUNDCT],
  804.                     row_names[ROW_WINCT],
  805.                     row_names[ROW_ASSISTS]
  806.             )
  807.            
  808.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\
  809.                 `%s` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',\
  810.                 `%s` int(11) DEFAULT NULL,\
  811.                 `%s` varchar(32) DEFAULT NULL,\
  812.                     PRIMARY KEY (%s),\
  813.                     KEY `%s` (`%s`(16)),\
  814.                     KEY `%s` (`%s`(16)),\
  815.                     KEY `%s` (`%s`)\
  816.                 ) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;",
  817.                
  818.                 row_names[ROW_FIRSTJOIN],
  819.                 row_names[ROW_LASTJOIN],
  820.                
  821.                 row_names[ROW_SESSIONID],
  822.                 row_names[ROW_SESSIONNAME],
  823.                
  824.                 row_names[ROW_ID],
  825.                 row_names[ROW_STEAMID],row_names[ROW_STEAMID],
  826.                 row_names[ROW_NAME],row_names[ROW_NAME],
  827.                 row_names[ROW_IP],row_names[ROW_IP]
  828.             )
  829.         }
  830.         // запрос для sqlite
  831.         else if(strcmp(type,"sqlite") == 0)
  832.         {
  833.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  834.                 CREATE TABLE IF NOT EXISTS `%s` (\
  835.                     `%s` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
  836.                     `%s`    TEXT NOT NULL,\
  837.                     `%s`    TEXT NOT NULL,\
  838.                     `%s`    TEXT NOT NULL,\
  839.                     `%s`    REAL NOT NULL DEFAULT 0.0,\
  840.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  841.                     `%s`    INTEGER NOT NULL DEFAULT 0,",
  842.                    
  843.                     tbl_name,
  844.                    
  845.                     row_names[ROW_ID],
  846.                     row_names[ROW_STEAMID],
  847.                     row_names[ROW_NAME],
  848.                     row_names[ROW_IP],
  849.                     row_names[ROW_SKILL],
  850.                     row_names[ROW_KILLS],
  851.                     row_names[ROW_DEATHS]
  852.             )
  853.                
  854.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  INTEGER NOT NULL DEFAULT 0,\
  855.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  856.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  857.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  858.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  859.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  860.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  861.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  862.                     `%s`    INTEGER NOT NULL DEFAULT 0,",
  863.                    
  864.                     row_names[ROW_HS],
  865.                     row_names[ROW_TKS],
  866.                     row_names[ROW_SHOTS],
  867.                     row_names[ROW_HITS],
  868.                     row_names[ROW_DMG],
  869.                     row_names[ROW_BOMBDEF],
  870.                     row_names[ROW_BOMBDEFUSED],
  871.                     row_names[ROW_BOMBPLANTS],
  872.                     row_names[ROW_BOMBEXPLOSIONS]
  873.             )
  874.                    
  875.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  INTEGER NOT NULL DEFAULT 0,\
  876.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  877.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  878.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  879.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  880.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  881.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  882.                     `%s`    INTEGER NOT NULL DEFAULT 0,",
  883.                    
  884.                     row_names[ROW_H0],
  885.                     row_names[ROW_H1],
  886.                     row_names[ROW_H2],
  887.                     row_names[ROW_H3],
  888.                     row_names[ROW_H4],
  889.                     row_names[ROW_H5],
  890.                     row_names[ROW_H6],
  891.                     row_names[ROW_H7]
  892.             )
  893.                    
  894.             // 0.7
  895.            
  896.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  INTEGER NOT NULL DEFAULT 0,\
  897.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  898.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  899.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  900.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  901.                     `%s`    INTEGER NOT NULL DEFAULT 0,\
  902.                     `%s`    INTEGER NOT NULL DEFAULT 0,",
  903.                    
  904.                     row_names[ROW_ONLINETIME],
  905.                     row_names[ROW_CONNECTS],
  906.                     row_names[ROW_ROUNDT],
  907.                     row_names[ROW_WINT],
  908.                     row_names[ROW_ROUNDCT],
  909.                     row_names[ROW_WINCT],
  910.                     row_names[ROW_ASSISTS]
  911.             )
  912.                    
  913.             que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\
  914.                     `%s`    TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',\
  915.                     `%s`    INTEGER,\
  916.                     `%s`    TEXT\
  917.                 );",
  918.                
  919.                 row_names[ROW_FIRSTJOIN],
  920.                 row_names[ROW_LASTJOIN],
  921.                 row_names[ROW_SESSIONID],
  922.                 row_names[ROW_SESSIONNAME]
  923.             )
  924.         }
  925.         else
  926.         {
  927.             set_fail_state("invalid ^"csstats_sql_type^" cvar value")
  928.         }
  929.        
  930.         DB_AddInitSeq()
  931.         SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  932.        
  933.         if(weapon_stats_enabled)
  934.         {
  935.             que_len = 0
  936.            
  937.             // запрос для mysql
  938.             if(strcmp(type,"mysql") == 0)
  939.             {
  940.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  941.                     CREATE TABLE IF NOT EXISTS `%s_weapons` (\
  942.                         `%s` int(11) NOT NULL AUTO_INCREMENT,\
  943.                         `%s` int(11) NOT NULL,\
  944.                         `%s` varchar(32) NOT NULL,\
  945.                         `%s` int(11) NOT NULL DEFAULT '0',\
  946.                         `%s` int(11) NOT NULL DEFAULT '0',\
  947.                         `%s` int(11) NOT NULL DEFAULT '0',",
  948.                        
  949.                         tbl_name,
  950.                         row_weapons_names[ROW_WEAPON_ID],
  951.                         row_weapons_names[ROW_WEAPON_PLAYER],
  952.                         row_weapons_names[ROW_WEAPON_NAME],
  953.                         row_weapons_names[ROW_WEAPON_KILLS],
  954.                         row_weapons_names[ROW_WEAPON_DEATHS],
  955.                         row_weapons_names[ROW_WEAPON_HS]
  956.                 )
  957.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
  958.                         `%s` int(11) NOT NULL DEFAULT '0',\
  959.                         `%s` int(11) NOT NULL DEFAULT '0',\
  960.                         `%s` int(11) NOT NULL DEFAULT '0',",
  961.                        
  962.                         row_weapons_names[ROW_WEAPON_TKS],
  963.                         row_weapons_names[ROW_WEAPON_SHOTS],
  964.                         row_weapons_names[ROW_WEAPON_HITS],
  965.                         row_weapons_names[ROW_WEAPON_DMG]  
  966.                 )
  967.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s` int(11) NOT NULL DEFAULT '0',\
  968.                         `%s` int(11) NOT NULL DEFAULT '0',\
  969.                         `%s` int(11) NOT NULL DEFAULT '0',\
  970.                         `%s` int(11) NOT NULL DEFAULT '0',\
  971.                         `%s` int(11) NOT NULL DEFAULT '0',\
  972.                         `%s` int(11) NOT NULL DEFAULT '0',\
  973.                         `%s` int(11) NOT NULL DEFAULT '0',\
  974.                         `%s` int(11) NOT NULL DEFAULT '0',",
  975.                        
  976.                         row_weapons_names[ROW_WEAPON_H0],
  977.                         row_weapons_names[ROW_WEAPON_H1],
  978.                         row_weapons_names[ROW_WEAPON_H2],
  979.                         row_weapons_names[ROW_WEAPON_H3],
  980.                         row_weapons_names[ROW_WEAPON_H4],
  981.                         row_weapons_names[ROW_WEAPON_H5],
  982.                         row_weapons_names[ROW_WEAPON_H6],
  983.                         row_weapons_names[ROW_WEAPON_H7]
  984.                 )
  985.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  986.                         PRIMARY KEY (%s),\
  987.                         KEY `%s` (`%s`(16))\
  988.                     ) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;",
  989.                    
  990.                     row_weapons_names[ROW_WEAPON_ID],
  991.                     row_weapons_names[ROW_WEAPON_NAME],
  992.                     row_weapons_names[ROW_WEAPON_NAME]
  993.                 )
  994.             }
  995.             // запрос для sqlite
  996.             else if(strcmp(type,"sqlite") == 0)
  997.             {
  998.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  999.                     CREATE TABLE IF NOT EXISTS `%s_weapons` (\
  1000.                         `%s` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,\
  1001.                         `%s`    INTEGER NOT NULL,\
  1002.                         `%s`    TEXT NOT NULL,\
  1003.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1004.                         `%s`    INTEGER NOT NULL DEFAULT 0,",
  1005.                        
  1006.                         tbl_name,
  1007.                         row_weapons_names[ROW_WEAPON_ID],
  1008.                         row_weapons_names[ROW_WEAPON_PLAYER],
  1009.                         row_weapons_names[ROW_WEAPON_NAME],
  1010.                         row_weapons_names[ROW_WEAPON_KILLS],
  1011.                         row_weapons_names[ROW_WEAPON_DEATHS]
  1012.                 )
  1013.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  INTEGER NOT NULL DEFAULT 0,\
  1014.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1015.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1016.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1017.                         `%s`    INTEGER NOT NULL DEFAULT 0,",
  1018.                        
  1019.                         row_weapons_names[ROW_WEAPON_HS],
  1020.                         row_weapons_names[ROW_WEAPON_TKS],
  1021.                         row_weapons_names[ROW_WEAPON_SHOTS],
  1022.                         row_weapons_names[ROW_WEAPON_HITS],
  1023.                         row_weapons_names[ROW_WEAPON_DMG]
  1024.                 )
  1025.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"`%s`  INTEGER NOT NULL DEFAULT 0,\
  1026.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1027.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1028.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1029.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1030.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1031.                         `%s`    INTEGER NOT NULL DEFAULT 0,\
  1032.                         `%s`    INTEGER NOT NULL DEFAULT 0",
  1033.                        
  1034.                         row_weapons_names[ROW_WEAPON_H0],
  1035.                         row_weapons_names[ROW_WEAPON_H1],
  1036.                         row_weapons_names[ROW_WEAPON_H2],
  1037.                         row_weapons_names[ROW_WEAPON_H3],
  1038.                         row_weapons_names[ROW_WEAPON_H4],
  1039.                         row_weapons_names[ROW_WEAPON_H5],
  1040.                         row_weapons_names[ROW_WEAPON_H6],
  1041.                         row_weapons_names[ROW_WEAPON_H7]
  1042.                 )
  1043.                 que_len += formatex(query[que_len],charsmax(query) - que_len,");")
  1044.             }
  1045.             else
  1046.             {
  1047.                 set_fail_state("invalid ^"csstats_sql_type^" cvar value")
  1048.             }
  1049.            
  1050.             if(que_len)
  1051.             {
  1052.                 DB_AddInitSeq()
  1053.                 SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  1054.             }
  1055.         }
  1056.     }
  1057.    
  1058.     DB_AutoClearOpt()
  1059.    
  1060.     // обновление статистики в БД каждые n сек
  1061.     if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) > 0)
  1062.     {
  1063.         set_task(
  1064.             float(get_pcvar_num(cvar[CVAR_UPDATESTYLE])),
  1065.             "DB_SaveAll",
  1066.             .flags = "b"
  1067.         )
  1068.     }
  1069.    
  1070.     if(get_pcvar_num(cvar[CVAR_USEFORWARDS]))
  1071.     {   FW_Death =  CreateMultiForward("client_death",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL)
  1072.         FW_Damage = CreateMultiForward("client_damage",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL,FP_CELL)
  1073.         FW_BPlanting = CreateMultiForward("bomb_planting",ET_IGNORE,FP_CELL)
  1074.         FW_BPlanted = CreateMultiForward("bomb_planted",ET_IGNORE,FP_CELL)
  1075.         FW_BExplode = CreateMultiForward("bomb_explode",ET_IGNORE,FP_CELL,FP_CELL)
  1076.         FW_BDefusing = CreateMultiForward("bomb_defusing",ET_IGNORE,FP_CELL)
  1077.         FW_BDefused = CreateMultiForward("bomb_defused",ET_IGNORE,FP_CELL)
  1078.         FW_GThrow = CreateMultiForward("grenade_throw",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL)
  1079.        
  1080.         register_forward(FM_SetModel,"FMHook_SetModel",true)
  1081.     }
  1082.  
  1083.     FW_SQLRead = CreateMultiForward("csxsql_read_data",ET_IGNORE,FP_CELL,FP_ARRAY) // id, stats[]
  1084.  
  1085.     // 0.7.2
  1086.     FW_Assist = CreateMultiForward("client_assist_sql",ET_IGNORE,FP_CELL,FP_CELL,FP_CELL)
  1087.    
  1088.     // 0.7.3
  1089.     FW_Initialized = CreateMultiForward("csxsql_initialized",ET_IGNORE)
  1090.    
  1091.     // 0.7
  1092.    
  1093.     //
  1094.     // запрос на получение ID сессии статистики за карту
  1095.     //
  1096.     if(map_stats_enabled)
  1097.     {
  1098.         new query[128],sql_data[1] = SQL_GETSESSID
  1099.        
  1100.         formatex(query,charsmax(query),"SELECT MAX(`session_id`) FROM `%s_maps`",
  1101.             tbl_name
  1102.         )
  1103.        
  1104.         DB_AddInitSeq()
  1105.         SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  1106.     }
  1107.    
  1108.     // защита от ретардов, которые не читаю README
  1109.     if(
  1110.         (get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -2) ||
  1111.         (get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == 0)
  1112.     )
  1113.     {
  1114.         // выключаем кеширование
  1115.         set_pcvar_num(cvar[CVAR_CACHETIME],0)
  1116.     }
  1117.    
  1118.     DB_InitSeq()
  1119. }
  1120.  
  1121. //
  1122. // последовательность перед началом работы плагина
  1123. //
  1124. DB_AddInitSeq()
  1125. {
  1126.     init_seq --
  1127. }
  1128.  
  1129. //
  1130. // проверяем выполнение последовательности инициализации
  1131. //
  1132. DB_InitSeq()
  1133. {
  1134.     if(init_seq ==0)
  1135.     {
  1136.         log_amx("!?!?!?!?!?")
  1137.         return
  1138.     }
  1139.    
  1140.     init_seq ++
  1141.    
  1142.     // все выполнено, начинаем работу
  1143.     if(init_seq == 0)
  1144.     {
  1145.         ExecuteForward(FW_Initialized,dummy_ret)
  1146.     }
  1147. }
  1148.  
  1149. //
  1150. // Функция очистки БД от неактивных игроков
  1151. //
  1152. DB_AutoClearOpt()
  1153. {
  1154.     // 0.7
  1155.     new autoclear_days = get_pcvar_num(cvar[CVAR_AUTOCLEAR])
  1156.    
  1157.     if(autoclear_days > 0)
  1158.     {
  1159.         DB_ClearTables(autoclear_days)
  1160.     }
  1161.    
  1162.     // полные сброс статистики в определенный день
  1163.     autoclear_days = get_pcvar_num(cvar[CVAR_AUTOCLEAR_DAY])
  1164.    
  1165.     if(autoclear_days > 0)
  1166.     {
  1167.           new s_data[10]
  1168.           get_time("%d",s_data,charsmax(s_data))
  1169.          
  1170.           if(str_to_num(s_data) == autoclear_days)
  1171.           {
  1172.             s_data[0] = 0
  1173.             get_vaultdata("csxsql_clear",s_data,charsmax(s_data))
  1174.            
  1175.             // проверяем не было ли сброса
  1176.             if(!str_to_num(s_data))
  1177.             {
  1178.                 set_vaultdata("csxsql_clear","1")
  1179.                 DB_ClearTables(-1)
  1180.             }
  1181.           }
  1182.           /// очищяем проверку на сброс
  1183.           else
  1184.           {
  1185.             set_vaultdata("csxsql_clear","0")
  1186.           }
  1187.     }
  1188. }
  1189.  
  1190. //
  1191. // Начало работы с БД
  1192. //
  1193. public csxsql_initialized()
  1194. {
  1195.     is_ready = true
  1196.    
  1197.     new players[MAX_PLAYERS],pnum
  1198.     get_players(players,pnum)
  1199.    
  1200.     // загружаем стату игроков
  1201.     for(new i ; i < pnum ; i++)
  1202.     {
  1203.         client_putinserver(players[i])
  1204.     }
  1205. }
  1206.  
  1207. public SrvCmd_DBReset()
  1208. {
  1209.     DB_ClearTables(-1)
  1210. }
  1211.  
  1212. //
  1213. // Очистка таблиц от неактивных записей
  1214. //
  1215. DB_ClearTables(by_days)
  1216. {
  1217.     if(by_days == -1)
  1218.     {
  1219.         log_amx("database reset")
  1220.     }
  1221.    
  1222.     new query[QUERY_LENGTH],que_len
  1223.    
  1224.     new type[10]
  1225.     get_pcvar_string(cvar[CVAR_SQL_TYPE],type,charsmax(type))
  1226.        
  1227.     if(strcmp(type,"mysql") == 0)
  1228.     {
  1229.         que_len += formatex(query[que_len],charsmax(query) - que_len,"DELETE `%s`",
  1230.             tbl_name
  1231.         )
  1232.        
  1233.         if(weapon_stats_enabled)
  1234.         {
  1235.             que_len += formatex(query[que_len],charsmax(query) - que_len,",`%s_weapons`",tbl_name)
  1236.         }
  1237.        
  1238.         if(map_stats_enabled)
  1239.         {
  1240.             que_len += formatex(query[que_len],charsmax(query) - que_len,",`%s_maps`",tbl_name)
  1241.         }
  1242.        
  1243.         que_len += formatex(query[que_len],charsmax(query) - que_len," FROM `%s`",
  1244.             tbl_name
  1245.         )
  1246.        
  1247.         if(weapon_stats_enabled)
  1248.         {
  1249.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1250.                 LEFT JOIN `%s_weapons` ON `%s`.`%s` = `%s_weapons`.`%s`",
  1251.                 tbl_name,
  1252.                 tbl_name,row_names[ROW_ID],
  1253.                 tbl_name,row_weapons_names[ROW_WEAPON_PLAYER]
  1254.             )
  1255.         }
  1256.        
  1257.         if(map_stats_enabled)
  1258.         {
  1259.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1260.                 LEFT JOIN `%s_maps` ON `%s`.`%s` = `%s_maps`.`%s`",
  1261.                 tbl_name,
  1262.                 tbl_name,row_names[ROW_ID],
  1263.                 tbl_name,row_weapons_names[ROW_WEAPON_PLAYER]
  1264.             )
  1265.         }
  1266.        
  1267.         if(by_days > 0)
  1268.         {
  1269.             que_len += formatex(query[que_len],charsmax(query) - que_len,"WHERE `%s`.`%s` <= DATE_SUB(NOW(),INTERVAL %d DAY);",
  1270.                 tbl_name,row_names[ROW_LASTJOIN],by_days
  1271.             )
  1272.         }
  1273.         else
  1274.         {
  1275.             que_len += formatex(query[que_len],charsmax(query) - que_len,"WHERE 1")
  1276.         }
  1277.     }
  1278.     else if(strcmp(type,"sqlite") == 0)
  1279.     {
  1280.         if(weapon_stats_enabled)
  1281.         {
  1282.             if(by_days > 0)
  1283.             {
  1284.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1285.                         DELETE FROM `%s_weapons` WHERE `%s` IN (\
  1286.                             SELECT `%s` FROM `%s` WHERE `%s` <= DATETIME('now','-%d day')\
  1287.                         );",
  1288.                         tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
  1289.                         row_names[ROW_ID],tbl_name,row_names[ROW_LASTJOIN],
  1290.                         by_days
  1291.                 )
  1292.             }
  1293.             else
  1294.             {
  1295.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1296.                         DELETE FROM `%s_weapons` WHERE `%s` IN (\
  1297.                             SELECT `%s` FROM `%s` WHERE 1\
  1298.                         );",
  1299.                         tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
  1300.                         row_names[ROW_ID],tbl_name
  1301.                     )
  1302.             }
  1303.         }
  1304.        
  1305.         if(map_stats_enabled)
  1306.         {
  1307.             if(by_days > 0)
  1308.             {
  1309.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1310.                     DELETE FROM `%s_maps` WHERE `%s` IN (\
  1311.                         SELECT `%s` FROM `%s` WHERE `%s` <= DATETIME('now','-%d day')\
  1312.                     );",
  1313.                     tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
  1314.                     row_names[ROW_ID],tbl_name,row_names[ROW_LASTJOIN],
  1315.                     by_days
  1316.                 )
  1317.             }
  1318.             else
  1319.             {
  1320.                 que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1321.                     DELETE FROM `%s_maps` WHERE `%s` IN (\
  1322.                         SELECT `%s` FROM `%s` WHERE 1\
  1323.                     );",
  1324.                     tbl_name,row_weapons_names[ROW_WEAPON_PLAYER],
  1325.                     row_names[ROW_ID],tbl_name
  1326.                 )
  1327.             }
  1328.         }
  1329.        
  1330.         if(by_days > 0)
  1331.         {
  1332.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1333.                     DELETE FROM `%s` WHERE `%s` <= DATETIME('now','-%d day');",
  1334.                     tbl_name,row_names[ROW_LASTJOIN],by_days
  1335.             )
  1336.         }
  1337.         else
  1338.         {
  1339.             que_len += formatex(query[que_len],charsmax(query) - que_len,"\
  1340.                     DELETE FROM `%s` WHERE 1;",tbl_name
  1341.             )
  1342.         }
  1343.     }
  1344.    
  1345.     new sql_data[1]
  1346.     sql_data[0] = SQL_AUTOCLEAR
  1347.    
  1348.     DB_AddInitSeq()
  1349.     SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  1350. }
  1351.  
  1352. public plugin_end()
  1353. {
  1354.     // выполняем накопившиеся запросы при смене карты или выключении серваре
  1355.     DB_FlushQuery()
  1356.    
  1357.     SQL_FreeHandle(sql)
  1358.    
  1359.     if(sql_con != Empty_Handle)
  1360.     {
  1361.         SQL_FreeHandle(sql_con)
  1362.     }
  1363.    
  1364.     if(stats_cache_trie)
  1365.     {
  1366.         TrieDestroy(stats_cache_trie)
  1367.     }
  1368.    
  1369.     TrieDestroy(log_ids_trie)
  1370.     ArrayDestroy(weapons_data)
  1371. }
  1372.  
  1373. /*
  1374. * загружаем статистику при подключении
  1375. */
  1376. public client_putinserver(id)
  1377. {
  1378.     // ждем начала работы с БД
  1379.     if(!is_ready)
  1380.     {
  1381.         return PLUGIN_CONTINUE
  1382.     }
  1383.    
  1384.     reset_user_allstats(id)
  1385.     reset_user_wstats(id)
  1386.    
  1387.     arrayset(player_data[id],0,player_data_struct)
  1388.    
  1389.     for(new wpn ; wpn < MAX_WEAPONS ; wpn ++)
  1390.     {
  1391.         arrayset(player_awstats[id][wpn],0,sizeof player_awstats[][])
  1392.     }
  1393.    
  1394.     DB_LoadPlayerData(id)
  1395.    
  1396.     return PLUGIN_CONTINUE
  1397. }
  1398.  
  1399. /*
  1400. * сохраняем статистику при дисконнекте
  1401. */
  1402. #if AMXX_VERSION_NUM < 183
  1403. public client_disconnect(id)
  1404. #else
  1405. public client_disconnected(id)
  1406. #endif
  1407. {
  1408.     DB_SavePlayerData(id)
  1409. }
  1410.  
  1411. public HamHook_PlayerSpawn(id)
  1412. {
  1413.     reset_user_wstats(id)
  1414. }
  1415.  
  1416. //
  1417. // Регистрация выстрелов
  1418. //
  1419. public EventHook_CurWeapon(player)
  1420. {
  1421.     #define LASTWEAPON  0   // id посл. оружия
  1422.     #define LASTCLIP    1   // кол-во потронов посл. оружия
  1423.    
  1424.     static event_tmp[MAX_PLAYERS + 1][LASTCLIP + 1] // помним послед
  1425.     static weapon_id; weapon_id = read_data(2)
  1426.     static clip_ammo; clip_ammo = read_data(3)
  1427.    
  1428.     if(event_tmp[player][LASTWEAPON] != weapon_id) // оружие было изменено, запоминаем новое кол-во патронов
  1429.     {
  1430.         event_tmp[player][LASTWEAPON] = weapon_id
  1431.         event_tmp[player][LASTCLIP] = clip_ammo
  1432.     }
  1433.     else if(event_tmp[player][LASTCLIP] > clip_ammo) // кол-во патронов в магазине уменьшилось, регистрируем выстрел
  1434.     {
  1435.         Stats_SaveShot(player,weapon_id)
  1436.         event_tmp[player][LASTCLIP] = clip_ammo
  1437.     }
  1438. }
  1439.  
  1440. //
  1441. // Регистрация попадания
  1442. //
  1443. public EventHook_Damage(player)
  1444. {
  1445.     static damage_take;damage_take = read_data(2)
  1446.     static dmg_inflictor;dmg_inflictor = pev(player,pev_dmg_inflictor)
  1447.    
  1448.     if(pev_valid(dmg_inflictor) != 2)
  1449.     {
  1450.         return PLUGIN_CONTINUE
  1451.     }
  1452.    
  1453.     if(!(0 < dmg_inflictor <= MaxClients))
  1454.     {
  1455.         // урон с гранаты на данным момент не учитывается
  1456.        
  1457.         return PLUGIN_CONTINUE
  1458.     }
  1459.    
  1460.     static weapon_id,last_hit,attacker
  1461.     attacker = get_user_attacker(player,weapon_id,last_hit)
  1462.    
  1463.     if(0 <= last_hit < HIT_END)
  1464.     {
  1465.         Stats_SaveHit(dmg_inflictor,player,damage_take,weapon_id,last_hit)
  1466.     }
  1467.    
  1468.     if(!is_user_alive(player))
  1469.     {
  1470.         if(is_user_connected(attacker))
  1471.         {
  1472.             Stats_SaveKill(attacker,player,weapon_id,last_hit)
  1473.         }
  1474.     }
  1475.    
  1476.     return PLUGIN_CONTINUE
  1477. }
  1478.  
  1479. //
  1480. // Регистрация установки и дефьюза бомбы
  1481. //
  1482. public EventHook_BarTime(player)
  1483. {
  1484.     new duration = read_data(1)
  1485.    
  1486.     if(!duration)
  1487.     {
  1488.         return PLUGIN_CONTINUE
  1489.     }
  1490.    
  1491.     if(duration == 3)
  1492.     {
  1493.         g_planter = player
  1494.         g_defuser = 0
  1495.        
  1496.         if(FW_BPlanting)
  1497.             ExecuteForward(FW_BPlanting,dummy_ret,player)
  1498.     }
  1499.     else
  1500.     {
  1501.         g_defuser = player
  1502.        
  1503.         Stats_SaveBDefusing(player)
  1504.     }
  1505.    
  1506.     return PLUGIN_CONTINUE
  1507. }
  1508.  
  1509. public EventHook_SendAudio(player)
  1510. {
  1511.     new audio_code[16]
  1512.     read_data(2,audio_code,charsmax(audio_code))
  1513.    
  1514.     if (!player && audio_code[7] == 'B')
  1515.     {
  1516.         if (audio_code[11]=='P' && g_planter)
  1517.         {
  1518.             Stats_SaveBPlanted(g_planter)
  1519.         }
  1520.         else if (audio_code[11] =='D' && g_defuser)
  1521.         {
  1522.             Stats_SaveBDefused(g_defuser)
  1523.            
  1524.             Event_CTWin()
  1525.         }
  1526.     }
  1527. }
  1528.  
  1529. public EventHook_TextMsg(player)
  1530. {
  1531.     new message[16]
  1532.     read_data(2,message,charsmax(message))
  1533.    
  1534.     if (!player)
  1535.     {
  1536.         // #Target_Bombed
  1537.         if ((message[1]=='T' && message[8] == 'B') && g_planter)
  1538.         {
  1539.             Stats_SaveBExplode(g_planter)
  1540.            
  1541.             g_planter = 0
  1542.             g_defuser = 0
  1543.            
  1544.             Event_TWin()
  1545.         }
  1546.         // #Terrorists_Win -- #Hostages_Not_R
  1547.         else if(
  1548.             (message[2] == 'e' && message[12] == 'W') ||
  1549.             (message[1] == 'H' && message[14] == 'R')
  1550.         )
  1551.         {
  1552.             Event_TWin()
  1553.         }
  1554.         // #Target_Saved -- #CTs_Win -- #All_Hostages_R
  1555.         else if(
  1556.             (message[1] == 'T' && message[8] == 'S') ||
  1557.             (message[2] == 'T' && message[5] == 'W') ||
  1558.             (message[1] == 'A' && message[14] == 'R')
  1559.         )
  1560.         {
  1561.             Event_CTWin()
  1562.         }
  1563.        
  1564.     }
  1565. }
  1566.  
  1567. //
  1568. // Победа TERRORIST
  1569. //
  1570. Event_TWin()
  1571. {
  1572.     new players[MAX_PLAYERS],pnum
  1573.     get_players(players,pnum)
  1574.    
  1575.     for(new i,player ; i < pnum ; i++)
  1576.     {
  1577.         player = players[i]
  1578.        
  1579.         // считаем статистику побед по командам
  1580.         if(player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] == 1)
  1581.         {
  1582.             player_data[player][PLAYER_STATS3][STATS3_WINT] ++
  1583.         }
  1584.     }
  1585. }
  1586.  
  1587. //
  1588. // Победа CT
  1589. //
  1590. Event_CTWin()
  1591. {
  1592.     new players[MAX_PLAYERS],pnum
  1593.     get_players(players,pnum)
  1594.    
  1595.     for(new i,player ; i < pnum ; i++)
  1596.     {
  1597.         player = players[i]
  1598.        
  1599.         // считаем статистику побед по командам
  1600.         if(player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] == 2)
  1601.         {
  1602.             player_data[player][PLAYER_STATS3][STATS3_WINCT] ++
  1603.         }
  1604.     }
  1605. }
  1606.  
  1607. //
  1608. // Форвард grenade_throw
  1609. //
  1610. public FMHook_SetModel(ent,model[])
  1611. {
  1612.     new owner = pev(ent,pev_owner)
  1613.    
  1614.     new Float:dmg_time
  1615.     pev(ent,pev_dmgtime,dmg_time)
  1616.    
  1617.     if(dmg_time <= 0.0 || !is_user_connected(owner))
  1618.     {
  1619.         return FMRES_IGNORED
  1620.     }
  1621.    
  1622.     new classname[32]
  1623.     pev(ent,pev_classname,classname,charsmax(classname))
  1624.    
  1625.     if(strcmp(classname,"grenade") != 0) // реагируем только на гранаты
  1626.     {
  1627.         return FMRES_IGNORED
  1628.     }
  1629.    
  1630.     new wId
  1631.    
  1632.     if(model[9] == 'h') // модель хеешки
  1633.     {
  1634.         wId = CSW_HEGRENADE
  1635.     }
  1636.     else if(model[9] == 'f') // модель флешки
  1637.     {
  1638.         wId = CSW_FLASHBANG
  1639.     }
  1640.     else if(model[9] == 's') // модель смока
  1641.     {
  1642.         wId = CSW_SMOKEGRENADE
  1643.     }
  1644.    
  1645.     ExecuteForward(FW_GThrow,dummy_ret,owner,ent,wId)
  1646.    
  1647.     return FMRES_IGNORED
  1648. }
  1649.  
  1650. //
  1651. // Учет ассистов
  1652. //
  1653. Stats_SaveAssist(player,victim,assisted)
  1654. {
  1655.     player_data[player][PLAYER_STATS3][STATS3_ASSIST] ++
  1656.    
  1657.     ExecuteForward(FW_Assist,dummy_ret,player,victim,assisted)
  1658.    
  1659.     return true
  1660. }
  1661.  
  1662. //
  1663. // Учет выстрелов
  1664. //
  1665. Stats_SaveShot(player,wpn_id)
  1666. {
  1667.     player_wstats[player][0][STATS_SHOTS] ++
  1668.     player_wstats[player][wpn_id][STATS_SHOTS] ++
  1669.    
  1670.     player_wrstats[player][0][STATS_SHOTS] ++
  1671.     player_wrstats[player][wpn_id][STATS_SHOTS] ++
  1672.    
  1673.     return true
  1674. }
  1675.  
  1676. //
  1677. // Учет попадания
  1678. //
  1679. Stats_SaveHit(attacker,victim,damage,wpn_id,hit_place)
  1680. {
  1681.     player_wstats[attacker][0][STATS_HITS] ++
  1682.     player_wstats[attacker][0][STATS_DMG] += damage
  1683.     player_wstats[attacker][0][hit_place + STATS_END] ++
  1684.    
  1685.     player_wrstats[attacker][0][STATS_HITS] ++
  1686.     player_wrstats[attacker][0][STATS_DMG] += damage
  1687.     player_wrstats[attacker][0][hit_place + STATS_END] ++
  1688.    
  1689.     player_wstats[attacker][wpn_id][STATS_DMG] += damage
  1690.     player_wrstats[attacker][wpn_id][STATS_DMG] += damage
  1691.     player_wstats[attacker][wpn_id][STATS_HITS] ++
  1692.     player_wrstats[attacker][wpn_id][STATS_HITS] ++
  1693.     player_wstats[attacker][wpn_id][hit_place + STATS_END] ++
  1694.     player_wrstats[attacker][wpn_id][hit_place + STATS_END] ++
  1695.    
  1696.     player_vstats[attacker][victim][STATS_HITS] ++
  1697.     player_vstats[attacker][victim][STATS_DMG] += damage
  1698.     player_vstats[attacker][victim][hit_place + STATS_END] ++
  1699.     player_astats[victim][attacker][STATS_HITS] ++
  1700.     player_astats[victim][attacker][STATS_DMG] += damage
  1701.     player_astats[victim][attacker][hit_place + STATS_END] ++
  1702.     player_vstats[attacker][0][STATS_HITS] ++
  1703.     player_vstats[attacker][0][STATS_DMG] += damage
  1704.     player_vstats[attacker][0][hit_place + STATS_END] ++
  1705.     player_astats[victim][0][STATS_HITS] ++
  1706.     player_astats[victim][0][STATS_DMG] += damage
  1707.     player_astats[victim][0][hit_place + STATS_END] ++
  1708.    
  1709.     // оружие, с которого убил для astats, vstats
  1710.     new weapon_info[WEAPON_INFO_SIZE]
  1711.     ArrayGetArray(weapons_data,wpn_id,weapon_info)
  1712.    
  1713.     copy(player_vstats[attacker][victim][STATS_END + HIT_END],
  1714.         MAX_NAME_LENGTH - 1,
  1715.         weapon_info[1]
  1716.     )
  1717.    
  1718.     copy(player_astats[victim][attacker][STATS_END + HIT_END],
  1719.         MAX_NAME_LENGTH - 1,
  1720.         weapon_info[1]
  1721.     )
  1722.    
  1723.     if(FW_Damage)
  1724.         ExecuteForward(FW_Damage,dummy_ret,attacker,victim,damage,wpn_id,hit_place,is_tk(attacker,victim))
  1725.        
  1726.     return true
  1727. }
  1728.  
  1729. //
  1730. // Учет смертей
  1731. //
  1732. Stats_SaveKill(killer,victim,wpn_id,hit_place)
  1733. {
  1734.     if(killer == victim) // не учитываем суицид
  1735.     {
  1736.         return false
  1737.     }
  1738.    
  1739.     if(!is_tk(killer,victim))
  1740.     {
  1741.         player_wstats[killer][0][STATS_KILLS] ++
  1742.         player_wstats[killer][wpn_id][STATS_KILLS] ++
  1743.            
  1744.         player_wrstats[killer][0][STATS_KILLS] ++
  1745.         player_wrstats[killer][wpn_id][STATS_KILLS] ++
  1746.            
  1747.         player_vstats[killer][victim][STATS_KILLS] ++
  1748.         player_astats[victim][killer][STATS_KILLS] ++
  1749.         player_vstats[killer][0][STATS_KILLS] ++
  1750.         player_astats[victim][0][STATS_KILLS] ++
  1751.            
  1752.         if(hit_place == HIT_HEAD)
  1753.         {
  1754.             player_wstats[killer][0][STATS_HS] ++
  1755.             player_wstats[killer][wpn_id][STATS_HS] ++
  1756.                
  1757.             player_wrstats[killer][0][STATS_HS] ++
  1758.             player_wrstats[killer][wpn_id][STATS_HS] ++
  1759.                
  1760.             player_vstats[killer][victim][STATS_HS] ++
  1761.             player_astats[victim][killer][STATS_HS] ++
  1762.             player_vstats[killer][0][STATS_HS] ++
  1763.             player_astats[victim][0][STATS_HS] ++
  1764.         }
  1765.     }
  1766.     else
  1767.     {
  1768.         player_wstats[killer][0][STATS_TK] ++
  1769.         player_wstats[killer][wpn_id][STATS_TK] ++
  1770.        
  1771.         player_wrstats[killer][0][STATS_TK] ++
  1772.         player_wrstats[killer][wpn_id][STATS_TK] ++
  1773.        
  1774.         player_vstats[killer][victim][STATS_TK] ++
  1775.         player_astats[victim][killer][STATS_TK] ++
  1776.         player_vstats[killer][0][STATS_TK] ++
  1777.         player_astats[victim][0][STATS_TK] ++
  1778.     }
  1779.        
  1780.     player_wstats[victim][0][STATS_DEATHS] ++
  1781.     player_wrstats[victim][0][STATS_DEATHS] ++
  1782.    
  1783.     // смотрим ассисты
  1784.     for(new i = 1,assist_hp = get_pcvar_num(cvar[CVAR_ASSISTHP]); (assist_hp) && (i <= MAX_PLAYERS) ; i++)
  1785.     {
  1786.         if(i == killer)
  1787.         {
  1788.             continue
  1789.         }
  1790.        
  1791.         if(player_astats[victim][i][STATS_DMG] >= assist_hp)
  1792.         {
  1793.             Stats_SaveAssist(i,victim,killer)
  1794.         }
  1795.     }
  1796.    
  1797.     new victim_wpn_id = get_user_weapon(victim)
  1798.    
  1799.     if(victim_wpn_id)
  1800.     {
  1801.         player_wstats[victim][victim_wpn_id][STATS_DEATHS] ++
  1802.         player_wrstats[victim][victim_wpn_id][STATS_DEATHS] ++
  1803.     }
  1804.    
  1805.     if(FW_Death)
  1806.         ExecuteForward(FW_Death,dummy_ret,killer,victim,wpn_id,hit_place,is_tk(killer,victim))
  1807.    
  1808.     if(player_data[killer][PLAYER_LOADSTATE] == LOAD_OK && player_data[victim][PLAYER_LOADSTATE] == LOAD_OK) // скилл расчитывается только при наличии статистики из БД
  1809.     {
  1810.         switch(get_pcvar_num(cvar[CVAR_SKILLFORMULA])) // расчет скилла
  1811.         {
  1812.             case 0: // The ELO Method (http://fastcup.net/rating.html)
  1813.             {
  1814.                 new Float:delta = 1.0 / (1.0 + floatpower(10.0,(player_data[killer][PLAYER_SKILL] - player_data[victim][PLAYER_SKILL]) / 100.0))
  1815.                 new Float:koeff = 0.0
  1816.                
  1817.                 if(player_data[killer][PLAYER_STATS][STATS_KILLS] < 100)
  1818.                 {
  1819.                     koeff = 2.0
  1820.                 }
  1821.                 else
  1822.                 {
  1823.                     koeff = 1.5
  1824.                 }
  1825.                
  1826.                 player_data[killer][PLAYER_SKILL] += (koeff * delta)
  1827.                 player_data[victim][PLAYER_SKILL] -= (koeff * delta)
  1828.             }
  1829.         }
  1830. //      log_amx("[CSTX %d] %f (Client k)", killer, player_data[killer][PLAYER_SKILL])
  1831. //      log_amx("[CSTX %d] %f (Client v)", victim, player_data[victim][PLAYER_SKILL])
  1832.     }
  1833.    
  1834.    
  1835.     // обновляем статистику в БД при смерти
  1836.     if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -2)
  1837.     {
  1838.         DB_SavePlayerData(victim)
  1839.     }
  1840.    
  1841.    
  1842.    
  1843.     return true
  1844. }
  1845.  
  1846. //
  1847. // Учет статистики по бомба
  1848. //
  1849. Stats_SaveBDefusing(id)
  1850. {
  1851.     player_wstats2[id][STATS2_DEFAT] ++
  1852.    
  1853.     if(FW_BDefusing)
  1854.         ExecuteForward(FW_BDefusing,dummy_ret,id)
  1855.        
  1856.     return true
  1857. }
  1858.  
  1859. Stats_SaveBDefused(id)
  1860. {
  1861.     player_wstats2[id][STATS2_DEFOK] ++
  1862.    
  1863.     if(FW_BDefused)
  1864.         ExecuteForward(FW_BDefused,dummy_ret,id)
  1865.        
  1866.     return true
  1867. }
  1868.  
  1869. Stats_SaveBPlanted(id)
  1870. {
  1871.     player_wstats2[id][STATS2_PLAAT] ++
  1872.    
  1873.     if(FW_BPlanted)
  1874.         ExecuteForward(FW_BPlanted,dummy_ret,id)
  1875.        
  1876.     return true
  1877. }
  1878.  
  1879. Stats_SaveBExplode(id)
  1880. {
  1881.     player_wstats2[id][STATS2_PLAOK] ++
  1882.    
  1883.     if(FW_BExplode)
  1884.         ExecuteForward(FW_BExplode,dummy_ret,id,g_defuser)
  1885.        
  1886.     return true
  1887. }
  1888.  
  1889. /*
  1890. * изменение ника игрока
  1891. */
  1892. public client_infochanged(id)
  1893. {
  1894.     new cur_name[MAX_NAME_LENGTH],new_name[MAX_NAME_LENGTH]
  1895.     get_user_name(id,cur_name,charsmax(cur_name))
  1896.     get_user_info(id,"name",new_name,charsmax(new_name))
  1897.    
  1898.     if(strcmp(cur_name,new_name) != 0)
  1899.     {
  1900.         copy(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]),new_name)
  1901.         mysql_escape_string(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
  1902.        
  1903.         if(get_pcvar_num(cvar[CVAR_RANK]) == 0)
  1904.         {
  1905.             DB_SavePlayerData(id,true)
  1906.         }
  1907.     }
  1908. }
  1909.  
  1910. /*
  1911. * сбрасываем astats,vstats статистику в начале раунда
  1912. */
  1913. public LogEventHooK_RoundStart()
  1914. {
  1915.     // сбрасываем wrstats, vstats, astats в начале раунда
  1916.     new players[32],pnum
  1917.     get_players(players,pnum)
  1918.    
  1919.     for(new i,player ; i < pnum ; i++)
  1920.     {
  1921.         player = players[i]
  1922.        
  1923.         // определяем в какой команде игрок
  1924.         switch(get_user_team(player))
  1925.         {
  1926.             // статистика сыгранных раундов по командам
  1927.             case 1:
  1928.             {
  1929.                 player_data[player][PLAYER_STATS3][STATS3_ROUNDT] ++
  1930.                 player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] = 1
  1931.             }
  1932.             case 2:
  1933.             {
  1934.                 player_data[player][PLAYER_STATS3][STATS3_ROUNDCT] ++
  1935.                 player_data[player][PLAYER_STATS3][STATS3_CURRENTTEAM] = 2
  1936.             }
  1937.         }
  1938.     }
  1939.  
  1940.    
  1941. }
  1942.  
  1943. //
  1944. // сохраняем статистику в конце раунда
  1945. //
  1946. public LogEventHooK_RoundEnd()
  1947. {
  1948.     if(get_pcvar_num(cvar[CVAR_UPDATESTYLE]) == -1)
  1949.     {
  1950.         DB_SaveAll()
  1951.     }
  1952. }
  1953.  
  1954. /*
  1955. * загрузка статистики игрока из базы данных
  1956. */
  1957. DB_LoadPlayerData(id)
  1958. {
  1959.     // пропускаем HLTV
  1960.     if(is_user_hltv(id))
  1961.     {
  1962.         return false
  1963.     }
  1964.    
  1965.     // пропускаем ботов, если отключена запись статистики ботов
  1966.     if( is_user_bot(id) && !get_pcvar_num(cvar[CVAR_RANKBOTS]))
  1967.     {
  1968.         return false
  1969.     }
  1970.    
  1971.     get_user_info(id,"name",player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
  1972.     mysql_escape_string(player_data[id][PLAYER_NAME],charsmax(player_data[][PLAYER_NAME]))
  1973.    
  1974.     get_user_authid(id,player_data[id][PLAYER_STEAMID],charsmax(player_data[][PLAYER_STEAMID]))
  1975.     get_user_ip(id,player_data[id][PLAYER_IP],charsmax(player_data[][PLAYER_IP]),true)
  1976.    
  1977.     // формируем SQL запрос
  1978.     new query[QUERY_LENGTH],len,sql_data[2]
  1979.    
  1980.     sql_data[0] = SQL_LOAD
  1981.     sql_data[1] = id
  1982.     player_data[id][PLAYER_LOADSTATE] = LOAD_WAIT
  1983.    
  1984.     len += formatex(query[len],charsmax(query)-len,"SELECT *,(")
  1985.     len += DB_QueryBuildScore(query[len],charsmax(query)-len)
  1986.     len += formatex(query[len],charsmax(query)-len,"),(")
  1987.     len += DB_QueryBuildStatsnum(query[len],charsmax(query)-len)
  1988.     len += formatex(query[len],charsmax(query)-len,")")
  1989.    
  1990.     switch(get_pcvar_num(cvar[CVAR_RANK]))
  1991.     {
  1992.         case 0: // статистика по нику
  1993.         {
  1994.             len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `name` = '%s'",
  1995.                 tbl_name,player_data[id][PLAYER_NAME]
  1996.             )
  1997.         }
  1998.         case 1: // статистика по steamid
  1999.         {
  2000.             len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `steamid` = '%s'",
  2001.                 tbl_name,player_data[id][PLAYER_STEAMID]
  2002.             )
  2003.         }
  2004.         case 2: // статистика по ip
  2005.         {
  2006.             len += formatex(query[len],charsmax(query)-len," FROM `%s` AS `a` WHERE `ip` = '%s'",
  2007.                 tbl_name,player_data[id][PLAYER_IP]
  2008.             )
  2009.         }
  2010.         default:
  2011.         {
  2012.             return false
  2013.         }
  2014.     }
  2015.    
  2016.     // отправка потокового запроса
  2017.     SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  2018.    
  2019.     return true
  2020. }
  2021.  
  2022. //
  2023. // Загрузка статистики по оружию
  2024. //
  2025. DB_LoadPlayerWstats(id)
  2026. {
  2027.     if(!player_data[id][PLAYER_ID])
  2028.     {
  2029.         return false
  2030.     }
  2031.    
  2032.     new query[QUERY_LENGTH],sql_data[2]
  2033.    
  2034.     sql_data[0] = SQL_GETWSTATS
  2035.     sql_data[1] = id
  2036.    
  2037.     formatex(query,charsmax(query),"SELECT * FROM `%s_weapons` WHERE `player_id` = '%d'",
  2038.         tbl_name,player_data[id][PLAYER_ID]
  2039.     )
  2040.    
  2041.     SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  2042.    
  2043.     return true
  2044.        
  2045. }
  2046.  
  2047. /*
  2048. * сохранение статистики игрока
  2049. */
  2050. DB_SavePlayerData(id,bool:reload = false)
  2051. {
  2052.     if(player_data[id][PLAYER_LOADSTATE] < LOAD_NEW) // игрок не загрузился
  2053.     {
  2054.         return false
  2055.     }
  2056.    
  2057.     new query[QUERY_LENGTH],i,len
  2058.     new sql_data[2]
  2059.    
  2060.     sql_data[1] = id
  2061.    
  2062.     new stats[8],stats2[4],hits[8]
  2063.     get_user_wstats(id,0,stats,hits)
  2064.     get_user_stats2(id,stats2)
  2065.    
  2066.     switch(player_data[id][PLAYER_LOADSTATE])
  2067.     {
  2068.         case LOAD_OK: // обновление данных
  2069.         {
  2070.             if(reload)
  2071.             {
  2072.                 player_data[id][PLAYER_LOADSTATE] = LOAD_UPDATE
  2073.             }
  2074.            
  2075.             sql_data[0] = SQL_UPDATE
  2076.            
  2077.             new diffstats[sizeof player_data[][PLAYER_STATS]]
  2078.             new diffstats2[sizeof player_data[][PLAYER_STATS2]]
  2079.             new diffhits[sizeof player_data[][PLAYER_HITS]]
  2080.             new to_save
  2081.            
  2082.             len += formatex(query[len],charsmax(query) - len,"UPDATE `%s` SET",tbl_name)
  2083.            
  2084.             // обновляем по разнице с предедущими данными
  2085.             for(i = 0 ; i < sizeof player_data[][PLAYER_STATS] ; i++)
  2086.             {
  2087.                 diffstats[i] = stats[i] - player_data[id][PLAYER_STATSLAST][i] // узнаем разницу
  2088.                 player_data[id][PLAYER_STATSLAST][i] = stats[i]
  2089.                
  2090.                 if(diffstats[i])
  2091.                 {
  2092.                     len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
  2093.                         !to_save ? " " : ",",
  2094.                         row_names[i + ROW_KILLS],
  2095.                         row_names[i + ROW_KILLS],
  2096.                         diffstats[i]
  2097.                     )
  2098.                    
  2099.                     to_save ++
  2100.                 }
  2101.             }
  2102.            
  2103.             // обновляем по разнице с предедущими данными
  2104.             for(i = 0 ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
  2105.             {
  2106.                 diffstats2[i] = stats2[i] - player_data[id][PLAYER_STATS2LAST][i] // узнаем разницу
  2107.                 player_data[id][PLAYER_STATS2LAST][i] = stats2[i]
  2108.                
  2109.                 if(diffstats2[i])
  2110.                 {
  2111.                     len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
  2112.                         !to_save ? " " : ",",
  2113.                         row_names[i + ROW_BOMBDEF],
  2114.                         row_names[i + ROW_BOMBDEF],
  2115.                         diffstats2[i]
  2116.                     )
  2117.                    
  2118.                     to_save ++
  2119.                 }
  2120.             }
  2121.        
  2122.            
  2123.             new Float:diffskill = player_data[id][PLAYER_SKILL] - player_data[id][PLAYER_SKILLLAST]
  2124.             player_data[id][PLAYER_SKILLLAST] = _:player_data[id][PLAYER_SKILL]
  2125.            
  2126. //          log_amx("[CSTX %d] %f (Disconnect) %f diff (last %f)", id, player_data[id][PLAYER_SKILL], diffskill, player_data[id][PLAYER_SKILLLAST]);
  2127.  
  2128.             if(diffskill != 0.0)
  2129.             {
  2130.                 len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %f",
  2131.                     !to_save ? " " : ",",
  2132.                     row_names[ROW_SKILL],
  2133.                     row_names[ROW_SKILL],
  2134.                     diffskill
  2135.                 )
  2136.                    
  2137.                 to_save ++
  2138.             }
  2139.            
  2140.             if(stats[STATS_HITS])
  2141.             {
  2142.                 // запрос на сохранение мест попаданий
  2143.                 for(i = 0; i < sizeof player_data[][PLAYER_HITS] ; i++)
  2144.                 {
  2145.                     diffhits[i] = hits[i] - player_data[id][PLAYER_HITSLAST][i] // узнаем разницу
  2146.                     player_data[id][PLAYER_HITSLAST][i] = hits[i]
  2147.                    
  2148.                     if(diffhits[i])
  2149.                     {
  2150.                         len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
  2151.                             !to_save ? " " : ",",
  2152.                             row_names[i + ROW_H0],row_names[i + ROW_H0],
  2153.                             diffhits[i]
  2154.                         )
  2155.                     }
  2156.                 }
  2157.             }
  2158.            
  2159.             // 0.7
  2160.             new diffstats3[STATS3_END]
  2161.            
  2162.             for(i = STATS3_CONNECT ; i < sizeof player_data[][PLAYER_STATS3] ; i++)
  2163.             {
  2164.                 diffstats3[i] = player_data[id][PLAYER_STATS3][i] - player_data[id][PLAYER_STATS3LAST][i]
  2165.                 player_data[id][PLAYER_STATS3LAST][i] = player_data[id][PLAYER_STATS3][i]
  2166.                
  2167.                 if(diffstats3[i])
  2168.                 {
  2169.                     len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
  2170.                         !to_save ? " " : ",",
  2171.                         row_names[(i - 1) + ROW_CONNECTS],row_names[(i - 1) + ROW_CONNECTS],
  2172.                         diffstats3[i]
  2173.                     )
  2174.                    
  2175.                     to_save ++
  2176.                 }
  2177.             }
  2178.            
  2179.             // не сохраняем только подключения
  2180.             to_save --
  2181.            
  2182.             // 0.7 задаем поля для тригерром статистики по картам
  2183.             if(session_id)
  2184.             {
  2185.                 len += formatex(query[len],charsmax(query) - len,"%s`%s` = '%d',`%s` = '%s'",
  2186.                         to_save <= 0 ? " " : ",",
  2187.                         row_names[ROW_SESSIONID],session_id,
  2188.                         row_names[ROW_SESSIONNAME],session_map
  2189.                 )
  2190.             }
  2191.            
  2192.             //
  2193.             player_data[id][PLAYER_ONLINE] += get_user_time(id) - player_data[id][PLAYER_ONLINEDIFF]
  2194.             player_data[id][PLAYER_ONLINEDIFF] = get_user_time(id)
  2195.            
  2196.             new diffonline = player_data[id][PLAYER_ONLINE]- player_data[id][PLAYER_ONLINELAST]
  2197.             player_data[id][PLAYER_ONLINELAST] = player_data[id][PLAYER_ONLINE]
  2198.            
  2199.             if(diffonline)
  2200.             {
  2201.                 len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + %d",
  2202.                     to_save <= 0 ? " " : ",",
  2203.                     row_names[ROW_ONLINETIME],
  2204.                     row_names[ROW_ONLINETIME],
  2205.                     diffonline
  2206.                 )
  2207.                
  2208.                 //to_save ++
  2209.             }
  2210.            
  2211.             // обновляем время последнего подключения, ник, ип и steamid
  2212.             len += formatex(query[len],charsmax(query) - len,",\
  2213.                 `last_join` = CURRENT_TIMESTAMP,\
  2214.                 `%s` = '%s',\
  2215.                 `%s` = '%s'",
  2216.                
  2217.                
  2218.                 row_names[ROW_STEAMID],player_data[id][PLAYER_STEAMID],
  2219.                 row_names[ROW_IP],player_data[id][PLAYER_IP],
  2220.                
  2221.                 row_names[ROW_ID],player_data[id][PLAYER_ID]
  2222.             )
  2223.            
  2224.             if(!reload) // не обновляем ник при его смене
  2225.             {
  2226.                 len += formatex(query[len],charsmax(query) - len,",`%s` = '%s'",
  2227.                     row_names[ROW_NAME],player_data[id][PLAYER_NAME]
  2228.                 )
  2229.             }
  2230.            
  2231.             len += formatex(query[len],charsmax(query) - len,"WHERE `%s` = '%d'",row_names[ROW_ID],player_data[id][PLAYER_ID])
  2232.            
  2233.             if(to_save <= 0) // нечего сохранять
  2234.             {
  2235.                 if(player_data[id][PLAYER_LOADSTATE] == LOAD_UPDATE) // релоад для обновления ника
  2236.                 {
  2237.                     player_data[id][PLAYER_LOADSTATE] = LOAD_NO
  2238.                     DB_LoadPlayerData(id)
  2239.                 }
  2240.                
  2241.                 return false
  2242.             }
  2243.             else
  2244.             {
  2245.                 //
  2246.                 // Сравниваем статистику
  2247.                 //
  2248.                 for(new i ; i < sizeof player_data[][PLAYER_STATS] ; i++)
  2249.                 {
  2250.                     player_data[id][PLAYER_STATS][i] += diffstats[i]
  2251.                 }
  2252.                
  2253.                 for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
  2254.                 {
  2255.                     player_data[id][PLAYER_HITS][i] += diffhits[i]
  2256.                 }
  2257.                
  2258.                 for(new i ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
  2259.                 {
  2260.                     player_data[id][PLAYER_STATS2][i] += diffstats2[i]
  2261.                 }
  2262.             }
  2263.         }
  2264.         case LOAD_NEW: // запрос на добавление новой записи
  2265.         {
  2266.             sql_data[0] = SQL_INSERT
  2267.            
  2268.             new Float:skill
  2269.            
  2270.             switch(get_pcvar_num(cvar[CVAR_SKILLFORMULA]))
  2271.             {
  2272.                 case 0: skill = 100.0
  2273.             }
  2274.            
  2275.             formatex(query,charsmax(query),"INSERT INTO `%s` \
  2276.                             (`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`)\
  2277.                             VALUES('%s','%s','%s','%f','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d',CURRENT_TIMESTAMP)\
  2278.                             ",tbl_name,
  2279.                            
  2280.                     row_names[ROW_STEAMID],
  2281.                     row_names[ROW_NAME],
  2282.                     row_names[ROW_IP],
  2283.                     row_names[ROW_SKILL],
  2284.                     row_names[ROW_KILLS],
  2285.                     row_names[ROW_DEATHS],
  2286.                     row_names[ROW_HS],
  2287.                     row_names[ROW_TKS],
  2288.                     row_names[ROW_SHOTS],
  2289.                     row_names[ROW_HITS],
  2290.                     row_names[ROW_DMG],
  2291.                     row_names[ROW_BOMBDEF],
  2292.                     row_names[ROW_BOMBDEFUSED],
  2293.                     row_names[ROW_BOMBPLANTS],
  2294.                     row_names[ROW_BOMBEXPLOSIONS],
  2295.                     row_names[ROW_LASTJOIN],
  2296.                    
  2297.                     player_data[id][PLAYER_STEAMID],
  2298.                     player_data[id][PLAYER_NAME],
  2299.                     player_data[id][PLAYER_IP],
  2300.                    
  2301.                     skill,
  2302.                    
  2303.                     stats[STATS_KILLS],
  2304.                     stats[STATS_DEATHS],
  2305.                     stats[STATS_HS],
  2306.                     stats[STATS_TK],
  2307.                     stats[STATS_SHOTS],
  2308.                     stats[STATS_HITS],
  2309.                     stats[STATS_DMG],
  2310.                    
  2311.                     stats2[STATS2_DEFAT],
  2312.                     stats2[STATS2_DEFOK],
  2313.                     stats2[STATS2_PLAAT],
  2314.                     stats2[STATS2_PLAOK]
  2315.             )
  2316.            
  2317.             //
  2318.             // Сравниваем статистику
  2319.             //
  2320.             for(new i ; i < sizeof player_data[][PLAYER_STATS] ; i++)
  2321.             {
  2322.                 player_data[id][PLAYER_STATS][i] = stats[i]
  2323.             }
  2324.                
  2325.             for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
  2326.             {
  2327.                 player_data[id][PLAYER_HITS][i] = hits[i]
  2328.             }
  2329.                
  2330.             for(new i ; i < sizeof player_data[][PLAYER_STATS2] ; i++)
  2331.             {
  2332.                 player_data[id][PLAYER_STATS2][i] = stats2[i]
  2333.             }
  2334.                
  2335.             player_data[id][PLAYER_SKILL] = _:player_data[id][PLAYER_SKILLLAST] = _:skill
  2336.            
  2337.             if(reload)
  2338.             {
  2339.                 player_data[id][PLAYER_LOADSTATE] = LOAD_UPDATE
  2340.             }
  2341.             else
  2342.             {
  2343.                 player_data[id][PLAYER_LOADSTATE] = LOAD_NEWWAIT
  2344.             }
  2345.         }
  2346.     }
  2347.    
  2348.     if(query[0])
  2349.     {
  2350.         if(weapon_stats_enabled)
  2351.         {
  2352.             DB_SavePlayerWstats(id)
  2353.         }
  2354.        
  2355.         switch(sql_data[0])
  2356.         {
  2357.             // накапливаем запросы
  2358.             case SQL_UPDATE:
  2359.             {
  2360.                 // запросов достаточно, сбрасываем их
  2361.                 DB_AddQuery(query,len)
  2362.                
  2363.                 return true
  2364.             }
  2365.         }
  2366.        
  2367.         SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  2368.     }
  2369.    
  2370.     return true
  2371. }
  2372.  
  2373. //
  2374. // Сохранение статистики по оружию
  2375. //
  2376. public DB_SavePlayerWstats(id)
  2377. {
  2378.     if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // игрок не загрузился
  2379.     {
  2380.         return false
  2381.     }
  2382.    
  2383.     new query[QUERY_LENGTH],len,log[MAX_NAME_LENGTH],wpn,stats_index,stats_index_last,to_save
  2384.     new diff[STATS_END + HIT_END]
  2385.    
  2386.     const load_index = sizeof player_awstats[][] - 1
  2387.    
  2388.     // по всем оружиям
  2389.     for(wpn = 0; wpn < MAX_WEAPONS ; wpn++)
  2390.     {
  2391.         Info_Weapon_GetLog(wpn,log,charsmax(log))
  2392.        
  2393.         if(!log[0])
  2394.         {
  2395.             continue
  2396.         }
  2397.        
  2398.         to_save = 0
  2399.         len = 0
  2400.        
  2401.         // расчитываем разницу статисткии
  2402.         for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
  2403.         {
  2404.             stats_index_last = stats_index + (STATS_END + HIT_END)
  2405.            
  2406.             diff[stats_index] = player_wstats[id][wpn][stats_index] - player_awstats[id][wpn][stats_index_last]
  2407.             player_awstats[id][wpn][stats_index_last] = player_wstats[id][wpn][stats_index]
  2408.         }
  2409.        
  2410.         switch(player_awstats[id][wpn][load_index])
  2411.         {
  2412.             // новая статистика оружия
  2413.             case LOAD_NEW:
  2414.             {
  2415.                 new id_row
  2416.                
  2417.                 // строим запрос
  2418.                 len += formatex(query[len],charsmax(query) - len,"INSERT INTO `%s_weapons` (`%s`,`%s`",
  2419.                     tbl_name,
  2420.                    
  2421.                     row_weapons_names[ROW_WEAPON_PLAYER],
  2422.                     row_weapons_names[ROW_WEAPON_NAME]
  2423.                 )
  2424.                
  2425.                 for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
  2426.                 {
  2427.                     id_row = ROW_WEAPON_KILLS + stats_index
  2428.                    
  2429.                     if(diff[stats_index])
  2430.                     {
  2431.                         len += formatex(query[len],charsmax(query) - len,",`%s`",
  2432.                             row_weapons_names[id_row]
  2433.                         )
  2434.                        
  2435.                         to_save ++
  2436.                     }
  2437.                 }
  2438.                
  2439.                 if(to_save)
  2440.                 {
  2441.                     len += formatex(query[len],charsmax(query) - len,") VALUES('%d','%s'",
  2442.                         player_data[id][PLAYER_ID],
  2443.                         log
  2444.                     )
  2445.                    
  2446.                     for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
  2447.                     {
  2448.                         id_row = ROW_WEAPON_KILLS + stats_index
  2449.                        
  2450.                         if(diff[stats_index])
  2451.                         {
  2452.                             len += formatex(query[len],charsmax(query) - len,",'%d'",
  2453.                                 diff[stats_index]
  2454.                             )
  2455.                         }
  2456.                     }
  2457.                    
  2458.                     len += formatex(query[len],charsmax(query) - len,")")
  2459.                     player_awstats[id][wpn][load_index]  = _:LOAD_OK
  2460.                 }
  2461.                
  2462.                
  2463.             }
  2464.             // обновляем статистику
  2465.             case LOAD_OK:
  2466.             {
  2467.                 new id_row
  2468.                
  2469.                 // строим запрос
  2470.                 len += formatex(query[len],charsmax(query) - len,"UPDATE `%s_weapons` SET",tbl_name)
  2471.                
  2472.                 for(stats_index = 0;  stats_index < STATS_END + HIT_END;  stats_index++)
  2473.                 {
  2474.                     id_row = ROW_WEAPON_KILLS + stats_index
  2475.                    
  2476.                     if(diff[stats_index])
  2477.                     {
  2478.                         len += formatex(query[len],charsmax(query) - len,"%s`%s` = `%s` + '%d'",
  2479.                             to_save ? "," : "",
  2480.                             row_weapons_names[id_row],
  2481.                             row_weapons_names[id_row],
  2482.                             diff[stats_index]
  2483.                         )
  2484.                        
  2485.                         to_save ++
  2486.                     }
  2487.                 }
  2488.                
  2489.                 len += formatex(query[len],charsmax(query) - len,"WHERE `%s` = '%s' AND `%s` = '%d'",
  2490.                     row_weapons_names[ROW_WEAPON_NAME],log,
  2491.                     row_weapons_names[ROW_WEAPON_PLAYER],player_data[id][PLAYER_ID]
  2492.                 )
  2493.             }  
  2494.         }
  2495.        
  2496.         if(to_save)
  2497.         {
  2498.             DB_AddQuery(query,len)
  2499.         }
  2500.     }
  2501.    
  2502.     return true
  2503. }
  2504.  
  2505. DB_AddQuery(query[],len)
  2506. {
  2507.     if((flush_que_len + len + 1) > charsmax(flush_que))
  2508.     {
  2509.         DB_FlushQuery()
  2510.     }
  2511.    
  2512.     flush_que_len += formatex(
  2513.         flush_que[flush_que_len],
  2514.         charsmax(flush_que) - flush_que_len,
  2515.         "%s%s",flush_que_len ? ";" : "",
  2516.         query
  2517.     )
  2518.        
  2519.     // задание на сброс накопленных запросов
  2520.     remove_task(task_flush)
  2521.     set_task(0.1,"DB_FlushQuery",task_flush)
  2522. }
  2523.  
  2524. //
  2525. // Сброс накопленных запросов
  2526. //
  2527. public DB_FlushQuery()
  2528. {
  2529.     if(flush_que_len)
  2530.     {
  2531.         new sql_data[1] = SQL_UPDATE
  2532.         SQL_ThreadQuery(sql,"SQL_Handler",flush_que,sql_data,sizeof sql_data)
  2533.        
  2534.         flush_que_len = 0
  2535.     }
  2536. }
  2537.  
  2538. #define falos false
  2539.  
  2540. /*
  2541. * получение новых позиции в топе игроков
  2542. */
  2543. public DB_GetPlayerRanks()
  2544. {
  2545.     new players[32],pnum
  2546.     get_players(players,pnum)
  2547.    
  2548.     new query[QUERY_LENGTH],len
  2549.    
  2550.     // строим SQL запрос
  2551.     len += formatex(query[len],charsmax(query) - len,"SELECT `id`,(")
  2552.     len += DB_QueryBuildScore(query[len],charsmax(query) - len)
  2553.     len += formatex(query[len],charsmax(query) - len,") FROM `%s` as `a` WHERE `id` IN(",tbl_name)
  2554.    
  2555.     new bool:letsgo
  2556.    
  2557.     for(new i,player,bool:y  ; i < pnum ; i++)
  2558.     {
  2559.         player = players[i]
  2560.        
  2561.         if(player_data[player][PLAYER_ID])
  2562.         {
  2563.             len += formatex(query[len],charsmax(query) - len,"%s'%d'",y ? "," : "",player_data[player][PLAYER_ID])
  2564.             y = true
  2565.             letsgo = true
  2566.         }
  2567.     }
  2568.    
  2569.     len += formatex(query[len],charsmax(query) - len,")")
  2570.    
  2571.     if(letsgo)
  2572.     {
  2573.         new data[1] = SQL_UPDATERANK
  2574.         SQL_ThreadQuery(sql,"SQL_Handler",query,data,sizeof data)
  2575.     }
  2576. }
  2577.  
  2578. new bool:update_cache = false
  2579.  
  2580. /*
  2581. * сохранение статистики всех игроков
  2582. */
  2583. public DB_SaveAll()
  2584. {
  2585.     new players[32],pnum
  2586.     get_players(players,pnum)
  2587.    
  2588.     if(get_pcvar_num(cvar[CVAR_CACHETIME]) == -1)
  2589.     {
  2590.         update_cache = true
  2591.     }
  2592.    
  2593.     for(new i ; i < pnum ; i++)
  2594.     {
  2595.         DB_SavePlayerData(players[i])
  2596.     }
  2597. }
  2598.  
  2599. /*
  2600. * запрос на просчет ранка
  2601. */
  2602. DB_QueryBuildScore(sql_que[] = "",sql_que_len = 0,bool:only_rows = falos,overide_order = 0)
  2603. {
  2604.     // стандартная формула csstats (убийства-смерти-tk)
  2605.    
  2606.     if(only_rows)
  2607.     {
  2608.         switch(overide_order ? overide_order : get_pcvar_num(cvar[CVAR_RANKFORMULA]))
  2609.         {
  2610.             case 1: return formatex(sql_que,sql_que_len,"`kills`")
  2611.             case 2: return formatex(sql_que,sql_que_len,"`kills`+`hs`")
  2612.             case 3: return formatex(sql_que,sql_que_len,"`skill`")
  2613.             case 4: return formatex(sql_que,sql_que_len,"`connection_time`")
  2614.             default: return formatex(sql_que,sql_que_len,"`kills`-`deaths`-`tks`")
  2615.         }
  2616.     }
  2617.     else
  2618.     {
  2619.         switch(overide_order ? overide_order : get_pcvar_num(cvar[CVAR_RANKFORMULA]))
  2620.         {
  2621.             case 1: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills)>=(a.kills)",tbl_name)
  2622.             case 2: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills+hs)>=(a.kills+a.hs)",tbl_name)
  2623.             case 3: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (skill)>=(a.skill)",tbl_name)
  2624.             case 4: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (connection_time)>=(a.connection_time)",tbl_name)
  2625.             default: return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE (kills-deaths-tks)>=(a.kills-a.deaths-a.tks)",tbl_name)
  2626.         }
  2627.    
  2628.    
  2629.     }
  2630.    
  2631.     return 0
  2632. }
  2633.  
  2634. /*
  2635. * запрос на общее кол-во записей в БД
  2636. */
  2637. DB_QueryBuildStatsnum(sql_que[] = "",sql_que_len = 0)
  2638. {
  2639.     return formatex(sql_que,sql_que_len,"SELECT COUNT(*) FROM %s WHERE 1",tbl_name)
  2640. }
  2641.  
  2642. /*
  2643. * запрос на выборку статистики по позиции
  2644. *   index - начальная позиция
  2645. *   index_count - кол-во выбираемых записей
  2646. */
  2647. DB_QueryBuildGetstats(query[],query_max,len = 0,index,index_count = 2,overide_order = 0)
  2648. {
  2649.     // строим запрос
  2650.     len += formatex(query[len],query_max-len,"SELECT *")
  2651.    
  2652.     // запрос на ранк
  2653.     len += formatex(query[len],query_max-len,",(")
  2654.     len += DB_QueryBuildScore(query[len],query_max-len,true,overide_order)
  2655.     len += formatex(query[len],query_max-len,") as `rank`")
  2656.    
  2657.     // запрашиваем следующию запись
  2658.     // если есть, то возврашаем нативом index + 1
  2659.     len += formatex(query[len],query_max-len," FROM `%s` as `a` ORDER BY `rank` DESC LIMIT %d,%d",
  2660.         tbl_name,index,index_count
  2661.     )
  2662.    
  2663.     return len
  2664. }
  2665.  
  2666. /*
  2667. * чтение результата get_stats запроса
  2668. */
  2669. 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)
  2670. {
  2671.     stats_count = SQL_NumResults(sqlQue)
  2672.    
  2673.     if(!stats_count)
  2674.     {
  2675.         return false
  2676.     }
  2677.    
  2678.     new stats_cache[stats_cache_struct]
  2679.    
  2680.     switch(get_pcvar_num(cvar[CVAR_RANK]))
  2681.     {
  2682.         case 0: SQL_ReadResult(sqlQue,ROW_NAME,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
  2683.         case 1: SQL_ReadResult(sqlQue,ROW_STEAMID,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
  2684.         case 2: SQL_ReadResult(sqlQue,ROW_IP,stats_cache[CACHE_STEAMID],charsmax(stats_cache[CACHE_STEAMID]))
  2685.     }
  2686.    
  2687.     SQL_ReadResult(sqlQue,ROW_NAME,stats_cache[CACHE_NAME],charsmax(stats_cache[CACHE_NAME]))
  2688.    
  2689.     copy(name,name_len,stats_cache[CACHE_NAME])
  2690.     copy(authid,authid_len,stats_cache[CACHE_STEAMID])
  2691.    
  2692.     new i
  2693.    
  2694.     for(i = ROW_SKILL ; i <= ROW_LASTJOIN ; i++)
  2695.     {
  2696.         switch(i)
  2697.         {
  2698.             case ROW_SKILL: SQL_ReadResult(sqlQue,i,stats_cache[CACHE_SKILL])
  2699.             case ROW_KILLS..ROW_DMG:
  2700.             {
  2701.                 stats_cache[CACHE_STATS][i - ROW_KILLS] = stats[i - ROW_KILLS] = SQL_ReadResult(sqlQue,i)
  2702.             }
  2703.             case ROW_BOMBDEF..ROW_BOMBEXPLOSIONS:
  2704.             {
  2705.                 stats_cache[CACHE_STATS2][i - ROW_BOMBDEF] = stats2[i - ROW_BOMBDEF] = SQL_ReadResult(sqlQue,i)
  2706.             }
  2707.             case ROW_H0..ROW_H7:
  2708.             {
  2709.                 stats_cache[CACHE_HITS][i - ROW_H0] = hits[i - ROW_H0] = SQL_ReadResult(sqlQue,i)
  2710.             }
  2711.             // 0.7
  2712.             case ROW_CONNECTS..ROW_ASSISTS:
  2713.             {
  2714.                 stats_cache[CACHE_STATS3][((i - ROW_CONNECTS) + 1)] = stats3[((i - ROW_CONNECTS) + 1)] = SQL_ReadResult(sqlQue,i)
  2715.             }
  2716.             case ROW_FIRSTJOIN..ROW_LASTJOIN:
  2717.             {
  2718.                 new date_str[32]
  2719.                 SQL_ReadResult(sqlQue,i,date_str,charsmax(date_str))
  2720.                            
  2721.                 stats_cache[(CACHE_FIRSTJOIN + (i - ROW_FIRSTJOIN))] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
  2722.             }
  2723.         }
  2724.        
  2725.     }
  2726.    
  2727.     // кеширование данных
  2728.     if(!stats_cache_trie)
  2729.     {
  2730.         stats_cache_trie = TrieCreate()
  2731.     }
  2732.    
  2733.     stats_cache[CACHE_LAST] = SQL_NumResults(sqlQue) <= 1
  2734.     SQL_ReadResult(sqlQue,ROW_SKILL,stats_cache[CACHE_SKILL])
  2735.     stats_cache[CACHE_ID] = SQL_ReadResult(sqlQue,ROW_ID)
  2736.     stats_cache[CACHE_TIME] = SQL_ReadResult(sqlQue,ROW_ONLINETIME)
  2737.    
  2738.     new index_str[10]
  2739.     num_to_str(index,index_str,charsmax(index_str))
  2740.    
  2741.     TrieSetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct)
  2742.     // кешироавние данных
  2743.    
  2744.     SQL_NextRow(sqlQue)
  2745.    
  2746.     return SQL_MoreResults(sqlQue)
  2747. }
  2748.  
  2749. //
  2750. // Задаем очередь для обновления кеша
  2751. //
  2752. Cache_Stats_SetQueue(start_index,top)
  2753. {
  2754.     // очередь уже создана
  2755.     if(Cache_Stats_CheckQueue(start_index,top))
  2756.     {
  2757.         return false
  2758.     }
  2759.    
  2760.     if(!stats_cache_queue)
  2761.     {
  2762.         stats_cache_queue = ArrayCreate(stats_cache_queue_struct)
  2763.     }
  2764.    
  2765.     new length = ArraySize(stats_cache_queue)
  2766.    
  2767.     new cache_queue_info[stats_cache_queue_struct]
  2768.     cache_queue_info[CACHE_QUE_START] = start_index
  2769.     cache_queue_info[CACHE_QUE_TOP] = top
  2770.    
  2771.     if(!length) // новая очередь
  2772.     {
  2773.         ArrayPushArray(stats_cache_queue,cache_queue_info)
  2774.     }
  2775.     else // в топ
  2776.     {
  2777.         ArrayInsertArrayBefore(stats_cache_queue,0,cache_queue_info)
  2778.     }
  2779.    
  2780.     length ++
  2781.    
  2782.     if(length > 5) // максимум 5 заданий в очереди
  2783.     {
  2784.         ArrayDeleteItem(stats_cache_queue,5)
  2785.         length --
  2786.     }
  2787.    
  2788.     return true
  2789. }
  2790.  
  2791. //
  2792. // Обновление кеша через очередь
  2793. //
  2794. Cache_Stats_UpdateQueue()
  2795. {
  2796.     if(!stats_cache_queue)
  2797.     {
  2798.         return false
  2799.     }
  2800.    
  2801.     for(new i,length = ArraySize(stats_cache_queue),cache_queue_info[stats_cache_queue_struct] ; i < length ; i++)
  2802.     {
  2803.         ArrayGetArray(stats_cache_queue,i,cache_queue_info)
  2804.         DB_QueryTop15(0,-1,-1,-1,cache_queue_info[CACHE_QUE_START],cache_queue_info[CACHE_QUE_TOP],-1)
  2805.     }
  2806.    
  2807.     return true
  2808. }
  2809.  
  2810. Cache_Stats_CheckQueue(start_index,top)
  2811. {
  2812.     if(!stats_cache_queue)
  2813.     {
  2814.         return false
  2815.     }
  2816.    
  2817.     for(new i,length = ArraySize(stats_cache_queue),cache_queue_info[stats_cache_queue_struct] ; i < length ; i++)
  2818.     {
  2819.         ArrayGetArray(stats_cache_queue,i,cache_queue_info)
  2820.        
  2821.         if(start_index == cache_queue_info[0] &&
  2822.             top == cache_queue_info[1]
  2823.         )
  2824.         {
  2825.             return true
  2826.         }
  2827.     }
  2828.    
  2829.     return false
  2830. }
  2831.  
  2832. //
  2833. // Потоковый запрос на Top15
  2834. //
  2835. DB_QueryTop15(id,plugin_id,func_id,position,start_index,top,params)
  2836. {
  2837.     // кеширование
  2838.     if((get_pcvar_num(cvar[CVAR_CACHETIME]) != 0) && stats_cache_trie)
  2839.     {
  2840.         Cache_Stats_SetQueue(start_index,top)
  2841.        
  2842.         new bool:use_cache = true
  2843.        
  2844.         // проверяем что требуемые данные есть в кеше
  2845.         for(new i =  start_index,index_str[10]; i < (start_index + top) ; i++)
  2846.         {
  2847.             num_to_str(i,index_str,charsmax(index_str))
  2848.            
  2849.             if(!TrieKeyExists(stats_cache_trie,index_str))
  2850.             {
  2851.                 use_cache = false
  2852.             }
  2853.         }
  2854.        
  2855.         // юзаем кеш
  2856.         if(use_cache)
  2857.         {
  2858.             // вызываем хандлер другого плагина
  2859.            
  2860.             if(func_id > -1)
  2861.             {
  2862.                 if(callfunc_begin_i(func_id,plugin_id))
  2863.                 {
  2864.                     callfunc_push_int(id)
  2865.                     callfunc_push_int(position)
  2866.                     callfunc_end()
  2867.                 }
  2868.             }
  2869.            
  2870.             return true
  2871.         }
  2872.     }
  2873.     // кеширование
  2874.    
  2875.     // строим новый запрос
  2876.     new query[QUERY_LENGTH]
  2877.    
  2878.     if(params == 5)
  2879.     {
  2880.         DB_QueryBuildGetstats(query,charsmax(query),.index = start_index,.index_count = top,.overide_order = get_param(5))
  2881.     }
  2882.     else
  2883.     {
  2884.         DB_QueryBuildGetstats(query,charsmax(query),.index = start_index,.index_count = top)
  2885.     }
  2886.    
  2887.     new sql_data[6]
  2888.    
  2889.     sql_data[0] = SQL_GETSTATS
  2890.     sql_data[1] = id
  2891.     sql_data[2] = plugin_id
  2892.     sql_data[3] = func_id
  2893.     sql_data[4] = position
  2894.     sql_data[5] = start_index
  2895.    
  2896.     SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,sizeof sql_data)
  2897.    
  2898.     return true
  2899. }
  2900.  
  2901. /*
  2902. * обновляем кеш для get_stats
  2903. */
  2904. Cache_Stats_Update()
  2905. {
  2906.     if(!stats_cache_trie)
  2907.         return false
  2908.    
  2909.     TrieClear(stats_cache_trie)
  2910.    
  2911.     return true
  2912. }
  2913.  
  2914. /*
  2915. * обработка ответов на SQL запросы
  2916. */
  2917. public SQL_Handler(failstate,Handle:sqlQue,err[],errNum,data[],dataSize){
  2918.     // есть ошибки
  2919.     switch(failstate)
  2920.     {
  2921.         case TQUERY_CONNECT_FAILED:  // ошибка соединения с mysql сервером
  2922.         {
  2923.             log_amx("SQL connection failed")
  2924.             log_amx("[ %d ] %s",errNum,err)
  2925.            
  2926.             return PLUGIN_HANDLED
  2927.         }
  2928.         case TQUERY_QUERY_FAILED:  // ошибка SQL запроса
  2929.         {
  2930.             new lastQue[QUERY_LENGTH]
  2931.             SQL_GetQueryString(sqlQue,lastQue,charsmax(lastQue)) // узнаем последний SQL запрос
  2932.            
  2933.             log_amx("SQL query failed")
  2934.             log_amx("[ %d ] %s",errNum,err)
  2935.             log_amx("[ SQL ] %s",lastQue)
  2936.            
  2937.             return PLUGIN_HANDLED
  2938.         }
  2939.     }
  2940.    
  2941.     switch(data[0])
  2942.     {
  2943.         case SQL_INITDB:
  2944.         {
  2945.             DB_InitSeq()
  2946.         }
  2947.         case SQL_LOAD: // загрзука статистики игрока
  2948.         {
  2949.             new id = data[1]
  2950.        
  2951.             if(!is_user_connected(id))
  2952.             {
  2953.                 return PLUGIN_HANDLED
  2954.             }
  2955.            
  2956.             if(SQL_NumResults(sqlQue)) // считываем статистику
  2957.             {
  2958.                 player_data[id][PLAYER_LOADSTATE] = LOAD_OK
  2959.                 player_data[id][PLAYER_ID] = SQL_ReadResult(sqlQue,ROW_ID)
  2960.                
  2961.                 // общая статистика
  2962.                 player_data[id][PLAYER_STATS][STATS_KILLS] = SQL_ReadResult(sqlQue,ROW_KILLS)
  2963.                 player_data[id][PLAYER_STATS][STATS_DEATHS] = SQL_ReadResult(sqlQue,ROW_DEATHS)
  2964.                 player_data[id][PLAYER_STATS][STATS_HS] = SQL_ReadResult(sqlQue,ROW_HS)
  2965.                 player_data[id][PLAYER_STATS][STATS_TK] = SQL_ReadResult(sqlQue,ROW_TKS)
  2966.                 player_data[id][PLAYER_STATS][STATS_SHOTS] = SQL_ReadResult(sqlQue,ROW_SHOTS)
  2967.                 player_data[id][PLAYER_STATS][STATS_HITS] = SQL_ReadResult(sqlQue,ROW_HITS)
  2968.                 player_data[id][PLAYER_STATS][STATS_DMG] = SQL_ReadResult(sqlQue,ROW_DMG)
  2969.                
  2970.                 // статистика cstrike
  2971.                 player_data[id][PLAYER_STATS2][STATS2_DEFAT] = SQL_ReadResult(sqlQue,ROW_BOMBDEF)
  2972.                 player_data[id][PLAYER_STATS2][STATS2_DEFOK] = SQL_ReadResult(sqlQue,ROW_BOMBDEFUSED)
  2973.                 player_data[id][PLAYER_STATS2][STATS2_PLAAT] = SQL_ReadResult(sqlQue,ROW_BOMBPLANTS)
  2974.                 player_data[id][PLAYER_STATS2][STATS2_PLAOK] = SQL_ReadResult(sqlQue,ROW_BOMBEXPLOSIONS)
  2975.                
  2976.                 // время онлайн
  2977.                 player_data[id][PLAYER_ONLINE] = player_data[id][PLAYER_ONLINELAST] = SQL_ReadResult(sqlQue,ROW_ONLINETIME)
  2978.                
  2979.                 // скилл
  2980.                 SQL_ReadResult(sqlQue,ROW_SKILL,player_data[id][PLAYER_SKILL])
  2981.                 player_data[id][PLAYER_SKILLLAST] = _:player_data[id][PLAYER_SKILL]
  2982. //              log_amx("[CSTX %d] %f (Sql Load)", id, player_data[id][PLAYER_SKILL]);
  2983.  
  2984.                
  2985.                 // посл подключение и первое подкчлючение
  2986.                 new date_str[32]
  2987.                
  2988.                 SQL_ReadResult(sqlQue,ROW_FIRSTJOIN,date_str,charsmax(date_str))
  2989.                 player_data[id][PLAYER_FIRSTJOIN] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
  2990.                 SQL_ReadResult(sqlQue,ROW_LASTJOIN,date_str,charsmax(date_str))
  2991.                 player_data[id][PLAYER_LASTJOIN] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
  2992.                
  2993.                 // доп. запросы
  2994.                 player_data[id][PLAYER_RANK] = SQL_ReadResult(sqlQue,row_ids)   // ранк игрока
  2995.                 statsnum = SQL_ReadResult(sqlQue,row_ids + 1)           // общее кол-во игроков в БД
  2996.                
  2997.                 // статистика попаданий
  2998.                 for(new i ; i < sizeof player_data[][PLAYER_HITS] ; i++)
  2999.                 {
  3000.                     player_data[id][PLAYER_HITS][i] = SQL_ReadResult(sqlQue,ROW_H0 + i)
  3001.                 }
  3002.                
  3003.                 // 0.7
  3004.                 for(new i = STATS3_CONNECT ; i < sizeof player_data[][PLAYER_STATS3] ; i++)
  3005.                 {
  3006.                     player_data[id][PLAYER_STATS3][i] = player_data[id][PLAYER_STATS3LAST][i] = SQL_ReadResult(sqlQue,(i - 1) + ROW_CONNECTS)
  3007.                    
  3008.                     // плюсуем стату подключений
  3009.                     if(i == STATS3_CONNECT)
  3010.                     {
  3011.                         player_data[id][PLAYER_STATS3][i] ++
  3012.                     }
  3013.                 }
  3014.                
  3015.                 if(weapon_stats_enabled)
  3016.                 {
  3017.                     DB_LoadPlayerWstats(id)
  3018.                 }
  3019.  
  3020.                 // запихиваем инфу в forward и шлём на .. плагины (альтернатива get_user_stats_sql)
  3021.                 ExecuteForward(FW_SQLRead,dummy_ret,id,player_data[id])
  3022.             }
  3023.             else // помечаем как нового игрока
  3024.             {
  3025.                 player_data[id][PLAYER_LOADSTATE] = LOAD_NEW
  3026.                
  3027.                 DB_SavePlayerData(id) // добавляем запись в базу данных
  3028.             }
  3029.         }
  3030.         case SQL_INSERT:    // запись новых данных
  3031.         {
  3032.             new id = data[1]
  3033.            
  3034.             if(is_user_connected(id))
  3035.             {
  3036.                 if(player_data[id][PLAYER_LOADSTATE] == LOAD_UPDATE)
  3037.                 {
  3038.                     player_data[id][PLAYER_LOADSTATE] = LOAD_NO
  3039.                     DB_LoadPlayerData(id)
  3040.                    
  3041.                     return PLUGIN_HANDLED
  3042.                 }
  3043.                
  3044.                 player_data[id][PLAYER_ID] = SQL_GetInsertId(sqlQue)    // первичный ключ
  3045.                 player_data[id][PLAYER_LOADSTATE] = LOAD_OK     // данные загружены
  3046.                
  3047.                 // я упрлся 0)0)0
  3048.                
  3049.                 // обновляем счетчик общего кол-ва записей
  3050.                 statsnum++
  3051.                
  3052.                 if(weapon_stats_enabled)
  3053.                 {
  3054.                     DB_LoadPlayerWstats(id)
  3055.                 }
  3056.             }
  3057.            
  3058.             // обновляем позици игроков
  3059.             // действие с задержкой, что-бы учесть изменения при множественном обновлении данных
  3060.             if(!task_exists(task_rankupdate))
  3061.             {
  3062.                 set_task(1.0,"DB_GetPlayerRanks",task_rankupdate)
  3063.             }
  3064.         }
  3065.         case SQL_UPDATE: // обновление данных
  3066.         {
  3067.             // обновляем позици игроков
  3068.             // действие с задержкой, что-бы учесть изменения при множественном обновлении данных
  3069.             if(!task_exists(task_rankupdate))
  3070.             {
  3071.                 set_task(0.1,"DB_GetPlayerRanks",task_rankupdate)
  3072.             }
  3073.            
  3074.             new players[MAX_PLAYERS],pnum
  3075.             get_players(players,pnum)
  3076.            
  3077.             for(new i,player ; i < pnum ; i++)
  3078.             {
  3079.                 player = players[i]
  3080.                
  3081.                 if(player_data[player][PLAYER_LOADSTATE] == LOAD_UPDATE)
  3082.                 {
  3083.                     player_data[player][PLAYER_LOADSTATE] = LOAD_NO
  3084.                     DB_LoadPlayerData(player)
  3085.                 }
  3086.             }
  3087.            
  3088.             if(update_cache)
  3089.             {
  3090.                 update_cache = false
  3091.                
  3092.                 Cache_Stats_Update()
  3093.                 Cache_Stats_UpdateQueue()
  3094.             }
  3095.         }
  3096.         case SQL_UPDATERANK:
  3097.         {
  3098.             while(SQL_MoreResults(sqlQue))
  3099.             {
  3100.                 new pK =  SQL_ReadResult(sqlQue,0)
  3101.                 new rank = SQL_ReadResult(sqlQue,1)
  3102.                
  3103.                 for(new i ; i < MAX_PLAYERS ; i++)
  3104.                 {
  3105.                     if(player_data[i][PLAYER_ID] == pK) // задаем ранк по первичному ключу
  3106.                     {
  3107.                         player_data[i][PLAYER_RANK] = rank
  3108.                     }
  3109.                 }
  3110.                
  3111.                 SQL_NextRow(sqlQue)
  3112.             }
  3113.         }
  3114.         case SQL_GETSTATS: // потоковый get_stats
  3115.         {
  3116.             new id = data[1]
  3117.            
  3118.             if(id && !is_user_connected(id))
  3119.             {
  3120.                 return PLUGIN_HANDLED
  3121.             }
  3122.            
  3123.             new index = data[5]
  3124.             new name[32],authid[30]
  3125.            
  3126.             // кешируем ответ
  3127.             while(DB_ReadGetStats(sqlQue,name,charsmax(name),authid,charsmax(authid),.index = index ++))
  3128.             {
  3129.             }
  3130.            
  3131.             if(data[3] > -1)
  3132.             {
  3133.                 // вызываем хандлер другого плагина
  3134.                 if(callfunc_begin_i(data[3],data[2]))
  3135.                 {
  3136.                     callfunc_push_int(id)
  3137.                     callfunc_push_int(data[4])
  3138.                     callfunc_end()
  3139.                 }
  3140.             }
  3141.         }
  3142.        
  3143.         // 0.7
  3144.         case SQL_GETWSTATS:
  3145.         {
  3146.             new id = data[1]
  3147.            
  3148.             if(!is_user_connected(id))
  3149.             {
  3150.                 return PLUGIN_HANDLED
  3151.             }
  3152.            
  3153.             const load_index = sizeof player_awstats[][] - 1
  3154.            
  3155.             // загружаем статистику по оружию
  3156.             while(SQL_MoreResults(sqlQue))
  3157.             {
  3158.                 new log[MAX_NAME_LENGTH]
  3159.                 SQL_ReadResult(sqlQue,ROW_WEAPON_NAME,log,charsmax(log))
  3160.                
  3161.                 new wpn = Info_Weapon_GetId(log)
  3162.                
  3163.                 if(wpn == -1)
  3164.                 {
  3165.                     continue
  3166.                 }
  3167.                
  3168.                 for(new i ; i < STATS_END + HIT_END ; i++)
  3169.                 {
  3170.                     player_awstats[id][wpn][i] = SQL_ReadResult(sqlQue,i + ROW_WEAPON_KILLS)
  3171.                 }
  3172.                
  3173.                 player_awstats[id][wpn][load_index] = _:LOAD_OK
  3174.                    
  3175.                 SQL_NextRow(sqlQue)
  3176.             }
  3177.            
  3178.             // помечаем статистику по другим оружиям как новую
  3179.             for(new wpn ; wpn < MAX_WEAPONS ; wpn++)
  3180.             {
  3181.                 if(_:player_awstats[id][wpn][load_index] != _:LOAD_OK)
  3182.                 {
  3183.                     player_awstats[id][wpn][load_index] = _:LOAD_NEW
  3184.                 }
  3185.             }
  3186.         }
  3187.         case SQL_GETSESSID:
  3188.         {
  3189.             session_id = SQL_ReadResult(sqlQue,0) + 1
  3190.             get_mapname(session_map,charsmax(session_map))
  3191.            
  3192.             DB_InitSeq()
  3193.         }
  3194.         // get_sestats_thread_sql
  3195.         case SQL_GETSESTATS:
  3196.         {
  3197.             new Array:sestats_array = ArrayCreate(sestats_array_struct)
  3198.             new sestats_data[sestats_array_struct]
  3199.            
  3200.             while(SQL_MoreResults(sqlQue))
  3201.             {
  3202.                 arrayset(sestats_data,0,sestats_array_struct)
  3203.                
  3204.                 // заполняем массив со статой сессии
  3205.                 for(new i = ROW_MAP_ID ; i <= ROW_MAP_LASTJOIN ; i++)
  3206.                 {
  3207.                     switch(i)
  3208.                     {
  3209.                         case ROW_MAP_ID: sestats_data[SESTATS_ID] = SQL_ReadResult(sqlQue,i)
  3210.                         case ROW_MAP_PLRID: sestats_data[SESTATS_PLAYERID] = SQL_ReadResult(sqlQue,i)
  3211.                         case ROW_MAP_MAP: SQL_ReadResult(sqlQue,i,sestats_data[SESTATS_MAP],charsmax(sestats_data[SESTATS_MAP]))
  3212.                         case ROW_MAP_SKILL: SQL_ReadResult(sqlQue,i,sestats_data[SESTATS_SKILL])
  3213.                         case ROW_MAP_KILLS..ROW_MAP_DMG: sestats_data[SESTATS_STATS][(i - ROW_MAP_KILLS)] = SQL_ReadResult(sqlQue,i)
  3214.                         case ROW_MAP_H0..ROW_MAP_H7: sestats_data[SESTATS_HITS][(i - ROW_MAP_H0)] = SQL_ReadResult(sqlQue,i)
  3215.                         case ROW_MAP_BOMBDEF..ROW_MAP_BOMBEXPLOSIONS: sestats_data[SESTATS_STATS2][(i - ROW_MAP_BOMBDEF)] = SQL_ReadResult(sqlQue,i)
  3216.                         case ROW_MAP_ROUNDT..ROW_MAP_ASSISTS: sestats_data[SESTATS_STATS3][((i - ROW_MAP_ROUNDT) + 1)] = SQL_ReadResult(sqlQue,i)
  3217.                         case ROW_MAP_ONLINETIME: sestats_data[SESTATS_ONLINETIME] = SQL_ReadResult(sqlQue,i)
  3218.                         case ROW_MAP_FIRSTJOIN,ROW_LASTJOIN:
  3219.                         {
  3220.                             new date_str[32]
  3221.                             SQL_ReadResult(sqlQue,i,date_str,charsmax(date_str))
  3222.                            
  3223.                             sestats_data[(SESTATS_FIRSTJOIN + (i - ROW_MAP_FIRSTJOIN))] = parse_time(date_str,"%Y-%m-%d %H:%M:%S")
  3224.                         }
  3225.                     }
  3226.                 }
  3227.                
  3228.                 ArrayPushArray(sestats_array,sestats_data)
  3229.                
  3230.                 SQL_NextRow(sqlQue)
  3231.             }
  3232.            
  3233.             new func_id = data[1]
  3234.             new plugin_id = data[2]
  3235.            
  3236.             if(callfunc_begin_i(func_id,plugin_id))
  3237.             {
  3238.                 callfunc_push_int(int:sestats_array)
  3239.                
  3240.                 // передаваемые данные
  3241.                 if(dataSize > 3)
  3242.                 {
  3243.                     new cb_data[MAX_DATA_PARAMS]
  3244.                    
  3245.                     for(new i ; i < (dataSize - 3) ; i++)
  3246.                     {
  3247.                         cb_data[i] = data[(3 + i)]
  3248.                     }
  3249.                    
  3250.                     callfunc_push_array(cb_data,(dataSize - 3))
  3251.                     callfunc_push_int((dataSize - 3))
  3252.                 }
  3253.                
  3254.                 callfunc_end()
  3255.             }
  3256.             else
  3257.             {
  3258.                 log_amx("get_sestats_thread_sql callback function failed")
  3259.             }
  3260.         }
  3261.         case SQL_AUTOCLEAR:
  3262.         {
  3263.             if(SQL_AffectedRows(sqlQue))
  3264.             {
  3265.                 log_amx("deleted %d inactive entries",
  3266.                     SQL_AffectedRows(sqlQue)
  3267.                 )
  3268.             }
  3269.            
  3270.             DB_InitSeq()
  3271.         }
  3272.     }
  3273.  
  3274.     return PLUGIN_HANDLED
  3275. }
  3276.  
  3277. //
  3278. // Поиск ID оружия по его лог коду
  3279. //
  3280. Info_Weapon_GetId(weapon[])
  3281. {
  3282.     new weapon_info[WEAPON_INFO_SIZE]
  3283.     new length = ArraySize(weapons_data)
  3284.    
  3285.     for(new i ; i < length; i++)
  3286.     {
  3287.         ArrayGetArray(weapons_data,i,weapon_info)
  3288.        
  3289.         new weapon_name[MAX_NAME_LENGTH]
  3290.         copy(weapon_name,charsmax(weapon_name),weapon_info[MAX_NAME_LENGTH])
  3291.        
  3292.         if(strcmp(weapon_name,weapon) == 0)
  3293.         {
  3294.             return i
  3295.         }
  3296.     }
  3297.    
  3298.     return -1
  3299. }
  3300.  
  3301. //
  3302. // Поиск лог кода по ID оружия
  3303. //
  3304. Info_Weapon_GetLog(wpn_id,weapon_name[],len)
  3305. {
  3306.     if(!(0 < wpn_id < ArraySize(weapons_data)))
  3307.     {
  3308.         formatex(weapon_name,len,"")
  3309.         return
  3310.     }
  3311.    
  3312.     new weapon_info[WEAPON_INFO_SIZE]
  3313.     ArrayGetArray(weapons_data,wpn_id,weapon_info)
  3314.    
  3315.     copy(weapon_name,len,weapon_info[MAX_NAME_LENGTH])
  3316. }
  3317.  
  3318. /*
  3319. *
  3320. * API
  3321. *
  3322. */
  3323.  
  3324. #define CHECK_PLAYER(%1) \
  3325.     if (%1 < 1 || %1 > MaxClients) { \
  3326.         log_error(AMX_ERR_NATIVE, "Player out of range (%d)", %1); \
  3327.         return 0; \
  3328.     } else { \
  3329.         if (!is_user_connected(%1) || pev_valid(%1) != 2) { \
  3330.             log_error(AMX_ERR_NATIVE, "Invalid player %d", %1); \
  3331.             return 0; \
  3332.         } \
  3333.     }
  3334.    
  3335. #define CHECK_PLAYERRANGE(%1) \
  3336.     if(%1 < 0 || %1 > MaxClients) {\
  3337.         log_error(AMX_ERR_NATIVE,"Player out of range (%d)",%1);\
  3338.         return 0;\
  3339.     }
  3340.    
  3341. #define CHECK_WEAPON(%1) \
  3342.     if(!(0 <= %1 < ArraySize(weapons_data))){\
  3343.         log_error(AMX_ERR_NATIVE,"Invalid weapon id %d",%1);\
  3344.         return 0;\
  3345.     }
  3346.    
  3347. public plugin_natives()
  3348. {
  3349.     // default csstats
  3350.     register_library("xstats")
  3351.    
  3352.     register_native("get_user_wstats","native_get_user_wstats")
  3353.     register_native("get_user_wrstats","native_get_user_wrstats")
  3354.     register_native("get_user_stats","native_get_user_stats")
  3355.     register_native("get_user_rstats","native_get_user_rstats")
  3356.     register_native("get_user_vstats","native_get_user_vstats")
  3357.     register_native("get_user_astats","native_get_user_astats")
  3358.     register_native("reset_user_wstats","native_reset_user_wstats")
  3359.     register_native("get_stats","native_get_stats")
  3360.     register_native("get_statsnum","native_get_statsnum")
  3361.     register_native("get_user_stats2","native_get_user_stats2")
  3362.     register_native("get_stats2","native_get_stats2")
  3363.    
  3364.     register_native("xmod_is_melee_wpn","native_xmod_is_melee_wpn")
  3365.     register_native("xmod_get_wpnname","native_xmod_get_wpnname")
  3366.     register_native("xmod_get_wpnlogname","native_xmod_get_wpnlogname")
  3367.     register_native("xmod_get_maxweapons","native_xmod_get_maxweapons")
  3368.     register_native("xmod_get_stats_size","native_get_statsnum")
  3369.     register_native("get_map_objectives","native_get_map_objectives")
  3370.    
  3371.     register_native("custom_weapon_add","native_custom_weapon_add")
  3372.     register_native("custom_weapon_dmg","native_custom_weapon_dmg")
  3373.     register_native("custom_weapon_shot","native_custom_weapon_shot")
  3374.    
  3375.     register_library("csstatsx_sql")
  3376.    
  3377.     // csstats mysql
  3378.     register_native("get_statsnum_sql","native_get_statsnum")
  3379.     register_native("get_user_stats_sql","native_get_user_stats")
  3380.     register_native("get_stats_sql","native_get_stats")
  3381.     register_native("get_stats_sql_thread","native_get_stats_thread")
  3382.     register_native("get_stats2_sql","native_get_stats2")
  3383.     register_native("get_user_skill","native_get_user_skill")
  3384.     register_native("get_skill","native_get_skill")
  3385.    
  3386.     // 0.5.1
  3387.     register_native("get_user_gametime","native_get_user_gametime")
  3388.     register_native("get_stats_gametime","native_get_stats_gametime")
  3389.     register_native("get_user_stats_id","native_get_user_stats_id")
  3390.     register_native("get_stats_id","native_get_stats_id")
  3391.     register_native("update_stats_cache","native_update_stats_cache")
  3392.    
  3393.     // 0.7
  3394.     register_native("get_user_stats3_sql","native_get_user_stats3")
  3395.     register_native("get_stats3_sql","native_get_stats3")
  3396.     register_native("get_user_wstats_sql","native_get_user_wstats_sql")
  3397.     register_native("get_sestats_thread_sql","native_get_sestats_thread_sql")
  3398.     register_native("get_sestats_read_count","native_get_sestats_read_count")
  3399.     register_native("get_sestats_read_stats","native_get_sestats_read_stats")
  3400.     register_native("get_sestats_read_stats2","native_get_sestats_read_stats2")
  3401.     register_native("get_sestats_read_stats3","native_get_sestats_read_stats3")
  3402.     register_native("get_sestats_read_online","native_get_sestats_read_online")
  3403.     register_native("get_sestats_read_skill","native_get_sestats_read_skill")
  3404.     register_native("get_sestats_read_map","native_get_sestats_read_map")
  3405.     register_native("get_sestats_read_stime","native_get_sestats_read_stime")
  3406.     register_native("get_sestats_read_etime","native_get_sestats_read_etime")
  3407.     register_native("get_sestats_free","native_get_sestats_free")
  3408.     register_native("get_user_firstjoin_sql","native_get_user_firstjoin_sql")
  3409.     register_native("get_user_lastjoin_sql","native_get_user_lastjoin_sql")
  3410.    
  3411.     // 0.7.2
  3412.     register_native("xmod_get_maxweapons_sql","native_xmod_get_maxweapons")
  3413. }
  3414.  
  3415. public native_get_user_firstjoin_sql(plugin_id,params)
  3416. {
  3417.     new id = get_param(1)
  3418.     CHECK_PLAYERRANGE(id)
  3419.    
  3420.     if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
  3421.     {
  3422.         return -1
  3423.     }
  3424.    
  3425.     return player_data[id][PLAYER_FIRSTJOIN]
  3426. }
  3427.  
  3428. public native_get_user_lastjoin_sql(plugin_id,params)
  3429. {
  3430.     new id = get_param(1)
  3431.     CHECK_PLAYERRANGE(id)
  3432.    
  3433.     if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
  3434.     {
  3435.         return -1
  3436.     }
  3437.    
  3438.     return player_data[id][PLAYER_LASTJOIN]
  3439. }
  3440.  
  3441. public native_get_sestats_read_stime(plugin_id,params)
  3442. {
  3443.     new Array:sestats = Array:get_param(1)
  3444.     new index = get_param(2)
  3445.    
  3446.     new sestats_size = ArraySize(sestats)
  3447.    
  3448.     if(!(0 <= index < sestats_size))
  3449.     {
  3450.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3451.         return 0
  3452.     }
  3453.    
  3454.     new sestats_data[sestats_array_struct]
  3455.     ArrayGetArray(sestats,index,sestats_data)
  3456.    
  3457.     return sestats_data[SESTATS_FIRSTJOIN]
  3458. }
  3459.  
  3460. public native_get_sestats_read_etime(plugin_id,params)
  3461. {
  3462.     new Array:sestats = Array:get_param(1)
  3463.     new index = get_param(2)
  3464.    
  3465.     new sestats_size = ArraySize(sestats)
  3466.    
  3467.     if(!(0 <= index < sestats_size))
  3468.     {
  3469.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3470.         return 0
  3471.     }
  3472.    
  3473.     new sestats_data[sestats_array_struct]
  3474.     ArrayGetArray(sestats,index,sestats_data)
  3475.    
  3476.     return sestats_data[SESTATS_LASTJOIN]
  3477. }
  3478.  
  3479. public native_get_sestats_free(plugin_id,params)
  3480. {
  3481.     new sestats = get_param_byref(1)
  3482.     ArrayDestroy(Array:sestats)
  3483.     set_param_byref(1,0)
  3484.     return true
  3485. }
  3486.  
  3487. public native_get_sestats_read_map(plugin_id,params)
  3488. {
  3489.     new Array:sestats = Array:get_param(1)
  3490.     new index = get_param(2)
  3491.     new length = get_param(4)
  3492.    
  3493.     new sestats_size = ArraySize(sestats)
  3494.    
  3495.     if(!(0 <= index < sestats_size))
  3496.     {
  3497.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3498.         return 0
  3499.     }
  3500.    
  3501.     new sestats_data[sestats_array_struct]
  3502.     ArrayGetArray(sestats,index,sestats_data)
  3503.    
  3504.     return set_string(3,sestats_data[SESTATS_MAP],length)
  3505. }
  3506.  
  3507. public Float:native_get_sestats_read_skill(plugin_id,params)
  3508. {
  3509.     new Array:sestats = Array:get_param(1)
  3510.     new index = get_param(2)
  3511.    
  3512.     new sestats_size = ArraySize(sestats)
  3513.    
  3514.     if(!(0 <= index < sestats_size))
  3515.     {
  3516.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3517.         return 0.0
  3518.     }
  3519.    
  3520.     new sestats_data[sestats_array_struct]
  3521.     ArrayGetArray(sestats,index,sestats_data)
  3522.    
  3523.     return sestats_data[SESTATS_SKILL]
  3524. }
  3525.  
  3526. public native_get_sestats_read_online(plugin_id,params)
  3527. {
  3528.     new Array:sestats = Array:get_param(1)
  3529.     new index = get_param(2)
  3530.    
  3531.     new sestats_size = ArraySize(sestats)
  3532.    
  3533.     if(!(0 <= index < sestats_size))
  3534.     {
  3535.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3536.         return 0
  3537.     }
  3538.    
  3539.     new sestats_data[sestats_array_struct]
  3540.     ArrayGetArray(sestats,index,sestats_data)
  3541.    
  3542.     return sestats_data[SESTATS_ONLINETIME]
  3543. }
  3544.  
  3545. public native_get_sestats_read_stats(plugin_id,params)
  3546. {
  3547.     new Array:sestats = Array:get_param(1)
  3548.     new index = get_param(2)
  3549.    
  3550.     new sestats_size = ArraySize(sestats)
  3551.    
  3552.     if(!(0 <= index < sestats_size))
  3553.     {
  3554.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3555.         return 0
  3556.     }
  3557.    
  3558.     new sestats_data[sestats_array_struct]
  3559.     ArrayGetArray(sestats,index,sestats_data)
  3560.    
  3561.     set_array(3,sestats_data[SESTATS_STATS],8)
  3562.     set_array(4,sestats_data[SESTATS_HITS],8)
  3563.    
  3564.     index ++
  3565.    
  3566.     return (index >= sestats_size) ? 0 : index
  3567. }
  3568.  
  3569. public native_get_sestats_read_stats2(plugin_id,params)
  3570. {
  3571.     new Array:sestats = Array:get_param(1)
  3572.     new index = get_param(2)
  3573.    
  3574.     new sestats_size = ArraySize(sestats)
  3575.    
  3576.     if(!(0 <= index < sestats_size))
  3577.     {
  3578.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3579.         return 0
  3580.     }
  3581.    
  3582.     new sestats_data[sestats_array_struct]
  3583.     ArrayGetArray(sestats,index,sestats_data)
  3584.    
  3585.     set_array(3,sestats_data[SESTATS_STATS2],4)
  3586.    
  3587.     index ++
  3588.    
  3589.     return (index >= sestats_size) ? 0 : index
  3590. }
  3591.  
  3592. public native_get_sestats_read_stats3(plugin_id,params)
  3593. {
  3594.     new Array:sestats = Array:get_param(1)
  3595.     new index = get_param(2)
  3596.    
  3597.     new sestats_size = ArraySize(sestats)
  3598.    
  3599.     if(!(0 < index < sestats_size))
  3600.     {
  3601.         log_error(AMX_ERR_NATIVE,"Stats index out of range (%d)",index)
  3602.         return 0
  3603.     }
  3604.    
  3605.     new sestats_data[sestats_array_struct]
  3606.     ArrayGetArray(sestats,index,sestats_data)
  3607.    
  3608.     set_array(3,sestats_data[SESTATS_STATS3],STATS3_END)
  3609.    
  3610.     index ++
  3611.    
  3612.     return (index >= sestats_size) ? 0 : index
  3613. }
  3614.  
  3615. public native_get_sestats_read_count(plugin_id,params)
  3616. {
  3617.     new Array:sestats = Array:get_param(1)
  3618.    
  3619.     return ArraySize(sestats)
  3620. }
  3621.  
  3622. public native_get_sestats_thread_sql(plugin_id,params)
  3623. {
  3624.     // статистика по картам выключена
  3625.     if(session_id == 0)
  3626.     {
  3627.         return false
  3628.     }
  3629.    
  3630.     new callback_func[32]
  3631.     get_string(2,callback_func,charsmax(callback_func))
  3632.    
  3633.     new func_id = get_func_id(callback_func,plugin_id)
  3634.    
  3635.     // функция ответа не найдена
  3636.     if(func_id == -1)
  3637.     {
  3638.         log_error(AMX_ERR_NATIVE,"Callback function ^"%s^" not found",callback_func)
  3639.         return false
  3640.     }
  3641.    
  3642.     new data_size = get_param(4)
  3643.    
  3644.     if(data_size > MAX_DATA_PARAMS)
  3645.     {
  3646.         log_error(AMX_ERR_NATIVE,"Max data size %d reached.",MAX_DATA_PARAMS)
  3647.         return false
  3648.     }
  3649.    
  3650.     // подготавливаем данные
  3651.     new sql_data[3 + MAX_DATA_PARAMS],data_array[MAX_DATA_PARAMS]
  3652.    
  3653.     sql_data[0] = SQL_GETSESTATS
  3654.     sql_data[1] = func_id
  3655.     sql_data[2] = plugin_id
  3656.    
  3657.     // передаваемые данные
  3658.     if(data_size)
  3659.     {
  3660.         get_array(3,data_array,data_size)
  3661.        
  3662.         for(new i ; i < data_size ; i++)
  3663.         {
  3664.             sql_data[i + 3] = data_array[i]
  3665.         }
  3666.     }
  3667.    
  3668.     new player_db_id = get_param(1) // ищем по ID игрока
  3669.     new limit = get_param(5)        // лимит на выборку
  3670.    
  3671.     new query[QUERY_LENGTH]
  3672.    
  3673.     formatex(query,charsmax(query),"SELECT * FROM `%s_maps` WHERE `%s` = '%d' ORDER BY `%s` DESC LIMIT %d",
  3674.         tbl_name,
  3675.         row_weapons_names[ROW_WEAPON_PLAYER],player_db_id,
  3676.         row_names[ROW_FIRSTJOIN],limit
  3677.     )
  3678.     SQL_ThreadQuery(sql,"SQL_Handler",query,sql_data,3 + data_size)
  3679.    
  3680.     return true
  3681. }
  3682.  
  3683. public native_get_user_wstats_sql(plugin_id,params)
  3684. {
  3685.     if(params != 4)
  3686.     {
  3687.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
  3688.        
  3689.         return false
  3690.     }
  3691.    
  3692.     if(!weapon_stats_enabled)
  3693.     {
  3694.         return -1
  3695.     }
  3696.    
  3697.     new player_id = get_param(1)
  3698.     CHECK_PLAYERRANGE(player_id)
  3699.    
  3700.     new weapon_id = get_param(2)
  3701.     CHECK_WEAPON(weapon_id)
  3702.    
  3703.     new stats[8],bh[8]
  3704.    
  3705.     const stats_index_last = (STATS_END + HIT_END)
  3706.    
  3707.     for(new i ; i < STATS_END ; i++)
  3708.     {
  3709.         stats[i] = player_awstats[player_id][weapon_id][i] + player_awstats[player_id][weapon_id][i + stats_index_last]
  3710.     }
  3711.    
  3712.     // игрок не пользовался этим оружием
  3713.     if(!stats[STATS_DEATHS] &&  !stats[STATS_SHOTS])
  3714.     {
  3715.         return false
  3716.     }
  3717.    
  3718.     for(new i = STATS_END ; i < (STATS_END + HIT_END) ; i ++)
  3719.     {
  3720.         bh[(i - STATS_END)] = player_awstats[player_id][weapon_id][i] + player_awstats[player_id][weapon_id][i + stats_index_last]
  3721.     }
  3722.    
  3723.     set_array(3,stats,sizeof stats)
  3724.     set_array(4,bh,sizeof bh)
  3725.    
  3726.     return true
  3727. }
  3728.  
  3729. public native_update_stats_cache()
  3730. {
  3731.     return Cache_Stats_Update()
  3732. }
  3733.  
  3734. /*
  3735. * Функция возвращает онлайн время игрока
  3736. *
  3737. * native get_user_gametime(id)
  3738. */
  3739. public native_get_user_gametime(plugin_id,params)
  3740. {
  3741.     new id = get_param(1)
  3742.     CHECK_PLAYERRANGE(id)
  3743.    
  3744.     if(player_data[id][PLAYER_LOADSTATE] == LOAD_NO)
  3745.     {
  3746.         return -1
  3747.     }
  3748.    
  3749.     return player_data[id][PLAYER_ONLINE]
  3750. }
  3751.  
  3752. /*
  3753. * Получение времени по позиции
  3754. *
  3755. * native get_stats_gametime(index,&game_time)
  3756. */
  3757. public native_get_stats_gametime(plugin_id,params)
  3758. {
  3759.     new index = get_param(1)    // индекс в статистике
  3760.    
  3761.     // кеширование
  3762.     new index_str[10],stats_cache[stats_cache_struct]
  3763.     num_to_str(index,index_str,charsmax(index_str))
  3764.    
  3765.     // есть информация в кеше
  3766.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  3767.     {
  3768.         set_param_byref(2,stats_cache[CACHE_TIME])
  3769.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  3770.     }
  3771.     // кеширование
  3772.    
  3773.     return 0
  3774. }
  3775.  
  3776.  
  3777. /*
  3778. * Функция возрващает ID игрока в БД
  3779. *
  3780. * native get_user_stats_id(id)
  3781. */
  3782. public native_get_user_stats_id(plugin_id,params)
  3783. {
  3784.     new id = get_param(1)
  3785.     CHECK_PLAYERRANGE(id)
  3786.    
  3787.     return player_data[id][PLAYER_ID]
  3788. }
  3789.  
  3790. /*
  3791. * Получение ID по позиции
  3792. *
  3793. * native get_stats_id(index,&db_id)
  3794. */
  3795. public native_get_stats_id(plugin_id,params)
  3796. {
  3797.     new index = get_param(1)    // индекс в статистике
  3798.    
  3799.     // кеширование
  3800.     new index_str[10],stats_cache[stats_cache_struct]
  3801.     num_to_str(index,index_str,charsmax(index_str))
  3802.    
  3803.     // есть информация в кеше
  3804.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  3805.     {
  3806.         set_param_byref(2,stats_cache[CACHE_ID])
  3807.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  3808.     }
  3809.     // кеширование
  3810.    
  3811.     return 0
  3812. }
  3813.  
  3814. /*
  3815. * Функция возрващает скилл игрока
  3816. *
  3817. * native get_user_skill(player,&Float:skill)
  3818. */
  3819. public native_get_user_skill(plugin_id,params)
  3820. {
  3821.     new id = get_param(1)
  3822.     CHECK_PLAYERRANGE(id)
  3823.    
  3824.     set_float_byref(2,player_data[id][PLAYER_SKILL])
  3825.    
  3826.     return true
  3827. }
  3828.  
  3829.  
  3830. /*
  3831. * Получение скилла по позиции
  3832. *
  3833. * native get_skill(index,&Float:skill)
  3834. */
  3835. public native_get_skill(plugin_id,params)
  3836. {
  3837.     new index = get_param(1)    // индекс в статистике
  3838.    
  3839.     // кеширование
  3840.     new index_str[10],stats_cache[stats_cache_struct]
  3841.    
  3842.     if(index < 0)
  3843.         index = 0
  3844.    
  3845.     num_to_str(index,index_str,charsmax(index_str))
  3846.    
  3847.     // есть информация в кеше
  3848.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  3849.     {
  3850. //      log_amx("[CSTX %d] %f (Native Skill)", index, Float:stats_cache[CACHE_SKILL]);
  3851.         set_float_byref(2,Float:stats_cache[CACHE_SKILL])
  3852.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  3853.     }
  3854.     // кеширование
  3855.  
  3856.     return 0
  3857. }
  3858.  
  3859. /*
  3860. * Добавление кастомного оружия для статистики
  3861. *
  3862. * native custom_weapon_add(const wpnname[], melee = 0, const logname[] = "")
  3863. */
  3864. public native_custom_weapon_add(plugin_id,params)
  3865. {
  3866.     if(ArraySize(weapons_data) >= MAX_WEAPONS)
  3867.     {
  3868.         return 0
  3869.     }
  3870.    
  3871.     new weapon_name[MAX_NAME_LENGTH],weapon_log[MAX_NAME_LENGTH],is_melee
  3872.     get_string(1,weapon_name,charsmax(weapon_name))
  3873.    
  3874.     if(params >= 2) // задан флаг is_melee
  3875.         is_melee = get_param(2)
  3876.        
  3877.     if(params == 3) // указан лог код
  3878.     {
  3879.         get_string(3,weapon_log,charsmax(weapon_log))
  3880.     }
  3881.     else // копируем название оружия для лог кода
  3882.     {
  3883.         copy(weapon_log,charsmax(weapon_log),weapon_name)
  3884.     }
  3885.    
  3886.     // регистриурем
  3887.     new weapon_info[WEAPON_INFO_SIZE]
  3888.     REG_INFO(is_melee,weapon_name,weapon_info)
  3889.    
  3890.     return ArraySize(weapons_data) - 1
  3891. }
  3892.  
  3893. /*
  3894. * Учет урона кастомного оружия
  3895. *
  3896. * native custom_weapon_dmg(weapon, att, vic, damage, hitplace = 0)
  3897. */
  3898. public native_custom_weapon_dmg(plugin_id,params)
  3899. {
  3900.     new weapon_id = get_param(1)
  3901.    
  3902.     CHECK_WEAPON(weapon_id)
  3903.    
  3904.     new att = get_param(2)
  3905.    
  3906.     CHECK_PLAYERRANGE(att)
  3907.    
  3908.     new vic = get_param(3)
  3909.    
  3910.     CHECK_PLAYERRANGE(vic)
  3911.    
  3912.     new dmg = get_param(4)
  3913.    
  3914.     if(dmg < 1)
  3915.     {
  3916.         log_error(AMX_ERR_NATIVE,"Invalid damage %d", dmg)
  3917.        
  3918.         return 0
  3919.     }
  3920.    
  3921.     new hit_place = get_param(5)
  3922.    
  3923.     return Stats_SaveHit(att,vic,dmg,weapon_id,hit_place)
  3924. }
  3925.  
  3926. /*
  3927. * Регистрация выстрела кастомного оружия
  3928. *
  3929. * native custom_weapon_shot(weapon, index)
  3930. */
  3931. public native_custom_weapon_shot(plugin_id,params)
  3932. {
  3933.     new weapon_id = get_param(1)
  3934.    
  3935.     CHECK_WEAPON(weapon_id)
  3936.    
  3937.     new id = get_param(2)
  3938.    
  3939.     CHECK_PLAYERRANGE(id)
  3940.    
  3941.     return Stats_SaveShot(id,weapon_id)
  3942. }
  3943.  
  3944. /*
  3945. * Возвращает true, если оружие рукопашного боя
  3946. *
  3947. * native xmod_is_melee_wpn(wpnindex)
  3948. */
  3949. public native_xmod_is_melee_wpn(plugin_id,params)
  3950. {
  3951.     new wpn_id = get_param(1)
  3952.    
  3953.     CHECK_WEAPON(wpn_id)
  3954.    
  3955.     new weapon_info[WEAPON_INFO_SIZE]
  3956.     ArrayGetArray(weapons_data,wpn_id,weapon_info)
  3957.    
  3958.     return weapon_info[0]
  3959. }
  3960.  
  3961. /*
  3962. * Получение полного названия оружия
  3963. *
  3964. * native xmod_get_wpnname(wpnindex, name[], len)
  3965. */
  3966. public native_xmod_get_wpnname(plugin_id,params)
  3967. {
  3968.     new wpn_id = get_param(1)
  3969.    
  3970.     CHECK_WEAPON(wpn_id)
  3971.    
  3972.     new weapon_info[WEAPON_INFO_SIZE]
  3973.     ArrayGetArray(weapons_data,wpn_id,weapon_info)
  3974.    
  3975.     new weapon_name[MAX_NAME_LENGTH]
  3976.     copy(weapon_name,charsmax(weapon_name),weapon_info[1])
  3977.    
  3978.     set_string(2,weapon_name,get_param(3))
  3979.    
  3980.     return strlen(weapon_name)
  3981. }
  3982.  
  3983. /*
  3984. * Получение лог кода для оружия
  3985. *
  3986. * native xmod_get_wpnlogname(wpnindex, name[], len)
  3987. */
  3988. public native_xmod_get_wpnlogname(plugin_id,params)
  3989. {
  3990.     new wpn_id = get_param(1)
  3991.     CHECK_WEAPON(wpn_id)
  3992.    
  3993.     new weapon_name[MAX_NAME_LENGTH]
  3994.     Info_Weapon_GetLog(wpn_id,weapon_name,get_param(3))
  3995.    
  3996.     set_string(2,weapon_name,get_param(3))
  3997.    
  3998.     return strlen(weapon_name)
  3999. }
  4000.  
  4001. /*
  4002. * Возврашение общего количества оружия для статистики
  4003. *
  4004. * native xmod_get_maxweapons()
  4005. */
  4006. public native_xmod_get_maxweapons(plugin_id,params)
  4007. {
  4008.     return ArraySize(weapons_data)
  4009. }
  4010.  
  4011. public native_get_map_objectives(plugin_id,params)
  4012. {
  4013.     return false
  4014. }
  4015.  
  4016. /*
  4017. * Статистика за текущую сессию
  4018. *
  4019. * native get_user_wstats(index, wpnindex, stats[8], bodyhits[8])
  4020. */
  4021. public native_get_user_wstats(plugin_id,params)
  4022. {
  4023.     new id = get_param(1)
  4024.    
  4025.     CHECK_PLAYERRANGE(id)
  4026.    
  4027.     new wpn_id = get_param(2)
  4028.    
  4029.     CHECK_WEAPON(wpn_id)
  4030.    
  4031.     new stats[8],bh[8]
  4032.     get_user_wstats(id,wpn_id,stats,bh)
  4033.    
  4034.     set_array(3,stats,STATS_END)
  4035.     set_array(4,bh,HIT_END)
  4036.    
  4037.     return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
  4038. }
  4039.  
  4040. /*
  4041. * Статистика за текущий раунд
  4042. *
  4043. * native get_user_wrstats(index, wpnindex, stats[8], bodyhits[8])
  4044. */
  4045. public native_get_user_wrstats(plugin_id,params)
  4046. {
  4047.     new id = get_param(1)
  4048.    
  4049.     CHECK_PLAYERRANGE(id)
  4050.    
  4051.     new wpn_id = get_param(2)
  4052.    
  4053.     CHECK_WEAPON(wpn_id)
  4054.    
  4055.     if(wpn_id != 0 && !(0 < wpn_id < MAX_WEAPONS))
  4056.     {
  4057.         log_error(AMX_ERR_NATIVE,"Weapon index out of bounds (%d)",id)
  4058.        
  4059.         return false
  4060.     }
  4061.    
  4062.     new stats[8],bh[8]
  4063.     get_user_wrstats(id,wpn_id,stats,bh)
  4064.    
  4065.     set_array(3,stats,STATS_END)
  4066.     set_array(4,bh,HIT_END)
  4067.    
  4068.     return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
  4069. }
  4070.  
  4071.  
  4072. /*
  4073. * Получение статистики игрока
  4074. *
  4075. * native get_user_stats(index, stats[8], bodyhits[8])
  4076. */
  4077. public native_get_user_stats(plugin_id,params)
  4078. {
  4079.     new id = get_param(1)
  4080.    
  4081.     CHECK_PLAYERRANGE(id)
  4082.    
  4083.     if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // данные отсутствуют
  4084.     {
  4085.         return 0
  4086.     }
  4087.    
  4088.     set_array(2,player_data[id][PLAYER_STATS],8)
  4089.     set_array(3,player_data[id][PLAYER_HITS],8)
  4090.    
  4091.     return player_data[id][PLAYER_RANK]
  4092. }
  4093.  
  4094. /*
  4095. * Статистика за текущий раунд
  4096. *
  4097. * native get_user_rstats(index, stats[8], bodyhits[8])
  4098. */
  4099. public native_get_user_rstats(plugin_id,params)
  4100. {
  4101.     new id = get_param(1)
  4102.    
  4103.     CHECK_PLAYERRANGE(id)
  4104.    
  4105.     new stats[8],bh[8]
  4106.     get_user_rstats(id,stats,bh)
  4107.    
  4108.     set_array(2,stats,STATS_END)
  4109.     set_array(3,bh,HIT_END)
  4110.    
  4111.     return (stats[STATS_DEATHS] || stats[STATS_SHOTS])
  4112. }
  4113. /*
  4114. * Статистика по жертвам
  4115. *
  4116. * native get_user_vstats(index, victim, stats[8], bodyhits[8], wpnname[] = "", len = 0);
  4117. */
  4118. public native_get_user_vstats(plugin_id,params)
  4119. {
  4120.     if(params != 6)
  4121.     {
  4122.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 6, passed %d",params)
  4123.        
  4124.         return false
  4125.     }
  4126.    
  4127.     new id = get_param(1)
  4128.     new victim = get_param(2)
  4129.    
  4130.     CHECK_PLAYERRANGE(id)
  4131.     CHECK_PLAYERRANGE(victim)
  4132.    
  4133.     new stats[STATS_END],hits[HIT_END],wname[MAX_NAME_LENGTH]
  4134.     unpack_vstats(id,victim,stats,hits,wname,charsmax(wname))
  4135.    
  4136.     set_array(3,stats,STATS_END)
  4137.     set_array(4,hits,HIT_END)
  4138.     set_string(5,wname,get_param(6))
  4139.    
  4140.     return (stats[STATS_KILLS] || stats[STATS_HITS])
  4141. }
  4142.  
  4143.  
  4144. unpack_vstats(killer,victim,stats[STATS_END],hits[HIT_END],vname[],vname_len)
  4145. {
  4146.     new i,stats_i
  4147.    
  4148.     for(i = 0; i < STATS_END ; i++,stats_i++)
  4149.     {
  4150.         stats[i]= player_vstats[killer][victim][stats_i]
  4151.     }
  4152.    
  4153.     for(i = 0; i < HIT_END ; i++,stats_i++)
  4154.     {
  4155.         hits[i]= player_vstats[killer][victim][stats_i]
  4156.     }
  4157.    
  4158.     copy(vname,vname_len,player_vstats[killer][victim][stats_i])
  4159. }
  4160.  
  4161. unpack_astats(attacker,victim,stats[STATS_END],hits[HIT_END],vname[],vname_len)
  4162. {
  4163.     new i,stats_i
  4164.    
  4165.     for(i = 0; i < STATS_END ; i++,stats_i++)
  4166.     {
  4167.         stats[i]= player_astats[victim][attacker][stats_i]
  4168.     }
  4169.    
  4170.     for(i = 0; i < HIT_END ; i++,stats_i++)
  4171.     {
  4172.         hits[i]= player_astats[victim][attacker][stats_i]
  4173.     }
  4174.    
  4175.     copy(vname,vname_len,player_astats[victim][attacker][stats_i])
  4176. }
  4177.  
  4178. /*
  4179. * Статистика по врагам
  4180. *
  4181. * native get_user_astats(index, victim, stats[8], bodyhits[8], wpnname[] = "", len = 0);
  4182. */
  4183. public native_get_user_astats(plugin_id,params)
  4184. {
  4185.     if(params != 6)
  4186.     {
  4187.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 6, passed %d",params)
  4188.        
  4189.         return false
  4190.     }
  4191.    
  4192.     new id = get_param(1)
  4193.     new attacker = get_param(2)
  4194.    
  4195.     CHECK_PLAYERRANGE(id)
  4196.     CHECK_PLAYERRANGE(attacker)
  4197.    
  4198.     new stats[STATS_END],hits[HIT_END],wname[MAX_NAME_LENGTH]
  4199.     unpack_astats(attacker,id,stats,hits,wname,charsmax(wname))
  4200.    
  4201.     set_array(3,stats,STATS_END)
  4202.     set_array(4,hits,HIT_END)
  4203.     set_string(5,wname,get_param(6))
  4204.    
  4205.     return (stats[STATS_KILLS] || stats[STATS_HITS])
  4206. }
  4207.  
  4208. public native_reset_user_wstats()
  4209. {
  4210.     new id = get_param(1)
  4211.    
  4212.     CHECK_PLAYERRANGE(id)
  4213.    
  4214.     return reset_user_wstats(id)
  4215. }
  4216.  
  4217. /*
  4218. * Возвращает общее количество записей в базе данных
  4219. *
  4220. * native get_statsnum()
  4221. */
  4222. public native_get_statsnum(plugin_id,params)
  4223. {
  4224.     return statsnum
  4225. }
  4226.  
  4227. /*
  4228. * Получение статистик по позиции
  4229. *
  4230. * native get_stats(index, stats[8], bodyhits[8], name[], len, authid[] = "", authidlen = 0);
  4231. */
  4232. public native_get_stats(plugin_id,params)
  4233. {
  4234.     // ждем начала работы с БД
  4235.     if(!is_ready)
  4236.     {
  4237.         return 0
  4238.     }
  4239.    
  4240.     if(params < 5)
  4241.     {
  4242.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 5, passed %d",params)
  4243.        
  4244.         return 0
  4245.     }
  4246.     else if(params > 5 && params != 7)
  4247.     {
  4248.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 7, passed %d",params)
  4249.        
  4250.         return 0
  4251.     }
  4252.    
  4253.     new index = get_param(1)    // индекс в статистике
  4254.    
  4255.     // кеширование
  4256.     new index_str[10],stats_cache[stats_cache_struct]
  4257.     num_to_str(index,index_str,charsmax(index_str))
  4258.    
  4259.     // есть информация в кеше
  4260.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  4261.     {
  4262.         set_array(2,stats_cache[CACHE_STATS],sizeof stats_cache[CACHE_STATS])
  4263.         set_array(3,stats_cache[CACHE_HITS],sizeof stats_cache[CACHE_HITS])
  4264.         set_string(4,stats_cache[CACHE_NAME],get_param(5))
  4265.        
  4266.         if(params == 7)
  4267.         {
  4268.             set_string(6,stats_cache[CACHE_STEAMID],get_param(7))
  4269.         }
  4270.    
  4271.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  4272.     }
  4273.     // кеширование
  4274.    
  4275.     /*
  4276.     * прямой запрос в БД, в случае если нету данных в кеше
  4277.     */
  4278.    
  4279.     // открываем соединение с БД для получения актуальных данных
  4280.     if(!DB_OpenConnection())
  4281.     {
  4282.         return false    // ошибка открытия соединения
  4283.     }
  4284.     else
  4285.     {
  4286.         // задание на сброс содеинения
  4287.         // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
  4288.         if(!task_exists(task_confin))
  4289.         {
  4290.             set_task(0.1,"DB_CloseConnection",task_confin)
  4291.         }
  4292.     }
  4293.    
  4294.     // подготавливаем запрос в БД
  4295.     new query[QUERY_LENGTH]
  4296.     DB_QueryBuildGetstats(query,charsmax(query),.index = index)
  4297.     new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
  4298.    
  4299.     // ошибка выполнения запроса
  4300.     if(!SQL_Execute(sqlQue))
  4301.     {
  4302.         new errNum,err[256]
  4303.         errNum = SQL_QueryError(sqlQue,err,charsmax(err))
  4304.        
  4305.         log_amx("SQL query failed")
  4306.         log_amx("[ %d ] %s",errNum,err)
  4307.         log_amx("[ SQL ] %s",query)
  4308.        
  4309.         SQL_FreeHandle(sqlQue)
  4310.        
  4311.         return 0
  4312.     }
  4313.    
  4314.     // читаем результат
  4315.     new name[32],steamid[30],stats[8],hits[8],stats_count
  4316.        
  4317.     DB_ReadGetStats(sqlQue,
  4318.         name,charsmax(name),
  4319.         steamid,charsmax(steamid),
  4320.         stats,
  4321.         hits,
  4322.         .stats_count = stats_count,
  4323.         .index = index
  4324.     )
  4325.    
  4326.     // статистики нет
  4327.     if(!stats_count)
  4328.     {
  4329.         return false
  4330.     }
  4331.    
  4332.     SQL_FreeHandle(sqlQue)
  4333.    
  4334.     // возвращаем данные натива
  4335.     set_array(2,stats,sizeof player_data[][PLAYER_STATS])
  4336.     set_array(3,hits,sizeof player_data[][PLAYER_HITS])
  4337.     set_string(4,name,get_param(5))
  4338.        
  4339.     if(params == 7)
  4340.     {
  4341.         set_string(6,steamid,get_param(7))
  4342.     }
  4343.    
  4344.     return stats_count > 1 ? index + 1 : 0
  4345. }
  4346.  
  4347. /*
  4348. * Получение статистик по позиции
  4349. *
  4350. * native get_stats2_sql(index, stats[4], authid[] = "", authidlen = 0)
  4351. */
  4352. public native_get_stats2(plugin_id,params)
  4353. {
  4354.     // ждем начала работы с БД
  4355.     if(!is_ready)
  4356.     {
  4357.         return 0
  4358.     }
  4359.    
  4360.     if(params < 2)
  4361.     {
  4362.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 2, passed %d",params)
  4363.        
  4364.         return false
  4365.     }
  4366.     else if(params > 2 && params != 4)
  4367.     {
  4368.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
  4369.        
  4370.         return false
  4371.     }
  4372.    
  4373.     new index = get_param(1)    // индекс в статистике
  4374.    
  4375.     // кеширование
  4376.     new index_str[10],stats_cache[stats_cache_struct]
  4377.     num_to_str(index,index_str,charsmax(index_str))
  4378.    
  4379.     // есть информация в кеше
  4380.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  4381.     {
  4382.         set_array(2,stats_cache[CACHE_STATS2],sizeof stats_cache[CACHE_STATS2])
  4383.        
  4384.         if(params == 4)
  4385.         {
  4386.             set_string(3,stats_cache[CACHE_STEAMID],get_param(4))
  4387.         }
  4388.        
  4389.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  4390.     }
  4391.     // кеширование
  4392.    
  4393.     /*
  4394.     * прямой запрос в БД, в случае если нету данных в кеше
  4395.     */
  4396.    
  4397.     // открываем соединение с БД для получения актуальных данных
  4398.     if(!DB_OpenConnection())
  4399.     {
  4400.         return false    // ошибка открытия соединения
  4401.     }
  4402.     else
  4403.     {
  4404.         // задание на сброс содеинения
  4405.         // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
  4406.         if(!task_exists(task_confin))
  4407.         {
  4408.             set_task(0.1,"DB_CloseConnection",task_confin)
  4409.         }
  4410.     }
  4411.    
  4412.     // подготавливаем запрос в БД
  4413.     new query[QUERY_LENGTH]
  4414.     DB_QueryBuildGetstats(query,charsmax(query),.index = index)
  4415.     new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
  4416.    
  4417.     // ошибка выполнения запроса
  4418.     if(!SQL_Execute(sqlQue))
  4419.     {
  4420.         new errNum,err[256]
  4421.         errNum = SQL_QueryError(sqlQue,err,charsmax(err))
  4422.        
  4423.         log_amx("SQL query failed")
  4424.         log_amx("[ %d ] %s",errNum,err)
  4425.         log_amx("[ SQL ] %s",query)
  4426.        
  4427.         SQL_FreeHandle(sqlQue)
  4428.        
  4429.         return 0
  4430.     }
  4431.    
  4432.     // читаем результат
  4433.     new name[32],steamid[30],stats2[4],stats_count
  4434.        
  4435.     DB_ReadGetStats(sqlQue,
  4436.         name,charsmax(name),
  4437.         steamid,charsmax(steamid),
  4438.         .stats2 = stats2,
  4439.         .stats_count = stats_count,
  4440.         .index = index
  4441.     )
  4442.    
  4443.     // статистики нет
  4444.     if(!stats_count)
  4445.     {
  4446.         return false
  4447.     }
  4448.    
  4449.     SQL_FreeHandle(sqlQue)
  4450.    
  4451.     // возвращаем данные натива
  4452.     set_array(2,stats2,sizeof player_data[][PLAYER_STATS2])
  4453.        
  4454.     if(params == 4)
  4455.     {
  4456.         set_string(3,steamid,get_param(4))
  4457.     }
  4458.    
  4459.     return stats_count > 1 ? index + 1 : 0
  4460. }
  4461.  
  4462. /*
  4463. * Потоковый запрос на получение статистик по позиции
  4464. *   id - для кого мы запрашиваем
  4465. *   position - позиция
  4466. *   top - кол-во
  4467. *   callback[] - хандлер ответа
  4468. *
  4469. * native get_stats_sql_thread(id,position,top,callback[]);
  4470. */
  4471. public native_get_stats_thread(plugin_id,params)
  4472. {
  4473.     // ждем начала работы с БД
  4474.     if(!is_ready)
  4475.     {
  4476.         return false
  4477.     }
  4478.    
  4479.     if(params < 4)
  4480.     {
  4481.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
  4482.        
  4483.         return false
  4484.     }
  4485.    
  4486.     new id = get_param(1)
  4487.     new position = min(statsnum,get_param(2))
  4488.     new top = get_param(3)
  4489.     new start_index = max((position - top),0)
  4490.    
  4491.     new callback[20]
  4492.     get_string(4,callback,charsmax(callback))
  4493.    
  4494.     new func_id = get_func_id(callback,plugin_id)
  4495.    
  4496.     if(func_id == -1)
  4497.     {
  4498.         log_error(AMX_ERR_NATIVE,"Unable to locate ^"%s^" handler.",callback)
  4499.        
  4500.         return false
  4501.     }
  4502.    
  4503.     return DB_QueryTop15(id,plugin_id,func_id,position,start_index,top,params)
  4504. }
  4505.  
  4506. // 0.7
  4507. /*
  4508. * Получение статистик по позиции
  4509. *
  4510. * native get_stats3_sql(index, stats3[STATS3_END], authid[] = "", authidlen = 0)
  4511. */
  4512. public native_get_stats3(plugin_id,params)
  4513. {
  4514.     // ждем начала работы с БД
  4515.     if(!is_ready)
  4516.     {
  4517.         return 0
  4518.     }
  4519.    
  4520.     if(params < 2)
  4521.     {
  4522.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 2, passed %d",params)
  4523.        
  4524.         return false
  4525.     }
  4526.     else if(params > 2 && params != 4)
  4527.     {
  4528.         log_error(AMX_ERR_NATIVE,"Bad arguments num, expected 4, passed %d",params)
  4529.        
  4530.         return false
  4531.     }
  4532.    
  4533.     new index = get_param(1)    // индекс в статистике
  4534.    
  4535.     // кеширование
  4536.     new index_str[10],stats_cache[stats_cache_struct]
  4537.     num_to_str(index,index_str,charsmax(index_str))
  4538.    
  4539.     // есть информация в кеше
  4540.     if(stats_cache_trie && TrieGetArray(stats_cache_trie,index_str,stats_cache,stats_cache_struct))
  4541.     {
  4542.         set_array(2,stats_cache[CACHE_STATS3],sizeof stats_cache[CACHE_STATS3])
  4543.        
  4544.         if(params == 4)
  4545.         {
  4546.             set_string(3,stats_cache[CACHE_STEAMID],get_param(4))
  4547.         }
  4548.        
  4549.         return !stats_cache[CACHE_LAST] ? index + 1 : 0
  4550.     }
  4551.     // кеширование
  4552.    
  4553.     /*
  4554.     * прямой запрос в БД, в случае если нету данных в кеше
  4555.     */
  4556.    
  4557.     // открываем соединение с БД для получения актуальных данных
  4558.     if(!DB_OpenConnection())
  4559.     {
  4560.         return false    // ошибка открытия соединения
  4561.     }
  4562.     else
  4563.     {
  4564.         // задание на сброс содеинения
  4565.         // чтобы не открывать новые и успеть получить сразу несколько данных за одно соединение
  4566.         if(!task_exists(task_confin))
  4567.         {
  4568.             set_task(0.1,"DB_CloseConnection",task_confin)
  4569.         }
  4570.     }
  4571.    
  4572.     // подготавливаем запрос в БД
  4573.     new query[QUERY_LENGTH]
  4574.     DB_QueryBuildGetstats(query,charsmax(query),.index = index)
  4575.     new Handle:sqlQue = SQL_PrepareQuery(sql_con,query)
  4576.    
  4577.     // ошибка выполнения запроса
  4578.     if(!SQL_Execute(sqlQue))
  4579.     {
  4580.         new errNum,err[256]
  4581.         errNum = SQL_QueryError(sqlQue,err,charsmax(err))
  4582.        
  4583.         log_amx("SQL query failed")
  4584.         log_amx("[ %d ] %s",errNum,err)
  4585.         log_amx("[ SQL ] %s",query)
  4586.        
  4587.         SQL_FreeHandle(sqlQue)
  4588.        
  4589.         return 0
  4590.     }
  4591.    
  4592.     // читаем результат
  4593.     new name[32],steamid[30],stats3[STATS3_END],stats_count
  4594.        
  4595.     DB_ReadGetStats(sqlQue,
  4596.         name,charsmax(name),
  4597.         steamid,charsmax(steamid),
  4598.         .stats3 = stats3,
  4599.         .stats_count = stats_count,
  4600.         .index = index
  4601.     )
  4602.    
  4603.     // статистики нет
  4604.     if(!stats_count)
  4605.     {
  4606.         return false
  4607.     }
  4608.    
  4609.     SQL_FreeHandle(sqlQue)
  4610.    
  4611.     // возвращаем данные натива
  4612.     set_array(2,stats3,sizeof player_data[][PLAYER_STATS3])
  4613.        
  4614.     if(params == 4)
  4615.     {
  4616.         set_string(3,steamid,get_param(4))
  4617.     }
  4618.    
  4619.     return stats_count > 1 ? index + 1 : 0
  4620. }
  4621.  
  4622. /*
  4623. * Получение статистик по позиции
  4624. *
  4625. * native get_user_stats3_sql(id,stats3[STATS3_END])
  4626. */
  4627. public native_get_user_stats3(plugin_id,params)
  4628. {
  4629.     new id = get_param(1)
  4630.    
  4631.     CHECK_PLAYERRANGE(id)
  4632.    
  4633.     if(player_data[id][PLAYER_LOADSTATE] < LOAD_OK) // данные отсутствуют
  4634.     {
  4635.         return 0
  4636.     }
  4637.    
  4638.     set_array(2,player_data[id][PLAYER_STATS3],STATS3_END)
  4639.    
  4640.     return player_data[id][PLAYER_RANK]
  4641. }
  4642.  
  4643. public native_get_user_stats2(plugin_id,params)
  4644. {
  4645.     new id = get_param(1)
  4646.    
  4647.     CHECK_PLAYERRANGE(id)
  4648.    
  4649.     set_array(2,player_data[id][PLAYER_STATS2],sizeof player_data[][PLAYER_STATS2])
  4650.    
  4651.     return true
  4652. }
  4653.  
  4654. /*
  4655. *
  4656. * ВСЯКАЯ ХРЕНЬ ДЛЯ САМОСТОЯТЕЛЬНОГО ПРОСЧЕТА СТАТИСТИКИ
  4657. *
  4658. */
  4659.  
  4660. is_tk(killer,victim)
  4661. {
  4662.     if(killer == victim)
  4663.         return true
  4664.    
  4665.     return false
  4666. }
  4667.  
  4668. get_user_wstats(index, wpnindex, stats[8], bh[8])
  4669. {
  4670.     for(new i ; i < STATS_END ; i++)
  4671.     {
  4672.         stats[i] = player_wstats[index][wpnindex][i]
  4673.     }
  4674.    
  4675.     #define krisa[%1] player_wstats[index][wpnindex][STATS_END + %1]
  4676.    
  4677.     for(new i ; i < HIT_END ; i++)
  4678.     {
  4679.         bh[i] = krisa[i]
  4680.     }
  4681. }
  4682.  
  4683. get_user_wrstats(index, wpnindex, stats[8], bh[8])
  4684. {
  4685.     for(new i ; i < STATS_END ; i++)
  4686.     {
  4687.         stats[i] = player_wrstats[index][wpnindex][i]
  4688.     }
  4689.    
  4690.     for(new i ; i < HIT_END ; i++)
  4691.     {
  4692.         bh[i] = player_wrstats[index][wpnindex][STATS_END + i]
  4693.     }
  4694. }
  4695.  
  4696. get_user_rstats(index, stats[8], bh[8])
  4697. {
  4698.     for(new i ; i < STATS_END ; i++)
  4699.     {
  4700.         stats[i] = player_wrstats[index][0][i]
  4701.     }
  4702.    
  4703.     for(new i ; i < HIT_END ; i++)
  4704.     {
  4705.         bh[i] = player_wrstats[index][0][STATS_END + i]
  4706.     }
  4707. }
  4708.  
  4709. get_user_stats2(index, stats[4])
  4710. {
  4711.     for(new i ; i < STATS2_END ; i++)
  4712.     {
  4713.         stats[i] = player_wstats2[index][i]
  4714.     }
  4715.    
  4716.     return true
  4717. }
  4718.  
  4719. reset_user_wstats(index)
  4720. {
  4721.     for(new i ; i < MAX_WEAPONS ; i++)
  4722.     {
  4723.         arrayset(player_wrstats[index][i],0,sizeof player_wrstats[][])
  4724.     }
  4725.    
  4726.     for(new i ; i < MAX_PLAYERS + 1 ;i++)
  4727.     {
  4728.         arrayset(player_vstats[index][i],0,sizeof player_vstats[][])
  4729.         arrayset(player_astats[index][i],0,sizeof player_astats[][])
  4730.     }
  4731.    
  4732.     return true
  4733. }
  4734.  
  4735. reset_user_allstats(index)
  4736. {
  4737.     for(new i ; i < MAX_WEAPONS ; i++)
  4738.     {
  4739.         arrayset(player_wstats[index][i],0,sizeof player_wstats[][])
  4740.     }
  4741.    
  4742.     arrayset(player_wstats2[index],0,sizeof player_wstats2[])
  4743.    
  4744.     return true
  4745. }
  4746.  
  4747. public DB_OpenConnection()
  4748. {
  4749.     if(!is_ready)
  4750.     {
  4751.         return false
  4752.     }
  4753.    
  4754.     if(sql_con != Empty_Handle)
  4755.     {
  4756.         return true
  4757.     }
  4758.    
  4759.     new errNum,err[256]
  4760.     sql_con = SQL_Connect(sql,errNum,err,charsmax(err))
  4761.    
  4762.     #if AMXX_VERSION_NUM >= 183
  4763.     SQL_SetCharset(sql_con,"utf8")
  4764.     #endif
  4765.    
  4766.     if(errNum)
  4767.     {
  4768.         log_amx("SQL query failed")
  4769.         log_amx("[ %d ] %s",errNum,err)
  4770.            
  4771.         return false
  4772.     }
  4773.    
  4774.     return true
  4775. }
  4776.  
  4777. public DB_CloseConnection()
  4778. {
  4779.     if(sql_con != Empty_Handle)
  4780.     {
  4781.         SQL_FreeHandle(sql_con)
  4782.         sql_con = Empty_Handle
  4783.     }
  4784. }
  4785.  
  4786. /*********    mysql escape functions     ************/
  4787. mysql_escape_string(dest[],len)
  4788. {
  4789.     //copy(dest, len, source);
  4790.     replace_all(dest,len,"\\","\\\\");
  4791.     replace_all(dest,len,"\0","\\0");
  4792.     replace_all(dest,len,"\n","\\n");
  4793.     replace_all(dest,len,"\r","\\r");
  4794.     replace_all(dest,len,"\x1a","\Z");
  4795.     replace_all(dest,len,"'","''");
  4796.     replace_all(dest,len,"^"","^"^"");
  4797. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top