diff --git a/src/Devices/AtcDimetronic.cs b/src/Devices/AtcDimetronic.cs
index 9f6c5d5..6ce85e1 100644
--- a/src/Devices/AtcDimetronic.cs
+++ b/src/Devices/AtcDimetronic.cs
@@ -1,4 +1,6 @@
-using OpenBveApi.Runtime;
+using System.Collections.Generic;
+using System.Globalization;
+using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin
{
@@ -49,9 +51,6 @@ namespace OpenbveFcmbTrainPlugin
/// The current state of the track.
private TrackStates TrackState;
- /// The upcoming signals in the route.
- private SignalData[] Signals;
-
/// The maximum speed in YARD mode.
private readonly Speed YardMaximumSpeed;
@@ -64,7 +63,6 @@ namespace OpenbveFcmbTrainPlugin
/// Whether ATO is available or not on the train.
private readonly bool AtoAvailable;
-
/// Represents an ATC speed code.
private class SpeedCode
{
@@ -72,13 +70,13 @@ namespace OpenbveFcmbTrainPlugin
internal Speed WarningOn { get; private set; }
internal Speed WarningOff { get; private set; }
internal Speed TargetLimit { get; private set; }
- internal double TargetLocation { get; private set; }
+ internal double TargetDistance { get; private set; }
- internal SpeedCode(Speed limit, Speed target, double location)
+ internal SpeedCode(Speed limit, Speed target, double distance)
{
CurrentLimit = limit;
TargetLimit = target;
- TargetLocation = location;
+ TargetDistance = distance;
if (limit == target)
{
// Constant speed
@@ -97,11 +95,56 @@ namespace OpenbveFcmbTrainPlugin
{
}
+ /// Updates the ATC speed code.
+ /// The distance to the end of the signalling block.
+ internal void Update(double distance)
+ {
+ TargetDistance = distance;
+ }
+
}
/// The current speed code received by the train.
private SpeedCode CurrentSpeedCode;
+ /// Represents a signal code.
+ internal class SignalCode
+ {
+ internal int Aspect;
+ internal Speed Limit;
+ internal Speed Target;
+
+ internal SignalCode(int aspect, string data)
+ {
+ Aspect = aspect;
+ Limit = new Speed(0);
+ Target = new Speed(0);
+ if (data.Contains("/"))
+ {
+ int separator = data.IndexOf('/');
+ string a = data.Substring(0, separator);
+ string b = data.Substring(separator + 1);
+ if (double.TryParse(a, NumberStyles.Float, CultureInfo.InvariantCulture, out double an) && double.TryParse(b, NumberStyles.Float, CultureInfo.InvariantCulture, out double bn))
+ {
+ if (an >= bn && an >= 0)
+ {
+ Limit = new Speed(an / 3.6);
+ }
+ if (bn <= an && bn >= 0)
+ {
+ Target = new Speed(bn / 3.6);
+ }
+ }
+ }
+ }
+ }
+
+ /// The list of signal codes recognised by the device.
+ private readonly List SignalCodes;
+
+ /// The aspect of the current signal in the route.
+ private int CurrentSignalAspect;
+
/// The ideal power notch for the AI.
private int AiPowerNotch;
@@ -110,10 +153,12 @@ namespace OpenbveFcmbTrainPlugin
/// Creates an instance of the Bombardier ATC device.
/// The maximum speed in YARD mode, in km/h.
+ /// The list of signal codes recognised by the device.
/// Whether ATO is available or not.
- internal AtcDimetronic(Speed yardMaxSpeed, bool atoAvailable)
+ internal AtcDimetronic(Speed yardMaxSpeed, List signalCodes, bool atoAvailable)
{
YardMaximumSpeed = yardMaxSpeed;
+ SignalCodes = signalCodes;
AtoAvailable = atoAvailable;
}
@@ -207,11 +252,13 @@ namespace OpenbveFcmbTrainPlugin
case DeviceStates.ATP:
train.ContinuousProtection = true;
train.VigilanceOverride = false;
+ CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
break;
// ATC device is in ATO driving mode
case DeviceStates.ATO:
train.ContinuousProtection = true;
train.VigilanceOverride = true;
+ CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
break;
}
@@ -265,8 +312,6 @@ namespace OpenbveFcmbTrainPlugin
if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected)
{
DeviceState = DeviceStates.ATP;
- // Update ATC speed code
- CurrentSpeedCode = new SpeedCode(AspectLimit[Signals[0].Aspect], AspectLimit[Signals[0].Aspect]);
}
}
}
@@ -281,8 +326,6 @@ namespace OpenbveFcmbTrainPlugin
if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected)
{
DeviceState = DeviceStates.ATO;
- // Update ATC speed code
- CurrentSpeedCode = new SpeedCode(AspectLimit[Signals[0].Aspect], AspectLimit[Signals[0].Aspect]);
}
}
}
@@ -310,6 +353,7 @@ namespace OpenbveFcmbTrainPlugin
// Override device if possible
if (stopped && train.PhysicalHandles.PowerNotch == 0)
{
+ CurrentSpeedCode = new SpeedCode(new Speed(0), new Speed(0));
DeviceState = DeviceStates.Override;
}
break;
@@ -331,12 +375,7 @@ namespace OpenbveFcmbTrainPlugin
/// The signal data.
internal override void SetSignal(SignalData[] signal)
{
- Signals = signal;
-
- if (DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO)
- {
- CurrentSpeedCode = new SpeedCode(AspectLimit[signal[0].Aspect], AspectLimit[signal[0].Aspect]);
- }
+ CurrentSignalAspect = signal[0].Aspect;
}
/// Is called when a beacon is passed.
@@ -364,13 +403,16 @@ namespace OpenbveFcmbTrainPlugin
/// The current route.
internal override void PerformAI(AIData data, Train train, Route route)
{
- // Set AI notches to what the AI is doing right now
- AiBrakeNotch = data.Handles.BrakeNotch;
- AiPowerNotch = data.Handles.PowerNotch;
-
double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05;
+ // Set reverser to forward
+ if (data.Handles.Reverser != 1)
+ {
+ data.Handles.Reverser = 1;
+ data.Response = AIResponse.Short;
+ }
+
switch (DeviceState)
{
case DeviceStates.NoMode:
@@ -386,46 +428,101 @@ namespace OpenbveFcmbTrainPlugin
}
break;
case DeviceStates.YARD:
+ // Select ATP (M+ATP) mode if the train is stopped and receiving ATC codes from the track
+ if (stopped)
+ {
+ switch (TrackState)
+ {
+ case TrackStates.Enable:
+ case TrackStates.ATC:
+ KeyChange(VirtualKeys.J, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.J, false, train);
+ break;
+ }
+ }
+ CalculateAiNotches(data, train, route);
+ break;
case DeviceStates.ATP:
- // Calculate ideal notch for AI when approaching the speed limit
- if (speed > CurrentSpeedCode.WarningOn.KilometersPerHour - 2 && train.Acceleration > 0.1)
+ // Select YARD (M+25) mode if the train is stopped and not receiving ATC codes from the track or a mode change is required
+ if (stopped)
{
- if (data.Handles.PowerNotch > 0)
+ switch (TrackState)
{
- AiPowerNotch -= 1;
- }
- else if (train.Specs.HasHoldBrake)
- {
- data.Handles.HoldBrake = true;
- }
- else
- {
- AiBrakeNotch += 1;
- }
- }
- else if (speed < CurrentSpeedCode.WarningOff.KilometersPerHour - 2 && train.Acceleration < 0.25)
- {
- if (data.Handles.BrakeNotch > 0)
- {
- AiBrakeNotch -= 1;
- }
- else
- {
- AiPowerNotch += 1;
- }
- }
- // If still far from next station, take control of AI handles
- if (speed / (route.CurrentStation.StopPosition - train.State.Location) < 0.2)
- {
- if (speed > CurrentSpeedCode.CurrentLimit.KilometersPerHour - 5)
- {
- data.Handles.PowerNotch = AiPowerNotch;
- data.Handles.BrakeNotch = AiBrakeNotch;
- data.Response = AIResponse.Medium;
+ case TrackStates.Disable:
+ case TrackStates.Unprotected:
+ KeyChange(VirtualKeys.I, true, train);
+ data.Response = AIResponse.Short;
+ KeyChange(VirtualKeys.I, false, train);
+ break;
}
}
+ CalculateAiNotches(data, train, route);
break;
}
}
+
+ /// Calculates the ideal notches for the AI driver.
+ /// The AI data.
+ /// The current train.
+ /// The current route.
+ private void CalculateAiNotches(AIData data, Train train, Route route)
+ {
+ double speed = train.State.Speed.KilometersPerHour;
+ bool stopped = speed < 0.05;
+
+ // Set AI notches to what the AI is doing right now
+ AiBrakeNotch = data.Handles.BrakeNotch;
+ AiPowerNotch = data.Handles.PowerNotch;
+
+ // Calculate ideal notch for AI when approaching the speed limit
+ if (speed > CurrentSpeedCode.WarningOn.KilometersPerHour - 2 && train.Acceleration > 0.1)
+ {
+ if (data.Handles.PowerNotch > 0)
+ {
+ AiPowerNotch -= 1;
+ }
+ else
+ {
+ AiBrakeNotch += 1;
+ }
+ }
+ else if (speed < CurrentSpeedCode.WarningOff.KilometersPerHour - 2 && train.Acceleration < 0.25)
+ {
+ if (data.Handles.BrakeNotch > 0)
+ {
+ AiBrakeNotch -= 1;
+ }
+ else
+ {
+ AiPowerNotch += 1;
+ }
+ }
+ // If still far from next station, take control of AI handles
+ if (speed / (route.CurrentStation.StopPosition - train.State.Location) < 0.2)
+ {
+ if (speed > CurrentSpeedCode.CurrentLimit.KilometersPerHour - 5)
+ {
+ data.Handles.PowerNotch = AiPowerNotch;
+ data.Handles.BrakeNotch = AiBrakeNotch;
+ data.Response = AIResponse.Medium;
+ }
+ }
+ }
+
+ /// Generates the corresponding speed code from a signal aspect.
+ /// The list of signal codes.
+ /// The current signal aspect.
+ private SpeedCode GetSpeedCodeFromAspect(List signalCodes, int aspect)
+ {
+ foreach (SignalCode signal in signalCodes)
+ {
+ if (signal.Aspect == aspect)
+ {
+ return new SpeedCode(signal.Limit, signal.Target);
+ }
+ }
+ return new SpeedCode(new Speed(0), new Speed(0));
+ }
}
}
diff --git a/src/Managers/ConfigManager.cs b/src/Managers/ConfigManager.cs
index 50a1d77..4d1ebe7 100644
--- a/src/Managers/ConfigManager.cs
+++ b/src/Managers/ConfigManager.cs
@@ -1,4 +1,6 @@
using System;
+using System.Globalization;
+using System.Collections.Generic;
using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin
@@ -32,6 +34,7 @@ namespace OpenbveFcmbTrainPlugin
internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6);
internal bool AtcDimetronicAtoAvailable;
+ internal List AtcDimetronicSignalCodes = new List();
}
/// Represents the plugin settings.
@@ -207,6 +210,18 @@ namespace OpenbveFcmbTrainPlugin
case "atoavailable":
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
break;
+ default:
+ int aspect;
+ if (int.TryParse(Key, NumberStyles.Integer, CultureInfo.InvariantCulture, out aspect))
+ {
+ AtcDimetronic.SignalCode signalCode = new AtcDimetronic.SignalCode(aspect, Value);
+ if (signalCode != null)
+ {
+ PluginSettings.AtcDimetronicSignalCodes.Add(signalCode);
+ break;
+ }
+ }
+ break;
}
break;
}
diff --git a/src/Train/Train.cs b/src/Train/Train.cs
index d7d17e1..e9e1fb8 100644
--- a/src/Train/Train.cs
+++ b/src/Train/Train.cs
@@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin
}
if (settings.AtcDimetronicDeviceEnabled)
{
- Devices.Add(new AtcDimetronic(settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicAtoAvailable));
+ Devices.Add(new AtcDimetronic(settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
}
}