| 1 | Сетевой транспорт | **Свой протокол: TCP/WebSocket + MessagePack** | `Netcode for GameObjects`**исключён** из стека. Общие DTO в `/shared`, генератор кода для клиента. Сервер — чистый .NET 8. |
| 2 | Объём MVP | **1-й бустер + 2 триальные колоды** | MVP = ядро правил + один сет (94 карты) + две готовые колоды + коллекция + **полный декбилдер** + бустеры. Турниры, команды, территории, косметика, баттлпасс, Draft — после MVP. |
| 3 | Описание карт | **C#-скрипты + статы в YAML** | 1 карта = 1 файл-скрипт + запись в YAML-сете. Контент-мейкер без C# не добавляет карты — учитываем в планировании. |
| 4 | Игровой сервер | **Microsoft Orleans** | GeekServer **исключён**. 1 матч = 1 grain, состояние в Redis/PostgreSQL через persistence-провайдер. |
| 5 | Платформа | **ПК (Windows) first**, мобилка после релиза | MVP-клиент — Windows + WPF-лаунчер. Тач-ввод, Addressables-доставка и сторы — веха после v1. |
| 6 | Сайд-дек / BO3 | **Убрать сайд-дек, BO1** | §13 плана правим: сайд-дек и «main + side ≤ 4 копий» удаляются. Валидация колоды проще. |
| 7 | Контент MVP | **TD01 «Blaster Blade», TD02 «Dragonic Overlord», BT01 «Descent of the King of Knights»** | Это **базовая эра 2011 г.**, а не D-серия. Меняет список механик, зон и триггеров. |
| 8 | Декбилдер | **Полный** | Поиск/фильтры, валидация, сохранение, шаринг — всё в MVP. |
| 9 | Онбординг | **Туториал → выбор триал-колоды + 5 токенов** | **1 токен = 1 бустер.** Токены универсальные, не только Draft. Новичок сразу собирает колоду из бустера. |
| 10 | Арты | **Официальные** | Юридический риск максимальный. Нужен план на takedown и правило «не храним арты на своём CDN без нужды». |
| 11 | Ride Deck / Persona Ride | **Нет в Classic** | Подтверждает базовую эру. Движок проектируется без них. |
| 12 | Локализация | **EN + RU** | Оба языка с первого дня, не «потом переведём». |
| 13 | Листы TD01/TD02 | **Получены** (вики + архив) | 50 карт каждая, 17/14/12/7 по грейдам. См. `content/cards-mvp.md`. |
| 14 | Бан-лист | **Банов в MVP нет** | Barcgal играется. Механизм `CardLegality` проектируем, но список пустой. |
| 15 | Параллельные арты | **Отдельные принты в коллекции**, привязка к базовому номеру карты (S02 → BT01/002) | Коллекция различает арты и **не имеет лимитов**. Лимит 4 копий — только при сборке колоды. |
| 16 | Название формата | **Classic** вместо «Standard» | Однозначно отделяет базовую эру от современного Standard. Переименовать в плане, коде и UI. |
| 17 | Лимиты коллекции | **Нет** — любое число копий и артов | 4 копии по имени — правило **декбилдера**, а не инвентаря. Duplicate protection — мягкий приоритет, а не жёсткий кап. |
| 18 | Правило дублей | Ключ — **`printingId`** (номер + арт), порог **4**; замена **внутри редкости**; иначе карта в коллекцию | Дубль разбирается в пыль **вручную** игроком, не автоматически. |
| 20 | Пыль | **Сквозная валюта крафта**, не привязана к сету | Накопленное тратится на карты нового сета в день выхода. При цикле 1–2 месяца инфляция в норме (13–27 % сета за цикл). |
| 21 | Темп сетов | **1–2 месяца на сет** (80 карт) | Требует 1,3–1,8 карты в день **через приёмку**. Контент, а не движок, становится критическим путём проекта. |
### 0.0.1 Контент MVP — точный объём
Проверено по официальному карт-листу:
| Продукт | Уникальных карт | Принтов | Особенности |
|---|---|---|---|
| **BT01** Descent of the King of Knights | 80 (BT01/001–080) | 92 | +12 параллельных артов (BT01/S01–S12) |
**Полный каталог с триггерами, редкостями и точными листами триал-дек — `content/cards-mvp.md`.**
Новые факты из вики:
- Редкости BT01: **RRR ×8, RR ×12, R ×20, C ×40** + **SP ×12**.
- В сете ровно **по 4 триггера каждого типа**: Critical, Draw, Stand, Heal.
- **Стартовый вэнгард — grade 0 без триггера** (Stardust Trumpeter в TD01, Undeux в TD02).
- **Draw-триггеры имеют 5000 щита, остальные триггеры — 10000.** Даёт бесплатный инвариант для валидатора.
**Кланы BT01:** Royal Paladin, Oracle Think Tank, Kagero, Nubatama, Tachikaze, Nova Grappler, Spike Brothers, Dark Irregulars, Granblue, Megacolony.
**Два вывода для модели данных:**
1. **`printingId` ≠ `nameId`.** BT01/002EN, TD01/005EN и BT01/S02EN — один и тот же «Blaster Blade». В коллекции это три разные записи без ограничений по количеству, а в деке лимит 4 копии **по имени** — иначе игрок соберёт 4 обычных + 4 параллельных = 8.
2. **Параллельные арты уже есть в первом сете** — вопрос §26 плана «нужны ли альтернативные арты» закрыт. 12 штук, каждый привязан к базовому номеру (`S02 → BT01/002`). Коллекция хранит арты раздельно, лимиты — по базовой карте.
### 0.0.2 Дельта правил: план писался под современный Vanguard
Это главная содержательная правка. Для базовой эры §4 плана даёт лишнее и не даёт нужного.
**Убрать из MVP:**
- Триггеры **Front** и **Over** — появились в V- и D-эре. В этом сете только **Critical, Draw, Stand, Heal**.
- Зоны **G Zone** и **Bind** — в 2011 их нет.
- Состояние **Lock** — появилось в 2013 (Link Joker).
- Понятие **Nation** — в 2011 только **Clan**. Поле `nation` оставить пустым/на будущее.
- **Ride Deck, Persona Ride** — подтверждено вами.
- **Limit Break, Break Ride, Legion, Stride, Imaginary Gift** — всё после MVP.
**Добавить в MVP (в плане отсутствует):**
- **Маллиган** в начале партии. В плане его нет вообще.
- **Стартовый вэнгард**: игрок выбирает grade 0 из колоды и выставляет его в начале игры.
- **Урон лицом вниз.** Damage-карты лежат рубашкой вверх; **Counter Blast** переворачивает одну лицом вверх. Значит, у damage-карты есть флаг `faceUp`, а не только счётчик. Плюс эффекты «turn all cards in your damage zone face up» (Embodiment of Victory, Aleph).
- **Twin Drive!!** — количество drive-чеков это модифицируемое свойство вэнгарда, а не константа: Dragonic Overlord умеет его терять.
- **Событие «атака попала»** отдельно от «атака объявлена»: половина карт сета триггерится на hit.
- **Boost как событие**с источником и целью: «when this unit boosts…» — массовая формулировка в сете.
- **События фаз**: начало main phase, начало close step боя, начало end phase — на них завязаны конкретные карты.
- **Sentinel** как ключевое слово с лимитом **4 карты в колоде** (не 4 копии по имени).
- **Heal-триггер**с лимитом **4 карты в колоде**.
- **Restraint** (не может атаковать) и «cannot [Stand] during next stand phase».
- **Атака в задний ряд той же колонки** (Wyvern Strike, Tejas) — нестандартная цель атаки.
**Ловушка контента — решена.** В официальном карт-листе тип триггера не виден в тексте (только иконка на арте), но в вики-таблицах есть отдельная колонка «Trigger». Все 16 триггеров BT01 и раскладка по триал-декам уже выгружены в `content/cards-mvp.md`. OCR не нужен.
**Что это дало проекту:** минус одна параллельная сетевая технология, минус один серверный фреймворк, минус неопределённость по объёму контента. Оценка MVP сократилась с «3–4 года» до реалистичного среза.
---
## 0. Результаты анализа плана
### 0.1 Что в плане хорошо
- Есть ясная базовая установка: авторитарный сервер, тонкий клиент, скрытая информация. Это правильный фундамент для ККИ.
- Экономика просчитана и внутренне непротиворечива: баттлпасс 2 500 + 21 000 + 35 000 = **58 500 XP**, «15 бустеров каждый 5-й уровень» = 15 бустеров. Совпадает.
- Разделение мета-сервера и игрового сервера, Redis для сессий, PostgreSQL для durable-данных — здоровая схема.
- Явно зафиксирован отказ от монетизации, голосового чата, ботов — меньше поверхности атаки и меньше работы.
- Есть раздел «что не обговорено» — редкость для дизайн-документов.
### 0.2 Противоречия и блокеры (решать до кода)
| # | Где | Проблема | Что делать |
|---|---|---|---|
| 1 | §2 | Игровой сервер — «TCP, MessagePack», но клиент — «Netcode for GameObjects». NGO — это Unity-рантайм (NetworkObject/NetworkBehaviour/Unity Transport). Он **не может** работать против standalone .NET 8 сервера. | ✅ **Решено:** свой протокол TCP/WebSocket + MessagePack, NGO убран. |
| 2 | §2 | «MessagePack / MemoryPack» — не выбрано. MemoryPack быстрее, но генерирует код и хуже дружит с межъязыковыми клиентами. | ✅ **Решено:** MessagePack. |
| 3 | §2 vs §1, §14 | «ScriptableObject (данные карт)» при том, что карты живут в БД, а логика — на сервере. Два источника истины. | SO — только визуал (префаб, арт, звук, VFX) по ключу `cardId`. Статы и текст — только с сервера. |
| 4 | §4 | «Все механики заложены сразу» (Limit Break → Break Ride → Legion → Stride → V → D) при объёме остальных разделов. | ✅ **Решено:** MVP = ядро + базовая D-эра на одном сете. Остальные эры — модули после MVP. |
| 5 | §3 | Редкости «Common/Uncommon/Rare/**Legendary**/RRR» — смешаны две разные таксономии (западная и официальная Vanguard). | Ввести официальную шкалу (C/R/RR/RRR/SP/…), «Legendary» убрать или явно определить как внутренний класс. |
| 6 | §13 | «Сайд-дек 5 карт» — в Vanguard сайд-деков нет, матчи BO1. | ✅ **Решено:** сайд-дек убран, формат BO1. |
| 7 | §21 | Тестовый матч «локальный, без сервера» → второй экземпляр движка правил на клиенте → неизбежное расхождение. | Туториал гонять через тот же серверный движок (локальный инстанс/ offline-режим сервера), либо принять риск и покрыть golden-тестами. |
| 8 | §21 | `TutorialStep`/`TutorialGameManager` — скриптованный туториал, а не «матч». | Решить: скрипт-события поверх реального движка или фейковая сцена. Рекомендую первое. |
| 9 | §2, §24 | Redis — единственное хранилище состояния матча. Потеря/эвикция = потерянный матч. | Redis с AOF + периодический снапшот матча в PostgreSQL + идемпотентное восстановление. |
| 10 | §11 vs §6 | «Casual — матчмейкинг просто по онлайну, без критериев» → новичок против топ-1. | Минимальный скрытый MMR даже в казуале (широкий диапазон), иначе отток новичков. |
| 11 | §24 | Реконнект 0/2/10/30 с, и что дальше — не сказано. | Политика: после N минут отсутствия — авто-поражение/пауза. См. блок 12. |
| 12 | §7 vs весь план | Тайм-контроль есть только в турнирах (35 мин). В обычном матче — нет. | Ввести таймер хода (rope) для всех матчей. |
| 13 | §13 | Нет правил конструирования колоды: размер, лимит копий по имени, лимит Heal-триггеров, Ride Deck (D). | Отдельный артефакт «Deck Construction Rules» на каждый формат. |
| 14 | §4 | В списке механик нет: Sentinel/Perfect Guard, Counter Charge, Soul Charge, Retire, Resist, Quintet Wall, Ultimate Stride, Persona Ride (есть только в D), Imaginary Gift-маркеров как объектов и т. д. | Полная инвентаризация механик по официальным правилам → Rules Reference. |
| 15 | §11 | Draft Run: 10 бустеров → колода. Правила сборки драфт-колоды (размер, триггеры, базовые карты) не заданы. | Определить формат (Sealed vs Draft), размер колоды, выдачу базовых триггеров. |
| 16 | §12 | «Готовые колоды за Gold» — легальны ли они в ранкеде, можно ли их менять. | Зафиксировать: это продукт-набор карт, колода собирается декбилдером. |
| 17 | §16 | Права модераторов описаны, инструментов — нет. | Нужна веб-админ-панель (блок 23). |
| 18 | весь план | Нет RNG-аудита (шаффл, drive/damage check) и реплеев. Без этого невозможны разбор жалоб, баланс и баг-репорты. | Server-side seeded RNG + журнал интентов + реплей (блок 8). |
| 19 | §10 | «Сброс 1-го числа» — таймзона не указана. | Зафиксировать UTC + отображать локально. |
| 20 | §15 | «Гайды… если нет лайков за неделю — удаляется» — неясно, чей лайк и зачем. | Переформулировать (например, авто-скрытие в «непопулярное»). |
| 21 | §4 | Триггеры перечислены как Critical/Draw/Stand/Heal/**Front/Over** — двух последних в 2011 не существует. | Только Critical, Draw, Stand, Heal (см. §0.0.2). |
| 22 | §4, §24 | Нет **маллигана**, **стартового вэнгарда** и **урона лицом вниз**. | Добавлено в блок 6. |
| 23 | §3 | Один `CardData.id` — не различает принт и имя карты. | Ввести `printingId` + `nameId` (см. §0.0.1). |
### 0.3 Крупные пробелы, которых в плане нет вообще
1. **Реплеи и детерминизм** — без них нет ни модерации, ни балансной аналитики, ни отладки.
2. **Админ-панель** (баны, муты, тикеты, бан-листы, выдача валюты, просмотр логов).
3. **Античит и мультиаккаунты** — только упомянуто в «не обговорено».
4. **Тайм-контроль обычных матчей.**
5. **Правила конструирования колод по форматам.**
6. **Пайплайн контента** — откуда берутся карты, как валидируются, как выкатываются сеты.
7. **Версионирование протокола и совместимость клиент/сервер.**
8. **Rate limiting / защита API / DDoS.**
9. **Наблюдаемость** (метрики, трейсы, алерты) — упомянута только как «мониторинг».
10. **Юридический риск** — фан-проект с чужими артами; нужен план на случай takedown и правила по ассетам.
### 0.4 Главные риски
- **R1. Правила.** Vanguard — это не «магия с реаргардами». Check Timing, одновременные триггеры, «may»-эффекты, порядок разрешения — самая дорогая часть проекта. Недооценка = переписывание ядра.
- **R2. Объём.** Раздел «все механики сразу» + 6 очередей + турниры + команды + территории — это 3–4 года для команды из 1–3 человек.
- **R3. Контент.** Карты надо не только описать данными, но и **заскриптовать**. 1 карта со сложным эффектом = 0,5–2 дня.
- **R4. Пустой онлайн.** 6 ранкед-очередей при маленькой аудитории = никто ни с кем не играет. Нужен план консолидации очередей.
- **R5. Юридический.** Bushiroad может потребовать прекратить использование артов/названий.
---
## 1. Дорожная карта (вехи и гейты)
| Веха | Содержание | Гейт (Definition of Done) |
|---|---|---|
| **M0. Решения и каркас** | ADR (уже готовы), Rules Reference v0, схема карт, репозиторий, docker, auth | `docker compose up` поднимает API + PostgreSQL + Redis + Orleans silo; логин/регистрация работают |
| **M1. Ядро правил (headless)** | Состояние, зоны, фазы, боевой цикл, Check Timing, RNG, реплеи | **Все 94 карты** (BT01 + TD01 + TD02) доигрывают матч в консольном раннере; реплей воспроизводится бит-в-бит |
| **M2. Сетевой матч** | Протокол, Orleans grain, скрытие информации, Unity-клиент с серым UI, реконнект | Два игрока по сети играют полный матч триал-колодами; убийство клиента на любом шаге восстанавливается |
| **M3. MVP-продукт** | Пайплайн контента, коллекция, минимальный декбилдер, триал-колоды, бустеры, Gold, XP, 1–2 очереди, базовый туториал | Новый игрок: логин → триал-дека → матч → бустер → собрал колоду из своих карт → сыграл ранкед |
| **M4. Мета и соцслой `[v1]`** | Ранкед/MMR/сезоны, баттлпасс, квесты, достижения, профиль, друзья, чат, лаунчер | Сезон отрабатывает полный цикл: старт → матчи → награды → сброс |
| **M5. Турниры и команды `[v1]`** | Турнирный движок, 3×3, снимки колод, архив, команды, территории, админка | Турнир на 8 человек проходит автоматически от регистрации до публикации архива |
| **M6. Мобилка и полировка `[later]`** | Тач-UI, Addressables-доставка, производительность, сторы, полный туториал | Билд проходит чеклист релиза (блок 26) |
> Рекомендация: **не начинать с UI**. Серый Unity-клиент на M2 — нормально. Красота — на M6.
- [ ] **P1** Анти-мультиаккаунт: эвристики по IP/устройству, флаги для админа (не автобан).
- [ ] **P1** Аудит-лог действий админов/модераторов (кто, что, когда, над кем).
- [ ] **P2** OAuth (Discord/Steam) — если нужен вход без пароля.
### Блок 4. Данные карт и контент-пайплайн `[MVP]`
- [x] **P0** Полный каталог на 94 карты / 124 принта составлен — `content/cards-mvp.md` (BT01 + TD01 + TD02, с триггерами и редкостями).
- [ ] **P0** Точные листы TD01 и TD02 **получены** (50 карт, 17/14/12/7 по грейдам) — см. `content/cards-mvp.md`. Сверить с официальным продуктом при первой возможности.
- [ ] **P1**`CardLegality`с датами действия — таблица проектируется сразу, но в MVP пустая (банов нет).
- [ ] **P1** Зафиксировать раскладку редкостей BT01 (C / R / RR / RRR / SP) — на ней держатся бустер и duplicate protection.
- [ ] **P0** Разделить `printingId` (`BT01/002EN`, `TD01/005EN`, `BT01/S02EN`) и `nameId` (стабильный слаг имени). Лимит копий и поиск «по имени» считаются по `nameId`, арт и цена — по `printingId`.
- [ ] **P0**`CardData` под базовую эру: `printingId`, `nameId`, `setId` (BT01/TD01/TD02), `cardType` (Normal Unit | Trigger Unit), `grade`, `power`, `shield`, `critical`, `triggerType` (null | Critical | Draw | Stand | Heal), `clan`, `nation` (nullable, на будущее), `rarity`, `isParallel` + `artVariant` (для S01–S12), `isSentinel`, `isRestraint`, `name_en/ru`, `text_en/ru`, `flavor_en/ru`, `imageKey`, `artist`, `errataVersion`.
- [ ] **P0****Не выводить `shield` из грейда или триггера** — в сете встречаются триггерные юниты и с 5000, и с 10000 щита. Значение всегда из данных.
- [ ] **P0** Триггеры и редкости выгружены из вики-таблиц — см. `content/cards-mvp.md`. Сверить выборочно 8–10 карт с иконками на артах.
- [ ] **P0** Добрать силу и щит для 14 карт, которых нет в BT01 (только TD01/TD02) — с карточных страниц.
- [ ] **P0** Нормализация текстов: в официальной БД есть опечатки (`Soul-Chage`, `begininng`, `cannnot`, `Own(VC/RC)`). Хранить `text_source` (как в источнике) и `text_normalized` (после правки), показывать игроку нормализованный.
- [ ] **P0** Зоны MVP: Vanguard Circle, Rear-Guard (3 колонки × 2 ряда; VG занимает центр переднего ряда, остальные 5 слотов — RC), Guardian, Soul, Damage, Drop, Trigger, Deck, Hand. **Без** G Zone, Bind и Ride Deck — в этой эре их нет.
- [ ] **P0** Модель юнита: `instanceId`, `printingId`, состояние (Stand/Rest), модификаторы силы/крита, временные эффекты с длительностью. **Без** Lock — появился позже.
- [ ] **P0** Модель Damage: карты лежат **лицом вниз**. Флаг `faceUp`у каждой карты, а не просто счётчик урона. Counter Blast = перевернуть одну лицом вверх; отдельные эффекты переворачивают весь damage-зон.
- [ ] **P0** Фазы: Mulligan → Stand → Draw → Ride → Main → Battle → End. Явные шаги внутри Battle: attack declare → guard → drive check → damage check → close step.
- [ ] **P0** Старт партии: выбор стартового grade 0 из колоды → выставление в Vanguard Circle → **маллиган** (замена любого числа карт из руки) → начало первого хода.
- [ ] **P0**`driveCheckCount` — изменяемое свойство вэнгарда (Twin Drive!! = 2), а не константа: Dragonic Overlord умеет его терять.
- [ ] **P0** Результат боя как явное событие: `Hit` / `Guarded` / `Missed`. Триггеры «when this unit's attack hits» — массовая формулировка сета.
- [ ] **P0** Boost как событие с источником и целью (нужно для «when this unit boosts…» и для модификаторов «boosted unit gets +N»).
- [ ] **P0** Counter Blast / Soul Blast / Soul Charge как первоклассные операции (с проверкой доступности). Counter Charge — позже, в сете его нет.
- [ ] **P0** Валидация действий: сервер отвечает `Rejected(reason)` на нелегальный интент, состояние не меняется.
- [ ] **P0** Машина состояний «чей сейчас ввод»: явный список легальных интентов для каждого игрока (нужен и для UI, и для античита).
- [ ] **P0** Юнит-тесты на каждое правило из Rules Reference (не на карты — на механику).
- [ ] **P1** Тайм-контроль хода (rope): 90 с на ход, 5 мин банк, авто-end.
- [ ] **P1** Обработка «нет легальных действий» (принудительный пас), защита от дедлоков.
- [ ] **P1** Лимит глубины рекурсии эффектов и защита от бесконечных циклов.
### Блок 7. Игровое ядро: способности и Check Timing `[MVP]` — **критический путь**
- [ ] **P0** Шина событий в `GameActor`: типизированные события (`UnitRode`, `UnitCalled`, `AttackDeclared`, `TriggerRevealed`, `DamageTaken`, `UnitRetired`, …).
- [ ] **P0** Три обработчика: `Continuous` (пересчёт слоёв модификаторов), `Activated` (по действию игрока), `Triggered` (по событию).
- [ ] **P0****Check Timing**: собрать сработавшие триггеры → отсортировать по правилам (обязательные/опциональные, владелец, порядок выбора) → разрешить по одному → повторить, пока очередь не пуста.
- [ ] **P0** Модель стоимости (`costs[]`): CB, SB, discard, rest self, retire self, put into soul, return to deck, «pay if you want» — с откатом, если оплата невозможна.
- [ ] **P0** Модель целей (`targetSpec`): авто-выбор по фильтру, выбор игроком, «до N», «ровно N», валидация на сервере.
- [ ] **P0** Модификаторы силы/крита как слои с длительностью (до конца боя / хода / пока на поле) — без ручного пересчёта в скриптах карт.
- [ ] **P0** Golden-тесты Check Timing: сценарии с 3+ одновременными триггерами и порядком разрешения.
- [ ] **P1** «Resist» и запрет выбора — как фильтр в `targetSpec`, а не как спецкод в картах.
- [ ] **P1** Логирование цепочки разрешения (для отладки и реплеев): «событие → сработавшие → порядок → результат».
- [ ] **P2** Инструмент-визуализатор цепочки для отладки карт.
### Блок 8. Детерминизм, RNG, реплеи `[MVP]` — **критический путь**
- [ ] **P0** Серверный PRNG с явным seed на матч; шаффл детерминированный (Fisher–Yates поверх seeded-потока).
- [ ] **P0** Журнал интентов: `[seq, playerId, intent, timestamp]` + итоговый seed → матч воспроизводим.
- [ ] **P0** Реплей-раннер: `GameState + intents + seed → финальное состояние`, сравнение хешей. В CI на каждый коммит ядра.
- [ ] **P1** Хранение реплеев: последние N матчей в горячем хранилище, остальное — в S3/файлах с сжатием.
- [ ] **P1** Проверяемая честность бустеров: публикация хеша сида до открытия, раскрытие после (опционально, но дёшево и снимает много жалоб).
- [ ] **P1** Лог «почему действие отклонено» для саппорта.
- [ ] **P2** Просмотр реплея в клиенте (шаг вперёд/назад) — сильный инструмент для комьюнити.
### Блок 9. Механики по эрам `[MVP → later]`
Порядок реализации = порядок возрастания сложности, не порядок выхода сетов.
> **Правило MVP:** в первую версию входят **только** механики из 94 карт MVP. Сначала матрица «карта → механика», из неё — список модулей. Ванильных карт без текста много, они не тянут за собой новых модулей.
- [ ] **P0** Триггеры: **только Critical, Draw, Stand, Heal**. Front и Over появятся в V/D-эре — не реализуем сейчас.
- [ ] **P0** Sentinel (Perfect Guard): нуллификация атаки, лимит **4 карты в колоде** — отдельно от лимита копий по имени.
- [ ] **P0** Heal-триггер: лимит **4 карты в колоде**, отдельная проверка в валидаторе.
- [ ] **P0** Ключевые слова и ограничения: Restraint (не может атаковать), «cannot [Stand] during next stand phase», «cannot be hit», «cannot boost this unit».
- [ ] **P0** Атака в задний ряд той же колонки (Wyvern Strike, Tejas) — нестандартная цель атаки, ломает наивную модель «атакую только передний ряд».
- [ ] **P1** Каждая механика — отдельный модуль с фича-флагом по формату (включение/выключение на уровне матча).
- [ ] **P2**`[later]` Limit Break (4+ урона) + Break Ride (+10000, тот же клан).
- [ ] **P2**`[later]` G-эра: Stride, Heart Card, G Guardian, G Zone.
- [ ] **P2**`[later]` V-эра: Imaginary Gift Force/Accel/Protect, Front-триггер.
- [ ] **P2**`[later]` D-эра: Ride Deck, Persona Ride, Over Trigger.
- [ ] **P1** Тесты: один и тот же набор базовых тестов прогоняется для каждого формата.
### Блок 10. Скрипты карт и тестирование контента `[MVP]`
- [ ] **P0** Шаблон новой карты для зафиксированного формата (**C#-скрипт + запись в YAML**): 1 файл = 1 карта, обязательные `// rule:` комментарии со ссылкой на официальный текст.
- [ ] **P0** Глоссарий примитивов, собранный из фактических текстов сета: `Draw`, `Retire` (одна/все/до N), `Search→call`, `Search→hand`, `Search→ride`, `Stand` (себя/выбранного/всех), `Soul-Charge`, `Soul-Blast`, `Counter-Blast`, `Flip damage face-up`, `Put into soul`, `Deck→drop`, `Return to deck + shuffle`, `Hand→deck`, `Discard as cost`, `Opponent discards`, `Look top & reorder`, `Power/Crit modifier`, `Gain/lose keyword`, `Attack back row`, `Cannot stand`, `Cannot be hit`. Всё остальное — комбинации этих примитивов.
- [ ] **P0** Хелперы «поиск по имени» (`nameId`) — в сете много карт, которые ищут/проверяют конкретные имена (Blaster Blade, Llew, Flogal, Tejas, Blue Dust, King of Sword).
- [ ] **P0** План скриптования: сначала обе триал-колоды (играбельно сразу), затем остальные карты BT01 — от простых к сложным. Ванильных карт с «–» в сете много — они закрываются одной строкой данных.
- [ ] **P0** Пропускная способность под темп **1–2 месяца на сет**: 80 карт / 45–60 дней = **1,3–1,8 карты в день**, каждый день, без пауз. Это узкое место проекта, а не движок. Варианты: второй контент-мейкер или буфер из двух готовых сетов до публичного запуска.
- [ ] **P1** Мерить «карты, прошедшие приёмку», а не «карты, написанные»: скрипт + тест + RU/EN + воспроизводимый реплей.
- [ ] **P0** Базовые «кирпичики» (helpers): `DrawCard`, `RetireUnit`, `AddPower`, `ChooseTarget`, `LookTopDeck`, `CallFromDeck` — чтобы 80 % карт были однострочными.
- [ ] **P1** Тест-харнесс для карт: «дано состояние → сыграй карту → ожидай состояние» на DSL/YAML.
- [ ] **P1** Чеклист приёмки карты: текст совпадает с официальным, все ветки эффекта покрыты тестом, RU/EN синхронны, работает в реплее.
- [ ] **P1** Метрика покрытия: сколько карт из сета заскриптовано/протестировано (дашборд).
- [ ] **P1** Fuzz-тест: случайные легальные матчи на 1000 партий, проверка инвариантов (нет отрицательных счётчиков, зоны не теряют карты, total cards = const).
- [ ] **P2** Визуальный редактор/валидатор карт.
### Блок 11. Игровой сервер и сетевой протокол `[MVP]`
- [ ] **P0** Конверт сообщения: `{type, seq, payload}`, типизированные DTO в `/shared`, генерация кода для C#-клиента.
- [ ] **P0** Orleans-модель: `IMatchGrain` (1 матч = 1 grain), `IQueueGrain` на формат, `IUserGrain` (сессия/presence). Последовательная обработка интентов — гонки исключены архитектурно.
- [ ] **P0** Кластеризация: dev — один silo, prod — 2+, Redis как clustering/persistence provider; readiness-проба на silo.
- [ ] **P0****Проекция состояния под клиента** (fog of war): каждый игрок получает свою руку, свой trigger zone и открытый урон. Никогда не отправлять: порядок колоды, руку противника, **лицом вниз лежащий урон (даже владельцу)**, seed.
- [ ] **P0** Авторитет: клиент отправляет только намерения (`PlayCard`, `Attack`, `PassGuard`), сервер валидирует и рассылает события.
- [ ] **P0** Последовательность событий (`eventSeq`) — клиент просит `resync` при разрыве.
- [ ] **P1** Пауза/возобновление матча при `OnApplicationPause` (мобилка) с лимитом.
- [ ] **P1** Логи клиента с отправкой в саппорт (кнопка «отправить лог»).
### Блок 15. Клиент: боевая сцена и UX `[MVP]`
- [ ] **P0** Экран старта партии: выбор стартового grade 0 из колоды → **маллиган** (отметить любые карты, подтвердить) → превью руки противника без содержимого.
- [ ] **P2** Настройка скорости анимаций, «пропустить всё».
- [ ] **P2** Режим наблюдателя / просмотр реплея.
### Блок 16. Колоды и коллекция `[MVP]`
- [ ] **P0** Декбилдер: поиск/фильтры (клан, грейд, редкость, тип Normal/Trigger, наличие арта), счётчики, валидация в реальном времени.
- [ ] **P0** Валидация на **сервере** (клиентская — только подсказка): ровно 50 карт, ≤4 копий **по `nameId`** (не по принту!), ≤4 карт с Sentinel, ≤4 карт с Heal-триггером, формат, бан-лист.
- [ ] **P0****Разделить инвентарь и колоду:** коллекция не ограничивает количество копий и артов вообще; лимит 4 по имени действует только в момент сборки/сохранения колоды.
- [ ] **P0** Отдельный тест-кейс: 4× обычный Blaster Blade + 4× параллельный (S02) должен отклоняться валидатором, при этом обе карты спокойно лежат в коллекции в любом количестве.
- [ ] **P0** Коллекция: каждый арт — отдельная запись (BT01/002 и BT01/S02 видны раздельно), привязка к базовому номеру, счётчик копий без верхней границы, «сколько в колодах», блокировка разбора.
- [ ] **P0** Лимиты: 30 колод на формат + 10 турнирных; понятные ошибки при превышении.
- [ ] **P1** Инвариант данных: у grade 0 щит 5000 **только**у Draw-триггеров, у остальных 10000. Автопроверка на всех 94 картах ловит ошибки разметки.
> **MVP-объём:** Gold, пыль, бустеры, duplicate protection, покупка триал-колод. Баттлпасс, квесты и Draft Run — после MVP. XP всё равно пишем с первого дня, иначе прогресс не восстановить задним числом.
- [ ] **P0****Журнал транзакций** (double-entry): каждая операция — запись с`idempotencyKey`, баланс — вычисляемый, не хранимый «на честном слове».
- [ ] **P0** Валюты: Gold, пыль, **токены** (универсальные — обмениваются на любой бустер). Все изменения — только через сервис экономики.
- [ ] **P0** Структура бустера: **5 карт** = 4 карты редкости **C** + 1 слот **«R и выше»**. Генерация слотовая, а не «5 случайных по редкости» — иначе гарантия не выполняется.
- [ ] **P0** Duplicate protection: ключ — **`printingId`** (номер + арт), порог **4 копии**. Слот выбирается только из принтов, которых у игрока меньше 4.
- [ ] **P0** Замена — **внутри той же редкости**, иначе поедут шансы слота.
- [ ] **P0** Если **вся редкость** насыщена (все принты по 4), а другие ещё нет — перебрасываем редкость с перенормировкой весов. Иначе все 20 R собираются раньше, чем RRR, и дальше каждый R-бросок становится «мёртвым».
- [ ] **P0** Если насыщен весь слот R+ — карта выдаётся как дубль и уходит в коллекцию.
> **Что дают веса** (коробка = 30 бустеров):
> | Редкость | Вес | На коробку | Копий до 4× | Бустеров, если добирать только эту редкость |
> |---|---|---|---|---|
> | R | 70 % | ~21 | 80 | ~114 |
> | RR | 22 % | ~6,6 | 48 | ~218 |
> | RRR | 7 % | ~2,1 | 32 | ~457 |
> | SP | 1 % | ~0,3 | — | вне прогресса сета |
>
> Защита от дублей не ускоряет добор **редкой** редкости: она лишь убирает повторы внутри неё. Поэтому хвост сета — это RRR.
> Точечно нужная карта добывается **пылью**, а не открытием: после насыщения C каждый бустер даёт ~20 пыли, крафт RRR = 400 → 20 бустеров на одну. Это и есть надёжный путь к турнирной колоде.
- [ ] **P0** Дубль **не разбирается автоматически**: игрок сам превращает его в пыль, с предупреждением, если карта стоит в колоде. Коллекция при этом не ограничена.
- [ ] **P0** SP **не учитывать** в прогрессе «собрано X/Y карт сета» и в достижениях за коллекцию — иначе сет не закрывается никогда. SP — косметический параллельный принт.
- [ ] **P0** Пыль под реальные редкости: разбор **C 5 / R 10 / RR 25 / RRR 100**, крафт ×4 — **20 / 40 / 100 / 400**. SP не крафтится (только из бустеров). В плане был «Uncommon» — в BT01 это R.
- [ ] **P0** Пыль — **сквозная валюта, не привязана к сету**: накопленное тратится на крафт карт нового сета в день его выхода. При смене сета пыль не сгорает и не конвертируется.
- [ ] **P1** Инфляция пыли при темпе сетов 1–2 месяца: за цикл накапливается ~800–1600 пыли против 6 000 на полный плейсет, то есть **13–27 %**. Это здоровый диапазон — крафт нового сета можно открывать сразу, задержка не нужна.
- [ ] **P2** Если темп сетов замедлится до 4+ месяцев, вернуться к вопросу задержки крафта: тогда доля доходит до 50 %+ и новинки теряют смысл.
- [ ] **P1**`[v1]` Баттлпасс: 75 уровней / 30 дней, XP-пороги 250/700/1000, награды каждые 5 уровней, Draft-пропуск на 40 и 75, переполнение 50 Gold/уровень.
- [ ] **P0** XP за матчи: 150/75/100, Draft 200/100, турниры 500/250/1000/2000 (начисление писать с первого дня).
- [ ] **P0** Gold за матчи: **30 / 15 / 20** (победа / поражение / ничья). Мнемоника — **Gold = XP / 5**: одна константа в конфиге, а не два независимых баланса.
- [ ] **P0** Gold **не** начисляется: за сдачу, АФК, приватные матчи. Только после подтверждённого сервером завершения.
- [ ] **P1** Бонус первой победы дня: **+20 Gold**. Компенсирует то, что квесты дают только XP, и держит ежедневный вход осмысленным.
- [x] **P0** Размер бустера подтверждён: **5 карт**, из них 1 гарантированно R или выше.
> **Проверка темпа** (5 карт в бустере = 4 C + 1 R+, 50 % побед, 5 матчей в день):
> - средний доход за матч — 22,5 Gold, то есть ~22 % бустера;
> - день — ~132 Gold (с бонусом первой победы) ≈ **1,3 бустера**;
> - неделя — ~9 бустеров = 36 C + 9 R+;
> - месяц — ~40 бустеров = **~160 C** (ровно 40 карт × 4 — полный C-сет) и **~40 R+**;
> - **узкое место — не коммоны, а R+:** 40 карт × 4 = 160 копий, то есть полный R+ закрывается за ~160 бустеров ≈ **4 месяца**;
> - **на один сет при темпе 1,5 месяца (~60 бустеров):** ~100 % C и ~37 % R+. Новинка ощущается свежей, но R+ остаётся хвостом.
- [ ] **P1**`[v1]` Квесты: 3 ежедневных (1/3/5 матчей → 300 XP), 1 недельный (20 матчей → 2000 XP), сброс по UTC.
- [ ] **P0** Засчитывание матча: доигран, без сдачи, без АФК; приватные — не засчитываются.
- [ ] **P2**`[later]` Правила драфт-колоды (размер, триггеры, базовые карты) — **сейчас не определены**.
- [ ] **P0** Онбординг: после туториала игрок выбирает **одну из двух триал-колод** (бесплатно) и получает **5 токенов**; токен обменивается на любой бустер. Выбор нельзя отменить — предусмотреть подтверждение.
- [ ] **P0** Покупка второй триал-колоды за Gold.
- [ ] **P1** Анти-дюп и защита от повторного применения `idempotencyKey`; лимит операций в секунду.
- [ ] **P1** Открытые вопросы: сгорает ли пыль в конце сезона, есть ли лимит на токены, есть ли лимит Gold.
- [ ] **P2** «Инфляция Gold»: что ещё продавать, чтобы валюта не обесценивалась.
### Блок 18. Рейтинг, сезоны, прогрессия, достижения `[v1]`
- [ ] **P0** MMR: скрытый, Elo/Glicko-2, отдельный на каждый формат (3 значения), K-фактор с учётом новичков.
- [ ] **P0** Ранги: 6 тиров × 5 дивизионов, Master без дивизионов; звёзды ±1, 5 звёзд = +1 дивизион.
- [ ] **P0** Защита от падения: Bronze/Silver — нет, Gold/Platinum/Diamond — до пола тира, Master — свободно.
- [ ] **P0**Сброс сезона 1-го числа (UTC): Master→Platinum 1, Diamond→Gold 1, Platinum→Silver 1, Gold→Bronze 1.
- [ ] **P1** Награды за ранг (Gold, пыль, Master — рубашка + титул).
- [ ] **P1** Бонусные звёзды при высоком MMR.
- [ ] **P1** Грейды аккаунта 0–5, XP аккаунта, награды (Gold, пыль, слоты колод, косметика, доступ к режимам).
- [ ] **P1** Достижения: категории, разовые/прогрессивные/скрытые, условия — данными, а не кодом.
- Wiki пишет «7 карт эксклюзивны» для TD01, но перечисляет 5. По факту эксклюзивны **7**: Brigitte, Bors, Tristan, Starlight Unicorn, Morgana, Stardust Trumpeter, Epona.
- Для TD02 wiki пишет «2 эксклюзивные», перечисляет 3. По факту **7**: Goku, Yaksha, Berserk Dragon, Aermo, Joka, Undeux, Rakshasa.
- Утверждения в текстах wiki проверять по таблицам карт, а не наоборот.
---
## 5. Структура бустера
- **5 карт в упаковке.**
- **1 карта гарантированно R или выше**, остальные 4 — C.
- Значит генерация слотовая: `4 × C` + `1 × взвешенный R+`. Гарантия должна выполняться всегда, поэтому нельзя генерировать «5 карт по редкости» и потом проверять.
- SP-принты (12 шт.) — отдельный исход в слоте R+. Для duplicate protection это отдельный принт: 4 обычных Blaster Blade не блокируют выпадение SP02.
- На коробку из 30 бустеров: ~21 R, ~6,6 RR, ~2,1 RRR, ~0,3 SP.
**Правило дублей:** ключ — `printingId` (номер + арт), порог 4 копии. Если принт уже в 4 экземплярах — замена внутри той же редкости. Если заменять нечем — карта падает в коллекцию, и игрок сам разбирает её в пыль.
Следствие для темпа: за ~40 бустеров набирается 160 C (это ровно 40 карт × 4, то есть полный C-сет), но только ~40 карт слота R+. R+ — долгий хвост: 40 карт × 4 = 160 копий ≈ 160 бустеров.
---
## 6. Что ещё нужно достать
- [ ] Сила и щит для 14 карт, которых нет в BT01 (TD01/001–002, 006, 010–013; TD02/002–003, 005, 009–010, 012, 016) — брать с карточных страниц.
- Фанатский проект без монетизации. Никаких реальных денег, твёрдой валюты, премиум-баттлпасса. Дисклеймер: "Fan-made project. Not affiliated with Bushiroad. All card names and art belong to their respective owners."
- Авторитарный сервер. Вся игровая логика на сервере. Клиент — тонкий терминал. Клиент просит, сервер решает.
- Скрытая информация. Клиент A не получает данных о руке клиента B.
- Два языка: русский и английский. UI — Unity Localization, карты — поля в БД.
Глоссарий: ключевые слова Vanguard (Ride, Call, Drive Check, Damage Check, Counter Blast, Soul Blast, Stand, Rest, Guard, Boost, Intercept) на двух языках. Тексты карт используют плейсхолдеры, подставляемые из глоссария.
## 4. Механики Vanguard (все заложены сразу, карты выпускаются постепенно)
Триггеры: Critical, Draw, Stand, Heal, Front, Over Trigger.
По эрам:
- Limit Break (4+ урона)
- Break Ride (тот же клан, +10000)
- Legion (Leader + Mate, Seek Mate)
- Stride / G Era (Heart Card, G Guardians)
- V Series (Imaginary Gift: Force/Accel/Protect)
- D Series (Ride Deck, Persona Ride, Over Trigger)
Реализация: каждая механика — отдельный модуль. Rule Engine применяет все, карты определяют активные. Check Timing обрабатывает порядок срабатывания.
## 5. Способности карт
AbilityData: type (Continuous/Activated/Triggered), triggerEvent, conditions[], costs[], effects[], target. Три обработчика. Шина событий в GameActor. Check Timing: событие → проверка триггеров → разрешение → повтор. Условия — отдельные Evaluate()-объекты.
## 6. Режимы игры
Варианты (форматы): Standard (делится на Эры), V, D.
Ранкед и Казуал — по вариантам (6 очередей). Рейтинг — по вариантам (3 MMR у игрока). Эры — только для турниров и ивентов (модификатор пула). Standard Ranked по умолчанию — весь пул Standard.
Casual: матчмейкинг просто по онлайну, без критериев.
Приватные матчи: приглашение друга → принятие → выбор колоды → матч. XP не начисляется, результат в историю пишется.
Бот: пока не делаем.
## 7. Турниры
Одиночные: 1х1, Swiss + Top Cut, 35 мин/раунд, Double Loss при таймауте. Фиксация колод при регистрации.
Командные 3х3: три параллельных 1х1. Капитаны видят составы и кланы колод соперников (не полный состав), выбирают порядок. Победа по сумме очков (2:1 или 3:0). Техническое поражение только в конкретной паре.
История: все турниры хранятся. После завершения снимки колод становятся публичными (полный состав), карты разблокируются. Архив меты.
## 8. Команды
Структура: полное название, короткий тег (2-5 символов), иконка. Префикс [TAG] в никнейме везде.
- Лидер: полный контроль, переименование, иконка, назначение офицеров, кик, передача лидерства, роспуск.
- Офицеры (1-3): одобряют заявки, приглашают. Не могут переименовать, сменить иконку, удалить.
- Участники: играют, общаются, выходят.
Передача лидерства: только офицеру, раз в 30 дней (кулдаун от последней передачи).
Лимит участников: зависит от уровня команды (1-10).
## 9. Командные награды и территории
Карта наций: 6 регионов (United Sanctuary, Dragon Empire, Star Gate, Zoo, Megalanica, Dark Zone). Территории внутри регионов (столица, ключевые точки, аутпосты).
Очки контроля: за победы в командных матчах. В конце цикла (неделя) команда с наибольшим количеством очков становится владельцем.
Награды: Gold, пыль, командный XP, рейтинг. Лимит 3 территории на команду. Убывающая отдача за длительное владение.
Командный рейтинг: глобальный лидерборд команд.
## 10. Рейтинговая система
Сезон = месяц. Совпадает с баттлпассом. Сброс 1-го числа.
Ранги: 6 тиров × 5 дивизионов (Bronze, Silver, Gold, Platinum, Diamond, Master). Master — без дивизионов, только MMR и лидерборд.
Звёзды: победа +1, поражение -1. 5 звёзд = +1 дивизион. Защита от падения: Bronze/Silver — нет, Gold/Platinum/Diamond — до пола тира, Master — свободно.
- Разбор любой карты, включая последнюю копию — с предупреждением.
- Карты в колодах (включая турнирные снимки) защищены от разбора до конца турнира.
Duplicate Protection: работает для покупных бустеров (общая коллекция). Бонусные бустеры внутри Draft Run — только в рамках захода (лимит 4 копии). Бустеры за токены — стандартная защита.
Баттлпасс: 75 уровней / 30 дней. XP на уровень: 1-10 = 250, 11-40 = 700, 41-75 = 1000. Всего ~58 500 XP. Награды: 15 бустеров (каждый 5-й уровень), пропуск Draft на уровнях 40 и 75, ~4000 Gold, ~1200 пыли. Переполнение (76+) — только 50 Gold/уровень.
XP за матчи: победа 150, поражение 75, ничья 100. Draft Run: победа 200, поражение 100. Турниры: участие 500, победа 250, Top Cut 1000, чемпион 2000.
Ежедневные задания: 3 задания, 1/3/5 матчей → 300 XP каждое. Еженедельное: 20 матчей → 2000 XP. Только XP.
Засчитывается матч: сыгран до конца, без сдачи, без АФК. Приватные матчи — не засчитываются.
Draft Run: вход 1000 Gold → 10 бустеров. Duplicate Protection только в рамках захода (лимит 4 копии). 5 побед → +5 бустеров. 10 побед → +5 токенов на любой бустер. Без пыли. Без лимита поражений.
## 12. Источники карт
Готовые колоды: фиксированный набор, покупка за Gold.
Бустеры: рандом по редкости, серверный рандом. Логи открытий.
Фойлы: is_foil в коллекции, визуальный вариант.
Промокарты: за ачивки/события.
## 13. Колоды
Лимиты: 30 обычных колод на вариант (Standard, V, D) + 10 турнирных. Турнирные привязаны к эре/турниру.
Сайд-дек: 5 карт, отдельная секция. Валидация: main + side ≤ 4 копий одной карты.
Шаринг: код колоды + ссылка.
Оценка: просмотры + лайки. Опционально «вес колоды» для матчмейкинга.
Защита от разбора: карты в колодах заблокированы. После турнира — разблокированы.