Решили: Маскировка стала четырёхступенчатым состоянием (ConcealmentTier: Слабая / Средняя / Сильная / Инвиз) с радиусом обнаружения из SimTuningConfig (6 / 4 / 2; Инвиз расстоянием не снимается). Кто скрыт — считает ConcealmentSystem раз в тик до выбора целей; таргетинг судит по состоянию RuntimeUnit.IsHidden, а не по тегу эффекта. Прежняя «Скрытность» Убийцы стала потребителем маскировки: тот же бафф урона и скорости плюс ступень Инвиз.

Почему: до этого «невидим» означало «висит EffectTag.Stealth» — бинарно и без расстояния. Со ступенями тег перестал быть достаточным: он не отличает Слабую от Сильной и ничего не знает о том, кто где стоит. Правило видимости при этом осталось в одной точке — ProfileBrain.SelectBest, — и это редкая удача: выбор цели во всём бою один, поэтому фильтр нигде не размножен.

Три правила механики, каждое из ответов Макса:

  • скрытого не выбирают целью — «на момент автоатаки, я притаился перед нанесением удара»;
  • удар по скрытому гаснет — «если его пытаются ударить и он уходит в инвиз, это уклонение и должно работать как уклонение». Случай краевой: враг занёс удар, пока цель была видна;
  • своя атака или каст выдают — снятием по тегу Stealth в AutoAttackSystem и AbilitySystem. Правило снятия живёт там, где действие: иначе каждый новый источник маскировки пришлось бы учить ему заново.

Обнаружение командное и не залипающее. Личное дало бы картину, которую нельзя прочитать глазами (игрок не понимает, кто именно его видит), а залипающее превратило бы маскировку в «бесплатный первый ход и больше ничего» — Убийце некуда было бы возвращаться из боя.

Грабли:

  • Ступень считает система, а не компонент. Маскировок на юните может оказаться две (пассив плюс активка), и снятие одной обнулило бы поле, оставив вторую висеть без действия. Пересчёт по списку эффектов такой гонки не знает — и заодно делает «сильнейшая побеждает» одним правилом.
  • SimTuning не может знать про ConcealmentTier: Guildmaster.Core не ссылается на Guildmaster.Data. Снимок держит только числа, а какое из них чьё — решает бой (ConcealmentSystem.RadiusOf).
  • Бафф Убийцы обязан был объявить ступень явно. Как только фильтр перестал смотреть на тег, ассет StealthBuff без ConcealmentComponent сделал бы Убийцу обычным видимым юнитом — тихий регресс, который не поймал бы ни один тест механики, только слайс-тест кита.
  • Новый ассет — это лок-ключи и Sync Content Database. Пять эффектов уронили два теста контента; заодно вскрылся хвост прошлого захода — ResoluteStrikeCharge тоже был без ключа.

Владелец правды: ConcealmentSystem (кто скрыт и почему), ConcealmentComponent (ступень источника и гашение удара), RuntimeUnit.IsHidden, ProfileBrain.SelectBest (единственный фильтр выбора цели), тесты ConcealmentTests и ProfileBrainStealthTests.