Files
MVP1/Docs/Modules/World.md
T

98 lines
11 KiB
Markdown
Raw Normal View History

# Глобальный мир
Карта и перемещения: замок с боссом, 20 соседних городов, 12 лагерей разбойников, походы по реальному времени (идут, даже когда игра закрыта).
- **Сборки:**
- `Bogatyri.World.Simulation` — карта и походы, чистый C# без Unity (переедет на сервер);
- `Bogatyri.World` — `MarchManager`, Unity-часть.
- **Папка:** `Assets/Scripts/Modules/World`.
- **Зависит от:** ядра. Войска — через `IArmy`, добыча — через `IEconomy`, бой — через `IBattleSystem`.
## Контракт `IWorld`
| Член | Что делает |
| --- | --- |
| `ActiveMarches` | Сколько походов в пути. |
| `TryStartMarch(targetId, soldiers, out error)` | Отправить войско на цель. |
Получить: `GameServices.Get<IWorld>()`. Интерфейсу карты (`WorldMapController`) можно обращаться к `MarchManager.Instance` и его C#-событиям: там полные данные похода.
## События
**Публикует:**
- `MarchStartedEvent` — войско выступило;
- `MarchBattleResolvedEvent` — бой у цели прошёл;
- `MarchReturnedEvent` — войско вернулось, солдаты и добыча зачислены. Поля: `MarchId`, `Victory`, `Survivors`, `Sent`, `TargetEmpty` (лагерь уже был разбит, боя не было), `TargetName`, `LootText`.
**Слушает:** ничего.
По этим событиям `App/GameModules`:
- считает статистику для заданий (`marchesSent`, `dailyMarches`, `worldWins`);
- показывает окно «ВОЙСКО ВЕРНУЛОСЬ» в городе (`UI/MarchReturnPopup.cs`): куда ходили, победа или поражение, сколько вернулось из скольких, добыча.
- Окно появляется и за походы, закончившиеся, пока игра была закрыта: сразу после входа в город.
- Несколько возвращений — окна по очереди.
- На карте мира окно своё (`WorldMapController`).
## Сохранение
Секция `"world"`: `{ "marches": [ MarchData ], "camps": [ { "id", "respawnMs" } ] }` — походы и разбитые лагеря с моментом их появления. Старые сохранения без `camps` читаются: все лагеря на месте.
Сброс (`ResetState`): все походы отменяются, все лагеря на месте. Войска в походе не возвращаются: их сбрасывает `GameProgress` вместе с армией.
Раньше походы лежали в `progress.json` (`sashaMarches`). При первом запуске `App/GameModules` переносит их в модуль Мира и удаляет из `progress.json` только после записи `save.json`.
## Файлы
| Файл | Что это |
| --- | --- |
| `MarchManager.cs` | Ведёт походы, реализует `IWorld` и `ISaveParticipant`. Создаётся сам при запуске игры. |
| `Simulation/WorldMapLayout.cs` | Карта: замок, город игрока, 20 соседей и 12 лагерей из seed. |
| `Simulation/WorldSimulation.cs` | Походы: старт, бой по прибытии, возвращение. Бой получает через `IBattleSystem`. |
**Бой с типами войск:**
- у похода есть состав по типам (`MarchData.units`, берётся у Армии при выступлении) и выжившие по типам (`survivorUnits`);
- у цели — состав гарнизона `WorldMapLayout.GarrisonUnits(node)`. Он вычисляется из id цели, а не из генератора карты, поэтому карта осталась прежней. У Змея Горыныча 40% пехоты, 30% лучников, 20% кавалерии, 10% осадных; у соседей пропорции свои у каждого;
- замок и города сражаются за стенами;
- выжившие возвращаются в Армию точно по типам (`IArmy.ReturnUnits`). Старые походы без состава — как раньше, по пропорции;
- окно атаки показывает состав гарнизона и ожидаемый исход: силу сторон, «скорее победа / поражение» и примерные потери. Расчёт тот же, что сделает модуль Боя.
**Лагеря разбойников (PvE):**
- 12 лагерей, по 4 каждого уровня. Ставятся отдельным генератором после городов (`seed ^ CampSeedSalt`), поэтому замок, твой город и соседи остались на прежних местах. Лагерь может стоять ближе к городу (2,6 клетки), чем город к городу (3,6).
| Уровень | Название | Гарнизон | Добыча | Нужно пехоты (примерно) |
| --- | --- | --- | --- | --- |
| 1 | Стан разбойников | 6–9 | 15 еды, 15 дерева | 8–12 |
| 2 | Логово лиходеев | 14–17 | 25 еды, 25 дерева, 8 золота | 18–21 |
| 3 | Становище Соловья-разбойника | 26–29 | 40 еды, 40 дерева, 15 золота, 8 металла | 34–37 |
- бой в поле: стен нет (`WorldMapLayout.IsFortified`), у разбойников нет осадных — их доля уходит пехоте;
- после победы лагерь **разбит** на 30 минут (`CampRules.RespawnMs`, отсчёт от момента боя): на карте серый, с таймером, напасть нельзя;
- если к лагерю шли два войска, бьётся первое пришедшее (бои считаются по времени прихода). Второе находит лагерь пустым: боя нет, домой идут все, добычи нет (`MarchData.targetEmpty`, окно «ЛАГЕРЬ ПУСТ»);
- на карте лагерь — фиолетовый круг, подпись «название, ур. N, гарнизон».
**Время** походов — по `GameClock`: кнопки «+1 час» / «+10 часов» в отладочной панели проматывают и походы.
В слое приложения остаются `WorldMap/WorldMapController.cs`, `MarchView.cs`, `MapCameraController.cs`, `SceneNavigator.cs`.
**В игре одна карта мира** — сцена WorldMap. Открывается кнопкой «БОЙ» и кнопкой «МИР» в городе (`UIPanelManager.Open("World")` ведёт в эту сцену).
## Решения и план
- **Этап 0, решено 19.10.2026:** осталась одна карта мира — эта. Маленькая карта (панель «МИР», `Meta/World`) удалена. Перед удалением проверены ссылки в коде, сценах и префабах. Перенос сохранений: солдаты из её походов (`marches` в `progress.json`) возвращаются в город при загрузке — отправленные, а если отряд уже шёл назад, то выжившие. Добыча таких походов не переносится.
- **Этап 4 (утверждён без изменений):** у позиций на карте — месторождения и их качество.
- **Этап 6:** временные ресурсные точки и кристальные разломы; войска на точке недоступны дома.
- **Лагеря:** числа (гарнизон, добыча, 30 минут до появления) — предложение, требуют балансировки. Позже их можно перенести в `EconomyConfig`. В мультиплеере разбитый лагерь — общий для всех игроков, его состояние будет вести сервер.
## Журнал изменений
| Дата | Кто | Что |
| --- | --- | --- |
2026-10-27 16:54:49 +01:00
| 27.10.2026 | Claude | В поход уходят только свободные воины: гарнизон остаётся в городе. Верхняя панель карты: «Свободно / Гарнизон / В походе». |
| 27.10.2026 | Claude | Лагеря разбойников (PvE): 12 лагерей трёх уровней, бой в поле, после победы лагерь разбит на 30 минут, второе войско находит его пустым. Секция `world` хранит разбитые лагеря, в `MarchReturnedEvent` добавлен `TargetEmpty`. Тесты: расстановка лагерей, разбит и появляется снова, сохранение. |
| 27.10.2026 | Claude | Бой с типами войск: состав похода и гарнизона, стены у замка и городов, выжившие по типам, ожидаемый исход в окне атаки. Время походов — по `GameClock` (перемотка в DEV проматывает походы). |
| 23.10.2026 | Claude | Окно «ВОЙСКО ВЕРНУЛОСЬ» в городе. В `MarchReturnedEvent` добавлены `Sent`, `TargetName`, `LootText`. |
| 19.10.2026 | Claude | Маленькая карта мира (`Meta/World`: WorldSystem, WorldMapPanel, WorldData, WorldLine) удалена, окно `Panel_World` убрано из сцены города. Кнопка «МИР» открывает эту карту. Солдаты из походов старой карты возвращаются в город. |
| 19.10.2026 | Claude | `ResetState()`: при сбросе сохранений походы отменяются. |
| 19.10.2026 | Claude | Модуль выделен. `MarchManager` больше не обращается к `GameProgress` и `ResourceManager`: войска через `IArmy`, добыча через `IEconomy`, сохранение — своя секция `"world"`, статистика — через события. Формула боя вынесена в модуль Боя. |