Sunday, 10 January 2016

Create your own Rail Fan Scenarios!

Creating Rail Fan or Trainspotting scenarios is almost identical to making a standard scenario, so if you've already got the hang of making your own scenarios then this will be easy!  If you haven't, this might be an interesting place to start because these are generally a bit easier than scenarios due to the player not actually moving anywhere.

The first step is to actually get in to the world editor and create a scenario, so from the main screen click the Build menu, then select the Scenario tab.

Scroll through the list that's presented until you find the route you want to make your Railfan scenario, select it and then click New Scenario.

On the dialog box that comes up, type in a name for the scenario, select "Standard scenario" as the type and then in the "Set Location" area see if the location you want is roughly there (on all steam DLC routes you should find one location for each station on the route), if not then select Route Origin.  Click Create.

Required Assets


Think about the kinds of trains you're going to want to include and let's get them enabled in the Object Set Filter.  Be selective about what you include because every tick box you enable is a piece of DLC that someone must own to run this scenario if you choose to share it on Steam Workshop.  Also, keep in mind that the game will load every asset contained in that package even if you just use one wagon out of it, so try not to pick a large package without making as much use of it as possible.

To enable items, you need to open the Object Set Filter, highlighted on the screen capture.

Once you click this, a window will be available on the top right hand side (you may need to move your mouse over it to make it fly out and be visible).  This will contain a drop-down box containing "providers" and a list of "products" for each one.  You will find most Dovetail steam content in either the "RSC" or "DTG" provider.  You should generally be able to recognise or guess what's in each of the products based on their name.  Tick the MIDDLE checkbox in order to enable it's rail vehicles for your scenario.


One important asset you must enable is the Railfan "loco" - this is included in new DTG products and there is a copy in each of the provider/product packages for the routes contained within TS2016.  For example, if you find provider DTG and product ExeterKingswear you will enable the Riviera in the 50's assets, which will give you the Railfan "loco".  If you don't have one of these products you could just use a regular loco.

The Player


The first thing you're going to want to do is find somewhere to place the invisible "player train".  Ideally this should be situated on a siding or a track that isn't going to be used, somewhere in the close vicinity of the station.

If you click on the loco selection icon in the middle-left flyout and then scroll through the list you should find the simply named "Railfan" entry as shown on this screen capture.

Once selected, simply place it somewhere just as you would a normal locomotive.  It looks like the cinematic camera icon.


As you can see, it's pretty small, and if you try to place it in the same are as a track marker you likely won't be able to see it - so find somewhere clearly visible and it should place fine.

Next, place a driver icon on it in the usual way.

Click on the timetable icon in the top left flyout and then you can start setting the player side of things up, this is really where the framework for the Rail fan scenario will be created.













As shown in the image to the left, essentially you want to add three instructions.













1. Trigger Instruction - this will be used to set up the LUA script that we write shortly.  Put "start" in the first smaller text field, you'll find out what it does soon.

2. Stop At - use this to tell the player train it needs to go somewhere, anywhere that's not near you will do, but it must be somewhere you could get to.  The player train won't be moving so it's fine.  Also keep it simple, add a new marker if necessary.

3. Final Destination - it's the player train so it must have a Final Destination instruction, just make it the same as the marker you set for the Stop At instruction.

The LUA Script

Now that the player train is set up we need to set the LUA script up.  If you're not a developer or haven't done any LUA scripting at all this might seem daunting, the good news is that it's really mostly a copy-paste task and you can re-use the same basic script over and over with almost no changes at all.

While still within the timetable window, click on the Script icon on the toolbar at the top of the service instructions:






In the window that pops up, don't worry if it gives an error about not being able to read a file - we haven't created it yet.  Click the Open Folder button and a Windows explorer application will open, pointing to the folder where the scenario data files are kept.

Create a new text file in here called ScenarioScript.lua and open it in your favourite text editor - I use Notepad++ but there are many great editing tools out there that will do the job nicely, even Notepad will do in a pinch :)

When you create the file, ensure that it does not retain the .txt extension.  When you're done, in Explorer it should show up as a file of type "LUA file".  If it still shows up as a file of type "Text file" then this is incorrect and means that internally in Windows it still thinks the file is ScenarioScript.lua.txt - even if all you can see is ScenarioScript.lua.  Click the View menu and on there ensure "filename extensions" is ticked.  If it isn't then when you tick it, you should see the full name of your file revealed and you can then rename it to fix it.

Next i'm just going to paste the whole file in, and then we can talk about what it is actually doing:

-- true/false defn
FALSE = 0
TRUE = 1

-- condition return values
CONDITION_NOT_YET_MET = 0
CONDITION_SUCCEEDED = 1
CONDITION_FAILED = 2

-- Message types
MT_INFO = 0   -- large centre screen pop up
MT_ALERT = 1  -- top right alert message

MSG_TOP = 1
MSG_VCENTRE = 2
MSG_BOTTOM = 4
MSG_LEFT = 8
MSG_CENTRE = 16
MSG_RIGHT = 32

MSG_SMALL = 0
MSG_REG = 1
MSG_LRG = 2

function OnEvent(event)
    return _G["OnEvent" .. event]();
end

function TestCondition(condition)
    return _G["TestCondition" .. event]();
end

function OnEventStart()
    SysCall("ScenarioManager:LockControls")
    SysCall("CameraManager:ActivateCamera", "startcamera", 0)
    SysCall("ScenarioManager:TriggerDeferredEvent", "WelcomeMessage", 17)
end

function OnEventWelcomeMessage()
    SysCall("ScenarioManager:UnlockControls")
    SysCall("ScenarioManager:ShowInfoMessageExt", "Knebworth Trainspotting", "Wait, we stopped?!", 15, MSG_LEFT+MSG_TOP, MSG_SMALL, TRUE)
    SysCall("CameraManager:ActivateCamera", "FreeCamera", 0)
    SysCall("ScenarioManager:TriggerDeferredEvent", "End", 300)
end

function OnEventEnd()
    SysCall("ScenarioManager:ShowInfoMessageExt", "Knebworth Trainspotting", "Time to go!", 15, MSG_LEFT+MSG_TOP, MSG_SMALL, TRUE)
    SysCall("ScenarioManager:TriggerDeferredEvent", "Complete", 0)
end

function OnEventComplete()
    SysCall("ScenarioManager:TriggerScenarioComplete", "Finished!")
end


The first block lists a selection of "constants" which are used to make the rest of the code a bit more readable.  You shouldn't ever need to edit these constants but if you start getting more complex with your scripting you may wish to add more to them - you'll know it when you want to!

The first two functions "OnEvent" and "TestCondition" set up a basic system that will make handling events more straight forward, you'll never need to edit these functions.

After this is when we start to get to the bits that are specific to our Rail fan scenario.

The function OnEventstart() is called by the game when our scenario starts.  You'll recall earlier we set up a trigger instruction and put "start" in the field - this is where that happens.  If you put "fred" in that field, then you'd need to rename this function "OnEventfred()" for it to work, whatever you put in that trigger field is what will end up being called in the script.  For simplicity, i'd just leave it as "start".

OnEventstart() locks the controls - you can choose to eliminate this line if you prefer, it just prevents the user from doing anything while you're introducing the scenario.  The next thing it does is to activate a cinematic camera called "startcamera" - you can add cinematic cameras later following one of my other tutorials, I won't go in to details and repeat that tutorial again here.  finally, it uses "TriggerDeferredEvent" to tell the script when to carry on - you should set this up so that it matches the time for your cinematic camera, if it lasts 25 seconds then put a "25" where there is a "17" in this line, it's that simple.  If you get it too short it will simply cut the cinematic camera sequence short.  Once this timeout expires it will call the next function - note the event is "WelcomeMessage" and therefore this leads us to the next function:

OnEventWelcomeMessage() unlocks the controls (if you remove the lock, you can remove the unlock too of course), pops up a message introducing the scenario to the player, activates the "free" camera allowing the player to move freely around the route and then sets up a timer to end the scenario.  This number is in seconds, the example above is 300, which is 5 minutes.  Once this timeout expires it will fire a further event "End" - bringing us to:

OnEventEnd() - this pops up a farewell message and then sets up another deferred event which will happen immediately.  This is just to return control to the game and let it handle the pop-up box.  The event is Complete:

OnEventComplete() will then finally issue a TriggerScenarioComplete system call which will cause the game to pop up the "Scenario Complete!" message box and end the scenario successfully, giving the user their green tick for completing the scenario.

Ok, so there's plenty to go through there and i'd recommend just reading through that description a couple more times until you understand it a bit better.  Remember that as long as you use the same names in future scenarios for things like "start" and "startcamera" you can literally copy/paste this script in to each Rail fan scenario you use and then make just two changes to make the whole thing work.

Change #1 - How long is your cinematic sequence? Set the time for that in OnEventstart(), it's set to 17 in the example above.

Change #2 - How long is your scenario? Set the time for that in OnEventWelcomeMessage(), it's set to 300 (5 minutes) in the example above.

Once the script is done, save it from your text editor and return to the game.  Click the "Reload" and "Compile" buttons and that's all you need to do.  If you find you need to make any adjustments just re-edit the file in your text editor, click the Script button on the toolbar in the timetable mode, click Reload and then click Compile.

Adding AI trains


Add AI trains in the nomal way!

Well.. nearly.  Remember the player train isn't moving, the player is naturally going to be sitting fairly well in the initial environment you set up for them.  Start trains close(ish) to the station so that they go through at the speed you want and work your way out away from the station setting up trains to come in one after the other almost like a parade of trains in a simple presentation.  The moment trains are out of visual sight aim to get them to disappear in to a portal as quickly as possible so that they're no longer in your way or consuming processing time on the computer.  This will also make it easier to set multiple trains to go through as you can just throw them all in to a portal and not have to worry about whether one train is blocking another.

General Tips for a Rail Fan scenario


Don't make it too long or it gets boring, remember the absolute entirety of what is keeping the player interested is those AI trains.  A 5 minute gap, however realistic it might be, can be interminably long with absolutely nothing else happening in the game.  Could you set up something in a nearby yard perhaps with a shunter to keep things moving during quieter times?  Perhaps beef up the timetable and make it slightly "hyper real" in order to keep it interesting.

Find the right place to set your scenario up so that you can acheive the above, you might want to recreate trainspotting at your local station, but if there are really only a couple of trains an hour then it's just not going to hold enough interest for anyone but you.  If you're just doing it for you, that's perfectly fine, but if you want to share it then you have to keep it interesting and put that above all else.

Perhaps use pop-ups to suggest "go to the north end of the platform for a great view" - where should the player actually stand for a good view? Have you any tips on how best they can enjoy this scenario?

Don't forget to get things like the scenario end functionality working, it's really nice to have a scenario actually tell you it is finished and then say "Scenario Complete" rather than leaving the player to wonder if this is just a quiet bit in the scenario or if it's all done now? The script above does this for you and while LUA script might be daunting I would encourage you to make the effort to get it working for you as it ups the professionalism of your rail fan scenarios considerably.

Some of the more interesting scenarios i've seen actually end with an AI train coming in and stopping on the platform that the player is notionally supposed to be on, as the doors open the end message comes up saying that it's time to catch your train and leave - that's awesome!

You can tune where the camera starts at the beginning of the scenario by moving the scenario marker around and placing it in the right place at the right angle.  Experiment to understand how this works and get the best effect.  Some have started it on the platform next to a soon-to-depart AI train (as if you just got off it), or even by a car in a car park.






That's all you need to know, I look forward to seeing your awesome Rail Fan scenarios on Workshop!

I hope this tutorial has been useful, I have a YouTube video to be uploaded soon which goes through all of these steps visually.  Hopefully this blog entry has expanded on what I discussed in the live stream for those who were watching and will help you get the most out of it.

Sunday, 22 November 2015

So you want the TSL In-Game Background music? Here's how.

I've had a lot of requests for the in-game background music that I use on TrainSimLive - it's a chilled instrumental version of the main theme tune and I love how it fits with the games menus etc, so i'm really happy to now be sharing the music and helping you install it.

First note - this tutorial is not a general how-to on how to put your own music in the menus, I have already done all the "hard" work to make this a simple drop-in task so that everyone can do it, if you want to put your own music in then I simply direct you to google for it, I believe there are guides and tutorials put together by others.

Second note - if you are not completely confident copying and pasting files around using Windows Explorer then this is probably not for you.  I've tried to make this as simple as possible but it does involve opening up Windows Explorer doing a rename and pasting a file inside the games core content, if that fills you with chills then I'd suggest you probably should leave the game as is.

Last note - if anything goes wrong with the game you can just do a verify local file cache to restore it.

Ok, installation - the first thing you'll need is the file itself, here - click the link to download  approx 43mb "DAV" file.  DAV files are the audio file format used by Train Simulator and are a properietary variant of the WAV file format.

TSL In-Game Music Audio

Once you've downloaded that it should be in your download folder somewhere - don't ask me where that is, it's different depending on how your machine is set up, what browser you're using and so forth.  For me, they normally just appear in the "downloads" folder that is accessible directly from Windows Explorer.  I'm using Chrome on Windows 10.

Let's find the location the audio file needs to go, fire up Windows Explorer and go to this location if your installation of Train Simulator is in the default location. If it's not in the default location, i'll leave it as an exercise for you to figure out where it is now since I can't predict what you've done :)

C:\Program Files (x86)\Steam\SteamApps\common\RailWorks\Assets\Kuju\RailSimulatorCore\Audio

Inside here you should find a file called:

UI_FrontEndLoop.dav

Rename this to:

ORIGINAL_UI_FrontEndLoop.dav

That way you have a backup and can quickly swap it back if you wish.

Now copy in the file you downloaded (which, conveniently has the right name already!) in to this folder.

Start the game, sit back, and chill :)

Enjoy!

Full credit for the music goes to Duo Astral Plane who did both the main TrainSimLive theme tune music (with vocals) and this instrumental version for the in-game menus.  You can find out more about their work at http://www.astralplanemusic.com/ and I sincerely thank them for their work putting this together!

Sunday, 26 April 2015

Creating Consists via Blueprints for Quick Drive and AI

There are no less than three ways of making consists in TS2015!

The first has been around since the beginning - simply place some vehicles on the track, go to the consist tool and then double click on the grey boxes above the vehicles, you can then give it a name and then re-use it later.  It was a good way to short cut the process for a single scenario but didn't persist between routes so it was of limited use.

Later, Train Simulator added an excellent built-in system for creating your own consists via a user interface in the menu system, which was a big step forwards however these consists still won't appear as AI trains in Quick Drive scenarios.

So how exactly do you create those?

The answer is in the third method - via blueprints.  It's a bit tricky and certainly not easy, but if you can figure out how to create them you may find it preferable since it has some neat ways of re-using sequences over and over that can be a huge time saver... not to mention that any consist you create here can show up as AI in your Quick Drive scenarios too!

Folder Structure

To get started, let's go in to the railworks home folder via Windows Explorer.  On most systems that install to the C: drive by default, that is:

C:\Program Files (x86)\Steam\SteamApps\common\railworks

Inside here, if you don't already have a "Source" folder, create one.

Now you're going to need to decide on a "provider" folder name - this can be anything you like, whether its a nickname, organisation name or your name in some form.  I've got for "MattPeddlesden".

Underneath that you need to think of a product name - so i've just gone for "QDStuff"  but you might want to take slightly more time and come up with something a bit better :)

Lastly, we need to add a folder "PreLoad" (note the capital P and the capital L are important!) underneath that.

When that's all done, you end up with this:

Inside the RailWorks folder you'll find an executable application file called "BlueprintEditor2.exe" - double click it to run, and you'll get a screen something like this:

On the top left pane, titled "Explorer" you can see the Source folder that you created, expand this a couple of times so that your new PreLoad folder is visible.  This is where we'll be doing all our work!

There are two types of consist blueprint within the game, one is the "Consist Blueprint" and these are the ones that result in new options being available in the game.  Ultimately what you do has to end up in new consist blueprints or nothing new will happen.  The other type is a "Consist Fragment Blueprint" and these are used to keep re-usable sequences, for example you could have a sequence of 40 wagons or a 12 passenger coaches and then later create a bunch of new Consist Blueprints by simply having a different loco plus the 12 coach fragment - two simple entries and an easy way to rapidly create some great variety.

We're going to start by creating the Consist Blueprint, get them working and then we'll almost immediately see how Fragment's will be useful - so we'll get one of those created and use it.

Consist Blueprints

Right click on the PreLoad folder and select Add, followed by New Item.

From the list that pops up, select "Blueprint" from the left side and "Consist Blueprint" from the right hand side.

Name it something sensible so that you can easily find it later.   The filename isn't used in-game but it is always useful to be able to work out what files contain what.  Since i'm planning on just making this a quick test, i've just gone with a simple name, later on we'll delete this once we get the hang of it and start doing it properly!

Click Ok and the new blueprint will be created.


There are a number of different sections to this file so let's take them one at a time as an overview first, and then we'll drill in to them to get it set up.

Consist Entry
This defines the actual vehicles that are in the consist.  A consist does not have to contain any locomotives, but it must have at least one of something of course!  If it has no locomotives, note there is a setting later that must be ticked to say it's not drivable.

Loco Name and Display Name
In the Quick Drive selection screen you have a list of locomotives, and then when you click on one you have a list of consists.  Let's look at a couple of screenshots that i've taken from the game, where I have highlighted the key sections.



Where i've highlighted in GREEN, this is the "Loco name" field.  Where I have highlighted in RED, this is the "Display Name" field.

If I create a new consist where the Loco Name is "A loco" then it will create a new entry in the grid in the first screenshot called "A loco".  If I call it the same as something else, e.g. "GE U36 SBD" then my consist will end up being one of the selections inside that.  What it means is that if you simply want more consist variety for a particular loco you can do so without polluting this already quite busy list with a lot of duplication.

The Display Name field should be used to describe the specific consist (e.g. "2+1+1 with 150 car manifest" or "12 Coach Mark 3 Passenger Blue Greys".  When someone clicks on the loco entry in the grid of the first shot, they get the list of consist display names that were found using that "loco name" (which again could be from lots of different places, it very handily merges them all in to one list).  You may choose to duplicate the "loco name" component for clarity, or you may choose not to - personally I don't duplicate it.  Once selected, the "display name" is shown in the right hand half of the current selected consist - top of the list of three boxes.

It's a little confusing at first, but once you get the hang of the naming system you'll find it does exactly what it needs to.

Engine Type
Straight forward - if this is a driveable consist what kind of lead loco is it? This is used for filtering.
If it's not driveable, it doesn't matter what you set this to as it won't be offered in a filterable lists.

Era Start Year and Era End Year
Note: There is currently a limitation in the game whereby if this doesn't include 2014 it won't be used, so for the time being I'd recommend leaving this at the defaults.
The intention of these options is to say what rough years this consist would have operated in.  When you define a Quick Drive scenario template, you can specify what year the template is relevant for and this will then influence which consists appear.  This means you can set up a 1950's Quick Drive that only features era-appropriate stock for instance.

Driving Engine Index
Where in the consist is the driving engine that the player will be sat in?  Normally this is 0 - the lead locomotive.  But if you have something like a Cab Forward or Big Boy then it might be further in the train.  0 is the front, 1 is the next rail vehicle in and so forth.

Valid Build and Drive Routes
This lists all of the valid routes that this consist can appear on, it's a list of route GUID's, and this is the way that the sim prevents SD70M's from appearing on ECML London to Peterborough, for example.  This does not affect the choice the player has, you might say this US freight consist is only good for a set of US routes but as a player, I can still choose to drive it on ECML London Peterborough if I wish - but I won't see it as AI.

Drivable Consist
Tick this box if it is something the player can drive, untick it if it is simply a list of wagons.  Consists that are just a variety of wagons and lengths of consists etc are great to have because they'll appear as "static consists" which will fill up your yards in Quick Drive's.

Consist Type
This one is crucial, it defines what kind of consist this is and is what will make it available to appear as an AI train.  Set this to something appropriate for the consist from the list.  You could choose also to make use of the additional "custom" types, these allow you to specify additional types of consists that have not been catered for already.  When someone sets up a Quick Drive scenario template they define the various AI start points and what the chances of a particular type of consist appearing, this is where you link particular types of consists to specific consists, locomotives and rolling stock.

Has Pantograph, 3rd Rail, 4th Rail
These ones are used as an additional AI filter. When an AI spawner is set up in a Quick Drive template scenario, it has some tick boxes saying whether this spawner is suitable for rail vehicles that have pantographs, or 3rd/4th rail pickups.  Simply tick these boxes to reflect the real requirements of this consist and the system will ensure you don't get overhead electric trains driving on 3rd rail electric routes (as long as it's all set up correctly of course :) ).

Setting Our First Consist Up

Now that we've looked at the options, let's get the first consist set up.  For this consist i'm just going to drop in a CSX SD40-2 followed by two wagons, just to keep it simple and show a couple of extra steps off.  We're also going to set it up so that it can appear as an AI train in Quick Drive scenarios.

First we need to add the vehicles.

Expand the "Consist Entry" section and click Add Element.

Expand the new entries that appear so that you can see it completely, it looks like this:

The CSX SD40-2 is part of the New York New Haven route, so the Provider should be set to "RSC" and the Product to "NewYorkNewHaven".  These are the same names as you would tick when adding the item to make it available in a regular scenario, and are the same as the folders under the Assets folder - take some time to have a browse and get familiar so that it will be easier to find what you're looking for.

This next step is where it gets a little hairy if you're not familiar with how locomotives are structured on your hard drive!

Assets, AP files and Other Complexities...

Before going any further I wanted to just outline how files are stored a little bit, just to give you a head start.  Assuming the install for your TS2015 is here:

C:\Program Files (x86)\Steam\SteamApps\common\railworks

Then all the rail vehicles and other assets are stored here in the assets folder.

C:\Program Files (x86)\Steam\SteamApps\common\railworks\Assets

Beneath that is the provider folder, then the product folder.  So if what we're looking for is RSC and NewYorkNewHaven, then our path for its assets is:

C:\Program Files (x86)\Steam\SteamApps\common\railworks\Assets\RSC\NewYorkNewHaven

If you go there however you'll find just an AP file (and possibly a PAK file, but ignore that!).  An AP file is basically the same as a ZIP file and can be opened in something like 7-zip.  Opening it, you will find a further series of files and folders.  If it's a route AP file (as this is) then you'll find quite a lot in there, if it's just a loco pack then there are fewer folders.

Rail Vehicles are  in the "RailVehicles" folder and from there the separation is usually fairly intuitive.

Continuing where we left off...

The Blueprint ID is the pathname and filename of the blueprint for the rail vehicle we want to add.  In this case the files are in an AP file - so open this with 7-zip (or your favourite ZIP explorer) and we find that the diesel locomotive we want can be found here inside the AP file:

RailVehicles\Diesel\SD40-2\Default\Engine\

Tip: a .ap file is just a renamed .zip file, so it should load fine in any ZIP tool.  Personally I use 7-zip as it's fast and free - you can download it from www.7-zip.org

Inside this folder are a bunch of files, the ones we are looking for are .bin files and in this case there are two - the one we want is sd40_2.bin - for the purposes of our consist, we will put "xml" instead of "bin" though.

This means that the final blueprint ID will be:

RailVehicles\Diesel\SD40-2\Default\Engine\sd40_2.xml

Even though the file itself is actually a .bin file, the game will look for both the .xml and .bin files, but as the blueprint editor is intended to work with source files, it must have the xml file.  If that doesn't make sense, don't worry, just go with it :)

The last option "Flipped" will flip the vehicle around so that it faces the other way.  We'll leave it as it is for now.

Ok, so this is where we're at now:


At this point it's worth answering a couple of questions you might be thinking about...

Can I use vehicles from lots of different provider/product's?
Yes, as many as you want, you can mix a "Marias Pass" loco with a "Miami West Palm Beach" wagon and a "New York New Haven" wagon if you want!  Just remember that the more you add, the more the game will have to load, since it loads the entirety of a provider/product when it accesses any part of one.

Do I need to unpack the AP file?
No, leave it exactly as it is.

That's the first entry on the consist done.  Let's add a couple of wagons - click the Add Element button again.

We'll add a wagon from the same route just to make things easy, set up the same Provider and Product as before.  Navigate back in to the AP file for New York New Haven and we can see that there are a number of wagon types, i'm going to go with the box car, so our blueprint folder is:

RailVehicles\Freight\BoxCar\Default\Wagon\

Inside here, there are a number of bin files, but two of them are the bogie definitions, leaving one which refers to the wagon itself.  Don't forget to change "bin" to "xml" for the blueprint ID, meaning our Blueprint ID is therefore:

RailVehicles\Freight\BoxCar\Default\Wagon\box_car.xml

Let's see how our consist is looking now:

With everything you've just done, you can imagine setting up a 120 wagon consist is going to start getting hard work!  Assuming you're repeating items however, there is a short cut to make it a bit easier so the second wagon we add is going to just be the same as the first.

Click the Add Element button and expand everything out again, as if we were going to do it the same way we did the first one.

Now right click on the "Consist Entry" header of the FIRST wagon we added and select Copy. Now right click on the "Consist Entry" header of the NEW entry we just added (the one that is currently blank) and select Paste.  That's the second wagon done, much easier.

Now that the rail vehicles themselves are done, let's go through the rest of the blueprint.

Loco name - let's make it the same as the existing Sd40-2 so that it simply adds to the list, which means it needs to have a Loco Name of "EMD SD40-2" - it is again essential that capitalisation matches.

Display Name - our consist is simply a couple of box cars so let's call it "2 Box cars".

Engine Type - Diesel.

I'll leave the era start and end years as they are.

Driving Engine Index we will leave as 0.

Valid Build and Drive Routes
For this, click the Add Element button and it will add a "Consist Valid Route" entry with a "Route GUID" entry.  What you need to know now is what the GUID's are for the routes you want to add it to. I found an excellent post on the Steam Forums which lists all the routes (and many freeware routes) and their GUID's, you can find it here:

http://forums.steampowered.com/forums/showthread.php?t=3257269

Simply paste one Route GUID in to the entry box to enable this consist to appear as AI on that route.  Let's add New York New Haven.
And then click Add Element again, and add the GUID for Miami West Palm Beach, so we now end up with:


This means that our consist can now randomly appear as an AI consist on quick drives that happen on these two routes, but it won't appear on any others.

Drivable Consist - this is drivable, so tick the box.

Consist Type - there really isn't an ideal type in this box so i'm going to set it to Freight - Container.  As I mentioned earlier, this relates to how the quick drives themselves are set up.  You pick anything - this could be a "freight livestock" if you want, and then if you give "freight livestock" a chance of showing in the quick drive it will all simply work.  Choosing a reasonably appropriate one just helps you create QD's that make sense and try to have the right trains in the right places.  If you find there aren't any appropriate options then you can use one of the "custom" options but again, these are no good unless the QD itself offers a chance of the same ones appearing.   If you're creating the consists  AND the quick drives then that's ideal and you can create something really nice.

I would recommend that if you create a quick drive, you should document the types of consists you've used and their chances of appearing, that'll help anyone making new consists to ensure that they use the right types.

The last three settings relate to electric trains, if this was an ACS-64 then I would tick the "has pantograph" button but as it's a diesel, I will leave them all unticked.

That's it - our first consist has been created.

Press CTRL-S to save it (or go to the file menu and click Save).

It's important to double check all of the entries you've typed in, the process of exporting will not check to make sure you have put the right paths in because to do that you need the full asset source.

In the "Explorer" section where your new blueprint consist file is, right click on the file and select "Export" followed by "Export This Only".  It's important to choose "Export This Only" because this option will not try to export anything else - and since we don't have the source for the locomotive and wagons that's a good thing!  If you do have all the source because you're actually making the stock yourself then just export as normal and it will error check everything properly as it goes.

Now let's go in to the game and test it!

Once in the Quick Drive section, find the EMD SD40-2 entry and then see if your consist is present.  If it is that's the first win.  Select it and enter the quick drive.  If it loads and then errors right at the end, it means one or more of the entries you've added for the blueprint id's or provider / products is incorrect - check it.  You might get some help by enabling logging (detailed in an earlier blog post).

Once all is working you should now be in the game driving the consist you just made!

That's all you need to get started, you can now make any consist you like - but making a consist that has the same 120 wagons but one of 5 different loco's at the front would currently either mean duplicating that 120 wagons five times.  Nightmare!  This is where Consist Fragments come to the rescue in a big way!

In the same way we created a Consist Blueprint, you can create a Consist Fragment blueprint.  I would strongly suggest a naming convention on the filenames so that fragments are easily identifyable, you could also put them in a sub-folder.  I would suggest a prefix like "F-" or "Fragment-" just to be clear.

Inside the fragment blueprint is just the section of consist entries, so all those blueprint id's, providers, products etc and nothing else.  You could make up a set of say 20 container wagons here or a 5 car passenger train (just the coaches).

Having saved and exported the fragment you can now use it in the main Consist Blueprint - set the provider and product to your provider and product (e.g. MattPeddlesden and QDStuff for my test example here) and then the blueprint ID simply points to the fragment.  There is, however, a nice easy way to do this!

Open the Consist Blueprint you want to use the fragment in and add an element where the next wagon should be placed.

Right click on the Fragment filename in the Explorer pane, select Copy.

Now expand the blank consist entry and right click where it says "blueprint name" - and click Paste.

The Blueprint editor is clever enough to know how to interpret the location of the blueprint you copied and fill in all the blanks for this consist entry!  That's the fragment added.

So if you defined say 10 coal cars, 10 auto racks, 15 low gons etc you could then add half a dozen different fragments and end up with a 100 car manifest train and still have a bunch of fragments you can chop and change around and re-use in other consists.

The other really nice thing about this reusability is that if, later, you find a better coal car, you can simply open each fragment that uses it and swap in the new car - and all of the consists which use those fragments will automatically reflect the changes.

It's been a long journey but we got to the end at last :)

In summary...

  • You need to create a consist using the Blueprint Editor.
  • You should create Consist Fragments for the commonly re-used portions.
  • You should create Consist Blueprints to actually define the final consists.
  • You can mix and match fragments and actual items of stock as much as you want.
  • You can pull in stock from lots of different provider/products if you want.
  • Set the consist type and valid routes to enable the consist to be seen in Quick Drive's as AI traffic.
  • Set the Loco Name of the consist to chose what loco name it shows up as when a player is picking from the list, and I'd recommend you try and add your consists to existing loco name entries so that the list does not get bloated.
  • Set the Display Name to represent what is unique about this consist, what actually is it.
  • You can set up consists with only freight cars / wagons / coaches if you want, make sure not to check the Drivable box for these, but make sure you do set the valid routes and consist type and then they should show up as static items placed in yards and so forth.
  • Do keep your own consist definitions in your own provider/product, it makes it easier for someone to update, remove etc than if you splat yours all over the main ones.

I look forward to seeing what you all do with this exciting feature :)

If you missed my video on creating quick drive scenarios then you can find it here on YouTube:

https://www.youtube.com/watch?v=uTSwEuWPZH8












Saturday, 25 April 2015

New Post Coming Soon

Just a short entry to say that this blog has not been forgotten :)

I recently did a tutorial on how to define your own Quick Drive scenario templates and there are a couple of topics that came out of it which are best served by a tutorial on here covering them in more detail.

Once i've got something written i'll get it posted up - hopefully in the next couple of days.

If there are topics you'd like to see covered then please do leave a comment and let me know, i'm struggling for things to say in the blog to be honest!

Sunday, 22 February 2015

TS2015 - Scenario Scripting in LUA Part 13 - Example Script

I've had a couple of requests to put the entire script from the YouTube video tutorial up so that it can be reviewed and understood in its entirety - so without further delay, here it is!

Note that I didn't use some of the techniques discussed here such as the _G[]() idea because the goal was to be quick and simple, but using this and the learnings in previous blog posts you should be able to use this in an effective way.

-- true/false defn
FALSE = 0
TRUE = 1

-- condition return values
CONDITION_NOT_YET_MET = 0
CONDITION_SUCCEEDED = 1
CONDITION_FAILED = 2

-- Message types
MT_INFO = 0 
MT_ALERT = 1 

MSG_TOP = 1
MSG_VCENTRE = 2
MSG_BOTTOM = 4
MSG_LEFT = 8
MSG_CENTRE = 16
MSG_RIGHT = 32

MSG_SMALL = 0
MSG_REG = 1
MSG_LRG = 2

function DisplayRecordedMessage( messageName )
  SysCall("RegisterRecordedMessage", "StartDisplay" .. messageName,  
      "StopDisplay" .. messageName, 1);
end

function StartDisplayIntroText()
  SysCall ( "ScenarioManager:ShowInfoMessageExt", "Title of the box",  
      "intromessage.html", 0, MSG_VCENTRE + MSG_CENTRE, MSG_REG, TRUE );
end

function StopDisplayIntroText()
end

function StartDisplayMoving()
  SysCall ( "ScenarioManager:ShowInfoMessageExt", "You're off!", 
      "moving.html", 0, MSG_VCENTRE + MSG_CENTRE, MSG_REG, TRUE );
end

function StopDisplayMoving()
end

function StartDisplayOverspeed1()
  SysCall ( "ScenarioManager:ShowInfoMessageExt", "Too fast!", 
      "overspeed1.html", 0, MSG_VCENTRE + MSG_CENTRE, MSG_REG, TRUE );
end

function StopDisplayOverspeed1()
end

function StartDisplayOverspeed2()
  SysCall ( "ScenarioManager:ShowInfoMessageExt", "Final warning!", 
      "overspeed2.html", 0, MSG_VCENTRE + MSG_CENTRE, MSG_REG, TRUE );
end

function StopDisplayOverspeed2()
end

function OnEvent(event)
  if (event == "introtext") then
    DisplayRecordedMessage("IntroText");
  end
 
  if (event == "cinematic") then
    SysCall ( "CameraManager:ActivateCamera", "introcinematic", 0 );
  end
 
  if (event == "cabcamera") then
    SysCall ( "CameraManager:ActivateCamera", "CabCamera", 0 );
  end

  if (event == "startmovingcheck") then
    SysCall ( "ScenarioManager:BeginConditionCheck", "StartMovingCondition" )
  end
 
  if (event == "startoverspeedcheck") then
    SysCall ( "ScenarioManager:BeginConditionCheck", "OverspeedCondition" )
  end
 
  if (event == "starttoofastcheck2") then
    SysCall ( "ScenarioManager:BeginConditionCheck", "OverspeedCondition2" )
  end
 
  if (event == "starttoofastcheck3") then
    SysCall ( "ScenarioManager:BeginConditionCheck", "StopCondition" )
    SysCall ( "ScenarioManager:BeginConditionCheck", "OverspeedCondition3" )
  end
end

function TestCondition(condition)
  if (condition == "StartMovingCondition") then
    speed = SysCall ( "PlayerEngine:GetSpeed" );
    if (speed > 0.89) then
      DisplayRecordedMessage("Moving");
      return CONDITION_SUCCEEDED;
    end
    return CONDITION_NOT_YET_MET;
  end
 
  if (condition == "OverspeedCondition") then
    speed = SysCall("PlayerEngine:GetSpeed");
    if (speed > 8.904) then
      DisplayRecordedMessage("Overspeed1");
      SysCall ( "ScenarioManager:TriggerDeferredEvent", "starttoofastcheck2", 5 );
      return CONDITION_SUCCEEDED;
    end
    return CONDITION_NOT_YET_MET;
  end
 
  if (condition == "OverspeedCondition2") then
    speed = SysCall("PlayerEngine:GetSpeed");
    if (speed > 8.904) then
      DisplayRecordedMessage("Overspeed2");
      SysCall ( "PlayerEngine:SetControlValue", "Regulator", 0, 0);
      SysCall ( "PlayerEngine:SetControlValue", "TrainBrakeController", 0, 1);
      SysCall ( "PlayerEngine:SetControlValue", "VirtualThrottle", 0, 0);
      SysCall ( "PlayerEngine:SetControlValue", "VirtualBrake", 0, 1);
      SysCall ( "ScenarioManager:LockControls");
      SysCall ( "ScenarioManager:TriggerDeferredEvent", "starttoofastcheck3", 5 );
      return CONDITION_SUCCEEDED;
    end
    return CONDITION_NOT_YET_MET;
  end
 
  if (condition == "StopCondition") then
    speed = SysCall("PlayerEngine:GetSpeed");
    if (speed < 0.1) then
      SysCall("ScenarioManager:UnlockControls");
      return CONDITION_SUCCEEDED;
    end
    return CONDITION_NOT_YET_MET;
  end
 
  if (condition == "OverspeedCondition3") then
    speed = SysCall("PlayerEngine:GetSpeed");
    if (speed > 8.904) then
      SysCall ( "ScenarioManager:TriggerScenarioFailure", 
          "I give up, you're out of here! Too much fast driving! - DarknezzMonster" );
      return CONDITION_SUCCEEDED;
    end
    return CONDITION_NOT_YET_MET;
  end
end
 




Saturday, 21 February 2015

TS2015 - Scenario Scripting in LUA Part 12 - Video

Apologies for the long time between articles!

In this article i'm going to show you how to incorporate videos in to your scenarios, done correctly they can really elevate your scenarios to a completely different level.

The overall API for playing videos is almost identical to the API for playing sounds - so if you haven't yet read the previous blog post on the subject then now would be a great time to do that.

At the top of your LUA script file you're going to want to drop in some definitions, just to make the rest of the script a bit easier to read:

FULLSCREEN = 0
FRONT_AND_CENTER = 1
CALL = 2

FALSE = 0
TRUE = 1

NO_CONTROLS = 0
PLAYPAUSE = 1
STOP = 2
SEEK = 4

Note: You may already have FALSE and TRUE defined, in which case there's no need to duplicate them here.

The calls to handle videos are as follows:

Start a video playing:
SysCall("ScenarioManager:PlayVideoMessage", "2013_startup.ogv", FRONT_AND_CENTER, FALSE, NO_CONTROLS,0)

Check to see if a video is playing:
SysCall("ScenarioManager:IsVideoMessagePlaying", "2013_startup.ogv")

Stop a video from playing:
SysCall("ScenarioManager:StopVideoMessage", "2013_startup.ogv")

Let's put it in a small example to provide some context:

function OnEvent(event)
  _G["OnEvent" .. event]();
end

function OnEventStart()
  SysCall("ScenarioManager:PlayVideoMessage", "2013_startup.ogv", FULLSCREEN, FALSE, NO_CONTROLS,0)
end

Here, i'm defining a trigger event "Start" (which should be initiated from a Trigger instruction in the scenario definition) and this will play a video, full screen.

Just as with audio, the call to play a video will return immediately and let the video carry on playing in the background, that's the main reason for the "IsVideoMessagePlaying" and "StopVideoMessage" calls.  I'll show them in action in a moment.

Parameters

There are a number of parameters to the PlayVideoMessage function that are interesting.

After the Filename, the next one tells the game how and where you want the video displayed.  The options are Fullscreen (0), Front and Center (1), and Video Call (2).  I've defined some constants above so that it's easier to see what it is doing rather than passing plain numbers in (never do that, trust me!).

Full Screen puts the video full screen, just as it says it will.  It will also include an X in the top right that allows the player to abort playback of the video if they wish.  In the screenshot below you can see it has completely filled the game screen.

Full Screen Playback
Front and Center gives you a video playback which does not fill the screen and therefore allows some context from within the game to still be seen, but it is meant to still command the users attention fully and is of sufficient size it can still contain some detail.
Front and Center Playback
Finally, Video Call is intended to show in the top left corner somewhat like if you had a video call going on with someone.  You could use this for giving brief snippets of information, perhaps a news bulletin about something that's just happened (based on the players action) or something similar.
Video Call Playback


The next option is either TRUE (1) or FALSE (0) and this tells the game whether to pause in-game action or leave it running.  If you're going to get in the way of the user such as a full screen video then I'd suggest pausing the game is a good idea.  If it's a video call, then you probably don't want to pause it so that it feels more like something that is happening as part of the game play.

The next option tells the game what kinds of controls to put on the video, do you want them to be able to pause it? skip to a particular bit? or stop it?  There are four constants defined for this in my example.  NO_CONTROLS (0) means show nothing, and is used in all the above three screenshot examples.  PLAYPAUSE (1), STOP (2) and SEEK (4) add the relevant controls that you would expect.  If you want to add more than one control, simply add them together like this:

SysCall("ScenarioManager:PlayVideoMessage", "2013_startup.ogv", FRONT_AND_CENTER, FALSE, (PLAYPAUSE+STOP+SEEK),0)

This would give you something like this::

Front and Center with all controls enabled along the bottom of the video
The final parameter is always a zero.

Format

The format of the video is an Ogg Vorbis ".ogv" video.  You will need to create your video and export it in some format using your preferred editing tool and then if it won't export to Ogv then you'll need to use an additional step to convert it.  As a reference example, the 2013_startup.ogv used as part of the start-up sequence of the game is in the correct format.  You can use this to confirm you're calling the video correctly and it is working, and then drop your own video in afterwards.  You can find this video in the data\videos folder.

I use FFMpeg2Theora to do my conversions, available here, once installed you can run it with this command line to get the right format:

ffmpeg2theora-0.29.exe myvideo.mp4 -vcodec libtheora -acodec libvorbis -v 10

Here i've used an mp4 video because that's what I exported from my video editing suite, the result will go out as myvideo.ogv .

The number at the end is the quality level, 10 is the maximum and reducing it can make a huge difference to the file size - as well as a huge difference to the quality.  You will likely find that you can drop it down one or two settings before you even notice a difference and then it will drop off quickly.  Find that right setting for your video that means you can get the file size down as far as possible while still remaining good quality.

Place the videos in the localised language folder, the same as the audio files.  So this would be in the "en" folder for English users, for example.

Bigger Example

So here's a bigger example showing how you can use conditions to work out when to continue with the scenario.

function OnEvent(event)
  _G["OnEvent" .. event]();
end

function TestCondition(condition)
  _G["TestCondition" .. condition]();
end

function OnEventStart()
  videoPlaying = SysCall("ScenarioManager:IsVideoMessagePlaying", "2013_startup.ogv")
  if (videoPlaying == TRUE) then
    SysCall("ScenarioManager:StopVideoMessage", "2013_startup.ogv")
  end
  SysCall("ScenarioManager:PlayVideoMessage", "2013_startup.ogv", FULLSCREEN, FALSE, NO_CONTROLS,0)
  SysCall("ScenarioManager:BeginConditionCheck", "HasItStoppedYet")
end

function OnEventNextStep()
  SysCall("ScenarioManager:ShowInfoMessageExt", "Get moving", "moving.html", 10, MSG_TOP + MSG_TOP, MSG_SMALL, TRUE);
end

function TestConditionHasItStoppedYet()
  videoPlaying = SysCall("ScenarioManager:IsVideoMessagePlaying", "2013_startup.ogv")
  if (videoPlaying == FALSE) then
    OnEventNextStep()
  end
end

This example is somewhat contrived to try and fit a few different things in to a small space but it should give you the "snippets" to do what you want to do.

In the scenario instructions we're triggering "Start", which ultimately calls OnEventStart().
In OnEventStart() we find out if the video is currently playing and if so, we stop it.  It's highly unlikely that would be the case here, but normally you might find a place where there's a chance a video is already playing and now as a result of a more gameplay based event you need to play a video so the first thing you do is make sure that nothing else is playing first.
We then kick off playing our video, and then finally start a condition check called HasItStoppedYet.

The game will now play the video, and while the user is enjoying this video the game will now be calling TestConditionHasItStoppedYet over and over again, each time it will find out if the video is currently playing.  At some point this is going to return FALSE because our video finally finished playing and when this happens we manually trigger another event NextStep.

When OnEventNextStep runs, it displays a message to the user, presumably saying "right, now get moving".  Had you just tried to put the message box up, it would have appeared over or simply interrupted the video.  In this way, you remain fully in control of when things are presented to the user.