/*
* CSB Prop Hunt
* Copyright (C) 2026 counter-strike-boost.com
*
* Prop Hunt. Hiders (Terrorists) are disguised as map props: their player model
* is swapped to a chosen prop model and its animation is frozen, so a still hider
* blends in with the scenery. Seekers (CTs) are frozen for a countdown, then hunt
* them down. A recurring taunt plays a sound and briefly glows every hider so the
* round always ends.
*
* 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 Prop Hunt"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
new const g_szProps[][] =
{
"models/w_backpack.mdl",
"models/w_kevlar.mdl",
"models/w_smokegrenade.mdl",
"models/w_flashbang.mdl"
}
#define TAUNT_SOUND "items/suitchargeok1.wav"
new g_pEnabled, g_pHiderTeam, g_pCountdown, g_pTaunt
new bool:g_bHider[33]
new bool:g_bHunting
new g_iHudSync
new g_iValidProps
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_ph_enabled", "1")
g_pHiderTeam = register_cvar("csb_ph_hiderteam", "1") /* 1=T 2=CT */
g_pCountdown = register_cvar("csb_ph_countdown", "15")
g_pTaunt = register_cvar("csb_ph_taunt", "25")
RegisterHam(Ham_Spawn, "player", "fwSpawnPost", 1)
register_event("DeathMsg", "eventDeath", "a", "1>0")
register_logevent("eventRoundStart", 2, "1=Round_Start")
g_iHudSync = CreateHudSyncObj()
set_task(1.0, "taskTauntLoop", 0, _, _, "b")
}
public plugin_precache()
{
g_iValidProps = 0
for (new i = 0; i < sizeof(g_szProps); i++)
{
if (file_exists(g_szProps[i]))
{
engfunc(EngFunc_PrecacheModel, g_szProps[i])
g_iValidProps++
}
}
precache_sound(TAUNT_SOUND)
}
public eventRoundStart()
{
g_bHunting = false
if (!get_pcvar_num(g_pEnabled))
return
set_task(2.5, "taskAssign", 8181)
}
public taskAssign()
{
new hiderTeam = get_pcvar_num(g_pHiderTeam)
new players[32], num
get_players(players, num, "a")
for (new i = 0; i < num; i++)
{
new id = players[i]
if (get_user_team(id) == hiderTeam)
makeHider(id)
else
set_user_maxspeed(id, 1.0) /* freeze seekers during countdown */
}
client_print(0, print_chat, "^x04[PropHunt]^x01 Hiders, disguise! Seekers unfreeze in %d seconds.", get_pcvar_num(g_pCountdown))
set_task(float(get_pcvar_num(g_pCountdown)), "taskRelease", 8282)
}
public fwSpawnPost(id)
{
g_bHider[id] = false
}
makeHider(id)
{
if (!is_user_alive(id))
return
g_bHider[id] = true
if (g_iValidProps > 0)
{
new pick = pickValidProp()
if (pick >= 0)
{
engfunc(EngFunc_SetModel, id, g_szProps[pick])
set_pev(id, pev_sequence, 0)
set_pev(id, pev_framerate, 0.0)
}
}
client_print(id, print_chat, "[CSB] You are a prop. Stay still to blend in.")
}
pickValidProp()
{
/* choose a random model that actually exists */
new tries = 0
while (tries < 20)
{
new i = random_num(0, sizeof(g_szProps) - 1)
if (file_exists(g_szProps[i]))
return i
tries++
}
return -1
}
public taskRelease()
{
g_bHunting = true
new players[32], num
get_players(players, num, "a")
for (new i = 0; i < num; i++)
{
if (!g_bHider[players[i]])
set_user_maxspeed(players[i], 250.0)
}
client_print(0, print_chat, "^x04[PropHunt]^x01 The hunt is on!")
}
public eventDeath()
{
new victim = read_data(2)
if (victim >= 1 && victim <= 32 && g_bHider[victim])
g_bHider[victim] = false
}
public taskTauntLoop()
{
static counter
counter++
if (!g_bHunting)
{
counter = 0
return
}
new interval = get_pcvar_num(g_pTaunt)
if (interval < 5)
interval = 5
if (counter % interval == 0)
taunt()
/* HUD */
new hiders = countHiders()
set_hudmessage(0, 200, 255, 0.02, 0.12, 0, 0.0, 1.1, 0.0, 0.0, -1)
ShowSyncHudMsg(0, g_iHudSync, "Props left: %d", hiders)
}
taunt()
{
new players[32], num
get_players(players, num, "a")
for (new i = 0; i < num; i++)
{
new id = players[i]
client_cmd(id, "play %s", TAUNT_SOUND)
if (g_bHider[id])
{
/* briefly reveal */
set_user_rendering(id, kRenderFxGlowShell, 255, 180, 0, kRenderNormal, 120)
set_task(1.5, "taskUnglow", id)
}
}
}
public taskUnglow(id)
{
if (is_user_connected(id))
set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 0)
}
countHiders()
{
new c = 0
for (new id = 1; id <= 32; id++)
if (g_bHider[id] && is_user_alive(id))
c++
return c
}