Алгоритм нахождения предполагаемой скорости юнита, т.е. как если бы небыло минимального/максимального предела.
код
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 — сумма всех множителей от прочих абилок что меняют скорость процентно.
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.
Тогда a присвоится -1, m присвоится 0.
Зачем оно надо? Это полезно если вы хотит обойти лимит в 522, но при этом сохранить воздействие стандартных модификаторов скорости от абилок.
Схожий алгоритм был задействован в определении скорости у блудсикера в первой дотке.
Напомню что он лутал 40% MS за каждого вражеского героя на карте, HP которого было ниже 30%.
Для этого подобным образом расчитывались a и m, но m обрезался до максимально возможного значения бонуса от абилки (0.4 * кол-во героев на лоухп, это чтобы небыло занебесных цифр от всяких там бонусов +1000% к скорости), после чего значения подставлялись в формулу и герой бегал как ужаленный. Такой подход позволял работать всяким замедляющим эффектам - если на блудсикера накинуть сильное замедло, так быстро он уже не побежит.
Схожий алгоритм был задействован в определении скорости у блудсикера в первой дотке.
Напомню что он лутал 40% MS за каждого вражеского героя на карте, HP которого было ниже 30%.
Для этого подобным образом расчитывались a и m, но m обрезался до максимально возможного значения бонуса от абилки (0.4 * кол-во героев на лоухп, это чтобы небыло занебесных цифр от всяких там бонусов +1000% к скорости), после чего значения подставлялись в формулу и герой бегал как ужаленный. Такой подход позволял работать всяким замедляющим эффектам - если на блудсикера накинуть сильное замедло, так быстро он уже не побежит.
На картинке у меня герой с сопогом на +100, и 2 бафами аур с модификаторами +2.00 и +0.40. В итоге все это дает 1360 предполагаемой сокрости перемещения.