User:Clairebun/Sandbox/Common Lua Functions
This page contains lua functions that could be generally useful to modders.
These are all formatted as global functions using the rawset()
function. You might consider reformatting some of these as local functions or functions under global tables. Please note that a few of these functions may call on other functions (listed as "Dependencies") -- dependencies need to be included in tandem with any functions you use from this list.
Math
Handles various math related functions.
For physics-related functions that affect objects, see #Objects.
L_DecimalFixed
Converts a decimal/float number within a string into a fixed value. If no number is found, returns 0.
arg (string) Should contain a number (e.g. '-2' or '1.506').
rawset(_G, 'L_DecimalFixed', function(str)
if str == nil return nil end
local dec_offset = string.find(str,'%.')
if dec_offset == nil
return (tonumber(str) or 0)*FRACUNIT
end
local whole = tonumber(string.sub(str,0,dec_offset-1)) or 0
local decimal = tonumber(string.sub(str,dec_offset+1)) or 0
whole = $ * FRACUNIT
local dec_len = string.len(decimal)
decimal = $ * FRACUNIT / (10^dec_len)
return whole + decimal
end)
L_FixedDecimal
Converts a fixed integer into a decimal/float within a string.
arg1 (string or fixed) Fixed value to convert. Returns an error string if invalid.
[arg2] (integer) Number of decimal places to output. 3 by default.
rawset(_G, 'L_FixedDecimal', function(str,maxdecimal)
if str == nil or tostring(str) == nil
return '<invalid FixedDecimal>'
end
local number = tonumber(str)
maxdecimal = ($ != nil) and $ or 3
if tonumber(str) == 0 return '0' end
local polarity = abs(number)/number
local str_polarity = (polarity < 0) and '-' or ''
local str_whole = tostring(abs(number/FRACUNIT))
if maxdecimal == 0
return str_polarity..str_whole
end
local decimal = number%FRACUNIT
decimal = FRACUNIT + $
decimal = FixedMul($,FRACUNIT*10^maxdecimal)
decimal = $>>FRACBITS
local str_decimal = string.sub(decimal,2)
return str_polarity..str_whole..'.'..str_decimal
end)
L_FixedLerp
Returns a fixed number using linear interpolation.
arg1 (fixed) value 1 to interpolate.
arg2 (fixed) value 2 to interpolate.
arg3 fixed) interpolation amount. e.g. 0 = 0%, FRACUNIT = 100%
rawset(_G, 'L_FixedLerp', function(val1,val2,amt)
local p = FixedMul(FRACUNIT-amt,val1) + FixedMul(amt,val2)
return p
end)
L_FixedPower
Performs a power operation on a fixed value.
arg1 (fixed) base number
arg2 (fixed) exponent. Supports negatives, and fractions (sort of)
[arg3] (integer) number of times the function is allowed to bitshift. 1 by default -- higher values may overflow!
Dependencies: #L_FixedDecimal
local warning
rawset(_G, 'L_FixedPower', function(base, exponent, shiftlimit)
if base == 0 return 0 end --Prevent div/0
if exponent == 0 return FRACUNIT end --Prevent div/0
local base_copy = base
local exp_copy = exponent
local inversion = false
local shift = 0
shiftlimit = $ or 1
--If our exponent is negative, turn positive and remember the negative for later.
if exponent < 0
exponent = abs(exponent)
inversion = true
end
--Deal with fractional exponents.
while exponent%FRACUNIT
exponent = $ << 1
shift = $ + 1
--Shift the exponent. We will correct for this later with square roots.
if shift >= shiftlimit
FixedRound(exponent)
break
end
if shift >= FRACBITS
if not warning
print('\x82'..'WARNING: Overflow detected in FixedPower function (base: '..Lib.FixedDecimal(base_copy)..', exponent: '..Lib.FixedDecimal(exp_copy)..')')
warning = true
end
return FRACUNIT
end
end
exponent = $>>FRACBITS
local result = FRACUNIT
--Perform multiplication according to exponent amount
for n = 1, exponent
result = FixedMul($, base)
end
if result == 0 --Prevent div/0
return 0
end
--Compensate for bitshifting using square roots
for n = 1, shift
result = FixedSqrt(result)
end
--Correct for negative exponents by inverting the result.
if inversion
result = FixedDiv(FRACUNIT, $)
end
return result
end)
L_GetZAngle
Returns the vertical angle trajectory between two fixed sets of coordinates.
arg1 (fixed) x1
arg2 (fixed) y1
arg3 (fixed) z1
arg4 (fixed) x2
arg5 (fixed) y2
arg6 (fixed) z2
rawset(_G,'L_GetZAngle', function(x1,y1,z1,x2,y2,z2)
local xydist = R_PointToDist2(x1,y1,x2,y2)
local zdist = z2-z1
return R_PointToAngle2(0,0,xydist,zdist)
end)
L_PredictLinearCollision
Determines whether two objects will collide based on their current positions, collision boxes, and movement speeds. Returns true if the two objects are already colliding. Otherwise, returns the number of tics that a collision is expected. If no collision is found or expected, returns false.
Note that this script assumes object momentum remains constant, and will be inaccurate if an object's speed is accelerating or changing direction.
arg1 (mobj) First object
arg2 (mobj) Second object
arg3 (integer) Number of dimensions to check (should be a number between 1-3)
rawset(_G,'L_PredictCollision', function(mo1, mo2, axes)
local c = {}
local r = {}
local m = {}
local near = {{}, {}}
axes = $ or 3
for n = 1, 2 do
local mo = n == 1 and mo1 or mo2
c[n] = {mo.x, mo.y, mo.z+mo.height/2}
r[n] = {mo.radius, mo.radius, mo.height/2}
m[n] = {mo.momx, mo.momy, mo.momz}
end
-- Get dimensions to check. Choose closest corner on bounding box to use for checks
local vacant = {}
local failed = 0
for n = 1,axes do
local c1, c2, r1, r2 = c[1][n], c[2][n], r[1][n], r[2][n]
if c2-r2 > c1+r1
vacant[n] = true
near[1][n] = c1 + r1
near[2][n] = c2 - r2
failed = $+1
elseif c1-r1 > c2+r2
vacant[n] = true
near[1][n] = c1 - r1
near[2][n] = c2 + r2
failed = $+1
else -- Overlapping coordinates
-- Get mutual center coordinate for both objects
if c1 > c2
near[1][n] = (c1+c2-r1+r2)/2
elseif c2 > c1
near[1][n] = (c1+c2+r1-r2)/2
else -- Resting on same position
near[1][n] = c1
end
near[2][n] = near[1][n]
-- Keep "vacant" uninitialized if bounding boxes are intersecting.
end
end
if not(failed)
return true -- If there are intersections across all axes, then we have already collided
end
local diff = {}
local rate = {}
local time = {}
-- Get rate of change and time needed for coordinates to intersect
for n = 1,axes do
if not(vacant[n]) continue end -- Already intersecting; time would simply return 0.
-- Get coordinate distance
diff[n] = near[2][n] - near[1][n]
-- Get rate of change in distance
rate[n] = m[1][n] - m[2][n]
-- Get time it will take to reach mutual coordinate
if rate[n] != 0
time[n] = FixedCeil(FixedDiv(diff[n], rate[n]))
end
end
local nearest_time
local new = {{}, {}}
for n = 1,axes do
-- Get coordinates at time
if not(rate[n]) continue end -- Not traveling on this axis (Prevent div/0)
for o = 1,axes do
-- Don't skip this axis even if we are already colliding; momentum might make us not collide anymore!
new[1][o] = c[1][o] + FixedMul(m[1][o], time[n]) -- Object 1's new coordinates (current coord + momentum * tics)
new[2][o] = c[2][o] + FixedMul(m[2][o], time[n]) -- Object 2's new coordinates
end
-- Check that there would be a collision at point
local failed = false
for o = 1,axes do
-- Again, all axes must be checked for this
if new[1][o] - r[1][o] > new[2][o] + r[2][o]
or new[2][o] - r[2][o] > new[1][o] + r[1][o]
failed = true
break
end
end
-- Get nearest time
if not(failed)
if nearest_time != nil
nearest_time = min($, time[n])
else
nearest_time = time[n]
end
end
end
if nearest_time == nil
return false -- Could not find a collision at any point along trajectories
end
return nearest_time/FRACUNIT -- Return the time it will take for objects to collide
end)
L_TurnAngle
Interpolates between two angles by a specified amount.
arg1 (angle) First angle to interpolate
arg2 (angle) Second angle to interpolate
[arg3] (fixed) Interpolation amount. Defaults to FRACUNIT/8
rawset(_G,'L_TurnAngle', function(oldangle,newangle,factor)
factor = $ or FRACUNIT/8
return oldangle + FixedMul(newangle-oldangle,factor)
end)
Objects
Functions that perform operations on objects, including movement and other object properties.
L_AngleTeleport
Teleports an object a specified distance away from a set of coordinates at a specified angle.
arg1 (mobj) Object to modify arg2 ({fixed, fixed, fixed}) Table containing the set of XYZ coordinates to use as a center of origin. arg3 (angle) XY angle to teleport away from the XYZ center. arg4 (angle) Z angle to teleport away from the XYZ center. arg5 (fixed) Distance to teleport away from the XYZ center.
rawset(_G,'L_AngleTeleport', function(mo,coords,xyangle,zangle,distance)
local x = coords[1]
local y = coords[2]
local z = coords[3]
local xythrust = P_ReturnThrustX(nil,zangle,distance)
local xthrust = P_ReturnThrustX(nil,xyangle,xythrust)
local ythrust = P_ReturnThrustY(nil,xyangle,xythrust)
local zthrust = P_ReturnThrustY(nil,zangle,distance)
P_TeleportMove(mo,x+xthrust,y+ythrust,z+zthrust)
return {xythrust/FRACUNIT,zthrust/FRACUNIT}
end)
L_DoBrakes
Reduces XYZ momentum of an object.
arg1 (mobj) object to modify.
arg2 (fixed) amount of speed to keep, e.g. mo.friction
rawset(_G,'L_DoBrakes', function(mo,factor)
mo.momx = FixedMul($,factor)
mo.momy = FixedMul($,factor)
mo.momz = FixedMul($,factor)
end)
L_DoBrakesXY
Reduces XY momentum of an object.
arg1 (mobj) object to modify.
arg2 (fixed) amount of speed to keep, e.g. mo.friction
rawset(_G,'L_DoBrakesXY', function(mo,factor)
mo.momx = FixedMul($,factor)
mo.momy = FixedMul($,factor)
end)
L_DoBrakesZ
Reduces Z momentum of an object.
arg1 (mobj) object to modify.
arg2 (fixed) amount of speed to keep, e.g. mo.friction
rawset(_G,'L_DoBrakesZ', function(mo,factor)
mo.momz = FixedMul($,factor)
end)
L_SpeedCap
Restrains an object to a specified speed limit.
arg1 (mobj) object to modify
arg2 (fixed) maximum allowed speed
[arg3] (fixed) % speed reduction if over the limit. If nil, speed reduction is instant.
Dependencies: #L_DoBrakes
rawset(_G,'L_SpeedCap', function(mo,limit,factor)
local spd_xy = R_PointToDist2(0,0,mo.momx,mo.momy)
local spd, ang =
R_PointToDist2(0,0,spd_xy,mo.momz),
R_PointToAngle2(0,0,mo.momx,mo.momy)
if spd > limit
if factor == nil
factor = FixedDiv(limit,spd)
end
L_DoBrakes(mo,factor)
return factor
end
end)
L_SpeedCapXY
Restrains an object to a specified speed limit, but only over the X and Y axes.
arg1 (mobj) object to modify
arg2 (fixed) maximum allowed speed
[arg3] (fixed) % speed reduction if over the limit. If nil, speed reduction is instant.
Dependencies: #L_DoBrakesXY
rawset(_G,'L_SpeedCapXY', function(mo,limit,factor)
local spd, ang =
R_PointToDist2(0,0,mo.momx,mo.momy),
R_PointToAngle2(0,0,mo.momx,mo.momy)
if spd > limit
if factor == nil
factor = FixedDiv(limit,spd)
end
L_DoBrakesXY(mo,factor)
return factor
end
end)
L_ThrustXYZ
Thrusts an object using the specified horizontal and vertical angles.
arg1 (mobj) object to modify
arg2 (angle) XY angle
arg3 (angle) Z angle
arg4 (fixed) thrust speed amount
arg5 (boolean) relative
rawset(_G,'L_ThrustXYZ', function(mo,xyangle,zangle,speed,relative)
local xythrust = P_ReturnThrustX(nil,zangle,speed)
local zthrust = P_ReturnThrustY(nil,zangle,speed)
if relative then
P_Thrust(mo,xyangle,xythrust)
mo.momz = $+zthrust
else
P_InstaThrust(mo,xyangle,xythrust)
mo.momz = zthrust
end
return xythrust/FRACUNIT, zthrust/FRACUNIT
end)
L_ZCollide
Performs a height check between two objects. For use in MobjCollide hooks.
arg1 (mobj) first object arg2 (mobj) second object
rawset(_G, 'L_ZCollide', function(mo1,mo2)
if mo1.z > mo2.height+mo2.z then return false end
if mo2.z > mo1.height+mo1.z then return false end
return true
end)
L_ZLaunch
Vertically thrusts an object with respect to water physics, scale and gravity polarity.
arg1 (mobj) object to modify
arg2 (fixed) thrust amount
[arg3] (boolean) relative
rawset(_G, 'L_ZLaunch', function(mo,thrust,relative)
if mo.eflags&MFE_UNDERWATER
thrust = $*3/5
end
P_SetObjectMomZ(mo,thrust,relative)
end)
Random
Functions for generating random ouputs.
L_Choose
Randomly returns one of the arguments put into the function.
Accepts any number/type of arguments. e.g. L_Choose(FRACUNIT, 0, -FRACUNIT)
, L_Choose(table1, table2, table3)
etc.
rawset(_G, 'L_Choose', function(...)
local args = {...}
local choice = P_RandomRange(1,#args)
return args[choice]
end)
L_Shuffle
Randomly shuffles the elements of a table. Returns the reshuffled table.
arg1 (table) Table to shuffle.
rawset(_G, 'L_Shuffle', function(t)
for n = #t, 1, -1 do
local k = P_RandomRange(1, n)
t[n], t[k] = t[k], t[n]
end
return t
end)
Statistics
prtable
Lists table contents, including subtable contents.
argument1 is text label to display, argument2 is table to output. argument3 and argument4 are reserved for recursion purposes.
rawset(_G, "prtable", function(text, t, prefix, cycles)
prefix = $ or ""
cycles = $ or {}
print(prefix..text.." = {")
for k, v in pairs(t)
if type(v) == "table"
if cycles[v]
print(prefix.." "..tostring(k).." = "..tostring(v))
else
cycles[v] = true
prtable(k, v, prefix.." ", cycles)
end
elseif type(v) == "string"
print(prefix.." "..tostring(k)..' = "'..v..'"')
else
if type(v) == "userdata" and v.valid and v.name
v = v.name
end
print(prefix.." "..tostring(k).." = "..tostring(v))
end
end
print(prefix.."}")
end)