╔══════════════════════════════════════════════════════════════════════╗
║               AFK Sentinel v3.0  —  by G3ntEZ                       ║
║           TG: @G3ntEZ  |  VK: vk.com/xzx111zxz                      ║
╚══════════════════════════════════════════════════════════════════════╝

  Smart Anti-AFK для CS:S v34 / SourceMod
  Edge-детектор кнопок · накопление угла · анти-обходы

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  СТРУКТУРА АРХИВА
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  afk_sentinel/
  ├── README.txt
  ├── addons/sourcemod/
  │   ├── scripting/
  │   │   └── afk_sentinel.sp          ← исходный код (компилируй)
  │   ├── plugins/
  │   │   └── (сюда .smx после компиляции)
  │   └── configs/
  │       ├── afk_sentinel.cfg          ← все настройки с комментариями
  │       └── downloadslist.txt         ← список файлов для клиентов
  └── sound/
      └── afk_sentinel/
          └── ПОЛОЖИ_ЗВУК_СЮДА.txt     ← заглушка, заменить MP3-файлом

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  УСТАНОВКА
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. КОМПИЛЯЦИЯ
   Windows:  scripting/compile.exe afk_sentinel.sp
   Linux:    ./scripting/spcomp afk_sentinel.sp -o afk_sentinel.smx

   Положи afk_sentinel.smx в:
     cstrike/addons/sourcemod/plugins/

2. КОНФИГ
   Скопируй afk_sentinel.cfg в:
     cstrike/addons/sourcemod/configs/

3. ЗВУК
   Положи MP3 сюда:
     cstrike/sound/afk_sentinel/afk_sentinel.mp3
   Требования: MP3 · 44100 Hz · до 192 kbps

4. DOWNLOADS
   Убедись, что в configs/downloadslist.txt есть:
     afk_sentinel/afk_sentinel.mp3

5. ПЕРЕЗАПУСК СЕРВЕРА / ЗАГРУЗКА:
     sm plugins load afk_sentinel

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  НАСТРОЙКА — ПОЛНЫЙ СПИСОК CVAR
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ConVar                   По умолч.  Описание
  ───────────────────────  ─────────  ───────────────────────────────────────
  sm_afk_enable            1          Вкл/выкл плагин
  sm_afk_time              120        Секунд без активности → AFK-состояние
  sm_afk_check_interval    1.0        Интервал таймера (сек), мин 0.5
  ───────────────────────  ─────────  ───────────────────────────────────────
  sm_afk_move_dist         20.0       Мин. дистанция (юниты) за интервал
  sm_afk_angle_threshold   20.0       Порог поворота (°, pitch+yaw) за окно
  sm_afk_angle_window      1.0        Размер окна накопления угла (сек)
  sm_afk_buttons_mask      0          Битовая маска кнопок (0 = дефолт)
  sm_afk_hold_max          15         Сек удержания без других событий → AFK
  ───────────────────────  ─────────  ───────────────────────────────────────
  sm_afk_action            1          0=сообщение, 1=spec, 2=kick, 3=spec→kick
  sm_afk_warn_time         10         Секунд обратного отсчёта перед действием
  sm_afk_kick_time         60         Сек в spec до кика (только режим 3)
  ───────────────────────  ─────────  ───────────────────────────────────────
  sm_afk_min_players       2          Мин. активных игроков для проверки
  sm_afk_ignore_dead       1          Игнорировать мёртвых (1/0)
  sm_afk_ignore_admins     0          Игнорировать ADMFLAG_GENERIC (1/0)
  sm_afk_grace_period      15         Сек после спавна/подключения без AFK
  ───────────────────────  ─────────  ───────────────────────────────────────
  sm_afk_sound             (путь)     Звук предупреждения (без "sound/")
  sm_afk_announce          1          Объявлять всем о переводе/кике (1/0)
  sm_afk_debug             0          Лог: 0=нет, 1=состояния, 2=всё

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  КАК РАБОТАЕТ — АРХИТЕКТУРА
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  OnPlayerRunCmd (каждый тик, только сбор данных):
    ┌─ Edge кнопок: отслеживает момент нажатия (0→1) и отпускания (1→0)
    │   Только новое нажатие = активность. Удержание не продлевает.
    └─ Накопление угла: суммирует дельту pitch+yaw, нормализованную [-180,180]
        Каждые angle_window сек — сравнивает с порогом и сбрасывает.

  Timer (раз в check_interval, вся тяжёлая логика):
    ┌─ Движение: GetClientAbsOrigin → дистанция от последней позиции
    ├─ Анти-зажим: если только удержание > hold_max сек → AFK
    ├─ Состояния: ACTIVE → WARNING → (action)
    └─ mode 3: отдельный счётчик времени в Spec → kick

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  АНТИ-ОБХОДЫ
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✓ Зажатая кнопка (анти-зажим)
      Только момент нажатия (edge) сбрасывает таймер.
      После hold_max секунд без новых событий — удержание не считается.

  ✓ Медленный поворот мыши
      Накопление идёт непрерывно в OnPlayerRunCmd.
      Даже 1°/тик аккумулируется. Но дрожание ±1–2° в рамках окна
      не дотягивает до порога (20°) — и не засчитывается.

  ✓ Микро-движение позиции
      Порог move_dist (20 юнитов) отсекает дрожание при стрельбе/физике.

  ✓ Wrap-around углов
      AngleDiff нормализует разницу в [-180, 180].
      Поворот с 179° → -179° даёт дельту 2°, а не 358°.

  ✓ Спавн / подключение
      Grace period (15 сек по умолчанию) — игрок не проверяется сразу.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ТЕСТ-ПЛАН
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✓ Стоит неподвижно 120 сек         → AFK через sm_afk_time
  ✓ Держит присед 5 минут             → AFK после hold_max сек
  ✓ Медленно крутит мышь (1°/тик)    → НЕ AFK (накапливается до порога)
  ✓ Дрожит мышью ±1° в окно          → AFK (не дотягивает до порога)
  ✓ Бегает / стреляет / прыгает      → никогда не AFK
  ✓ Только что заспавнился            → grace period, не проверяется
  ✓ Вернулся из AFK-состояния         → сброс в ACTIVE, сообщение

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  CHANGELOG
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  v3.0 (текущая)
    + Edge-детектор кнопок (0→1 и 1→0): удержание не продлевает AFK
    + Накопление угла за окно: устойчиво к медленному повороту
    + Анти-зажим: hold_max — после превышения удержание не считается
    + Разделение архитектуры: RunCmd = сырые данные, таймер = логика
    + Режим action=3: spec → kick через kick_time
    + sm_afk_ignore_admins: освободить admins от проверки
    + sm_afk_grace_period: применяется при каждом спавне
    + sm_afk_debug: уровни 0/1/2
    + AFK_State enum: ACTIVE / WARNING / SPECCED
    + AngleDiff с нормализацией [-180, 180]
    + ForcePlayerSuicide перед ChangeClientTeam (нет крашей)
    + Горячая перезагрузка плагина

  v2.0
    + Фикс gLastActivity = 0.0 → мгновенный AFK при заходе
    + Фикс таймера: пересоздание на каждой карте
    + Фикс gLastAng: обновляется каждый кадр
    + Фикс min_players: теперь реально применяется
    + sm_afks_announce
    + LogAction для всех переводов

  v1.0 — первый релиз (G3ntEZ)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  © G3ntEZ, 2025 — свободное использование с указанием автора
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
