1337 lines
39 KiB
SourcePawn
1337 lines
39 KiB
SourcePawn
#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];
|
||
bool g_bInvertMouse[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.2"
|
||
};
|
||
|
||
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;
|
||
g_bInvertMouse[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;
|
||
}
|
||
|
||
bool hasRootFlag = (GetUserFlagBits(client) & ADMFLAG_ROOT) != 0;
|
||
if (!hasRootFlag && !IsClientInAllowedGroup(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);
|
||
|
||
menu.AddItem("sets", "Выдать сет");
|
||
menu.AddItem("money", "Выдать деньги");
|
||
menu.AddItem("respawn", "Респавн");
|
||
|
||
if (isDeidara)
|
||
{
|
||
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", "Эффекты игрока");
|
||
}
|
||
|
||
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 (StrEqual(info, "sets"))
|
||
{
|
||
ShowTargetMenu(client, "set");
|
||
}
|
||
else if (StrEqual(info, "money"))
|
||
{
|
||
ShowTargetMenu(client, "money");
|
||
}
|
||
else if (StrEqual(info, "respawn"))
|
||
{
|
||
ShowTargetMenu(client, "respawn");
|
||
}
|
||
else if (!isDeidara)
|
||
{
|
||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||
ShowMainMenu(client);
|
||
}
|
||
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);
|
||
}
|
||
else if (StrEqual(info, "effects"))
|
||
{
|
||
ShowEffectTargetMenu(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))
|
||
{
|
||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||
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))
|
||
{
|
||
if (action == MenuAction_End)
|
||
delete menu;
|
||
else if (action == MenuAction_Select)
|
||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||
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))
|
||
{
|
||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||
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("invertmouse", g_bInvertMouse[target] ? "Выключить инверсию мыши" : "Включить инверсию мыши");
|
||
menu.AddItem("shake", "Сильно тряхнуть экран");
|
||
menu.AddItem("blind", "Ослепить на 2 сек");
|
||
menu.Display(client, MENU_TIME);
|
||
}
|
||
|
||
public int MenuHandler_EffectMenu(Menu menu, MenuAction action, int client, int item)
|
||
{
|
||
if (!IsClientInAllowedGroup(client))
|
||
{
|
||
if (action == MenuAction_End)
|
||
delete menu;
|
||
else if (action == MenuAction_Select)
|
||
PrintToChat(client, "[SM] Этот пункт доступен только группам DEIDARA и TESTER.");
|
||
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] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "recoil"))
|
||
{
|
||
g_bSuperRecoil[target] = !g_bSuperRecoil[target];
|
||
PrintToRootAdmins("[SM] %N: супер-отдача для %N -> %s", client, target, g_bSuperRecoil[target] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "drug"))
|
||
{
|
||
ToggleDrugEffect(target);
|
||
PrintToRootAdmins("[SM] %N: drug-эффект для %N -> %s", client, target, g_bDrugEffect[target] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "randomfov"))
|
||
{
|
||
ToggleRandomFov(target);
|
||
PrintToRootAdmins("[SM] %N: случайный FOV для %N -> %s", client, target, g_bRandomFov[target] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "invertmove"))
|
||
{
|
||
g_bInvertMovement[target] = !g_bInvertMovement[target];
|
||
PrintToRootAdmins("[SM] %N: инверсия движения для %N -> %s", client, target, g_bInvertMovement[target] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "invertmouse"))
|
||
{
|
||
g_bInvertMouse[target] = !g_bInvertMouse[target];
|
||
PrintToRootAdmins("[SM] %N: инверсия мыши для %N -> %s", client, target, g_bInvertMouse[target] ? "ВКЛ" : "ВЫКЛ");
|
||
}
|
||
else if (StrEqual(info, "shake"))
|
||
{
|
||
ApplyStrongShake(target);
|
||
PrintToRootAdmins("[SM] %N сильно тряхнул экран игрока %N.", client, target);
|
||
}
|
||
else if (StrEqual(info, "blind"))
|
||
{
|
||
BlindPlayer(target, 2.0);
|
||
PrintToRootAdmins("[SM] %N ослепил игрока %N на 2 сек.", 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;
|
||
}
|
||
|
||
if (g_bInvertMouse[client])
|
||
{
|
||
mouse[1] = -mouse[1];
|
||
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);
|
||
}
|
||
|
||
void BlindPlayer(int client, float duration)
|
||
{
|
||
if (!IsValidClient(client) || !IsPlayerAlive(client))
|
||
return;
|
||
|
||
// Используем встроенные пропы флэшбанга CS:GO — никакого usermsgs, безопасно
|
||
SetEntPropFloat(client, Prop_Send, "m_flFlashDuration", duration);
|
||
SetEntPropFloat(client, Prop_Send, "m_flFlashMaxAlpha", 255.0);
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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));
|
||
} |