const IMMUNITY_FLAG = ADMFLAG_ROOT; // Иммунитет к функциям плагина
const Float:AFK_CHECK_INTERVAL = 10.0; // Частота проверок
const Float:AFK_THRESHOLD = 30.0; // Погрешность в расчетах Origin в CS:GO [менять не стоит :)]
const Float:AFK_TIME_MOVE = 40.0; // Через сколько секунд бездействия игрока перевести в спектры
const AFK_PLAYERS_KICK = 30; // Сколько должно быть игроков на сервере, чтобы игрока кикнуло из спектров
const Float:AFK_TIME_KICK = 120.0; // Через сколько секунд игрока выкинуть с сервера с учетом AFK_PLAYERS_KICK
float g_fAfkTime[MAXPLAYERS + 1];
float g_fEyePos[MAXPLAYERS + 1][3];
float g_fOriginPos[MAXPLAYERS + 1][3];
int g_iObserverMode[MAXPLAYERS + 1];
int g_iObserverTarget[MAXPLAYERS + 1];
const SpecMode_Free_Look = 6;
const CS_TEAM_SPECTATOR = 1;
description = "AFK Manager",
public void OnPluginStart()
HookEvent("player_spawn", Event_PlayerSpawn);
HookEvent("player_team", Event_PlayerTeam);
HookEvent("player_death", Event_PlayerDeath);
public void OnConfigsExecuted()
CreateTimer(.interval = AFK_CHECK_INTERVAL, .func = CheckPlayerAfk, .flags = TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
public void Event_PlayerSpawn(Handle event, const char[] name, bool dontBroadcast)
int client = GetClientOfUserId(GetEventInt(event, "userid"));
if(IsClientInGame(client) && IsPlayerAlive(client))
public void Event_PlayerTeam(Handle event, const char[] name, bool dontBroadcast)
int client = GetClientOfUserId(GetEventInt(event, "userid"));
if(IsClientInGame(client))
if(GetEventInt(event, "team") == CS_TEAM_SPECTATOR)
GetClientEyeAngles(client, g_fEyePos[client]);
g_iObserverMode[client] = GetEntProp(client, Prop_Send, "m_iObserverMode");
g_iObserverTarget[client]= GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
public void Event_PlayerDeath(Handle event, const char[] name, bool dontBroadcast)
int client = GetClientOfUserId(GetEventInt(event, "userid"));
public Action CheckPlayerAfk(Handle timer, any data)
// PrintToChatAll("-> afk check");
bool bSpecKick = (GetClientCount(true) >= AFK_PLAYERS_KICK && AFK_TIME_KICK > 0.0);
for(int client = 1, team; client <= MaxClients; client++)
if(!IsClientInGame(client))
team = GetClientTeam(client);
if(IsClientObserver(client))
if(team > CS_TEAM_SPECTATOR && !IsPlayerAlive(client))
else if(team == CS_TEAM_SPECTATOR || CheckObserver(client))
g_fAfkTime[client] += AFK_CHECK_INTERVAL;
g_fAfkTime[client] = 0.0;
fEyePos = g_fEyePos[client];
fOriginPos = g_fOriginPos[client];
GetClientEyeAngles(client, g_fEyePos[client]);
GetClientAbsOrigin(client, g_fOriginPos[client]);
if((g_fEyePos[client][0] == fEyePos[0]) &&
(g_fEyePos[client][1] == fEyePos[1]) &&
(g_fEyePos[client][2] == fEyePos[2]) &&
(FloatAbs(g_fOriginPos[client][0] - fOriginPos[0]) < AFK_THRESHOLD) &&
(FloatAbs(g_fOriginPos[client][1] - fOriginPos[1]) < AFK_THRESHOLD) &&
(FloatAbs(g_fOriginPos[client][2] - fOriginPos[2]) < AFK_THRESHOLD) &&
~GetEntityFlags(client) & FL_FROZEN)
g_fAfkTime[client] += AFK_CHECK_INTERVAL;
g_fAfkTime[client] = 0.0;
if(team > CS_TEAM_SPECTATOR)
if((AFK_TIME_MOVE - g_fAfkTime[client]) <= 0.0)
ChangeClientTeam(client, CS_TEAM_SPECTATOR);
"\x01[\x04AFK\x01] \x08Вы находитесь AFK \x03%.0f \x08сек из \x01допустимых \x03%.0f \x08сек",
else if(bSpecKick && (AFK_TIME_KICK - g_fAfkTime[client]) <= 0.0 && ~GetUserFlagBits(client) & IMMUNITY_FLAG)
KickClient(client, "Вы слишком долго находились AFK");
void ResetPlayerData(int client)
g_fAfkTime[client] = 0.0;
g_fEyePos[client][0] = g_fEyePos[client][1] = g_fEyePos[client][2] = 0.0;
g_iObserverMode[client] = g_iObserverTarget[client] = 0;
bool CheckObserver(int client)
int iLastObserverMode = g_iObserverMode[client];
g_iObserverMode[client]= GetEntProp(client, Prop_Send, "m_iObserverMode");
if(iLastObserverMode && g_iObserverMode[client] != iLastObserverMode)
fEyePos = g_fEyePos[client];
if(g_iObserverMode[client] == SpecMode_Free_Look)
GetClientEyeAngles(client, g_fEyePos[client]);
int iLastObserverTarget = g_iObserverTarget[client];
g_iObserverTarget[client]= GetEntPropEnt(client, Prop_Send, "m_hObserverTarget");
if(!iLastObserverMode && !iLastObserverTarget)
if(iLastObserverTarget > 0 && g_iObserverTarget[client] != iLastObserverTarget)
iLastObserverTarget > MaxClients ||
!IsClientInGame(iLastObserverTarget)
) ? false : (!IsPlayerAlive(iLastObserverTarget));
(g_fEyePos[client][0] == fEyePos[0]) &&
(g_fEyePos[client][1] == fEyePos[1]) &&
(g_fEyePos[client][2] == fEyePos[2])