Слияние с feature/battle-famine (бой, голод, гарнизон, лагеря)
This commit is contained in:
+36
-7
@@ -1,6 +1,6 @@
|
||||
# Армия
|
||||
|
||||
Войска и их характеристики: сколько воинов каждого типа в городе, сколько в походах, обучение, потери, уход в поход и возвращение. **Единственное место, где хранятся войска.**
|
||||
Войска и их характеристики: сколько воинов каждого типа в городе, сколько из них в гарнизоне, сколько в походах, обучение, потери, уход в поход и возвращение. **Единственное место, где хранятся войска.**
|
||||
|
||||
- **Сборка:** `Bogatyri.Army` (без Unity).
|
||||
- **Папка:** `Assets/Scripts/Modules/Army`.
|
||||
@@ -12,12 +12,17 @@
|
||||
| --- | --- |
|
||||
| `TypeCount` | Типов войск — 4 (пехота, лучники, кавалерия, осадные; порядок как в `GameData.Troops`). |
|
||||
| `GetTroops(type)` | Воинов этого типа в городе. |
|
||||
| `SoldiersAtHome` | Всего воинов в городе. |
|
||||
| `SoldiersAtHome` | Всего воинов в городе (вместе с гарнизоном). |
|
||||
| `TroopsInMarches` | Воинов в походах. |
|
||||
| `GarrisonTotal`, `GetGarrison(type)` | Сколько воинов в гарнизоне — всего и по типам. |
|
||||
| `AvailableForMarch` | Свободные воины: в городе минус гарнизон. Только их можно отправить в поход. |
|
||||
| `SetGarrison(count)` | Назначить гарнизон: набирается по составу армии в городе (30 пехоты и 10 лучников, гарнизон 8 → 6 пехоты и 2 лучника). Не больше, чем воинов в городе; возвращает, сколько назначено. |
|
||||
| `AddTroops(type, count)` | Добавить воинов (обучение в Казармах). |
|
||||
| `LoseFraction(fraction)` | Потери в бою: от каждого типа погибает доля (с округлением вниз); возвращает, сколько погибло. |
|
||||
| `TakeForMarch(marchId, count)` | Забрать воинов в поход пропорционально составу армии и запомнить состав. |
|
||||
| `ReturnFromMarch(marchId, survivors)` | Вернуть выживших по тем же типам. |
|
||||
| `TakeForMarch(marchId, count)` | Забрать свободных воинов (без гарнизона) в поход пропорционально составу и запомнить состав. `false` — ничего не взято: не хватает воинов или поход с таким номером уже есть. |
|
||||
| `ReturnFromMarch(marchId, survivors)` | Вернуть выживших по тем же типам (пропорционально). `false` — поход неизвестен, никто не добавлен. |
|
||||
| `GetMarchUnits(marchId)` | Состав похода по типам — для боя с типами войск. |
|
||||
| `ReturnUnits(marchId, survivorUnits)` | Вернуть выживших точно по типам, как посчитал бой. Больше, чем ушло, не вернётся. `false` — поход неизвестен. |
|
||||
|
||||
Получить: `GameServices.Get<IArmy>()`. Регистрирует `App/GameModules`. `GameProgress` (обучение, кампания, арена, сила армии) и панели работают с войсками только через этот контракт.
|
||||
|
||||
@@ -25,9 +30,26 @@
|
||||
|
||||
Воин либо в городе, либо в походе. Поход забирает воинов из города и запоминает состав, возвращение раздаёт выживших по тем же типам. Тест `ArmyService_MarchNeverCreatesOrLosesSoldiers` проверяет, что «дома + в походах» всегда равно общему числу.
|
||||
|
||||
**Возвращение — только по известному походу и только один раз** (ревью 27.10.2026, п. 2.1):
|
||||
|
||||
- неизвестный поход (повторное событие, испорченное сохранение) не добавляет никого — раньше такие выжившие зачислялись пехотой;
|
||||
- после возвращения запись похода удаляется, второе возвращение того же похода возвращает `false`;
|
||||
- вернуться может не больше, чем ушло;
|
||||
- два похода с одним номером невозможны: `TakeForMarch` отклоняет повтор, загрузка и перенос старых данных пропускают дубликаты;
|
||||
- перенос старых сохранений — отдельно, в `ImportLegacy`.
|
||||
|
||||
**Гарнизон** — часть воинов города. Они по-прежнему в городе (`SoldiersAtHome`), но в поход не уходят:
|
||||
|
||||
- 30 воинов, 10 в гарнизоне → 20 свободны, всего по-прежнему 30 (тест `ArmyService_Garrison_OneSoldierInOnePlace`);
|
||||
- гарнизон по каждому типу никогда не больше воинов этого типа: после потерь (`LoseFraction`) он обрезается;
|
||||
- новые воины из Казарм становятся свободными, гарнизон не меняется;
|
||||
- назначается в окне «Войска» в городе, карточка «Гарнизон города»: кнопки 0, -10, -1, +1, +10, «Все».
|
||||
|
||||
Пока гарнизон только держит воинов дома: на город игрока никто не нападает. Защита города, еда гарнизона и дебаффы при голоде — по плану ниже.
|
||||
|
||||
## События
|
||||
|
||||
- **Публикует:** `TroopsChangedEvent` (воинов в городе и в походах) — при обучении, потерях, походе, возвращении, загрузке, сбросе. По нему `App/GameModules` перерисовывает панели HUD.
|
||||
- **Публикует:** `TroopsChangedEvent` (воинов в городе, из них в гарнизоне, и в походах) — при обучении, потерях, походе, возвращении, загрузке, сбросе. По нему `App/GameModules` перерисовывает панели HUD.
|
||||
- **Слушает:** ничего.
|
||||
|
||||
## Сохранение
|
||||
@@ -36,10 +58,13 @@
|
||||
|
||||
```
|
||||
troops=<пехота>,<лучники>,<кавалерия>,<осадные>
|
||||
garrison=<пехота>,<лучники>,<кавалерия>,<осадные> (часть troops)
|
||||
march=<id похода>:<пехота>,<лучники>,<кавалерия>,<осадные>
|
||||
```
|
||||
|
||||
Сброс (`ResetState`): войск и походов нет.
|
||||
Старое сохранение без строки `garrison` читается: гарнизона нет.
|
||||
|
||||
Сброс (`ResetState`): войск, гарнизона и походов нет.
|
||||
|
||||
**Перенос из старых сохранений:**
|
||||
- Раньше войска лежали в `progress.json`: `troops` хранил `GameProgress`, `sashaMarchUnits` — мост `ArmyBridge`.
|
||||
@@ -62,13 +87,17 @@ march=<id похода>:<пехота>,<лучники>,<кавалерия>,<о
|
||||
- общая армия = гарнизон + доступные отряды + войска в походах, на точках и в гарнизоне Круга, **один солдат не может быть в двух местах**;
|
||||
- гарнизон ест еду и участвует в защите;
|
||||
- при голоде дебаффы действуют и на гарнизон, и на походы.
|
||||
- **Следующий шаг модуля:** гарнизон — третье место для солдата рядом с «дома» и «в походе».
|
||||
- **Сделано 27.10.2026:** гарнизон города (`SetGarrison`, `AvailableForMarch`).
|
||||
- **Дальше по гарнизону:** участие в защите города (когда на него смогут напасть — PvP), еда гарнизона (сейчас все воины едят одинаково, считает модуль Населения), дебаффы при голоде. Выбор состава по типам — если понадобится.
|
||||
- Описания типов войск (`GameData.Troops`: цена, сила, время обучения) пока в слое приложения; цены перейдут в `EconomyConfig`.
|
||||
|
||||
## Журнал изменений
|
||||
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 28.10.2026 | Claude | По ревью 27.10.2026 (п. 2.1–2.2): `ReturnFromMarch` и `ReturnUnits` возвращают `bool` и зачисляют только по известному походу и только один раз; `TakeForMarch` отклоняет повторный номер похода; дубликаты походов в сохранении пропускаются. Тесты: неизвестный поход, повторное возвращение, повторный номер. |
|
||||
| 27.10.2026 | Claude | Гарнизон города: `GarrisonTotal`, `GetGarrison`, `AvailableForMarch`, `SetGarrison`; в поход уходят только свободные; строка `garrison=` в сохранении; поле `Garrison` в `TroopsChangedEvent`; карточка «Гарнизон города» в окне «Войска». Тест «один солдат в одном месте» с гарнизоном. |
|
||||
| 27.10.2026 | Claude | `GetMarchUnits` и `ReturnUnits`: бой с типами войск получает состав похода, выжившие возвращаются точно по типам. |
|
||||
| 23.10.2026 | Claude | Войска переехали в модуль: `ArmyService` — единственное хранилище войск (секция `"army"`), `IArmy` расширен (типы, обучение, потери, войска в походах), событие `TroopsChangedEvent`. Перенос из `progress.json` с удалением старых данных только после записи `save.json`. `ArmyBridge` удалён — контракты и перенос сохранений проверены тестами. |
|
||||
| 19.10.2026 | Claude | `ArmyBridge.TroopsInMarches` для панели «Войска». После удаления маленькой карты войска в походах учитываются только здесь (`sashaMarchUnits`). |
|
||||
| 19.10.2026 | Claude | Модуль создан: `ArmyMath` (правила деления войск, без Unity, тесты на отсутствие двойного учёта). `ArmyBridge` сохранён и теперь реализует `IArmy` через `ArmyMath`; формат `sashaMarchUnits` не изменён. |
|
||||
|
||||
+96
-13
@@ -1,28 +1,87 @@
|
||||
# Боевая система
|
||||
|
||||
Урон, потери, исход боя. Модуль только считает: кто победил и сколько погибло. Кто идёт в бой и что делать с итогом, решают другие модули.
|
||||
Урон, потери, исход боя с учётом типов войск. Модуль только считает: кто победил и сколько погибло каждого типа. Кто идёт в бой и что делать с итогом, решают другие модули.
|
||||
|
||||
- **Сборка:** `Bogatyri.Battle` (без Unity — тот же код будет считать бои на сервере).
|
||||
- **Сборка:** `Bogatyri.Battle` (без Unity и без float — тот же код будет считать бои на сервере).
|
||||
- **Папка:** `Assets/Scripts/Modules/Battle`.
|
||||
- **Зависит от:** ядра.
|
||||
|
||||
## Контракт `IBattleSystem`
|
||||
|
||||
`BattleOutcome Resolve(BattleRequest request)`
|
||||
- `BattleOutcome Resolve(BattleRequest request)` — бой.
|
||||
- `BattleForecast Forecast(BattleRequest request)` — прогноз до боя с учётом случайности. Итог конкретного боя не раскрывает.
|
||||
|
||||
| `BattleRequest` | `BattleOutcome` |
|
||||
| `BattleRequest` | Что это |
|
||||
| --- | --- |
|
||||
| `Attackers` — атакующих | `Victory` — победил атакующий |
|
||||
| `Defenders` — защитников | `AttackerLosses`, `DefenderLosses`, `Survivors` |
|
||||
| `AttackerUnits`, `DefenderUnits` | Состав сторон по типам (`TroopType`: пехота, лучники, кавалерия, осадные). |
|
||||
| `Attackers`, `Defenders` | Число воинов, если состав не задан (`null`) — тогда все считаются пехотой. |
|
||||
| `DefenderFortified` | Защитники за стенами (город, замок). У лагерей разбойников стен нет — бой в поле. |
|
||||
| `AttackerBonusPercent`, `DefenderBonusPercent` | Бонусы сторон в процентах: герой, технологии, голод (минус). |
|
||||
| `AttackerConditions`, `DefenderConditions` | Состояния сторон (`BattleCondition`, флаги): `Famine` — голод, `Fatigue` — усталость. |
|
||||
| `Seed` | Номер боя. Из него считается случайность сторон: тот же номер с теми же войсками — всегда тот же итог. |
|
||||
|
||||
Регистрирует `App/GameModules`. Мир получает модуль при создании симуляции, не через реестр — так симуляцию можно запустить на сервере.
|
||||
| `BattleOutcome` | Что это |
|
||||
| --- | --- |
|
||||
| `Victory` | Победил атакующий. |
|
||||
| `BattleId`, `RulesVersion` | Номер боя (= `Seed`) и версия правил, по которой посчитан итог. |
|
||||
| `AttackerPower`, `DefenderPower` | Итоговая сила сторон ×100 (целые числа): с контрами, стенами, бонусами и случайностью. |
|
||||
| `AttackerLuckPermille`, `DefenderLuckPermille` | Выпавшая случайность сторон в десятых долях процента: +23 = +2,3%. |
|
||||
| `AttackerConditionPercent`, `DefenderConditionPercent` | Сколько силы оставили состояния: 100 — без штрафов, 50 — голод, 40 — голод и усталость. |
|
||||
| `AttackerLosses`, `DefenderLosses`, `Survivors` | Выбывшие (погибшие + раненые) и выжившие атакующие — всего. |
|
||||
| `…UnitsBefore`, `…SurvivorUnits`, `…DeadUnits`, `…WoundedUnits` | По типам войск и **для обеих сторон**: до боя, выжившие, погибшие, раненые. По каждому типу: до = выжившие + погибшие + раненые. Раненых пока нет (нули): доля не утверждена. |
|
||||
| `DefenderLossUnits` | Выбывшие защитники по типам — для старого кода. |
|
||||
|
||||
## Текущие правила
|
||||
| `BattleForecast` | Что это |
|
||||
| --- | --- |
|
||||
| `Chance` | `Advantage` — победа при любой случайности, `Uncertain` — решает случайность, `HighRisk` — поражение при любой случайности. |
|
||||
| `AttackerPowerMin/Max`, `DefenderPowerMin/Max` | Сила сторон при крайних значениях случайности. |
|
||||
| `AttackerLossesMin/Max` | Потери атакующего: от лучшего случая до худшего. |
|
||||
|
||||
- Побеждает тот, у кого больше солдат; ничья — победа защитника.
|
||||
- Проигравший теряет половину своего войска, победитель — столько же.
|
||||
Регистрирует `App/GameModules`: числа боя — из таблицы `BattleConfig`, сила воина каждого типа — из `GameData.Troops` (4 / 5 / 9 / 16). Мир получает модуль при создании симуляции, не через реестр — так симуляцию можно запустить на сервере.
|
||||
|
||||
Пример: 30 против 20 — победа, погибает 10 атакующих и 10 защитников, домой идут 20.
|
||||
## Правила
|
||||
|
||||
Числа — **стартовые для тестирования** (план от 27.10.2026). Все они в одном месте:
|
||||
|
||||
- **в игре** — таблица `Assets/Resources/BattleConfig.asset`: выдели её в окне Project и меняй числа в Inspector, изменения действуют со следующего запуска. Скрипт таблицы — `App/BattleConfig.cs`;
|
||||
- **в модуле** — `BattleRules.cs` (значения по умолчанию для тестов и сервера). `App/GameModules` переводит таблицу в `BattleRules`;
|
||||
- **сила воинов** — в `GameData.Troops`, рядом с ценой и временем обучения;
|
||||
- **поменял числа — подними `version`**: итог боя запоминает версию правил (`RulesVersion`).
|
||||
|
||||
| Правило | Значение |
|
||||
| --- | --- |
|
||||
| Сила стороны | Сумма по типам: воины × сила типа × (100% + контры + осадный бонус) × (100% + бонусы стороны). |
|
||||
| Контры, +25% | Пехота сильнее кавалерии, кавалерия сильнее лучников, лучники сильнее пехоты. Бонус взвешивается по составу врага: против армии, где кавалерии 20%, пехота получает +5%. |
|
||||
| Осадные | Против стен +50%, в поле −25%. |
|
||||
| Стены | Защитники за стенами сильнее на 20%. |
|
||||
| Случайность, ±5% | Каждой стороне от −5% до +5% (с шагом 0,1%), отдельно. Считается из номера боя (`Seed`, алгоритм SplitMix64) — одинаково на любой платформе. Применяется последней: после контр, стен и бонусов. |
|
||||
| Голод, −50% | Утверждено 27.10.2026. Сила голодной стороны ×50%. Проверяется на момент боя. Действует и на нападающих, и на защитников. |
|
||||
| Усталость, −20% | Утверждено 27.10.2026. Сила ×80%. Правило уже в модуле, но **пока никто её не выставляет**: не утверждено, как учитывать смешивание свежих и уставших войск. |
|
||||
| Голод и усталость вместе | Последовательно: 50% × 80% = **40%** силы (а не 30%). |
|
||||
| Порядок | Контры и осадные → бонусы стороны → состояния (голод, усталость) → случайность. |
|
||||
| Исход | Побеждает тот, у кого итоговая сила больше; ничья — защитнику. |
|
||||
| Потери проигравшего | Половина каждого типа. |
|
||||
| Потери победителя | Половина × (сила проигравшего / сила победителя): чем ровнее бой, тем больше потерь, но не больше половины. |
|
||||
|
||||
Примеры (замок Змея Горыныча, гарнизон 20: пехота 8, лучники 6, кавалерия 4, осадные 2, за стенами):
|
||||
|
||||
| Атакующие | Сила | Исход | Вернутся |
|
||||
| --- | --- | --- | --- |
|
||||
| 30 пехоты | 126 против 155 | поражение | 15 |
|
||||
| 40 пехоты | 168 против 155 | победа | 22 |
|
||||
| 30 смешанных (12 / 8 / 6 / 4) | 248 против 154 | победа | — |
|
||||
|
||||
**Прогноз с учётом случайности** (тот же замок, 10 000 боёв с разными номерами):
|
||||
|
||||
| Атакующие | Прогноз | Сила | Потери | Побед на деле |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 30 пехоты | высокий риск поражения | 119–132 против 147–163 | 15 | 0% |
|
||||
| 36 пехоты | исход неясен | 143–158 против 147–163 | 16–18 | 27% |
|
||||
| 40 пехоты | исход неясен | 159–176 против 147–163 | 16–20 | 97% |
|
||||
| 45 пехоты | преимущество | 179–198 против 147–163 | 16–20 | 100% |
|
||||
| 30 смешанных (12 / 8 / 6 / 4) | преимущество | 235–260 против 146–162 | 7–9 | 100% |
|
||||
|
||||
Бой без состава (старые походы, `Attackers` и `Defenders` числами) считается так, будто все — пехота. Без стен 30 против 20 — по-прежнему победа и 20 вернувшихся.
|
||||
|
||||
## События
|
||||
|
||||
@@ -34,11 +93,35 @@
|
||||
|
||||
## Решения и план
|
||||
|
||||
- **Этап 6:** формула с типами войск — кто кого контрит и как делятся потери. Сначала записать правила в документ экономики.
|
||||
- **Решение команды от 19.10.2026:** при голоде сильные дебаффы на боевую эффективность, включая гарнизон и походы. В `BattleRequest` для этого появятся модификаторы силы сторон; проценты — из `EconomyConfig`.
|
||||
- **Сделано 28.10.2026 (этап 2 плана):** числа — в таблицу `BattleConfig` с версией; итог боя симметричный для обеих сторон; случайность ±5% из номера боя; прогноз «преимущество / исход неясен / высокий риск поражения».
|
||||
- **Открыто: прогноз.** «Исход неясен» охватывает и 27%, и 97% побед (таблица выше). Показывать ли игроку шанс победы в процентах — решает команда (посчитать его можно точно).
|
||||
- **Сделано 28.10.2026: голод в бою.** Голод игрока берётся из модуля Населения (`IPopulation.IsStarving`) в момент боя. Пример: 40 пехоты берут замок Змея Горыныча (168 против 155), голодные — нет (84 против 155). Числа — `famineStrengthPercent` и `fatigueStrengthPercent` в `BattleConfig` (версия правил 2).
|
||||
- **Ограничение голода в офлайне:** если бой прошёл, пока игра была закрыта, берётся голод на момент входа в игру — истории голода у модуля Населения нет. Точно — когда бои будет считать сервер или Население будет хранить, когда начался и кончился голод (договориться с экономикой).
|
||||
- **Голод гарнизона** пока не нужен: на город игрока никто не нападает. Правило защитника уже есть (`DefenderConditions`).
|
||||
- **Открыто: порядок бонусов и случайности.** Сейчас случайность применяется последней, после бонусов стороны.
|
||||
- **Номер боя в мультиплеере** должен выдавать сервер: иначе клиент мог бы подбирать удачный.
|
||||
- **Командный план и ревью от 27.10.2026** (`Bogatyri_Plan_razrabotki.docx`, `Bogatyri_Battle_Army_Review_27-10-2026.docx`): случайность ±5% каждой стороне (воспроизводимая), прогноз риска вместо точного итога, потери от соотношения сил, раненые и погибшие, голод −50%, усталость −20%, числа — в настройки. Делается на этапе 2 плана.
|
||||
- **Открыто: малые отряды и округление.** Потери округляются вниз по каждому типу, поэтому одиночный проигравший не гибнет никогда. Проверено 28.10.2026:
|
||||
|
||||
| Бой | Исход | Потери атакующего | Потери защитника |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 против 1 | ничья, защитнику | 0 | 0 |
|
||||
| 1 против 10 | поражение | 0 | 0 |
|
||||
| 10 против 1 | победа | 0 | 0 |
|
||||
|
||||
Варианты: округлять потери проигравшего вверх; или воспроизводимая случайность для остатка (одиночка гибнет с шансом 50%). Решает команда, тест `Battle_EdgeCases_OutcomeAndArithmetic` правило не фиксирует.
|
||||
|
||||
- **Утвердить формулу** (контры, стены, осадные, потери) или поправить числа в `BattleSystem.cs`.
|
||||
- **Бонус героя** пока не передаётся в поход: `GameProgress.ArmyBonus` и сила героя в слое приложения. Нужен способ передать их в `AttackerBonusPercent` — например, через новый контракт или поле похода.
|
||||
- **Решение команды от 19.10.2026:** при голоде сильные дебаффы на боевую эффективность, включая гарнизон и походы. Для этого есть `AttackerBonusPercent` / `DefenderBonusPercent` (минус), проценты — из `EconomyConfig`. Голод уже считает модуль Населения (`IsStarving`).
|
||||
- **Гарнизоны соседей** пока не уменьшаются после боя: соседи — заглушки до сервера.
|
||||
|
||||
## Журнал изменений
|
||||
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 28.10.2026 | Claude | Голод и усталость: `BattleCondition` (флаги), `BattleRequest.AttackerConditions` / `DefenderConditions`, `BattleOutcome.…ConditionPercent`; голод −50%, усталость −20%, вместе 40% (последовательно); числа в `BattleConfig` и `BattleRules` (версия 2). Тесты: штрафы, голод переворачивает бой у нападающего и у защитника, прогноз с голодом. |
|
||||
| 28.10.2026 | Claude | Этап 2 плана: числа боя — в таблицу `BattleConfig` (`Assets/Resources/BattleConfig.asset`) и `BattleRules` с версией; случайность ±5% каждой стороне из `BattleRequest.Seed`; `Forecast` — прогноз риска; `BattleOutcome` симметричный: до боя, выжившие, погибшие, раненые (пока нули) по типам у обеих сторон, номер боя, версия правил, удача сторон. Тесты: случайность воспроизводима и в пределах ±5%, прогноз не противоречит бою, итог сходится по типам, правила из таблицы. |
|
||||
| 28.10.2026 | Claude | Тест крайних случаев (ревью, п. 2.4): 1×1, 1×10, 10×1, 0×0, пустая сторона, смешанный состав, бонусы −100%, −500%, +100000%, бой числом. Проверяются исход и арифметика (нет отрицательных, выжившие + погибшие = ушедшие). Правило округления потерь — открытый вопрос. |
|
||||
| 27.10.2026 | Claude | Бой с типами войск: сила по типам из `GameData.Troops`, контры (пехота > кавалерия > лучники > пехота, +25%), стены +20%, осадные +50% против стен и −25% в поле, потери по типам. `BattleRequest` и `BattleOutcome` расширены, старый бой «числом» считается пехотой. Тесты: контры, стены, осадные, потери в пределах состава. |
|
||||
| 19.10.2026 | Claude | Модуль выделен: `BattleResolver` из `WorldSimulation.cs` стал `BattleSystem` с контрактом `IBattleSystem`; `BattleOutcome` перенесён в ядро. Правила не изменились. |
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
| `IPopulation` | Поселение, часть «Население» (`PopulationService`) | Жители, рабочие по профессиям, воины, предел жилья, расход еды и прирост в час, голод и его история (`WasStarvingAt`), найм воинов из жителей; `Tick` — досчитать до момента. |
|
||||
| `IArmy` | Армия (`ArmyService`) | Войска по типам, в городе и в походах; обучение, потери; забрать в поход, вернуть выживших. |
|
||||
| `IWorld` | Мир (`MarchManager`) | Сколько походов в пути; начать поход. |
|
||||
| `IBattleSystem` | Бой (`BattleSystem`) | Посчитать исход боя по `BattleRequest`. |
|
||||
| `IBattleSystem` | Бой (`BattleSystem`) | Посчитать исход боя по `BattleRequest`: состав сторон по типам, стены, бонусы. |
|
||||
| `IChat` | Чат (`ChatService`) | История каналов, можно ли писать в канал, отправка сообщения от локального игрока. |
|
||||
| `ICircle` | Круг (`CircleService`) | Круг игрока, список Кругов; основать, вступить, выйти. |
|
||||
| `ISaveSystem` | Сохранения (`SaveManager`) | Есть ли сохранение; сохранить сейчас; стереть; сбросить всё (`ResetAll`). |
|
||||
@@ -59,6 +59,12 @@
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 28.10.2026 | Claude | `IPopulation`: `WasStarvingAt` (история голода для боя), найм — `CivilianReserve`, `Recruitable`, `InTraining`, `TryRecruit`, `RecruitsTrained`. Население — часть Поселения. |
|
||||
| 28.10.2026 | Claude | Бой: `BattleCondition` (голод, усталость), `BattleRequest.AttackerConditions` / `DefenderConditions`, `BattleOutcome.AttackerConditionPercent` / `DefenderConditionPercent`. |
|
||||
| 28.10.2026 | Claude | Бой: `BattleRequest.Seed`; `BattleOutcome` — номер боя, версия правил, удача сторон, состав до боя, выжившие, погибшие и раненые по типам у обеих сторон; `IBattleSystem.Forecast`, `BattleForecast`, `BattleChance`. |
|
||||
| 28.10.2026 | Claude | `IArmy.ReturnFromMarch` и `IArmy.ReturnUnits` возвращают `bool`: зачисление только по известному походу и один раз. `TakeForMarch` отклоняет повторный номер похода. |
|
||||
| 27.10.2026 | Claude | `IArmy`: гарнизон (`GarrisonTotal`, `GetGarrison`, `AvailableForMarch`, `SetGarrison`); `TroopsChangedEvent.Garrison`. |
|
||||
| 27.10.2026 | Claude | `MarchReturnedEvent.TargetEmpty`: войско пришло к уже разбитому лагерю. |
|
||||
| 27.10.2026 | Claude | `TroopType` (типы войск), `BattleRequest` / `BattleOutcome` с составом по типам, силой сторон и бонусами; `IArmy.GetMarchUnits`, `IArmy.ReturnUnits`. |
|
||||
| 27.10.2026 | Claude | `WorkJob`; контракт `IProduction`; `IEconomy.GetCapacity`; `IPopulation`: `Workforce`, `FreeWorkers`, `GetWorkers`, `SetWorkers`; событие `WorkersChangedEvent`. |
|
||||
| 26.10.2026 | Claude | `GameClock`; контракт `IPopulation`; события `GameTimeAdvancedEvent`, `PopulationChangedEvent`, `StarvationChangedEvent`, `NewGameStartedEvent`. |
|
||||
| 23.10.2026 | Claude | `IArmy` расширен (типы, `AddTroops`, `LoseFraction`, `TroopsInMarches`), событие `TroopsChangedEvent`. `GameLoadedEvent` публикуется и когда файла сохранения нет. |
|
||||
|
||||
+60
-13
@@ -1,19 +1,58 @@
|
||||
# Модульная система «Богатырей»
|
||||
|
||||
Игра собрана из девяти модулей вокруг общего **Игрового ядра**. Модули общаются только через контракты и события ядра и не управляют внутренним кодом друг друга. Это правило проверяет сам Unity: каждый модуль — отдельная сборка (`.asmdef`), которая видит только ядро, поэтому прямое обращение к соседнему модулю не скомпилируется.
|
||||
Игра собрана из восьми модулей вокруг общего **Игрового ядра** — как на схеме Димы. Модули общаются только через контракты и события ядра и не управляют внутренним кодом друг друга. Это правило проверяет сам Unity: каждый модуль — отдельная сборка (`.asmdef`), которая видит только ядро, поэтому прямое обращение к соседнему модулю не скомпилируется.
|
||||
|
||||
```
|
||||
Игровое ядро (Bogatyri.Core)
|
||||
контракты (IEconomy, IArmy...) · события (EventBus) · реестр (GameServices)
|
||||
┌───────────┬────────────┬───────────┬──────────────┬───────────────┬────────────┬──────────┬──────────┐
|
||||
Экономика Поселение Армия Глобальный мир Боевая система Сохранения Чат Круг
|
||||
ресурсы, здания, войска, карта, урон, потери, игровое мир и объединение
|
||||
производство и люди характеристики перемещения исход состояние Круг игроков
|
||||
▲
|
||||
App/GameModules — точка сборки: регистрирует модули и соединяет их события
|
||||
со старыми системами (GameProgress, Казармы, панели UI)
|
||||
┌─────────────────────────────────────────┐
|
||||
│ ОБЩЕЕ ИГРОВОЕ ЯДРО (Core) │
|
||||
│ контракты · события · реестр · время игры │
|
||||
└─────────────────────────────────────────┘
|
||||
все модули видят только ядро, друг друга — нет
|
||||
|
||||
┌──────────────────────┐ ┌──────────────────────┐
|
||||
│ ЭКОНОМИКА │ │ ПОСЕЛЕНИЕ │
|
||||
│ ресурсы, склады, │ │ здания: Ратуша, │
|
||||
│ лимиты, добыча │ │ стройка; │
|
||||
│ рабочими │ │ люди: жители, еда, │
|
||||
│ │ │ голод, прирост, найм │
|
||||
└──────────────────────┘ └──────────────────────┘
|
||||
┌──────────────────────┐ ┌──────────────────────┐
|
||||
│ АРМИЯ │ │ ГЛОБАЛЬНЫЙ МИР │
|
||||
│ воины по типам: дома,│ │ карта, походы, замок,│
|
||||
│ в гарнизоне, │ │ соседи, лагеря │
|
||||
│ в походе │ │ разбойников │
|
||||
└──────────────────────┘ └──────────────────────┘
|
||||
┌──────────────────────┐ ┌──────────────────────┐
|
||||
│ БОЕВАЯ СИСТЕМА │ │ КРУГ │
|
||||
│ сила, контры, стены, │ │ объединение игроков, │
|
||||
│ удача ±5%, голод, │ │ роли │
|
||||
│ прогноз │ │ │
|
||||
└──────────────────────┘ └──────────────────────┘
|
||||
┌──────────────────────┐ ┌──────────────────────┐
|
||||
│ ЧАТ │ │ СОХРАНЕНИЯ │
|
||||
│ общий мир и чат │ │ save.json, у каждого │
|
||||
│ Круга │ │ модуля своя секция │
|
||||
└──────────────────────┘ └──────────────────────┘
|
||||
|
||||
App/GameModules — точка сборки: регистрирует модули и соединяет их события
|
||||
со старыми системами (GameProgress, Казармы, панели UI)
|
||||
```
|
||||
|
||||
**Не путать:**
|
||||
|
||||
- **Поселение** — это **город**: его **здания** (что построено и какого уровня, `Modules/Settlement`) и его **люди** (сколько их, кто работает, сколько едят, кого нанять в войско, `Modules/Settlement/Population`). Люди — отдельная сборка без Unity внутри Поселения, как правила добычи внутри Экономики. Связь: уровень Ратуши задаёт предел жилья.
|
||||
- **Армия** хранит, где стоит каждый воин. **Боевая система** только считает бой: кто победил и кто погиб.
|
||||
- **Глобальный мир** решает, куда и когда идёт войско; бой он просит у Боевой системы.
|
||||
- **Производство** (`Bogatyri.Economy.Rules`) — не отдельный модуль, а часть Экономики без Unity: добыча через рабочих.
|
||||
|
||||
**Кто отвечает** (договорённость команды от 27.10.2026):
|
||||
|
||||
| Кто | Модули |
|
||||
| --- | --- |
|
||||
| Валдемар (экономика) | Экономика, люди Поселения (`Settlement/Population`) |
|
||||
| Саша (война и карта) | Армия, Боевая система, Глобальный мир, Круг, Чат |
|
||||
| Общее | Ядро, здания Поселения, Сохранения |
|
||||
|
||||
| Модуль | Сборка | Папка | Документ |
|
||||
| --- | --- | --- | --- |
|
||||
| Игровое ядро | `Bogatyri.Core` (без Unity), `Bogatyri.Core.Unity` | `Assets/Scripts/Modules/Core`, `Core.Unity` | [Core.md](Core.md) |
|
||||
@@ -46,14 +85,14 @@
|
||||
|
||||
EditMode-тесты: `Assets/Scripts/Modules/Tests/ModuleTests.cs`. Запуск: **Window → General → Test Runner → EditMode → Run All**.
|
||||
|
||||
Уже есть: Армия (поход не создаёт и не теряет солдат, потери по типам, сохранение, перенос старых данных, сброс), Круг (основание, вступление, выход, полный Круг, сохранение), канал «Круг» в чате только для участников, чат (пустое сообщение, обрезка длинного, событие, предел истории), деление войск без двойного учёта и без потерь, бой (больше солдат — победа, ничья — защитнику), поход с офлайн-прогрессом, шина событий (ошибка подписчика не ломает остальных), реестр модулей.
|
||||
Уже есть: голод в бою (−50%, с усталостью 40%, у нападающих и защитников, в момент боя), боевой цикл (случайность воспроизводима и в пределах ±5%, прогноз не противоречит бою, итог сходится по типам у обеих сторон, правила из таблицы, тот же поход — тот же бой), безопасная отправка и возвращение (неизвестный поход, повторное возвращение, повторный номер, откат похода), крайние случаи боя (1×1, 1×10, 0×0, предельные бонусы), гарнизон города (свободные и гарнизон, в поход только свободные, потери, сохранение), лагеря разбойников (расстановка, бой в поле, разбит и появляется снова, второе войско находит лагерь пустым, сохранение), бой с типами войск (контры, стены, осадные, потери в пределах состава), состав гарнизонов, Армия (поход не создаёт и не теряет солдат, потери по типам, сохранение, перенос старых данных, сброс), Круг (основание, вступление, выход, полный Круг, сохранение), канал «Круг» в чате только для участников, чат (пустое сообщение, обрезка длинного, событие, предел истории), деление войск без двойного учёта и без потерь, бой (больше солдат — победа, ничья — защитнику), поход с офлайн-прогрессом, шина событий (ошибка подписчика не ломает остальных), реестр модулей.
|
||||
|
||||
Добавить вместе с этапами 1, 2 и 5 (решение команды от 19.10.2026):
|
||||
|
||||
- [x] лимит жилья: 300 жителей при лимите 300 — прирост стоит, предел вырос — прирост идёт (`PopulationTests`; пока предел растёт от Ратуши, Дома ещё нет);
|
||||
- [x] нельзя призвать ниже гражданского резерва: 150 свободных, резерв 30 → призвать можно не больше 120 (`PopulationTests`);
|
||||
- [ ] назначение гарнизона: 30 солдат, 10 в гарнизон → 20 доступны, всего по-прежнему 30 (основа — тест «один солдат в одном месте» для походов уже есть);
|
||||
- [ ] голод и восстановление: еда кончилась → дебаффы, в том числе у защитников; еда вернулась → снятие по правилу (голод в бою — у Саши; история голода — `PopulationTests`);
|
||||
- [x] назначение гарнизона: 30 солдат, 10 в гарнизон → 20 доступны, всего по-прежнему 30 (`ArmyService_Garrison_OneSoldierInOnePlace`);
|
||||
- [ ] голод и восстановление: еда кончилась → дебаффы, в том числе у защитников; еда вернулась → снятие по правилу. Бой уже проверен (`Battle_Famine_HalvesPower_AndStacksWithFatigue`, `World_FamineAtBattleTime_WeakensMarch`: −50% у нападающих и у защитников, вместе с усталостью 40%), история голода на момент боя — `PopulationTests`; остаются дебаффы производства и правило снятия — экономика;
|
||||
- [ ] предел синих кристаллов: кристаллы не копятся бесконечно, сверх лимита — по общему правилу.
|
||||
|
||||
## Журнал изменений
|
||||
@@ -61,6 +100,14 @@ EditMode-тесты: `Assets/Scripts/Modules/Tests/ModuleTests.cs`. Запуск
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 28.10.2026 | Claude | Население стало частью Поселения, как на схеме Димы: `Settlement/Population`, сборка `Bogatyri.Settlement.Population`. Найм воинов из свободных жителей с гражданским резервом, история голода для боя. Обновлены Settlement, Population, Core. |
|
||||
| 28.10.2026 | Claude | Схема модулей обновлена: десять модулей (добавлено Население), «Не путать» (Поселение и Население, Армия и Боевая система), кто за что отвечает. |
|
||||
| 28.10.2026 | Claude | Голод в бою (−50%) и правило усталости (−20%, вместе 40%). Обновлены Battle, World, Core. |
|
||||
| 28.10.2026 | Claude | Этап 2 плана, начало: таблица баланса боя `BattleConfig`, случайность ±5%, прогноз риска, полный итог боя для обеих сторон. Обновлены Battle, World, Core. |
|
||||
| 28.10.2026 | Claude | Исправления по ревью 27.10.2026 (п. 2.1, 2.2, 2.4): воины не появляются из неизвестных и повторных походов, отправка с откатом, тесты крайних случаев боя. Обновлены Army, World, Battle, Core. |
|
||||
| 27.10.2026 | Claude | Слой приложения: содержимое окон города (`BasePanel`) — в безопасной зоне, левый край больше не уходит под вырез камеры. `SafeArea.fitInsideParent` — для объектов не на весь экран. |
|
||||
| 27.10.2026 | Claude | Гарнизон города в модуле Армии. Обновлены Army, Core, World. |
|
||||
| 27.10.2026 | Claude | Лагеря разбойников (PvE) на карте мира. Обновлены World, Battle, Save, Core. |
|
||||
| 27.10.2026 | Claude | Боевая система с типами войск (контры, стены, осадные, потери по типам), состав гарнизонов на карте, ожидаемый исход в окне атаки. Обновлены Battle, World, Army, Core. |
|
||||
| 27.10.2026 | Claude | Свободная стройка на сетке: призрак здания, красные занятые клетки, разный размер зданий. Обновлён Settlement. |
|
||||
| 27.10.2026 | Claude | Этапы 1 и 3: склады и лимиты, добыча через рабочих, окно здания и рабочих, улучшение зданий, Склад и Амбар. Тесты `ProductionTests`. Обновлены Economy, Population, Core, Save. |
|
||||
| 26.10.2026 | Claude | Модуль Населения ([Population.md](Population.md)), таблица баланса `EconomyConfig` (`Assets/Resources/EconomyConfig.asset`), часы игры `GameClock`, отладочная панель «DEV». Обновлены Core, Economy, Save. |
|
||||
|
||||
@@ -34,7 +34,7 @@ SaveRegistry.Register(myModule); // при запуске модуля
|
||||
| --- | --- |
|
||||
| `economy` | Экономика |
|
||||
| `settlement` | Поселение |
|
||||
| `world` | Глобальный мир |
|
||||
| `world` | Глобальный мир (походы и разбитые лагеря) |
|
||||
| `circle` | Круг (простые строки, не JSON — модуль без Unity) |
|
||||
| `army` | Армия (простые строки: `troops=…`, `march=…`) |
|
||||
| `population` | Население (простые строки: `civilians=…`, `jobs=…`, `lastTick=…` и др.) |
|
||||
@@ -71,7 +71,7 @@ SaveRegistry.Register(myModule); // при запуске модуля
|
||||
- **Экономика** — стартовые ресурсы из Inspector `ResourceManager` (лимиты склада пересчитает `App/CitySync` по зданиям);
|
||||
- **Добыча** — мест нет (построек нет);
|
||||
- **Поселение** — Ратуша 1 уровня, постройки убраны, участки свободны;
|
||||
- **Мир** — все походы отменены;
|
||||
- **Мир** — все походы отменены, все лагеря разбойников на месте;
|
||||
- **Круг** — игрок ни в каком Круге, его Круги распущены;
|
||||
- **Армия** — войск и походов нет;
|
||||
- **Население** — стартовый город (270 жителей). После сброса `App/GameModules` выдаёт стартовое войско и ресурсы из `EconomyConfig`.
|
||||
@@ -106,6 +106,7 @@ SaveRegistry.Register(myModule); // при запуске модуля
|
||||
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 27.10.2026 | Claude | Секция `world`: добавлен список разбитых лагерей `camps`. |
|
||||
| 27.10.2026 | Claude | Новая секция `production`; в секции `economy` — список `capacities` (лимиты склада). |
|
||||
| 26.10.2026 | Claude | Новая секция `population` (модуль Населения). `GameBootstrap` публикует `NewGameStartedEvent`, если файла нет. |
|
||||
| 23.10.2026 | Claude | Новая секция `army` (модуль Армии). `GameLoadedEvent` публикуется и без файла сохранения. |
|
||||
|
||||
+41
-5
@@ -1,6 +1,6 @@
|
||||
# Глобальный мир
|
||||
|
||||
Карта и перемещения: замок с боссом, 20 соседних городов, походы по реальному времени (идут, даже когда игра закрыта).
|
||||
Карта и перемещения: замок с боссом, 20 соседних городов, 12 лагерей разбойников, походы по реальному времени (идут, даже когда игра закрыта).
|
||||
|
||||
- **Сборки:**
|
||||
- `Bogatyri.World.Simulation` — карта и походы, чистый C# без Unity (переедет на сервер);
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
- `MarchStartedEvent` — войско выступило;
|
||||
- `MarchBattleResolvedEvent` — бой у цели прошёл;
|
||||
- `MarchReturnedEvent` — войско вернулось, солдаты и добыча зачислены. Поля: `MarchId`, `Victory`, `Survivors`, `Sent`, `TargetName`, `LootText`.
|
||||
- `MarchReturnedEvent` — войско вернулось, солдаты и добыча зачислены. Поля: `MarchId`, `Victory`, `Survivors`, `Sent`, `TargetEmpty` (лагерь уже был разбит, боя не было), `TargetName`, `LootText`.
|
||||
|
||||
**Слушает:** ничего.
|
||||
|
||||
@@ -36,9 +36,9 @@
|
||||
|
||||
## Сохранение
|
||||
|
||||
Секция `"world"`: `{ "marches": [ MarchData ] }`.
|
||||
Секция `"world"`: `{ "marches": [ MarchData ], "camps": [ { "id", "respawnMs" } ] }` — походы и разбитые лагеря с моментом их появления. Старые сохранения без `camps` читаются: все лагеря на месте.
|
||||
|
||||
Сброс (`ResetState`): все походы отменяются. Войска в походе не возвращаются: их сбрасывает `GameProgress` вместе с армией.
|
||||
Сброс (`ResetState`): все походы отменяются, все лагеря на месте. Войска в походе не возвращаются: их сбрасывает `GameProgress` вместе с армией.
|
||||
|
||||
Раньше походы лежали в `progress.json` (`sashaMarches`). При первом запуске `App/GameModules` переносит их в модуль Мира и удаляет из `progress.json` только после записи `save.json`.
|
||||
|
||||
@@ -47,9 +47,38 @@
|
||||
| Файл | Что это |
|
||||
| --- | --- |
|
||||
| `MarchManager.cs` | Ведёт походы, реализует `IWorld` и `ISaveParticipant`. Создаётся сам при запуске игры. |
|
||||
| `Simulation/WorldMapLayout.cs` | Карта: замок, город игрока, 20 соседей из seed. |
|
||||
| `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, гарнизон».
|
||||
|
||||
**Отправка целиком или никак** (ревью 27.10.2026, п. 2.2): `MarchManager.TryStartMarch` создаёт поход, затем просит Армию забрать воинов. Если Армия отказала, поход откатывается (`WorldSimulation.CancelMarch`) и игрок видит ошибку. Если при возвращении Армия не знает поход, ни воины, ни добыча не зачисляются (предупреждение в консоли).
|
||||
|
||||
**Номер боя:** при выступлении поход получает `battleSeed` (из номера похода, времени выступления и цели) и хранит его в сохранении. Тот же поход всегда даёт тот же бой. После боя в походе запоминаются силы сторон и выпавшая случайность (`attackerPower`, `defenderPower`, `attackerLuck`, `defenderLuck`). Окно итога боя на карте показывает «Сила 356 : 160, удача −3,1% / +3,2%» (твоя / врага); текст окна ужимается, чтобы не уходить под кнопку OK. Окно атаки показывает прогноз риска и диапазоны силы и потерь.
|
||||
|
||||
**Голод в бою:** перед боем мир спрашивает состояние войска нападающего (`WorldSimulation.AttackerConditions`). `MarchManager` отвечает по модулю Населения: город голодает — войско бьётся на 50% силы. Мир сам голод не считает. Если бой прошёл, пока игра была закрыта, берётся голод на момент входа (истории голода нет). Окно атаки предупреждает: «Голод: войско слабее, сила 50%. Накормите город до боя», прогноз учитывает голод. Если голод начался или кончился, пока окно атаки открыто, предупреждение и прогноз обновляются сами. Окно итога боя пишет «голод: сила 50%». В походе запоминается `attackerConditions` и `attackerConditionPercent`.
|
||||
|
||||
**Время** походов — по `GameClock`: кнопки «+1 час» / «+10 часов» в отладочной панели проматывают и походы.
|
||||
|
||||
В слое приложения остаются `WorldMap/WorldMapController.cs`, `MarchView.cs`, `MapCameraController.cs`, `SceneNavigator.cs`.
|
||||
|
||||
**В игре одна карта мира** — сцена WorldMap. Открывается кнопкой «БОЙ» и кнопкой «МИР» в городе (`UIPanelManager.Open("World")` ведёт в эту сцену).
|
||||
@@ -59,11 +88,18 @@
|
||||
- **Этап 0, решено 19.10.2026:** осталась одна карта мира — эта. Маленькая карта (панель «МИР», `Meta/World`) удалена. Перед удалением проверены ссылки в коде, сценах и префабах. Перенос сохранений: солдаты из её походов (`marches` в `progress.json`) возвращаются в город при загрузке — отправленные, а если отряд уже шёл назад, то выжившие. Добыча таких походов не переносится.
|
||||
- **Этап 4 (утверждён без изменений):** у позиций на карте — месторождения и их качество.
|
||||
- **Этап 6:** временные ресурсные точки и кристальные разломы; войска на точке недоступны дома.
|
||||
- **Лагеря:** числа (гарнизон, добыча, 30 минут до появления) — предложение, требуют балансировки. Позже их можно перенести в `EconomyConfig`. В мультиплеере разбитый лагерь — общий для всех игроков, его состояние будет вести сервер.
|
||||
|
||||
## Журнал изменений
|
||||
|
||||
| Дата | Кто | Что |
|
||||
| --- | --- | --- |
|
||||
| 28.10.2026 | Claude | Голод в момент боя ослабляет войско игрока (−50%): `WorldSimulation.AttackerConditions`, `MarchManager.PlayerConditions`; предупреждение в окне атаки, строка в итоге боя. Тест: голод в момент боя — поражение. |
|
||||
| 28.10.2026 | Claude | Номер боя у похода (`battleSeed`), силы и удача сторон в итоге; прогноз риска в окне атаки, удача в окне итога боя. Тест: тот же поход — тот же бой. |
|
||||
| 28.10.2026 | Claude | По ревью 27.10.2026: отправка с проверкой и откатом (`CancelMarch`), возвращение по неизвестному походу ничего не зачисляет. Тест отмены похода. |
|
||||
| 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()`: при сбросе сохранений походы отменяются. |
|
||||
|
||||
Reference in New Issue
Block a user