/*
* CSB Ammo Packs
* Copyright (C) 2026 counter-strike-boost.com
*
* An ammo-pack currency for zombie / boss servers. Packs are earned for kills,
* headshots and round wins, persisted per SteamID in nVault, and exposed to
* other plugins through natives (csb_get_packs / csb_set_packs / csb_add_packs)
* so a shop or extra-items plugin can spend them. /packs shows the balance.
*
* Inspired by the ammo-pack economy of Zombie Plague. This is an independent
* GPL re-implementation; no original code is reused.
*
* 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 the GNU General
* Public License for more details: .
*/
#include
#include
#include
new const PLUGIN[] = "CSB Ammo Packs"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#define NO_VAULT (-1)
new g_iVault = NO_VAULT
new g_iPacks[33]
new g_szAuth[33][35]
new bool:g_bLoaded[33]
new g_pStart, g_pKill, g_pHeadshot, g_pRoundWin, g_pMax
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pStart = register_cvar("csb_packs_start", "5")
g_pKill = register_cvar("csb_packs_kill", "1")
g_pHeadshot = register_cvar("csb_packs_headshot", "1")
g_pRoundWin = register_cvar("csb_packs_roundwin", "2")
g_pMax = register_cvar("csb_packs_max", "1000000")
register_event("DeathMsg", "eDeath", "a")
register_event("SendAudio", "eTerWin", "a", "2&%!MRAD_terwin")
register_event("SendAudio", "eCtWin", "a", "2&%!MRAD_ctwin")
register_clcmd("say /packs", "cmdPacks")
register_clcmd("say_team /packs", "cmdPacks")
register_clcmd("csb_packs", "cmdPacks")
register_concmd("csb_givepacks", "cmdGive", ADMIN_LEVEL_A, " ")
}
public plugin_natives()
{
register_native("csb_get_packs", "native_get_packs")
register_native("csb_set_packs", "native_set_packs")
register_native("csb_add_packs", "native_add_packs")
}
public plugin_cfg()
{
g_iVault = nvault_open("csb_ammo_packs")
if (g_iVault == NO_VAULT)
log_amx("[CSB Packs] could not open the nVault file 'csb_ammo_packs' - balances will not persist.")
}
public plugin_end()
{
if (g_iVault != NO_VAULT)
nvault_close(g_iVault)
}
/* ---------- persistence ---------- */
public client_authorized(id)
{
g_bLoaded[id] = false
g_iPacks[id] = 0
g_szAuth[id][0] = 0
if (is_user_bot(id) || is_user_hltv(id))
return
get_user_authid(id, g_szAuth[id], charsmax(g_szAuth[]))
new value[16]
if (g_iVault != NO_VAULT && nvault_get(g_iVault, g_szAuth[id], value, charsmax(value)))
g_iPacks[id] = str_to_num(value)
else
g_iPacks[id] = get_pcvar_num(g_pStart)
g_bLoaded[id] = true
}
public client_disconnected(id)
{
savePacks(id)
g_bLoaded[id] = false
g_szAuth[id][0] = 0
}
savePacks(id)
{
if (g_iVault == NO_VAULT || !g_bLoaded[id] || !g_szAuth[id][0])
return
new value[16]
num_to_str(g_iPacks[id], value, charsmax(value))
nvault_pset(g_iVault, g_szAuth[id], value)
}
/* ---------- earning ---------- */
givePacks(id, amount)
{
if (id < 1 || id > 32 || !g_bLoaded[id] || amount == 0)
return
new maxPacks = get_pcvar_num(g_pMax)
g_iPacks[id] += amount
if (g_iPacks[id] < 0)
g_iPacks[id] = 0
if (maxPacks > 0 && g_iPacks[id] > maxPacks)
g_iPacks[id] = maxPacks
savePacks(id)
}
public eDeath()
{
new killer = read_data(1)
new victim = read_data(2)
new headshot = read_data(3)
if (killer < 1 || killer > 32 || killer == victim || !is_user_connected(killer))
return
new reward = get_pcvar_num(g_pKill)
if (headshot)
reward += get_pcvar_num(g_pHeadshot)
if (reward > 0)
{
givePacks(killer, reward)
client_print(killer, print_center, "+%d ammo pack(s)", reward)
}
}
public eTerWin()
{
awardTeam(1)
}
public eCtWin()
{
awardTeam(2)
}
awardTeam(team)
{
new reward = get_pcvar_num(g_pRoundWin)
if (reward <= 0)
return
new players[32], num
get_players(players, num, "ae")
for (new i = 0; i < num; i++)
{
new id = players[i]
if (get_user_team(id) == team)
givePacks(id, reward)
}
}
/* ---------- commands ---------- */
public cmdPacks(id)
{
client_print(id, print_chat, "[CSB] You have %d ammo pack(s).", g_iPacks[id])
return PLUGIN_HANDLED
}
public cmdGive(id, level, cid)
{
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED
new arg[32], amtArg[16]
read_argv(1, arg, charsmax(arg))
read_argv(2, amtArg, charsmax(amtArg))
new target = cmd_target(id, arg, 0)
if (!target)
return PLUGIN_HANDLED
new amount = str_to_num(amtArg)
givePacks(target, amount)
new tname[32]
get_user_name(target, tname, charsmax(tname))
console_print(id, "[CSB] %s now has %d ammo pack(s).", tname, g_iPacks[target])
return PLUGIN_HANDLED
}
/* ---------- natives ---------- */
public native_get_packs(plugin, params)
{
new id = get_param(1)
if (id < 1 || id > 32)
return 0
return g_iPacks[id]
}
public native_set_packs(plugin, params)
{
new id = get_param(1)
new amount = get_param(2)
if (id < 1 || id > 32)
return 0
g_iPacks[id] = amount < 0 ? 0 : amount
savePacks(id)
return 1
}
public native_add_packs(plugin, params)
{
new id = get_param(1)
new amount = get_param(2)
if (id < 1 || id > 32)
return 0
givePacks(id, amount)
return g_iPacks[id]
}