/* 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), "%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: %s %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: %s %s\n", "Info Panel Text - Time", player.ID, GOKZ_HUD_FormatTime(player.ID, info.Time), GetPausedString(player, info)); } } } else { FormatEx(timeString, sizeof(timeString), "%T: %s %s\n", "Info Panel Text - Time", player.ID, GOKZ_HUD_FormatTime(player.ID, info.Time), GetPausedString(player, info)); } } else { FormatEx(timeString, sizeof(timeString), "%T: %T %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), "(%T)", "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: %.0f 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: %.0f %s\n", "Info Panel Text - Speed", player.ID, RoundToPowerOfTen(info.Speed, -2), GetTakeoffString(info)); } else { FormatEx(speedString, sizeof(speedString), "%T: %.0f %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 = " C"; infoPanelShowDuckString[info.ID] = true; } else { duckString = ""; infoPanelShowDuckString[info.ID] = false; } if (info.HitJB) { FormatEx(takeoffString, sizeof(takeoffString), "(%.0f)%s", RoundToPowerOfTen(info.TakeoffSpeed, -2), duckString); } else if (info.HitPerf) { FormatEx(takeoffString, sizeof(takeoffString), "(%.0f)%s", RoundToPowerOfTen(info.TakeoffSpeed, -2), duckString); } else { FormatEx(takeoffString, sizeof(takeoffString), "(%.0f)%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: %c %c %c %c %c %c\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), "%s", format); for (int i = strlen(buff); i < sizeof(buff) - 1; i++) { buff[i] = ' '; } buff[sizeof(buff) - 1] = '\0'; Protobuf pb = view_as(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(); }