function lerp(a, b, c) return a + (b - a) * c end function dlerp(a, b, c) return lerp(b, a, 0.5^c) end function bton(bool) return bool and 1 or 0 end function try(fn, ...) if fn then fn(...) end end function min(a, b) if a < b then return a end return b end function normalize(x, y) if x == 0 and y == 0 then return 0, 0 end local leng = math.sqrt(x*x + y*y) return x / leng, y / leng end -- Top left corner function point_in_rect(px, py, rx, ry, rw, rh) return px > rx and px < rx + rw and py > ry and py < ry + rh end function dist(x1, y1, x2, y2) local dx = x1 - x2 local dy = y1 - y2 return (dx*dx + dy*dy)^0.5 end function sign(x) if x == 0 then return 0 end return x < 0 and -1 or 1 end function round(x) return math.floor(x + 0.5) end function clamp(a, min, max) return math.min(max, math.max(a, min)) end function snap(x, step) return round(x / step) * step end function frac(x) return x - math.floor(x) end local function angle_diff(a, b) local diff = (b - a) % (math.pi * 2) return (2 * diff) % (math.pi * 2) - diff end function lerp_angle(a, b, t) return a + angle_diff(a, b) * (1 - 0.5^t) end function dot(x, y, xx, yy) return x*xx + y*yy end function vec_sqlen(x, y) return x*x + y*y end function vec_len(x, y) return math.sqrt(x*x + y*y) end function rotate_vec(x, y, r) local angle = math.atan2(y, x) + r local len = mathx.vec_len(x, y) return math.cos(angle) * len, math.sin(angle) * len end function table.shallow_copy(t) local t2 = {} for k,v in pairs(t) do t2[k] = v end return t2 end