From ad96018c0a85d1eb91a719e566f5162b3fb9f6c9 Mon Sep 17 00:00:00 2001 From: chexit Date: Mon, 2 Nov 2026 21:01:07 +0300 Subject: [PATCH] Explain unavailable coordinate-strike loadouts in map and documentation (#118) Co-Authored-By: Codex --- README.md | 9 ++------- airdef-mod/src/lib.rs | 2 +- airdef-mod/src/map.rs | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d6f3602..d326775 100644 --- a/README.md +++ b/README.md @@ -160,13 +160,8 @@ API мода `render.set-lights` (до 512, плавно интерполиру - `/airdef import` — перенести в текущий мир комплексы и цели из старой версии мода (до 0.2.x они были общими для всех миров); - `/airdef raid` — налёт, настроенный в меню; `/airdef target here` — отметить объект под ногами; `/airdef repair` — ремонт; - `/airdef lastchance ` — «последний шанс»: комплекс стреляет и по классу вне ролей, если цель вот-вот попадёт (по умолчанию вкл; сохраняется); -- `/airdef sites` — известные пусковые площадки (ПУ) и ударные ракеты; `/airdef strike <номер ПУ>` — ответный удар по ПУ (#101, «удары по ПУ»). Как это играется: - - **Разведка без волшебства.** РЛС в пределах досягаемости и прямой видимости может заметить сам пуск и получить неточную позицию. Несколько наблюдённых пусков уточняют её. Если дрон обнаружен позже, используются только две измеренные позиции: обратный курс — слабое предположение, манёвр до обнаружения неизвестен, поэтому место старта не считается установленным. Повторные треки одного полёта не создают ложную точность. Для удара нужна достаточно точная наблюдённая позиция; скрытые координаты ПУ и время невидимого старта её не подменяют. - - **Удар.** Ударных ракет мало (3 в запасе, максимум 4, новая за 5 минут), дальность до 4500 блоков; стартуют оттуда, где вы стоите, летят 4 блока в тик (2 км за 25 с) в точку *оценки*. На подлёте ракету может сбить ПВО противника: у ПУ её нет (40%), лёгкая (35%, сбивает в 30%) или тяжёлая (25%, 65%), у баллистических батарей тяжёлая чаще; узнаёте только по итогу. Разброс ракеты 14 блоков; решает истинное расстояние до ПУ: до 35 блоков — **уничтожена** (запас сгорел и рвётся, отложенные запуски отменены, огонь и дымящийся остов, взрыв общим кодом), до 90 — **подавлена** на 30 с (пуски отложены, не отменены), дальше — **промах**, воронка рядом, ПУ цела: очередь за попадание в соседний грунт не списывается. Плохо известную ПУ (круг в сотни блоков) бить почти бесполезно. - - **Вне карты.** ПУ без земли (нет загруженной карты) тоже находится: азимут и дальность по трекам, но не рисуется. Удар, который попал бы, прекращает её пуски («результат не виден»); промах теряется. - - **Цена выбора.** Ракета запаса не вернётся, пока летит, налёт идёт: близкие площадки не остановить, далёкие (крылатые и баллистические за 2–4 км) успеваете, но для этого нужны РЛС с обзором в сторону налёта и риск промаха или ПВО противника. Отчёт налёта называет сорванные пуски: «Налёт сорван ударами по ПУ (№…): не взлетело N из заявленных M». - - Столкновение с рельефом или строением по пути взрывает ракету в точке контакта, не поражая ПУ; неизвестная геометрия задерживает полёт, а не считается воздухом. Если новая волна сворачивает старую ПУ, уже выпущенная ракета всё равно завершает полёт и даёт обычный исход. - - Запись: полёт ударной ракеты, её двигатель и исход попадают в журнал повтора (трек, строка и взрыв/огонь на карте), самостоятельный удар удерживает запись до завершения; сами ПУ в повторе не рисуются. Запас ракет входит в сохранение и сценарий (`strikes <запас> <тиков до следующей>`), прогресс пополнения автосохраняется контрольными точками с точностью до 5 секунд. Все числа механики в одной таблице `TUNE` в `src/sim/strike.rs`. +- `/airdef sites` — известные пусковые площадки (ПУ). РЛС с прямой видимостью может заметить сам пуск и получить неточную позицию; несколько наблюдённых пусков уточняют её. Обнаруженный позже дрон даёт только слабое предположение об обратном курсе: скрытые координаты площадки и время невидимого старта не используются. Повторные треки одного полёта не создают ложную точность. +- `/airdef strike <номер ПУ>` — ручной приказ, **пока недоступен**: для текущей техники ещё не реализован подтверждённый совместимый боеприпас и режим удара по координатам (#118). Приказ объясняет причину, не запускает ракету от игрока и не тратит общий запас. Старые поля запаса сохраняются для совместимости формата; автоматически он больше не пополняется. Случайный перехват несуществующим «ПВО площадки» удалён. Механика полёта/коллизий/записи сохранена и проверяется отдельными тестовыми пусками. Следующий этап — физический носитель, поштучный совместимый боекомплект, подготовка пуска и снабжение; наземный режим не назначается всем зенитным ракетам по умолчанию. - `/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 блоках перед собой; diff --git a/airdef-mod/src/lib.rs b/airdef-mod/src/lib.rs index b35e100..02cca4b 100644 --- a/airdef-mod/src/lib.rs +++ b/airdef-mod/src/lib.rs @@ -2218,7 +2218,7 @@ impl Mod for AirDef { None } ["strike", n] => { - // A strike missile at known site n, from where the player stands. + // A manual order: the simulation validates availability; player position is no launcher. let p = player().ok_or("Нет игрока")?; let id = n.parse::().map_err(|_| "/airdef strike <номер ПУ из /airdef sites>")?; let said = self.sim.order_strike(id, DVec3::new(p.x, p.y, p.z), &mut out)?; diff --git a/airdef-mod/src/map.rs b/airdef-mod/src/map.rs index f7e5322..54c14a8 100644 --- a/airdef-mod/src/map.rs +++ b/airdef-mod/src/map.rs @@ -2395,12 +2395,12 @@ impl AirDef { (None, _) => lines.push(("Данных нет".into(), GREY)), } lines.push((format!("Пусков замечено: {}; последний {} с назад", k.launches, now.saturating_sub(k.last) / 20), GREY)); - lines.push((format!("Ударных ракет: {}", self.sim.strikes.stock), WHITE)); + lines.push(("Удар недоступен: нет совместимого боеприпаса".into(), GREY)); if k.aimed { lines.push(("Ракета по ней уже в полёте".into(), YELLOW)); } if k.est.is_some_and(|e| e.fix) && !matches!(k.state, SiteState::Destroyed(_)) { - btns.push(("Ударить по пусковой".into(), Act::Strike(id), false)); + btns.push(("Почему удар недоступен?".into(), Act::Strike(id), false)); } btns.push(("В центр".into(), Act::Centre, false)); }