Разведка М1: туман, обзор, чужие армии, последний контакт; патрули-заглушки

- Новый модуль Bogatyri.Intelligence (без Unity): туман в трёх состояниях,
  обзор поселения 5 / армии 1 клетка, «Обзор» +10/20/30% (заменяет),
  примерная численность ±20%, опознание 50% на событие наблюдения,
  последний контакт 10 реальных минут, офлайн-досчёт шагами 10 с,
  сохранение в секции intelligence.
- Мир: IWorldMap (армии в момент времени), WorldAdvancingEvent,
  патрули-заглушки соседей (временно, выключаются в MarchConfig).
- Карта: IntelligenceOverlay — туман и метки чужих армий.
- Таблица IntelligenceConfig, 11 новых тестов, документы.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander
2026-10-31 17:05:17 +01:00
co-authored by Claude Opus 5.5
parent c1832a2ae7
commit 552694f882
28 changed files with 1470 additions and 7 deletions
+3
View File
@@ -34,6 +34,8 @@
| `IPopulation` | Поселение, часть «Население» (`PopulationService`) | Жители, рабочие по профессиям, воины, предел жилья, расход еды и прирост в час, голод и его история (`WasStarvingAt`), найм воинов из жителей; `Tick` — досчитать до момента. |
| `IArmy` | Армия (`ArmyService`) | Войска по типам, в городе и в походах; обучение, потери; забрать в поход, вернуть выживших. |
| `IWorld` | Мир (`MarchManager`) | Сколько походов в пути; начать поход. |
| `IWorldMap` | Мир (`MarchManager`) | Для Разведки: границы карты, где поселение, все армии в момент времени (`ArmyOnMap`). |
| `IIntelligence` | Разведка (`IntelligenceService`) | Туман (`GetVisibility`), «Обзор», известные чужие армии (`KnownContact`), `ObserveUntil`. |
| `IBattleSystem` | Бой (`BattleSystem`) | Посчитать исход боя по `BattleRequest`: состав сторон по типам, стены, бонусы. |
| `IChat` | Чат (`ChatService`) | История каналов, можно ли писать в канал, отправка сообщения от локального игрока. |
| `ICircle` | Круг (`CircleService`) | Круг игрока, список Кругов; основать, вступить, выйти. |
@@ -58,6 +60,7 @@
| Дата | Кто | Что |
| --- | --- | --- |
| 31.10.2026 | Claude | Разведка М1: контракты `IWorldMap`, `IIntelligence` (`ArmyOnMap`, `MapVisibility`, `KnownContact`), события `WorldAdvancingEvent`, `ArmySpottedEvent`, `ArmyIdentifiedEvent`, `ArmyLostContactEvent`. |
| 31.10.2026 | Claude | `MarchReturnedEvent.IsGather` — поход на ресурсную точку. |
| 31.10.2026 | Claude | `IArmy.MarchSlots`, `IArmy.ActiveMarches` — слоты похода. |
| 30.10.2026 | Claude | События похода: `TimeMs` (когда случилось по часам игры) у `MarchStartedEvent`, `MarchBattleResolvedEvent`, `MarchReturnedEvent`; `BattleId` у `MarchBattleResolvedEvent`. |
+109
View File
@@ -0,0 +1,109 @@
# Разведка
Туман войны, источники обзора, чужие армии и последний контакт. Этап М1 по ТЗ разведки от 31.10.2026, решение №46: отдельный модуль.
- **Сборка:** `Bogatyri.Intelligence` (без Unity: тот же код будет считать видимость на сервере).
- **Папка:** `Assets/Scripts/Modules/Intelligence`.
- **Зависит от:** только ядра. Карту и армии читает у Мира через контракт `IWorldMap`, отряды — их часть. Сам Мир о Разведке не знает: прямых ссылок между World и Intelligence нет.
- **Отвечает:** Саша (решение №46).
## Что умеет М1
| | |
| --- | --- |
| Туман | Три состояния клетки: **не исследовано**, **исследовано** (было в обзоре), **видно сейчас**. Клетка = клетка карты (1000 милли-единиц). |
| Источники обзора | Своё поселение — 5 клеток, своя армия в походе — 1 клетка. Башни и герой-разведчик — позже (числа в правилах уже есть). |
| «Обзор» I/II/III | +10 / +20 / +30% к радиусам. Уровни **не складываются** — действует текущий. Пока нет дерева технологий, уровень для теста задаётся в таблице. |
| Чужие армии | Видны, только пока они в обзоре. Примерная численность ±20%, владелец — после опознания. |
| Событие наблюдения | Армия вошла в обзор. На событие — **один** бросок численности и **один** бросок опознания (50%). Повторный расчёт, загрузка или нажатие не перебрасывают. Вышла и вошла снова — новое событие. |
| Последний контакт | Армия вышла из обзора — остаётся бледная метка с последними данными. Данные больше не обновляются. Метка живёт 10 **реальных** минут. |
| Офлайн | Наблюдение досчитывается шагами по 10 реальных секунд, не больше 48 часов. Армия, прошедшая через обзор, пока игра была закрыта, тоже будет замечена — события в порядке времени. |
Примерная численность: окно шириной 40% от настоящей численности, сдвинутое случайно так, чтобы настоящая численность всегда была внутри. Пример: 50 воинов → «~42–62».
## Контракт `IIntelligence`
| Член | Что делает |
| --- | --- |
| `ObservationLevel` | Уровень «Обзора» 0..3. |
| `GetVisibility(x, y)` | `Unexplored` / `Explored` / `Observed` для точки карты — по последнему расчёту. |
| `Contacts` | Известные чужие армии (`KnownContact`): где, куда идёт, `~ApproxMin–ApproxMax`, опознан ли и чей (`OwnerId` — только после опознания), видна ли сейчас, когда видели. |
| `ObserveUntil(nowMs)` | Досчитать наблюдение до момента. Зовёт `App/GameModules` по `WorldAdvancingEvent`. |
## Что берёт у Мира: `IWorldMap`
Реализует `MarchManager` (модуль Мира).
| Член | Что это |
| --- | --- |
| `HalfWidth`, `HalfHeight` | Границы карты от центра. |
| `TryGetSettlement(ownerId, …)` | Где поселение игрока. |
| `GetArmies(timeMs, …)` | Все армии на карте в момент `timeMs` (`ArmyOnMap`: id, владелец, где, куда, сколько воинов). Позиция считается по времени похода, поэтому можно спросить и о прошедших минутах. |
## События
**Публикует** (у всех — `EventId` = «армия#номер наблюдения» и `TimeMs` по часам игры):
- `ArmySpottedEvent` — чужая армия вошла в обзор, с примерной численностью;
- `ArmyIdentifiedEvent` — владелец опознан;
- `ArmyLostContactEvent` — армия вышла из обзора.
**Слушает:** ничего напрямую. `WorldAdvancingEvent` (публикует Мир перед каждым расчётом) связан с `ObserveUntil` в `App/GameModules`.
## Патрули-заглушки (временно)
Решение команды 31.10.2026: для проверки М1 соседние поселения иногда отправляют тестовые отряды к другим городам и лагерям. **Это временная тестовая механика, а не ИИ соседей.**
- Патрули — обычные походы Мира (`MarchData.patrol`): Разведка видит их через тот же `IWorldMap`, что и настоящие армии. Когда появится PvP, их выключают в таблице — Разведка не меняется.
- Боя, добычи и разбития лагеря нет. Армия игрока, окна итогов и события похода их не касаются.
- Выходят из ближайших к игроку соседних городов и идут к ближайшим к игроку целям — чтобы проходили через обзор.
- Выпускаются по расписанию из seed карты: тот же расчёт после офлайна даёт те же патрули. Сохраняются в секции `world`.
- Таблица `MarchConfig`: `patrolsEnabled` (вкл/выкл), `patrolMaxActive` 3, `patrolIntervalMinutes` 10 реальных минут, `patrolSoldiersMin/Max` 10–40.
## Карта мира
`WorldMap/IntelligenceOverlay.cs` рисует то, что вернула Разведка:
- туман: не исследовано — тёмное, исследовано — притушено, в обзоре — чисто;
- чужая армия в обзоре — красный ромб, подпись «чужая армия / ~42–62 воинов» или имя владельца, если опознан;
- последний контакт — бледный ромб «контакт N мин назад».
Свои походы рисуются как раньше (`MarchView`). Чужие походы `WorldMapController` сам не рисует — только через Разведку.
**Открытый вопрос команде: что видно в неисследованных местах.** Пока не решено, по умолчанию города, лагеря и ресурсные точки видны всегда, а туман затемняет только землю. `IntelligenceConfig.hideUnexploredObjects` закрывает неисследованное вместе с объектами (тап по скрытому объекту пока работает).
## Таблица `IntelligenceConfig`
`Assets/Resources/IntelligenceConfig.asset`, числа — ТЕСТ: `settlementRadius` 5, `armyRadius` 1 (клеток), `observationPercent` 10/20/30, `testObservationLevel` (только для теста), `lastContactMinutes` 10, `approxPercent` 20, `identifyPercent` 50, `sampleStepSeconds` 10, `hideUnexploredObjects`.
## Сохранение
Секция `"intelligence"`, простые строки (модуль без Unity):
- `tick=<мс>` — до какого момента посчитано наблюдение;
- `obzor=<уровень>`;
- `grid=<ширина>x<высота>:<hex>` — исследованные клетки, по биту на клетку;
- `contact=<армия>|<владелец>|<опознан>|<видна>|x|y|toX|toY|min|max|<видели>|<номер наблюдения>`.
Сброс (`ResetState`): туман закрыт, контактов нет, «Обзор» 0.
## Файлы
| Файл | Что это |
| --- | --- |
| `IntelligenceService.cs` | `IntelligenceRules` (числа) и `IntelligenceService` (`IIntelligence`, `ISaveParticipant`). |
| `Bogatyri.Intelligence.asmdef` | Сборка: только ядро, без Unity. |
Вне модуля: `App/IntelligenceConfig.cs` (таблица), `WorldMap/IntelligenceOverlay.cs` (рисование), `World/Simulation/WorldSimulation.Patrols.cs` (патрули и позиция армии в момент времени — часть Мира).
## Тесты
`ModuleTests`: вход и выход из обзора, последний контакт и его устаревание, свои армии как источники, «Обзор» заменяет уровень, туман «исследовано» остаётся, офлайн-проход через обзор, воспроизводимые броски и ~50% опознаний, новое событие при повторном входе, сохранение и загрузка без повторного обнаружения; патрули без боёв и событий, выключение, воспроизводимость и сохранение, позиция по времени, патрули замечаются Разведкой.
## Решения и план
- М2–М4 по ТЗ: башни, герой-разведчик, разведка поселений, отчёты — следующими этапами.
- Открыто: видимость объектов в неисследованных местах (см. выше).
## Журнал изменений
| Дата | Кто | Что |
| --- | --- | --- |
| 31.10.2026 | Claude | Модуль создан: этап М1 — туман, источники обзора, «Обзор», чужие армии, примерная численность, опознание, последний контакт, офлайн-наблюдение, сохранение. Патрули-заглушки соседей для проверки (выключаются в `MarchConfig`). |
+3 -1
View File
@@ -50,7 +50,7 @@ App/GameModules — точка сборки: регистрирует модул
| Кто | Модули |
| --- | --- |
| Валдемар (экономика) | Экономика, люди Поселения (`Settlement/Population`) |
| Саша (война и карта) | Армия, Боевая система, Глобальный мир, Круг, Чат |
| Саша (война и карта) | Армия, Боевая система, Глобальный мир, Круг, Чат, Разведка |
| Общее | Ядро, здания Поселения, Сохранения |
| Модуль | Сборка | Папка | Документ |
@@ -64,6 +64,7 @@ App/GameModules — точка сборки: регистрирует модул
| Сохранения | `Bogatyri.Save` | `Assets/Scripts/Modules/Save` | [Save.md](Save.md) |
| Чат | `Bogatyri.Chat` (без Unity) | `Assets/Scripts/Modules/Chat` | [Chat.md](Chat.md) |
| Круг | `Bogatyri.Circle` (без Unity) | `Assets/Scripts/Modules/Circle` | [Circle.md](Circle.md) |
| Разведка | `Bogatyri.Intelligence` (без Unity) | `Assets/Scripts/Modules/Intelligence` | [Intelligence.md](Intelligence.md) |
## Правила
@@ -99,6 +100,7 @@ EditMode-тесты: `Assets/Scripts/Modules/Tests/ModuleTests.cs`. Запуск
| Дата | Кто | Что |
| --- | --- | --- |
| 31.10.2026 | Claude | Модуль Разведки, этап М1 ([Intelligence.md](Intelligence.md)): туман, обзор, чужие армии, последний контакт. Патрули-заглушки соседей для проверки. Обновлены World, Core, Save. |
| 31.10.2026 | Claude | Панель армий на карте мира (регламент 31.10). Обновлён World. |
| 31.10.2026 | Claude | Ресурсные точки на карте мира по регламенту 31.10 (наша часть по решению №46: состояние точки и сбор; зачисление — Экономика через `IEconomy`). Обновлены World, Save, Core. |
| 31.10.2026 | Claude | Скорости маршей по типам и слоты похода по регламенту 31.10 (таблица `MarchConfig`). Обновлены World, Army, Core. |
+3 -1
View File
@@ -34,7 +34,8 @@ SaveRegistry.Register(myModule); // при запуске модуля
| --- | --- |
| `economy` | Экономика |
| `settlement` | Поселение |
| `world` | Глобальный мир (походы, разбитые лагеря, ресурсные точки) |
| `world` | Глобальный мир (походы, разбитые лагеря, ресурсные точки, патрули-заглушки) |
| `intelligence` | Разведка (простые строки: `tick=…`, `obzor=…`, `grid=…`, `contact=…`) |
| `circle` | Круг (простые строки, не JSON — модуль без Unity) |
| `army` | Армия (простые строки: `troops=…`, `march=…`) |
| `population` | Население (простые строки: `civilians=…`, `jobs=…`, `lastTick=…` и др.) |
@@ -106,6 +107,7 @@ SaveRegistry.Register(myModule); // при запуске модуля
| Дата | Кто | Что |
| --- | --- | --- |
| 31.10.2026 | Claude | Секция `intelligence` (Разведка М1); в `world` — состояние патрулей-заглушек `patrols`. |
| 31.10.2026 | Claude | Секция `world`: ресурсные точки (`points`: запасы, сроки, кто собирает). Старые сохранения без точек читаются — точки появятся при первом расчёте мира. |
| 27.10.2026 | Claude | Секция `world`: добавлен список разбитых лагерей `camps`. |
| 27.10.2026 | Claude | Новая секция `production`; в секции `economy` — список `capacities` (лимиты склада). |
+10
View File
@@ -15,6 +15,10 @@
| `ActiveMarches` | Сколько походов в пути. |
| `TryStartMarch(targetId, soldiers, out error)` | Отправить войско на цель. |
`MarchManager` реализует и `IWorldMap` — для Разведки: границы карты, где поселение, где все армии в момент времени (`WorldSimulation.TryGetPositionAt`). `ActiveMarches` считает только походы игрока.
**Патрули-заглушки** (Разведка М1, временно): соседи иногда отправляют отряды к городам и лагерям и обратно. Без боя и добычи, Армия о них не знает. Включаются в `MarchConfig` (`patrolsEnabled` и др.), см. [Intelligence.md](Intelligence.md).
Получить: `GameServices.Get<IWorld>()`. Интерфейсу карты (`WorldMapController`) можно обращаться к `MarchManager.Instance` и его C#-событиям: там полные данные похода.
## События
@@ -27,6 +31,10 @@
- `MarchBattleResolvedEvent` — бой у цели прошёл (`TimeMs` = приход, `BattleId` = номер боя);
- `MarchReturnedEvent` — войско вернулось, солдаты и добыча зачислены. Поля: `MarchId`, `Victory`, `Survivors`, `Sent`, `TargetEmpty` (лагерь уже был разбит, боя не было), `TargetName`, `LootText`.
- `WorldAdvancingEvent` — мир сейчас продвинется до `ToMs` (перед каждым расчётом): Разведка успевает досчитать наблюдение, пока вернувшиеся походы ещё на карте.
У патрулей-заглушек событий нет.
**Слушает:** ничего.
По этим событиям `App/GameModules`:
@@ -51,6 +59,7 @@
| `MarchManager.cs` | Ведёт походы, реализует `IWorld` и `ISaveParticipant`. Создаётся сам при запуске игры. |
| `Simulation/WorldMapLayout.cs` | Карта: замок, город игрока, 20 соседей и 12 лагерей из seed. |
| `Simulation/WorldSimulation.cs` | Походы: старт, бой по прибытии, возвращение. Бой получает через `IBattleSystem`. |
| `Simulation/WorldSimulation.Patrols.cs` | Патрули-заглушки соседей (`PatrolRules`, `PatrolState`) и позиция армии в момент времени (`TryGetPositionAt`). |
**Бой с типами войск:**
- у похода есть состав по типам (`MarchData.units`, берётся у Армии при выступлении) и выжившие по типам (`survivorUnits`);
@@ -135,6 +144,7 @@
| Дата | Кто | Что |
| --- | --- | --- |
| 31.10.2026 | Claude | Для Разведки М1: `IWorldMap` (армии на карте в момент времени), `WorldAdvancingEvent`, патрули-заглушки соседей (`MarchData.patrol`, сохранение `patrols`, таблица `MarchConfig`). |
| 31.10.2026 | Claude | Панель армий (`WorldMap/ArmiesWindow.cs`, кнопка «Армии» на карте мира): местонахождение и действие каждого войска, состав, груз, время до цели / конца сбора / возвращения. В окне атаки — длительность всего задания для боя. |
| 31.10.2026 | Claude | Ресурсные точки (регламент 31.10, раздел 7): `ResourcePoint`, `ResourcePointRules`, `WorldSimulation.Points.cs` — появление, сбор (`MarchState.Gathering`), истощение, исчезновение, замена новой точкой; события `GatherStarted`, `GatherFinished`; сохранение в секции `world`; таблица `WorldResourceConfig`; на карте — ромбы точек, окно отправки с прогнозом сбора, подпись отряда «сбор». Тесты: появление, сбор и груз, истощение и новая точка, осадные без груза, точка исчезла до прихода и во время сбора, одна точка — одно войско, сохранение посреди сбора. |
| 31.10.2026 | Claude | Скорости маршей по типам (регламент 31.10: 8 / 9 / 12 / 4 клетки за реальный час, таблица `MarchConfig`), войско — по самому медленному типу, обратно — по составу выживших; `WorldSimulation.TravelTimeMs`, `AssignUnits`, `MarchSpeedRules`; слоты похода (база 2) в окне атаки и верхней строке. Тесты: скорости по типам, смешанное войско, обратный путь; старые тесты переведены на часовые марши. |