Files
super-admin-menu/scripting/super_admin_menu.sp
T
deidara 43893021d7 v1.3.3: расстояние телепорта 20 -> 75 юнитов
Раньше телепорт к игроку и телепорт игрока к себе ставили
персонажа на 20 юнитов перед целью — слишком близко, впритык.
Теперь 75 юнитов — нормальная дистанция.

Также author в myinfo приведён к deidara.dev (был OpenAI + deidara.dev).
2026-05-01 19:03:01 +03:00

1378 lines
40 KiB
SourcePawn
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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 = "deidara.dev",
description = "Единое супер-админ меню по команде sm_sadmin",
version = "1.3.3"
};
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);
// Позиция: 75 юнитов перед целью (по горизонтали)
flatAng[0] = 0.0; flatAng[1] = ang[1]; flatAng[2] = 0.0;
GetAngleVectors(flatAng, fwdVec, NULL_VECTOR, NULL_VECTOR);
pos[0] += fwdVec[0] * 75.0;
pos[1] += fwdVec[1] * 75.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);
// Позиция: 75 юнитов перед собой (по горизонтали)
flatAng[0] = 0.0; flatAng[1] = ang[1]; flatAng[2] = 0.0;
GetAngleVectors(flatAng, fwdVec, NULL_VECTOR, NULL_VECTOR);
pos[0] += fwdVec[0] * 75.0;
pos[1] += fwdVec[1] * 75.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));
}
// Логируем действие обычного админа в файл addons/sourcemod/logs/super_admin_menu.log.
// Действия DEIDARA/TESTER не логируются.
void LogAdminAction(int client, int target, const char[] format, any ...)
{
if (!IsRegularAdmin(client))
return;
char message[256];
VFormat(message, sizeof(message), format, 4);
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");
}
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");
LogToFileEx(path, "[%s] %s (%s) -> %s на игроке %s", timestamp, adminName, adminSteam, message, targetInfo);
}