diff options
Diffstat (limited to 'sourcemod/scripting/gokz-hud')
| -rw-r--r-- | sourcemod/scripting/gokz-hud/commands.sp | 116 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/hide_weapon.sp | 30 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/info_panel.sp | 307 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/menu.sp | 96 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/natives.sp | 33 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/options.sp | 190 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/options_menu.sp | 181 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/racing_text.sp | 167 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/spectate_text.sp | 119 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/speed_text.sp | 141 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/timer_text.sp | 135 | ||||
| -rw-r--r-- | sourcemod/scripting/gokz-hud/tp_menu.sp | 415 |
12 files changed, 1930 insertions, 0 deletions
diff --git a/sourcemod/scripting/gokz-hud/commands.sp b/sourcemod/scripting/gokz-hud/commands.sp new file mode 100644 index 0000000..fc5ed4e --- /dev/null +++ b/sourcemod/scripting/gokz-hud/commands.sp @@ -0,0 +1,116 @@ +void RegisterCommands() +{ + RegConsoleCmd("sm_menu", CommandMenu, "[KZ] Toggle the simple teleport menu."); + RegConsoleCmd("sm_cpmenu", CommandMenu, "[KZ] Toggle the simple teleport menu."); + RegConsoleCmd("sm_adv", CommandToggleAdvancedMenu, "[KZ] Toggle the advanced teleport menu."); + RegConsoleCmd("sm_panel", CommandToggleInfoPanel, "[KZ] Toggle visibility of the centre information panel."); + RegConsoleCmd("sm_timerstyle", CommandToggleTimerStyle, "[KZ] Toggle the style of the timer text."); + RegConsoleCmd("sm_timertype", CommandToggleTimerType, "[KZ] Toggle visibility of your time type."); + RegConsoleCmd("sm_speed", CommandToggleSpeed, "[KZ] Toggle visibility of your speed and jump pre-speed."); + RegConsoleCmd("sm_hideweapon", CommandToggleShowWeapon, "[KZ] Toggle visibility of your weapon."); +} + +public Action CommandMenu(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_TPMenu) != TPMenu_Disabled) + { + GOKZ_HUD_SetOption(client, HUDOption_TPMenu, TPMenu_Disabled); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_TPMenu, TPMenu_Simple); + } + return Plugin_Handled; +} + +public Action CommandToggleAdvancedMenu(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_TPMenu) != TPMenu_Advanced) + { + GOKZ_HUD_SetOption(client, HUDOption_TPMenu, TPMenu_Advanced); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_TPMenu, TPMenu_Simple); + } + return Plugin_Handled; +} + +public Action CommandToggleInfoPanel(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_InfoPanel) == InfoPanel_Disabled) + { + GOKZ_HUD_SetOption(client, HUDOption_InfoPanel, InfoPanel_Enabled); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_InfoPanel, InfoPanel_Disabled); + } + return Plugin_Handled; +} + +public Action CommandToggleTimerStyle(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_TimerStyle) == TimerStyle_Standard) + { + GOKZ_HUD_SetOption(client, HUDOption_TimerStyle, TimerStyle_Precise); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_TimerStyle, TimerStyle_Standard); + } + return Plugin_Handled; +} + +public Action CommandToggleTimerType(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_TimerType) == TimerType_Disabled) + { + GOKZ_HUD_SetOption(client, HUDOption_TimerType, TimerType_Enabled); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_TimerType, TimerType_Disabled); + } + return Plugin_Handled; +} + +public Action CommandToggleSpeed(int client, int args) +{ + int speedText = GOKZ_HUD_GetOption(client, HUDOption_SpeedText); + int infoPanel = GOKZ_HUD_GetOption(client, HUDOption_InfoPanel); + + if (speedText == SpeedText_Disabled) + { + if (infoPanel == InfoPanel_Enabled) + { + GOKZ_HUD_SetOption(client, HUDOption_SpeedText, SpeedText_InfoPanel); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_SpeedText, SpeedText_Bottom); + } + } + else if (infoPanel == InfoPanel_Disabled && speedText == SpeedText_InfoPanel) + { + GOKZ_HUD_SetOption(client, HUDOption_SpeedText, SpeedText_Bottom); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_SpeedText, SpeedText_Disabled); + } + return Plugin_Handled; +} + +public Action CommandToggleShowWeapon(int client, int args) +{ + if (GOKZ_HUD_GetOption(client, HUDOption_ShowWeapon) == ShowWeapon_Disabled) + { + GOKZ_HUD_SetOption(client, HUDOption_ShowWeapon, ShowWeapon_Enabled); + } + else + { + GOKZ_HUD_SetOption(client, HUDOption_ShowWeapon, ShowWeapon_Disabled); + } + return Plugin_Handled; +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/hide_weapon.sp b/sourcemod/scripting/gokz-hud/hide_weapon.sp new file mode 100644 index 0000000..b290d8f --- /dev/null +++ b/sourcemod/scripting/gokz-hud/hide_weapon.sp @@ -0,0 +1,30 @@ +/* + Hides weapon view model. +*/ + + + +// =====[ EVENTS ]===== + +void OnPlayerSpawn_HideWeapon(int client) +{ + UpdateHideWeapon(client); +} + +void OnOptionChanged_HideWeapon(int client, HUDOption option) +{ + if (option == HUDOption_ShowWeapon) + { + UpdateHideWeapon(client); + } +} + + + +// =====[ PRIVATE ]===== + +static void UpdateHideWeapon(int client) +{ + SetEntProp(client, Prop_Send, "m_bDrawViewmodel", + GOKZ_HUD_GetOption(client, HUDOption_ShowWeapon) == ShowWeapon_Enabled); +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/info_panel.sp b/sourcemod/scripting/gokz-hud/info_panel.sp new file mode 100644 index 0000000..3563404 --- /dev/null +++ b/sourcemod/scripting/gokz-hud/info_panel.sp @@ -0,0 +1,307 @@ +/* + Displays information using hint text. + + This is manually refreshed whenever player has taken off so that they see + their pre-speed as soon as possible, improving responsiveness. +*/ + + + +static bool infoPanelDuckPressedLast[MAXPLAYERS + 1]; +static bool infoPanelOnGroundLast[MAXPLAYERS + 1]; +static bool infoPanelShowDuckString[MAXPLAYERS + 1]; + + +// =====[ PUBLIC ]===== + +bool IsDrawingInfoPanel(int client) +{ + KZPlayer player = KZPlayer(client); + return player.InfoPanel != InfoPanel_Disabled + && !NothingEnabledInInfoPanel(player); +} + + + +// =====[ EVENTS ]===== + +void OnPlayerRunCmdPost_InfoPanel(int client, int cmdnum, HUDInfo info) +{ + int updateSpeed = gB_FastUpdateRate[client] ? 1 : 10; + if (cmdnum % updateSpeed == 0 || info.IsTakeoff) + { + UpdateInfoPanel(client, info); + } + infoPanelOnGroundLast[info.ID] = info.OnGround; + infoPanelDuckPressedLast[info.ID] = info.Ducking; +} + + + +// =====[ PRIVATE ]===== + +static void UpdateInfoPanel(int client, HUDInfo info) +{ + KZPlayer player = KZPlayer(client); + + if (player.Fake || !IsDrawingInfoPanel(player.ID)) + { + return; + } + char infoPanelText[512]; + FormatEx(infoPanelText, sizeof(infoPanelText), GetInfoPanel(player, info)); + if (infoPanelText[0] != '\0') + { + PrintCSGOHUDText(player.ID, infoPanelText); + } +} + +static bool NothingEnabledInInfoPanel(KZPlayer player) +{ + bool noTimerText = player.TimerText != TimerText_InfoPanel; + bool noSpeedText = player.SpeedText != SpeedText_InfoPanel || player.Paused; + bool noKeys = player.ShowKeys == ShowKeys_Disabled + || player.ShowKeys == ShowKeys_Spectating && player.Alive; + return noTimerText && noSpeedText && noKeys; +} + +static char[] GetInfoPanel(KZPlayer player, HUDInfo info) +{ + char infoPanelText[512]; + FormatEx(infoPanelText, sizeof(infoPanelText), + "%s%s%s%s", + GetSpectatorString(player, info), + GetTimeString(player, info), + GetSpeedString(player, info), + GetKeysString(player, info)); + if (infoPanelText[0] == '\0') + { + return infoPanelText; + } + else + { + Format(infoPanelText, sizeof(infoPanelText), "<font color='#ffffff08'>%s", infoPanelText); + } + TrimString(infoPanelText); + return infoPanelText; +} + +static char[] GetSpectatorString(KZPlayer player, HUDInfo info) +{ + char spectatorString[255]; + if (player.SpecListPosition != SpecListPosition_InfoPanel || player.ShowSpectators == ShowSpecs_Disabled) + { + return spectatorString; + } + // Only return something if the player is alive or observing someone else + if (player.Alive || player.ObserverTarget != -1) + { + FormatEx(spectatorString, sizeof(spectatorString), "%s", FormatSpectatorTextForInfoPanel(player, KZPlayer(info.ID))); + } + return spectatorString; +} + +static char[] GetTimeString(KZPlayer player, HUDInfo info) +{ + char timeString[128]; + if (player.TimerText != TimerText_InfoPanel) + { + timeString = ""; + } + else if (info.TimerRunning) + { + if (player.GetHUDOption(HUDOption_TimerType) == TimerType_Enabled) + { + switch (info.TimeType) + { + case TimeType_Nub: + { + FormatEx(timeString, sizeof(timeString), + "%T: <font color='#ead18a'>%s</font> %s\n", + "Info Panel Text - Time", player.ID, + GOKZ_HUD_FormatTime(player.ID, info.Time), + GetPausedString(player, info)); + } + case TimeType_Pro: + { + FormatEx(timeString, sizeof(timeString), + "%T: <font color='#b5d4ee'>%s</font> %s\n", + "Info Panel Text - Time", player.ID, + GOKZ_HUD_FormatTime(player.ID, info.Time), + GetPausedString(player, info)); + } + } + } + else + { + FormatEx(timeString, sizeof(timeString), + "%T: <font color='#ffffff'>%s</font> %s\n", + "Info Panel Text - Time", player.ID, + GOKZ_HUD_FormatTime(player.ID, info.Time), + GetPausedString(player, info)); + } + } + else + { + FormatEx(timeString, sizeof(timeString), + "%T: <font color='#ea4141'>%T</font> %s\n", + "Info Panel Text - Time", player.ID, + "Info Panel Text - Stopped", player.ID, + GetPausedString(player, info)); + } + return timeString; +} + +static char[] GetPausedString(KZPlayer player, HUDInfo info) +{ + char pausedString[64]; + if (info.Paused) + { + FormatEx(pausedString, sizeof(pausedString), + "(<font color='#ffffff'>%T</font>)", + "Info Panel Text - PAUSED", player.ID); + } + else + { + pausedString = ""; + } + return pausedString; +} + +static char[] GetSpeedString(KZPlayer player, HUDInfo info) +{ + char speedString[128]; + if (player.SpeedText != SpeedText_InfoPanel || info.Paused) + { + speedString = ""; + } + else + { + if (info.OnGround || info.OnLadder || info.Noclipping) + { + FormatEx(speedString, sizeof(speedString), + "%T: <font color='#ffffff'>%.0f</font> u/s\n", + "Info Panel Text - Speed", player.ID, + RoundToPowerOfTen(info.Speed, -2)); + infoPanelShowDuckString[info.ID] = false; + } + else + { + if (GOKZ_HUD_GetOption(player.ID, HUDOption_DeadstrafeColor) == DeadstrafeColor_Enabled + && Movement_GetVerticalVelocity(info.ID) > 0.0 && Movement_GetVerticalVelocity(info.ID) < 140.0) + { + FormatEx(speedString, sizeof(speedString), + "%T: <font color='#ff2020'>%.0f</font> %s\n", + "Info Panel Text - Speed", player.ID, + RoundToPowerOfTen(info.Speed, -2), + GetTakeoffString(info)); + } + else + { + FormatEx(speedString, sizeof(speedString), + "%T: <font color='#ffffff'>%.0f</font> %s\n", + "Info Panel Text - Speed", player.ID, + RoundToPowerOfTen(info.Speed, -2), + GetTakeoffString(info)); + } + } + } + return speedString; +} + +static char[] GetTakeoffString(HUDInfo info) +{ + char takeoffString[96], duckString[32]; + + if (infoPanelShowDuckString[info.ID] + || (infoPanelOnGroundLast[info.ID] + && !info.HitBhop + && info.IsTakeoff + && info.Jumped + && info.Ducking + && (infoPanelDuckPressedLast[info.ID] || GOKZ_GetCoreOption(info.ID, Option_Mode) == Mode_Vanilla))) + { + duckString = " <font color='#71eeb8'>C</font>"; + infoPanelShowDuckString[info.ID] = true; + } + else + { + duckString = ""; + infoPanelShowDuckString[info.ID] = false; + } + + if (info.HitJB) + { + FormatEx(takeoffString, sizeof(takeoffString), + "(<font color='#ffff20'>%.0f</font>)%s", + RoundToPowerOfTen(info.TakeoffSpeed, -2), + duckString); + } + else if (info.HitPerf) + { + FormatEx(takeoffString, sizeof(takeoffString), + "(<font color='#40ff40'>%.0f</font>)%s", + RoundToPowerOfTen(info.TakeoffSpeed, -2), + duckString); + } + else + { + FormatEx(takeoffString, sizeof(takeoffString), + "(<font color='#ffffff'>%.0f</font>)%s", + RoundToPowerOfTen(info.TakeoffSpeed, -2), + duckString); + } + return takeoffString; +} + +static char[] GetKeysString(KZPlayer player, HUDInfo info) +{ + char keysString[64]; + if (player.ShowKeys == ShowKeys_Disabled) + { + keysString = ""; + } + else if (player.ShowKeys == ShowKeys_Spectating && player.Alive) + { + keysString = ""; + } + else + { + int buttons = info.Buttons; + FormatEx(keysString, sizeof(keysString), + "%T: <font color='#ffffff'>%c %c %c %c %c %c</font>\n", + "Info Panel Text - Keys", player.ID, + buttons & IN_MOVELEFT ? 'A' : '_', + buttons & IN_FORWARD ? 'W' : '_', + buttons & IN_BACK ? 'S' : '_', + buttons & IN_MOVERIGHT ? 'D' : '_', + buttons & IN_DUCK ? 'C' : '_', + buttons & IN_JUMP ? 'J' : '_'); + } + return keysString; +} + +// Credits to Franc1sco (https://github.com/Franc1sco/FixHintColorMessages) +void PrintCSGOHUDText(int client, const char[] format) +{ + char buff[HUD_MAX_HINT_SIZE]; + Format(buff, sizeof(buff), "</font>%s", format); + + for (int i = strlen(buff); i < sizeof(buff) - 1; i++) + { + buff[i] = ' '; + } + + buff[sizeof(buff) - 1] = '\0'; + + Protobuf pb = view_as<Protobuf>(StartMessageOne("TextMsg", client, USERMSG_BLOCKHOOKS)); + pb.SetInt("msg_dst", 4); + pb.AddString("params", "#SFUI_ContractKillStart"); + pb.AddString("params", buff); + pb.AddString("params", NULL_STRING); + pb.AddString("params", NULL_STRING); + pb.AddString("params", NULL_STRING); + pb.AddString("params", NULL_STRING); + + EndMessage(); +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/menu.sp b/sourcemod/scripting/gokz-hud/menu.sp new file mode 100644 index 0000000..4b7259e --- /dev/null +++ b/sourcemod/scripting/gokz-hud/menu.sp @@ -0,0 +1,96 @@ +/* + Tracks whether a GOKZ HUD menu or panel element is being shown to the client. +*/ + + + +// Update the TP menu i.e. item text, item disabled/enabled +void CancelGOKZHUDMenu(int client) +{ + // Only cancel the menu if we know it's the TP menu + if (gB_MenuShowing[client]) + { + CancelClientMenu(client); + } +} + + + +// =====[ EVENTS ]===== + +void OnPlayerSpawn_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnOptionChanged_Menu(int client, HUDOption option) +{ + if (option == HUDOption_TPMenu || option == HUDOption_TimerText) + { + CancelGOKZHUDMenu(client); + } +} + +void OnTimerStart_Menu(int client) +{ + // Prevent the menu from getting cancelled every tick if player use start timer button zone. + if (GOKZ_GetTime(client) > 0.0) + { + CancelGOKZHUDMenu(client); + } +} + +void OnTimerEnd_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnTimerStopped_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnPause_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnResume_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnMakeCheckpoint_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnCountedTeleport_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnJoinTeam_Menu(int client) +{ + CancelGOKZHUDMenu(client); +} + +void OnStartPositionSet_Menu(int client) +{ + // Prevent the menu from getting cancelled every tick if player use start timer button zone. + if (GOKZ_GetTime(client) > 0.0) + { + CancelGOKZHUDMenu(client); + } +} + +void OnPluginEnd_Menu() +{ + for (int client = 1; client <= MaxClients; client++) + { + if (IsValidClient(client)) + { + CancelGOKZHUDMenu(client); + } + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/natives.sp b/sourcemod/scripting/gokz-hud/natives.sp new file mode 100644 index 0000000..bb877e2 --- /dev/null +++ b/sourcemod/scripting/gokz-hud/natives.sp @@ -0,0 +1,33 @@ +void CreateNatives() +{ + CreateNative("GOKZ_HUD_ForceUpdateTPMenu", Native_ForceUpdateTPMenu); + CreateNative("GOKZ_HUD_GetMenuShowing", Native_GetMenuShowing); + CreateNative("GOKZ_HUD_SetMenuShowing", Native_SetMenuShowing); + CreateNative("GOKZ_HUD_GetMenuSpectatorText", Native_GetSpectatorText); +} + +public int Native_ForceUpdateTPMenu(Handle plugin, int numParams) +{ + SetForceUpdateTPMenu(GetNativeCell(1)); + return 0; +} + +public int Native_GetMenuShowing(Handle plugin, int numParams) +{ + return view_as<int>(gB_MenuShowing[GetNativeCell(1)]); +} + +public int Native_SetMenuShowing(Handle plugin, int numParams) +{ + gB_MenuShowing[GetNativeCell(1)] = view_as<bool>(GetNativeCell(2)); + return 0; +} + +public int Native_GetSpectatorText(Handle plugin, int numParams) +{ + HUDInfo info; + GetNativeArray(2, info, sizeof(HUDInfo)); + KZPlayer player = KZPlayer(GetNativeCell(1)); + FormatNativeString(3, 0, 0, GetNativeCell(4), _, "", FormatSpectatorTextForMenu(player, info)); + return 0; +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/options.sp b/sourcemod/scripting/gokz-hud/options.sp new file mode 100644 index 0000000..84bbf2b --- /dev/null +++ b/sourcemod/scripting/gokz-hud/options.sp @@ -0,0 +1,190 @@ +/* + Options for controlling appearance and behaviour of HUD and UI. +*/ + + + +// =====[ EVENTS ]===== + +void OnOptionsMenuReady_Options() +{ + RegisterOptions(); +} + +void OnOptionChanged_Options(int client, HUDOption option, any newValue) +{ + PrintOptionChangeMessage(client, option, newValue); +} + + + +// =====[ PRIVATE ]===== + +static void RegisterOptions() +{ + for (HUDOption option; option < HUDOPTION_COUNT; option++) + { + GOKZ_RegisterOption(gC_HUDOptionNames[option], gC_HUDOptionDescriptions[option], + OptionType_Int, gI_HUDOptionDefaults[option], 0, gI_HUDOptionCounts[option] - 1); + } +} + +static void PrintOptionChangeMessage(int client, HUDOption option, any newValue) +{ + // NOTE: Not all options have a message for when they are changed. + switch (option) + { + case HUDOption_TPMenu: + { + switch (newValue) + { + case TPMenu_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Teleport Menu - Disable"); + } + case TPMenu_Simple: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Teleport Menu - Enable (Simple)"); + } + case TPMenu_Advanced: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Teleport Menu - Enable (Advanced)"); + } + } + } + case HUDOption_InfoPanel: + { + switch (newValue) + { + case InfoPanel_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Info Panel - Disable"); + } + case InfoPanel_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Info Panel - Enable"); + } + } + } + case HUDOption_TimerStyle: + { + switch (newValue) + { + case TimerStyle_Standard: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Timer Style - Standard"); + } + case TimerStyle_Precise: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Timer Style - Precise"); + } + } + } + case HUDOption_TimerType: + { + switch (newValue) + { + case TimerType_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Timer Type - Disabled"); + } + case TimerType_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Timer Type - Enabled"); + } + } + } + case HUDOption_ShowWeapon: + { + switch (newValue) + { + case ShowWeapon_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Weapon - Disable"); + } + case ShowWeapon_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Weapon - Enable"); + } + } + } + case HUDOption_ShowControls: + { + switch (newValue) + { + case ReplayControls_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Controls - Disable"); + } + case ReplayControls_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Controls - Enable"); + } + } + } + case HUDOption_DeadstrafeColor: + { + switch (newValue) + { + case DeadstrafeColor_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Dead Strafe - Disable"); + } + case DeadstrafeColor_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Dead Strafe - Enable"); + } + } + } + case HUDOption_ShowSpectators: + { + switch (newValue) + { + case ShowSpecs_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Spectators - Disable"); + } + case ShowSpecs_Number: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Spectators - Number"); + } + case ShowSpecs_Full: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Show Spectators - Full"); + } + } + } + case HUDOption_SpecListPosition: + { + switch (newValue) + { + case SpecListPosition_InfoPanel: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Spectator List Position - Info Panel"); + } + case SpecListPosition_TPMenu: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Spectator List Position - TP Menu"); + } + } + } + case HUDOption_DynamicMenu: + { + switch (newValue) + { + case DynamicMenu_Legacy: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Dynamic Menu - Legacy"); + } + case DynamicMenu_Disabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Dynamic Menu - Disable"); + } + case DynamicMenu_Enabled: + { + GOKZ_PrintToChat(client, true, "%t", "Option - Dynamic Menu - Enable"); + } + } + } + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/options_menu.sp b/sourcemod/scripting/gokz-hud/options_menu.sp new file mode 100644 index 0000000..705df27 --- /dev/null +++ b/sourcemod/scripting/gokz-hud/options_menu.sp @@ -0,0 +1,181 @@ +static TopMenu optionsTopMenu; +static TopMenuObject catHUD; +static TopMenuObject itemsHUD[HUDOPTION_COUNT]; + + + +// =====[ EVENTS ]===== + +void OnOptionsMenuCreated_OptionsMenu(TopMenu topMenu) +{ + if (optionsTopMenu == topMenu && catHUD != INVALID_TOPMENUOBJECT) + { + return; + } + + catHUD = topMenu.AddCategory(HUD_OPTION_CATEGORY, TopMenuHandler_Categories); +} + +void OnOptionsMenuReady_OptionsMenu(TopMenu topMenu) +{ + // Make sure category exists + if (catHUD == INVALID_TOPMENUOBJECT) + { + GOKZ_OnOptionsMenuCreated(topMenu); + } + + if (optionsTopMenu == topMenu) + { + return; + } + + optionsTopMenu = topMenu; + + // Add HUD option items + for (int option = 0; option < view_as<int>(HUDOPTION_COUNT); option++) + { + itemsHUD[option] = optionsTopMenu.AddItem(gC_HUDOptionNames[option], TopMenuHandler_HUD, catHUD); + } +} + +public void TopMenuHandler_Categories(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) +{ + if (action == TopMenuAction_DisplayOption || action == TopMenuAction_DisplayTitle) + { + if (topobj_id == catHUD) + { + Format(buffer, maxlength, "%T", "Options Menu - HUD", param); + } + } +} + +public void TopMenuHandler_HUD(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) +{ + HUDOption option = HUDOPTION_INVALID; + for (int i = 0; i < view_as<int>(HUDOPTION_COUNT); i++) + { + if (topobj_id == itemsHUD[i]) + { + option = view_as<HUDOption>(i); + break; + } + } + + if (option == HUDOPTION_INVALID) + { + return; + } + + if (action == TopMenuAction_DisplayOption) + { + switch (option) + { + case HUDOption_TPMenu: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_TPMenuPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_ShowKeys: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_ShowKeysPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_TimerText: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_TimerTextPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_TimerStyle: + { + int optionValue = GOKZ_HUD_GetOption(param, option); + if (optionValue == TimerStyle_Precise) + { + FormatEx(buffer, maxlength, "%T - 01:23.45", + gC_HUDOptionPhrases[option], param); + } + else + { + FormatEx(buffer, maxlength, "%T - 1:23", + gC_HUDOptionPhrases[option], param); + } + } + case HUDOption_TimerType: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_TimerTypePhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_SpeedText: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_SpeedTextPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_ShowControls: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_ShowControlsPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_DeadstrafeColor: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_DeadstrafeColorPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_UpdateRate: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_HUDUpdateRatePhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_ShowSpectators: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_ShowSpecsPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_SpecListPosition: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_SpecListPositionPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + case HUDOption_DynamicMenu: + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], param, + gC_DynamicMenuPhrases[GOKZ_HUD_GetOption(param, option)], param); + } + default:FormatToggleableOptionDisplay(param, option, buffer, maxlength); + } + } + else if (action == TopMenuAction_SelectOption) + { + GOKZ_HUD_CycleOption(param, option); + optionsTopMenu.Display(param, TopMenuPosition_LastCategory); + } +} + + + +// =====[ PRIVATE ]===== + +static void FormatToggleableOptionDisplay(int client, HUDOption option, char[] buffer, int maxlength) +{ + if (GOKZ_HUD_GetOption(client, option) == 0) + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], client, + "Options Menu - Disabled", client); + } + else + { + FormatEx(buffer, maxlength, "%T - %T", + gC_HUDOptionPhrases[option], client, + "Options Menu - Enabled", client); + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/racing_text.sp b/sourcemod/scripting/gokz-hud/racing_text.sp new file mode 100644 index 0000000..ac6ea3d --- /dev/null +++ b/sourcemod/scripting/gokz-hud/racing_text.sp @@ -0,0 +1,167 @@ +/* + Uses HUD text to show the race countdown and a start message. + + This is manually refreshed when a race starts to show the start message as + soon as possible, improving responsiveness. +*/ + + + +static Handle racingHudSynchronizer; +static float countdownStartTime[MAXPLAYERS + 1]; + + + +// =====[ EVENTS ]===== + +void OnPluginStart_RacingText() +{ + racingHudSynchronizer = CreateHudSynchronizer(); +} + +void OnPlayerRunCmdPost_RacingText(int client, int cmdnum) +{ + int updateSpeed = gB_FastUpdateRate[client] ? 3 : 6; + if (gB_GOKZRacing && cmdnum % updateSpeed == 2) + { + UpdateRacingText(client); + } +} + +void OnRaceInfoChanged_RacingText(int raceID, RaceInfo prop, int newValue) +{ + if (prop != RaceInfo_Status) + { + return; + } + + if (newValue == RaceStatus_Countdown) + { + for (int client = 1; client <= MaxClients; client++) + { + if (GOKZ_RC_GetRaceID(client) == raceID) + { + countdownStartTime[client] = GetGameTime(); + } + } + } + else if (newValue == RaceStatus_Aborting) + { + for (int client = 1; client <= MaxClients; client++) + { + if (GOKZ_RC_GetRaceID(client) == raceID) + { + ClearRacingText(client); + } + } + } + else if (newValue == RaceStatus_Started) + { + for (int client = 1; client <= MaxClients; client++) + { + if (GOKZ_RC_GetRaceID(client) == raceID) + { + UpdateRacingText(client); + } + } + } +} + + + +// =====[ PRIVATE ]===== + +static void UpdateRacingText(int client) +{ + KZPlayer player = KZPlayer(client); + + if (player.Fake) + { + return; + } + + if (player.Alive) + { + ShowRacingText(player, player); + } + else + { + KZPlayer targetPlayer = KZPlayer(player.ObserverTarget); + if (targetPlayer.ID != -1 && !targetPlayer.Fake) + { + ShowRacingText(player, targetPlayer); + } + } +} + +static void ClearRacingText(int client) +{ + ClearSyncHud(client, racingHudSynchronizer); +} + +static void ShowRacingText(KZPlayer player, KZPlayer targetPlayer) +{ + if (GOKZ_RC_GetStatus(targetPlayer.ID) != RacerStatus_Racing) + { + return; + } + + int raceStatus = GOKZ_RC_GetRaceInfo(GOKZ_RC_GetRaceID(targetPlayer.ID), RaceInfo_Status); + if (raceStatus == RaceStatus_Countdown) + { + ShowCountdownText(player, targetPlayer); + } + else if (raceStatus == RaceStatus_Started) + { + ShowStartedText(player, targetPlayer); + } +} + +static void ShowCountdownText(KZPlayer player, KZPlayer targetPlayer) +{ + float timeToStart = (countdownStartTime[targetPlayer.ID] + RC_COUNTDOWN_TIME) - GetGameTime(); + int colour[4]; + GetCountdownColour(timeToStart, colour); + + SetHudTextParams(-1.0, 0.3, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), colour[0], colour[1], colour[2], colour[3], 0, 1.0, 0.0, 0.0); + ShowSyncHudText(player.ID, racingHudSynchronizer, "%t\n\n%d", "Get Ready", IntMax(RoundToCeil(timeToStart), 1)); +} + +static void GetCountdownColour(float timeToStart, int buffer[4]) +{ + // From red to green + if (timeToStart >= RC_COUNTDOWN_TIME) + { + buffer[0] = 255; + buffer[1] = 0; + } + else if (timeToStart > RC_COUNTDOWN_TIME / 2.0) + { + buffer[0] = 255; + buffer[1] = RoundFloat(-510.0 / RC_COUNTDOWN_TIME * timeToStart + 510.0); + } + else if (timeToStart > 0.0) + { + buffer[0] = RoundFloat(510.0 / RC_COUNTDOWN_TIME * timeToStart); + buffer[1] = 255; + } + else + { + buffer[0] = 0; + buffer[1] = 255; + } + + buffer[2] = 0; + buffer[3] = 255; +} + +static void ShowStartedText(KZPlayer player, KZPlayer targetPlayer) +{ + if (targetPlayer.TimerRunning) + { + return; + } + + SetHudTextParams(-1.0, 0.3, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), 0, 255, 0, 255, 0, 1.0, 0.0, 0.0); + ShowSyncHudText(player.ID, racingHudSynchronizer, "%t", "Go!"); +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/spectate_text.sp b/sourcemod/scripting/gokz-hud/spectate_text.sp new file mode 100644 index 0000000..9700c38 --- /dev/null +++ b/sourcemod/scripting/gokz-hud/spectate_text.sp @@ -0,0 +1,119 @@ +/* + Responsible for spectator list on the HUD. +*/ + +#define SPECATATOR_LIST_MAX_COUNT 5 + +// =====[ PUBLIC ]===== + +char[] FormatSpectatorTextForMenu(KZPlayer player, HUDInfo info) +{ + int specCount; + char spectatorTextString[224]; + if (player.GetHUDOption(HUDOption_ShowSpectators) >= ShowSpecs_Number) + { + for (int i = 1; i <= MaxClients; i++) + { + if (gI_ObserverTarget[i] == info.ID) + { + specCount++; + if (player.GetHUDOption(HUDOption_ShowSpectators) == ShowSpecs_Full) + { + char buffer[64]; + if (specCount < SPECATATOR_LIST_MAX_COUNT) + { + GetClientName(i, buffer, sizeof(buffer)); + Format(spectatorTextString, sizeof(spectatorTextString), "%s\n%s", spectatorTextString, buffer); + } + else if (specCount == SPECATATOR_LIST_MAX_COUNT) + { + StrCat(spectatorTextString, sizeof(spectatorTextString), "\n..."); + } + } + } + } + if (specCount > 0) + { + if (player.GetHUDOption(HUDOption_ShowSpectators) == ShowSpecs_Full) + { + Format(spectatorTextString, sizeof(spectatorTextString), "%t\n ", "Spectator List - Menu (Full)", specCount, spectatorTextString); + } + else + { + Format(spectatorTextString, sizeof(spectatorTextString), "%t\n ", "Spectator List - Menu (Number)", specCount); + } + } + else + { + FormatEx(spectatorTextString, sizeof(spectatorTextString), ""); + } + } + return spectatorTextString; +} + +char[] FormatSpectatorTextForInfoPanel(KZPlayer player, KZPlayer targetPlayer) +{ + int specCount; + char spectatorTextString[160]; + if (player.GetHUDOption(HUDOption_ShowSpectators) >= ShowSpecs_Number) + { + for (int i = 1; i <= MaxClients; i++) + { + if (gI_ObserverTarget[i] == targetPlayer.ID) + { + specCount++; + if (player.GetHUDOption(HUDOption_ShowSpectators) == ShowSpecs_Full) + { + char buffer[64]; + if (specCount < SPECATATOR_LIST_MAX_COUNT) + { + GetClientName(i, buffer, sizeof(buffer)); + if (specCount == 1) + { + Format(spectatorTextString, sizeof(spectatorTextString), "%s", buffer); + } + else + { + Format(spectatorTextString, sizeof(spectatorTextString), "%s, %s", spectatorTextString, buffer); + } + } + else if (specCount == SPECATATOR_LIST_MAX_COUNT) + { + Format(spectatorTextString, sizeof(spectatorTextString), " ..."); + } + } + } + } + if (specCount > 0) + { + if (player.GetHUDOption(HUDOption_ShowSpectators) == ShowSpecs_Full) + { + Format(spectatorTextString, sizeof(spectatorTextString), "%t\n", "Spectator List - Info Panel (Full)", specCount, spectatorTextString); + } + else + { + Format(spectatorTextString, sizeof(spectatorTextString), "%t\n", "Spectator List - Info Panel (Number)", specCount); + } + } + else + { + FormatEx(spectatorTextString, sizeof(spectatorTextString), ""); + } + } + return spectatorTextString; +} + +void UpdateSpecList() +{ + for (int client = 1; client <= MaxClients; client++) + { + if (IsValidClient(client) && !IsFakeClient(client)) + { + gI_ObserverTarget[client] = GetObserverTarget(client); + } + else + { + gI_ObserverTarget[client] = -1; + } + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/speed_text.sp b/sourcemod/scripting/gokz-hud/speed_text.sp new file mode 100644 index 0000000..3f83949 --- /dev/null +++ b/sourcemod/scripting/gokz-hud/speed_text.sp @@ -0,0 +1,141 @@ +/* + Uses HUD text to show current speed somewhere on the screen. + + This is manually refreshed whenever player has taken off so that they see + their pre-speed as soon as possible, improving responsiveness. +*/ + + + +static Handle speedHudSynchronizer; + +static bool speedTextDuckPressedLast[MAXPLAYERS + 1]; +static bool speedTextOnGroundLast[MAXPLAYERS + 1]; +static bool speedTextShowDuckString[MAXPLAYERS + 1]; + + + +// =====[ EVENTS ]===== + +void OnPluginStart_SpeedText() +{ + speedHudSynchronizer = CreateHudSynchronizer(); +} + +void OnPlayerRunCmdPost_SpeedText(int client, int cmdnum, HUDInfo info) +{ + int updateSpeed = gB_FastUpdateRate[client] ? 3 : 6; + if (cmdnum % updateSpeed == 0 || info.IsTakeoff) + { + UpdateSpeedText(client, info); + } + speedTextOnGroundLast[info.ID] = info.OnGround; + speedTextDuckPressedLast[info.ID] = info.Ducking; +} + +void OnOptionChanged_SpeedText(int client, HUDOption option) +{ + if (option == HUDOption_SpeedText) + { + ClearSpeedText(client); + } +} + + + +// =====[ PRIVATE ]===== + +static void UpdateSpeedText(int client, HUDInfo info) +{ + KZPlayer player = KZPlayer(client); + + if (player.Fake + || player.SpeedText != SpeedText_Bottom) + { + return; + } + + ShowSpeedText(player, info); +} + +static void ClearSpeedText(int client) +{ + ClearSyncHud(client, speedHudSynchronizer); +} + +static void ShowSpeedText(KZPlayer player, HUDInfo info) +{ + if (info.Paused) + { + return; + } + + int colour[4] = { 255, 255, 255, 0 }; // RGBA + float velZ = Movement_GetVerticalVelocity(info.ID); + if (!info.OnGround && !info.OnLadder && !info.Noclipping) + { + if (GOKZ_HUD_GetOption(player.ID, HUDOption_DeadstrafeColor) == DeadstrafeColor_Enabled && velZ > 0.0 && velZ < 140.0) + { + colour = { 255, 32, 32, 0 }; + } + else if (info.HitPerf) + { + if (info.HitJB) + { + colour = { 255, 255, 32, 0 }; + } + else + { + colour = { 64, 255, 64, 0 }; + } + } + } + + switch (player.SpeedText) + { + case SpeedText_Bottom: + { + // Set params based on the available screen space at max scaling HUD + if (!IsDrawingInfoPanel(player.ID)) + { + SetHudTextParams(-1.0, 0.75, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), colour[0], colour[1], colour[2], colour[3], 0, 1.0, 0.0, 0.0); + } + else + { + SetHudTextParams(-1.0, 0.65, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), colour[0], colour[1], colour[2], colour[3], 0, 1.0, 0.0, 0.0); + } + } + } + + if (info.OnGround || info.OnLadder || info.Noclipping) + { + ShowSyncHudText(player.ID, speedHudSynchronizer, + "%.0f", + RoundFloat(info.Speed * 10) / 10.0); + speedTextShowDuckString[info.ID] = false; + } + else + { + if (speedTextShowDuckString[info.ID] + || (speedTextOnGroundLast[info.ID] + && !info.HitBhop + && info.IsTakeoff + && info.Jumped + && info.Ducking + && (speedTextDuckPressedLast[info.ID] || GOKZ_GetCoreOption(info.ID, Option_Mode) == Mode_Vanilla))) + { + ShowSyncHudText(player.ID, speedHudSynchronizer, + "%.0f\n (%.0f)C", + RoundToPowerOfTen(info.Speed, -2), + RoundToPowerOfTen(info.TakeoffSpeed, -2)); + speedTextShowDuckString[info.ID] = true; + } + else { + ShowSyncHudText(player.ID, speedHudSynchronizer, + "%.0f\n(%.0f)", + RoundToPowerOfTen(info.Speed, -2), + RoundToPowerOfTen(info.TakeoffSpeed, -2)); + speedTextShowDuckString[info.ID] = false; + } + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/timer_text.sp b/sourcemod/scripting/gokz-hud/timer_text.sp new file mode 100644 index 0000000..a5fd17b --- /dev/null +++ b/sourcemod/scripting/gokz-hud/timer_text.sp @@ -0,0 +1,135 @@ +/* + Uses HUD text to show current run time somewhere on the screen. + + This is manually refreshed whenever the players' timer is started, ended or + stopped to improve responsiveness. +*/ + + + +static Handle timerHudSynchronizer; + + + +// =====[ PUBLIC ]===== + +char[] FormatTimerTextForMenu(KZPlayer player, HUDInfo info) +{ + char timerTextString[32]; + if (info.TimerRunning) + { + if (player.GetHUDOption(HUDOption_TimerType) == TimerType_Enabled) + { + FormatEx(timerTextString, sizeof(timerTextString), + "%s %s", + gC_TimeTypeNames[info.TimeType], + GOKZ_HUD_FormatTime(player.ID, info.Time)); + } + else + { + FormatEx(timerTextString, sizeof(timerTextString), + "%s", + GOKZ_HUD_FormatTime(player.ID, info.Time)); + } + if (info.Paused) + { + Format(timerTextString, sizeof(timerTextString), "%s (%T)", timerTextString, "Info Panel Text - PAUSED", player.ID); + } + } + return timerTextString; +} + + + +// =====[ EVENTS ]===== + +void OnPluginStart_TimerText() +{ + timerHudSynchronizer = CreateHudSynchronizer(); +} + +void OnPlayerRunCmdPost_TimerText(int client, int cmdnum, HUDInfo info) +{ + int updateSpeed = gB_FastUpdateRate[client] ? 3 : 6; + if (cmdnum % updateSpeed == 1) + { + UpdateTimerText(client, info); + } +} + +void OnOptionChanged_TimerText(int client, HUDOption option) +{ + if (option == HUDOption_TimerText) + { + ClearTimerText(client); + } +} + +void OnTimerEnd_TimerText(int client) +{ + ClearTimerText(client); +} + +void OnTimerStopped_TimerText(int client) +{ + ClearTimerText(client); +} + + +// =====[ PRIVATE ]===== + +static void UpdateTimerText(int client, HUDInfo info) +{ + KZPlayer player = KZPlayer(client); + + if (player.Fake) + { + return; + } + + ShowTimerText(player, info); +} + +static void ClearTimerText(int client) +{ + ClearSyncHud(client, timerHudSynchronizer); +} + +static void ShowTimerText(KZPlayer player, HUDInfo info) +{ + if (!info.TimerRunning) + { + if (player.ID != info.ID) + { + CancelGOKZHUDMenu(player.ID); + } + return; + } + if (player.TimerText == TimerText_Top || player.TimerText == TimerText_Bottom) + { + int colour[4]; // RGBA + if (player.GetHUDOption(HUDOption_TimerType) == TimerType_Enabled) + { + switch (info.TimeType) + { + case TimeType_Nub:colour = { 234, 209, 138, 0 }; + case TimeType_Pro:colour = { 181, 212, 238, 0 }; + } + } + else colour = { 255, 255, 255, 0}; + + switch (player.TimerText) + { + case TimerText_Top: + { + SetHudTextParams(-1.0, 0.07, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), colour[0], colour[1], colour[2], colour[3], 0, 1.0, 0.0, 0.0); + } + case TimerText_Bottom: + { + SetHudTextParams(-1.0, 0.9, GetTextHoldTime(gB_FastUpdateRate[player.ID] ? 3 : 6), colour[0], colour[1], colour[2], colour[3], 0, 1.0, 0.0, 0.0); + } + } + + ShowSyncHudText(player.ID, timerHudSynchronizer, GOKZ_HUD_FormatTime(player.ID, info.Time)); + } +}
\ No newline at end of file diff --git a/sourcemod/scripting/gokz-hud/tp_menu.sp b/sourcemod/scripting/gokz-hud/tp_menu.sp new file mode 100644 index 0000000..bb78f1e --- /dev/null +++ b/sourcemod/scripting/gokz-hud/tp_menu.sp @@ -0,0 +1,415 @@ +/* + Lets players easily use teleport functionality. + + This menu is displayed whenever the player is alive and there is + currently no other menu displaying. +*/ + + + +#define ITEM_INFO_CHECKPOINT "cp" +#define ITEM_INFO_TELEPORT "tp" +#define ITEM_INFO_PREV "prev" +#define ITEM_INFO_NEXT "next" +#define ITEM_INFO_UNDO "undo" +#define ITEM_INFO_PAUSE "pause" +#define ITEM_INFO_START "start" + +static bool oldCanMakeCP[MAXPLAYERS + 1]; +static bool oldCanTP[MAXPLAYERS + 1]; +static bool oldCanPrevCP[MAXPLAYERS + 1]; +static bool oldCanNextCP[MAXPLAYERS + 1]; +static bool oldCanUndoTP[MAXPLAYERS + 1]; +static bool oldCanPause[MAXPLAYERS + 1]; +static bool oldCanResume[MAXPLAYERS + 1]; +static bool forceRefresh[MAXPLAYERS + 1]; + +// =====[ EVENTS ]===== + +void OnPlayerRunCmdPost_TPMenu(int client, int cmdnum, HUDInfo info) +{ + int updateSpeed = gB_FastUpdateRate[client] ? 3 : 6; + if (cmdnum % updateSpeed == 2) + { + UpdateTPMenu(client, info); + } +} + +public int PanelHandler_Menu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Cancel) + { + gB_MenuShowing[param1] = false; + } + return 0; +} + +public int MenuHandler_TPMenu(Menu menu, MenuAction action, int param1, int param2) +{ + if (action == MenuAction_Select) + { + char info[16]; + menu.GetItem(param2, info, sizeof(info)); + + if (StrEqual(info, ITEM_INFO_CHECKPOINT, false)) + { + GOKZ_MakeCheckpoint(param1); + } + else if (StrEqual(info, ITEM_INFO_TELEPORT, false)) + { + GOKZ_TeleportToCheckpoint(param1); + } + else if (StrEqual(info, ITEM_INFO_PREV, false)) + { + GOKZ_PrevCheckpoint(param1); + } + else if (StrEqual(info, ITEM_INFO_NEXT, false)) + { + GOKZ_NextCheckpoint(param1); + } + else if (StrEqual(info, ITEM_INFO_UNDO, false)) + { + GOKZ_UndoTeleport(param1); + } + else if (StrEqual(info, ITEM_INFO_PAUSE, false)) + { + GOKZ_TogglePause(param1); + } + else if (StrEqual(info, ITEM_INFO_START, false)) + { + GOKZ_TeleportToStart(param1); + } + + // Menu closes when player selects something, so... + gB_MenuShowing[param1] = false; + } + else if (action == MenuAction_Cancel) + { + gB_MenuShowing[param1] = false; + } + else if (action == MenuAction_End) + { + delete menu; + } + return 0; +} + +// =====[ PUBLIC ]===== +void SetForceUpdateTPMenu(int client) +{ + forceRefresh[client] = true; +} + +// =====[ PRIVATE ]===== + +static void UpdateTPMenu(int client, HUDInfo info) +{ + KZPlayer player = KZPlayer(client); + + if (player.Fake) + { + return; + } + + bool force = forceRefresh[client] + || player.CanMakeCheckpoint != oldCanMakeCP[client] + || player.CanTeleportToCheckpoint != oldCanTP[client] + || player.CanPrevCheckpoint != oldCanPrevCP[client] + || player.CanNextCheckpoint != oldCanNextCP[client] + || player.CanUndoTeleport != oldCanUndoTP[client] + || player.CanPause != oldCanPause[client] + || player.CanResume != oldCanResume[client]; + + + if (player.Alive) + { + if (player.TPMenu != TPMenu_Disabled) + { + if (GetClientMenu(client) == MenuSource_None + || gB_MenuShowing[player.ID] && GetClientAvgLoss(player.ID, NetFlow_Both) > EPSILON + || gB_MenuShowing[player.ID] && player.TimerRunning && !player.Paused && player.TimerText == TimerText_TPMenu + || gB_MenuShowing[player.ID] && force) + { + ShowTPMenu(player, info); + } + } + else + { + // There is no need to update this very often as there's no menu selection to be done here. + if (GetClientMenu(client) == MenuSource_None + || gB_MenuShowing[player.ID] && player.TimerRunning && !player.Paused && player.TimerText == TimerText_TPMenu) + { + ShowPanel(player, info); + } + } + } + else if (player.ObserverTarget != -1) // If the player is spectating someone else + { + // Check if the replay plugin wants to display the replay control menu. + if (!(IsFakeClient(player.ObserverTarget) && gB_GOKZReplays && GOKZ_RP_UpdateReplayControlMenu(client))) + { + ShowPanel(player, info); + } + } + + oldCanMakeCP[client] = player.CanMakeCheckpoint; + oldCanTP[client] = player.CanTeleportToCheckpoint; + oldCanPrevCP[client] = player.CanPrevCheckpoint; + oldCanNextCP[client] = player.CanNextCheckpoint; + oldCanUndoTP[client] = player.CanUndoTeleport; + oldCanPause[client] = player.CanPause; + oldCanResume[client] = player.CanResume; + forceRefresh[client] = false; +} + +static void ShowPanel(KZPlayer player, HUDInfo info) +{ + char panelTitle[256]; + // Spectator List + if (player.ShowSpectators >= ShowSpecs_Number && player.SpecListPosition == SpecListPosition_TPMenu) + { + Format(panelTitle, sizeof(panelTitle), "%s", FormatSpectatorTextForMenu(player, info)); + } + // Timer panel + if (player.TimerText == TimerText_TPMenu && info.TimerRunning) + { + if (panelTitle[0] != '\0') + { + Format(panelTitle, sizeof(panelTitle), "%s \n%s", panelTitle, FormatTimerTextForMenu(player, info)); + } + else + { + Format(panelTitle, sizeof(panelTitle), "%s", FormatTimerTextForMenu(player, info)); + } + if (info.TimeType == TimeType_Nub && info.CurrentTeleport != 0) + { + Format(panelTitle, sizeof(panelTitle), "%s\n%t", panelTitle, "TP Menu - Spectator Teleports", info.CurrentTeleport); + } + } + + if (panelTitle[0] != '\0' && GetClientMenu(player.ID) == MenuSource_None || gB_MenuShowing[player.ID]) + { + Panel panel = new Panel(null); + panel.SetTitle(panelTitle); + panel.Send(player.ID, PanelHandler_Menu, MENU_TIME_FOREVER); + + delete panel; + gB_MenuShowing[player.ID] = true; + } +} + +static void ShowTPMenu(KZPlayer player, HUDInfo info) +{ + Menu menu = new Menu(MenuHandler_TPMenu); + menu.OptionFlags = MENUFLAG_NO_SOUND; + menu.ExitButton = false; + menu.Pagination = MENU_NO_PAGINATION; + TPMenuSetTitle(player, menu, info); + TPMenuAddItems(player, menu); + menu.Display(player.ID, MENU_TIME_FOREVER); + gB_MenuShowing[player.ID] = true; +} + +static void TPMenuSetTitle(KZPlayer player, Menu menu, HUDInfo info) +{ + char title[256]; + if (player.ShowSpectators >= ShowSpecs_Number && player.SpecListPosition == SpecListPosition_TPMenu) + { + Format(title, sizeof(title), "%s", FormatSpectatorTextForMenu(player, info)); + } + if (player.TimerRunning && player.TimerText == TimerText_TPMenu) + { + if (title[0] != '\0') + { + Format(title, sizeof(title), "%s \n%s", title, FormatTimerTextForMenu(player, info)); + } + else + { + Format(title, sizeof(title), "%s", FormatTimerTextForMenu(player, info)); + } + } + if (title[0] != '\0') + { + menu.SetTitle(title); + } +} + +static void TPMenuAddItems(KZPlayer player, Menu menu) +{ + switch (player.TPMenu) + { + case TPMenu_Simple: + { + TPMenuAddItemCheckpoint(player, menu); + TPMenuAddItemTeleport(player, menu); + TPMenuAddItemPause(player, menu); + TPMenuAddItemStart(player, menu); + } + case TPMenu_Advanced: + { + TPMenuAddItemCheckpoint(player, menu); + TPMenuAddItemTeleport(player, menu); + TPMenuAddItemPrevCheckpoint(player, menu); + TPMenuAddItemNextCheckpoint(player, menu); + TPMenuAddItemUndo(player, menu); + TPMenuAddItemPause(player, menu); + TPMenuAddItemStart(player, menu); + } + } +} + +static void TPMenuAddItemCheckpoint(KZPlayer player, Menu menu) +{ + char display[24]; + FormatEx(display, sizeof(display), "%T", "TP Menu - Checkpoint", player.ID); + if (player.TimerRunning) + { + Format(display, sizeof(display), "%s #%d", display, player.CheckpointCount); + } + + // Legacy behavior: Always able to make checkpoint attempts. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Enabled && !player.CanMakeCheckpoint) + { + menu.AddItem(ITEM_INFO_CHECKPOINT, display, ITEMDRAW_DISABLED); + } + else + { + menu.AddItem(ITEM_INFO_CHECKPOINT, display, ITEMDRAW_DEFAULT); + } + +} + +static void TPMenuAddItemTeleport(KZPlayer player, Menu menu) +{ + char display[24]; + FormatEx(display, sizeof(display), "%T", "TP Menu - Teleport", player.ID); + if (player.TimerRunning) + { + Format(display, sizeof(display), "%s #%d", display, player.TeleportCount); + } + + // Legacy behavior: Only able to make TP attempts when there is a checkpoint. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Disabled || player.CanTeleportToCheckpoint) + { + menu.AddItem(ITEM_INFO_TELEPORT, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_TELEPORT, display, ITEMDRAW_DISABLED); + } +} + +static void TPMenuAddItemPrevCheckpoint(KZPlayer player, Menu menu) +{ + char display[24]; + FormatEx(display, sizeof(display), "%T", "TP Menu - Prev CP", player.ID); + + // Legacy behavior: Only able to do prev CP when there is a previous checkpoint to go back to. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Disabled || player.CanPrevCheckpoint) + { + menu.AddItem(ITEM_INFO_PREV, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_PREV, display, ITEMDRAW_DISABLED); + } +} + +static void TPMenuAddItemNextCheckpoint(KZPlayer player, Menu menu) +{ + char display[24]; + FormatEx(display, sizeof(display), "%T", "TP Menu - Next CP", player.ID); + + // Legacy behavior: Only able to do prev CP when there is a next checkpoint to go forward to. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Disabled || player.CanNextCheckpoint) + { + menu.AddItem(ITEM_INFO_NEXT, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_NEXT, display, ITEMDRAW_DISABLED); + } +} + +static void TPMenuAddItemUndo(KZPlayer player, Menu menu) +{ + char display[24]; + FormatEx(display, sizeof(display), "%T", "TP Menu - Undo TP", player.ID); + + // Legacy behavior: Only able to attempt to undo TP when it is allowed. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Disabled || player.CanUndoTeleport) + { + menu.AddItem(ITEM_INFO_UNDO, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_UNDO, display, ITEMDRAW_DISABLED); + } + +} + +static void TPMenuAddItemPause(KZPlayer player, Menu menu) +{ + char display[24]; + + // Legacy behavior: Always able to attempt to pause. + if (gI_DynamicMenu[player.ID] == DynamicMenu_Enabled) + { + if (player.Paused) + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Resume", player.ID); + if (player.CanResume) + { + menu.AddItem(ITEM_INFO_PAUSE, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_PAUSE, display, ITEMDRAW_DISABLED); + } + } + else + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Pause", player.ID); + if (player.CanPause) + { + menu.AddItem(ITEM_INFO_PAUSE, display, ITEMDRAW_DEFAULT); + } + else + { + menu.AddItem(ITEM_INFO_PAUSE, display, ITEMDRAW_DISABLED); + } + } + } + else + { + if (player.Paused) + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Resume", player.ID); + } + else + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Pause", player.ID); + } + menu.AddItem(ITEM_INFO_PAUSE, display, ITEMDRAW_DEFAULT); + } +} + +static void TPMenuAddItemStart(KZPlayer player, Menu menu) +{ + char display[24]; + if (player.StartPositionType == StartPositionType_Spawn) + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Respawn", player.ID); + menu.AddItem(ITEM_INFO_START, display, ITEMDRAW_DEFAULT); + } + else if (player.TimerRunning) + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Restart", player.ID); + menu.AddItem(ITEM_INFO_START, display, ITEMDRAW_DEFAULT); + } + else + { + FormatEx(display, sizeof(display), "%T", "TP Menu - Start", player.ID); + menu.AddItem(ITEM_INFO_START, display, ITEMDRAW_DEFAULT); + } +}
\ No newline at end of file |
