-
Notifications
You must be signed in to change notification settings - Fork 1
Lua Workshops
_Note: For the Lua API documentation (a complete list of the Lua functions and tables that interact with the engine) please see the `Documents` folder packaged in your TombEngine download._
Below you can find some really great tutorials by Adngel for Lua and TombEngine (TEN).
The first we are going to do is modify our gameflow
script to can include our new level (or the many levels that we want).
What are these Lua files?
In the TombIDE program, you can find your Lua files by pressing the third button on the left panel:
In your Scripts folder, you will find these files, they are part of the Ten system. (You need them, you can edit them, but not delete them).
- Settings: This contains some options about error logs, and some movements conditions, (in development).
- Gameflow: This is like your main script file, here you will add your new levels, and their object data.
- Strings: This is the place where you can set your new text lines.
- Util: This is a code that contains some functions to make scripting easier.
- Timer: This is a module with tools to make timed actions.
- EventSequence: This module includes the EvenSequence structure to schedule a series of actions. (in development).
Apart from these ones, then there are some extra Lua files dedicated to each level, for example, you have their Title.lua
and TestLevel.lua
.
To add a new level, you must do three things:
- Create a new level block in the Gameflow.lua.
- Create a new string for your level name.
- Create a new lua file for that level.
The script may look complex at first sight, but if you take a more general look, you can see that there are some 3 areas in this script.
- Header, is the area that initialize system data, you usually don’t need to touch this.
- Title level also need its block, and this is its place.
- Level blocks, in this pic it’s shown 1 level block, but you may add as many level blocks as levels has your game.
So you can add your next level block at the end of the list. The level block has this minimal structure:
**Level1** = Level.new()
Level1.nameKey = "L0_Title"
Level1.scriptFile = "Scripts\\l_LaraGym.lua"
Level1.ambientTrack = "108"
Level1.levelFile = "Data\\LaraGym.ten"
Level1.loadScreenFile = "Screens\\rome.jpg"
Flow.AddLevel (level1)
Please not that "Level1" as above must be unique for each level, I think an easy way to do that is just calling Level1 the first level, Level2 the second, etc..
Completing the level block:
- nameKey Is the name of your level, you must add it to your strings file and put it here.
- scriptFile Here is where you will put you Lua level file, we will cover it later.
- ambientTrack This is the ambient music that has your level at the begginng, you can find the songs in the folder Engine/Audio
- levelFile This is the file of your level, located in the Engine/Data folder.
- loadScreenFile This is the image that will appear while your level is loading, you can find and add pictures in the folder Engine/Screens
The strings go in your String.lua file, so open it and go at the end of the file.
Before the bracket close, that's the place to inject your new strings. You can just copy the structure of the previous string and paste it below.
Pay attention to the commas, only the last string don’t need comma at the end, but the rest yes need a comma after the bracket like: },
- In the string, the string var (variable) name need to be unique, I’m using L0_Title, L1_Title, L2_Title, etc..
- Inside, there are many gaps, it’s designed so each one will be used for different languages, at the moment we are going to fill only the first one that is used for English.
- Once you’ve got it, save the strings.lua, and write in the nameKey of your level block, the string var name, between double commas. So in my case, L0_title
In TombIDE, you can add a new file by pressing the left button of the mouse, on File Explorer, there you can find the create a new file.
In the new window, just put the name of your new file, and choose the Lua format. Then press Create.
When you create a new file, this file will be empty, to have a minimal workable level code, you need to add the next lines:
-- FILE: \Levels\l_laraGym.lua
LevelFuncs.OnLoad = function() end
LevelFuncs.OnSave = function() end
LevelFuncs.OnStart = function() end
LevelFuncs.OnControlPhase = function() end
LevelFuncs.OnEnd = function() end
Put this code in the file you've just created and save it.
Finally, you can update the **scriptFile ** value in your level block with the address to your lua file. (In my case: "Scripts\l_LaraGym.lua")
Once you've done, you should be able to find your level in the game menu and play it, (although first you must have compiled the Tomb Editor level!)
If it fails, the first check should be the log document. (you will find it in Engine\Logs), look for a line that says [error], usually at the end of the document, these logs tend to provide useful information, like the line where your script has failed. (It can be for the lack of a comma, for a misspelled word, etc...)
That provided code, was quite minimal, there are more elements that you can add to your level block, like horizon, sky layer, fog, weather, etc... You can find all the features in the documentation. (You can download from this git hub: https://github.com/Stranger1992/Tomb-Engine-Demo-Levels )
For example:
Level0 = Level.new()
Level0.nameKey = "l0_Title"
Level0.scriptFile = "Scripts\\Levels\\l_LaraGym.lua"
Level0.ambientTrack = "108"
Level0.levelFile = "Data\\LaraMoves.ten"
Level0.loadScreenFile = "Screens\\rome.jpg"
Level0.horizon = true
Level0.weather = 2
Level0.weatherStrength = 1
Level0.layer1 = Flow.SkyLayer.new(Color.new(72, 80, 96), 5)
Level0.fog = Flow.Fog.new(Color.new(32, 56, 64), 5, 20)
Flow.AddLevel(Level0)
In this next section I will explain how to create functions and how to link them with the level of Tomb Editor, for that, we will use simple functions that only will print a line of text.
Once you’ve got your level, you also will have a Lua file dedicated to that level, that document is where we write the functions.
If the previous section, our level code starts like this:
LevelFuncs.OnLoad = function() end
LevelFuncs.OnSave = function() end
LevelFuncs.OnStart = function() end
LevelFuncs.OnControlPhase = function() end
LevelFuncs.OnEnd = function() end
These lines are functions, the instructions you put inside (between the brakets (), and the end), only will be activated when the function is called, (like a trigger) so they are very useful to control a program.
- OnLoad - Is triggered when you enter the level due to a save game load.
- OnSave - Is triggered when you do a save in your level.
- OnStart - Is triggered when you start your level from the beggining.
-
OnControlPhase - Is triggered on every cycle. If your PC renders the game 30 frames per second, then this function is called 30 times per second. Think on this like an
OnUpdate
. - OnEnd - Is triggered when you close your level. (To go to the main menu, or to the next level).
These are the default level functions, but you can create more. I’ll add two here:
LevelFuncs.OnLoad = function() end
LevelFuncs.OnSave = function() end
LevelFuncs.OnStart = function() end
LevelFuncs.OnControlPhase = function() end
LevelFuncs.OnEnd = function() end
m_Util = require("Util")
m_Util.ShortenTENCalls()
LevelFuncs.PrintTextVolume = function()
local text = "Function Text Volume Activated"
local string = DisplayString(text, 100, 100, Color.new(250,250,250))
ShowString(string, 5)
end
function PrintTextFunc ()
local text = "Function Text Function Activated"
local string = DisplayString(text, 100, 200, Color.new(250,250,250))
ShowString(string, 5)
end
Here you can see we have two structures for functions.
LevelFuncs.FunctionName = function()
[All code goes here]
end
And
function FunctionName ()
[All code goes here]
end
The difference is that the LevelFuncs version, can be detected by Tomb Editor, and you can use call it from a volume trigger. The second one, is more traditional, but only can be called from Lua code.
About the content, you can see is mostly similar in both cases:
local text = "Function Text Function Activated"
This is the text we are going to show. Check the local word at the beginning, that means that when this function ends, the game will forget about this variable. (So same name can be used in the other function).
local string,
this variable contains information about the text line we want to print, (the actual text, the x y position and the colour of the letters)
ShowString (string, 5)
what it das is show the text line we have stored in string, during 5 seconds.
In order to can use the TEN specific functions, (like DisplayString and ShowString), is necessary we call also a module, that what these two lines are doing:
m_Util = require("Util") m_Util.ShortenTENCalls()
But, we will talk about modules another day.
For now, copy these functions to your level and save the file.
Open your level in Tomb Editor.
The first step we must do to can call your Levelfuncs in the level, is link the level lua file with your level Tomb Editor project. So we have to open the Level Settings (in the Tools Tab of the top).
Once in the level settings, go to the Misc area, and fill the Lua slot with your level lua file. Then save your project to avoid this step in the future.
After linking the file, Tomb Editor has access to the functions you write in the Lua file. But to activate the level, you need a trigger volume.
To create a trigger volume, select a group of tiles, and press the key V. (You can press Ok in the window for now).
That pink cube, is a new version of trigger, you can move, rotate and scale. If you select it and press the o
key, you will open the Edit Trigger Volume
window.
In this window we create the eventriggers that will link to our code functions.
-
To start, press the
+
button in the top left corner. That will create an event. (An event is like a trigger, but you can connect different volumes to this same event). -
When you create a new event, you have to put the Event Name (something that helps you to identify and know what it does).
-
Under the name, you see 3 tabs:
- When Entering,
- When Inside,
- When Leaving,
these are the moments when the function will trigger. We will keep working with When Entering
tab.
-
Then, you should be able to see a list of all your LevelFuncs from your Lua level file. (If you don’t, review that your file is linked correctly in the Level Settings). You have to make click on the function you want to activate with this volume.
-
After it, there is a box called Arguments, it’s used to send values to the function, like the timer box of the classic triggers.
-
Also, there is a call counter, If you leave 0, the trigger will activate every time, But if you put another value, like 3, then volume only will activate the first 3 times. This is the new version of the One Shot feature.
-
At the bottom, there are the Activators, this is who can activate the volume, by default is Lara, but you can tick other boxes if that’s what you need.
- Lara: Obviously Lara activates this event if checked.
- NPC: Guides, Baddies, Von Croy etc.
- Other Objects: Rollingballs, Pushable objects, Animatings
- Statics: Static meshes.
- Flyby Camera: Flyby Cameras will activate the event if the path of motion collides with the volume.
For our test we don’t need anything else. We can compile and test our new volume.
If everything has gone well, we will be able to see our text line every time we step in the volume.
That was the way to activate the Levelfunc function, but how do we call the traditional function? As we told, it has to be done from Lua, for example, we are going to add the call in the function Start() so our traditional function print its text at the beggining of the level.
LevelFuncs.OnLoad = function() end
LevelFuncs.OnSave = function() end
LevelFuncs.OnStart = function()
PrintTextFunc ()
LevelFuncs.PrintTextVolume ()
end
LevelFuncs.OnControlPhase = function() end
LevelFuncs.OnEnd = function() end
m_Util = require("Util")
m_Util.ShortenTENCalls()
LevelFuncs.PrintTextVolume = function()
local text = "Function Text Volume Activated"
local string = DisplayString(text, 100, 100, Color.new(250,250,250))
ShowString(string, 5)
end
function PrintTextFunc ()
local text = "Function Text Function Activated"
local string = DisplayString(text, 100, 200, Color.new(250,250,250))
ShowString(string, 5)
end
That’s all that you need. To call a traditional function, you must put its name, followed by the brackets, in another function.
You can see that I also put the function LevelFuncs.PrintTextVolume
in there, that's to show you can call LevelFuncs from Lua too.
Save the file, and run your level, (you don’t need to recompile your level to see your Lua changes). If everything is ok, we should be able to see both lines at the beginning of the level.
To end this section, I’ll show about sending arguments to the function.
Sometimes we may want to use the same function, but with a little small change, (a different timer, a different object, a different password, etc...) to do that, we use arguments. We are going to read some arguments and print them on the screen.
In the Tomb Editor, we’ve already seen that there is a box to type arguments for our functions, we are going to put something there, it can be a number, or a word. I’ll type chocolate
.
Although we must do some changes in our code to can read that. Take a look at the next version of the code.
LevelFuncs.OnLoad = function() end
LevelFuncs.OnSave = function() end
LevelFuncs.OnStart = function()
PrintTextFunc ("Vainilla")
end
LevelFuncs.OnControlPhase = function() end
LevelFuncs.OnEnd = function() end
m_Util = require("Util")
m_Util.ShortenTENCalls()
LevelFuncs.PrintTextVolume = function( triggerer, arg )
local text = "Function Text Volume Activated likes " .. arg
local string = DisplayString(text, 100, 100, Color.new(250,250,250))
ShowString(string, 5)
end
function PrintTextFunc ( arg )
local text = "Function Text Function Activated likes " .. arg
local string = DisplayString(text, 100, 200, Color.new(250,250,250))
ShowString(string, 5)
end
In our LevelFuncs, in the brackets (), we have put two arguments:
-
triggerer
is a reference to the moveable that activated the volume. -
arg
is the argument we put in the volume.
Although we are not using the triggerer
in this function, we have to put it because the order is important, the arguments in LevelFuncs functions, are the second input value. That’s why we have to put triggerer
first.
Once we’ve got the argument variable in the parameters (inside the bracket), we can use it inside that function, for example, the text I’m sending is a combination of the written line "Function Text Function Activated likes " and whatever is in the argument arg. (Check that I used the double periods' ..
to combine both words).
But we don’t always need the volumes to set arguments, we can sent arguments directly to our traditional functions too, we just need to put the value, in the brackets when we call the function.
In this same code, look at the call in OnStart function, We keep calling our traditional function but we are sending the word "vainilla", (We put the " to make the program knows that is a text, not a variable).
The traditional functions do not have triggerers, so we don’t need to put it on the parameter, that’s why I put directly arg, and used it in a similar way I did on LevelFuncs.
Now, if we save the code and run the level, we should be able to see ours texts using the words we send.
Using arguments with the functions is also a very useful feature which definitely we will use in our codes from now on.