#pragma semicolon 1 #define PLUGIN_AUTHOR "jenz" #define PLUGIN_VERSION "1.4" #include #include #include #include Database g_hDatabase; //check if autismbot bool is_bot_player[MAXPLAYERS + 1]; Handle g_h_time_activity = null; char g_csSID[MAXPLAYERS + 1][65]; char g_cTimeRecords[1000][128]; int g_iPlayerTimeServer[MAXPLAYERS + 1]; int g_iPlayerAFKTime; int g_iPlayerRTVCapacity; int g_iAvgHour_Contribution_per_player; int g_iRtvBoost_tier; int g_iPlayerTier[MAXPLAYERS + 1]; int g_iPlayerNextTierHours[MAXPLAYERS + 1]; char g_GroupNames[32][64]; char g_GroupFlags[32][32]; int g_GroupNameCount = 0; StringMap g_GroupOverrides; // group name -> comma-separated override list static Handle g_hForwardPlayerHours; static Handle g_hForwardPlayerTier; public Plugin myinfo = { name = "UNLOZE_player_time", author = PLUGIN_AUTHOR, description = "checks playtime on servers", version = PLUGIN_VERSION, url = "www.unloze.com" }; public Action time_query_activity(Handle timer, any data) { if (!g_hDatabase) { return Plugin_Continue; } char sServer[64]; int i_port = GetConVarInt(FindConVar("hostport")); if (i_port == 27015 || i_port == 27035) //might as well count play time on ze2. it was not done before but its a bit like why not anyways. { Format(sServer, sizeof(sServer), "ze_time"); } else if (i_port == 27016) { Format(sServer, sizeof(sServer), "zr_time"); } else if (i_port == 27017) { Format(sServer, sizeof(sServer), "mg_time"); } else { return Plugin_Continue; } for (int client = 1; client <= MaxClients; client++) { if (IsValidClient(client) && !IsFakeClient(client) && IsPlayerAlive(client)) { char sIP[32]; GetClientIP(client, sIP, sizeof(sIP)); char sQuery[512]; char sName[MAX_NAME_LENGTH]; GetClientName(client, sName, sizeof(sName)); int size2 = 2 * strlen(sName) + 1; char[] sEscapedName = new char[size2 + 1]; g_hDatabase.Escape(sName, sEscapedName, size2 + 1); Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.player_time set `%s` = `%s` + 10 where steam_id = '%s' and ipv4 = '%s'", sServer, sServer, g_csSID[client], sIP); g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); Format(sQuery, sizeof(sQuery), "update unloze_playtimestats.player_time set player_name = '%s' where steam_id = '%s' and player_name != '%s'", sEscapedName, g_csSID[client], sEscapedName); g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); } } return Plugin_Continue; } public void LoadGroupOverrides() { KeyValues kv = new KeyValues("Groups"); char path[PLATFORM_MAX_PATH]; BuildPath(Path_SM, path, sizeof(path), "configs/admin_groups.cfg"); if (!kv.ImportFromFile(path)) { delete kv; return; } g_GroupNameCount = 0; if (kv.GotoFirstSubKey()) { do { char sName[64]; kv.GetSectionName(sName, sizeof(sName)); if (StrContains(sName, "tier", false) == 0) { strcopy(g_GroupNames[g_GroupNameCount], 64, sName); kv.GetString("flags", g_GroupFlags[g_GroupNameCount], 32, ""); g_GroupNameCount++; } } while (kv.GotoNextKey() && g_GroupNameCount < 32); } // now for each group, rewind and re-navigate fresh for (int i = 0; i < g_GroupNameCount; i++) { kv.Rewind(); if (!kv.JumpToKey(g_GroupNames[i])) continue; if (!kv.JumpToKey("Overrides")) continue; if (!kv.GotoFirstSubKey(false)) continue; char overrideList[512]; overrideList[0] = '\0'; do { char cmd[64]; kv.GetSectionName(cmd, sizeof(cmd)); if (overrideList[0] != '\0') StrCat(overrideList, sizeof(overrideList), ", "); StrCat(overrideList, sizeof(overrideList), cmd); } while (kv.GotoNextKey(false)); g_GroupOverrides.SetString(g_GroupNames[i], overrideList); } delete kv; } public void OnPluginStart() { g_GroupOverrides = new StringMap(); LoadGroupOverrides(); if (!g_hDatabase) { Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats"); } RegConsoleCmd("sm_playtime", Command_Time, "retreives total connection time on all connected servers"); RegConsoleCmd("sm_tier", Command_Tier, "shows what tier features you have"); RegConsoleCmd("sm_tiers", Command_Tier, "shows what tier features you have"); RegConsoleCmd("sm_topplaytime", Command_TopTime, "retreives top 1000 playtime highscores on all connected servers"); g_h_time_activity = CreateTimer(10.0, time_query_activity, INVALID_HANDLE, TIMER_REPEAT); CreateTimer(600.0, UpdateForward, _, TIMER_REPEAT); ConVar cvar; HookConVarChange((cvar = CreateConVar("sm_mapchooser_afk_detect_time", "120", "Time in seconds until a player is considered as AFK and therefore excluded from player average time.")), Cvar_playerAFKTime); g_iPlayerAFKTime = cvar.IntValue; delete cvar; ConVar cvar2; HookConVarChange((cvar2 = CreateConVar("sm_rtv_avg_capacity", "5", "The capacity for how many times the average a players rtv can be worth.")), Cvar_playerRTVAverageCap); g_iPlayerRTVCapacity = cvar2.IntValue; delete cvar2; ConVar cvar3; HookConVarChange((cvar3 = CreateConVar("sm_avg_hour_contribution_per_player", "5000", "How many hours maximum each player can contribute to averagehours")), Cvar_AverageHourContribution); g_iAvgHour_Contribution_per_player = cvar3.IntValue; delete cvar3; ConVar cvar4; HookConVarChange((cvar4 = CreateConVar("sv_rtv_boost_tier", "4", "which tier for giving the rtv/mapvote/nominations boost")), Cvar_RTVBoostTier); g_iRtvBoost_tier = cvar4.IntValue; delete cvar3; } public Action UpdateForward(Handle timer) { for (int i = 0; i < MaxClients; i++) { if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !is_bot_player[i]) { select_client_time_server(i); } } return Plugin_Handled; } public void Cvar_playerAFKTime(ConVar convar, const char[] oldValue, const char[] newValue) { g_iPlayerAFKTime = convar.IntValue; } public void Cvar_playerRTVAverageCap(ConVar convar, const char[] oldValue, const char[] newValue) { g_iPlayerRTVCapacity = convar.IntValue; } public void Cvar_AverageHourContribution(ConVar convar, const char[] oldValue, const char[] newValue) { g_iAvgHour_Contribution_per_player = convar.IntValue; } public void Cvar_RTVBoostTier(ConVar convar, const char[] oldValue, const char[] newValue) { g_iRtvBoost_tier = convar.IntValue; } public APLRes AskPluginLoad2(Handle myself, bool late, char [] error, int err_max) { CreateNative("GetAveragePlayerTimeOnServer", Native_GetAveragePlayerActiveTimeServer); CreateNative("GetPlayerWorthRTV_boost_", Native_GetPlayerWorthRTV_boost); CreateNative("GetPlayerTier_native", Native_GetPlayerTier); g_hForwardPlayerHours = CreateGlobalForward("GetPlayerHoursServer", ET_Ignore, Param_Cell, Param_Cell, Param_Cell); g_hForwardPlayerTier = CreateGlobalForward("GetPlayerTier", ET_Ignore, Param_Cell, Param_Cell); return APLRes_Success; } public int GetAveragePlayerActiveTimeServer() { int total_hours = 0; int total_players = 0; for (int i = 0; i < MaxClients; i++) { if (IsValidClient(i) && !IsFakeClient(i) && !IsClientSourceTV(i) && !is_bot_player[i] && GetClientIdleTime(i) < g_iPlayerAFKTime) { //re-introducing the hour capacity but putting it here is better than putting it at the mysql query //at the time of making this change its only affeting me jenz and nobody else. this is meant to prevent //the average hour from being too skewed by high playtime people. int added_hours = g_iPlayerTimeServer[i] > g_iAvgHour_Contribution_per_player ? g_iAvgHour_Contribution_per_player : g_iPlayerTimeServer[i]; total_hours += added_hours; total_players++; } } if (total_hours == 0) { return 0; } return total_hours / total_players; } public int Native_GetAveragePlayerActiveTimeServer(Handle plugin, int numParams) { return GetAveragePlayerActiveTimeServer(); } public int Native_GetPlayerTier(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client > MaxClients || client <= 0) { ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid."); return view_as(-1); } if(!IsClientInGame(client)) { ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game."); return view_as(-1); } return g_iPlayerTier[client]; } public int Native_GetPlayerWorthRTV_boost(Handle plugin, int numParams) { int client = GetNativeCell(1); if(client > MaxClients || client <= 0) { ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid."); return view_as(-1); } if(!IsClientInGame(client)) { ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game."); return view_as(-1); } int avg = GetAveragePlayerActiveTimeServer(); //give vips the rtv/nomination/mapvote boost by default AdminId id = GetUserAdmin(client); if (id != INVALID_ADMIN_ID && GetAdminFlag(id, Admin_Reservation)) { return g_iPlayerRTVCapacity; } //give tier the rtv/nomination/mapvote boost if (g_iPlayerTier[client] >= g_iRtvBoost_tier) { return g_iPlayerRTVCapacity; } if (g_iPlayerTimeServer[client] <= avg || avg == 0 || is_bot_player[client] || IsFakeClient(client)) { return 1; } if ((float(g_iPlayerTimeServer[client]) / float(avg)) > g_iPlayerRTVCapacity) { return g_iPlayerRTVCapacity; //1.0-5.0 booster probably } int val = RoundToFloor((g_iPlayerTimeServer[client]) / float(avg)); if (val < 1) { val = 1; } return val; } public void OnPluginEnd() { if (g_h_time_activity != null) delete g_h_time_activity; CloseHandle(g_hForwardPlayerHours); CloseHandle(g_hForwardPlayerTier); } public void SQL_OnDatabaseConnect(Database db, const char[] error, any data) { if(!db || strlen(error)) { LogError("Database error: %s", error); return; } g_hDatabase = db; for (int i = 1; i <= MaxClients; i++) { if(IsValidClient(i) && !IsFakeClient(i)) { OnClientPostAdminCheck(i); } } OnMapStart(); } public void OnClientPostAdminCheck(int client) { g_iPlayerNextTierHours[client] = 0; GetClientAuthId(client, AuthId_Steam2, g_csSID[client], sizeof(g_csSID[])); is_bot_player[client] = false; g_iPlayerTier[client] = -1; g_iPlayerTimeServer[client] = 0; if(!IsValidClient(client) || IsFakeClient(client)) return; if (!g_hDatabase) { return; } insert_client(client); select_client_time_server(client); if (StrEqual("[U:1:1221121532]", g_csSID[client], false) || StrEqual("STEAM_0:0:610560766", g_csSID[client], false)) { is_bot_player[client] = true; } if (StrEqual("[U:1:408797742]", g_csSID[client], false) || StrEqual("STEAM_0:0:204398871", g_csSID[client], false)) { is_bot_player[client] = true; } if (StrEqual("[U:1:1036189204]", g_csSID[client], false) || StrEqual("STEAM_0:0:518094602", g_csSID[client], false)) { is_bot_player[client] = true; } if (StrEqual("[U:1:120378081]", g_csSID[client], false) || StrEqual("STEAM_0:1:60189040", g_csSID[client], false)) { is_bot_player[client] = true; } } public void select_client_time_server(int client) { char sServer[32]; int i_port = GetConVarInt(FindConVar("hostport")); if (i_port == 27015 || i_port == 27019 || i_port == 27035) { Format(sServer, sizeof(sServer), "ze_time"); } else if (i_port == 27016) { Format(sServer, sizeof(sServer), "zr_time"); } else if (i_port == 27017) { Format(sServer, sizeof(sServer), "mg_time"); } else { return; } char sQuery[512]; Format(sQuery, sizeof(sQuery), "select sum(%s) as %s_total from unloze_playtimestats.player_time pt where pt.steam_id = '%s' GROUP BY steam_id order by %s_total desc", sServer, sServer, g_csSID[client], sServer); g_hDatabase.Query(SQL_OnQueryCompletedTimeServer, sQuery, GetClientSerial(client), DBPrio_High); } public void SQL_OnQueryCompletedTimeServer(Database db, DBResultSet results, const char[] error, int iSerial) { if (!db || strlen(error)) { delete results; LogError("Query error 3: %s", error); return; } int client; if ((client = GetClientFromSerial(iSerial)) == 0) { delete results; return; } int iTime_Server; while (results.RowCount && results.FetchRow()) { iTime_Server += results.FetchInt(0); } delete results; int iHours_Server = (iTime_Server / 60) / 60; int iMinutes_Server = (iTime_Server / 60) % 60; g_iPlayerTimeServer[client] = iHours_Server; Call_StartForward(g_hForwardPlayerHours); Call_PushCell(client); Call_PushCell(g_iPlayerTimeServer[client]); Call_PushCell(iMinutes_Server); Call_Finish(); if (g_iPlayerTier[client] == -1) { SetPlayerTier(client); if (g_iPlayerTier[client] > 0) { WritePlayerTierToFile(client); //checks if all tiers have to be written } } else if (check_if_client_new_tier(client)) //called every 10 minutes to fill new times from DB { SetPlayerTier(client); WritePlayerTierToFile(client); //write only the new tier to the file at the end. } } public void WritePlayerTierToFile(int client) { char sPath[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sPath, sizeof(sPath), "configs/admins_simple.ini"); // --- Read entire file into memory --- File f = OpenFile(sPath, "r"); if (!f) { LogError("WritePlayerTierToFile: failed to open %s for reading", sPath); return; } bool foundSeparator = false; //always write the steamIDs as steamID 2 format. char sSID[64]; GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID)); bool write_all_tiers = true; bool write_newest_tier = false; char line[256]; while (f.ReadLine(line, sizeof(line))) { int len = strlen(line); while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0'; if (StrEqual(line, "//here begins the unloze_play_time plugin tiers", false)) { foundSeparator = true; continue; } if (!foundSeparator) { continue; } // Each line looks like: "STEAM_0:0:12345" "@tier3" // Extract steam ID and tier number char steamid[65]; char group[64]; int pos = 1; //skip opening quote int sidStart = pos; while (line[pos] != '"') { pos++; } int sidLen = pos - sidStart; strcopy(steamid, sidLen + 1, line[sidStart]); if (!StrEqual(steamid, sSID)) { continue; } //if steam ID does not exist write all tiers write_all_tiers = false; write_newest_tier = true; pos++; // skip closing quote of steamid while (line[pos] == ' ' || line[pos] == '\t') pos++; // skip whitespace pos++; // skip opening quote of group int grpStart = pos; while (line[pos] != '"') pos++; int grpLen = pos - grpStart; strcopy(group, grpLen + 1, line[grpStart]); // group is "@tier3", extract tier number char tierStr[8]; strcopy(tierStr, sizeof(tierStr), group[5]); // skip "@tier" int tierNum = StringToInt(tierStr); if (tierNum == g_iPlayerTier[client]) { write_newest_tier = false; break; //we confirmed the most recent tier was already written here. } } delete f; if (write_all_tiers) { // Open file for appending File fAppend = OpenFile(sPath, "a"); for (int t = 1; t <= g_iPlayerTier[client]; t++) { char linewrite[256]; Format(linewrite, sizeof(linewrite), "\"%s\" \"@tier%i\"\n", sSID, t); fAppend.WriteString(linewrite, false); } delete fAppend; SetTierRewards(client); } else if (write_newest_tier) { // Open file for appending File fAppend = OpenFile(sPath, "a"); char linewrite[256]; Format(linewrite, sizeof(linewrite), "\"%s\" \"@tier%i\"\n", sSID, g_iPlayerTier[client]); fAppend.WriteString(linewrite, false); delete fAppend; SetTierRewards(client); } } public bool check_if_client_new_tier(int client) { char sPath[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sPath, sizeof(sPath), "configs/unloze_playt_time_tiers.cfg"); KeyValues kv = new KeyValues("PlayTimeTiers"); if (!kv.ImportFromFile(sPath)) { LogError("configs/unloze_playt_time_tiers not found"); delete kv; return false; } if (!kv.GotoFirstSubKey(false)) { LogError("configs/unloze_playt_time_tiers.cfg is empty or malformed"); delete kv; return false; } bool upgrade_tier = false; do { char sKey[16], sVal[16]; kv.GetSectionName(sKey, sizeof(sKey)); kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1"); int tier = StringToInt(sVal); int hours = StringToInt(sKey); if (hours > g_iPlayerTimeServer[client]) { break; } if (tier > g_iPlayerTier[client]) { PrintToChatAll("%N Leveled up to Tier: %i!", client, tier); upgrade_tier = true; } } while (kv.GotoNextKey(false)); delete kv; return upgrade_tier; } public void SetTierRewards(int client) { if (g_iPlayerTier[client] < 1) { return; } for (int i = 1; i <= g_iPlayerTier[client]; i++) { char groupname[64]; Format(groupname, sizeof(groupname), "tier%i", i); AddClientToGroup(client, groupname); } } public void AddClientToGroup(int client, const char[] groupName) { AdminId id = GetUserAdmin(client); if (id == INVALID_ADMIN_ID) { id = CreateAdmin(); SetUserAdmin(client, id, true); } GroupId grp = FindAdmGroup(groupName); if (grp == INVALID_GROUP_ID) { grp = CreateAdmGroup(groupName); } AdminInheritGroup(id, grp); } public void SetPlayerTier(int client) { char sPath[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sPath, sizeof(sPath), "configs/unloze_playt_time_tiers.cfg"); KeyValues kv = new KeyValues("PlayTimeTiers"); if (!kv.ImportFromFile(sPath)) { LogError("configs/unloze_playt_time_tiers not found"); delete kv; return; } if (!kv.GotoFirstSubKey(false)) { LogError("configs/unloze_playt_time_tiers.cfg is empty or malformed"); delete kv; return; } int next_hours = 0; do { char sKey[16], sVal[16]; kv.GetSectionName(sKey, sizeof(sKey)); kv.GetString(NULL_STRING, sVal, sizeof(sVal), "-1"); int tier = StringToInt(sVal); int hours = StringToInt(sKey); next_hours = hours; if (hours > g_iPlayerTimeServer[client]) { break; } g_iPlayerTier[client] = tier; } while (kv.GotoNextKey(false)); if (g_iPlayerTier[client] == -1) { g_iPlayerTier[client] = 0; } Call_StartForward(g_hForwardPlayerTier); Call_PushCell(client); Call_PushCell(g_iPlayerTier[client]); Call_Finish(); if (g_iPlayerTimeServer[client] < next_hours) { g_iPlayerNextTierHours[client] = next_hours - g_iPlayerTimeServer[client]; PrintToChat(client, "You need %i hours to reach next tier. Check your features with !sm_tier", g_iPlayerNextTierHours[client]); } else delete kv; } public void OnClientDisconnect(int client) { g_iPlayerNextTierHours[client] = 0; g_iPlayerTier[client] = -1; Format(g_csSID[client], sizeof(g_csSID[]), ""); is_bot_player[client] = false; g_iPlayerTimeServer[client] = 0; } public void insert_client(int client) { char sName[MAX_NAME_LENGTH]; GetClientName(client, sName, sizeof(sName)); int size2 = 2 * strlen(sName) + 1; char[] sEscapedName = new char[size2 + 1]; g_hDatabase.Escape(sName, sEscapedName, size2 + 1); char sIP[32]; GetClientIP(client, sIP, sizeof(sIP)); char sQuery[512]; Format(sQuery, sizeof(sQuery), "INSERT INTO `player_time` (`steam_id`, `ipv4`, `player_name`, `ze_time`, `mg_time`, `zr_time`, `jb_time`) VALUES ('%s', '%s', '%s', 0, 0, 0, 0) ON DUPLICATE KEY UPDATE `player_name` = '%s'", g_csSID[client], sIP, sEscapedName, sEscapedName); g_hDatabase.Query(SQL_FinishedQuery, sQuery, _, DBPrio_Low); } public void SQL_FinishedQuery(Database db, DBResultSet results, const char[] error, any data) { if (!db || strlen(error)) { LogError("Query error 3: %s", error); } delete results; } stock bool IsValidClient(int client) { if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) return true; return false; } public void OnMapStart() { if (!g_hDatabase) { Database.Connect(SQL_OnDatabaseConnect, "unloze_playtimestats"); return; } char sQuery[512]; char sServer[32]; int i_port = GetConVarInt(FindConVar("hostport")); if (i_port == 27015 || i_port == 27019 || i_port == 27035) { Format(sServer, sizeof(sServer), "ze_time"); } else if (i_port == 27016) { Format(sServer, sizeof(sServer), "zr_time"); } else if (i_port == 27017) { Format(sServer, sizeof(sServer), "mg_time"); } else { return; } Format(sQuery, sizeof(sQuery), "select player_name, sum(%s) as %s_total from unloze_playtimestats.player_time GROUP BY steam_id order by %s_total desc limit 1000", sServer, sServer, sServer); g_hDatabase.Query(SQL_OnQueryCompletedTopTime, sQuery); } public Action Command_TopTime(int client, int args) { char sTitle[64]; char sServer[32]; int i_port = GetConVarInt(FindConVar("hostport")); if (i_port == 27015 || i_port == 27019 || i_port == 27035) { Format(sServer, sizeof(sServer), "ZE"); } else if (i_port == 27016) { Format(sServer, sizeof(sServer), "ZR"); } else if (i_port == 27017) { Format(sServer, sizeof(sServer), "MG"); } else if (i_port == 27023) { Format(sServer, sizeof(sServer), "JB"); } Format(sTitle, sizeof(sTitle), "[UNLOZE Playtime] Top 1000 Record Holders for %s:", sServer); Menu menu = new Menu(MenuHandler1); menu.SetTitle(sTitle); for (int i = 0; i < sizeof(g_cTimeRecords); i++) { menu.AddItem("-1", g_cTimeRecords[i], ITEMDRAW_DISABLED); } menu.ExitButton = true; menu.Display(client, 0); return Plugin_Handled; } public void PrintClientGroupOverrides(int client) { char sTitle[128]; Format(sTitle, sizeof(sTitle), "Tier %i | Next tier requires %i hours.", g_iPlayerTier[client], g_iPlayerNextTierHours[client]); Menu menu = new Menu(MenuHandler1); menu.SetTitle(sTitle); char rtv_boost_tier[32]; Format(rtv_boost_tier, sizeof(rtv_boost_tier), "tier%i", g_iRtvBoost_tier); char spray_tier[32]; Format(spray_tier, sizeof(spray_tier), "tier%i", FindConVar("sm_spraymanager_tier_required").IntValue); char entwatch_tier[32]; Format(entwatch_tier, sizeof(entwatch_tier), "tier%i", FindConVar("sm_entwatch_tier_requirement").IntValue); char multi_nomination_tier[32]; Format(multi_nomination_tier, sizeof(multi_nomination_tier), "tier%i", FindConVar("mce_multiple_nominations_tier").IntValue); for (int i = 0; i < g_GroupNameCount; i++) { char entry[128]; char overrides[512]; if (StrEqual(g_GroupNames[i], rtv_boost_tier)) { Format(entry, sizeof(entry), "%s: %ix Mapvote/RTV/Nomination boost", g_GroupNames[i], g_iPlayerRTVCapacity); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } if (StrEqual(g_GroupNames[i], spray_tier)) { Format(entry, sizeof(entry), "%s: Sprays", g_GroupNames[i]); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } if (StrEqual(g_GroupNames[i], entwatch_tier)) { Format(entry, sizeof(entry), "%s: Items", g_GroupNames[i]); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } if (StrEqual(g_GroupNames[i], multi_nomination_tier)) { Format(entry, sizeof(entry), "%s: Multiple nominations", g_GroupNames[i]); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } if (g_GroupFlags[i][0] != '\0' && StrEqual(g_GroupFlags[i], "aop")) { Format(entry, sizeof(entry), "%s: VIP", g_GroupNames[i]); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } if (g_GroupOverrides.GetString(g_GroupNames[i], overrides, sizeof(overrides))) { Format(entry, sizeof(entry), "%s: %s", g_GroupNames[i], overrides); menu.AddItem("-1", entry, ITEMDRAW_DISABLED); } } menu.AddItem("-1", "any tier: playermodels in zclass.", ITEMDRAW_DISABLED); menu.ExitButton = true; menu.Display(client, 0); } public Action Command_Tier(int client, int args) { PrintClientGroupOverrides(client); return Plugin_Handled; } public Action Command_Time(int client, int args) { if (!g_hDatabase) { return Plugin_Handled; } char sQuery[512]; Format(sQuery, sizeof(sQuery), "select ze_time, mg_time, zr_time, jb_time from unloze_playtimestats.player_time pt where pt.steam_id = '%s'", g_csSID[client]); g_hDatabase.Query(SQL_OnQueryCompletedTime, sQuery, GetClientSerial(client)); return Plugin_Handled; } public void SQL_OnQueryCompletedTopTime(Database db, DBResultSet results, const char[] error, int iSerial) { if (!db || strlen(error)) { delete results; LogError("Query error 3: %s", error); return; } int iTime; char sName[MAX_NAME_LENGTH]; int counter = 0; while (results.RowCount && results.FetchRow()) { char sBuffer[256]; results.FetchString(0, sName, sizeof(sName)); iTime = results.FetchInt(1); int iHours = (iTime / 60) / 60; Format(sBuffer, sizeof(sBuffer), "%i %s %d Hours", counter + 1, sName, iHours); Format(g_cTimeRecords[counter], sizeof(g_cTimeRecords[]), sBuffer); counter++; } delete results; } public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2) { switch(action) { case MenuAction_End: { delete menu; } } return 0; } public void SQL_OnQueryCompletedTime(Database db, DBResultSet results, const char[] error, int iSerial) { if (!db || strlen(error)) { delete results; LogError("Query error 3: %s", error); return; } int client; if ((client = GetClientFromSerial(iSerial)) == 0) { delete results; return; } int iTime_ze; int iTime_mg; int iTime_zr; int iTime_jb; while (results.RowCount && results.FetchRow()) { iTime_ze += results.FetchInt(0); iTime_mg += results.FetchInt(1); iTime_zr += results.FetchInt(2); iTime_jb += results.FetchInt(3); } delete results; int iHours_ze = (iTime_ze / 60) / 60; int iMinutes_ze = (iTime_ze / 60) % 60; int iSeconds_ze = (iTime_ze % 60); int iHours_mg = (iTime_mg / 60) / 60; int iMinutes_mg = (iTime_mg / 60) % 60; int iSeconds_mg = (iTime_mg % 60); int iHours_zr = (iTime_zr / 60) / 60; int iMinutes_zr = (iTime_zr / 60) % 60; int iSeconds_zr = (iTime_zr % 60); int iHours_jb = (iTime_jb / 60) / 60; int iMinutes_jb = (iTime_jb / 60) % 60; int iSeconds_jb = (iTime_jb % 60); char sTime_ze[64]; char sTime_mg[64]; char sTime_zr[64]; char sTime_jb[64]; char sTitle[64]; Format(sTitle, sizeof(sTitle), "[UNLOZE Playtime] Player %N:", client); Format(sTime_ze, sizeof(sTime_ze), "Zombie Escape: %d Hours %d Minutes %d Seconds", iHours_ze, iMinutes_ze, iSeconds_ze); Format(sTime_mg, sizeof(sTime_mg), "MiniGame: %d Hours %d Minutes %d Seconds", iHours_mg, iMinutes_mg, iSeconds_mg); Format(sTime_zr, sizeof(sTime_zr), "Zombie Riot: %d Hours %d Minutes %d Seconds", iHours_zr, iMinutes_zr, iSeconds_zr); Format(sTime_jb, sizeof(sTime_jb), "Jail Break: %d Hours %d Minutes %d Seconds", iHours_jb, iMinutes_jb, iSeconds_jb); Panel mSayPanel = new Panel(GetMenuStyleHandle(MenuStyle_Radio)); mSayPanel.SetTitle(sTitle); mSayPanel.DrawItem("", ITEMDRAW_SPACER); mSayPanel.DrawText(sTime_ze); mSayPanel.DrawItem("", ITEMDRAW_SPACER); mSayPanel.DrawText(sTime_mg); mSayPanel.DrawItem("", ITEMDRAW_SPACER); mSayPanel.DrawText(sTime_zr); mSayPanel.DrawItem("", ITEMDRAW_SPACER); mSayPanel.DrawText(sTime_jb); mSayPanel.DrawItem("", ITEMDRAW_SPACER); mSayPanel.DrawItem("1. Got it!", ITEMDRAW_RAWLINE); mSayPanel.SetKeys(1023); mSayPanel.Send(client, Handler_Menu, 0); delete mSayPanel; } public int Handler_Menu(Menu menu, MenuAction action, int param1, int param2) { switch(action) { case MenuAction_Select, MenuAction_Cancel: delete menu; } return 0; }