Guide to the TrainPlayer Programming Language


Part Two - The Scripting Commands and Functions

Introduction

Comments and Spaces

Train Commands

Wait Conditions

Layout Commands

Menu Commands

Variables

Flow Commands

Call, Return and Exit

Subroutines

Procedures

User Interface Commands

Display Strings

System Functions

Developer Commands & Functions

ADDITIONAL RESOURCES

Part 1 - The Scripting Tools

Part 3 - The Subroutines Library

Part 4 - A Worked Example

Part 5 - Scripting for Advanced Ops

Introduction to the TrainPlayer Programming Language

It is intended that this document will assist an inexperienced scripter to familiarize themselves with the syntax used in the various TPL statements. The full set of TPL statements can be used in any of the four script types (Master Script, Train Script, Subroutine or Junction Action) and in the Script Command Prompt dialog. These Scripting Tools were covered in detail in Part 1 of this series of documents should you need to refer to it.

The TrainPlayer Programming Language is continually developing and the most up-to-date information on the command set can always be found within the program on the "Reference" tab of the Script Central dialogue.

This document seeks to provide additional support regarding the syntax required for each command or statement. The information is structured by the perceived use of the Commands as summarized below. For an alphabetical glossary we would refer you to the aforementioned Reference tab in Script Central which can be sorted on any column.

TPL code is not not case sensitive, and for the Speed command you can use SPEED, speed, Speed, or even sPeEd. just use whatever you are most comfortable with.

Throughout this document we have used square brackets within the reference tables to indicate where the parameters are optional.

Train Commands

To start, stop and drive the trains, set the direction, control the speed, and initiate other train scripts.

Wait Conditions

To ensure subsequent commands are not processed until certain events have already occurred.

Layout Commands

To set routes, control turntables, play sounds and load and unload cars at set points on the layout.

Menu Commands

Most of the Menu Commands available in the TrainPlayer interface can also be used within a script. Executing a menu command from a script causes the same action as choosing it from the menu.

Variables

Variables are used to store the data and information required to control the trains. These can be broadly categorized as User Variables, System Variables and Registry Variables.

The System variables are automatically being updated as the trains move. User variables are global and accessible to all open layouts by default. User variables can also be defined as Local to confine the data to a specific subroutine or procedure if necessary.

Flow Commands

To control the flow or order of events through the scripts based on different conditions encountered while running trains.

Interface Commands

To pass messages, process responses, record key presses, and set new values for processing.

System Functions

Functions to process the data held in system variables and manipulate the information found.

All of the script types can use the full extended set of TPL statements and any script type can call up a subroutine (including one subroutine calling another subroutine). There is no limit to the number of commands or statements that can be used in any script, although for some basic Junction Actions only one or two lines of very basic code may be needed.

The best way for a novice to learn about writing scripts is to study the code used in existing well commented scripts and to experiment with short batches of their own code on a small test layout. Example script segments have been included in this text where it is felt these will help to clarify the purpose of a particular statement.

Scripting a layout can be a lot of fun, if you look at another user's scripts they may appear daunting but it is important to remember that this is just a list of short sequences to perform specific tasks, and if you take a step by step approach scripting is not as difficult as it might first appear.

Back to Contents


Comments and Spaces

Spaces before and after TPL statements, and blank lines within a script, are ignored during processing but can be used to advantage to break up and indent the code into manageable segments, thereby improving the appearance and readability of the script.

We strongly recommend that you make liberal use of comments throughout all your scripts to help yourself and anyone else who might need to understand them.

The image on the right depicts a tidy approach to commenting and is an extract from the Master Script at Rheilfford Bach. This clearly shows what each few lines of code are intended to do.

Comments can be prefixed by * an asterisk, ** two asterisks, // two slashes, or a # followed by at least one space. It is a matter of personal preference which you choose to use.

The Schedule Window includes a context menu option to "Show Script Comments". When this option is checked the *, # and // style of comment will echo to the Status Bar and the Schedule Window. This can be useful to follow where you are in your script during program development.

Comments starting with ** plus one space, instead of just a single *, will not echo to the schedule window and may be preferable in scripts intended for distribution or publication to the TrainPlayer web chooser.

The default "Echo to Status Bar" option can be disabled from the Schedule Window context menu if not required - but it usually is.

Back to Contents


Train Commands

Forward

Sets direction to forward, has no effect if engine is already set to forward, command is affected by Autopause (see below).

Reverse

Sets direction to reverse, has no effect if engine is already set to reverse, command is affected by Autopause (see below).

Speed <mph>

Sets speed to given mph (kph if metric); starts train moving if it is stopped.

Stop

Decelerates the scripted train to a stop, command is affected by Autopause (see below).

Horn [2000]

Sounds train horn for the stipulated time in milliseconds. If no parameter supplied sounds horn for three seconds. Uses the horn sound already attached to the train.

Autopause <secs>

Turns on pauses of <secs> duration between certain commands during train movements, use Autopause 0 to cancel. Autopause only affects Forward, Reverse, Stop and Uncouple.

Uncouple <slot>

<slot> is an integer number, 1=behind 1st car, 2=behind 2nd etc., uncouple is affected by Autopause (see above). Slot is calculated from head end of train. If the train is in reverse the head end is not the engine and slot can be unpredictable, it is better to use uncouple carID if the ID is known.

Uncouple <carID>

Uncouple specified car from the portion of train which has the engine attached, uncouple is affected by Autopause (see above)

Uncouple <carID><carID>

Uncouples between the two specified cars, uncouple is affected by Autopause (see above).

Train <train>

Selects the named train as the train of focus in the train window.

For <train> you can use the train name, the train ID or the label of any car in the train.

Note: this only changes the train window focus, it does not make the named train run the curent script unless it is already running it.

Start <train> [<mph>]

If the specified train has no script it will start moving at the given speed in whatever direction it is facing (5 mph if speed is omitted). If the specified train has a script then the script is started, or rewound and started, so caution is needed if that train has already been moved.

For <train> you can use the train name, the train ID or the label of any car in the train.

Note: The statements which follow the "Start" command continue to control the current scripted train, not the one you have just started.

Drive <train>

Transfers control temporarily to the specified train, subsequent commands apply to that train until an Enddrive command is reached.

For <train> you can use the train name, the train ID or the label of any car in the train.

Statements in the drive block are packaged as a little script, which is attached to the target train and started. When the "EndDrive" statement is reached control returns immediately to the calling train leaving both scripts running simultaneously.

Enddrive

Transfers control back to the original train after attaching code to another train from within a "Drive; .....; Enddrive" block.

Note: The Drive; ....; Enddrive block also allows Train Control commands to be used in a Master Script which is not attached to any train.


** USING THE TRAIN COMMAND TO CHANGE FOCUS OF THE SELECTED TRAIN
** Changes focus of the train window and train controller to the "Stock Hauler"
Train "Stock Hauler"

** USING START TO START ANOTHER TRAIN RUNNING THAT IS NOT CONNECTED TO THIS SCRIPT
Start "Jim Dill" 10
   ** Starts the named train at 10 mph, if it has a script this is rewound and restarted.

** USING THE "DRIVE; ...; ENDDRIVE" BLOCK WHICH DIRECTS COMMANDS TO A DIFFERENT TRAIN
** The command "Drive" is followed by a train identifier (name as found on the train menu, or the label of any car in the train)
** Assume our script is operating a freight train and we want to start another train moving
speed 15
   ** this is a command sent to the train which is attached to this script
drive Train28
   ** the indented statements shown in italics are attached to Train28 and started
   speed 20
   after 0:0:04 reverse
   stop
enddrive
   ** original script then continues without waiting for the drive block script to complete
AT J123 Speed 10
   ** This command applies to the original train (the one controlled by this script)
   ** If necessary you should be able to nest one "drive" block inside another should you need to do so.

Back to Contents


Wait Conditions

Most Train Commands are preceded by a Wait Condition, the wait condition and command can both be entered on the same line, or the wait condition can be on one line with the subsequent command beneath it. A command without any wait condition executes immediately and a wait condition doesn't necessarily have to be followed by a command.

It is important to be aware that a Wait Condition refers to making the "Script" wait for the required condition to be met, it is not an instruction for the "train" to stop or wait. In the event that we also want the train to stop and wait (e.g. when waiting for ON THROW before moving) then we must ensure we script the train to STOP before the script reaches the wait condition.

** EXAMPLE TPL CODE DEMONSTRATING WAIT CONDITIONS COMBINED WITH COMMANDS ON THE LAST TWO LINES
** Here the train will start moving forward at 10 mph.
   Forward
   Speed 10
** When it it reaches junction 123 it will stop.
   AT J123 STOP
** It will wait for five seconds at J123 then move off at 10 mph.
   AFTER 0:0:05 SPEED 10

AT <jxn>

Script waits until midpoint of lead car crosses junction, <jxn> should be a numerical ID which can optionally include a j prefix.

AT (<t j d>)

Script waits until midpoint of lead car crosses a point on track t which is d% of the track length from junction j. The three numerical parameters can optionally include the prefixes t, j and d.

AFTER <jxn>

Script waits until midpoint of last car crosses junction, <jxn> should be a numerical ID which can optionally include a j prefix.

AFTER (<t j d>)

Script waits until midpoint of last car crosses a point on track t which is d% of the track length from junction j. The three numerical parameters can optionally include the prefixes t, j and d.

AT <h:m[:s]>

Script waits until specified time is reached on the layout clock; h:m required, seconds are optional, the layout clock must be operating to use this.

AFTER <h:m:s>

Script waits until specified time has elapsed on the real time clock (not the layout clock), the seconds must be included.

ON STOP

Script waits until the train comes to a complete stop, this has no effect if the train is already stationary.

ON COUPLE

Script waits until the train couples with another car, the subsequent script commands then operate the longer train.

ON THROW <jxn>

Script waits until the specified switch is thrown by any means (i.e. by the operator or by another script). If the <jxn> is to be thrown only by a script command then any jxn reference can be used, even if the specified jxn is not a switch.

ON TABLESTOP

Used following a Rotate command. The script waits until the turntable finishes rotating. (Turntables are covered in the Layout Commands section below.)

ON NOTECLOSE

This is a wait condition designed to work with the NOTEBOX (not the Note) command.

It holds up the processing of a script until the active NoteBox is closed by any means, usually by clicking in the NoteBox itself. The next script command will only be processed after the Notebox has been closed.

ON KEY [<key>]

Script waits until the user presses the specified key. e.g. On Key F1, On Key A, if <key> is omitted then any key press is accepted

On Key should be preceded by a prompt in an Echo or Note command to explain the action required.


Notes:

Particular care is needed when using AT and AFTER close together within a script, if the train has already fulfilled the condition for the second of these statements before the condition for the first is met, the script will fail because it cannot seek to detect the second condition until after it has processed the first.

For example if a script requires the last car of a train to trigger an AFTER command before the first car triggers an AT command further down the track - and the train is longer than the distance between the two junctions - then the second command will fail because the front of the train will have already passed the second junction when the script starts waiting for it to do so.

Although Wait Conditions may be followed on the same line by a Command Statement, a TPL statement normally ends with a line break. A semicolon can be used (;) to separate two statements on the same line.

Where a comment is added to the end of a line it is good practice to precede the comment with ; semicolon delimiter to avoid any confusion that can occasionally occur if the * character is mistaken for a mathematical expression.

** Example showing Wait Conditions used with Commands
** Stop the reversing train when it couples with another car
   on couple stop
** Set train ready to move forward
   forward
** Uncouple at the fifth slot (to retain five cars including engine)
   uncouple 5
** Start the train moving forward at 6 mph
   speed 6
** Pause the script until the center of the last car has reached j33
   after j33
** Allow the train two more seconds to clear the junction and stop
   after 0:0:02 stop
** Set the train ready to move in reverse
   reverse
** Throw the switch immediately behind the train to open the siding
   throw j33 1
** Start the train moving in reverse into the siding
   speed 6
** When the lead car reaches junction 695 stop
   at j695 stop
** Set the train ready to move forward
   forward
** Uncouple immediately behind the engine to leave the cut in the siding
   uncouple 1
** Move forward (ready to reverse back after junction for rest of train)
   speed 6

Back to Contents


Layout Commands

Throw <jxn> [<pos>]

Throws switch to stated position or to the next available position if not stated, <pos> is 0 or 1 (or 2 for 3 way switch). <jxn> can be a number only or include a j prefix, e.g. Throw 123 0 or Throw J123 0).

Load [Toggle] Train [<name>]

Loads all cars in the specified train with their default loads, if the optional name is absent then the current train is assumed, if optional keyword toggle is present, the loads are toggled.

Load [Toggle] Car <ids> [<loadname>]

Loads the specified car(s) <ids> which can be a comma-delimited list of car ids with the optional specified loadname or with their default loads if loadname not present, if keyword toggle is present, toggle the loads. Cars can be anywhere on the layout.

Load [Toggle] Cut <ids> [<loadname>]

Loads the cut of identical car types around the specified car with the optional specified loadname, or with their default loads if the loadname is not present, if keyword toggle is present, toggle the loads. Specified cut can be anywhere on the layout.

Unload [Toggle] Car/Train/Cut <ids>

Unloads specified car(s), same syntax used as in load.

Sound <spath>

Plays the wav file from spath once only. spath is either a full pathname, or a path relative to the TP Sounds folder.

Sound loop <spath>

Plays the wav file from spath repeatedly until told to stop. If you put a comment on the same line you will need a ; semicolon after thhe filename.

Sound stop <spath>

Stops the repeated playing of the wav file specified. If you put a comment on the same line you need a ; semicolon after the filename.

Rotate <ttbl> <jxn> [cw/ccw]

Rotates the turntable to the specified junction on its rim, <ttble> is ID # of turntable, <jxn> is the ID of the junction, cw specifies clockwise which is the default and can be omitted, ccw specifies rotation will be counter clockwise.

Tablestop

Stops turntable rotation.

On Tablestop

Wait Condition USED to hold up the script until the turntable finishes rotating (can only be used after a rotate command).

** Examples of the use of the load and unload commands

** Toggles the load status of the three listed cars
   load toggle car X44,H22,H24

** Loads the car H33 with its default load
   load car H33

** Loads the specified list of cars with the load "aggregates"
   load car H33,H35,H36 aggregates

** Loads a cut of identical cars around car X14 with default load
   load cut X14

** Unloads all cars in the train running the script
   unload train

** Example of the Sound Loop Command.
** Plays the specified sound file continuously for 3 seconds and then stops
   SOUND LOOP Loco\Heavy freight.wav;    ** Starts the sound. Requires semicolon to delimit filename from any comment.
   after 0:0:03
   SOUND STOP Loco\Heavy freight.wav;    ** Stops the sound. Requires semicolon to delimit filename from any comment.

** Example turntable script, for an engine entering bridge track 376 which is on turntable 377
** Wait condition until engine is on turntable, stop when it is 50% along bridge track 376 from the end marked as junction 374
   at (376 374 50) stop
** wait condition to prevent turntable rotation until engine has stopped
   on stop
** rotate turntable 377 to junction 279 in a counter clockwise direction
   rotate 377 279 ccw
** wait condition to prevent engine starting until rotation has stopped
   on tablestop
** command to drive train off turntable and continue with script
   Forward speed 15

Note: Turntable Scripts prepared with the Script Recorder will need editing to insert the ccw attribute if needed, this is because mouse clicks on the turntable rim always cause the turntable to take the shortest route, whereas on playback a script will always default to clockwise rotation unless counter clockwise (ccw) is specified in the script.

Back to Contents


Menu Commands

Menu Commands In addition to the comprehensive range of TPL statements any command accessible from the TrainPlayer menus can also be used within a script. Executing a menu command from a script causes the same action as choosing it from the menu.

Menu commands apply only to the train depicted in the train window. Therefore to use a menu command for the scripted train, that train must be the train of focus in the Train Window (Use the command Train "train name" to achieve this). You need to be aware that there could be consequences for anyone driving a train with the train controller while the script is running, as changing the selection in the script would take control away from their train. It is therefore advisable not to use the Menu Commands unless there is no alternative, or unless you are sure that all other activity on the layout is suspended. These commands can be very useful at the beginning of a Master Script as part of the set up procedure before any of the trains have started running.

If an item in the menu at any level consists of more than one word, then that item must be enclosed in quotes. Popup menu items are also available for the Car, Layout, Switch, Turntable, Track, Circle and Horn context menus. As a shortcut, you do not need to spell out all the words in full. You may abbreviate a menu item to its first few characters. e.g. "view toolbars customize" may be shortened to "vi to cu."

Note: Many menu commands will make little sense in the context of a script. Some bring up dialogs, which are not scriptable. Some duplicate the functions available using Train Commands. Some are toggle switches, but since a script does not always have a way to know the current setting, the results can be unpredictable. Context menus often need to reference a point on the layout -- where you right-clicked to bring up the menu -- but since a script cannot supply this, context menus may do nothing or work unpredictably.

** Examples of using Menu Commands, note that commands with embedded spaces must be quoted.

** bring up File Save As dialog to save the current layout
   file "save as"

** select train Freight1
   train freight1

** change the name of the selected train to the name given
   train name "SF Express"

** bring up Tools Customization dialog
   tool cust

** Insert a hopper at the current insert point of the selected train
   car "add car" hopper

** turn on Yard Mode operation
   tools "enable yard mode"

** create new four-car train at the default location
   train new

** if multiple document windows are visible, tile them
   window "tile horiz"

** double the speed of the selected train
   train speed double

** select a car in the current train
   train car HK22

   car exclude
   ** exclude is a toggle and the same command can be used to cancel the flag

Back to Contents


Variables

Variables are a powerful element of TPL which can broadly be categorized into User Variables, System Variables, Registry Variables and Local User Variables. By extracting and testing the values stored in these variables the scripts can take branching decisions on how to proceed.

To store a value in any type of variable, or to extract the contents of one variable to another we use the SET and LET commands.

SET <var> <value>

<var> is user assigned alphabetic or alpha numeric name.

<value> syntax varies according to variable type.

LET <var> = <value>

<var> is user assigned alphabetic or alpha numeric name.

<value> syntax varies according to variable type.

These two commands both perform the same task but the syntax for each is different. The <value> syntax also differs for each of the variable types as covered in the following subsections.

User Variables       System Variables       Registry Variables       Local Variables

Back to Contents


User Variables

User Variables are manipulated using the SET and LET commands, if you allocate a value to a variable not previously defined it will be automatically created as the value is allocated. Set and Let perform the same task and are interchangeable.

It is considered good programming practice to initialize your variables in the Master Script as a layout is opened - but TrainPlayer is very forgiving if you omit to do this.

The name given to a User Variable must start with an alphabetic character. There must be a space before and after the variable name.

User Variables are global in scope and can be accessed by any layout that is open during a TrainPlayer session. Any numeric or string value can be assigned, matches on names and values are case-insensitive. The values of User Variables are not lost when a layout is closed, but they are lost when TrainPlayer is closed.

** Example: Define a variable called "v1" and give it the value 44
** If the variable already exists its value will be overwritten with 44
   LET v1 = 44

** Values do not have to be numeric
   SET Block23 "Occupied"

** Examples of using Let for Arithmetic and string concatenation
** Quotes are required for concatenation
** Quotes are optional for a single literal string.
   LET vnum = 22+33-4
   LET vstr = "abc" + "def"
   LET vst2 = vstr + "ghi"
   LET v2 = 9 + 6

** Allocate the value of a System Variable to a User Variable.
   AFTER J123
   SET siding $x_train

Accessing the contents of a User Variable

@variablename allows the value of a User Variable to be used in place of a literal value anywhere in a script, this applies to both numerical values and text strings. The @ symbol can be taken to mean "contents of" the referenced variable when it is used to represent the <value> parameter at the end of a SET or LET statement. @variablename must only be used on the right-hand side of SET and LET statements, not on the left.

** Examples showing the use of the @variablename reference

** Allocate the value of one user variable to another user variable.
   LET thistrain = @thattrain   ; ** Note the use of @ for "contents of".
** Without the @ symbol thistrain would receive the literal string "thattrain".

** Read the value of v1, add 1 to it and place the result back in v1
   Let v1 = (@v1 + 1)

** Place the value 22 in v1, if the variable doesn't exist it is created.
   Set v1 22

** Extract the value from v1 and place it in a new variable v2
   Set v2 @v1

** Take the of v2, add the value of v1 to it and store the result in v2.
   Let v2 = (@v2 +@v1)

** Take the name of scripted train from $x_train, store it in train_name.
   Let train_name = $x_train

** Send the text and the name of the train to the Schedule Window.
   Echo Train is @train_name

** Multiply the contents of v2 by 6.3 and store the result in v1.
   Let v1 = @v2 * 6.3

** Place a string in v2 comprising the text followed by the number from v1.
   Let v2 = "a string" + @v1

** Place the name of the car triggering a Junction Action in the variable "car".
   Let car = $x_car

** Place the name of the train containing the car in the variable "train".
   Let train = $x_car(@car,name)

** Embed the name of the car and train in a displayed string.
   Echo The car @car is located in train @train@.
** Note the need to close the @ reference to enable the period to be displayed.

** Practical example as used in a Junction Action
** Place the name of the train crossing the junction into the variable BSA
   set BSA $x_train
** Remove the name of the train from the previous block it occupied
   set BM "clear"
** Report position of train to schedule window using name stored in variable
   echo @BSA in tunnel
** Reduce the speed to the speed already defined as the yard speed
   speed @yardspeed
** Throw the switch behind the train back to its default setting
   throw 102 0
** Stop train when hidden in tunnel
   AT 750 Stop
** Check the variable to see if this is the Freight Train (Train4)
   IF (@BSA="Train4")
** If it is load the cut of cars while the train is out of sight
    load cut g30
** End the conditional IF statement
   endif

Redirection

@@variable references the "contents of" a variable which contains the name of another variable in order to extract the <value> from the second referenced variable. So the expression "@@<var>" gets you the <value> of the variable whose name is stored in <var>.

** Example: Using @@ to access the value of a variable whose name is stored in the first variable.
   LET v2 = abc
   LET v1 = "v2"          ** v2 is the name of a variable not its contents.
   LET v2 = "some text"   ** We want to be able to access this without using v2 as a name.
   Echo @@v1              ** Will display the value from v2 (not v1) in the Schedule Window.

** LET allows @ on the left hand side for the special purpose of placing values in a referenced variable
   LET @v1 = abc   ** put the value "abc" into the variable whose name is stored in v1
   Echo @v1        ** will print a variable name (let us assume this is v2)
   Echo @@v1       ** will print the contents of v2, which in this case is abc

Back to Variables


System Variables

System Variables all have a $ prefix. These variables are being continually updated by the program and, with two exceptions, cannot be SET by the user, however the values of a System Variable can be extracted to a user variable for testing or later use in the current script or in another script. The system variables can also be tested using conditional statements such as IF (see flow commands below). System variables can be embedded directly into strings where required (without needing the @ symbol).

$DATADIR

Used to locate the TrainPlayer AppData folder on any PC no arguments are required, this can be used to set paths to the sub directories.

Returns the TP application data directory path.
e.g. C:\Users\Richard Fletcher\AppData\Roaming\TrainPlayer

** Examples
   let SoundsPath = $DATADIR + "\Sounds"
      ** places the full path to the Sounds Directory in the variable "SoundsPath"
   echo $DataDir
      ** outputs full path to the TP apps data to the Schedule Window.

$LAYOUT

Returns the name of the Selected Layout. e.g. "Ffarquhar", "Burnt Cabin", "railroad1" etc.

$TRAIN

Returns the name of the selected train. e.g. "GR17 Tramp", "train2" etc.

$CAR

Returns the label of the selected car. e.g. "ES11", "XM101" etc.

$X_TRAIN

Returns the name of the train owning the script.
In a Junction Action script this is the Train that crossed the junction and picked up the script.

$X_SPEED

Returns the speed of the train that is running the script.

$X_CAR

Returns the label of the car when a JA script is triggered by the car.
This is only relevant to a Junction Action Script triggered by a crossing car.

$CRASHES

Returns a count of the crashes or bounces since the layout was last opened or reset.

$TIME

Returns current time of day in (h:m:s in 24-hour format), i.e real time, not layout time.

$DATE

Returns today's date (mm/dd/yyyy).

$SPEED

Returns the speed of the train running the script in MPH (KPH if metric settings in effect).

$Speed can also be written to using LET or SET.

$KEY

Returns the numeric code of last key pressed on the keyboard for processing.

$Key can also be written to using LET or SET. This is useful to seed it with a common code to detect a subsequent change.

** Example to report location of train running the script
   AFTER J123
   NOTE $x_train passing through Blindman's Bluff

** In a Junction Action triggered by a car with a specific aar code, load the car
   load Sx_car   ** $x_car can't be used in a train script, only a Junction Action

** Extract the current value from a System Variable and send it to a Note Window
   Note The time is $TIME

** Processing Car Properties using $car
   let carlabel = "X333"
   let isLoaded = $CAR(@carlabel, loaded)
   if (isLoaded = "1")
    echo car @carlabel is loaded with $CAR(@carlabel, "loadname")
   endif

** Populating a user variable with the name of the train running the script.
   LET savedtrain = $x_train
** and then starting the train up in another script
   Start @savedtrain   ** for an explanation of @ see User Variables

** Copy the value of a System Variable to a User Variable for subsequent processing by IF
   AFTER J123
   SET siding $x_train

** Embedding System Variables in strings
   set v2 "Time and date:" + $TIME + " " + $DATE
   echo This train is $x_train

Back to Variables


Registry Variables

Registry Variables are effectively temporary copies of the entries in the TrainPlayer registry folder "hkcu\Software\TrainPlayer\TrainPlayer\Settings". TPL permits the values of these keys to be modified from within a script.

SET and LET are the commands used for allocating temporary values to Registry Variables. RESET is the command to restore the original registry value.

To extract the current value of any registry setting, use the $SETTING function (see System Functions). In order to maintain the integrity of the Windows Registry any changes made during a session are lost and the Registry defaults to its original values when TrainPlayer is closed.

Caveat: Some registry keys use multiple word names. If SET applies a value to a key with a multiple word name the name must be enclosed in quotation marks. This is not the case with LET which reads the name up to the = sign regardless of embedded spaces.

$SETTING <var>

Returns the value of the named registry setting stored under the key: HKEY_CURRENT_USER\Software\TrainPlayer\Trainplayer\Settings

The name used in the argument must match a value name in that key folder. Quotes round the argument are accepted but not required. Most values are true/false (1/0), strings, or numeric values. Values and operators must be separated by spaces.

Example: Let $setting(maxMPH) = 60

SET <var> <value>

<var> is the named registry key the variable is copied from.

New <value> = a number, a string, an arithmetic combination using + - * or /, or a string concatenation using +.

LET <var> = <value>

<var> = The named registry key the variable is copied from. The = sign is mandatory.

New <value> = a number, a string, an arithmetic combination using + - * or /, or a string concatenation using +.

RESET <var>

Returns a modified temporary registry variable back to the original value stored in the Windows registry. If modified registry variables are not Reset they will retain their temporary values until the end of the current TrainPlayer session.

** Examples of setting registry variables to temporary values for the duration of a session.

** Put the current Note Window co-ordinates into a user variable.
let notepos = $setting(NoteWndRect)

** Set the Acceleration Factor to 20 for the duration of the session.
   SET AccelFactor 20

** Set a Global Max Speed of 100 MPH for the duration of the session.
   Let Max MPH = 100
   SET "Max MPH" 100

** Permit passenger cars to be loaded and unloaded. Default setting is 0
   SET PassengerCarsLoadable 1

** Changing the fast clock reset time.
** Change the fast clock reset time from its default of 05:00 to 09:00
   SET ClockResetTime 900
   ** Note this command must be followed by a CLOCK RESET and a CLOCK START command in the script

** Adjusting the Scroll Distance Factor
** Default value is 70, changing to 25 will keep Loco central on screen.
   SET ScrollDistFactorx10 25
   ** The Value represents a fraction of the size of the layout window, default 1/7 from the edge.
   ** Set this to 30 and it would start 1/3 from the edge.
   ** Don't set below 20 as results are undefined and unpredictable.

** Reset modified Acceleration Factor to its original value from the Registry
   RESET AccelFactor

** Reset Max Speed to the users own usual setting from the Registry
   RESET Max MPH

** Resets passenger cars to its original value from the Registry
   RESET PassengerCarsLoadable

** Reset the size, properties and position of the Note Window within the application window.
   set NoteWndRect "0,0,400,300"
   ** Co-ordinates represent "top,left,bottom,right" corners of window.
   set NoteWndAutoFit 1
   ** Allows vertical expansion of Note to autofit text, 0 is fixed size.
   set NoteWndTextPos L
   ** Sets text alignment within Note, L left, R right, C center.

Third Party Tools

The TrainPlayer Registry Variables are not officially documented but many of our experienced users are familiar with them. Anyone who wants to learn more about modifying TrainPlayer Registry Variables without resorting to Windows RegEdit might find the standalone TPx_RegMgr program from Alan Conover to be a very useful addition to their TrainPlayer toolkit.

You can download TPx_RegMgr from here. To use it just unzip into any convenient folder. This is completely stand alone and doesn't install itself to your Registry in the traditional sense, if you don't like it then just delete it.

Back to Variables


Local Variables

User Variables are normally global in nature which means that any open layout can access and modify them. Local Variables which follow the exact the same syntax in the way they are accessed through SET and LET can be confined for use within specific subroutines and procedures. Even if a Local Variable has the same name as a global User Variable it will be kept separate and treated as a completely different variable.

Declaring variable names as "Local" prevents multiple scripts which simultaneously call the same subroutine, or procedure, from interfering with each other.

LOCAL <list>

<list> = a single variable name or a comma separated list of variable names.

For use only within a subroutine or a defined procedure.

If the routine containing the "Local" statement is called by two different scripts the values of the defined variables will be kept separate in each script. Global user variables with the same name will not be affected.

** Example to define variables i and j as local variables within a subroutine or procedure.
   LOCAL i, j
   let i=10   ;  ** Does not affect any global i declared elsewhere.
   ** Several examples of Local Variables in subroutines can be found in the Subroutines library.

Back to Variables


Flow Commands

Flow Commands - Are used to control the flow or order of events based on different conditions encountered while running the trains. This is achieved by testing variables and properties with "Conditional Statements" to ascertain what events have occurred and redirecting the flow through the scripts accordingly.

All flow commands and conditional statements can be nested within other flow commands and conditional statements in order to make the branching decisions necessary to dictate the sequence to be followed through the script based on the current layout situation.

GoTo & Label

<label>>:

<label>>: is a single word ending with a colon for use with "goto".
It is mandatory that a label must be placed on a line by itself.

Goto <label>

Causes the script to jump directly to the statement after the label, skipping all commands in between, it can also jump back to an earlier label


If ; Elseif; Else; Endif;

If (<expr> <comp-op> <expr>)

Compares two expressions and branches the program based on the result of the comparison, <expr> is a number, string, variable, or complex expression; <comp-op> is an operator comparing the values of two expressions. (parentheses are required around the comparison). The comparison operator must be one of: =, <, >, <=, >=, <>.

Elseif (<expr> <comp-op> <expr>)

Evaluates an alternate comparison after the IF. Else if is an optional component, there can be more than one Elseif if necessary. Uses same syntax as If.

Else

Begins an alternate block of code to actioned if the previous conditions are not met. Else is an optional component but if used there can only be one Else.

Endif

Ends the IF block (essential component).

@ references must only appear on the right-hand side of an IF statement comparison. When a script encounters @variablename it is replaced by the value of the named variable, this also allows for the value to be embedded in string statements providing a space delimiter follows the @variable statement. If a trailing space needs to be avoided, for example to display a period after the variable contents, @variablename@ can be used without spaces.

** Example monitoring keyboard and using labels to to direct the flow of the script.

start:
   ** First a label (a word ending in a colon: on a line of its own)
on key
   ** On Key is a Wait Condition which suspends the script until a key is pressed
echo $key
   ** Echo reports the value of $key to the Schedule Window to show which key was pressed
if ($key = 65)
   ** Check to see if key A was pressed.
   ** If it was set speed 20 and jump to label carryon:
speed 20
GoTo carryon
elseif ($key = 66)
   ** If first condition was not met.
   ** Check to see if key B was pressed.
   ** If it was set Reverse and jump to label carryon:
reverse
GoTo carryon
   elseif ($key = 67)
   ** If neither A or B pressed.
   ** Check to see if key C was pressed.
   ** If it was Stop the train and jump to label carryon:
stop
GoTo carryon
endif
   ** End the If conditional check.
   ** If the script is here, none of the conditions were met.
   ** So jump back to the start: label and wait for another key press to test.
goto start

carryon:
   ** carryon: is a label, if we are here the appropriate change is made and the script can continue.

** The IF statement structure may also be combined on one line with statements separated by semicolons.
** If variable BSA matches the contents of BS, Set BSA to "clear".
   If (BSA=@BS); set BSA "clear"; endif

While ; Break ; Continue ; Endwhile ;

While (<expr> <comp-op> <expr>)

Compares two expressions and executes or skips the block up to endwhile based on the result of the test. The loop is repeated the test becomes false, or until the loop is terminated by some other means (e.g. A Break or GoTo statement from an embedded If statement).

<expr> is a number, string, variable, or complex expression; <comp-op> is an operator comparing the values of two expressions. (parentheses are required around the comparison). The comparison operator must be one of: =, <, >, <=, >=, <>.

Break

Optional component normally used by an embedded If statement within the While loop. If the conditions of the If statement are met the While loop immediately terminates and the script continues from the line which immediately follows the Endwhile statement.

Continue

Optional component normally used by an embedded If statement within the While loop. Continue immediately suspends the current iteration of the loop, but instead of terminating the loop, it continues with the next iteration of the loop from the beginning and skips the processing of any remaining lines left in the loop.

Endwhile

Ends a WHILE block (essential component)

While loops are extremely powerful structures that enable you to emulate almost any customized Wait Condition you require.

@ references must only appear on the right-hand side of a While loop comparison. When a script encounters @variablename it is replaced by the value of the named variable, this also allows for the value to be embedded in string statements providing a space delimiter follows the @variable statement. If a trailing space needs to be avoided, for example to display a period after the variable contents, @variablename@ can be used without spaces.

** Example: Script on a Northbound train standing in a passing siding.
** While DPM does not hold the name of the Southbound, Wait.
   While (DPM<>@T3); AFTER 0:0:01; endwhile
   ** This train is waiting until a Southbound train whose name is stored in T3 has cleared the North Switch.
   ** The Southbound train will SET its name in DPM after clearing the switch and enable this loop to end.
   ** When the While loop has terminated our Northbound train is clear to proceed.
   Forward speed 10

Back to Variables


Call, Return and Exit

"Call" is the statement used to branch the script processing into a separate subroutine, to run a procedure defined within a script, or to extract data from a system function.

The name of a subroutine is its filename minus the text extension. Subroutine files must reside in the Subroutines directory or a subdirectory.

The name of a procedure is the name declared in the PROC statement which begins the procedure definition. A Proc defined in the master script is always loaded; a Proc defined in another script or subroutine is not loaded until its parent has been started.

Call <subroutine> [<param>]

<subroutine> is the filename of the subroutine minus its extension.
The optional <param> is single parameter or space delimited list of parameters that can be numeric or string. Quotes are mandatory in this list for strings containing spaces.

Call <proc> [<param>]

<proc> is the name given to the procedure in the PROC statement of the subroutine.
The optional <param> is single parameter or space delimited list of parameters that can be numeric or string. Quotes are mandatory in this list for any strings that contain spaces.

Return

Optionally used in a subroutine or procedure to immediately terminate the subroutine or procedure and continue running the calling script.
Example: if (i = 0) ; return ; endif

Exit

Optionally used in a subroutine or procedure to terminate the current routine and the calling scripts. This is equivalent to inserting a label at the end and using Goto Label. Example: if (i = 0) ; exit ; endif

Note: Exit is extremely useful during script development to prevent the processing of subsequent code when testing.

Caveats: If you insert Exit in a subroutine or procedure it terminates the calling script, not just the subroutine. If you use Exit in a Junction Action and the train is also running a train script, it terminates the Train Script not just the JA.

Call <function>(arg1,arg2)

<function> is the named System Function which is prefixed with a $ symbol.
This takes the form of $name(arg1,arg2) but some take three arguments and some take only one. Most system functions are read only but a handful can be written to using SET or Let.

Calls to System Functions use a different syntax to subroutine and procedure calls, the argument list must be in parenthesis, with the arguments separated by commas.

Example: call $view(show, schedule) which displays the Schedule Window on the screen as if you had selected it from the Tools menu.

Back to Contents


Subroutines

Introduction

A subroutine is a separate text file containing Script Code that is stored in a separate file within the Subroutines folder. A subroutine can be accessed from any Script using the CALL command. Subroutines are usually prepared using an external text editor such as Windows Notepad, Notepad++ or the excellent TPx_XSE (External Script Editor) designed by one of our dedicated users, Alan Conover.

The Subroutines root folder is located within your TrainPlayer Apps data, underneath the TrainPlayer folder and at the same level as your Layouts folder and Carsets folder. Once created your subroutines can be updated or amended using the built in editor on the Subroutines tab of Script Central.

The main advantage of subroutines is that they can be used to code repetitive tasks so that only a single line is needed to access the code in the subroutine - rather than needing to insert the same code into every script that needs it.

To call a subroutine, you use the CALL command and supply the subroutine's filename (without the .txt extension).

Example: CALL mysubroutine

When a script encounters a subroutine CALL it opens the file, copies it into the current script at the position of the CALL command and closes the file. The subroutine itself does not become attached to any train nor stay open while it is being executed. Once the loaded subroutine has finished executing the control returns to the remainder of the calling script.

You can call up a subroutine from any of the script types, master, train or junction, or by typing the required "Call" command directly into the "Script Command Prompt" dialog.

Parameters

You can also pass additional values, often referred to as parameters or arguments, to a subroutine. If there are two or more parameters they should be separated by spaces. If a single parameter consists of more than one word it should be enclosed in quotes. These parameters are represented within the subroutine script by placeholders which are replaced by the actual values of the parameters passed to the the subroutine when it is called.

Insert placeholders in your subroutine where it will take variables from the calling script. A placeholder is of the form %n, where n is the position in the argument list from left to right. For example, if your subroutine takes two arguments, use %1 in the code to stand for the first argument, %2 for the second. For example you could use:

CALL mysubroutine 123 1

To pass the id number of a switch and the position you want it to be set to. The appropriate line within the subroutine that used this information would then be simply THROW %1 %2 which would substitute 123 for %1 and 1 for %2.

A subroutine can even be used as a complete Train Script in which case the script stored in the Train Script or Junction Action script would only need to be a single line instruction to CALL the subroutine.

** Example of Subroutine code stored in a separate text file
** Requires three parameters %1 %2 %3
** %1 is the name of a variable
** %2 is the value waited for, control will not return to the calling script until the value is correct.
** %3 is the speed required when restarting the train
** Save the current speed
   SET Trainspeed %3
** Hold this script here until the value is set by another script.
   WHILE (%1 <> %2); STOP; ENDWHILE
** Start the train again and return control to the calling script.
   Speed @Trainspeed

** Example of a subroutine to set or change the properties of the Note Window
** Requires three arguments, %1 dimensions, %2 Autofit flag 0 or 1, %3 text justification L C or R
** Example call >> call setupnote "0,0,400,300" 0 C
    set NoteWndRect %1
    set NoteWndAutoFit %2
    set NoteWndTextPos %3

Custom extensions to TPL keywords

Although the CALL command can be used to run all subroutines, any scripts stored in the Subroutines root folder are a special case where the CALL command can be omitted. This has the effect of making the name of any subroutine in the root folder into an additional command in the TPL language.

An example of this is the supplied "F" subroutine which requires a single parameter representing the required speed that the train is required to move forward. The "R" subroutine does the same thing but with the train travelling in reverse.

So instead of typing: Forward ; Speed 20 repeatedly into your script. All you need is F 20 to drive your train forwards at 20 mph. R 20 will do the same thing in reverse. F 0 will stop the train with the direction control set to forward, and R 0 will do the same thing with the controller set in reverse.

This is only possible because the two subroutines "F" and "R" are stored in the subroutines root folder. If they were in one of the child folders then the keyword CALL would need to precede the rest of the command.

** Subroutine F is a shortcut for Forward Speed x
** Just enter "F 20" in your script to move forward at 20 mph
Forward
Speed %1

Back to Contents


Third Party Script Editor

Although TrainPlayer includes all the essential tools for editing your scripts it would be remiss of us not to mention an excellent third party editor designed by Alan Conover specifically for the editing of TrainPlayer scripts. TPx_XSE (External Script Editor) is launched from within TrainPlayer by typing XSE into the Script Command Prompt box. This editor includes some rudimentary syntax checking on your scripts and constantly keeps the Layout you are working on up-to-date.

You can download the TPx_XSE (External Script Editor) from the TrainPlayer forum on Groups IO. Just unzip the file into any convenient folder and start using it. This editor does not write any data into your Windows Registry and if, for any reason, you don't like it you can just delete it.


Procedures

Procedures can be defined in any script but cannot be CALLed until the script that defines them has already been run. It therefore makes good sense to define procedures in your Master Script as this usually runs automatically when the layout is loaded.

A Procedure fulfills exactly the same function as a Subroutine in that it can be used for any repetitive sequence of Script Commands. The only difference between a Subroutine and a Procedure is that the Subroutine is stored in an external file so that it can be CALLed from any layout, whereas a Procedure is embedded in the layout which it is specific to.

When a script encounters a CALL statement, that is not followed by $ to denote a system function, it first checks to see if a procedure has been defined in the layout, if so it copies the code from the procedure into the script and runs it. If no defined procedure is found a check is made of the Subroutines folder and its subfolders (and of the folder containing the layout) to see if there is a subroutine of that name. If found the file is temporarily opened, the code is copied into the script at the position of the CALL statement and run as if it were part of the original script.

Because the program checks for an embedded procedure first, it is possible to maintain a standard set of subroutines in the Subroutines folder, but to customize them for specific purposes by copying them into a procedure definition in the layout file and making the required adjustments. Before you can CALL a procedure it must have already been read into the program and for this reason it makes sense to define procedures in the Master Script as this runs automatically when the layout first opens.

One particularly valuable use for Procedures is to design new customized Wait Conditions to hold up the processing of your script until the required conditions are met. HoldUntil is an example which checks to see if a train is moving or stationary, whether it is set to a forward or reverse direction, and to check if the required number of cars are in the train.

HoldUntil is used in the "Midthorpe Branch (Interactive Demo)" layout which can be found on the web tab of your "Scripts and Puzzles\Scripted Layouts" folder.

NOTE STOP - Signal at Danger\n\nWait here for clearance to proceed.
CALL HoldUntil @hty S R 12

The first line of this example call displays an alert to tell the operator of the train whose name is stored in the variable "hty" to stop. The second line calls the subroutine to prevent the script from proceding until the reversing train, which has 12 cars, has stopped moving. A further procedure then checks the track ahead of the reversing train and holds up both the script and the train until the route is clear, when it can issue a further instruction for the operator to move again.

The "HoldUntil" procedure is called a total of 148 times by the scripts at Midthorpe to ensure that the trains meet the required conditions to enable the scripts to continue.

If, as is the case with HoldUntil, a procedure has been given the same name as a subroutine. the CALL command will give precedence to the Procedure over the Subroutine on the assumption that the procedure has been deliberately customized for use on the layout which contains it.

Back to Contents


User Interface Commands

Echo <display_string>

Echo displays the given "display string" in the schedule window and on the status bar.
All display strings may contain substitutable variables prefixed by $, @ or @@.

These substituable variables can be used within the text of any User Interface statement to display the value stored in the named variable - whether this be a reference to a CarID, a TrainID, a string of text or a numerical value.

Input <var> [<prompt>]

Input sets the value of a user variable from an input dialog box by displaying a prompt and waiting for a response. The result is copied into the specified variable for testing. If the variable does not already exist it will be created. Input is like a Wait Condition, the script pauses and waits for a response, the next command does not execute until the user clicks on OK or Cancel. You may supply your own optional prompt string; if this is omitted a default string is used.

Note <display_string>

Note displays a given "display string" in a popup window; or hides the window if no "display string" argument is given. Notes may contain substitutable variables prefixed by $, @ or @@ and line feeds can be inserted with \n (i.e. backslash n).

Note has the big advantage over Input and $msgbox in that it does not stop the action on the layout while awaiting a user response. Only one Note can be displayed at a time, if a note is open when another is called the first one will be overwritten (this can be useful for supplying apparently seamless rolling information).

The style and position of a Note window can be modified, repositioned and resized (Right-click and choose Properties to open the note in the scenery object dialog, where changes can be made to the background color, font, etc. After saving the layout, the next time the script is run, the window will appear in the position it was in when the layout was saved.)

There can only be one Note window open at any time but its size and position can be modified explicitly from within a script before the Note is opened. This is achieved by resetting the temporary Registry Variables containing the information about the positioning of the Note.

Set NoteWndRect "159,109,249,690"
   ** Pixel co-ords used are "top,left,bottom,right".
set NoteWndAutoFit 1
   ** Allows depth of window to extend downwards to accomodate more text.
set NoteWndTextPos L
   ** Sets text alignment Left. Other options C=Center, R=Right.

Notebox <display_string>

Notebox is a similar, but not identical user interface command to Note. You can only have one Note (and/or one Notebox) in a script so having both features can be helpful. The difference between the two commands is that they use different windows.

All Notebox commands are similar to the Note commands but Notebox has some extra features which include a few more window styles and automatic dismiss on timer.

One key difference is that you can dismiss a Notebox just by clicking inside it whereas the default setting for a Note requires a scripted command to dismiss it. This makes Notebox vulnerable to accidental dismissal and where possible Note seems to be the preferable option for script writers.

However NoteBox can be used to great advantage with the "ON NOTECLOSE" command to instruct a script to pause until the user clicks in the NoteBox to allow it to proceed.

Example to use a Notebox to start the trains.
Notebox Click Here to Start the Trains
   ** Opens notebox message.
On NoteClose
   ** Waits for user to close the NoteBox.
call starttrain es1 F 10
   ** Starts the train with engine es1 to move forward at 10 mph.

Note <Color=r.g.b>

Notebox <Color=r.g.b>

NOTE and NOTEBOX can both take an argument "COLOR=" to set the background color of the specified note box. The color remains as set for the duration of the current session (not permanently).

Note Color=255.0.0
   ** sets the Note background to red for this session

Notebox Color=0.255.0
   ** sets the Notebox background to green for this session

$Msgbox([<type>,]<text>)

$msgbox is a system function which displays the supplied <text> as a prompt, <type> if present must be OC for a box with OK/Cancel buttons, or YN for a box with Yes/No buttons.

The function returns 1 if OK or Yes is clicked, returns 0 if No or Cancel is clicked (the response can be used for subsequent conditional processing).

In this format the $msgbox is modal, all action on the layout is frozen and a response must be given before you can undertake any work on the layout outside of the message box dialog. Once one of the buttons has been pressed any paused action resumes.

Note: This command is particularly useful at the start of a Master Script up as it stops all script action while the function is awaiting the user's response.

$Msgbox(<text>)

$msgbox can also be used without the <type> parameter to pause a script without freezing the action on the layout (if any). In this format there are no choices to be made and only an OK button is displayed to enable the script to resume.

This version of $msgbox is pseudo modeless and enables a developer to make changes to the layout design and the ops data grids before clicking OK to enable the script to proceed.

This feature is designed to assist with Ops development work and should be used with care.

** Example of using Echo for passing information to the Schedule Window
   At J123
   Echo The train has reached Junction 123

** Example of using Note to obtain a simple user response
   After 123 STOP
   Note "The train has now stopped
Press a key when ready to start"
      ** See following section for info on multi-line display strings.
   On Key
      ** Script waits for the user to press a key on the keyboard.
      ** If the key code is not specified any key will suffice.
   FORWARD Speed 10

** Example of using Input to obtain a value for a variable from the user
   Input myvariable "Enter the ID of the car you want to set down"
   Uncouple @myvariable

** Examples of using $msgbox
   call $msgbox(This is a note!, all trains are stopped, click OK to continue)
   let v1 = $msgbox(YN, Want to continue?)
      ** makes the value of v1=1 if Yes is clicked, or 0 if No

** Example of a single line string, either of these is valid:
   echo this is a string to be output
   echo "this is a string to be output"

** In a display string, variables are substituted whether or not the string is quoted.
   echo The speed of the crossing train is $train($x_train, speed)
   echo "Today is $date and it is already $time"

** Quotes are optional around most function arguments and keywords (both of these are valid)
   echo The speed is $train(train66, speed)
   echo The speed is $train("train66", "speed")

** Examples where quotes are essential:
   file open "c:\my file.txt"
      ** filename with embedded spaces
   file "revert to saved"
      ** menu command with embedded spaces.
   set "Default Car Length" 400
      ** multiword reg setting name

** String in a function call which includes a ")" must be quoted to avoid terminating the function.
   call $write(c:\myfile.txt, "a string with ) paren")

** Multiple line string must be quoted
   echo "this is a single string
with multiple lines

and a blank line above this one"

Back to Contents


Display Strings

Display Strings can be used with Echo, Note, Input, and $msgbox to present information to the user, and also with the $write file function.

Single Line
Display Strings

May be enclosed in quotation marks but need not be.
Can include \n (backslash n) to force a new line with Note, $msgbox and $write, but not with Echo.
Can include embedded information in the form of substitutable variables represented by $, @ or @@
Quotation marks can be included in display strings by doubling them, e.g. "" reproduces as ".

Multiple Line
Display Strings

Must always be enclosed in quotation marks.
Can include embedded information in the form of substitutable variables represented by $, @ or @@
Quotation marks can be included in display strings by doubling them, e.g. "" reproduces as ".


Where Quotation Marks are Mandatory.

  1. Around a multi-word command, registry setting name, or filename -- that is any reference name that contains a space.
  2. In a menu command where the item to be selected contains a space, this applies only to a single level of a cascading menu.
  3. Around a string containing a parsable character, where the meaning of that depends on the context.
    -- In a function call, an unquoted string must not contain the character ")", because that would terminate the call to the function.
    -- In a comma-delimited list, a string must be quoted if it contains a comma, otherwise the list would terminate at the first comma.
  4. Around a multi-line text block. This is the only way to define such a block, by enclosing it in double quotes and including carriage returns.

Back to Contents


System Functions

System Functions (like System Variables) all have the $ prefix. The functions take additional parameters to identify exactly what property of the variable is required and can provide a wider range of results dependent on the argument offered. They can be embedded directly into strings without needing the @ symbol.

Train Functions

Car Functions

Layout Functions

Scenery Functions

Clock Functions

User Interface Functions

Set Functions

String Functions

File Functions

Ops Functions

The properties of each System Function can can be extracted to a user variable for testing, or for subsequent use in the current script or in another script. This properties data is being continually updated by the program and in most cases these properties cannot be modified by the user but there are a few exceptions.

While most functions remain "read only" because they are being continually updated by the system there are also many functions that can be set to new values from within a script. The functions that can be reset in this way are all designated as r/w in the ref tab of Script Central, and marked as "Settable Property" in the tables below.

To use a r/w function to set a value, just call it with SET or LET and follow with a value.

** Example to ensure $key is empty so it can be monitored in a loop for another value.
** This prevents suspension of train monitoring which would occur if we used ON KEY
   Let $key = 0

Back to Contents


Train Functions

Each function requires two arguments, the "trainID" can be the name given to the train, the id number of the train, or the label of any car in the train. Either argument can be supplied as an explicit reference or as the contents of a variable in the @variable format. Functions marked "Settable Property" can be written to with Set or Let. Let $train(ES1,name) = "Atticus Special"

$TRAIN

If no argument is given, $Train returns the name of the selected train.
Otherwise the first argument must be the id number or name of a train on the layout, or "Train" plus a numeric ID, or any car label that is in the train.

$TRAIN(trainID, <any>)

Settable Property

Custom property, set blank to remove.

User defined train properties can serve a variety of purposes, such as carrying a train timetable, or recording the use of water as an engine progresses on its journey. The information stored in these user defined fields can't be seen in Train props dialog but they can be identified and extracted for processing using additional Script commands. These custom properties stay with the train until removed, they are saved with the layout and will travel with a train across linked layouts.

Hint: User defined Car Properties can be seen in the PropStr box of the Car Data properties dialog and it might be more convenient to use the Engine Car Props data to store this type of extra custom information.

** Example to add a custom timtable to a train.
** This can be processed by scripts as the train progresses.
   Let $train(@train,timetable) = "0800,0900,thru,1100"
   ** Use Let $train(@train,timetable) = "" to delete this property.

$TRAIN(trainID, car i)

Returns the label of car i, where i is a number between 0 and Ncars-1 representing the position of a car within the train.

$TRAIN(trainID, CarIDs)

Returns a comma delimited set of car id numbers in the named train.
trainID can be the train name or the label of any car in the train.

$TRAIN(trainID, CarLabels)

Returns a comma delimited set of all car labelsin the named train.
trainID can be the train name or the label of any car in the train.

$TRAIN(trainID, Direction)

Settable Property

Returns the current direction setting for the named train. F = forward, R = reverse.
Can be modified with Set or Let, acceptable values F, R, or T = toggle.
trainID can be the train name or the label of any car in the train.

$TRAIN(trainID, Flip)

Turns the train from end to end on the track, as if you had driven on to a cassette storage track and turned it around.

$TRAIN(trainID, ID)

Returns the id number of the named train.

$TRAIN(trainID, Layout)

Returns the name of the layout on which the train is located.

$TRAIN(trainID, LayoutID)

Returns the Layout ID of the layout on which the train is located.

$TRAIN(trainID, Length)

Returns the length of the train in terms of the number of cars in the train.This is the same value as returned by NCars.

$TRAIN(trainID, Name)

Settable Property

Returns the name of the train as shown in the train properties dialog. This may be a custom name provided by the designer or a default such as "Train3" if no name has been allocated.

Can be written to with Set or Let.
Example: Let $train(ES1,name) = "Atticus Special"

$TRAIN(trainID, NCars)

Returns the number of cars in the train. This is the same value as returned by $TRAIN(trainID, Length).

$TRAIN(trainID, Speed)

Settable Property

Returns the current speed in mph of the named train (kph if metric).
This is the same value returned by $SPEED.

** Example to discover the number of cars (or length) of a train.
** Identify the train running the script, then get car count
   let trainname = $x_train
   let trainLen = $TRAIN(@trainname, Ncars)
      ** let trainLen = $TRAIN(@trainname, length) is also acceptable.

** Example to obtain Car ID of the fifth car in the train.
   echo car 5 label is $TRAIN(@trainname, car 5)

** Delay loop to hold up a script until the operator starts moving the train whose ID is in variable hty.
   While ($train(@hty,Speed)<1); endwhile

** Example to check a reversing engine has coupled to consist and is moving Forward.
   NOTE Couple up to your train\nProceed to next station
      ** The embedded "\n" forces the note to display across two lines.
   While ($train(@hty,Ncars)<1); endwhile    While ($train(@hty,Direction)<>"F"); endwhile
      ** Holds up script until train is set to go forward.
   While ($train(@hty,Speed)<1); endwhile
      ** Holds up script until train is moving.
   After J123
      ** Holds up script until train has passed J123

Back to System Functions


Car Functions

The $car functions are used for extracting status information about any car on the active layout. This function requires two arguments, the car label and the property required. The car label can be the numeric id number of the car or the full label made up of the AAR code and id number. Either argument can be supplied as an explicit reference or as the contents of a variable in the @variable format.

$CAR

If no argument is given, $Car returns the carID of the selected car.
Otherwise the first argument must be the id number or label of a car on the layout.

$CAR(carID, <any>)

Settable Property

Returns the name of a custom property. Set this to a null value to remove it. The CarID must be the label or ID number of a car on the layout,

User defined car properties can serve a variety of purposes, such as carrying a train timetable on the engine, or recording the use of water as the engine progresses on its journey. They are also used in our Advanced Ops system for carrying additional data such as the route the car will follow and the locations where it will be loaded.

The information stored in these user defined fields is shown in the Props box of the Car Data properties dialog as a | (pipe) delimited list. These user defined properties can be manipulated using any of the Car Functions and they stay with the car until removed, they are always saved with the layout and will travel with a car across linked layouts.

** Example to create a custom property field on a car.
   Let $car(X14,ReturnMTto) = "Moth Lake Yard"
   ** Use Let $car(X14,ReturnMTto) = "" to delete this property.

$CAR(carID, AAR)

Returns the AAR code for the specified car.
CarID must be the label or ID number of a car on the layout,

$CAR(label, Car_ID)

Finds the unique numerical carID from the car label.

$CAR(carID, Class)

Returns the general car class from the carID. e.g. AAR = XM = General Service Box.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Consist)

Returns a one-word description of the train consist containing the car. e.g. Freight.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Dest)

Settable Property

Returns the user-applied (or Ops applied) destination tag on the car.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, DistTo, carID)

Returns the distance between two cars in rru. Requires three arguments.
This is distance as the crow files, not track distance.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, ExcludeOps)

Settable Property

Returns X if the car is excluded, otherwise null.
Cars which are excluded do not search the advanced ops card waybill database. Routes must be set by the designer.
CarID must be the label or ID number of a car on the layout,

$CAR(label, ID)

Returns the unique numeric car id for the supplied car label.

$CAR(carID, IsSpotted)

Returns 1 if the car is spotted on its destination track, otherwise 0. For Advanced Ops use.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Label)

Settable Property

Returns the car label from the supplied unique car ID number.

$CAR(carID, Layout)

Returns the layout name on which the car is located.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, LayoutID)

Returns the layoutID on which the car is located.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Load)

Returns the current load or 'unloadable' or 'empty'
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Loaded)

Settable Property

Returns 1 if the car is loaded, otherwise 0.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Loadname)

Settable Property

Returns the name of the load assigned to the car (if any). This does not mean the car is loaded (see load property).
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Location)

Returns the track label (or if none the track number) that the car is standing on.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Note)

Settable Property

Returns the text stored in the note field of the car properties.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Position)

Settable Property

Returns the exact position of the center of the car using the (t j d) format. This represents: trackno, jxnno, and % dist from jxnno. Example report: (T38 J65 67r) the "r" suffix denotes the train direction control is in reverse.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, PropsStr)

Settable Property

Returns user defined property string used by scripts. This is a | pipe delimited list of the custom named properties applied to this car by the scripter. Also used by the Advanced Ops system.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, ShowLabel)

Settable Property

Returns 1 if the car label is set to show, or 0 if hidden. Can be changed with Set or Let.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, SortOrder)

Settable Property

Returns a user-applied integer value for the car sort order.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Track)

Returns the Track ID number on which the car is standing.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Train)

Returns the name of owning train as shown in the Train Props dialog.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Train_ID)

Returns the unique numeric id of the owning train as shown in the Train Props dialog. This train id is subject to constant changes as consists change.
CarID must be the label or ID number of a car on the layout,

$CAR(carID, Type)

Returns the car type as defined within the car collection. e.g. tank acf 11 mobil.
CarID must be the label or ID number of a car on the layout,

** Example to check and see if a car is loaded or unloaded
   let carlabel = "X333"
   let isLoaded = $CAR(@carlabel, "loaded")
   if (isLoaded = "1")
    echo car @carlabel is loaded with $CAR(@carlabel, "loadname")
   else
    echo car @carlabel is not loaded
   endif

Back to System Functions


Layout Functions

$CAPAC(loc[,mode])

Calculates track capacity. Specify a track label and optionally a mode (All/Free/Occ) and the function will return the number of car-sized spaces available at all tracks of that label. ALL returns the total capacity (but can be omitted), FREE returns the number of empty spaces, OCC the number of spaces currently occupied by cars.

A "car-sized space" is one large enough to hold the "standard car length." This value is calculated by the program as the average length of all cars on the layout. If there are no cars on the layout, then the value in the setting "StdCarLen" is used.

Examples: echo Total spaces at XY = $capac("XY")
          echo Occupied spaces = $capac("XY", occ)
          echo Available spaces = $capac("XY", free)

$EXPIMAGE(path [,size,options])

Exports the layout image to a given file path. Existing files are overwritten, non existent files are created. File type should be specified by the extension (jpg, png, bmp etc.)

Size is a value from 0 to 10 corresponding to the slider position in the File Export Wizard Size screen.
0 => minimum output file size, 10 => maximum. Actual size depends on layout. Defaults to 7 if argument not supplied.

Options are the sum of values from the table below indicating what features are to be included in the image. If options are omitted or specified as zero the image will match the current view settings of the layout.

Tracks         2
Background     4
Grid           1
Switch lights  256    Turning on this bit means do NOT display switch lights.
Ties           1024
Rails          8
Roadbed        2048
Track labels   16384
Trains         16
Car IDs        512
Track numbers  32
Locations      128
FG scenery     64     ** FG/BG bits work together giving four choices.
BG scenery     4096   ** FG/BG bits work together giving four choices.

** 0+0 = both layers off, 64+0 = both layers on, 64+4096 = FG only, 0+4096 = BG only.

$INT(x)

Returns the integer portion of number x.

$JXN(id, Label)

Settable Property

Returns a user-applied label from the jxn id number. The label can be any string but can only be set by script. If a junction has a label it shows up on the object's tooltip. If applied the label may be used as an identifier (the first argument) in other JXN property calls.

$JXN(id, X)

Settable Property

Returns the X coordinate in rru of where the Junction is located on the layout.

$JXN(id, Y)

Settable Property

Returns the Y coordinate in rru of where the Junction is located on the layout.

$LAYOUT

$Layout with no argument returns the name of the active layout. Same as $layout(id).

$LAYOUT(Active)

Settable Property

Returns 1 if the layout is in the active document window, otherwise 0.

$LAYOUT(Description)

Settable Property

Returns the text notes used in the layout properties dialog, the Description property can be written to using Set or Let.

$LAYOUT(IDset,type)

Returns a comma delimited Set of id's for the given "type" which are suitable for processing with the $set functions.

Type can be: CarIDs, CarLabels, TrainIDs, TrainNames, TrackIDs, TrackLabels, JunctionIDs, JunctionLabels, SwitchIDs, SceneryIDs, Variables.

$LAYOUT(JxnLabels)

Returns a comma-delimited set of all user applied junction labels. Returns null if none.

$LAYOUT(LayoutID)

Settable Property

Returns the TrainPlayer applied, or user modified, layoutID number for the layout.

$LAYOUT(Name)

Settable Property

Returns the layout name as shown in the layout properties dialog. Can be modified using Set or Let.

$LAYOUT(NTrains)

Returns the total number of trains on the layout.

$LAYOUT(Path)

Settable Property

Returns the full windows path to the rrw file.

$LAYOUT(ReadOnly)

Settable Property

Can be used to extract or set the flag that marks the layout file as read-only to prevent if from being overwritten. 1 = read only, otherwise 0.

$LAYOUT(RoadStyleFromGlobals)

Copies the global roadsyle settings to the default layout roadstyle.

$LAYOUT(SaveVars)

Settable Property

Retrieves or sets the flag that dictates if the current values of the variables are saved with the layout for use when it is reloaded. 1 = save the variables, otherwise 0. Property can be assigned with Set or Let.

$LAYOUT(TrackLabels)

Returns a comma-delimited list of all track labels on the layout which is suitable for processing with the $set functions.

Deprecated but still functional. Replaced by $layout(IDset,tracklabels)

$LAYOUT(Train <i>)

Returns the name of train i, where i is a number between 0 and Ntrains.

$RAND(i1,i2)

Returns a random integer between i1 and i2. Both arguments must be integers.

$RAND with no arguments returns a random number between 0 and 100.
$RAND(i1,i2) returns a random number between i1 and i2.
$RAND(i2) a single argument is taken as i2 (maximum), i1 defaults to zero.

** Examples:

** Place a random number between 1 and 10 and vrand1
   let vrand1 = $rand(1,10)

** Place a random number between 0 and 100 in vrand2
   let vrand2 = $rand

** On a junction action gives instruction to operator
   echo Pick up $RAND(1,5) cars here

** Outputs a percentage figure to the Schedule Window
   echo random percent = $RAND

** Place a random number between 2000 and 3000 in a variable
   let WaterUsage = $rand(2000,3000)

$SETTING(name)

Settable Property

Returns the value of the named registry setting.
If the name contains a space the Set argument for assigning a Registry Variable must be in quotes, but not for assigning it via a Registry Function.

Examples:
echo Current accel factor = $setting(AccelFactor)
Let AccelFactor = 20

** These are all equivalent. Quotes are mandatory with first example only.
Set "Max MPH" 100
Let Max MPH = 100
Set $setting(Max MPH) 100
Let $setting(Max MPH) = 100

$SYSTEM(command)

Executes the given system command from the Windows Command Box
-- Command is any command you can type into the Windows system Command Prompt box.
-- Code is executed within a command window.
-- Returns an undocumented code indicating success or failure.
-- If you want time to read the output from the command window you should append "& pause"

EXAMPLE(s):
call $system("type myfile.txt")
call $system(type @file)
let retcode = $system("rename abc.txt def.txt")

EXAMPLE
let prompt = "c:test.xml"
let code = $system(@prompt)
if (code = 0)
   echo file exists!
Else
   echo file not found
endif

$SWITCH(jxnID)

Settable Property

Takes one argument jxnID, which is a junction ID number. Returns the switch position (0 or 1 for a standard switch), -1 if the junction is not a switch. Argument can optionally include a prefix J or j. Can be used to reset the switch with Set or Let.

"Set $switch(56) 1" -- Is the same as "Throw 56 1".

$TRACK(id, Label)

Settable Property

Returns the user-applied track label from the track id number.
The label can be modified with Set or Let.

$TRACK(id, Length)

Returns the length of the stipulated trackID number in rru.
Using the tracklabel can give false results as more than one trackID can use the same label.

$TRACK(id, OccupiedBy)

Returns a comma delimited set of car labels for the cars on the designated track.
The resulting set is suitable for processing with the $set or $string functions.

$TRACK(jxn1, FindFromJxns, jxn2)

Returns the trackID number of the track between two stipulated junctionID numbers, produces an error message if no such track exists.

$TURNTABLE(id, AlignedTo)

id(s) of 1 or 2 locked external tracks

Returns the id number of 1 or 2 locked external tracks, to check if the Rotation command is needed or not. Returns 0 if not aligned to any tracks.

$TURNTABLE(id, Label)

Settable Property

Returns the user-applied label from the turntable with the matching ID. This property can be created or updated by the user with Set or Let.

Example: let $turntable(3,label) = "Engine House"

$TURNTABLE(id, OccupiedBy)

Returns a comma delimited Set of the labels of any cars on the turntable which matches the id, this data can be processed with $Set or $String, or used with the Train Commands.

$TURNTABLE(id, Track)

Returns the id number of the turntable bridge track.

$VIEW(op,name)

Used for opening or closing the various TrainPlayer tools, or testing their visibility status. Dialog names may be quoted, but need not be. Most of the names on the Tools menu can be used.

op = IsVisible, Show, Hide.    Name = Any dialog listed on the Tools Menu.

$VIEW (IsVisible,Name) returns 1 (true) if the named feature is visible, otherwise 0.
$VIEW(Show,Name) opens and displays the window or feature named.
$VIEW(Hide,Name) closes or hides the window or feature named.

** Example: Display the Schedule Window if not already already showing.
   Call $view(show, schedule)
** Example of using $layout to get a report list of the trains on a layout
   let i = 0
   while (i < $LAYOUT(ntrains))
      echo Train @i is named $LAYOUT(train @i)
      let i = i + 1
   endwhile <

** Example: Stop and throw switch ahead if not set to position 0
   at 122
      ** When we reach here check the switch ahead
   if ($Switch(123)<>0)
      ** If not set to position 0 stop and instruct operator to throw it
    Stop
    note Throw upcoming switch
    while ($Switch(123)<>0); endwhile
      ** Hold up script until switch is in correct position
    speed 10
      ** Restart train and carry on
    note
      ** Hide the Note window
   endif

Example to check if a Turntable needs rotating to accept a train.
** Stop train on Turntable approach track
   AT 189 STOP
   echo TTtrack is $TURNTABLE(1,TRACK)
   echo $TURNTABLE(1,Alignedto)
** Copy current alignment string into a variable
   let align = $TURNTABLE(1,alignedto)
   let approach = 151
   let jxn = 156
** Check to see if turntable is aligned correctly
   IF ($findstr(@approach,@align)=-1)
      ** If not rotate
      rotate 1 @jxn
      on tablestop
   ENDIF
   echo $TURNTABLE(1,Alignedto)
   Forward
   speed 5
   AFTER 156
   AFTER 0:0:05
   STOP
   rotate 1 156 ccw
   echo $TURNTABLE(1,OccupiedBy)

** Example using $View to check if the Schedule Window is visible.
   let v1 = $view(isvisible, schedule)
   if (v1 = 0)
      echo The schedule window is not visible, but I expect you knew that already :>)
   endif

Back to System Functions


Scenery Functions

$SCENERY(id, Hide)

Call $scenery(id,hide) to hide a scenery object from view.
Has no effect if object is already hidden from view.
id is the unique scenery id number or a user allocated name.

$SCENERY(id, IsVisible)

Let IsVis = $scenery(id,isvisible).
If the scenery object is showing IsVis will be 1 , if it is not showing IsVis will be 0.
id is the unique scenery id number or a user allocated name.

$SCENERY(id, Label)

Settable Property

Call $scenery(id,label) returns a user allocated scenery label, if no label returns null. Label can be applied with Set or Let.
id is the unique scenery id number or a user allocated name.

Example: Let $scenery(33,label) = "Queen Supply"

$SCENERY(id, Show)

Call $scenery(id,show) to display a previously hidden scenery object.
Has no effect if object is already visible.
id is the unique scenery id number or a user allocated name.

$SCENERY(id, Toggle)

Call $scenery(id,toggle) changes the visibility of a scenery object, if hidden it is shown or if visible it is hidden.
id is the unique scenery id number or a user allocated name.

** Example hide a ferry under an image of the water when it sails and restore it when it returns.
** Assumes scenery object 1 is a rectangle of water set to Hide Track and Trains.
   AT 0700; call $SCENERY(1, show)   ** Hides loaded ferry and its cars.
   AT 1500; call $SCENERY(1, hide)   ** Reveals inbound ferry and its cars.

Back to System Functions


Clock Functions

$rrclock is a powerful family of functions for setting and managing the "Fast Time" scale clock and conducting clock arithmetic. This is extremely flexible and the usage depends on the arguments supplied.

Time values passed as arguments do not need the colon between hours and minutes but the processor will accept these, for times before 10:00 the leading 0 is optional (0700, 07:00, 700 and 7:00 are all accepted). Values returned from the clock function will always include the colon in the return value (e.g. 23:45) so if you need to make a string comparison you must include a colon in your comparison variable.

$RRCLOCK

$RRCLOCK()

With no time argument $rrclock returns the current time shown on the scale clock.
$rrclock with empty parens is equivalent.

** Report the fast clock time to the Schedule Window
   echo Current time on layout is $RRCLOCK
   let curtime = $RRCLOCK

** Extract the current clock time to a variable
   let layout_time = $RRCLOCK()

** Menu command to reset the clock to its default setting.
   clock reset

$RRCLOCK(hhmm)

$RRCLOCK(hh:mm)

With a single time argument sets the clock to the specified time which should be in the 24 hour format hhmm or hh:mm. For times before 10:00 the leading zero is optional and can be omitted.

** Set the layout clock to 0530 (using 24 hour format)
   call $RRCLOCK(0530)

** If the clock is not running use a menu command to start it.
   clock start

$RRCLOCK(hhmm,hhmm)

$RRCLOCK(hh:mm,hh:mm)

With two arguments performs clock arithmetic, the second value can be a negative value for subtraction.
The calculation does not alter the current clock settings in any way.

** Add 1 hr 59 mins to 2200 hrs.
   echo sum(2200,0159) = $rrclock(2200,0159)
      ** returns sum(2200, 0159) = 23:59

** Add 2 hrs 1 min to 2200 hrs.
   echo sum(2200,0201) = $rrclock(2200,0201)
      ** returns sum(2200,0201) = 00:01

$RRCLOCK(x)

With single argument X returns the current time speed multiplier setting.

** Check the current speed multiplier being used by the fast clock.
   echo $rrclock(x)

$RRCLOCK(x<n>)

Sets the time speed multiplier to the value given by <n>. There should be no space between x and n.

** Reset the layout clock to run at 12x normal speed.
   Call $rrclock(x12)

Examples

** Example of using the clock for a random delay, also uses $rand function.
   Clock Start
      ** Start the clock running
   STOP
      ** Stop the train
   Let start=$rrclock
      ** Extract current time from clock
   let delay =$rand(10,59)
      ** Use $rand function to get delay between 10 & 59 mins
   let end=$rrclock(@start,@delay)
      ** Set the end time by adding delay to start time
   While $rrclock<@end; endwhile
      ** Hold up the script until the end time is reached
   speed 40
      ** Restart the train moving

** Example of using the $rrclock function within an IF statement
   set ferrytime 07:00
      ** Set variable for testing against the clock
   if ($rrclock<@ferrytime)
      ** Compare ferrytime with current time and report
    echo The ferry sails at @ferrytime, the time now is $rrclock
   else
    echo Wait here, time is $rrclock, ferry left at @ferrytime
   endif
   ** In this case the comparison done by the IF statement is a string comparison, this means a colon
   ** is needed in the ferrytime variable for comparison with the value returned from the function

** Define a Procedure to set up and start the fast time clock
** Requires two arguments: %1 speed clock is to run, %2 start time (without colon)
** Called by: CALL startclock x10 0800
PROC startclock
   clock stop
   set clockresettime %2
   call $rrclock(%1)
   clock reset
   call $view(show,clock)
   clock start
endproc

Manipulating time with clock arithmetic

Recap: When $rrclock is used with two arguments it can perform clock arithmetic, neither of the values used have any effect on the current clock setting which retains its present value regardless of the times used as arguments for the arithmetic. The value returned by the argument is the sum of the two arguments, a negative value can be used as the second argument to represent subtraction.

** Example to record a period of elapsed time.
   Echo $rrclock
      ** Outputs the current layout time to the Schedule Window
   Let Start = 16:00
      ** Stores a start time in variable start
   Let Finish = 19:30
      ** Stores a finish time in variable finish
   Echo $rrclock(@finish, -@start)
      ** Outputs the result of deducting start time from finish time
   Echo $rrclock
      ** Demonstrates the calculation has not changed the clock value

** Example to calculate what the layout time will be one hour from now to dispatch a train.
   Stop
      ** Stop the train and wait for one hour
   Let arrivetime = $rrclock
      ** Get current layout time from the $rrclock function
   Let departtime = $rrclock(@arrivetime,0100)
      ** Add one hour to the current time
   echo Train arrived at @arrivetime and will depart at @departtime
   AT @departtime Speed 10
      ** Restart the train

** Examples to demonstrate that the arithmetic works properly from late evening to midnight and beyond.
   echo sum(2200,0159) = $rrclock(2200,0159)
      ** returns sum(2200, 0159) = 23:59
   echo sum(22:00,02:00) = $rrclock(22:00,02:00)
      ** returns sum(22:00,02:00) = 00:00
   echo sum(2200,0201) = $rrclock(2200,0201)
      ** returns sum(2200,0201) = 00:01
   echo sum(2200,0301) = $rrclock(22:00,03:01)
      ** returns sum(2200:0301) = 01:01
   echo sum(600,-200) = $rrclock(600,-200)
      ** returns sum(600,-200) = 04:00
   echo sum(2200,0301) = $rrclock(2200, 0301)
      ** returns sum(2200,0301) = 01:01
   echo sum(100,-200) = $rrclock(100,-200)
      ** returns sum(100,-200) = 23:00
   echo sum(00,300) = $rrclock(00,300)
      ** returns sum(00,300) = 03:00 (midnight as first arg)

Back to System Functions


User Interface Functions

$Msgbox([<type>,]<text>)

$msgbox is a system function which displays the supplied <text> as a prompt, <type> if present must be OC for a box with OK/Cancel buttons, or YN for a box with Yes/No buttons.

The function returns 1 if Ok or Yes is clicked, returns 0 if No or Cancel is clicked (the response can be used for subsequent conditional processing).

In this format the $msgbox is modal, all action on the layout is frozen and a response must be given before you can undertake any work on the layout outside of the message box dialog. Once one of the buttons has been pressed any paused action resumes.

Note: This command is particularly useful at the start of a Master Script up as it stops all script action while the function is awaiting the user's response.

$Msgbox(<text>)

$msgbox can also be used without the <type> parameter to pause a script without freezing the action on the layout (if any). In this format there are no choices to be made and only an OK button is displayed to enable the script to resume.

This version of $msgbox is pseudo modeless and enables a developer to make changes to the layout design and the ops data grids before clicking OK to enable the script to proceed.

This feature is designed to assist with Ops development work and should be used with care.

** Example: Pass a string message to the user and accept a mouse click response
   let prompt = This layout has a script to run the train.\n\nWould you like to start it?
   if ($msgbox(YN, @prompt) = "1")
   train script play
   endif

** Example: Pass a string message to the user and accept a mouse click response
   let v1 = $msgbox(YN, Do you want to continue?)
      ** returns 1 if click Yes
   IF (v1<>1); EXIT; endif
      ** terminates script if user clicks No, otherwise script continues.
   echo OK we are continuing

Back to System Functions


Set Functions

A Set is a list of integers or strings, comma- or space-delimited stored in a string variable. Comma delimited Sets are returned by various built in functions, or can be created by the user using the $set functions.

This is an example of a set of car labels returned by the system function $track(tracklabel,occupiedby):
      FL25,LO26,G23,RB15,XM12,T28,X9,F5,RP2,X14,G7
It depicts the cut of cars occupying the multiple tracks which share the supplied tracklabel.

This is the same set after being sorted with $set(@carset,sort):
      F5,FL25,G23,G7,LO26,RB15,RP2,T28,X14,X9,XM12

Each $SET call requires the name of the set as the first argument and is then followed by one, or two, more arguments. Where the set is a string stored in a variable it must be prefixed by the @symbol to depict "contents of". Sets entered as literal strings must be enclosed in quotes.

The second argument is always a mandatory keyword as depicted in the tables below.

The third argument can be another set, an object or an integer number.

$set calls with two arguments

$SET(set, Count)

Returns the number of set members contained in the supplied set.

$SET(set, Dedupe)

Returns the supplied set with all duplicates removed.

$SET(set, Flatten)

Returns the supplied set with any subsets merged into the named set.

$SET(set, Randomize)

Returns the supplied set sorted into a random order.

$SET(set, Sort)

Returns the supplied set sorted alphanumerically.

$SET(set, SortRev)

Returns the supplied set sorted in reverse order.

$set calls with three arguments

$SET(set, Add, value)

Adds the new value to the end of the set and returns the new set.
If value contains subsets they are flattened and added as individual values.

$SET(set, Contains, query)

Returns 1 (true) if the set contains the query, otherwise returns 0.

$SET(set, ContainsSet, set2)

Returns 1 (true) if the set contains all members of set2, otherwise returns 0.

$SET(set, Difference, set2)

Returns a set containing only those members of the supplied set that are not also present in set2.

$SET(set, EqualSets, set2)

Returns 1 (true) if the sets are equal to each other, otherwise 0.

$SET(set, Find, query)

Finds and returns the index number of the member matching the query identifying its position in the set, returns -1 if the query is not present. Note: The index is zero based placing the first set member at position 0.

$SET(set, Get, i)

Returns the i'th member of set (starting with zero)

$SET(set, Intersection, set2)

Returns a new set containing only the members that are present in both the supplied set and set2.

$SET(set, Remove, i)

Removes the i'th member from the supplied set (first i = 0) and modifies the stored set.

$SET(set, Union, set2)

Unifies the contents of two sets (set and set2) to form a single set, removing any duplicates.

Sets which can be processed by the above functions are $layout(idset, type), $train(trainID, CarIDs), $train(trainID, CarLabels), $track(trackID, occupiedby) and $turntable(turntableID, occupiedby).

Sets used as arguments in conditional statements must also be preceded by the @ (contents of) symbol.

Examples:

** Identify list of all cars on a layout - Clist
   let Clist = $layout(idset,carlabels)

** Identify the cars which are already spotted - Cspottedset
   let Cspottedset = $layout(idset,carlabels,spotted)
** Identify cars which are not yet spotted - Cstilltospot
      let Cstilltospot = $set(@Clist,difference,@Cspottedset)

** Count the number of cars still to be spotted
   let Ntospot = $set(@Cstilltospot,count)

** Flatten a set which contains subsets as members
   let s1=1,"2,3,4",5
   echo s1 count = $set(@s1, count)
   let s1f = $set(@s1, flatten)
   echo s1f count = $set(@s1f, count), set = @s1f
** outputs: s1 count = 3, s1f count = 5, set = 1,2,3,4,5

** Add a value or values to an existing set, flatten any values that are subsets into separate single values
   let s1=2,4,6,8,10
   let s2=$set(@s1, add, "12,14")
   echo s2 count = $set(@s2, count), set = @s2
** outputs: s2 count = 7, set = 2,4,6,8,10,12,14

Back to System Functions


String Functions

$STRING(str, Contains, str2)

Returns 1 (true) if str contains str2, otherwise 0.

** Example
   echo $string(@str,contains,@str2)

$STRING(str, EndsWith, str2)

Returns 1 (true) if str ends with str2, otherwise 0.

** Example
   echo $string(@str,EndsWith,"so on")

$STRING(str, Length)

Returns the length of string str in characters. If str is a variable then @str is needed to signify contents of str. If literal strings contain spaces then they must be in quotes.
This returns the same result as $StrLen(str).

** Count the characters in a given string.
   let len = $string("abcde",length)
      ** Allocates the value 5 to the variable len

$STRING(str, NextToken[, delims])

Extracts and returns the next substring up to the first delimiter character.
-- Then it removes the extracted data (and the delimiter) from the original string.
-- This leaves the modified string ready for the next call which will extract the next substring.
-- Default delimiter if unspecified is blank or comma. Adjacent blanks and commas count as one.
-- You can specify different delimiters in the call: let t = $string(str, NextToken, ";-/")
-- The use of @ is optional in a NextToken call. You can say (str, NextToken) or (@str, NextToken).
-- NextToken returns "EOL" if there are no more tokens, but you don't have to check for this.
-- You can just look at whether the string has been reduced to an empty string (see examples).
-- If you use a literal instead of a variable, nothing is modified, but you can only get the 1st token.

** Using NextToken to extract data from strings.
   let string = "Jim, Bruno, Alan, Richard, and so on"
   while (1=1)
      let token = $string(@string, NextToken,",")
      ** Note defining comma delimiter prevents spaces from separating "and so on".
      echo token => @token
      if (string = "");break; endif
   endwhile

$STRING(str, StartsWith, str2)

Returns 1 (true) if str starts with str2, otherwise 0.

** Example
   echo $string(@str,StartsWith,@str2)

$FINDSTR(sub,str)

Returns the zero-based position of sub within str, or -1 if not found

** Find the start position of a substring within another string
   let anystring = "Now is the time for all good men to come to the aid of the party"
   let searchstring = "good men"
   let position = $findstr(@searchstring,@anystring)
   echo @searchstring starts after character @position
      ** position is found as after character 24

$STRLEN(str)

Returns the length of string str in characters. If str is a variable then @str is needed to signify contents of str. If literal strings contain spaces then they must be in quotes.
This returns the same result as $string(str,length).

** Count the characters in a given string. (Quotes optional).
   let len = $STRLEN("TrainPlayer")
      ** Allocates the value 11 to the variable len

$SUBSTR(i1,n,str)

Returns the substring (sub) of the string (str) starting at i1, n chars long; if n = -1 read from i1 through to the end of the string. i1 is taken as 0 in front of first character effectively making the first character in str position 0.

** Extracting a substring from within a longer string
   let anystring = "Now is the time for all good men to come to the aid of the party"
   let substring = $substr(20,12,@anystring)
   echo @substring
   ** Outputs "all good men" to the Schedule Window, i.e. 12 characters starting after character 20
** Sending only the first few words to the Schedule Window
   echo $substr(0,15,@anystring)
   ** Outputs "Now is the time" to the schedule window, 15 characters after character 0)

** Sending the text from a given point to the end of the string.
   let totheend = $substr(16, -1,@anystring)
      ** -1 means from the stated start to the end of the string
   echo @totheend
      ** Stores the string from after character 16 to the end of the string
      ** echo statement reports as "for all good men to come to the aid of the party"
** If the substring is not found the function returns -1 to the variable
   let anystring = "Now is the time for all good men to come to the aid of the party"
   let searchstring = "Jim Dill"
   let position = $findstr(@searchstring,@anystring)
   echo @searchstring starts after character @position
   ** position is reported as after character -1 (in other words it doesn't exist)

** Using / as a custom delimiter.
   let string = "token 1/token2/token3/and so on"
   while (1=1)
      let token = $string(string, NextToken,"/")
      echo token=> @token
      if (string = "");break; endif
   endwhile

Back to System Functions


File Functions

$READ(filepath)

Retrieves the complete contents of the specified text file as a display string, same as $FILE(id, ReadAll). Arguments are unquoted.

$WRITE(filepath,[append,]string)

Write the designated string to the filepath, optionally append to existing contents. Returns 1 if successful, 0 it not. If the file does not exist it will be created. If the file exists it will be overwritten. Arguments are unquoted.

If the optional argument "append" is included the data is appended to the existing file with this name. The optional argument "append" can be abbreviated to "a."

If you APPEND to a file that doesn't exist it will be created, if there is no CR /LF at the end of the output it will be added automatically. If you wish you can use CALL to activate these functions and ignore the return value. $read and $write will both accept Windows relative pathnames.

** Example: Write the Schedule Window contents to a file in the reports folder on D:
   call $write(d:\reports\output.txt,$output(all))

Note: We recommend writing to a file in a named folder, attempting to write to the root folder of a drive can cause difficulties as trainplayer attempts to build the path to a new file.

$FILE(filepath, ReadVars)

Reads in the names and resets the values of the user variables from a previously saved variables file in XML format.

Example: call $file(d:\reports\savedvars.xml,readvars)
Example: echo $file(d:\reports\savedvars.xml,readvars)
   ** Using echo instead of call allows you to check the return code, 1=success, 0=failure.

$FILE(filepath, SaveVars)

Writes out the complete list of all global variable names and values to a named file in xml format. Filename can be a full or a relative pathname.

Example: call $file(d:\reports\savedvars.xml,savevars)
Example: echo $file(d:\reports\savedvars.xml,savevars)
   ** Using echo instead of call allows you to check the return code, 1=success, 0=failure.

$FILE(filepath, Delete)

Returns 1 if the file is successfully deleted, otherwise 0.

$FILE(filepath, Exists)

Returns 1 if the file exists, otherwise 0.

$FILE(filepath, GetDir)

Returns the directory path, without the filename.

$FILE(filepath, GetNameExt)

Returns filename plus extension only, no path.

The functions listed above do not require the file to be opened prior to using them.

** Example of writing data to separate text file placed in the same folder as the layout.rrw file.
   let myfile = .\myfile.txt
   let report = "This is the report text to be written
if it contains more than one line it must be quoted."
   call $write(@myfile,@report)

** Example of appending data to an existing text file in the same folder as the layout.rrw file.
** Note: if the file does not exist it will be created.
   let statsfile = .\timesaver_challenge_data.txt
   let newdata = "This line will be appended to the statsfile"
   call $write(@statsfile,append,@report)
** Example of reading in and displaying a text file from the same folder the layout is stored in.
** Note: the required file must already exist.
   let statsfile = .\timesaver_challenge_data.txt
   echo $read(@statsfile)

The following functions require the file to be specifically opened to enable repeated access.
This requires a system generated FileHandle which is obtained from the $file(filepath,open) function.

$FILE(name, Open)

Use with LET to open a named text file, the function returns an id number filehandle if successful, or 0 if the file is not found.

The filename you provide is first checked as a literal path, if not found it is treated as a relative path.

EXAMPLE which seeks to open a text file in a "subs" subfolder of the folder containing the rrw file.
let filehandle = $file("subs\myfile.txt", Open)
   ** Allocates a system generated handle for the opened file.

$FILE(filehandle, ReadAll)

Retrieves the complete contents of the specified text file as a display string, same result as $Read(filepath). Arguments are unquoted.

First argument, filehandle, is the system generated file handling id generated by the $file(filepath, open) function.

$FILE(filehandle, ReadLine)

Retrieves the next line of the file, and returns 'EOF' when the last line has been read.
-- First argument is the file handle obtained from the $file(filename,Open) command.
-- ReadLine returns "EOF" when there are no more lines to read.
-- You can insert EOF as a line in a text file and the read will terminate there.
-- The Readline option can be used to extract lines from a CSV file for processing with $String.

$FILE(filehandle, Close)

Closes an an open file. First argument is the file handle id from the open file command, not the filename.
-- You do not need to call Close if you use ReadAll as the file will be closed automatically.
-- You do not need to call Close if your ReadLine calls go all the way to the end as the file will close anyway.
-- However since you don't know if it read all the way to the end it is good practice to call $FILE(filehandle, Close) anyway.

** Example call to a subroutine to extract data from a file in the same folder as the layout.
Call getlinebynumber ".\tmp.txt" myhandle mycounter reportvariable 5

** Example Subroutine to extract a particular line from a file with multiple lines
** GETLINEBYNUMBER extracts a specified line from a file based by on its position in the file.
** The Call to this subroutine requires 5 arguments:
** %1 is the filename to be opened
** %2 is a variable name to hold this particular file handle
** (to ensure no conflicts with other calls to this same subroutine)
** %3 is a variable name to use as a counter to move through the required file
** %4 is a variable name to return the extracted line to the calling script for processing
** %5 is the line number containing the data required to be extracted from the file
** Note Fifth argument can be a literal line number or contents of a variable (e.g. @myline)
** ------------------------------
let %2 = $file(%1, Open)
if (@%2 = 0)
   echo Error: File %1 not found
endif
let %3 = 1
while (@%2 > 0)
   let %4 = $file(@%2, ReadLine)
   if (@%4 = "EOF") break; endif
   if (@%3 = %5);break;endif
   let %3 = @%3 + 1
endwhile
call $file(@%2, close)
** ------------------------------
** End of subroutine getlinebynumber

** Example Subroutine to find the first line that starts with matching characters supplied in argument 4.
** GETLINEBYSTART extracts a specified line from a file based on the first few characters on the line.
** The Call to this subroutine requires 4 arguments:
** %1 is the filename to be opened
** %2 is a variable name to hold this particular file handle
** (to ensure no conflicts with other calls to this subroutine)
** %3 is a variable name to return the extracted line to the calling script for processing
** %4 is the opening text which is used to identify
** the line containing the data required to be extracted from the file
**
** Example call to extract data from a file in the same folder as the layout.
** Call getlinebystart .\tmp.txt myhandle reportvariable "Peter Prunka"
** Note Fourth argument can be a literal string, contents of a variable (e.g. @myline),
** or a train/car name ($x_train or $x_car)
** ------------------------------
let %2 = $file(%1, Open)
if (@%2 = 0)
   echo Error: File %1 not found
endif
while (@%2 > 0)
   let %3 = $file(@%2, ReadLine)
   if (@%3 = "EOF") break; endif
   if (@%3 = %4)
    if ($string(@%3,StartsWith,%4) = 1)
    break
   endif
endwhile
call $file(@%2, close)
** ------------------------------
** End of subroutine getlinebystart

Back to System Functions


Ops Functions

The Ops Functions are an advanced topic and only the briefest introduction is included here.

$AO_DEV(mode,arg)

The $ao_dev functions are used to search for, extract and insert the data stored in the dedicated ops variables and sets. $ao_dev can also be used to run some of the embedded C++ system functions used by the switchlist generator and car monitor.

** If switchlist exists rewind trains to first switchlist.
   if ($ao_dev(getset,cpickuplist)<>"")
      let test = $ops(nswitchlistno)
      if (test > 1)
         let message = @message + "> Layout = $layout @cr@> Resetting Ops sequence to Switchlist 1 for testing. @cr@"
         note @message
         call $ao_dev(dev,Reset trains to start)
         call $ao_dev(dev,Generate First Switchlist)
      endif
   else
      let message = @message +"> Layout = $layout @cr@> This layout has not yet been prepared for Ops.@cr@"
      note @message
   endif

$OPS(mode,grid.col,qry)

Settable Property

Use the $ops functions to find, extract, process and insert data stored in the various Ops Central grids. There are two special keyword actions, get and set, and a short list of property names.

There are four grids, named by their tabs (Industries, Cars, Locations, Train Seqs), each with its own set of named columns.

To identify a column within the entire database, you use a compound name (gridname, dot, colname); to get at a particular cell of data, you use one of these plus a row number.

The "Tabnames" can be abbreviated to "ind", "car", "loc", "seq", or a word containing the same.

The "Column" argument identifies both a column and a grid, using the format "tabname.colname." as shown in Ops Central.

** Write viain and viaout data to @row in Industries grid.
   call $ops(set,industries.viain,@row,@via)
   call $ops(set,industries.viaout,@row,@via)

For detailed information on Scripting for Advanced Ops please see Part 5 of this series of documents.

Back to System Functions


Developer Commands & Functions

$NOTE(id)

Settable Property

Not to be confused with the UI Commands "Note" and "Notebox", the System Function $NOTE refers to the script developer information Notes that can be defined on the Scripts Tab of the Script Central dialog.

Each of these Notes is allotted an ID number when it is created on the Scripts Tab.

** To display data from a developer note.
   echo $note(id)

** To replace data in an existing developer note.
   let $note(id) = @textstring
      ** The note must exist, it will not be created.
      ** If a literal string has more than one line it must be quoted.

Timestamp

Timestamp reset

Timestamp echoes the time that has elapsed since the command was last used to the Schedule Window to assist scripters with debugging and speeding up scripts and subroutines. To reset the timer use Timestamp Reset.

The first time Timestamp is called it will return an elapsed time of 0 ms, 0.00 secs. Thereafter it will return the time that has elapsed since it was last called and the total time that has elapsed since the last reset.

Example output: 12/04/2024 10:58:48 elapsed=2600261 ms total=2676.12 sec

$OUTPUT([all])

System function to return the last line or all lines of Script Output as displayed in the Schedule Window.
$output with no arguments returns only the last line.
$output(all) returns all contents of the Schedule Window.

** Example: Write the contents of the Schedule Window to a file on D:
   call $write(d:\reports\output.txt,$output(all))

Note: We recommend writing to a file in a named folder, attempting to write to the root folder of a drive can cause difficulties as trainplayer attempts to build the path to a new file.

$TIMER(Reset)

Resets the $timer function to 0 milliseconds based on the current system clock time.

Example: let start = $timer(reset) ; echo @start

$TIMER(ElapsedMS)

Returns the number of milliseconds elapsed since the last $timer(Reset) call.
This uses the same data as Timestamp but allows the elapsed milliseconds to be extracted to a variable for further processing.

Example: let elapsed = $timer(elapsedMS) ; echo @elapsed milliseconds

Launch <path>Title

Launches an external application by opening the supplied path (see example below).

** Example: NPP subroutine launches the active TrainPlayer rrw file in Notepad++ for editing.

** Get the Data Directory for the current user.
   let datadir = $datadir
   echo datadir = @datadir

** Get the path to the active open layout
   let layoutpath = $layout(path)
   echo layoutpath = @layoutpath

** Store the the default path to the NP++ application
   let editorpath = "C:\Program Files (x86)\Notepad++\notepad++.exe"

** Start NP++
   launch "@editorpath" "@layoutpath"

Back to Contents


Richard Fletcher for TrainPlayer - December 2024