[GUIDE] To Factorio LUA 0.2.10
Posted: Tue Mar 19, 2013 6:18 am
I wrote this in about an hour or two (but it's late and I'm tired) so there probably are mistakes Please let me know when you find them so I can edit this and not mislead people.
Also this is written for 0.2.10 and earlier. I'm not sure yet exactly how much may change with the coming 0.3 so if you are reading this after 0.3 is out and it has not been updated BEWARE OF POSSIBLE CHANGES. now that that is out of the way, here it is:
First I'll say I am in no way an expert on either lua or Factorio. Second I use Notepad++ for modding (and adobe photshop cs5 for the graphics). I also happen to be using the Windows 7 64 bit OS. As such any locations I give as to where to find files may, or may not, be accurate depending on if you are using the same OS. In relation the my first statement, Notepad++ is only for windows, it has not been ported to linux or mac (though it is open source, GPL license, written in c++).
Next I will say there are two things, once you start with lua, that are really really helpful.
first the wiki https://forums.factorio.com/wiki/inde ... _scripting (go there read it).
Second the Factorios campaign lua files. They are found under factorio\data\campaigns then you have demo and beta within both of those there are the levels folders inside of each level is a control.lua. These are the lua files that control the campagins. It can be very useful to look through these (especially when you are first learning) to see how the devs did something
Beyond that use the forums and experiment, not necessarily in that order.
Now, if you were to open factorio\data\lualib\freeplay.lua you would be looking at the lua code that is run whenever you start a new game. This is/will be copied into the player's saves. What this means is that if someone tries to play your mod from their save file it probably WILL NOT WORK, unless you let them know that they need to copy your freeplay.lua (or control.lua as it is called in the save files) into their save directory (which is C:\Users\<user>\AppData\Roaming\Factorio\saves on windows 7 64bit installation, if they have the zip file it is simply Factorio\saves).
One other thing before we jump into the Lua code. When you start an 'if' statement you MUST end it with 'end', you may hear/see it called an if-then statement, this is because without a 'then' there is no code to execute. the basic syntax is:
if something == something then
do this
end
Notice the double ==, lua uses a single = to SET a variable, and double == to CHECK a variable. You CAN NOT use a single = to check if x equals 10. it will give an error! (sorry about stressing this but if you are not used to coding it will cause problems, and you will use if statements alot. If you have some experience then you will understand)
Now then onto a bit of code:
When you open freeplay.lua you will see
This tells the game that when freeplay.lua loads it also needs to load util.lua, story.lua, and defines.lua (don't change these unless you know for sure what you are doing)
next you will see:
This is a function that is run at the start of a game. Anything between function() and end will be run once at the start, when I make a mod I usually move the initial giving of items here because it makes more sense to me than having the game keep checking if it has given items already. You'll understand this more in a bit.
Then you will see
Most of your coding will probably go here. Mostly because alot of what you will want to do is based on Events that happen in the game, such as onplayerdied, or onbuiltentity. if you noticed the word event with in the function(), pat yourself on the back, event is a variable that is being passed on to the code that is within the onevent = function() end.
an entity if you do not know is anything, repeat anything, that is generated when the world is (like trees, coal, and creeper spawners) or that you can place 'in' the world (like furnaces, assembling machines, and inserters). The only thing that you will see in the game that are NOT entities are the tiles (the grass/water/'hills' that you walk on) and the items in your inventory (or that of a chest/furnace/etc.)
BTW: a 'block' is a section of code that works together, in an if statement the 'block' of code that is executed is the code between then and end.
The next block of code is another if statement:
what this says is if the event.name (ie the name of the event which just occured) is ontick (notice the double =s) then give the player some iron plates, a pistol, and some ammo. ontick is used if you need something to be run constantly, like checking if the creepers should be attacking. Anything between the then and the end that closes the if statement are run when ontick is called (which as you might guess is every tick, and there are 60 ticks per second in factorio it might be different in other games but...).
To break this down:
glob is a table that is loaded when the game is (this mean if you place any tables/variables you need to create inside of the glob table you do not need to worry about if they are loaded or not). introduction is a variable within the glob table and this statement checks to see if it has been defined (nil is the same as saying something does not exist. You can set a variable to nil to delete it from the games memory.) So, if the introduction variable in the table glob has not been defined (which when you first start a game it has not) then it will run the code that is within then and the end statement. You'll notice that the very first line of code is glob.introduction = true this defines the introduction variable so that it is no longer nil (nonexistent) and does not run on the next 'tick'.
The next line is
insert is a function that, well, 'inserts' items into an inventory. In this instance it is inserting 8 "iron-plate"s into the player's inventory. When you want to refer the game to the player you use game.getplayer(). In the campaigns you might see glob.player, this is because in the begining of the control.lua files the devs set glob.player = game.getplayer(). probably because it is simply easier to type than game.getplayer(). This is fine to use as long as you make sure that the game knows what glob.player is (also, if I am wrong on this let me know so I can edit this lol).
Notice that after insert are curly brackets { this tells the insert function that the data is in the form of a table/array. There are four types of variables, there are tables which contain the other three types (though tables can contain tables), then you have you basic numbers (which can be decimal), then you have strings which is text like "This is a string." It is possible to have numbers as a string "This string contains the number 5, but it is still a string type variable", then last you have the boolean type variable, which is very simple. A boolean variable is either true or false, note that if you set a variable this="true" it is a string variable not a boolean variable. There is one other type of variable, there are global variables which lua creates whenever you write: and there are local variables which only exit within the block of code where they are defined. To set a local variable you use . Locals variables are useful to keep from cluttering the memory that the game is using in your (and other's) computers. It also allows you to use the same variable name for simple things like counters, that only need to exist within the block that is using them and that is not going to be used anywhere else in your code.
You should now see that the name variable is a string that tells insert to give the player the item named iron-plate (the items are defined in the json files of factorio\data\prototype-definition\item) and that count is a variable containing the number of iron-plate's to insert. Pretty simple right?
After the iron plates the game lua code also gives the player a pistol and some basic ammo.
That's the very basics of lua for factorio. To really learn how to code then you will need to watch the wiki for updated information (especially the events) and simply TRY IT OUT. Another good way is to look at the code that other people have written to see if you can A) understand it and B) see why they did it that way and if how they did it is better than you would have done it.
One last thing to be aware of, ingame you can type lua commands by pressing the ~ (the key next to the 1 on a standard us keyboard). Note that this has a limited amount of typing space, though you can use it to set variables and then use those variables to execute a longer commad.
Some common variables/commands to know (there are probably alot more, i'll edit this when people yell at me or i remember them)
game.getplayer().print("some text") will print text to the screen (very useful when debugging your code, and if you were creating a mission for someone)
game.showmessagedialog("text") Will pop message up so that the user has to hit TAB to acknowledge it.
game.getplayer().position.x and game.getplayer().position.y the x and y positions of the player.
Useful code aka "cheater chest":
The block of code that begins with for is called a for loop because it will loop through the code after 'do' and before 'end' until the table is empty. It can also be used like:
You may also notice that in this example chest.insert({}) has regular curved brackets (also known as parentheses) surrounding the curly brackets {}. This is the proper way to write it since some functions could accept more than one table as inputs.
Also not sure if I mentioned it or not but if is a comment and the game will not read the rest of the line
if you want to comment out more than one line (for debugging or you just want a long intro to your mod whatever) use
Edit 1: here is a lua tutorial that I've referenced on occasion (this is about the lua language in general not just in factorio). Not sure why I didn't include this in the original post...but it's here now!
http://lua-users.org/wiki/TutorialDirectory
Also this is written for 0.2.10 and earlier. I'm not sure yet exactly how much may change with the coming 0.3 so if you are reading this after 0.3 is out and it has not been updated BEWARE OF POSSIBLE CHANGES. now that that is out of the way, here it is:
First I'll say I am in no way an expert on either lua or Factorio. Second I use Notepad++ for modding (and adobe photshop cs5 for the graphics). I also happen to be using the Windows 7 64 bit OS. As such any locations I give as to where to find files may, or may not, be accurate depending on if you are using the same OS. In relation the my first statement, Notepad++ is only for windows, it has not been ported to linux or mac (though it is open source, GPL license, written in c++).
Next I will say there are two things, once you start with lua, that are really really helpful.
first the wiki https://forums.factorio.com/wiki/inde ... _scripting (go there read it).
Second the Factorios campaign lua files. They are found under factorio\data\campaigns then you have demo and beta within both of those there are the levels folders inside of each level is a control.lua. These are the lua files that control the campagins. It can be very useful to look through these (especially when you are first learning) to see how the devs did something
Beyond that use the forums and experiment, not necessarily in that order.
Now, if you were to open factorio\data\lualib\freeplay.lua you would be looking at the lua code that is run whenever you start a new game. This is/will be copied into the player's saves. What this means is that if someone tries to play your mod from their save file it probably WILL NOT WORK, unless you let them know that they need to copy your freeplay.lua (or control.lua as it is called in the save files) into their save directory (which is C:\Users\<user>\AppData\Roaming\Factorio\saves on windows 7 64bit installation, if they have the zip file it is simply Factorio\saves).
One other thing before we jump into the Lua code. When you start an 'if' statement you MUST end it with 'end', you may hear/see it called an if-then statement, this is because without a 'then' there is no code to execute. the basic syntax is:
if something == something then
do this
end
Notice the double ==, lua uses a single = to SET a variable, and double == to CHECK a variable. You CAN NOT use a single = to check if x equals 10. it will give an error! (sorry about stressing this but if you are not used to coding it will cause problems, and you will use if statements alot. If you have some experience then you will understand)
Now then onto a bit of code:
When you open freeplay.lua you will see
Code: Select all
require "util"
require "story"
require "defines"
next you will see:
Code: Select all
game.oninit = function()
end
Then you will see
Code: Select all
game.onevent = function(event)
an entity if you do not know is anything, repeat anything, that is generated when the world is (like trees, coal, and creeper spawners) or that you can place 'in' the world (like furnaces, assembling machines, and inserters). The only thing that you will see in the game that are NOT entities are the tiles (the grass/water/'hills' that you walk on) and the items in your inventory (or that of a chest/furnace/etc.)
BTW: a 'block' is a section of code that works together, in an if statement the 'block' of code that is executed is the code between then and end.
The next block of code is another if statement:
Code: Select all
if event.name == "ontick" then
if glob.introduction == nil then
glob.introduction = true
game.getplayer().insert{name="iron-plate", count=8}
game.getplayer().insert{name="pistol", count=1}
game.getplayer().insert{name="basic-bullet-magazine", count=10}
end
To break this down:
Code: Select all
if glob.introduction == nil then
The next line is
Code: Select all
game.getplayer().insert{name="iron-plate", count=8}
Notice that after insert are curly brackets { this tells the insert function that the data is in the form of a table/array. There are four types of variables, there are tables which contain the other three types (though tables can contain tables), then you have you basic numbers (which can be decimal), then you have strings which is text like "This is a string." It is possible to have numbers as a string "This string contains the number 5, but it is still a string type variable", then last you have the boolean type variable, which is very simple. A boolean variable is either true or false, note that if you set a variable this="true" it is a string variable not a boolean variable. There is one other type of variable, there are global variables which lua creates whenever you write:
Code: Select all
var=whatever
Code: Select all
local var=whatever
You should now see that the name variable is a string that tells insert to give the player the item named iron-plate (the items are defined in the json files of factorio\data\prototype-definition\item) and that count is a variable containing the number of iron-plate's to insert. Pretty simple right?
After the iron plates the game lua code also gives the player a pistol and some basic ammo.
That's the very basics of lua for factorio. To really learn how to code then you will need to watch the wiki for updated information (especially the events) and simply TRY IT OUT. Another good way is to look at the code that other people have written to see if you can A) understand it and B) see why they did it that way and if how they did it is better than you would have done it.
One last thing to be aware of, ingame you can type lua commands by pressing the ~ (the key next to the 1 on a standard us keyboard). Note that this has a limited amount of typing space, though you can use it to set variables and then use those variables to execute a longer commad.
Some common variables/commands to know (there are probably alot more, i'll edit this when people yell at me or i remember them)
game.getplayer().print("some text") will print text to the screen (very useful when debugging your code, and if you were creating a mission for someone)
game.showmessagedialog("text") Will pop message up so that the user has to hit TAB to acknowledge it.
game.getplayer().position.x and game.getplayer().position.y the x and y positions of the player.
Useful code aka "cheater chest":
Code: Select all
if event.name == "onbuiltentity" then
if event.createdentity.name=="wooden-chest" then
entities = game.findentities{topleft = {x = event.createdentity.position.x - .1, y = event.createdentity.position.y - .1}, bottomright = {x = event.createdentity.position.x + .1, y = event.createdentity.position.y + .1}}
for fieldName, _ in pairs(entities) do chest=entities[fieldName].getinventory(defines.inventory.chest) end
if chest.isvalid() and chest.caninsert({name="iron-ore", count="200"}) then
chest.insert({name="iron-plate", count="200"})
game.showmessagedialog("Gratis")
game.getplayer().insert({name="rifle-gun", count="1"})
game.getplayer().insert({name="copper-rifle-ammo", count="200"})
game.getplayer().insert({name="coal", count="200"})
game.getplayer().insert({name="car", count="1"})
end --end if chest is valid
end --end if entity=wooden-chest
end--end onbuiltentity
The block of code that begins with for is called a for loop because it will loop through the code after 'do' and before 'end' until the table is empty. It can also be used like:
Code: Select all
for i=1, v do
count=count+1
game.getplayer().print(count) --note we are print the value of the variable count, not the text string count. This is why "" are important when you want to print something to the screen
end
Also not sure if I mentioned it or not but if
Code: Select all
--anthing
if you want to comment out more than one line (for debugging or you just want a long intro to your mod whatever) use
Code: Select all
--[[comment]]
http://lua-users.org/wiki/TutorialDirectory