library HunterCamera initializer ini import Math import Units import Players import Game native UnitAlive takes unit u returns boolean constant real CLOCK_PERIOD = 1. / 3. constant real OFFSET_STATIC = 300. constant real OFFSET_JITTER = 80. constant real OFFSET_DYNAMIC = 400. constant real JITTER_THRESHOLD = bj_PI / 3. constant integer KERNEL_SIZE = 4 // filter kernel for estimating jitter real array kernel integer array kernelIndex function kernelApply takes integer index, real facing returns real real min = bj_PI real max = -1. * bj_PI integer i = 0 // append kernel facing = Math.radiansNormalizeHalf(facing) kernel[index * KERNEL_SIZE + kernelIndex[index]] = facing // fetch minimax loop exitwhen i >= KERNEL_SIZE if i != index then min = Math.minReal(min, Math.radiansNormalizeHalf(facing - kernel[index * KERNEL_SIZE + i])) max = Math.maxReal(max, Math.radiansNormalizeHalf(facing - kernel[index * KERNEL_SIZE + i])) end i++ end // increment kernel index kernelIndex[index]++ kernelIndex[index] = ModuloInteger(kernelIndex[index], KERNEL_SIZE) return Math.radiansNormalizeHalfModulo(max - min) end function act takes nothing returns nothing integer index = 0 real facing real minimax real offset = OFFSET_STATIC //if (not Cinematic.enabled) then if Game.roundEnabled then loop exitwhen index >= Players.FIRST_BEAST if UnitAlive(Units.hero[index]) then facing = GetUnitFacing(Units.hero[index]) * bj_DEGTORAD minimax = kernelApply(index, facing) if (minimax > JITTER_THRESHOLD) then offset = OFFSET_JITTER elseif (GetUnitCurrentOrder(Units.hero[index]) == OrderId("smart")) then offset = OFFSET_DYNAMIC end if Players.locl == Players.fromId[index] then PanCameraToTimed(GetUnitX(Units.hero[index]) + offset*Cos(facing), GetUnitY(Units.hero[index]) + offset*Sin(facing), CLOCK_PERIOD*2.) end end index++ end end end public struct HunterCamera static method resetKernel takes nothing returns nothing integer index = 0 integer j loop exitwhen index >= Players.COUNT kernelIndex[index] = 0 j = 0 loop exitwhen j >= KERNEL_SIZE kernel[index * KERNEL_SIZE + j] = 270. j++ end index++ end end end function ini takes nothing returns nothing TimerStart(CreateTimer(), CLOCK_PERIOD, true, function act) HunterCamera.resetKernel() end endlibrary