Решения 04.11: снос убран (только перенос), кристаллы грабятся с технологией Грабёж, офлайн по временным меткам, защита от повторного начисления, тесты

This commit is contained in:
2026-11-04 23:36:14 +03:00
parent d30fd34810
commit 8b6a7869a4
18 changed files with 220 additions and 73 deletions
+3 -2
View File
@@ -20,7 +20,7 @@
- **История голода:** модуль помнит отрезки голода за последние `MaxOfflineHours` (48 ч) с точностью до шага расчёта (10 минут). Нужна Бою: поход мог дойти до цели, пока игра была закрыта, и голод берётся на момент боя (`WasStarvingAt`), а не на момент входа в игру.
- **Предел жилья:** `HousingBase + HousingPerTownHallLevel × (уровень Ратуши − 1) + HousingPerHouseLevel × уровни Домов` = 300 + 50 + 50. По решению команды от 19.10 стартовый город (300) упирается в предел: прирост пойдёт после постройки Дома. Прибавки не утверждены.
- **Добыча** идёт внутри расчёта населения: в каждом куске сначала `IProduction.Produce`, потом еда, потом прирост. Иначе офлайн город «голодал» бы, хотя фермы работали.
- **Время** — только из `GameClock`. Расчёт идёт кусками по 10 минут, и в игре, и офлайн, и при перемотке — правила одни. Офлайн досчитывается не больше чем за `MaxOfflineHours`. Если часы ушли назад, расчёт просто продолжается с «сейчас».
- **Время** — только из `GameClock`. Расчёт идёт кусками по 10 минут, и в игре, и офлайн, и при перемотке — правила одни. Офлайн досчитывается не больше чем за `MaxOfflineHours`. Если часы ушли назад, ничего не считается, а метка последнего расчёта назад **не** уходит: когда часы снова дойдут до уже посчитанного, второй раз оно не начислится (решения 04.11). В начале каждого шага и в конце `Tick` модуль публикует `GameTimeSimulatedEvent` — до какого момента дошёл расчёт; по нему стройка, закончившаяся офлайн, вступает в силу ровно в свой момент (`App/ConstructionClock`).
- **Еда списывается целыми единицами,** доли копятся в модуле: склад хранит `float`, и частые мелкие списания давали бы ошибку округления.
## Контракт `IPopulation`
@@ -88,7 +88,7 @@
- упёрлись в предел — прирост стоит, Ратуша выше — идёт; предел не превышается;
- офлайн ограничен 48 часами;
- частые расчёты дают то же, что один большой;
- часы назад — ничего не ломается;
- часы назад — ничего не ломается, уже посчитанное время не начисляется второй раз;
- перемотка идёт через те же правила;
- сохранение;
- стартовый набор — один раз;
@@ -112,6 +112,7 @@
| Дата | Кто | Что |
| --- | --- | --- |
| 04.11.2026 | Claude (Валдемар) | Решения 04.11 (офлайн по временным меткам): событие `GameTimeSimulatedEvent` на каждом шаге расчёта и в конце `Tick` — стройка, закончившаяся офлайн, вступает в силу в свой момент, добыча с момента завершения. Часы назад: метка последнего расчёта не уходит назад — закрыто повторное начисление. Тесты в `ProductionTests` (офлайн-стройка, повторный Tick, загрузка), обновлён тест про часы назад. Побочный эффект: после «DEV +10 часов» и перезапуска расчёт стоит, пока реальное время не догонит перемотку. |
| 01.11.2026 | Claude (Саша) | Раненые считаются людьми: `Soldiers` = в городе + в походах + `IArmy.WoundedTotal` (решения 31.10, п. 7). Погибшие уходят из людей, вылеченные не появляются заново. Еда раненых — как у воинов (нормы четырёх групп — открытый вопрос). |
| 01.11.2026 | Claude (Саша) | Очередь обучения перенесена в Армию (решения 31.10, п. 8). Население по-прежнему отдаёт жителей (`TryRecruit`) и принимает новобранцев в воины (`CompleteTraining`) — его код не менялся, зовёт их теперь Армия. `RecruitsTrained` больше никто не вызывает. |
| 31.10.2026 | Claude | `CompleteTraining`: новобранцы переходят в Армию одним действием с откатом, если Армия не приняла. Заказ обучения помечает, брали ли под него людей (`TrainingOrder.recruited`); старые заказы — по-старому. Интеграционные тесты с настоящей Армией: переход без потерь, отказ Армии, повтор, нет Армии, часть заказа. |