- CrystalRewards (без Unity) + 6 тестов из раздела 6 регламента - Задания: сколько помещается, остаток ждёт в задании («Забрать»); третья не помещающаяся награда не выдаётся - Остальные награды: не поместившееся -- письмом «Кристаллы ждут места», из письма -- сколько помещается - Награды заданий 1-2 вместо 20-250, ежедневные -- без кристаллов Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
132 lines
18 KiB
Markdown
132 lines
18 KiB
Markdown
# Экономика
|
||
|
||
Ресурсы и производство: сколько у игрока дерева, еды, золота и остального, кто их добывает и тратит.
|
||
|
||
- **Сборки:**
|
||
- `Bogatyri.Economy` — склад ресурсов и здания-рабочие места (Unity);
|
||
- `Bogatyri.Economy.Rules` — правила добычи, чистый C# без Unity (папка `Rules`).
|
||
- **Папка:** `Assets/Scripts/Modules/Economy`.
|
||
- **Зависит от:** ядра.
|
||
|
||
## Контракт `IEconomy`
|
||
|
||
| Метод | Что делает |
|
||
| --- | --- |
|
||
| `Get(type)` | Сколько ресурса сейчас. |
|
||
| `Has(type, amount)` | Хватает ли. |
|
||
| `Add(type, amount)` | Добавить (или отнять отрицательным числом; в минус не уходит). |
|
||
| `TrySpend(type, amount)` | Потратить, если хватает. |
|
||
| `CanAfford(cost)` / `TrySpend(cost)` | Проверить и списать цену из нескольких ресурсов — всё или ничего. |
|
||
| `GetCapacity(type)` | Лимит склада; `float.PositiveInfinity` — без лимита (люди, сила). |
|
||
|
||
Получить: `GameServices.Get<IEconomy>()`.
|
||
|
||
## Контракт `IProduction` (добыча через рабочих, этап 3)
|
||
|
||
| Метод | Что делает |
|
||
| --- | --- |
|
||
| `Slots(job)` | Мест для рабочих этой профессии во всех зданиях города. |
|
||
| `Efficiency(job)` | Множитель нормы от уровня зданий (1 — здания 1 уровня). |
|
||
| `RatePerHour(type)` | Добыча ресурса в час сейчас. |
|
||
| `Produce(hours)` | Добыть за `hours` часов. Вызывает модуль Населения в своём расчёте: сначала добыли, потом съели. |
|
||
|
||
Получить: `GameServices.Get<IProduction>()`.
|
||
|
||
## Ресурсы и склады (этап 1)
|
||
|
||
- **Ресурсы:** дерево, еда, золото, камень, металл, синий кристалл. `Power` («Сила») — не ресурс, а вычисляемая мощь для рейтинга (`GameProgress.TotalPower`), лимита у неё нет. «Люди» — отражение модуля Населения.
|
||
- **Лимиты:** без построек — 1000 дерева, камня, металла и золота, 1500 еды. Каждый уровень **Склада** — +1000 к первым четырём, каждый уровень **Амбара** — +1500 к еде. Синий кристалл — отдельный небольшой лимит 50 (решение команды от 19.10). Все числа — `EconomyConfig`, раздел «Склады и лимиты», не утверждены.
|
||
- **Сверх лимита ресурс не прибавляется** — ни добыча, ни награды, лишнее пропадает. Если запас уже выше лимита (старое сохранение), он не урезается, просто больше не растёт.
|
||
- **Склад и Амбар** появляются в списке стройки кодом (`App/StorageBootstrap`, как Казармы), пока без своего арта — отличаются цветом. Компонент `App/StorageBuilding`.
|
||
- **Верхняя панель** (`ResourceUIText`): «запас / лимит» и строкой ниже прирост в час (у еды — добыча минус расход). Без сокращений 1.2K. У «Людей» — население / предел жилья и прирост людей.
|
||
|
||
## Добыча через рабочих (этап 3)
|
||
|
||
- **Ресурс производят люди, здание даёт места и эффективность.** Добыча в час = min(рабочие, места) × норма × эффективность.
|
||
- **Голод** (регламент 31.10, ТЕСТ): пока город голодает (`IPopulation.IsStarving`), добыча всего, кроме еды, ×0.5 (`EconomyConfig`, `famineNonFoodMultiplier`). Еда добывается без штрафа, штраф снимается сразу, как только город снова сыт.
|
||
- **Нормы T1 в час:** лесоруб — 2 дерева, фермер — 2 еды, каменотёс — 1.5 камня, шахтёр — 1 металла (Шахта) или 0.4 золота (Золотой рудник).
|
||
- **Здание 1 уровня — 30 мест.** Каждый следующий уровень: +10 мест и +10% к норме. Не утверждено.
|
||
- **Кликер убран.** `ResourceCollector` теперь здание-рабочее место (имя класса оставлено, чтобы не перенастраивать префабы). Тап по зданию — окно здания и рабочих (`App/BuildingWindow`): `−` / `+` на каждую профессию, «Свободно: N из M», кнопка «Улучшить». `ResourceProducer` (добыча по таймеру) выключен.
|
||
- **Дом** (здание «Население», `resourceType = Population`) — не рабочее место: каждый уровень +50 к пределу жилья.
|
||
- **Кристалл** — рабочих нет, синий кристалл добывается в разломах на карте мира (этап 6).
|
||
- **Какие здания стоят,** модулю сообщает `App/CitySync`: раз в полсекунды смотрит город и передаёт места, Дома и уровни Складов. Модуль запоминает места в сохранении, поэтому добыча идёт и на карте мира, и офлайн.
|
||
- **Новые места сами не заполняются** (регламент 31.10): построили или улучшили здание — места пустые, пока игрок не поставит рабочих в окне здания. Автоматически — только стартовая расстановка один раз (новая игра или первая загрузка старого сохранения): до 120 рабочих поровну по местам.
|
||
- **Голод в офлайне** считается по тем же шагам, что и в игре: Население досчитывает время кусками по 10 минут, и в каждом куске добыча берёт голод на этот момент.
|
||
- **Проверка из документа** (тест `BalancedCity_…`): 45 фермеров, 25 лесорубов, 15 каменотёсов, 15 шахтёров → 90 еды, 50 дерева, 22.5 камня, 15 металла в час.
|
||
|
||
## События
|
||
|
||
- **Публикует:** `ResourceChangedEvent` — при любом изменении ресурса (тип и новое значение).
|
||
- **Слушает:** ничего.
|
||
|
||
Для интерфейса остаётся C#-событие `ResourceManager.OnResourceChanged` (его слушает `ResourceUIText`).
|
||
|
||
## Сохранение
|
||
|
||
Секция `"economy"`: `{ "resources": [ { "type", "amount" } ], "capacities": [ … ] }` — имена полей как в старом `save.json`, лимиты склада — новым списком.
|
||
|
||
Секция `"production"` (`ProductionService`, простые строки): `slots=` — места по профессиям, `eff=` — эффективность, `pending=` — доли добычи меньше 1.
|
||
|
||
Сброс (`ResetState`): стартовые значения из Inspector `ResourceManager` (`startWood` и т.д.).
|
||
|
||
## Файлы
|
||
|
||
| Файл | Что это |
|
||
| --- | --- |
|
||
| `ResourceManager.cs` | Хранилище ресурсов и лимитов склада, реализует `IEconomy` и `ISaveParticipant`. Живёт между сценами. |
|
||
| `ResourceCollector.cs` | Здание-рабочее место (или Дом, Кристалл). Реализует `ILeveledBuilding`. Тап — событие `Tapped`. |
|
||
| `ResourceProducer.cs` | Устарело: выключен, оставлен для старых префабов. |
|
||
| `Rules/ProductionService.cs` | Добыча через рабочих: `ProductionRules`, `IProduction`, секция `"production"`. |
|
||
|
||
Слой приложения:
|
||
|
||
| Файл | Что это |
|
||
| --- | --- |
|
||
| `Economy/ResourceUIText.cs` | Ресурс на верхней панели: «запас / лимит» и прирост в час. |
|
||
| `Economy/BuildingUI.cs` | Полоска над зданием: рабочие / места. |
|
||
| `App/CitySync.cs` | Здания города → места, Дома, лимиты. |
|
||
| `App/BuildingWindow.cs` | Окно здания и рабочих. |
|
||
| `App/StorageBuilding.cs`, `App/StorageBootstrap.cs` | Склад и Амбар. |
|
||
|
||
## Синие кристаллы при пределе 50 (регламент 05.11.2026, ред. 1.1)
|
||
|
||
Предел — строго 50, не повышается. Правила — `Modules/Economy/Rules/CrystalRewards.cs` (без Unity), тесты — `CrystalRewardsTests`.
|
||
|
||
- **Не сверх предела и без потерь.** Кристаллы, которым нет места, не начисляются и не пропадают.
|
||
- **Задания.** Выдаётся, сколько помещается; остаток ждёт в задании (в окне заданий — «Ждут места: N кристаллов», кнопка «Забрать»), не сгорает. Одновременно ждут не больше **2** наград; пока оба места заняты, задание, кристаллы которого не помещаются целиком, не выдаётся совсем — остаётся «Забрать». Сохраняется в `progress.json`: `crystalWaiting` («m:<задание>|сколько»).
|
||
- **Остальные награды** (вход, события, бои, почта уровня): то, что не поместилось, приходит письмом «Кристаллы ждут места». Из письма забирается, сколько помещается, остаток остаётся в письме.
|
||
- **Числа заданий (разд. 3):** простое — 1 кристалл, сложное — 2 (было 20–250). В ежедневных заданиях кристаллов нет (было 10) — вместо них 200 золота. ТЕСТ.
|
||
- **Ещё не сделано:** Кристальная шахта (3 за 7 реальных суток), недельный PvE-предел 6, точки на карте, торговля, грабёж с пределом получателя.
|
||
- **Вопросы команде:** источники, которых нет в регламенте, — награды за вход (50 и 200), письмо-приветствие (100), подарок за уровень (10 × уровень), события, обмен золота на кристаллы и покупки в магазине. Сейчас они не теряют кристаллы, но дают их много.
|
||
|
||
## Таблица баланса `EconomyConfig`
|
||
|
||
Все числа экономики — в ассете `Assets/Resources/EconomyConfig.asset` (класс `App/EconomyConfig.cs`, слой приложения). Меняются в Inspector без перекомпиляции. Разделы: население, стартовые ресурсы новой игры, производство T1, месторождения, цена солдата. Числа с пометкой «не утверждено» — временные.
|
||
|
||
Модули конфиг не видят: `App/GameModules` переводит его в правила модуля (например, `PopulationRules`). Нет ассета — берутся числа по умолчанию из `EconomyConfig.cs` и в консоли предупреждение.
|
||
|
||
Стартовые ресурсы новой игры выдаёт `App/GameModules` (при первой игре и после сброса): ресурс поднимается до стартового, если его меньше.
|
||
|
||
Ресурс `Population` («Люди») теперь отражает модуль Населения: `App/GameModules` держит его равным `IPopulation.Total`. Тратить его напрямую не нужно.
|
||
|
||
## Решения и план
|
||
|
||
- **Этап 1 (план разработки):** сделано 27.10.2026 — лимиты Склада и Амбара, «запас / лимит» и прирост на панели, без сокращений. `Gems` по-прежнему называется `Gems` (числа enum записаны в сохранениях), в интерфейсе — «Кристаллы».
|
||
- **Решение команды от 19.10.2026:** у синего кристалла отдельный небольшой настраиваемый лимит хранения, не бесконечный. Переполнение — одно правило для наград и добычи. Число не утверждено.
|
||
- **Этап 3:** сделано 27.10.2026 — кликер убран, производство = рабочие × норма × эффективность уровня. Множитель качества месторождения добавится в этапе 4.
|
||
- Все числа — из `EconomyConfig`, не в коде. Таблица создана 26.10.2026; производство, месторождения и цена солдата в ней уже есть, но используются начиная с этапов 3–5.
|
||
|
||
## Журнал изменений
|
||
|
||
| Дата | Кто | Что |
|
||
| --- | --- | --- |
|
||
| 05.11.2026 | Claude (Саша) | Регламент синих кристаллов, пп. 1 и 3: кристаллы не начисляются сверх 50 и не теряются — награды заданий ждут (не больше 2), остальные — письмом «Кристаллы ждут места», из письма забирается сколько помещается (`CrystalRewards`, `GameProgress.Grant/ClaimQuest/ClaimMail`, 6 тестов). Задания — 1–2 кристалла вместо 20–250, ежедневные — без кристаллов. |
|
||
| 04.11.2026 | Claude | Решения 04.11: кристаллы грабятся только нападающим с технологией «Грабёж» (`IResourceProtection.Lootable(type, attackerHasPlunder)`; с ней — не больше `plunderGemsShare` запаса, ТЕСТ 10%, точные ограничения — позже). Защита остальных ресурсов без изменений. Из `EconomyConfig` убран возврат при сносе. Офлайн: добыча здания, достроенного в офлайне, — с момента завершения; уже посчитанное время второй раз не начисляется (тесты в `ProductionTests`). |
|
||
| 01.11.2026 | Claude | `EconomyConfig`: разделы «Стройка» (время, строители, ускорение, возврат при сносе), «Лимит зданий по уровню Ратуши», «Защита ресурсов от грабежа» — всё ТЕСТ. Защита: без Складов 100 каждого ресурса, +200 за уровень Склада; еда 100, +300 за уровень Амбара; кристаллы не грабятся. Контракт `IResourceProtection` (`App/ResourceProtection`), в окне Склада и Амбара — «спрятано / можно унести». |
|
||
| 31.10.2026 | Claude | Новые места после стройки и улучшения больше не заполняются сами (`App/CitySync`), только стартовая расстановка один раз. |
|
||
| 31.10.2026 | Claude | Голод: добыча всего, кроме еды, ×0.5 (`ProductionRules.FamineNonFoodMultiplier`, ТЕСТ). Тест `Famine_HalvesNonFoodProduction_…`. |
|
||
| 27.10.2026 | Claude | Этапы 1 и 3: лимиты склада (`GetCapacity`, Склад, Амбар), «запас / лимит» и прирост на панели; добыча через рабочих (`Bogatyri.Economy.Rules`, `IProduction`), кликер убран, окно здания и рабочих, улучшение зданий. Исправлены лишние `ResourceUIText` «Люди» на ячейках панели. |
|
||
| 26.10.2026 | Claude | Таблица баланса `EconomyConfig`. Стартовые ресурсы новой игры. Ресурс «Люди» отражает модуль Населения. |
|
||
| 19.10.2026 | Claude | `ResetState()`: при сбросе сохранений ресурсы возвращаются к стартовым. |
|
||
| 19.10.2026 | Claude | Модуль выделен: `ResourceManager`, `ResourceProducer`, `ResourceCollector` перенесены в `Modules/Economy`. `ResourceManager` реализует `IEconomy`, публикует `ResourceChangedEvent`, сам сохраняет секцию `"economy"`. |
|