diff --git a/ze_jump_king/jump_king_plus.sp b/ze_jump_king/jump_king_plus.sp new file mode 100644 index 00000000..7629c5f3 --- /dev/null +++ b/ze_jump_king/jump_king_plus.sp @@ -0,0 +1,679 @@ +#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); +}