Fahrpläne und Disposition im Script-System

  • Fahrpläne, Disposition und Scripts treffen sich an verschiedenen Stellen und für jeden Fall gibt es natürlich entsprechende Scriptfunktionen, die hier erläutert werden.

    1 Allgemein

    Aufgrund von Problemen mit den Begrifflichkeiten möchte ich hier nochmal die englischen Übersetzungen erwähnen:

    • RBL-Server ==> ITCS server
    • Strecke ==> Route
    • Route/Weg ==> Way
    • Fahrt ==> Trip
    • Linie/Kurs ==> Line/Course
    • Umlauf(plan) ==> Tour (plan)

    2 Im Fahrzeug

    Hier geht es darum, dass das RBL-Bordgerät, also das IBIS-Gerät (Straßenbahn oder früher in Bussen) oder der "Drucker" (bei Bussen), Zugriff auf diverse Daten der Fahrpläne erhält.

    FIS-Datei und Fahrplan

    Wichtig ist hierbei auch das Zusammenspiel von FIS-Dateien und den Fahrplänen der Karte:

    • Die ID der Stationen in der FIS-Datei muss mit der FIS-ID des Gleises oder – falls keines extra eingegeben wurde – der FIS-ID der Station, oder – falls auch hier nichts eingegeben wurde – dem internen Namen der Station übereinstimmen
    • Routen/Wege der Fahrpläne werden mit einer FIS-Linie und einer FIS-Route beschriftet, die mit Linien- und Routeninformation der zugehörigen Route in der FIS-Datei übereinstimmen muss.

    Wenn dies eingehalten wird, dann können entsprechend gescriptete RBL-Bordgeräte einerseits auf die Informationen der FIS-Datei zugreifen (z.B. diverse Strings), aber parallel auch auf die Informationen des Fahrplans zugreifen (z.B. ob sich das Fahrzeug auf dem korrekten Weg befindet).

    2.1 Trennung Disposition und RBL

    Und ebenso wichtig ist es, sich bewusst zu machen, dass zunächst einmal streng getrennt wird zwischen:

    • der LOTUS-Disposition: Der Umlauf, auf dem man "tatsächlich" fährt, den man also im Singleplayer-Spiel im Vorfeld oder während des Spiels über die entsprechenden Menüs ausgewählt hat bzw. den einem der Spielleiter im Multiplayer zugewiesen hat und
    • dem RBL-Server des Verkehrsbetriebs, auf den man sich mit dem RBL-Bordrechner anmelden kann [Funktion noch nicht verfügbar] und die Fahrplandaten aller Art, die auf dem Bordrechner gespeichert sind.

    Nur, weil man sich eine Fahrt bzw. einen Umlauf in LOTUS ausgesucht hat, ist man noch lange nicht auf dem RBL-Server angemeldet und erscheint an den entsprechenden vom RBL-Server verknüpften Stellen – und umgekehrt reicht es nicht, sich einfach per RBL anzumelden – "offiziell" fährt man erst dann den Umlauf (mit allen Konsequenzen wie Fahrtauswertung [Funktion noch nicht verfügbar] ), wenn man ihn in LOTUS auswählt bzw. einem der Spielleiter zugeordnet hat.


    Mit seinem RBL-Gerät hat man daher keinerlei Zugriff auf den aktuellen Stand der Disposition in LOTUS (tatsächliche Verspätungen, Fahrzeugpositionen usw.)! Das einzige, worauf man Zugriff hat, sind die planerischen Fahrplandaten, da unterstellt wird, dass diese bereits auf dem Gerät gespeichert sind.

    2.2 Nummern vs. Strings

    Damit das System möglichst offen ist, werden für Linien, Routen usw. Strings zur Identifikation genutzt. Die "üblichen" Geräte (insbesondere jene aus dem Standardcontent) nutzen hierfür reine Ganzzahlen (integer). Das bedeutet natürlich, dass es des Öfteren nötig ist, gegebene Integer-Werte (z.B. aus der Eingabe des Bordrechners) in String-Werte (z.B. für die unten aufgeführten Fahrplanfunktionen) umzuwandeln.


    Hierbei gilt: Keine führenden Nullen verwenden! Auch wenn die Eingabe "001" auf dem Bordrechner ist – intern dürfen die führenden Nullen trotzdem nicht übergeben werden!

    2.3 Funktionen nur für Routen

    function TimetableGetWayIndex(self: integer; itcsServer: string; line: string; route: string): integer Diese Funktion liefert den internen Index der Route, die per Linie und Routen-Code und unter Angabe des RBL-Server-Namens abgefragt wird. Sie gibt "-1" zurück, falls es in den Fahrplandaten keine Route mit dieser Linie und diesem Routen-Code gibt.

    function TimetableAtSectionOfWay(self: integer; wayindex: integer): integer Mit dieser Funktion kann ermittelt werden, ob sich das Fahrzeug aktuell auf der mit "wayindex" bezeichneten Route befindet. Falls ja, wird die sogenannte "Section" übermittelt. Diese zählt Station für Station hoch, wobei auch die Strecken zwischen den Stationen extra gezählt werden. Also:

    • 0: an der Abfahrtsstation
    • 1: zwischen der ersten und zweiten Station
    • 2: an der zweiten Station
    • 3: zwischen der zweiten und dritten Station
    • ...

    Falls sich das Fahrzeug abseits der Strecke befindet, wird eine -1 zurück gegeben. Nochmal Achtung! Es ist völlig egal, ob und auf welchem Umlauf das Fahrzeug in LOTUS tatsächlich angemeldet wurde! Die Ausgabe arbeitet komplett unabhängig davon!

    function TimetableAtBusstopOfWay(self: integer; wayindex, sectionindex: integer; out stnID: string): boolean Diese Funktion gibt (unter Angabe von Routenindex und Section) zurück, ob sich das Fahrzeug an einer Station befindet und übermittelt dann über stnID die FIS-ID des Gleises oder – falls diese leer ist – die FIS-ID der Station oder – falls diese ebenfalls leer ist – die interne Bezeichnung der Station.

    function TimetableDistBetweenStns(self: integer; wayindex: integer; startStn, endStn: string): single Gibt entlang der Route "wayindex" die Entfernung zwischen den genannten Stationen zurück, gemessen entlang der Route in Metern.

    2.4 Funktionen für Fahrten

    (also inklusive Zeiten)


    procedure TimetableGetTripAndTourIndexByLineCourseDate(self: integer; date: single; time: single; itcsServer: string; line: string; course: string; out iTimetable, iTrip, iTourplan, iTour, iTourtrip: integer) Gibt Fahrplan-, (fahrplanweiter) Fahrt-Index sowie die Indizes zurück, die den Umlauf definieren (also Index des Umlaufplans, des Umlaufs innerhalb des Umlaufplans sowie des Fahrt-Index innerhalb des Umlaufs). Benötigen tut die Funktion hierfür das Datum und die Uhrzeit der Abfrag, den Namen des zugehörigen RBL-Rechners sowie Linie und Kurs.


    procedure TimetableGenerateTempTripListByTour(self: integer; timetableIndex: integer; iTourplan, iTour: integer) Legt unter Angabe von Fahrplan-, Umlaufplan- und Umlaufindex (zu ermitteln bspw. durch die vorherige Prozedur) eine temporäre Liste der Fahrten dieses Umlaufs an. Diese Liste bleibt so lange bestehen, bis diese Prozedur erneut ausgeführt wird (oder das sichtbare Objekt, in welchem das Script arbeitet, entladen wird).


    function TimetableGetTempTripListCount(self: integer): integer Gibt die Anzahl der Elemente in dieser Liste zurück.


    procedure TimetableGetTripInfoByTempListIndex(self: integer; templistindex: integer; out line: string; out course: string; out route: string; out tripIndex: integer; out depTime: single) Liefert aus der Fahrt aus der temporären Liste weitere Informationen:

    • Line: Linie als String
    • Course: Kurs als String
    • Route: Routen-ID als String
    • Tripindex: Fahrplanweiter Index der Fahrt, also nicht innerhalb des Umlaufs, sondern umlaufunabhängig!
    • DepTime: Abfahrtszeit in Tagen. Startete der Umlauf bereits am Vortag, wird auch relativ zu 00:00 Uhr relativ zum Vortag gerechnet. Die Zahl wird dann also größer als 1,0.


    procedure TimetableGenerateTempStnListByTrip(self: integer; timetableIndex: integer; tripIndex: integer) Erzeugt eine temporäre Liste von Haltestellen der Fahrt, die durch Fahrtindex (z.B. "tripindex" aus der vorherigen Prozedur) und Index des Fahrplans identifiziert wird. Diese Liste besteht so lange, bis diese Prozedur erneut aufgerufen wird.


    function TimetableGetTempStnListCount(self: integer): integer Gibt die Anzahl der Elemente in dieser Liste zurück.


    procedure TimetableGetInfoByTempStnListIndex(self: integer; templistindex: integer; out FIS_ID: string; out arrTime: single; out depTime: single) Gibt von der Haltestelle aus der temporären Liste die FIS-ID (entspricht der ID in der FIS-Datei), die planmäßige Ankunfts- und Abfahrtszeit zurück.

    2.5 Leitstelleninteraktionen

    2.5.1 Textmeldung Leitstelle an Fahrzeug

    Um Leitstellen-Meldungen empfangen zu können, muss im Script die Prozedur ReceiveFromITCS(id, value: string) definiert werden, die dann aufgerufen wird, sobald eine Nachricht kommt. Es ist egal, ob diese Prozedur im Fahrzeug- und/oder Modulscript definiert wird, da sowohl Fahrzeug als auch Module die Nachricht bekommen. In der Variable value steht die eigentliche Nachricht, id enthält zusätzliche Information – momentan wird hier stets "MSG_INFO" übertragen, fest geplant ist außerdem "MSG_CONFIRM" für Meldungen, die aktiv bestätigt werden müssen. Es ist möglich, dass in Zukunft weitere Leitstellenfunktionen über weitere IDs realisiert werden.

    3 Auf der Strecke

    3.1 Stellwerk vs. RBL

    Auf der Strecke gibt es nun schon die Möglichkeit, auf die LOTUS-interne Disposition zuzugreifen.


    Hierzu muss man kurz erläutern, wie die Dinge ganz grob in der Realität laufen:

    • Bei Bussen und Straßenbahnen läuft "alles", also auch Echtzeitanzeigen, das Stellen der Weichen (falls nicht über Linienkennung o.Ä.) , die Leitstelle usw. übers RBL; wer sich hier nicht anmeldet, hat "verloren" und muss alles manuell machen
    • Bei U-, S- und Eisenbahnen dagegen kann man sich auch "irgendwo" anmelden, aber für die entscheidenden Dinge (Fahrdienstleitung und somit Weichen und Signale stellen, Bahnsteiganzeigen usw.) wird der Zug über seine Zugnummer identifiziert und "von außen" begleitet. Egal ob ICE, Dampflok oder Draisine, die Fahrdienstleiter wissen Bescheid, wer man ist. Das ganze läuft unabhängig davon, ob man sich mit seinen Bordgeräten irgendwo anmeldet.

    Während in LOTUS für den ersten Fall ein oder mehrere RBL-Server simuliert werden, die unabhängig von der LOTUS-internen Disposition geführt werden, sind die Stellwerke und Bahnsteiganzeigen (der Bahn) bei LOTUS direkt mit der internen Disposition verbunden. Es wäre unserer Ansicht nach übertrieben, zumindest zum jetzigen Stand hier nochmal eine Zwischenebene einzuziehen.


    Dementsprechend gibt es bei den folgenden Befehlen die Unterscheidung, ob die Daten vom RBL-Rechner oder von der internen Disposition stammen.

    3.2 Script-Funktionen

    Die folgenden Funktionen dienen der Daten-Versorgung von z.B. dynamischen Haltestellenanzeigern:


    procedure StatPIS_Login(Self: integer; stationname, trackname: string) Meldet das Objekt an einer Station und einem Gleis an. Hierbei werden jeweils die internen Bezeichnungen erwartet. Wird als Gleis ein Leerstring übergeben, dann werden bei allen folgenden Prozeduren und Funktionen alle Gleise berücksichtigt.


    procedure StatPIS_GenerateTempDataList(Self: integer; timespan_d: single) Erzeugt eine temporäre Liste von Fahrten, die innerhalb des kommenden Zeitraum der Länge "timespan_d" (gerechnet in Tagen) erfolgen oder erfolgen sollten. Hierbei werden die Daten (Verspätungen, Ausfälle, ...) der LOTUS-internen Disposition verwendet. Die temporäre Liste bleibt bestehen, bis eine der vier hier genannten Prozeduren erneut ausgeführt werden.


    procedure StatPIS_GenerateTempDataListWholeStation(Self: integer; timespan_d: single) Erzeugt eine temporäre Liste der Fahrten sämtlicher Gleise (also auch dann, wenn beim Login ein konkretes Gleis angegeben wurde). Hierbei werden die Daten (Verspätungen, Ausfälle, ...) der LOTUS-internen Disposition verwendet. Die temporäre Liste bleibt bestehen, bis eine der vier hier genannten Prozeduren erneut ausgeführt werden.


    procedure StatPIS_GenerateTempITCSDataList(Self: integer; timespan_d: single; itcsServer: string) und procedure StatPIS_GenerateTempITCSDataListWholeStation(Self: integer; timespan_d: single; itcsServer: string) Diese beiden Prozeduren entsprechen der beiden vorher genannten, der Unterschied ist aber, dass hier die Verspätungen, Ausfälle usw. den Daten entnommen werden, die dem RBL-Server vorliegen. Hier ist also nicht entscheidend, dass die entsprechenden Fahrzeuge LOTUS-"offiziell" einem Umlauf zugeordnet wurden, sondern dass sie sich per RBL-Bordgerät auf dem RBL-Server angemeldet haben. [Da die RBL-Server noch nicht vollständig implementiert wurden, werden hier momentan ebenfalls die LOTUS-Daten zugrundegelegt.]


    function StatPIS_GetTempDataCount(Self: integer): integer gibt die Anzahl der Einträge der mit den vorherigen Prozeduren angelegten, temporären Liste zurück.


    procedure StatPIS_SortTempList(Self: integer; by: byte) sortiert die Elemente der temporären Liste. "by" gibt das Sortierkriterium an, momentan gibt es nur "0", welches die Liste nach der tatsächlichen Abfahrtszeit sortiert.


    function StatPIS_GetTempListData(Self: integer; templistindex: integer): TStatPISTrip gibt einen Datensatz aus der temporären zurück. Dieser ist vom Typ "TStatPISTrip", der wie folgt deklariert ist:

    Die Elemente haben folgende Bedeutungen:

    • Index: Index der dispositionsmäßigen Fahrt (dieselbe Fahrt an verschiedenen Tagen hat verschiedene Indizes)
    • TourIndex: Index der dispositionsmäßigen Tour (derselbe Umlauf an verschiedenen Tagen hat verschiedene Indizes)
    • Category: Index der Zuggattung
    • Name: "Name" der Fahrt, für gewöhnlich sollte es einfach die Zug-/Fahrtnummer sein
    • Line: Linie, die im zugehörigen Weg/Route) hinterlegt ist
    • Start, Terminus: FIS-Bezeichnung von Start und Ziel (erste bzw. letzte Station mit Fahrgasthalt)
    • AT's und DT's: Ankunfts- und Abfahrts-(Departure)-Zeiten in Tagen, jeweils planmäßig und tatsächlich als absolute Zahl ( < 1,0, d.h. 25 Uhr wird zu 1 Uhr usw.) und die tatsächliche Zeit relativ zur aktuellen Uhrzeit.
    • Delay: " + " = Verspätung, " – " = Verfrühung
    • TrainLoggedIn: Wenn die Quelle das RBL ist, dann gibt diese Variable an, dass sich ein Fahrzeug unter Angabe der zugehörigen Linie und Kurs auf dem RBL-Rechner angemeldet hat, andernfalls gibt die Variable an, dass einem Fahrzeug in LOTUS eine Fahrt und ein Umlauf zugeordnet wurde.
    • RemainingLegs: Wie nahe ist das Fahrzeug bereits der Station, auf die eingeloggt wurde? 0 = ist bereits eingefahren, -1 = bereits abgefahren, +1 = hat die vorherige Station verlassen, +2 = in vorheriger Station usw.
    • Track_Plan, Track_Curr: Öffentlicher Name des planmäßigen und des tatsächlichen Gleises
    • First, Last: ist die eingeloggte Station die erste und/oder letzte (Fahrgasthalt-)Station der Fahrt?

    function StatPIS_GetViaStationsOfTripTabSep(Self: integer; tripindex: integer; count: integer): string Gibt in Tabstops getrennt die Reihe der nächsten Stationen des Zuges an. Dabei

    • entspricht "tripindex" der Variable "Index" im Record TStatPISTrip
    • werden maximal so viele Halte gelistet, wie durch "count" angegeben
    • wird die Auswahl (nicht Reihenfolge!) abhängig davon gewählt, welche Priorität die einzelnen Stationen haben. Im Zweifelsfall wird eher versucht, die Stationen höherer Priorität komplett aufzuführen, bevor Stationen niedrigerer Priorität hinzugefügt werden. Falls nicht alle Stationen einer Priorität aufgeführt werden können, wird den näheren Stationen gegenüber den entfernteren der Vorzug gegeben
    • wird die Liste sortiert nach Reihenfolge der Stationen, der nächste Halt zuerst, der letzte zuletzt und
    • werden keinesfalls die aktuelle noch die letzte Station mit aufgeführt.

    function StatPIS_GetInfotext(Self: integer): string; Gibt den Infotext (z.B. Lauftext) zurück, der z.B. von der Leitstelle der zugeordneten Haltestelle gesendet wurde.

    3.3 Script-Beispiel