Exploring the TEN workflow - Tomb-Raider-Level-Editor/Tutorials GitHub Wiki
Written by Kubsy
Note: I am aware that there is a tutorial by Adngel on how to set up the level however it is pretty outdated since some stuff has changed. However with this thread I am able to update it as the new stuff gets modified.
1: Creating a new TEN level through TIDE and basic folder structure
The first thing that we will do is create a new TEN level through TIDE. Go through the usual process and select TEN as the engine.
After creating your TEN folder. You can now go to your folder and see what is inside:
Audio: Folder which contain your soundtracks. In TEN you can name them instead of having to have digits. Bin: Folder with necessary dlls and TEN exe itself, comes with 2 additional folders: x86 and x64. Data: Folder with compiled levels. Screens: Folder with pictures to use when the level/game is loaded. Scripts: Folder with lua files. (Very important!) Shaders: Folder containing shaders. Do not delete this folder, or any of its components. The game will crash/not display stuff correctly if missing! Textures: Folder with textures such as Font, logo, loading bar etc. Logs: Folder which game initialisation is written into log.txt also important for Lua.
Inside the bin folder, you will have 2 extra folders x64 and x86:
Both of these contain the TEN exe and dlls as described at the beginning of the post, but suited to the bitness (so x86 folder will have 32-bit TEN exe etc).
However a new question arises: what is the difference between x64 and x86? Well the difference is that x64 program is able to use a lot more RAM than x86, x86 only is able to use up to 4GB RAM whilst x64 can use up to 16 Exabytes (An extremely huge number!) which means in x64 you can:
- You are able to create much bigger levels
- Trigger even more stuff
Tomb Editor will automatically assign the path in level settings, depending on your system bitness (x64 or x86)
2: Gameflow.lua
Now Having explored the basic folder structure, we can now explore gameflow.lua. Go back to TIDE, and select scripts at the left bar but don't create a new level yet!
Now when you arrive at your script. you will now notice a file called "Gameflow.lua" file which is one of the most important files. Let's explore each section in detail.
The Flow sections defines the global settings for your game such as: Total secrets in game, fly cheat enable, enable level select etc. You can turn each off/on with false and true boolean values.
This section defines your title level.
title = Level.new() - this instantiates a new level object, creates it basically. the title variable can be any value such as "BeautifulTitle", but instead of "title.ambientTrack", you would change to: "BeautifulTitle.ambientTrack".
which means you can now give a certain properties:
title.ambientTrack - define the soundtrack from Audio folder to be used. It is a string value so your soundtracks can be names such as "Croft manor main", no need for numbers!
title.levelFile - The pointed level file that TEN will execute from Data folder. Note the "title.ten" you have to change it if you rename in the Data folder!! can be any value such as "AdventureTitle.ten".
title.scriptFile - The pointed lua file that TEN will execute from the Script folder. Note the "title.lua". You have to change it if you rename in the script folder!! Can be any value such as "ExecuteFlybyTitle.lua".
title.loadscreenfile - The pointed image file from the Screens folder Note the "Main.png". You have to change it if you rename in the Screensfolder!! Can be any value such as "beautifulArtwork.png".
Flow.AddLevel(title) This tells the engine to add the title level to the game.
test = Level.new() - See above for title = Level.new()
test.nameKey - This is the strings where your level will be called in game. This is found in the strings.lua file.
test.scriptfile - See above for title.scriptFile.
test.ambientTrack - See above for title.AmbientTrack.
test.levelFile - See above for title.levelfile.
test.loadScreenFile - points to the picture in the screen folder when level is loaded.
test.weather - weather type.
test.weatherStrength - weather strength.
test.horizon - enables horizon in the level.
test.farview - a number that sets the far view. Can be any number such as 180, 500, 1000 etc.
test.layer1 - Defines a sky layer like the one from TR4 Cairo levels. For more please check the API for what it takes: https://tombengine.github.io/2%20cla...SkyLayer.html#
test.fog - Defines the Distance fog in the level. For more check the API: https://tombengine.github.io/2%20classes/Flow.Fog.html#
test.objects - this section defines the inventory items such as the name of the puzzle hole, type, displayed in inventory etc. It is a list so you can define all of the keys, puzzles you have. For more check in the API: https://tombengine.github.io/2%20cla...toryItem.html#
Flow.AddLevel(test) Adds the level to the game.
Note: As of 1.0.9, the script won't generate this test block anymore. But I will still keep it here for reference of how a typical level block looks like.
So now that you have an overview of what is going on in the gameflow.lua, you can now add a new level in TIDE. So create a new level, and head back to the Script section. You will now notice a new block at the bottom of the script:
Since I created mine to be called just "New_Level", TIDE automatically renamed the instantiation and the variables.
Now you will also see that a new value is inserted into strings.lua:
Note: the left hand side of the value (New_Level) goes to gameflow.lua as a nameKey (can be renamed but make sure to change the value aswell in your gameflow.lua otherwise when saving the string will say "String not found"). Whereas the right hand side value is for the string to appear in the game. Can be changed to whatever you want your level to be called.
Now there are problems since you now have the example level block and the actual level block. You have 2 options:
1st option: You can delete the new level block, and insert the values to the example level block (test = newlevel). You will have to match the strings in scriptfile and levelfile to the ones you have in the folders respectively!!!!!! Otherwise you can check the log folder and see Logs.txt which will tell you where you need to change the value.
2nd option: delete the example level block - any traces that contains test and test. etc. Again you can check in the log folder (logs.txt) to see what you have missed.
However there is a consequence:
- you will need to define weather, farview, horizon etc,
- define a new block for inventory stuff.
This can be risky especially if you are starting out. I recommend to go through the 1st option.
If you want to learn more about properties such as storm (storm effect), then go here: https://tombengine.github.io/2%20cla...low.Level.html
Congrats now you have basic knowledge of folder structure and gameflow.lua.
3: Scripts Folder
In the previous section we learned about the Gameflow.lua file. Now we can talk about the rest of the Lua files that TIDE provides when creating a TEN level.
This is the scripts folder. A standard file will usually have 5 lua scripts; and an "Engine" folder. When you have more level, it will be likely that you will have each lua file for each level.
Gameflow.lua - An important file that makes your level and game run. For more info please see part 2 of this tutorial.
New_Level.lua - A level lua file which is generated for you automatically with 5 functions for you to use should you wish so. Depending on what you name your level when first creating it, it will have that name. For instance, if you create a level which is called "Emperor Gardens" then the lua file will be called "Emperor_Gardens.lua". It can be changed, but bearing in mind you have to make sure it is changed in gameflow.lua, and in the level settings of your Tomb Editor window.
Settings.lua - This is where you can enable/disable animations to your needs and to your level.
Strings.lua - This is the file containing strings for your level. Simillar to English.txt in TRNG.
Title.lua - Same as "New_Level.lua", generated for you automatically with 5 functions.
The Engine Folder
The engine folder provides additional lua files, if you want to include them in your level.
NodeCatalogs - This is a crucial folder with a bunch of yet another lua files, but they are used for Node editor. And also for allowing you to export nodes as a text to use in your lua file. Check my Node Editor tutorial for details.
EventSequence.lua - this is a module file which allows you to make event sequences, similar to TRNG organizers. Usually you would be able to use it if your Lua file has "local EventSequence = require("Engine.EventSequence")"
For more info check https://tombengine.github.io/5%20lua...tSequence.html
Timer.lua - This is another module file which allows to make timers in your level. Again, can be used if your file has "local Timer = require("Engine.Timer")" inside your level lua file.
For more info check: https://tombengine.github.io/5%20lua...les/Timer.html
Settings.lua
As mentioned previously: Settings.lua contains a set of commands to toggle certain animations off/on
In this file you should just be able to set either true or false values for each command.
crawlExtended - Krys' crawlspace flexibility animations.
crouchRoll - Lara's roll while crouching.
CrawlspaceSwanDive - Allows Lara to reach crawlspaces while swandiving.
MonkeyAutoJump - Jump from a ladder.
OverhangClimb - Krys' Overhang climbing like in TRAOD slope ceiling climb. Not yet Implemented.
SlideExtended - Allows Lara to slide on slopes freely and any direction. Not yet Implemented.
SprintJump - Allows Sprint jump. Sprint roll is performed with WALK+JUMP if enabled.
Pose (AfkPose) - Lara will make an idle pose after 30 seconds.
ledgeJumps - Enables Lara for ledge jumping as seen in LAU and in a few custom levels.
Strings.lua
Strings.lua allow you to change strings in game. Just like English.txt.
Just change the current string between the quotes ""
But do not remove the existing entries. Otherwise, you will have strings missing!!! You can of course modify them.
Level and title lua files
This is where the lua fun begins - in these files, you make your scripts for your level. the level and title files provide 5 functions:
LevelFuncs.OnLoad - make stuff happen when player loads the game.
LevelFuncs.OnSave - make stuff happen when player saves the game.
LevelFuncs.OnStart - Make stuff happen when player starts the level.
LevelFuncs.OnControlPhase - Make stuff happen on each game frame.
LevelFuncs.OnEnd - Make stuff happen when player quits the level with a reason (explained in the API).
To find out about more what do these functions mean and what LevelFuncs means head over to here: https://tombengine.github.io/1%20mod...tml#LevelFuncs
To start Learning Lua, I can suggest these resources to follow:
- My Lua basics tutorial. Which also shows how to trigger stuff with Volumes.
- Short example of an infinite boulder
- Lua tutorials in German by Die Basis and others. Translate in English.
4: Adding new Strings for inventory puzzles and keys
This part of the tutorial will now focus on adding string to our inventory puzzles and keys (This also applies to naming the level), just like you can in TRNG where you rename certain values in English.txt and then link.
In TEN this works a bit differently since you can add new entries (unlimited). You are not bound to certain limit.
So go to your gameflow.lua and find this block where you can name your keys and puzzles:
Note: if you find this missing, then you can copy this code here and adjust it to your needs:
X.objects = {
InventoryItem.new(
"",
ObjID.PUZZLE_ITEM2,
0,
0.5,
Rotation.new(0, 0, 0),
RotationAxis.Y,
-1,
ItemAction.USE
)
}
Where:
X = the variable name in your left hand side of Level.new() creation. just replace the X with whatever your variable is named.
"" = the value to match the string in the strings.lua
As you can see in my example, I have named my PUZZLE_ITEM2 as "fuse". Which should be enough right? Well unfortunately this isn't enough because now you need to tell strings.lua that you are introducing a new string into game.
Therefore, launch your string.lua and insert a new entry
Note: make sure you put the new entry before the closing curly brace of the list itself and put a comma at the end of previous entry otherwise the game will not launch. You can see the example as you look at the entries.
Now you have inserted a new entry to your Strings list. However you now need to bear in mind a few stuff:
-
Make sure that the left hand side value matches with whatever you have put between the commas in InventoryItem.new stuff. It needs to match otherwise the game will not launch!!!!!!
-
the right hand side value is what actually will display in game. In my case "hello blue fuse" will display in game.
Once you have done everything correctly. You can now go in game and see effect so save the script (very important to save the script!!!) and launch the game.
In my case this is how will it appear, if done correctly with gameflow.lua and strings.lua:
5: Level Settings and types of triggers in TEN
This part will focus slightly on Level Settings and Volume Trigger.
First let's check the Level Settings. Click on Tools -> Level settings.
There isn't much of a difference between TEN, TRNG and classic engines since they all have the same option to browse the exe, data folder etc. But what is different is the additional box to load a lua file, this is where TE will recognise the file and load functions from lua file to be used in either Volume trigger or in a legacy trigger (floor based trigger, used to trigger with keys, switches etc)
Volume Triggers
First Let's look at the volumes. You have 3 options to insert a volume trigger.
1st) Go to Item -> Add box volume (Alt+V) or Add Sphere volume (Shift+V) and click anywhere on the map
2nd) You can have the Box volume and Sphere icon on the toolbar above the 3D scene. To do that:
- Right click on toolbar to customize
- move the Add box volume and Sphere volume to the right hand side.
After that, the 2 buttons should appear at the top
3rd) Highlight the floor where you want to select and press V to add a Box volume.
After doing either options and inserting the volumes inside the map, then they should look like this:
Note: These triggers are not bound to floor and ceiling anymore, which means you can move and resize them. This also means you can make the TRNG so-called: "fragmented" and "Vertical" triggers very easily in TEN.
You can now double click on them. Initially you will be greeted with a node editor graph but that's not what we want at the moment. Instead, select the "Level script functions" checkbox beside node editor.
this is where all of your Levelfuncs. functions will appear if you make in the lua file that was specified in the level settings.
- If you want to learn more about volume triggers, then I recommend you to go check this Tutorial where I talk more about Volume trigger window.
Legacy trigger
Legacy Triggers are floorbased triggers used basically all the time for switches, keys, puzzles etc in TRNG and classic engines. In TEN this is slightly more advanced.
Highlight any floor then add a legacy trigger. A window should pop up. There isn't much a difference to the window between TEN, TRNG, and classic engines, however in TEN you have more trigger types:
Such as: Tightrope, Crawl, Monkey etc which were also present in OG TR5 engine. Although I would say that it's much more easier to do these in a volume trigger since you have more freedom in them such as placement, movement, size etc.
The "What" type also has not changed pretty much:
However what we are very interested in though is the "EventSet" this is a new trigger type introduced in 1.0.6 TEN where you can trigger lua functions OR node editor stuff via keys, levers, puzzles, pushblocks and such.
All you have to do is go back to the Edit volume box (see previously how to do that) then implement a node function (or selecting a lua function) then event set would appear in the "Param" section
Note: the timers (On enter, When Inside, On leave) DO NOT WORK in legacy triggers due to the nature of the floorbased triggers. instead they should be used in a volume.
6: The log folder and TENlog.txt
We have explored all of the Lua scripts, and the TEN level folder. It's time to talk about TENlog.txt.
TENlog.txt is a log file that will report what the engine does to initialise the game. It will also highlight any warnings, and any errors you have whether it is Lua or wad related warnings (more on that later).
TENlog.txt will typically look like this:
The log file will show you the step by step process of initialising and launching the game. Each entry starts with a full date, hour:minute:seconds format and the type of action that has been done.
The Log folder and log.txt will not be created when you create a project via TIDE. When you start the exe, the Logs will be created for you:
There are 3 types of log entries:
Info: Info tells you the action that has been done.
Warning: Warning that will tell you what is missing. This usually does not mean that the game will crash, but some stuff will not be working/displayed properly.
Error: An error that you need to fix to. Otherwise title (or level) will not launch.
Warnings
As said previously - Warnings are a type of entries that the game will tell you what is missing. A warning could look like this:
In this case this warning entry tells me that Main.png is missing in the Screens folder. I have 2 options:
-
Simply supply a Main.png and insert it to the Screens folder.
-
Change the string in gameflow.lua to tell the engine that my picture for loading screen is differently named:
These 4 warnings tell me that I have no animation for goons and no meshswap for Shiva and Baddy1.
To fix this I would simply insert the meshswaps for Shiva and Baddy1 and insert animations for goon.
Note: the silencer goon2 and silencer goon3 have been coded to take animations from silencer goon1 variant. You can take prepared goons from here: https://github.com/TombEngine/Resources.
Errors
Errors are the annoying type of entry you will get almost all of the time as a beginner. But you will most likely encounter it whilst doing Lua/Node editor stuff.
There are many types of errors that you might encounter. But here are 2 error types that you will most certainly encounter:
Syntax error
A syntax error is a type of error where the statement will not execute because a comma, or a closing bracket or any other syntax symbol is missing.
Consider this example which should print "hello" to the TEN log:
print('hello'
What can you notice in this statement? That's right - a missing closing bracket. If you were to execute it (i.e just trying to launch your level.) The game would not let you and print an error statement:
The log entry will tell you which line number and Lua file the error is present.
In this case. I would have to put ")" at the end of the line.
Logic error
Logic error is a type of error where the behaviour you wanted to make is doing unexpected actions. Such as: A flyby sequence will switch to another sequence when a soundtrack stops; An enemy running to the wrong AI nullmesh; or an arithmetic error in the code where instead of multiplying 2 numbers, you instead add them which also causes unintended behaviour.
Some of these will be reported in the TENlog.txt but unfortunately the world is not perfect enough, and most of these will not be noted in the TENlog.txt. In this case you will have to figure out yourself what is wrong with the lua script/node action graph or ask other people.
General tips to TENlog.txt
Whenever you have an error in the game:
-
if the title successfully launches but the level does not, the game will boot you to the title screen and will add an error entry to TENlog.txt. Check it, and fix it.
-
if your script has an error in the title lua script, the game will not launch from exe, although if the level compiles then you can go straight to it via Build and play button in Tomb Editor. as that method will skip the title and you can fix the title later.
-
If both title and level does not work, you will have no way to enter the game. You need to fix whatever the TENlog.txt tells you to fix.
7: Miscellaneous Information
This section is dedicated to miscellaneous information with workflow that don't need separate posts.
Secrets
In TR4 vanilla and TRNG engines, the secret soundtrack was hardcoded to "005". In TEN, this is not the case anymore because TEN will now play the secret soundtrack of the sound file Starting with 3 digits with the highest numerical prefix.
Consider the screenshot with 3 files with 3 digits. The highest numerical prefix with 3 digits soundtrack is 333.ogg, hence this will be played as a secret soundtrack
Now consider this screenshot (attached as attachment - "audio folder.png"). I have 3 tracks, my highest numerical prefix with 3 digits track is "110", this means that this track will be used as my secret track.
IF you do not have any sound file with 3 digits then the secret track will not play.
TEN default wad and objects
Whenever you create a new level in your TEN TIDE project, a default TEN wad will be loaded up for you automatically. The wad is located in the Tomb Editor folder -> assets -> wads -> tombengine.wad2 which then you can open it in wadtool by going to Tools -> Start Wad Tool... in your TE navigation bar.
IMPORTANT: You should use this wad whenever you create a new TEN level, and modify it as usual. It is there since TEN has majorly reworked some objects such as LARA.
You can just copy it and insert to your level folder so you can have your own copy of it and modify it and leave the original in the Tomb Editor folder.
TEN also comes with a separate github repository for objects, this is also essential since TEN has fixed and removed most of the hardcoded aspects of some enemies. Also modified state changes and animations in some enemies.
The repository can be found here: https://github.com/TombEngine/Resources
All you need to do is click on the green code button -> download as zip and it will download all of the stuff that it lists (Fonts, Lua, wad2 objects, sounds etc)
Note: it's best to check this often as new stuff will be added
Or you can download objects here: https://tombengine.com/objects-downloads/ but it's best to check the github first since it will take a bit of time to update the site.
Converting any wad to TEN target
We can also convert any TRNG (only) wad to TEN wad.
Let's download a wad from Trsearch.org (For this example, I used this Alpha Lara pack: https://www.trsearch.org/item/5761)
Open the wad and now in Wadtool's toolbar, go to tools -> Convert wad to Tombengine... which will prompt you to name the new wad and select the folder to save the wad. Once you did so, wadtool will convert and open the new wad for you.
Multi-action pickups
In chapter 4, we explored how to give names (and generally setup an inventory pickup). Now in Recent version, we can now assign multi-action to them
InventoryItem.new(
"fuse",
ObjID.KEY_ITEM1,
0,
0.5,
Rotation.new(0, 0, 0),
RotationAxis.X,
-1,
ItemAction.USE | ItemAction.EXAMINE
)
We are interested in
Code:
ItemAction.USE | ItemAction.EXAMINE
the vertical bar "|" makes all the magic, in a programming language it has a special meaning - namely it's a Binary OR, which you don't really need to know what it does behind the scenes (unless you are very curious) all you need to know is that you can use it to have multi-actions to pickups.
Unfortunately, there are limits - you can only have 2 actions, so any combo of: "EQUIP and COMBINE" "USE and EQUIP" "COMBINE and USE" etc. This is due to the coding constraints in the engine code at the moment.