/* * CSB Freeze Tag * Copyright (C) 2026 counter-strike-boost.com * * A freeze-tag game mode. A lethal hit does not kill: instead the victim is * frozen in place as a glowing ice statue (maxspeed pinned, glow-shell render) * and the attacker scores a freeze. A living teammate who stands next to a * frozen player for a few seconds thaws them. A team wins the round when every * living opponent is frozen. Kills are intercepted with Ham_TakeDamage. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. It is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See for details. */ #include #include #include #include new const PLUGIN[] = "CSB Freeze Tag" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define TASK_SCAN 6300 new g_pEnabled, g_pReviveTime, g_pRadius new bool:g_bFrozen[33] new Float:g_fSavedSpeed[33] new Float:g_fReviveProg[33] new bool:g_bRoundOver = false public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_ft_enabled", "1") g_pReviveTime = register_cvar("csb_ft_revive_time", "3.0") g_pRadius = register_cvar("csb_ft_revive_radius", "90.0") RegisterHam(Ham_TakeDamage, "player", "hamTakeDamage") register_logevent("eventNewRound", 2, "1=Round_Start") set_task(0.5, "taskScan", TASK_SCAN, _, _, "b") } public client_disconnected(id) { g_bFrozen[id] = false g_fReviveProg[id] = 0.0 } public hamTakeDamage(victim, inflictor, attacker, Float:damage, damagebits) { if (!get_pcvar_num(g_pEnabled)) return HAM_IGNORED if (victim < 1 || victim > 32 || !is_user_alive(victim)) return HAM_IGNORED /* frozen statues take no further damage */ if (g_bFrozen[victim]) return HAM_SUPERCEDE /* would this hit be lethal? if so, freeze instead of kill */ if (damage >= float(get_user_health(victim))) { freezePlayer(victim) if (attacker >= 1 && attacker <= 32 && attacker != victim && is_user_connected(attacker)) { new an[32], vn[32] get_user_name(attacker, an, charsmax(an)) get_user_name(victim, vn, charsmax(vn)) client_print(0, print_chat, "^x04[CSB]^x03 %s^x01 froze^x03 %s^x01!", an, vn) } return HAM_SUPERCEDE } return HAM_IGNORED } freezePlayer(id) { g_bFrozen[id] = true g_fReviveProg[id] = 0.0 g_fSavedSpeed[id] = get_user_maxspeed(id) set_user_maxspeed(id, 1.0) /* icy blue glow shell */ set_user_rendering(id, kRenderFxGlowShell, 20, 120, 255, kRenderNormal, 25) } thawPlayer(id, bool:announce) { g_bFrozen[id] = false g_fReviveProg[id] = 0.0 if (!is_user_connected(id)) return new Float:spd = g_fSavedSpeed[id] if (spd < 10.0) spd = 250.0 set_user_maxspeed(id, spd) set_user_rendering(id) if (announce && is_user_alive(id)) { new vn[32] get_user_name(id, vn, charsmax(vn)) client_print(0, print_chat, "^x04[CSB]^x03 %s^x01 was thawed by a teammate.", vn) } } public eventNewRound() { g_bRoundOver = false for (new id = 1; id <= 32; id++) { if (g_bFrozen[id]) thawPlayer(id, false) g_bFrozen[id] = false g_fReviveProg[id] = 0.0 } } public taskScan() { if (!get_pcvar_num(g_pEnabled)) return new players[32], num, pid get_players(players, num, "a") new Float:radius = get_pcvar_float(g_pRadius) new Float:needTime = get_pcvar_float(g_pReviveTime) new tAlive[3], tFrozen[3] // index 1 = T, 2 = CT tAlive[1] = tAlive[2] = 0 tFrozen[1] = tFrozen[2] = 0 new origin[3], other[3] for (new i = 0; i < num; i++) { pid = players[i] new team = get_user_team(pid) if (team == 1 || team == 2) { tAlive[team]++ if (g_bFrozen[pid]) tFrozen[team]++ } if (!g_bFrozen[pid]) continue /* look for a living teammate standing close */ get_user_origin(pid, origin) new bool:reviving = false for (new j = 0; j < num; j++) { new mate = players[j] if (mate == pid || g_bFrozen[mate]) continue if (get_user_team(mate) != team) continue get_user_origin(mate, other) if (float(get_distance(origin, other)) <= radius) { reviving = true break } } if (reviving) { g_fReviveProg[pid] += 0.5 set_hudmessage(20, 160, 255, -1.0, 0.65, 0, 0.0, 0.6, 0.0, 0.0, -1) show_hudmessage(pid, "Thawing... %d%%", floatround(g_fReviveProg[pid] / needTime * 100.0)) if (g_fReviveProg[pid] >= needTime) thawPlayer(pid, true) } else if (g_fReviveProg[pid] > 0.0) { g_fReviveProg[pid] = 0.0 } } checkWin(tAlive, tFrozen) } checkWin(tAlive[3], tFrozen[3]) { if (g_bRoundOver) return for (new team = 1; team <= 2; team++) { new foe = (team == 1) ? 2 : 1 /* this team has living players and all of them are frozen -> they lose */ if (tAlive[team] > 0 && tFrozen[team] >= tAlive[team] && tAlive[foe] > 0) { g_bRoundOver = true client_print(0, print_chat, "^x04[CSB]^x01 %s froze the whole enemy team! Round over.", (foe == 1) ? "The Terrorists" : "The Counter-Terrorists") for (new id = 1; id <= 32; id++) if (g_bFrozen[id]) thawPlayer(id, false) set_task(2.0, "taskRestart") return } } } public taskRestart() { server_cmd("sv_restartround 1") server_exec() }