#include <amxmodx>
#include <amxmisc>
#include <zombieplague>
#include <vault>
stock const ZP_BANK_FMT[] = "^x04[AC] %L"
stock const zplog[] = "zp_bank_activity.log"
new g_iAmmoPacks[33]
new g_iSessionMovement[33]
new g_iWithdrawLimit[33]
new g_szAuth[33][32]
new cvAnnounceTime
new cvBankMax
new cvDepositMin
new cvWithdrawMax
new cvWithdrawLimit
new cvBankSaveDays
new cvAutoSave
new cvDeBug
// Temporary Database vars (used to restore players stats in case they get disconnected)
new db_playerip[64][32] // player name
new db_wlimit[64] // withdraw limit
new db_slot_i // additional saved slots counter (should start on maxplayers+1)
// Temporary save player's stats to database
Tmp_Save(id)
{
new PIP[32]
get_user_ip(id, PIP, 31, 1)
// Check whether there is another record already in that slot
if (db_playerip[id][0] && !equal(PIP, db_playerip[id]))
{
// If DB size is exceeded, write over old records
if (db_slot_i >= sizeof db_playerip)
db_slot_i = get_maxplayers()+1
// Move previous record onto an additional save slot
copy(db_playerip[db_slot_i], charsmax(db_playerip[]), db_playerip[id])
db_wlimit[db_slot_i] = db_wlimit[id]
db_slot_i++
}
copy(db_playerip[id], charsmax(db_playerip[]), PIP) // name
db_wlimit[id] = g_iWithdrawLimit[id] // withdraw limit
}
// Load temporary saved player's stats from database (if a record is found)
Tmp_Load(id)
{
new PIP[32]
get_user_ip(id, PIP, 31, 1)
// Look for a matching record
static i
for (i = 0; i < sizeof db_playerip; i++)
{
if (equal(PIP, db_playerip[i]))
{
// Bingo!
g_iWithdrawLimit[id] = db_wlimit[i]
return;
}
}
}
LoadClient(id, szAuth[])
{
static szValue[11]
new iValue = 0
new key[38], vaultdata[56], name[34], timestamp[11]
// Little memory cleanup
szValue[0] = '^0'
key[0] = '^0'
vaultdata[0] = '^0'
name[0] = '^0'
timestamp[0] = '^0'
format(key,37,"ZBANK.%s",szAuth)
get_vaultdata(key,vaultdata,55)
parse(vaultdata,name,33,timestamp,10,szValue,10)
remove_quotes(name)
if (strlen(szValue) > 0)
{
iValue = (g_iAmmoPacks[id] = str_to_num(szValue))
}
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_LOAD", iValue, szAuth, (get_pcvar_num(cvWithdrawLimit) - g_iWithdrawLimit[id]))
if (get_pcvar_num(cvDeBug) >= 2)
{
if (iValue != 0)
{
log_to_file(zplog,"[ZP] DBLoad: loaded ^"%d^" ammovalue for (Player ^"%s^") (IP ^"%s^")",iValue,name,szAuth)
}
else
{
log_to_file(zplog,"[ZP] DBLoad: nothing to load for (IP ^"%s^"). So sad.",szAuth)
}
}
}
SaveClient(id, szAuth[])
{
static szValue[11]
new key[38], vaultdata[56], name[32]
// Little memory cleanup
szValue[0] = '^0'
key[0] = '^0'
vaultdata[0] = '^0'
name[0] = '^0'
num_to_str(g_iAmmoPacks[id] + g_iSessionMovement[id], szValue, charsmax(szValue))
get_user_name(id, name, 31)
format(key,37,"ZBANK.%s",szAuth)
format(vaultdata,55,"^"%s^" %d %s",name,get_systime(),szValue)
if (str_to_num(szValue) <= 0)
{
remove_vaultdata(key)
}
else
{
set_vaultdata(key,vaultdata)
}
if (get_pcvar_num(cvDeBug) >= 2)
{
if (str_to_num(szValue) > 0)
{
log_to_file(zplog,"[ZP] DBSave: saved ^"%s^" ammovalue for (Player ^"%s^") (IP ^"%s^")",szValue,name,szAuth)
}
else
{
log_to_file(zplog,"[ZP] DBSave: nothing to save for (IP ^"%s^"). So sad.",szAuth)
}
}
}
MemClr(id)
{
g_szAuth[id][0] = '^0'
g_iAmmoPacks[id] = 0
g_iSessionMovement[id] = 0
g_iWithdrawLimit[id] = 0
}
cleanDB()
{
// Open up the vault file - read line by line
// Use vault to delete to any data over a certain age
new gVaultFile[128]
if ( !file_exists(gVaultFile) ) return
get_localinfo("amxx_vault", gVaultFile, 127)
new ammoSaveDays = get_pcvar_num(cvBankSaveDays)
if ( ammoSaveDays < 0) return
if (get_pcvar_num(cvDeBug) >= 1)
{
log_to_file(zplog,"[ZP] DBClean: starting DB cleanup...")
}
// Create a copy of savekeys to remove
new temp[128], pcounter
formatex(temp, 127, "%s~", gVaultFile)
new vaultFile = fopen(gVaultFile, "r")
new tempFile = fopen(temp, "w+")
// Read through the file looking for valid entries
// Check the epoch time to see if deletion should happen
new data[93], vaultSaveKey[38], name[34], epoch[11], value[11]
new maxTime = ammoSaveDays * 24 * 3600
new curTime = get_systime()
new bool:dataFound
while ( !feof(vaultFile) ) {
data[0] = '^0'
// Read the line in vault and if zp save info check to see if we should copy vault key to temp file
// Don't need to read whole line only enough for what we need to parse
fgets(vaultFile, data, 92)
if ( equal(data, "ZBANK", 5) ) {
vaultSaveKey[0] = '^0'
name[0] = '^0'
epoch[0] = '^0'
value[0] = '^0'
// Only copy keys if older than max save days
parse(data, vaultSaveKey, 37, name, 33, epoch, 10, value, 10)
if ( (str_to_num(epoch) + maxTime) < curTime ) {
fprintf(tempFile, "%s^n", vaultSaveKey)
dataFound = true
}
}
}
// Finished reading vault close it
fclose(vaultFile)
if ( dataFound ) {
// Reset to top of temp file
fseek(tempFile, 0, SEEK_SET)
// Remove all entries in temp file from vault.ini
while ( !feof(tempFile) ) {
vaultSaveKey[0] = '^0'
fgets(tempFile, vaultSaveKey, 38)
trim(vaultSaveKey)
if ( vaultSaveKey[0] != '^0' )
{
remove_vaultdata(vaultSaveKey)
pcounter++
if (get_pcvar_num(cvDeBug) >= 1)
{
log_to_file(zplog,"[ZP] DBClean: Deleting %s due to defined autoprune",vaultSaveKey)
}
}
}
}
fclose(tempFile)
delete_file(temp)
if (get_pcvar_num(cvDeBug) >= 1)
{
log_to_file(zplog,"[ZP] DBClean: database prunned successfully. %d users deleted. Settings: %d days",pcounter,ammoSaveDays)
}
}
// Admin set ammopacks for player bank
public cmd_zpbankset(id, level, cid)
{
// Check for access flag
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED;
// Retrieve arguments
static arg[32], ammo[11], player, amount
read_argv(1, arg, sizeof arg - 1)
read_argv(2, ammo, sizeof arg - 1)
amount = str_to_num(ammo)
player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
// Invalid target
if (!player) return PLUGIN_HANDLED;
if (amount >= 0)
{
g_iAmmoPacks[player] = amount
}
if (get_pcvar_num(cvDeBug) >= 1)
{
new PIP[32],Pname[32]
get_user_name(player, Pname, 31)
get_user_ip(player, PIP, 31, 1)
log_to_file(zplog,"[ZP] BankSet: set ^"%d^" bank ammovalue for (Player ^"%s^") (IP ^"%s^")",amount,Pname,PIP)
console_print(id,"[ZP] Set ^"%d^" bank ammovalue for ^"%s^"",amount,Pname,PIP)
}
// If autosave enabled save this bullshit to vault
if (get_pcvar_num(cvAutoSave) == 1)
{
SaveClient(player, g_szAuth[player])
}
return PLUGIN_HANDLED;
}
// Admin add ammopacks to player bank
public cmd_zpbankadd(id, level, cid)
{
// Check for access flag
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED;
// Retrieve arguments
static arg[32], ammo[11], player, amount
read_argv(1, arg, sizeof arg - 1)
read_argv(2, ammo, sizeof arg - 1)
amount = str_to_num(ammo)
player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
// Invalid target
if (!player) return PLUGIN_HANDLED;
g_iAmmoPacks[player] += amount
if (get_pcvar_num(cvDeBug) >= 1)
{
new PIP[32],Pname[32]
get_user_name(player, Pname, 31)
get_user_ip(player, PIP, 31, 1)
log_to_file(zplog,"[ZP] BankSet: added ^"%d^" bank ammovalue for (Player ^"%s^") (IP ^"%s^")",amount,Pname,PIP)
console_print(id,"[ZP] Added ^"%d^" bank ammovalue for ^"%s^"",amount,Pname,PIP)
}
// If autosave enabled save this bullshit to vault
if (get_pcvar_num(cvAutoSave) == 1)
{
SaveClient(player, g_szAuth[player])
}
return PLUGIN_HANDLED;
}
// Admin set withdraw limit status for player
public cmd_zpbanklim(id, level, cid)
{
// Check for access flag
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED;
// Retrieve arguments
static arg[32], limit[11], player, amount
read_argv(1, arg, sizeof arg - 1)
read_argv(2, limit, sizeof arg - 1)
amount = str_to_num(limit)
player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
// Invalid target
if (!player) return PLUGIN_HANDLED;
g_iWithdrawLimit[player] = amount
if (get_pcvar_num(cvDeBug) >= 1)
{
new PIP[32],Pname[32]
get_user_name(player, Pname, 31)
get_user_ip(player, PIP, 31, 1)
log_to_file(zplog,"[ZP] BankSet: set ^"%d^" withdraw limit for (Player ^"%s^") (IP ^"%s^")",amount,Pname,PIP)
console_print(id,"[ZP] Set ^"%d^" withdraw limit for ^"%s^"",amount,Pname,PIP)
}
return PLUGIN_HANDLED;
}
// Admin set ammopacks to pocket
public cmd_zpammoset(id, level, cid)
{
// Check for access flag
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED;
// Retrieve arguments
static arg[32], ammo[11], player, amount
read_argv(1, arg, sizeof arg - 1)
read_argv(2, ammo, sizeof arg - 1)
amount = str_to_num(ammo)
player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
// Invalid target
if (!player) return PLUGIN_HANDLED;
zp_set_user_ammo_packs(player, amount)
if (get_pcvar_num(cvDeBug) >= 1)
{
new PIP[32],Pname[32]
get_user_name(player, Pname, 31)
get_user_ip(player, PIP, 31, 1)
log_to_file(zplog,"[ZP] BankSet: set ^"%d^" pocket ammovalue for (Player ^"%s^") (IP ^"%s^")",amount,Pname,PIP)
console_print(id,"[ZP] Set ^"%d^" pocket ammovalue for ^"%s^"",amount,Pname,PIP)
}
return PLUGIN_HANDLED;
}
// Admin add ammopacks to pocket
public cmd_zpammoadd(id, level, cid)
{
// Check for access flag
if (!cmd_access(id, level, cid, 3))
return PLUGIN_HANDLED;
// Retrieve arguments
static arg[32], ammo[11], player, amount
read_argv(1, arg, sizeof arg - 1)
read_argv(2, ammo, sizeof arg - 1)
amount = str_to_num(ammo)
player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
// Invalid target
if (!player) return PLUGIN_HANDLED;
zp_set_user_ammo_packs(player, zp_get_user_ammo_packs(player) + amount)
if (get_pcvar_num(cvDeBug) >= 1)
{
new PIP[32],Pname[32]
get_user_name(player, Pname, 31)
get_user_ip(player, PIP, 31, 1)
log_to_file(zplog,"[ZP] BankSet: added ^"%d^" pocket ammovalue for (Player ^"%s^") (IP ^"%s^")",amount,Pname,PIP)
console_print(id,"[ZP] Added ^"%d^" pocket ammovalue for ^"%s^"",amount,Pname,PIP)
}
return PLUGIN_HANDLED;
}
// Admin check players bank accounts
public cmd_zpbanklist(id, level, cid)
{
if (!cmd_access(id, level, cid, 1))
return PLUGIN_HANDLED
new playerCount
new players[32], name[32]
get_players(players, playerCount)
console_print(id,"Players Bank Accounts:^n")
new pid, teamName[5]
for ( new team = 1; team >= 0; team-- ) {
for ( new x = 0; x < playerCount; x++ ) {
pid = players[x]
if ( zp_get_user_zombie(pid) != team ) continue
get_user_name(pid, name, 31)
teamName[0] = '^0'
if ( zp_get_user_zombie(pid) == 1 ) copy(teamName, 4, "ZM :")
else if ( zp_get_user_zombie(pid) == 0 ) copy(teamName, 4, "HU :")
else copy(teamName, 4, "S :")
console_print(id, "%s%-24s (Bank: ^"%d^") (Pocket: ^"%d^") (WLimit: ^"%d^")", teamName, name, (g_iAmmoPacks[pid] + g_iSessionMovement[pid]), zp_get_user_ammo_packs(pid), (get_pcvar_num(cvWithdrawLimit) - g_iWithdrawLimit[pid]))
}
}
console_print(id, "")
if (get_pcvar_num(cvDeBug) >= 3)
{
new PIP[32],Pname[32]
get_user_name(id, Pname, 31)
get_user_ip(id, PIP, 31, 1)
log_to_file(zplog,"[ZP] Bank: (Player ^"%s^") (IP ^"%s^") asked for players bank account list",Pname,PIP)
}
return PLUGIN_HANDLED;
}
public plugin_init()
{
register_plugin("[ZP] Ammo Bank", "1.4", "danielkza and Lethal")
register_clcmd("say", "Command_Say")
register_dictionary("zp_bank_ammo.txt")
cvAnnounceTime = register_cvar("zp_bank_announce_time", "300")
cvBankMax = register_cvar("zp_bank_store_max", "50000")
cvDepositMin = register_cvar("zp_bank_deposit_min", "25")
cvWithdrawMax = register_cvar("zp_bank_withdraw_max", "250")
cvWithdrawLimit = register_cvar("zp_bank_withdraw_limit", "750")
cvBankSaveDays = register_cvar("zp_bank_savedays", "14")
cvAutoSave = register_cvar("zp_bank_autosave", "1")
cvDeBug = register_cvar("zp_bank_debug", "1")
register_concmd("playerbank", "cmd_zpbanklist", ADMIN_ALL, " - Show current ammo values for players")
register_concmd("zp_bankosszeg", "cmd_zpbankset", ADMIN_IMMUNITY, "<name> <amount> - Set player ammobank value")
register_concmd("zp_bankammo", "cmd_zpbankadd", ADMIN_IMMUNITY, "<name> <amount> - Add ammopacks to player ammobank")
register_concmd("zp_limbank", "cmd_zpbanklim", ADMIN_IMMUNITY, "<name> <amount> - Set player ammobank withdraw limit status")
register_concmd("zp_setammo", "cmd_zpammoset", ADMIN_IMMUNITY, "<name> <amount> - Set player pocket ammopacks")
register_concmd("zp_addammo", "cmd_zpammoadd", ADMIN_IMMUNITY, "<name> <amount> - Add ammopacks to players pocket")
// For temporarily save player stats
register_logevent("logevent_round_end", 2, "1=Round_End")
Task_Announce()
}
// For temporarily save player stats
public logevent_round_end()
{
// Prevent this from getting called twice when restarting (bugfix)
static Float:lastendtime
if (get_gametime() - lastendtime < 0.5) return;
lastendtime = get_gametime()
// Temporarily save player stats?
if (get_pcvar_num(cvAutoSave))
{
static id
for (id = 1; id <= get_maxplayers(); id++)
{
// Not connected
if (!is_user_connected(id))
continue;
Tmp_Save(id)
}
}
}
public plugin_end()
{
// Client's should have already been saved by now (client_disconnect is called before plugin_end).
// But it costs nothing to be sure.
new iPlayers[32], iNum
get_players(iPlayers, iNum)
new iPlayer
for(new i=0; i < iNum;i++)
{
iPlayer = iPlayers[i]
if (strlen(g_szAuth[iPlayer]) > 0)
SaveClient(iPlayer, g_szAuth[iPlayer])
MemClr(iPlayer)
}
cleanDB()
}
public client_putinserver(id)
{
static szAuth[32]
MemClr(id)
get_user_ip(id, szAuth, 31, 1)
copy(g_szAuth[id], charsmax(g_szAuth[]), szAuth)
LoadClient(id, szAuth)
// For temporarily save player stats
Tmp_Load(id)
}
public client_disconnect(id)
{
if (strlen(g_szAuth[id]) > 0)
SaveClient(id, g_szAuth[id])
// For temporarily save player stats
Tmp_Save(id)
MemClr(id)
}
new msgSayText = -1
stock bool:SayText(const receiver, sender, const msg[], any:...)
{
if(msgSayText == -1)
msgSayText = get_user_msgid("SayText")
if(msgSayText)
{
if(!sender)
sender = receiver
static buffer[512]
vformat(buffer,charsmax(buffer),msg,4)
if(receiver)
message_begin(MSG_ONE_UNRELIABLE,msgSayText,_,receiver)
else
message_begin(MSG_BROADCAST,msgSayText)
write_byte(sender)
write_string(buffer)
message_end()
return true
}
return false
}
public Task_Announce()
{
static iPlayers[32], iNum, iPlayer
get_players(iPlayers, iNum)
for(new i=0; i < iNum;i++)
{
iPlayer = iPlayers[i]
SayText(iPlayer, iPlayer, ZP_BANK_FMT, LANG_PLAYER, "ZP_BANK_ANNOUNCE")
}
set_task(get_pcvar_float(cvAnnounceTime), "Task_Announce")
}
enum
{
CMD_DEPOSIT = 1,
CMD_WITHDRAW,
CMD_INFO
}
public Command_Say(id)
{
static szArgs[32], szArg1[32], szArg2[32]
szArgs[0] = '^0'
szArg1[0] = '^0'
szArg2[0] = '^0'
read_args(szArgs, charsmax(szArgs))
remove_quotes(szArgs)
parse(szArgs, szArg1, charsmax(szArg1), szArg2, charsmax(szArg2))
new iCommand = 0
if(equali(szArg1, "/berak"))
iCommand = CMD_DEPOSIT
else if(equali(szArg1, "/kivesz"))
iCommand = CMD_WITHDRAW
if(equali(szArg1, "berak"))
iCommand = CMD_DEPOSIT
else if(equali(szArg1, "kivesz"))
iCommand = CMD_WITHDRAW
else if(equali(szArg1, "/bank"))
iCommand = CMD_INFO
if(iCommand)
{
if(iCommand == CMD_INFO)
Command_Info(id)
else
{
new iValue;
if (equali(szArg2, "all"))
{
iValue = zp_get_user_ammo_packs(id)
if(iValue <= 0)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_NO_AMMO_TO_SET")
return PLUGIN_HANDLED
}
}
else
{
iValue = str_to_num(szArg2)
if(iValue <= 0)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_INVALID_AMOUNT")
return PLUGIN_HANDLED
}
}
if(iCommand == CMD_DEPOSIT)
Command_Deposit(id, iValue)
else
Command_Withdraw(id, iValue)
}
return PLUGIN_HANDLED
}
return PLUGIN_CONTINUE
}
Command_Info(id)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_LOAD", g_iAmmoPacks[id] + g_iSessionMovement[id], g_szAuth[id], (get_pcvar_num(cvWithdrawLimit) - g_iWithdrawLimit[id]))
}
Command_Deposit(id, iDeposit)
{
new iCurrentAmount = zp_get_user_ammo_packs(id)
new iDepositMin = get_pcvar_num(cvDepositMin)
if(!iCurrentAmount)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_NO_AMMO")
return
}
if(iDeposit > iCurrentAmount)
iDeposit = iCurrentAmount
if(iCurrentAmount < iDepositMin)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_DMIN", iDepositMin)
return
}
if(iDeposit < iDepositMin)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_DMIN", iDepositMin)
return
}
new iCurrent = g_iAmmoPacks[id] + g_iSessionMovement[id]
new iSum = iCurrent + iDeposit
new iBankMax = get_pcvar_num(cvBankMax)
if(iBankMax && (iSum > iBankMax))
{
iDeposit = iBankMax - iCurrent
iSum = iBankMax
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_MAX", iBankMax)
}
if(iDeposit)
{
g_iSessionMovement[id] += iDeposit
if (g_iWithdrawLimit[id] > abs(iDeposit))
{
g_iWithdrawLimit[id] -= abs(iDeposit)
}
else
{
g_iWithdrawLimit[id] = 0
}
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_DEPOSIT", iDeposit, iSum, (get_pcvar_num(cvWithdrawLimit) - g_iWithdrawLimit[id]))
zp_set_user_ammo_packs(id, iCurrentAmount - iDeposit)
if (get_pcvar_num(cvDeBug) >= 3)
{
new PIP[32],Pname[32]
get_user_ip(id, PIP, 31, 1)
get_user_name(id, Pname, 31)
log_to_file(zplog,"[ZP] Bank: (Player ^"%s^") (IP ^"%s^") deposited ^"%d^" ammovalue to vault",Pname,PIP,iDeposit)
}
}
// If autosave enabled save this bullshit to vault
if (get_pcvar_num(cvAutoSave) == 1)
{
SaveClient(id, g_szAuth[id])
}
}
Command_Withdraw(id, iWithdraw)
{
new iDeposited = g_iAmmoPacks[id] + g_iSessionMovement[id]
new iWithdrawMax = get_pcvar_num(cvWithdrawMax)
new iWithdrawLimit = get_pcvar_num(cvWithdrawLimit)
if(!iDeposited)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_EMPTY")
return
}
if(iWithdraw > iDeposited)
iWithdraw = iDeposited
if(iWithdraw > iWithdrawMax)
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_WMAX", iWithdrawMax)
return
}
if((g_iWithdrawLimit[id] > iWithdrawLimit) || ((g_iWithdrawLimit[id] + iWithdraw) > iWithdrawLimit))
{
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_WLIM", iWithdrawLimit, (iWithdrawLimit - g_iWithdrawLimit[id]))
return
}
g_iWithdrawLimit[id] += iWithdraw
g_iSessionMovement[id] -= iWithdraw
SayText(id, id, ZP_BANK_FMT, id, "ZP_BANK_WITHDRAW", iWithdraw, iDeposited - iWithdraw, (get_pcvar_num(cvWithdrawLimit) - g_iWithdrawLimit[id]))
zp_set_user_ammo_packs(id, zp_get_user_ammo_packs(id) + iWithdraw)
if (get_pcvar_num(cvDeBug) >= 3)
{
new PIP[32],Pname[32]
get_user_ip(id, PIP, 31, 1)
get_user_name(id, Pname, 31)
log_to_file(zplog,"[ZP] Bank: (Player ^"%s^") (IP ^"%s^") withdrawed ^"%d^" ammovalue from vault",Pname,PIP,iWithdraw)
}
// If autosave enabled save this bullshit to vault
if (get_pcvar_num(cvAutoSave) == 1)
{
SaveClient(id, g_szAuth[id])
}
}
stock SayText(const id, const input[], any:...)
{
new count = 1, players[32]
static msg[191]
vformat(msg, 190, input, 3)
replace_all(msg, 190, "!g", "^4") // Green Color
replace_all(msg, 190, "!y", "^1") // Default Color
replace_all(msg, 190, "!t", "^3") // Team Color
if (id) players[0] = id; else get_players(players, count, "ch")
{
for ( new i = 0; i < count; i++ )
{
if ( is_user_connected(players[i]) )
{
message_begin(MSG_ONE_UNRELIABLE, SayText, _, players[i])
write_byte(players[i]);
write_string(msg);
message_end();
}
}
}
}