26-08-24, 16:55 | #1 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
TEN - Script elements and operations (basics)
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. The second tutorial of this sequence is about the things which I found the most important script element for a TEN level builder: functions. This current tutorial is the third part about scripting techniques in TEN. It is about the basic script elements and operations. CONTENTS: 1. Placing script elements 2. Variables and variable values 3. Basic mathematical operations 4. Checking conditions 5. Logical operations ---------- Notes:
Last edited by AkyV; 04-11-24 at 20:10. |
26-08-24, 18:26 | #2 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
1. Placing script elements
Even the brand new, still empty level script files have six initial functions (so-called "level callbacks"), which represent different game phases:
Notes:
Last edited by AkyV; 04-11-24 at 20:21. |
02-09-24, 19:47 | #3 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
2. Variables and variable values
Variables are simple textual names to your eyes, they don't have any graphical form. The purpose of the variables is to store some value. (I.e. the value is assigned to the textual variable name.) You can use the value stored in the variable, anywhere in your game, if you simply refer to the textual variable name. If you are already an advanced or expert TRNG builder, then you surely used some variables there previously. - Let's sum up the most important things about the TRNG variables:
X = 6 The variable value is a positive integer number. X = -122 The variable value is a negative integer number. X = 52.487 The variable value is a positive floating number. (Note that that is a decimal point, not a comma.) X = Y The value of Y variable will be copy/pasted to be the value of X variable. X = X + 1 The variable value is bigger with 1 than the previous value of the same variable. X = true The variable value is a boolean (true or false). X = OCBValue == 1 The variable value is "true", if the value of OCBValue variable is 1, or "false", if the value of OCBValue variable is not 1. X = "Hello, Lara!" The variable value is some text. (Note the quotation marks.) The text don't need to be repeated in any strings LUA file. X = flame:GetOCB() The variable value is the result of a function. X = TEN.Objects.GetMoveableByName("flame_emitter2_117" ) The variable value is an object - as the result of a function, anyway. X = nil If a variable can't have a valid value, then the variable will be deleted automatically. - For example: Code:
-- FILE: Levels\My_level.lua LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() end LevelFuncs.OnLoop = function() objectSize = (...) if objectSize < 600 then X = 8 end A = X + 46 end LevelFuncs.OnEnd = function() end "If" naturally will be checked in each moment of the loop. The "end" inside the loop belongs to "if", which means that all the contents between that "if" and that "end" are something which are checked by the "if". So if objectSize value is less than 600, any time during the loop, then 8 value will be set for X variable - while if it is not true, then won't be any value set for X variable, during the loop. So, again, the game reads all the OnLoop script lines again and again, in each moment of the game loop. So A = X + 46 line will be also read again and again. If the game reads that line when objectSize is less than 600, then the line will use X=8 variable value, so A will be 8+46=54. However, if the game reads that line when objectSize is equal to or bigger than 600, then the line can't use any X variable value, because X value doesn't exist for this objectSize value, X variable is deleted automatically for this case. - I.e. this is seemingly a bad scripting, variable A value cannot be computed when objectSize >= 600. "Nil" is not zero, nil means "nothing" - i.e. this is the value of a variable before the creation and after the deletion of the variable. Forcing this value in a variable is the way to remove the variable manually. (Note that neither "true", nor "nil" are set in quotation marks for the variable, because these values are technically not texts.) Text or number What if you want to print a number on the screen? Eg. the current X value (8 or nil) of the previous example. Then you can't do it directly. I mean, printing functions can print only texts. So, if you want to print a number on the screen, then you need to interpret it as some text. It will be done for you with "tostring" function: So eg. if X=8, then tostring will interpret 8 for a printing function as some text: printX = DisplayString(tostring(X), 250, 250, Color(255,0,0)) ShowString(printX, 10) But don't misunderstand: "8" or "nil" will be printed, i.e. 8 won't be printed as "eight". Linking values If the text you want to print on the screen has some non-constant contents, then you can use the "two dots operation" to link the text parts to each other. - For example (please, note the spaces inside the quotation marks, to also have spaces in the printed text): A = 5 B = 7 C = 18 D = 100 printtext = DisplayString(tostring(A) .. ", " .. tostring(B) .. " and " .. tostring(C) .. " is less than " .. tostring(D) .. ", but bigger than 3.", 250, 250, Color(255,0,0)) ShowString(printtext, 10) And now this is what will be printed on the screen: 5, 7 and 18 is less than 100, but bigger than 3. Local or global variables In TEN the fact that a variable is global, is not a guarantee that the global variable which you defined in Level A, will be also available in Level B. I.e. when you say in TEN that a variable is local or global, that has basically a different meaning, compared to TRNG:
Code:
-- FILE: Levels\My_level.lua function PrintA() A = 200 printA = DisplayString(tostring(A), 250, 100, Color(255,0,0)) ShowString(printA, 10) end function PrintAnyNumber(numberany) printAny = DisplayString(tostring(numberany), 250, 250, Color(255,0,0)) ShowString(printAny, 10) end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() A = 100 PrintA() if A == 100 then PrintAnyNumber(A) end if A == 200 then A = 300 PrintAnyNumber(A) end end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end The printed values are based in different variations of A variable:
Why? Because none of the variable definitions are labelled there. So in the case when all the variables are local, all of their definitions should be labelled as "local": Code:
-- FILE: Levels\My_level.lua function PrintA() local A = 200 printA = DisplayString(tostring(A), 250, 100, Color(255,0,0)) ShowString(printA, 10) end function PrintAnyNumber(numberany) printAny = DisplayString(tostring(numberany), 250, 250, Color(255,0,0)) ShowString(printAny, 10) end LevelFuncs.OnLoad = function() end LevelFuncs.OnSave = function() end LevelFuncs.OnStart = function() local A = 100 PrintA() if A == 100 then PrintAnyNumber(A) end if A == 200 then local A = 300 PrintAnyNumber(A) end end LevelFuncs.OnLoop = function() end LevelFuncs.OnEnd = function() end When you save a savegame, and then load it, then will the variable value be restored from it? I.e. will variables be saved in savegames? Well, you don't need to worry about it, in the case of continuous variable definitions. I mean, see the example above when the value of Z variable in OnLoop callback is the current value of Lara's animation index. I.e. when you load a savegame, then you don't need to restore the value of this variable from the savegame, because Z variable will get the current index immediately from the current playtime. But the situation is different with simple variable definitions like X = 8. Let's suppose you define X = 8 global variable value in OnStart callback, i.e. when the level starts. Then you start playing. The variable keeps its value, because it is global. After that you save the game, and then load that savegame. - Bad surprise! The variable has been automatically deleted. I.e. variable values usually won't be saved in savegames. (Either they are local or global, anyway.) You can have some tricks to prevent that:
Use variables having "LevelVars" or "GameVars" tags in their name. - For example: LevelVars.objectSize = 8 GameVars.FlipMapNumber = 16 LevelVars and GameVars variables are special global variables, because their value will be automatically saved when you save a savegame, and will be automatically restored when you load that savegame. Variable values transferred to other levels The values of local, "casual" global or LevelVars variables cannot be transferred to other levels. That is why the difference between LevelVars and GameVars variables is important:
---------- Notes:
Last edited by AkyV; 31-10-24 at 00:17. |
08-09-24, 10:40 | #4 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
3. Basic mathematical operations
Let's sum up all the basic mathematical operations you can use in the script. In our examples we have two variables, which are A = 6.5 and B = 4.2:
Note: Always use the round brackets in the proper way. I mean, I hope it is clear for you that eg. 2 * (A + B) or 2 * A + B have different results. Last edited by AkyV; 05-10-24 at 09:36. |
08-09-24, 12:55 | #5 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
4. Checking conditions
You could already see that conditions are handled in "if" blocks:
Code:
function LaraFlame() local LaraHealth = Lara:GetHP() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") if LaraHealth == 500 then flame:Enable() end end ==: equality ~=: inequality ("is not equal to") <: less than >: greater than <=: less or equal >=: greater or equal However, a condition could be either true or false. As you can see above, we don't need to mark it if it is "true", because it is obvious ("if LaraHealth == 500 then"). However, you can mark it, if you want: if LaraHealth == 500 == true then But if you want to check if the condition is false, then you need to mark it everyway: if LaraHealth == 500 == false then Naturally you can embed condition checks into each other: Code:
function LaraFlame() local LaraHealth = Lara:GetHP() local flame = TEN.Objects.GetMoveableByName("flame_emitter2_117") if LaraHealth > 500 == true then flame:Enable() if Lara:GetRoomNumber() == 10 == false then Lara:SetPoison(15) end end end "Else" and "elseif" statements Naturally you can check a condition even with its opposite. I mean eg. if you tell the game what to do when the condition is true, then perhaps you should also tell the game what to do when it is false: Code:
if LaraHealth > 500 then flame:Enable() end if LaraHealth <= 500 then flame:Disable() end Code:
if LaraHealth > 500 then flame:Enable() end if LaraHealth > 500 == false then flame:Disable() end Code:
if LaraHealth > 500 then flame:Enable() else flame:Disable() end Code:
if LaraHealth == 500 then flame:Enable() end if LaraHealth == 600 then Lara:SetPoison(15) end
Code:
if LaraHealth == 500 then flame:Enable() elseif LaraHealth == 600 then Lara:SetPoison(15) end Code:
if LaraHealth == 500 then flame:Enable() elseif LaraHealth == 600 then Lara:SetPoison(15) else flame:Disable() end Notes:
Last edited by AkyV; 09-09-24 at 18:47. |
08-09-24, 13:08 | #6 |
Moderator
Joined: Dec 2011
Posts: 5,054
|
5. Logical operations
You will use logical operators mostly to check conditions. "And" operator in conditions It could be really tiresome to check more than one conditions together: Code:
if LaraHealth > 500 == true then if Lara:GetRoomNumber() == 10 == false then flame:Enable() Lara:SetPoison(15) end end So you can modify the structure, using an "and" operator: Code:
if LaraHealth > 500 == true and Lara:GetRoomNumber() == 10 == false then flame:Enable() Lara:SetPoison(15) end "Or" operator in conditions Now it is enough if one of the conditions is passed, to execute the condition contents: Code:
if LaraHealth > 500 == true or Lara:GetRoomNumber() == 10 == false then flame:Enable() Lara:SetPoison(15) end "Not" operator in conditions It works the same way as a ~= relation (but only for true or false): Code:
if LaraHealth > 500 == not false then flame:Enable() Lara:SetPoison(15) end The operators out of conditions Now the operator needs to know that an argument:
---------- Notes:
Last edited by AkyV; 16-10-24 at 22:49. |
Bookmarks |
Thread Tools | |
|
|