sm-plugins/maprate.sp

858 lines
21 KiB
SourcePawn

#pragma semicolon 1
#include <sourcemod>
#undef REQUIRE_PLUGIN
#include <adminmenu>
#define REQUIRE_PLUGIN
#define MR_VERSION "1.2"
#define MAXLEN_MAP 32
#define CVAR_DB_CONFIG 0
#define CVAR_VERSION 1
#define CVAR_AUTORATE_TIME 2
#define CVAR_ALLOW_REVOTE 3
#define CVAR_TABLE 4
#define CVAR_AUTORATE_DELAY 5
#define CVAR_DISMISS 6
#define CVAR_RESULTS 7
#define CVAR_NUM_CVARS 8
#define FLAG_RESET_RATINGS ADMFLAG_VOTE
new String:g_current_map[64];
new Handle:db = INVALID_HANDLE;
new Handle:g_cvars[CVAR_NUM_CVARS];
new bool:g_SQLite = false;
new Handle:g_admin_menu = INVALID_HANDLE;
new String:g_table_name[32];
new g_lastRateTime[MAXPLAYERS+1];
new bool:g_dismiss = false;
enum MapRatingOrigin
{
MRO_PlayerInitiated,
MRO_ViewRatingsByRating,
MRO_ViewRatingsByMap
};
new MapRatingOrigin:g_maprating_origins[MAXPLAYERS+1];
public Plugin:myinfo =
{
name = "Map Rate",
author = "Ryan \"FLOOR_MASTER\" Mannion & Chefe",
description = "Allow players to rate the current map and view the map's average rating.",
version = MR_VERSION,
url = "http://forums.alliedmods.net/showthread.php?p=1530651"
}
public OnPluginStart()
{
LoadTranslations("maprate.phrases");
RegConsoleCmd("sm_maprate", Command_Rate);
RegConsoleCmd("sm_maprating", Command_Rating);
/* RegConsoleCmd("sm_mapratings", Command_Ratings); */
RegAdminCmd("sm_maprate_resetratings", Command_ResetRatings, FLAG_RESET_RATINGS);
g_cvars[CVAR_DB_CONFIG] = CreateConVar("sm_maprate_db_config", "default", "Database configuration to use for Map Rate plugin", FCVAR_PLUGIN);
g_cvars[CVAR_VERSION] = CreateConVar("sm_maprate_version", MR_VERSION, "Map Rate Version", FCVAR_PLUGIN|FCVAR_REPLICATED|FCVAR_NOTIFY);
g_cvars[CVAR_AUTORATE_TIME] = CreateConVar("sm_maprate_autorate_time", "0", "If non-zero, automatically asks dead players to rate map after they have played the map for this number of seconds", FCVAR_PLUGIN);
g_cvars[CVAR_ALLOW_REVOTE] = CreateConVar("sm_maprate_allow_revote", "1", "If non-zero, allow a user to override his/her previous vote on a map", FCVAR_PLUGIN);
g_cvars[CVAR_TABLE] = CreateConVar("sm_maprate_table", "map_ratings", "The name of the database table to use", FCVAR_PLUGIN);
g_cvars[CVAR_AUTORATE_DELAY] = CreateConVar("sm_maprate_autorate_delay", "5", "After a player dies, wait this number of seconds before asking to rate if maprate_autorate_tie is non-zero", FCVAR_PLUGIN);
g_cvars[CVAR_DISMISS] = CreateConVar("sm_maprate_dismiss", "0", "If non-zero, the first voting option will be \"Dismiss\"", FCVAR_PLUGIN);
g_cvars[CVAR_RESULTS] = CreateConVar("sm_maprate_autoresults", "1", "If non-zero, the results graph will automatically be displayed when a player rates a map", FCVAR_PLUGIN);
HookEvent("player_death", Event_PlayerDeath);
AutoExecConfig(true, "maprate");
g_dismiss = GetConVarBool(g_cvars[CVAR_DISMISS]);
new Handle:top_menu;
if (LibraryExists("adminmenu") && ((top_menu = GetAdminTopMenu()) != INVALID_HANDLE))
{
OnAdminMenuReady(top_menu);
}
}
public OnConfigsExecuted()
{
GetConVarString(g_cvars[CVAR_TABLE], g_table_name, sizeof(g_table_name));
g_dismiss = GetConVarBool(g_cvars[CVAR_DISMISS]);
PrintToServer("[MAPRATE] Using table name \"%s\"", g_table_name);
if (!ConnectDB())
{
LogError("FATAL: An error occurred while connecting to the database.");
SetFailState("An error occurred while connecting to the database.");
}
}
public OnLibraryRemoved(const String:name[])
{
if (StrEqual(name, "adminmenu"))
{
g_admin_menu = INVALID_HANDLE;
}
}
public OnAdminMenuReady(Handle:topmenu)
{
if (topmenu == g_admin_menu)
{
return;
}
g_admin_menu = topmenu;
new TopMenuObject:server_commands = FindTopMenuCategory(g_admin_menu, ADMINMENU_SERVERCOMMANDS);
if (server_commands == INVALID_TOPMENUOBJECT)
{
return;
}
AddToTopMenu(g_admin_menu, "sm_all_maprate", TopMenuObject_Item, AdminMenu_AllRate, server_commands, "sm_all_maprate", ADMFLAG_VOTE);
}
public AdminMenu_AllRate(Handle:topmenu, TopMenuAction:action, TopMenuObject:object_id, param, String:buffer[], maxlength)
{
switch (action)
{
case TopMenuAction_DisplayOption:
{
Format(buffer, maxlength, "%T", "Everyone Rate Command", param);
}
case TopMenuAction_SelectOption:
{
new max_clients = GetMaxClients();
for (new i = 1; i <= max_clients; i++)
{
if (IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) > 0)
{
InitiateRate(i, g_current_map, false, param);
}
}
}
}
}
public OnMapStart()
{
GetCurrentMap(g_current_map, sizeof(g_current_map));
g_dismiss = GetConVarBool(g_cvars[CVAR_DISMISS]);
}
public OnMapEnd()
{
if (db != INVALID_HANDLE)
{
CloseHandle(db);
db = INVALID_HANDLE;
}
}
public Action:Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
new autorateTime = GetConVarInt(g_cvars[CVAR_AUTORATE_TIME]);
new death_flags = GetEventInt(event, "death_flags");
if (IsClientInGame(client) && !IsFakeClient(client) && autorateTime && g_lastRateTime[client] + autorateTime < GetTime() && !(death_flags & 32))
{
new Float:time = GetConVarFloat(g_cvars[CVAR_AUTORATE_DELAY]);
if (time >= 0.0)
{
decl String:steamid[24];
GetClientAuthString(client, steamid, sizeof(steamid));
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
WritePackString(dp, steamid);
CreateTimer(time, Timer_AutoRateClient, dp);
}
}
return Plugin_Continue;
}
public Action:Timer_AutoRateClient(Handle:timer, any:dp)
{
decl String:steamid_orig[24];
decl String:steamid[24];
ResetPack(dp);
new client = ReadPackCell(dp);
ReadPackString(dp, steamid_orig, sizeof(steamid_orig));
CloseHandle(dp);
g_lastRateTime[client] = GetTime();
if (IsClientConnected(client))
{
GetClientAuthString(client, steamid, sizeof(steamid));
if (!strcmp(steamid, steamid_orig))
{
InitiateRate(client, g_current_map, false);
}
}
}
stock bool:ConnectDB()
{
decl String:db_config[64];
GetConVarString(g_cvars[CVAR_DB_CONFIG], db_config, sizeof(db_config));
/* Verify that the configuration is defined in databases.cfg */
if (!SQL_CheckConfig(db_config))
{
LogError("Database configuration \"%s\" does not exist", db_config);
return false;
}
/* Establish a connection */
new String:error[256];
db = SQL_Connect(db_config, true, error, sizeof(error));
if (db == INVALID_HANDLE)
{
LogError("Error establishing database connection: %s", error);
return false;
}
decl String:driver[32];
SQL_ReadDriver(db, driver, sizeof(driver));
if (!strcmp(driver, "sqlite"))
{
g_SQLite = true;
}
decl String:query[256];
if (g_SQLite)
{
Format(query, sizeof(query), "CREATE TABLE IF NOT EXISTS %s (steamid TEXT, map TEXT, rating INTEGER, rated DATE, UNIQUE (map, steamid))", g_table_name);
if (!SQL_FastQuery(db, query)) {
new String:sqlerror[300];
SQL_GetError(db, sqlerror, sizeof(sqlerror));
LogError("FATAL: Could not create table %s. (%s)", g_table_name, sqlerror);
SetFailState("Could not create table %s.", g_table_name);
}
}
else
{
Format(query, sizeof(query), "CREATE TABLE IF NOT EXISTS %s (steamid VARCHAR(24), map VARCHAR(48), rating INT(4), rated DATETIME, UNIQUE KEY (map, steamid))", g_table_name);
if (!SQL_FastQuery(db, query))
{
new String:sqlerror[300];
SQL_GetError(db, sqlerror, sizeof(sqlerror));
LogError("FATAL: Could not create table %s. (%s)", g_table_name, sqlerror);
SetFailState("Could not create table %s.", g_table_name);
}
}
return true;
}
public Menu_Rate(Handle:menu, MenuAction:action, param1, param2)
{
new client = param1;
switch (action)
{
/* User selected a rating - update database */
case MenuAction_Select:
{
decl String:steamid[24];
decl String:map[MAXLEN_MAP];
GetClientAuthString(client, steamid, sizeof(steamid));
if (!GetMenuItem(menu, param2, map, sizeof(map)))
{
return;
}
if (g_dismiss && param2 == 0)
{
return;
}
/* param2 is the menu selection index starting from 0 */
new rating = param2 + 1 - (g_dismiss ? 1 : 0);
decl String:query[256];
if (g_SQLite)
{
Format(query, sizeof(query), "REPLACE INTO %s VALUES ('%s', '%s', %d, DATETIME('NOW'))", g_table_name, steamid, map, rating);
}
else
{
Format(query, sizeof(query), "INSERT INTO %s SET map = '%s', steamid = '%s', rating = %d, rated = NOW() ON DUPLICATE KEY UPDATE rating = %d, rated = NOW()", g_table_name, map, steamid, rating, rating);
}
LogAction(client, -1, "%L rated %s: %d", client, map, rating);
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
WritePackString(dp, map);
SQL_TQuery(db, T_PostRating, query, dp);
}
case MenuAction_Cancel:
{
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
}
public Action:Command_Rating(client, args)
{
if (!client)
{
return Plugin_Handled;
}
CreateMenuRatings(client);
return Plugin_Handled;
}
stock CreateMenuRatings(client)
{
new Handle:menu = CreateMenu(Menu_Ratings);
decl String:text[64];
Format(text, sizeof(text), "%T", "View Ratings", client);
SetMenuTitle(menu, text);
AddMenuItem(menu, "none", g_current_map);
Format(text, sizeof(text), "%T", "Ordered by Rating", client);
AddMenuItem(menu, "rating", text);
Format(text, sizeof(text), "%T", "Ordered by Map Name", client);
AddMenuItem(menu, "map", text);
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 300);
}
public Menu_Ratings(Handle:menu, MenuAction:action, param1, param2)
{
new client = param1;
switch (action)
{
case MenuAction_Select:
{
switch (param2)
{
case 0:
{
g_maprating_origins[client] = MRO_PlayerInitiated;
GetMapRating(client, g_current_map);
}
case 1:
{
ViewRatingsByRating(client);
}
case 2:
{
ViewRatingsByMap(client);
}
}
}
case MenuAction_Cancel:
{
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
}
stock ViewRatingsByRating(client)
{
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
decl String:text[64];
Format(text, sizeof(text), "%T", "Ordered by Rating Title", client);
WritePackString(dp, text);
g_maprating_origins[client] = MRO_ViewRatingsByRating;
decl String:query[256];
Format(query, sizeof(query), "SELECT map, AVG(rating) AS rating, COUNT(*) AS ratings FROM %s GROUP BY map ORDER BY rating DESC", g_table_name);
SQL_TQuery(db, T_CreateMenuRatingsResults, query, dp);
}
stock ViewRatingsByMap(client)
{
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
decl String:text[64];
Format(text, sizeof(text), "%T", "Ordered by Map Name Title", client);
WritePackString(dp, text);
g_maprating_origins[client] = MRO_ViewRatingsByMap;
decl String:query[256];
Format(query, sizeof(query), "SELECT map, AVG(rating) AS rating, COUNT(*) AS ratings FROM %s GROUP BY map ORDER BY map", g_table_name);
SQL_TQuery(db, T_CreateMenuRatingsResults, query, dp);
}
public T_CreateMenuRatingsResults(Handle:owner, Handle:hndl, const String:error[], any:data)
{
if (hndl == INVALID_HANDLE)
{
LogError("Query failed! %s", error);
PrintToChat(data, "A database error occurred. Please try again later.");
return;
}
ResetPack(data);
new client = ReadPackCell(data);
decl String:menu_title[64];
ReadPackString(data, menu_title, sizeof(menu_title));
CloseHandle(data);
new Handle:menu = CreateMenu(Menu_ViewMapRatings);
decl String:map[MAXLEN_MAP];
new Float:rating;
new ratings;
decl String:menu_item[128];
while (SQL_FetchRow(hndl))
{
SQL_FetchString(hndl, 0, map, sizeof(map));
rating = SQL_FetchFloat(hndl, 1);
ratings = SQL_FetchInt(hndl, 2);
Format(menu_item, sizeof(menu_item), "%.2f %s (%d)", rating, map, ratings);
AddMenuItem(menu, map, menu_item);
}
CloseHandle(hndl);
SetMenuTitle(menu, menu_title);
SetMenuExitButton(menu, true);
SetMenuExitBackButton(menu, true);
DisplayMenu(menu, client, 300);
}
public Menu_ViewMapRatings(Handle:menu, MenuAction:action, param1, param2)
{
new client = param1;
switch (action)
{
case MenuAction_Select:
{
decl String:map[MAXLEN_MAP];
if (GetMenuItem(menu, param2, map, sizeof(map)))
{
GetMapRating(client, map);
}
}
case MenuAction_Cancel:
{
switch (param2)
{
case MenuCancel_ExitBack:
{
CreateMenuRatings(client);
}
}
}
case MenuAction_End: {
CloseHandle(menu);
}
}
}
public T_CreateMenuRating(Handle:owner, Handle:hndl, const String:error[], any:data)
{
ResetPack(data);
new client = ReadPackCell(data);
if (hndl == INVALID_HANDLE)
{
LogError("Query failed! %s", error);
CloseHandle(data);
PrintToChat(client, "A database error occurred. Please try again later.");
return;
}
decl String:map[MAXLEN_MAP];
ReadPackString(data, map, sizeof(map));
new my_rating = ReadPackCell(data);
CloseHandle(data);
/* This is kind of ugly */
new rating = 0;
new arr_ratings[5] = {0, 0, 0, 0, 0};
new ratings = 0;
new total_ratings = 0;
new total_rating = 0;
decl String:menu_item[64];
while (SQL_FetchRow(hndl))
{
rating = SQL_FetchInt(hndl, 0);
ratings = SQL_FetchInt(hndl, 1);
total_rating += rating * ratings;
arr_ratings[rating - 1] = ratings;
total_ratings += ratings;
}
CloseHandle(hndl);
/* Now build the menu */
decl String:menu_title[64];
new Handle:menu = CreateMenu(Menu_ViewRating);
new Float:average_rating = 0.0;
if (total_ratings)
{
average_rating = float(total_rating) / float(total_ratings);
}
Format(menu_title, sizeof(menu_title), "%T\n%T", "Ratings Title", client, map, "Average Rating", client, average_rating);
if (my_rating)
{
Format(menu_title, sizeof(menu_title), "%s\n%T", menu_title, "Your Rating", client, my_rating);
}
SetMenuTitle(menu, menu_title);
/* VARIABLE WIDTH FONTS ARE EVIL */
new bars[5];
new max_bars = 0;
if (total_ratings)
{
for (new i = 0; i < sizeof(arr_ratings); i++)
{
bars[i] = RoundToNearest(float(arr_ratings[i] * 100 / total_ratings) / 5);
max_bars = (bars[i] > max_bars ? bars[i] : max_bars);
}
if (max_bars >= 15)
{
for (new i = 0; i < sizeof(arr_ratings); i++)
{
bars[i] /= 2;
}
max_bars /= 2;
}
}
decl String:menu_item_bars[64];
new String:rating_phrase[] = "1 Star";
for (new i = 0; i < sizeof(arr_ratings); i++)
{
new j;
for (j = 0; j < bars[i]; j++)
{
menu_item_bars[j] = '=';
}
new max = RoundToNearest(float(max_bars - j) * 2.5) + j;
for (; j < max; j++)
{
menu_item_bars[j] = ' ';
}
menu_item_bars[j] = 0;
rating_phrase[0] = '1' + i;
Format(menu_item, sizeof(menu_item), "%s (%T - %T)", menu_item_bars, rating_phrase, client, (arr_ratings[i] == 1 ? "Rating" : "Rating Plural"), client, arr_ratings[i]);
/* AddMenuItem(menu, map, menu_item, ITEMDRAW_DISABLED); */
AddMenuItem(menu, map, menu_item);
}
decl String:text[64];
if (!my_rating)
{
Format(text, sizeof(text), "%T", "Rate Map", client);
AddMenuItem(menu, map, text);
}
else if (GetConVarInt(g_cvars[CVAR_ALLOW_REVOTE]))
{
Format(text, sizeof(text), "%T", "Change Rating", client);
AddMenuItem(menu, map, text);
}
SetMenuExitBackButton(menu, true);
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 300);
}
public Menu_ViewRating(Handle:menu, MenuAction:action, param1, param2)
{
new client = param1;
switch (action)
{
case MenuAction_Select:
{
switch (param2)
{
case 5:
{
decl String:map[MAXLEN_MAP];
if (GetMenuItem(menu, param2, map, sizeof(map)))
{
InitiateRate(client, map, true);
}
}
}
}
case MenuAction_Cancel:
{
switch (param2)
{
case MenuCancel_ExitBack:
{
switch (g_maprating_origins[client])
{
case MRO_PlayerInitiated:
{
CreateMenuRatings(client);
}
case MRO_ViewRatingsByRating:
{
ViewRatingsByRating(client);
}
case MRO_ViewRatingsByMap:
{
ViewRatingsByMap(client);
}
}
}
}
}
case MenuAction_End:
{
CloseHandle(menu);
}
}
}
public Action:Command_Rate(client, args)
{
if (!client)
{
return Plugin_Handled;
}
InitiateRate(client, g_current_map, true);
return Plugin_Handled;
}
stock InitiateRate(client, const String:map[], bool:voluntary, initiator = 0)
{
decl String:steamid[24];
GetClientAuthString(client, steamid, sizeof(steamid));
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
WritePackString(dp, map);
WritePackCell(dp, voluntary);
WritePackCell(dp, initiator);
decl String:query[256];
Format(query, sizeof(query), "SELECT rating FROM %s WHERE map = '%s' AND steamid = '%s'", g_table_name, map, steamid);
SQL_TQuery(db, T_CreateMenuRate, query, dp);
}
public T_PostRating(Handle:owner, Handle:hndl, const String:error[], any:data)
{
ResetPack(data);
new client = ReadPackCell(data);
if (hndl == INVALID_HANDLE)
{
LogError("Query failed! %s", error);
PrintToChat(client, "%t", "Database Error");
CloseHandle(data);
return;
}
decl String:map[MAXLEN_MAP];
ReadPackString(data, map, sizeof(map));
CloseHandle(data);
PrintToChat(client, "\03%t", "Successful Rate", map);
g_maprating_origins[client] = MRO_PlayerInitiated;
if (GetConVarInt(g_cvars[CVAR_RESULTS]))
{
GetMapRating(client, map);
}
}
stock GetMapRating(client, const String:map[])
{
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
WritePackString(dp, map);
decl String:steamid[24];
GetClientAuthString(client, steamid, sizeof(steamid));
decl String:query[256];
Format(query, sizeof(query), "SELECT rating FROM %s WHERE steamid = '%s' AND map = '%s'", g_table_name, steamid, map);
SQL_TQuery(db, T_GetMapRating2, query, dp);
}
public T_GetMapRating2(Handle:owner, Handle:hndl, const String:error[], any:data)
{
ResetPack(data);
new client = ReadPackCell(data);
if (hndl == INVALID_HANDLE)
{
LogError("Query failed! %s", error);
PrintToChat(data, "%t", "Database Error");
CloseHandle(data);
return;
}
decl String:map[MAXLEN_MAP];
ReadPackString(data, map, sizeof(map));
CloseHandle(data);
new Handle:dp = CreateDataPack();
WritePackCell(dp, client);
WritePackString(dp, map);
if (SQL_GetRowCount(hndl) == 1)
{
SQL_FetchRow(hndl);
WritePackCell(dp, SQL_FetchInt(hndl, 0));
}
else
{
WritePackCell(dp, 0);
}
CloseHandle(hndl);
decl String:query[256];
Format(query, sizeof(query), "SELECT rating, COUNT(*) FROM %s WHERE map = '%s' GROUP BY rating ORDER BY rating DESC", g_table_name, map);
SQL_TQuery(db, T_CreateMenuRating, query, dp);
}
public T_CreateMenuRate(Handle:owner, Handle:hndl, const String:error[], any:data)
{
ResetPack(data);
new client = ReadPackCell(data);
if (hndl == INVALID_HANDLE)
{
LogError("Query failed! %s", error);
if (IsClientConnected(client))
{
PrintToChat(client, "%t", "Database Error");
}
CloseHandle(data);
return;
}
decl String:map[MAXLEN_MAP];
ReadPackString(data, map, sizeof(map));
new bool:voluntary = bool:ReadPackCell(data);
new initiator = ReadPackCell(data);
new rating = 0;
CloseHandle(data);
new allow_revote = GetConVarInt(g_cvars[CVAR_ALLOW_REVOTE]);
/* The player has rated this map before */
if (SQL_GetRowCount(hndl) == 1)
{
SQL_FetchRow(hndl);
rating = SQL_FetchInt(hndl, 0);
/* If the user didn't initiate the maprate, just ignore the request */
if (!voluntary)
{
return;
}
/* Deny rerating if the applicable cvar is set */
else if (!allow_revote)
{
PrintToChat(client, "\03%t", "Already Rated", rating);
return;
}
}
CloseHandle(hndl);
decl String:title[256];
/* If an initiator was set, then this map rating request was initiated by
* an admin. We'll specify who in the map rate panel title. */
if (initiator)
{
decl String:initiator_name[32];
GetClientName(initiator, initiator_name, sizeof(initiator_name));
Format(title, sizeof(title), "%T", "Everyone Rate Title",
client, initiator_name, g_current_map);
}
else
{
Format(title, sizeof(title), "%T", "Rate Map Title", client, map);
}
/* If the player already rated this map, show the previous rating. */
if (rating)
{
Format(title, sizeof(title), "%s\n%T", title, "Previous Rating", client, rating);
}
/* Build the menu panel */
new Handle:menu = CreateMenu(Menu_Rate);
SetMenuTitle(menu, title);
decl String:menu_item[128];
if (g_dismiss)
{
Format(menu_item, sizeof(menu_item), "%T", "Dismiss", client);
AddMenuItem(menu, "dismiss", menu_item);
}
new String:rating_phrase[] = "1 Star";
for (new i = 0; i < 5; i++)
{
rating_phrase[0] = '1' + i;
Format(menu_item, sizeof(menu_item), "%T", rating_phrase, client);
AddMenuItem(menu, map, menu_item);
}
SetMenuExitButton(menu, true);
DisplayMenu(menu, client, 300);
}
public Action:Command_ResetRatings(client, args)
{
ResetRatings(client, g_current_map);
return Plugin_Handled;
}
stock ResetRatings(client, const String:map[])
{
decl String:query[256];
Format(query, sizeof(query), "DELETE FROM %s WHERE map = '%s'",
g_table_name, map);
PrintToServer(query);
SQL_LockDatabase(db);
SQL_FastQuery(db, query);
SQL_UnlockDatabase(db);
LogAction(client, -1, "%L reset ratings for map %s", client, g_current_map);
}
public OnClientPostAdminCheck(client)
{
g_lastRateTime[client] = GetTime();
}