Files
super-admin-menu/scripting/super_admin_menu.sp
T

1391 lines
41 KiB
SourcePawn
Raw Normal View History

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <cstrike>
#pragma semicolon 1
#pragma newdecls required
#define MENU_TIME MENU_TIME_FOREVER
int g_iSelectedTargetUserId[MAXPLAYERS + 1];
bool g_bInvisible[MAXPLAYERS + 1];
bool g_bZeroDamageAttack[MAXPLAYERS + 1];
bool g_bSuperRecoil[MAXPLAYERS + 1];
bool g_bDrugEffect[MAXPLAYERS + 1];
bool g_bRandomFov[MAXPLAYERS + 1];
bool g_bInvertMovement[MAXPLAYERS + 1];
Handle g_hDrugTimer[MAXPLAYERS + 1];
Handle g_hRandomFovTimer[MAXPLAYERS + 1];
int g_iEffectTargetUserId[MAXPLAYERS + 1];
public Plugin myinfo =
{
name = "Super Admin Menu",
author = "OpenAI + deidara.dev",
description = "Единое супер-админ меню по команде sm_sadmin",
version = "1.3.2-debug"
};
public void OnPluginStart()
{
RegConsoleCmd("sm_sadmin", Command_SuperAdminMenu, "Открыть супер-админ меню");
HookEvent("player_spawn", OnPlayerSpawn, EventHookMode_Post);
HookEvent("weapon_fire", OnWeaponFire, EventHookMode_Post);
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
OnClientPutInServer(i);
}
}
public void OnClientPutInServer(int client)
{
SDKHook(client, SDKHook_SetTransmit, Hook_SetTransmit);
SDKHook(client, SDKHook_OnTakeDamage, Hook_OnTakeDamage);
SDKHook(client, SDKHook_OnTakeDamageAlive, Hook_OnTakeDamage);
g_hDrugTimer[client] = null;
g_hRandomFovTimer[client] = null;
}
public void OnClientDisconnect(int client)
{
StopDrugEffect(client);
StopRandomFov(client);
g_iSelectedTargetUserId[client] = 0;
g_iEffectTargetUserId[client] = 0;
g_bInvisible[client] = false;
g_bZeroDamageAttack[client] = false;
g_bSuperRecoil[client] = false;
g_bDrugEffect[client] = false;
g_bRandomFov[client] = false;
g_bInvertMovement[client] = false;
}
public void OnPlayerSpawn(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if (!IsValidClient(client))
return;
if (g_bInvisible[client])
{
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 0);
HidePlayerWeapons(client, true);
}
if (g_bRandomFov[client])
SetEntProp(client, Prop_Send, "m_iFOV", GetRandomInt(65, 125));
else if (!g_bDrugEffect[client])
SetEntProp(client, Prop_Send, "m_iFOV", 90);
}
public Action Hook_SetTransmit(int entity, int viewer)
{
if (entity < 1 || entity > MaxClients)
return Plugin_Continue;
if (!g_bInvisible[entity])
return Plugin_Continue;
if (entity == viewer)
return Plugin_Continue;
return Plugin_Handled;
}
public Action Command_SuperAdminMenu(int client, int args)
{
if (!IsValidClient(client))
{
ReplyToCommand(client, "[SM] Эту команду можно использовать только из игры.");
return Plugin_Handled;
}
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
{
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
return Plugin_Handled;
}
ShowMainMenu(client);
return Plugin_Handled;
}
void ShowMainMenu(int client)
{
Menu menu = new Menu(MenuHandler_Main);
menu.SetTitle("Супер-Админ Меню");
menu.ExitButton = true;
bool isDeidara = IsClientInAllowedGroup(client);
if (isDeidara)
{
menu.AddItem("sets", "Выдать сет");
menu.AddItem("money", "Выдать деньги");
menu.AddItem("respawn", "Респавн");
menu.AddItem("restore", "Восстановить 100 HP / 100 Armor");
menu.AddItem("invis", g_bInvisible[client] ? "Выключить невидимость" : "Включить невидимость");
menu.AddItem("tp_to", "Телепорт к игроку");
menu.AddItem("tp_here", "Телепортировать игрока к себе");
menu.AddItem("plant", "Телепорт на плент");
menu.AddItem("effects", "Эффекты игрока");
}
else
{
// Обычный админ: только Эффекты игрока
menu.AddItem("effects", "Эффекты игрока");
}
menu.Display(client, MENU_TIME);
}
public int MenuHandler_Main(Menu menu, MenuAction action, int client, int item)
{
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action != MenuAction_Select)
return 0;
char info[32];
menu.GetItem(item, info, sizeof(info));
bool isDeidara = IsClientInAllowedGroup(client);
// Обычные админы могут открыть только меню эффектов
if (!isDeidara && !StrEqual(info, "effects"))
{
PrintToChat(client, "[SM] У тебя нет доступа к этому пункту.");
ShowMainMenu(client);
return 0;
}
if (StrEqual(info, "effects"))
{
ShowEffectTargetMenu(client);
return 0;
}
if (StrEqual(info, "sets"))
{
ShowTargetMenu(client, "set");
}
else if (StrEqual(info, "money"))
{
ShowTargetMenu(client, "money");
}
else if (StrEqual(info, "respawn"))
{
ShowTargetMenu(client, "respawn");
}
else if (StrEqual(info, "restore"))
{
ShowTargetMenu(client, "restore");
}
else if (StrEqual(info, "invis"))
{
ToggleInvisibility(client);
ShowMainMenu(client);
}
else if (StrEqual(info, "tp_to"))
{
ShowTargetMenu(client, "tp_to");
}
else if (StrEqual(info, "tp_here"))
{
ShowTargetMenu(client, "tp_here");
}
else if (StrEqual(info, "plant"))
{
ShowPlantMenu(client);
}
return 0;
}
void ShowTargetMenu(int client, const char[] actionType)
{
if (!IsClientInAllowedGroup(client)
&& (StrEqual(actionType, "restore") || StrEqual(actionType, "tp_to") || StrEqual(actionType, "tp_here")))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
ShowMainMenu(client);
return;
}
Menu menu = new Menu(MenuHandler_TargetSelect);
char title[128];
Format(title, sizeof(title), "Выбор игрока [%s]", actionType);
menu.SetTitle(title);
menu.ExitButton = true;
menu.ExitBackButton = true;
char itemInfo[32];
char name[MAX_NAME_LENGTH];
int added = 0;
if (StrEqual(actionType, "restore") || StrEqual(actionType, "respawn") || StrEqual(actionType, "set"))
{
Format(itemInfo, sizeof(itemInfo), "%s:self", actionType);
menu.AddItem(itemInfo, "Себе");
added++;
}
if (StrEqual(actionType, "restore") || StrEqual(actionType, "respawn"))
{
Format(itemInfo, sizeof(itemInfo), "%s:all", actionType);
menu.AddItem(itemInfo, "Всем");
added++;
}
for (int i = 1; i <= MaxClients; i++)
{
if (!IsValidClient(i) || IsFakeClient(i))
continue;
if (StrEqual(actionType, "set") && !IsPlayerAlive(i))
continue;
GetClientName(i, name, sizeof(name));
Format(itemInfo, sizeof(itemInfo), "%s:%d", actionType, GetClientUserId(i));
menu.AddItem(itemInfo, name);
added++;
}
if (added == 0)
{
delete menu;
PrintToChat(client, "[SM] Нет доступных игроков.");
ShowMainMenu(client);
return;
}
menu.Display(client, MENU_TIME);
}
public int MenuHandler_TargetSelect(Menu menu, MenuAction action, int client, int item)
{
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowMainMenu(client);
return 0;
}
if (action != MenuAction_Select)
return 0;
char info[32], parts[2][16];
menu.GetItem(item, info, sizeof(info));
ExplodeString(info, ":", parts, sizeof(parts), sizeof(parts[]));
if (StrEqual(parts[0], "set"))
{
if (StrEqual(parts[1], "self"))
g_iSelectedTargetUserId[client] = GetClientUserId(client);
else
g_iSelectedTargetUserId[client] = StringToInt(parts[1]);
ShowSetMenu(client);
}
else if (StrEqual(parts[0], "money"))
{
g_iSelectedTargetUserId[client] = StringToInt(parts[1]);
ShowMoneyMenu(client);
}
else if (StrEqual(parts[0], "restore"))
{
HandleRestoreSelection(client, parts[1]);
}
else if (StrEqual(parts[0], "respawn"))
{
HandleRespawnSelection(client, parts[1]);
}
else if (StrEqual(parts[0], "tp_to"))
{
HandleTeleportToPlayer(client, StringToInt(parts[1]));
}
else if (StrEqual(parts[0], "tp_here"))
{
HandleTeleportPlayerHere(client, StringToInt(parts[1]));
}
return 0;
}
void ShowSetMenu(int client)
{
int target = GetClientOfUserId(g_iSelectedTargetUserId[client]);
if (!IsValidClient(target) || !IsPlayerAlive(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return;
}
char title[128];
Format(title, sizeof(title), "Выдать сет игроку: %N", target);
Menu menu = new Menu(MenuHandler_Set);
menu.SetTitle(title);
menu.ExitButton = true;
menu.ExitBackButton = true;
menu.AddItem("ak", "AK-47");
menu.AddItem("m4a4", "M4A4");
menu.AddItem("m4a1s", "M4A1-S");
menu.AddItem("awp", "AWP");
menu.AddItem("pistol", "Deagle Only");
menu.Display(client, MENU_TIME);
}
public int MenuHandler_Set(Menu menu, MenuAction action, int client, int item)
{
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowTargetMenu(client, "set");
return 0;
}
if (action != MenuAction_Select)
return 0;
int target = GetClientOfUserId(g_iSelectedTargetUserId[client]);
if (!IsValidClient(target) || !IsPlayerAlive(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return 0;
}
char info[32];
menu.GetItem(item, info, sizeof(info));
GiveFullLoadout(target, info);
PrintToRootAdmins("[SM] %N выдал сет игроку %N.", client, target);
ShowSetMenu(client);
return 0;
}
void ShowMoneyMenu(int client)
{
int target = GetClientOfUserId(g_iSelectedTargetUserId[client]);
if (!IsValidClient(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return;
}
char title[128];
Format(title, sizeof(title), "Выдать деньги игроку: %N", target);
Menu menu = new Menu(MenuHandler_Money);
menu.SetTitle(title);
menu.ExitButton = true;
menu.ExitBackButton = true;
menu.AddItem("3000", "3000$");
menu.AddItem("5000", "5000$");
menu.AddItem("10000", "10000$");
menu.AddItem("16000", "16000$");
menu.Display(client, MENU_TIME);
}
public int MenuHandler_Money(Menu menu, MenuAction action, int client, int item)
{
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowTargetMenu(client, "money");
return 0;
}
if (action != MenuAction_Select)
return 0;
int target = GetClientOfUserId(g_iSelectedTargetUserId[client]);
if (!IsValidClient(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return 0;
}
char info[16];
menu.GetItem(item, info, sizeof(info));
int amount = StringToInt(info);
int currentMoney = GetEntProp(target, Prop_Send, "m_iAccount");
int newMoney = currentMoney + amount;
if (newMoney > 16000)
newMoney = 16000;
SetEntProp(target, Prop_Send, "m_iAccount", newMoney);
PrintToRootAdmins("[SM] %N выдал %d$ игроку %N. Теперь у него %d$.", client, amount, target, newMoney);
ShowMoneyMenu(client);
return 0;
}
void HandleRestoreSelection(int client, const char[] targetInfo)
{
if (!IsClientInAllowedGroup(client))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
ShowMainMenu(client);
return;
}
if (StrEqual(targetInfo, "self"))
{
RestorePlayer(client);
PrintToRootAdmins("[SM] %N восстановил себе 100 HP / 100 Armor.", client);
}
else if (StrEqual(targetInfo, "all"))
{
int restored = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (IsValidClient(i) && IsPlayerAlive(i))
{
RestorePlayer(i);
restored++;
}
}
PrintToRootAdmins("[SM] %N восстановил всех живых игроков (%d).", client, restored);
}
else
{
int target = GetClientOfUserId(StringToInt(targetInfo));
if (!IsValidClient(target) || !IsPlayerAlive(target))
{
PrintToChat(client, "[SM] Игрок недоступен или мертв.");
}
else
{
RestorePlayer(target);
PrintToRootAdmins("[SM] %N восстановил игроку %N 100 HP / 100 Armor.", client, target);
}
}
ShowMainMenu(client);
}
void HandleRespawnSelection(int client, const char[] targetInfo)
{
if (StrEqual(targetInfo, "self"))
{
if (CanRespawnPlayer(client))
{
CS_RespawnPlayer(client);
PrintToRootAdmins("[SM] %N возродил себя.", client);
}
else
{
PrintToChat(client, "[SM] Вы уже живы или не выбрали команду.");
}
}
else if (StrEqual(targetInfo, "all"))
{
int respawned = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (CanRespawnPlayer(i))
{
CS_RespawnPlayer(i);
respawned++;
}
}
PrintToRootAdmins("[SM] %N возродил игроков: %d.", client, respawned);
}
else
{
int target = GetClientOfUserId(StringToInt(targetInfo));
if (!CanRespawnPlayer(target))
{
PrintToChat(client, "[SM] Игрок недоступен, уже жив или не выбрал команду.");
}
else
{
CS_RespawnPlayer(target);
PrintToRootAdmins("[SM] %N возродил игрока %N.", client, target);
}
}
ShowMainMenu(client);
}
void ToggleInvisibility(int client)
{
if (!IsClientInAllowedGroup(client))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
return;
}
if (!IsPlayerAlive(client))
{
PrintToChat(client, "[SM] Невидимость можно включать только когда ты жив.");
return;
}
g_bInvisible[client] = !g_bInvisible[client];
if (g_bInvisible[client])
{
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 0);
SetEntProp(client, Prop_Send, "m_bSpotted", 0);
HidePlayerWeapons(client, true);
PrintToRootAdmins("[SM] %N включил невидимость.", client);
}
else
{
SetEntityRenderMode(client, RENDER_NORMAL);
SetEntityRenderColor(client, 255, 255, 255, 255);
HidePlayerWeapons(client, false);
PrintToRootAdmins("[SM] %N выключил невидимость.", client);
}
}
void HidePlayerWeapons(int client, bool hide)
{
for (int slot = 0; slot <= 4; slot++)
{
int weapon = GetPlayerWeaponSlot(client, slot);
if (weapon != -1 && IsValidEntity(weapon))
{
SetEntityRenderMode(weapon, RENDER_TRANSCOLOR);
SetEntityRenderColor(weapon, 255, 255, 255, hide ? 0 : 255);
}
}
}
void HandleTeleportToPlayer(int client, int targetUserId)
{
if (!IsClientInAllowedGroup(client))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
return;
}
int target = GetClientOfUserId(targetUserId);
if (!IsValidClient(target) || !IsPlayerAlive(target) || !IsPlayerAlive(client))
{
PrintToChat(client, "[SM] Телепорт невозможен. Ты или выбранный игрок мертвы/недоступны.");
ShowMainMenu(client);
return;
}
float pos[3], ang[3], fwdVec[3], flatAng[3];
GetClientAbsOrigin(target, pos);
GetClientAbsAngles(target, ang);
// Позиция: 20 юнитов перед целью (по горизонтали)
flatAng[0] = 0.0; flatAng[1] = ang[1]; flatAng[2] = 0.0;
GetAngleVectors(flatAng, fwdVec, NULL_VECTOR, NULL_VECTOR);
pos[0] += fwdVec[0] * 20.0;
pos[1] += fwdVec[1] * 20.0;
// Смотрим на цель (разворот на 180°)
float faceAng[3];
faceAng[0] = 0.0;
faceAng[1] = ang[1] + 180.0;
if (faceAng[1] > 180.0) faceAng[1] -= 360.0;
if (faceAng[1] <= -180.0) faceAng[1] += 360.0;
faceAng[2] = 0.0;
TeleportEntity(client, pos, faceAng, NULL_VECTOR);
PrintToRootAdmins("[SM] %N телепортировался к игроку %N.", client, target);
ShowMainMenu(client);
}
void HandleTeleportPlayerHere(int client, int targetUserId)
{
if (!IsClientInAllowedGroup(client))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
return;
}
int target = GetClientOfUserId(targetUserId);
if (!IsValidClient(target) || !IsPlayerAlive(target) || !IsPlayerAlive(client))
{
PrintToChat(client, "[SM] Телепорт невозможен. Ты или выбранный игрок мертвы/недоступны.");
ShowMainMenu(client);
return;
}
float pos[3], ang[3], fwdVec[3], flatAng[3];
GetClientAbsOrigin(client, pos);
GetClientAbsAngles(client, ang);
// Позиция: 20 юнитов перед собой (по горизонтали)
flatAng[0] = 0.0; flatAng[1] = ang[1]; flatAng[2] = 0.0;
GetAngleVectors(flatAng, fwdVec, NULL_VECTOR, NULL_VECTOR);
pos[0] += fwdVec[0] * 20.0;
pos[1] += fwdVec[1] * 20.0;
// Игрок смотрит на нас (разворот на 180°)
float faceAng[3];
faceAng[0] = 0.0;
faceAng[1] = ang[1] + 180.0;
if (faceAng[1] > 180.0) faceAng[1] -= 360.0;
if (faceAng[1] <= -180.0) faceAng[1] += 360.0;
faceAng[2] = 0.0;
TeleportEntity(target, pos, faceAng, NULL_VECTOR);
PrintToRootAdmins("[SM] %N телепортировал игрока %N к себе.", client, target);
ShowMainMenu(client);
}
void ShowPlantMenu(int client)
{
if (!IsClientInAllowedGroup(client))
{
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
ShowMainMenu(client);
return;
}
Menu menu = new Menu(MenuHandler_Plant);
menu.SetTitle("Телепорт на плент");
menu.ExitButton = true;
menu.ExitBackButton = true;
menu.AddItem("A", "Плент A");
menu.AddItem("B", "Плент B");
menu.Display(client, MENU_TIME);
}
public int MenuHandler_Plant(Menu menu, MenuAction action, int client, int item)
{
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowMainMenu(client);
return 0;
}
if (action != MenuAction_Select)
return 0;
char info[8];
menu.GetItem(item, info, sizeof(info));
if (!IsPlayerAlive(client))
{
PrintToChat(client, "[SM] Для телепорта на плент нужно быть живым.");
ShowMainMenu(client);
return 0;
}
float origin[3];
if (FindBombsiteCenter(info[0], origin))
{
origin[2] += 10.0;
TeleportEntity(client, origin, NULL_VECTOR, NULL_VECTOR);
PrintToRootAdmins("[SM] %N телепортировался на плент %s.", client, info);
}
else
{
PrintToChat(client, "[SM] Плент %s не найден на этой карте.", info);
}
ShowMainMenu(client);
return 0;
}
// Проверяет, совпадает ли имя сущности с нужным плентом (A или B)
bool IsBombsiteNameMatch(int entity, char siteLetter)
{
char name[64];
GetEntPropString(entity, Prop_Data, "m_iName", name, sizeof(name));
if (name[0] == '\0')
return false;
char lo[2];
lo[0] = CharToLower(siteLetter);
lo[1] = '\0';
char pat1[32], pat2[32], pat3[32], pat4[32];
Format(pat1, sizeof(pat1), "bombsite_%s", lo); // bombsite_a / bombsite_b
Format(pat2, sizeof(pat2), "bombsite%s", lo); // bombsitea / bombsiteb
Format(pat3, sizeof(pat3), "site_%s", lo); // site_a / site_b
Format(pat4, sizeof(pat4), "bomb_%s", lo); // bomb_a / bomb_b
return (StrContains(name, pat1, false) != -1
|| StrContains(name, pat2, false) != -1
|| StrContains(name, pat3, false) != -1
|| StrContains(name, pat4, false) != -1);
}
// Центр brush-сущности через абсолютный origin + локальные bounds
void GetBrushCenter(int entity, float out[3])
{
float absOrigin[3], mins[3], maxs[3];
GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", absOrigin);
GetEntPropVector(entity, Prop_Send, "m_vecMins", mins);
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", maxs);
out[0] = absOrigin[0] + (mins[0] + maxs[0]) / 2.0;
out[1] = absOrigin[1] + (mins[1] + maxs[1]) / 2.0;
out[2] = absOrigin[2] + maxs[2]; // верхняя граница, игрок встанет сверху
}
bool FindBombsiteCenter(char siteLetter, float origin[3])
{
// Проход 1: func_bomb_target (brush) с совпадением имени
int entity = -1;
while ((entity = FindEntityByClassname(entity, "func_bomb_target")) != -1)
{
if (IsBombsiteNameMatch(entity, siteLetter))
{
GetBrushCenter(entity, origin);
return true;
}
}
// Проход 2: info_bomb_target (point entity) с совпадением имени
entity = -1;
while ((entity = FindEntityByClassname(entity, "info_bomb_target")) != -1)
{
if (IsBombsiteNameMatch(entity, siteLetter))
{
GetEntPropVector(entity, Prop_Data, "m_vecAbsOrigin", origin);
return true;
}
}
// Проход 3: безымянный/нестандартный — берём первый/второй по порядку
// A = первый найденный, B = второй найденный
entity = -1;
int found = 0;
int target = (siteLetter == 'A') ? 1 : 2;
while ((entity = FindEntityByClassname(entity, "func_bomb_target")) != -1)
{
found++;
if (found == target)
{
GetBrushCenter(entity, origin);
return true;
}
}
return false;
}
void RestorePlayer(int client)
{
if (!IsValidClient(client) || !IsPlayerAlive(client))
return;
SetEntityHealth(client, 100);
SetEntProp(client, Prop_Send, "m_ArmorValue", 100);
SetEntProp(client, Prop_Send, "m_bHasHelmet", 1);
}
bool CanRespawnPlayer(int client)
{
return IsValidClient(client) && !IsPlayerAlive(client) && GetClientTeam(client) >= CS_TEAM_T;
}
void GiveFullLoadout(int client, const char[] type)
{
StripWeapons(client);
SetEntProp(client, Prop_Send, "m_ArmorValue", 100);
SetEntProp(client, Prop_Send, "m_bHasHelmet", 1);
if (GetClientTeam(client) == CS_TEAM_CT)
SetEntProp(client, Prop_Send, "m_bHasDefuser", 1);
if (StrEqual(type, "ak"))
GivePlayerItem(client, "weapon_ak47");
else if (StrEqual(type, "m4a4"))
GivePlayerItem(client, "weapon_m4a1");
else if (StrEqual(type, "m4a1s"))
GivePlayerItem(client, "weapon_m4a1_silencer");
else if (StrEqual(type, "awp"))
GivePlayerItem(client, "weapon_awp");
GivePlayerItem(client, "weapon_deagle");
GivePlayerItem(client, "weapon_knife");
if (!StrEqual(type, "pistol"))
{
GivePlayerItem(client, "weapon_hegrenade");
GivePlayerItem(client, "weapon_smokegrenade");
GivePlayerItem(client, "weapon_flashbang");
GivePlayerItem(client, "weapon_flashbang");
if (GetClientTeam(client) == CS_TEAM_T)
GivePlayerItem(client, "weapon_molotov");
else
GivePlayerItem(client, "weapon_incgrenade");
}
if (g_bInvisible[client])
HidePlayerWeapons(client, true);
}
void StripWeapons(int client)
{
int weapon;
for (int slot = 0; slot <= 4; slot++)
{
while ((weapon = GetPlayerWeaponSlot(client, slot)) != -1)
{
RemovePlayerItem(client, weapon);
AcceptEntityInput(weapon, "Kill");
}
}
}
void ShowEffectTargetMenu(int client)
{
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
{
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
ShowMainMenu(client);
return;
}
Menu menu = new Menu(MenuHandler_EffectTarget);
menu.SetTitle("Эффекты: выбор игрока");
menu.ExitButton = true;
menu.ExitBackButton = true;
char info[16];
char name[MAX_NAME_LENGTH];
int added = 0;
for (int i = 1; i <= MaxClients; i++)
{
if (!IsValidClient(i) || IsFakeClient(i))
continue;
GetClientName(i, name, sizeof(name));
IntToString(GetClientUserId(i), info, sizeof(info));
menu.AddItem(info, name);
added++;
}
if (added == 0)
{
delete menu;
PrintToChat(client, "[SM] Нет доступных игроков.");
ShowMainMenu(client);
return;
}
menu.Display(client, MENU_TIME);
}
public int MenuHandler_EffectTarget(Menu menu, MenuAction action, int client, int item)
{
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
{
if (action == MenuAction_End)
delete menu;
else if (action == MenuAction_Select)
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
return 0;
}
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowMainMenu(client);
return 0;
}
if (action != MenuAction_Select)
return 0;
char info[16];
menu.GetItem(item, info, sizeof(info));
g_iEffectTargetUserId[client] = StringToInt(info);
ShowEffectMenu(client);
return 0;
}
void ShowEffectMenu(int client)
{
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
{
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
ShowMainMenu(client);
return;
}
int target = GetClientOfUserId(g_iEffectTargetUserId[client]);
if (!IsValidClient(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return;
}
char title[128];
Format(title, sizeof(title), "Эффекты для игрока: %N", target);
Menu menu = new Menu(MenuHandler_EffectMenu);
menu.SetTitle(title);
menu.ExitButton = true;
menu.ExitBackButton = true;
menu.AddItem("nodamage", g_bZeroDamageAttack[target] ? "Выключить 0 урона" : "Включить 0 урона");
menu.AddItem("recoil", g_bSuperRecoil[target] ? "Выключить супер-отдачу" : "Включить супер-отдачу");
menu.AddItem("drug", g_bDrugEffect[target] ? "Выключить drug-эффект" : "Включить drug-эффект");
menu.AddItem("randomfov", g_bRandomFov[target] ? "Выключить случайный FOV" : "Включить случайный FOV");
menu.AddItem("invertmove", g_bInvertMovement[target] ? "Выключить инверсию движения" : "Включить инверсию движения");
menu.AddItem("shake", "Сильно тряхнуть экран");
menu.Display(client, MENU_TIME);
}
public int MenuHandler_EffectMenu(Menu menu, MenuAction action, int client, int item)
{
if (!IsClientInAllowedGroup(client) && !IsRegularAdmin(client))
{
if (action == MenuAction_End)
delete menu;
else if (action == MenuAction_Select)
PrintToChat(client, "[SM] У тебя нет доступа к этому меню.");
return 0;
}
if (action == MenuAction_End)
{
delete menu;
return 0;
}
if (action == MenuAction_Cancel)
{
if (item == MenuCancel_ExitBack)
ShowEffectTargetMenu(client);
return 0;
}
if (action != MenuAction_Select)
return 0;
int target = GetClientOfUserId(g_iEffectTargetUserId[client]);
if (!IsValidClient(target))
{
PrintToChat(client, "[SM] Игрок недоступен.");
ShowMainMenu(client);
return 0;
}
char info[16];
menu.GetItem(item, info, sizeof(info));
if (StrEqual(info, "nodamage"))
{
g_bZeroDamageAttack[target] = !g_bZeroDamageAttack[target];
PrintToRootAdmins("[SM] %N: 0 урона для %N -> %s", client, target, g_bZeroDamageAttack[target] ? "ВКЛ" : "ВЫКЛ");
LogAdminAction(client, target, "0 урона -> %s", g_bZeroDamageAttack[target] ? "ВКЛ" : "ВЫКЛ");
}
else if (StrEqual(info, "recoil"))
{
g_bSuperRecoil[target] = !g_bSuperRecoil[target];
PrintToRootAdmins("[SM] %N: супер-отдача для %N -> %s", client, target, g_bSuperRecoil[target] ? "ВКЛ" : "ВЫКЛ");
LogAdminAction(client, target, "Супер-отдача -> %s", g_bSuperRecoil[target] ? "ВКЛ" : "ВЫКЛ");
}
else if (StrEqual(info, "drug"))
{
ToggleDrugEffect(target);
PrintToRootAdmins("[SM] %N: drug-эффект для %N -> %s", client, target, g_bDrugEffect[target] ? "ВКЛ" : "ВЫКЛ");
LogAdminAction(client, target, "Drug-эффект -> %s", g_bDrugEffect[target] ? "ВКЛ" : "ВЫКЛ");
}
else if (StrEqual(info, "randomfov"))
{
ToggleRandomFov(target);
PrintToRootAdmins("[SM] %N: случайный FOV для %N -> %s", client, target, g_bRandomFov[target] ? "ВКЛ" : "ВЫКЛ");
LogAdminAction(client, target, "Случайный FOV -> %s", g_bRandomFov[target] ? "ВКЛ" : "ВЫКЛ");
}
else if (StrEqual(info, "invertmove"))
{
g_bInvertMovement[target] = !g_bInvertMovement[target];
PrintToRootAdmins("[SM] %N: инверсия движения для %N -> %s", client, target, g_bInvertMovement[target] ? "ВКЛ" : "ВЫКЛ");
LogAdminAction(client, target, "Инверсия движения -> %s", g_bInvertMovement[target] ? "ВКЛ" : "ВЫКЛ");
}
else if (StrEqual(info, "shake"))
{
ApplyStrongShake(target);
PrintToRootAdmins("[SM] %N сильно тряхнул экран игрока %N.", client, target);
LogAdminAction(client, target, "Тряска экрана");
}
ShowEffectMenu(client);
return 0;
}
public Action Hook_OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype)
{
if (attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && g_bZeroDamageAttack[attacker])
{
damage = 0.0;
damagetype = 0;
return Plugin_Changed;
}
return Plugin_Continue;
}
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
{
if (!IsValidClient(client) || !IsPlayerAlive(client))
return Plugin_Continue;
bool changed = false;
if (g_bInvertMovement[client])
{
vel[0] = -vel[0];
vel[1] = -vel[1];
bool hasForward = (buttons & IN_FORWARD) != 0;
bool hasBack = (buttons & IN_BACK) != 0;
bool hasMoveLeft = (buttons & IN_MOVELEFT) != 0;
bool hasMoveRight= (buttons & IN_MOVERIGHT) != 0;
buttons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT);
if (hasForward) buttons |= IN_BACK;
if (hasBack) buttons |= IN_FORWARD;
if (hasMoveLeft) buttons |= IN_MOVERIGHT;
if (hasMoveRight) buttons |= IN_MOVELEFT;
changed = true;
}
return changed ? Plugin_Changed : Plugin_Continue;
}
public void OnWeaponFire(Event event, const char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(event.GetInt("userid"));
if (!IsValidClient(client) || !IsPlayerAlive(client) || !g_bSuperRecoil[client])
return;
float recoil[3];
recoil[0] = GetRandomFloat(-18.0, -10.0);
recoil[1] = GetRandomFloat(-8.0, 8.0);
recoil[2] = 0.0;
SetEntPropVector(client, Prop_Send, "m_aimPunchAngle", recoil);
SetEntPropVector(client, Prop_Send, "m_viewPunchAngle", recoil);
ApplyStrongShake(client);
}
void ToggleRandomFov(int client)
{
if (!IsValidClient(client))
return;
if (g_bRandomFov[client])
{
StopRandomFov(client);
return;
}
g_bRandomFov[client] = true;
if (g_hRandomFovTimer[client] != null)
{
KillTimer(g_hRandomFovTimer[client]);
g_hRandomFovTimer[client] = null;
}
if (IsPlayerAlive(client))
SetEntProp(client, Prop_Send, "m_iFOV", GetRandomInt(65, 125));
g_hRandomFovTimer[client] = CreateTimer(1.0, Timer_RandomFov, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
void StopRandomFov(int client)
{
if (client < 1 || client > MaxClients)
return;
g_bRandomFov[client] = false;
if (g_hRandomFovTimer[client] != null)
{
KillTimer(g_hRandomFovTimer[client]);
g_hRandomFovTimer[client] = null;
}
if (IsValidClient(client) && !g_bDrugEffect[client])
SetEntProp(client, Prop_Send, "m_iFOV", 90);
}
public Action Timer_RandomFov(Handle timer, any userid)
{
int client = GetClientOfUserId(userid);
if (!IsValidClient(client) || !IsPlayerAlive(client) || !g_bRandomFov[client])
{
if (client > 0 && client <= MaxClients)
g_hRandomFovTimer[client] = null;
return Plugin_Stop;
}
SetEntProp(client, Prop_Send, "m_iFOV", GetRandomInt(65, 125));
return Plugin_Continue;
}
void ToggleDrugEffect(int client)
{
if (!IsValidClient(client))
return;
if (g_bDrugEffect[client])
{
StopDrugEffect(client);
return;
}
g_bDrugEffect[client] = true;
if (g_hDrugTimer[client] != null)
{
KillTimer(g_hDrugTimer[client]);
g_hDrugTimer[client] = null;
}
g_hDrugTimer[client] = CreateTimer(0.8, Timer_DrugEffect, GetClientUserId(client), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
void StopDrugEffect(int client)
{
if (client < 1 || client > MaxClients)
return;
g_bDrugEffect[client] = false;
if (g_hDrugTimer[client] != null)
{
KillTimer(g_hDrugTimer[client]);
g_hDrugTimer[client] = null;
}
if (IsValidClient(client) && !g_bRandomFov[client])
SetEntProp(client, Prop_Send, "m_iFOV", 90);
}
public Action Timer_DrugEffect(Handle timer, any userid)
{
int client = GetClientOfUserId(userid);
if (!IsValidClient(client) || !IsPlayerAlive(client) || !g_bDrugEffect[client])
{
if (client > 0 && client <= MaxClients)
g_hDrugTimer[client] = null;
return Plugin_Stop;
}
float punch[3];
punch[0] = GetRandomFloat(-7.0, 7.0);
punch[1] = GetRandomFloat(-7.0, 7.0);
punch[2] = 0.0;
SetEntPropVector(client, Prop_Send, "m_viewPunchAngle", punch);
SetEntPropVector(client, Prop_Send, "m_aimPunchAngle", punch);
SetEntProp(client, Prop_Send, "m_iFOV", GetRandomInt(80, 115));
ApplyStrongShake(client);
return Plugin_Continue;
}
void ApplyStrongShake(int client)
{
if (!IsValidClient(client))
return;
int shake = CreateEntityByName("env_shake");
if (shake == -1)
return;
DispatchKeyValueFloat(shake, "amplitude", 20.0);
DispatchKeyValueFloat(shake, "radius", 300.0);
DispatchKeyValueFloat(shake, "duration", 1.2);
DispatchKeyValueFloat(shake, "frequency", 255.0);
DispatchSpawn(shake);
float pos[3];
GetClientAbsOrigin(client, pos);
TeleportEntity(shake, pos, NULL_VECTOR, NULL_VECTOR);
AcceptEntityInput(shake, "StartShake", client, client);
CreateTimer(1.5, Timer_KillEntity, EntIndexToEntRef(shake), TIMER_FLAG_NO_MAPCHANGE);
}
public Action Timer_KillEntity(Handle timer, any entRef)
{
int ent = EntRefToEntIndex(entRef);
if (ent != INVALID_ENT_REFERENCE && ent != -1 && IsValidEntity(ent))
AcceptEntityInput(ent, "Kill");
return Plugin_Stop;
}
#define SADMIN_NOTIFY_GROUP_1 "DEIDARA"
#define SADMIN_NOTIFY_GROUP_2 "TESTER"
bool IsClientInAllowedGroup(int client)
{
if (!IsValidClient(client))
return false;
AdminId admin = GetUserAdmin(client);
if (admin == INVALID_ADMIN_ID)
return false;
int groupCount = GetAdminGroupCount(admin);
char groupName[64];
for (int i = 0; i < groupCount; i++)
{
GroupId gid = GetAdminGroup(admin, i, groupName, sizeof(groupName));
if (gid != INVALID_GROUP_ID)
{
if (StrEqual(groupName, SADMIN_NOTIFY_GROUP_1, false) || StrEqual(groupName, SADMIN_NOTIFY_GROUP_2, false))
{
return true;
}
}
}
return false;
}
// Обычный админ: имеет любой админ-флаг, но НЕ имеет ROOT и НЕ в группах DEIDARA/TESTER
bool IsRegularAdmin(int client)
{
if (!IsValidClient(client))
return false;
if (IsClientInAllowedGroup(client))
return false;
int flags = GetUserFlagBits(client);
if (flags == 0)
return false;
if ((flags & ADMFLAG_ROOT) != 0)
return false;
return true;
}
void PrintToRootAdmins(const char[] format, any ...)
{
char buffer[256];
VFormat(buffer, sizeof(buffer), format, 2);
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInAllowedGroup(i))
{
PrintToChat(i, "%s", buffer);
}
}
}
bool IsValidClient(int client)
{
return (client > 0 && client <= MaxClients && IsClientInGame(client));
}
// Логируем действие админа. Действия обычного админа -> в super_admin_menu.log.
// Все действия (любого админа) -> в стандартный SM лог (L<date>.log) для отладки.
void LogAdminAction(int client, int target, const char[] format, any ...)
{
char message[256];
VFormat(message, sizeof(message), format, 4);
bool isReg = IsRegularAdmin(client);
bool isAllowed = IsClientInAllowedGroup(client);
int flags = GetUserFlagBits(client);
// [DEBUG] показываем в чате что произошло
PrintToChat(client, "\x04[SADMIN-DBG]\x01 isReg=%d allowedGroup=%d flags=%d", isReg, isAllowed, flags);
char adminName[MAX_NAME_LENGTH], adminSteam[32];
GetClientName(client, adminName, sizeof(adminName));
if (!GetClientAuthId(client, AuthId_Steam2, adminSteam, sizeof(adminSteam)))
strcopy(adminSteam, sizeof(adminSteam), "UNKNOWN");
char targetInfo[128];
if (IsValidClient(target))
{
char targetName[MAX_NAME_LENGTH], targetSteam[32];
GetClientName(target, targetName, sizeof(targetName));
if (!GetClientAuthId(target, AuthId_Steam2, targetSteam, sizeof(targetSteam)))
strcopy(targetSteam, sizeof(targetSteam), "UNKNOWN");
Format(targetInfo, sizeof(targetInfo), "%s (%s)", targetName, targetSteam);
}
else
{
strcopy(targetInfo, sizeof(targetInfo), "UNKNOWN");
}
// [DEBUG] всегда пишем в стандартный SM лог (L<date>.log) — этот файл точно существует
LogMessage("[super_admin_menu DEBUG] isReg=%d allowedGroup=%d flags=%d | %s (%s) -> %s на игроке %s",
isReg, isAllowed, flags, adminName, adminSteam, message, targetInfo);
if (!isReg)
return;
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "logs/super_admin_menu.log");
char timestamp[32];
FormatTime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S");
PrintToChat(client, "\x04[SADMIN-DBG]\x01 пишу в %s", path);
LogToFileEx(path, "[%s] %s (%s) -> %s на игроке %s", timestamp, adminName, adminSteam, message, targetInfo);
}