Решили: удар с разбега начинает замах ЗА границей досягаемости и доезжает остаток дистанции ходом, поэтому кадр контакта приходится ровно на момент, когда дистанции хватает для удара. Заряд разбега переехал со взвода «по прибытии» на взвод «по полному разгону», а рут на время такого замаха снят.
Почему: жалоба была визуальная — «бежит, упирается в юнита и только потом бьёт», — но кадр удара
оказался ни при чём: маркер контакта скрабится по WindupRemaining и всегда совпадает с сим-тиком
урона. Стоял сам замах: гейт пускал свинг только из reach, движение рутовало юнита на замахе, а заряд
взводился прибытием, то есть появлялся, когда бежать уже некуда. Три вещи вместе делали «добежал →
встал → 0.6 с замаха на месте → удар» единственно возможным поведением, и никакой правкой клипа это
не лечится: позицией владеет сим, показ её не переписывает.
Отвергли два дешёвых варианта. Первый — только укоротить ChargeAttackWindupMult: стояние сокращается
вдвое, но остаётся стоянием. Второй — оставить рут и «доиграть» въезд анимацией: это ровно то враньё
показа о позиции, которое у нас запрещено.
Сближение считается ПЕССИМИСТИЧНО: свой ход плюсуется, уход цели вычитается, а движение цели навстречу не засчитывается вовсе. Полная относительная скорость честнее на бумаге, но в сшибке двух линий она удваивает дистанцию старта — и стоит цели затормозить (её собственный замах рутует её), атакующий не доезжает половину пути и бьёт по воздуху. Ошибка «слишком рано» стоит промаха, ошибка «слишком поздно» стоит лишь того, что последние тики замаха юнит стоит.
Грабли: разбег на заряженном замахе пришлось ЗАМОРАЗИТЬ, а не пересчитывать. Гистерезис гасит
разгон, когда зазор падает ниже SprintExitGap, — то есть ровно в тиках подъезда. Скорость упала бы
на треть уже после того, как гейт посчитал по ней точку старта, и удар не доезжал бы. По той же
причине въезду не выдаётся штраф «стрельбы на ходу».
Второе: перенос взвода заряда в разгон сломал бы правило «разбег, оборванный не прибытием, заряда не
оставляет» — раньше оно держалось порядком строк (заряд просто не успевал взвестись). Понадобился
отдельный глагол RuntimeUnit.AbortSprint, и теперь каждый обрыв гасит заряд явно.
Третье, организационное: параллельная сессия закоммитила свой рефакторинг и утащила часть этих правок
в чужой коммит 98a1fecc7. git commit берёт весь индекс — при параллельной работе коммитить только
git commit -F - -- <пути>.
Владелец правды: CombatPositioning.CanCloseIntoReach, AutoAttackSystem.ChargesIntoReach,
MovementSystem (флаг chargingIn), тест ChargeAttackTests.