Lua Snippets

From time to time I tend to stumble upon a function that I reuse over and over again on my addons.
These snippets are and too small to contribute to the WAYWO thread and way too small for their own threads.

I tend to notice snippets being posted on the WAYWO thread as well, and they’re not typically speaking what people are working on, just small snippets that they deemed practical to coding.

So without further ado, I present to you guys a thread to contribute your snippets and stumble-upons while playing around in lua.

Here’s my contribution:
Returns a log’d number to the base of x.
[lua]
function math.logx( x, num )
return math.log10( num ) / math.log10( x )
end
[/lua]

Threads are bad for something like that, you lose the overview a way too fast.

Someone should make a website thats kinda like pastebin but only for gmod lua snippets, shouldn’t take lots of coding.

Here’s my contribution, this may help more with pure-Lua class implementations, which are less frequently seen in GMod due to having existing built-in class extensions already available. If for whatever reason you need to write such classes, it’s nice to know what the type is, rather than getting “table” generically.

[lua]if ( rawtype ) then
return
end

local tostring = tostring
local getmetatable = getmetatable
rawtype = type

function type( v )
local metatable = getmetatable( v )
if ( metatable and metatable.__type ) then
return tostring( metatable.__type )
end
return rawtype( v )
end
[/lua]

I also wrote this one today, is there already something like this in GMod?

[lua]function math.roundToNearestMultiple( n, mul )
return math.floor( n/mul + 0.5 )*mul
end
[/lua]

UtilX if anyone can remember.

[lua]

– utilx
– A project stared by Gbps
– expanded with community input

utilx = {}
utilx.Version = 1.0


– Meta –

local meta = FindMetaTable(“Player”)
if (meta) then
–[[
User: blackops7799
Name: GetUserGroup()
Usage:
if player.GetByID(1):GetUserGroup() == “<group name>” then
– do something
end
]]

function meta:GetUserGroup()
	return self:GetNetworkedString("UserGroup")  
end

--[[
User: Python1320
Name: IsStuck() - Taken from Source SDK, doesn't fully work though. Just throwing ideas.
Usage:
	&lt;missing&gt;
]]

function meta:IsStuck()
	local tracedata = {}
	tracedata.start = self:GetPos()
	tracedata.endpos = self:GetPos()
	tracedata.mask = MASK_PLAYERSOLID or 33636363
	tracedata.filter = self
	local trace = util.TraceEntity(tracedata,self)
	return trace.StartSolid
end

end


– utilx –

–[[
User: Kogitsune
Name: InSet(object:value,vararg list …) - used to determine if value is inside the list of parameters.
Usage:
if utilx.InSet(ent:GetClass(),“prop_door_rotating”,“player”,“prop_vehicle_jeep”) then
ent:Remove()
end
]]

function utilx.InSet(val,…)
local k, v
for k, v in ipairs{…} do
if v == val then
return true
end
end
return false
end

–[[
User: Kogitsune
Name: HasBit(value,bit) - used to determine if the bit value contains the mask bit.
Usage:
local a,b,c,d,firemodes,mask

a = 0x01
b = 0x02
c = 0x04
d = 0x08

firemodes = a & b & d

if utilx.HasBit(firemodes,c) then
	-- do something
end	

]]

function utilx.HasBit(value,bit)
return (value & bit) == bit
end

–[[
User: Kogitsune
Name: SimplePointEntity(string:class) - Creates a simple point entity with no special methods (pretty much stolen from thomasfn, I believe)
Usage:
utilx.SimplePointEntity(“info_player_zombie”)
utilx.SimplePointEntity(“info_player_human”)
]]

function utilx.SimplePointEntity(class)
local t
t = { }
t.Type = “point”
t.Base = “base_point”
t.Data = {}

function t:SetKeyValue(k,v)
	self.Data[k] = v
end

function t:GetKeyValue(k)
	return self.Data[k]
end	
scripted_ents.Register(t,class)

end

–[[
User: Kogitsune
Name: FastExplode(str:string,str:sep) - Performs a very fast, pattern-based explode on the string, only works with one char as seperator
Usage:
for k,v in ipairs(utilx.FastExplode(file.Read(“sometextfile.txt”),"
")) do
– do something
end
]]

function utilx.FastExplode(str,sep)
local k,t
t = {}
for k in str:gmatch("[^"…sep…"]+") do
table.insert(t,k)
end
return t
end

–[[
User: Overv
Name: IndexFromValue(table:tbl,string:val) - Quickly get the index of the given value or nil if the value wasn’t found
Usage:
local tbl = {“a”,“b”,“c”,“d”,“e”,“f”,“g”}
print(utilx.IndexFromValue(tbl,“f”))
]]

function utilx.IndexFromValue(tbl,val)
local k,v
for k,v in pairs(tbl) do
if (v == val) then return k end
end
return nil
end

–[[
User: stoned (the-stone)
Name: CleanString(string:str) - Makes string usable for filenames
Usage:
file.Write(utilx.CleanString(ply:SteamID())…".txt",“file content…”)
]]

function utilx.CleanString(str)
str = str:gsub(" “,”")
str = str:gsub("[^%a%d
]","")
return str
end

–[[
User: Carnag3
Name: GetSoundLength(string:strPath) - Gets the sound length
Usage:
local len = utilx.GetSoundLength(“sounds/mysong.wav”)
print(len)
]]

function utilx.GetSoundLength(strPath)
return string.ToMinutesSeconds(SoundDuration(strPath))
end

–[[
User: Gbps
Name: FindPointsInLine(vector:vec1,vector:vec2) - It returns a table of all the points(vectors) that make up the line between vec1 and vec2.
Usage:
<missing>
]]

function utilx.FindPointsInLine(vec1,vec2)
local ptstbl = {}
for i=1,100 do
ptstbl* = LerpVector(i*0.01,vec1,vec2)
end
return ptstbl
end

–[[
User: Gbps
Name: GetPlayerTrace(ply,distance) - In a sense, it’s GetPlayerTrace with the added distance argument that is ‘missing’ from the current ply:GetPlayerTrace()
Usage:
<missing>
]]

function utilx.GetPlayerTrace(ply,distance)
local pos = ply:GetShootPos()
local ang = ply:GetAimVector()
local tracedata = {}
tracedata.start = pos
tracedata.endpos = pos+(ang*distance)
tracedata.filter = ply
local trace = util.TraceLine(tracedata)
return trace
end

–[[
User: slayer3032
Name: AddSteamFriend(steamid) – Adds the given user to your steam friendlist
Usage:

]]

function utilx.AddSteamFriend(steamid)
local expl = string.Explode(":",steamid)
local serverid,accountid = tonumber(expl[2]),tonumber(expl[3])
local friendid = string.format(“765%0.f”,accountid * 2 + 61197960265728 + serverid)
http.Get(“http://www.garry.tv/go.php?steam://friends/add/"..friendid,"”,function() print(“User has been added!”) end)
end

–[[
User: awatemonosan
Name: AngleOffset(angle:ang1,angle:ang2) - Finds the difference between ang1 and ang2. Because DOT just doesn’t always do the job.
Usage:
local off = utilx.AngleOffset(Angle(0,0,0),Angle(0,90,0))
> Angle(0,90,0)
local off = utilx.AngleOffset(Angle(345,270,0),Angle(0,180,0))
> Angle(-15,-90,0)
]]

function utilx.AngleOffset(ang1,ang2)
return Angle((ang1.p+180-ang2.p)%360-180,(ang1.y+180-ang2.y)%360-180,(ang1…r+180-ang2.r)%360-180)
end

–[[
User: thomasfn
Name: AddToTable(tbl,val) / RemoveFromTable(tbl,val) - Secure adds and removes values from a given table
Usage:
<missing>
]]

function utilx.AddToTable(tbl,val)
if (!table.HasValue(tbl,val)) then
table.insert(tbl,val)
end
end

function utilx.RemoveFromTable(tbl,val)
for k,v in pairs(tbl) do
if (v == val) then
table.remove(tbl,k)
return
end
end
end

–[[
User: Overv
Name: getCommand(string:str) / getArguments(string:str)
Usage:
<missing>
]]

function utilx.GetCommand(str)
return str:match("%w+")
end

function utilx.GetArguments(str)
local args = {}
local i = 1

for v in str:gmatch("%S+") do  
	if i &gt; 1 then table.insert(args,v) end  
	i = i + 1  
end  
return args  

end

–[[
User: MakeR
Name: Average
Usage:
<missing>
]]

function utilx.Average(…)
local ret, num = 0
for _, num in ipairs(arg) do
ret = ret + num
end
return ret / #arg, ret
end

/*


/\ /\ /__ \_ \ /\ \ /\ \ /\ \
\ \ \ \ /
/\ ///\ / \ \ \ \ \/’/’
\ \ \ \ \ \ \ \ \ \ \ \ \ \ __\/ > < \ \ \_\ \ \ \ \ \_\ \__\ \ \_\ \ \/'/\\
\ _
\ \ _\ /_\ _/ /_\ _
/
/ /_/ // // // /_/

Compiled by Entoros
Function authors listed by respective functions

*/

utilx = {};

/-------------------------------------------------------------------------------------------------------------------------
utilx.InSet( Object val, … )
Returns: Bool inSet
Available On: Shared
Description: Gets whether a value is in a list of parameters
Author: Kogistune
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.InSet( val, … )
local k, v

for k, v in ipairs{ ... } do
	if v == val then
		return true
	end
end

return false

end

/-------------------------------------------------------------------------------------------------------------------------
utilx.SimplePointEntity( String class )
Returns: Entity point_ent
Available On: Server
Description: Creates a simple point entity without any methods
Author: Kogistune
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.SimplePointEntity( class )
local t

t = { }

t.Type = "point"
t.Base = "base_point"
t.Data = { }

function t:SetKeyValue( k, v )
	self.Data[ k ] = v
end

function t:GetKeyValue( k )
	return self.Data[ k ]
end

scripted_ents.Register( t, class )
return t

end

/-------------------------------------------------------------------------------------------------------------------------
utilx.FastExplode( String str, String separator )
Returns: Table exploded_string
Available On: Shared
Description: Breaks up a string based on a separator
Author: Kogitsune
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.FastExplode( str, sep )
local k, t

t = { }

for k in str:gmatch( "[^" .. sep .. "]+" ) do
	table.insert( t, k )
end

return t

end

/-------------------------------------------------------------------------------------------------------------------------
utilx.CleanPath( String path )
Returns: String cleaned_path
Available On: Shared
Description: Makes a string usable in file names
Author: Averice
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.CleanPath(str)
return string.gsub(tostring(str), “[:/\”*%?<>]", “_”)
end

/-------------------------------------------------------------------------------------------------------------------------
utilx.IndexFromValue( Table tab, Object value )
Returns: Object index
Available On: Shared
Description: Gets the index from a table based on the first occurance of a given value
Author: Overv
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.IndexFromValue( tbl, val )
for k, v in pairs( tbl ) do
if ( v == val ) then return k end
end
end

/-------------------------------------------------------------------------------------------------------------------------
utilx.GetPlayerTrace( Player ply, Number distance )
Returns: Trace tr
Available On: Shared
Description: Gets a trace from the player for a certain distance
Author: Gbps
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.GetPlayerTrace(ply,distance)
local pos = ply:GetShootPos()
local ang = ply:GetAimVector()
local tracedata = {}
tracedata.start = pos
tracedata.endpos = pos+(ang*distance)
tracedata.filter = ply
local trace = util.TraceLine(tracedata)
return trace;
end

/-------------------------------------------------------------------------------------------------------------------------
utilx.AddStreamFriend( String steamid )
Returns: nil
Available On: Client
Description: Adds a friend in steam
Author: slayer3032
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.AddSteamFriend(steamid)
local expl = string.Explode(":", steamid)
local serverid, accountid = tonumber(expl[2]), tonumber(expl[3])
local friendid = string.format(“765%0.f”, accountid * 2 + 61197960265728 + serverid)
local panel = vgui.Create(“HTML”)
panel:SetSize(1,1)
panel:OpenURL(“http://www.garry.tv/go.php?steam://friends/add/”…friendid)
timer.Simple(10, panel.Remove, panel)
end

/-------------------------------------------------------------------------------------------------------------------------
utilx.IsOccupied( Vector pos )
Returns: Bool isOccupied
Available On: Shared
Description: Checks if something is at a particular position
Author: Gbps
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.IsOccupied(pos)
local trace = nil
local tracedata = {}
tracedata.start = pos
tracedata.endpos = pos
tracedata.mask = MASK_PLAYERSOLID or 33636363
trace = util.TraceEntity( tracedata , self )
return trace.StartSolid
end

/-------------------------------------------------------------------------------------------------------------------------
utilx VGUI Things
Description: Describe these things
Author: JetBoom
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.WordBox(parent, text, font, textcolor)
local cpanel = vgui.Create(“DPanel”, parent)
local label = EasyLabel(cpanel, text, font, textcolor)
local tsizex, tsizey = label:GetSize()
cpanel:SetSize(tsizex + 16, tsizey + 8)
label:SetPos(8, (tsizey + 8) * 0.5 - tsizey * 0.5)
cpanel:SetVisible(true)
cpanel:SetMouseInputEnabled(false)
cpanel:SetKeyboardInputEnabled(false)

return cpanel

end

function utilx.EasyLabel(parent, text, font, textcolor)
local dpanel = vgui.Create(“DLabel”, parent)
if font then
dpanel:SetFont(font or “Default”)
end
dpanel:SetText(text)
dpanel:SizeToContents()
if textcolor then
dpanel:SetTextColor(textcolor)
end
dpanel:SetKeyboardInputEnabled(false)
dpanel:SetMouseInputEnabled(false)

return dpanel

end

function utilx.EasyButton(parent, text, xpadding, ypadding)
local dpanel = vgui.Create(“DButton”, parent)
if textcolor then
dpanel:SetFGColor(textcolor or color_white)
end
if text then
dpanel:SetText(text)
end
dpanel:SizeToContents()

if xpadding then
	dpanel:SetWide(dpanel:GetWide() + xpadding * 2)
end

if ypadding then
	dpanel:SetTall(dpanel:GetTall() + ypadding * 2)
end

return dpanel

end

/-------------------------------------------------------------------------------------------------------------------------
utilx.DTextDraw( String text, String font, Number x, Number y, Panel parent [, Color col] )
Returns: DPanel pan
Available On: Client
Description: Draws text on a panel with more flexibility than a DLabel
Author: Entoros
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.DTextDraw(text,font,x,y,parent,col)
col = col or color_white
local pan = vgui.Create(“DPanel”,parent)
pan:SetSize(parent:GetWide(),parent:GetTall())
pan:SetPos(0,0)
pan.Paint = function()
draw.DrawText(text,font,x,y,col)
end
return pan
end

/-------------------------------------------------------------------------------------------------------------------------
utilx.PlayeCanSee( Player ply, Entity obj )
Returns: Bool isVisible
Available On: Shared
Description: Checks if a player can see an entity
Author: haza55
-------------------------------------------------------------------------------------------------------------------------
/
function utilx.PlayerCanSee(ply, obj)
if not IsValid( ply ) or not ply:IsPlayer() then return false end
if not obj then return false end

local posmin, posmax = 0, 0

if type(obj) == "vector" then
	posmin, posmax = obj, obj
else
	if !obj:IsValid() then return false end
	posmin, posmax = obj:GetPos() + obj:OBBMaxs(), obj:GetPos() + obj:OBBMins()
end

if CLIENT then
	return (posmin:ToScreen().visible + posmax:ToScreen().visible) &gt; 0
else
	local eye = ply:GetPos() + ply:GetViewOffset()

	local tMin = util.TraceLine({start=eye, endpos=posmin})
	-- If it didnt hit, it must be visible! And if it did hit, and it hit our Entity then we can see it.
	if(!tMin.Hit || (tMin.Hit && tMin.Entity == obj)) then return true end

	local tMax = util.TraceLine({start=eye, endpos=posmax})
	if(!tMax.Hit || (tMax.Hit && tMax.Entity == obj)) then return true end

	return false
end

return false

end

/-------------------------------------------------------------------------------------------------------------------------
A Whole Bunch of Math Functions
Description: Just read the comments
Author: blob202
-------------------------------------------------------------------------------------------------------------------------
/

– Performs a linear interpolation between start and end with the factor amount
function utilx.Lerp(start, endval, amount)
return ((1.0 - amount) * start) + (amount * endval)
end

– Performs a Hermite interpolation (linear with eased inner and outer limits) between start and end with the factor amount
function utilx.Hermite(start, endval, amount)
return utilx.Lerp(start, endval, amount * amount * (3.0 - 2.0 * amount))
end

– Performs a sinusoidal interpolation, while easing around the end (when the return value approaches 1)
function utilx.Sinerp(start, endval, amount)
return utilx.Lerp(start, endval, math.sin(amount * math.pi * 0.5))
end

– Performs a cosinusoidal interpolation, while easing around the start (when the return value approaches 0)
function utilx.Coserp(start, endval, amount)
return utilx.Lerp(start, endval, 1.0 - math.cos(amount * math.pi * 0.5))
end

– Performs a boing-like interpolation, where the end value is initially overshot, and the return value bounces back and fourth the end value before coming to rest
function utilx.Berp(start, endval, amount)
amount = utilx.Clamp(amount, 0.0, 1.0)

amount = (math.sin(amount * math.pi * (0.2 + 2.5 * (amount ^ 3))) * math.pow(1.0 - amount, 2.2) + amount) * (1.0 + (1.2 * (1.0 - amount)))

return start + (endval - start) * amount

end

– Performs a linear interpolation, but eases the values
function utilx.SmoothStep(x, min, max)
x = Clamp(x, min, max)
v1 = (x-min)/(max-min)
v2 = (x-min)/(max-min)
return -2*v1 * v1 v1 + 3v2 * v2
end

– Performs an approach from the old value to the new value
function utilx.Curve(newvalue, oldvalue, increments)
if (increments > 1) then oldvalue = oldvalue - (oldvalue - newvalue) / increments end
if (increments <= 1) then oldvalue = newvalue end
return oldvalue
end

– Returns a value between 0 and 1 as if a ball was bouncing and moving X units
function utilx.Bounce(x)
return math.abs(math.sin(6.28*(x+1.0)*(x+1.0)) * (1.0-x))
end

– Performs a linear interpolation but with respect to circular limits (0 - 360 degrees)
– NOTE: start and end are expected in units of Degrees (0 - 360)
function utilx.Clerp(start, endval, amount)
min = 0.0;
max = 360.0;
half = math.abs((max - min)/2.0)
retval = 0.0;
diff = 0.0;

if((endval - start) &lt; -half) then	
	diff = ((max - start)+endval)*amount
	retval =  start+diff    
elseif((endval - start) &gt; half) then	
	diff = -((max - endval)+start)*amount
	retval =  start+diff    
else 
	retval =  start+(endval-start)*amount
end

return retval

end

– Performs a positive cumulative approach from current to target using the absolute value of the indicated increment
function utilx.Approach(current, target, increment)
increment = math.abs( increment )

if (current &lt; target) then 
	return utilx.Clamp( current + increment, current, target )    
elseif (current &gt; target) then    
	return utilx.Clamp( current - increment, target, current )
end   
return target

end

– Prevention / Precision

– Clamps the value between the minimum and maximum limits
function utilx.Clamp(value, min, max)
if (value < min) then
value = min
elseif (value > max) then
value = max
end
return value
end

– Calculation
function utilx.Average(values)
total = 0

for i,v in pairs(values) do    
	total = total + values*
end
return (total / #values)

end

function utilx.StandardDeviation(values)
avg = 0
totaldev = 0

avg = utilx.Average(values);

for i,v in ipairs(values) do    
	totaldev = totaldev + math.pow(values* - avg, 2);
end

return math.sqrt(totaldev / #values);

end

– Comparison

– Determines whether the difference between the value and target is less than the permitted error
function utilx.Approximate(value, target, errorval)
return ( ( math.abs(value - target) < errorval) )
end

function utilx.CompareFloat(a, b, tolerance)
if ( ( a + tolerance ) < b ) then return -1 end
if ( ( b + tolerance ) < a ) then return 1 end
return 0
end

local pmeta = FindMetaTable(“Player”)
if pmeta then

// ########################
// FUNC: Player.GetUserGroup
// DESC: Get's the usergroup (i.e. admin/superadmin) of a player
// ARGS: none
// AUTH: BlackOps
function _R.Player:GetUserGroup()
	return self:GetNetworkedString( "UserGroup" )
end

end

// ########################
// CONCMD: lua_openscript_sh
// DESC: Basically lua_openscript + lua_openscript_cl on a file at the same time
// ARGS: STRING path
// AUTH: FlapJack/Entoros
if CLIENT then
local function includeCallBack(um)
local path = um:ReadString()
if path then
include(path)
end
end
usermessage.Hook(“LuaInclude” , includeCallBack)
else
local function includeCommand(pl , cmd , args)
if pl:IsSuperAdmin() then
umsg.Start(“LuaInclude”)
umsg.String(table.concat(" " , args))
umsg.End()
include(table.concat(" " , args))
end
end
local function GetPathBefore( path )
if not string.find(path,"/") then return “” end
local path = string.Explode( “/”, path )
table.remove( path, #path )
return table.concat( path, “/” ) … “/”
end
local function getAutoComplete(cmd,args)
local blocked = { “.”, “…”, }
local files = file.FindInLua( string.Trim(args) … “*” )
for k,v in pairs( files ) do
local validfile = true
for blockedk,blockedv in pairs( blocked ) do
if string.find( blockedv, string.Trim(v) ) then
table.remove(files,k)
validfile = false
end
end
if validfile then
if file.IsDir( “…/lua/”…GetPathBefore(args)…v ) then files[k] = cmd …" " … GetPathBefore(args) … v
else files[k] = cmd … GetPathBefore(args) … v end
end
end
return files
end
concommand.Add(“lua_openscript_sh” , includeCommand,getAutoComplete)
end

// ########################
// FUNC: debug.getparams
// DESC: Gets the variable names of the parameters to a function
// ARGS: FUNCTION func
// AUTH: Deco
function debug.getparams(f)
local co = coroutine.create(f)
local params = {}
debug.sethook(co, function()
local i, k = 1, debug.getlocal(co, 2, 1)
while k do
if k ~= “(*temporary)” then
table.insert(params, k)
end
i = i+1
k = debug.getlocal(co, 2, i)
end
error(“end”)
end, “c”)
local res, err = coroutine.resume(co)
if res then
error(“The function provided defies the laws of the universe.”, 2)
elseif string.sub(tostring(err), -7) ~= “end” then
error("The function failed with the error: "…tostring(err), 2)
end
return params
end

// ########################
// FUNC: chat.AddText
// DESC: Serverside func that allows you to add color text to chat
// ARGS: COLOR col OR PLAYER pl OR STRING text
// AUTH: Overv
if SERVER then
chat = { }
function chat.AddText( … )
if ( type( arg[1] ) == “Player” ) then ply = arg[1] end

	umsg.Start( "AddText", ply )
		umsg.Short( #arg )
		for _, v in pairs( arg ) do
			if ( type( v ) == "string" ) then
				umsg.String( v )
			elseif ( type ( v ) == "table" ) then
				umsg.Short( v.r )
				umsg.Short( v.g )
				umsg.Short( v.b )
				umsg.Short( v.a )
			end
		end
	umsg.End( )
end

else
usermessage.Hook( “AddText”, function( um )
local argc = um:ReadShort( )
local args = { }
for i = 1, argc / 2, 1 do
table.insert( args, Color( um:ReadShort( ), um:ReadShort( ), um:ReadShort( ), um:ReadShort( ) ) )
table.insert( args, um:ReadString( ) )
end

	chat.AddText( unpack( args ) )
end )

end

// ########################
// FUNC: draw.RoundedBoxOutlined
// DESC: Draw function that draws a runded box with an outline
// ARGS: NUMBER bordersize, NUMBER x, NUMBER y, NUMBER w, NUMBER h, COLOR bgcol, COLOR bordercol
// AUTH: Jinto?
if CLIENT then
function draw.RoundedBoxOutlined( bordersize, x, y, w, h, color, bordercol )

	x = math.Round( x )
	y = math.Round( y )
	w = math.Round( w )
	h = math.Round( h )

	draw.RoundedBox( bordersize, x, y, w, h, color )
	
	surface.SetDrawColor( bordercol )
	
	surface.SetTexture( texOutlinedCorner )
	surface.DrawTexturedRectRotated( x + bordersize/2 , y + bordersize/2, bordersize, bordersize, 0 ) 
	surface.DrawTexturedRectRotated( x + w - bordersize/2 , y + bordersize/2, bordersize, bordersize, 270 ) 
	surface.DrawTexturedRectRotated( x + w - bordersize/2 , y + h - bordersize/2, bordersize, bordersize, 180 ) 
	surface.DrawTexturedRectRotated( x + bordersize/2 , y + h -bordersize/2, bordersize, bordersize, 90 ) 
	
	surface.DrawLine( x+bordersize, y, x+w-bordersize, y )
	surface.DrawLine( x+bordersize, y+h-1, x+w-bordersize, y+h-1 )
	
	surface.DrawLine( x, y+bordersize, x, y+h-bordersize )
	surface.DrawLine( x+w-1, y+bordersize, x+w-1, y+h-bordersize )

end

end

// ########################
// FUNC: Particle
// DESC: Like function “Sound”, precaches particle system and returns the name
// ARGS: STRING particle_name
// AUTH: Entoros
function Particle( name )
PrecacheParticleSystem( name )
return name
end[/lua]

Not really complicated or anything, still useful.

[lua]
– Format line
– Adds new lines to a string to make it fit in a certain panel

function JB.util.FormatLine(str,font,size) --size equals width in pixes
surface.SetFont( font );

local start = 1;
local c = 1;	
local endstr = "";
local n = 0;
local lastspace = 0;
while( string.len( str ) &gt; c )do
	local sub = string.sub( str, start, c );
	if( string.sub( str, c, c ) == " " ) then
		lastspace = c;
	end

	if( surface.GetTextSize( sub ) &gt;= size ) then
		local sub2;
		
		if( lastspace == 0 ) then
			lastspace = c;
		end
		
		if( lastspace &gt; 1 ) then
			sub2 = string.sub( str, start, lastspace - 1 );
			c = lastspace;
		else
			sub2 = string.sub( str, start, c );
		end
		endstr = endstr .. sub2 .. "

";
start = c + 1;
n = n + 1;
end
c = c + 1;
end

if( start &lt; string.len( str ) ) then
	endstr = endstr .. string.sub( str, start );
end

return endstr, n;

end[/lua]

[editline]27th October 2011[/editline]

copy pasted right from my jailbreak game mode

you’re missing the JB and JB.util table there

Technically we are.

[lua]function util.GetNumberSuffix(num)
local n = num%10
if (num-n)==10 then return “th” end
return (n==1 and “st” or n==2 and “nd” or n ==3 and “rd” or “th”)
end[/lua]

Base64

[lua]
base64 = {}

local value = 1

function base64:lsh(value,shift)

value = value or 1

return (value*(2^shift)) % 256

end

function base64:rsh(value,shift)

value = value or 1

return math.floor(value/2^shift) % 256

end

function base64:bit(x,b)

return (x % 2^b - x % 2^(b-1) &gt; 0)

end

function base64:lor(x,y)

result = 0

for p=1,8 do result = result + (((self:bit(x,p) or self:bit(y,p)) == true) and 2^(p-1) or 0) end

return result

end

local base64chars = {[0]=‘A’,[1]=‘B’,[2]=‘C’,[3]=‘D’,[4]=‘E’,[5]=‘F’,[6]=‘G’,[7]=‘H’,[8]=‘I’,[9]=‘J’,[10]=‘K’,[11]=‘L’,[12]=‘M’,[13]=‘N’,[14]=‘O’,[15]=‘P’,[16]=‘Q’,[17]=‘R’,[18]=‘S’,[19]=‘T’,[20]=‘U’,[21]=‘V’,[22]=‘W’,[23]=‘X’,[24]=‘Y’,[25]=‘Z’,[26]=‘a’,[27]=‘b’,[28]=‘c’,[29]=‘d’,[30]=‘e’,[31]=‘f’,[32]=‘g’,[33]=‘h’,[34]=‘i’,[35]=‘j’,[36]=‘k’,[37]=‘l’,[38]=‘m’,[39]=‘n’,[40]=‘o’,[41]=‘p’,[42]=‘q’,[43]=‘r’,[44]=‘s’,[45]=‘t’,[46]=‘u’,[47]=‘v’,[48]=‘w’,[49]=‘x’,[50]=‘y’,[51]=‘z’,[52]=‘0’,[53]=‘1’,[54]=‘2’,[55]=‘3’,[56]=‘4’,[57]=‘5’,[58]=‘6’,[59]=‘7’,[60]=‘8’,[61]=‘9’,[62]=’-’,[63]=’_’}

function base64:enc(data)

local bytes = {}

local result = ""

for spos=0,string.len(data)-1,3 do

	for byte=1,3 do bytes[byte] = string.byte(string.sub(data,(spos+byte))) or 0 end

	result = string.format('%s%s%s%s%s',result,base64chars[self:rsh(bytes[1],2)],base64chars[self:lor(self:lsh((bytes[1] % 4),4), self:rsh(bytes[2],4))] or "=",((#data-spos) &gt; 1) and base64chars[self:lor(self:lsh(bytes[2] % 16,2), self:rsh(bytes[3],6))] or "=",((#data-spos) &gt; 2) and base64chars[(bytes[3] % 64)] or "=")

end

return result

end

local base64bytes = {
[‘A’]=0,[‘B’]=1,[‘C’]=2,[‘D’]=3,[‘E’]=4,[‘F’]=5,[‘G’]=6,[‘H’]=7,[‘I’]=8,[‘J’]=9,[‘K’]=10,[‘L’]=11,[‘M’]=12,[‘N’]=13,[‘O’]=14,[‘P’]=15,[‘Q’]=16,[‘R’]=17,[‘S’]=18,[‘T’]=19,[‘U’]=20,[‘V’]=21,[‘W’]=22,[‘X’]=23,[‘Y’]=24,[‘Z’]=25,[‘a’]=26,[‘b’]=27,[‘c’]=28,[‘d’]=29,[‘e’]=30,[‘f’]=31,[‘g’]=32,[‘h’]=33,[‘i’]=34,[‘j’]=35,[‘k’]=36,[‘l’]=37,[‘m’]=38,[‘n’]=39,[‘o’]=40,[‘p’]=41,[‘q’]=42,[‘r’]=43,[‘s’]=44,[‘t’]=45,[‘u’]=46,[‘v’]=47,[‘w’]=48,[‘x’]=49,[‘y’]=50,[‘z’]=51,[‘0’]=52,[‘1’]=53,[‘2’]=54,[‘3’]=55,[‘4’]=56,[‘5’]=57,[‘6’]=58,[‘7’]=59,[‘8’]=60,[‘9’]=61,[’-’]=62,[’_’]=63,[’=’]=nil
}

function base64:dec(data)

local chars = {}

local result=""

for dpos=0,string.len(data)-1,4 do

	for char=1,4 do chars[char] = base64bytes[(string.sub(data,(dpos+char),(dpos+char)) or "=")] end

	result = string.format('%s%s%s%s',result,string.char(self:lor(self:lsh(chars[1],2), self:rsh(chars[2],4))),(chars[3] ~= nil) and string.char(self:lor(self:lsh(chars[2],4), self:rsh(chars[3],2))) or "",(chars[4] ~= nil) and string.char(self:lor(self:lsh(chars[3],6) % 192, (chars[4]))) or "")

end

return result

end[/lua]

Sweet! I had needed a base64 encoding written in Lua, that was until Garry made the net library

[lua]local b=‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/’

– encoding
function enc(data)
return ((data:gsub(’.’, function(x)
local r,b=’’,x:byte()
for i=8,1,-1 do r=r…(b%2^i-b%2^(i-1)>0 and ‘1’ or ‘0’) end
return r;
end)…‘0000’):gsub(’%d%d%d?%d?%d?%d?’, function(x)
if (#x < 6) then return ‘’ end
local c=0
for i=1,6 do c=c+(x:sub(i,i)==‘1’ and 2^(6-i) or 0) end
return b:sub(c+1,c+1)
end)…({ ‘’, ‘==’, ‘=’ })[#data%3+1])
end

– decoding
function dec(data)
data = string.gsub(data, ‘[^’…b…’=]’, ‘’)
return (data:gsub(’.’, function(x)
if (x == ‘=’) then return ‘’ end
local r,f=’’,(b:find(x)-1)
for i=6,1,-1 do r=r…(f%2^i-f%2^(i-1)>0 and ‘1’ or ‘0’) end
return r;
end):gsub(’%d%d%d?%d?%d?%d?%d?%d?’, function(x)
if (#x ~= 8) then return ‘’ end
local c=0
for i=1,8 do c=c+(x:sub(i,i)==‘1’ and 2^(8-i) or 0) end
return string.char©
end))
end[/lua]

Base64 in less code.