· 6 years ago · Jul 12, 2019, 06:32 AM
1#include < amxmodx >
2#include < amxmisc >
3#include < engine >
4#include < sqlx >
5
6#define MAX_PLAYERS 32
7
8#define MAX_PATTERN_LEN 255
9
10enum ( <<= 1 )
11{
12 GAG_CHAT = 1,
13 GAG_TEAMSAY,
14 GAG_VOICE
15};
16
17enum _:GagData
18{
19 GAG_AUTHID[ 35 ],
20 GAG_TIME,
21 GAG_START,
22 GAG_FLAGS
23};
24
25enum _:TimeUnit
26{
27 TIMEUNIT_SECONDS = 0,
28 TIMEUNIT_MINUTES,
29 TIMEUNIT_HOURS,
30 TIMEUNIT_DAYS,
31 TIMEUNIT_WEEKS
32};
33
34new const g_szTimeUnitName[ TimeUnit ][ 2 ][ ] =
35{
36 { "second", "seconds" },
37 { "minute", "minutes" },
38 { "hour", "hours" },
39 { "day", "days" },
40 { "week", "weeks" }
41};
42
43new const g_iTimeUnitMult[ TimeUnit ] =
44{
45 1,
46 60,
47 3600,
48 86400,
49 604800
50};
51
52new const DATETIME_FORMAT[ ] = "%Y-%m-%d %H:%M:%S";
53const DATE_SIZE = 20;
54
55new Array:g_aGagTimes;
56new Array:g_aGagData;
57new Trie:g_tArrayPos;
58new Trie:g_tTimeUnitWords;
59
60new g_iGagged;
61new g_iThinker;
62new g_iTotalGagTimes;
63new g_iMsgSayText;
64
65new g_szAuthid[ MAX_PLAYERS + 1 ][ 35 ];
66new g_iMenuOption[ MAX_PLAYERS + 1 ];
67new g_iMenuPosition[ MAX_PLAYERS + 1 ];
68new g_iMenuPlayers[ MAX_PLAYERS + 1 ][ 32 ];
69new g_iMenuFlags[ MAX_PLAYERS + 1 ];
70
71new g_szGagFile[ 64 ];
72
73new bool:g_bColorSupported;
74
75new g_pCvarDefaultFlags;
76new g_pCvarDefaultTime;
77new g_pCvarTimeUnit;
78new g_pCvarMaxTime;
79new g_pCvarSQL;
80new g_pCvarSQLHost;
81new g_pCvarSQLUser;
82new g_pCvarSQLPass;
83new g_pCvarSQLDb;
84
85new bool:g_bUsingSQL = false;
86new Handle:g_hSqlTuple;
87
88public plugin_init( )
89{
90 register_plugin( "AMXX Gag", "1.4.9", "xPaw & Exolent" );
91
92 register_clcmd( "say", "CmdSay" );
93 register_clcmd( "say_team", "CmdTeamSay" );
94
95 register_concmd( "amx_gag", "CmdGagPlayer", ADMIN_KICK, "<nick or #userid> <time> <a|b|c> -- Use 0 time for permanent" );
96 register_concmd( "amx_addgag", "CmdAddGag", ADMIN_KICK, "<authid> <time> <a|b|c> -- Use 0 time for permanent" );
97 register_concmd( "amx_ungag", "CmdUnGagPlayer", ADMIN_KICK, "<nick or #userid>" );
98 register_concmd( "amx_gagmenu", "CmdGagMenu", ADMIN_KICK, "- displays gag menu" );
99 register_srvcmd( "amx_gag_times", "CmdSetBanTimes" );
100
101 register_menu( "Gag Menu", 1023, "ActionGagMenu" );
102 register_menu( "Gag Flags", 1023, "ActionGagFlags" );
103 register_message( get_user_msgid( "SayText" ), "MessageSayText" );
104
105 g_pCvarDefaultFlags = register_cvar( "amx_gag_default_flags", "abc" );
106 g_pCvarDefaultTime = register_cvar( "amx_gag_default_time", "600" );
107 g_pCvarTimeUnit = register_cvar( "amx_gag_time_units", "0" );
108 g_pCvarMaxTime = register_cvar( "amx_gag_max_time", "86400" );
109 g_pCvarSQL = register_cvar( "amx_gag_sql", "0" );
110 g_pCvarSQLHost = register_cvar( "amx_gag_sql_host", "" );
111 g_pCvarSQLUser = register_cvar( "amx_gag_sql_user", "" );
112 g_pCvarSQLPass = register_cvar( "amx_gag_sql_pass", "" );
113 g_pCvarSQLDb = register_cvar( "amx_gag_sql_db", "" );
114
115 g_tArrayPos = TrieCreate( );
116 g_aGagTimes = ArrayCreate( );
117 g_aGagData = ArrayCreate( GagData );
118 g_bColorSupported = bool:colored_menus( );
119 g_iMsgSayText = get_user_msgid( "SayText" );
120
121 // let words work with the time unit cvar
122 g_tTimeUnitWords = TrieCreate( );
123
124 for( new i = 0; i < TimeUnit; i++ )
125 {
126 TrieSetCell( g_tTimeUnitWords, g_szTimeUnitName[ i ][ 0 ], i );
127 TrieSetCell( g_tTimeUnitWords, g_szTimeUnitName[ i ][ 1 ], i );
128 }
129
130 // this is used for ungag in the menu
131 ArrayPushCell( g_aGagTimes, 0 );
132
133 // Gag times for the gag menu (amx_gagmenu)
134 // Default values: 60 300 600 1800 3600 7200 86400
135 new const iDefaultTimes[ ] = { 60, 300, 600, 1800, 3600, 7200, 86400, 0 };
136
137 // Load up standart times
138 for( new i = 0; i < sizeof( iDefaultTimes ); i++ )
139 {
140 ArrayPushCell( g_aGagTimes, iDefaultTimes[ i ] );
141 }
142
143 g_iTotalGagTimes = sizeof( iDefaultTimes ) + 1;
144
145 // Set up entity-thinker
146 new const szClassName[ ] = "gag_thinker";
147
148 g_iThinker = create_entity( "info_target" );
149 entity_set_string( g_iThinker, EV_SZ_classname, szClassName );
150
151 register_think( szClassName, "FwdThink" );
152
153 // load gags from file
154 get_datadir( g_szGagFile, charsmax( g_szGagFile ) );
155 add( g_szGagFile, charsmax( g_szGagFile ), "/gags.txt" );
156
157 // set server's SteamID to "SERVER"
158 copy( g_szAuthid[ 0 ], charsmax( g_szAuthid[ ] ), "SERVER" );
159}
160
161public plugin_cfg( )
162{
163 // check SQL
164 InitSQL( );
165
166 if( !g_bUsingSQL )
167 {
168 // if no SQL, load file
169 LoadFromFile( );
170 }
171}
172
173InitSQL( )
174{
175 // init SQL after configs were executed
176 if( get_pcvar_num( g_pCvarSQL ) )
177 {
178 new szHost[ 64 ], szUser[ 64 ], szPass[ 64 ], szDb[ 64 ];
179 get_pcvar_string( g_pCvarSQLHost, szHost, charsmax( szHost ) );
180 get_pcvar_string( g_pCvarSQLUser, szUser, charsmax( szUser ) );
181 get_pcvar_string( g_pCvarSQLPass, szPass, charsmax( szPass ) );
182 get_pcvar_string( g_pCvarSQLDb, szDb, charsmax( szDb ) );
183
184 g_hSqlTuple = SQL_MakeDbTuple( szHost, szUser, szPass, szDb );
185
186 if( g_hSqlTuple == Empty_Handle ) return;
187
188 // TABLE STRUCTURE
189 // admin_name VARCHAR(32) NOT NULL
190 // admin_steamid VARCHAR(35) NOT NULL
191 // admin_ip VARCHAR(15) NOT NULL
192 // player_name VARCHAR(32) NOT NULL
193 // player_steamid VARCHAR(35) NOT NULL PRIMARY KEY
194 // player_ip VARCHAR(15) NOT NULL
195 // date_gagged DATETIME NOT NULL
196 // date_ungag DATETIME NOT NULL
197 // gag_seconds INT NOT NULL
198 // gag_flags VARCHAR(3) NOT NULL
199
200 new iError, szError[ 128 ];
201 new Handle:hDb = SQL_Connect( g_hSqlTuple, iError, szError, charsmax( szError ) );
202
203 if( hDb == Empty_Handle )
204 {
205 log_amx( "Failed to connect to database: (%d) %s", iError, szError );
206 return;
207 }
208
209 new Handle:hQuery = SQL_PrepareQuery( hDb, "CREATE TABLE IF NOT EXISTS gagged_players (\
210 admin_name VARCHAR(32) NOT NULL,\
211 admin_steamid VARCHAR(35) NOT NULL,\
212 admin_ip VARCHAR(15) NOT NULL,\
213 player_name VARCHAR(32) NOT NULL,\
214 player_steamid VARCHAR(35) NOT NULL PRIMARY KEY,\
215 player_ip VARCHAR(15) NOT NULL,\
216 date_gagged DATETIME NOT NULL,\
217 date_ungag DATETIME NOT NULL,\
218 gag_seconds INT NOT NULL,\
219 gag_flags VARCHAR(3) NOT NULL);" );
220
221 if( !SQL_Execute( hQuery ) )
222 {
223 SQL_QueryError( hQuery, szError, charsmax( szError ) );
224 log_amx( "Failed create table query: %s", szError );
225 }
226 else
227 {
228 SQL_FreeHandle( hQuery );
229
230 new szDate[ DATE_SIZE ];
231 get_time( DATETIME_FORMAT, szDate, charsmax( szDate ) );
232
233 // load all users
234 hQuery = SQL_PrepareQuery( hDb, "SELECT * FROM gagged_players WHERE date_ungag > '%s';", szDate );
235
236 if( !SQL_Execute( hQuery ) )
237 {
238 SQL_QueryError( hQuery, szError, charsmax( szError ) );
239 log_amx( "Failed load gags query: %s", szError );
240 }
241 else
242 {
243 g_bUsingSQL = true;
244
245 if( SQL_NumResults( hQuery ) )
246 {
247 new data[ GagData ];
248 new szFlags[ 4 ];
249
250 new iFieldSteamID = SQL_FieldNameToNum( hQuery, "player_steamid" );
251 new iFieldDateGagged = SQL_FieldNameToNum( hQuery, "date_gagged" );
252 new iFieldGagTime = SQL_FieldNameToNum( hQuery, "gag_seconds" );
253 new iFieldGagFlags = SQL_FieldNameToNum( hQuery, "gag_flags" );
254
255 while( SQL_MoreResults( hQuery ) )
256 {
257 SQL_ReadResult( hQuery, iFieldSteamID, data[ GAG_AUTHID ], charsmax( data[ GAG_AUTHID ] ) );
258 SQL_ReadResult( hQuery, iFieldDateGagged, szDate, charsmax( szDate ) );
259 data[ GAG_TIME ] = SQL_ReadResult( hQuery, iFieldGagTime );
260 SQL_ReadResult( hQuery, iFieldGagFlags, szFlags, charsmax( szFlags ) );
261
262 data[ GAG_START ] = strtotime( szDate );
263 data[ GAG_FLAGS ] = read_flags( szFlags );
264
265 ArrayPushArray( g_aGagData, data );
266 TrieSetCell( g_tArrayPos, data[ GAG_AUTHID ], g_iGagged );
267 g_iGagged++;
268
269 SQL_NextRow( hQuery );
270 }
271 }
272 }
273 }
274
275 SQL_FreeHandle( hQuery );
276 SQL_FreeHandle( hDb );
277 }
278}
279
280public plugin_end( )
281{
282 TrieDestroy( g_tArrayPos );
283 ArrayDestroy( g_aGagData );
284 ArrayDestroy( g_aGagTimes );
285 TrieDestroy( g_tTimeUnitWords );
286}
287
288public CmdSetBanTimes( )
289{
290 new iArgs = read_argc( );
291
292 if( iArgs <= 1 )
293 {
294 server_print( "Usage: amx_gag_times <time1> [time2] [time3] ..." );
295 return PLUGIN_HANDLED;
296 }
297
298 ArrayClear( g_aGagTimes );
299
300 // this is used for ungag in the menu
301 ArrayPushCell( g_aGagTimes, 0 );
302 g_iTotalGagTimes = 1;
303
304 // get max time allowed
305 new iTimeLimit = get_pcvar_num( g_pCvarMaxTime );
306
307 new szBuffer[ 32 ], iTime;
308 for( new i = 1; i < iArgs; i++ )
309 {
310 read_argv( i, szBuffer, 31 );
311
312 if( !is_str_num( szBuffer ) )
313 {
314 server_print( "[AMXX GAG] Time must be an integer!" );
315 continue;
316 }
317
318 iTime = str_to_num( szBuffer );
319
320 if( iTime < 0 )
321 {
322 server_print( "[AMXX GAG] Time must be a positive integer!" );
323 continue;
324 }
325
326 if( 0 < iTimeLimit < iTime )
327 {
328 server_print( "[AMXX GAG] Time more then %d is not allowed!", iTimeLimit );
329 continue;
330 }
331
332 ArrayPushCell( g_aGagTimes, iTime );
333 g_iTotalGagTimes++;
334 }
335
336 return PLUGIN_HANDLED;
337}
338
339public client_putinserver( id )
340{
341 if( CheckGagFlag( id, GAG_VOICE ) )
342 {
343 set_speak( id, SPEAK_MUTED );
344 }
345
346 // default flags to "abc"
347 g_iMenuFlags[ id ] = GAG_CHAT | GAG_TEAMSAY | GAG_VOICE;
348}
349
350public client_authorized( id )
351 get_user_authid( id, g_szAuthid[ id ], 34 );
352
353public client_disconnect( id )
354{
355 if( TrieKeyExists( g_tArrayPos, g_szAuthid[ id ] ) )
356 {
357 new szName[ 32 ];
358 get_user_name( id, szName, 31 );
359
360 new iPlayers[ 32 ], iNum, iPlayer;
361 get_players( iPlayers, iNum, "ch" );
362
363 for( new i; i < iNum; i++ )
364 {
365 iPlayer = iPlayers[ i ];
366
367 if( get_user_flags( iPlayer ) & ADMIN_KICK )
368 {
369 if( g_bColorSupported )
370 {
371 GreenPrint( iPlayer, id, "^4[AMXX GAG]^1 Gagged player ^"^3%s^1<^4%s^1>^" has disconnected!", szName, g_szAuthid[ id ] );
372 }
373 else
374 {
375 client_print( iPlayer, print_chat, "[AMXX GAG] Gagged player ^"%s<%s>^" has disconnected!", szName, g_szAuthid[ id ] );
376 }
377 }
378 }
379 }
380
381 g_szAuthid[ id ][ 0 ] = '^0';
382}
383
384public client_infochanged( id )
385{
386 if( !CheckGagFlag( id, ( GAG_CHAT | GAG_TEAMSAY ) ) )
387 {
388 return;
389 }
390
391 static const name[ ] = "name";
392
393 static szNewName[ 32 ], szOldName[ 32 ];
394 get_user_info( id, name, szNewName, 31 );
395 get_user_name( id, szOldName, 31 );
396
397 if( !equal( szNewName, szOldName ) )
398 {
399 if( g_bColorSupported )
400 {
401 GreenPrint( id, id, "^4[AMXX GAG]^1 Gagged players cannot change their names!" );
402 }
403 else
404 {
405 client_print( id, print_chat, "[AMXX GAG] Gagged players cannot change their names!" );
406 }
407
408 set_user_info( id, name, szOldName );
409 }
410}
411
412public MessageSayText( )
413{
414 static const Cstrike_Name_Change[ ] = "#Cstrike_Name_Change";
415
416 new szMessage[ sizeof( Cstrike_Name_Change ) + 1 ];
417 get_msg_arg_string( 2, szMessage, charsmax( szMessage ) );
418
419 if( equal( szMessage, Cstrike_Name_Change ) )
420 {
421 new szName[ 32 ], id;
422 for( new i = 3; i <= 4; i++ )
423 {
424 get_msg_arg_string( i, szName, 31 );
425
426 id = get_user_index( szName );
427
428 if( is_user_connected( id ) )
429 {
430 if( CheckGagFlag( id, ( GAG_CHAT | GAG_TEAMSAY ) ) )
431 {
432 return PLUGIN_HANDLED;
433 }
434
435 break;
436 }
437 }
438 }
439
440 return PLUGIN_CONTINUE;
441}
442
443public FwdThink( const iEntity )
444{
445 if( !g_iGagged )
446 return;
447
448 new iSystime = get_systime( );
449 new bool:bRemovedGags = false;
450
451 new bool:bUsingSQL = g_bUsingSQL;
452 new Array:aRemoveSteamIDs, iNumRemoveSteamIDs;
453
454 if( bUsingSQL )
455 {
456 aRemoveSteamIDs = ArrayCreate( 35 );
457 g_bUsingSQL = false;
458 }
459
460 new data[ GagData ], id, szName[ 32 ];
461 for( new i = 0; i < g_iGagged; i++ )
462 {
463 ArrayGetArray( g_aGagData, i, data );
464
465 if( data[ GAG_TIME ] > 0 && ( data[ GAG_START ] + data[ GAG_TIME ] ) <= iSystime )
466 {
467 id = find_player( "c", data[ GAG_AUTHID ] );
468
469 if( is_user_connected( id ) )
470 {
471 get_user_name( id, szName, 31 );
472
473 if( g_bColorSupported )
474 {
475 GreenPrint( 0, id, "^4[AMXX GAG]^1 Player ^"^3%s^1^" is no longer gagged", szName );
476 }
477 else
478 {
479 client_print( 0, print_chat, "[AMXX GAG] Player ^"%s^" is no longer gagged", szName );
480 }
481 }
482 else
483 {
484 if( g_bColorSupported )
485 {
486 GreenPrint( 0, 0, "^4[AMXX GAG]^1 SteamID ^"^3%s^1^" is no longer gagged", data[ GAG_AUTHID ] );
487 }
488 else
489 {
490 client_print( 0, print_chat, "[AMXX GAG] SteamID ^"%s^" is no longer gagged", data[ GAG_AUTHID ] );
491 }
492 }
493
494 DeleteGag( i-- );
495
496 bRemovedGags = true;
497
498 if( bUsingSQL )
499 {
500 ArrayPushString( aRemoveSteamIDs, data[ GAG_AUTHID ] );
501 iNumRemoveSteamIDs++;
502 }
503 }
504 }
505
506 if( !bUsingSQL )
507 {
508 if( bRemovedGags )
509 {
510 SaveToFile( );
511 }
512 }
513 else
514 {
515 if( iNumRemoveSteamIDs )
516 {
517 static szQuery[ 1024 ];
518 new iLen = copy( szQuery, charsmax( szQuery ), "DELETE FROM gagged_players WHERE " );
519
520 for( new i = 0; i < iNumRemoveSteamIDs; i++ )
521 {
522 ArrayGetString( aRemoveSteamIDs, i, data[ GAG_AUTHID ], charsmax( data[ GAG_AUTHID ] ) );
523
524 iLen += formatex( szQuery[ iLen ], charsmax( szQuery ) - iLen, "%splayer_steamid = ^"%s^"", i ? " OR " : "", data[ GAG_AUTHID ] );
525 }
526
527 szQuery[ iLen++ ] = ';';
528 szQuery[ iLen ] = 0;
529
530 SQL_ThreadQuery( g_hSqlTuple, "QueryDeleteMultiple", szQuery );
531 }
532
533 ArrayDestroy( aRemoveSteamIDs );
534
535 g_bUsingSQL = true;
536 }
537
538 if( !g_iGagged )
539 return;
540
541 new iNextTime = 999999;
542 for( new i = 0; i < g_iGagged; i++ )
543 {
544 ArrayGetArray( g_aGagData, i, data );
545
546 if( data[ GAG_TIME ] > 0 )
547 iNextTime = min( iNextTime, data[ GAG_START ] + data[ GAG_TIME ] - iSystime );
548 }
549
550 if( iNextTime < 999999 )
551 entity_set_float( iEntity, EV_FL_nextthink, get_gametime( ) + iNextTime );
552}
553
554public QueryDeleteMultiple( iFailState, Handle:hQuery, szError[ ], iError, iData[ ], iDataSize, Float:flQueueTime )
555{
556 switch( iFailState )
557 {
558 case TQUERY_CONNECT_FAILED: log_amx( "Failed to connect to database: (%d) %s", iError, szError );
559 case TQUERY_QUERY_FAILED: log_amx( "Failed delete multiple query: (%d) %s", iError, szError );
560 }
561}
562
563public CmdSay( const id )
564 return CheckSay( id, 0 );
565
566public CmdTeamSay( const id )
567 return CheckSay( id, 1 );
568
569CheckSay( const id, const bTeam )
570{
571 new iArrayPos;
572 if( TrieGetCell( g_tArrayPos, g_szAuthid[ id ], iArrayPos ) )
573 {
574 new data[ GagData ];
575 ArrayGetArray( g_aGagData, iArrayPos, data );
576
577 new const iFlags[ ] = { GAG_CHAT, GAG_TEAMSAY };
578
579 if( data[ GAG_FLAGS ] & iFlags[ bTeam ] )
580 {
581 if( data[ GAG_TIME ] > 0 )
582 {
583 new szInfo[ 128 ], iTime = data[ GAG_START ] + data[ GAG_TIME ] - get_systime( );
584
585 GetTimeLength( iTime, szInfo, charsmax( szInfo ) );
586
587 if( g_bColorSupported )
588 {
589 GreenPrint( id, id, "^4[AMXX GAG]^3 %s^1 left before your ungag!", szInfo );
590 }
591 else
592 {
593 client_print( id, print_chat, "[AMXX GAG] %s left before your ungag!", szInfo );
594 }
595 }
596 else
597 {
598 if( g_bColorSupported )
599 {
600 GreenPrint( id, id, "^4[AMXX GAG]^3 You are gagged permanently!" );
601 }
602 else
603 {
604 client_print( id, print_chat, "[AMXX GAG] You are gagged permanently!" );
605 }
606 }
607
608 client_print( id, print_center, "** You are gagged from%s chat! **", bTeam ? " team" : "" );
609
610 return PLUGIN_HANDLED;
611 }
612 }
613
614 return PLUGIN_CONTINUE;
615}
616
617public CmdGagPlayer( const id, const iLevel, const iCid )
618{
619 if( !cmd_access( id, iLevel, iCid, 2 ) )
620 {
621 console_print( id, "Flags: a - Chat | b - Team Chat | c - Voice communications" );
622 return PLUGIN_HANDLED;
623 }
624
625 new szArg[ 32 ];
626 read_argv( 1, szArg, 31 );
627
628 new iPlayer = cmd_target( id, szArg, CMDTARGET_OBEY_IMMUNITY | CMDTARGET_NO_BOTS );
629
630 if( !iPlayer )
631 {
632 return PLUGIN_HANDLED;
633 }
634
635 new szName[ 20 ];
636 get_user_name( iPlayer, szName, 19 );
637
638 if( TrieKeyExists( g_tArrayPos, g_szAuthid[ iPlayer ] ) )
639 {
640 console_print( id, "User ^"%s^" is already gagged!", szName );
641 return PLUGIN_HANDLED;
642 }
643
644 new iFlags;
645 new iGagTime;
646
647 read_argv( 2, szArg, 31 );
648
649 if( szArg[ 0 ] ) // No time entered
650 {
651 if( is_str_num( szArg ) ) // Seconds entered
652 {
653 iGagTime = abs( str_to_num( szArg ) );
654 }
655 else
656 {
657 console_print( id, "The value must be in seconds!" );
658 return PLUGIN_HANDLED;
659 }
660
661 read_argv( 3, szArg, 31 );
662
663 if( szArg[ 0 ] )
664 {
665 iFlags = read_flags( szArg );
666 }
667 }
668
669 GagPlayer( id, iPlayer, iGagTime, iFlags );
670
671 return PLUGIN_HANDLED;
672}
673
674GagPlayer( id, iPlayer, iGagTime, iFlags )
675{
676 new iTimeUnit = GetTimeUnit( );
677 new iMaxTime = get_pcvar_num( g_pCvarMaxTime );
678 iGagTime = clamp( iGagTime, 1, iMaxTime ) * g_iTimeUnitMult[ iTimeUnit ];
679
680 if( !iFlags )
681 {
682 new szFlags[ 27 ];
683 get_pcvar_string( g_pCvarDefaultFlags, szFlags, charsmax( szFlags ) );
684
685 iFlags = read_flags( szFlags );
686 }
687
688 new data[ GagData ];
689 data[ GAG_START ] = get_systime( );
690 data[ GAG_TIME ] = iGagTime;
691 data[ GAG_FLAGS ] = iFlags;
692 copy( data[ GAG_AUTHID ], 34, g_szAuthid[ iPlayer ] );
693
694 TrieSetCell( g_tArrayPos, g_szAuthid[ iPlayer ], g_iGagged );
695 ArrayPushArray( g_aGagData, data );
696
697 new szFrom[ 64 ];
698
699 if( iFlags & GAG_CHAT )
700 {
701 copy( szFrom, 63, "say" );
702 }
703
704 if( iFlags & GAG_TEAMSAY )
705 {
706 if( !szFrom[ 0 ] )
707 copy( szFrom, 63, "say_team" );
708 else
709 add( szFrom, 63, " / say_team" );
710 }
711
712 if( iFlags & GAG_VOICE )
713 {
714 set_speak( iPlayer, SPEAK_MUTED );
715
716 if( !szFrom[ 0 ] )
717 copy( szFrom, 63, "voicecomm" );
718 else
719 add( szFrom, 63, " / voicecomm" );
720 }
721
722 g_iGagged++;
723
724 if( iGagTime > 0 )
725 {
726 new Float:flGametime = get_gametime( ), Float:flNextThink;
727 flNextThink = entity_get_float( g_iThinker, EV_FL_nextthink );
728
729 if( !flNextThink || flNextThink > ( flGametime + iGagTime ) )
730 entity_set_float( g_iThinker, EV_FL_nextthink, flGametime + iGagTime );
731 }
732
733 if( g_bUsingSQL )
734 {
735 AddGag( id, iPlayer, iGagTime, iFlags );
736 }
737 else
738 {
739 SaveToFile( );
740 }
741
742 new szName[ 20 ];
743 get_user_name( iPlayer, szName, 19 );
744
745 new szInfo[ 32 ], szAdmin[ 20 ];
746 get_user_name( id, szAdmin, 19 );
747
748 if( iGagTime > 0 )
749 {
750 new iLen = copy( szInfo, 31, "for " );
751 GetTimeLength( iGagTime, szInfo[ iLen ], charsmax( szInfo ) - iLen );
752 }
753 else
754 {
755 copy( szInfo, 31, "permanently" );
756 }
757
758 show_activity( id, szAdmin, "Has gagged %s from speaking %s! (%s)", szName, szInfo, szFrom );
759
760 console_print( id, "You have gagged ^"%s^" (%s) !", szName, szFrom );
761
762 log_amx( "Gag: ^"%s<%s>^" has gagged ^"%s<%s>^" %s. (%s)", szAdmin, g_szAuthid[ id ], szName, g_szAuthid[ iPlayer ], szInfo, szFrom );
763}
764
765public CmdAddGag( const id, const iLevel, const iCid )
766{
767 if( !cmd_access( id, iLevel, iCid, 2 ) )
768 {
769 console_print( id, "Flags: a - Chat | b - Team Chat | c - Voice communications" );
770 return PLUGIN_HANDLED;
771 }
772
773 new szArg[ 32 ];
774 read_argv( 1, szArg, 31 );
775
776 if( !IsValidSteamID( szArg ) )
777 {
778 console_print( id, "Invalid SteamID provided (%s). Must be in ^"STEAM_0:X:XXXXX^" format (remember to use quotes!)", szArg );
779 return PLUGIN_HANDLED;
780 }
781
782 new iPlayer = find_player( "c", szArg );
783
784 if( is_user_connected( iPlayer ) )
785 {
786 new szTime[ 12 ], szFlags[ 4 ];
787 read_argv( 2, szTime, charsmax( szTime ) );
788 read_argv( 3, szFlags, charsmax( szFlags ) );
789
790 client_cmd( id, "amx_gag #%d ^"%s^" ^"%s^"", get_user_userid( iPlayer ), szTime, szFlags );
791 return PLUGIN_HANDLED;
792 }
793
794 if( TrieKeyExists( g_tArrayPos, szArg ) )
795 {
796 console_print( id, "This user is already gagged!" );
797 return PLUGIN_HANDLED;
798 }
799
800 if( GetAccessBySteamID( szArg ) & ADMIN_IMMUNITY )
801 {
802 console_print( id, "This user has immunity!" );
803 return PLUGIN_HANDLED;
804 }
805
806 new data[ GagData ];
807 copy( data[ GAG_AUTHID ], 34, szArg );
808
809 get_pcvar_string( g_pCvarDefaultFlags, szArg, charsmax( szArg ) );
810 new iFlags = read_flags( szArg );
811
812 new iTimeUnit = GetTimeUnit( );
813 new iMaxTime = get_pcvar_num( g_pCvarMaxTime );
814 new iGagTime = clamp( get_pcvar_num( g_pCvarDefaultTime ), 1, iMaxTime );
815
816 read_argv( 2, szArg, 31 );
817
818 if( szArg[ 0 ] ) // No time entered
819 {
820 if( is_str_num( szArg ) ) // Seconds entered
821 {
822 iGagTime = min( abs( str_to_num( szArg ) ), iMaxTime );
823 }
824 else
825 {
826 console_print( id, "The value must be in seconds!" );
827 return PLUGIN_HANDLED;
828 }
829
830 read_argv( 3, szArg, 31 );
831
832 if( szArg[ 0 ] )
833 {
834 iFlags = read_flags( szArg );
835 }
836 }
837
838 // convert to seconds
839 iGagTime *= g_iTimeUnitMult[ iTimeUnit ];
840
841 data[ GAG_START ] = get_systime( );
842 data[ GAG_TIME ] = iGagTime;
843 data[ GAG_FLAGS ] = iFlags;
844
845 TrieSetCell( g_tArrayPos, data[ GAG_AUTHID ], g_iGagged );
846 ArrayPushArray( g_aGagData, data );
847
848 new szFrom[ 64 ];
849
850 if( iFlags & GAG_CHAT )
851 {
852 copy( szFrom, 63, "say" );
853 }
854
855 if( iFlags & GAG_TEAMSAY )
856 {
857 if( !szFrom[ 0 ] )
858 copy( szFrom, 63, "say_team" );
859 else
860 add( szFrom, 63, " / say_team" );
861 }
862
863 if( iFlags & GAG_VOICE )
864 {
865 if( !szFrom[ 0 ] )
866 copy( szFrom, 63, "voicecomm" );
867 else
868 add( szFrom, 63, " / voicecomm" );
869 }
870
871 g_iGagged++;
872
873 if( iGagTime > 0 )
874 {
875 new Float:flGametime = get_gametime( ), Float:flNextThink;
876 flNextThink = entity_get_float( g_iThinker, EV_FL_nextthink );
877
878 if( !flNextThink || flNextThink > ( flGametime + iGagTime ) )
879 entity_set_float( g_iThinker, EV_FL_nextthink, flGametime + iGagTime );
880 }
881
882 if( g_bUsingSQL )
883 {
884 AddGag( id, iPlayer, iGagTime, iFlags );
885 }
886 else
887 {
888 SaveToFile( );
889 }
890
891 new szInfo[ 32 ], szAdmin[ 20 ];
892 get_user_name( id, szAdmin, 19 );
893
894 if( iGagTime > 0 )
895 {
896 new iLen = copy( szInfo, 31, "for " );
897 GetTimeLength( iGagTime, szInfo[ iLen ], charsmax( szInfo ) - iLen );
898 }
899 else
900 {
901 copy( szInfo, 31, "permanently" );
902 }
903
904 show_activity( id, szAdmin, "Has gagged a non-connected player <%s> from speaking %s! (%s)", data[ GAG_AUTHID ], szInfo, szFrom );
905
906 console_print( id, "You have gagged ^"%s^" (%s) !", data[ GAG_AUTHID ], szFrom );
907
908 log_amx( "Gag: ^"%s<%s>^" has gagged a non-connected player ^"<%s>^" %s. (%s)", szAdmin, g_szAuthid[ id ], data[ GAG_AUTHID ], szInfo, szFrom );
909
910 return PLUGIN_HANDLED;
911}
912
913public CmdUnGagPlayer( const id, const iLevel, const iCid )
914{
915 if( !cmd_access( id, iLevel, iCid, 2 ) )
916 return PLUGIN_HANDLED;
917
918 new szArg[ 32 ];
919 read_argv( 1, szArg, 31 );
920
921 if( szArg[ 0 ] == '@' && equali( szArg[ 1 ], "all" ) )
922 {
923 if( !g_iGagged )
924 {
925 console_print( id, "No gagged players!" );
926 return PLUGIN_HANDLED;
927 }
928
929 DeleteAllGags( );
930
931 if( entity_get_float( g_iThinker, EV_FL_nextthink ) > 0.0 )
932 entity_set_float( g_iThinker, EV_FL_nextthink, 0.0 );
933
934 console_print( id, "You have ungagged all players!" );
935
936 new szAdmin[ 32 ];
937 get_user_name( id, szAdmin, 31 );
938
939 show_activity( id, szAdmin, "Has ungagged all players." );
940
941 log_amx( "UnGag: ^"%s<%s>^" has ungagged all players.", szAdmin, g_szAuthid[ id ] );
942
943 return PLUGIN_HANDLED;
944 }
945
946 new iPlayer = cmd_target( id, szArg, CMDTARGET_NO_BOTS );
947 new iArrayPos, szName[ 32 ];
948
949 if( !iPlayer )
950 {
951 // Maybe it's a steamid
952
953 if( !IsValidSteamID( szArg ) )
954 {
955 return PLUGIN_HANDLED;
956 }
957
958 if( !TrieGetCell( g_tArrayPos, szArg, iArrayPos ) )
959 {
960 console_print( id, "This steamid is not gagged!" );
961 return PLUGIN_HANDLED;
962 }
963
964 copy( szName, charsmax( szName ), szArg );
965 }
966 else
967 {
968 get_user_name( iPlayer, szName, charsmax( szName ) );
969
970 if( !TrieGetCell( g_tArrayPos, g_szAuthid[ iPlayer ], iArrayPos ) )
971 {
972 console_print( id, "User ^"%s^" is not gagged!", szName );
973 return PLUGIN_HANDLED;
974 }
975 }
976
977 DeleteGag( iArrayPos );
978
979 if( !g_bUsingSQL )
980 {
981 SaveToFile( );
982 }
983
984 new szAdmin[ 32 ];
985 get_user_name( id, szAdmin, 31 );
986
987 show_activity( id, szAdmin, "Has ungagged %s.", szName );
988
989 console_print( id, "You have ungagged ^"%s^" !", szName );
990
991 log_amx( "UnGag: ^"%s<%s>^" has ungagged ^"%s<%s>^"", szAdmin, g_szAuthid[ id ], szName, g_szAuthid[ iPlayer ] );
992
993 return PLUGIN_HANDLED;
994}
995
996public CmdGagMenu( const id, const iLevel, const iCid )
997{
998 if( !cmd_access( id, iLevel, iCid, 1 ) )
999 {
1000 return PLUGIN_HANDLED;
1001 }
1002
1003 g_iMenuOption[ id ] = 0;
1004 arrayset( g_iMenuPlayers[ id ], 0, 32 );
1005
1006 DisplayGagMenu( id, g_iMenuPosition[ id ] = 0 );
1007
1008 return PLUGIN_HANDLED;
1009}
1010
1011#define PERPAGE 6
1012
1013public ActionGagMenu( const id, const iKey )
1014{
1015 switch( iKey )
1016 {
1017 case 6: DisplayGagFlags( id );
1018 case 7:
1019 {
1020 ++g_iMenuOption[ id ];
1021 g_iMenuOption[ id ] %= g_iTotalGagTimes;
1022
1023 DisplayGagMenu( id, g_iMenuPosition[ id ] );
1024 }
1025 case 8: DisplayGagMenu( id, ++g_iMenuPosition[ id ] );
1026 case 9: DisplayGagMenu( id, --g_iMenuPosition[ id ] );
1027 default:
1028 {
1029 new iPlayer = g_iMenuPlayers[ id ][ g_iMenuPosition[ id ] * PERPAGE + iKey ];
1030
1031 if( is_user_connected( iPlayer ) )
1032 {
1033 if( !g_iMenuOption[ id ] )
1034 {
1035 //client_cmd( id, "amx_ungag #%i", get_user_userid( iPlayer ) );
1036
1037 new iArrayPos;
1038
1039 if( TrieGetCell( g_tArrayPos, g_szAuthid[ iPlayer ], iArrayPos ) )
1040 {
1041 DeleteGag( iArrayPos );
1042
1043 if( !g_bUsingSQL )
1044 {
1045 SaveToFile( );
1046 }
1047
1048 new szName[ 32 ];
1049 get_user_name( iPlayer, szName, 31 );
1050
1051 new szAdmin[ 32 ];
1052 get_user_name( id, szAdmin, 31 );
1053
1054 show_activity( id, szAdmin, "Has ungagged %s.", szName );
1055
1056 console_print( id, "You have ungagged ^"%s^" !", szName );
1057
1058 log_amx( "UnGag: ^"%s<%s>^" has ungagged ^"%s<%s>^"", szAdmin, g_szAuthid[ id ], szName, g_szAuthid[ iPlayer ] );
1059 }
1060 }
1061 else if( !TrieKeyExists( g_tArrayPos, g_szAuthid[ iPlayer ] ) )
1062 {
1063 /*new szFlags[ 4 ];
1064 get_flags( g_iMenuFlags[ id ], szFlags, 3 );
1065
1066 client_cmd( id, "amx_gag #%i %i %s", get_user_userid( iPlayer ), ArrayGetCell( g_aGagTimes, g_iMenuOption[ id ] ), szFlags );*/
1067
1068 GagPlayer( id, iPlayer, ArrayGetCell( g_aGagTimes, g_iMenuOption[ id ] ), g_iMenuFlags[ id ] );
1069 }
1070 }
1071
1072 DisplayGagMenu( id, g_iMenuPosition[ id ] );
1073 }
1074 }
1075}
1076
1077// I just copied this from AMXX Ban menu, so don't blame me :D
1078DisplayGagMenu( const id, iPosition )
1079{
1080 if( iPosition < 0 )
1081 {
1082 arrayset( g_iMenuPlayers[ id ], 0, 32 );
1083 return;
1084 }
1085
1086 new iPlayers[ 32 ], iNum, iCount, szMenu[ 512 ], iPlayer, iFlags, szName[ 32 ];
1087 get_players( iPlayers, iNum, "ch" ); // Ignore bots and hltv
1088
1089 new iStart = iPosition * PERPAGE;
1090
1091 if( iStart >= iNum )
1092 iStart = iPosition = g_iMenuPosition[ id ] = 0;
1093
1094 new iEnd = iStart + PERPAGE, iKeys = MENU_KEY_0 | MENU_KEY_8;
1095 new iLen = formatex( szMenu, 511, g_bColorSupported ? "\rGag Menu\R%i/%i^n^n" : "Gag Menu %i/%i^n^n", iPosition + 1, ( ( iNum + PERPAGE - 1 ) / PERPAGE ) );
1096
1097 new bool:bUngag = bool:!g_iMenuOption[ id ];
1098
1099 if( iEnd > iNum ) iEnd = iNum;
1100
1101 for( new i = iStart; i < iEnd; ++i )
1102 {
1103 iPlayer = iPlayers[ i ];
1104 iFlags = get_user_flags( iPlayer );
1105 get_user_name( iPlayer, szName, 31 );
1106
1107 if( iPlayer == id || ( iFlags & ADMIN_IMMUNITY ) || bUngag != TrieKeyExists( g_tArrayPos, g_szAuthid[ iPlayer ] ) )
1108 {
1109 ++iCount;
1110
1111 if( g_bColorSupported )
1112 iLen += formatex( szMenu[ iLen ], 511 - iLen, "\d%i. %s^n", iCount, szName );
1113 else
1114 iLen += formatex( szMenu[ iLen ], 511 - iLen, "#. %s^n", szName );
1115 }
1116 else
1117 {
1118 iKeys |= ( 1 << iCount );
1119 ++iCount;
1120
1121 iLen += formatex( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "\r%i.\w %s\y%s\r%s^n" : "%i. %s%s%s^n", iCount, szName, TrieKeyExists( g_tArrayPos, g_szAuthid[ iPlayer ] ) ? " GAGGED" : "", ( ~iFlags & ADMIN_USER ? " *" : "" ) );
1122 }
1123 }
1124
1125 g_iMenuPlayers[ id ] = iPlayers;
1126
1127 new szFlags[ 4 ];
1128 get_flags( g_iMenuFlags[ id ], szFlags, 3 );
1129
1130 iLen += formatex( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? ( bUngag ? "^n\d7. Flags: %s" : "^n\r7.\y Flags:\w %s" ) : ( bUngag ? "^n#. Flags: %s" : "^n7. Flags: %s" ), szFlags );
1131
1132 if( !bUngag )
1133 {
1134 iKeys |= MENU_KEY_7;
1135
1136 new iGagTime = ArrayGetCell( g_aGagTimes, g_iMenuOption[ id ] );
1137
1138 if( iGagTime )
1139 {
1140 new szTime[ 128 ];
1141 GetTimeLength( iGagTime * g_iTimeUnitMult[ GetTimeUnit( ) ], szTime, charsmax( szTime ) );
1142
1143 iLen += formatex( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r8.\y Time:\w %s^n" : "^n8. Time: %s^n", szTime );
1144 }
1145 else
1146 iLen += copy( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r8.\y Time: Permanent^n" : "^n8. Time: Permanent^n" );
1147 }
1148 else
1149 iLen += copy( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r8.\w Ungag^n" : "^n8. Ungag^n" );
1150
1151 if( iEnd != iNum )
1152 {
1153 formatex( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r9.\w More...^n\r0.\w %s" : "^n9. More...^n0. %s", iPosition ? "Back" : "Exit" );
1154 iKeys |= MENU_KEY_9;
1155 }
1156 else
1157 formatex( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r0.\w %s" : "^n0. %s", iPosition ? "Back" : "Exit" );
1158
1159 show_menu( id, iKeys, szMenu, -1, "Gag Menu" );
1160}
1161
1162public ActionGagFlags( const id, const iKey )
1163{
1164 switch( iKey )
1165 {
1166 case 9: DisplayGagMenu( id, g_iMenuPosition[ id ] );
1167 default:
1168 {
1169 g_iMenuFlags[ id ] ^= ( 1 << iKey );
1170
1171 DisplayGagFlags( id );
1172 }
1173 }
1174}
1175
1176DisplayGagFlags( const id )
1177{
1178 new szMenu[ 512 ];
1179 new iLen = copy( szMenu, 511, g_bColorSupported ? "\rGag Flags^n^n" : "Gag Flags^n^n" );
1180
1181 if( g_bColorSupported )
1182 {
1183 iLen += formatex( szMenu[ iLen ], 511 - iLen, "\r1.\w Chat: %s^n", ( g_iMenuFlags[ id ] & GAG_CHAT ) ? "\yYES" : "\rNO" );
1184 iLen += formatex( szMenu[ iLen ], 511 - iLen, "\r2.\w TeamSay: %s^n", ( g_iMenuFlags[ id ] & GAG_TEAMSAY ) ? "\yYES" : "\rNO" );
1185 iLen += formatex( szMenu[ iLen ], 511 - iLen, "\r3.\w Voice: %s^n", ( g_iMenuFlags[ id ] & GAG_VOICE ) ? "\yYES" : "\rNO" );
1186 }
1187 else
1188 {
1189 iLen += formatex( szMenu[ iLen ], 511 - iLen, "1. Chat: %s^n", ( g_iMenuFlags[ id ] & GAG_CHAT ) ? "YES" : "NO" );
1190 iLen += formatex( szMenu[ iLen ], 511 - iLen, "2. TeamSay: %s^n", ( g_iMenuFlags[ id ] & GAG_TEAMSAY ) ? "YES" : "NO" );
1191 iLen += formatex( szMenu[ iLen ], 511 - iLen, "3. Voice: %s^n", ( g_iMenuFlags[ id ] & GAG_VOICE ) ? "YES" : "NO" );
1192 }
1193
1194 copy( szMenu[ iLen ], 511 - iLen, g_bColorSupported ? "^n\r0. \wBack to Gag Menu" : "^n0. Back to Gag Menu" );
1195
1196 show_menu( id, ( MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_0 ), szMenu, -1, "Gag Flags" );
1197}
1198
1199CheckGagFlag( const id, const iFlag )
1200{
1201 new iArrayPos;
1202
1203 if( TrieGetCell( g_tArrayPos, g_szAuthid[ id ], iArrayPos ) )
1204 {
1205 new data[ GagData ];
1206 ArrayGetArray( g_aGagData, iArrayPos, data );
1207
1208 return ( data[ GAG_FLAGS ] & iFlag );
1209 }
1210
1211 return 0;
1212}
1213
1214DeleteAllGags( )
1215{
1216 new data[ GagData ];
1217 new iPlayer;
1218
1219 for( new i = 0; i < g_iGagged; i++ )
1220 {
1221 ArrayGetArray( g_aGagData, i, data );
1222
1223 iPlayer = find_player( "c", data[ GAG_AUTHID ] );
1224 if( is_user_connected( iPlayer ) )
1225 set_speak( iPlayer, SPEAK_NORMAL );
1226 }
1227
1228 ArrayClear( g_aGagData );
1229 TrieClear( g_tArrayPos );
1230 g_iGagged = 0;
1231
1232 if( g_bUsingSQL )
1233 {
1234 SQL_ThreadQuery( g_hSqlTuple, "QueryDeleteAll", "DELETE FROM gagged_players;" );
1235 }
1236}
1237
1238public QueryDeleteAll( iFailState, Handle:hQuery, szError[ ], iError, iData[ ], iDataSize, Float:flQueueTime )
1239{
1240 switch( iFailState )
1241 {
1242 case TQUERY_CONNECT_FAILED: log_amx( "Failed to connect to database: (%d) %s", iError, szError );
1243 case TQUERY_QUERY_FAILED: log_amx( "Failed delete all query: (%d) %s", iError, szError );
1244 }
1245}
1246
1247DeleteGag( const iArrayPos )
1248{
1249 new data[ GagData ];
1250 ArrayGetArray( g_aGagData, iArrayPos, data );
1251
1252 if( data[ GAG_FLAGS ] & GAG_VOICE )
1253 {
1254 new iPlayer = find_player( "c", data[ GAG_AUTHID ] );
1255 if( is_user_connected( iPlayer ) )
1256 set_speak( iPlayer, SPEAK_NORMAL );
1257 }
1258
1259 TrieDeleteKey( g_tArrayPos, data[ GAG_AUTHID ] );
1260 ArrayDeleteItem( g_aGagData, iArrayPos );
1261 g_iGagged--;
1262
1263 for( new i = iArrayPos; i < g_iGagged; i++ )
1264 {
1265 ArrayGetArray( g_aGagData, i, data );
1266 TrieSetCell( g_tArrayPos, data[ GAG_AUTHID ], i );
1267 }
1268
1269 if( g_bUsingSQL )
1270 {
1271 new szQuery[ 128 ];
1272 formatex( szQuery, charsmax( szQuery ), "DELETE FROM gagged_players WHERE player_steamid = '%s';", data[ GAG_AUTHID ] );
1273
1274 SQL_ThreadQuery( g_hSqlTuple, "QueryDelete", szQuery );
1275 }
1276}
1277
1278public QueryDelete( iFailState, Handle:hQuery, szError[ ], iError, iData[ ], iDataSize, Float:flQueueTime )
1279{
1280 switch( iFailState )
1281 {
1282 case TQUERY_CONNECT_FAILED: log_amx( "Failed to connect to database: (%d) %s", iError, szError );
1283 case TQUERY_QUERY_FAILED: log_amx( "Failed delete query: (%d) %s", iError, szError );
1284 }
1285}
1286
1287LoadFromFile( )
1288{
1289 new hFile = fopen( g_szGagFile, "rt" );
1290
1291 if( hFile )
1292 {
1293 new szData[ 128 ], szTime[ 16 ], szStart[ 16 ], szFlags[ 4 ];
1294 new data[ GagData ], iSystime = get_systime( ), iTimeLeft, iShortestTime = 999999;
1295 new bool:bRemovedGags = false;
1296
1297 while( !feof( hFile ) )
1298 {
1299 fgets( hFile, szData, charsmax( szData ) );
1300 trim( szData );
1301
1302 if( !szData[ 0 ] ) continue;
1303
1304 parse( szData,
1305 data[ GAG_AUTHID ], charsmax( data[ GAG_AUTHID ] ),
1306 szTime, charsmax( szTime ),
1307 szStart, charsmax( szStart ),
1308 szFlags, charsmax( szFlags )
1309 );
1310
1311 // remove old gags
1312 if( contain( szStart, "." ) > 0 ) continue;
1313
1314 data[ GAG_TIME ] = str_to_num( szTime );
1315 data[ GAG_START ] = str_to_num( szStart );
1316 data[ GAG_FLAGS ] = read_flags( szFlags );
1317
1318 if( data[ GAG_TIME ] > 0 )
1319 {
1320 iTimeLeft = data[ GAG_START ] + data[ GAG_TIME ] - iSystime;
1321
1322 if( iTimeLeft <= 0 )
1323 {
1324 bRemovedGags = true;
1325 continue;
1326 }
1327
1328 if( iShortestTime > iTimeLeft )
1329 {
1330 iShortestTime = iTimeLeft;
1331 }
1332 }
1333
1334 TrieSetCell( g_tArrayPos, data[ GAG_AUTHID ], g_iGagged );
1335 ArrayPushArray( g_aGagData, data );
1336 g_iGagged++;
1337 }
1338
1339 fclose( hFile );
1340
1341 if( bRemovedGags )
1342 {
1343 SaveToFile( );
1344 }
1345
1346 if( iShortestTime < 999999 )
1347 {
1348 entity_set_float( g_iThinker, EV_FL_nextthink, get_gametime( ) + iShortestTime );
1349 }
1350 }
1351}
1352
1353SaveToFile( )
1354{
1355 new hFile = fopen( g_szGagFile, "wt" );
1356
1357 if( hFile )
1358 {
1359 new data[ GagData ], szFlags[ 4 ];
1360
1361 for( new i = 0; i < g_iGagged; i++ )
1362 {
1363 ArrayGetArray( g_aGagData, i, data );
1364
1365 get_flags( data[ GAG_FLAGS ], szFlags, charsmax( szFlags ) );
1366
1367 fprintf( hFile, "^"%s^" ^"%i^" ^"%i^" ^"%s^"^n", data[ GAG_AUTHID ], data[ GAG_TIME ], data[ GAG_START ], szFlags );
1368 }
1369
1370 fclose( hFile );
1371 }
1372}
1373
1374GetTimeUnit( )
1375{
1376 new szTimeUnit[ 64 ], iTimeUnit;
1377 get_pcvar_string( g_pCvarTimeUnit, szTimeUnit, charsmax( szTimeUnit ) );
1378
1379 if( is_str_num( szTimeUnit ) )
1380 {
1381 iTimeUnit = get_pcvar_num( g_pCvarTimeUnit );
1382
1383 if( !( 0 <= iTimeUnit < TimeUnit ) )
1384 {
1385 iTimeUnit = -1;
1386 }
1387 }
1388 else
1389 {
1390 strtolower( szTimeUnit );
1391
1392 if( !TrieGetCell( g_tTimeUnitWords, szTimeUnit, iTimeUnit ) )
1393 {
1394 iTimeUnit = -1;
1395 }
1396 }
1397
1398 if( iTimeUnit == -1 )
1399 {
1400 iTimeUnit = TIMEUNIT_SECONDS;
1401
1402 set_pcvar_num( g_pCvarTimeUnit, TIMEUNIT_SECONDS );
1403 }
1404
1405 return iTimeUnit;
1406}
1407
1408GetTimeLength( iTime, szOutput[ ], iOutputLen )
1409{
1410 new szTimes[ TimeUnit ][ 32 ];
1411 new iUnit, iValue, iTotalDisplay;
1412
1413 for( new i = TimeUnit - 1; i >= 0; i-- )
1414 {
1415 iUnit = g_iTimeUnitMult[ i ];
1416 iValue = iTime / iUnit;
1417
1418 if( iValue )
1419 {
1420 formatex( szTimes[ i ], charsmax( szTimes[ ] ), "%d %s", iValue, g_szTimeUnitName[ i ][ iValue != 1 ] );
1421
1422 iTime %= iUnit;
1423
1424 iTotalDisplay++;
1425 }
1426 }
1427
1428 new iLen, iTotalLeft = iTotalDisplay;
1429 szOutput[ 0 ] = 0;
1430
1431 for( new i = TimeUnit - 1; i >= 0; i-- )
1432 {
1433 if( szTimes[ i ][ 0 ] )
1434 {
1435 iLen += formatex( szOutput[ iLen ], iOutputLen - iLen, "%s%s%s",
1436 ( iTotalDisplay > 2 && iLen ) ? ", " : "",
1437 ( iTotalDisplay > 1 && iTotalLeft == 1 ) ? ( ( iTotalDisplay > 2 ) ? "and " : " and " ) : "",
1438 szTimes[ i ]
1439 );
1440
1441 iTotalLeft--;
1442 }
1443 }
1444
1445 return iLen
1446}
1447
1448GreenPrint( id, iSender, const szRawMessage[ ], any:... )
1449{
1450 if( !iSender )
1451 {
1452 new iPlayers[ 32 ], iNum;
1453 get_players( iPlayers, iNum, "ch" );
1454
1455 if( !iNum ) return;
1456
1457 iSender = iPlayers[ 0 ];
1458 }
1459
1460 new szMessage[ 192 ];
1461 vformat( szMessage, charsmax( szMessage ), szRawMessage, 4 );
1462
1463 message_begin( id ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, g_iMsgSayText, _, id );
1464 write_byte( iSender );
1465 write_string( szMessage );
1466 message_end( );
1467}
1468
1469bool:IsValidSteamID( const szSteamID[ ] )
1470{
1471 // STEAM_0:(0|1):\d+
1472 // 012345678 90
1473
1474 // 0-7 = STEAM_0:
1475 // 8 = 0 or 1
1476 // 9 = :
1477 // 10+ = integer
1478
1479 return ( ( '0' <= szSteamID[ 8 ] <= '1' ) && szSteamID[ 9 ] == ':' && equal( szSteamID, "STEAM_0:", 8 ) && is_str_num( szSteamID[ 10 ] ) );
1480}
1481
1482GetAccessBySteamID( const szSteamID[ ] )
1483{
1484 new szAuthData[ 44 ], iCount = admins_num( );
1485
1486 for( new i; i < iCount; i++ )
1487 {
1488 if( admins_lookup( i, AdminProp_Flags ) & FLAG_AUTHID )
1489 {
1490 admins_lookup( i, AdminProp_Auth, szAuthData, charsmax( szAuthData ) );
1491
1492 if( equal( szAuthData, szSteamID ) )
1493 {
1494 return admins_lookup( i, AdminProp_Access );
1495 }
1496 }
1497 }
1498
1499 return 0;
1500}
1501
1502strtotime(const string[])
1503{
1504 new szTemp[ 32 ];
1505 new szYear[ 5 ], szMonth[ 3 ], szDay[ 3 ], szHour[ 3 ], szMinute[ 3 ], szSecond[ 3 ];
1506 strtok( string, szYear, charsmax( szYear ), szTemp, charsmax( szTemp ), '-' );
1507 strtok( szTemp, szMonth, charsmax( szMonth ), szTemp, charsmax( szTemp ), '-' );
1508 strtok( szTemp, szDay, charsmax( szDay ), szTemp, charsmax( szTemp ), ' ' );
1509 strtok( szTemp, szHour, charsmax( szHour ), szTemp, charsmax( szTemp ), ':' );
1510 strtok( szTemp, szMinute, charsmax( szMinute ), szSecond, charsmax( szSecond ), ':' );
1511
1512 return TimeToUnix( str_to_num( szYear ), str_to_num( szMonth ), str_to_num( szDay ), str_to_num( szHour ), str_to_num( szMinute ), str_to_num( szSecond ) );
1513}
1514
1515AddGag( admin, player, iGagTime, iFlags )
1516{
1517 new szAdminName[ 32 ], szAdminIP[ 16 ];
1518
1519 if( admin )
1520 {
1521 get_user_name( admin, szAdminName, charsmax( szAdminName ) );
1522 }
1523 else
1524 {
1525 copy( szAdminName, charsmax( szAdminName ), "SERVER" );
1526 }
1527
1528 get_user_ip( admin, szAdminIP, charsmax( szAdminIP ), 1 );
1529
1530 new szPlayerName[ 32 ], szPlayerIP[ 16 ];
1531 get_user_name( player, szPlayerName, charsmax( szPlayerName ) );
1532 get_user_ip( player, szPlayerIP, charsmax( szPlayerIP ), 1 );
1533
1534 new szDateNow[ DATE_SIZE ], szDateUngag[ DATE_SIZE ];
1535 get_time( DATETIME_FORMAT, szDateNow, charsmax( szDateNow ) );
1536 format_time( szDateUngag, charsmax( szDateUngag ), DATETIME_FORMAT, get_systime( ) + iGagTime );
1537
1538 new szFlags[ 4 ];
1539 get_flags( iFlags, szFlags, charsmax( szFlags ) );
1540
1541 new szQuery[ 256 ];
1542 formatex( szQuery, charsmax( szQuery ), "REPLACE INTO gagged_players \
1543 (admin_name, admin_steamid, admin_ip, player_name, player_steamid, player_ip, date_gagged, date_ungag, gag_seconds, gag_flags) \
1544 VALUES \
1545 (^"%s^", ^"%s^", ^"%s^", ^"%s^", ^"%s^", ^"%s^", ^"%s^", ^"%s^", %d, ^"%s^");",\
1546 szAdminName, g_szAuthid[ admin ], szAdminIP,\
1547 szPlayerName, g_szAuthid[ player ], szPlayerIP,\
1548 szDateNow, szDateUngag, iGagTime, szFlags );
1549
1550 SQL_ThreadQuery( g_hSqlTuple, "QueryAdd", szQuery );
1551}
1552
1553public QueryAdd( iFailState, Handle:hQuery, szError[ ], iError, iData[ ], iDataSize, Float:flQueueTime )
1554{
1555 switch( iFailState )
1556 {
1557 case TQUERY_CONNECT_FAILED: log_amx( "Failed to connect to database: (%d) %s", iError, szError );
1558 case TQUERY_QUERY_FAILED: log_amx( "Failed add gag query: (%d) %s", iError, szError );
1559 }
1560}
1561
1562// CODE BELOW FROM BUGSY'S UNIX TIME INCLUDE
1563//
1564
1565stock const YearSeconds[2] =
1566{
1567 31536000, //Normal year
1568 31622400 //Leap year
1569};
1570
1571stock const MonthSeconds[12] =
1572{
1573 2678400, //January 31
1574 2419200, //February 28
1575 2678400, //March 31
1576 2592000, //April 30
1577 2678400, //May 31
1578 2592000, //June 30
1579 2678400, //July 31
1580 2678400, //August 31
1581 2592000, //September 30
1582 2678400, //October 31
1583 2592000, //November 30
1584 2678400 //December 31
1585};
1586
1587stock const DaySeconds = 86400;
1588stock const HourSeconds = 3600;
1589stock const MinuteSeconds = 60;
1590
1591stock TimeToUnix( const iYear , const iMonth , const iDay , const iHour , const iMinute , const iSecond )
1592{
1593 new i;
1594 new iTimeStamp;
1595
1596 for ( i = 1970 ; i < iYear ; i++ )
1597 iTimeStamp += YearSeconds[ IsLeapYear(i) ];
1598
1599 for ( i = 1 ; i < iMonth ; i++ )
1600 iTimeStamp += SecondsInMonth( iYear , i );
1601
1602 iTimeStamp += ( ( iDay - 1 ) * DaySeconds );
1603 iTimeStamp += ( iHour * HourSeconds );
1604 iTimeStamp += ( iMinute * MinuteSeconds );
1605 iTimeStamp += iSecond;
1606
1607 return iTimeStamp;
1608}
1609
1610stock SecondsInMonth( const iYear , const iMonth )
1611{
1612 return ( ( IsLeapYear( iYear ) && ( iMonth == 2 ) ) ? ( MonthSeconds[iMonth - 1] + DaySeconds ) : MonthSeconds[iMonth - 1] );
1613}
1614
1615stock IsLeapYear( const iYear )
1616{
1617 return ( ( (iYear % 4) == 0) && ( ( (iYear % 100) != 0) || ( (iYear % 400) == 0 ) ) );
1618}