· 9 years ago · Nov 18, 2016, 03:58 AM
1/*
2 [CS:S] CT Bans
3 by: databomb
4
5 Description:
6
7 Allows admins to restrict access to the CT team from those who violate the server's rules. There are already two plugins posted that I'm aware of for this. Mr. Zero's Team Restrict plugin which has basic command functionality but doesn't save the data past a map change/disconnect. Azelphur's TeamBans plugin also uses ClientPrefs but doesn't allow for banning those who disconnect or timed team bans.
8
9 Features:
10 - CT Bans are stored in the ClientPrefs database and survive map changes, re-joins, and server crashes.
11 - The Rage Ban feature allows admins to CT ban rage quitters who break the server's rules and then quickly disconnect.
12 - You may give a timed CT ban which will work based on in minutes spent alive (so idlers in spectate or those who suicide at the beginning of the round will not be working toward an unban.)
13 - The timed CT bans are stored in a SQL table for stateful access.
14 - The plugin logs CT ban to a SQL table in addition to your regular SM logs.
15 - Re-displays the team selection screen after an improper selection was made.
16 - SM Menu integration for the rageban and ctban commands.
17 - Displays helpful message to users who are CT banned when they join the server.
18 - SM Translations support.
19
20 Installation:
21 Place the phrases.txt in your addons/sourcemod/translations directory.
22 Place the .smx in your addons/sourcemod/plugins directory.
23 Check your logs/server-console after the initial load for any SQL errors. If you have any SQL errors check your addons/sourcemod/configs/databases.cfg file and verify you can connect using the drivers you have specified.
24
25 Command Usage:
26
27 sm_ctban <player>
28 Bans the selected player from joining the CT team.
29
30 sm_removectban <player> | sm_unctban <player>
31 Removes the CT ban on the selected player.
32
33 sm_isbanned <player>
34 Reports back the status of the current player's CT ban and the time remaining on the ban, if any.
35
36 sm_rageban
37 Brings up a menu so you may choose a recently disconnected player to permanently CT ban.
38
39 sm_ctban_offline <steamid>
40 Bans the given Steam Id from playing on the CT team.
41
42 sm_removectban_offline <steamid> | sm_unctban_offline <steamid>
43 Unbans the given Steam Id from the CT team.
44
45 Settings:
46 sm_ctban_enable, [0,1]: Toggles functionality. When set to 0 this will allow those players who are CT banned to join the CT team.
47 sm_ctban_soundfile, <path>: The path to the soundfile to play when denying a team-change request. Set to "" to disable.
48 sm_ctban_joinbanmsg, <message>: This message is appended to a time-stamp when a CT banned user joins the server.
49 sm_ctban_table_prefix, <prefix>: This prefix will be added in front of the table names.
50 sm_ctban_database_driver, <driver>: This specifies which driver to use from database.cfg
51
52 Special Thanks:
53 Azelphur for the idea of using bitmasks to improve efficiency and snippets of cross-mod code.
54 Kigen for the idea of CT banning based on time spent alive.
55
56 Future Considerations:
57 Allow offline editing as soon as SetAuthIdCookie native is added to latest SourceMod
58 Improved web interface
59 Allowing for more than 7 reasons to CT Ban
60
61 Change Log:
62 1.6.1.3 Fixed bug with EscapeString function which caused query failures
63 1.6.1.2 Fixed SQL Injection vulnerability
64 1.6.1.1 Fixed problem in UTIL_TeamMenu()
65 1.6.1 Support for new SM1.4 natives, Added confi file generation
66 1.6.0 Added support for new SM1.4 natives
67 1.5.0 Initial public release
68 1.4.4 Stable internal build
69
70*/
71
72#pragma semicolon 1
73#define CHAT_BANNER "\x03[SM] \x01%t"
74
75#include <sourcemod>
76#include <clientprefs>
77#include <sdktools>
78#include <adminmenu>
79#include <cstrike>
80
81#define PLUGIN_VERSION "1.6.1.3"
82
83// compilation settings:
84// (set DEBUG and OCAOFF to 1 for best debugging results)
85// (setting USESQL to 0 is not recommended)
86#define DEBUG 0
87#define OCAOFF 0
88#define USESQL 1
89
90new Handle:g_CT_Cookie = INVALID_HANDLE;
91new Handle:gH_Cvar_Enabled = INVALID_HANDLE;
92new Handle:g_Handles[MAXPLAYERS+1];
93new Handle:gH_TopMenu = INVALID_HANDLE;
94new Handle:gH_Cvar_SoundName = INVALID_HANDLE;
95new String:gS_SoundPath[PLATFORM_MAX_PATH];
96new Handle:gH_Cvar_JoinBanMessage = INVALID_HANDLE;
97new Handle:gH_Cvar_Database_Driver = INVALID_HANDLE;
98new Handle:gA_DNames = INVALID_HANDLE;
99new Handle:gA_DSteamIDs = INVALID_HANDLE;
100new Handle:gH_CP_DataBase = INVALID_HANDLE;
101new Handle:gH_BanDatabase = INVALID_HANDLE;
102new Handle:gH_Cvar_Table_Prefix = INVALID_HANDLE;
103new g_iCookieIndex;
104new bool:g_bAuthIdNativeExists = false;
105new Handle:gA_TimedBanLocalList = INVALID_HANDLE;
106new gA_LocalTimeRemaining[MAXPLAYERS+1];
107#if USESQL == 0
108new Handle:gA_TimedBanSteamList = INVALID_HANDLE;
109#endif
110new gA_CTBanTargetUserId[MAXPLAYERS+1];
111new gA_CTBanTimeLength[MAXPLAYERS+1];
112new String:g_sLogTableName[32];
113new String:g_sTimesTableName[32];
114
115public Plugin:myinfo =
116{
117 name = "CT Ban",
118 author = "databomb",
119 description = "Allows admins to ban players from joining the CT team.",
120 version = PLUGIN_VERSION,
121 url = "vintagejailbreak.org"
122};
123
124public OnPluginStart()
125{
126 CreateConVar("sm_ctban_version", PLUGIN_VERSION, "CT Ban Version", FCVAR_SPONLY|FCVAR_DONTRECORD|FCVAR_REPLICATED|FCVAR_NOTIFY);
127 gH_Cvar_Enabled = CreateConVar("sm_ctban_enable","1","Enables CT bans cookie handling", FCVAR_PLUGIN);
128 gH_Cvar_SoundName = CreateConVar("sm_ctban_soundfile", "buttons/button11.wav", "The name of the sound to play when an action is denied",FCVAR_PLUGIN);
129 gH_Cvar_JoinBanMessage = CreateConVar("sm_ctban_joinbanmsg", "To appeal this go to VintageJailbreak.org", "This text is appended to the time the user was last CT banned when they join T or Spectator teams.", FCVAR_PLUGIN);
130 gH_Cvar_Table_Prefix = CreateConVar("sm_ctban_table_prefix", "", "Adds a prefix to the CT Bans table, leave this blank unless you have a need to add a prefix for multiple servers on one database.", FCVAR_PLUGIN);
131 gH_Cvar_Database_Driver = CreateConVar("sm_ctban_database_driver", "default", "Specifies the configuration driver to use from SourceMod's database.cfg", FCVAR_PLUGIN);
132
133 AutoExecConfig(true, "ctban");
134
135 g_CT_Cookie = RegClientCookie("Banned_From_CT", "Tells if you are restricted from joining the CT team", CookieAccess_Protected);
136
137 RegAdminCmd("sm_ctban", Command_CTBan, ADMFLAG_SLAY, "sm_ctban <player> <optional: time> - Bans a player from being a CT.");
138 RegAdminCmd("sm_isbanned", Command_IsCTBanned, ADMFLAG_GENERIC, "sm_isbanned <player> - Lets you know if a player is banned from CT team.");
139 RegAdminCmd("sm_removectban", Command_UnCTBan, ADMFLAG_SLAY, "sm_removectban <player> - Unrestricts a player from being a CT.");
140 RegAdminCmd("sm_unctban", Command_UnCTBan, ADMFLAG_SLAY, "sm_unctban <player> - Unrestricts a player from being a CT.");
141 RegAdminCmd("sm_rageban", Command_RageBan, ADMFLAG_SLAY, "sm_rageban <player> - Allows you to ban those who rage quit.");
142 RegAdminCmd("sm_ctban_offline", Command_Offline_CTBan, ADMFLAG_KICK, "sm_ctban_offline <steamid> - Allows admins to CT Ban players who have long left the server using their Steam Id.");
143 RegAdminCmd("sm_unctban_offline", Command_Offline_UnCTBan, ADMFLAG_KICK, "sm_unctban_offline <steamid> - Allows admins to remove CT Bans on players who have long left the server using their Steam Id.");
144 RegAdminCmd("sm_removectban_offline", Command_Offline_UnCTBan, ADMFLAG_KICK, "sm_unctban_offline <steamid> - Allows admins to remove CT Bans on players who have long left the server using their Steam Id.");
145
146 LoadTranslations("ctban.phrases");
147 LoadTranslations("common.phrases");
148
149 // create arrays for the rage bans
150 gA_DNames = CreateArray(MAX_TARGET_LENGTH);
151 gA_DSteamIDs = CreateArray(22);
152 g_iCookieIndex = 0;
153
154 // Hook this to block joins when player is banned
155 AddCommandListener(Command_CheckJoin, "jointeam");
156
157 // create local array for timed bans
158 // block 0: client index
159 gA_TimedBanLocalList = CreateArray(2);
160 for (new idx = 1; idx <= MaxClients; idx++)
161 {
162 gA_LocalTimeRemaining[idx] = 0;
163 gA_CTBanTargetUserId[idx] = 0;
164 }
165 #if USESQL == 0
166 // steam array structure:
167 // blocks 0-21: steamID string
168 // block 22: ban time remaining
169 gA_TimedBanSteamList = CreateArray(23);
170 #endif
171
172 // periodic timer to handle timed bans
173 CreateTimer(60.0, CheckTimedCTBans, _, TIMER_REPEAT);
174
175 /* Account for late loading */
176 new Handle:topmenu;
177 if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
178 {
179 OnAdminMenuReady(topmenu);
180 }
181}
182
183public OnAllPluginsLoaded()
184{
185 g_bAuthIdNativeExists = IsSetAuthIdNativePresent();
186}
187
188// consider if someone does a 'retry' and clientprefs is accessinsg on its ClientConnectCallback and this is also trying to set a value
189public OnClientAuthorized(client, const String:sSteamID[])
190{
191 #if OCAOFF == 0
192 // check if the Steam ID is in the Rage Ban list
193 new iNeedle = FindStringInArray(gA_DSteamIDs, sSteamID);
194 if (iNeedle != -1)
195 {
196 RemoveFromArray(gA_DNames, iNeedle);
197 RemoveFromArray(gA_DSteamIDs, iNeedle);
198 #if DEBUG == 1
199 LogMessage("removed %N from Rage Bannable player list for re-connecting to the server", client);
200 #endif
201 }
202 #endif
203
204 #if USESQL == 1
205 // check if the Steam ID is in the Timed Ban list
206 decl String:query[255];
207 Format(query, sizeof(query), "SELECT ctbantime FROM %s WHERE steamid = '%s'", g_sTimesTableName, sSteamID);
208 SQL_TQuery(gH_BanDatabase, DB_Callback_OnClientAuthed, query, _:client);
209
210 #else
211
212 new iSteamArrayIndex = FindStringInArray(gA_TimedBanSteamList, sSteamID);
213 if (iSteamArrayIndex != -1)
214 {
215 gA_LocalTimeRemaining[client] = GetArrayCell(gA_TimedBanSteamList, iSteamArrayIndex, 22);
216 #if DEBUG == 1
217 LogMessage("%N joined with %i time remaining on ban", client, gA_LocalTimeRemaining[client]);
218 #endif
219 }
220 #endif
221}
222
223public DB_Callback_OnClientAuthed(Handle:owner, Handle:hndl, const String:error[], any:client)
224{
225 if (hndl == INVALID_HANDLE)
226 {
227 LogError("Error in OnClientAuthorized query: %s", error);
228 }
229 else
230 {
231 new iRowCount = SQL_GetRowCount(hndl);
232 #if DEBUG == 1
233 LogMessage("SQL Auth: %d row count", iRowCount);
234 #endif
235 if (iRowCount)
236 {
237 SQL_FetchRow(hndl);
238 new iBanTimeRemaining = SQL_FetchInt(hndl, 0);
239 #if DEBUG == 1
240 LogMessage("SQL Auth: %N joined with %i time remaining on ban", client, iBanTimeRemaining);
241 #endif
242 // update local time
243 PushArrayCell(gA_TimedBanLocalList, client);
244 gA_LocalTimeRemaining[client] = iBanTimeRemaining;
245 }
246 }
247}
248
249public AdminMenu_RageBan(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
250{
251 if (action == TopMenuAction_DisplayOption)
252 {
253 Format(buffer, maxlength, "Rage Ban");
254 }
255 else if (action == TopMenuAction_SelectOption)
256 {
257 DisplayRageBanMenu(param, GetArraySize(gA_DNames));
258 }
259}
260
261DisplayRageBanMenu(Client, ArraySize)
262{
263 if (ArraySize == 0)
264 {
265 PrintToChat(Client, CHAT_BANNER, "No Targets");
266 }
267 else
268 {
269 new Handle:menu = CreateMenu(MenuHandler_RageBan);
270
271 SetMenuTitle(menu, "%T", "Rage Ban Menu Title", Client);
272 SetMenuExitBackButton(menu, true);
273
274 for (new ArrayIndex = 0; ArrayIndex < ArraySize; ArrayIndex++)
275 {
276 decl String:sName[MAX_TARGET_LENGTH];
277 GetArrayString(gA_DNames, ArrayIndex, sName, sizeof(sName));
278 decl String:sSteamID[22];
279 GetArrayString(gA_DSteamIDs, ArrayIndex, sSteamID, sizeof(sSteamID));
280 AddMenuItem(menu, sSteamID, sName);
281 }
282
283 DisplayMenu(menu, Client, MENU_TIME_FOREVER);
284 }
285}
286
287public MenuHandler_RageBan(Handle:menu, MenuAction:action, param1, param2)
288{
289 if (action == MenuAction_End)
290 {
291 CloseHandle(menu);
292 }
293 else if (action == MenuAction_Cancel)
294 {
295 if ((param2 == MenuCancel_ExitBack) && (gH_TopMenu != INVALID_HANDLE))
296 {
297 DisplayTopMenu(gH_TopMenu, param1, TopMenuPosition_LastCategory);
298 }
299 }
300 else if (action == MenuAction_Select)
301 {
302 decl String:sInfoString[22];
303 GetMenuItem(menu, param2, sInfoString, sizeof(sInfoString));
304
305 if (g_bAuthIdNativeExists)
306 {
307 SetAuthIdCookie(sInfoString, g_CT_Cookie, "1");
308 }
309 else
310 {
311 // determine if they're in the clientprefs SQL database yet
312 if (gH_CP_DataBase != INVALID_HANDLE)
313 {
314 decl String:query[255];
315 Format(query, sizeof(query), "SELECT value FROM sm_cookie_cache WHERE player = '%s' and cookie_id = '%i'", sInfoString, g_iCookieIndex);
316 new Handle:TheDataPack = CreateDataPack();
317 // authID
318 WritePackString(TheDataPack, sInfoString);
319 // admin who banned (client index)
320 WritePackCell(TheDataPack, param1);
321 // array index to CTBan
322 WritePackCell(TheDataPack, param2);
323 SQL_TQuery(gH_CP_DataBase, CP_Callback_CheckBan, query, TheDataPack);
324 }
325 }
326 #if DEBUG == 1
327 PrintToChat(param1, CHAT_BANNER, "Ready to CT Ban", sInfoString);
328 #endif
329 }
330}
331
332public CP_Callback_CheckBan(Handle:owner, Handle:hndl, const String:error[], any:stringPack)
333{
334 if (hndl == INVALID_HANDLE)
335 {
336 LogError("CT Ban query had a failure: %s", error);
337 CloseHandle(stringPack);
338 }
339 else
340 {
341 ResetPack(stringPack);
342 decl String:authID[22];
343 ReadPackString(stringPack, authID, sizeof(authID));
344 new iAdminIndex = ReadPackCell(stringPack);
345 new iArrayBanIndex = ReadPackCell(stringPack);
346 CloseHandle(stringPack);
347
348 new iTimeStamp = GetTime();
349
350 new iRowCount = SQL_GetRowCount(hndl);
351 if (iRowCount)
352 {
353 #if DEBUG == 1
354 SQL_FetchRow(hndl);
355 new iCTBanStatus = SQL_FetchInt(hndl, 0);
356 LogMessage("CTBan status on player is currently %i. Will do UPDATE on %s", iCTBanStatus, authID);
357 #endif
358
359 decl String:query[255];
360 Format(query, sizeof(query), "UPDATE sm_cookie_cache SET value = '1', timestamp = %i WHERE player = '%s' AND cookie_id = '%i'", iTimeStamp, authID, g_iCookieIndex);
361 #if DEBUG == 1
362 LogMessage("Query to run: %s", query);
363 #endif
364 SQL_TQuery(gH_CP_DataBase, CP_Callback_IssueBan, query);
365 }
366 else
367 {
368 #if DEBUG == 1
369 LogMessage("couldn't find steamID in database, need to INSERT");
370 #endif
371
372 decl String:query[255];
373 Format(query, sizeof(query), "INSERT INTO sm_cookie_cache (player, cookie_id, value, timestamp) VALUES ('%s', %i, '1', %i)", authID, g_iCookieIndex, iTimeStamp);
374 #if DEBUG == 1
375 LogMessage("Query to run: %s", query);
376 #endif
377 SQL_TQuery(gH_CP_DataBase, CP_Callback_IssueBan, query);
378 }
379
380 // log this info
381 decl String:sTargetName[MAX_TARGET_LENGTH];
382 GetArrayString(gA_DNames, iArrayBanIndex, sTargetName, sizeof(sTargetName));
383 decl String:adminSteamID[32];
384 GetClientAuthId(iAdminIndex, AuthId_Steam2, adminSteamID, sizeof(adminSteamID));
385
386 #if USESQL == 1
387 decl String:logQuery[350];
388 decl String:temp[300];
389 new String:escapedPerpName[300];
390 Format(temp, sizeof(temp), "%s", sTargetName);
391 SQL_EscapeString(gH_BanDatabase, temp, escapedPerpName, sizeof(escapedPerpName));
392 Format(logQuery, sizeof(logQuery), "INSERT INTO %s (timestamp, perp_steamid, perp_name, admin_steamid, admin_name, bantime, timeleft, reason) VALUES (%d, '%s', '%s', '%s', 'Console', 0, 0, 'Rage ban')", g_sLogTableName, iTimeStamp, authID, escapedPerpName, adminSteamID);
393 #if DEBUG == 1
394 LogMessage("log query: %s", logQuery);
395 #endif
396 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, logQuery, iAdminIndex);
397 #endif
398
399 LogMessage("%N (%s) has issued a rage ban on %s (%s) indefinitely.", iAdminIndex, adminSteamID, sTargetName, authID);
400
401 ShowActivity2(iAdminIndex, "[SM] ", "%t", "Rage Ban", sTargetName);
402
403 // clear the position from array
404 RemoveFromArray(gA_DNames, iArrayBanIndex);
405 RemoveFromArray(gA_DSteamIDs, iArrayBanIndex);
406 #if DEBUG == 1
407 LogMessage("Removed %i index from rage ban menu.", iArrayBanIndex);
408 #endif
409 }
410}
411
412public CP_Callback_IssueBan(Handle:owner, Handle:hndl, const String:error[], any:data)
413{
414 if (hndl == INVALID_HANDLE)
415 {
416 LogError("Error writing to database: %s", error);
417 }
418 else
419 {
420 #if DEBUG == 1
421 LogMessage("succesfully wrote to the database");
422 #endif
423 }
424}
425
426public Action:Command_Offline_CTBan(client, args)
427{
428 decl String:sAuthId[32];
429 GetCmdArgString(sAuthId, sizeof(sAuthId));
430 if (g_bAuthIdNativeExists)
431 {
432 SetAuthIdCookie(sAuthId, g_CT_Cookie, "1");
433 ReplyToCommand(client, CHAT_BANNER, "Banned AuthId", sAuthId);
434 }
435 else
436 {
437 ReplyToCommand(client, CHAT_BANNER, "Feature Not Available");
438 }
439 return Plugin_Handled;
440}
441
442public Action:Command_Offline_UnCTBan(client, args)
443{
444 decl String:sAuthId[32];
445 GetCmdArgString(sAuthId, sizeof(sAuthId));
446 if (g_bAuthIdNativeExists)
447 {
448 SetAuthIdCookie(sAuthId, g_CT_Cookie, "0");
449 ReplyToCommand(client, CHAT_BANNER, "Unbanned AuthId", sAuthId);
450 }
451 else
452 {
453 ReplyToCommand(client, CHAT_BANNER, "Feature Not Available");
454 }
455 return Plugin_Handled;
456}
457
458public Action:Command_RageBan(client, args)
459{
460 new iArraySize = GetArraySize(gA_DNames);
461 if (iArraySize == 0)
462 {
463 ReplyToCommand(client, CHAT_BANNER, "No Targets");
464 return Plugin_Handled;
465 }
466
467 if (!args)
468 {
469 if (client)
470 {
471 DisplayRageBanMenu(client, iArraySize);
472 }
473 else
474 {
475 ReplyToCommand(client, CHAT_BANNER, "Feature Not Available On Console");
476 }
477 return Plugin_Handled;
478 }
479 else
480 {
481 ReplyToCommand(client, "[SM] Usage: sm_rageban");
482 }
483
484 return Plugin_Handled;
485}
486
487public Action:CheckTimedCTBans(Handle:timer)
488{
489 // check if anyone has a time
490 new iTimeArraySize = GetArraySize(gA_TimedBanLocalList);
491
492 // credit for this idea goes to Kigen
493 for (new idx = 0; idx < iTimeArraySize; idx++)
494 {
495 new iBannedClientIndex = GetArrayCell(gA_TimedBanLocalList, idx);
496 if (IsClientInGame(iBannedClientIndex))
497 {
498 if (IsPlayerAlive(iBannedClientIndex))
499 {
500 gA_LocalTimeRemaining[iBannedClientIndex]--;
501 #if DEBUG == 1
502 LogMessage("found alive time banned client with %i remaining", gA_LocalTimeRemaining[iBannedClientIndex]);
503 #endif
504 // check if we should remove the CT ban
505 if (gA_LocalTimeRemaining[iBannedClientIndex] <= 0)
506 {
507 // remove CT ban
508 RemoveFromArray(gA_TimedBanLocalList, idx);
509 iTimeArraySize--;
510 Remove_CTBan(0, iBannedClientIndex, true);
511 #if DEBUG == 1
512 LogMessage("removed CT ban on %N", iBannedClientIndex);
513 #endif
514 }
515 }
516 }
517 }
518}
519
520public OnConfigsExecuted()
521{
522 SQL_TConnect(CP_Callback_Connect, "clientprefs");
523
524 decl String:sDatabaseDriver[64];
525 GetConVarString(gH_Cvar_Database_Driver, sDatabaseDriver, sizeof(sDatabaseDriver));
526 SQL_TConnect(DB_Callback_Connect, sDatabaseDriver);
527}
528
529public DB_Callback_Connect(Handle:owner, Handle:hndl, const String:error[], any:data)
530{
531 if (hndl == INVALID_HANDLE)
532 {
533 LogError("Default database database connection failure: %s", error);
534 SetFailState("Error while connecting to default database. Exiting.");
535 }
536 else
537 {
538 gH_BanDatabase = hndl;
539
540 // figure out table prefix situation
541 decl String:sPrefix[64];
542 GetConVarString(gH_Cvar_Table_Prefix, sPrefix, sizeof(sPrefix));
543 if (strlen(sPrefix) > 0)
544 {
545 Format(g_sTimesTableName, sizeof(g_sTimesTableName), "%s_CTBan_Times", sPrefix);
546 }
547 else
548 {
549 Format(g_sTimesTableName, sizeof(g_sTimesTableName), "CTBan_Times");
550 }
551
552 decl String:sQuery[255];
553 Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS %s (steamid VARCHAR(22), ctbantime INT(16), PRIMARY KEY (steamid))", g_sTimesTableName);
554
555 // create database if not already there
556 SQL_TQuery(gH_BanDatabase, DB_Callback_Create, sQuery);
557
558 if (strlen(sPrefix) > 0)
559 {
560 Format(g_sLogTableName, sizeof(g_sLogTableName), "%s_CTBan_Log", sPrefix);
561 }
562 else
563 {
564 Format(g_sLogTableName, sizeof(g_sLogTableName), "CTBan_Log");
565 }
566
567 Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS %s (timestamp INT, perp_steamid VARCHAR(22), perp_name VARCHAR(32), admin_steamid VARCHAR(22), admin_name VARCHAR(32), bantime INT(16), timeleft INT(16), reason VARCHAR(200), PRIMARY KEY (timestamp))", g_sLogTableName);
568 SQL_TQuery(gH_BanDatabase, DB_Callback_Create, sQuery);
569 }
570}
571
572public DB_Callback_Create(Handle:owner, Handle:hndl, const String:error[], any:data)
573{
574 if (hndl == INVALID_HANDLE)
575 {
576 LogError("Error establishing table creation: %s", error);
577 SetFailState("Unable to ascertain creation of table in default database. Exiting.");
578 }
579}
580
581public CP_Callback_Connect(Handle:owner, Handle:hndl, const String:error[], any:data)
582{
583 if (hndl == INVALID_HANDLE)
584 {
585 LogError("Clientprefs database connection failure: %s", error);
586 SetFailState("Error while connecting to clientprefs database. Exiting.");
587 }
588 else
589 {
590 gH_CP_DataBase = hndl;
591
592 // find the Banned_From_CT Cookie id #
593 SQL_TQuery(gH_CP_DataBase, CP_Callback_FindCookie, "SELECT id FROM sm_cookies WHERE name = 'Banned_From_CT'");
594 }
595}
596
597public CP_Callback_FindCookie(Handle:owner, Handle:hndl, const String:error[], any:data)
598{
599 if (hndl == INVALID_HANDLE)
600 {
601 LogError("Cookie query failure: %s", error);
602 }
603 else
604 {
605 new iRowCount = SQL_GetRowCount(hndl);
606 if (iRowCount)
607 {
608 SQL_FetchRow(hndl);
609 new CookieIDIndex = SQL_FetchInt(hndl, 0);
610 #if DEBUG == 1
611 LogMessage("found cookie index as %i", CookieIDIndex);
612 #endif
613 g_iCookieIndex = CookieIDIndex;
614 }
615 else
616 {
617 LogError("Could not find the cookie index. Rageban functionality disabled.");
618 }
619 }
620}
621
622public OnMapStart()
623{
624 // pre-cache deny sound
625 decl String:buffer[PLATFORM_MAX_PATH];
626 GetConVarString(gH_Cvar_SoundName, gS_SoundPath, sizeof(gS_SoundPath));
627 if(strcmp(gS_SoundPath, ""))
628 {
629 PrecacheSound(gS_SoundPath, true);
630 Format(buffer, sizeof(buffer), "sound/%s", gS_SoundPath);
631 AddFileToDownloadsTable(buffer);
632 }
633}
634
635public OnAdminMenuReady(Handle:topmenu)
636{
637 /* Block us from being called twice */
638 if (topmenu == gH_TopMenu)
639 {
640 return;
641 }
642
643 /* Save the Handle */
644 gH_TopMenu = topmenu;
645
646 /* Build the "Player Commands" category */
647 new TopMenuObject:frequent_commands = FindTopMenuCategory(gH_TopMenu, "ts_commands");
648
649 if (frequent_commands != INVALID_TOPMENUOBJECT)
650 {
651 AddToTopMenu(gH_TopMenu,
652 "sm_ctban",
653 TopMenuObject_Item,
654 AdminMenu_CTBan,
655 frequent_commands,
656 "sm_ctban",
657 ADMFLAG_SLAY);
658 }
659
660 /* Build the "Player Commands" category */
661 new TopMenuObject:player_commands = FindTopMenuCategory(gH_TopMenu, ADMINMENU_PLAYERCOMMANDS);
662
663 if (player_commands != INVALID_TOPMENUOBJECT)
664 {
665 AddToTopMenu(gH_TopMenu,
666 "sm_rageban",
667 TopMenuObject_Item,
668 AdminMenu_RageBan,
669 player_commands,
670 "sm_rageban",
671 ADMFLAG_SLAY);
672
673 if (frequent_commands == INVALID_TOPMENUOBJECT)
674 {
675 AddToTopMenu(gH_TopMenu,
676 "sm_ctban",
677 TopMenuObject_Item,
678 AdminMenu_CTBan,
679 player_commands,
680 "sm_ctban",
681 ADMFLAG_SLAY);
682 }
683 }
684}
685
686public AdminMenu_CTBan(Handle:topmenu,
687 TopMenuAction:action,
688 TopMenuObject:object_id,
689 param,
690 String:buffer[],
691 maxlength)
692{
693 if (action == TopMenuAction_DisplayOption)
694 {
695 Format(buffer, maxlength, "CT Ban");
696 }
697 else if (action == TopMenuAction_SelectOption)
698 {
699 DisplayCTBanPlayerMenu(param);
700 }
701}
702
703DisplayCTBanPlayerMenu(client)
704{
705 new Handle:menu = CreateMenu(MenuHandler_CTBanPlayerList);
706
707 SetMenuTitle(menu, "%T", "CT Ban Menu Title", client);
708 SetMenuExitBackButton(menu, true);
709
710 AddTargetsToMenu(menu, client, true, false);
711
712 DisplayMenu(menu, client, MENU_TIME_FOREVER);
713}
714
715DisplayCTBanTimeMenu(client, targetUserId)
716{
717 new Handle:menu = CreateMenu(MenuHandler_CTBanTimeList);
718
719 SetMenuTitle(menu, "%T", "CT Ban Length Menu", client, GetClientOfUserId(targetUserId));
720 SetMenuExitBackButton(menu, true);
721
722 AddMenuItem(menu, "0", "Permanent");
723 AddMenuItem(menu, "5", "5 Minutes");
724 AddMenuItem(menu, "10", "10 Minutes");
725 AddMenuItem(menu, "30", "30 Minutes");
726 AddMenuItem(menu, "60", "1 Hour");
727 AddMenuItem(menu, "120", "2 Hours");
728 AddMenuItem(menu, "240", "4 Hours");
729
730 DisplayMenu(menu, client, MENU_TIME_FOREVER);
731}
732
733DisplayCTBanReasonMenu(client)
734{
735 new Handle:menu = CreateMenu(MenuHandler_CTBanReasonList);
736
737 SetMenuTitle(menu, "%T", "CT Ban Reason Menu", client, GetClientOfUserId(gA_CTBanTargetUserId[client]));
738 SetMenuExitBackButton(menu, true);
739
740 decl String:sMenuReason[128];
741 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 1", client);
742 AddMenuItem(menu, "1", sMenuReason);
743 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 2", client);
744 AddMenuItem(menu, "2", sMenuReason);
745 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 3", client);
746 AddMenuItem(menu, "3", sMenuReason);
747 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 4", client);
748 AddMenuItem(menu, "4", sMenuReason);
749 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 5", client);
750 AddMenuItem(menu, "5", sMenuReason);
751 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 6", client);
752 AddMenuItem(menu, "6", sMenuReason);
753 Format(sMenuReason, sizeof(sMenuReason), "%T", "CT Ban Reason 7", client);
754 AddMenuItem(menu, "7", sMenuReason);
755
756 DisplayMenu(menu, client, MENU_TIME_FOREVER);
757}
758
759public MenuHandler_CTBanReasonList(Handle:menu, MenuAction:action, param1, param2)
760{
761 if (action == MenuAction_End)
762 {
763 CloseHandle(menu);
764 }
765 else if (action == MenuAction_Cancel)
766 {
767 if (param2 == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
768 {
769 DisplayTopMenu(gH_TopMenu, param1, TopMenuPosition_LastCategory);
770 }
771 }
772 else if (action == MenuAction_Select)
773 {
774 decl String:sBanChoice[10];
775 GetMenuItem(menu, param2, sBanChoice, sizeof(sBanChoice));
776 new iBanReason = StringToInt(sBanChoice);
777 new iTimeToBan = gA_CTBanTimeLength[param1];
778 new iTargetIndex = GetClientOfUserId(gA_CTBanTargetUserId[param1]);
779
780 decl String:sBanned[3];
781 GetClientCookie(iTargetIndex, g_CT_Cookie, sBanned, sizeof(sBanned));
782 new banFlag = StringToInt(sBanned);
783 if (!banFlag)
784 {
785 PerformCTBan(iTargetIndex, param1, iTimeToBan, iBanReason);
786 }
787 else
788 {
789 PrintToChat(param1, CHAT_BANNER, "Already CT Banned", iTargetIndex);
790 }
791 }
792}
793
794public MenuHandler_CTBanPlayerList(Handle:menu, MenuAction:action, param1, param2)
795{
796 if (action == MenuAction_End)
797 {
798 CloseHandle(menu);
799 }
800 else if (action == MenuAction_Cancel)
801 {
802 if (param2 == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
803 {
804 DisplayTopMenu(gH_TopMenu, param1, TopMenuPosition_LastCategory);
805 }
806 }
807 else if (action == MenuAction_Select)
808 {
809 decl String:info[32];
810 new userid, target;
811
812 GetMenuItem(menu, param2, info, sizeof(info));
813 userid = StringToInt(info);
814
815 if ((target = GetClientOfUserId(userid)) == 0)
816 {
817 PrintToChat(param1, "[SM] %t", "Player no longer available");
818 }
819 else if (!CanUserTarget(param1, target))
820 {
821 PrintToChat(param1, "[SM] %t", "Unable to target");
822 }
823 else
824 {
825 gA_CTBanTargetUserId[param1] = userid;
826 DisplayCTBanTimeMenu(param1, userid);
827 }
828 }
829}
830
831public MenuHandler_CTBanTimeList(Handle:menu, MenuAction:action, param1, param2)
832{
833 if (action == MenuAction_End)
834 {
835 CloseHandle(menu);
836 }
837 else if (action == MenuAction_Cancel)
838 {
839 if (param2 == MenuCancel_ExitBack && gH_TopMenu != INVALID_HANDLE)
840 {
841 DisplayTopMenu(gH_TopMenu, param1, TopMenuPosition_LastCategory);
842 }
843 }
844 else if (action == MenuAction_Select)
845 {
846 decl String:info[32];
847 GetMenuItem(menu, param2, info, sizeof(info));
848 new iTimeToBan = StringToInt(info);
849 gA_CTBanTimeLength[param1] = iTimeToBan;
850 DisplayCTBanReasonMenu(param1);
851 }
852}
853
854public OnPluginEnd()
855{
856 for(new client = 1; client <= MaxClients; client++)
857 {
858 if(g_Handles[client] != INVALID_HANDLE)
859 {
860 CloseHandle(g_Handles[client]);
861 g_Handles[client] = INVALID_HANDLE;
862 }
863 }
864}
865
866public OnClientPostAdminCheck(client)
867{
868 if (GetConVarBool(gH_Cvar_Enabled))
869 {
870 g_Handles[client] = INVALID_HANDLE;
871 CreateTimer(0.0, CheckBanCookies, client, TIMER_FLAG_NO_MAPCHANGE);
872 }
873}
874
875public OnClientDisconnect(client)
876{
877 decl String:sDisconnectSteamID[32];
878 GetClientAuthId(client, AuthId_Steam2, sDisconnectSteamID, sizeof(sDisconnectSteamID));
879
880 if(g_Handles[client] != INVALID_HANDLE)
881 {
882 CloseHandle(g_Handles[client]);
883 g_Handles[client] = INVALID_HANDLE;
884 }
885
886 // add information to rage ban list
887 decl String:sName[MAX_TARGET_LENGTH];
888 GetClientName(client, sName, sizeof(sName));
889
890 // add information to array
891 // if information isn't already in the arrays then add it
892 if (FindStringInArray(gA_DSteamIDs, sDisconnectSteamID) == -1)
893 {
894 PushArrayString(gA_DNames, sName);
895 PushArrayString(gA_DSteamIDs, sDisconnectSteamID);
896
897 if (GetArraySize(gA_DNames) >= 7)
898 {
899 RemoveFromArray(gA_DNames, 0);
900 RemoveFromArray(gA_DSteamIDs, 0);
901 }
902 }
903
904 // check if they were in the timed array
905 new iBannedArrayIndex = FindValueInArray(gA_TimedBanLocalList, client);
906 if (iBannedArrayIndex != -1)
907 {
908 // remove them from the local array
909 RemoveFromArray(gA_TimedBanLocalList, iBannedArrayIndex);
910
911 // make a datapack for the next query
912 new Handle:ClientDisconnectPack = CreateDataPack();
913 WritePackCell(ClientDisconnectPack, client);
914 WritePackString(ClientDisconnectPack, sDisconnectSteamID);
915
916 #if USESQL == 1
917 // update steam array
918 decl String:query[255];
919 Format(query, sizeof(query), "SELECT ctbantime FROM %s WHERE steamid = '%s'", g_sTimesTableName, sDisconnectSteamID);
920 SQL_TQuery(gH_BanDatabase, DB_Callback_ClientDisconnect, query, ClientDisconnectPack);
921
922 #else
923
924 new iSteamArrayIndex = FindStringInArray(gA_TimedBanSteamList, sDisconnectSteamID);
925 if (iSteamArrayIndex != -1)
926 {
927 if (gA_LocalTimeRemaining[client] <= 0)
928 {
929 RemoveFromArray(gA_TimedBanSteamList, iSteamArrayIndex);
930 }
931 else
932 {
933 SetArrayCell(gA_TimedBanSteamList, iSteamArrayIndex, gA_LocalTimeRemaining[client], 22);
934 }
935 }
936 #endif
937 }
938}
939
940public DB_Callback_ClientDisconnect(Handle:owner, Handle:hndl, const String:error[], any:thePack)
941{
942 if (hndl == INVALID_HANDLE)
943 {
944 LogError("Error with query on client disconnect: %s", error);
945 CloseHandle(thePack);
946 }
947 else
948 {
949 ResetPack(thePack);
950 new client = ReadPackCell(thePack);
951 decl String:sAuthID[22];
952 ReadPackString(thePack, sAuthID, sizeof(sAuthID));
953
954 new iRowCount = SQL_GetRowCount(hndl);
955 if (iRowCount)
956 {
957 #if DEBUG == 1
958 SQL_FetchRow(hndl);
959 new iBanTimeRemaining = SQL_FetchInt(hndl, 0);
960
961 if (IsClientInGame(client))
962 {
963 LogMessage("SQL: %N disconnected with %i time remaining on ban", client, iBanTimeRemaining);
964 }
965 else
966 {
967 LogMessage("SQL: %i client index disconnected with %i time remaining on ban", client, iBanTimeRemaining);
968 }
969 #endif
970
971 if (gA_LocalTimeRemaining[client] <= 0)
972 {
973 // remove steam array
974 decl String:query[255];
975 Format(query, sizeof(query), "DELETE FROM %s WHERE steamid = '%s'", g_sTimesTableName, sAuthID);
976 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, query);
977 Format(query, sizeof(query), "UPDATE %s SET timeleft=-1 WHERE perp_steamid = '%s' AND timeleft >= 0", g_sLogTableName, sAuthID);
978 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, query);
979 }
980 else
981 {
982 // update the time
983 decl String:query[255];
984 Format(query, sizeof(query), "UPDATE %s SET ctbantime = %d WHERE steamid = '%s'", g_sTimesTableName, gA_LocalTimeRemaining[client], sAuthID);
985 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, query);
986 Format(query, sizeof(query), "UPDATE %s SET timeleft = %d WHERE perp_steamid = '%s' AND timeleft >= 0", g_sLogTableName, gA_LocalTimeRemaining[client], sAuthID);
987 SQL_TQuery(gH_BanDatabase, DB_Callback_DisconnectAction, query);
988 }
989 }
990 }
991}
992
993public DB_Callback_DisconnectAction(Handle:owner, Handle:hndl, const String:error[], any:data)
994{
995 if (hndl == INVALID_HANDLE)
996 {
997 LogError("Error with updating/deleting record after client disconnect: %s", error);
998 }
999}
1000
1001public Action:CheckBanCookies(Handle:timer, any: client)
1002{
1003 if (AreClientCookiesCached(client))
1004 {
1005 ProcessBanCookies(client);
1006 }
1007 else if(IsClientInGame(client))
1008 {
1009 CreateTimer(5.0, CheckBanCookies, client, TIMER_FLAG_NO_MAPCHANGE);
1010 }
1011}
1012
1013ProcessBanCookies(client)
1014{
1015 if(client && IsClientInGame(client))
1016 {
1017 decl String:cookie[32];
1018 GetClientCookie(client, g_CT_Cookie, cookie, sizeof(cookie));
1019
1020 if (StrEqual(cookie, "1"))
1021 {
1022 // check to see if they joined CT
1023 if (GetClientTeam(client) == CS_TEAM_CT)
1024 {
1025 if (IsPlayerAlive(client))
1026 {
1027 // strip their weapons so they cannot gunplant after death
1028 new wepIdx;
1029 for (new i; i < 4; i++)
1030 {
1031 if ((wepIdx = GetPlayerWeaponSlot(client, i)) != -1)
1032 {
1033 RemovePlayerItem(client, wepIdx);
1034 AcceptEntityInput(wepIdx, "Kill");
1035 }
1036 }
1037
1038 ForcePlayerSuicide(client);
1039 }
1040
1041 ChangeClientTeam(client, CS_TEAM_T);
1042 PrintToChat(client, CHAT_BANNER, "Enforcing CT Ban");
1043 }
1044 }
1045 }
1046}
1047
1048public Action:Command_UnCTBan(client, args)
1049{
1050 if (args < 1)
1051 {
1052 ReplyToCommand(client, "[SM] Usage: sm_unctban <player>");
1053 }
1054 else
1055 {
1056 decl String:target[64];
1057 GetCmdArg(1, target, sizeof(target));
1058
1059 decl String:clientName[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
1060 target_count = ProcessTargetString(target, client, target_list, MAXPLAYERS, 0, clientName, sizeof(clientName), tn_is_ml);
1061 // make sure we have exactly one target here.. we don't want to CT ban lots of people
1062 if (target_count != 1)
1063 {
1064 ReplyToTargetError(client, target_count);
1065 }
1066 else
1067 {
1068 // check if the cookies are ready
1069 if (AreClientCookiesCached(target_list[0]))
1070 {
1071 Remove_CTBan(client, target_list[0]);
1072 }
1073 else
1074 {
1075 ReplyToCommand(client, CHAT_BANNER, "Cookie Status Unavailable");
1076 }
1077 }
1078 }
1079
1080 return Plugin_Handled;
1081}
1082
1083Remove_CTBan(adminIndex, targetIndex, bExpired=false)
1084{
1085 decl String:isBanned[3];
1086 GetClientCookie(targetIndex, g_CT_Cookie, isBanned, sizeof(isBanned));
1087 new banFlag = StringToInt(isBanned);
1088
1089 if (banFlag)
1090 {
1091 decl String:targetSteam[32];
1092 GetClientAuthId(targetIndex, AuthId_Steam2, targetSteam, sizeof(targetSteam));
1093
1094 #if USESQL == 1
1095 decl String:logQuery[350];
1096 Format(logQuery, sizeof(logQuery), "UPDATE %s SET timeleft=-1 WHERE perp_steamid = '%s' and timeleft >= 0", g_sLogTableName, targetSteam);
1097 #if DEBUG == 1
1098 LogMessage("log query: %s", logQuery);
1099 #endif
1100 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, logQuery, targetIndex);
1101 #endif
1102
1103 LogMessage("%N has removed the CT ban on %N (%s).", adminIndex, targetIndex, targetSteam);
1104
1105 if (!bExpired)
1106 {
1107 ShowActivity2(adminIndex, "[SM] ", "%t", "CT Ban Removed", targetIndex);
1108 }
1109 else
1110 {
1111 ShowActivity2(adminIndex, "[SM] ", "%t", "CT Ban Auto Removed", targetIndex);
1112 }
1113
1114 // delete from the timedban database if there was one
1115 decl String:query[255];
1116 Format(query, sizeof(query), "DELETE FROM %s WHERE steamid = '%s'", g_sTimesTableName, targetSteam);
1117 SQL_TQuery(gH_BanDatabase, DB_Callback_RemoveCTBan, query, targetIndex);
1118 }
1119
1120 // error on side of caution and just set cookie to 0 regardless of what it was
1121 SetClientCookie(targetIndex, g_CT_Cookie, "0");
1122}
1123
1124public DB_Callback_RemoveCTBan(Handle:owner, Handle:hndl, const String:error[], any:client)
1125{
1126 if (hndl == INVALID_HANDLE)
1127 {
1128 LogError("Error handling steamID after CT ban removal: %s", error);
1129 }
1130 else
1131 {
1132 #if DEBUG == 1
1133 if (IsClientInGame(client))
1134 {
1135 LogMessage("CTBan on %N was removed in SQL", client);
1136 }
1137 else
1138 {
1139 LogMessage("CTBan on --- was removed in SQL");
1140 }
1141 #endif
1142 }
1143}
1144
1145public Action:Command_CTBan(client, args)
1146{
1147 if (args < 1)
1148 {
1149 ReplyToCommand(client, "[SM] Usage: sm_ctban <player> <time> <reason>");
1150 }
1151 else
1152 {
1153 new numArgs = GetCmdArgs();
1154 decl String:target[64];
1155 GetCmdArg(1, target, sizeof(target));
1156 decl String:sBanTime[16];
1157 GetCmdArg(2, sBanTime, sizeof(sBanTime));
1158 new iBanTime = StringToInt(sBanTime);
1159 new String:sReasonStr[200];
1160 decl String:sArgPart[200];
1161 for (new arg = 3; arg <= numArgs; arg++)
1162 {
1163 GetCmdArg(arg, sArgPart, sizeof(sArgPart));
1164 Format(sReasonStr, sizeof(sReasonStr), "%s %s", sReasonStr, sArgPart);
1165 }
1166
1167 decl String:clientName[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
1168 target_count = ProcessTargetString(target, client, target_list, MAXPLAYERS, 0, clientName, sizeof(clientName), tn_is_ml);
1169 // make sure we have exactly one target here.. we don't want to CT ban lots of people
1170 if ((target_count != 1))
1171 {
1172 ReplyToTargetError(client, target_count);
1173 }
1174 else
1175 {
1176 if(target_list[0] && IsClientInGame(target_list[0]))
1177 {
1178 // check if the cookies are ready
1179 if (AreClientCookiesCached(target_list[0]))
1180 {
1181 decl String:isBanned[3];
1182 GetClientCookie(target_list[0], g_CT_Cookie, isBanned, sizeof(isBanned));
1183 new banFlag = StringToInt(isBanned);
1184 if (banFlag)
1185 {
1186 ReplyToCommand(client, CHAT_BANNER, "Already CT Banned", target_list[0]);
1187 }
1188 else
1189 {
1190 PerformCTBan(target_list[0], client, iBanTime, _, sReasonStr);
1191 }
1192 }
1193 else
1194 {
1195 ReplyToCommand(client, CHAT_BANNER, "Cookie Status Unavailable");
1196 }
1197 }
1198 }
1199 }
1200 return Plugin_Handled;
1201}
1202
1203PerformCTBan(client, adminclient, banTime=0, reason=0, String:manualReason[]="")
1204{
1205 // set cookie to ban
1206 SetClientCookie(client, g_CT_Cookie, "1");
1207
1208 decl String:targetSteam[32];
1209 GetClientAuthId(client, AuthId_Steam2, targetSteam, sizeof(targetSteam));
1210
1211 // check if they're on CT team
1212 if (GetClientTeam(client) == CS_TEAM_CT)
1213 {
1214 if (IsPlayerAlive(client))
1215 {
1216 // strip their weapons so they cannot gunplant after death
1217 new wepIdx;
1218 for (new i; i < 4; i++)
1219 {
1220 if ((wepIdx = GetPlayerWeaponSlot(client, i)) != -1)
1221 {
1222 RemovePlayerItem(client, wepIdx);
1223 AcceptEntityInput(wepIdx, "Kill");
1224 }
1225 }
1226
1227 ForcePlayerSuicide(client);
1228 }
1229 ChangeClientTeam(client, CS_TEAM_T);
1230 }
1231
1232 decl String:sReason[128];
1233 if (strlen(manualReason) > 0)
1234 {
1235 Format(sReason, sizeof(sReason), "%s", manualReason);
1236 }
1237 // or else they picked a reason # from the admin menu
1238 else
1239 {
1240 switch (reason)
1241 {
1242 case 1:
1243 {
1244 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 1", adminclient);
1245 }
1246 case 2:
1247 {
1248 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 2", adminclient);
1249 }
1250 case 3:
1251 {
1252 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 3", adminclient);
1253 }
1254 case 4:
1255 {
1256 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 4", adminclient);
1257 }
1258 case 5:
1259 {
1260 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 5", adminclient);
1261 }
1262 case 6:
1263 {
1264 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 6", adminclient);
1265 }
1266 case 7:
1267 {
1268 Format(sReason, sizeof(sReason), "%T", "CT Ban Reason 7", adminclient);
1269 }
1270 default:
1271 {
1272 Format(sReason, sizeof(sReason), "No reason given.");
1273 }
1274 }
1275 }
1276
1277 new timestamp = GetTime();
1278
1279 if(adminclient && IsClientInGame(adminclient))
1280 {
1281 decl String:adminSteam[32];
1282 GetClientAuthId(adminclient, AuthId_Steam2, adminSteam, sizeof(adminSteam));
1283
1284 #if USESQL == 1
1285 decl String:logQuery[350];
1286 decl String:temp[300];
1287 new String:escapedPerpName[300];
1288 new String:escapedAdminName[300];
1289 new String:escapedReason[300];
1290 Format(temp, sizeof(temp), "%N", client);
1291 SQL_EscapeString(gH_BanDatabase, temp, escapedPerpName, sizeof(escapedPerpName));
1292 Format(temp, sizeof(temp), "%N", adminclient);
1293 SQL_EscapeString(gH_BanDatabase, temp, escapedAdminName, sizeof(escapedAdminName));
1294 Format(temp, sizeof(temp), "%s", sReason);
1295 SQL_EscapeString(gH_BanDatabase, temp, escapedReason, sizeof(escapedReason));
1296 Format(logQuery, sizeof(logQuery), "INSERT INTO %s (timestamp, perp_steamid, perp_name, admin_steamid, admin_name, bantime, timeleft, reason) VALUES (%d, '%s', '%s', '%s', '%s', %d, %d, '%s')", g_sLogTableName, timestamp, targetSteam, escapedPerpName, adminSteam, escapedAdminName, banTime, banTime, escapedReason);
1297 #if DEBUG == 1
1298 LogMessage("log query: %s", logQuery);
1299 #endif
1300 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, logQuery, client);
1301 #endif
1302 LogMessage("%N (%s) has issued a CT ban on %N (%s) for %d minutes for %s.", adminclient, adminSteam, client, targetSteam, banTime, sReason);
1303 }
1304 else
1305 {
1306 #if USESQL == 1
1307 decl String:logQuery[350];
1308 decl String:temp[300];
1309 new String:escapedPerpName[300];
1310 new String:escapedReason[300];
1311 Format(temp, sizeof(temp), "%N", client);
1312 SQL_EscapeString(gH_BanDatabase, temp, escapedPerpName, sizeof(escapedPerpName));
1313 Format(temp, sizeof(temp), "%s", sReason);
1314 SQL_EscapeString(gH_BanDatabase, temp, escapedReason, sizeof(escapedReason));
1315 Format(logQuery, sizeof(logQuery), "INSERT INTO %s (timestamp, perp_steamid, perp_name, admin_steamid, admin_name, bantime, reason) VALUES (%d, '%s', '%s', 'STEAM_0:1:1', 'Console', %d, %d, '%s')", g_sLogTableName, timestamp, targetSteam, escapedPerpName, banTime, banTime, escapedReason);
1316 #if DEBUG == 1
1317 LogMessage("log query: %s", logQuery);
1318 #endif
1319 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, logQuery, client);
1320 #endif
1321 LogMessage("Console has issued a CT ban on %N (%s) for %d.", client, targetSteam, banTime);
1322 }
1323
1324 // check if there is a time
1325 if (banTime > 0)
1326 {
1327 ShowActivity2(adminclient, "[SM] ", "%t", "Temporary CT Ban", client, banTime);
1328 // save in local quick-access array
1329 PushArrayCell(gA_TimedBanLocalList, client);
1330 gA_LocalTimeRemaining[client] = banTime;
1331
1332 #if USESQL == 1
1333 // save in long-term database (already guaranteed to run only once per steam ID)
1334 decl String:query[255];
1335 Format(query, sizeof(query), "INSERT INTO %s (steamid, ctbantime) VALUES ('%s', %d)", g_sTimesTableName, targetSteam, banTime);
1336 #if DEBUG == 1
1337 LogMessage("ctban query: %s", query);
1338 #endif
1339 SQL_TQuery(gH_BanDatabase, DB_Callback_CTBan, query, client);
1340
1341 #else
1342
1343 new iSteamArrayIndex = PushArrayString(gA_TimedBanSteamList, targetSteam);
1344 SetArrayCell(gA_TimedBanSteamList, iSteamArrayIndex, banTime, 22);
1345 #endif
1346 }
1347 else
1348 {
1349 ShowActivity2(adminclient, "[SM] ", "%t", "Permanent CT Ban", client);
1350 }
1351}
1352
1353public DB_Callback_CTBan(Handle:owner, Handle:hndl, const String:error[], any:client)
1354{
1355 if (hndl == INVALID_HANDLE)
1356 {
1357 LogError("Error writing CTBan to Timed Ban database: %s", error);
1358 }
1359 else
1360 {
1361 #if DEBUG == 1
1362 if (IsClientInGame(client))
1363 {
1364 LogMessage("SQL CTBan: Updated database with CT Ban for %N", client);
1365 }
1366 #endif
1367 }
1368}
1369
1370public Action:Command_IsCTBanned(client, args)
1371{
1372 if ((args < 1) || !args)
1373 {
1374 ReplyToCommand(client, "[SM] Usage: sm_isbanned <player>");
1375 }
1376 else
1377 {
1378 decl String:target[64];
1379 GetCmdArg(1, target, sizeof(target));
1380
1381 decl String:clientName[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
1382 target_count = ProcessTargetString(target, client, target_list, MAXPLAYERS, 0, clientName, sizeof(clientName), tn_is_ml);
1383 // make sure we have exactly one target here
1384 if (target_count != 1)
1385 {
1386 ReplyToTargetError(client, target_count);
1387 }
1388 else
1389 {
1390 if(target_list[0] && IsClientInGame(target_list[0]))
1391 {
1392 if (AreClientCookiesCached(target_list[0]))
1393 {
1394 decl String:isBanned[3];
1395 GetClientCookie(target_list[0], g_CT_Cookie, isBanned, sizeof(isBanned));
1396 new banFlag = StringToInt(isBanned);
1397 if (banFlag)
1398 {
1399 // find the time if any
1400 if (gA_LocalTimeRemaining[target_list[0]] <= 0)
1401 {
1402 ReplyToCommand(client, CHAT_BANNER, "Permanent CT Ban", target_list[0]);
1403 }
1404 else
1405 {
1406 ReplyToCommand(client, CHAT_BANNER, "Temporary CT Ban", target_list[0], gA_LocalTimeRemaining[target_list[0]]);
1407 }
1408 }
1409 else
1410 {
1411 ReplyToCommand(client, CHAT_BANNER, "Not CT Banned", target_list[0]);
1412 }
1413 }
1414 else
1415 {
1416 ReplyToCommand(client, CHAT_BANNER, "Cookie Status Unavailable");
1417 }
1418 }
1419 else
1420 {
1421 ReplyToCommand(client, CHAT_BANNER, "Unable to target");
1422 }
1423 }
1424 }
1425
1426 return Plugin_Handled;
1427}
1428
1429public Action:Command_CheckJoin(client, const String:command[], args)
1430{
1431 // Check to see if we should continue (not a listen server, is in game, not a bot, if cookies are cached, and we're enabled)
1432 if(!client || !IsClientInGame(client) || IsFakeClient(client) || !AreClientCookiesCached(client) || !GetConVarBool(gH_Cvar_Enabled))
1433 {
1434 return Plugin_Continue;
1435 }
1436
1437 // Get the target team
1438 decl String:teamString[3];
1439 GetCmdArg(1, teamString, sizeof(teamString));
1440 new Target_Team = StringToInt(teamString);
1441
1442 decl String:sCookie[5];
1443 GetClientCookie(client, g_CT_Cookie, sCookie, sizeof(sCookie));
1444 new iBanStatus = StringToInt(sCookie);
1445
1446 // check for an active ban to send a mesage
1447 if ((Target_Team == CS_TEAM_SPECTATOR || Target_Team == CS_TEAM_T) && iBanStatus)
1448 {
1449 // display them a message about the ban
1450 new iTimeBanned = GetClientCookieTime(client, g_CT_Cookie);
1451 decl String:sTimeBanned[150];
1452 FormatTime(sTimeBanned, sizeof(sTimeBanned), NULL_STRING, iTimeBanned);
1453 decl String:sJoinBanMsg[100];
1454 GetConVarString(gH_Cvar_JoinBanMessage, sJoinBanMsg, sizeof(sJoinBanMsg));
1455 PrintHintText(client, "%t", "Last CT Banned On", sTimeBanned, sJoinBanMsg);
1456 }
1457 // otherwise they joined CT or auto-select and are banned
1458 else if (iBanStatus)
1459 {
1460 if(strcmp(gS_SoundPath, ""))
1461 {
1462 decl String:buffer[PLATFORM_MAX_PATH + 5];
1463 Format(buffer, sizeof(buffer), "play %s", gS_SoundPath);
1464 ClientCommand(client, buffer);
1465 }
1466 PrintCenterText(client, "%t", "Enforcing CT Ban");
1467 UTIL_TeamMenu(client);
1468 return Plugin_Stop;
1469 }
1470
1471 return Plugin_Continue;
1472}
1473
1474// This helper procedure will re-display the team join menu
1475// and is equivalent to what ClientCommand(client, "chooseteam") did in the past
1476UTIL_TeamMenu(client)
1477{
1478 new clients[1];
1479 new Handle:bf;
1480 clients[0] = client;
1481 bf = StartMessage("VGUIMenu", clients, 1);
1482
1483 if (GetUserMessageType() == UM_Protobuf)
1484 {
1485 PbSetString(bf, "name", "team");
1486 PbSetBool(bf, "show", true);
1487 }
1488 else
1489 {
1490 BfWriteString(bf, "team"); // panel name
1491 BfWriteByte(bf, 1); // bShow
1492 BfWriteByte(bf, 0); // count
1493 }
1494
1495 EndMessage();
1496
1497}
1498
1499// figure out if we can use the handy native SetAuthIdCookie
1500bool:IsSetAuthIdNativePresent()
1501{
1502 if (GetFeatureStatus(FeatureType_Native, "SetAuthIdCookie") == FeatureStatus_Available)
1503 {
1504 return true;
1505 }
1506 return false;
1507}