Tomb Raider Forums  

Go Back   Tomb Raider Forums > Tomb Raider Level Editor and Modding > Tomb Raider Level Editor > Tutorials and Resources

Closed Thread
 
Thread Tools
Old 05-11-24, 19:43   #1
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default TEN - Scripting: mechanism, forms, settings

Made using Tomb Editor 1.7.2. pack (including Tomb Engine 1.5.)
Last update to TE/TEN: -


In the tutorial about the script files I started a tutorial sequence about TEN scripting techniques.

The further parts of the sequence so far:
functions, basic scripting, advanced scripting.

So this current tutorial is the fifth - and, for the time being, surely the last - part about scripting techniques in TEN. It helps you to feel comfortable while scripting, eg. introducing the script settings in TIDE, etc.

CONTENTS:

1. Scripting Studio layout
2. The script reading mechanism in the game
3. Writing script
4. Settings for the appearance
5. Building issues and the error log

----------

Notes:
  • As the title says, it is “only” a Tomb Engine (TEN) tutorial. Many aspects you need to know for this tutorial are specific Tomb Editor (TE), TombIDE (TIDE), WadTool (WT) etc. features.
    So non-TEN features are only referred now, if it is necessary. And as much as I found it necessary. You need to also meet these features in other tutorials, for further details about them.
  • Some related TEN features are only mentioned, but not discussed in this tutorial, because they belong better to (an)other tutorial(s).
    Find another info source or be patient till those other tutorials are made.
  • Some options or commands can be executed in several ways. I may not introduce all of the ways in the tutorial. (Using default keys are presumed.)
  • Explainig basics about Lua scripting is not the best decision in a precise way when you, the reader, is a beginner TEN builder. That is why I try to interpret Lua scripting mostly with my own words - while I also try to remain authentical, naturally. (Which is not too hard, anyway, because when I am making this tutorial sequence then I am not a Lua expert myself...)I linked the tutorial of script files in the first post.
  • TEN could have not only the script files I introduced in the tutorial about the script files.
    I mean here I also tell that you can create even brand new, empty script files in TEN. (As I tell there, I think the only reason usually in TEN to create a new script file nowadays could be when you create a level manually in TIDE, not using the wizard. - Except: latter tutorials I will tell more...)
  • The structures of the different script files are different. In the post I linked in the previous note I've already introduced the structure of Gameflow.lua, and shortly also introduced there Strings.lua. And in the previous tutorials of the current tutorial sequence I've already introduced the structure of level script files, via numerous scripting examples.
    All of this about script structures should be enough for you to place the variables, functions etc. of the scripts in the required positions of the current script file.
    (Yes, some further knowledge is also available for script structures - eg. SystemStrings.lua structure -, but that is not necessary for doing your general scripting.)

Last edited by AkyV; 18-11-24 at 20:31.
AkyV is offline  
Old 05-11-24, 20:12   #2
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default

1. Scripting Studio layout

The scripting for TEN (or for any engines of TE) is made in Scripting Studio page of TIDE.
The big window to edit the script and the dropdown menu are constant in the Scripting Studio layout, but you can open/close the other parts, if you wish:
  • File Explorer panel - a default part.
    The panel on the right side, listing the script files.
  • Tool Strip (toolbar buttons) - a default part.
  • Status Strip - a default part.
    A thin strip at the bottom, with some information: Line, Column, Selected.
  • Search Results panel - not a default part, so perhaps you can't see it even now.
    It is meaningless to open it before you searching for anything in the script.
Opening/closing them happens this way:
  • Closing them:

    • any panel: clicking on its X, or
    • any panel or strip: unticking it in dropdown menu/View, or
    • Search Results: clicking on Restore Default Layout it in dropdown menu/View, or

  • Opening them:

    • any panel or strip: ticking it in dropdown menu/View, or
    • File Explorer: clicking on Restore Default Layout it in dropdown menu/View, or
    • any strip: closing/reopening TIDE, then coming back to Scripting Studio, or
    • any strip: going to TIDE Start page, then coming back to Scripting Studio.
Panels can be resized:
  • grab the left edge of File Explorer, by the mouse, and move it leftwards or rightwards, or
  • grab the upper edge of Search Results, by the mouse, and move it upwards or downwards.
Naturally you can also resize the whole TIDE window, to resize Scripting Studio.

----------

Note:
In dropdown menu/Options/Text Editor Settings you have an option to set the required background color. But the feature is not added yet.

Last edited by AkyV; 08-11-24 at 18:07.
AkyV is offline  
Old 05-11-24, 20:13   #3
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default

2. The script reading mechanism in the game

The game will read a specific script file when it just needs that. Eg. the level script file of level X naturally will be read when the current level running is level X.
Whatever script file is just open in the big window, then you can see that its lines are numbered, in an ascending order: 1, 2, 3, 4, 5 etc. - Naturally it is really useful, because now you can easily identify each line of the current script file.
The game reads the script lines from top to bottom, but the game never reads the line ID numbers to identify its current position. Instead, it tries to find specific signs to identify its position.

Let's see this example (which should be familiar from the previous tutorial of this tutorial sequence), from a level script file:

Click image for larger version

Name:	105.jpg
Views:	21
Size:	57.7 KB
ID:	8506

The signs (in the order of reading it) which will tell the game how to continue reading the script:
  • The contents of OnLoop callback is being read only during the effective playtime.
  • When FlameAmbience custom function is called in OnLoop callback, then it remembers the "function" tag (in Line 3) where the function name was already typed previously: this is the point where the function contents start.
    After the closing round bracket for the function arguments (still in Line 3) the game starts reading these contents.
  • The first thing in the contents of the function is the declaration of a variable, labelled as "local", with defining the variable value (local flameOn = 0).
    After this 0 digit there is nothing else you can do for defining the value of the variable. I mean, you could define this 0 value naturally eg. even in the "local flameOn = -2 + 2" way. In that case, after reading -2, the game will realize the + sign to add 2 for the 0 value of the variable.
    But there is no any operation like that here, so defining the variable value ends here.
  • The next thing in the contents of the function is a "for" tag, signaling a "for" loop starts here. It waits for the variable of the loop, and the values of the variable (i = 1, 10). After that, the game reads the "do" tag, so it will know that what come now are the contents of the loop.
  • The first thing in the contents of the loop is an "if" tag, signaling a condition will be read here. This condition is "GetMoveableByName("flame_emitter_" .. i):GetActive() == true". After that, the "then" tag says the contents will be read which should be executed when the condition is true.
  • The only thing which should be executed is "flameOn = flameOn + 1", to modify the value of flameOn variable. The operation doesn't continue after the digit of 1, so the game will know that the definition of the new value of the variable ends here.
  • Then an "end" tag is the next. An "end" always closes the latest opened block. Which is that "if" now, so the game will know that there are no further things to be executed when that condition is true.
  • Then another "end" tag is the next. An "end" always closes the latest opened block. Which is that "for" now, so the game will know that there is nothing more to do for the current value of the loop.
    If this value is not the last value of the loop, then the game will jump back to that "for" tag, running the loop again, for the next value of the loop.
    But if this value is the last value of the loop (10), then the game will continue reading the script.
  • As the next step, the game will execute EmitLight preset function, with the required argument values.
  • Then another "end" tag is the next. An "end" always closes the latest opened block. Which is the block of FlameAmbience custom function now, so executing the function ends here.
  • FlameAmbience is called in OnLoop callback, so in the next moment of the effective playtime, the function contents will be read once more. And again once more, and again once more... in the further moments of the effective playtime.
As you can see, LUA scripting doesn't say that "the line has been ended here, so there will be something else in the next line". I mean, the whole code is fluent, and only the signs I mentioned will tell when something new happens - for example:
  • When the operation for defining a variable value has been ended, then the next thing will be about something else, i.e. not about the definition of the variable value.
  • The game has just read a "do" tag of a loop, so what follow it are the things what happen in this loop.
  • The game has just read a "then" tag of a condition, so what follow it are the things what happen when this condition is true.
  • The game has just read an "end" tag of the latest opened block, so what follow it belong to the block which is the new latest opened block. (Or, if there is no new latest opened block, then they are just simply things which don't belong to the block which has just been closed.)
  • Etc.
Which means that, after all, you don't need to type the script as a nice way as you can see in the image above. Instead, you can type even the whole (!) contents of the script file in one line. - Or, at least, if we typed the whole FlameAmbience function definition in one line, that looks this way:

Code:
function FlameAmbience() local flameOn = 0 for i = 1, 10 do if GetMoveableByName("flame_emitter_" .. i):GetActive() == true then flameOn = flameOn + 1 end end EmitLight(Vec3(12288, -1280, 10086), Color(200 * flameOn / 10, 100 * flameOn / 10, 20 * flameOn / 10), 20) end
It is naturally really ugly - but, again: it is totally workable.

----------

Note:
In dropdown menu/Options/Text Editor Settings you can untick "Show line numbers" if you feel the line ID numbers which are unnecessary to the game, are also disturbing to you.

Last edited by AkyV; 12-11-24 at 20:40.
AkyV is offline  
Old 06-11-24, 18:58   #4
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default

3. Writing script

Just type the characters the same way as you type your text in a Word document - this is the main thing you need to know when you type your code in the script.
But there are some additional things you also need to know:
  • Adding a new line: naturally just hit ENTER.
  • Deleting a line: SHIFT + DELETE. (Not only the contents, but the whole line.)
  • Be careful, TEN scripting has case sensitivity!
    So eg. if you type Getmoveablebyname instead of the exact name of GetMoveableByName function, then the game will ignore this function, while reading the script.
  • Positioning the cursor (in the interval between the first and the last numbered line):

    • Naturally just click there.
    • Moving one line up/down: up/down arrow keys.
    • Moving one character left/right: left/right arrow keys.
      If you are at the start of a line, then, moving left, the cursor jumps to the end of the previous line.
      If you are at the end of a line, then, moving right, the cursor jumps to the start of the next line.
    • Moving to the first line of the script file: PAGE UP.
    • Moving to the last currently existing line of the script file: PAGE DOWN.
    • Moving to the start of the first line of the script file: CTRL + HOME.
    • Moving to the end of the last currently existing line of the script file: CTRL + END.
    • Moving to the start of the current line: HOME.
    • Moving to the end of the current line: END.
    • Moving to the left or right, to the left/right side of the unit there: CTRL + left/right arrow.
      Units eg. in the line of "if GetMoveableByName("flame_emitter_" .. i):GetActive() == true then", from left to right: tabulation, if (with space after it), GetMoveableByName, (", flame_emitter_, " (with space after it), .. (with space after it), i, ):, GetActive, () (with space after it), == (with space after it), true (with space after it), then.

  • CTRL + PAGE UP/DOWN: turn a page up/down. (Without moving the cursor.)
  • Cut (CTRL+X), copy (CTRL+C), paste (CTRL+V) is also available in dropdown menu/Edit, or as toolbar buttons, or in a right-click popup menu.
  • Specific text selections (i.e. not when holding the left mouse button down + drawing the mouse):

    • Click with holding SHIFT: selecting between that point and the previous cursor position.
    • Moving the cursor to a point, holding down SHIFT: selecting between that point and the cursor position before the moves.
    • SHIFT + HOME/END (which is also a HOME/END move for the cursor): the current line will be selected between that point and the previous cursor position.
    • Click on an ID number of a line: select that line. (The cursor will jump to the start of the next line. In the case of selecting the last numbered line it will jump to the end of the last line.)
    • CTRL + A, or dropdown menu/Edit/Select All: select the whole contents of the script file.

  • Undo/redo: CTRL+Y/CTRL+Z, but they are also available in dropdown menu/Edit, or as toolbar buttons.
Nice appearance

In the previous chapter, you could see the function typed only in one line.
If you find that ugly, then you can split the function into more lines, eg.:

Code:
function FlameAmbience()
local flameOn = 0
for i = 1, 10 do if GetMoveableByName("flame_emitter_" .. i):GetActive() == true then flameOn = flameOn + 1 end end
EmitLight(Vec3(12288, -1280, 10086), Color(200 * flameOn / 10, 100 * flameOn / 10, 20 * flameOn / 10), 20)
end
But naturally the best look is what you can see in the image of the previous chapter.
For a nice look, keep these rules in your mind:
  • Each operation should be typed in its own line. Operations are not mixed in the same line.
  • There could be empty lines between some parts of the script, which makes easier to separate them from each other.
  • Empty spaces also makes the script look better. Eg. a + b = c looks better than a+b=c.
  • Tabulating the start of the line a bit rightwards helps you to identify the script hierarchy (see that image again):

    • No tabulations: the highest (first) hierarchy level. First of all they will be read from the script, by the game.
      Mostly callbacks, but eg. the description of FlameAmbience function here also starts in the highest hierarchy.
    • One tabulation: the second hierarchy level. When a highest hierarchy level element has just been read, then these elements in it can be also read:
      FlameAmbience function can be called in OnLoop callback.
      Or these operations can be done inside the FlameAmbience function description: define 0 value for flameOn variable, run a "for" loop, execute EmitLight function.
    • Two tabulations: the third hierarchy level. When a second hierarchy level element has just been read, then these elements in it can be also read: an "if" condition will be checked for the current value of the "for" loop. (There are no further examples for this in that image.)
    • Three tabulations: the fourth hierarchy level. When a third hierarchy level element has just been read, then these elements in it can be also read: flameOn variable value will be increased by one, if that "if" condition is true. (There are no further examples for this in that image.)
    • Four tabulations, five tabulations etc.

    But I also need to tell these:

    • If the element of a hierarchy level is a block (for, if etc.), then the "end" tag which closes it naturally should be placed in the same hierarchy. So you can easily identify where that block ends.
    • As you can see, EmitLight function arguments are split into two lines, because the line would be too long if I type all of them in only one line. (Please note that where the line is broken, that place doesn't need to be marked by any sign.)
      Yes, it is possible to type even each unit of a line into different lines. (See above what a "unit" means.) - So, for example, it also works:

      Code:
          EmitLight
          (
          Vec3
          (
          12288
          , 
          -
          1280
          , 
          10086
          ), 
          Color
          (
          200 
          * 
          flameOn 
          / 
          10
          , 
          100 
          * 
          flameOn 
          / 
          10
          , 
          20 
          * 
          flameOn 
          / 
          10
          ), 
          20
          )
  • In TEN scripting two "-" signs mark the place where a remark (i.e. a comment) starts.
    A comment is always skipped by the game while reading the script. Comments are only for you (or anyone else who reads your script). Comments tell what the script is currently doing there - so the different parts of the script can be easily followed. - For example:

    Code:
    --Extended light ambience for flames:
    
    function FlameAmbience()
        local flameOn = 0	--no flames are burning
        for i = 1, 10 do	--loop for each flame
           	if GetMoveableByName("flame_emitter_" .. i):GetActive() == true then --if the flame is burning
               	flameOn = flameOn + 1 --burning flame counter
    	end    	
        end
        
        --"Big light bulb" intensity:
        
        EmitLight(Vec3(12288, -1280, 10086),
        	Color(200 * flameOn / 10, 100 * flameOn / 10, 20 * flameOn / 10), 20) 	
    end
    All the characters after the -- sign will be used as a comment, in that line.
----------

Notes:
  • TEN scripting doesn't have an autocomplete function.
    So eg. if you type "TEN.", waiting for a popup window to show the module names (Effects, Flow, Input etc.) of TEN master table, then nothing will happen.
  • The information you can see in Status Strip:

    • Line: the ID number of the current line of the cursor.
    • Column: the current character position of the cursor in its current line.
    • Selected: if there is some text selected, then this is the amount of the selected characters.

  • These signs are used with a closing pair, so basically the closing pair will be automatically also printed when you type the opening pair: (, [, {, ".
    Untick them at dropdown menu/Options/Text Editor Settings, if you don't want that automatic printing.
  • See these tasks at dropdown menu/Document/Convert:

    • Tabs to Spaces: all the tabulations of the current script file will be converted into empty spaces.
    • Spaces to Tabs: all the empty spaces of the current script file will be converted into tabulations. (But naturally if some spaces next to each other not long enough to be a tabulation for that tabulated position, then they remain spaces.)

  • If you want, then you can use semicolons to signal the end of the lines. They show nicely where a single line should be ended if you write more single lines fluently in one line:

    Code:
    function FlameAmbience();
    local flameOn = 0;
    for i = 1, 10 do; if GetMoveableByName("flame_emitter_" .. i):GetActive() == true then; flameOn = flameOn + 1; end; end;
    EmitLight(Vec3(12288, -1280, 10086), Color(200 * flameOn / 10, 100 * flameOn / 10, 20 * flameOn / 10), 20);
    end;
  • Notes for comments:

    • The fact that an operation can be typed even in more lines, i.e. in more parts, makes the comments more useful - so you can type a comment not only for the whole operation, but even for a part of it:

      Code:
      local NatlasTeam = {
           {"Natla", "Pierre", "Larson"},  --ID1 subtable
           {"Kold", "Kid", "Cowboy"}       --ID2 subtable
      }
    • Comments are also useful if you want to ignore some code temporarily.
      For example, you can have two different results for variable a, and you still don't know which one to choose. So you'll try both in the game - and while you try one of them, the other one is ignored. Then you swap them for each other, the first one will be ignored, the other one will be tried:

      Code:
      b = 12
      --a = b * 6 + 8
      a = (b + 72) / 4
    • You don't need to set/remove the -- sign of a comment manually.
      I mean, place the cursor in any line, which is fully a comment. (Or select at least a few characters of the line.) Then use "comment out" or "uncomment" tasks, to add or remove that --, to/from the start of the line.
      The tasks are available at dropdown menu/Document, or as toolbar buttons, or in a right-click popup menu.

      Anyway, the "comment out"/"uncomment" tasks are really useful for stacked commenting:

      Code:
      --b = 12
      ----a = b * 6 + 8
      --a = (b + 72) / 4
      In this example, first you turned the second line into a comment, then turned all the lines into a comment. I.e. the second line is "double commented", with the ---- sign.
      If you want to make the lines valid later again (except keeping the second line still ignored), then the easiest solution to select the three lines, and uncomment them. This will remove the -- sign from each of the line, i.e. the second line remains a comment, still having the -- sign.

  • You can control your custom bookmarks in the script file: at dropdown menu/Document, or as toolbar buttons, or in a right-click popup menu, or with shortcut keys.
    The darker highlighted line is a bookmark. The ligthter highlighted line shows the current line of the cursor:

    Click image for larger version

Name:	106.jpg
Views:	9
Size:	23.7 KB
ID:	8588

    • Toggle Bookmark (CTRL + B): places a bookmark in the current line/removes the bookmark of the current line.
    • Go to Previous Bookmark (CTRL + comma): the cursor jumps to the previous (upper) bookmark of the script file.
    • Go to Next Bookmark (CTRL + dot): the cursor jumps to the next (lower) bookmark of the script file.
    • Clear All Bookmarks (CTRL + SHIFT + B): deletes all the bookmarks of the script file.

    If there is no more bookmark upwards/downwards, then the game jumps to the last/first bookmark of the script file.
  • Undo stack size can be adjusted at dropdown menu/Options/Text Editor Settings.
  • The Scripting Studio also has a Find & Replace feature, which is not discussed in this tutorial.

Last edited by AkyV; 13-11-24 at 19:22.
AkyV is offline  
Old 07-11-24, 00:29   #5
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default

4. Settings for the appearance

These settings (for all your LUA script files) can be done in dropdown menu/Options/Text Editor Settings:
  • Font size and font type ("font family").
  • Font color customization is still not available here - but you can already identify these features on the settings panel.
  • Tick or untick to have the current line of the cursor highlighted.
  • Word wrap: if you tick it, then all the long lines will be nicely seeable, even if the big window of Scripting Studio has a not really big size.

    Click image for larger version

Name:	107.jpg
Views:	12
Size:	43.8 KB
ID:	8591
  • Show visible spaces: empty spaces will be marked by dots.
    Show visible tabs: tabulations will be marked by double arrows.

    Click image for larger version

Name:	108.jpg
Views:	12
Size:	43.2 KB
ID:	8592
----------

Notes:
  • Default font colors - which, as I said, cannot be customized, for the time being:

    • numbers: green
    • strings: orange
    • booleans (true, false): light blue
    • special values (like nil): white
    • statements (function, for, if, do, then, end etc.): dark blue
    • signs (like -, +, =, :, {, } etc.): white
    • any names not followed by brackets (variable and table names, or eg. the callback function name in LevelFuncs.OnLoop = function()): white
    • any names followed by brackets (like FlameAmbience() function name or NatlasTeam[2] table value): yellow
    • higher table levels (like LevelFuncs in LevelFuncs.OnLoop): purple
    • comments: grey

    Be careful: if you realize that a script part has different color like that, that means you have a crucial typo in the script, near that part, which you need to fix. Otherwise the script file will be useless in the game.
  • See these features at dropdown menu/Document:

    • As you can see in the image just above, there are meaningless spaces and tabulations in some script lines: after the last useful character of the line, or in empty lines.
      These are not harmful, only ugly. You don't need to remove them manually, instead simply use the Trim Ending Whitspace feature.
    • Reindent Code does the same that Trim Ending Whitspace could do.
      It should be an extended version of Trim Ending Whitspace, eg. to automatically print a space after a comma as well, if you previously did not type that space yourself. - But this extension is still not available in TEN scripting. (But it is in TRNG scripting.)

Last edited by AkyV; 12-11-24 at 20:18.
AkyV is offline  
Old 07-11-24, 00:43   #6
AkyV
Moderator
 
Joined: Dec 2011
Posts: 5,075
Default

5. Building issues and the error log

As I said above, sometimes the wrong text color is enough to identify the issue in the script, which makes that script file useless in the game.
But sometimes it is not so obvious. I mean, you will surely realize that when you hit New Game in the game title, to start testing your freshly edited level, then the game won't load that level. Instead, it will load you back into the title. This means there is an error somewhere in your script (even if the character colors are all the proper ones).

Open the Engine folder now in your project folder. Here yo can find Logs folder, with TENLog.txt in it.
Open the TXT, and scroll down the lines. Soon you will find a line here with the text of "A Lua error occurred while running a level". The problematic script file and its problematic line are identified in this log line. You can also identify here where is the issue in that line.

----------

Notes:
  • You can have more controls on your TEN log file like that, but we will discuss it in another tutorial.
  • Be careful: sometimes the issue is not enough to make the file useless. In these cases the game will be running nicely - but those problematic parts of the script will be ignored. Now it is naturally more complicated to find and fix the issue.
    And sometimes it is worse than that: the problematic line is able to ruin even the script lines, which follow it, even if those other script lines aren't problematic anyway.

Last edited by AkyV; 12-11-24 at 20:14.
AkyV is offline  
Closed Thread

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



All times are GMT. The time now is 12:16.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Tomb Raider Forums is not owned or operated by CDE Entertainment Ltd.
Lara Croft and Tomb Raider are trademarks of CDE Entertainment Ltd.