#include <amxmodx>
#include <amxmisc>
#include <cromchat>
//Comment this line to use on a mod different than Counter-Strike.
#define USE_CSTRIKE
//Uncomment to log restrictions in the server's console.
//#define CRX_CMDRESTRICTIONS_DEBUG
#if defined USE_CSTRIKE
#include <cstrike>
#endif
#define PLUGIN_VERSION "1.2"
#define CMD_ARG_SAY "say"
#define CMD_ARG_SAYTEAM "say_team"
#define MAX_COMMANDS 128
#define MAX_CMDLINE_LENGTH 128
#define MAX_STATUS_LENGTH 12
#define MAX_TYPE_LENGTH 12
#define MAX_MSG_LENGTH 160
#define INVALID_ENTRY -1
enum _:Types
{
TYPE_ALL,
TYPE_NAME,
TYPE_IP,
TYPE_STEAM,
TYPE_FLAGS,
#if defined USE_CSTRIKE
TYPE_TEAM,
#endif
TYPE_LIFE
}
enum _:PlayerData
{
PDATA_NAME[32],
PDATA_IP[20],
PDATA_STEAM[35]
}
enum _:RestrictionData
{
bool:Block,
Type,
#if defined USE_CSTRIKE
CsTeams:ValueTeam,
#endif
ValueString[35],
ValueInt,
Message[MAX_MSG_LENGTH]
}
new const g_szCommandArg[] = "$cmd$"
new const g_szNoMessageArg[] = "#none"
new const g_szLogs[] = "CommandRestrictions.log"
new const g_szFilename[] = "CommandRestrictions.ini"
new Array:g_aRestrictions[MAX_COMMANDS],
Trie:g_tCommands,
g_ePlayerData[33][PlayerData],
g_iTotalCommands = INVALID_ENTRY,
g_iRestrictions[MAX_COMMANDS],
g_szQueue[MAX_CMDLINE_LENGTH]
public plugin_init()
{
register_plugin("Command Restrictions", PLUGIN_VERSION, "OciXCrom")
register_cvar("CRXCommandRestrictions", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY|FCVAR_UNLOGGED)
register_dictionary("common.txt")
}
public plugin_precache()
{
register_clcmd(CMD_ARG_SAY, "OnSay")
register_clcmd(CMD_ARG_SAYTEAM, "OnSay")
g_tCommands = TrieCreate()
ReadFile()
}
public plugin_end()
{
for(new i; i < g_iTotalCommands; i++)
ArrayDestroy(g_aRestrictions[i])
TrieDestroy(g_tCommands)
}
public client_putinserver(id)
{
get_user_name(id, g_ePlayerData[id][PDATA_NAME], charsmax(g_ePlayerData[][PDATA_NAME]))
strtolower(g_ePlayerData[id][PDATA_NAME])
get_user_ip(id, g_ePlayerData[id][PDATA_IP], charsmax(g_ePlayerData[][PDATA_IP]), 1)
get_user_authid(id, g_ePlayerData[id][PDATA_STEAM], charsmax(g_ePlayerData[][PDATA_STEAM]))
}
public client_infochanged(id)
{
if(!is_user_connected(id))
return
static szNewName[32]
get_user_info(id, "name", szNewName, charsmax(szNewName))
if(!equali(szNewName, g_ePlayerData[id][PDATA_NAME]))
{
copy(g_ePlayerData[id][PDATA_NAME], charsmax(g_ePlayerData[][PDATA_NAME]), szNewName)
strtolower(g_ePlayerData[id][PDATA_NAME])
}
}
ReadFile()
{
new szConfigsName[256], szFilename[256]
get_configsdir(szConfigsName, charsmax(szConfigsName))
formatex(szFilename, charsmax(szFilename), "%s/%s", szConfigsName, g_szFilename)
new iFilePointer = fopen(szFilename, "rt")
if(iFilePointer)
{
new szData[MAX_CMDLINE_LENGTH + MAX_STATUS_LENGTH + MAX_TYPE_LENGTH + MAX_MSG_LENGTH], szStatus[MAX_TYPE_LENGTH], szType[MAX_STATUS_LENGTH],\
eItem[RestrictionData], bool:bQueue, iSize, iLine
while(!feof(iFilePointer))
{
fgets(iFilePointer, szData, charsmax(szData))
trim(szData)
iLine++
switch(szData[0])
{
case EOS, ';': continue
case '[':
{
if(bQueue && g_iTotalCommands > INVALID_ENTRY)
register_commands_in_queue()
iSize = strlen(szData)
if(szData[iSize - 1] != ']')
{
log_config_error(iLine, "Closing bracket not found for command ^"%s^"", szData[1])
continue
}
szData[0] = ' '
szData[iSize - 1] = ' '
trim(szData)
if(contain(szData, ",") != -1)
{
strtok(szData, szData, charsmax(szData), g_szQueue, charsmax(g_szQueue), ',')
trim(szData); trim(g_szQueue)
bQueue = true
}
else bQueue = false
if(contain(szData, CMD_ARG_SAY) != -1)
{
replace(szData, charsmax(szData), CMD_ARG_SAY, "")
trim(szData)
}
else register_clcmd(szData, "OnRestrictedCommand")
g_aRestrictions[++g_iTotalCommands] = ArrayCreate(RestrictionData)
TrieSetCell(g_tCommands, szData, g_iTotalCommands)
#if defined CRX_CMDRESTRICTIONS_DEBUG
log_config_error(_, "RN #%i: %s", g_iTotalCommands, szData)
#endif
}
default:
{
eItem[ValueString][0] = EOS
eItem[Message][0] = EOS
parse(szData, szStatus, charsmax(szStatus), szType, charsmax(szType), eItem[ValueString], charsmax(eItem[ValueString]), eItem[Message], charsmax(eItem[Message]))
switch(szStatus[0])
{
case 'A', 'a': eItem[Block] = false
case 'B', 'b': eItem[Block] = true
default:
{
log_config_error(iLine, "Unknown status type ^"%s^"", szStatus)
continue
}
}
switch(szType[0])
{
case 'A', 'a': eItem[Type] = TYPE_ALL
case 'N', 'n':
{
eItem[Type] = TYPE_NAME
if(!eItem[ValueString][0])
{
log_config_error(iLine, "Name not specified")
continue
}
else
strtolower(eItem[ValueString])
}
case 'I', 'i':
{
eItem[Type] = TYPE_IP
if(!eItem[ValueString][0])
{
log_config_error(iLine, "IP address not specified")
continue
}
}
case 'S', 's':
{
eItem[Type] = TYPE_STEAM
if(!eItem[ValueString][0])
{
log_config_error(iLine, "SteamID not specified")
continue
}
}
case 'F', 'f':
{
eItem[Type] = TYPE_FLAGS
if(!eItem[ValueString][0])
{
log_config_error(iLine, "Flag(s) not specified")
continue
}
}
#if defined USE_CSTRIKE
case 'T', 't':
{
eItem[Type] = TYPE_TEAM
if(!eItem[ValueString][0])
{
log_config_error(iLine, "Flag(s) not specified")
continue
}
switch(eItem[ValueString][0])
{
case 'C', 'c': eItem[ValueTeam] = _:CS_TEAM_CT
case 'T', 't': eItem[ValueTeam] = _:CS_TEAM_T
case 'S', 's': eItem[ValueTeam] = _:CS_TEAM_SPECTATOR
case 'U', 'u': eItem[ValueTeam] = _:CS_TEAM_UNASSIGNED
default:
{
log_config_error(iLine, "Unknown team name ^"%s^"", eItem[ValueString])
continue
}
}
}
#endif
case 'L', 'l':
{
eItem[Type] = TYPE_LIFE
if(!eItem[ValueString][0])
{
log_config_error(iLine, "Life status not specified")
continue
}
switch(eItem[ValueString][0])
{
case 'A', 'a': eItem[ValueInt] = 1
case 'D', 'd': eItem[ValueInt] = 0
default:
{
log_config_error(iLine, "Unknown life status ^"%s^"", eItem[ValueString])
continue
}
}
}
default:
{
log_config_error(iLine, "Unknown information type ^"%s^"", szType)
continue
}
}
g_iRestrictions[g_iTotalCommands]++
ArrayPushArray(g_aRestrictions[g_iTotalCommands], eItem)
}
}
}
fclose(iFilePointer)
if(bQueue)
register_commands_in_queue()
if(g_iTotalCommands == INVALID_ENTRY)
{
log_config_error(_, "No command restrictions found.")
pause("ad")
}
}
else
{
log_config_error(_, "Configuration file not found or cannot be opened.")
pause("ad")
}
}
public OnSay(id)
{
new szArg[32], szCommand[32]
read_argv(1, szArg, charsmax(szArg))
parse(szArg, szCommand, charsmax(szCommand), szArg, charsmax(szArg))
if(!TrieKeyExists(g_tCommands, szCommand))
return PLUGIN_CONTINUE
return is_restricted(id, szCommand) ? PLUGIN_HANDLED : PLUGIN_CONTINUE
}
public OnRestrictedCommand(id)
{
new szCommand[32]
read_argv(0, szCommand, charsmax(szCommand))
return is_restricted(id, szCommand) ? PLUGIN_HANDLED : PLUGIN_CONTINUE
}
bool:is_restricted(const id, const szCommand[])
{
static eItem[RestrictionData], bool:bBlock, iCommand, iAlive, i
TrieGetCell(g_tCommands, szCommand, iCommand)
bBlock = false
#if defined USE_CSTRIKE
static CsTeams:iTeam
#endif
iAlive = is_user_alive(id)
iTeam = cs_get_user_team(id)
for(i = 0; i < g_iRestrictions[iCommand]; i++)
{
ArrayGetArray(g_aRestrictions[iCommand], i, eItem)
switch(eItem[Type])
{
case TYPE_ALL: bBlock = eItem[Block]
case TYPE_NAME:
{
if(equal(g_ePlayerData[id][PDATA_NAME], eItem[ValueString]))
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
case TYPE_IP:
{
if(equal(g_ePlayerData[id][PDATA_IP], eItem[ValueString]))
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
case TYPE_STEAM:
{
if(equal(g_ePlayerData[id][PDATA_STEAM], eItem[ValueString]))
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
case TYPE_FLAGS:
{
if(has_all_flags(id, eItem[ValueString]))
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
#if defined USE_CSTRIKE
case TYPE_TEAM:
{
if(iTeam == eItem[ValueTeam])
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
#endif
case TYPE_LIFE:
{
if(iAlive == eItem[ValueInt])
{
bBlock = eItem[Block]
if(bBlock)
break
}
}
}
}
if(bBlock)
{
if(eItem[Message][0])
{
if(equal(eItem[Message], g_szNoMessageArg))
return true
static szMessage[MAX_MSG_LENGTH]
copy(szMessage, charsmax(szMessage), eItem[Message])
replace_all(szMessage, charsmax(szMessage), g_szCommandArg, szCommand)
client_print(id, print_console, szMessage)
CC_SendMessage(id, szMessage)
}
else
{
client_print(id, print_console, "%L (%s)", id, "NO_ACC_COM", szCommand)
CC_SendMessage(id, "&x07%L &x01(&x04%s&x01)", id, "NO_ACC_COM", szCommand)
}
return true
}
return false
}
register_commands_in_queue()
{
static szData[MAX_CMDLINE_LENGTH]
while(g_szQueue[0] != 0 && strtok(g_szQueue, szData, charsmax(szData), g_szQueue, charsmax(g_szQueue), ','))
{
trim(g_szQueue); trim(szData)
if(contain(szData, CMD_ARG_SAY) != -1)
{
replace(szData, charsmax(szData), CMD_ARG_SAY, "")
trim(szData)
}
else register_clcmd(szData, "OnRestrictedCommand")
TrieSetCell(g_tCommands, szData, g_iTotalCommands)
#if defined CRX_CMDRESTRICTIONS_DEBUG
log_config_error(_, "RQ #%i: %s", g_iTotalCommands, szData)
#endif
}
g_szQueue[0] = EOS
}
log_config_error(const iLine = INVALID_ENTRY, const szInput[], any:...)
{
new szError[128]
vformat(szError, charsmax(szError), szInput, 3)
if(iLine == INVALID_ENTRY)
log_to_file(g_szLogs, "%s: %s", g_szFilename, szError)
else
log_to_file(g_szLogs, "%s (%i): %s", g_szFilename, iLine, szError)
}