Installing and importing modules

<<< PREV NEXT >>>

The builder interface revolves around importing modules into level scripts. While as a builder, you do not need to code the modules yourself (it’s the coder’s job), you must understand how the Particle System Plugin manages these modules and level scripts, which implies knowing how they are connected to each other.

Module scripts, as mentioned in the introduction, are Lua script files (text files with the .lua extension). Coders are responsible for writing them and ensuring they work, so the module you receive as a builder should be fully functional, if the coder did a good job. However, once you decide to use some module in your level, you are responsible for the setup needed to get it to work. This includes installing the module in the right place, inside the working directory of your project, importing it into chosen levels and (possibly) performing some customization via the parameter system. If the effect also requires some external assets (e.g. a special mesh or object, a specific sound effect or sprite texture, an additional TRNG script invoked by the module), then as a builder, you need to include these additional assets in your project accordingly.

In this first chapter, I will describe the process of correctly installing a module (with respective differences for whether you have a project managed by TombIDE or done the old-school way), creating a level script, then importing a module into said level script. In the next chapter, I will explain how the (optional) parameter system works for modules and how you can change parameters that were added by the module’s coder. The third and final chapter goes into guarding the text-based scripts from nosy players and preventing trivial tampering, to protect the integrity of your publicly released levelset.


Sections

        1. The module system
        2. Creating a level script
        3. Linking (importing) modules in a level script

The module system

The plugin’s module system was designed to make particle effect modules highly reusable and shareable among members of the TRLE building community. It also provides the opportunity for builders with no coding skills to still use the modules with relative ease, after learning how to link modules with levels.

That is why the plugin is divided into the builder (level script) interface and coder (module script) interface. The coder’s main workspace is in the module scripting interface, whereas the builder works with the finished modules and imports them via the level script interface. It must be emphasized, however, that the aforementioned level scripts are distinct and separate from [Level] sections in the scripts.txt file (which determine the order of levels in a level set and optionally host TRNG scripting for a given level). That is the domain of TRLE scripting and TRNG scripting Paolone built on top of it. The plugin uses Lua scripting though, which while different and requires separate Lua files, is pretty simple in the scope needed to import modules (or we hope so, at least)!

The level scripts we are talking about here are their own, individual Lua script files, with the .lua extension. These Lua level scripts are not mandatory for any level, nor are they required by the plugin to function. However, if no Lua level scripts are associated with a level, that level cannot use any special particle effects (which is the whole purpose of having the Particle System plugin in the first place).

Where level scripts should be placed

Level scripts need to be placed in a folder named levelscripts. The case of the letters does not matter, meaning that LevelScripts is also acceptable, but it must be spelled as a single word (level_scripts or Level Scripts is incorrect and the plugin will not be able to recognize it). This folder is unlikely to exist, so it must be created in your TRLE project folder, in a specific location.

Where this location is depends on whether the TRLE project is managed with the TombIDE (TIDE) application from the Tomb Editor suite, or if it’s a project created the classic way, without new tools. I will describe both cases: Any number of Lua level script files can be associated with a level file, through a Customize TRNG script command, with a special CUST_LEVEL_SCRIPTS constant belonging to the plugin. However, the details of this process will be explained in the Creating a level script section later.

If the Lua level scripts are correctly paired with the level, you will be able to import module scripts inside of them. Importing a module means that the particle effect implemented by the module will be able to appear in the level (there may be extra prerequisites involved in actually using the effect, for this you must read any instructions given by the module’s author).

For a module to be importable, it must be visible to the Particle System plugin. Modules are visible only if they are installed into a concrete directory inside the TRLE project folder.

Where to install modules

Modules, in order to be imported, must be added to a folder named effects or Effects. The case does not make a difference, either is fine, but the spelling must be exact (effect, singular, will not work). This folder is also unlikely to be present in the normal layout of TRLE projects, so it must be newly created.

The location is the exact same as for the levelscripts folder, described above. The folder should be placed alongside data, audio and other asset folders (which in case of a TombIDE project, are contained inside the Engine folder). If this is the case and you see levelscripts, effects, audio, data and the main tomb4.exe all in one place, you’re on the right track.

After the creation of the effects folder in the proper location, you can insert various effect modules into it. Modules have the form of .lua files (or .luac files, more on this later). These contain the Lua code necessary to implement the effect. If you were to open such a file, you would see the code written in plain text, by the coder. But if you are not a coder yourself, you don’t need to know what goes on in there. Rather, you will be concerned with creating level scripts to import these module files.


Creating a level script

A level script is a Lua file – a plain-text file with the .lua extension, located in the levelscripts folder. Such files are linked to a particular level entry with the use of Customize= CUST_LEVEL_SCRIPTS command in TRNG script. By using this script command, you specify to the plugin which level script files to load from the levelscripts folder. But there is the question, how do we specify these files? Do we do it by file name? Well, yes, but not in a direct way.

Due to limitations of TRNG script syntax, it is not possible to directly type the name of a file in the CUST_LEVEL_SCRIPTS command. Instead, we have to rely on ExtraNG strings in english.txt. The name of a level script file, added as an ExtraNG string, must be written in a particular way. You type the name of the file, but without the .lua extension at the end. For example, in levelscripts, there is a level script file called temple.lua. Due to the way TRNG works, the names of any installed plugins are included as ExtraNG string entries, hence if you installed this plugin, you are bound to have at least one NG string entry already occupied. But it does not matter, we can add new ones easily. The layout of ExtraNG strings (if using TombIDE) can look something like this:

ID Hex [ExtraNG]
1 $001 Plugin_ParticleSystem

To this, we can add another entry, by typing in the next free row the name of the level script file, without the extension: temple. We should have something like this:

ID Hex [ExtraNG]
1 $001 Plugin_ParticleSystem
2 $002 temple


It’s important to note that no additional characters (not even spaces) can be before or after this name (otherwise the plugin will get confused). After we have added this entry to ExtraNG strings, we can refer to it via its ID number, 2.

You use these IDs in CUST_LEVEL_SCRIPTS in a [Level] (or [Title]) section, first beginning with the Customize= TRNG script command:
Customize= CUST_LEVEL_SCRIPTS,
After the CUST_LEVEL_SCRIPTS constant, you type ID numbers of ExtraNG strings added to english.txt:
Customize= CUST_LEVEL_SCRIPTS, 2
Numerous IDs can be specified, separated with commas, meaning you can use not just one, but several level scripts per each level (up to a maximum of 64 different NG string IDs).

It’s possible for no script files to be linked to the level, simply by not writing a CUST_LEVEL_SCRIPTS script in the [Level] entry. The plugin assumes no special effects will be used for this level in such case.

The level script file is a raw text file. This means the file consists purely of text characters and contains no non-text data. Files with the .txt extension are a prime example of this. If you create and save such a file, you will notice the file retains no extra data regarding formatting of the text (font style, size, color, boldness, italics, etc), leaving just the raw text. This is exactly what we want for .lua files, too!

So, one more question that remains is… how do you make a .lua file? Given that these files must be plain-text, could we just make one in Notepad, the way we make .txt files? Well, as a matter of fact, we can, but it can be a bit cumbersome, as you will see for yourself.

Using Windows Notepad (not recommended)

If you decide on using Windows Notepad, you can create a new text file and save it under the same name as the level file it will soon be paired to. There is one problem that needs addressing – it still has the .txt file extension, but we need a .lua extension. Depending on your system settings, you may not be able to see the extensions of common file types, just their names. If that’s the case, you can change the settings for this in the File Explorer (how exactly depends on the version of Windows OS you are using, unfortunately it isn’t consistent between Win 7, 10 or 11 – all I can say is Google is your friend here). Once all file extensions are visible, it is a matter of changing the three letters txt after the dot to lua. Windows will probably complain now that changing files’ extensions manually can break them. Since both txt and lua are plain text files, in this instance it’s just Windows making a mountain out of a molehill (as it often tends to do...), rest assured nothing bad will happen to the file.

However, if you want to avoid the faff of changing your File Explorer settings and then manually editing the file’s extension, with Windows making an overly dramatic scene about it each time, I can recommend an alternative (and superior) solution. The solution is using a special text editor for such purposes: Notepad++!

Using Notepad++ (recommended)

Notepad++ is a more technical-oriented text editor, ideal for working with various scripts, source code, markup files and similar technical text files. It allows you to save plain text to dozens of extensions directly, including to Lua source files (.lua)! On top of that, it’s also very easy to use, similar to Notepad, with non-invasive extra features. It can be downloaded for free from its official website: https://notepad-plus-plus.org/
Notepad++ is better than the regular Notepad for many reasons. Firstly, you can immediately save text to Lua files, without the renaming workaround. Secondly, if the extension is recognized, the text editor displays color-coded syntax specific to the language, which when dealing with source code, greatly improves the readability. Thirdly – you can pick custom themes, dark, bright or anything in between!



The latter two reasons are mainly beneficial to coders, but there is no disputing that the primary reason (saving to .lua without annoying workarounds) is great for everyone.

In Notepad++, to create a level script file, just create a new, empty file and save it in the levelscripts subfolder (where you find the level files themselves). When saving, enter some chosen name for the level script file (here we will go with the name of the level file, tut1, but this need not be the case) AND importantly, the .lua extension after the name! You can also select the Lua source file option from the dropdown, but either way, the filename must explicitly include the extension, otherwise the file will be saved without it (extensionless files are rather uncommon in Windows but are very common in UNIX operating systems, like Linux, hence the saving dialog does not assume an extension, it must be visibly appended to the file name). Double check that the file was correctly saved, with the .lua extension, inside the levelscripts folder (e.g. you should have levelscripts/tut1.lua).

Do not forget to then add a suitable ExtraNG string entry for the file, which in our example should simply be tut1, no extension. Note down whatever ID number is assigned to this string (e.g. ID 3) and then add the following line to the appropriate [Level] entry:

Customize= CUST_LEVEL_SCRIPTS, 3
Of course, you may have additional level scripts, assigned to different ID numbers in ExtraNG strings.

Now that an empty level script file has been created and linked to the TR4 level itself, we are able to import effect modules into it!


Linking (importing) modules in a level script

By now, you should now have a level script file (such as tut1.lua) in the levelscripts subfolder, the name of this file (minus the extension) added as an ExtraNG string, and the Customize= CUST_LEVEL_SCRIPTS line to go with it in the appropriate [Level] section. We should also have some modules in the effects subfolder, ready to be imported. What’s that? You don’t have any modules yet? Well, you should have said so! To get you started, you may grab a few example modules from this repository: [LINK HERE]

Download and place them in the effects folder, which was described in the earlier section on installing modules.

Let’s say we want to import one of the downloaded modules, firehead.lua. There is a special syntax for importing, and this is where the minimal amount of Lua scripting comes into play.

The require() instruction

There is a specific instruction for the Particle System plugin, called require(). When the plugin loads the level script, it sees this instruction and imports (loads) the module requested in the instruction. In the case of the firehead.lua module, the import instruction you write inside tut1.lua (or whatever your level script happens to be) should look like this:

require('firehead')
Don’t run away just yet, let me explain what it means!

The require instruction signals to the plugin that the level will “require” a certain module. The instruction has the imported module specified inside round parentheses, but you may notice a few quirks:
  1. The name of the module script is written without the .lua extension
  2. The name is placed inside the parentheses next to require and encased in single-quotes, 'like this text here'. Alternatively to the single-quote characters you can use double-quotes, "like this example". Both quote types are acceptable, but they cannot be mixed, e.g. "this is not allowed', 'nor is this".
I’ll do my best to explain the reasons for these two quirks. Regarding the first point, we are not specifying the .lua extension of the file, because module scripts can have two different extensions, .lua or .luac. Their differences will be explained eventually, but the module file’s actual extension is omitted in either case. Just something to keep in mind, otherwise the plugin will reject the import instruction.

About the second point, in the Lua programming language, there are some predefined “instructions” that it can understand, like the require instruction. Anything that Lua does not recognize as an instruction is often treated as a syntax error. This is a problem, because modules can have practically any name (that is allowed for files, at least). How do we make this distinction between a specific Lua instruction and a random file name? By putting the name inside quotes (the name actually becomes a string, but we will get to that later). In a way, putting the module name in quote characters serves the same purpose as putting the level script name in an ExtraNG string did.

Make note of the fact, that there are no white-space characters before or after the name of the module file, the quote characters are tightly wrapped around the name (without the extension, of course). Any whitespace will confuse the importer.

Once you save the level script with the newly added import instruction, you can go into the game and run the level to which the level script is paired. You should then see the effect of the firehead module (I think its name is quite apt)!

Importing more modules

If you want to import another module from the bunch (e.g. party.lua), you can do it on the next line in the level script:

require('firehead')
require("party")
For the party.lua module I used double-quotes this time, but as mentioned, it does not make a difference which one you use, as long as they are not mixed together.

If you save, launch the game and go into the level corresponding to the level script, sure enough, you should see some colorful, silly particle effects dance around Lara! If that’s indeed the case, you have successfully imported both modules! Feel free to import some other modules and play around (note that some have custom parameters, something that’s explained in the upcoming chapter).


The require() instruction is what you will be mostly using as a level builder. You now have 50% of the knowledge necessary to use the plugin, and for simple modules, it’s sufficient. However, coders can also make modules that contain customizable parameters, which needs a more indepth explanation (and a bit more insight about Lua).

I will not overload you with this information yet, though. I’ll leave it for our next chapter. In the meantime, you can take a breather and relax!




<<< PREV NEXT >>>