Now that Pete showed me the light called scenario-specific signal objects, I cannot hold back the top half of the ideas floating around in me for years.
The basic idea is this: The scenario author places bespoke objects next the track, and the track link(s) on the track, just like signals. These objects talk to signals and modify their behaviour. Or they do other nice things. Since these objects are specific to a certain scenario, they can give signals information about what is going on that they dearly miss otherwise.
Unless otherwise noted, the blueprint setup is as follows.
- In some 3D editor, create a small quad that is a metre underground. I.e., the quad is 1 metre below the object of the origin. Export to IGS.
- Create a simple object that somehow represents the functionality. E.g., a double-sided quad with something written on. E.g., on a return point marker, you could put "return" or put some U-shaped arrow. But the quad on a post if you like. I make these things 1 m wide so they look ok in the six-foot. They will only be seen in the editor, so visuals are not critical, but they should help the authors remember what they did there. Export to IGS.
- In Blueprint Editor, create an Editor shape blueprint. That is scenery only seen in the world editor, like scenario markers, but without a built-in function, of course. The IGS is the second of the both above. Keep Category at Uncategorised. Export and save.
- Then create a Signal blueprint with the first IGS above. Set Category to Track Infrastructure. Set Valid in scenarios (just below) to True.
Unless specified otherwise below, the number of track links is one and Stopping is false. Script is one of those given below.
Make the blueprint created above a child of this blueprint. This results in a quad 1 m below ground shown all the time and the descriptive object shown in world and scenario editors only. Export and save.
Things you can use right nowPlease consider the code below beta. I can't test it now in the version presented here, but it is all proven stuff from various unfinished works of mine.
Suppress initial clearing of signalYou start a train at a platform that has a starter at both ends and you hate to see them both clear.
Place this object between the train and the starter that should stay at red, track link pointing to signal.
1 track link, Stopping=false. Script:
- Code: Select all
--------------------------------------------------------------------------------------
-- Do nothing but suppress INITIALISE_TO_PREPARED
--------------------------------------------------------------------------------------
function Initialise ()
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
end
function OnSignalMessage( message, parameter, direction, linkIndex )
-- Forward each message, except INITIALISE_TO_PREPARED
if ( parameter ~= "DoNotForward" and message == INITIALISE_TO_PREPARED ) then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
INITIALISE_TO_PREPARED = 3
function GetSignalState( )
return Call( "GetNextSignalState", "", 1, 1, 0 )
end
Returning pointYour train is returning from an intermediate stations and you hate to the starter clear for travelling further on.
Place this object where the train comes to a halt, track link pointing into original direction of travel before returning.
1 track link, Stopping=false. Script:
- Code: Select all
--------------------------------------------------------------------------------------
-- Suppress preparation messages. When train stops, send SIGNAL_PREPARED_VISIBLE backwards.
-- Does nothing for trains starting on it and for trains in the opposite direction.
--------------------------------------------------------------------------------------
function Initialise ()
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
-- Train is on link
if frontDist < 0 and backDist > 0 then
-- We haven't done anything yet for this train and it is approaching from the right side
if interestingTrain then
local speed = Call("GetConsistSpeed")
-- Define standing as 0 m/s plus a bit of random quivering seen in standing consists
if speed < 0.05 then
-- we are done with that one
interestingTrain = false
-- send preparation message back to signal for other direction, parameter 1 could be tuned to receiving signal
Call( "SendSignalMessage", SIGNAL_PREPARED_VISIBLE, "1", -1, -1, linkIndex )
end
end
-- Train is not on link, but is approaching from the "normal" side
elseif frontDist > 0 and backDist > frontDist then
interestingTrain = false
end
end
function OnSignalMessage( message, parameter, direction, linkIndex )
-- Forward each message, except all the preparation messages
if ( parameter ~= "DoNotForward"
and message ~= SIGNAL_UNPREPARED
and message ~= SIGNAL_PREPARED
and message ~= SIGNAL_PREPARED_VISIBLE
and message ~= SIGNAL_TYPE_CONTROL_APPROACH_RED
and message ~= SIGNAL_TYPE_CONTROL_APPROACH_FLASHING_YELLOW
and message ~= PASS_OFFSET + SIGNAL_UNPREPARED
and message ~= PASS_OFFSET + SIGNAL_PREPARED
and message ~= PASS_OFFSET + SIGNAL_PREPARED_VISIBLE
and message ~= PASS_OFFSET + SIGNAL_TYPE_CONTROL_APPROACH_RED
and message ~= PASS_OFFSET + SIGNAL_TYPE_CONTROL_APPROACH_FLASHING_YELLOW ) then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
function GetSignalState( )
return Call( "GetNextSignalState", "", 1, 1, 0 )
end
AI-only signalYou got an unsignalled yard and you want more than one AI move about it it, or you want to stop the dispatcher from changing switches under the train.
Signal it using these signals - as far as required in your scenario.
Stopping = true! Track links to taste (3 track links for a diversion into two branches).
The following script does absolutely nothing. But the dispatcher will see signals and benefit from your link placement.
- Code: Select all
--------------------------------------------------------------------------------------
-- Do nothing, but don't block the message passing.
--------------------------------------------------------------------------------------
function Initialise ()
end
function OnConsistPass ( prevFrontDist, prevBackDist, frontDist, backDist, linkIndex )
end
function OnSignalMessage( message, parameter, direction, linkIndex )
-- Forward each message
if ( parameter ~= "DoNotForward" ) then
Call( "SendSignalMessage", message, parameter, -direction, 1, linkIndex )
end
end
function GetSignalState( )
return Call( "GetNextSignalState", "", 1, 1, 0 )
end
Further uses of the single link version of this signal:
- Defy undue rule 39 applications. AI loves to loose time at signals when the second or third block ahead is occupied. But 1 to 3 of these dummy signals at each signal where this disturbs your plans and the dispatcher will see the same number of additional clear blocks.
Put these signals on the approach side of link 0(i.e., "before" the signal). Put them close to each other - when the real signal shows red, the AI will stop at each of these dummy signals, inching along mysteriously. You only notice this if there is enough distance between these stops. - Get two trains into the same block. You can add block separations using this signal. This can lead to permissive block working with AI, but beware that AI may stop in the middle of the block at the invisible signal if the second half is occupied. Slowing down at each invisible signal should not be as much of a problem since you run slow anyway. Just the opposite - better distribute invisible signals evenly as AI will speed between them as if under normal block working.
Don't say I lured you into coupling to an AI train or stuff like that. Last time I tried, I got very exciting visuals, but nothing satisfying. - Depending on how you set things up, you may use one such signal in approach to a "broken down consist" which you are going to rescue.
Random delays in signal clearingFor the player train, where you don't see the AI ahead anyway, it can increase the continued value of a scenario to clear some signals at different delays. Of course, you would no do it for all signals and you would devise maximum delays. But getting a yellow here and there that they did not get last time they ran the scenario is something many people dream of.
Implementing that with the default signal is a bit tricky because of the design of their scripts. You must remember the issue with AWS and late clearing anyway. So I would not be too bold in proposing much, but basically, you would start a timer for a random duration when you receive a preparation message and forward it only after the timer completed. Timers are simply implemented by adding up parameter time in function Update.
You could also delay OCCUPATION_DECREMENT from the signal in advance. This has the advantage that you can place the delaying signal objects beyond the signal that is delayed, which is on the open route for starter signal. It is much more realistic for those to be delayed, but a late arrival of the preceding train in the distant station ahead. On game start-up, this object would send OCCUPATION_INCREMENT back, simulating block occupation without the need of a preceding train.
The important bit for me is to keep these objects out of the loop of AWS and the like so my invention does not get associated with the working or not-working of these things. So a stretch of plain track is the best place for them.
Helpers for improved signalsThe following objects only make sense together with signals that make use of their assistence. While you will say that many of these objects should be placed permanently as needed - and this is true - permanent signals have a fixed value in the Identity field and you need to put scenario-specific content there. So you will find yourself placing some of these objects at the same place in several scenarios, but with a different ID causing different signalling sequences.
Switching between shunting and running movementsFor starters with subsidiary signals, it is impossible to decide what to show because the path ahead is used for both departing and running around the train or doing some other shunting move. This is more common on the continent, but still an issue in UK.
You could place an object next the starter that tells it what to show when. Specific parameters could be written into the Identity field in the signal properties - invisible signals don't need a signal plate anyway. E.g., 201 would mean that the first train does two forward shunting movements before departing, the second none, the third one.
A more advanced version of this object would not only tell the signal ahead, but also the signal for the opposite direction ahead what will happen. This would reduce the number of helper objects a scenario author needs to place. In the ID, you would (instead of the digits in the previous paragraph), specify for each time a preparation message occurs, where this will be a) a running movement, b) a shunting movement not returning, c) a reversing shunting movement over the switches ahead, d) a reversing movement over the switches in rear, not bothering the signals in advance at all.
Foretelling AI movementsAI trains waiting at junctions start moving when the switches start to change over. This is 2 seconds before the signal has a chance to know the new path. Placing a prompting object next to them can tell the signal which path the AI will take in this single case, so the signal can display the aspect for the path that will be set in a few seconds, just in time before AI starts to move.
Wrong line workingTo implement the UK style of setting the semaphore at the right track for a train on the wrong track, you need a two-link object. Link 0 in the wrong track, link 1 in the right track, in approach to each signal. When link 0 receives train preparation messages, they are forwarded at link 1, causing the main signal to clear. As the train passes, a preparation message is sent from link 0 and SIGNAL_UNPREPARED is sent from link 1 causing the main signal to reset.
However, this does not work for junction signals. Those will refuse to clear while the path is not set for them (and it will not be set, certainly not where the train changes back from the wrong to the right track). So you need a new message "force clear" which is sent from link 1 of this signal object and modified main signals obeying to this message, even if the path is not set for them.
Influencing signal reset timingSometimes you want a certain semaphore to reset later. Place a "reset here" object somewhere. It will tell the real signal to wait with reset and later send a message "reset now", when the train reaches it. (You are right in saying that this would not be placed scenario-specific.)
Foretelling train typeIn many signalling schemes, CLS show a specific aspect when a train with cab signalling should ignore them. The signal must know this, of course, and there is no way to send a message from the train to the signal ahead.
A signal object doing nothing but reading this information from its Identity field and forwarding it to the next signal could help here. E.g., an ID of 0110 would mean that the first train does not have cab signalling, the next two does, the fourth does not.
Failed signalsPut a signal object in front of the signal telling it that it failed. As above, you could switch this behaviour for a series of trains based on 0 and 1 in the ID field.
Selecting the starterIn modern installations e.g. in Germany, there are two starters at the platform. The first is spaced from the fouling point by the complete overlap (100 to 250 m), so a train can reach it without blocking the station exit. The second is at the far end of the platform track, utilising the full length of that track but its overlap blocks neighbouring exit paths while a train arrives there. Again, a simple object can foretell the situation.
Other funShunting guardOk, Pete tells me that animating custom figures is not possible currently (at least not with Blender), so think of an animated 2D puppet for the following.
You place a guard besides the rake of wagons you are going to couple to. This guard has a track link pointing towards the wagons, placed precisely at the coupling. It monitors the speed of the consists around him. OnConsistPass gets called for anything that moves. He discards what moves away or not at all. So he will pick out your consist as you propel it into that track, having no clue when to stop, as is prototypical. He computes the deceleration you need to stop there:
deceleration = square(speed) / 2 / distance
distance is parameter frontDist, speed is result of GetConsistSpeed, deceleration is in m/s2.
In a simple implementation, the guard shows "stop" (doing some waving animation) when the require deceleration exceeds some threshold like 0.5. Otherwise he shows "approach slowly". If the required deceleration is below some other threshold, or if your consist is too far away, he does nothing, meaning that you should maintain your speed (or even accelerate if you braked to hard or too early).
In a more sophisticated implementation, he can force you into a two-step approach where you take the last metres at 1 m/s (the speed of walking) depending on what the regulations prescribe.
You can make the guard a child object of the signal blueprint (called Guard). Then you can do the following using
- Code: Select all
Call("Guard:setNearPosition", x, y, z)
- Make the guard slide along the track to align with the place of uncoupling. I don't think he can sense the standing wagons but he can sense the leaving consist and he gets characterist sequence of OCCUPATION_DECREMENT followed by one or two OCCUPATION_INCREMENT, depending on where the track link is. So he can get there to direct you when you return to recouple, after setting off some wagons somewhere.
- Make the guard jump between parallel sidings depending on which you approach. He needs a track link in each to get the preparation message when you set the path to a new track. However, he does not sense the initially placed wagons there and the links must be aligned precisely since he is positioned relativ to the original location near link 0, so this will not get too far.
- Make him disappear by moving him underground, and make his twin appear in the neighbouring track as you get there. Disappearing when the shunting consist is 500 m away or SIGNAL_UNPREPARED is received (because switches are set for another track) should be a safe strategy. For small yards, you might change him to a hanging-around pose though.
Of course, it would be even more fun to have a shunter ride on the front wagon of the propelled consist directing you depending on the messages he receives from the first guard. That waggon would need to be a driving trailer (i.e. unpowered but with engine blueprint). However, I don't think those receive messages if they are not the active cab. But it's not my domain of expertise.
Custom loading/unloading animationsYou could have a mobile crane approach your wagon precisely as it stops near the track link of the crane. Of course, much of that can be done by loading points, assuming you can place them in scenario editor (after modifying ValidInScenarios). I am not sure about the sophistication of the animations possible there. In signals, you have complete control to do the following.
- Load or unload a single block of stone, or a box, using a crane that first lifts it, then rotates around its centre, then lowers it. Ok, to make the block disappear from the wagon, it must be an unloading point. And you need matching blocks on wagons, thus not so easy.
- Have cattle march into the van. Ok, the problem of not having bone-based animation strikes again.
- Wheel stuff in and out a van. Ok, same animation problem.
At least on the continent, the vans of passenger trains carried mail and smaller parcels, at least until the 80ies or whenever they started rationalising=closing everything. So it was a normal sight that as the train stops at the station, someone waiting there with a cart, maybe in the middle of the platform, would scurry to the van's door to hand over something and get some other things handed down. Of course, seeing the current state of passengers, this sounds a bit over-ambitious, but it is pretty scenic nonetheless.
Edits:
1) Added a paragraph in the shunting helper object.
2) Added section Random delays in signal clearing