· 8 years ago · May 30, 2018, 01:56 PM
1#include <amxmodx>
2#include <sqlx>
3#include <reapi>
4const REASON_LENGTH = 64;
5
6
7
8#define CLEAR_PERIOD 30 // Через Ñколько дней удалÑть иÑтекшие GAG'и из MySQL
9
10//#define SORRY // Разрешить команду /sorry Ð´Ð»Ñ Ð¸Ð·Ð²Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ¾Ð²
11//#define MUTEMENU // Поддержка команды /mute
12#define GAG_ACCESS ADMIN_BAN // ДоÑтуп к функциÑм гага
13#define SORRYTIME 60 // Как чаÑто можно пользоватьÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾Ð¹ /sorry. Ð’Ñ€ÐµÐ¼Ñ Ð² Ñекундах
14#define PREFIX "*" // ÐŸÑ€ÐµÑ„Ð¸ÐºÑ Ð² чате
15#define SUPERADMIN ADMIN_RCON
16 // * Ðдмин Ñ Ñ„Ð»Ð°Ð³Ð¾Ð¼ L может гагать других админов Ñ Ð¸Ð¼Ð¼ÑƒÐ½Ð¸Ñ‚ÐµÑ‚Ð¾Ð¼
17 // * Ðдмин Ñ Ñ„Ð»Ð°Ð³Ð¾Ð¼ L может Ñнимать вÑе гаги
18 // * Ðдмин без Ñтого флага не Ñможет Ñнимать чужие гаги
19 // *** ЕÑли не требуетÑÑ - закомментируйте ***
20
21//#define CHATS_BY_STATS // Включает функции блокировки чата игрокам, которые не набрали N фрагов/опыта на Ñервере
22#define VOICE_CONTROL_BY_STATS 0
23 // 0 - CSX
24 // 1 - CSSTATS MYSQL by SKAJIbnEJIb
25 // 2 - CSSTATSX SQL by serfreeman1337
26 // 3 - AES 0.5 Vega by serfreeman1337
27#define BLOCK_TEXT_CHAT
28 // Блокировать текÑтовый чат и голоÑовой
29 // ЕÑли закомментировано - блокировуетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ голоÑ
30#define BLOCK_CHATS_INFO
31 // Выводит в текÑтовый чат Ñообщение о том, что чат/чаты Ð´Ð»Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ° заблокированы
32const MIN_FRAGS = 1;
33 // Минимальное количеÑтво фрагов Ð´Ð»Ñ Ð´Ð¾Ñтупа к микро
34 // Ð”Ð»Ñ VOICE_CONTROL_BY_STATS 3 наÑтройка принимает значение ранга юзера(Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1)
35const ADMIN_FLAG = ADMIN_IMMUNITY;
36 // Флаг доÑтупа, Ð´Ð»Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ не будут работать функции CHATS_BY_STATS
37
38new g_BlockTimes[] = // Ð’Ñ€ÐµÐ¼Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ GAG в минутах
39{
40 5,
41 10,
42 30,
43 60,
44 180,
45 0 // навÑегда
46}
47
48new g_Reasons[][REASON_LENGTH] = // Причины GAG'ов
49{
50 "Флуд",
51 "Отдохни",
52 "Ðеадекват"
53}
54
55new g_AllowCommands[][] = // Разрешенные команды
56{
57 "/pts",
58 "/rank",
59 "/s",
60 "/score"
61}
62
63/* Словарь плагина */
64#define MSG_SORRY_FLOOD "^4%s^1 ^3Прекратите флудить! ^4Повторно извинитьÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ через ^3%d Ñек"
65#define MSG_SORRY_ADMIN "^4%s^1 ^4Уважаемый ^3адмниÑтратор^4, ^3%s ^4проÑит ÑнÑть ^3GAG^4! Причина GAG'a ^3%s"
66#define MSG_CHAT_IS_BLOCKED "^4%s^1 ^4Уважаемый ^3%s^4, Ваш чат ^3заблокирован^4! Причина ^3%s"
67#define MSG_BLOCK_EXPIRED_TIME "^4%s^1 ^4До разблокировки оÑталоÑÑŒ ^1примерно ^3%d ^4мин."
68#define MSG_BLOCK_EXPIRED "^4%s^1 ^4Ð’Ñ€ÐµÐ¼Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ ^3иÑтекло^4. ^1Подождите Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ ..."
69#define MSG_SAY_SORRY "^4%s^1 ^4Чтобы извинитьÑÑ, напишите в чат ^3/sorry^4. Возможно, разблокируют раньше :)"
70#define MSG_CHAT_UNBLOCK_ALL "^4%s^1 ^4Игроку ^3%s ^4был разблокирован чат админиÑтратором ^3%s"
71#define MSG_CHAT_UNBLOCK_PL "^4%s^1 ^4Уважаемый ^3%s^4, админиÑтратор ^3%s ^4ÑнÑл Ñ Ð’Ð°Ñ Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÑƒ чата"
72#define MSG_CHAT_BLOCK_ALL "^4%s^1 ^4ÐдминиÑтратор ^3%s ^4заблокировал чат игроку ^3%s ^1%s^4. Причина ^3%s"
73#define MSG_CHAT_BLOCK_PL "^4%s^1 ^4Уважаемый ^3%s^4, админиÑтратор ^3%s ^4заблокировал Вам чат ^1%s^4. Причина ^3%s"
74#define MSG_MUTE_ALL_PLAYERS "^4%s^1 ^4Ð’Ñ‹ уÑтановили mute на ^3вÑех ^4игроков."
75#define MSG_UNMUTE_ALL_PLAYERS "^4%s^1 ^4Ð’Ñ‹ ÑнÑли mute Ñо ^3вÑех ^4игроков."
76#define MSG_UNMUTE_PLAYER "^4%s^1 ^4Ð’Ñ‹ ÑнÑли ^3mute ^4Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ° ^3%s^4."
77#define MSG_MUTE_PLAYER "^4%s^1 ^4Ð’Ñ‹ уÑтановили ^3mute ^4на игрока ^3%s^4."
78#define MSG_BLOCK_CHATS0 "^4%s^1 ^4ДоÑтуп к текÑтовому и голоÑовому чатам ^3закрыт^4!"
79#define MSG_BLOCK_CHATS1 "^4%s^1 ^4ДоÑтуп к голоÑовому чату ^3закрыт^4!"
80#define MSG_BLOCK_CHATS2 "^4%s^1 ^4Ðеобходимо получить уровень ^3%s!"
81#define MSG_BLOCK_CHATS3 "^4%s^1 ^4Ðеобходимо набрать ^3%i^1/^3%i ^4фрагов"
82
83/* ТехничеÑкие данные */
84
85#if defined CHATS_BY_STATS && !defined _reapi_included
86 #include <hamsandwich>
87#endif
88enum _:MENU_SETTINGS
89{
90 Menu,
91 SelectTime,
92 SelectReason,
93 Pos
94};
95enum _:BlockInfo
96{
97 expired,
98 reason[REASON_LENGTH],
99 admin_steamid[32],
100 bool:chatsGAG,
101 bool:chatsSTATS
102};
103enum MENUS
104{
105 GAG,
106 MUTE
107};
108enum queStates
109{
110 SQL_INIT,
111 DROP_TABLE,
112 LOAD_PLAYER,
113 SAVE_BLOCK,
114 REMOVE_BLOCK
115};
116
117#if !defined MAX_PLAYERS
118 const MAX_PLAYERS = 32;
119#endif
120new Handle:g_hTuple, g_szQuery[1024], g_Data[3];
121new g_BlockInfo[MAX_PLAYERS + 1][BlockInfo];
122new Trie:g_tAllowCmds;
123new pl[MAX_PLAYERS], pnum;
124new g_iMutePlayer[MAX_PLAYERS + 1][MAX_PLAYERS + 1];
125new g_arrPlayers[MAX_PLAYERS + 1][MAX_PLAYERS];
126new g_iMenuInfo[MAX_PLAYERS + 1][MENU_SETTINGS];
127#if AMXX_VERSION_NUM < 183
128 #include <colorchat>
129#endif
130/*#if !defined _reapi_included
131 #include <VtcApi>
132#endif*/
133#if defined MUTEMENU && !defined _reapi_included
134 #include <fakemeta>
135#endif
136#if defined CHATS_BY_STATS
137 #if VOICE_CONTROL_BY_STATS == 0
138 #include <csstats>
139 #endif
140 #if VOICE_CONTROL_BY_STATS == 1
141 #include <csstats_mysql>
142 #endif
143 #if VOICE_CONTROL_BY_STATS == 2
144 #include <csstatsx_sql>
145 #endif
146 #if VOICE_CONTROL_BY_STATS == 3
147 #include <aes_v>
148 #endif
149 #if defined BLOCK_CHATS_INFO
150 new g_iFragStats[MAX_PLAYERS + 1];
151 #if VOICE_CONTROL_BY_STATS == 3
152 new g_szAesLevelName[64];
153 #endif
154 #endif
155#endif
156#if !defined REAPI_VERSION || REAPI_VERSION < 52145
157 #error Needed ReAPI version >= 5.2.0.145
158#endif
159
160public plugin_natives()
161{
162 register_native("ucc_is_client_gaged", "native_ucc_is_client_gaged");
163 register_native("ucc_set_client_gag", "native_ucc_set_client_gag");
164}
165
166public plugin_init()
167{
168#define PNAME "Ultimate Chats Control"
169#define VERSION "4.1"
170#define AUTHOR "neygomon"
171 register_plugin(PNAME, VERSION, AUTHOR);
172 register_cvar("ucc_version", VERSION, FCVAR_SERVER | FCVAR_SPONLY);
173#if defined _reapi_included
174 if(has_vtc())
175 {
176 register_clcmd("amx_gagmenu", "ClCmdGagMenu");
177 #if defined CHATS_BY_STATS
178 RegisterHookChain(RG_CBasePlayer_Spawn, "CBasePlayer_Spawn_Post", true);
179 #endif
180 }
181 #if !defined MUTEMENU
182 else set_fail_state("Needed meta plugin VTC [https://my-amxx.ru/threads/257/]");
183 #endif
184 #if defined MUTEMENU
185 RegisterHookChain(RG_CSGameRules_CanPlayerHearPlayer, "CanPlayerHearPlayer_Pre", false);
186 #endif
187#else
188 register_clcmd("amx_gagmenu", "ClCmdGagMenu");
189 #if defined CHATS_BY_STATS
190 RegisterHam(Ham_Spawn, "player", "CBasePlayer_Spawn_Post", true);
191 #endif
192#endif
193#if defined MUTEMENU
194 register_clcmd("say /mute", "ClCmdMuteMenu");
195 register_clcmd("say_team /mute", "ClCmdMuteMenu");
196 #if !defined _reapi_included
197 register_forward(FM_Voice_SetClientListening, "SetClientListening_Pre", false);
198 #endif
199#endif
200#if defined SORRY
201 register_clcmd("say /sorry", "SaySorry");
202 register_clcmd("say_team /sorry", "SaySorry");
203#endif
204 register_clcmd("say", "SayChat");
205 register_clcmd("say_team", "SayChat");
206
207 register_srvcmd("uÑc_flush", "SrvCmdFlush");
208
209 register_menucmd(register_menuid("UCC Menu"), 1023, "MenuHandler");
210
211 set_task(60.0, "CheckBlockedUsers", .flags = "b");
212}
213
214public plugin_cfg()
215{
216 SQL_Init();
217#if defined CHATS_BY_STATS && defined BLOCK_CHATS_INFO && VOICE_CONTROL_BY_STATS == 3
218 set_task(1.0, "task__aes_get_level_name"); // fucking serfreeman1337. govnocoder
219#endif
220 g_tAllowCmds = TrieCreate();
221 for(new i; i < sizeof g_AllowCommands; ++i)
222 TrieSetCell(g_tAllowCmds, g_AllowCommands[i], i);
223}
224#if defined CHATS_BY_STATS && defined BLOCK_CHATS_INFO && VOICE_CONTROL_BY_STATS == 3
225public task__aes_get_level_name()
226{
227 aes_get_level_name(MIN_FRAGS, g_szAesLevelName, charsmax(g_szAesLevelName), LANG_SERVER);
228}
229#endif
230public client_putinserver(id)
231{
232 if(is_user_bot(id) || is_user_hltv(id))
233 return;
234
235 arrayset(g_iMutePlayer[id], 0, sizeof g_iMutePlayer[]);
236 g_BlockInfo[id][expired] = -1;
237 g_BlockInfo[id][reason][0] = EOS;
238 g_BlockInfo[id][admin_steamid][0]= EOS;
239 g_BlockInfo[id][chatsGAG] = false;
240#if defined BLOCK_TEXT_CHAT
241 g_BlockInfo[id][chatsSTATS] = false;
242#endif
243#if defined CHATS_BY_STATS
244 if(!get_chats_access(id))
245 {
246 VTC_MuteClient(id);
247 #if defined BLOCK_TEXT_CHAT
248 g_BlockInfo[id][chatsSTATS] = true;
249 #endif
250 }
251#endif
252 new szIP[16], szAuth[32];
253 get_user_ip(id, szIP, charsmax(szIP), 1);
254 get_user_authid(id, szAuth, charsmax(szAuth));
255
256 formatex(g_szQuery, charsmax(g_szQuery),
257 "SELECT `expired_time`, `reason`, `admin_steamid` FROM `ucc_gag` WHERE (`ip` = '%s' OR `steamid` = '%s') AND `expired_time` >= '0'",
258 szIP, szAuth
259 );
260
261 g_Data[0] = LOAD_PLAYER;
262 g_Data[1] = id;
263 SQL_ThreadQuery(g_hTuple, "SQL_ThreadsHandler", g_szQuery, g_Data, sizeof(g_Data));
264}
265#if defined MUTEMENU
266 #if defined _reapi_included
267 public CanPlayerHearPlayer_Pre(const iReciever, const iSender)
268 {
269 if(iSender != iReciever)
270 {
271 if(g_iMutePlayer[iReciever][iSender])
272 {
273 SetHookChainReturn(ATYPE_INTEGER, false);
274 return HC_SUPERCEDE;
275 }
276 }
277 return HC_CONTINUE;
278 }
279 #else
280 public SetClientListening_Pre(iReciever, iSender)
281 {
282 if(iSender != iReciever)
283 {
284 if(g_iMutePlayer[iReciever][iSender])
285 {
286 engfunc(EngFunc_SetClientListening, iReciever, iSender, false);
287 forward_return(FMV_CELL, false);
288 return FMRES_SUPERCEDE;
289 }
290 }
291 return FMRES_IGNORED;
292 }
293 #endif
294#endif
295#if defined SORRY
296public SaySorry(id)
297{
298 if(g_BlockInfo[id][chatsGAG])
299 {
300 static iFloodTime[MAX_PLAYERS + 1], systime;
301 if(iFloodTime[id] > (systime = get_systime()))
302 ChatColor(id, 0, MSG_SORRY_FLOOD, PREFIX, iFloodTime[id] - systime);
303 else
304 {
305 new sName[32];
306 get_user_name(id, sName, charsmax(sName));
307
308 get_players(pl, pnum, "ch");
309 for(new i; i < pnum; ++i)
310 {
311 if(get_user_flags(pl[i]) & GAG_ACCESS)
312 ChatColor(pl[i], 0, MSG_SORRY_ADMIN, PREFIX, sName, g_BlockInfo[id][reason]);
313 }
314
315 iFloodTime[id] = systime + SORRYTIME;
316 }
317 }
318 return PLUGIN_HANDLED;
319}
320#endif
321public SayChat(id)
322{
323#if defined CHATS_BY_STATS && defined BLOCK_TEXT_CHAT
324 if(!g_BlockInfo[id][chatsGAG] && !g_BlockInfo[id][chatsSTATS])
325#else
326 if(!g_BlockInfo[id][chatsGAG])
327#endif
328 return PLUGIN_CONTINUE;
329
330 new sMessage[128];
331 read_args(sMessage, charsmax(sMessage));
332 remove_quotes(sMessage);
333
334 if(TrieKeyExists(g_tAllowCmds, sMessage))
335 return PLUGIN_CONTINUE;
336 else if(g_BlockInfo[id][chatsGAG])
337 {
338 new sName[32], ost;
339 get_user_name(id, sName, charsmax(sName));
340 ChatColor(id, 0, MSG_CHAT_IS_BLOCKED, PREFIX, sName, g_BlockInfo[id][reason]);
341
342 if(g_BlockInfo[id][expired] > 0)
343 {
344 if((ost = g_BlockInfo[id][expired] - get_systime()) / 60 > 0)
345 ChatColor(id, 0, MSG_BLOCK_EXPIRED_TIME, PREFIX, ost / 60);
346 else ChatColor(id, 0, MSG_BLOCK_EXPIRED, PREFIX);
347 }
348
349 ChatColor(id, 0, MSG_SAY_SORRY, PREFIX);
350 }
351 #if defined CHATS_BY_STATS && defined BLOCK_CHATS_INFO
352 else
353 {
354 ChatColor(id, 0, MSG_BLOCK_CHATS0, PREFIX);
355 #if VOICE_CONTROL_BY_STATS == 3
356 ChatColor(id, 0, MSG_BLOCK_CHATS2, PREFIX, g_szAesLevelName);
357 #else
358 ChatColor(id, 0, MSG_BLOCK_CHATS3, PREFIX, g_iFragStats[id], MIN_FRAGS);
359 #endif
360 }
361 #endif
362 return PLUGIN_HANDLED;
363}
364#if defined CHATS_BY_STATS
365public CBasePlayer_Spawn_Post(const id)
366{
367 if(!is_user_connected(id))
368 return;
369 if(get_chats_access(id))
370 {
371 VTC_UnmuteClient(id);
372 #if defined BLOCK_TEXT_CHAT
373 g_BlockInfo[id][chatsSTATS] = false;
374 #endif
375 }
376 #if defined BLOCK_CHATS_INFO
377 else if(!g_BlockInfo[id][chatsGAG])
378 {
379 #if defined BLOCK_TEXT_CHAT
380 ChatColor(id, 0, MSG_BLOCK_CHATS0, PREFIX);
381 #else
382 ChatColor(id, 0, MSG_BLOCK_CHATS1, PREFIX);
383 #endif
384 #if VOICE_CONTROL_BY_STATS == 3
385 ChatColor(id, 0, MSG_BLOCK_CHATS2, PREFIX, g_szAesLevelName);
386 #else
387 ChatColor(id, 0, MSG_BLOCK_CHATS3, PREFIX, g_iFragStats[id], MIN_FRAGS);
388 #endif
389 }
390 #endif
391}
392#endif
393public SrvCmdFlush()
394{
395 g_Data[0] = DROP_TABLE;
396 SQL_ThreadQuery(g_hTuple, "SQL_ThreadsHandler", "TRUNCATE `ucc_gag`", g_Data, sizeof(g_Data));
397
398 for(new id; id < sizeof g_BlockInfo; ++id)
399 {
400 g_BlockInfo[id][expired] = -1;
401 g_BlockInfo[id][reason][0] = EOS;
402 g_BlockInfo[id][admin_steamid][0]= EOS;
403 g_BlockInfo[id][chatsGAG] = false;
404 }
405
406 log_amx("%s [v: %s][a: %s] flushed all gags", PNAME, VERSION, AUTHOR);
407}
408
409public CheckBlockedUsers()
410{
411 get_players(pl, pnum);
412 for(new i, sys = get_systime(); i < pnum; ++i)
413 {
414 if(g_BlockInfo[pl[i]][expired] > 0)
415 {
416 if(sys > g_BlockInfo[pl[i]][expired])
417 user_unblock(pl[i]);
418 }
419 }
420}
421
422public ClCmdGagMenu(id)
423{
424 if(get_user_flags(id) & GAG_ACCESS)
425 {
426 g_iMenuInfo[id][SelectTime] = 0;
427 g_iMenuInfo[id][Pos] = 0;
428 g_iMenuInfo[id][Menu] = any:GAG;
429
430 ShowMenu(id, 0);
431 }
432
433 return PLUGIN_HANDLED;
434}
435
436public ClCmdMuteMenu(id)
437{
438 g_iMenuInfo[id][Pos] = 0;
439 g_iMenuInfo[id][Menu] = any:MUTE;
440
441 ShowMenu(id, 0);
442 return PLUGIN_HANDLED;
443}
444
445const MENU_ITEMS = 6;
446ShowMenu(id, iPos)
447{
448 new sAuth[25];
449 new start, end;
450 new iLen, sMenu[512];
451 new iKeys = MENU_KEY_0|MENU_KEY_7|MENU_KEY_8;
452 get_players(g_arrPlayers[id], pnum, "ch");
453 get_user_authid(id, sAuth, charsmax(sAuth));
454
455 start = iPos * MENU_ITEMS;
456 end = start + MENU_ITEMS;
457
458 switch(g_iMenuInfo[id][Menu])
459 {
460 case GAG:
461 {
462 iLen = formatex(sMenu, charsmax(sMenu), "\d[\rAMX Gag\d] \yВыберите игрока\w\R%d/%d^n^n", iPos + 1, (pnum / MENU_ITEMS + ((pnum % MENU_ITEMS) ? 1 : 0)));
463 }
464 case MUTE:
465 {
466 iLen = formatex(sMenu, charsmax(sMenu), "\d[\rMute\d] \yВыберите игрока\w\R%d/%d^n^n", iPos + 1, (pnum / MENU_ITEMS + ((pnum % MENU_ITEMS) ? 1 : 0)));
467 }
468 }
469
470 if(start >= pnum)
471 start = iPos = g_iMenuInfo[id][Pos] = 0;
472 if(end > pnum)
473 end = pnum;
474
475 switch(g_iMenuInfo[id][Menu])
476 {
477 case GAG:
478 {
479 #if defined SUPERADMIN
480 for(new i = start, bool:superadmin = bool:(get_user_flags(id) & SUPERADMIN), sName[32], plr, a; i < end; ++i)
481 #else
482 for(new i = start, sName[32], plr, a; i < end; ++i)
483 #endif
484 {
485 plr = g_arrPlayers[id][i];
486 get_user_name(plr, sName, charsmax(sName));
487
488 if(id == plr)
489 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rÐто Ð’Ñ‹\y]^n", ++a, sName);
490 #if defined SUPERADMIN
491 else if(!superadmin && get_user_flags(plr) & ADMIN_IMMUNITY)
492 #else
493 else if(get_user_flags(plr) & ADMIN_IMMUNITY)
494 #endif
495 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rImmunity\y]^n", ++a, sName);
496 #if defined CHATS_BY_STATS
497 else if(g_BlockInfo[plr][chatsSTATS])
498 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rLowStats\y]^n", ++a, sName);
499 #endif
500 else if(g_BlockInfo[plr][chatsGAG])
501 {
502 #if defined SUPERADMIN
503 if(superadmin || strcmp(g_BlockInfo[plr][admin_steamid], sAuth) == 0)
504 {
505 iKeys |= (1 << a++);
506 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s \d[\yUngag\d]^n", a, sName);
507 }
508 else iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s^n", ++a, sName);
509 #else
510 iKeys |= (1 << a++);
511 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s \d[\yUngag\d]^n", a, sName);
512 #endif
513 }
514 else
515 {
516 iKeys |= (1 << a++);
517 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s%s^n", a, sName, VTC_IsClientSpeaking(plr) ? " \d[\rSpeaking\d]" : "");
518 }
519 }
520
521 if(!g_BlockTimes[g_iMenuInfo[id][SelectTime]])
522 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r7. \wGag\d'\wнуть \rнавÑегда^n");
523 else iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r7. \wGag\d'\wнуть на \y%d \wмин^n", g_BlockTimes[g_iMenuInfo[id][SelectTime]]);
524
525 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r8. \wReason: \r%s^n^n", g_Reasons[g_iMenuInfo[id][SelectReason]]);
526 }
527 case MUTE:
528 {
529 for(new i = start, sName[32], plr, a; i < end; ++i)
530 {
531 plr = g_arrPlayers[id][i];
532 get_user_name(plr, sName, charsmax(sName));
533
534 if(id == plr)
535 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rÐто Ð’Ñ‹\y]^n", ++a, sName);
536 else
537 {
538 iKeys |= (1 << a++);
539 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s%s^n", a, sName, g_iMutePlayer[id][plr] ? " \d[\yMuted\d]" : "");
540 }
541 }
542
543 iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r7. \wЗаглушить \rвÑех^n\r8. \wСнÑть Mute Ñо \rвÑех^n^n");
544 }
545 }
546
547 if(end != pnum)
548 {
549 formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r9. \yДалее^n\r0. \r%s", iPos ? "Ðазад" : "Выход");
550 iKeys |= MENU_KEY_9;
551 }
552 else formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r0. \r%s", iPos ? "Ðазад" : "Выход");
553
554 show_menu(id, iKeys, sMenu, -1, "UCC Menu");
555 return PLUGIN_HANDLED;
556}
557
558public MenuHandler(id, iKey)
559{
560 switch(iKey)
561 {
562 case 6:
563 {
564 switch(g_iMenuInfo[id][Menu])
565 {
566 case GAG:
567 {
568 if(++g_iMenuInfo[id][SelectTime] > charsmax(g_BlockTimes))
569 g_iMenuInfo[id][SelectTime] = 0;
570
571 ShowMenu(id, g_iMenuInfo[id][Pos]);
572 }
573 case MUTE:
574 {
575 arrayset(g_iMutePlayer[id], 1, sizeof g_iMutePlayer[]);
576 ChatColor(id, 0, MSG_MUTE_ALL_PLAYERS, PREFIX);
577 }
578 }
579 }
580 case 7:
581 {
582 switch(g_iMenuInfo[id][Menu])
583 {
584 case GAG:
585 {
586 if(++g_iMenuInfo[id][SelectReason] > charsmax(g_Reasons))
587 g_iMenuInfo[id][SelectReason] = 0;
588
589 ShowMenu(id, g_iMenuInfo[id][Pos]);
590 }
591 case MUTE:
592 {
593 arrayset(g_iMutePlayer[id], 0, sizeof g_iMutePlayer[]);
594 ChatColor(id, 0, MSG_UNMUTE_ALL_PLAYERS, PREFIX);
595 }
596 }
597 }
598 case 8: ShowMenu(id, ++g_iMenuInfo[id][Pos]);
599 case 9:
600 {
601 if(g_iMenuInfo[id][Pos])
602 ShowMenu(id, --g_iMenuInfo[id][Pos]);
603 }
604 default:
605 {
606 switch(g_iMenuInfo[id][Menu])
607 {
608 case GAG:
609 {
610 GagHandler(
611 id,
612 g_arrPlayers[id][g_iMenuInfo[id][Pos] * MENU_ITEMS + iKey],
613 g_BlockTimes[g_iMenuInfo[id][SelectTime]],
614 g_Reasons[g_iMenuInfo[id][SelectReason]]
615 );
616 }
617 case MUTE:
618 {
619 MuteHandler(id, g_arrPlayers[id][g_iMenuInfo[id][Pos] * MENU_ITEMS + iKey]);
620 }
621 }
622 }
623 }
624 return PLUGIN_HANDLED;
625}
626
627GagHandler(id, player, blocktime, blockreason[REASON_LENGTH])
628{
629 if(!is_user_connected(player))
630 return;
631
632 new sNameAdmin[32], sNamePlayer[32];
633 get_user_name(id, sNameAdmin, charsmax(sNameAdmin));
634 get_user_name(player, sNamePlayer, charsmax(sNamePlayer));
635
636 if(g_BlockInfo[player][chatsGAG])
637 {
638 user_unblock(player);
639
640 ChatColor(0, player, MSG_CHAT_UNBLOCK_ALL, PREFIX, sNamePlayer, sNameAdmin);
641 ChatColor(player, 0, MSG_CHAT_UNBLOCK_PL, PREFIX, sNamePlayer, sNameAdmin);
642 }
643 else
644 {
645 user_block(player, id, blocktime, blockreason);
646
647 new blocktimeinfo[32];
648 if(!blocktime)
649 formatex(blocktimeinfo, charsmax(blocktimeinfo), "навÑегда");
650 else formatex(blocktimeinfo, charsmax(blocktimeinfo), "на %d минут", blocktime);
651
652 ChatColor(0, player, MSG_CHAT_BLOCK_ALL, PREFIX, sNameAdmin, sNamePlayer, blocktimeinfo, blockreason);
653 ChatColor(player, 0, MSG_CHAT_BLOCK_PL, PREFIX, sNamePlayer, sNameAdmin, blocktimeinfo, blockreason);
654 }
655 ShowMenu(id, g_iMenuInfo[id][Pos]);
656}
657
658MuteHandler(id, player)
659{
660 if(!is_user_connected(player))
661 return;
662
663 new sNamePlayer[32];
664 get_user_name(player, sNamePlayer, charsmax(sNamePlayer));
665
666 g_iMutePlayer[id][player] = !g_iMutePlayer[id][player];
667 ChatColor(id, 0, g_iMutePlayer[id][player] ? MSG_MUTE_PLAYER : MSG_UNMUTE_PLAYER, PREFIX, sNamePlayer);
668
669 ShowMenu(id, g_iMenuInfo[id][Pos]);
670}
671
672user_block(id, admin, blocktime, blockreason[REASON_LENGTH])
673{
674 VTC_MuteClient(id);
675 client_cmd(id, "-voicerecord");
676
677 new szName[64], szIP[16], szAuth[32];
678 get_user_name(id, szName, charsmax(szName));
679 get_user_ip(id, szIP, charsmax(szIP), 1);
680 get_user_authid(id, szAuth, charsmax(szAuth));
681
682 new szAdminName[64], szAdminIP[16], szAdminAuth[32];
683 get_user_name(admin, szAdminName, charsmax(szAdminName));
684 get_user_ip(admin, szAdminIP, charsmax(szAdminIP), 1);
685 get_user_authid(admin, szAdminAuth, charsmax(szAdminAuth));
686
687 new iSystime = get_systime();
688 g_BlockInfo[id][chatsGAG] = true;
689 g_BlockInfo[id][expired] = !blocktime ? 0 : iSystime + blocktime * 60;
690 formatex(g_BlockInfo[id][reason], charsmax(g_BlockInfo[][reason]), blockreason);
691 formatex(g_BlockInfo[id][admin_steamid], charsmax(g_BlockInfo[][admin_steamid]), szAdminAuth);
692
693 mysql_escape_string(szName, charsmax(szName));
694 mysql_escape_string(szAdminName, charsmax(szAdminName));
695
696 formatex(g_szQuery, charsmax(g_szQuery),
697 "INSERT INTO `ucc_gag` (`name`, `steamid`, `ip`, `admin_name`, `admin_steamid`, `admin_ip`, `create_time`, `expired_time`, `reason`) \
698 VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s') \
699 ON DUPLICATE KEY UPDATE `name` = '%s', `ip` = '%s', `admin_name` = '%s', `admin_steamid` = '%s', `admin_ip` = '%s', `create_time` = '%d', `expired_time` = '%d', `reason` = '%s'",
700 szName, szAuth, szIP, szAdminName, szAdminAuth, szAdminIP, iSystime, g_BlockInfo[id][expired], g_BlockInfo[id][reason],
701 szName, szIP, szAdminName, szAdminAuth, szAdminIP, iSystime, g_BlockInfo[id][expired], g_BlockInfo[id][reason]
702 );
703
704 g_Data[0] = SAVE_BLOCK;
705 SQL_ThreadQuery(g_hTuple, "SQL_ThreadsHandler", g_szQuery, g_Data, sizeof(g_Data));
706}
707
708user_unblock(id)
709{
710 g_BlockInfo[id][expired] = -1;
711 g_BlockInfo[id][reason][0] = EOS;
712 g_BlockInfo[id][admin_steamid][0]= EOS;
713 g_BlockInfo[id][chatsGAG] = false;
714 VTC_UnmuteClient(id);
715
716 new szIP[16], szAuth[32];
717 get_user_ip(id, szIP, charsmax(szIP), 1);
718 get_user_authid(id, szAuth, charsmax(szAuth));
719
720 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `ucc_gag` SET `expired_time` = '-1' WHERE `ip` = '%s' OR `steamid` = '%s'", szIP, szAuth);
721
722 g_Data[0] = REMOVE_BLOCK;
723 SQL_ThreadQuery(g_hTuple, "SQL_ThreadsHandler", g_szQuery, g_Data, sizeof(g_Data));
724}
725
726SQL_Init()
727{
728 SQL_SetAffinity("mysql");
729 g_hTuple = SQL_MakeDbTuple(DB_HOST, DB_USER, DB_PASS, DB_NAME, 1);
730
731 new errcode, errstr[128], Handle:hTest = SQL_Connect(g_hTuple, errcode, errstr, charsmax(errstr));
732 if(hTest == Empty_Handle)
733 {
734 #if AMXX_VERSION_NUM < 183
735 new szError[128]; formatex(szError, charsmax(szError), "[SQL ERROR #%d] %s", errcode, errstr);
736 set_fail_state(szError);
737 #else
738 set_fail_state("[SQL ERROR #%d] %s", errcode, errstr);
739 #endif
740 }
741 else
742 {
743 SQL_FreeHandle(hTest);
744#if AMXX_VERSION_NUM >= 183
745 SQL_SetCharset(g_hTuple, "utf8");
746#endif
747 new iClearPeriod = get_systime() - 86400 * CLEAR_PERIOD;
748 // superfix compile for amxx 1.8.2
749 new iLen = formatex(g_szQuery, charsmax(g_szQuery),
750 "CREATE TABLE IF NOT EXISTS `ucc_gag` ( \
751 `id` smallint(6) NOT NULL AUTO_INCREMENT, \
752 `name` varchar(32) NOT NULL, \
753 `steamid` varchar(32) NOT NULL, \
754 `ip` varchar(16) NOT NULL, \
755 `admin_name` varchar(32) NOT NULL, \
756 `admin_steamid` varchar(32) NOT NULL, \
757 `admin_ip` varchar(32) NOT NULL, ");
758 formatex(g_szQuery[iLen], charsmax(g_szQuery),
759 "`create_time` int(11) NOT NULL, \
760 `expired_time` int(11) NOT NULL, \
761 `reason` varchar(%d) NOT NULL, \
762 PRIMARY KEY (`id`), \
763 UNIQUE KEY `steamid` (`steamid`) \
764 )ENGINE=InnoDB DEFAULT CHARSET=utf8; \
765 DELETE FROM `ucc_gag` WHERE (`expired_time` < '%d' AND `expired_time` > '0') OR (`expired_time` = '-1' AND `create_time` < '%d');",
766 REASON_LENGTH, iClearPeriod, iClearPeriod);
767
768 g_Data[0] = SQL_INIT;
769 SQL_ThreadQuery(g_hTuple, "SQL_ThreadsHandler", g_szQuery, g_Data, sizeof(g_Data));
770 }
771}
772
773public SQL_ThreadsHandler(failstate, Handle:query, err[], errcode, data[], datasize)
774{
775 switch(failstate)
776 {
777 case TQUERY_CONNECT_FAILED, TQUERY_QUERY_FAILED:
778 {
779 log_amx("[SQL ERROR #%d] %s", errcode, err);
780 return;
781 }
782 }
783
784 switch(data[0])
785 {
786 case SQL_INIT, DROP_TABLE, SAVE_BLOCK, REMOVE_BLOCK: {}
787 case LOAD_PLAYER:
788 {
789 if(SQL_NumResults(query))
790 {
791 VTC_MuteClient(data[1]);
792
793 g_BlockInfo[data[1]][expired] = SQL_ReadResult(query, 0);
794 g_BlockInfo[data[1]][chatsGAG] = true;
795 SQL_ReadResult(query, 1, g_BlockInfo[data[1]][reason], charsmax(g_BlockInfo[][reason]));
796 SQL_ReadResult(query, 2, g_BlockInfo[data[1]][admin_steamid], charsmax(g_BlockInfo[][admin_steamid]));
797 }
798 }
799 }
800}
801
802public native_ucc_is_client_gaged(plugin, params)
803{
804 enum { index = 1, exp_time, gag_reason };
805
806 new id = get_param(index);
807
808 if(is_user_connected(id))
809 {
810 set_param_byref(exp_time, g_BlockInfo[id][expired]);
811 set_string(gag_reason, g_BlockInfo[id][reason], charsmax(g_BlockInfo[][reason]));
812
813 return g_BlockInfo[id][chatsGAG];
814 }
815
816 log_error(AMX_ERR_NATIVE, "Client %d not connected or index out of range!", id);
817 return -1;
818}
819
820public native_ucc_set_client_gag(plugin, params)
821{
822 enum { index = 1, admin_id, block_time, gag_reason };
823
824 new id = get_param(index);
825 new admin = get_param(admin_id);
826
827 if(!is_user_connected(id))
828 {
829 log_error(AMX_ERR_NATIVE, "Client %d not connected or index out of range!", id);
830 return 0;
831 }
832 if(!is_user_connected(admin))
833 admin = 0;
834
835 new szReason[REASON_LENGTH];
836 get_string(gag_reason, szReason, charsmax(szReason));
837
838 user_block(id, admin, get_param(block_time), szReason);
839 return 1;
840}
841
842public plugin_end()
843{
844 SQL_FreeHandle(g_hTuple);
845 TrieDestroy(g_tAllowCmds);
846}
847#if defined CHATS_BY_STATS
848bool:get_chats_access(id)
849{
850 if(get_user_flags(id) & ADMIN_FLAG)
851 return true;
852#if VOICE_CONTROL_BY_STATS == 0
853 new st[8], bh[HIT_RIGHTLEG + 1];
854 if(!get_user_stats(id, st, bh))
855 return false;
856#endif
857#if VOICE_CONTROL_BY_STATS == 1
858 new st[22];
859 if(csstats_get_user_stats(id, st) <= 0)
860 return false;
861#endif
862#if VOICE_CONTROL_BY_STATS == 2
863 new st[8], bh[HIT_RIGHTLEG + 1];
864 if(!get_user_stats_sql(id, st, bh))
865 return false;
866#endif
867#if VOICE_CONTROL_BY_STATS == 3
868 new st[1]; st[0] = aes_get_player_level(id);
869 if((st[0] = aes_get_player_level(id)) == -1)
870 return false;
871#endif
872#if defined BLOCK_CHATS_INFO
873 g_iFragStats[id] = st[0];
874#endif
875 return (st[0] < MIN_FRAGS) ? false : true;
876}
877#endif
878stock ChatColor(id, id2, const szMessage[], any:...)
879{
880 new szMsg[190];
881 vformat(szMsg, charsmax(szMsg), szMessage, 4);
882
883 if(id)
884 {
885 client_print_color(id, print_team_default, szMsg);
886 }
887 else
888 {
889 get_players(pl, pnum, "c");
890 for(new i; i < pnum; ++i)
891 {
892 if(pl[i] != id2)
893 {
894 client_print_color(pl[i], print_team_default, szMsg);
895 }
896 }
897 }
898}
899
900#if !defined replace_string
901 #define replace_string replace_all
902#endif
903stock mysql_escape_string(output[], len)
904{
905 static const szReplaceIn[][] = { "\\", "\0", "\n", "\r", "\x1a", "'", "^"" };
906 static const szReplaceOut[][] = { "\\\\", "\\0", "\\n", "\\r", "\Z", "\'", "\^"" };
907 for(new i; i < sizeof szReplaceIn; i++)
908 replace_string(output, len, szReplaceIn[i], szReplaceOut[i]);
909}