I keep a file handy with a list of such functions. Here it is. If you use any of these in a project, please give me credit in a readme or something. If you want to use one of them but can't figure it out, just ask and I can explain it better (the comments are mainly a reminder to myself).
Code: Select all
----------------------------------------------------------------
----------------------------- Math -----------------------------
----------------------------------------------------------------
-- Averages angles (properly).
function math.averageAngles(...)
local x,y = 0,0
for i=1,select('#',...) do local a= select(i,...) x, y = x+math.cos(a), y+math.sin(a) end
return math.atan2(y, x)
end
-- Returns the distance between two points.
function math.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end
-- Optional 3D capacity:
function math.dist(x1,y1,z1, x2,y2,z2) return ((x2-x1)^2+(y2-y1)^2+((z2 or 0) - (z1 or 0))^2)^0.5 end
-- Returns the angle between two points.
function math.getAngle(x1,y1, x2,y2) return math.atan2(y2-y1, x2-x1) end
-- Returns the closest multiple of 'size' (defaulting to 10).
function math.multiple(n, size) size = size or 10 return math.round(n/size)*size end
-- Clamps a number to within a certain range.
function math.clamp(low, n, high) return math.min(math.max(n, low), high) end
-- Linear interpolation between two numbers
function lerp(a,b,t) return a+(b-a)*t end
-- Cosine interpolation between two numbers
function cerp(a,b,t) local f=(1-math.cos(t*math.pi))*.5 return a*(1-f)+b*f end
-- Normalizes a table of numbers.
function math.normalize(t) local n,m = #t,0 for i=1,n do m=m+t[i] end m=1/m for i=1,n do t[i]=t[i]*m end return t end
-- Normalizes two numbers.
function math.normalize(x,y) local l=(x*x+y*y)^.5 if l==0 then return 0,0,0 else return x/l,y/l,l end end
-- Returns 'n' rounded to the nearest 'deci'th.
function math.round(n, deci) deci = 10^(deci or 0) return math.floor(n*deci+.5)/deci end
-- Randomly returns either -1 or 1.
function math.rsign() return math.random(2) == 2 and 1 or -1 end
-- Returns 1 if number is positive, -1 if it's negative, or 0 if it's 0.
function math.sign(n) return n>0 and 1 or n<0 and -1 or 0 end
-- Checks if two lines intersect (or line segments if seg is true)
function findIntersect(l1p1x,l1p1y, l1p2x,l1p2y, l2p1x,l2p1y, l2p2x,l2p2y, seg1, seg2)
local a1,b1,a2,b2 = l1p2y-l1p1y, l1p1x-l1p2x, l2p2y-l2p1y, l2p1x-l2p2x
local c1,c2 = a1*l1p1x+b1*l1p1y, a2*l2p1x+b2*l2p1y
local det,x,y = a1*b2 - a2*b1
if det==0 then return false, "The lines are parallel." end
x,y = (b2*c1-b1*c2)/det, (a1*c2-a2*c1)/det
if seg1 or seg2 then
local min,max = math.min, math.max
if seg1 and not (min(l1p1x,l1p2x) <= x and x <= max(l1p1x,l1p2x) and min(l1p1y,l1p2y) <= y and y <= max(l1p1y,l1p2y)) or
seg2 and not (min(l2p1x,l2p2x) <= x and x <= max(l2p1x,l2p2x) and min(l2p1y,l2p2y) <= y and y <= max(l2p1y,l2p2y)) then
return false, "The lines don't intersect."
end
end
return x,y
end
-- Turns eight true/false values (bits) into a character (byte)
function formByte(a,b,c,d,e,f,g,h) return string.char((a and 128 or 0)+(b and 64 or 0)+(c and 32 or 0)+(d and 16 or 0)+(e and 8 or 0)+(f and 4 or 0)+(g and 2 or 0)+(h and 1 or 0)) end
-- Splits a character (byte) into eight true/false values (bits)
function splitByte(input) local b,p,f = string.byte(input),128,{false,false,false,false,false,false,false,false}
for i=1,8 do if b>=p then f[i],b = true,b-p end p=p*.5 end return f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8] end
----------------------------------------------------------------
--------------------------- Strings ----------------------------
----------------------------------------------------------------
-- Correct the print function to wrap text correctly to a given width (defaulting to 80).
oldprint = print
function print(s, n)
n = (n or 80) - 1
repeat
line = string.sub(s, 1, n) -- Get one console-width of the string
local ended = false
if string.find(line, " ") and string.len(line) >= n then
while not ended do -- Find the last " " in it
local length = string.len(line)
if string.sub(line, length, length) ~= " " then line = string.sub(line, 1, length-1)
else ended = true end
end
end
s = string.sub(s, string.len(line)+1, string.len(s)) -- Remove the single line from the string
local length = string.len(line) length length length
if string.sub(line, length, length) == " " then line = string.sub(line, 1, length-1) end
oldprint(" "..line)
until string.len(s) < 1
end
-- Turns a table into an English-correct comma-delimited list string.
function listTable(t, combiner, keys)
local l, e, current, last, combiner = "", "", 0, #t, combiner or "and"
combiner = combiner == "" or combiner.." "
for k, v in pairs(t) do
current = current + 1
if keys then e = k else e = v end
if last == 1 then l = e
elseif current == last then l = l..combiner..e
elseif last < 3 and combiner ~= "" then l = e.." "
else l = l..e..", "
end
end
return l
end
-- Capitalize a string.
function string.capitalize(s) if string.len(s)<2 then return string.upper(s) end return string.upper(string.sub(s, 1, 1))..string.sub(s,1-string.len(s)) end
----------------------------------------------------------------
---------------------------- Tables ----------------------------
----------------------------------------------------------------
-- Like ipairs(t), but lets you specify starting position.
function iipairs(t,i) local function iter(t,i) i=i+1 if t[i] then return i, t[i] end end return iter,t,(i or 1)-1 end
-- An ordered version of pairs().
function kpairs(t, f)
local a, i = {}, 0 for n in pairs(t) do table.insert(a, n) end table.sort(a, f)
return function() i = i+1 if a[i] == nil then return nil else return a[i], t[a[i]] end end
end
-- Combines an arbitrary number of tables. Tables are not cross-contaminated in this process. Can't handle circular references.
function table.combine(replace, ...) local nt = {} for i=1, select('#', ...) do local t = select(i, ...) for k, v in pairs(t) do
if replace then if type(v) == "table" then nt[k] = table.combine(replace, v) else nt[k] = v end
else if type(v) == "table" then table.insert(nt, table.combine(true, v)) else table.insert(nt, v) end
end end end return nt end
-- Create a new copy a table. Can't handle circular references.
function table.copy(t) local t2={} for k,v in pairs(t) do if type(v)=="table" then t2[k]=table.copy(v) else t2[k]=v end end return t2 end
-- Find the key for a given value in a table.
function table.getkey(t,value) for k,v in pairs(t) do if v==value then return k end end end
-- Returns the nth key of a table.
function table.nkey(t,n) local a={} for k in pairs(t) do if type(k)=="number" then table.insert(a, k) end end table.sort(a) return a[n] end
-- Turns a table into a printable string.
function table.tostring(t,n) local s,n = "", (n or -1)+1 for k,v in pairs(t) do for i=1,n do s=s.." " end
s=s..tostring(k).." = "..(type(v)=="table" and "\n"..table.tostring(v,n) or tostring(v)).."\n" end return s end
----------------------------------------------------------------
---------------------------- Other -----------------------------
----------------------------------------------------------------
-- Time how fast a function is
function time(n,f,...) local t1=os.clock() for i=1,n do f(...) end return(os.clock()-t1) end
-- Converts HSL to RGB. (input and output range: 0 - 255)
function HSL(h, s, l)
if s <= 0 then return l,l,l end
h, s, l = h/256*6, s/255, l/255
local c = (1-math.abs(2*l-1))*s
local x = (1-math.abs(h%2-1))*c
local m,r,g,b = (l-.5*c), 0,0,0
if h < 1 then r,g,b = c,x,0
elseif h < 2 then r,g,b = x,c,0
elseif h < 3 then r,g,b = 0,c,x
elseif h < 4 then r,g,b = 0,x,c
elseif h < 5 then r,g,b = x,0,c
else r,g,b = c,0,x
end return (r+m)*255,(g+m)*255,(b+m)*255
end
-- ASCII Vigenere cypher
function vigenere(key, data, decrypt)
local result, kl, method = "", string.len(key), decrypt and -1 or 1
local char, byte = string.char, string.byte
for i = 1,string.len(data) do
local ki = (i-1) % kl + 1
result = result .. char( (byte(data, i,i) + byte(key, ki,ki)*method) % 256 )
end
return result
end
-- Bresenham's line algorithm (slower than the following function)
function Bline(x0,y0, x1,y1, f)
local dx,dy = math.abs(x1-x0), math.abs(y1-y0)
local sx,sy = x0<x1 and 1 or -1, y0<y1 and 1 or -1
local err = dx-dy
while true do
f(x0,y0)
if x0 == x1 and y0 == y1 then break end
local e2 = err*2
if e2 > -dy then err,x0 = err-dy, x0+sx end
if e2 < dx then err,y0 = err+dx, y0+sy end
end
end
-- Iterate function f over all coordinates from one point to another
function line(x0,y0, x1,y1, f)
local t = math.abs(y1-y0) > math.abs(x1-x0)
if t then x0,y0, x1,y1 = y0,x0, y1,x1 end
if x0>x1 then x0,x1, y0,y1 = x1,x0, y1,y0 end
local dx,dy = x1-x0, math.abs(y1-y0)
local err,y,ystep = dx*.5, y0, y0<y1 and 1 or -1
for x=x0,x1 do if t then f(y,x) else f(x,y) end err=err-dy if err<0 then y,err=y+ystep,err+dx end end
end
-- Trigger some Instant Elevator Music (but pops up a command window...)
os.execute[[""%ProgramFiles%\Instant Elevator Music\instantelevatormusic.exe"" -play app_name]]
EDIT) Updated with the most recent version of my list.