Trainz/Scenarios (Scripted Activities)

From Wikibooks, open books for an open world
Jump to navigation Jump to search
Fundamentals for Trainz Trainees
TOC | BeginningsFun | AM&C | Creation | InBook Refs ORP Refs:  • Index • Containers • Kinds • Tags | Appendixes  • Vers
 Mouse use
Trainz-scenarios will be an unsupported type in Trainz/Trainz: A New Era (TANE) (post-TS12 64 bit release of Beta 'Community Edition' by download December 2014, Standard Edition (also a Beta) arrived May 2015; 1st Service Pack improvements expected end of Summer 2015.

Scenario Introduction

[edit | edit source]
Highland Valley Coal scenario begins. The nine built-in TRS2004 scenarios were each bundled first as part of Trainz UTC, then republished. This is a challenging switching & puzzle scenario, with scoring deductions for overuse of junction switching, so placed a premium on getting things 'right' in your head before acting.
 • Written on the original Highland Valley Map by Chuck 'Cee Bee' Barkman, the route/map itself was modified into Highland Valley Industries and used to demonstrate the new fangled sessions technology and interactive industries.
The first Game-play in Trainz

A scenario in fiction  has a well understood connotation as the circumstances consisting of a backstory and a situation which a protagonist must somehow deal. This broad definition while applicable in the same broad sense in Trainz, actually has two mechanisms of presenting the game-play aspect of Trainz, that is the Gameplay in the software suite: a task which an operator is supposed to perform in a Driver session, a Goal, or Problem. In short a quest with a mission to master. A well written one presents aome kind of scoring of 'Points' to measure your performing self against both a standard, and your own high score. Also well written ones present a clear outline of the task, its end conditions, and assumes the Driver (Us) knows nothing of the Route/Layout ahead of time. Most fail that criteria. Further, well written ones allow one to reopen the instructions and refresh the memory and compare the names (sometimes odd to the ear) to the minimap labels.

They also present situational modifiers, it was an unforgettable experience to once drive a Freight to a Schedule only to realize a misidentification of where the consist was (resulting in backing down speed considerably for about four or five minutes) required the Driver to play catch-up—but whilst careful to stay below the posted speed limit, the Session writer didn't bother to tell us the rules in that country automatically decrement at certain ranges of speed, meaning a Freight had to stay 10, 15 or 25 mph under the speed posted limit when and if it fell into those range brackets. Like many such problem missions, this one deducted points for speeding. Would you ever forget the experience of bringing the Freight into the final couple of stops on time, completing it and finding your final score was -384 (down from 800+ when last noticed/checked!)

The older of these game-play quest sequences was in fact called a scenario by Auran in 2001-2002 (hereafter called a 'Trainz-scenario'), while the newer mode is called a session. From the standpoint of game-play to the Driver in Trainz there is virtually no difference save one: They show up differently in the Driver menu. From the standpoint of creation of one or the other, the difference is vast.

Trainz-Scenarios are interactive scripted activities for a user to operate in the Trainz Driver GUI module—the most game-like of the varied kinds of entertainment offered by the software system. They invariably have targeted completion goal or state, and many are written to provide scoring allowing a Driver an opportunity to compete with others or best her previous best score. They vary in nature considerably, some providing step-by-step instructions for each stage of an operation (e.g. Tutorials on how to run Trainz), others merely displaying the details of an objective and leaving it to user to devise a method of achieving it. 'Shunting puzzle scenarios', perhaps the most realistic Trainz Driver 'quest' or 'problems' model  'typical Railroad operations'  tend to adopt the latter style. Some 'schedule keeping challenges' follow the terse mode, presenting a single schedule at the start up of a driver situation. A wide variety of different events can be triggered within a Trainz-Scenario. It is possible to display HTML text and images, and to play sounds, add trains 'out of the blue' as traffic (not visible on the map just moments before), or change load states of rolling stock.

In the earliest Trainz, Trainz-Scenarios which are written using TrainzScript.exe, a separate utility no longer shipped as part of releases beginning with TRS2006, the script language based scenario was necessary for filling coal cars or other such loads 'off camera' and so were well suited to mirror the reality of many shortline or yard engine 'switching' operations where the locomotive engines pick up and drop off cars at various locations and return the loaded or unloaded rolling stock to a collection yard or sorting yard where it is appropriately shunted into or taken from a longer regional train. But TRS2004 also introduced interactive industries (in 2003) and the Session editor and driver rules improvements, while still fully supporting the Trainz-Scenario. Versions since might be best considered as 'read-only' implementations where a downloaded Trainz-Scenario can still be played, but not written.

Trainz Session Rules, are TrainzScript 'modules' that are far more user friendly to the non-programmer, being implemented as a graphical icon, with a limited number of input or output modes.

Trainz-Scenarios were introduced with the release of Service Pack 3 to the original Trainz release as well as in Trainz UTC, and are one of the main improvements that make many veteran Trainzers consider that Trainz 1.3 version a second separate major release. Scenarios were fully supported in TRS2004, as an alternative back-compatible mode of scripting activities … even as the release introduced the new more generalized Sessions'. They are only partially supported in TRS2006 and Trainz Classics through the newest Trainz Trainz 2012, meaning existing sessions will (usually) still run if imported or downloaded, but the TrainzScript software utility has neither been updated and has not been bundled as part of those newer releases because the 'Session' is more flexible, and can do everything the older Trainz-Scenario technology could do. In other words (compare above vs scenario): "Trainz-Sessions are interactive scripted activities for a user to operate in the Trainz Driver GUI module—the most game-like of the varied kinds of entertainment offered by the software system".

Some Methods Of Creating Scenarios

[edit | edit source]
  • TRS2004 owners can use the built-in method of creating the initial structure of a scenario, then using a text editor program to write the necessary coding. This method involves programming in GameScript, which is a "C"-like language with numerous extensions.
  • Both TRS2004 and TRS2006 owners can use the SCS (Scenario Creation System) program which is offered as freeware by the Trainz Pro Routes third-party Trainz fansite. There are separate versions of SCS for TRS2004 and TRS2006. SCS aims to make the scenario creation process as straightforward as possible but even then some considerable effort will be required. Full manuals are available for SCS.
This Trainz page is dated or in need of reorganization and improvement, and as such has been listed for Clean-up as soon as we can get around to it. It has been listed at Category:Trainz pages needing attention, and we apologize for any inconvenience you may incur because our vlunteer staff hasn't found time to make it better. To do:
See if can be updated, and link, or decide if should be placed as 'dated' in the Appendices.

An Overview Of TRS2004 Scenario Creation

[edit | edit source]

The GameScript API (Application Programming Interface) documentation can be found in the "Trainz Railroad Simulator 2004 User Activity Creation Guide" which can be downloaded from Auran's web site. Some familiarity with the concepts and individual functions listed in this document is vital.

The following is a highly simplified overview of what is inherently quite a complicated procedure. To keep things as simple as possible, it omits many details.

Open the relevant layout in Surveyor.

Add any desired trackmarks, triggers and other trackside objects. Trains can be created at trackmarks. Events will be triggered when trains enter triggers. Do not save the changes to the layout.

In the Surveyor menu, invoke the "Export Scene Data" option and choose a suitable name for the new scenario.

Close Surveyor. Once again, do not save the changes to the layout.

A new folder will have been created in C:\Program Files\Auran\TRS2004\World\Custom\scenarios folder with the name that you specified in Surveyor. This newly created folder will contain the files which form the basis for the scenario.

The TSO (trackside object) file contains the details of the modifications to the layout which are individual to this scenario, for example the additional trackmarks and triggers that you added in Surveyor.

Using a text editor, open the scenario's config.txt file. The kuid-table will already include the layout. You need to add the rolling stock assets that the scenario uses, for example: (How!!!)

	testscenario		<kuid:154110:5701376>
	AN_830_Class		<kuid:-1:100737>
	QR_QLX			<kuid:-1:101154>

If you wish, also embellish the description text.

Using a text editor, open the gs (GameScript) file. By default this file contains a daunting amount of coding, almost all of which should be left unmodified. You need to add additional sections of code in the correct places.

In the "create consist specs" section, add coding to specify the rolling stock which makes up each train when it is initially placed on the layout. The following example has one train consisting of an AN830 Class loco pulling one QLX louvre wagon:

KUID[] PlayerTrainKuids = new KUID[ 2 ];
PlayerTrainKuids[ 0 ] = World.FindKUID( "AN_830_Class" );
PlayerTrainKuids[ 1 ] = World.FindKUID("QR_QLX" );

In the "create consists" section, add coding to place the trains at trackmarks. The following example places a train made up of the "PlayerTrainKuids" consist specification at a trackmark named TM01:

Train PlayerTrain = World.CreateTrain( PlayerTrainKuids, "TM01", true );

In the "gameplay" section, above the "scenarioDone = true;" line, add coding to set some initial parameters and perform the scenario's actions. The following is a very simple example which merely allows the user to drive the PlayerTrain and nothing else.

World.SetGameTimeRate( World.TIME_RATE_1X );
World.SetGameTime( 0.875 );	// 9am
World.SetCamera( PlayerTrain, World.CAMERA_EXTERNAL );
World.SetCameraAngle( 75, -15, 50 );
PlayerTrain.SetAutopilotMode( Train.CONTROL_MANUAL );

while( 1 == 1 )
	Sleep( 0.1 );

In the above example the "while" loop will wait forever until the user exits the scenario. A real scenario would normally complete properly and shut down without user intervention being required.

No compilation is required. Once the gs file is correctly created, the scenario can be run. In practice, there is usually a need for numerous iterations around the editing and testing cycle.

Comparisons to programming languages

[edit | edit source]
Editor's note: The utility of GameScript is not limited to Trainz Scenarios generation, but also applies to writing rules for the scenarios replacement, game Sessions (kind profiles). A variant, TrainzScript is central to making various kinds of interactive and animated content such as loading and unloading traincars, and other animations including actions at kind mocrossings, kind industry, draw, swing, and lift bridges, steamboats, drivable vehicles and basically anything in world which moves is dependent upon script files.
  • In short, this page is far from dated and unimportant to anyone needing more information about TrainzScript or GameScripting.
Some Comments Regarding GameScript & TrainzScript for people familiar only with traditional BASIC or Visual BASIC, and no other high level computer languages

Tip: A few simple examples can be found at the end of this section.

The following applies to GameScript as used to create TRS2004 scenarios. Its use in Rules, commands, asset action scriptlets, scripted asset behaviors, and etcetera is different in some important respects to what follows here, but all share the same foundation requirements and basis syntax. Scripted assets such as a trackside signal, animated logger, linked junctions or signals all have to interface with run-time software, so live in the same house, so to speak.

For anyone unfamiliar with any form of most programming languages except BASIC, learning GameScript will probably prove quite difficult. This section attempts to list some of the "gotchas" that may confuse beginners.

GameScript does not have a dedicated program editor or IDE (integrated development environment). Instead, a text editor program such as Notepad or a superior alternative (Notepad++, Programmer's Notepad, ConTEXT, Crimson are introduced herein) is used to edit program source files, and unlike within an IDE 'project', the user has to do all the file management manually. In GameScript, entities such as trains, signals, junctions, etc are regarded as being objects with properties that can be specified and accessed by the program. (An alternative word for properties in computer science is attributes—circumscribed 'characteristics'.)

GameScript is based on the "C" language.
"C" has numerous differences to BASIC, for example:
  • In GameScript, all the coding is held in one file. Because there is no integrated development environment, all the parts of the code are visible when editing.
  • Variables must be declared in advance, as they are and must in most programming languages, and most often before use, initialized (value defined) as well.
    • They can be declared when first given a value if desired; the syntax is to specify the variable type (int, float, etc), then its name, then a equals sign, then an expression which gives the variable its initial value.
  • Array subscripts are enclosed in square brackets, not round brackets.
  • The syntax for declaring arrays will seem very strange to BASIC programmers. See the example below.
  • Comment lines start with two forward slashes, not REM. This is often called 'hack-hack' commenting and in most C-language derivatives, they may appear anywhere in a line and affect everything until the newline (End of Line, Line Break, CR+LF, or other equivalent terms) character sequence ends the text line.
  • Groups of dependent statements (or code blocks) are enclosed in matching pairs of curly brackets, which can or should be regarded as bounding (boundary) keywordsthe opening 'curly-brace '{'' serves to mark the beginning of the block (as the PASCAL 'begin' keyword).
  • These include the groups of sequential processing statements (procedures) in FOR loops, in WHILE loops, and in IF statements.
  • Therefore there are no 'onto mapped' equivalents of BASIC's NEXT, WEND or ENDIF statements in "C", but the closing 'curly-brace '}'' serves to mark the END of any block of grouped statements.
  • It follows logically that the closing 'curly-brace '}'' also serves to mark the END of the block (as the PASCAL 'end' keyword) of ordinally grouped and executed statements known in C-based language offshoots as a 'function' (or 'process' or 'procedure' or BASIC's 'sub-program').
  • Most valid statements must have a semi-colon on the end, but not all. Leaving one off when required is a common cause of errors and unexpected results.
  • The exceptions are branching identifiers (tags) and where usually the dependent statements that follow are enclosed in curly brackets such as block operators like while, do, for loops and if-then-else conditional blocks.

Tip: In C virtually all important blocks of code, including even a procedure, or sub-program (all called 'functions' in C) will be bounded by paired curly-braces. These days, such might also be called 'wrappers'-the meaning drawing on the parallel to HTML tag pairs.

Examples of statements which must not have semi-colons include
  • case
  • default
  • else {...}
  • FOR loop headers, WHILE loop headers and IF statement headers where the dependent statements that follow are enclosed in curly brackets.
  • include
  • switch {...} (it's scope blocks include default and case blocks)
  • function declaration (not those of definitions) header lines (it's scope contains everything before the bounding end block (the closing curly-brace '}')
  • labels (unconditional branching targets for goto statements-which must be within the function wrapper.)
  • Most operations are performed using functions, or statements which have the same syntax as functions. Therefore in many cases parameters must be enclosed in round brackets where none are required in BASIC. This gives rise to syntax like:
result=14*myfunction( new-input-value ); where 'myfunction{...}' is a code elsewhere, perhaps one getting a specific state and returning it's value to the expression and saving the value in the variable 'result'.
  • Assignment statements take one equals sign,
    • relational expressions (equality tests) in IF statements take two equals signs (if(result==0){...}).
    • In such evaluation expressions: Not equals is !=
  • "C" features a large number of obscure methods of incrementing and decrementing variables using two adjacent arithmetical operators. Since these are difficult to remember and therefore open to confusion, they are probably best avoided by beginners. The difference in performance caused by not using these methods is trivial in the extreme compared to the millions of calculations required to generate each screen frame in Trainz.


  • Instead of variables being converted from one type to another with functions such as STR$ and NUM, or automatically as in Visual BASIC, in "C" the <cast> statement is used.
  • Unlike Visual BASIC, GameScript is not inherently event driven.
    • There is no concept of "click on this object to run this little bit of code". However, event handlers (sections of code which are obeyed when an event occurs) can be created. These are particularly useful for handling AI train events, in situations where they can occur asynchronously with the scenario processing and the user's actions.
    • However, GameScript also has the Schedule mechanism for controlling AI trains independently of scenario execution.
  • A function prefixed with the word void means it is being declared as one which does not return a value. Hence the assignment: result=14*myfunction(); or even just the number * function() part will (and should) produce a compile error.
  • In Auran's API documentation, a function declaration with the 'parenthesized parameter ( void )' does not take any pass parameters (void myfunction(void); thus declares a child-process which takes and needs no pass values that is run whenever the 'calling code' myfunction(); occurs in-line), but as shown, it does require the empty pair of round brackets.
    • When declared, it also requires the use of both void keywords.
  • "C" does not have an exponentiation operator. But writing a C function to cube is:
float fcube(float finput;){ return finput*finput*finput; }
  • Note the return statement both requires a terminating semi-colon, but also, in a 'non-void declared' function, an expression returning some value to pass back to the calling code block.
Boolean (Logic) expressions
  • GameScript uses and and or in complex relational Boolean arithmetic expressions, in the same way as in BASIC. Normal "C" is very different. Bitwise Boolean operations are possible but probably best ignored by beginners.
  • GameScript uses true and false for literal Boolean values.
  • GameScript uses + for string concatenation, in the same way as BASIC.
  • Whereas Visual BASIC consistently uses the 'Object.Property' syntax, GameScript only does so to a limited extent.
  • GameScript uses the SetOfFunctions.SpecificFunction syntax extensively (possibly universally).
  • In GameScript, in most cases, a property of an object must be specified using a function whose name starts with Set..., and a property of an object must be obtained using a function whose name starts with Get...
  • Whereas in Visual BASIC it is vital to regularly perform a DoEvents statement so as to refresh the screen and prevent Windows locking up, in GameScript there is only a general fairly obvious need to avoid tight loops and insert Sleep functions in such situations.
  • GameScript functions which pause scenario execution while waiting for an event will not lock up Trainz or Windows.
  • Some of the functions in GameScript can take a varying number of parameters, usually with the omitted parameters being given sensible default values.
  • Some of the functions in GameScript operate differently depending on the variable type of the parameters they are supplied with (passed).
  • For example, the function for specifying the camera angles regards its parameters as
being in 'degrees' if they are integers
but in 'radians' if they are floating point.

As with Visual BASIC, for the beginner there is considerable confusion regarding which aspects are handled by the operating system or the programming language, and which must be handled by the programmer. In Trainz there are the additional complicating possibilities of the user's train and AI trains performing train movements asynchronously with the scenario.

  • Windows and Trainz handle all the hardware aspects of input and output.
  • Trainz will automatically call the main() section of the program when the scenario starts. (This is a C standard function/task/certainty)
  • Once the user's train has been created and control given the user, the user can drive it forwards or backwards as they desire. The scenario needs to react as events occur, such as the user's train entering a trigger or a junction.
  • Trainz will automatically call some other 'boilerplate' (standard library) sections of the program when a user train overspeed event occurs, when a collision event occurs, etc.
  • The default coding to handle these events is created when a new scenario is created but with sufficient knowledge it can be modified.
  • There are functions available in GameScript to pause scenario execution at a point in the coding until an event occurs, such as the user's train entering a junction or a trigger.

As with Visual BASIC, in addition to the relatively straightforward core language there is also a need to learn the vast number of objects, their properties and their functions. These are documented in the Auran GameScript API.

An important practical comment: in the Auran GameScript API document, a pair of matching adjacent square brackets may be displayed so closely together as to appear to be an outline box.

Editor's note: 'Web-Search' quoted phrases: "The C Language" and "The C Programming Language" for online sources of syntax and operators. Obtaining the seminal work "The C Programming Language" by Kernighan and Ritchie (The language inventors) is HIGHLY RECOMMENDED for anyone assaying C or C-derived languages such as C/C++/C#, Java, Java script (actually most modern and recent script languages). No one work will give you a firmer faster start than that work.

In Trainz, objects internally pass messages between themselves. These internal messages are not seen by the user. GameScript coding can generate internal messages and also detect and receive internal messages. Each internal message has four properties: its source, its destination, its major (i.e. its major message type) and its minor (i.e. its minor message type). While this message passing concept can be ignored by the beginner, it is often featured in the Auran documentation and therefore worthy of mention here.

One final vital piece of advice: start with something really, really simple. Making a train appear on a track is in itself a very considerable achievement for someone starting to learn GameScript.

Example #1: IF Statement

//Equivalent to IF A=10 THEN...
if (a==10)
	//dependent statements go here

Example #2: FOR Loop

// Equivalent to FOR N=1 TO 5 STEP 1
for (n=1; n<=5; n=n+1)
	//statements within the loop go here

Example #3: WHILE Loop

while (a<50)
	//statements within the loop go here

Example #4: Variable declaration and initialisation

int x=8;

Example #5: Declare an array

//Equivalent to DIM A(12) - possible subscript values will run from 0 to 12
float[] A = new float[ 13 ];

Example #6: Define a user-defined function

int Cube(x)
	//local variable declarations go here
	//function statements go here
	return (x*x*x);