Initial release 1.0.0
Browse Source1.0.0 - Initial release.
4 changed files
with 226 additions and 0 deletions
A
CHANGELOG.md
+3 -0
A
README.md
+1 -0
A
addons/amxmodx/scripting/csb_c4_timer.sma
+186 -0
A
csb.json
+36 -0
CHANGELOG.md
A
| @@ -0,0 +1,3 @@ | ||
| 1 | +## 1.0.0 (2025-09-03) | |
| 2 | + | |
| 3 | +1.0.0 - Initial release. |
README.md
A
| @@ -0,0 +1 @@ | ||
| 1 | +<p><strong>CSB C4 Timer</strong> shows a live countdown of the seconds left on a planted bomb, computed from <code>mp_c4timer</code> and the exact plant time. The fuse colour ramps from green to amber to red, an intensity bar fills as the explosion nears, and each living CT is told whether they can still defuse in time given their defuse kit.</p><h2>How it works</h2><p>The plant is detected through the <code>Planted_The_Bomb</code> log event; a fast HUD task then draws the countdown to everyone. For each CT the plugin compares the time left against the stock defuse timings (10 s without a kit, 5 s with one, read via <code>cs_get_user_defuse</code>) and prints either "Defusable" or "TOO LATE to defuse". The timer stops on defuse, on explosion, or when a new round starts.</p><h2>Features</h2><ul><li>Exact seconds-left countdown based on the real plant time.</li><li>Green → amber → red colour ramp plus a fill bar for urgency.</li><li>Per-CT defusable / too-late notice using the player's defuse kit.</li><li>Cleans up correctly on defuse, explosion and round restart.</li></ul><p>Inspired by the classic <em>C4 Timer</em> plugins for AMX Mod X; this is an independent GPL re-implementation.</p><h2>Installation</h2><ol><li>Compile and copy <code>csb_c4_timer.amxx</code> into <code>addons/amxmodx/plugins/</code>.</li><li>Make sure the <code>cstrike</code> module is enabled (it is by default).</li><li>Add it to <code>plugins.ini</code> and change the map.</li></ol> |
addons/amxmodx/scripting/csb_c4_timer.sma
A
| @@ -0,0 +1,186 @@ | ||
| 1 | +/* | |
| 2 | + * CSB C4 Timer | |
| 3 | + * Copyright (C) 2026 counter-strike-boost.com | |
| 4 | + * | |
| 5 | + * Once the bomb is planted this shows a live HUD countdown of the exact seconds | |
| 6 | + * left, based on mp_c4timer and the moment of the plant. The colour ramps from | |
| 7 | + * green to red as the fuse burns down, and each CT is told whether they can | |
| 8 | + * still reach and defuse it in time given their defuse kit. | |
| 9 | + * | |
| 10 | + * Inspired by the classic "C4 Timer" plugins for AMX Mod X. This is an | |
| 11 | + * independent GPL re-implementation; no original code is reused. | |
| 12 | + * | |
| 13 | + * This program is free software: you can redistribute it and/or modify it | |
| 14 | + * under the terms of the GNU General Public License as published by the Free | |
| 15 | + * Software Foundation, either version 3 of the License, or (at your option) | |
| 16 | + * any later version. It is distributed in the hope that it will be useful, | |
| 17 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | |
| 19 | + * Public License for more details: <https://www.gnu.org/licenses/>. | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <amxmodx> | |
| 23 | +#include <cstrike> | |
| 24 | + | |
| 25 | +new const PLUGIN[] = "CSB C4 Timer" | |
| 26 | +new const VERSION[] = "1.0.0" | |
| 27 | +new const AUTHOR[] = "counter-strike-boost.com" | |
| 28 | + | |
| 29 | +/* stock defuse timings without / with a defuse kit */ | |
| 30 | +#define DEFUSE_NOKIT 10.0 | |
| 31 | +#define DEFUSE_KIT 5.0 | |
| 32 | + | |
| 33 | +new g_pEnabled, g_pBeep | |
| 34 | +new g_pC4Timer | |
| 35 | + | |
| 36 | +new bool:g_bPlanted = false | |
| 37 | +new Float:g_flExplodeAt | |
| 38 | +new g_iSync | |
| 39 | + | |
| 40 | +public plugin_init() | |
| 41 | +{ | |
| 42 | + register_plugin(PLUGIN, VERSION, AUTHOR) | |
| 43 | + | |
| 44 | + g_pEnabled = register_cvar("csb_c4timer_enabled", "1") | |
| 45 | + g_pBeep = register_cvar("csb_c4timer_beep", "1") | |
| 46 | + | |
| 47 | + g_pC4Timer = get_cvar_pointer("mp_c4timer") | |
| 48 | + | |
| 49 | + g_iSync = CreateHudSyncObj() | |
| 50 | + | |
| 51 | + register_logevent("evPlanted", 3, "2=Planted_The_Bomb") | |
| 52 | + register_logevent("evDefused", 3, "2=Defused_The_Bomb") | |
| 53 | + | |
| 54 | + /* new round resets everything (HLTV new-round message) */ | |
| 55 | + register_event("HLTV", "evNewRound", "a", "1=0", "2=0") | |
| 56 | + register_event("TextMsg", "evRestart", "a", "2=#Game_will_restart_in") | |
| 57 | +} | |
| 58 | + | |
| 59 | +public evPlanted() | |
| 60 | +{ | |
| 61 | + if (!get_pcvar_num(g_pEnabled)) | |
| 62 | + return | |
| 63 | + | |
| 64 | + new Float:c4timer = g_pC4Timer ? get_pcvar_float(g_pC4Timer) : 45.0 | |
| 65 | + | |
| 66 | + if (c4timer <= 0.0) | |
| 67 | + c4timer = 45.0 | |
| 68 | + | |
| 69 | + g_bPlanted = true | |
| 70 | + g_flExplodeAt = get_gametime() + c4timer | |
| 71 | + | |
| 72 | + set_task(0.2, "taskTick", 0, _, _, "b") | |
| 73 | +} | |
| 74 | + | |
| 75 | +public evDefused() | |
| 76 | +{ | |
| 77 | + stopTimer() | |
| 78 | +} | |
| 79 | + | |
| 80 | +public evNewRound() | |
| 81 | +{ | |
| 82 | + stopTimer() | |
| 83 | +} | |
| 84 | + | |
| 85 | +public evRestart() | |
| 86 | +{ | |
| 87 | + stopTimer() | |
| 88 | +} | |
| 89 | + | |
| 90 | +stopTimer() | |
| 91 | +{ | |
| 92 | + if (!g_bPlanted) | |
| 93 | + return | |
| 94 | + | |
| 95 | + g_bPlanted = false | |
| 96 | + remove_task(0) | |
| 97 | + ClearSyncHud(0, g_iSync) | |
| 98 | +} | |
| 99 | + | |
| 100 | +public taskTick() | |
| 101 | +{ | |
| 102 | + if (!g_bPlanted) | |
| 103 | + { | |
| 104 | + remove_task(0) | |
| 105 | + return | |
| 106 | + } | |
| 107 | + | |
| 108 | + new Float:remain = g_flExplodeAt - get_gametime() | |
| 109 | + | |
| 110 | + if (remain <= 0.0) | |
| 111 | + { | |
| 112 | + stopTimer() | |
| 113 | + return | |
| 114 | + } | |
| 115 | + | |
| 116 | + new r, g, b | |
| 117 | + fuseColor(remain, r, g, b) | |
| 118 | + | |
| 119 | + /* the bomb is a shared threat - draw it to everyone, then add the | |
| 120 | + personal defuse note only for living CTs */ | |
| 121 | + new players[32], num, pid | |
| 122 | + get_players(players, num, "ch") | |
| 123 | + | |
| 124 | + new bars[16] | |
| 125 | + beepBars(remain, bars, charsmax(bars)) | |
| 126 | + | |
| 127 | + for (new i = 0; i < num; i++) | |
| 128 | + { | |
| 129 | + pid = players[i] | |
| 130 | + | |
| 131 | + new note[64] | |
| 132 | + note[0] = 0 | |
| 133 | + | |
| 134 | + if (is_user_alive(pid) && cs_get_user_team(pid) == CS_TEAM_CT) | |
| 135 | + defuseNote(pid, remain, note, charsmax(note)) | |
| 136 | + | |
| 137 | + set_hudmessage(r, g, b, 0.02, 0.20, 0, 0.0, 0.3, 0.0, 0.0, -1) | |
| 138 | + | |
| 139 | + if (note[0]) | |
| 140 | + ShowSyncHudMsg(pid, g_iSync, "C4: %.1f %s^n%s", remain, bars, note) | |
| 141 | + else | |
| 142 | + ShowSyncHudMsg(pid, g_iSync, "C4: %.1f %s", remain, bars) | |
| 143 | + } | |
| 144 | +} | |
| 145 | + | |
| 146 | +fuseColor(Float:remain, &r, &g, &b) | |
| 147 | +{ | |
| 148 | + if (remain <= 5.0) { r = 255; g = 0; b = 0; } | |
| 149 | + else if (remain <= 15.0) { r = 255; g = 140; b = 0; } | |
| 150 | + else { r = 0; g = 220; b = 0; } | |
| 151 | +} | |
| 152 | + | |
| 153 | +beepBars(Float:remain, out[], len) | |
| 154 | +{ | |
| 155 | + if (!get_pcvar_num(g_pBeep)) | |
| 156 | + { | |
| 157 | + out[0] = 0 | |
| 158 | + return | |
| 159 | + } | |
| 160 | + | |
| 161 | + /* more filled bars the closer the explosion is */ | |
| 162 | + new filled | |
| 163 | + | |
| 164 | + if (remain <= 5.0) filled = 5 | |
| 165 | + else if (remain <= 10.0) filled = 4 | |
| 166 | + else if (remain <= 20.0) filled = 3 | |
| 167 | + else if (remain <= 30.0) filled = 2 | |
| 168 | + else filled = 1 | |
| 169 | + | |
| 170 | + new p = 0 | |
| 171 | + | |
| 172 | + for (new i = 0; i < 5 && p < len - 1; i++) | |
| 173 | + out[p++] = (i < filled) ? '|' : '.' | |
| 174 | + | |
| 175 | + out[p] = 0 | |
| 176 | +} | |
| 177 | + | |
| 178 | +defuseNote(id, Float:remain, out[], len) | |
| 179 | +{ | |
| 180 | + new Float:need = cs_get_user_defuse(id) ? DEFUSE_KIT : DEFUSE_NOKIT | |
| 181 | + | |
| 182 | + if (remain >= need) | |
| 183 | + formatex(out, len, "Defusable (%.0fs needed)", need) | |
| 184 | + else | |
| 185 | + formatex(out, len, "TOO LATE to defuse") | |
| 186 | +} |
csb.json
A
| @@ -0,0 +1,36 @@ | ||
| 1 | +{ | |
| 2 | + "name": "CSB C4 Timer", | |
| 3 | + "category": "hud-info", | |
| 4 | + "tags": "c4, bomb, timer", | |
| 5 | + "image": "", | |
| 6 | + "original_author": "AMX Mod X community (C4 Timer)", | |
| 7 | + "original_url": "", | |
| 8 | + "license": "GPL-3.0", | |
| 9 | + "title": "CSB C4 Timer", | |
| 10 | + "short_desc": "Live HUD countdown after the bomb is planted, colour-coded, with a per-CT defusable / too-late notice.", | |
| 11 | + "version": "1.0.0", | |
| 12 | + "amxx_min": "1.9", | |
| 13 | + "amxx_compile_default": "1.9", | |
| 14 | + "rehlds_ok": true, | |
| 15 | + "hlds_ok": true, | |
| 16 | + "regamedll_required": false, | |
| 17 | + "metamod_flavor": "any", | |
| 18 | + "reapi_required": false, | |
| 19 | + "modules": "cstrike", | |
| 20 | + "install_notes": "1. Put csb_c4_timer.amxx in addons/amxmodx/plugins/\n2. Add it to plugins.ini\n3. Change map. mp_c4timer controls the fuse length.", | |
| 21 | + "known_conflicts": "Other C4 timer HUD plugins will draw on top of this one.", | |
| 22 | + "cvars": [ | |
| 23 | + { | |
| 24 | + "name": "csb_c4timer_enabled", | |
| 25 | + "default": "1", | |
| 26 | + "description": "Enable or disable the C4 timer HUD." | |
| 27 | + }, | |
| 28 | + { | |
| 29 | + "name": "csb_c4timer_beep", | |
| 30 | + "default": "1", | |
| 31 | + "description": "Show the urgency fill bar next to the countdown." | |
| 32 | + } | |
| 33 | + ], | |
| 34 | + "commands": [], | |
| 35 | + "main": "addons/amxmodx/scripting/csb_c4_timer.sma" | |
| 36 | +} | |
| 0 | 37 |









