#pragma semicolon 1 #define DEBUG #define PLUGIN_AUTHOR "jenz" #define PLUGIN_VERSION "1.5" #define g_dLength 256 #define g_dIndex 65 #include #include #include #include #include #include #include #include #pragma newdecls required char g_cMapname[g_dLength]; char g_cSpecialMapStart[g_dLength]; char g_cSpecialMapEnd[g_dLength]; static char g_sConfigzones[PLATFORM_MAX_PATH]; int g_iRoundMinutes; float g_fRoundSeconds; int g_iMinutesIndividual[MAXPLAYERS + 1]; float g_fSecondsIndividual[MAXPLAYERS + 1]; float g_fClientVectors[MAXPLAYERS + 1][3]; int g_iClientFrames[MAXPLAYERS + 1]; int g_iClientSpeedInterval[MAXPLAYERS + 1]; int g_iClientChecking[MAXPLAYERS + 1]; bool g_bDisplaySpecial; bool g_bHumansAllowedTime[MAXPLAYERS + 1]; bool g_bHideTimer[MAXPLAYERS + 1]; bool g_bDev[MAXPLAYERS + 1]; Handle g_hClientCookie = INVALID_HANDLE; Database g_dDatabase; Handle hText; float playertime_leaving_zone[MAXPLAYERS + 1]; int player_stage[MAXPLAYERS + 1]; public Plugin myinfo = { name = "UNLOZE_racetimer_css", author = PLUGIN_AUTHOR, description = "tracers times on race maps", version = PLUGIN_VERSION, url = "www.unloze.com" }; //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnPluginStart() { //cmds RegConsoleCmd("sm_toptime", cmd_timerCheckTop, "checking top 10"); RegConsoleCmd("sm_mytime", cmd_timerCheckSelf, "checking your personal time"); RegConsoleCmd("sm_stages", cmd_timerCheckStage, "Checking race stages"); RegConsoleCmd("sm_hidetimer", cmd_hideTimerHUD, "Hides timer HUD"); RegAdminCmd("sm_cleantime", Cmd_timeReset, ADMFLAG_GENERIC); RegAdminCmd("sm_devtime", Cmd_devtest, ADMFLAG_GENERIC); //hooks HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); //HUD hText = CreateHudSynchronizer(); //cookies g_hClientCookie = RegClientCookie("hide_timer_cookie", "Hides the timer HUD", CookieAccess_Private); for (int i = MaxClients; i > 0; --i) { if (!AreClientCookiesCached(i)) { continue; } OnClientCookiesCached(i); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnMapStart() { //mysql placed here just in case somebody wants to reset database without having to reload plugin g_bDisplaySpecial = unloze_gBSpecialMapDisplay(); SQL_StartConnection(); GetCurrentMap(g_cMapname, sizeof(g_cMapname)); CreateTimer(0.1, Timer_CountdownRace, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); startTimer(); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnPluginEnd() { CloseHandle(hText); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void startTimer() { char line[g_dLength]; Handle zonefile = INVALID_HANDLE; BuildPath(Path_SM, g_sConfigzones, sizeof(g_sConfigzones), "configs/unloze_zones/%s.zones.txt", g_cMapname); zonefile = OpenFile(g_sConfigzones, "r"); if (zonefile != INVALID_HANDLE) { while (!IsEndOfFile(zonefile) && ReadFileLine(zonefile, line, sizeof(line))) { if (StrContains(line, "ZONE_PREFIX_RACE", false) > -1 || g_bDisplaySpecial) { MYSQLCheckMapEntry(); break; } } } delete zonefile; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action Timer_CountdownRace(Handle timer, any data) { float l_milisecond = 0.0000; while (l_milisecond < 0.1000) { l_milisecond += 0.0001; g_fRoundSeconds += 0.0001; if (g_fRoundSeconds > 59.9999) { g_iRoundMinutes += 1; g_fRoundSeconds = 0.0000; } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void Event_RoundStart(Handle event, const char[] name, bool dontBroadcast) { g_iRoundMinutes = 0; g_fRoundSeconds = 0.0; int l_iZoneCount = unloze_zoneCount(); for (int i = 1; i <= MaxClients; i++) if (IsValidClient(i)) { resetClientVectors(i); if (l_iZoneCount != 1) g_bHumansAllowedTime[i] = false; else { mysql_get_player_time(i, 0); g_bHumansAllowedTime[i] = true; } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientPostAdminCheck(int client) { resetClient(client); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientCookiesCached(int client) { char sValue[8]; GetClientCookie(client, g_hClientCookie, sValue, sizeof(sValue)); g_bHideTimer[client] = (sValue[0] != '\0' && !!StringToInt(sValue)); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientDisconnect(int client) { resetClient(client); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void resetClient(int client) { g_fSecondsIndividual[client] = 0.0; g_iMinutesIndividual[client] = 0; g_iClientChecking[client] = 0; g_bHumansAllowedTime[client] = false; resetClientVectors(client); g_bDev[client] = false; player_stage[client] = 0; playertime_leaving_zone[client] = 0.0; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) { if (g_bHumansAllowedTime[client] && (GetClientTeam(client) == CS_TEAM_CT) && IsPlayerAlive(client)) { int frameCap = 11; if (g_iClientFrames[client] >= frameCap) { g_iClientFrames[client] = 0; float clientVectors[3]; GetClientAbsOrigin(client, clientVectors); if (checkClientOrigin(g_fClientVectors[client], clientVectors, client) && !g_bDev[client]) { g_bHumansAllowedTime[client] = false; resetClientVectors(client); PrintToChat(client, "Disabled timer due to potential teleport abuse"); return Plugin_Continue; } int speedCheckerCap = 10; if (g_iClientSpeedInterval[client] > speedCheckerCap && !g_bDev[client]) { g_iClientSpeedInterval[client] = 0; bool bNoclip = (GetEntityMoveType(client) == MOVETYPE_NOCLIP); if (bNoclip) { g_bHumansAllowedTime[client] = false; resetClientVectors(client); PrintToChat(client, "Disabled timer due to Noclip"); return Plugin_Continue; } float speed = GetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue"); if (speed > 1.0) { if (StrContains(g_cMapname, "surf", false) == -1) { g_bHumansAllowedTime[client] = false; resetClientVectors(client); PrintToChat(client, "Disabled timer due to modified run speed"); return Plugin_Continue; } } float client_gravity = GetEntityGravity(client); ConVar gravity = FindConVar("sv_gravity"); float gravityFloat = gravity.FloatValue; int minimalPermitedGravity = 610; //PrintToChat(client, "client_gravity: %f\ngravityFloat: %f", client_gravity, gravityFloat); if (((client_gravity > 1.3 || client_gravity < 0.6000) && client_gravity != 0.000000) || gravityFloat < minimalPermitedGravity) { //PrintToChat(client, "client_gravity: %f\ngravityFloat: %f", client_gravity, gravityFloat); g_bHumansAllowedTime[client] = false; resetClientVectors(client); PrintToChat(client, "Disabled timer due to modified gravity"); return Plugin_Continue; } } g_fClientVectors[client] = clientVectors; { if (hText != INVALID_HANDLE && !g_bHideTimer[client]) { SetHudTextParams(0.35, 0.85, 0.1, 125, 255, 255, 85); int l_iCalculateMins = CalculateValuesMinutes(client); float l_fCalculateSecs = CalculateValues(client); float leftover_seconds = playertime_leaving_zone[client] - RoundToFloor(playertime_leaving_zone[client]); leftover_seconds = leftover_seconds * 100; int minutes = RoundToFloor(playertime_leaving_zone[client]); if (g_bDev[client]) { //PrintToChat(client, "leftover_seconds: %f", leftover_seconds); //PrintToChat(client, "minutes: %i", minutes); } if (l_fCalculateSecs < 10.0) { if (leftover_seconds < 10.0) { ShowSyncHudText(client, hText, "%N Time: 0%i:0%.4f\nRecord: 0%i:0%.4f\nMap: %s\nCourse: %i", client, l_iCalculateMins, l_fCalculateSecs, minutes, leftover_seconds, g_cMapname, player_stage[client]); } else { ShowSyncHudText(client, hText, "%N Time: 0%i:0%.4f\nRecord: 0%i:%.4f\nMap: %s\nCourse: %i", client, l_iCalculateMins, l_fCalculateSecs, minutes, leftover_seconds, g_cMapname, player_stage[client]); } } else { if (leftover_seconds < 10.0) { ShowSyncHudText(client, hText, "%N Time: 0%i:%.4f\nRecord: 0%i:0%.4f\nMap: %s\nCourse: %i", client, l_iCalculateMins, l_fCalculateSecs, minutes, leftover_seconds, g_cMapname, player_stage[client]); } else { ShowSyncHudText(client, hText, "%N Time: 0%i:%.4f\nRecord: 0%i:%.4f\nMap: %s\nCourse: %i", client, l_iCalculateMins, l_fCalculateSecs, minutes, leftover_seconds, g_cMapname, player_stage[client]); } } } } g_iClientSpeedInterval[client]++; } g_iClientFrames[client]++; } return Plugin_Continue; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void resetClientVectors(int client) { g_fClientVectors[client][0] = 0.000000; g_fClientVectors[client][1] = 0.000000; g_fClientVectors[client][2] = 0.000000; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public bool checkClientOrigin(float oldVals[3], float newVals[3], int client) { float zero = 0.000000; if ((oldVals[0] == zero && oldVals[1] == zero && oldVals[2] == zero) || (newVals[0] == zero && newVals[1] == zero && newVals[2] == zero)) { return false; } float teleport_range = 100000.0; int velocityCap = 325; float distance = GetVectorDistance(oldVals, newVals, true); //PrintToChatAll("distance: %f", distance); bool bInAir = (GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") == -1); if (distance > teleport_range) { if (StrContains(g_cMapname, "surf", false) != -1) return false; float fVelocity[3]; GetEntPropVector(client, Prop_Data, "m_vecVelocity", fVelocity); float currentspeed = SquareRoot(Pow(fVelocity[0],2.0)+Pow(fVelocity[1],2.0)); //PrintToChat(client, "currentspeed: %f", currentspeed); if (bInAir && currentspeed > velocityCap) return false; return true; } return false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void unloze_zoneEntry(int client, char[] zone) { int zoneIndex = RetrieveZoneIndex(zone); int l_iZoneCount = unloze_zoneCount(); if (((GetClientTeam(client) == CS_TEAM_CT && g_bHumansAllowedTime[client]) && StrContains(zone, "ZONE_PREFIX_RACE") > -1) || StrEqual(zone, g_cSpecialMapEnd)) { if (IsClientAuthorized(client)) { if (l_iZoneCount < 2) { player_stage[client] = 0; } if (player_stage[client] == (zoneIndex / 2) || l_iZoneCount < 2) { FinishedStageRaceZone(client); } } if (!g_bDev[client]) g_bHumansAllowedTime[client] = false; } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void unloze_zoneLeave(int client, char[] zone) { //only maps with multiple zones need ZONE_PREFIX_START if (((GetClientTeam(client) == CS_TEAM_CT) && StrContains(zone, "ZONE_PREFIX_START") > -1) || StrEqual(zone, g_cSpecialMapStart)) { resetClientVectors(client); g_fSecondsIndividual[client] = g_fRoundSeconds; g_iMinutesIndividual[client] = g_iRoundMinutes; float notRounded = float(RetrieveZoneIndex(zone)); player_stage[client] = RoundToCeil(notRounded / 2); mysql_get_player_time(client, player_stage[client]); g_bHumansAllowedTime[client] = true; CPrintToChat(client, "Timer started for Course: %i", player_stage[client]); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void unloze_zoneCreated() { startTimer(); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void CheckIfSpecialRoundZones(char[] resultstart, char[] resultend) { Format(g_cSpecialMapStart, sizeof(g_cSpecialMapStart), resultstart); Format(g_cSpecialMapEnd, sizeof(g_cSpecialMapEnd), resultend); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void CheckifAntiZones(int client, bool reset) { if (reset) g_bHumansAllowedTime[client] = false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int RetrieveZoneIndex(char[] zone) { //if you leave zone_2 you want the corresponding racezone to be zone_3 int iterator = strlen(zone) - 1; if (iterator == -1) return 1; char l_sZone[g_dIndex]; Format(l_sZone, sizeof(l_sZone), zone); while (IsCharNumeric(l_sZone[iterator])) iterator--; iterator++; strcopy(l_sZone, sizeof(l_sZone), l_sZone[iterator]); return StringToInt(l_sZone[iterator]); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void FinishedStageRaceZone(int client) { int l_iZoneCount = unloze_zoneCount(); int l_iCalculateMins; float l_fCalculateSecs; float leftover_seconds = playertime_leaving_zone[client] - RoundToFloor(playertime_leaving_zone[client]); int minutes = RoundToFloor(playertime_leaving_zone[client]); leftover_seconds = leftover_seconds * 100; if (g_bDev[client]) PrintToChat(client, "leftover_seconds: %f", leftover_seconds); if (minutes == 0 && leftover_seconds == 0.0) CPrintToChat(client, "Your record: None yet \nCommand: !toptime !mytime !stages"); else if (leftover_seconds < 10.0) CPrintToChat(client, "Your record: 0%i:0%.4f \nCommand: !toptime !mytime !stages", minutes, leftover_seconds); else CPrintToChat(client, "Your record: 0%i:%.4f \nCommand: !toptime !mytime !stages", minutes, leftover_seconds); if (l_iZoneCount < 2) { //no start zone, we use round time CPrintToChat(client, "{green}[UNLOZE] Client: %N Time: 0%i:%.4f", client, g_iRoundMinutes, g_fRoundSeconds); if (g_iRoundMinutes < minutes) sendMYSQL(client, g_iRoundMinutes, g_fRoundSeconds, player_stage[client]); else if (g_iRoundMinutes == minutes && g_fRoundSeconds < leftover_seconds) sendMYSQL(client, g_iRoundMinutes, g_fRoundSeconds, player_stage[client]); else if (minutes == 0 && leftover_seconds == 0.0) sendMYSQL(client, g_iRoundMinutes, g_fRoundSeconds, player_stage[client]); } else { //uses start zone, we use time when leaving start zone l_iCalculateMins = CalculateValuesMinutes(client); l_fCalculateSecs = CalculateValues(client); //tricking ppl !hehe CPrintToChat(client, "{green}[UNLOZE] Stage: %i", player_stage[client]); CPrintToChat(client, "{green}[UNLOZE] Client: %N Time: 0%i:%.4f", client, l_iCalculateMins, l_fCalculateSecs); if (l_iCalculateMins < minutes) sendMYSQL(client, l_iCalculateMins, l_fCalculateSecs, player_stage[client]); else if (l_iCalculateMins == minutes && l_fCalculateSecs < leftover_seconds) sendMYSQL(client, l_iCalculateMins, l_fCalculateSecs, player_stage[client]); else if (minutes == 0.0 && leftover_seconds == 0.0) sendMYSQL(client, l_iCalculateMins, l_fCalculateSecs, player_stage[client]); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int CalculateValuesMinutes(int client) { float l_fRoundSeconds = g_fRoundSeconds; float l_fRoundSecondsIndividual = g_fSecondsIndividual[client]; int l_iRoundMinutes = g_iRoundMinutes; int l_iRoundMinutesIndividual = g_iMinutesIndividual[client]; if (l_iRoundMinutesIndividual > l_iRoundMinutes) return 0; l_iRoundMinutes = l_iRoundMinutes - l_iRoundMinutesIndividual; if (l_fRoundSeconds < l_fRoundSecondsIndividual) l_iRoundMinutes--; return l_iRoundMinutes; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public float CalculateValues(int client) { // 2:24 enter with roundtime 5:29 = 3:05 // 3:01 enter with roundtime 3:59 = 58 sec //example roundtime is 5 mins 40 seconds, client entered at 4 mins and 50 seconds, so 50 sec race float l_fRoundSeconds = g_fRoundSeconds; float l_fRoundSecondsIndividual = g_fSecondsIndividual[client]; float l_fSecAdd; if (l_fRoundSeconds < l_fRoundSecondsIndividual) { while (l_fRoundSecondsIndividual < 59.9) { l_fRoundSecondsIndividual++; l_fSecAdd++; } float returnvalue = l_fSecAdd + l_fRoundSeconds; //PrintToChat(client, "returnvalue float: %f", returnvalue); return returnvalue; } else { float returnvalueminus = l_fRoundSeconds - l_fRoundSecondsIndividual; //PrintToChat(client, "returnvalueminus float: %f", returnvalueminus); return returnvalueminus; } } public void mysql_get_player_time(int client, int stage) { DBResultSet rs; char query[g_dLength]; char steam_auth[g_dIndex]; GetClientAuthId(client, AuthId_Steam2, steam_auth, sizeof(steam_auth)); if (!stage) Format(query, sizeof(query), "SELECT `%s` FROM `zetimer_table` where steam_auth = '%s'", g_cMapname, steam_auth); else Format(query, sizeof(query), "SELECT `%sS%i` FROM `zetimer_table` where steam_auth = '%s'", g_cMapname, stage, steam_auth); if ((rs = SQL_Query(g_dDatabase, query)) == null) { delete rs; return; } rs.FetchRow(); if (rs.RowCount > 0) playertime_leaving_zone[client] = rs.FetchFloat(0); if (g_bDev[client]) { PrintToChat(client, "query: %s", query); PrintToChat(client, "playertime_leaving_zone[client]: %f", playertime_leaving_zone[client]); } delete rs; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void MYSQLCheckMapEntry() { int l_iRaceCount; int l_iZoneCount = unloze_zoneCount(); char sQuery[g_dLength]; char l_cZoneIndexName[g_dIndex][g_dLength]; if (l_iZoneCount < 2) { Format(sQuery, sizeof(sQuery), "SELECT `%s` FROM `zetimer_table` LIMIT 1", g_cMapname); SQL_TQuery(g_dDatabase, TqueryThreadCallback, sQuery); } else for (int iterator = 0; iterator <= l_iZoneCount; iterator++) { if (IsCorrectZone(iterator, l_cZoneIndexName[iterator][g_dLength -1], "ZONE_PREFIX_RACE")) { l_iRaceCount++; Format(sQuery, sizeof(sQuery), "SELECT `%sS%i` FROM `zetimer_table` LIMIT 1", g_cMapname, l_iRaceCount); SQL_TQuery(g_dDatabase, TqueryThreadCallback, sQuery); } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void TqueryThreadCallback(Handle owner, Handle rs, const char[] error, any data) { int l_iRaceCount; int l_iZoneCount = unloze_zoneCount(); char sQuery[g_dLength]; char l_cZoneIndexName[g_dIndex][g_dLength]; if (rs == null) { if (l_iZoneCount == 1) { Format(sQuery, sizeof(sQuery), "ALTER TABLE `zetimer_table` ADD COLUMN `%s` DECIMAL(8,7) NOT NULL DEFAULT 0.000000", g_cMapname); SQL_FastQuery(g_dDatabase, sQuery); } else { //this might seem repetitive but one null check adds all required coloumns for (int iterator = 0; iterator <= l_iZoneCount; iterator++) { if (IsCorrectZone(iterator, l_cZoneIndexName[iterator][g_dLength -1], "ZONE_PREFIX_RACE")) { l_iRaceCount++; Format(sQuery, sizeof(sQuery), "ALTER TABLE `zetimer_table` ADD COLUMN `%sS%i` DECIMAL(8,7) NOT NULL DEFAULT 0.000000", g_cMapname, l_iRaceCount); SQL_FastQuery(g_dDatabase, sQuery); } } } } } //---------------------------------------------------------------------------------------------------- // Purpose: TODO implement if needed //---------------------------------------------------------------------------------------------------- public int GetTotalRaceZones() { int l_iZoneCount = unloze_zoneCount(); char l_cIndexName[g_dLength]; int l_iCountRace; for (int iterator = 0; iterator < l_iZoneCount; iterator++) { ZoneNameBasedOnIndex(iterator, l_cIndexName[iterator]); if (StrContains(l_cIndexName[iterator], "ZONE_PREFIX_RACE") > -1) l_iCountRace++; } return l_iCountRace; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void sendMYSQL(int client, int minutes, float seconds, int stage) { int l_iZoneCount = unloze_zoneCount(); float l_fPlayerTime = float(minutes); char sSID[g_dIndex]; char l_cClientName[g_dIndex]; char sQuery[g_dLength]; char sQuery2[g_dLength]; char sName[MAX_NAME_LENGTH]; GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID)); GetClientName(client, sName, sizeof(sName)); int size2 = 2 * strlen(sName) + 1; char[] sEscapedName = new char[size2 + 1]; SQL_EscapeString(g_dDatabase, sName, sEscapedName, size2 + 1); Format(l_cClientName, sizeof(l_cClientName), sEscapedName); //STEAM_ID_STOP_IGNORING_RETVALS might be considered exploit? if (StrEqual(sSID, "STEAM_ID_STOP_IGNORING_RETVALS") || StrEqual(sSID, "STEAM_ID_PENDING")) return; l_fPlayerTime = l_fPlayerTime + (seconds / 100); if (l_iZoneCount < 2) { Format(sQuery2, sizeof(sQuery2), "SELECT %s FROM unloze_racetimer_css.zetimer_table zt where steam_auth = '%s'", g_cMapname, sSID); Format(sQuery, sizeof(sQuery), "INSERT INTO `zetimer_table` (`steam_auth`, `name`, `%s`) VALUES ('%s', '%s', '%f') ON DUPLICATE KEY UPDATE `name` = '%s', `%s` = '%f'", g_cMapname, sSID, l_cClientName, l_fPlayerTime, l_cClientName, g_cMapname, l_fPlayerTime); } else { Format(sQuery2, sizeof(sQuery2), "SELECT %sS%i FROM unloze_racetimer_css.zetimer_table zt where steam_auth = '%s'", g_cMapname, stage, sSID); Format(sQuery, sizeof(sQuery), "INSERT INTO `zetimer_table` (`steam_auth`, `name`, `%sS%i`) VALUES ('%s', '%s', '%f') ON DUPLICATE KEY UPDATE `name` = '%s', `%sS%i` = '%f'", g_cMapname, stage, sSID, l_cClientName, l_fPlayerTime, l_cClientName, g_cMapname, stage, l_fPlayerTime); } DBResultSet rs; if ((rs = SQL_Query(g_dDatabase, sQuery2)) == null) { delete rs; return; } rs.FetchRow(); if (!rs.RowCount) { delete rs; return; } float oldtime = rs.FetchFloat(0); bool update_time = l_fPlayerTime < oldtime ? true : false; if (!update_time) update_time = oldtime == 0.0 ? true : false; delete rs; if (g_bDev[client]) { PrintToChat(client, "sQuery: %s", sQuery); PrintToChat(client, "sQuery2: %s", sQuery2); PrintToChat(client, "update_time: %i", update_time); PrintToChat(client, "l_fPlayerTime: %f", l_fPlayerTime); PrintToChat(client, "oldtime: %f", oldtime); return; } if (update_time) { SQL_TQuery(g_dDatabase, DummyCallbackSimple, sQuery); CPrintToChat(client, "Updated timer"); } //PrintToChatAll("SEND MYSQL sQuery: %s", sQuery); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void SQL_StartConnection() { char error[g_dLength]; if (SQL_CheckConfig("racetimercss")) g_dDatabase = SQL_Connect("racetimercss", true, error, sizeof(error)); if (g_dDatabase == null) { CPrintToChatAll("{green}[UNLOZE] {white}Error! Could not connect to MYSQL-DB!"); } //create tables char sQuery[g_dLength]; Format(sQuery, sizeof(sQuery), "CREATE TABLE IF NOT EXISTS `zetimer_table` (`steam_auth` VARCHAR(254) NOT NULL, `name` VARCHAR(254) NOT NULL, PRIMARY KEY (`steam_auth`))"); SQL_TQuery(g_dDatabase, DummyCallbackSimple, sQuery); MYSQLCheckMapEntry(); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void DummyCallbackSimple(Handle hOwner, Handle hChild, const char[] err, DataPack pack1) { if (hOwner == null || hChild == null) LogError("Query error. (%s)", err); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action cmd_timerCheckTop(int client, int args) { CheckTop(client, 0, 0); return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void CheckTop(int client, int index, int autismstate) { int l_iZoneCount = unloze_zoneCount(); char sQuery[g_dLength]; //PrintToChatAll("checktop l_iZoneCount: %i", l_iZoneCount); if (l_iZoneCount < 1) { PrintToChat(client, "No zones active on this map"); return; } if (!autismstate) { CheckStagesOnMap(client, 0); return; } //we have index now from menu selection if (l_iZoneCount < 2) Format(sQuery, sizeof(sQuery), "SELECT name, %s FROM `zetimer_table` WHERE %s > 0.000 ORDER BY %s ASC LIMIT 10", g_cMapname, g_cMapname, g_cMapname); else Format(sQuery, sizeof(sQuery), "SELECT name, `%sS%i` FROM `zetimer_table` WHERE `%sS%i` > 0.000 ORDER BY `%sS%i` ASC LIMIT 10", g_cMapname, index, g_cMapname, index, g_cMapname, index); SQL_TQuery(g_dDatabase, SQL_SelectTop_Callback, sQuery, GetClientUserId(client)); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void SQL_SelectTop_Callback(Handle db, Handle results, const char[] error, any data) { int iclient = GetClientOfUserId(data); int l_iMinutes; int l_iPosition; float l_fRecord; float l_iSeconds; //Player Name char[] g_cPlayerName = new char[MAX_NAME_LENGTH]; char g_cContent[g_dLength]; if (iclient == 0) { return; } Menu menu = new Menu(MenuHandler1); menu.SetTitle("Maptimer: %s", g_cMapname); if (results != INVALID_HANDLE) { while (SQL_GetRowCount(results) > 0 && SQL_FetchRow(results)) { l_iPosition++; SQL_FetchString(results, 0, g_cPlayerName, MAX_NAME_LENGTH); l_fRecord = SQL_FetchFloat(results, 1); l_iMinutes = RoundToFloor(l_fRecord); l_iSeconds = (l_fRecord - l_iMinutes) * 100; Format(g_cContent, sizeof(g_cContent), "#%i: Time: 0%i:%.4f - %s", l_iPosition, l_iMinutes, l_iSeconds, g_cPlayerName); menu.AddItem("-1", g_cContent, ITEMDRAW_DISABLED); } if (!l_iPosition) { menu.AddItem("-1", "No results. Commands: !toptime !stages", ITEMDRAW_DISABLED); } menu.ExitButton = true; menu.Display(iclient, 0); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int MenuHandler1(Menu menu, MenuAction action, int param1, int param2) { if (action == MenuAction_End) { delete menu; } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action Cmd_devtest(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; g_bDev[client] = !g_bDev[client]; PrintToChat(client, "dev mode: %i", g_bDev[client]); return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action Cmd_timeReset(int client, int args) { if (!IsValidClient(client)) return Plugin_Handled; if (args != 2) { ReplyToCommand(client, "[SM] Usage cleantime "); return Plugin_Handled; } char sTarget[65], steam2[64]; GetCmdArg(1, sTarget, sizeof(sTarget)); int targetID = FindTarget(client, sTarget, false); if(targetID == -1) return Plugin_Handled; GetClientAuthId(targetID, AuthId_Steam2, steam2, sizeof(steam2)); GetCmdArg(2, sTarget, sizeof(sTarget)); deleteClientTime(steam2, StringToInt(sTarget)); return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action cmd_hideTimerHUD(int client, int args) { if (!g_bHideTimer[client]) { g_bHideTimer[client] = true; SetClientCookie(client, g_hClientCookie, "1"); PrintToChat(client, "Disabled timer HUD"); } else { g_bHideTimer[client] = false; PrintToChat(client, "Enabled timer HUD"); SetClientCookie(client, g_hClientCookie, "0"); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action cmd_timerCheckStage(int client, int args) { CheckStagesOnMap(client, 0); return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void CheckStagesOnMap(int client, int state) { int l_iCount; int l_iZoneCount = unloze_zoneCount(); Menu StageMenu = CreateMenu(Stage_menu); char l_cZoneIndexName[g_dIndex][g_dLength]; char l_cMenuContent[g_dLength]; if (!l_iZoneCount) { CPrintToChat(client, "[UNLOZE] Map does not support racestage timer"); return; } //state 0 == toptime, state 1 == own time g_iClientChecking[client] = state; StageMenu.SetTitle("Stages on: %s", g_cMapname); if (g_bDisplaySpecial) { l_iCount++; Format(l_cMenuContent, sizeof(l_cMenuContent), "Stage: %i", l_iCount); StageMenu.AddItem("", l_cMenuContent); } else { for (int Iterator = 0; Iterator <= l_iZoneCount; Iterator++) { if (IsCorrectZone(Iterator, l_cZoneIndexName[Iterator][g_dLength -1], "ZONE_PREFIX_RACE")) { l_iCount++; Format(l_cMenuContent, sizeof(l_cMenuContent), "Stage: %i", l_iCount); StageMenu.AddItem("", l_cMenuContent); } } } StageMenu.ExitButton = true; StageMenu.Display(client, 0); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public bool IsCorrectZone(int index, char[] zoneIndexName, char[] zone_prefix) { ZoneNameBasedOnIndex(index, zoneIndexName); if (StrContains(zoneIndexName, zone_prefix) > -1) { return true; } return false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int Stage_menu(Menu menu, MenuAction action, int client, int selection) { if (action == MenuAction_Select && IsValidClient(client)) { selection++; if (!g_iClientChecking[client]) { CheckTop(client, selection, 1); } else { CheckStageSelf(client, selection); } } else if (action == MenuAction_End) { delete(menu); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action cmd_timerCheckSelf(int client, int args) { Checkself(client); return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void deleteClientTime(char[] steam2, int stage) { char l_cQuery[g_dLength]; if (stage > 1) { Format(l_cQuery, sizeof(l_cQuery), "UPDATE `zetimer_table` SET `%sS%i` = 0.000 WHERE steam_auth = '%s'", g_cMapname, stage, steam2); } else { Format(l_cQuery, sizeof(l_cQuery), "UPDATE `zetimer_table` SET `%s` = 0.000 WHERE steam_auth = '%s'", g_cMapname, steam2); SQL_TQuery(g_dDatabase, DummyCallbackSimple, l_cQuery); Format(l_cQuery, sizeof(l_cQuery), "UPDATE `zetimer_table` SET `%sS1` = 0.000 WHERE steam_auth = '%s'", g_cMapname, steam2); } SQL_TQuery(g_dDatabase, DummyCallbackSimple, l_cQuery); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void Checkself(int client) { int l_iZoneCount = unloze_zoneCount(); char l_cQuery[g_dLength]; char l_cSID[g_dIndex]; GetClientAuthId(client, AuthId_Steam2, l_cSID, sizeof(l_cSID)); if (l_iZoneCount < 1) { PrintToChat(client, "No zones active on this map"); return; } if (l_iZoneCount < 2) { Format(l_cQuery, sizeof(l_cQuery), "SELECT name, `%s` FROM `zetimer_table` WHERE steam_auth = '%s'", g_cMapname, l_cSID); SQL_TQuery(g_dDatabase, TqueryCheckSelf, l_cQuery, GetClientUserId(client)); } else { CheckStagesOnMap(client, 1); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void CheckStageSelf(int client, int selection) { char l_cQuery[g_dLength]; char l_cSID[g_dIndex]; GetClientAuthId(client, AuthId_Steam2, l_cSID, sizeof(l_cSID)); Format(l_cQuery, sizeof(l_cQuery), "SELECT name, `%sS%i` FROM `zetimer_table` WHERE steam_auth = '%s'", g_cMapname, selection, l_cSID); SQL_TQuery(g_dDatabase, TqueryCheckSelf, l_cQuery, GetClientUserId(client)); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void TqueryCheckSelf(Handle db, Handle rs, const char[] error, any data) { int l_iMinutes; float l_fRecord; float l_iSeconds; char l_cMessageContent[g_dLength]; char[] l_cPlayerName = new char[MAX_NAME_LENGTH]; int iclient; if ((iclient = GetClientOfUserId(data)) == 0) return; if (SQL_GetRowCount(rs) > 0 && SQL_FetchRow(rs)) { SQL_FetchString(rs, 0, l_cPlayerName, MAX_NAME_LENGTH); l_fRecord = SQL_FetchFloat(rs, 1); if (l_fRecord == 0.000) { CPrintToChat(iclient, "You have no time yet!"); return; } l_iMinutes = RoundToFloor(l_fRecord); l_iSeconds = (l_fRecord - l_iMinutes) * 100; Format(l_cMessageContent, sizeof(l_cMessageContent), "%i:%.4f - %s", l_iMinutes, l_iSeconds, l_cPlayerName); CPrintToChat(iclient, "Your best time: 0%s", l_cMessageContent); } else CPrintToChat(iclient, "You have no time yet!"); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- stock bool IsValidClient(int client) { if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) { return true; } return false; }