/*
* CSB Death Effects
* Copyright (C) 2026 counter-strike-boost.com
*
* Adds extra visual flair to kills: a blood burst and gib shower at the victim's
* position, plus an optional explosion for headshot or knife kills. Everything
* is sent as temp entities to nearby players, each effect is cvar-toggled, and a
* short per-victim cooldown keeps the effects from spamming the network.
*
* 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
new const PLUGIN[] = "CSB Death Effects"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#define TE_EXPLOSION 3
#define TE_BLOODSPRITE 115
new const g_szExplode[] = "sprites/zerogxplode.spr"
new const g_szBloodSpray[] = "sprites/bloodspray.spr"
new const g_szBloodDrop[] = "sprites/blood.spr"
new const g_szGibs[] = "models/hgibs.mdl"
new g_pEnabled, g_pBlood, g_pGibs, g_pExplode
new g_iSprExplode, g_iSprSpray, g_iSprDrop, g_iMdlGibs
new Float:g_fLastFx[33]
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_deathfx_enabled", "1")
g_pBlood = register_cvar("csb_deathfx_blood", "1")
g_pGibs = register_cvar("csb_deathfx_gibs", "1")
g_pExplode = register_cvar("csb_deathfx_explode", "1")
register_event("DeathMsg", "eventDeath", "a", "1>0")
}
public plugin_precache()
{
g_iSprExplode = precache_model(g_szExplode)
g_iSprSpray = precache_model(g_szBloodSpray)
g_iSprDrop = precache_model(g_szBloodDrop)
g_iMdlGibs = precache_model(g_szGibs)
}
public eventDeath()
{
if (!get_pcvar_num(g_pEnabled))
return
new victim = read_data(2)
new hs = read_data(3)
if (victim < 1 || victim > 32 || !is_user_connected(victim))
return
/* rate limit per victim slot */
if (get_gametime() - g_fLastFx[victim] < 0.3)
return
g_fLastFx[victim] = get_gametime()
new weapon[32]
read_data(4, weapon, charsmax(weapon))
new bool:knife = (containi(weapon, "knife") != -1)
static iOrigin[3], Float:fOrigin[3]
get_user_origin(victim, iOrigin)
fOrigin[0] = float(iOrigin[0])
fOrigin[1] = float(iOrigin[1])
fOrigin[2] = float(iOrigin[2])
if (get_pcvar_num(g_pBlood))
bloodBurst(fOrigin, iOrigin)
if (get_pcvar_num(g_pGibs))
gibShower(fOrigin, iOrigin)
if (get_pcvar_num(g_pExplode) && (hs || knife))
explosion(fOrigin, iOrigin)
}
bloodBurst(const Float:fOrigin[3], const iOrigin[3])
{
message_begin_f(MSG_PVS, SVC_TEMPENTITY, fOrigin)
write_byte(TE_BLOODSPRITE)
write_coord(iOrigin[0])
write_coord(iOrigin[1])
write_coord(iOrigin[2] + 12)
write_short(g_iSprSpray)
write_short(g_iSprDrop)
write_byte(70) /* red blood colour index */
write_byte(12) /* scale */
message_end()
}
gibShower(const Float:fOrigin[3], const iOrigin[3])
{
message_begin_f(MSG_PVS, SVC_TEMPENTITY, fOrigin)
write_byte(TE_BREAKMODEL)
write_coord(iOrigin[0])
write_coord(iOrigin[1])
write_coord(iOrigin[2] + 24)
write_coord(16) /* size x */
write_coord(16) /* size y */
write_coord(16) /* size z */
write_coord(0) /* velocity x */
write_coord(0) /* velocity y */
write_coord(80) /* velocity z */
write_byte(120) /* random velocity */
write_short(g_iMdlGibs)
write_byte(12) /* count */
write_byte(25) /* life (*0.1s) */
write_byte(0x02) /* flags: BREAK_FLESH */
message_end()
}
explosion(const Float:fOrigin[3], const iOrigin[3])
{
message_begin_f(MSG_PVS, SVC_TEMPENTITY, fOrigin)
write_byte(TE_EXPLOSION)
write_coord(iOrigin[0])
write_coord(iOrigin[1])
write_coord(iOrigin[2] + 16)
write_short(g_iSprExplode)
write_byte(10) /* scale */
write_byte(20) /* framerate */
write_byte(0x01) /* TE_EXPLFLAG_NOADDITIVE off / no sound flag stub */
message_end()
}