Доки Valve закрыты Anubis, читал первоисточник
ValveSoftware/source-sdk-2013, src/game/shared/gamemovement.cpp.
Записаны точные причины двух симптомов пользователя и ещё трёх расхождений:
1. StepMove у оригинала пробует оба варианта (вниз и вверх на flStepSize) и
берёт тот, что ушёл дальше по горизонтали; вертикальную скорость берёт из
движения ВНИЗ (m_vecVelocity.z = vecDownVel.z). У нас подшаг всегда идёт
путём «поднять 18 и уронить», режет путь на рампе и добавляет паразитную
вертикаль — отсюда и потеря скорости вверх, и «прыжки с рампы» вниз.
2. Friction() вызывается каждый кадр на земле безусловно, формула
control = max(speed, sv_stopspeed), drop = control*friction*frametime.
У нас трение только при отсутствии ввода — по рампе на бегу его нет.
3. Гравитация делится 0.5 до и 0.5 после движения (StartGravity/FinishGravity).
4. Ускорение — Quake-формула accelspeed = accel*frametime*wishspeed, а в
воздухе ещё и ограничение sv_air_max_wishspeed = 30. Отсюда «вязкое»
управление в воздухе, которого у нас нет.
5. Прыжок по фронту: в оригинале при выходе из воды ставится
m_nOldButtons |= IN_JUMP с комментарием «don't jump again until released» —
наша защёлка воспроизводит штатный приём движка.
Код не менял: сначала фиксирую расхождения, чтобы не подгонять тесты.