Zufälliges Auslösen von Stories

Zufälliges Auslösen von Stories

Stories machen den Betrieb abwechslungsreicher. Das ist im Beitrag →Köf-Tanken eindrucksvoll zu sehen. Ein besonderer Aspekt ist das zufällige Auslösen, welches die eigentliche Story unvorhersehbar macht und noch mehr Spannung bringt. Hier könnt ihr erfahren, wie das genau funktioniert. Natürlich mit Xml-Scripting 😉

Ereignisgesteuerter Trigger (CheckTrigger)


Am Anfang steht das Ereignis, welches eintreten muss, damit die Story grundsätzlich auslösen kann. Das kann erstmal jede beliebige True/False-Bedingung sein, die sich in Rocrail abfragen lässt. Ist eine Fahrstraße gestellt, ist das Loklicht ausgestellt worden, hat sich die Blockbelegung geändert?

Wichtig ist, dass der Trigger nicht andauernd feuert; insbesondere da der StoryTrigger (der “Haupt-Trigger”) ja alle paar Sekunden kommt. Es ist also erforderlich, z.B. durch zusätzliches Abprüfen des vorherigen Zustandes nur das Änderungs-Ereignis zu ermitteln. Der vorherige Zustand lässt sich in einer Variable speichern:

Durch diesen Mechanismus feuert der Trigger nur dann genau einmal, wenn der Blockstatus von “frei” (bzw. Nicht-Belegt) auf “Belegt” wechselt. Er feuert nicht, wenn der Blockstatus belegt bleibt und auch nicht, wenn er wieder frei wird.
Wie gesagt, dieser Trigger muss sauber funktionieren.

Die Trigger-Xml-Programmierung (StoryTrigger.xml)

Schalter “Zufall”

Im StoryTrigger muss natürlich regelmäßig geprüft werden, ob das Trigger-Event für diese Story nun auslöst oder nicht. Zuvor macht es aber Sinn, durch einen Button die Zufalls-Stories grundsätzlich zu erlauben (oder eben nicht). Dafür wird ein neuer Button coStoryRandom im Plan eingeführt. Im Xml wird der StoryTrigger dann abgebrochen, wenn der Button aus ist:

Variable StoryRandomId

Als nächstes brauchen wir einen Mechanismus, um dem StoryTrigger mitzuteilen, dass überhaupt ein Trigger gefeuert wurde. Dazu nutzen wir wieder eine Variable, und zwar mit dem Namen StoryRandomId. Es ist nun so definiert:

  • wenn StoryRandomId = “..” => derzeit wird keine Zufalls-Story ausgeführt. Rocrail ist bereit für eine neue Zufalls-Story => der Trigger muss abgefragt werden.
  • StoryRandomId hat einen Wert: Ein Trigger hat ausgelöst bzw. eine Zufalls-Story läuft jetzt

Abhängig vom Inhalt dieser Variable müssen wir nun den Zufalls-Trigger prüfen oder die Zufalls-Story ausführen:

In der Zufalls-Story muss die Variable natürlich genau dann beschrieben werden, wenn der Trigger feuert. Dazu setzt man die Variable auf einen definierten, “sprechenden” Wert:

Im StoryTrigger muss der Wert der Variable entsprechend weiter ausgewertet werden, so dass die Zufalls-Story auch durchlaufen werden kann. Dazu wird ein Switch-Case eingeführt, welches abhängig vom Variablenwert beliebig viele Zufalls-Stories bedienen kann:

Damit gibt es eine Art Framework auch für mehrere Zufalls-Stories. Wichtig ist natürlich, dass der Wert in der CheckTrigger und der Abfragewert im Switch-Case hier absolut gleich sind: z.B. SRI_StoryRandom1. Ich habe diesen Wert gewählt, weil er relativ sprechend und daher gut zuzuordnen ist. SRI steht hier für StoryRandomId, gefolgt vom Dateinamen der Story. So findet man sich relativ gut zurecht.

Xml-Funktion CheckTrigger

Damit es übersichtlich bleibt und man nicht zuviele Dateien anlegen muss, bietet sich das Feature der Xml-Funktion an. Damit lässt in einer Xml-Datei Code “gruppieren” und von extern gezielt aufrufen. Das ist vergleichbar mit einem “Call”, wie man ihn z.B. noch aus Basic kennt. Hier gibt es allerdings keine Aufruf- oder Rückgabeparameter.
Die reine Function mit dem Namen CheckTrigger würde also so aussehen:

und zusammen mit der Trigger-Logik so:

Der Aufruf dieser CheckTrigger-Function im StoryTrigger sieht folgendermaßen aus:

Die Funktion von StoryTrigger und CheckTrigger ist nochmal in diesem Diagramm dargestellt:

Der schematische Ablauf ergibt sich dann zu:

  • StoryTrigger wird aufgerufen
  • Falls normale (nicht zufallsgesteuerte) Stories aktiv sind, haben diese Vorrang. Diese werden regulär ausgeführt.
  • Falls der Schalter “Zufall” auf Aus ist, ist die Ausführung von Zufalls-Stories nicht erlaubt => das Script ist beendet
  • StoryRandomId wird abgefragt: Ist der Wert “..”, werden alle Trigger-Functions abgefragt. Diese stehen mit in der Datei der jeweiligen Zufalls-Story, sind aber getrennt vom Story-Code.
  • In allen anderen Fällen hat ein Trigger gefeuert und die jeweilige Zufalls-Story wird ausgeführt.

Auch hier ist angedeutet, dass es durchaus mehrere Zufalls-Stories geben kann. Diese können derzeit allerdings nicht gleichzeitig ablaufen. Doch dazu später mehr.

Zufall & Eintrittswahrscheinlichkeit

Bisher haben wir uns nur um den ersten Teil der Story-Auslösung gekümmert: das Trigger-Event. Ohne Weiteres würde unsere Story nun immer gestartet, wenn der Block auf belegt wechselt. Da das auf Dauer langweilig wird, nehmen wir uns eine Zufallszahl. Diese initialisieren wir über eine Variable:

Dann führen wir eine Rocrail-Aktion aus, die die eigentliche Zufallszahl generiert (mir ist nicht bekannt, dass das direkt über Xml möglich ist):

Schließlich kopieren wir die Zufallszahl in eine eigene Variable rValue:

Nun kommt die eigentliche Zufalls-Abfrage, hier z.B. mit einer Eintrittswahrscheinlichkeit von 30%:

Also wenn man diesen Zufallsfaktor mit dem Trigger oben kombiniert, ergibt sich eine zufällige Ausführung:

Die Rocrail-Aktion zum Generieren der Zufallszahl hat hier dann den Namen GetRandomValue und muss natürlich auf die Variable randomValue wirken.

Überlegungen

Das war es dann auch schon! Wie ihr im →Zeitraffer-Teil des Videos sehen könnt, funktioniert das sehr gut. Ein bißchen Testcode habe ich auch hinzugefügt.
Wie gesagt, derzeit kann immer nur eine Zufalls-Story gleichzeitig ausgeführt werden. Das liegt daran, dass allein StoryRandomId entscheidet, um welche Story es sich handelt. Und derzeit ist man mit einer Zufallsstory auch ausgelastet, wie das →Köf-Tanken zeigt.
Theoretisch sind auch mehrere Stories gleichzeitig denkbar. Das erfordert aber mindestens mehrere StoryRandomIds und macht es nicht einfacher. Außerdem muss auch die Rechenzeit im Auge behalten werden. Da der StoryTrigger häufig feuert, braucht es schon einige Ressourcen.

Und eine ganz wichtige Grundregel nie vergessen: Keine Eingriffe in die Automatik mit dem Xml-Script! Nur Dinge mit Xml-Script machen, bei denen man sich sicher ist. Sonst gibt es – insbesondere bei den häufigen Aufrufen – sehr unschöne Effekte bis hin zum Rocrail-Absturz mitten im Betrieb. Das macht dann natürlich weniger Spaß. →Hier gibt’s noch ein paar Hinweise dazu. Ich kann aber sagen, dass Rocrail meiner Auffassung nach recht robust ist und auch die Ausführung vieler (verschachtelter oder gleichzeitiger) Xml-Scripte möglich ist.

Download

→Hier der Link zum Download der Scripte und des Plans

Fazit

Alles super! Ich freue mich auf eure Rückmeldungen und/oder weitere Vorschläge.

Übrigens: Der Zufallsfaktor lässt sich nicht nur am Anfang, sondern auch mitten in einer Story nutzen. So bekommt die Story zusätzlich zu den Reaktionen des Fahrdienstleiters/Lokführers eine weitere, unvorhersehbare Note. Spannender könnte es nicht sein!



Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.