#pragma semicolon 1 #pragma newdecls required #include #include #include #include #define DATA_CONFIG_PATH "addons/sourcemod/configs/jump_king_records.cfg" #define SKIN_FOR_TOP "models/microrost/player_solaire1.mdl" #define CROWN "models/microrost/jumpking/star.mdl" #define Entity_GetTargetName(%1,%2,%3) GetEntPropString(%1, Prop_Data, "m_iName", %2, %3) #define RECORD_LIMIT 20 #define MAX_TOP_PLAYERS 4 #define MAX_DISPLAY 4 public Plugin myinfo = { name = "[MAP] Jump King Plus", author = "Kotya", version = "0.1.0" }; char g_szString[256]; float g_fRoundStart; enum struct class_record { char szName[128]; char szSteam[32]; float fTime; } enum struct class_cookie { Cookie PassMain; } enum struct class_player { int iDisplayID; bool bPassMain; bool bTop; } class_cookie g_Cookie; class_player g_PlayerData[MAXPLAYERS+1]; ArrayList g_alRecords; ArrayList g_alSteamAcces; class_record g_rLastRun; Handle g_hTimerSkin; float g_fRecord; bool g_bAddRecord; bool g_bDisplay; bool g_bRecord; bool g_bEnding; public void OnPluginStart() { g_hTimerSkin = INVALID_HANDLE; g_alSteamAcces = new ArrayList(ByteCountToCells(32)); g_alRecords = new ArrayList(sizeof(class_record)); // Cookie g_Cookie.PassMain = RegClientCookie("jump_king_plus_passmain", "Jump King beat map", CookieAccess_Private); // Commands RegAdminCmd("sm_af_remove", Command_Remove, ADMFLAG_BAN); // Hooks HookEvent("round_freeze_end", Event_FreezeEnd); HookEvent("round_end", Event_RoundEnd); HookEvent("round_start", Event_RoundStart); for (int iClient = 1; iClient <= MaxClients; iClient++) { if (AreClientCookiesCached(iClient)) { OnClientCookiesCached(iClient); } else { OnClientDisconnect(iClient); } } } public void OnClientCookiesCached(int iClient) { if (IsFakeClient(iClient)) { return; } GetClientCookie(iClient, g_Cookie.PassMain, g_szString, sizeof(g_szString)); g_PlayerData[iClient].bPassMain = false; if (g_szString[0] != '\0') { g_PlayerData[iClient].bPassMain = view_as(StringToInt(g_szString)); } g_PlayerData[iClient].bTop = false; if (g_alSteamAcces.Length > 0) { GetClientAuthId(iClient, AuthId_Steam2, g_szString, sizeof(g_szString)); int ID = g_alSteamAcces.FindString(g_szString); if (ID != -1) { g_PlayerData[iClient].bTop = true; g_alSteamAcces.Erase(ID); } } } public void OnClientDisconnect(int iClient) { g_PlayerData[iClient].iDisplayID = 0; g_PlayerData[iClient].bPassMain = false; g_PlayerData[iClient].bTop = false; } public void Event_FreezeEnd(Event hEvent, const char[] sEvName, bool bDontBroadcast) { if (g_alRecords.Length > 0) { class_record Record; g_alRecords.GetArray(0, Record, sizeof(Record)); g_fRecord = Record.fTime; int iM = RoundToFloor(g_fRecord / 60); int iS = RoundToFloor(g_fRecord - (iM * 60)); char szD[4]; FormatEx(g_szString, sizeof(g_szString), "%.3f", (g_fRecord - RoundToFloor(g_fRecord))); strcopy(szD, sizeof(szD), g_szString[2]); CPrintToChatAll(" {default}[{red}MAP{default}] {green}%s{default} {{purple}%s{default}} map record: {orange}%i:%i:%s", Record.szName, Record.szSteam, iM, iS, szD); } } public void Event_RoundEnd(Event hEvent, const char[] sEvName, bool bDontBroadcast) { if (g_bEnding) { for (int iClient = 1; iClient <= MaxClients; iClient++) { if (!IsClientInGame(iClient) || IsFakeClient(iClient) || !IsPlayerAlive(iClient) || GetClientTeam(iClient) != 3) { continue; } g_PlayerData[iClient].bPassMain = true; SetClientCookie(iClient, g_Cookie.PassMain, "1"); } } Reset(); } public void Event_RoundStart(Event hEvent, const char[] sEvName, bool bDontBroadcast) { if (g_bAddRecord) { TryInsert(g_rLastRun); g_bAddRecord = false; } if (g_alRecords.Length > 0) { g_alSteamAcces.Clear(); class_record Record; for (int i = 0; i < g_alRecords.Length; i++) { if (i >= MAX_TOP_PLAYERS) { break; } g_alRecords.GetArray(i, Record, sizeof(Record)); g_alSteamAcces.PushString(Record.szSteam); } for (int iClient = 1, ID; iClient <= MaxClients; iClient++) { if (!IsClientInGame(iClient) || IsFakeClient(iClient)) { continue; } g_PlayerData[iClient].iDisplayID = 0; g_PlayerData[iClient].bTop = false; if (g_alSteamAcces.Length > 0) { GetClientAuthId(iClient, AuthId_Steam2, g_szString, sizeof(g_szString)); ID = g_alSteamAcces.FindString(g_szString); if (ID != -1) { g_PlayerData[iClient].bTop = true; g_alSteamAcces.Erase(ID); } } } if (g_hTimerSkin != INVALID_HANDLE) { KillTimer(g_hTimerSkin); } g_hTimerSkin = CreateTimer(34.0, Timer_SetSkin); } Reset(); } public Action Timer_SetSkin(Handle hTimer) { g_hTimerSkin = INVALID_HANDLE; for (int iClient = 1; iClient <= MaxClients; iClient++) { if (!IsClientInGame(iClient) || IsFakeClient(iClient) || !IsPlayerAlive(iClient) || GetClientTeam(iClient) != 3) { continue; } if (g_PlayerData[iClient].bTop) { SetEntityModel(iClient, SKIN_FOR_TOP); } if (g_PlayerData[iClient].bPassMain) { SetCrown(iClient); } } return Plugin_Handled; } public void SetCrown(int iClient) { float vecPos[3]; int iEntity = CreateEntityByName("prop_dynamic"); if (iEntity) { DispatchKeyValue(iEntity, "model", CROWN); // DispatchKeyValue(iEntity, "rendermode", "1"); // DispatchKeyValue(iEntity, "renderamt", "192"); DispatchKeyValue(iEntity, "disableshadows", "1"); DispatchKeyValue(iEntity, "disableflashlight", "1"); if (DispatchSpawn(iEntity)) { GetClientAbsOrigin(iClient, vecPos); vecPos[2] += 73.0; TeleportEntity(iEntity, vecPos); SetVariantString("!activator"); AcceptEntityInput(iEntity, "SetParent", iClient, iEntity, 0); } } int iEntity1 = CreateEntityByName("env_spritetrail"); if (iEntity1) { DispatchKeyValue(iEntity1, "rendermode", "5"); DispatchKeyValue(iEntity1, "spritename", "sprites/physbeam.vmt"); DispatchKeyValue(iEntity1, "startwidth", "16"); DispatchKeyValue(iEntity1, "rendercolor", "255 223 0"); DispatchKeyValue(iEntity1, "lifetime", "40"); if (DispatchSpawn(iEntity1)) { GetClientAbsOrigin(iClient, vecPos); vecPos[2] += 24.0; TeleportEntity(iEntity1, vecPos); SetVariantString("!activator"); AcceptEntityInput(iEntity1, "SetParent", iClient, iEntity1, 0); SetVariantString("OnUser1 !self,SetScale,1.0,2.0,1"); AcceptEntityInput(iEntity1, "AddOutPut"); AcceptEntityInput(iEntity1, "FireUser1"); } } } public void Reset() { g_bDisplay = false; g_bEnding = false; } public void OnMapEnd() { Save_Config(); if (g_hTimerSkin != INVALID_HANDLE) { KillTimer(g_hTimerSkin); } g_hTimerSkin = INVALID_HANDLE; } public void OnMapStart() { GetCurrentMap(g_szString, sizeof(g_szString)); if (StrContains(g_szString, "ze_jump_king") == -1) { GetPluginFilename(INVALID_HANDLE, g_szString, sizeof(g_szString)); return; } g_alRecords.Clear(); KeyValues kv = new KeyValues(""); if (FileExists(DATA_CONFIG_PATH) && kv.ImportFromFile(DATA_CONFIG_PATH) && kv.GotoFirstSubKey()) // Has Config { int iCount = 0; class_record Record; do { kv.GetString("name", Record.szName, sizeof(Record.szName)); kv.GetString("steam", Record.szSteam, sizeof(Record.szSteam)); Record.fTime = kv.GetFloat("time", 5000.000); g_alRecords.PushArray(Record, sizeof(Record)); iCount++; } while (kv.GotoNextKey() && RECORD_LIMIT > iCount); } delete kv; PrecacheModel(SKIN_FOR_TOP); PrecacheModel(CROWN); } public void TryInsert(class_record newRecord) { bool bSave = false; int Index = -1; class_record Record; for (int i = 0; i < g_alRecords.Length; i++) { g_alRecords.GetArray(i, Record, sizeof(Record)); if (!strcmp(newRecord.szSteam, Record.szSteam)) { if (Record.fTime > newRecord.fTime) { g_alRecords.Erase(i); } else { return; } break; } } for (int i = 0; i < g_alRecords.Length; i++) { g_alRecords.GetArray(i, Record, sizeof(Record)); if (Record.fTime > newRecord.fTime) { Index = i; break; } } if (g_alRecords.Length < RECORD_LIMIT) { bSave = true; g_alRecords.PushArray(newRecord, sizeof(newRecord)); } if (Index != -1) { for (int i = g_alRecords.Length - 2; i >= Index; i--) { g_alRecords.GetArray(i, Record, sizeof(Record)); g_alRecords.SetArray(i + 1, Record, sizeof(Record)); } g_alRecords.SetArray(Index, newRecord, sizeof(newRecord)); } if (bSave) { Save_Config(); } } public void Save_Config() { KeyValues kv = new KeyValues("Data"); class_record Record; for (int i = 0; i < g_alRecords.Length; i++) { FormatEx(g_szString, sizeof(g_szString), "%i", i); kv.JumpToKey(g_szString, true); g_alRecords.GetArray(i, Record, sizeof(Record)); kv.SetString("name", Record.szName); kv.SetString("steam", Record.szSteam); FormatEx(g_szString, sizeof(g_szString), "%.3f", Record.fTime); kv.SetString("time", g_szString); kv.GoBack(); } kv.ExportToFile(DATA_CONFIG_PATH); delete kv; } public void OnGameFrame() { if (!g_bDisplay) { return; } float fTottal; if (g_bEnding) { fTottal = g_rLastRun.fTime; } else { fTottal = GetGameTime() - g_fRoundStart; } g_bRecord = (fTottal < g_fRecord); int iM = RoundToFloor(fTottal / 60); int iS = RoundToFloor(fTottal - (iM * 60)); char szD[4]; FormatEx(g_szString, sizeof(g_szString), "%.3f", (fTottal - RoundToFloor(fTottal))); strcopy(szD, sizeof(szD), g_szString[2]); int iColor[3] = {255, 255, 255}; if (g_alRecords.Length > 0) { if (g_bRecord) { FormatEx(g_szString, sizeof(g_szString), "%i:%i:%s -%.3f", iM, iS, szD, (g_fRecord - fTottal)); iColor = {255, 215, 0}; } else { FormatEx(g_szString, sizeof(g_szString), "%i:%i:%s +%.3f", iM, iS, szD, (fTottal - g_fRecord)); if (fTottal - g_fRecord < 20.0) { iColor = {0, 255, 0}; } else { iColor = {255, 0, 0}; } } } else { FormatEx(g_szString, sizeof(g_szString), "%i:%i:%s", iM, iS, szD); iColor = {255, 215, 0}; } SetHudTextParams(-1.0, 0.15, 1.5, iColor[0], iColor[1], iColor[2], 0, 0, 0.25, 0.0, 0.0); for (int iClient = 1; iClient <= MaxClients; iClient++) { if (IsClientInGame(iClient)) { ShowHudText(iClient, 1, g_szString); } } } public Action Command_Remove(int iClient, int iArgs) { // Hook_EndTimer("123", 0, iClient, 0.00); // return Plugin_Handled; GetCmdArgString(g_szString, sizeof(g_szString)); class_record Record; for (int i = 0; i < g_alRecords.Length; i++) { g_alRecords.GetArray(i, Record, sizeof(Record)); if (!strcmp(Record.szSteam, g_szString)) { g_alRecords.Erase(i); Save_Config(); break; } } return Plugin_Handled; } public void OnEntityCreated(int iEntity, const char[] szClassName) { if (!strcmp(szClassName, "trigger_once") || !strcmp(szClassName, "trigger_multiple") || !strcmp(szClassName, "logic_relay")) { SDKHook(iEntity, SDKHook_SpawnPost, Hook_SpawnPost); } } public void Hook_SpawnPost(int iEntity) { SDKUnhook(iEntity, SDKHook_SpawnPost, Hook_SpawnPost); if (!IsValidEntity(iEntity)) { return; } Entity_GetTargetName(iEntity, g_szString, sizeof(g_szString)); if (g_szString[0] == '\0') { return; } if (!strcmp(g_szString, "speedrun_timer_start")) { HookSingleEntityOutput(iEntity, "OnStartTouch", Hook_StartTimer, true); } else if (!strcmp(g_szString, "speedrun_stop_timer")) { HookSingleEntityOutput(iEntity, "OnTrigger", Hook_EndTimer, true); } else if (!strcmp(g_szString, "nigger")) { HookSingleEntityOutput(iEntity, "OnStartTouch", Hook_ShowTop); } } public void Hook_ShowTop(const char[] szOutput, int iCaller, int iClient, float fDelay) { SetHudTextParams(-1.0, 0.6, 4.0, 0, 255, 255, 0, 0, 0.25, 0.0, 0.0); if (g_alRecords.Length < 1) { ShowHudText(iClient, 1, "No records"); return; } class_record Record; char szString[512]; int iM; int iS; char szD[4]; int iStart = g_PlayerData[iClient].iDisplayID * MAX_DISPLAY; int iEnd = iStart + MAX_DISPLAY; if (iEnd > g_alRecords.Length) { iEnd = g_alRecords.Length; } bool bFind; for (int i = iStart; i < iEnd; i++) { g_alRecords.GetArray(i, Record, sizeof(Record)); GetClientAuthId(iClient, AuthId_Steam2, g_szString, sizeof(g_szString)); bFind = (!strcmp(g_szString, Record.szSteam)); iM = RoundToFloor(Record.fTime / 60); iS = RoundToFloor(Record.fTime - (iM * 60)); FormatEx(g_szString, sizeof(g_szString), "%.3f", (Record.fTime - RoundToFloor(Record.fTime))); strcopy(szD, sizeof(szD), g_szString[2]); if (bFind) { Format(szString, sizeof(szString), "%s>>> %i. %s {%s} - %im %is %sms <<<", szString, i+1, Record.szName, Record.szSteam[6], iM, iS, szD); } else { Format(szString, sizeof(szString), "%s%i. %s {%s} - %im %is %sms", szString, i+1, Record.szName, Record.szSteam[6], iM, iS, szD); } if (i + 1 < iEnd) { StrCat(szString, sizeof(szString), "\n"); } } ShowHudText(iClient, 1, szString); g_PlayerData[iClient].iDisplayID++; if (g_PlayerData[iClient].iDisplayID >= RoundToCeil(float(g_alRecords.Length) / MAX_TOP_PLAYERS)) { g_PlayerData[iClient].iDisplayID = 0; } } public void Hook_StartTimer(const char[] szOutput, int iCaller, int iActivator, float fDelay) { g_fRoundStart = GetGameTime(); g_bDisplay = true; } public void Hook_EndTimer(const char[] szOutput, int iCaller, int iClient, float fDelay) { g_bEnding = true; g_bAddRecord = true; char szSteam[32]; GetClientAuthId(iClient, AuthId_Steam2, szSteam, sizeof(szSteam)); FormatEx(g_rLastRun.szName, sizeof(g_rLastRun.szName), "%N", iClient); FormatEx(g_rLastRun.szSteam, sizeof(g_rLastRun.szSteam), szSteam); g_rLastRun.fTime = GetGameTime() - g_fRoundStart; g_bRecord = (g_rLastRun.fTime < g_fRecord); int iM = RoundToFloor(g_rLastRun.fTime / 60); int iS = RoundToFloor(g_rLastRun.fTime - (iM * 60)); char szD[4]; FormatEx(g_szString, sizeof(g_szString), "%.3f", (g_rLastRun.fTime - RoundToFloor(g_rLastRun.fTime))); strcopy(szD, sizeof(szD), g_szString[2]); if (g_alRecords.Length > 0) { if (g_bRecord) { FormatEx(g_szString, sizeof(g_szString), " {default}[{red}MAP{default}] {green}%N{default} {{purple}%s{default}} new record map: {orange}%i:%i:%s {green}-%.3f", iClient, szSteam, iM, iS, szD, (g_fRecord - g_rLastRun.fTime)); } else { FormatEx(g_szString, sizeof(g_szString), " {default}[{red}MAP{default}] {green}%N{default} {{purple}%s{default}} complete map: %i:%i:%s {red}+%.3f", iClient, szSteam, iM, iS, szD, (g_rLastRun.fTime - g_fRecord)); } } else { FormatEx(g_szString, sizeof(g_szString), " {default}[{red}MAP{default}] {green}%N{default} {{purple}%s{default}} new record map: {orange}%i:%i:%s", iClient, szSteam, iM, iS, szD); } CPrintToChatAll(g_szString); }