Способ реализации:
Версия Warcraft:
Алгоритм нахождения предполагаемой скорости юнита, т.е. как если бы небыло минимального/максимального предела.
код
library EstimateMS

    globals
        private constant real MIN_UNIT_SPEED = 100
        private constant real MAX_UNIT_SPEED = 522
        
        public real ParamDef
        public real ParamAdd
        public real ParamMul
    endglobals
    
    function CalculateMoveSpeed takes real def, real add, real mul returns real
        return (def + add)*(1 + mul)
    endfunction
    
    function GetUnitEstimateMoveSpeed takes unit u returns real
        local real def = GetUnitDefaultMoveSpeed(u)
        local real add
        local real mul
        local real x1
        local real y1
        local real x2
        local real y2
        local real step = 1000
        local boolean check = GetUnitMoveSpeed(u) > (MIN_UNIT_SPEED + MAX_UNIT_SPEED)/2
        set x1 = def
        loop
            call SetUnitMoveSpeed(u, x1)
            set y1 = GetUnitMoveSpeed(u)
            exitwhen x1 > MIN_UNIT_SPEED*100
            if y1 == MAX_UNIT_SPEED then 
                if not check then
                    set check = true
                    set step = step/2
                endif
                set x1 = x1 - step
            elseif y1 == MIN_UNIT_SPEED then
                if check then
                    set check = false
                    set step = step/2
                endif
                set x1 = x1 + step
            else
                exitwhen true
            endif
        endloop
        if y1 > (MIN_UNIT_SPEED + MAX_UNIT_SPEED)/2 then
            set x2 = x1 - step/100
        else
            set x2 = x1 + step/100
        endif
        call SetUnitMoveSpeed(u, x2)
        set y2 = GetUnitMoveSpeed(u)
        if y1 != y2 then
            set mul = (y1 - y2)/(x1 - x2) - 1
            set add = y1/(1 + mul) - x1
        else
            set mul = -1
            set add = 0
        endif
        call SetUnitMoveSpeed(u, def)
        set ParamDef = def
        set ParamAdd = add
        set ParamMul = mul
        return CalculateMoveSpeed(def, add, mul)
    endfunction

endlibrary

Для начала, формула скорости перемещения юнита:
S = (D' + a)*(1 + m)
S — текущая скорость юнита,
D' — дефолтная скорость юнита из РО (ниже напишу почему со штрихом),
a — прибавка от абилки сопог,
m — сумма всех множителей от прочих абилок что меняют скорость процентно.
И есть следующие функции для работы со скоростью перемещения юнита:
constant native GetUnitDefaultMoveSpeed takes unit whichUnit returns real
constant native GetUnitMoveSpeed takes unit whichUnit returns real
native SetUnitMoveSpeed takes unit whichUnit, real newSpeed returns nothing
Ну тут и так ясно что где.
Алгоритм основан на том что функция SetUnitMoveSpeed не меняет текущую скорость юнита как такову, а как-бы заменяет дефолтное значение D на новое D' (GetUnitDefaultMoveSpeed все так же будет возвращать значение из РО), таким образом формула перерасчитывается. Это приводит к тому что после установки скорости функцией SetUnitMoveSpeed, функция GetUnitMoveSpeed может возвращать совершенно иное значение.
Алгоритм построен так что он пытается установить скорость юнита на такую, чтобы при текущих модификаторах скорости, результат не выходил за пределы игровых констант. Как только он находит такое значение, он делает это еще раз, после чего сравнивает эти значения между собой, выполняя обратные расчеты для получения приблизительных значений a и m (на само деле это довольно точно).
После чего подставляет полученные значения в функцию выше и возвращает результат.
Однако стоит упомянуть что этот алгоритм не сможет выполнится если юнит замедлен на 100% и более - т.к. в таком случае GetUnitMoveSpeed всегда будет возвращать минимальный предел. То же самое с юнитом который пойман в сеть или аналоги.
Тогда a присвоится -1, m присвоится 0.
Зачем оно надо? Это полезно если вы хотит обойти лимит в 522, но при этом сохранить воздействие стандартных модификаторов скорости от абилок.
Схожий алгоритм был задействован в определении скорости у блудсикера в первой дотке.
Напомню что он лутал 40% MS за каждого вражеского героя на карте, HP которого было ниже 30%.
Для этого подобным образом расчитывались a и m, но m обрезался до максимально возможного значения бонуса от абилки (0.4 * кол-во героев на лоухп, это чтобы небыло занебесных цифр от всяких там бонусов +1000% к скорости), после чего значения подставлялись в формулу и герой бегал как ужаленный. Такой подход позволял работать всяким замедляющим эффектам - если на блудсикера накинуть сильное замедло, так быстро он уже не побежит.
На картинке у меня герой с сопогом на +100, и 2 бафами аур с модификаторами +2.00 и +0.40. В итоге все это дает 1360 предполагаемой сокрости перемещения.
`
ОЖИДАНИЕ РЕКЛАМЫ...