Решили: рекаст — один глагол RuntimeUnit.RecastAttack(recoveryMult, nextWindupMult), и он делает ровно три вещи (модель Макса): обрезает хвост текущей атаки, снимает ожидание интервала, сокращает замах следующей. Уже занесённый замах не ускоряется никогда.

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

Три развилки внутри:

  1. Что именно ускоряется. Только хвост текущей атаки и замах следующей — формулировка Макса. Первый отвергнутый вариант «жать весь свинг одним множителем» проще в данных, но крадёт телеграф: удар, который уже занесён, приходит раньше обещанного, и парирование с уклонением теряют окно, ради которого существуют. Второй отвергнутый — «два разных числа на замах и доигрыш у каждого источника»: гибче, но множит ручки и расходится с анимацией.
  2. Нужно ли снимать интервал. Обязательно, и это не деталь: без снятия обрезанный хвост лишь удлиняет боевое ожидание, а следующий удар всё равно ждёт своей очереди — то есть рекаст не даёт ничего. Именно поэтому старый код обнулял таймер: он делал главную часть работы, просто без имени.
  3. Ограничивать ли цепочки. Решение Макса: нет, никаких блоков в коде — рекаст может взвести рекаст, а сдерживают заряды и кулдауны самих источников. Мой proposed (флаг «рекаст не порождает рекаст») отклонён: дизайн такого не планирует, а искусственный запрет ограничил бы будущие киты.

Грабли:

  • Множитель хвоста жил дольше своего свинга. Когда рекаст приходит в уже идущий хвост, остаток режется на месте — и множитель обязан там же потратиться. Иначе он доживал до следующей атаки и обрезал её доигрыш тоже, то есть рекаст незаметно превращался в постоянный режим кита.
  • Фазу глагол не двигает намеренно (её владелец — AutoAttackSystem), и на этом упал старый тест Монаха: он проверял Phase == Idle сразу после захода. Проверка переехала на остаток хвоста — суть та же, а фазу там смотреть нельзя и по второй причине: монах успевает провести сам удар в спину и войти в новый хвост, так что «не Recovery» перестаёт быть признаком успеха.

Что это открывает: парирование получит ответную атаку почти бесплатно — по вердикту Макса это «автоатака по рекасту с множителем», то есть готовый глагол плюс уже существующее усиление следующего удара.

Владелец правды: RuntimeUnit.RecastAttack (<remarks> — модель и все три части жеста), AutoAttackSystem.EnterRecovery (трата множителя), тесты — группа «Рекаст» в WindupAutoAttackTests (пять штук) и MonkSliceTests.VortexEntry_LoopsControl_StunsBeforeTheBackstab_AndCutsTheQueue.