# AirDef — дальнобойные дроны и ПВО для Horizon Клиентский sandbox-мод для Horizon (Minecraft 26.3 на Rust): налёты дронов и ракет, эшелонированная ПВО, раздельные батареи, наземная логистика, разведка, РЭБ, повреждения, повторы и экспорт видео. Характеристики и временные масштабы игровые; это не тренажёр реальных комплексов. Работает на **[своём форке Horizon](https://gitea.maoniao.team/chexit/horizon-airdef)** (`horizon/` — сабмодуль, закреплённый SHA): в нём добавлен API отрисовки 3D-моделей, которого нет в основном Horizon. Рабочая ветка — **`kimi-work`**. Подробный проверенный объём и оставшаяся приёмка: [состояние задач](docs/IMPLEMENTATION-STATUS.md). Для передачи разработки: [технический журнал и handoff](docs/CODEX-HANDOFF.md). Открытый issue не означает отсутствие реализации: по просьбе владельца агенты оставляют комментарии, но не закрывают задачи. ![Перехваты](screenshots/intercepts.jpg) ## Запуск Пошаговый гайд для Windows и macOS (готовая сборка из релиза или сборка из исходников): [docs/INSTALL.md](docs/INSTALL.md). Устройство HD-рендера, его статус и план доработки: [docs/HD-RENDERER.md](docs/HD-RENDERER.md). Коротко, из исходников: ```bash git switch kimi-work git pull --ff-only git submodule update --init --recursive # также выполняется командой all python3 tools/airdef.py all # получить закреплённый движок, собрать игру и мод, установить мод python3 tools/airdef.py play # запустить (аргументы игры — после: --world "Имя мира") ``` `all` синхронизирует URL сабмодуля из `.gitmodules`, включая обновление со старого upstream. Диагностика в игре: `/airdef capabilities` показывает доступность API, принятие запроса и подготовку дыма, акустики и захвата именно этого мода. Подготовка не означает готовый GPU-кадр или MP4. Для разработчика: `python3 tools/airdef.py test-wasm` — лёгкий ABI-тест; `python3 tools/airdef.py test-budgets` — отдельный тяжёлый сценарий с JSON-отчётом. Для разработки: `./install.sh` перегенерирует модели (`tools/gen_models.py`, нужен Pillow) и звуки (`tools/gen_sounds.py`, нужны numpy и ffmpeg), собирает и ставит мод. Сгенерированные файлы лежат в репозитории, так что для обычной сборки нужен только Rust. CI: `.gitea/workflows/build.yml` на каждый пуш собирает только мод (`airdef.hmod`), а пуш в `main` публикует его релизом `build-N`. Игру-форк собирают вручную: `.gitea/workflows/game.yml` (Linux) и `.gitea/workflows/desktop.yml` (macOS и Windows, на раннерах с метками `macos-latest` / `windows-latest`); оба запускаются из Actions с тегом готового релиза `build-N`. Перед сборкой workflow проверяет, что такой релиз создан `build.yml` (имя релиза = тег, есть `airdef.hmod`), иначе падает с ошибкой; затем выкачивает ровно коммит этого тега (а не ветку, с которой запущен), сверяет его с коммитом релиза и дописывает архивы только в этот релиз. ## Как играть `/airdef give` выдаёт пульты. Все срабатывают на **ПКМ**. | Предмет | Что делает | |---|---| | Целеуказатель | ставит или снимает цель на блоке под прицелом (до 512 блоков) | | Пуск: Шахед-136 / Герань-3 / Ланцет-3 / Х-101 / Калибр / Х-22 / Циркон / Искандер-М / Кинжал | запускает дрон или ракету в точку под прицелом | | Развернуть Patriot / Гепард / Панцирь-С1 / С-400 / С-500 | ставит комплекс на блок под прицелом, носом по взгляду | | Свернуть ПВО | убирает ближайший комплекс у точки под прицелом | **Командный пункт:** клавиша **N** или `/airdef menu`. В нём список комплексов: выбери комплекс и включай или выключай классы целей (дроны, реактивные дроны, крылатые, сверхзвуковые, баллистика), есть сброс по умолчанию. Там же кнопки «Командный пункт» (сетка), «Налёт…» и «Огонь, ремонт, эффекты…» (огонь ПВО, ремонт всех, эффекты, разрушения). **Налёт (меню N → «Налёт: состав и запуск…»):** на первой странице состав — клик по типу листает число (0, 1, 2, 3, 4, 6, 8, 10, 15, 20, 30, 40); на второй — готовый вариант («Рой Шахедов», «Массированный удар», «Баллистика», «Гиперзвук», «Орешник с прикрытием», «Подавление ПВО»), откуда (один сектор, два, со всех сторон, волнами по типам), дальность старта, цели и **ПУСК**. Цели: - *только объекты* — всё летит по отмеченным объектам (или по игроку, если их нет); - *объекты и ПВО* — треть ударных средств бьёт по случайным комплексам; - *умный противник* — планировщик использует наблюдённые контакты и последние известные позиции комплексов: ведёт дроны и крылатые ракеты маршрутами в обход зон поражения, низко, за рельефом и через мёртвые зоны; «Герберы» прилетают на 15 с раньше, чтобы оттянуть ракеты; «Ланцеты» идут по Гепардам и Панцирям, Х-22/Циркон и часть баллистики — по дальнобойным комплексам; на наблюдённые РЛС дальнего обнаружения выделяются 2–3 быстрых ударника (Х-22, Циркон, Искандер, Кинжал, затем Х-101, Герань-3, Ланцет, Шахед; не больше четверти налёта); всё остальное стартует со сдвигом так, чтобы прилететь одновременно. После налёта приходит отчёт: сколько сбито и прорвалось, ракет ПВО потрачено, комплексов потеряно, урон объектам. **Обнаружение.** РЛС видит цель не дальше, чем позволяют: - её размер: дальность растёт как корень четвёртой степени из ЭПР — Х-101 и Ланцет видно примерно вдвое ближе, чем Х-22; - радиогоризонт: низколетящую цель видно поздно (Шахед на 25 м — с ~250 м, баллистику — издалека); - рельеф и лес: за холмом цель не видна (каждый комплекс строит свой горизонт по 48 лучам; рельеф известен в прогруженных чанках); - вблизи (24 м) видно всё. Радар игрока и мониторы показывают только то, что держат РЛС; в сводке видно «Вне видимости РЛС: N». Мёртвые зоны — ближе минимальной дальности ракет (Patriot 10 м, Панцирь 25, С-400 30, С-500 40). **Сохранение.** Комплексы, объекты, их повреждения и настройки сохраняются отдельно для каждого мира (и для каждого сервера); уничтоженный комплекс остаётся остовом и после перезахода, пока его не отремонтируют. **Сеть ПВО.** Единицы обмениваются измеренными треками в пределах игровой связи; повреждение связи сокращает её дальность. Можно поставить несколько С-400/С-500 без собственной РЛС и общие радары поиска, сопровождения и мачтового обзора: N → «Разместить элементы батареи…». Поисковый радар даёт подсказку; огневой должен сам измерить цель, прежде чем разрешить пуск. Старая сборная конфигурация сохранена. [Команды, источники и ограничения](docs/BATTERIES-AND-COLD-LAUNCH.md). P1-SUN также использует чужие данные. Пушкам (Гепард, пушки Панциря) нужна своя цель: они стреляют только по тому, что видят сами. Уничтоженная РЛС — дыра в сети. **Радиомолчание.** `/airdef radar <номер> off|on` или кнопка в карточке техники на карте выключает/включает собственный радар. Приём разрешённых внешних треков сохраняется; чужой трек не заменяет обязательное собственное сопровождение. Выключение не стирает старые сведения противника: он продолжает использовать последнюю наблюдённую позицию, а пуски и РЭБ могут снова раскрыть технику. **Логистика.** Пока нет ни одного склада, магазины пополняются сами, как раньше. Как только поставлен склад, боекомплект считается: комплекс без ракет пишет «ЖДЁТ БК»; в 60 м от склада он перезаряжается прямо с него, а дальние обслуживают **ТЗМ**: заправляются на складе (2 перезарядки), сами едут к ждущим комплексам, ближайшим первым, и возвращаются. Запас склада — 30 перезарядок, он виден в сводке. Склад и ТЗМ детонируют всем грузом. Ударная **RM48U у С-400** — отдельный условный игровой боеприпас, который делит четыре ячейки с ракетами ПВО. `/airdef ground-stock <склад> <количество>` задаёт конечный начальный запас sandbox-сценария, `/airdef ground-load <С-400>` загружает одну ракету рядом со складом либо создаёт заявку на доставку ТЗМ. Груз едет физически; снятая ракета ПВО возвращается на склад. Заявка и груз сохраняются в пути. `/airdef ground-unload <С-400>` выгружает ракету у склада, а вдали создаёт заявку на обратный вывоз ТЗМ. Одна ракета резервируется от пуска до забора; `/airdef ground-cancel <С-400>` отменяет ещё ожидающую доставку или вывоз. После забора ракета находится в машине и едет на склад. Отмена заявки не возвращает уже вывезенный груз в ПУ. Без склада этот ударный боеприпас сам не появляется. Бук и остальные комплексы такого профиля пока не имеют. Порядок подготовки, разведка и номера двух списков: [как ударить по ПУ](docs/GROUND-STRIKES.md). **Перемещение.** **Пульт перемещения**: навестись на технику (выбрать), затем на точку на земле — она сворачивается (С-400 и другие с вертикальным пуском дольше, Гепард и Панцирь быстро), едет по рельефу и разворачивается; всё это время не стреляет и не светит РЛС. Или `/airdef move <номер>` — к тому месту, где ты стоишь. **РЭБ.** Клавиша **U** (или `/airdef ew on|off`) включает все станции. Станция в радиусе 350 м сбивает спутниковую навигацию у Шахедов, Герань, Гербер, Х-101 и Калибров: они теряют маршрут и уводятся с цели (баллистике и Ланцетам с оптикой всё равно). Передатчик работает до 20 с и перегревается; остывает ~35 с, пока не остынет — не включить. Включённая станция себя выдаёт: умный противник запоминает её и шлёт на неё Ланцеты и Х-22, а маршруты спутниковых дронов прокладывает в обход. **Умный противник учится.** Он запоминает, откуда его налёты сбивали, а откуда они прорывались, и следующий налёт ведёт с лучшего направления; помнит комплексы, выдавшие себя пуском, и станции РЭБ, и во время налёта перенацеливает ещё не взлетевшие Ланцеты и Шахеды на них; если цель-комплекс уничтожен, дроны идут к следующему известному. Дроны под обстрелом прижимаются к земле. **Ночь.** Исправные пушки с собственным свежим радарным сопровождением не теряют точность из-за темноты. Цели освещают **прожекторы** (луч ведёт ближайшую цель из сети, приоритет — цели пушек) и **осветительные ракеты**: пушечные комплексы пускают их сами (раз в 25 с на цель в темноте), игрок — **осветительным пистолетом** или `/airdef flare`. Ракета висит ~30 с и освещает всё вокруг на ~60–90 м. **Графика: три пресета** (меню N → «Огонь, ремонт, эффекты…» → «Эффекты», или `/airdef shader off|on|hd`): выкл — ванильная картинка; обычные — шейдерные огненные шары, ударная волна и подсветка; **HD** — свой рендер освещения в форке: мир дополнительно рисуется в G-буфер (цвет без света и нормали), и все источники света мода освещают его попиксельно в HDR — факелы ракет и двигатели, раскалённые боевые блоки, осветительные ракеты, вспышки выстрелов, трассеры, взрывы (вспышка и догорающий шар), горящие остовы, пятна прожекторов, — затем bloom и мягкий тонмаппинг (ванильный диапазон не трогается, сжимается только то, что ярче). Источники передаются движку новым API мода `render.set-lights` (до 512, плавно интерполируются), режим — `render.set-lighting`. В HD дымовые следы ракет немного уплотнены; число сегментов и время появления/выгорания сохранены. Это относится к ракетам ПВО, RM48U, крылатым, сверхзвуковым и баллистическим средствам; дым пожаров и слабая дымка винтовых дронов остались прежними. **Сетка J** после сбития ещё 3,5 с держит камеру на сбитой цели, и комплекс в это время не пропадает из сетки. **Повреждения.** Взрыв рядом с комплексом повреждает его: он хуже поворачивается, хуже видит и попадает, дымит, ниже 35% горит. Уничтоженный остаётся горящим остовом, его боекомплект детонирует: чем больше ракет оставалось, тем мощнее взрыв и дольше вторичные (у Гепарда рвутся снаряды); соседние комплексы тоже могут пострадать. Объекты (Целеуказатель или `/airdef target here`) имеют прочность, она видна в сводке. Ремонт — кнопкой в меню или `/airdef repair`. Известные стены и рельеф ослабляют **непрямой** урон корпусу, узлам и объектам; проёмы дают частичное воздействие. Используется геометрия, известная перед разрушением. При неизвестной или устаревшей геометрии сохраняется прежний урон без защиты; поздний ответ его повторно не наносит. Прямое вооружённое попадание этим ослаблением не отменяется. **Монитор комплекса:** клавиша **K** листает комплексы по очереди, после последнего монитор скрывается. Слева вверху показано: - состояние комплекса (поиск, сопровождение, доворот, захват, пуск, огонь, перезарядка, огонь запрещён); - его РЛС: цели, по которым он работает, красным, остальные серым, текущая цель жёлтым; - камера комплекса: настоящий вид мира из точки комплекса (второй рендер форка), с зумом на цель — тепловизор при сопровождении, в поиске днём цвет, ночью ПНВ; рамка захвата, дальность, высота, скорость и пеленг. **Командный пункт ПВО (сетка):** клавиша **J** (или `/airdef grid`, или кнопка в меню N) — на весь экран сетка до 8 комплексов: у каждого состояние, РЛС, живая камера, прочность и боекомплект. Если комплексов больше, показываются самые занятые (стреляют, держат захват, сопровождают, горят), раз в 2 секунды; комплекс с монитора K — всегда. Повторное J закрывает. **Повторы.** Каждый налёт записывается сам: с первой цели в небе до момента, когда небо 5 с чисто (хранятся 3 последних). Меню N → «Повторы…» или клавиша **R**: - **карта налёта** — вид сверху: комплексы и их зоны, объекты, треки целей (красные), ложных целей (серые) и перехватчиков (жёлтые), сбития (x), прилёты, шкала времени с событиями; время идёт само, колесо мыши перематывает; - **повтор момента** — клик по событию в списке: «призраки» дронов и ракет снова летят в мире, камера идёт за целью, потом за перехватчиком (или смотрит из пушки, со стороны на прилёт), в момент сбития время замедляется; - **полный повтор** — весь налёт, камера-режиссёр сама выбирает, за чем следить; колесо — перемотка, стрелки — скорость; - **лучшие моменты** — нарезка до 8 самых интересных событий (перехват баллистики и гиперзвука, поражения объектов, потерянные комплексы, разделение «Орешника») с титрами и замедлением; колесо листает моменты. Повтор идёт на весь экран с леттербоксом; звук слышен так, как его слышала бы камера. Управление (подсказка показывается в начале, после нажатия и на паузе): **← →** — перемотка на 5 с (в нарезке — соседний момент), **↑ ↓** — скорость (×0.25–×32), **Пробел** — пауза (в конце — сначала), **колесо** — время / моменты, **R** или **Backspace** — выход, **N** — выйти в меню. В конце повтор встаёт на паузу. Чтобы в повторах и камерах комплексов была видна земля далеко от игрока, мод включает дальний ландшафт (48 чанков, упрощённый); выключается в меню N → «Огонь, ремонт, эффекты…» → «Дальний ландшафт». Клавиши N, K, J, R и U можно переназначить в «Настройки → Моды». Команды: - `/airdef wave <тип> [кол-во] [дальность]` — налёт на ближайшую цель. Дальность старта — от 60 до 4000 блоков (в меню: 200–4000); землю для площадок, которой нет в загруженных чанках, игра подгружает сама (API 22, `render.load-chunks`, пока идёт поиск), а где подгрузить нельзя (сервер) или нет пригодного места, дроны всё равно стартуют: «за картой», с высоты полёта на заказанной дальности, без площадки. Типы: `shahed`, `geran3`, `lancet`, `gerbera`, `kh101`, `kalibr`, `kh22`, `zircon`, `iskander`, `kinzhal`, `oreshnik` и `mix` (комбинированный удар двумя секторами: «Герберы», шахеды, Герани-3, Х-101, «Калибры», Х-22, Циркон, «Искандер», «Кинжал», при 30+ — «Орешник»); - `/airdef replay [map|full|reel|stop]` — повтор последнего налёта; - `/airdef replay film [best|all|N]` — фильм режиссёра: для каждого перехвата/прилёта несколько планов (комплекс, пуск, погоня за ракетой, взгляд с цели, замедленный крупный план поражения, общий план после), склейки, плавные движения камеры, камера не уходит под землю; играется в максимальном качестве (HD, мир в полном разрешении, больше шагов облаков и тумана; настройки возвращаются после); - `/airdef replay export [имя] [best|all|N] [fps=60] [size=1920x1080] [crf=14] [sec=N] [noaudio]` — тот же фильм кадр за кадром с фиксированным шагом (скорость компьютера не важна) в MP4 с звуком: `/airdef-films/<имя>.mp4` (нужен `ffmpeg` в PATH или `HORIZON_FFMPEG`; без него — PNG-последовательность и готовая команда ffmpeg). Прогресс в чате, отмена — `/airdef replay stop`. Окно игры держите в фокусе (пауза останавливает съёмку); чат попадает в кадр. - `/airdef import` — перенести в текущий мир комплексы и цели из старой версии мода (до 0.2.x они были общими для всех миров); - `/airdef raid` — налёт, настроенный в меню; `/airdef target here` — отметить объект под ногами; `/airdef repair` — ремонт; - `/airdef lastchance ` — «последний шанс»: комплекс стреляет и по классу вне ролей, если цель вот-вот попадёт (по умолчанию вкл; сохраняется); - `/airdef sites` — известные пусковые площадки (ПУ). РЛС с прямой видимостью может заметить сам пуск и получить неточную позицию; несколько наблюдённых пусков уточняют её. Обнаруженный позже дрон даёт только слабое предположение об обратном курсе: скрытые координаты площадки и время невидимого старта не используются. Повторные треки одного полёта не создают ложную точность. - `/airdef strike <номер ПУ>` — ручной удар по разведанной площадке из готового физического С-400 с отдельно загруженной RM48U (игровой профиль, #118). Четыре ячейки делятся с боезапасом ПВО; приказ резервирует носитель и ячейку, открывает крышку и списывает одну ударную ракету при выбросе. Выбирается готовый комплекс с наибольшим остатком RM48U, затем ближайший к цели. Есть открытие ТПК, выброс, отложенное включение двигателя и разгон, ограниченная игровая траектория, столкновения и запись пуска. Несуществующее «ПВО площадки» не перехватывает ракету по броску вероятности. - `/airdef ground-stock <номер склада> <количество>` — задать остаток RM48U для sandbox-сценария (по умолчанию 0). `/airdef ground-load <номер С-400>` загружает одну ракету у склада либо заказывает ТЗМ; `ground-unload` возвращает её у склада либо заказывает вывоз; `ground-cancel` отменяет ожидающую заявку. Доставка и обратный вывоз через ТЗМ реализованы, запас и груз сохраняются. [Пошаговый пример](docs/GROUND-STRIKES.md). Совместимость профиля основана на [публикации ГУР](https://gur.gov.ua/content/warsanctions-hur-mo-rozkryvaie-budovu-komponentnu-bazu-ta-pidpryiemstva-kooperatsii-z-vyrobnytstva-udarnykh-raket-rm48u.html); это сообщение ведомства, не независимая сертификация. Дальность, форма полёта и оформление условны для Minecraft. - `/airdef deploy s400_launcher` и `s500_launcher` — отдельные пусковые без своей РЛС; `radar_search`, `radar_track`, `radar_height` — обзорная, сопровождающая и мачтовая игровые РЛС. Они также доступны через меню N → «Разместить элементы батареи…». `/airdef battery` показывает состав и связь; `/airdef battery <номер> integrated|launcher` меняет конфигурацию, `/airdef radar <номер> multi|search|engagement|height` — роль отдельной РЛС. Обзорная РЛС передаёт подсказки; станция сопровождения должна сама получить свежее измерение, чтобы разрешить пуск. Старые С-400/С-500 сохраняют упрощённую сборную конфигурацию. [Устройство игровой батареи и пуска](docs/BATTERIES-AND-COLD-LAUNCH.md). - `/airdef roles` — показать, по каким классам целей работает каждый комплекс; `/airdef roles <классы|default>` — задать (классы через запятую: `drone`, `jet`, `cruise`, `supersonic`, `ballistic` или `all`), например `/airdef roles s400 cruise,ballistic`; - `/airdef doctrine` — доктрины комплексов (#47; в меню N: «Доктрины…»): `/airdef doctrine <номер|all> reserve ` — держать K ракет для срочных целей (баллистика или до удара меньше 12 с); `salvo eco|normal|heavy` — сколько перехватчиков на цель (только базовые / как обычно / на один больше); `sector <центр°> <полуширина°>` или `sector off` — сектор ответственности (0° — север); `guard <объект№>[,<№>]` или `guard off` — стрелять только по тому, что идёт на охраняемые объекты (отметка: `/airdef target here`). По умолчанию ограничений нет; последний шанс сильнее доктрины; `/airdef why <номер>` называет, какая настройка остановила или разрешила пуск; сохраняется с миром и сценариями. Карта охраны и пробелов в ней — вместе с картой (#48). - `/airdef deploy ` — поставить комплекс в 8 блоках перед собой; - `/airdef hold on|off` — запретить или разрешить ПВО огонь, удобно для съёмки ударов; - `/airdef damage on|off` — разрушать ли ландшафт взрывами (через TNT, нужны читы); - `/airdef shader on|off` — шейдерные эффекты; - `/airdef clear` — убрать дроны и ракеты; - `/airdef targets clear` — снять все цели; - `/airdef stats` — сводка. Интерфейс: - **сверху справа — сводка:** тревога, цели по типам, ближайшая угроза (дальность, высота, скорость), перехватчики в воздухе, по каждому комплексу боезапас или перезарядка, его текущая цель и число сбитых, итоговый счёт; - **снизу справа — радар на 500 м** со сканирующим лучом. Отметки гаснут после прохода луча. Красное — цели (с хвостом по курсу), жёлтое — ракеты, синее — ПВО с кругами дальности, крест — цели удара. Комплексы ПВО и цели сохраняются между сессиями. ## Техника | Дрон / ракета | Поведение | |---|---| | Шахед-136 | 43 км/ч в игре, 45 м над целью, 18 м над рельефом, крен в поворотах, пикирует, винт крутится | | Герань-3 | реактивный, 115 км/ч, факел из сопла | | Ланцет-3 | Х-образные крылья, низко (25 м), манёвренный, его труднее сбить | | Гербера | ложная цель из пенопласта, без боевой части: отвлекает ракеты ПВО | | Х-101 | крылатая ракета, 170 км/ч, огибает рельеф на 12 м, мощная боевая часть | | Калибр | крылатая ракета, 150 км/ч, огибает рельеф на 15 м | | Х-22 | сверхзвуковая, 290 км/ч, идёт на 140 м и круто пикирует издалека | | Циркон | гиперзвуковая, 400 км/ч, её трудно сбить | | Искандер-М | баллистическая: стартует за 1 км, дуга с апогеем ~250 м, на конечном участке доворачивает на цель | | Кинжал | аэробаллистическая, 540 км/ч, стартует за 1,5 км; реально сбивает только С-500 | | Орешник | баллистическая средней дальности: стартует за 2,6 км, над целью разделяется на 6 блоков, каждый — на 6 светящихся суббоеприпасов («огненный дождь», ~5 с); С-500 успевает сбить лишь несколько | Сила взрыва зависит от боевой части: ложные цели — хлопок, дроны — средний взрыв, Шахед — сильный, Х-101/Х-22/Калибр — тяжёлый (двойной удар, столб земли, тряска до 160 м), Искандер/Кинжал — самый мощный (огненный шар 13 м, тряска до 240 м); у каждого уровня свой звук. | ПВО | Вооружение | Дальность | |---|---|---| | Patriot | 4 × PAC-3, пусковая разворачивается на цель | 10–450 | | Гепард | 2 × 35 мм, башня и стволы со слежением и упреждением, 160 очередей | 135 (слежение с 195) | | Панцирь-С1 | 12 × 57Э6 и 2 × 30 мм; модуль поворачивается, пакеты и стволы поднимаются | ракеты 25–225, пушки 90 | | С-400 | 4 × 48Н6, вертикальный холодный старт, РЛС обзора на прицепе | 30–720 | | С-500 | 2 × 77Н6, холодный старт, самые быстрые ракеты | 40–1050 | | IRIS-T SLM | 8 ракет, вертикальный пуск, быстрые и манёвренные | 15–600 | | NASAMS | 6 × AMRAAM, наводимая пусковая на прицепе | 10–450 | | Бук-М2 | 4 × 9М317 на направляющих, башня с РЛС подсвета | 20–675 | | Тор-М2 | 8 × 9М338 вертикально из башни, быстрая реакция против дронов | 8–240 | | P1-SUN | 8 дронов-перехватчиков против Шахедов и Герань; своей РЛС нет — стреляет по данным сети | 5–675 | Обслуживающая техника (тоже пультами или `/airdef deploy <ключ>`): **РЛС дальнего обнаружения** (`radar`, видит на 2,5 км с высокой мачты, хуже прячутся за рельефом), **склад боеприпасов** (`depot`), **ТЗМ** (`tzm`), **станция РЭБ** (`ew`), **прожектор** (`light`). Новые комплексы: `irist`, `nasams`, `buk`, `tor`, `p1sun`. **Согласование огня.** Комплексы делят цели между собой: на обычную цель идёт одна ракета, на баллистическую две; чем ближе цель к своей точке попадания, тем больше перехватчиков разрешено на неё сразу (за ~12 с до удара ещё один, за ~5 с — ещё один). Комплекс, у которого кончились ракеты или идёт перезарядка, цель не держит; тот, кто не смог навестись за ~2 с, отпускает её другим. Пушки расходятся по разным целям. Первыми бьют по самым опасным (быстрым и тяжёлым) целям, при этом ложные «Герберы» выглядят для них как настоящие. Геометрия встречи проверяется по движению обоих объектов за тик, а остаточный шанс учитывает фактическую скорость перехватчика. **Энергетика перехватчика.** После холодного выброса ракета разгоняется, но двигатель работает конечное игровое время. После выгорания ракета летит по инерции, теряет скорость и манёвренность; при недостаточной скорости сопровождение срывается. Факел, звук двигателя и новый дым прекращаются при выгорании и в live, и в повторе; уже созданный дым продолжает рассеиваться. **Последний шанс** (`/airdef lastchance on|off`, по умолчанию вкл). Комплекс стреляет и по классу целей вне своих ролей (С-400, С-500 и Patriot по умолчанию не бьют дроны), если цель долетит до своей точки меньше чем за 10 с и на ней ещё нет ничьего перехватчика. Комплексу с пустыми ролями (огонь запрещён) это не касается. `/airdef why` пишет «последний шанс». **Дальний пуск по РЛС.** С-400, С-500 и Patriot могут стрелять дальше своей дальности (до 1,6×) по цели, которую держит свежим треком РЛС дальнего обнаружения в радиусе связи: не чаще раза в 15 с, при не менее чем половине боезапаса, только по своим ролям и только пока в обычной дальности нет цели; шанс поражения на краю вдвое ниже. `/airdef why`: «дальний пуск по РЛС». **Роли по умолчанию** (в сводке в квадратных скобках: Д — дроны, Г — реактивные, К — крылатые, С — сверхзвуковые, Б — баллистика): Гепард ДГК, Панцирь ДГКС, Patriot ГКСБ, С-400 ГКСБ, С-500 СБ. Сбитый дрон падает с остатком скорости, и его боевая часть может сдетонировать на земле. ## Звук Все звуки синтезированы (`tools/gen_sounds.py`: шум, тоны, фильтры и эхо на numpy, кодирует ffmpeg), сэмплов нет. У каждого объекта свой звук и своя дальность слышимости (`attenuation_distance` в `sounds.json`): - **двигатели:** двухтактный мопед шахеда (220 м), турбина Герани-3, электромотор Ланцета, тяжёлый рёв крылатых ракет (320 м), ракетный рёв Х-22, Циркона и перехватчиков, нарастающий визг падающей баллистики и её ударная волна (700–900 м); Двигатели дронов и ракет — **постоянные источники звука** (API 20, `render.sound-sources`, #95): один источник на объект идёт за его настоящей позицией, зажигается с нарастанием, при сбитии «захлёбывается» (тон падает, громкость гаснет за секунду) и замолкает вместе с объектом; в повторе и экспорте источники берутся из записанных траекторий и времени повтора (перемотка и смена плана пересоздают их). Одновременно звучат 24 ближайших и громких, остальные «виртуальные». Взрывы, пуски и выстрелы остались разовыми, с задержкой по скорости звука. Баллистика (визг при падении) тоже разовая. Зацикливается устойчивая часть файла (начало и затухание в конце обрезаны), стык — 50 мс. - **пуски:** хлопок и рвущийся рёв Patriot, свистящий старт Панциря, глухой газовый выброс и затем огромный рёв С-400, у С-500 ещё ниже и дольше (до 1 км); - **пушки:** тяжёлые 35-мм очереди Гепарда и частые 30-мм Панциря; - **взрывы:** хлопок, суббас, рокот и треск обломков с длинным эхом, у разных калибров по-разному (до 900 м). ## Эффекты Мод передаёт движку шейдер пост-обработки (`airdef-mod/shaders/effects.wgsl`): - **объёмный огненный шар:** шум, «прошитый» лучом камеры, с переходом раскалённое ядро → пламя → чёрный дым, который поднимается и рассеивается; - **вспышка** с ореолом и засветкой всего кадра; - **ударная волна**, искажающая картинку за собой; - **тепловое марево** над огнём; - **свечение** факелов ракет, дульных вспышек, красных трассеров и маркеров цели; - **освещение от огня:** взрывы, факелы и трассеры подсвечивают землю и технику, ночью намного сильнее. У Гепарда и Панциря каждый снаряд — летящий красный трассер. Всё размещено в мире и скрывается за тем, что стоит перед ним (по глубине сцены). Выключить: `/airdef shader off`. ![Удар](screenshots/blast-fireball.jpg) ![Холодный старт С-400](screenshots/s400-cold-launch.jpg) ## Устройство ``` .gitmodules URL отдельного репозитория движка horizon/ git submodule: точный SHA форка Horizon. Что в нём меняется: crates/horizon-mod-sdk/wit/horizon.wit render.set-models, spawn-particles, play-sound, query-ground / ground crates/horizon-mods/src/runtime.rs хост этих функций crates/horizon-client/src/game/mod_models.rs интерполяция и отрисовка моделей, частицы crates/horizon-client/src/gfx/mod_post.rs пост-проход мода: render.set-post / set-params airdef-core/ SDK-free сборка общего ядра; использует те же исходники sim, без копии airdef-mod/ адаптер: Rust → WebAssembly src/sim/mod.rs симуляция: дроны, ракеты, ПВО, эффекты (20 тиков/с) src/sim/battery.rs конфигурации пусковых и роли общей РЛС src/sim/launch.rs резервирование ячеек и анимация крышек ТПК src/lib.rs предметы, команды, сохранение, передача в движок src/panel.rs сводка, src/radar.rs — радар, src/monitor.rs — монитор комплекса assets/airdef/sounds звуки (генерирует tools/gen_sounds.py) shaders/effects.wgsl шейдер взрывов и свечения assets/, data/ модели, текстуры, предметы (генерирует tools/gen_models.py) tools/gen_models.py генератор моделей и текстур legacy/ первая версия: датапак на командах и контент-мод run-home/ тестовая игровая папка (для проверок через horizon-ctl) ``` Как рисуются модели. Мод раз в тик отдаёт список объектов: блок-модель, позиция, кватернион и масштаб. Движок держит для каждого id две последние позы и в каждом кадре рисует объект между ними: - позиция интерполируется линейно, поворот — через slerp; - освещение учитывает поворот модели; - `glow` даёт полную яркость (пламя, вспышки). Модели — обычные блочные JSON-модели, по одной на часть: корпус, винт, башня, стволы. Их генерирует `tools/gen_models.py`. Координаты элементов должны быть в пределах −16..32, иначе Horizon отбросит модель. Рельеф и коллизии приходят асинхронно через ground/ray/section queries. Высотной карты недостаточно для точного попадания: известные блоки и формы проверяются отдельно; ожидание/Unknown не считается доказанным свободным путём. Историческое отображение повтора отделено от live-геометрии симуляции. ## Известные ограничения - Для [#122](https://gitea.maoniao.team/chexit/airdef/issues/122) воспроизведено и исправлено исчерпание fuel при массовых взрывах: каждый взрыв больше не обходит всю карту высот. Проверка на конкретном Windows-компьютере ещё нужна; прирост FPS этим исправлением не обещается. - Мод клиентский: дроны и ПВО видит только тот, у кого он стоит. Мультиплеер не поддерживается. - Окно Horizon на macOS не рисует кадры, пока оно перекрыто другими окнами (это поведение движка). - Шейдер работает, только если не включён шейдер-пак Horizon (они взаимоисключающие). Разработка и обновление закреплённого движка: [docs/ENGINE.md](docs/ENGINE.md).