├── C4Timer.csproj ├── README.md ├── C4Timer.sln └── C4Timer.cs /C4Timer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C4 Timer 2 | This plugin adds countdown to c4 bomb explosion to your server. 3 | 4 | ![image](https://i.imgur.com/rE9S8ag.jpg) 5 | 6 | The countdown can look any way you want it to look. 7 | All you have to do is customize the configuration to your liking. 8 | 9 | # Config 10 | ``` 11 | { 12 | "EnableTimer": true, 13 | "EnableProgressBar": true, 14 | "TimerStarting": 45, 15 | "LeftSideTimer": "-[ ", 16 | "RightSideTimer": " ]-", 17 | "EnableColorMessage": true, 18 | "SidesTimerColor": "45:white", 19 | "TimeColor": "20:yellow, 10:red, 5:darkred", 20 | "ProgressBarColor": "20:yellow, 10:red, 5:darkred" 21 | } 22 | 23 | -------------------------------------------------------------------------------- /C4Timer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34723.18 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "C4Timer", "C4Timer.csproj", "{ABC03A0F-2111-47C4-BEA8-A5589DE99BA2}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {ABC03A0F-2111-47C4-BEA8-A5589DE99BA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {ABC03A0F-2111-47C4-BEA8-A5589DE99BA2}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {ABC03A0F-2111-47C4-BEA8-A5589DE99BA2}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {ABC03A0F-2111-47C4-BEA8-A5589DE99BA2}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {4222F3D5-AEDF-4CA5-9400-FE0C8D6E16F4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /C4Timer.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Memory; 4 | using CounterStrikeSharp.API.Modules.Timers; 5 | using CounterStrikeSharp.API.Modules.Utils; 6 | using Microsoft.Extensions.Logging; 7 | using System.Text.Json.Serialization; 8 | using Timer = CounterStrikeSharp.API.Modules.Timers.Timer; 9 | 10 | namespace C4Timer; 11 | 12 | public class C4TimerConfig : BasePluginConfig 13 | { 14 | [JsonPropertyName("EnableTimer")] 15 | public bool EnableTimer { get; set; } = true; 16 | 17 | [JsonPropertyName("EnableProgressBar")] 18 | public bool EnableProgressBar { get; set; } = true; 19 | 20 | [JsonPropertyName("TimerStarting")] 21 | public int TimerStarting { get; set; } = 45; 22 | 23 | [JsonPropertyName("LeftSideTimer")] 24 | public string LeftSideTimer { get; set; } = "-[ "; 25 | 26 | [JsonPropertyName("RightSideTimer")] 27 | public string RightSideTimer { get; set; } = " ]-"; 28 | 29 | [JsonPropertyName("EnableColorMessage")] 30 | public bool EnableColorMessage { get; set; } = true; 31 | 32 | [JsonPropertyName("SidesTimerColor")] 33 | public string SidesTimerColor { get; set; } = "45:white"; 34 | 35 | [JsonPropertyName("TimeColor")] 36 | public string TimeColor { get; set; } = "20:yellow, 10:red, 5:darkred"; 37 | 38 | [JsonPropertyName("ProgressBarColor")] 39 | public string ProgressBarColor { get; set; } = "20:yellow, 10:red, 5:darkred"; 40 | } 41 | 42 | public class C4Timer : BasePlugin, IPluginConfig 43 | { 44 | public override string ModuleName => "C4 Timer"; 45 | public override string ModuleVersion => "1.6"; 46 | public override string ModuleAuthor => "belom0r"; 47 | 48 | Dictionary TimeColor = new Dictionary(); 49 | Dictionary ProgressBarColor = new Dictionary(); 50 | Dictionary SidesTimerColor = new Dictionary(); 51 | 52 | private bool PlantedC4 = false; 53 | 54 | private int TimerLength = 0; 55 | private int TimerСountdown = 0; 56 | 57 | private string messageCountdown = ""; 58 | 59 | private Timer? CountdownToExplosion; 60 | 61 | public required C4TimerConfig Config { get; set; } 62 | 63 | public void OnConfigParsed(C4TimerConfig config) { Config = config; } 64 | 65 | public override void Load(bool hotReload) 66 | { 67 | RegisterEventHandler(BombPlantedPost); //bPlantedC4 = true 68 | RegisterEventHandler((_, _) => { PlantedC4 = false; return HookResult.Continue; }); 69 | RegisterEventHandler((_, _) => { PlantedC4 = false; return HookResult.Continue; }); 70 | RegisterEventHandler((_, _) => { PlantedC4 = false; return HookResult.Continue; }); 71 | 72 | if (Config.EnableColorMessage) 73 | { 74 | RegisterListener(OnTick); 75 | } 76 | 77 | ColorMsg(Config.TimeColor, TimeColor); 78 | ColorMsg(Config.ProgressBarColor, ProgressBarColor); 79 | ColorMsg(Config.SidesTimerColor, SidesTimerColor); 80 | } 81 | 82 | private HookResult BombPlantedPost(EventBombPlanted @event, GameEventInfo info) 83 | { 84 | var planted = GetPlantedC4(); 85 | 86 | if (planted == null) 87 | return HookResult.Continue; 88 | 89 | PlantedC4 = true; 90 | 91 | TimerLength = TimerСountdown = (int)(planted.TimerLength + 1.0f); 92 | 93 | Config.TimerStarting = Math.Clamp(Config.TimerStarting, 0, TimerLength); 94 | 95 | CountdownToExplosion = new Timer(1.0f, CountdownToExplosionC4, TimerFlags.REPEAT); 96 | 97 | Timers.Add(CountdownToExplosion); 98 | 99 | return HookResult.Continue; 100 | } 101 | 102 | public void OnTick() 103 | { 104 | if (string.IsNullOrEmpty(messageCountdown)) 105 | return; 106 | 107 | foreach (var Player in GetPlayers()) 108 | { 109 | Player.PrintToCenterHtml(messageCountdown); 110 | } 111 | } 112 | 113 | public void CountdownToExplosionC4() 114 | { 115 | TimerСountdown--; 116 | 117 | if ((int)TimerСountdown == 0) 118 | { 119 | messageCountdown = WrapWithColor("C4 bomb exploded !!!", "darkred"); 120 | } 121 | else if (TimerСountdown < 0 || !PlantedC4) 122 | { 123 | CountdownToExplosion!.Kill(); 124 | Timers.Remove(CountdownToExplosion); 125 | CountdownToExplosion = null; 126 | 127 | TimerLength = 0; 128 | TimerСountdown = 0; 129 | 130 | messageCountdown = ""; 131 | 132 | return; 133 | } 134 | else messageCountdown = GenerateCountdownMessage(); 135 | 136 | if (!Config.EnableColorMessage) 137 | VirtualFunctions.ClientPrintAll(HudDestination.Center, messageCountdown, 0, 0, 0, 0); 138 | } 139 | 140 | private string GenerateCountdownMessage() 141 | { 142 | if (TimerСountdown > Config.TimerStarting) 143 | return ""; 144 | 145 | string timerStyle = GenerateTimerStyle(); 146 | string progressBarStyle = GenerateProgressBarStyle(); 147 | 148 | return Config.EnableColorMessage 149 | ? $"{timerStyle}{progressBarStyle}" 150 | : ConnectStrings(timerStyle, progressBarStyle); 151 | } 152 | 153 | private string GenerateTimerStyle() 154 | { 155 | if (!Config.EnableTimer) 156 | return ""; 157 | 158 | string leftSide = WrapWithColor(Config.LeftSideTimer, SidesTimerColor[TimerСountdown]); 159 | string time = WrapWithColor(TimerСountdown.ToString(), TimeColor[TimerСountdown]); 160 | string rightSide = WrapWithColor(Config.RightSideTimer, SidesTimerColor[TimerСountdown]); 161 | 162 | return $"{leftSide}{time}{rightSide}"; 163 | } 164 | 165 | private string GenerateProgressBarStyle() 166 | { 167 | if (!Config.EnableProgressBar) 168 | return ""; 169 | 170 | int total = Math.Min(Config.TimerStarting, TimerLength); 171 | 172 | char[] progressBar = new char[total]; 173 | for (int i = 0; i < total; i++) 174 | progressBar[i] = i >= TimerСountdown ? '-' : '|'; 175 | 176 | string progressBar_txt = WrapWithColor(new string(progressBar), ProgressBarColor[TimerСountdown]); 177 | 178 | return Config.EnableTimer && Config.EnableColorMessage ? "
" + progressBar_txt : progressBar_txt; 179 | } 180 | 181 | private string WrapWithColor(string text, string color) 182 | { 183 | return Config.EnableColorMessage ? $"{text}" : text; 184 | } 185 | 186 | private CPlantedC4? GetPlantedC4() 187 | { 188 | var PlantedC4 = Utilities.FindAllEntitiesByDesignerName("planted_c4"); 189 | 190 | if (PlantedC4 == null || !PlantedC4.Any()) 191 | return null; 192 | 193 | return PlantedC4.FirstOrDefault(); 194 | } 195 | 196 | public string ConnectStrings(string str1, string str2) 197 | { 198 | if (string.IsNullOrEmpty(str2)) 199 | return str1; 200 | 201 | return $"{str1}{Environment.NewLine}{str2}"; 202 | } 203 | 204 | public void ColorMsg(string msg, Dictionary colorDictionary) 205 | { 206 | colorDictionary.Clear(); 207 | 208 | for (int i = 0; i <= Config.TimerStarting; i++) 209 | colorDictionary[i] = "white"; 210 | 211 | if (!Config.EnableColorMessage || string.IsNullOrEmpty(msg)) 212 | return; 213 | 214 | foreach (var color in msg.Split(',', StringSplitOptions.RemoveEmptyEntries)) 215 | { 216 | try 217 | { 218 | var elements = color.Split(':', StringSplitOptions.RemoveEmptyEntries); 219 | if (elements.Length != 2) continue; 220 | 221 | int index = int.Parse(elements[0]); 222 | string colorValue = elements[1]; 223 | 224 | for (int i = index; i >= 0; i--) 225 | colorDictionary[i] = colorValue; 226 | } 227 | catch 228 | { 229 | Logger.LogError($"Invalid color format: {color}"); 230 | } 231 | } 232 | } 233 | 234 | public List GetPlayers() 235 | { 236 | return Utilities.GetPlayers().Where(player => 237 | player != null && player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected).ToList(); 238 | } 239 | } --------------------------------------------------------------------------------