Код
/*
Версии:
* 1.0 Beta 1 - 8. Написание плагина и исправления ошибок
* 1.0 Beta 9. Фикс гага навсегда
* 1.0 Beta 10. Полировка кода
* 1.0 Beta 11. Добавлен /mute
* 1.1. Добавлен "словарь". Выход из беты
* 1.2. Добавлен VoiceTranscoder API for GAG function's
* 1.3. Фикс менюшки в /mute
* 1.4. Фикс блокировки голосового чата
* 1.0 Beta X. //#define MYSQL // Поддержка MySQL | Не актуально. Так сказать это в планах.
*/
#include <amxmodx>
//#define USE_API_VTC
/*
Раскомментируйте, если используете VTC версии не ниже 2.0RC1 (требуется модуль VoiceTranscoderApiProvider)
Несмотря на доп модуль, это работает намного быстрее, нежели через Fakemeta
Работает только для функции Gag. Надеюсь, простотема допилит.
*/
#define SORRY // Разрешить команду /sorry для извинения игроков
//#define MUTEMENU // Поддержка команды /mute
#define GAG_ACCESS ADMIN_BAN // Доступ к функциям гага
#define SORRYTIME 30 // Как часто можно пользоваться командой /sorry. Время в секундах
#define PREFIX "Информация" // Префикс в чате
#define SUPERADMIN // Админ с флагом L(изменить можно на 281 строке) может гагать других админов с иммунитетом
new g_BlockTimes[] = // Время блокировки в минутах
{
5,
10,
30,
60,
180,
240,
360,
0 // навсегда
}
new g_AllowCommands[][] = // Разрешенные команды
{
"/me",
"/top15",
"/rank",
"/top",
"/myonline",
"timeleft",
"rtv",
"/rtv",
"/hp"
}
/* Словарь плагина */
#define MSG_SORRY_FLOOD "^1[^4%s^1] Прекратите флудить! Повторно извиниться можно через ^3%d ^1сек."
#define MSG_SORRY_ADMIN "^1[^4%s^1] Уважаемый ^3адмнистратор^1, игрок ^3%s ^1просит снять с него ^3GAG^1!"
#define MSG_CHAT_IS_BLOCKED "^1[^4%s^1] Уважаемый ^3%s^1, Ваш чат ^3заблокирован^1!"
#define MSG_BLOCK_EXPIRED_TIME "^1[^4%s^1] До разблокировки осталось ^1примерно ^3%d ^1мин."
#define MSG_BLOCK_EXPIRED "^1[^4%s^1] Время блокировки ^3истекло^1. Не нарушайте больше правила сервера."
#define MSG_SAY_SORRY "^1[^4%s^1] Чтобы извиниться перед администраторами, напишите в чат ^3/sorry^1."
#define MSG_CHAT_UNBLOCK_ALL "^4* ^1Администратор ^3%s ^1разблокировал чат игроку ^3%s^1."
#define MSG_CHAT_UNBLOCK_PL "^1[^4%s^1] Уважаемый ^3%s^1, администратор ^3%s ^1снял с Вас блокировку чата."
#define MSG_CHAT_BLOCK_ALL "^4* ^1Администратор ^3%s ^1заблокировал чат игроку ^3%s ^1%s"
#define MSG_CHAT_BLOCK_PL "^1[^4%s^1] Уважаемый ^3%s^1, администратор ^3%s ^1заблокировал Вам чат ^1%s"
#define MSG_MUTE_ALL_PLAYERS "^1[^4%s^1] ^1Вы установили mute на ^3всех ^1игроков."
#define MSG_UNMUTE_ALL_PLAYERS "^1[^4%s^1] ^1Вы сняли mute со ^3всех ^1игроков."
#define MSG_UNMUTE_PLAYER "^1[^4%s^1] ^1Вы сняли ^3mute ^1с игрока ^3%s^1."
#define MSG_MUTE_PLAYER "^1[^4%s^1] ^1Вы установили ^3mute ^1на игрока ^3%s^1."
/* Технические данные */
#if defined USE_API_VTC
#include <VoiceTranscoderAPI>
#endif
#if defined MUTEMENU || !defined USE_API_VTC
#include <fakemeta>
#endif
#define STORAGE "addons/amxmodx/data/amx_gag.dat"
#define MAX_ITEMS 1000
#define GetBit(%1,%2) (%1 & (1 << (%2 & 31)))
#define SetBit(%1,%2) %1 |= (1 << (%2 & 31))
#define ResetBit(%1,%2) %1 &= ~(1 << (%2 & 31))
new g_bitBlockVoice;
enum _:DATA
{
IP[16],
STEAMID[25],
BLOCKTIME
};
new g_aLoadedData[33][DATA];
new Trie:g_tAllowCmds;
new Array:g_aUsersBlocked;
new g_arrData[DATA];
new pl[32], pnum;
#if defined MUTEMENU
new g_iMutePlayer[33][33];
#endif
public plugin_init()
{
#if defined USE_API_VTC
#define VERSION "1.4.1[VTC Api]"
#else
#define VERSION "1.4.1"
#endif
register_plugin("Gag Chat", VERSION, "neygomon");
register_cvar("adv_gag", VERSION, FCVAR_SERVER | FCVAR_SPONLY);
#if defined MUTEMENU || !defined USE_API_VTC
register_forward(FM_Voice_SetClientListening, "FwdSetClientListening", false);
#endif
register_clcmd("gag_menu", "ClCmdGagMenu");
register_menucmd(register_menuid("AmxGag Menu"), 1023, "GagMenuHandler");
#if defined MUTEMENU
register_clcmd("say /mute", "ClCmdMuteMenu");
register_clcmd("say_team /mute", "ClCmdMuteMenu");
register_menucmd(register_menuid("Mute Menu"), 1023, "MuteMenuHandler");
#endif
register_clcmd("say", "SayChat");
register_clcmd("say_team", "SayChat");
set_task(60.0, "CheckBlockedUsers", .flags = "b");
}
public plugin_cfg()
{
g_aUsersBlocked = ArrayCreate(DATA);
new fp = fopen(STORAGE, "rt");
if(fp)
{
new i, blocktime[15], buffer[128];
new sys = get_systime();
while(!feof(fp) && i < MAX_ITEMS)
{
fgets(fp, buffer, charsmax(buffer));
trim(buffer);
if(buffer[0] == EOS || buffer[0] == ';') continue;
if(parse(buffer,
g_arrData[IP], charsmax(g_arrData[IP]),
g_arrData[STEAMID], charsmax(g_arrData[STEAMID]),
blocktime, charsmax(blocktime)
)
)
{
g_arrData[BLOCKTIME] = str_to_num(blocktime);
if(!g_arrData[BLOCKTIME] || g_arrData[BLOCKTIME] > sys)
{
ArrayPushArray(g_aUsersBlocked, g_arrData);
i++;
}
}
}
fclose(fp);
}
g_tAllowCmds = TrieCreate();
for(new i; i < sizeof g_AllowCommands; i++)
TrieSetCell(g_tAllowCmds, g_AllowCommands[i], i);
}
public client_putinserver(id)
{
if(is_user_bot(id) || is_user_hltv(id)) return;
get_user_ip(id, g_aLoadedData[id][IP], charsmax(g_aLoadedData[][IP]), 1);
get_user_authid(id, g_aLoadedData[id][STEAMID], charsmax(g_aLoadedData[][STEAMID]));
if(IsUserBlocked(id, g_aLoadedData[id][IP], g_aLoadedData[id][STEAMID]) != -1)
SetBit(g_bitBlockVoice, id);
else ResetBit(g_bitBlockVoice, id);
#if defined MUTEMENU
arrayset(g_iMutePlayer[id], 0, sizeof g_iMutePlayer[]);
#endif
}
#if defined MUTEMENU || !defined USE_API_VTC
public FwdSetClientListening(iReciever, iSender)
{
if(iSender != iReciever)
{
#if !defined USE_API_VTC && defined MUTEMENU
if(GetBit(g_bitBlockVoice, iSender) || g_iMutePlayer[iReciever][iSender])
#endif
#if defined MUTEMENU && defined USE_API_VTC
if(g_iMutePlayer[iReciever][iSender])
#endif
{
engfunc(EngFunc_SetClientListening, iReciever, iSender, false);
forward_return(FMV_CELL, false);
return FMRES_SUPERCEDE;
}
}
return FMRES_IGNORED;
}
#endif
public SayChat(id)
{
if(!GetBit(g_bitBlockVoice, id))
return PLUGIN_CONTINUE;
static sMessage[128];
read_args(sMessage, charsmax(sMessage));
remove_quotes(sMessage);
if(TrieKeyExists(g_tAllowCmds, sMessage))
return PLUGIN_CONTINUE;
#if defined SORRY
else if(!strcmp(sMessage, "/sorry"))
{
static iFloodTime[33], systime;
if(iFloodTime[id] > (systime = get_systime()))
ChatColor(id, 0, MSG_SORRY_FLOOD, PREFIX, iFloodTime[id] - systime);
else
{
static sName[32]; get_user_name(id, sName, charsmax(sName));
get_players(pl, pnum, "ch");
for(new i; i < pnum; i++)
{
if(get_user_flags(pl[i]) & GAG_ACCESS)
ChatColor(pl[i], 0, MSG_SORRY_ADMIN, PREFIX, sName);
}
iFloodTime[id] = systime + SORRYTIME;
}
}
#endif
else
{
static sName[32], ost;
get_user_name(id, sName, charsmax(sName));
ChatColor(id, 0, MSG_CHAT_IS_BLOCKED, PREFIX, sName);
if(g_aLoadedData[id][BLOCKTIME])
{
if((ost = g_aLoadedData[id][BLOCKTIME] - get_systime()) / 60 > 0)
ChatColor(id, 0, MSG_BLOCK_EXPIRED_TIME, PREFIX, ost / 60);
else ChatColor(id, 0, MSG_BLOCK_EXPIRED, PREFIX);
}
ChatColor(id, 0, MSG_SAY_SORRY, PREFIX);
}
return PLUGIN_HANDLED;
}
public CheckBlockedUsers()
{
static i, sys; sys = get_systime();
get_players(pl, pnum);
for(i = 0; i < pnum; i++)
{
if(g_aLoadedData[pl[i]][BLOCKTIME] && sys > g_aLoadedData[pl[i]][BLOCKTIME])
UserBlock(pl[i], 0);
}
}
new g_iMenuSelectBlock[33], g_iMenuPos[33], players[33][32];
public ClCmdGagMenu(id)
{
if(get_user_flags(id) & GAG_ACCESS)
{
g_iMenuSelectBlock[id] = g_iMenuPos[id] = 0;
ShowGagMenu(id, 0);
}
return PLUGIN_HANDLED;
}
ShowGagMenu(id, iPos)
{
static sMenu[512], iLen, iKeys, sName[32], a, start, end;
get_players(players[id], pnum, "ch");
start = iPos * 7;
end = start + 7;
a = 0;
if(start >= pnum) start = iPos = g_iMenuPos[id] = 0;
if(end > pnum) end = pnum;
iLen = formatex(sMenu, charsmax(sMenu), "\rВыберите игрока:^n\y(чат)\w\R%d/%d^n^n", iPos + 1, (pnum / 7 + ((pnum % 7) ? 1 : 0))), iKeys = MENU_KEY_0|MENU_KEY_8;
#if defined SUPERADMIN
new bool:superadmin = bool:(get_user_flags(id) & ADMIN_RCON);
#endif
for(new i = start; i < end; i++)
{
get_user_name(players[id][i], sName, charsmax(sName));
if(id == players[id][i])
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rЭто Вы\y]^n", ++a, sName);
#if defined SUPERADMIN
else if(!superadmin && get_user_flags(players[id][i]) & ADMIN_IMMUNITY)
#else
else if(get_user_flags(players[id][i]) & ADMIN_IMMUNITY)
#endif
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rИммунитет\y]^n", ++a, sName);
else
{
iKeys |= (1 << a++);
if(GetBit(g_bitBlockVoice, players[id][i]))
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s \d[\yСнять МУТ\d]^n", a, sName);
else
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s^n", a, sName);
}
}
if(!g_BlockTimes[g_iMenuSelectBlock[id]])
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r8. \wГагнуть \rнавсегда^n^n");
else iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r8. \wГагнуть на \y%d \wмин^n^n", g_BlockTimes[g_iMenuSelectBlock[id]]);
if(end != pnum)
{
formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r9. \yДалее^n\r0. \r%s", iPos ? "Назад" : "Выход");
iKeys |= MENU_KEY_9;
}
else formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r0. \w%s", iPos ? "Назад" : "Выход");
return show_menu(id, iKeys, sMenu, -1, "AmxGag Menu");
}
public GagMenuHandler(id, iKey)
{
switch(iKey)
{
case 7:
{
if(++g_iMenuSelectBlock[id] > charsmax(g_BlockTimes))
g_iMenuSelectBlock[id] = 0;
ShowGagMenu(id, g_iMenuPos[id]);
}
case 8: ShowGagMenu(id, ++g_iMenuPos[id]);
case 9: if(g_iMenuPos[id]) ShowGagMenu(id, --g_iMenuPos[id]);
default:
{
new sNameAdmin[32], sNamePlayer[32];
new iPlayer = players[id][g_iMenuPos[id] * 7 + iKey];
get_user_name(id, sNameAdmin, charsmax(sNameAdmin));
get_user_name(iPlayer, sNamePlayer, charsmax(sNamePlayer));
if(GetBit(g_bitBlockVoice, iPlayer))
{
UserBlock(iPlayer, 0);
ChatColor(0, iPlayer, MSG_CHAT_UNBLOCK_ALL, sNameAdmin, sNamePlayer);
ChatColor(iPlayer, 0, MSG_CHAT_UNBLOCK_PL, PREFIX, sNamePlayer, sNameAdmin);
}
else
{
UserBlock(iPlayer, 1, g_BlockTimes[g_iMenuSelectBlock[id]]);
new blocktimeinfo[32];
if(!g_BlockTimes[g_iMenuSelectBlock[id]])
formatex(blocktimeinfo, charsmax(blocktimeinfo), "^3навсегда.");
else formatex(blocktimeinfo, charsmax(blocktimeinfo), "на ^3%d ^1минут.", g_BlockTimes[g_iMenuSelectBlock[id]]);
ChatColor(0, iPlayer, MSG_CHAT_BLOCK_ALL, PREFIX, sNameAdmin, sNamePlayer, blocktimeinfo);
ChatColor(iPlayer, 0, MSG_CHAT_BLOCK_PL, PREFIX, sNamePlayer, sNameAdmin, blocktimeinfo);
}
ShowGagMenu(id, g_iMenuPos[id]);
}
}
return PLUGIN_HANDLED;
}
#if defined MUTEMENU
new g_iMuteList[33];
new plMute[33][32], plNum[33];
public ClCmdMuteMenu(id)
{
g_iMuteList[id] = 0;
ShowMuteMenu(id, 0);
return PLUGIN_HANDLED;
}
ShowMuteMenu(id, iPos)
{
static sMenu[512], iLen, iKeys, sName[32], a, start, end;
get_players(plMute[id], plNum[id], "ch");
start = iPos * 6;
end = start + 6;
a = 0;
if(start >= plNum[id]) start = iPos = g_iMuteList[id] = 0;
if(end > plNum[id]) end = plNum[id];
iLen = formatex(sMenu, charsmax(sMenu), "\d[\rMute Menu\d] \yВыберите игрока\w\R%d/%d^n^n", iPos + 1, (plNum[id] / 6 + ((plNum[id] % 6) ? 1 : 0))), iKeys = MENU_KEY_0|MENU_KEY_7|MENU_KEY_8;
for(new i = start; i < end; i++)
{
get_user_name(plMute[id][i], sName, charsmax(sName));
if(id == plMute[id][i])
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \d%s \y[\rЭто Вы\y]^n", ++a, sName);
else
{
iKeys |= (1 << a++);
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r%d. \w%s%s^n", a, sName, g_iMutePlayer[id][plMute[id][i]] ? "\d[\rMuted\d]" : "");
}
}
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\r7. \wЗаглушить \rвсех^n");
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r8. \wРазглушить \rвсех^n^n");
if(end != plNum[id])
{
formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r9. \yДалее^n\r0. \r%s", iPos ? "Назад" : "Выход");
iKeys |= MENU_KEY_9;
}
else formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\r0. \r%s", iPos ? "Назад" : "Выход");
return show_menu(id, iKeys, sMenu, -1, "Mute Menu");
}
public MuteMenuHandler(id, iKey)
{
switch(iKey)
{
case 6:
{
for(new i; i < plNum[id]; i++)
if(id != plMute[id][i])
g_iMutePlayer[id][plMute[id][i]] = 1;
ChatColor(id, 0, MSG_MUTE_ALL_PLAYERS, PREFIX);
}
case 7:
{
for(new i; i < plNum[id]; i++)
if(id != plMute[id][i])
g_iMutePlayer[id][plMute[id][i]] = 0;
ChatColor(id, 0, MSG_UNMUTE_ALL_PLAYERS, PREFIX);
}
case 8: ShowMuteMenu(id, ++g_iMuteList[id]);
case 9: if(g_iMuteList[id]) ShowMuteMenu(id, --g_iMuteList[id]);
default:
{
new sNamePlayer[32];
new iPlayer = plMute[id][g_iMuteList[id] * 6 + iKey];
get_user_name(iPlayer, sNamePlayer, charsmax(sNamePlayer));
if(g_iMutePlayer[id][iPlayer])
ChatColor(id, 0, MSG_UNMUTE_PLAYER, PREFIX, sNamePlayer);
else ChatColor(id, 0, MSG_MUTE_PLAYER, PREFIX, sNamePlayer);
g_iMutePlayer[id][iPlayer] = g_iMutePlayer[id][iPlayer] ? 0 : 1;
ShowMuteMenu(id, g_iMuteList[id]);
}
}
return PLUGIN_HANDLED;
}
#endif
UserBlock(id, block, btime = 0)
{
switch(block)
{
case 0: IsUserBlocked(id, g_aLoadedData[id][IP], g_aLoadedData[id][STEAMID], 1);
case 1:
{
g_aLoadedData[id][BLOCKTIME] = !btime ? 0 : get_systime() + btime * 60;
ArrayPushArray(g_aUsersBlocked, g_aLoadedData[id]);
SetBit(g_bitBlockVoice, id);
#if defined USE_API_VTC
VTC_MuteClient(id);
#endif
//client_cmd(id, "-voicerecord"); // типа отключаем войс, ога
engclient_cmd(id, "-voicerecord"); // типа отключаем войс, ога
}
}
}
IsUserBlocked(id, const Ip[], const SteamID[], UnBlock = 0)
{
static i, ArraySizee, sys; sys = get_systime();
ArraySizee = ArraySize(g_aUsersBlocked);
for(i = 0; i < ArraySizee; i++)
{
ArrayGetArray(g_aUsersBlocked, i, g_arrData);
if(!strcmp(g_arrData[IP], Ip) || !strcmp(g_arrData[STEAMID], SteamID))
{
if(!UnBlock && (!g_arrData[BLOCKTIME] || g_arrData[BLOCKTIME] > sys))
{
g_aLoadedData[id][BLOCKTIME] = g_arrData[BLOCKTIME];
return i;
}
else
{
ArrayDeleteItem(g_aUsersBlocked, i);
ResetBit(g_bitBlockVoice, id);
#if defined USE_API_VTC
VTC_UnmuteClient(id);
#endif
}
break;
}
}
return -1;
}
public plugin_end()
{
if(file_exists(STORAGE))
unlink(STORAGE);
new ArraySizee, fp = fopen(STORAGE, "w+");
if(!fprintf(fp, "; File generated by AMX Gag. [ neygomon | https://neugomon.ru ]^n^n"))
{
new err[128]; formatex(err, charsmax(err), "Plugin not write file %s! Users not saved!", STORAGE);
set_fail_state(err);
}
ArraySizee = ArraySize(g_aUsersBlocked);
for(new i; i < ArraySizee; i++)
{
ArrayGetArray(g_aUsersBlocked, i, g_arrData);
fprintf(fp, "^"%s^" ^"%s^" ^"%d^"^n", g_arrData[IP], g_arrData[STEAMID], g_arrData[BLOCKTIME]);
}
if(ArraySizee) log_amx("Successfully saved %d items in %s :)", ArraySizee, STORAGE);
fclose(fp);
ArrayDestroy(g_aUsersBlocked);
TrieDestroy(g_tAllowCmds);
}
stock ChatColor(id, id2, const szMessage[], any:...)
{
static szMsg[190], IdMsg;
vformat(szMsg, charsmax(szMsg), szMessage, 4);
if(!IdMsg) IdMsg = get_user_msgid("SayText");
if(id)
{
if(!is_user_connected(id)) return;
pnum = 1;
pl[0] = id;
}
else get_players(pl, pnum, "c");
for(new i; i < pnum; i++)
{
if(id2 == pl[i]) continue;
message_begin(MSG_ONE_UNRELIABLE, IdMsg, .player = pl[i]);
write_byte(pl[i]);
write_string(szMsg);
message_end();
}
}