/*
* CSB Zombie Knockback
* Copyright (C) 2026 counter-strike-boost.com
*
* Pushes a zombie backwards when it is shot. On Ham_TakeDamage the plugin adds
* a velocity vector along the attacker's aim, scaled by the damage, the weapon
* and the zombie's speed. This is the core "feel" plugin of any zombie server.
*
* Inspired by the knockback found in the classic Zombie Plague mod. This is an
* independent GPL re-implementation; no original code is reused. It has no hard
* dependency on a specific zombie mod: a zombie is simply any player on the team
* chosen by csb_kb_zombie_team.
*
* 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. See for details.
*/
#include
#include
#include
new const PLUGIN[] = "CSB Zombie Knockback"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
new g_pEnabled, g_pPower, g_pZombieTeam, g_pAirMul, g_pMaxSpeed
/* per-weapon multipliers, indexed by CSW_* id (0..30) */
new Float:g_fWeaponMul[31]
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_kb_enabled", "1")
g_pPower = register_cvar("csb_kb_power", "6.0")
g_pZombieTeam = register_cvar("csb_kb_zombie_team", "1") /* 1 = T, 2 = CT */
g_pAirMul = register_cvar("csb_kb_air_mul", "1.4")
g_pMaxSpeed = register_cvar("csb_kb_max_speed", "1200.0")
RegisterHam(Ham_TakeDamage, "player", "fwTakeDamage")
setupWeaponMultipliers()
}
setupWeaponMultipliers()
{
/* default 1.0 for everything, then tune the ones that feel wrong */
for (new i = 0; i < sizeof(g_fWeaponMul); i++)
g_fWeaponMul[i] = 1.0
g_fWeaponMul[CSW_KNIFE] = 4.0
g_fWeaponMul[CSW_AWP] = 2.0
g_fWeaponMul[CSW_SCOUT] = 1.8
g_fWeaponMul[CSW_M3] = 0.6
g_fWeaponMul[CSW_XM1014] = 0.5
g_fWeaponMul[CSW_DEAGLE] = 1.6
g_fWeaponMul[CSW_M249] = 0.7
}
public fwTakeDamage(victim, inflictor, attacker, Float:damage, damagebits)
{
if (!get_pcvar_num(g_pEnabled))
return HAM_IGNORED
if (attacker < 1 || attacker > get_maxplayers() || attacker == victim)
return HAM_IGNORED
if (!is_user_alive(victim) || !is_user_connected(attacker))
return HAM_IGNORED
/* only push players who are on the zombie team */
if (get_user_team(victim) != get_pcvar_num(g_pZombieTeam))
return HAM_IGNORED
new weapon = get_user_weapon(attacker)
new Float:mul = (weapon >= 0 && weapon < sizeof(g_fWeaponMul)) ? g_fWeaponMul[weapon] : 1.0
/* direction: from attacker's aim, so grenades/knife still shove correctly */
new Float:vAngle[3], Float:vForward[3]
pev(attacker, pev_v_angle, vAngle)
angle_vector(vAngle, ANGLEVECTOR_FORWARD, vForward)
new Float:power = damage * get_pcvar_float(g_pPower) * mul
/* zombies get shoved harder in the air, it looks better */
new flags = pev(victim, pev_flags)
if (!(flags & FL_ONGROUND))
power *= get_pcvar_float(g_pAirMul)
new Float:vel[3]
pev(victim, pev_velocity, vel)
vel[0] += vForward[0] * power
vel[1] += vForward[1] * power
vel[2] += vForward[2] * power * 0.35 /* a little lift, not a launch */
/* clamp so a burst does not fling a zombie across the map */
new Float:maxSpeed = get_pcvar_float(g_pMaxSpeed)
new Float:speed = vector_length(vel)
if (speed > maxSpeed && speed > 0.0)
{
new Float:scale = maxSpeed / speed
vel[0] *= scale
vel[1] *= scale
vel[2] *= scale
}
set_pev(victim, pev_velocity, vel)
return HAM_IGNORED
}