Navigation

Knowledgebase

gLua 101 - An Introduction to Garry's Mod coding

Last updated: 02/24/19
written by  Nodecraft Staff

Introduction

Learning any kind of programming language won't happen overnight. It takes a lot of time, dedication and trial and error to perfect your knowledge. While this guide aims to give you a head start, you can really only learn by playing with the language and engine, in your own good time.

Here's a few tips though:

  • Get an idea. Learning a language is so much easier when you are trying to make some specific.
  • Don't give up. Just because things aren't working right off the bat, doesn't mean you can't fix it. Spend time with it. Spend time planning and thinking how you want to set up the logic.
  • Learn by reading - chances are there are already scripts on the internet that do something similar to what you are wanting to do. Find those examples, then see how they have done it. Try to understand the logic of what a script is doing, even if you don't understand all the specific functions.

The language is combining a vast amount of different concepts, which, no doubt, will be hard to grasp for a beginner. The best tip here is to ignore it, and focus on the logic. You'll pick up the rest in your own good time.

Resources

There are a few resources we'd recommend getting familiar with for Garry's Mod coding.

  • An editor. Notepad++ is a great free editor, though Sublime Text, or VS Code will work just as well.
  • Recommended gLua sytnax highligher. Notepad++ variant. Sublime Text variant.
  • Garry's Mod Wiki. This contains everything gLua. Everything related to anything in Garry's Mod, including some tutorials and other resources.
  • Lua Documentation. Very useful resource, but can be overwhelming and hard to read for beginners.

Useful folder locations

  • steam\steamapps\<username>\garrysmod\garrysmod\lua\ You can put single script files in here, and open them directly ingame, no further configuration required. Try it! Run the command lua_openscript .lua in console in singleplayer.
  • steam\steamapps\<username>\garrysmod\garrysmod\addons\ This is where you can put your addons, even your own if you create one
  • steam\steamapps\<username>\garrysmod\garrysmod\gamemodes\ You can download gamemodes such as darkrp and put them in here, to create your own server with that gamemode on.

What is gLua?

gLua is Garry's Mod adaption of the open source Lua language.

Lua is a language best described as a plugin language, often used for addons and plugins, from everything between Garry's Mod to World of Warcraft, Factorio, and even VLC. One way to think of it is that Lua is a simplified language which allows you to run functions on a more complex, underlying engine.

For us, that means that doing stuff in Lua is sent to the source engine, which puts it together. It also means that whatever limitations the source engine has, we also have.

As noted, we often call the Garry's Mod adaption of the Lua language, gLua. The adaption involves a few differences from the official language, listed below.

Name Standard Lua gLua (C-Style)
Multi-Line Comments --[[ comment ]] /* comment */
Single Line Comments -- comment // comment
And and &&
Or or ||
Not not !
Not-Equal ~= !=

These additions to standard Lua make it easier for users coming from another language to write code in Lua. The standard Lua syntax still works, but these additions are just for ease-of-use.

Concepts

  • Variable - The bread and butter of any programming language, it functions like a container, or holder, and can be assigned to hold anything. It can be called anything. Its wise to call it something that'll make you understand what it is used for.
  • Datatypes - A variable can only hold one specific datatype at a time. String, number, vector (location), color, functions, and so forth are datatypes.
  • String - Simple text. Encased by quotes, like this "text". You've probably already noticed that you have to do the same for some console commands?
  • Table - Also called arrays. This is a datatype that holds other variables.
  • Function - A piece of reusable code that will perform the same action every time it is called.
  • SWEP - Short for Scripted Weapon. Keys, flamethrower, ak47, are all examples of SWEP's.
  • SENT - Short for Scripted Entity. Keypad, weapon shipment, dynamic doors, dropped money are all examples of SENT's.
  • Entity - In source engine, and in many other contexts, objects are referred to as entities. A player is an entity. The weapon a player is holding is an entity. Dropped money is an entity. All SWEP's and SENT's are entities.
  • Shared, serverside, clientside, cl_init, init, etc - Gmod revolves around two worlds; what happens on the server, and what happens on the client (on your computer as you play). The expressions mentioned here are essential as to describe where something is happening.

Example

MyString = "Hello world" -- Notice how it supports spaces? That is not the case for variable names (string, left of the equal sign)
MyNumber = 15 -- No quotes necessary here. The program understands a number
MyTable = { "Hello world", 15 } -- Notice how we were able to place both of the above variables into a single variable here - such is the power of tables.
function myFunction()
    print(MyString, MyNumber, MyTable) -- each time we call myFunction(), it will print the string, number, and table into the ingame console.
end
myFunction() -- and this is how we call the function.

This is actual, working code. Run that ingame, and it will output "Hello world" 15 table: [Some random number].

Dissecting our first script

The best way to learn Lua (or any language) is to look at existing code; there is no way to avoid it. You will be presented with both functions and concepts you won't understand. Instead, take the code for granted, and instead focus on understanding the logic. The logic is the main barrier in any script. Knowledge is easy - figuring out how to make it work is the hard part.

We'll begin by looking at part of an older money printer's logic. Note that this example is limited, and may not work in more recent versions of Garry's Mod or DarkRP. It serves purely as an introduction to Garry's Mod Lua.

local PrintMore
function ENT:Initialize() -- This is a function that is called when the printer is created.
        self:SetModel("models/props_c17/consolebox01a.mdl") -- Here we set the model. This is a model you can find in the Q menu ingame.
        self:PhysicsInit(SOLID_VPHYSICS) -- We want the money printer to be affected by physics, such as gravity. This is automatically taken care of by the engine when we set this.
        self:SetMoveType(MOVETYPE_VPHYSICS) -- This defines how the money printer reacts to movement.
        self:SetSolid(SOLID_VPHYSICS) -- Here we set whether or not the printer is solid or not.
        local phys = self:GetPhysicsObject() -- PhysicsInit above gave the printer a physic object, which we retrieve here.
        if phys:IsValid() then phys:Wake() end -- We check that everything went according to plan, then we wake the physic object up (it'll fly midair unless we do this).
        self.sparking = false -- This is a variable we'll be using later.
        self.damage = 100 -- This is the health of the printer.
        self.IsMoneyPrinter = true
        timer.Simple(27, PrintMore, self) -- We start the first print cycle. Notice that it's set to 27 seconds.
end

function ENT:OnTakeDamage(dmg) -- This function is called when the printer takes damage.
        if self.burningup then return end -- If the printer is already burning, we "return", meaning we interrupt the script, thus disallowing damage to the printer.

        self.damage = (self.damage or 100) - dmg:GetDamage() -- Here we use the variable `.damage` that was set in Initialize, then apply the received damage.
        if self.damage <= 0 then -- if the health of our printer is equal to or less than 0...
                local rnd = math.random(1, 10) -- pick a random number between 1 and 10, and store it in the "rnd" variable
                if rnd < 3 then -- if the random number we picked is less than 3 then we...
                        self:BurstIntoFlames() -- put it on fire!
                else -- but if the number was 3 or higher then we..
                        self:Destruct() -- explode it
                        self:Remove() -- and remove it!
                end
        end
end

function ENT:Destruct() -- This is a custom function that is called when we want to blow the printer up.
        -- We'll create a custom effect of an explosion.
        local vPoint = self:GetPos() -- First, we get the position of our printer, and store that in vPoint for later use
        local effectdata = EffectData() -- Then we create the effect...
        effectdata:SetStart(vPoint) -- set its position using vPoint
        effectdata:SetOrigin(vPoint) -- this is also setting its position
        effectdata:SetScale(1) -- this is how big the explosion will appear
        util.Effect("Explosion", effectdata) -- We've finished defining our explosion, time to put it into action. util.Effect(effect-type, settings)
        Notify(self.dt.owning_ent, 1, 4, "Your money printer has exploded!") -- we give the player a heads up, that their printer has blown up.
end

function ENT:BurstIntoFlames() -- This is a custom function that is called when we want to put the printer on fire.
        Notify(self.dt.owning_ent, 1, 4, "Your money printer is overheating!") -- we start off by giving the player a heads up that their printer is on fire!
        self.burningup = true -- We prevent the printer from taking more damage, so it can burn in peace (see ENT:OnTakeDamage())
        local burntime = math.random(8, 18) -- we pick a random number between 8 and 18, which will be how long it will burn
        self:Ignite(burntime, 0) -- we put the printer on fire..
        timer.Simple(burntime, self.Fireball, self) -- .. and after that duration we call the ENT:Fireball() function, which will blow the printer up.
end

function ENT:Fireball() -- This is a custom function that is called after the printer has been burning for a while
        if not self:IsOnFire() then return end -- If the printer isn't on fire, this must have been called by a mistake. Abort abort!
        local dist = math.random(20, 280) -- Explosion radius.
        self:Destruct() -- We call the ENT:Destruct() function to create the explosion effect.
        for k, v in pairs(ents.FindInSphere(self:GetPos(), dist)) do -- We search the surrounding vicinity of the printer, and for each item we find we..
                if not v:IsPlayer() and not v.IsMoneyPrinter then v:Ignite(math.random(5, 22), 0) end -- check that the item is not a player or another printer, then we put it on fire for a random duration between 5 and 22 seconds.
        end
        self:Remove() -- All done! The printer has gone KABOOM and ignited other random things in the area. Now we can remove the printer.
end

PrintMore = function(ent) -- This is an alternative version of creating a function. Don't be alarmed, it works exactly the same.
        if ValidEntity(ent) then -- if the printer still exists..
                ent.sparking = true -- we make the printer spark, like it does when its about to print money
                timer.Simple(3, ent.CreateMoneybag, ent) -- after 3 seconds it will attempt to create money. Notice: 27 seconds first time + 3 seconds - 30 seconds from spawn. Always.
        end
end

function ENT:CreateMoneybag() -- This is a custom function that we call when we want the printer to attempt printing money
        if not ValidEntity(self) then return end -- Printer no longer exist! Abort abort!
        if self:IsOnFire() then return end -- Printer is burning! Abort abort!
        local MoneyPos = self:GetPos() -- All is well, we proceed to figure out where the money should be spawned. We use the location of the printer.

        if math.random(1, 22) == 3 then self:BurstIntoFlames() end -- We make a random number between 1, and 22. And if that number is 3 exactly, we put the printer on fire! >:3

        local amount = GetConVarNumber("mprintamount") -- We check the server CVAR for how much money we should print
        if amount == 0 then -- if server cvar is somehow set to 0 (probably broken), we default to 250
                amount = 250
        end

        DarkRPCreateMoneyBag(Vector(MoneyPos.x + 15, MoneyPos.y, MoneyPos.z + 15), amount) -- We actually create the money.
        self.sparking = false -- we are done creating money. No need to spark anymore.
        timer.Simple(math.random(100, 350), PrintMore, self) -- We start the next print cycle, between 100-350 seconds from now.
end

function ENT:Think() -- This is an engine function, which is called every "frame" or FPS that the server is alive on (i.e extremely often)
        if not self.sparking then return end -- if we aren't busy printing money, we have no further business here. We stop the script.

        -- the following is creating the spark effect the printer makes when its about to print money. As defined in PrintMore, it'll continue to do so for 3 whole seconds.
        local effectdata = EffectData()
        effectdata:SetOrigin(self:GetPos())
        effectdata:SetMagnitude(1)
        effectdata:SetScale(1)
        effectdata:SetRadius(2)
        util.Effect("Sparks", effectdata)
end

Copy this script into your editor of choice, such as Notepad++ and activate your GLua syntax checker. Comments (text after the -- characters) are generally highlighted in grey, which will hopefully help you understand how it works.

So, what are the main parts to take with you from this example? To make a money printer, we have to figure out the following parts:

  • What happens when the printer is spawned? Is it automatically bound by gravity and physics?
  • How do we make it start printing money, and how do we make this continue to happen as long as the printer is alive?
  • What happens when the printer takes damage?
  • How do we determine how much money the printer should print?
  • How can we make it appear like the printer is randomly overheating?
  • How can we randomize all of the events above?

Other Useful Tips

  • Be realistic. Don't try to make a gamemode on your first day of writing lua. Start with something easy, such as changing the ammo type of an existing weapon.
  • Lua is always accessible ingame. If you are hosting a server from your computer, you can do lua_run <lua code> from your console! lua_run_cl is also available on the client to run client-side code, unless prevented by the server.
  • Learn how to navigate https://wiki.garrysmod.com. It can instantly tell you how anything works, if you know how to use the site.
  • Create yourself an environment you can experiment in! By using the "Start new game" from main menu, Garry's Mod, followed by "Start multiplayer", you've got yourself a fully functional, free, all-included multiplayer server. Download an admin mod addon to change map and such.
  • When you are experimenting with code:
    • lua_openscript to mess with simple one-file scripts (requires no restart)
    • Map restart when you are editing existing scripts
    • If you add or remove files (such as addons, or gamemode files), this generally requires a restart

Can't find answers to your questions?

Feel free to contact our support team for personal and professional help.

Write Articles, Get FREE Servers!

More information coming soon.

Chat blocked!

Nodecraft is an ad-free website! Disable adblock if you have any questions.