29-07-24, 23:12 | #1 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
TEN - Script functions
Made using Tomb Editor 1.7.1. pack (including Tomb Engine 1.4.)
Last update to TE/TEN: 1.7.2./1.5. In the tutorial about the script files I started a sequence about introducing the basics of the so-called Lua scripting: i.e. Lua scripting techniques. Lua scripting is the method how the script is made for TEN. Scripted events In the tutorial which concentrates on the nodes I told that node events can be executable ("action") events or condition events for action events. You could also know that TEN events can be defined by nodes or by scripting. Which means there can also be executable scripted events and condition scripted events. Functions Probably the main elements of TEN scripting are the so-called functions. Scripted events are organized in the form of functions. So this is my second tutorial about the scripting techniques, concentrating on the basics of the functions this time. CONTENTS: 1. Identifying the functions 2. The origin of the functions 3. Function contents 4. Forcing or query 5. Placing functions 6. Function name structure 7. Nodes and functions ---------- Notes:
Last edited by AkyV; 04-11-24 at 20:02. |
30-07-24, 23:15 | #2 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
1. Identifying the functions
If you first look at any script files (including the ones you should never edit in Engine subfolder), then you will be surely terrified: "What is this? Is this scripting? Yes, you told me that it is different than TRNG scripting, but... but... how can I identify anything in this mess? How can I identify a function, for example?" Be patient. Yes, you are right, it is not easy at first sight. But you start learning scripting in TEN now, and sooner or later you will know enough to understand everyhting in a TEN script. So, yes, that question is a good start: how could you identify a function? Well, here is a hint - very primitive, but it works: If you see round brackets somewhere in the script, which are not parts of textual notes or not for a mathematical operation (like eg. (a+b)=c), then you have just found a function there. (As I told here, notes can be identified with starting -- sign.) But those brackets also need to have some text before them. - For example: Flow.AddLevel(title) Yes, it is a function. (You can find it in the initial version of Gameflow.lua, anyway.) The text before the brackets is the name of the function. The (numerical, or - just like in this example - textual) value in the brackets is the argument of the function. The argument is an input data for the function - i.e. without the argument value, the function cannot work. To understand it easily, consider it like a classic trigger action and its parameter. Eg. a trigger with "FlipMap" action chosen and value "2" typed in "Param" trigger window will turn on the flipmap which has ID2. So "Flow.AddLevel" is an "action" now, and "title" is the "parameter" for this action, and the game will read it this way: "I will do now what a Flow.AddLevel function should do, using title as the argument value". (But we won't discuss now what a Flow.AddLevel function should do.) ---------- Notes:
Last edited by AkyV; 21-08-24 at 10:02. |
30-07-24, 23:24 | #3 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
2. The origin of the functions
The functions are coming from two different origins:
After that find proper names for the function and the arguments. (Basically name them as you wish. However, I highly suggest to examine the function and argument names of the preset functions, and follow the naming methods used there - see for example here.) After that you are ready to create a custom function, as a new script entry. The entry needs to use "function" tag at the brackets. There has to be an equals sign before the "function" tag. The function name you've just found out has to be typed before the equals sign. The argument names you've just found out have to be typed in the brackets. So eg. when you want to create the function above with "FunctionX(A, B, C)" syntax, then use this rule: function_name = "function"(argument1_name, argument2_name, argument3_name) Which will look like this now: FunctionX = function(A, B, C) Or, alternatively, just simply type "function" tag before the function syntax: function FunctionX(A, B, C) FunctionX will be created when the game just reads this entry of the script. - However, naturally FunctionX cannot do anything for the time being, because you didn't tell it what to do. Below in the tutorial we will discuss that how you can add some contents to the function, so it will know what to do. ---------- Note: Not you are the only one who can create a custom function. I mean, see eg. how many times functions are created in the script files of Engine subfolder. As I said, you should never touch those script files, only TEN developers are editing them. Which means TEN developers are also creating custom functions. You ask why developers didn't make them as preset functions. Well, later in the tutorial I will tell that why developer-made custom functions exist. Last edited by AkyV; 21-08-24 at 10:10. |
01-08-24, 16:56 | #4 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
3. Function contents
You will never know the contents of the preset functions, but it is it not important, anyway. I mean, it is enough if you know the syntax of the function (function and argument names), the purpose of the function, and the meaning of the arguments. The function will work as the developers coded it. But that is not true for your custom functions where you are the one who needs to code the function contents. After that entry, which is for creating a function, just start typing the function contents in the further lines of the script. If it is done, then type one more latest line with the "end" tag - which means that the lines, which belong to that function, end here: Code:
function_name = "function"(arguments) function_contents end Code:
"function" function_name(arguments) function_contents end For example: Code:
FunctionX = function(A, B, C) local result = (A+B)*C end Code:
function FunctionX(A, B, C) local result = (A+B)*C end Let's say you run this function, with these argument values: FunctionX(3, 2, 4) What will happen in the moment when the game just reads this script line? Well, the value of "result" variable will be 20. Why? Because A=3, B=2, C=4, and (3+2)*4=20. Let's make this function is a bit more complex: Code:
FunctionX = function(A, B, C) local result = (A+B)*C SetItemCount(ObjID.UZI_AMMO_ITEM, result) end The function has two arguments. The name of the first argument is "objectID", the name of the second argument is "count". (The argument names can be identified in any tutorial, which is about the syntax of this function.) In this example the value of objectID argument is "ObjID.UZI_AMMO_ITEM", the value of count argument is the value of the result variable. In the case of running "FunctionX(3, 2, 4)" now, the value of the result variable will be still 20, so this preset function sets 20 Uzi bullets in the inventory. - So this time we will do something with the result in result variable at last... (Yes, the order of the lines is naturally important inside the function contents: first the first line will be read by the game, then the second one etc.) As you can see, the contents of a custom function can be really diverse: variables, preset functions - and so on. In further tutorials it will be discussed more. ---------- Note: Any value can be substituted with anything else, which has the same value. See eg. the previous example: When you don't want to be bothered by the result variable, then you can ignore it, delete it. Which means that count argument won't call "(A+B)*C" operation indirectly, i.e. via result variable. Instead, count argument will call "(A+B)*C" operation directly: Code:
FunctionX = function(A, B, C) SetItemCount(ObjID.UZI_AMMO_ITEM, (A+B)*C) end Last edited by AkyV; 24-08-24 at 18:16. |
03-08-24, 10:32 | #5 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
4. Forcing or query
As I said that there are executable scripted events and condition scripted events. So does that mean that there are executable functions and there are condition functions? Yes, it is true, but it is not always so easy to tell that which function is which type. - I mean, see for example this function: Code:
function MakeTinyFlame(FlameSize) local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") flame:SetOCB(FlameSize) end Or, when the same contents are only in one line, using the substitution I mentioned above: Code:
function MakeTinyFlame(FlameSize) TEN.Objects.GetMoveableByName("flame_emitter2_117"):SetOCB(FlameSize) end MakeTinyFlame(1) OCB 1 value for FLAME_EMITTER2 objects will make the flames half-sized. So the size of flame_emitter2_117 flame will be decreased now. Perhaps it is clearer this way (i.e. first we create the function, then we can run it): Code:
function MakeTinyFlame(FlameSize) TEN.Objects.GetMoveableByName("flame_emitter2_117"):SetOCB(FlameSize) end MakeTinyFlame(1) Code:
function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") flame:GetOCB() end CheckTinyFlame() This custom function first identifies a FLAME_EMITTER2 nullmesh object with flame_emitter2_117 name, storing this result in the local flame variable. Then it asks its OCB value, using another preset function. Perhaps it is clearer this way (i.e. first we create the function, then we can run it): Code:
function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") flame:GetOCB() end CheckTinyFlame() Does that mean that the second one (CheckTinyFlame) is a condition function? I mean, conditions always check something, like "if Lara is holding pistols in the hands" or "if the flipmap is on" etc., right? I mean, CheckTinyFlame also asks something: "which is the OCB value"? No, that is not true. I mean, CheckTinyFlame is really a query, but a condition could be only a "yes or no" question, i.e. it should start with "if...". And that question starts with something else: "which...". So CheckTinyFlame is also an executable function: it does something, it gets a value. The difference is that it does not force a value, because it works in the opposite direction: it gets a value. So MakeTinyFlame does not have an output value, while CheckTinyFlame has one. So if you want to turn that executable query into a condition query, then you need a "yes or no" question at the end of the function - for example: Code:
function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") local OCB = flame:GetOCB() return OCB == 1 end When you type "return" command (officially called "statement", not command), there you create another output value for the function. This value is always an answer for a "yes or no" question, which is equal to another "yes or no" question about the whole function. I.e. when you ask (anywhere in the code, but out of this function) that "if CheckTinyFlame function is true?", then the answer for this is the answer at the return entry of this function. I mean, the "==" sign you can see at the return entry always means there is a "yes or no" question there. So "OCB == 1" means that "if the value of OCB variable is 1?" The answer is naturally yes (true) if the OCB variable value is 1, or a no (false) if the OCB variable value is not 1. So when you type this, out of the function: if CheckTinyFlame() == true then that is another "yes or no" question, which means "if CheckTinyFlame function is true?", and which also means the previous "yes or no" question, i.e. "if the value of OCB variable is 1?" (I.e. "if that flame is half-sized?") So CheckTinyFlame is a condition function now, and if you'd like to check if this condition is true or false, then you need an "if CheckTinyFlame() == true then" entry where you want to check it. (But the method to use "if" situations - including how to exactly check a condition function output - will be discussed in another tutorial.) Perhaps it is clearer this way (i.e. first we create the function, then we can check it - so we don't need to run it): Code:
function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") local OCB = flame:GetOCB() return OCB == 1 end if CheckTinyFlame() == true then (...) ---------- Notes:
Last edited by AkyV; 08-10-24 at 09:43. |
03-08-24, 10:35 | #6 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
5. Placing functions
Technically you can make/use functions in any of the script files. However, you should use them this way:
So in this chapter we only discuss that how to place event functions in the level script files. Initially all the level script files are almost totally empty. Now they only have a note to introduce the route of the current file, and six empty functions (i.e. six functions which seemingly have no contents): Please note that you cannot find the sixth initial function (LevelFuncs.OnUseItem) in the screenshots or the examples of the tutorial, because those are made with a previous version of TE. Reading the script The game always reads the scripts from top to bottom: first the first script line, then the second script line, then the third script line etc. (I've mentioned it above yet, anyway.) Which means if two things are connected to each other in the script, then the thing, which should happen first, must be in the upper position (so it will be read sooner), and the one that should happen after that, must be in the lower position (so it will be read later). For example, when you want to run a function, then first you need to create the function. I.e. the block with the function contents must be typed in the upper position, and the line to run the function must be typed in the lower position. Naturally any of the six initial functions will run only when that game phase is running. Eg. "OnStart" function will run only when the game starts. So if you place a "run function" line in "OnStart" initial function, as the contents of the initial function, then that "run function" line will happen only when the level starts. - That is why I do not suggest to run a function out of the initial functions, because the game will not know exactly that in which game phase it should read a "run function" line. Code:
-- FILE: Levels\My_level.lua function_name(arguments) function_name = function(arguments) function_contents end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua function_name = function(arguments) function_contents end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end function_name(arguments) LevelFuncs.OnEnd = function() end However, the function is not running inside an initial function, so you can't be sure that when exactly it will be running. Code:
-- FILE: Levels\My_level.lua function_name = function(arguments) function_contents end LevelFuncs.OnLoad = function() function_name(arguments) end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() function_name(arguments) end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Besides, you can exactly tell that when the function will be running: first when the level starts, then later each time when you load a savegame in that level. Code:
-- FILE: Levels\My_level.lua LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() function_name = function(arguments) function_contents end function_name(arguments) end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end CONCLUSION: Any pure "run/call function" line you want to type in the script should be typed in an initial function. Everything typed out of initial functions must be only definitions: defining function contents, defining a variable value etc. - However, definitions also can go into initial functions. (With "pure" I want to say that you type only that line there. I mean, naturally you can type "run/call function" lines even when you type not only that line there, but having the line in definitions instead. See above eg. "SetItemCount(ObjID.UZI_AMMO_ITEM, result)" line which runs "only" as a part of a custom function contents. Or see above eg. "local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117" )", which is "only" to set flame variable value - also in a custom function contents this time, anyway.) Functions called directly in the script As I told above, initial functions will run (automatically) when their phase is just running in the game. So you don't need to run (i.e. to call) a function in the script everyway. - This is what I call "indirect calling". So, when a function runs in the script, then that should be called "direct calling". If a function event runs in the script, that will be always considered as a global event. For example: Code:
-- FILE: Levels\My_level.lua function LevelFuncs.PrintHello() local write = "Hello, Lara!" local display = DisplayString(write, 250, 250, Color(255,0,0)) ShowString(display, 10) end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() LevelFuncs.PrintHello() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end It first defines in "write" variable the text (quoted) which you want to print. Then DisplayString preset function defines the coordinates and color for the value of write variable, i.e. for "Hello, Lara" text. The function result will be stored in display variable. Then ShowsString preset function will print the text on the screen, for 10 seconds. It gets the values (text, coordinates, color) from display variable value. This time:
If a function is called via event set editors (I told here how), then that is naturally an indirect calling, because the function will not be called via the script. (These function events could be either local - i.e. "volume" - or global events.) Which means you can create the function anywhere in the script, because you don't need to define the proper script spot below that creation, where this function will run in an initial function. - For example "LevelFuncs.PrintHello" will be called this time in a (any) event set editor: Code:
-- FILE: Levels\My_level.lua LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end LevelFuncs.PrintHello = function() local write = "Hello, Lara!" local display = DisplayString(write, 250, 250, Color(255,0,0)) ShowString(display, 10) end
Let'see how the examples above will look, when the custom functions have some input values. - First let's see how you can use direct inputs. I called an input "direct", when exactly the input value are typed in the brackets, when you run the function. Modify the "called in the script" example above, to have an input value, which is called directly: Code:
-- FILE: Levels\My_level.lua function LevelFuncs.PrintHello(write) local display = DisplayString(write, 250, 250, Color(255,0,0)) ShowString(display, 10) end LevelFuncs.OnLoad = function() LevelFuncs.PrintHello("Hello, you have just loaded a savegame!") end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() LevelFuncs.PrintHello("Hello, Lara!") end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end "Hello, Lara!" will be printed on the screen when the level starts. But "Hello, you have just loaded a savegame!" will be printed on the screen each time when you have just loaded a savegame. (Naturally you don't need quotation marks when the value is not textual, but numerical.) Functions with an indirect input I called an input "indirect", when not exactly the input value are typed in the brackets, when you run the function. I.e. the value is substituted for something else. Modify the "called in the script, input called directly" example above, to have an input value, which is called indirectly: Code:
-- FILE: Levels\My_level.lua function LevelFuncs.PrintHello(write) local display = DisplayString(write, 250, 250, Color(255,0,0)) ShowString(display, 10) end local hellotext = "Hello, Lara!" LevelFuncs.OnLoad = function() hellotext = "Hello, you have just loaded a savegame!" LevelFuncs.PrintHello(hellotext) end LevelFuncs.OnSave = function() LevelFuncs.PrintHello(hellotext) end LevelFuncs.OnStart = function() LevelFuncs.PrintHello(hellotext) end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end
Code:
-- FILE: Levels\My_level.lua function LevelFuncs.PrintHello(write, PosX, PosY) local display = DisplayString(write, PosX, PosY, Color(255,0,0)) ShowString(display, 10) end local hellostart = "Hello, Lara!" local helloload = "Hello, you have just loaded a savegame!" local hellosave = "Hello, you have just saved a savegame!" local A = 250 local B = A * 2 LevelFuncs.OnLoad = function() LevelFuncs.PrintHello(helloload, A, B) end LevelFuncs.OnSave = function() LevelFuncs.PrintHello(hellosave, A, B) end LevelFuncs.OnStart = function() LevelFuncs.PrintHello(hellostart, A, B) end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end In the case of functions in event set editors, you don't need to run functions in the script. So how can you set an input value? Well, it is a bit tricky. - I mean, you need to type that input value in the little Argument window of the event set editor, on that page where the function is called. - For example: But:
Let's see the example again when we created a global OCB variable in CheckTinyFlame function, to use the variable value out of the function. So we have the actual OCB value of flame_emitter2_117 in OCB global variable. We create another function as well, to force this OCB variable value on flame_emitter2_118 object, to make it its OCB value, too, when the game has just been loaded. I.e. the input value of the new function is called "forcedValue", its actual value will be the value of that OCB variable. What will happen is: when you load a savegame, then you can be sure that the OCB of the two objects will be surely the same, even if you changed the OCB of flame_emitter2_118 with some other method in the meantime: Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") OCB = flame:GetOCB() end function ForceOCB(forcedValue) TEN.Objects.GetMoveableByName("flame_emitter2_118"):SetOCB(forcedValue) end LevelFuncs.OnLoad = function() CheckTinyFlame() ForceOCB(OCB) end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua LevelFuncs.OnLoad = function() function ForceOCB(forcedValue) TEN.Objects.GetMoveableByName("flame_emitter2_118"):SetOCB(forcedValue) end local OCB = TEN.Objects.GetMoveableByName("flame_emitter2_117"):GetOCB() ForceOCB(OCB) end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua LevelFuncs.OnLoad = function() function ForceOCB(forcedValue) TEN.Objects.GetMoveableByName("flame_emitter2_118"):SetOCB(forcedValue) end ForceOCB(TEN.Objects.GetMoveableByName("flame_emitter2_117"):GetOCB()) end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Using the outputs of condition functions As I said, you don't need to run the function, if it is a condition with a return value, it is enough if you check it out of the function. But I didn't still say that this check must happen in another function, which is executable. Which is logical, because "if condition function event is true then executable condition event will happen". - For example: Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") local OCB = flame:GetOCB() return OCB == 1 end function DoSomething() if CheckTinyFlame() == true then (...) end LevelFuncs.OnLoad = function() DoSomething() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame(Emitter) local flame = TEN.Objects.GetMoveableByName(Emitter) local OCB = flame:GetOCB() return OCB == 1 end function DoSomething(Fire) if CheckTinyFlame(Fire) == true then (...) end LevelFuncs.OnLoad = function() DoSomething("flame_emitter2_117") end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua local Flame1 = "flame_emitter2_117" local Flame2 = "flame_emitter2_118" function CheckTinyFlame(Emitter) local flame = TEN.Objects.GetMoveableByName(Emitter) local OCB = flame:GetOCB() return OCB == 1 end function DoSomething(Fire) if CheckTinyFlame(Fire) == true then (...) end LevelFuncs.OnLoad = function() DoSomething(Flame1) end LevelFuncs.OnSave = function() DoSomething(Flame2) end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua local Fire = "flame_emitter2_117" function CheckTinyFlame(Emitter) local flame = TEN.Objects.GetMoveableByName(Emitter) local OCB = flame:GetOCB() return OCB == 1 end function DoSomething() if CheckTinyFlame(Fire) == true then (...) end LevelFuncs.OnLoad = function() DoSomething() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame(Emitter) local flame = TEN.Objects.GetMoveableByName(Emitter) local OCB = flame:GetOCB() return OCB == 1 end function DoSomething() if CheckTinyFlame("flame_emitter2_117") == true then (...) end function DoDifferentThing() if CheckTinyFlame("flame_emitter2_118") == true then (...) end LevelFuncs.OnLoad = function() DoSomething() end LevelFuncs.OnSave = function() DoDifferentThing() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") local OCB = flame:GetOCB() return OCB == 1 end LevelFuncs.DoSomething = function() if CheckTinyFlame() == true then (...) end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Code:
-- FILE: Levels\My_level.lua function CheckTinyFlame(Emitter) local flame = TEN.Objects.GetMoveableByName(Emitter) local OCB = flame:GetOCB() return OCB == 1 end LevelFuncs.DoSomething = function(activator, Emitter) if CheckTinyFlame(Emitter) == true then (...) end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end Notes:
Last edited by AkyV; 13-11-24 at 07:26. |
04-08-24, 11:47 | #7 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
6. Function name structure
Custom function names As I said above, name the custom functions as you wish - except: probably you'd better follow the usual naming pattern of developers. However, it is obviously a good question that why I thought it was important to add "LevelFuncs" tag to "DoSomething" function in the previous chapter, when I wanted to call the function in event set editors? I said, event set editors are unable to realize preset functions, they will realize only custom functions - if the function is created with the "function_name = function(arguments)" formula. But I still did not say that a custom function can be realized in event set editors, only if its name has that "LevelFuncs" tag: LevelFuncs.function_name = function(arguments) A custom function created with the formula above will be realized by event set editors. However, this custom function can be also called in the script. function_name = function(arguments) function function_name(arguments) function LevelFuncs.function_name(arguments) A custom function created with the formulas above will not be realized by event set editors. These custom functions can be called only in the script. However, as you can see, even if the event set editors realize a function, they never repeat the "LevelFuncs" tag in the editor: eg. LevelFuncs.DoSomething will be printed there simply only as DoSomething. Preset function names Preset functions are named differently. They are placed nicely in a "function name hierarchy":
---------- Notes:
Last edited by AkyV; 04-11-24 at 20:09. |
20-08-24, 11:48 | #8 |
Moderator
Joined: Dec 2011
Posts: 5,074
|
7. Nodes and functions
There are two connections between nodes and functions. Node events defined by functions As I said above, not you are the only one who can create a custom function. Many of them are initially created - naturally by developers - in the LUA files of Engine subfolder, which you should never touch. The script files we are interested in now, are in NodeCatalogs sub-subfolder here: (almost) each of them is for a group, which group you can find in the node menu when you right-click on the node editor surface, to add a node to an event set. You can find eg. this in Moveable.lua there (which LUA is for "Moveable state" and "Moveable parameters" group): Code:
-- !Name "If position of a moveable is within range..." -- !Section "Moveable parameters" -- !Description "Checks if moveable's current position is within specified range." -- !Description "If single-dimension check is needed, set other dimensions to values well out of level bounds." -- !Conditional "True" -- !Arguments "NewLine, Moveables" -- !Arguments "NewLine, Vector3, [ -1000000 | 1000000 ], Upper position bound" "NewLine, Vector3, [ -1000000 | 1000000 ], Lower position bound" LevelFuncs.Engine.Node.TestMoveablePosition = function(moveableName, pos1, pos2) local pos = TEN.Objects.GetMoveableByName(moveableName):GetPosition() return (pos.x >= pos1.x and pos.x <= pos2.x and pos.y >= pos1.y and pos.y <= pos2.y and pos.z >= pos1.z and pos.z <= pos2.z) end
I.e. if you want, you can do exactly what a node event does, if you use the proper scripting instead of nodes. Export nodes into the script Just like when you exported a TRNG trigger into the script, you can export node contents into the script. Just add this node in the event set editors to an event set (just temporarily, because you don't want to keep this node this time), then click on the "Pages" ("Export Lua script to clipboard") button at the bottom of the event set editor panel. Now go into the level script file of this level, then hit CTRL+V. The contents of this node will be pasted there, as the contents of a new custom function (the first "end" belongs to the "if"): Code:
LevelFuncs.ExportedNodeFunction = function(activator) if (LevelFuncs.Engine.Node.TestMoveablePosition("animating14_5", TEN.Vec3(1024,2048,4096), TEN.Vec3(2048,4096,8192))) then end end (Naturally it will not check but run the function, if it is not a condition node event, but an executable one.) What you can do here is:
See for example, that how this complex example looks exported into the script: Code:
LevelFuncs.ExportedNodeFunction = function(activator) if (LevelFuncs.Engine.Node.TestLaraWeaponType(1)) then if (LevelFuncs.Engine.Node.TestLaraHandStatus(4)) then LevelFuncs.Engine.Node.EnableMoveable("flame_emitter_a", 0) else if (LevelFuncs.Engine.Node.TestLaraHandStatus(0)) then LevelFuncs.Engine.Node.EnableMoveable("flame_emitter_b", 0) else LevelFuncs.Engine.Node.EnableMoveable("flame_emitter_c", 0) end end end end ---------- Note: As you can see - see TEN.Vec3(...) functions - some preset functions have different name hierarchy than I introduced them in the previous chapter. Never mind, there are always some exceptions - there will be tutorials for them, where we will discuss them. Last edited by AkyV; 23-11-24 at 13:00. |
Bookmarks |
Thread Tools | |
|
|