Files
MVP1/Docs/Modules/Economy.md
T
AlexanderandClaude Opus 5.5 b51ad41925 Редкий PvE-торговец: синий кристалл за 30 000 / 60 000 золота, не больше 2 за 7 суток (регламент валют, разд. 3)
- CrystalTrader (без Unity) + 5 тестов из раздела 12
- Входит в недельный PvE-предел; нет квоты, места или покупок -- блок, золото не списывается
- Магазин: карточка «Редкий торговец»; DEV «Золото 100 000» для проверки

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 16:27:27 +01:00

147 lines
24 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.
# Экономика
Ресурсы и производство: сколько у игрока дерева, еды, золота и остального, кто их добывает и тратит.
- **Сборки:**
- `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` | Склад и Амбар. |
## Синие кристаллы
Действующие документы: «Регламент валют, кристаллов и торговли» от 05.11.2026 и «Ответ Володе» от 06.11.2026 — они приоритетнее «Регламента редкости синих кристаллов» от 05.11 (ред. 1.1). Правила выдачи — `Modules/Economy/Rules/CrystalRewards.cs` (без Unity), тесты — `CrystalRewardsTests`.
**Сделано:**
- **Не сверх вместимости и без потерь.** Задания: сколько помещается, остаток ждёт в задании (не больше 2 ждущих наград). Остальное — письмом «Кристаллы ждут места», из письма забирается сколько помещается. Сохранение — `progress.json`, `crystalWaiting`.
- **Источники (06.11, разд. 5.1 регламента валют).** Синие кристаллы дают только:
- верхняя ступень недельного события — 1 (`GameData.EventTierRewards`);
- каждый 10-й этап боя — 1 (`StageGemsEvery`, `StageGemsAmount`).
Всё ТЕСТ. Без кристаллов теперь: задания (основные и ежедневные), награды за вход (было 50 и 200), письмо-приветствие (было 100), подарок за уровень (было 10 × уровень), арена (было 5), этапы боя (было 25 на каждом 5-м), бесплатный сундук (было 15). Вместо них — золото и ресурсы.
- **Хранилище — платное расширение (разд. 8 регламента валют, ответ 06.11, п. 1).** Старт 50; ступени (ТЕСТ): Ратуша 3 — 75 (2000 золота, 1500 дерева, 1500 камня), Ратуша 5 — 100 (4000 / 3000 / 3000 + 1000 металла), Ратуша 7 — 150 (7000 / 5000 / 5000 / 2000), Ратуша 9 — 200 (10000 / 8000 / 8000 / 4000). Ратуша только разрешает ступень, покупается в окне Ратуши («Хранилище синих кристаллов» → «Расширить до N»). Цена списывается один раз, всё или ничего. Правила — `Modules/Economy/Rules/CrystalStorage.cs`, тесты — `CrystalStorageTests`; числа — `EconomyConfig` → «Склады и лимиты» → `crystalCap`, `crystalExpansions`. Купленная ступень сохраняется в секции `"economy"` (`crystalStorageLevel`; в старом сохранении её нет — 0), вместимость по ней считается заново.
- **Недельный PvE-предел (разд. 5.2, 10, 12 регламента валют; ответ 06.11, п. 2).** Не больше 6 новых синих кристаллов за скользящие 7 реальных суток из заданий, событий и боёв (позже — PvE-торговец). Сверх квоты — 1000 золота за кристалл (компенсация не согласована, ТЕСТ), на следующую неделю не переносится; при частичной квоте — часть кристаллами, остальное золотом. Квота и место в хранилище — разные условия: взятое по квоте, но не поместившееся ждёт места и квоту второй раз не тратит; кристаллы из письма «Кристаллы ждут места» квоту не берут. Задание берёт квоту один раз (по id). Видно в окне Ратуши: «Новых кристаллов из заданий, событий и боёв за 7 дней: N / 6». Правила — `Modules/Economy/Rules/CrystalQuota.cs`, тесты — `CrystalQuotaTests`; числа — `EconomyConfig` → `crystalPveLimit`, `crystalPveWindowDays`, `crystalCompensationGold`; сохранение — `progress.json`, `crystalQuota`. DEV: «+1 PvE-кристалл», «Сбросить квоту».
- **Редкий PvE-торговец (разд. 3 и 10 регламента валют).** Магазин → «Редкий торговец: синий кристалл»: за скользящие 7 реальных суток первая покупка — 30 000 золота, вторая — 60 000, третьей нет (`EconomyConfig` → `crystalTraderPrices`, ТЕСТ). Покупка входит в недельный PvE-предел. Все проверки — до оплаты: нет покупок в окне, нет квоты или нет места в хранилище — блок, золото не списывается, компенсации нет. Одна покупка — один id, повтор ничего не делает; после покупки игра сразу сохраняется. Правила — `Modules/Economy/Rules/CrystalTrader.cs`, тесты — `CrystalTraderTests`; сохранение — `progress.json`, `crystalTrader`. DEV: «Золото 100 000» (мимо лимита склада, для проверки), «Сбросить квоту» сбрасывает и покупки. **Вопрос:** при лимите золота 1000 + 1000 за уровень Склада цены 30 000 / 60 000 почти недостижимы.
- **Ускорения — за золото** (06.11, решение Саши, ТЕСТ): стройка, улучшение и обучение войск — 1 золото за 10 секунд (`EconomyConfig` → «Стройка» → `secondsPerGold`, `EconomyConfig.SpeedUpGold`); было 1 синий кристалл за 30 секунд. Подтвердить у руководителя валюту и курс.
- **Магазин — за золото** (пакеты дерева, камня, еды, железа: 600 / 700 / 600 / 900 золота, ТЕСТ). Убраны пакеты за 50–80 кристаллов, «Мешок золота», обмен золота на кристаллы, «Горсть» (500) и «Сундук» (3000) кристаллов.
**Ещё не сделано:** Кристальная шахта (до двух, 3 за 7 реальных суток, пауза при полном хранилище); космо-кристаллы; торговля и военная добыча — этап мультиплеера.
**Открыто:** окончательные цены расширения хранилища, компенсация за кристалл сверх недельного предела, уровень Ратуши для второй шахты.
## Таблица баланса `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.
## Журнал изменений
| Дата | Кто | Что |
| --- | --- | --- |
| 06.11.2026 | Claude (Саша) | Редкий PvE-торговец: синий кристалл за 30 000 / 60 000 золота, не больше 2 за 7 реальных суток, в пределах недельной квоты; блок без списания (`CrystalTrader` + 5 тестов, магазин, DEV «Золото 100 000»). |
| 06.11.2026 | Claude (Саша) | Недельный PvE-предел синих кристаллов: 6 за 7 реальных суток, сверх — 1000 золота за кристалл (ТЕСТ); `CrystalQuota` + 6 тестов, `GameProgress.Grant/ClaimQuest`, окно Ратуши, DEV-кнопки. |
| 06.11.2026 | Claude (Саша) | Ускорения стройки, улучшения и обучения войск — за золото: 1 золото за 10 с (`secondsPerGold`, ТЕСТ), было 1 кристалл за 30 с. |
| 06.11.2026 | Claude (Саша) | Хранилище синих кристаллов: платное расширение 50 → 75 / 100 / 150 / 200 на Ратуше 3 / 5 / 7 / 9 в окне Ратуши (`CrystalStorage`, `EconomyConfig.crystalExpansions`, `ResourceManager.CrystalStorageLevel` в сохранении, 5 тестов). Вместимость кристаллов больше не константа 50. |
| 06.11.2026 | Claude (Саша) | Регламент валют 05.11, разд. 2 и 5.1: синие кристаллы только за верхнюю ступень недельного события (1) и каждый 10-й этап боя (1); задания, вход, письма, уровень, арена, сундук — золото и ресурсы; магазин за золото, убраны пакеты за кристаллы, обмен золота на кристаллы, «Горсть» и «Сундук». |
| 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"`. |