diff --git a/src/Devices/Deadman.cs b/src/Devices/Deadman.cs
index a541693..1d4955c 100644
--- a/src/Devices/Deadman.cs
+++ b/src/Devices/Deadman.cs
@@ -31,9 +31,10 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the device state should be updated.
/// The current train.
+ /// The current route.
/// Whether the device should initialize.
/// The time elapsed since the previous call.
- internal override void Update(Train train, bool init, Time elapsedTime)
+ internal override void Update(Train train, Route route, bool init, Time elapsedTime)
{
if (train.VigilanceOverride)
{
@@ -100,7 +101,8 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the plugin should perform the AI.
/// The AI data.
/// The current train.
- internal override void PerformAI(AIData data, Train train)
+ /// The current route.
+ internal override void PerformAI(AIData data, Train train, Route route)
{
if (DeviceState != DeviceStates.Inactive)
{
diff --git a/src/Devices/Device.cs b/src/Devices/Device.cs
index 3bd0843..c0e0461 100644
--- a/src/Devices/Device.cs
+++ b/src/Devices/Device.cs
@@ -17,9 +17,10 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the device state should be updated.
/// The current train.
+ /// The current route.
/// Whether the device should initialize.
/// The time elapsed since the previous call.
- internal virtual void Update(Train train, bool init, Time elapsedTime) { }
+ internal virtual void Update(Train train, Route route, bool init, Time elapsedTime) { }
/// Is called when the driver changes the reverser.
/// The new reverser position.
@@ -59,6 +60,7 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the plugin should perform the AI.
/// The AI data.
/// The current train.
- internal virtual void PerformAI(AIData data, Train train) { }
+ /// The current route.
+ internal virtual void PerformAI(AIData data, Train train, Route route) { }
}
}
diff --git a/src/Devices/Doors.cs b/src/Devices/Doors.cs
index 6d231dd..5140d80 100644
--- a/src/Devices/Doors.cs
+++ b/src/Devices/Doors.cs
@@ -14,9 +14,10 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the device state should be updated.
/// The current train.
+ /// The current route.
/// Whether the device should initialize.
/// The time elapsed since the previous call.
- internal override void Update(Train train, bool init, Time elapsedTime)
+ internal override void Update(Train train, Route route, bool init, Time elapsedTime)
{
if (init)
{
@@ -136,31 +137,89 @@ namespace OpenbveFcmbTrainPlugin
/// The new state of the doors.
internal override void DoorChange(DoorStates oldState, DoorStates newState)
{
- LeftDoorsClosing = false;
- RightDoorsClosing = false;
+ if ((oldState == DoorStates.Both || oldState == DoorStates.Left) && (newState == DoorStates.None || newState == DoorStates.Right))
+ {
+ LeftDoorsClosing = false;
+ // Unselect doors automatically when closed, just in case
+ RequestedDoorInterlock = newState == DoorStates.None ? DoorInterlockStates.Locked : DoorInterlockStates.Right;
+ }
+ if ((oldState == DoorStates.Both || oldState == DoorStates.Right) && (newState == DoorStates.None || newState == DoorStates.Left))
+ {
+ RightDoorsClosing = false;
+ // Unselect doors automatically when closed, just in case
+ RequestedDoorInterlock = newState == DoorStates.None ? DoorInterlockStates.Locked : DoorInterlockStates.Left;
+ }
}
/// Is called when the device should perform the AI.
/// The AI data.
/// The current train.
- internal override void PerformAI(AIData data, Train train)
+ /// The current route.
+ internal override void PerformAI(AIData data, Train train, Route route)
{
- //// Select the correct doors for the current station
- //if (Stations.State != Stations.StationStates.Completed)
- //{
- // if (((Stations.Current.OpenLeftDoors && !LeftDoorsSelected) || (!Stations.Current.OpenLeftDoors && LeftDoorsSelected)) && !LeftDoorsClosing)
- // {
- // // Select or unselect the doors on the left.
- // KeyDown(VirtualKeys.G);
- // data.Response = AIResponse.Short;
- // }
- // if (((Stations.Current.OpenRightDoors && !RightDoorsSelected) || (!Stations.Current.OpenRightDoors && RightDoorsSelected)) && !RightDoorsClosing)
- // {
- // // Select or unselect the doors on the right.
- // KeyDown(VirtualKeys.H);
- // data.Response = AIResponse.Short;
- // }
- //}
+ // Select doors to be opened on the current stop, at least 200 meters before the stop point.
+ if (route.CurrentStation.PlayerStops() && train.State.Location >= route.CurrentStation.StopPosition - 200 && route.StationState == Route.StationStates.Pending)
+ {
+ switch (RequestedDoorInterlock)
+ {
+ case DoorInterlockStates.Unlocked:
+ if (!route.CurrentStation.OpenLeftDoors)
+ {
+ KeyChange(VirtualKeys.G, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.G, false, train);
+ }
+ if (!route.CurrentStation.OpenRightDoors)
+ {
+ KeyChange(VirtualKeys.H, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.H, false, train);
+ }
+ break;
+ case DoorInterlockStates.Left:
+ if (!route.CurrentStation.OpenLeftDoors)
+ {
+ KeyChange(VirtualKeys.G, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.G, false, train);
+ }
+ if (route.CurrentStation.OpenRightDoors)
+ {
+ KeyChange(VirtualKeys.H, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.H, false, train);
+ }
+ break;
+ case DoorInterlockStates.Right:
+ if (route.CurrentStation.OpenLeftDoors)
+ {
+ KeyChange(VirtualKeys.G, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.G, false, train);
+ }
+ if (!route.CurrentStation.OpenRightDoors)
+ {
+ KeyChange(VirtualKeys.H, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.H, false, train);
+ }
+ break;
+ case DoorInterlockStates.Locked:
+ if (route.CurrentStation.OpenLeftDoors)
+ {
+ KeyChange(VirtualKeys.G, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.G, false, train);
+ }
+ if (route.CurrentStation.OpenRightDoors)
+ {
+ KeyChange(VirtualKeys.H, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.H, false, train);
+ }
+ break;
+ }
+ }
}
}
}
diff --git a/src/OpenbveFcmbTrainPlugin.cs b/src/OpenbveFcmbTrainPlugin.cs
index 203e429..dcc400e 100644
--- a/src/OpenbveFcmbTrainPlugin.cs
+++ b/src/OpenbveFcmbTrainPlugin.cs
@@ -9,6 +9,9 @@ namespace OpenbveFcmbTrainPlugin
/// The train that is simulated by this plugin.
private Train Train;
+ /// The route where the train is running.
+ private Route Route;
+
/// Whether the train is initializing or reinitializing.
internal static bool Initializing = true;
@@ -23,6 +26,7 @@ namespace OpenbveFcmbTrainPlugin
properties.AISupport = AISupport.Basic;
properties.Panel = new int[256];
Train = new Train(properties.Panel);
+ Route = new Route();
return true;
}
@@ -51,7 +55,8 @@ namespace OpenbveFcmbTrainPlugin
/// The data passed to the plugin.
public void Elapse(ElapseData data)
{
- Train.Elapse(data);
+ Route.Elapse(data);
+ Train.Elapse(data, Route);
Initializing = false;
}
@@ -100,6 +105,7 @@ namespace OpenbveFcmbTrainPlugin
/// The new state of the doors.
public void DoorChange(DoorStates oldState, DoorStates newState)
{
+ Route.DoorChange(oldState, newState);
Train.DoorChange(oldState, newState);
}
@@ -119,7 +125,7 @@ namespace OpenbveFcmbTrainPlugin
/// The AI data.
public void PerformAI(AIData data)
{
- Train.PerformAI(data);
+ Train.PerformAI(data, Route);
}
}
diff --git a/src/OpenbveFcmbTrainPlugin.csproj b/src/OpenbveFcmbTrainPlugin.csproj
index 54c6b9b..e6fc0c3 100644
--- a/src/OpenbveFcmbTrainPlugin.csproj
+++ b/src/OpenbveFcmbTrainPlugin.csproj
@@ -40,10 +40,12 @@
+
+
diff --git a/src/Route/Route.cs b/src/Route/Route.cs
new file mode 100644
index 0000000..0602f7c
--- /dev/null
+++ b/src/Route/Route.cs
@@ -0,0 +1,112 @@
+using System.Collections.Generic;
+using OpenBveApi.Runtime;
+
+namespace OpenbveFcmbTrainPlugin
+{
+ internal class Route
+ {
+ /// Represents the state of the current station.
+ internal enum StationStates
+ {
+ /// The train has not arrived at the station yet.
+ Pending = 0,
+ /// The train has arrived at the station.
+ Arrived = 1,
+ /// The train is ready to depart.
+ Completed = 2,
+ }
+
+ /// The state of the current station.
+ internal StationStates StationState { get; private set; } = StationStates.Arrived;
+
+ /// The list of stations in the route.
+ internal List Stations;
+
+ /// The current station in the route.
+ internal Station CurrentStation;
+
+ /// The next station in the route.
+ internal Station NextStation;
+
+ /// The current state of the train doors.
+ private DoorStates DoorState;
+
+ /// The previous state of the train doors.
+ private DoorStates PreviousDoorState;
+
+ /// Is called every frame.
+ /// The data passed to the plugin.
+ internal void Elapse(ElapseData data)
+ {
+ if (OpenbveFcmbTrainPlugin.Initializing)
+ {
+ // Get the list of stations and set the current station
+ Stations = data.Stations;
+ UpdateStationData(data.Vehicle.Location);
+ }
+
+ if (StationState == StationStates.Completed && data.Vehicle.Location > CurrentStation.StopPosition + CurrentStation.ForwardTolerance)
+ {
+ // The train is heading for the next station
+ StationState = StationStates.Pending;
+ UpdateStationData(data.Vehicle.Location);
+ }
+
+ if (StationState == StationStates.Pending && data.Vehicle.Location > CurrentStation.StopPosition + CurrentStation.ForwardTolerance + 100)
+ {
+ // The train has passed the station without stopping
+ UpdateStationData(data.Vehicle.Location);
+ }
+
+ // Update station status after closing the doors
+ if (StationState == StationStates.Arrived && DoorState == DoorStates.None)
+ {
+ // The train is ready to leave the station
+ StationState = StationStates.Completed;
+ }
+
+ // Check if the train is at a station where the doors should open
+ bool ArrivedDoorStop = (PreviousDoorState == DoorStates.None && DoorState != DoorStates.None && (CurrentStation.OpenLeftDoors || CurrentStation.OpenRightDoors));
+ // Check if the train is at a station where the doors should not open
+ bool ArrivedNoDoorStop = (DoorState == DoorStates.None && !CurrentStation.OpenLeftDoors && !CurrentStation.OpenRightDoors);
+ if (StationState == StationStates.Pending && (ArrivedDoorStop || ArrivedNoDoorStop) && data.Vehicle.Speed.KilometersPerHour < 0.05 && data.Vehicle.Location >= CurrentStation.DefaultTrackPosition)
+ {
+ // The train has arrived at the station
+ StationState = StationStates.Arrived;
+ }
+ }
+
+ /// Is called when the state of the doors changes.
+ /// The old state of the doors.
+ /// The new state of the doors.
+ internal void DoorChange(DoorStates oldState, DoorStates newState)
+ {
+ PreviousDoorState = oldState;
+ DoorState = newState;
+ }
+
+ /// Updates the data for the current and next station.
+ /// The current location of the train.
+ internal void UpdateStationData(double location)
+ {
+ // Calculate the index of the current station
+ double position = location;
+ int currentIndex = 0;
+ if (Stations.Count > 1)
+ {
+ while (currentIndex > 0 && (Stations[currentIndex].StopPosition + Stations[currentIndex].ForwardTolerance > position || !Stations[currentIndex].PlayerStops()))
+ {
+ // Detects the station index when driving or jumping backwards
+ currentIndex--;
+ }
+ while (currentIndex < Stations.Count - 1 && (Stations[currentIndex].StopPosition + Stations[currentIndex].ForwardTolerance <= position || !Stations[currentIndex].PlayerStops()))
+ {
+ // Detects the station index when driving or jumping forwards
+ currentIndex++;
+ }
+ }
+ CurrentStation = Stations[currentIndex];
+ NextStation = currentIndex < Stations.Count - 1 ? Stations[currentIndex + 1] : null;
+ }
+ }
+}
diff --git a/src/Train/Train.cs b/src/Train/Train.cs
index 8c5726f..daf2898 100644
--- a/src/Train/Train.cs
+++ b/src/Train/Train.cs
@@ -62,7 +62,8 @@ namespace OpenbveFcmbTrainPlugin
/// Is called every frame.
/// The data.
- internal void Elapse(ElapseData data)
+ /// The route data.
+ internal void Elapse(ElapseData data, Route route)
{
State = data.Vehicle;
@@ -74,12 +75,11 @@ namespace OpenbveFcmbTrainPlugin
// Retrieve data from all devices
foreach (Device dev in Devices)
{
- dev.Update(this, OpenbveFcmbTrainPlugin.Initializing, data.ElapsedTime);
+ dev.Update(this, route, OpenbveFcmbTrainPlugin.Initializing, data.ElapsedTime);
data.DoorInterlockState |= dev.RequestedDoorInterlock;
if (dev.RequestedPowerNotch != -1) data.Handles.PowerNotch = dev.RequestedPowerNotch;
if (dev.RequestedBrakeNotch != -1) data.Handles.BrakeNotch = dev.RequestedBrakeNotch;
}
- data.DebugMessage = DoorState.ToString() + " " + data.DoorInterlockState.ToString();
}
/// Is called when the driver changes the reverser.
@@ -141,11 +141,12 @@ namespace OpenbveFcmbTrainPlugin
/// Is called when the plugin should perform the AI.
/// The AI data.
- internal void PerformAI(AIData data)
+ /// The route data.
+ internal void PerformAI(AIData data, Route route)
{
foreach (Device dev in Devices)
{
- dev.PerformAI(data, this);
+ dev.PerformAI(data, this, route);
}
}
}