/*
* CSB VIP Objective Mod
* Copyright (C) 2026 counter-strike-boost.com
*
* An assassination-style objective for any map. Each round a random CT becomes
* the VIP: a glowing, heavily armored player with only a knife. CTs win by
* escorting the VIP into an escape zone, and Terrorists win by killing them.
* Escape zones are read from a per-map data file and checked in PlayerPreThink.
*
* 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
#include
new const PLUGIN[] = "CSB VIP Objective Mod"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#define MAX_ZONES 8
new g_pEnabled, g_pArmor
new Float:g_fZone[MAX_ZONES][3]
new Float:g_fZoneRadius[MAX_ZONES]
new g_iZoneCount
new g_iVip
new bool:g_bRoundOver
new g_iHudSync
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_vip_enabled", "1")
g_pArmor = register_cvar("csb_vip_armor", "200")
register_logevent("eventRoundStart", 2, "1=Round_Start")
register_event("DeathMsg", "eventDeath", "a", "1>0")
register_forward(FM_PlayerPreThink, "fwPreThink")
g_iHudSync = CreateHudSyncObj()
set_task(1.0, "taskHud", 0, _, _, "b")
}
public plugin_cfg()
{
loadZones()
}
loadZones()
{
g_iZoneCount = 0
new map[32]
get_mapname(map, charsmax(map))
new dir[128], path[192]
get_localinfo("amxx_configsdir", dir, charsmax(dir))
if (!dir[0])
copy(dir, charsmax(dir), "addons/amxmodx/configs")
formatex(path, charsmax(path), "%s/csb_vip/%s.ini", dir, map)
if (!file_exists(path))
return
new line[96], len, pos = 0
while (g_iZoneCount < MAX_ZONES && (pos = read_file(path, pos, line, charsmax(line), len)))
{
trim(line)
if (!line[0] || line[0] == ';' || line[0] == '#')
continue
new sx[16], sy[16], sz[16], sr[16]
parse(line, sx, charsmax(sx), sy, charsmax(sy), sz, charsmax(sz), sr, charsmax(sr))
if (!sx[0] || !sy[0] || !sz[0])
continue
g_fZone[g_iZoneCount][0] = str_to_float(sx)
g_fZone[g_iZoneCount][1] = str_to_float(sy)
g_fZone[g_iZoneCount][2] = str_to_float(sz)
g_fZoneRadius[g_iZoneCount] = sr[0] ? str_to_float(sr) : 100.0
g_iZoneCount++
}
}
public eventRoundStart()
{
g_iVip = 0
g_bRoundOver = false
if (!get_pcvar_num(g_pEnabled))
return
set_task(2.5, "taskPickVip", 6161)
}
public taskPickVip()
{
/* pick a random alive CT */
new cts[32], num = 0
new players[32], total
get_players(players, total, "ae", "CT")
for (new i = 0; i < total; i++)
cts[num++] = players[i]
if (num == 0)
return
new vip = cts[random_num(0, num - 1)]
makeVip(vip)
}
makeVip(id)
{
g_iVip = id
strip_user_weapons(id)
give_item(id, "weapon_knife")
set_user_armor(id, get_pcvar_num(g_pArmor))
set_user_rendering(id, kRenderFxGlowShell, 255, 215, 0, kRenderNormal, 180)
new name[32]
get_user_name(id, name, charsmax(name))
client_print(0, print_chat, "^x04[VIP]^x01 %s is the VIP! CTs escort them to the escape zone, Ts hunt them down.", name)
}
public eventDeath()
{
new victim = read_data(2)
if (victim != g_iVip || g_bRoundOver)
return
g_bRoundOver = true
client_print(0, print_chat, "^x04[VIP]^x01 The VIP is dead - Terrorists win the objective!")
set_task(2.0, "taskEndRound")
}
public fwPreThink(id)
{
if (g_bRoundOver || id != g_iVip || g_iZoneCount == 0)
return
if (!is_user_alive(id))
return
static Float:fPos[3]
pev(id, pev_origin, fPos)
for (new z = 0; z < g_iZoneCount; z++)
{
new Float:dx = fPos[0] - g_fZone[z][0]
new Float:dy = fPos[1] - g_fZone[z][1]
new Float:dz = fPos[2] - g_fZone[z][2]
new Float:r = g_fZoneRadius[z]
if (dx*dx + dy*dy + dz*dz < r * r)
{
g_bRoundOver = true
client_print(0, print_chat, "^x04[VIP]^x01 The VIP escaped - Counter-Terrorists win the objective!")
set_task(2.0, "taskEndRound")
return
}
}
}
public taskEndRound()
{
server_cmd("sv_restartround 1")
}
public taskHud()
{
if (g_iVip == 0 || !is_user_alive(g_iVip))
return
new name[32]
get_user_name(g_iVip, name, charsmax(name))
set_hudmessage(255, 215, 0, 0.02, 0.14, 0, 0.0, 1.1, 0.0, 0.0, -1)
ShowSyncHudMsg(0, g_iHudSync, "VIP: %s (%d HP / %d AP)", name, get_user_health(g_iVip), get_user_armor(g_iVip))
}