Files
MVP1/Docs/Modules/Population.md
T

14 KiB
Raw Blame History

Поселение: население

Люди города: сколько их, кто работает, сколько едят, как прирастают и кого можно нанять в войско. Это часть модуля Поселения: Поселение — это город, его здания и люди. Этап 2 плана разработки.

  • Ответственный: Вальдемар.
  • Сборка: Bogatyri.Settlement.Population (без Unity). Отдельная сборка внутри Поселения — как правила добычи внутри Экономики: правила людей без Unity переедут на сервер.
  • Папка: Assets/Scripts/Modules/Settlement/Population.
  • Зависит от: ядра. Еду берёт через IEconomy, воинов считает через IArmy, уровень Ратуши — через ISettlement.

Как устроено

  • Люди города = жители + новобранцы в Казармах + воины. Жителей и новобранцев хранит этот модуль, воинов — Армия. Так один человек не записан в двух местах.
  • Жители: способные работать (Workforce — 40% всех людей города, в стартовом городе 120 из 300) и остальные. Способные работать стоят на профессиях (WorkJob: лесорубы, фермеры, каменотёсы, шахтёры металла и золота) или свободны (FreeWorkers).
  • Найм воинов (решение команды от 19.10.2026). Воины набираются из свободных жителей (не на работе), гражданский резерв не отдаётся: 150 свободных, резерв 30 — нанять можно не больше 120 (Recruitable). Воин стоит PeoplePerSoldier жителей (1). Человек уходит из жителей в начале обучения (TryRecruit), учится в Казармах (InTraining, ест как воин) и после обучения переходит в Армию (RecruitsTrained). Погибшие в бою воины уменьшают население — их больше нет в Армии. Резерв задаёт уровень поселения: CivilianReserve + прибавка за уровень Ратуши (прибавка не утверждена, сейчас 0).
  • Рабочих ставят окно здания (SetWorkers) и App/CitySync (новые места заполняются свободными сами). Больше, чем мест в зданиях (IProduction.Slots) и свободных, не поставить.
  • Еда в час: 0.1 на жителя, 0.2 на воина. Стартовый город (270 жителей + 30 воинов) ест 33 еды в час.
  • Прирост: +2.5 человека в час, только если еды хватило и население ниже предела жилья.
  • Голод: еды не хватило — остатки доедаются, прирост останавливается, IsStarving = true. Бой ослабляет голодное войско (модуль Боя, −50%).
  • История голода: модуль помнит отрезки голода за последние MaxOfflineHours (48 ч) с точностью до шага расчёта (10 минут). Нужна Бою: поход мог дойти до цели, пока игра была закрыта, и голод берётся на момент боя (WasStarvingAt), а не на момент входа в игру.
  • Предел жилья: 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 Еды не хватило на последний расчёт.
CivilianReserve Гражданский резерв: столько свободных жителей в войско не взять.
Recruitable Сколько воинов можно нанять прямо сейчас: (свободные − резерв) / жителей на воина.
InTraining Людей, взятых из жителей и ещё обучающихся в Казармах.
TryRecruit(n), RecruitsTrained(n) Забрать людей в Казармы в начале обучения; обучение закончено — их считает Армия.
WasStarvingAt(unixTime) Голодал ли город в этот момент (секунды Unix, время GameClock). Позже последнего расчёта -- как сейчас; старше 48 часов -- нет.
Tick(unixNow) Досчитать население до момента unixNow.

Получить: GameServices.Get<IPopulation>().

События

  • Публикует:
    • PopulationChangedEvent — изменилось число людей;
    • WorkersChangedEvent — переставили рабочих;
    • StarvationChangedEvent — голод начался или закончился.
  • Слушает (через App/GameModules):
    • GameLoadedEvent — офлайн-прогресс;
    • GameTimeAdvancedEvent — перемотка в отладочной панели;
    • TroopsChangedEvent, TownHallLevelChangedEvent — пересчёт общего числа и предела.

Сохранение

Секция "population", простые строки: civilians=, jobs= (рабочие по профессиям), jobsInit=, houses=, growth=, food=, lastTick=, starving=, training= (новобранцы в Казармах), famine= (история голода: начало-конец;начало-конец, конец 0 -- голод идёт), kit=.

Сброс (ResetState): стартовый город, 270 жителей. Стартовое войско (30 пехоты) и стартовые ресурсы выдаёт App/GameModules после сброса и при первой игре (NewGameStartedEvent) — один раз (kit=1). Старым сохранениям без секции населения стартовый набор не выдаётся.

Связь с игрой (слой приложения)

Файл Что делает
App/GameModules.cs Создаёт модуль с числами из EconomyConfig, подписывает на события, выдаёт стартовый набор, держит ресурс «Люди» на верхней панели равным Total.
Meta/Core/GameProgress.cs Казармы: перед обучением проверяет Recruitable, забирает людей (TryRecruit), после обучения — RecruitsTrained, потом воины в Армию.
Meta/Panels/TroopsPanel.cs Панель «Войска»: «Обучаются в Казармах», «Можно нанять из жителей (резерв N)»; кнопки найма серые, если жителей не хватает.
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 часами;
  • частые расчёты дают то же, что один большой;
  • часы назад — ничего не ломается;
  • перемотка идёт через те же правила;
  • сохранение;
  • стартовый набор — один раз;
  • сброс;
  • найм: 150 свободных, резерв 30 → не больше 120; людей столько же, новобранцы не считаются дважды; рабочие остаются на работе; новобранцы едят как воины и сохраняются; старый заказ обучения не уводит в минус;
  • история голода: бой офлайн видит голод на свой момент, история сохраняется, сбрасывается и забывается через 48 часов.

Решения и план

  • Голод: дебаффы (в том числе у защитников) и правило снятия — решение команды от 19.10.2026, числа не утверждены. Модуль уже сообщает StarvationChangedEvent.
  • Предел жилья: по решению команды растёт с постройкой Дома — сделано (здание «Население»).
  • Этап 3: сделано 27.10.2026 — рабочие по профессиям, Дома, добыча в общем расчёте.
  • Вопросы Саши от 28.10.2026 (отчёт по военной части):
    • п. 7, история голода -- сделано (WasStarvingAt). Бою нужно перейти с IsStarving на WasStarvingAt(время боя). Походы идут по реальному времени, Население -- по GameClock: после перемотки в DEV-панели они расходятся.
    • п. 8, норма еды на солдата -- сейчас 0.2 еды в час реального времени, игрового календаря нет. Предложение: не вводить; если нужен «игровой месяц» -- 1 месяц = 1 сутки, норма ≈ 5 еды. Решает Дима.
  • Этап 5: найм воина забирает человека из жителей (гражданский резерв — решение от 19.10.2026) — сделано 28.10.2026. Цену воина в ресурсах (EconomyConfig, раздел «Солдат»: 15 еды, 5 металла, 5 золота) Казармы пока не используют — у них своя цена в GameData.Troops.
  • Схема модулей (28.10.2026): население — часть Поселения, как на схеме Димы из 8 модулей.

Журнал изменений

Дата Кто Что
28.10.2026 Claude Население стало частью Поселения: папка Modules/Settlement/Population, сборка Bogatyri.Settlement.Population. Найм воинов из свободных жителей с гражданским резервом (CivilianReserve, Recruitable, InTraining, TryRecruit, RecruitsTrained), строка training=, Workforce — 40% всех людей. Тесты.
28.10.2026 Claude История голода: IPopulation.WasStarvingAt, строка famine= в сохранении, тесты (вопрос Саши п. 7).
27.10.2026 Claude Рабочие по профессиям (Workforce, FreeWorkers, GetWorkers, SetWorkers, автозаполнение), Дома в пределе жилья, базовый предел 300 (решение 19.10), добыча в общем расчёте.
26.10.2026 Claude Создан модуль: жители, еда, прирост, голод, предел жилья, офлайн-прогресс, секция population, тесты.