This page serves as a good reference for Lua code stuff. Read in small chunks as you need it. Don't try and just read front-to-back if you've never coded before. :D
Our dream game has been planned. It's been in the back of our heads for decades, and finally we decide we're gonna do something about it.
But now we need to start making magic happen. Except since magic doesn't exist, we go for the next best thing, that also requires high Intelligence and Wisdom. We call this magical thing scripting. LuaVerge uses a scripting language called Lua, which you can read about elsewhere. vx is a bunch of nifty additions to LuaVerge that look pretty.
Lua scripts are extremely useful and cool! But they might be hard to read and understand if you've never seen them before. So let's explain the various pieces of language!
Variables can have any name consisting of letters, cute little underscores and happy digits. For example, x, y, x2, nachos45 or octopus_leg_count!
Think of variables as a way of remembering information! If you give something to the computer it normally only looks at once and then forgets about it. With variables, you can talk about something you did earlier, and Lua will totally remember!
You're given the equivalent of "Hey can you remember that an octopus has eight legs?" And Lua will be all, "Hey yeah, I can do that!". Provided you give declare it a variable:
octopus_leg_count = 8
See how simple that was? We use the equals = sign for setting a variable.
And we've magically made a Lua variable. We can now use this little trivia to come up with a formula for how many legs the legendary quadrapus would have. And a few of their close cousins too!
octopus_leg_count = 8 -- The quadrapus has half the number of legs an octopus has! quadrapus_leg_count = octopus_leg_count / 2 -- The pentapus has one more leg than a quadrapus! pentapus_leg_count = quadrapus_leg_count + 1 -- The heptapus is one leg short of an octopus. Sad story. heptapus_leg_count = octopus_leg_count - 1 -- The hexapus has twice as many legs as an octopus! Scary. hexapus_leg_count = octopus_leg_count * 2
Whoa! That's a lot of stuff!
Okay first of all, see those lines with the two dashes -- in front of them? Those are comments. Little remarks you can put so that you, and other people can get a clue as to what's going on in your code. They're completely ignored by Lua. As you can probably imagine, comments are sometimes handy when you want to keep parts of your code from running in your script. (Oh and there's another type of comment that can work multiple lines! --[[ COMMENT GOES HERE ]])
Now, we used a bunch of arithmetic there. We used + for addition, - for subtraction, * for multiplication, and / for division. There are other operations that can be done as well! % does modulo (remainder from division) and ^ does exponentation.
Now you can crunch out numbers to your heart's content!
Now that we know how to do all sorts of crazy number manipulation, maybe we'd want to do stuff with text as well?
This calls for strings. Strings are a way representing text in Lua.
Think of a big spool of phantasmal, thin rope-like fabric tying together text. We're in kindergarten again, so we're going to use our glue stick, our favorite construction paper and blue safety scissors to put our name on this string. We've just strung together the letters, and clumped them on! Now we've got a pretty decoration to show off!
I just made mine, it says "ANDY" in red construction paper.
Now the Lua equivalent to that flashback to kindergarten is as follows:
name = "Andy"
The quotes are Lua's equivalent to construction paper and glue and physical spools of string. The text is now on display for Lua. And we put it in a variable called name. We can use either single or double quotes.
This would store our name, Andy. But we didn't exactly introduce ourselves very well. We just went straight to the names. Don't you remember anything about talking to people? You need to make that a complete sentence so you don't seem like some scary sociopath!
name = "Andy" greeting = "Hello. My name is " .. name .. "!"
Much better! Note the use of .. to put strings together with variables. It concatenates them. In other words, think of the strings being tied together, and .. is like tying a knot between the strings, attaching them to each other.
But what if we want to tell them how old we are, and we use a variable to figure out that number?
name = "Andy" age = 2008 - 1988 greeting = "Hello. My name is " .. name .. "!" greeting = greeting .. " I am " .. tostring(age) .. " years old!"
This is where we use tostring. This turns a number (like 20) into in a string (like "20"). Why the distinction between text and numbers? Who knows! Just remember that if you want to treat numbers as if they were text, you need to convert them, hence tostring. Note the parentheses ()around age there. They mean business. Don't forget them!
Anything that can be classified as a simple yes or no with no middle ground, can be a boolean.
Let's tell Lua I'm wearing pants right now, but I haven't flossed today.
pants = true flossed = false
The values true and false are the only boolean values.
My pants are on! True.
I forgot to floss! No means False.
They can be used as on/off, yes/no toggles like that.
But sometimes you want to ask questions that can be answered yes or no.
So let's do that! Let's give Lua a pop quiz! Is my name Andy? Is 3 greater than or equal to 5? My name isn't Gus, right?
name = "Andy" answer = (name == "Andy") answer2 = (3 >= 5) answer3 = (name ~= "Gus")
We'd get that answer is true, answer2 is false and answer3 is true. But what are those parentheses () and weird equals signs for?
Well, okay the parentheses aren't really needed, they just make it easier to read when you're assigning the comparison to a variable.
...But uhm, anyway!
Those equal signs are for comparing things. == compares for equality and gives back true if the things on both sides of the double equals are the same. ~= compares for inequality, that is, the two things aren't the same. < is less than, > is greater than, <= is less than or equal to, and >= is is greater than or equal to. These come in handy.
We can also combine boolean conditions with the or operator, and operator, and not operator. The or operation is true if either or both conditions are true and it's false otherwise. The and operation is true only when both conditions are true. The not operation tells us the opposite of a condition, so not false conditions are true and not true conditions are false.
It's silly, but I've always had a hunger for espionage. If I could turn invisible, nobody could see me! I could sneak into peoples' rooms, follow them around, and read their cute little secrets.
It's not quite as overwhelming as reading peoples' minds, because you don't need to hear annoying voices all the time. And you'd be a pro at hide-and-seek! Well, provided your friends actually looked for you and weren't jerks who were doing as a way of telling you to get lost.
Invisibility would also mean you could perform awesome magic tricks, and run away from those jerks who won't stop following you.
Anyway, I told you how awesome it'd be if I were invisible. Now let's convince Lua in simple words that I am invisible!
invisible = true
if invisible then
happiness = 5 -- When I can't be seen, I'm a very happy guy.
end
But what if weren't invisible? What if invisible was... false? Then what happens?
Nothing, currently. We need to tell Lua if we want it to do something otherwise.
if invisible then
happiness = 5 -- When I can't be seen, I'm a very happy guy.
else
happiness = -24576 -- I'm really embarrassed when I can be seen.
end
We use else! This is what happens otherwise
Well, that isn't strictly true though. I'm usually okay with being visible when I'm wearing pants
if invisible and not clothed then
happiness = 5 -- When I can't be seen, I'm a very happy guy.
elseif clothed then
happiness = 3 -- I guess I'm alright. But admit it, being invisible would rock!
else
happiness = -24576 -- I'm really embarrassed when I can be seen without pants.
end
I used a middle thing elseif, to say "otherwise, do this, but only if ____". You can have as many of those as you want after an if.
Notice that we used boolean variables there in our if statements so far. This is important in most cases.
We can use other types, but this has limited use. Lua will convert a non-boolean value into automatically when in a conditional statement. This automatic transformation is known as coercion.
if 0 then -- Always executes!
message = "Hey, it's a zero! How are you?"
else -- Never happens!
message = "This will never be executed"
end
But note that practically every value is coerced to true! Except for the value false, ... and, one other value, that is cold and empty. This seems useless generally, until we explain something. (This is an important distinction from a handful of languages have many kinds of "empty" values that evaluate to false)
Sometimes we have a bunch of similar data. We want to group it together, somehow. These are where tables come in handy!
Lua's table type is multipurpose and extremely handy! Understanding at least some of there simple uses gives you a ton of mileage in Lua code.
These tables are a beautiful glossy wood, and are living breathing beings. They have at least 12,000 gallant legs and can grow a million more . They can fold up into a tiny lump, and they serve as a Lua's dinner table, Lua's desk, Lua's wardrobe.
Before going any further with tables, I think it's best I warn about the darkened weilder of Lua anti-matter, nil. He's an adversary, but used carefully, the warrior of absense can be an ally. He appears whenever a variable or table entry doesn't exist! nil represents the absolute absense of anything.
If you try use a variable that isn't there (maybe just a typo -- watch out), without checking if it's nil then extremely terrible things happen. nil isn't cooperative, he's downright fiendish. He'll cause you to terminate (if you're a Lua script, anyway).
Setting something equal to nil is letting that thing be destroyed. Useful for covering your tracks and getting rid of information you don't need anymore. You know, toss some crap into the trash compactor and have it be squished into nonexistance. NIL.
As a boolean, nil is false, just because he's the embodiment of falsehoods and emptiness! Also because it's handy to check if something exists.
nil is the only other value that is coerced to false. So when we use if statements, we can check that a variable was set to something (initialized) by going something like:
if not myvar then
happiness = -5000
end
The simplest kind of table is an empty one. It's an empty container. You can do this by going:
container = {}
The {} represents the empty table. There's nothing inside of it! But it exists, unlike nil.
Strings also have an "empty" form.
name = ""
Nil is absolutely nothing. {} are "" empty, but 'exist' to the Lua code, meaning you can add onto them. These can both come in handy if you want to start something off empty and gradually add the things to a table or string later.
The second simplest kind of table is pretty much a list.
Think of a simple list of meals during the day. You could list them: Breakfast, Lunch and Dinner.
The same way of expressing that list in Lua is like this:
meals = {"Breakfast", "Lunch", "Dinner"}
We just made a list (or table!) of meals. meals is a table variable we made up. The curly braces { and } say where the listing starts and where it ends. The comma , is used to separate each thing, just like we do with regular English.
Those quotes are just because we put strings inside, but we can actually put pretty much anything in the list (I'll demonstrate this later on if you don't quite see how it works).
We can now retreive these things from the list, sort of like variables but with a small difference.
meals = {"Breakfast", "Lunch", "Dinner"}
message = "I had eggs for " .. meals[1] .. ", burritos for " .. meals[2] .. ", and steak for " .. meals[3] .. "!"
This puts "I had eggs for Breakfast, burritos for Lunch, and steak for Dinner!" into the variable message. Notice the square brackets [] with a number inside after refering to a specific meal entry. This lets us get the first item, the second item, and the third item, any item out of the table! We can even substitute that number inside the [] for a variable! (Note that this is different than a bunch of other programming languages that use 0 as the first item, 1 as the second item and go up to n-1 items)
Maybe you want to be sneaky and switch up the meals? Try this!
meals = {"Breakfast", "Lunch", "Dinner"}
meals[0] = "Brunch"
meals[1] = "a Snack"
meals[2] = "my Birthday"
message = "I had eggs for " .. meals[1] .. ", burritos for " .. meals[2] .. ", and steak for " .. meals[3] .. "!"
This puts "I had eggs for Brunch, burritos for a Snack, and steak for my Birthday!" into the variable message. We got this by setting a specific item in the list.
And as I promised, I demonstrate that you can store other things inside these tables.
winning_lottery_numbers = {4, 12, 23, 35, 39, 46}
Here in this case I just used numbers. Winning lucky numbers! Ho ho ho. I'm gonna be rich!
But let's do something funky.
crazy = {34, "Waffle fries", true}
How to know what this does completely depends on context. But now we've just put together three things of unique types in a list.
Oh yeah, and sometimes we wanna know just how many things there are in the list. A count.
meals = {"Breakfast", "Lunch", "Dinner"}
if #meals > 0 then
ate_today = true
end
This is what the # sign is for. Put it in front of a list kind of variable and it'll tell you how many things are there, giving you back a number.
Another simple kind of table is one that lets you look things up, a dictionary. It pairs things together, much like a dictionary in real life pairs a word up with its meaning.
words = {
kitten = "A kind of feline that's really cute! They meow and claw up your furniture!",
puppy = "A kind of canine that that's really cute! They bark and drool on your newspaper!"
}
Lua's dictionaries can be used for other things though. Like storing tidbits of information!
person = {
name = "Andy",
job = "Warrior",
age = 2008-1988,
pants = true,
invisible = true
}
See? As with other tables, you still have braces {} around the table. There's a key name, then an equals sign for assignment =, then the value.
So, how do we get the entries out of a dictionary table? Let's form another greeting about Andy!
person = {
name = "Andy",
job = "Warrior",
age = 2008-1988,
pants = false,
invisible = true
}
greeting = "Hello, my name is " .. person["name"] .. ", and I am a " .. person["age"] .. " year old " .. person["job"] .. ". "
if person["pants"] then
greeting = greeting .. " I am delighted to inform you that I am wearing pants. "
else
greeting = greeting .. " I regret to inform you that I am NOT wearing pants. "
end
if person["invisible"] then
greeting = greeting .. "But unfortunately you can't see me anyway. Mwahahahah."
end
Note that, as before, you have the square brackets [] around the thing you're looking up. But this time they're strings, not numbers.
You can, however, use numbers or booleans or even other values to look up in the table. That is, without turning them into string form.
...
Wait, using numbers to look up things? Doesn't that sound like a list?
You're right! Lists are made when you don't specify a key to go with a value. But you can make something equivalent to a list with a dictionary!
meals = {"Breakfast", "Lunch", "Dinner"}
meals_dictionary = {
[1] = "Breakfast",
[2] = "Lunch",
[3] = "Dinner"
}
This dictionary is identical to the table.
Notice that the dictionary has square brackets [] around the numbered entries we specify. We need those to tell Lua that we want to use a non-string key.
And as before, you can set things in a list, similar to how you get them out of a list:
person["name"] = "Gus"
Dictionary-style tables are used a lot. So learn how to use them!
Okay, tables have plenty of uses. And we've gone long enough without telling you a quick way to loop over their entries.
person = {
name = "Andy",
job = "Warrior",
age = 2008-1988,
pants = false,
invisible = true
}
message = ""
for key, value in pairs(person) do
message = key .. " = " .. value .. "! "
end
See that? A for loop! This iterates over the pairs of the person table and puts each key in a variable called key and value in a variable called value. The pairs(person) part is tells it to spit out each entry as we go along. Then it performs the code in the block for each each entry in the table.
pairs does not guarantee the order of anything. So it could print things out in an order completely different than the way we put them in!
This is because tables don't actually keep things in order when you store them.
It's much like how I keep stuff in my room! I know where everything is when I want to find it, but I don't exactly find the contents of my room in alphabetical order! That's too much bookkeeping and just doesn't make sense most of the time.
I mean, alphabetizing your bookshelf? Maybe.
Alphabetizing the placement of your furniture? You're a sad, sad excuse for a human, and you should get a job.
If order matters, we have ipairs (indexed pairs) for list-like tables anyway.
meals = {"Breakfast", "Lunch", "Dinner"}
message = "The meals I have are "
for i, meal in ipairs(meals) do
if i > 0 then
message = message .. ", then "
end
message = message .. value
end
It'll print out our list of meals. ipairs(meals) starts from entry 1 and works its way up to #meals (or 3). Sweet.
But what if we want to loop over numbers, with no table involved? There's a different loop for that.
Let's add together the numbers one to ten!
sum = 0
for i = 1, 10 do
sum = sum + i
end
That adds up to 55!
But what if we want to loop backwards through numbers? Let's add the numbers 50 to -60, going down by 1 each time.
sum = 0
for i = 50, -60, -1 do
sum = sum + i
end
This totals -555!
Functions are a basically way of naming a bunch of steps in your code.
Let's say you were going to make a function to define clothing yourself. That way if someone screams "Put your clothes on!", you think of it the same as "Go into your closet! Put on a shirt! Go into your drawer! Put on underwear! Go into your other drawer! Put on pants!". But the advantage of the former, is it's less work to say!
This is an example, translated to lua code!
-- Put on some clothes!
function ClotheYourself()
wearing_shirt = true
wearing_underwear = true
wearing_pants = true
end
Then to yell out the command to clothe yourself later, you write:
ClotheYourself()
After a lot of work explaining variables, I can also show you an example: How to get Lua to write something!
print("Hello world!")
Whoa! print(...)'s a function too! We can even call functions inside functions -- very handy!
With this knowledge of how functions work, we could make our own custom introduction: "Hey [insert name here]!". Let's write a Lua function to do that!
But if we want to share variables with a function, there's a certain way to do this. So if we want to pass in the name of a person, we can declare an argument in our function.
function SayHello(name)
print("Hey " .. name .. "!")
end
Notice that (name) after function SayHello, this tells Lua the function can take a variable called name.
Now to pass in an argument, we've already seen this with print, but here we go:
SayHello("Dennis") -- Says "Hey Dennis!"
We can make this even more friendly, with more arguments!
function SayHello(name, thing)
print("Hey " .. name .. "! How's " .. thing .. "?")
end
And now to call this:
SayHello("Dennis", "life") -- Says "Hey Dennis! How's life?"
And something to take special note of is that variables we declare as arguments disappear after the function's gone. This brings me to the next concept!
Local variables are a kind of variable that only exist temporarily.
Normally in Lua, variables in Lua last forever, as global variables, but this is very often not what you want. There's plenty of times where you have some piece of information you only need for a short while (like the scope of a function), and this is where local variables should be used.
You declare a local variable by doing the following:
local x -- Creates a space for a variable x, that only exists in the "block" of code it was declared in
So if we go to our greeting example, we can do something like this:
function SayHello(name, thing)
local greeting
greeting = "Hey " .. name .. "! How's " .. thing .. "?"
print(greeting)
end
We just declared a local variable called greeting, and we set it equal to the message string. This variable appears once SayHello(...) is called, and disappears again after SayHello(...) has finished. It is a variable with a scope.
To wit, the following wouldn't work as expected:
SayHello("Dennis", "life")
print(tostring(greeting)) -- most likely prints "nil"
And things other than functions can use this too!
if not wearing_pants then
local message = "You need to put on some pants!"
print(message)
end
It also works for while and for loops.
Lua sprinkles tasty syntax sugar in its code to make it sweet to write to and easy to digest! One pretty shortcut in Lua that makes dictionary style tables look like structures.
So we can reuse the old example from the earlier table section here, but with a small and delighful twist! Read it now!
person = {
name = "Andy",
job = "Warrior",
age = 2008-1988,
pants = false,
invisible = true
}
if person.pants then
greeting = " I am delighted to inform you that I am wearing pants. "
else
greeting = " I regret to inform you that I am NOT wearing pants. "
end
if person.invisible then
greeting = greeting .. "But unfortunately you can't see me anyway. Mwahahahah."
end
Notice the small twist there! I use a dot . instead of the square brackets with a string ["whatever"] and now I don't need to type as much! This works as a shortcut for any string name without spaces or funky special characters. And now you can make things that almost resemble structs from C or objects from Java.
And to make it seem even more like C code, where you declare the table, you can use semi-colons instead of commas.
person = {
name = "Andy";
job = "Warrior";
age = 2008 - 1988;
pants = false;
invisible = true;
}
-- [...]
Wow, neat, huh?
So there's actually even a bit more elaboration. You can get tables to do something magical for you, object oriented programming! Tables can have functions that act on them!
Let me show you an example of how it's done.
person = {
name = "Andy";
job = "Warrior";
age = 2008 - 1988;
pants = false;
invisible = true;
}
-- A colon?! Odd, we've never seen that before
function person:Clothe()
self.pants = true
end
-- The above colon syntax is the same as this:
function person.Clothe(self)
self.pants = true
end
See the colon : in the first example? It's equivalent to the dot method . except it tacks on an extra, hidden argument called self!
And how do you invoke such a monstrosity? Let me show you:
person:Clothe() -- Also done with a colon person.Clothe(person) -- Done without a dot, much less pretty (especially if there's nested tables)
As you can see, this tiny sprinkle of syntax sugar makes our task of writing Lua much, much nicer.
Why don't we look at what horrendousness would have to be done if we didn't have this sugar there?
person["Clothe"](person) -- Yuck!
Lua doesn't have preprocessor statements. Including files is done at runtime!
require "blargh"If you actually want to package together files, you can create a folder named like "mypackage", and put a Lua file named "init.lua" inside, which will do the loading of all the crap. Then you just require the entire package like this (which will load the init.lua in that folder)
require "mypackage"If for some reason you need to change the way files are included, check out
package.path.require "Nachos" require "Hats" require "Pants"To allow this, you can modify the load path.
package.path = package.path .. ";Awesome?.lua"So you are able to add rules which will change how files are included. Each entry is separated by ; semicolon. Question marks ? represent "wildcards", which are whatever the text provided to
require happens to be.Though this is really more useful for requiring files in subfolders or something, but same rules.
Some other useful guides to Lua include the following: