Статус: План согласован (2026-07-14). Развилки §6 закрыты решениями Макса (порядок data-first, имя BattlePresetData, релик = весь кит, всё на UI Toolkit — не Odin). UI релика уточнён — полноэкранный loadout-экран (§5). Реализация — по шагам, каждый шаг отдельной сессией, с ресёрчем перед большими шагами. Остаются мелкие уточнения — §6.


План последовательности работ для игрового среза: интерактивная фаза расстановки, надевание реликов, система энкаунтеров, готовые бои и dev-переключатель между ними. Опирается на уже согласованный дизайн 10. Арена и расстановка (дизайн) и достраивает его до играбельного dev-инструмента.

Связано: 10. Арена и расстановка (дизайн), 7. Флоу забега и сессия, 07. ТЗ — Фаза 4 (Контент-каркас), 01. Roadmap реализации.


1. Что уже есть (карта после разведки 2026-07-14)

Дата-слой — готов. EnemyData и RelicData существуют, оба — тонкие наследники общего UnitData (кит вынесен в базу). Сборка рантайма едина и типо-агностична: RuntimeUnitFactory.Create(UnitData, VesselData, …). Домены id (enemy.*, relic.*) настроены, есть ContentDatabase + Content Hub (редактор). Единственный враг в контенте — enemy.training_dummy; гоблинов нет — контент создаётся с нуля.

Расстановка — данные и правила готовы, интерактива нет. DeploymentService.CanPlace(pos, side, canUseExtended) реализован и покрыт тестами; ArenaLayoutData/DeploymentZone/Rect2D/ArenaBounds готовы; Odin-авторинг арены (ArenaLayoutAuthoring + Scene-хэндлы) готов. Нет: мышиного ввода, picking юнита, drag, визуального фидбэка (outline/зоны/валидность), оркестратора фазы. InputContext.Deployment существует, но включает только камеру. У UnitView есть сокеты и feedback-хуки, но нет outline/selection.

Запуск боёв — конвейер готов, data-driven слоя нет. DI-цепочка GameBootstrap → GameFlow → SceneLoader → CombatLifetimeScope → CombatLoopService работает. ResetBattle()/OnBattleReset — рабочий «загрузчик боя на месте» (чистит сим без перезагрузки сцены, презентация подписана). Нет: ни одного data-driven описания боя (Encounter/Wave/BattleDefinition отсутствуют как класс и как домен). Состав тестовых боёв захардкожен императивно в GuildmasterCommands (gm_spawn_*) + заготовка BattleSetupBuilder.SetupTestBattle (в DI, но никто не вызывает). Dev-UI = Quantum Console команды + хоткеи R/F5, графической панели выбора боя нет.

Вывод: фундамент под всё это есть, но состав боя живёт хардкодом. Это определяет порядок ниже.


2. Рекомендованный порядок и его логика

Ведущий принцип: сначала развязать состав боя от хардкода (данные), потом наполнить (враги), потом сделать интерактив (расстановка, релики).

Почему НЕ начинать с расстановки, хотя запрос начинался с неё:

  • Расстановка живёт внутри боя, который надо откуда-то загрузить. Сейчас бой = хардкод в GuildmasterCommands. Если делать расстановку первой, она встанет на этот хардкод, и её придётся перепроводить, когда появится data-driven загрузка. Фундамент дешевле сделать первым.
  • Расставляться надо против кого-то. Сейчас враг — дамми. Настоящий бой требует врагов (гоблинов) раньше расстановки.
  • «Готовый бой без расстановки» и «с расстановкой» — две ветки одного загрузчика. Значит загрузчик боя первичен, а фаза расстановки — надстройка над ним.
  • Надевание реликов — надстройка над выбором юнита в расстановке. Значит оно идёт последним из интерактива.

Порядок: данные (энкаунтер) → контент (враги) → пресеты (готовые бои) → интерактив (расстановка) → релики. Каждый шаг оставляет играбельный результат и не переделывается следующим.


3. Шаги реализации

Шаг 1 — Энкаунтер-данные + загрузчик + dev-переключатель [фундамент]

Содержание:

  • EncounterData : ContentDefinition (новый домен encounter в ContentDomains.cs). Поля по эскизу 10. Арена и расстановка (дизайн) §3, §5: список врагов (EnemyData + позиция + опц. каунт), ключ/ссылка арены, опц. фиксированный сид, метка сложности.
  • EncounterLoader — data-driven строитель боя поверх паттерна ResetForNewBattle() → EnqueueUnitSpawn (оживить/заменить BattleSetupBuilder). Переиспользует ResetBattle как движок переключения без перезагрузки сцены.
  • Реестр энкаунтеров в ContentDatabase (механика доменов + TryGet уже есть).
  • Минимальный dev-UI: список доступных энкаунтеров с кнопками запуска (UI Toolkit — единая дизайн-система, решение Макса; не Odin). Сохранить R = рестарт выбранного.
  • Перенести 2–3 существующих хардкод-боя в encounter-ассеты (враги пока = дамми).

Разблокирует: всё дальнейшее встаёт на data-driven загрузку. Хардкод боёв начинает отмирать. Ресёрч перед шагом: 7. Флоу забега и сессия — владелец EncounterData и связь «энкаунтер → ключ арены» (открытый вопрос дизайна §9); финальная структура полей. За Максом: визуальная проверка в сцене.

Шаг 2 — Враги: common-гоблины (контент + AI) [контент]

Содержание:

  • Дизайн 3–4 базовых common-гоблинов (архетипы, статы, поведение) — по GDD.
  • EnemyData + парные AIPresetData ассеты (новым врагам сразу назначать пресет, не легаси inline-AI).
  • Наполнить 4–6 энкаунтеров разной сложности настоящими врагами (микс гоблинов + каунты).

Разблокирует: осмысленные бои для расстановки и тестов. Ресёрч перед шагом: docs/wiki/gdd/enemies, damage-model-schools-affinities (сродства по типу существа), какие архетипы гоблинов дают спектр сложности (танк / рой / стрелок / бьющий). За Максом: дизайн-ревью гоблинов, визуал.

Шаг 3 — Готовые бои (пресеты) + перенос тестовых боёв + второй dev-список [пресеты]

Содержание:

  • BattlePresetData: EncounterData (враги) + player-ростер (слоты: VesselData + RelicData + опц. предметы + сохранённая позиция) + DeploymentMode { Fixed, Free }. Слот релика всегда заполнен: у «пустого» сосуда стоит базовый релик без особенностей (дамми-кит), см. §5.
  • Загрузчик расширяется: Fixed = спавн сразу по сохранённым позициям (чистый запуск, «реплей-подобный»); Free = отдать player-сторону в фазу расстановки (Шаг 4).
  • Перенести все тестовые бои (gm_spawn_spearman/_shepherd/…) в BattlePreset-ассеты.
  • Dev-UI: два списка — «Энкаунтеры» и «Готовые бои».

Разблокирует: полноценные пресеты боёв, чистый запуск, основа для фазы расстановки. Ресёрч перед шагом: структура player-ростера; как «сохранённая расстановка» сериализуется в SO (позиции как данные). За Максом: ревью набора пресетов, визуал.

Шаг 4 — Интерактивная расстановка (Free-режим) [интерактив]

Содержание:

  • Оркестратор фазы: state-машина Deployment → Combat, старт боя по «Готово». 4 юнита игрока создаются сразу в фазе расстановки.
  • Мышиный ввод: карта/действия мыши в InputService для InputContext.Deployment (позиция + Press).
  • Picking юнита: математический — ближайший UnitView в радиусе тела (Size × BodyRadiusPerSize), без коллайдеров (ближе к «геометрия = данные»). Различать одиночный клик/drag (двигать) и дабл-клик (открыть loadout, Шаг 5).
  • Drag + валидация через готовый DeploymentService.CanPlace; анти-оверлап при drop (открытый вопрос дизайна §9).
  • Визуальный фидбэк: outline выбранного/наведённого юнита, призрак-превью, зелёная/красная индикация валидности, отрисовка DeploymentZone в рантайме (сейчас только редакторные гизмо).

Разблокирует: игровую фазу расстановки; на неё встаёт надевание реликов. Ресёрч перед шагом: picking (математика vs collider), архитектура фазы под host-authoritative команды (§6 дизайна — на будущее, но шов заложить), overlay зон и подсветка Extended. За Максом: весь визуальный QA (feel перетаскивания, читаемость).

Шаг 5 — Loadout-экран: надевание релика на сосуд [интерактив]

Утверждённый дизайн (Макс, 2026-07-14). Полноэкранное меню «герой + инвентарь», UI Toolkit.

Содержание:

  • Триггер: дабл-клик по сосуду на арене (персонаж без релика или с реликом) → открывается полноэкранный loadout-экран.
  • Структура — разделы (табы): сейчас активен только «Релик». Будущие разделы (Предметы, Улучшения, смена AI) — видимые заглушки/disabled-табы, чтобы заложить структуру (реализация — потом).
  • Раздел «Релик»: грид карточек реликов. Карточка = анимированный спрайт релика (не иконка) + подпись-название. Наведение → карточка играет idle-анимацию + тултип (описание, теги релика из InfoTags/TagData, статы). Выбор (клик) → карточка играет анимацию атаки + звук (см. ниже).
  • Звук при выборе: при выборе релика играет звук — озвучка/voice-стингер релика. Заложить хук в FMOD-каталог (sfx-plan-2026-07); ассет — позже.
  • Иконки: поле _icon оставить в данных (может понадобиться в других местах), но в карточках loadout primary = спрайт, не иконка.
  • Кнопки: «Принять» — применяет выбор и закрывает экран; «Сохранить» — применяет выбор, но не закрывает (остаёшься в меню). Оба коммитят текущий выбор; разница только в закрытии.
  • Механика: релик = весь боевой кит сосуда (один релик на юнита). Назначение слоту → пересборка юнита через RuntimeUnitFactory.Create(relic, vessel). «Пустой» сосуд = базовый релик без особенностей (слот всегда заполнен). Релики могут повторяться между слотами.
  • MVVM сразу (как settings-меню), дизайн-система 640×360.

Разблокирует: сборку состава игроком; задел под предметы/улучшения/AI (табы); запоминание между боями. Ресёрч перед шагом: источник анимированного спрайта релика для карточки (переиспользовать боевой UnitVisual/спрайт-лист idle+attack?); FMOD-хук под звук выбора; MVVM-разводка loadout-экрана по образцу settings-меню (ui-toolkit-settings-menu). За Максом: визуальный QA, наполнение спрайтов/анимаций реликов, озвучка выбора.

Будущее (вне этого захода)

  • Запоминание последней расстановки + реликов между боями (озвучено как «в будущем»).
  • Загрузка арена-префаба через Addressables по ключу энкаунтера (сейчас FindFirstObjectByType).
  • Host-authoritative сетевые команды расстановки (кооп) — шов заложить в Шаге 4, реализация в сетевой фазе.

4. Граф зависимостей (кратко)

Шаг 1 (энкаунтер-данные + загрузчик)
   ├── Шаг 2 (враги-гоблины)  ──┐
   └── Шаг 3 (готовые бои) ◄─────┘
          └── Шаг 4 (расстановка, Free)
                 └── Шаг 5 (релики)

Шаги 1 и 2 частично параллелятся (данные vs контент), но 3 требует обоих. 4 требует 3 (загрузчик Free-ветки). 5 требует 4 (выбор юнита).


5. UI надевания реликов — утверждённый дизайн (Макс, 2026-07-14)

Полноэкранное меню «герой + инвентарь» на UI Toolkit, дизайн-система 640×360. Открывается дабл-кликом по сосуду на арене (с реликом или без).

  • Разделы (табы). Меню задумано как хаб экипировки: сейчас — «Релик»; на будущее заложить видимые заглушки под Предметы, Улучшения, смену AI (структура сейчас, реализация потом).
  • Раздел «Релик». Грид карточек: внешний вид релика + название. Наведение → тултип (описание, теги релика, статы). Клик → выбор.
  • Действия. «Принять» = применить + закрыть; «Сохранить» = применить, не закрывая. Оба коммитят текущий выбор.
  • Модель. Один релик = весь боевой кит сосуда. Релики могут повторяться между слотами.

Детали реализации — в Шаге 5. Ранее рассмотренные альтернативы (drag с полки, поповер, dock карточек) отклонены в пользу этого полноэкранного хаба — он масштабируется под будущие разделы (предметы/улучшения/AI), чего точечные варианты не давали.


6. Развилки

Закрыты (решения Макса, 2026-07-14)

  1. Порядок — data-first (энкаунтер-first), как в §2. ✅
  2. Имя «готового боя»BattlePresetData (энкаунтер + player-ростер + DeploymentMode). ✅
  3. Релик на юните — один релик = весь боевой кит сосуда. «Пустой» сосуд = базовый релик без особенностей (слот всегда заполнен). ✅
  4. UI-технологияUI Toolkit везде, включая dev-панели. Odin отклонён. ✅
  5. UI релика — полноэкранный loadout-хаб, дабл-клик по сосуду; карточки = анимированные спрайты (idle при наведении, атака + звук при выборе), не иконки (§5). ✅

Остаются (мелкие, с дефолтами — уточнить при реализации соответствующего шага)

  • Доступность loadout. Дефолт: только в фазе расстановки (в бою не переодеваешься).
  • Базовый релик — нужен ассет relic.* «пустого» дамми-кита (создать в Шаге 3, если нет).

7. Принципы этого захода

  • Data-first: состав боя становится данными до того, как строится интерактив поверх.
  • Переиспользуем готовое: DeploymentService.CanPlace (валидатор + тесты), ResetBattle/OnBattleReset (движок переключения), RuntimeUnitFactory (типо-агностичная сборка) — не переписываем.
  • Шов под кооп/сеть закладываем, реализацию откладываем (host-authoritative команды расстановки — §6 дизайна).
  • Каждый шаг = отдельная сессия + коммит после завершённой фазы. Ресёрч перед большими шагами (2, 4, 5).