Мод доступности для многопользовательской коллекционной карточной игры MTG Arena получил несколько обновлений.
v1.3
Вкладка PlayBlade / События:
- Вкладка «События» теперь представляет собой правильную иерархию с детализацией: Вкладки → Фильтры-чипсы → Плитки событий, аналогично тому, как другие вкладки устроены по схеме Вкладки → Папки → Колоды. Раньше чипсы фильтров («Alle», «In Arbeit», «Neu», «Limited», «Constructed» и все привязанные к форматам) смешивались с плитками событий в единый плоский список из 23 элементов, отсортированный по позиции на экране, поэтому они оказывались между текущими событиями и остальными — это сбивало с толку и приводило к ложным активациям (чипс запускал переход к списку папок, которого не существовало, и навигатор зависал). Теперь чипсы фильтров образуют собственную группу между вкладками и плитками событий. Enter на вкладке «События» помещает фокус на строку чипсов, Enter на чипсе погружает в отфильтрованный список событий, Backspace на каждом уровне поднимается на шаг назад, а восстановление позиции запоминает, с какого чипса и вкладки пришёл пользователь. Для определения чипсов используется штатная ссылка
EventBladeContentView._eventTileContainer: всё, что внутри этого контейнера, считается плиткой, всё остальное внутри панели событий — чипсом. - Активация плитки события больше не пытается отправить навигатор в несуществующий список папок. Код, который для каждой активации
PlayBladeContentвызывалRequestFoldersEntry(), теперь пропускает этот шаг для плиток событий (обнаруживаемых через ту же проверку на вхождение в_eventTileContainer) и позволяет системе панелей естественным образом обработать переход на страницу события.
Дуэль:
- Озвучивание информации о карте теперь показывает данные о выбранном / названном объекте. Карты, которые запоминают тип существа (Cavern of Souls, Engineered Plague), цвет (Iona, Shield of Emeria) или имя карты (Pithing Needle, Meddling Mage, Cabal Therapy), отображают этот выбор в своём внутриигровом тексте правил для зрячих игроков, а мод его терял. Теперь стрелка вниз после текста правил зачитывает «Выбрано: Wizard» и «Названа карта: Cabal Therapy», получая данные из
MtgCardInstance.LinkedInfoTextиLinkedInfoTitleLocIdsчерез тот же путьIGreLocProvider, который используют штатныеLinkedInfoTextParser/LinkedInfoTitleTextParser, так что результирующие строки совпадают с тем, что отрисовано на карте. Добавлено @LordLuceus (PR #99). - Новая горячая клавиша N озвучивает, что в данный момент разрешается на стеке — самый верхний элемент стека с его текстом правил, в том же формате, что мод использует при появлении нового объекта в стеке. Подсказки процесса во время длинных комбинаций («Подтвердить 0», «выберите цель», «вы можете сбросить карту») часто не дают понять, к какому триггеру они относятся: автоматическое объявление стека срабатывает лишь раз при обновлении зоны, поэтому запрос, появляющийся на несколько тактов позже, не имеет голосовой привязки. N закрывает этот пробел по требованию. Если стек пуст, произносится «Ничего в стеке». Добавлено @LordLuceus (PR #102).
Исправления ошибок:
- Было сломано отслеживание зон при Слежке (Surveil): список
_bottomCardsмода всегда оставался пустым, поэтому каждая карта читалась как «keep» (оставить), независимо от того, куда игрок её переместил, объявления по Tab лгали о выборе, а Tab → Enter на «сброшенной» карте повторял попытку в том же направлении, вместо того чтобы переключить её обратно в библиотеку (не было способа снять выбор, кроме как отменить весь браузер). Коренная причина:RefreshSurveilCardListsобходилBrowserCardHolder_ViewDismissдля нижней зоны, которого у Surveil нет — Surveil хранит обе зоны в одномcardHolderсо спискамиlibraryGroup/graveyardGroup, отслеживающими разделение. Теперь обновление читает эти списки напрямую через публичные геттерыGetLibraryCards()/GetGraveyardCards()изSurveilBrowser, как это делает сама игра при компоновке карт. В качестве дополнительной меры отслеживаемые списки также обновляются сразу же после успешного перемещения по Enter, так чтоDetectCardZoneкорректен в течение 0,2-секундного окна до срабатывания сверочной корутины (это также закрывает аналогичный зазор для Scry, где списки были корректны после задержки, но устаревали внутри неё). Добавлено @LordLuceus (PR #100). - Карты с нулевой стоимостью теперь озвучиваются корректно. PR #91 подключил текущую стоимость разыгрывания действия, чтобы учитывались эффекты снижения стоимости (Warden of Evos Isle, Goblin Electromancer и т.д.), но пустой
Action.ManaCostнулевой длины воспринимался как «ещё не вычислено» и пропускался — в итоге происходил возврат кPrintedCastingCost. Результат: карта, чья стоимость снижена до 0, всё равно читалась с напечатанной стоимостью, так что «бесплатное» разыгрывание объявлялось как требующее одной маны, которую игрок на самом деле никогда не заплатит. Теперь пустой список мана-стоимости считается настоящим сигналом нулевой стоимости (снижатели стоимости довели заклинание до нуля, либо это Suspend/Cascade разыгрывание из изгнания, либо это напечатанный 0-стоимостный артефакт вроде Memnite);ParseManaQuantityArrayпреобразует пустой массив в локализованноеManaFree(«Бесплатно» в русской локализации), обрывая цепочку возврата. Блок мана-стоимости теперь читается и для напечатанных карт с нулевой стоимостью (Memnite, Mox Amber, Ornithopter), а не замалчивается. Добавлено @LordLuceus (PR #101). - Браузер Слежки больше не объявляет «перемещено в низ библиотеки» при нажатии Enter на карте. Surveil сбрасывает выбранные карты на кладбище, а не под низ библиотеки, но
GetZoneName/GetShortZoneNameиспользовали фразу из Scry. Теперь нижняя зона читается как «Graveyard» (кладбище) для Surveil (объявления становятся «X перемещён на кладбище», «Кладбище: пусто» и т.д.); Scry, Read Ahead и Split сохраняют свои формулировки. Добавлено @LordLuceus (PR #98). - Shift+Enter на карте в конструкторе колоды при активном фильтре «Крафт» больше не тратит дикую карту автоматически.
TryOpenCardViewerForFocusedCardчерез рефлексию вызывалDeckBuilderActionsHandler.OpenCardViewer, не устанавливаяInputManager.BlockNextEnterKeyUp, поэтому последнее событие Return KeyUp попадало вPopupManager.HandleKeyUp→CardViewerController.OnEnter()→OnCraftClicked(), инициируя крафт без повторного подтверждения. Обычный Enter и активация правой кнопкой мыши уже ставили защиту черезCardTileActivator/UIActivator; теперь путь через Shift+Enter (через рефлексию) тоже её устанавливает, аналогично исправлению, применённому для всплывающего окна приглашения в испытание в версии v0.9.4. - Земли больше не объявляют «Мана-стоимость: Бесплатно» после исправления для карт с нулевой стоимостью в v1.3. Земли не имеют стоимости разыгрывания, поэтому пустой массив всегда превращал их в «Бесплатно» — бесполезный шум, добавлявший лишнее нажатие стрелки вниз перед чтением строки типа и текста правил. Теперь подавляется, если
CardTypesсодержитLand; Memnite, Mox Amber и сниженные до 0 заклинания по-прежнему объявляются как «Бесплатно», потому что их действительно можно разыграть. Добавлено @LordLuceus (PR #103).
v1.2
Дуэль:
- Эмоции, отключение звука и взаимодействие с питомцем во время дуэли теперь работают из зоны информации об игроке (клавиша V). Enter на себе открывает колесо экипированных эмоций — читается напрямую из
EmoteOptionsController._equippedEmoteOptionsи отправляется черезUIMessageHandler.TrySendEmote, так что колесо не обязано быть визуально открыто. Enter на противнике переключает отключение звука для данного дуэля черезOpponentDialogController.UpdateIsMuted, зеркально повторяя иконку отключения звука. Shift+Enter на себе открывает меню взаимодействия с питомцем (Погладить, Похлопать или Грудь/Лапа/Нога/Голова в зависимости от питомца), направляемое через активныйAccessoryController. Входящие эмоции противника объявляются через коллбэкUIMessageHandler.EmoteRecievedCallback, локализованный черезEmoteUtils.GetFullLocKey, и фильтруются в соответствии с текущим состоянием отключения звука. Объявления эмоций противника используют приоритет High, чтобы их не заглушали чтения карт с приоритетом Immediate, когда вы перемещаетесь по картам. - Меню действий питомца скрывает действия, чей префабный UnityEvent не имеет постоянных слушателей. Некоторые питомцы (например, питомец мастерства ONE_Skitterling) привязывают события наведения к ничему — показ «Погладить» привёл бы к объявлению «Streicheln ausgelöst» без какого-либо игрового эффекта. Теперь меню показывает только действия, действительно запрограммированные что-то делать (триггер аниматора, звуковое событие и т.д.); питомец без реальных действий объявляется как «У этого питомца нет взаимодействий», чтобы не вводить пользователя в заблуждение фантомными опциями.
- Ctrl+F1 внутри зоны информации об игроке теперь показывает контекстную подсказку (Left/Right переключают между вами и противником, Up/Down листают значения, Enter для эмоции / отключения звука, Shift+Enter для питомца, Backspace для выхода) вместо полного списка клавиш управления дуэлью.
Косметика:
- Теперь полностью доступен выбор косметики для каждой колоды (аватар, питомец, рубашка). Активация кнопки названия колоды открывает всплывающее окно деталей колоды; плитки озвучивают текущий выбор («Аватар: Стандартный, нажмите Enter для смены»), а Enter открывает соответствующий селектор. Всплывающие окна питомцев и рубашек накладываются поверх — питомцы, рубашки и бюсты аватаров читаются с их локализованными именами плюс статус (выбрано, по умолчанию, имеется, заблокировано) вместо неподписанных хитбоксов, с которыми раньше сталкивалась программа чтения с экрана. Backspace закрывает активный селектор и возвращает к плиткам деталей колоды.
- Селектор питомца в профиле теперь действительно применяет выбор при нажатии Enter.
PetPopUpV2использует двухэтапный процесс (предпросмотр, затем явное подтверждение); теперь мод вызываетOnConfirmпосле клика предпросмотра, так что выбранный питомец сохраняется, а не сбрасывается при закрытии всплывающего окна. - Селектор аватара работает как встроенный, а не как отдельное всплывающее окно. Активация бюста аватара теперь запускает бесшумное обновление, чтобы текст названия и биографии (TMP_Text) справа обновлялся для каждого предпросмотра — стрелка вверх читает новую биографию, не покидая селектор.
- Метки косметических значений обновляются после закрытия суб-селектора, так что плитка деталей колоды отражает только что выбранный аватар / питомца / рубашку.
- Под капотом внедрена новая инфраструктура режима всплывающих окон: поддержка вложенных окон в
BaseNavigatorпозволяет любому суб-окну, открывшемуся поверх существующего, корректно навигироваться, а затем возвращаться к родительскому окну с обновлёнными метками. Это пригодится для любых будущих сценариев с вложенными окнами, а не только для косметики. - Блоки информации о карте в конструкторе колоды (стрелка вниз) заканчиваются строкой «Стиль» (например, «Стиль: Showcase Etched»), считываемой напрямую с каждой плитки — как на стороне колоды, так и в пуле коллекции. Коды рубашек читаются для каждой строки из собственного
MtgCardInstance.SkinCode(плитки колоды) или_lastDisplayInfo.Skin(плитки пула), а не из словаря рубашек уровня колоды, поэтому две строки одной карты с разными рубашками озвучиваются по-разному. Когда стиль не переопределён, строка откатывается к идентификатору печати (название выпуска + номер коллекционера, например, «Стиль: Dominaria 26»), так что две строки одной карты из разных печатей — с разнымиGrpId— тоже можно различить на слух. - Новая комбинация
Shift+Enterна сфокусированной карте в конструкторе колоды открывает всплывающее окно просмотра карты, аналогично правому клику у зрячих игроков. Работает на картах коллекции, записях списка колоды, сайтборда, командиров и картах только для чтения. Само всплывающее окно крафта теперь начинается с заголовка «Стиль:», так что пользователь сразу получает подтверждение, на какую именно версию печати он тратит дикие карты (разные версии одной карты хранятся в инвентаре как отдельныеGrpId; окно по своей сути одностилевое). - Новая комбинация
Ctrl+Enterна сфокусированной карте пула раскрывает название в ряд смежных плиток — по одной на каждый доступный вариант оформления или печати. Под капотом вызывается игровое раскрытие предпочитаемой печати через шеврон (PagesMetaCardView.ExpandClicked()→PreferredPrintingState.ExpandCard/CollapseCard), то есть то же разворачивание, которое получает зрячий игрок при клике по ленте плитки. Повторное нажатие сворачивает. Внутри активного развёрнутого списка каждая плитка варианта сразу озвучивает своё отличие (например, «Sagenumwobener Durchgang, Showcase Etched» против «Sagenumwobener Durchgang, Avatar TFTUR Extra 57»), не повторяя голое имя для каждого элемента; объявление читает_lastDisplayInfo.ExpandedStyle(Expanded_First/Mid/LastпротивSolo/Stacked), чтобы обычная навигация оставалась тихой. Одиночные карты (без альтернатив) объявляют «Нет доступных альтернативных стилей» вместо вводящей в заблуждение реплики о разворачивании/сворачивании.Shift+Enterна выбранном варианте затем открывает всплывающее окно крафта именно для этой (печати, рубашки). В справке F1 появился новый раздел «Горячие клавиши карт конструктора колод», охватывающий обе комбинации; в подсказкеCtrl+F1конструктора они также упоминаются.
Исправления ошибок:
- Универсальная мана в стоимости карт теперь озвучивается как «универсальная», а не «бесцветная» (например,
{5}{U}{B}→ «5 универсальной, синяя, чёрная»). «Бесцветная» имеет особый смысл в Magic — символ{C}и цветовой идентификатор Colorless по-прежнему читаются как «бесцветная». Добавлено @LordLuceus (PR #90). - Повторяющиеся символы маны внутри одной фигурной скобки больше не теряют токены. Игра кодирует пары типа
{B}{B}как{oBoB}, а регулярное выражение поглощало ведущуюoперед разбором — так что строка Spree+ {B}{B} —читалась как+ Black —. Теперь читается+ Black, Black —. Добавлено @LordLuceus (PR #90). - Гибридные альтернативные стоимости, такие как Evoke, больше не пропускаются. Игра кодирует
{U/B}{U/B}как{o(U/B)o(U/B)}, что парсер вообще не мог разобрать (скобки не распознавались) — поэтому строка Deceit «Evoke {U/B}{U/B}» читалась просто как «Evoke». Теперь читается «Evoke Blue or Black, Blue or Black». Исправление парсера для формы в скобках добавлено @LordLuceus (PR #90); впоследствии расширено на голый текст и параметризованные последовательности hanger для полного соответствия. - Магазин / офлайн: открытие магазина при отсутствии соединения больше не зачитывает пустое модальное окно Welcome Bundle («000000 Edelsteine, $X.XX, …»). Модальное подтверждение магазина теперь игнорируется, пока его кнопки валют содержат замещающие значения, поэтому реальное всплывающее окно SystemMessage «Store-Fehler» / «Не удалось получить предметы» объявляется и доступно для навигации с клавиатуры.
- Всплывающие окна SystemMessageView (офлайн / ошибка / требуется перезапуск) теперь имеют приоритет над обычными модальными подтверждениями, открывшимися в том же кадре, так что системное сообщение становится активной панелью, а не маскируется.
- Всплывающее окно награды за бустер больше не озвучивает название предыдущего выпуска. Игровой объект наград живёт на Canvas — Screenspace Popups и остаётся активным между покупками, поэтому кэш названия бустера и флаг
_revealingWasSeenпереживали разные всплывающие окна — второй бустер повторно использовал название первого, а 2-секундный тайм-аут резервного режима ненадолго активировал навигатор после каждого получения. Состояние для каждого окна теперь сбрасывается при переходе True→False, так что каждое новое получение чисто извлекает название набора бустеров. - Четыре строки из версии 1.1, связанные с наложением на поле боя (
StackSelect_Unavailable,SettingBattlefieldStacking+ Desc,HelpCtrlEnterStack), переведены на es, fr, it, ja, ko, pl, pt-BR, ru, zh-CN, zh-TW — ранее были только на английском. - Ctrl+F1 в дуэли теперь читает подсказку для активного подсостояния (Выбор X, спиннер, выбор цвета маны, назначение блокирующих, браузер), а не всегда выдаёт полный список клавиш дуэли.
- Предупреждение о пропуске фазы теперь также срабатывает во время шага «Назначение блокирующих»: нажатие Space для подтверждения «нет блокирующих», пока у вас ещё есть развёрнутые существа и ничего не назначено, один раз предупреждает и требует второго нажатия для подтверждения. Предупреждение действует только в ход оппонента — именно в этот момент пользователь является защищающимся игроком и может назначать блокирующих — так что атака в ваш собственный ход больше не вызывает ложного срабатывания защиты на шаге блокирования оппонента.
- Объявления пула маны теперь отражают реальное количество, когда одна способность даёт несколько единиц маны одного цвета. Игра упаковывает одинаковую ману в одну запись
MtgManaсCount=N(Rofellos = одна запись сCount=3); парсер прибавлял по 1 на запись, так что тап Rofellos объявлялся как «1 зелёная» вместо «3 зелёных». Теперь суммируетсяMtgMana.Countпо цветам. - Запросы выбора цели для опциональных триггеров (по типу Tinybones «вы можете разыграть выбранную карту») больше не заточают игрока. Браузер представлял каркас
SelectCardsMultiZoneсAllowCancel.Noи словарём провайдера, содержащим толькоDoneButton; выбор единственной допустимой цели и последующая отмена разыгрывания зацикливались обратно в браузер с залипшим выбором, который автоматически отправлялся снова, без возможности выхода через существующий путь CancelButton. Теперь Backspace зеркалит защиту подтверждения через Space: первое нажатие предупреждает, второе нажатие снимает выделение черезSimulatePointerClickдля каждой карты и вызываетOnButtonCallback("DoneButton"), который игра переключает на вариант FailToFind, когда счётчик падает до 0. Две защиты взаимно сбрасывают свои предупредительные биты при первом нажатии, чтобы смена намерения с Space на Backspace не могла оставить заряженное состояние при последующем нажатии той же клавиши. - Браузеры
SelectCardsMultiZoneсAllowCancel.Noи отключённой кнопкойDoneButton(счётчик ниже минимума, нет вкладки зоны для переключения) больше не заточают игрока в цикле Exit→Re-enter.ClickConfirmButtonбезусловно ставил_pendingRescan = trueв самом начале; затем каждый путь провайдера/рабочего процесса не кликал никуда, но повторное сканирование всё равно срабатывало на следующемUpdate— заново объявляло вход в браузер и переносило фокус обратно на карту 1, заглушая сообщение о неудаче. Теперь путь без действий очищает_pendingRescan(не было клика, нечего отслеживать), а прежнее общее сообщение «No confirm button found» заменено на уже переведённое «No target selected», когда словарь провайдера сообщает, чтоDoneButtonотключена — так игрок слышит причину, связанную с игровым состоянием, а не строку ошибки мода. - Объявления стоимости карт теперь отражают активные снижения стоимости, а не всегда читают напечатанную стоимость. При наличии Warden of Evos Isle на поле боя, второй Warden в руке теперь читается как
1 универсальная, синяя(соответствуя плитке в руке), а не2 универсальные, синие(напечатанная стоимость). Мод теперь читает стоимость разыгрывания действия в реальном времени (Action.ManaCostиз спискаActionsконкретной карты, преобразованную черезGreClient.CardData.ManaUtilities.ConvertManaCostsToList) — тот же источник, который использует отрисовщик плиток в MTGA — и откатывается кPrintedCastingCost, когда действие разыгрывания недоступно. Представления библиотеки / коллекции / конструктора (без живого экземпляра, а значит, без действий) по-прежнему читают напечатанную стоимость. Добавлено @LordLuceus (PR #91). - Добавления в стек теперь объявляют каждый новый элемент, а не только видимую вершину. Когда оппонент отвечает на ваше заклинание своим (так что два объекта попадают в стек почти одновременно — его ответ плюс, зачастую, одно из его сработавших triggered-способностей, активирующихся от той же стоимости или триггера), сам разыгрываемый ответ замалчивался: мод проверял только верхний CDC, который обычно был триггером, и никогда не произносил сам ответ. Теперь мод отслеживает объявленные элементы стека по
MtgCardInstance.InstanceIdи объявляет каждый вновь добавленный CDC при каждом обновлении счётчика зоны Stack, очищая трекер, когда стек опустошается. - В конструкторе колоды стрелка вниз на первой карте после поиска/фильтра теперь читает детали карты, а не переходит к следующей карте. Повторное сканирование после поиска переопределяло фокус EventSystem на первый элемент в целом (например, на строку Wildcards), а не на восстановленный сгруппированный элемент, что деактивировало CardInfoNavigator и превращало первую стрелку вниз в шаг навигации.
- Браузер распределения повреждений больше не перехватывается общим SpinnerNavigator. Оба навигатора активировались на виджетах
SpinnerAnimated, но SpinnerNavigator выполнялся первым и перехватывал ввод — объявлял блокирующих какCard #483(его распознаватель, заточенный только на поле боя, пропускал карты, перемещённые в браузер), сообщал «Verteile 0» (нет родительской SpinnerGroup → max=0) и отправлял черезPromptButton_PrimaryвместоDoneActionбраузера, так что подтверждение летального распределения по умолчанию ничего не делало. Теперь SpinnerNavigator уступает, когда активен браузер AssignDamage, позволяяBrowserNavigator.AssignDamageобрабатывать его корректно (правильные имена карт, общий урон, статус летальности, Space → DoneAction, Backspace → UndoAction). - Запрос Yes/No для Мутации (например, Huntmaster Liger спрашивает «мутировать на X?») больше не блокирует игрока. Каркас
BrowserScaffold_YesNo_Mutate_…приводился к простомуYesNoс помощьюExtractBrowserTypeFromScaffold, теряя вариант: Tab перебирал только карты из стопки мутации (никогда не доходя до кнопок Yes/No), Space проваливался доPromptButton_Primaryуровня дуэли (кнопка паса — неверная цель, браузер оставался зависшим), входная подсказка объявляла буквальный ключ локалиBrowserHint, а дружественное имя читалось «Choose yes or no» вместо «Mutate choice». ТеперьBrowserDetectorпомечает вариант Mutate вBrowserInfo, иBrowserNavigatorзеркалит для него поток OptionalAction: Tab перебирает карты, затем кнопки, Space направляется через логическуюDoneButtonпровайдера (превращается в2Button_Right= Yes), Backspace черезCancelButton(= No), с правильной подсказкойBrowserHint_Mutate, переведённой на все 12 языков. - Запросы браузера Yes/No теперь читают сам вопрос, а не просто «Choose yes or no». Всплывающее окно Ancestral Recall «Are You Sure?» (и любой другой браузер только с кнопками, такой как запросы Optional-action / Mutate) читает
Вы хотите сделать оппонента целью Ancestral Recall? Choose yes or no— текст подзаголовка каркаса извлекается через существующий помощникExtractBrowserHeaderTextи добавляется перед меткой типа. Добавлено @LordLuceus (PR #93). - P/T существ на поле боя теперь объявляет текущий урон отдельным элементом после счётчиков, соответствуя тому, как игра показывает красное число рядом с выносливостью для зрячих игроков. Существо 3/3, получившее 2 повреждения, читается как
3/3, 2 повреждения(или со счётчиками:4/4, 1 +1/+1, 2 повреждения); напечатанная/изменённая эффектами выносливость остаётся нетронутой, так что понятно, как значение было получено. ЧитаетMtgCardInstance.Damageиз модели — 0 при отсутствии живого экземпляра, так что конструктор / коллекция / показы библиотеки остаются без изменений. Функция первоначально предложена @LordLuceus (PR #92, как модификация выносливости); переработана для вывода урона отдельной строкой, чтобы объявление соответствовало визуальной компоновке игры. - Рука оппонента (Shift+C) больше не показывает карты, которые уже покинули руку. Карты, которые оппонент разыграл (их CDC остаётся под держателем OpponentHand с
IsDisplayedFaceUp=trueдаже после перемещения на кладбище / в изгнание / на поле боя), раньше оставались в списке раскрытых карт, создавая несоответствие «Рука оппонента, 2 карты. … 1 из 3», где отображаемое количество и навигационный список расходились, а карта, которую оппонент уже разыграл, всё ещё выглядела так, будто она у него в руке. Теперь список OpponentHand применяет ту же проверкуIsRealHandCardпо зоне модели, которую уже использовал подсчёт карт в руке, так что список и счётчик совпадают. Добавлено @LordLuceus (PR #95). - Навигация по Tab больше не пропускает карты с доступными действиями. Визуальная HotHighlight в MTGA не всегда надёжно обновляется в переходных состояниях — как у разыгрываемых карт в руке (особенно сразу после розыгрыша земли, когда подсветка активируемой способности существа на поле боя остаётся, а у карт в руке игрока, которые всё ещё можно разыграть, визуальная подсказка пропадает), так и у собственных перманентов игрока на поле боя с активируемыми способностями (например, существо с
{T}: do X, чьё свечение не обновилось после разрешения вражеского заклинания на кладбище). Сканирование мода совпадало только с GameObject’ами, чьи имена содержали буквальную подстроку"HotHighlight", поэтому Tab перебирал лишь тот элемент, у которого случайно сохранилась подсветка. Теперь и рука, и ваша сторона поля боя дополнены запросом к штатномуActionsAvailableWorkflow: workflow отслеживаетGreInteractionдля каждого доступного действия с предвычисленным флагомCanAffordToCast(устанавливаемым при создании взаимодействия изAction.CanAffordToCast()), и мы включаем любую карту, у которой есть играбельное взаимодействие — любой вариантCast*(половинки разделённых карт, приключения, MDFC, прототипы, Rooms, Omens), обычныйActivate(циклинг, ченнелинг, предсказание карты, заговор карты, ниндзюцу, активируемые способности на поле боя, способности planeswalker-ов) или не требующие оплатыSpecial/SpecialTurnFaceUp(сговор, монарх, продвижение по подземелью, переворот morph/manifest) — которое сам workflow считает доступным по средствам. Мана-способности (ActivateMana), земельные броски (Play*), перманенты оппонента и поддействия оплаты отфильтровываются, так что Tab по-прежнему перебирает только значимые действия. Никаких собственных эвристик доступности — игра сама отвечает на вопрос. Основа для разыгрываемой руки предоставлена @LordLuceus (PR #96); впоследствии расширена на типы действийActivate/Specialи на перманенты на своей стороне поля боя.
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.