/*
* CSB Paintball
* Copyright (C) 2026 counter-strike-boost.com
*
* Turns bullets into paint. In a Ham_TraceAttack hook every shot draws a coloured
* beam from the shooter to the impact point and stamps a decal there, with each
* player assigned a colour. Damage can be normalised to a fixed value or set to a
* guaranteed one-hit kill.
*
* Inspired by Paintball Mod by dnz. Independent GPL re-implementation.
*
* 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
new const PLUGIN[] = "CSB Paintball"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
new g_pEnabled, g_pOneHit, g_pDamage
new g_iBeamSpr
new const g_iColors[][3] =
{
{ 255, 40, 40 },
{ 40, 120, 255 },
{ 40, 255, 80 },
{ 255, 220, 40 },
{ 255, 40, 255 },
{ 40, 255, 255 },
{ 255, 140, 20 },
{ 200, 200, 200 }
}
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_pb_enabled", "1")
g_pOneHit = register_cvar("csb_pb_onehit", "0")
g_pDamage = register_cvar("csb_pb_damage", "35.0")
RegisterHam(Ham_TraceAttack, "player", "fwTraceAttack", 0)
}
public plugin_precache()
{
g_iBeamSpr = precache_model("sprites/laserbeam.spr")
}
public fwTraceAttack(victim, attacker, Float:damage, Float:direction[3], ptr, damagebits)
{
if (!get_pcvar_num(g_pEnabled))
return HAM_IGNORED
if (attacker < 1 || attacker > 32 || !is_user_connected(attacker))
return HAM_IGNORED
static Float:fEye[3], Float:fOfs[3], Float:fEnd[3]
pev(attacker, pev_origin, fEye)
pev(attacker, pev_view_ofs, fOfs)
fEye[0] += fOfs[0]
fEye[1] += fOfs[1]
fEye[2] += fOfs[2]
get_tr2(ptr, TR_vecEndPos, fEnd)
new c = attacker % sizeof(g_iColors)
/* paint beam from muzzle to impact */
message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
write_byte(TE_BEAMPOINTS)
engfunc(EngFunc_WriteCoord, fEye[0])
engfunc(EngFunc_WriteCoord, fEye[1])
engfunc(EngFunc_WriteCoord, fEye[2])
engfunc(EngFunc_WriteCoord, fEnd[0])
engfunc(EngFunc_WriteCoord, fEnd[1])
engfunc(EngFunc_WriteCoord, fEnd[2])
write_short(g_iBeamSpr)
write_byte(0)
write_byte(0)
write_byte(4)
write_byte(12)
write_byte(0)
write_byte(g_iColors[c][0])
write_byte(g_iColors[c][1])
write_byte(g_iColors[c][2])
write_byte(200)
write_byte(0)
message_end()
/* paint splat at impact */
message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
write_byte(TE_GUNSHOTDECAL)
engfunc(EngFunc_WriteCoord, fEnd[0])
engfunc(EngFunc_WriteCoord, fEnd[1])
engfunc(EngFunc_WriteCoord, fEnd[2])
write_short(victim > 0 ? victim : 0)
write_byte(random_num(41, 45))
message_end()
if (get_pcvar_num(g_pOneHit))
{
SetHamParamFloat(3, 1000.0)
}
else
{
new Float:d = get_pcvar_float(g_pDamage)
if (d > 0.0)
SetHamParamFloat(3, d)
}
return HAM_IGNORED
}