ATC Dimetronic: Allow custom speed codes
This commit is contained in:
parent
e962d851b2
commit
77869e9c1e
3 changed files with 169 additions and 57 deletions
|
@ -1,4 +1,6 @@
|
||||||
using OpenBveApi.Runtime;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using OpenBveApi.Runtime;
|
||||||
|
|
||||||
namespace OpenbveFcmbTrainPlugin
|
namespace OpenbveFcmbTrainPlugin
|
||||||
{
|
{
|
||||||
|
@ -49,9 +51,6 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <summary>The current state of the track.</summary>
|
/// <summary>The current state of the track.</summary>
|
||||||
private TrackStates TrackState;
|
private TrackStates TrackState;
|
||||||
|
|
||||||
/// <summary>The upcoming signals in the route.</summary>
|
|
||||||
private SignalData[] Signals;
|
|
||||||
|
|
||||||
/// <summary>The maximum speed in YARD mode.</summary>
|
/// <summary>The maximum speed in YARD mode.</summary>
|
||||||
private readonly Speed YardMaximumSpeed;
|
private readonly Speed YardMaximumSpeed;
|
||||||
|
|
||||||
|
@ -64,7 +63,6 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <summary>Whether ATO is available or not on the train.</summary>
|
/// <summary>Whether ATO is available or not on the train.</summary>
|
||||||
private readonly bool AtoAvailable;
|
private readonly bool AtoAvailable;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>Represents an ATC speed code.</summary>
|
/// <summary>Represents an ATC speed code.</summary>
|
||||||
private class SpeedCode
|
private class SpeedCode
|
||||||
{
|
{
|
||||||
|
@ -72,13 +70,13 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
internal Speed WarningOn { get; private set; }
|
internal Speed WarningOn { get; private set; }
|
||||||
internal Speed WarningOff { get; private set; }
|
internal Speed WarningOff { get; private set; }
|
||||||
internal Speed TargetLimit { 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;
|
CurrentLimit = limit;
|
||||||
TargetLimit = target;
|
TargetLimit = target;
|
||||||
TargetLocation = location;
|
TargetDistance = distance;
|
||||||
if (limit == target)
|
if (limit == target)
|
||||||
{
|
{
|
||||||
// Constant speed
|
// Constant speed
|
||||||
|
@ -97,11 +95,56 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Updates the ATC speed code.</summary>
|
||||||
|
/// <param name="distance">The distance to the end of the signalling block.</param>
|
||||||
|
internal void Update(double distance)
|
||||||
|
{
|
||||||
|
TargetDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>The current speed code received by the train.</summary>
|
/// <summary>The current speed code received by the train.</summary>
|
||||||
private SpeedCode CurrentSpeedCode;
|
private SpeedCode CurrentSpeedCode;
|
||||||
|
|
||||||
|
/// <summary>Represents a signal code.</summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The list of signal codes recognised by the device.</summary>
|
||||||
|
private readonly List<SignalCode> SignalCodes;
|
||||||
|
|
||||||
|
/// <summary>The aspect of the current signal in the route.</summary>
|
||||||
|
private int CurrentSignalAspect;
|
||||||
|
|
||||||
/// <summary>The ideal power notch for the AI.</summary>
|
/// <summary>The ideal power notch for the AI.</summary>
|
||||||
private int AiPowerNotch;
|
private int AiPowerNotch;
|
||||||
|
|
||||||
|
@ -110,10 +153,12 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
|
|
||||||
/// <summary>Creates an instance of the Bombardier ATC device.</summary>
|
/// <summary>Creates an instance of the Bombardier ATC device.</summary>
|
||||||
/// <param name="yardMaxSpeed">The maximum speed in YARD mode, in km/h.</param>
|
/// <param name="yardMaxSpeed">The maximum speed in YARD mode, in km/h.</param>
|
||||||
|
/// <param name="signalCodes">The list of signal codes recognised by the device.</param>
|
||||||
/// <param name="atoAvailable">Whether ATO is available or not.</param>
|
/// <param name="atoAvailable">Whether ATO is available or not.</param>
|
||||||
internal AtcDimetronic(Speed yardMaxSpeed, bool atoAvailable)
|
internal AtcDimetronic(Speed yardMaxSpeed, List<SignalCode> signalCodes, bool atoAvailable)
|
||||||
{
|
{
|
||||||
YardMaximumSpeed = yardMaxSpeed;
|
YardMaximumSpeed = yardMaxSpeed;
|
||||||
|
SignalCodes = signalCodes;
|
||||||
AtoAvailable = atoAvailable;
|
AtoAvailable = atoAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,11 +252,13 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
case DeviceStates.ATP:
|
case DeviceStates.ATP:
|
||||||
train.ContinuousProtection = true;
|
train.ContinuousProtection = true;
|
||||||
train.VigilanceOverride = false;
|
train.VigilanceOverride = false;
|
||||||
|
CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
|
||||||
break;
|
break;
|
||||||
// ATC device is in ATO driving mode
|
// ATC device is in ATO driving mode
|
||||||
case DeviceStates.ATO:
|
case DeviceStates.ATO:
|
||||||
train.ContinuousProtection = true;
|
train.ContinuousProtection = true;
|
||||||
train.VigilanceOverride = true;
|
train.VigilanceOverride = true;
|
||||||
|
CurrentSpeedCode = GetSpeedCodeFromAspect(SignalCodes, CurrentSignalAspect);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,8 +312,6 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected)
|
if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected)
|
||||||
{
|
{
|
||||||
DeviceState = DeviceStates.ATP;
|
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)
|
if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected)
|
||||||
{
|
{
|
||||||
DeviceState = DeviceStates.ATO;
|
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
|
// Override device if possible
|
||||||
if (stopped && train.PhysicalHandles.PowerNotch == 0)
|
if (stopped && train.PhysicalHandles.PowerNotch == 0)
|
||||||
{
|
{
|
||||||
|
CurrentSpeedCode = new SpeedCode(new Speed(0), new Speed(0));
|
||||||
DeviceState = DeviceStates.Override;
|
DeviceState = DeviceStates.Override;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -331,12 +375,7 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <param name="signal">The signal data.</param>
|
/// <param name="signal">The signal data.</param>
|
||||||
internal override void SetSignal(SignalData[] signal)
|
internal override void SetSignal(SignalData[] signal)
|
||||||
{
|
{
|
||||||
Signals = signal;
|
CurrentSignalAspect = signal[0].Aspect;
|
||||||
|
|
||||||
if (DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO)
|
|
||||||
{
|
|
||||||
CurrentSpeedCode = new SpeedCode(AspectLimit[signal[0].Aspect], AspectLimit[signal[0].Aspect]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called when a beacon is passed.</summary>
|
/// <summary>Is called when a beacon is passed.</summary>
|
||||||
|
@ -364,13 +403,16 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <param name="route">The current route.</param>
|
/// <param name="route">The current route.</param>
|
||||||
internal override void PerformAI(AIData data, Train train, Route 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;
|
double speed = train.State.Speed.KilometersPerHour;
|
||||||
bool stopped = speed < 0.05;
|
bool stopped = speed < 0.05;
|
||||||
|
|
||||||
|
// Set reverser to forward
|
||||||
|
if (data.Handles.Reverser != 1)
|
||||||
|
{
|
||||||
|
data.Handles.Reverser = 1;
|
||||||
|
data.Response = AIResponse.Short;
|
||||||
|
}
|
||||||
|
|
||||||
switch (DeviceState)
|
switch (DeviceState)
|
||||||
{
|
{
|
||||||
case DeviceStates.NoMode:
|
case DeviceStates.NoMode:
|
||||||
|
@ -386,46 +428,101 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DeviceStates.YARD:
|
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:
|
case DeviceStates.ATP:
|
||||||
// Calculate ideal notch for AI when approaching the speed limit
|
// 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 (speed > CurrentSpeedCode.WarningOn.KilometersPerHour - 2 && train.Acceleration > 0.1)
|
if (stopped)
|
||||||
{
|
{
|
||||||
if (data.Handles.PowerNotch > 0)
|
switch (TrackState)
|
||||||
{
|
{
|
||||||
AiPowerNotch -= 1;
|
case TrackStates.Disable:
|
||||||
}
|
case TrackStates.Unprotected:
|
||||||
else if (train.Specs.HasHoldBrake)
|
KeyChange(VirtualKeys.I, true, train);
|
||||||
{
|
data.Response = AIResponse.Short;
|
||||||
data.Handles.HoldBrake = true;
|
KeyChange(VirtualKeys.I, false, train);
|
||||||
}
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CalculateAiNotches(data, train, route);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Calculates the ideal notches for the AI driver.</summary>
|
||||||
|
/// <param name="data">The AI data.</param>
|
||||||
|
/// <param name="train">The current train.</param>
|
||||||
|
/// <param name="route">The current route.</param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Generates the corresponding speed code from a signal aspect.</summary>
|
||||||
|
/// <param name="signalCodes">The list of signal codes.</param>
|
||||||
|
/// <param name="aspect">The current signal aspect.</param>
|
||||||
|
private SpeedCode GetSpeedCodeFromAspect(List<SignalCode> 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Collections.Generic;
|
||||||
using OpenBveApi.Runtime;
|
using OpenBveApi.Runtime;
|
||||||
|
|
||||||
namespace OpenbveFcmbTrainPlugin
|
namespace OpenbveFcmbTrainPlugin
|
||||||
|
@ -32,6 +34,7 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
|
|
||||||
internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6);
|
internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6);
|
||||||
internal bool AtcDimetronicAtoAvailable;
|
internal bool AtcDimetronicAtoAvailable;
|
||||||
|
internal List<AtcDimetronic.SignalCode> AtcDimetronicSignalCodes = new List<AtcDimetronic.SignalCode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Represents the plugin settings.</summary>
|
/// <summary>Represents the plugin settings.</summary>
|
||||||
|
@ -207,6 +210,18 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
case "atoavailable":
|
case "atoavailable":
|
||||||
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
|
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
}
|
}
|
||||||
if (settings.AtcDimetronicDeviceEnabled)
|
if (settings.AtcDimetronicDeviceEnabled)
|
||||||
{
|
{
|
||||||
Devices.Add(new AtcDimetronic(settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicAtoAvailable));
|
Devices.Add(new AtcDimetronic(settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue