| <<< PREV | NEXT >>> |
In the previous chapter, we have learned the basics of installing modules and importing them into level scripts, by using the require() instruction.
I also mentioned that modules can come with or without customizable parameters. Whether a module has parameters or not is up to the coder, the author of the module. As (only) a builder, you are limited to modifying values of these given parameters. This is not to say you can’t (or shouldn’t) branch out and learn how to change module code yourself (if anything, I’d encourage it, once you get comfortable with importing modules)! But going by our idealized categorizations of plugin users, a builder (with no knowledge nor interest in coding) never interferes with module code directly, and only changes parameters implemented by the coder.
Parameters provide a way to modify selected aspects of the particle effect, without having to change the module code itself. An example could be changing the sprite texture used by the particles. Or their color, or size, or duration, or determine how many particles are spawned and how often. With more complex modules, they can determine how much damage a particle can do to Lara or an enemy. If the particle has an area of effect, a parameter can describe the radius or range of that area. A parameter can specify the NGLE Script ID of the moveable object that will serve as a particle emitter or a target for a projectile. When dealing with mesh particles, parameters may determine which object slot and which mesh of the slot will be used for the mesh particles. If the particles play certain sound effects, a parameter can control which sound effect is played.
As you see, parameters can control and influence many different things. Because of this, customizable module parameters are quite reminiscent of the Customize= and Parameters= script commands in TRNG, which can describe various customizations of some TRLE or TRNG feature. However, what exactly is customizable varies between one feature and another, and you cannot change any aspects that are not explicitly given a parameter in the script command. The same can be said about module customization: what is customizable for a module depends on the module itself (and the intentions of the module’s author). It is the responsibility of the coder to communicate how many parameters a module has, what their names are and provide information about what each parameter is responsible for in the module (the same way CUST_ and PARAM_ constants have their parameters explained in the TRNG reference).
In this chapter, I will explain how the parameter system works and how the syntax changes when importing a module with parameters (there is a bit more Lua scripting involved here than for simply importing with require()).
As mentioned above, module parameters can be well understood by TRNG users through an analogy to parameters in Customize= and Parameters= scripts. The parameter list for each individual CUST_ or PARAM_ constant is different, and the same applies to modules.
Furthermore, just as parameters in the CUST_ / PARAM_ scripts often have default values (that are used if you don’t set a particular parameter, e.g. by typing IGNORE), module parameters have these default values too. If you do not set any value to the parameter yourself, the module will use the default value set by the coder instead (you literally ignore the parameter you do not wish to change). However, this does not mean that the default value that the parameter falls back to is always useful! To give an explanatory example: imagine that one parameter asks for the NGLE script ID of a moveable, which could be the emitter for the particle effect, let’s say. The coder decided to give this parameter the arbitrary placeholder value 51. Notice, which object has that specific NGLE script ID is different for each level map. It may even turn out that there is no object with that NGLE script ID in the level map yet! Hence the “default value” of this parameter is quite useless. Therefore, with some modules, certain parameters must always be changed after import, because the placeholder value is not meaningful or not applicable to your level map. Again, coders, as module authors, should communicate which parameters need obligatory adjustment.
Parameters for modules can be numbers, booleans or strings. I believe that number parameters should be self-explanatory (e.g. “a number for the particle’s lifetime”, “the number values of red, green and blue”), but I feel I should explain what booleans and strings are for.
Booleans in Lua can have two possible values: true or false. These words are always typed as lowercase to be seen as booleans. Neither True nor FALSE will be recognized as booleans by Lua. There is a high likelyhood you have some idea of what booleans are, generally speaking, but in a nutshell, they are used in mathematics and computer science to determine the logical value of a statement. For example, 2 > 1 is true, while 3 < 2 is false. Booleans also can also be used as an on/off toggle for something, with true usually representing the on-state and false representing off-state. As an example, the module implements a damaging projectile, which can optionally set Lara on fire, or just do regular damage with no fire. The coder can add a boolean parameter, which will answer the question: “Does the projectile set Lara on fire?”. The builder can then use the boolean parameter to answer with true (“yes”), so the projectile will indeed set her on fire. Answering with false (“no”) instead, the projectile will only hurt Lara, but will not set her on fire. Essentially, a boolean is useful for answering a yes or no question, enabling or disabling, turning something on / off.
Also, we can have strings. We have already seen strings before actually, when we were importing the modules with require() by their name. The name of the module typed in quotes, as in require("firehead"), was actually a string! A string is nothing more that some text placed inside a (matching) pair of quotes. String parameters can therefore be used to give arbitrary text data to a module. Admittedly, not that many features of the plugin call for the use of strings. However, it is possible to access values of the TRNG text variables (BigText, Last Input Text, Text1-4) with the plugin, so perhaps a module could do something with the text you provide to it via the string parameter. I will leave it up to creative module coders to figure it out, though!
To recap, module parameters can come in 3 different forms:
The require() instruction, in the form it was shown in the last chapter, imports a module by disregarding any parameters it may have (and assuming the default values of the parameters, which the coder must also provide). If the module, as indicated by the coder, has no parameters, then you might as well use the simplified import instruction:
An identifier is simply a label given to something inside Lua. Examine the below line:
Why did I bring up these labels all of a sudden? Well, because we also can label imported modules. And by doing so (labelling the module), we gain access to any parameters it may have!
Let me demonstrate a “labeled” module import:
| and | break | do | else | elseif | end |
| false | for | function | goto | if | in |
| local | nil | not | or | repeat | return |
| then | true | until | while |
Alright, we can now give modules these identifiers, but what’s the purpose of that? Well, if you have an unlabeled module, you cannot access its parameters, even if it may have them. Some parameters can fall back on default values, which is not the worst case. The worst case is when the module has a mandatory parameter that always needs changing (like the NGLE script index), but the unlabeled import prevents you from accessing it! That is why importing with an identifier is generally more recommended, unless you know for a fact that the module does not have any parameters to change.
To access a specific parameter of a module (e.g. in order to change it), you first must know how the coder called the parameter in question (again, the coder should disclose this kind of information when distributing the module). For example, party.lua has a parameter called size, which is a number parameter describing the general size of the particles which spawn around Lara.
We will attempt to import the module and change its size parameter. Let’s open up a level script file (refer back to the previous chapter on how to create one). In the first line, we import the module with an identifier (label), as described before:
Accessing parameters is not the only reason why importing a module with an identifier is worth the hassle. You see, we are not limited to importing a module only once...
What happens if we import the same module twice, but using different identifiers?
Up to this point, we have covered 90% of what a builder should know about modules and level scripts. The parameter system in tandem with the module copying mechanism allow the builder to get far more out of modules compared to the simple, unlabeled import we have seen in the previous chapter.
The remaining 10% is finally revealing how to protect the integrity of these plain-text Lua scripts once you package the finished custom level project in preparation to upload it to a hosting site (like trle.net or trcustoms.org). However, this 10% makes all the difference if you want to prevent devious players from making harmful traps heal Lara instead!
Do not skip this upcoming chapter, it is especially important to level builders! Take a break here, then we will continue our endevours.
| <<< PREV | NEXT >>> |