Episode 32: Random Stories
Stories make operation more exciting. This can be seen impressively in the article →Köf-Refuel. A special aspect is the random triggering, which makes the actual story unpredictable and brings even more excitement. Here you can find out exactly how this works. Of course with xml-scripting 😉
Event-based Trigger (CheckTrigger)
At the beginning there is the event that has to happen in order for the story to be triggered. This can be any True/False condition that can be queried in Rocrail. Has a street been set, has the locomotive light been turned off, has the block occupancy changed?
It is important that the trigger does not fire continuously, especially since the story trigger (the “main trigger”) comes every few seconds. It is therefore necessary to determine only the change event, e.g. by additionally checking the previous state. The previous state can be stored in a variable:
By this mechanism, the trigger fires only once when the block status changes from “free” (or not occupied) to “occupied”. It does not fire if the block status remains occupied and also not if it becomes free again.
As I said, this trigger must work properly.
The Trigger-Xml-Programming (StoryTrigger.xml)
In the StoryTrigger you must of course check regularly whether the trigger event for this story triggers or not. But before that, it makes sense to allow random stories in principle by a button (or not). Therefore a new button coStoryRandom will be introduced in the plan. In the xml the StoryTrigger will be aborted, if the button is off:
Next, we need a mechanism to tell the StoryTrigger that a trigger was fired at all. To do this, we use another variable called StoryRandomId. It is now defined like this:
- if StoryRandomId = “…” => currently no random story is executed. Rocrail is ready for a new random story => the trigger must be queried
- StoryRandomId has a value: A trigger has been triggered or a random story is running now
Depending on the content of this variable we now have to check the random trigger or execute the random story:
In the random story the variable must of course be described exactly when the trigger fires. To do this, you set the variable to a defined, “speaking” value:
In the StoryTrigger, the value of the variable must be further evaluated accordingly, so that the random story can be run through. For this purpose, a switch case is introduced, which can serve any number of random stories depending on the variable value:
So there is a kind of framework also for several random stories. Of course it is important that the value in the CheckTrigger function and the query value in the switch case are absolutely the same here: e.g. SRI_StoryRandom1. I chose this value because it is relatively meaningful and therefore easy to assign. SRI here stands for StoryRandomId, followed by the file name of the story. So you can find your way around relatively well.
To keep it clear and not to create too many files, the feature of the xml-function is useful. With this function you can “group” code in a section of the xml-file and call it from outside. This is comparable to a “call”, as you know it e.g. from Basic maybe. But there are no call or return-parameters.
The pure function with the name CheckTrigger would look like this:
and together with the trigger logic like this:
Calling this CheckTrigger function in the StoryTrigger looks like this:
Die Funktion von StoryTrigger und CheckTrigger ist nochmal in diesem Diagramm dargestellt:
The schematic procedure then follows:
- StoryTrigger is called
- If normal (non-random) stories are active, they have priority. These are executed regularly.
- If the “Random” switch is set to Off, the execution of random stories is not allowed => the script is finished
- StoryRandomId is queried: If the value is “…”, all trigger functions are queried. These are included in the file of the respective random story, but are separate from the story code.
- In all other cases a trigger has fired and the respective random story is executed.
Here, too, it is indicated that there may well be several random stories. However, these cannot run simultaneously at present. But more about that later.
Coincidence & Probability of Occurrence
So far we have only dealt with the first part of the story triggering: the trigger event. Without further ado, our story would now always start when the block changes to occupied. Since this gets boring in the long run, we’ll take a random number. We initialize it with a variable:
Then we execute a Rocrail action that generates the actual random number (I am not aware that this is possible directly via xml):
Finally we copy the random number into an own variable rValue:
Now comes the actual random query, here for example with a probability of 30%:
So if you combine this random factor with the trigger above, the result is a random execution:
The Rocrail action to generate the random number has here the name GetRandomValue and must of course act on the variable randomValue.
That’s it! As you can see in the →timelapse part of the video, this works very well. I also added a little test code.
As I said, currently only one random story can be run at a time. This is because only StoryRandomId decides which story it is. And at the moment you’re also busy with a random story, as the →Koef Refuel shows. In theory, several stories can be run at the same time. However, this requires at least several StoryRandomIds and doesn’t make it any easier. You also have to keep an eye on the computing time. Since the StoryTrigger fires frequently, it already requires some resources.
And never forget one very important basic rule: Do not interfere with the automatic with the xml-script! Only do things with xml-script, you are sure about. Otherwise there will be – especially with the frequent calls – very unpleasant effects up to the Rocrail-crash in the middle of the operation. That makes less fun, of course. →Here are a few more hints on this. But I can say that Rocrail is quite robust in my opinion and it is also possible to run many (nested or concurrent) xml-scripts.
Everything’s great! I look forward to your feedback and/or further suggestions.
By the way: The random factor can be used not only at the beginning, but also in the middle of a story. This gives the story a further, unpredictable touch in addition to the reactions of the dispatcher/engine driver. It could not be more exciting!