Files
MVP1/Docs/Modules/Population.md
T

98 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Население
Сколько в городе людей, сколько они едят и как прирастают. Этап 2 плана разработки.
- **Сборка:** `Bogatyri.Population` (без Unity).
- **Папка:** `Assets/Scripts/Modules/Population`.
- **Зависит от:** ядра. Еду берёт через `IEconomy`, воинов считает через `IArmy`, уровень Ратуши — через `ISettlement`.
## Как устроено
- **Люди города = жители + воины.** Жителей хранит этот модуль, воинов — Армия. Так один человек не записан в двух местах.
- **Жители:** способные работать (`Workforce` — 120 из 270 в стартовом городе, доля сохраняется при росте) и остальные. Способные работать стоят на профессиях (`WorkJob`: лесорубы, фермеры, каменотёсы, шахтёры металла и золота) или свободны (`FreeWorkers`).
- **Рабочих ставят** окно здания (`SetWorkers`) и `App/CitySync` (новые места заполняются свободными сами). Больше, чем мест в зданиях (`IProduction.Slots`) и свободных, не поставить.
- **Еда в час:** 0.1 на жителя, 0.2 на воина. Стартовый город (270 жителей + 30 воинов) ест 33 еды в час.
- **Прирост:** +2.5 человека в час, только если еды хватило и население ниже предела жилья.
- **Голод:** еды не хватило — остатки доедаются, прирост останавливается, `IsStarving = true`. Что ещё происходит при голоде, команда пока не решила.
- **Предел жилья:** `HousingBase + HousingPerTownHallLevel × (уровень Ратуши − 1) + HousingPerHouseLevel × уровни Домов` = 300 + 50 + 50. По решению команды от 19.10 стартовый город (300) упирается в предел: прирост пойдёт после постройки Дома. Прибавки не утверждены.
- **Добыча** идёт внутри расчёта населения: в каждом куске сначала `IProduction.Produce`, потом еда, потом прирост. Иначе офлайн город «голодал» бы, хотя фермы работали.
- **Время** — только из `GameClock`. Расчёт идёт кусками по 10 минут, и в игре, и офлайн, и при перемотке — правила одни. Офлайн досчитывается не больше чем за `MaxOfflineHours`. Если часы ушли назад, расчёт просто продолжается с «сейчас».
- **Еда списывается целыми единицами,** доли копятся в модуле: склад хранит `float`, и частые мелкие списания давали бы ошибку округления.
## Контракт `IPopulation`
| Член | Что это |
| --- | --- |
| `Total` | Все люди: жители + воины (в городе и в походах). |
| `Civilians`, `Workers`, `Idle` | Жители, из них на работе и остальные. |
| `Workforce`, `FreeWorkers` | Сколько могут работать; сколько из них без работы. |
| `GetWorkers(job)`, `SetWorkers(job, n)` | Рабочие профессии; поставить n (в пределах мест и свободных). |
| `Soldiers` | Воины — из модуля Армии. |
| `HousingCap` | Предел населения. |
| `FoodPerHour`, `GrowthPerHour` | Расход еды и прирост в час сейчас. |
| `IsStarving` | Еды не хватило на последний расчёт. |
| `Tick(unixNow)` | Досчитать население до момента `unixNow`. |
Получить: `GameServices.Get<IPopulation>()`.
## События
- **Публикует:**
- `PopulationChangedEvent` — изменилось число людей;
- `WorkersChangedEvent` — переставили рабочих;
- `StarvationChangedEvent` — голод начался или закончился.
- **Слушает** (через `App/GameModules`):
- `GameLoadedEvent` — офлайн-прогресс;
- `GameTimeAdvancedEvent` — перемотка в отладочной панели;
- `TroopsChangedEvent`, `TownHallLevelChangedEvent` — пересчёт общего числа и предела.
## Сохранение
Секция `"population"`, простые строки: `civilians=`, `jobs=` (рабочие по профессиям), `jobsInit=`, `houses=`, `growth=`, `food=`, `lastTick=`, `starving=`, `kit=`.
Сброс (`ResetState`): стартовый город, 270 жителей. Стартовое войско (30 пехоты) и стартовые ресурсы выдаёт `App/GameModules` после сброса и при первой игре (`NewGameStartedEvent`) — один раз (`kit=1`). Старым сохранениям без секции населения стартовый набор не выдаётся.
## Связь с игрой (слой приложения)
| Файл | Что делает |
| --- | --- |
| `App/GameModules.cs` | Создаёт модуль с числами из `EconomyConfig`, подписывает на события, выдаёт стартовый набор, держит ресурс «Люди» на верхней панели равным `Total`. |
| `App/PopulationTicker.cs` | Раз в 2 секунды вызывает `Tick` (модуль без Unity и не знает про `Update`). |
| `App/DebugPanel.cs` | Кнопка «DEV»: «+1 час», «+10 часов», ресурсы, «Еда = 0». Только редактор и Development Build. |
## Файлы
| Файл | Что это |
| --- | --- |
| `PopulationRules.cs` | Числа правил (заполняются из `EconomyConfig`). |
| `PopulationService.cs` | Модуль: расчёт, контракт `IPopulation`, сохранение. |
## Тесты
`Modules/Tests/PopulationTests.cs`:
- стартовый город — 300 человек, ест 33 еды в час;
- прирост 2.5 в час;
- голод останавливает прирост, еда вернулась — прирост идёт;
- упёрлись в предел — прирост стоит, Ратуша выше — идёт; предел не превышается;
- офлайн ограничен 48 часами;
- частые расчёты дают то же, что один большой;
- часы назад — ничего не ломается;
- перемотка идёт через те же правила;
- сохранение;
- стартовый набор — один раз;
- сброс.
## Решения и план
- **Голод:** дебаффы (в том числе у защитников) и правило снятия — решение команды от 19.10.2026, числа не утверждены. Модуль уже сообщает `StarvationChangedEvent`.
- **Предел жилья:** по решению команды растёт с постройкой Дома — сделано (здание «Население»).
- **Этап 3:** сделано 27.10.2026 — рабочие по профессиям, Дома, добыча в общем расчёте.
- **Этап 5:** найм воина забирает человека из жителей (гражданский резерв — решение от 19.10.2026).
## Журнал изменений
| Дата | Кто | Что |
| --- | --- | --- |
| 27.10.2026 | Claude | Рабочие по профессиям (`Workforce`, `FreeWorkers`, `GetWorkers`, `SetWorkers`, автозаполнение), Дома в пределе жилья, базовый предел 300 (решение 19.10), добыча в общем расчёте. |
| 26.10.2026 | Claude | Создан модуль: жители, еда, прирост, голод, предел жилья, офлайн-прогресс, секция `population`, тесты. |