Initial release 1.0.0
Browse Source1.0.0 — Initial release.
4 changed files
with 320 additions and 0 deletions
A
CHANGELOG.md
+3 -0
A
README.md
+4 -0
A
addons/amxmodx/scripting/csb_zombie_core.sma
+257 -0
A
csb.json
+56 -0
CHANGELOG.md
A
| @@ -0,0 +1,3 @@ | ||
| 1 | +## 1.0.0 (2026-02-07) | |
| 2 | + | |
| 3 | +1.0.0 — Initial release. |
README.md
A
| @@ -0,0 +1,4 @@ | ||
| 1 | +<p>A <strong>Zombie Plague style infection core</strong>. After a short countdown a random player becomes the first zombie: knife only, with scaled health, speed and gravity and a zombie model. Zombies are Terrorists and humans are Counter-Terrorists, so the round ends naturally when one side is wiped out. Knifing a human turns them into a zombie.</p><p>The core exposes natives so the rest of the CSB zombie suite can build on it:</p><pre>native csb_is_zombie(id) | |
| 2 | +native csb_infect(id) | |
| 3 | +native csb_make_human(id) | |
| 4 | +forward csb_zombie_infected(id, infector)</pre><p>Independent GPL re-implementation inspired by <strong>Zombie Plague</strong> by MeRcyLeZZ.</p><h2>Features</h2><ul><li>Random first zombie after a configurable release delay.</li><li>Scaled zombie HP, speed and gravity via cvars.</li><li>Knife infection with a superseded damage hit (no accidental kill).</li><li>Team-based rounds end automatically; live zombie/human HUD counter.</li><li>Natives and an infection forward for add-on plugins.</li></ul><h2>Installation</h2><ol><li>Put <code>csb_zombie_core.amxx</code> in <code>addons/amxmodx/plugins/</code>.</li><li>Add it to <code>plugins.ini</code> <strong>above</strong> any CSB zombie add-ons.</li><li>Install a zombie player model at <code>models/player/zombie_source/</code> (or set <code>csb_zm_model</code>).</li><li>Change the map.</li></ol> |
addons/amxmodx/scripting/csb_zombie_core.sma
A
| @@ -0,0 +1,257 @@ | ||
| 1 | +/* | |
| 2 | + * CSB Zombie Core | |
| 3 | + * Copyright (C) 2026 counter-strike-boost.com | |
| 4 | + * | |
| 5 | + * A Zombie Plague style infection core. After a short countdown a random | |
| 6 | + * player is turned into the first zombie: knife only, scaled health, speed and | |
| 7 | + * gravity, and a zombie model. Zombies are Terrorists, humans are Counter- | |
| 8 | + * Terrorists, so the round ends naturally when one side is wiped out. Knifing | |
| 9 | + * a human converts them. Other plugins hook in through the exposed natives | |
| 10 | + * (csb_is_zombie, csb_infect, csb_make_human). | |
| 11 | + * | |
| 12 | + * Inspired by Zombie Plague by MeRcyLeZZ. Independent GPL re-implementation. | |
| 13 | + * | |
| 14 | + * This program is free software: you can redistribute it and/or modify it | |
| 15 | + * under the terms of the GNU General Public License as published by the Free | |
| 16 | + * Software Foundation, either version 3 of the License, or (at your option) | |
| 17 | + * any later version. Distributed WITHOUT ANY WARRANTY. See the GNU General | |
| 18 | + * Public License for more details: <https://www.gnu.org/licenses/>. | |
| 19 | + */ | |
| 20 | + | |
| 21 | +#include <amxmodx> | |
| 22 | +#include <hamsandwich> | |
| 23 | +#include <cstrike> | |
| 24 | +#include <fun> | |
| 25 | + | |
| 26 | +new const PLUGIN[] = "CSB Zombie Core" | |
| 27 | +new const VERSION[] = "1.0.0" | |
| 28 | +new const AUTHOR[] = "counter-strike-boost.com" | |
| 29 | + | |
| 30 | +#define TASK_RELEASE 4321 | |
| 31 | + | |
| 32 | +new g_pEnabled, g_pReleaseDelay, g_pZombieHp, g_pZombieSpeed, g_pZombieGravity, g_pModel | |
| 33 | + | |
| 34 | +new bool:g_bZombie[33] | |
| 35 | +new bool:g_bRoundActive | |
| 36 | +new g_iMaxPlayers | |
| 37 | + | |
| 38 | +new Forward:g_fwInfected | |
| 39 | + | |
| 40 | +public plugin_precache() | |
| 41 | +{ | |
| 42 | + // Zombie model must be installed as models/player/zombie_source/*. | |
| 43 | + // Nothing to precache for the player model itself here. | |
| 44 | +} | |
| 45 | + | |
| 46 | +public plugin_init() | |
| 47 | +{ | |
| 48 | + register_plugin(PLUGIN, VERSION, AUTHOR) | |
| 49 | + | |
| 50 | + g_pEnabled = register_cvar("csb_zm_enabled", "1") | |
| 51 | + g_pReleaseDelay = register_cvar("csb_zm_release_delay", "15.0") | |
| 52 | + g_pZombieHp = register_cvar("csb_zm_zombie_hp", "1500") | |
| 53 | + g_pZombieSpeed = register_cvar("csb_zm_zombie_speed", "270") | |
| 54 | + g_pZombieGravity = register_cvar("csb_zm_zombie_gravity", "0.80") | |
| 55 | + g_pModel = register_cvar("csb_zm_model", "zombie_source") | |
| 56 | + | |
| 57 | + RegisterHam(Ham_Spawn, "player", "fwSpawnPost", 1) | |
| 58 | + RegisterHam(Ham_TakeDamage, "player", "fwTakeDamage", 0) | |
| 59 | + | |
| 60 | + register_event("HLTV", "evNewRound", "a", "1=0", "2=0") | |
| 61 | + | |
| 62 | + g_iMaxPlayers = get_maxplayers() | |
| 63 | + | |
| 64 | + // csb_zombie_infected(id, infector) -- infector is 0 for the first zombie | |
| 65 | + g_fwInfected = CreateMultiForward("csb_zombie_infected", ET_IGNORE, FP_CELL, FP_CELL) | |
| 66 | + | |
| 67 | + set_task(1.0, "taskHud", _, _, _, "b") | |
| 68 | +} | |
| 69 | + | |
| 70 | +public plugin_natives() | |
| 71 | +{ | |
| 72 | + register_native("csb_is_zombie", "native_is_zombie", 1) | |
| 73 | + register_native("csb_infect", "native_infect", 1) | |
| 74 | + register_native("csb_make_human", "native_make_human", 1) | |
| 75 | +} | |
| 76 | + | |
| 77 | +public native_is_zombie(plugin, params) | |
| 78 | +{ | |
| 79 | + new id = get_param(1) | |
| 80 | + if (id < 1 || id > g_iMaxPlayers) | |
| 81 | + return 0 | |
| 82 | + return g_bZombie[id] ? 1 : 0 | |
| 83 | +} | |
| 84 | + | |
| 85 | +public native_infect(plugin, params) | |
| 86 | +{ | |
| 87 | + new id = get_param(1) | |
| 88 | + if (!is_user_alive(id)) | |
| 89 | + return 0 | |
| 90 | + makeZombie(id, 0) | |
| 91 | + return 1 | |
| 92 | +} | |
| 93 | + | |
| 94 | +public native_make_human(plugin, params) | |
| 95 | +{ | |
| 96 | + new id = get_param(1) | |
| 97 | + if (!is_user_connected(id)) | |
| 98 | + return 0 | |
| 99 | + makeHuman(id) | |
| 100 | + return 1 | |
| 101 | +} | |
| 102 | + | |
| 103 | +public client_disconnected(id) | |
| 104 | +{ | |
| 105 | + g_bZombie[id] = false | |
| 106 | +} | |
| 107 | + | |
| 108 | +public evNewRound() | |
| 109 | +{ | |
| 110 | + if (!get_pcvar_num(g_pEnabled)) | |
| 111 | + return | |
| 112 | + | |
| 113 | + g_bRoundActive = false | |
| 114 | + remove_task(TASK_RELEASE) | |
| 115 | + | |
| 116 | + // Everyone starts human this round. | |
| 117 | + for (new id = 1; id <= g_iMaxPlayers; id++) | |
| 118 | + { | |
| 119 | + if (!is_user_connected(id)) | |
| 120 | + continue | |
| 121 | + g_bZombie[id] = false | |
| 122 | + } | |
| 123 | + | |
| 124 | + set_task(get_pcvar_float(g_pReleaseDelay), "taskFirstZombie", TASK_RELEASE) | |
| 125 | + client_print(0, print_chat, "[Zombie] The infection begins in %d seconds. Run!", get_pcvar_num(g_pReleaseDelay)) | |
| 126 | +} | |
| 127 | + | |
| 128 | +public taskFirstZombie() | |
| 129 | +{ | |
| 130 | + new candidates[32], num = 0 | |
| 131 | + for (new id = 1; id <= g_iMaxPlayers; id++) | |
| 132 | + { | |
| 133 | + if (is_user_alive(id)) | |
| 134 | + candidates[num++] = id | |
| 135 | + } | |
| 136 | + | |
| 137 | + if (num < 2) | |
| 138 | + { | |
| 139 | + client_print(0, print_chat, "[Zombie] Not enough players to start the infection.") | |
| 140 | + return | |
| 141 | + } | |
| 142 | + | |
| 143 | + g_bRoundActive = true | |
| 144 | + new pick = candidates[random_num(0, num - 1)] | |
| 145 | + makeZombie(pick, 0) | |
| 146 | + | |
| 147 | + new name[32] | |
| 148 | + get_user_name(pick, name, charsmax(name)) | |
| 149 | + client_print(0, print_chat, "[Zombie] %s is the first zombie!", name) | |
| 150 | +} | |
| 151 | + | |
| 152 | +public fwSpawnPost(id) | |
| 153 | +{ | |
| 154 | + if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id)) | |
| 155 | + return | |
| 156 | + | |
| 157 | + // Freshly spawned players are human until infected. | |
| 158 | + makeHuman(id) | |
| 159 | +} | |
| 160 | + | |
| 161 | +public fwTakeDamage(victim, inflictor, attacker, Float:damage, damagebits) | |
| 162 | +{ | |
| 163 | + if (!get_pcvar_num(g_pEnabled) || !g_bRoundActive) | |
| 164 | + return HAM_IGNORED | |
| 165 | + | |
| 166 | + if (attacker < 1 || attacker > g_iMaxPlayers || attacker == victim) | |
| 167 | + return HAM_IGNORED | |
| 168 | + | |
| 169 | + // Only a zombie's knife infects, and only a living human can be infected. | |
| 170 | + if (!g_bZombie[attacker] || g_bZombie[victim] || !is_user_alive(victim)) | |
| 171 | + return HAM_IGNORED | |
| 172 | + | |
| 173 | + makeZombie(victim, attacker) | |
| 174 | + return HAM_SUPERCEDE // absorb the hit; infection replaces the damage | |
| 175 | +} | |
| 176 | + | |
| 177 | +makeZombie(id, infector) | |
| 178 | +{ | |
| 179 | + g_bZombie[id] = true | |
| 180 | + | |
| 181 | + if (cs_get_user_team(id) != CS_TEAM_T) | |
| 182 | + cs_set_user_team(id, CS_TEAM_T) | |
| 183 | + | |
| 184 | + strip_user_weapons(id) | |
| 185 | + give_item(id, "weapon_knife") | |
| 186 | + | |
| 187 | + set_user_health(id, get_pcvar_num(g_pZombieHp)) | |
| 188 | + set_user_gravity(id, get_pcvar_float(g_pZombieGravity)) | |
| 189 | + set_user_maxspeed(id, get_pcvar_float(g_pZombieSpeed)) | |
| 190 | + | |
| 191 | + set_user_rendering(id, kRenderFxNone, 60, 120, 60, kRenderNormal, 20) | |
| 192 | + | |
| 193 | + new model[32] | |
| 194 | + get_pcvar_string(g_pModel, model, charsmax(model)) | |
| 195 | + if (model[0]) | |
| 196 | + cs_set_user_model(id, model) | |
| 197 | + | |
| 198 | + new ret | |
| 199 | + ExecuteForward(g_fwInfected, ret, id, infector) | |
| 200 | + | |
| 201 | + checkRoundBalance() | |
| 202 | +} | |
| 203 | + | |
| 204 | +makeHuman(id) | |
| 205 | +{ | |
| 206 | + g_bZombie[id] = false | |
| 207 | + | |
| 208 | + if (is_user_alive(id) && cs_get_user_team(id) != CS_TEAM_CT) | |
| 209 | + cs_set_user_team(id, CS_TEAM_CT) | |
| 210 | + | |
| 211 | + set_user_gravity(id, 1.0) | |
| 212 | + set_user_maxspeed(id, 240.0) | |
| 213 | + set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 16) | |
| 214 | + cs_reset_user_model(id) | |
| 215 | + | |
| 216 | + if (is_user_alive(id)) | |
| 217 | + { | |
| 218 | + give_item(id, "weapon_knife") | |
| 219 | + give_item(id, "weapon_usp") | |
| 220 | + cs_set_user_bpammo(id, CSW_USP, 24) | |
| 221 | + } | |
| 222 | +} | |
| 223 | + | |
| 224 | +checkRoundBalance() | |
| 225 | +{ | |
| 226 | + new zombies, humans | |
| 227 | + for (new id = 1; id <= g_iMaxPlayers; id++) | |
| 228 | + { | |
| 229 | + if (!is_user_alive(id)) | |
| 230 | + continue | |
| 231 | + if (g_bZombie[id]) zombies++ | |
| 232 | + else humans++ | |
| 233 | + } | |
| 234 | + | |
| 235 | + if (zombies == 0 && humans > 0) | |
| 236 | + client_print(0, print_chat, "[Zombie] Humans have survived the outbreak!") | |
| 237 | + else if (humans == 0 && zombies > 0) | |
| 238 | + client_print(0, print_chat, "[Zombie] The zombies have consumed everyone!") | |
| 239 | +} | |
| 240 | + | |
| 241 | +public taskHud() | |
| 242 | +{ | |
| 243 | + if (!get_pcvar_num(g_pEnabled)) | |
| 244 | + return | |
| 245 | + | |
| 246 | + new zombies, humans | |
| 247 | + for (new id = 1; id <= g_iMaxPlayers; id++) | |
| 248 | + { | |
| 249 | + if (!is_user_alive(id)) | |
| 250 | + continue | |
| 251 | + if (g_bZombie[id]) zombies++ | |
| 252 | + else humans++ | |
| 253 | + } | |
| 254 | + | |
| 255 | + set_hudmessage(60, 200, 60, 0.02, 0.90, 0, 0.0, 1.1, 0.0, 0.0, -1) | |
| 256 | + show_hudmessage(0, "Zombies: %d Humans: %d", zombies, humans) | |
| 257 | +} |
csb.json
A
| @@ -0,0 +1,56 @@ | ||
| 1 | +{ | |
| 2 | + "name": "CSB Zombie Core", | |
| 3 | + "category": "zombie", | |
| 4 | + "tags": "zombie, infection, core", | |
| 5 | + "image": "", | |
| 6 | + "original_author": "MeRcyLeZZ (Zombie Plague)", | |
| 7 | + "original_url": "", | |
| 8 | + "license": "GPL-3.0", | |
| 9 | + "title": "CSB Zombie Core", | |
| 10 | + "short_desc": "Zombie Plague style infection core: a random first zombie, knife-only infection and clean team-based round end. Exposes natives.", | |
| 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": "hamsandwich,cstrike,fun", | |
| 20 | + "install_notes": "1. Put csb_zombie_core.amxx in addons/amxmodx/plugins/\n2. Add it to plugins.ini ABOVE the zombie add-ons\n3. Install a model at models/player/zombie_source/\n4. Change the map", | |
| 21 | + "known_conflicts": "Other zombie/infection cores. Free-for-all or match mods.", | |
| 22 | + "cvars": [ | |
| 23 | + { | |
| 24 | + "name": "csb_zm_enabled", | |
| 25 | + "default": "1", | |
| 26 | + "description": "Master switch for the zombie core." | |
| 27 | + }, | |
| 28 | + { | |
| 29 | + "name": "csb_zm_release_delay", | |
| 30 | + "default": "15.0", | |
| 31 | + "description": "Seconds before the first zombie is released." | |
| 32 | + }, | |
| 33 | + { | |
| 34 | + "name": "csb_zm_zombie_hp", | |
| 35 | + "default": "1500", | |
| 36 | + "description": "Base zombie health." | |
| 37 | + }, | |
| 38 | + { | |
| 39 | + "name": "csb_zm_zombie_speed", | |
| 40 | + "default": "270", | |
| 41 | + "description": "Base zombie max speed." | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + "name": "csb_zm_zombie_gravity", | |
| 45 | + "default": "0.80", | |
| 46 | + "description": "Base zombie gravity multiplier." | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "name": "csb_zm_model", | |
| 50 | + "default": "zombie_source", | |
| 51 | + "description": "Zombie player model folder name." | |
| 52 | + } | |
| 53 | + ], | |
| 54 | + "commands": [], | |
| 55 | + "main": "addons/amxmodx/scripting/csb_zombie_core.sma" | |
| 56 | +} | |
| 0 | 57 |









