Система оружия: архетип, облачение, голова

Статус: фазы 0–4 ВЫПОЛНЕНЫ 06.08.2026 одной сессией; фаза 5 (головы) ждёт арта, которого пока нет. План утверждён Максом в тот же день и вырос из аудита визуального слоя юнита.

Продолжает Planning - Attack Timing и пересматривает одну его отвергнутую альтернативу — см. §4.

Что изменилось в мире с момента написания плана (тело плана ниже НЕ переписано — оно след замысла): UnitVisual теперь AnimationArchetypeData и держит префаб вида, доли замаха и контактов; поля UnitData._viewPrefab и _windupShare сняты; заведены OutfitData (облачение) и объявленный вылет на UnitHeldItem. Инварианты закрыты тестами SimulationReadsNoClipTests, OutfitCoverageTests, DeclaredReachTests.

1. Зачем

Заказ Макса 06.08.2026, дословно:

«Учитывай, что в будущем будет другие виды оружия. И все должно удобно работать под разные скины оружия, под разную экипировку, типы оружий (а от типа - меняются наимации) и т.д.

Также изучи где у нас в логики просчетов используется визуал, меши спрайтов или что-то с этим связанное. Будто логичнее создать отдельные элементы (например, рекомендуемый размер оружия Х (например, меча)), который используется в логике и никак не зависит от конечной графики.»

Аудит ответил на вторую половину неожиданно: размеры спрайтов логику не трогают. Грепы по мешам, рамкам и рендерерам в Game, UI, Balance, Guild, Net, Core, DevTools — ноль; внутри Combat графика упомянута один раз, в комментарии. Радиус тела (Size × BodyRadiusPerSize), дальность (шесть ступеней AttackRange) и размеры VFX (доли роста H) уже декларативны.

Логика опирается на другое — на разметку анимационного клипа:

Что читаетсяГдеКто потребляет
clip.length, clip.frameRate, clip.events[].timeClipMarkersUnitVisual
число кадров, кадр контакта, позиции контактовUnitVisualAttackTiming
тики замаха hitFrame × durationTicks / frameCountAttackTimingAutoAttackSystem, MovementSystem
число Ударов в Атаке и момент каждогоAttackTiming.ContactTicksAutoAttackSystem, RuntimeUnit

Это доходит до CombatPositioning.CanLandWindup — то есть решение «идти или бить» зависит от того, где аниматор поставил маркер. Балансные прогоны наследуют то же ядро. Аниматор двигает маркер на два кадра — едет баланс, и об этом никто не узнаёт.

Декларативный выход уже написан и по коду первичен: UnitData._windupShare проверяется первой (AttackTiming.cs:144-147), покадровый расчёт — фолбэк. Но данные его не наполняют: из 48 юнитов долю задают 10 (сверено грепом по ассетам 06.08). Второго декларативного числа — позиций контактов серии — не существует вовсе.

Состояние ростера на день плана: 48 из 48 юнит-ассетов держат один UnitVisual, 47 из 48 — один префаб вида. Все боевые юниты — одно тело с мечом и щитом и один клип атаки; Attack2/Attack3 лежат в контроллере невыбранными, _deathClip указывает на Idle.anim.

2. Кто чем владеет: человек носит голову, Мементо несёт всё остальное

Канон Character Animation называет три оси переиспользования: скелет → набор клипов → набор спрайтов. Заказ 06.08 расставил по ним владельцев, и главное в нём — граница проходит по «Сосуд против Мементо», а не по «оружие против брони». Слова Макса:

«У нас архетип зависит от релика. Броня зависит от релика. Предметы в руках зависят от релика. Голова и части - от вессела. […] По итогу у нас есть вессел. Он надевает релик.»

ЧтоВладелец у герояВладелец у врага
Архетип — какие клипы играют и какие узлы есть в ригеМементоEnemyData
Облачение — броня, предметы в руках, позже головной уборМементоEnemyData
Голова и её частиСосуд (из BirthSeed)пул вида (SpeciesData) либо явная голова

Термин «облачение», а не «визуал». Слово занято: UnitVisual сегодня означает набор клипов, и второй «визуал» рядом с ним читался бы как то же самое. Облачение — всё, что надето.

Скин оружия — не отдельная сущность. Архетипы повторяются у разных Мементо («меч и щит» будет у многих), поэтому спрайты оружия обязаны отвязаться от архетипа. Но отдельного ассета им не нужно: они едут в облачении вместе с бронёй, потому что владелец у них один и тот же. Слова Макса:

«У нас могут повторяться архетипы анимаций у разных реликов, поэтому нам нужны скины на оружие. Их можно включить в принципе также как и броню в одно - в одно место - визуал релика»

Отсутствие щита — запись в облачении, а не отдельный архетип. Решение Макса 06.08: «лучше „отсутствие” щита сдеай как „скин” на этот тип оружия. Это даже более правильно. Просто да, скин, где щит без спрайта». Хореография «меча и щита» не меняется от того, есть ли щит в кадре, и плодить архетипы под каждое сочетание значило бы дублировать наборы клипов ради пустого спрайта.

Облачений на Мементо — одно, но полем под несколько. Сегодня у каждого ровно одно; косметический второй скин добавится новым ассетом и выбором поля, а не переделкой всех Мементо.

3. Пять слоёв наложения

Механизм один — список «часть рига → спрайт», где пустая запись означает „часть не показывать”. Порядок наложения жёсткий, источники разные:

СлойФормаУ герояУ врага
1состав частейPrefab Variantархетип Мементоархетип врага
2голова и её частиспрайтыиз BirthSeed Сосудапул вида либо явная голова
3тело: броняспрайтыоблачение Мементооблачение врага
4предметы в рукахспрайтыоблачение Мементооблачение врага
5головной убор (пока нет)спрайтыоблачение Мементооблачение врага

Почему состав частей — префаб, а спрайты — данные. Архетип меняет не картинку, а РИГ: у копья свой узел, своя калибровка нуля, свой RigProfile, своя длина. Это структурная работа в редакторе, и вариантов будет 3–5 — их немного, и они уже так собраны (BoneUnit_Spear от 02.08). Облачений же будет много, они комбинируются с архетипами и приходят как контент — плодить под каждое префаб-вариант значит вернуться к форк-копиям, которые расходятся молча (прецедент: боевой префаб оказался форком рига, и правки в бой не попадали).

Головной убор — слого Мементо поверх головы Сосуда (решение Макса 06.08). Шлем принадлежит снаряжению, а не человеку; отсюда следует, что слой 5 обязан уметь скрывать часть слоя 2 — шлем прячет волосы. Механизм тот же, что и у щита без спрайта: пустая запись гасит часть. Отдельной оси «головной убор» не заводим — его источником всё равно осталось бы Мементо.

Почему слои 2 и 3 разделены. Голова — якорь личности и живёт весь путь Сосуда; тело меняется вместе с Мементо, которое он надел. Это и есть канон «голова — якорь, тело носит Мементо» (ГД-журнал 2026-08-01/8).

Сцепка со стилем. Отдельный узел-рисунок (_Art) у каждой кости уже есть по конвенции рига, а адресный канал «данные → часть» уже работает для свечения (AbilityData.CastSourceCastGlowMask.Resolve → маска частей). Облачение пользуется той же адресацией, а не заводит вторую.

3.1. Голова: у героя из сида, у врага из пула вида

У Сосуда голова уже имеет законного владельца и заводить его не нужно. VesselState.BirthSeed существует, лежит в сейве, и его докстринг говорит прямо: «из него детерминированно разворачивается досье (мечта / характер / байка) и внешность. Привязка именно к рождению, а не к забегу […] Меняться не должен никогда». Голова выводится из сида — не хранится отдельным полем и не может разойтись между клиентами.

У врага два пути, и выбирает сам враг (решение Макса 06.08: «Зависит от врагов. Можно включить как „выбрать конкретную” (мб какой-то уник или элита), так и „общий пул” (в него не входят уник головы)»):

  • EnemyData называет голову явно — так выглядят уники, элита и боссы: их узнают в лицо;
  • EnemyData молчит — голова берётся из пула вида (SpeciesData: Бандиты, Гоблины, Звери, Големы) выбором через IRngService от сида боя. Толпа перестаёт быть клонами, а в кооперативе двое видят одних и тех же гоблинов.

Уникальные головы не исключаются из пула — они в него просто не входят. Пул перечисляет, а не запрещает: список общих голов лежит на виде, уникальная живёт отдельным ассетом и назначается явно. Так «уник случайно выпал рядовому» становится невозможным структурно, а не по флагу, который забудут проставить.

Пул голов ложится на существующую SpeciesData — она и есть «вид», её же используют подвиды («Северные гоблины»), и каждый подвид вправе объявить свой пул. Отдельную сущность под это заводить незачем.

4. Тайминг: замер становится офлайн-шагом

Меняется не то, ЧЕМ меряем, а КОГДА. Замер по графике честный — это единственный способ узнать, где кончается клинок и на каком кадре он касается. Но он должен происходить в редакторе, с явной записью результата в данные, а рантайм читает число.

Прецедент в проекте уже есть и работает: RigStride / LocomotionStrideMeter меряет подошву по графике офлайн и записывает темп числом в поле префаба (UnitView._runUnitsPerSecond); в рантайме логика меш не спрашивает.

Это пересмотр решения 01.06.2026. Planning - Attack Timing §Альтернативы отверг ровно этот путь: «оставить в Presentation + запекать windup в RelicData эдитор-кнопкой при изменении кадра. Работает, детерминизм цел, но добавляет шаг синхронизации и риск „забыл нажать”».

Что изменилось с тех пор, по пунктам:

  1. Тогда данные и клип были одним ассетом. Дизайнер авторил _attackHitFrames кликами по полоске кадров в том же SO визуала — синхронизировать было нечего. Покадровые виды удалены 04.08.2026; сегодня разметка живёт в AnimationClip, отдельном ассете, который правит другой инструмент в другом окне. Расхождение стало возможным именно потому, что источник разъехался.
  2. Тогда клип был свой у каждого юнита. Сегодня один клип у 48 юнитов: правка маркера двигает тайминг всему ростеру разом. Цена ошибки выросла на два порядка.
  3. Риск «забыл нажать» лечится гейтом, а не дисциплиной. Тест сверяет объявленное с замеренным и падает при расхождении сверх порога — так же, как GameDataPathTests держит кодовые имена, а FeelToggleCoverageTests — перепись тумблеров. В 2026-06 такой механизм не предлагался; сейчас он в проекте штатный.

Побочная выгода, которой тогда тоже не было: AnimationClip — движковый объект, и сегодня из-за него тайминг недоступен быстрым headless-тестам, а EffectTestSupport вынужден фабриковать клип с событием. Декларативные доли снимают это.

Что перечисляет архетип (на КАЖДУЮ атаку, а не одной парой чисел): доля замаха, позиции контактов серии, объявленный вылет в долях H. Набором — потому что Attack2/Attack3 уже лежат в контроллере невыбранными, и как только их начнут выбирать, у каждой атаки будет свой тайминг. Ретрофитить дороже, чем заложить списком сразу.

5. Сущности данных

WeaponArchetypeData                     // ассет на архетип, их 3-5
  Id                    weapon.sword_shield / weapon.spear / …
  ViewPrefab            префаб вида (Prefab Variant с нужными узлами)
  Clips                 набор клипов (сегодняшний UnitVisual)
  Attacks[]             на каждую атаку:
      WindupShare       доля замаха
      ContactShares[]   позиции контактов серии
  Reach                 объявленный вылет, доли H (база архетипа)

OutfitData                              // облачение: что надето. Их много
  Archetype             под какой архетип собрано
  Parts[]               часть рига → спрайт (пусто = не показывать)
                        сюда же уезжают броня, оружие, щит, позже головной убор
  ReachOverride?        если оружие облачения заметно короче/длиннее базы

HeadData                                // голова и её части
  Parts[]               череп, лицо, волосы — той же адресацией

SpeciesData                             // существует; вид врага
  + Heads[]             пул ОБЩИХ голов вида. Уникальные сюда не входят

UnitData (база RelicData / EnemyData)
  Archetype             вместо сегодняшних _visual + _viewPrefab
  Outfit                облачение по умолчанию (поле под несколько — позже)

EnemyData
  + Head?               явная голова: уник, элита, босс. Пусто = из пула вида

VesselState                             // существует; голова НЕ хранится
  BirthSeed             из него разворачивается внешность Сосуда

6. Фазы

ФазаЧтоЗакрываетГотово, когда
0СДЕЛАНО 06.08.2026 — чистка легаси и выправление нейминга«беспорядок, из-за которого путаемся»дерево не содержит того, чем не играют; имена не врут
1СДЕЛАНО 06.08.2026 — облачение как данные, префаб вида переехал в архетип, два облачениязаказ «щиты только у носителя»Защитник со щитом, остальные без; гейт OutfitCoverageTests зелёный
2СДЕЛАНО 06.08.2026 — доля замаха и контакты серии объявлены в архетипе, покадровый путь удалёнглавное нарушение аудита37 юнитов бит в бит, 10 сдвинуты решением Макса; гейт SimulationReadsNoClipTests зелёный
3СДЕЛАНО 06.08.2026 — объявленный вылет на UnitHeldItem, кнопка замера, гизмо, гейт«рекомендуемый размер оружия»длину клинка видно жёлтой линией рядом с зелёной «как рисует арт»
4СДЕЛАНО 06.08.2026 — область корпуса со смещением к атакующему, детерминированный сидзаказ 06.08восемь ударов не бьют в один пиксель
5головы: пул на виде, явная у уников, вывод внешности Сосуда из BirthSeedтолпа перестаёт быть клонамиЖДЁТ АРТА: нарисованных голов нет, механизм проверять не на чем

Фаза 4 ни от чего не зависит и может идти первой. Фаза 5 стоит последней намеренно: она требует нарисованных голов, которых пока нет, и до них весь механизм проверять не на чем.

Цена фазы 2, обязательная к соблюдению: доли заполняются замером из текущих клипов, а не «на глаз». Иначе тайминги сорока восьми юнитов сдвинутся молча и поедет баланс.

Образец для фазы 3зона расстановки арены: ArenaLayoutAuthoring держит геометрию с гизмо и печёт неизменяемый снапшот, а в комментарии стоит формула, которая и нужна оружию: «геометрия ведёт, арт следует». Тянется хэндлами (BoxBoundsHandle, авто-Undo, форс-перерисовка сцены при правке чисел — иначе гизмо отстаёт).

6.1. Фаза 0 в деталях: чистка и нейминг — ВЫПОЛНЕНО 06.08.2026

Сделано пятью коммитами: 0d19a17f4 (удаление легаси), 7deee9368 (дев-дуэлянт и имена контроллеров), 1d43974ef (покадровое тело), 31397cb85 (класс архетипа), 1a9f428fe (мусор в паках). Итог: −27 тысяч строк, ноль красных тестов по своим областям.

Раскладка папок из фазы вынута — решение Макса 06.08: «дам потом отдельную таску на проверку папок и изучу вопрос о них подробнее после нашего основного „блюда”». Переименована только та папка, чьё ИМЯ врало (VisualsAnimationArchetypes); сведение клипов в один адрес и остальное дерево — за отдельным заходом. Список находок сохранён ниже.

Что вскрылось при выполнении и стоило отдельной записи журнала (Renaming A Field Breaks Whoever Asks For It By String): переименование поля ломает всех, кто просит его СТРОКОЙ. Компиляция прошла с первого раза, а боевые тесты дали 123 падения из 536 — тестовый хелпер ставил поле по строке. Вторая находка страшнее: RelicCardVisualRig брал удалённое UnitView._sprite рефлексией, и тест бы промолчал — карточка тихо рисовала бы случайную часть тела.

Согласие Макса 06.08.2026, дословно: «все помимо BoneUnit_Storybook - это ЛЕГАСИ. Остальное можно удалять, даю свое согласие. (Будь то префабы без бон анимаций (и код для них) или тот же Spear или Man128. Это все стоит удалить, чтобы не путаться». Плюс: «разберись еще где и что лежит (архитектура в папках). Там тоже у нас беспорядок».

Часть работы уже сделана

Покадровых префабов в дереве нет: 16 штук из Prefabs/Units/legacy/ ушли коммитом 969f3c2d0, UnitView_Human128 («Man128») — коммитом 1c4adca48 от 05.08. Под Prefabs/Units/ осталось два файла. Хвосты — только генерировавший их код и текстовые упоминания в append-only журналах.

Удаляем: безопасно, ноль ссылок

ЧтоПочему безопасно
Prefabs/Bones/BoneUnit_Spear.prefabдержится только собственным риг-профилем
Prefabs/Bones/BoneUnit_Spear_RigProfile.assetноль ссылок; вдобавок протух — пути суставов старой конвенции, отменённой 04.08
Prefabs/Bones/Weapons/Spear.prefabединственный держатель — префаб копья
Prefabs/Bones/Spear/CombatIdle.animрешение Макса: «Удалить всё, включая клип»
Prefabs/Bones/Arm.prefab, Leg.prefabноль ссылок с 28.07, заготовки сборки
ScriptableObjects/Visuals/ — 11 UnitVisual + 11 .overrideController + 58 .animноль ссылок из контента; держались своими же генераторами
Scripts/EditorTools/ContentHub/AuditUnitAnimations.csаудитит только покадровые паки
Scripts/EditorTools/ContentHub/BuildUnitViewPrefabs.csзаряженное ружьё: генерирует несуществующие префабы И перезаписывает _viewPrefab живым Relic/Enemy-ассетам. Один клик по пункту меню снимает вид 47 юнитам

Удаляем, расшив зависимость

ЧтоЧто расшить
Prefabs/Units/UnitView_BoneStandart.prefabдержит BoneDevDuelist.asset
ScriptableObjects/DevTools/BoneDevDuelist.assetзапись в ContentDatabase; команда gm bones (GuildmasterCommands); лок-ключи enemy.bone_dev.* — снимать только через API локализации
Prefabs/Bones/BoneUnit_Combat.controlleroverride на дев-префабе; BoneUnitControllerBuilder пересоздаст его при следующей перестройке; BoneUnitLayerStackTests упадёт на null
Scripts/Presentation/Body/SpriteBodyVisual.cs, UnitView._spriteнедостижимая ветка UnitView, докстринг IUnitBodyVisual, UnitPartRegistry.ForSingleSprite, тест
ClipSpriteFrames.cs, ContentHubWindow.Visual.csпревью юнита в ContentHub исчезает. Решение Макса: «Удалить всё, превью переписать потом» — то есть потеря осознанная, а не молчаливая

Дев-дуэлянт уходит потому, что он копия. BoneDevDuelist и BoneStorybookDevDuelist отличаются ровно тремя строками — имя, id, префаб вида; статы и класс идентичны байт в байт. Пара имела смысл, пока видов было два и их сравнивали рядом; сейчас второй показывает то, чем не играют. Команда gm storybook делает то же на живом виде.

Трогать нельзя

Prefabs/UnitView.prefab (база обоих вариантов + ссылка из боевой сцены), BoneUnit_Standart.prefab (база варианта BoneUnit_Storybook — проверено по guid в m_SourcePrefab), его контроллер и аватар (наследуются живым видом), Prefabs/Bones/*.anim и Mask_*.mask, ScriptableObjects/Visuals/BoneStandart.asset (единственный живой UnitVisual, на него смотрят все 48 юнитов), UnitBase.controller.

Нейминг: имена, которые врут

СейчасСтанетЧем врёт
UnitVisual (класс)AnimationArchetypeDataдержит клипы, а не визуал; единственный класс-определение без суффикса Data
ScriptableObjects/Visuals/ScriptableObjects/AnimationArchetypes/71 файл из 82 в ней — не ScriptableObject вовсе
Visuals/BoneStandart.assetSwordShield.asset«стандартный» перестанет быть стандартным на третьем архетипе
BoneUnit_Standart.* (префаб, аватар, риг-профиль)по архетипу, в ряд с BoneUnit_Spearопечатка плюс смысл: это риг «меч и щит», а не «стандартный»
BoneUnit_Standart.controllerчестное боевое имяиграет в бою у всех 47 юнитов, хотя по имени числится лабораторным
BoneUnit_Combat.controller(удаляется вместе с дев-префабом)по имени боевой, а стоит только на дев-дуэлянте
MAT_Vfx_HitForm_Add, MAT_Vfx_SwingArc_Addсуффикс по фактическому блендингу_Add остался от аддитива, снятого 05.08

Путаница контроллеров — главная ловушка фазы. Удалять «лабораторный» по имени нельзя: сломается живой бой, а не стенд. Переименование обоих идёт ОДНИМ шагом с удалением дев-префаба, иначе между шагами дерево остаётся в состоянии, где имя и роль разошлись сильнее прежнего.

Раскладка: только то, что трогает система оружия

Решение Макса — «сначала то, что трогает система оружия»; остальное дерево отдельным заходом.

Клипы живут по трём адресам, и предписанный документом пуст. ScriptableObjects/Visuals/ (58), Prefabs/Bones/ (11), Art/Animations/ (0, только .gitkeep) — при том что adding-assets §2 велит класть клипы именно в третью. Сводим в одну, с подпапкой на архетип; док правится в том же заходе, иначе у факта снова станет два владельца.

Мусор распаковки и дубли паков (решение Макса — «только мусор и дубли»): __MACOSX 19 файлов, .DS_Store 3, gif-превью 98, плюс три пары побайтово идентичных паков. Сам арт остаётся в git — правило «мегабайты дешевле работы» в силе.

Не входит в фазу 0, но найдено и записано, чтобы не искать заново: материалы в трёх папках (Art/Materials, Art/Materials/Vfx, Art/Shaders); ScriptableObjects/Configs/ как Misc под приличным именем (12 ассетов 11 типов, ни один не покрыт ContentPaths); контракты MessagePipe по пяти адресам; дев-экраны в двух папках; Scripts/MiniGames — сборка без единого .cs; Scripts/Net/_Parked/ — пустая папка; ScriptableObjects/Vessels/ — объявлена в коде, пуста на диске.

Два битых ассета: QC_KeyConfig.asset ссылается на удалённый QFSW, Assets/DefaultNetworkPrefabs.asset — на удалённый NGO; оба в git. Личная сцена Макса MaxSceneForTests.unity закоммичена: правило в .gitignore записано как *Scene For Tests.unity, с пробелами, и этого имени не ловит.

Раскладку не проверяет ни один тест — при том что корень редакторного меню, невидимые символы и границы сборок тестами закрыты. Владельцев правды про папки три (док adding-assets, код ContentPaths, Assets/_Project/UI/AGENTS.md), и они друг с другом расходятся. Пока конвенция не записана решением и не закрыта тестом, любая раскладка разъедется снова.

7. Инварианты (каждый закрывается тестом)

  1. Симуляция не читает AnimationClip. После фазы 2 — ни одной ссылки на клип из Guildmaster.Combat и Guildmaster.Data, кроме офлайн-замера.
  2. Объявленное сходится с замеренным. Гейт сверяет Reach архетипа/облачения с длиной меша ReachPart и падает при расхождении сверх порога. Он же ловит «забыл нажать замер».
  3. Облачение называет только существующие части. Запись про часть, которой нет в риге архетипа, — красный тест, а не тихо проигнорированная строка.
  4. Весь показной рандом идёт из IRngService — и разброс точки удара, и выбор головы из пула. Требование канона: Random разведёт клиентов в кооперативе, и двое увидят разных гоблинов.
  5. Уникальная голова не попадает в пул вида. Пул перечисляет общие головы, а не исключает уникальные, — тест следит, что ни одна голова не значится и там, и в EnemyData явно.
  6. Внешность Сосуда выводится из BirthSeed и никогда не хранится полем. Второе поле стало бы вторым владельцем, способным разойтись с сидом при переименовании или переносе сейва.
  7. Кончик оружия считается одной реализацией. Сегодня их три с разными опорными точками (рантайм UnitPartGeometry.TryGetTip — от нуля рендерера, офлайн RigProfile.MeasureAxis — от точки хвата, RigSweep.SpriteQuad — самая длинная пара вершин). Свести к одной.

8. Что остаётся открытым

  • Размер области попадания числом не задан — канон говорит «прямоугольник корпуса», конкретика за фазой 4.
  • Второй клинок в левой руке упирается в HeldKind, где левая — это Shield. Развилка описана в docs/weapon-archetype-animations-progress.md и копья с посохом не касается.
  • Поза левой руки при скрытом щите. Клип ставит её в хват; без спрайта рука держит пустоту. Решение Макса 06.08: «Все ок, это временный вариант» — смотрим в игре, правим при необходимости.
  • Головных уборов пока нет. Слой 5 объявлен и его источник назван (Мементо), но ни спрайтов, ни правила «что именно шлем прячет» ещё не существует. Заводить механизм скрытия волос — вместе с первым убором, не раньше.
  • Как именно внешность разворачивается из сида — сколько частей у головы, какие оси гуляют (череп, лицо, волосы, цвет), общий ли пул у всех Сосудов. Это работа фазы 5 и она требует арта.
  • Броня как экипировка — слой 3 заложен, наполнение отложено до появления самой экипировки.