[amx_gag] Необходимо доработать возможность простым администраторам ("d") глушить любых игроков за исключением самого себя, главного администратора ("l"), простых администраторов ("d"). В меню всех иммунитированных игроков помечать с желтой звездочкой возле никнейма (в конце), себя соответственно видеть с красной звездочкой. Главный администратор в свою очередь имеет возможность заглушить всех без исключения (включая самого себя). Конструкция со звездочками та же. Не за спасибо, если кто возьмется. )
- Код: Выделить всё
/*
Версии:
* 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>
#include <gmf_directory>
//#define USE_API_VTC
/*
Раскомментируйте, если используете VTC версии не ниже 2.0RC1 (требуется модуль VoiceTranscoderApiProvider)
Несмотря на доп модуль, это работает намного быстрее, нежели через Fakemeta
Работает только для функции Gag. Надеюсь, простотема допилит.
*/
#define SORRY // Разрешить команду /sorry для извинения игроков
#define MUTEMENU // Поддержка команды /mute
#define GAG_ACCESS ADMIN_BAN // Доступ к функциям гага
#define SORRYTIME 60 // Как часто можно пользоваться командой /sorry. Время в секундах
#define PREFIX "*" // Префикс в чате
#define SUPERADMIN // Админ с флагом L(изменить можно на 281 строке) может гагать других админов с иммунитетом
new g_BlockTimes[] = // Время блокировки в минутах
{
30,
60,
180,
360,
720,
1440,
10080
}
new g_AllowCommands[][] = // Разрешенные команды
{
"/me",
"/top15",
"/rank",
"/hp",
"/rtv",
"/top",
"/rs",
"rtv"
}
/* Словарь плагина */
#define MSG_SORRY_FLOOD "^4%s ^1Повторно извиниться можно через %d секунд(у, ы)"
#define MSG_SORRY_ADMIN "^4%s ^1Игрок %s извинился и просит снять заглушку"
// #define MSG_CHAT_IS_BLOCKED "^4%s ^1Вы заглушены"
#define MSG_BLOCK_EXPIRED_TIME "^4%s ^1До снятия заглушки осталось %d минут(у, ы)"
#define MSG_BLOCK_EXPIRED "^4%s ^1Время заглушки истекло. Подождите обновления информации"
#define MSG_SAY_SORRY "^4%s ^1Чтобы извиниться, напишите в чат /sorry"
#define MSG_CHAT_SORRY "^4%s ^1Ваше извинение было отправлено"
#define MSG_CHAT_UNBLOCK_ALL "^4%s ^1Администратор %s снял заглушку с игрока %s"
#define MSG_CHAT_UNBLOCK_PL "^4%s ^1Администратор %s снял с Вас заглушку"
#define MSG_CHAT_BLOCK_ALL "^4%s ^1Администратор %s заглушил %s %s"
#define MSG_CHAT_BLOCK_PL "^4%s ^1Администратор %s заглушил Вас %s"
#define MSG_MUTE_ALL_PLAYERS "^4%s ^1Вы заглушили всех игроков"
#define MSG_UNMUTE_ALL_PLAYERS "^4%s ^1Вы сняли заглушку со всех игроков"
#define MSG_UNMUTE_PLAYER "^4%s ^1Вы сняли заглушку с игрока %s"
#define MSG_MUTE_PLAYER "^4%s ^1Вы заглушили игрока %s"
/* Технические данные */
#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_bitBlockChats;
enum _:DATA
{
IP[16],
STEAMID[25],
BLOCKTIME
};
new g_aLoadedData[33][DATA];
new Trie:g_tAllowCmds;
new Array:g_aUsersBlocked;
new g_arrData[DATA];
static iFloodTime[33], systime;
const PATH_STRLEN = 96;
new g_LogsDir[PATH_STRLEN];
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.2[VTC Api]"
#else
#define VERSION "1.4.2"
#endif
register_plugin("Advanced Gag", 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("amx_gagmenu", "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()
{
gmf_get_logsdir(g_LogsDir, charsmax(g_LogsDir));
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_bitBlockChats, id);
else ResetBit(g_bitBlockChats, 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_bitBlockChats, 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_bitBlockChats, 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
{
ChatColor(id, 0, MSG_CHAT_SORRY, PREFIX);
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)
{
new 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), "\yМеню заглушки\d (%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, "\y%d. \d%s \r*^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, "\y%d. \d%s \y*^n", ++a, sName);
else
{
iKeys |= (1 << a++);
if(GetBit(g_bitBlockChats, players[id][i]))
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y%d. \w%s \r (снять заглушку)^n", a, sName);
else
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y%d. \w%s^n", a, sName);
}
}
if(!g_BlockTimes[g_iMenuSelectBlock[id]])
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\y8. \wЗаглушить навсегда^n^n");
else iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\y8. \wЗаглушить на %d мин^n^n", g_BlockTimes[g_iMenuSelectBlock[id]]);
if(end != pnum)
{
formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y9. \wДалее^n\y0. \w%s", iPos ? "Назад" : "Выход");
iKeys |= MENU_KEY_9;
}
else formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y0. \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], AdmAuthId[24], UsrAuthId[24];
new iPlayer = players[id][g_iMenuPos[id] * 7 + iKey];
get_user_name(id, sNameAdmin, charsmax(sNameAdmin));
get_user_authid(id, AdmAuthId, charsmax(AdmAuthId));
get_user_name(iPlayer, sNamePlayer, charsmax(sNamePlayer));
get_user_authid(iPlayer, UsrAuthId, charsmax(UsrAuthId));
if(GetBit(g_bitBlockChats, iPlayer))
{
UserBlock(iPlayer, 0);
iFloodTime[iPlayer] = 0;
ChatColor(0, iPlayer, MSG_CHAT_UNBLOCK_ALL, PREFIX, sNameAdmin, sNamePlayer);
ChatColor(iPlayer, 0, MSG_CHAT_UNBLOCK_PL, PREFIX, sNameAdmin, sNamePlayer);
}
else
{
UserBlock(iPlayer, 1, g_BlockTimes[g_iMenuSelectBlock[id]]);
new blocktimeinfo[32];
if(!g_BlockTimes[g_iMenuSelectBlock[id]])
formatex(blocktimeinfo, charsmax(blocktimeinfo), "навсегда");
else formatex(blocktimeinfo, charsmax(blocktimeinfo), "на %d минут(у, ы)", g_BlockTimes[g_iMenuSelectBlock[id]]);
Logging(g_LogsDir, "mute_", "^"%s<%d><%s><>^" mute %s ^"%s<%d><%s><>^" ", sNameAdmin, get_user_userid(id), AdmAuthId, blocktimeinfo, sNamePlayer, get_user_userid(iPlayer), UsrAuthId);
ChatColor(0, iPlayer, MSG_CHAT_BLOCK_ALL, PREFIX, sNameAdmin, sNamePlayer, blocktimeinfo);
ChatColor(iPlayer, 0, MSG_CHAT_BLOCK_PL, PREFIX, sNameAdmin, /*sNamePlayer,*/ 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)
{
new 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), "\yМеню заглушки \d(%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, "\y%d. \d%s \r*^n", ++a, sName);
else
{
iKeys |= (1 << a++);
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y%d. \w%s%s^n", a, sName, g_iMutePlayer[id][plMute[id][i]] ? "\r (снять заглушку)" : "");
}
}
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "^n\y7. \wЗаглушить всех^n");
iLen += formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y8. \wСнять заглушку со всех^n^n");
if(end != plNum[id])
{
formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y9. \wДалее^n\y0. \w%s", iPos ? "Назад" : "Выход");
iKeys |= MENU_KEY_9;
}
else formatex(sMenu[iLen], charsmax(sMenu) - iLen, "\y0. \w%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_bitBlockChats, id);
#if defined USE_API_VTC
VTC_MuteClient(id);
#endif
client_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_bitBlockChats, 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];
vformat(szMsg, charsmax(szMsg), szMessage, 4);
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, 76, .player = pl[i]);
write_byte(pl[i]);
write_string(szMsg);
message_end();
}
}
Logging(const LogsDir[], const FileName[] = "", const Message[], any:...) {
new Msg[512], Time[32], File[PATH_STRLEN + 32], pFile;
vformat(Msg, charsmax(Msg), Message, 4);
get_time("%Y%m.log", Time, charsmax(Time));
formatex(File, charsmax(File), "%s/%s%s", LogsDir, FileName, Time);
pFile = fopen(File, "at");
get_time("%Y/%m/%d - %H:%M:%S", Time, charsmax(Time));
fprintf(pFile, "%s: %s^n", Time, Msg);
fclose(pFile);
}
Тема перемещена в раздел "Биржа труда" // Subb98