openbve-fcmb-train-plugin/src/Devices/Deadman.cs

125 lines
No EOL
5.2 KiB
C#

using System;
using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin
{
/// <summary>A deadman switch device to stop the train if the driver does not periodically acknowledge it.</summary>
internal class Deadman : Device
{
/// <summary>Represents the state of the device.</summary>
private enum DeviceStates
{
/// <summary>The device is inactive.</summary>
Inactive,
/// <summary>The device is active.</summary>
Active,
/// <summary>The device is in emergency state.</summary>
Emergency,
}
/// <summary>The current state of the device.</summary>
private DeviceStates DeviceState;
/// <summary>The counter. This starts at zero and counts up until the brake delay time is reached.</summary>
private double Counter;
/// <summary>The delay time until the service brake is applied, in seconds.</summary>
private double BrakeDelay = 5.0;
/// <summary>Whether the train must be completely stopped to release the brakes.</summary>
private bool FullReset;
/// <summary>Creates an instance of the Deadman device.</summary>
/// <param name="brakeDelay">The delay before the brakes are applied, in seconds.</param>
/// <param name="fullReset">Whether the train must be completely stopped to release the brakes.</param>
internal Deadman(double brakeDelay, bool fullReset)
{
BrakeDelay = brakeDelay;
FullReset = fullReset;
}
/// <summary>Is called when the device state should be updated.</summary>
/// <param name="train">The current train.</param>
/// <param name="route">The current route.</param>
/// <param name="init">Whether the device should initialize.</param>
/// <param name="elapsedTime">The time elapsed since the previous call.</param>
internal override void Update(Train train, Route route, bool init, Time elapsedTime)
{
if (train.VigilanceOverride)
{
// The train wants to override vigilance devices, so the device is inactive
DeviceState = DeviceStates.Inactive;
}
switch (DeviceState)
{
case DeviceStates.Active:
// The device is active, update the counter every frame
Counter += elapsedTime.Seconds;
RequestedBrakeNotch = -1;
if (Counter > BrakeDelay)
{
// Switch to emergency mode when the counter reaches the brake delay time
DeviceState = DeviceStates.Emergency;
}
break;
case DeviceStates.Inactive:
// The device is being overridden, release the brakes
RequestedBrakeNotch = -1;
if (!train.VigilanceOverride)
{
// If the device is no longer overridden, it should be active again
DeviceState = DeviceStates.Active;
}
break;
case DeviceStates.Emergency:
// Apply the brakes when the device is in emergency mode
RequestedBrakeNotch = train.Specs.BrakeNotches;
break;
}
}
/// <summary>Is called when the state of a key changes.</summary>
/// <param name="key">The key.</param>
/// <param name="pressed">Whether the key is pressed or released.</param>
/// <param name="train">The current train.</param>
internal override void KeyChange(VirtualKeys key, bool pressed, Train train)
{
double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05;
if (pressed)
{
switch (key)
{
case VirtualKeys.S:
if (DeviceState == DeviceStates.Active || (DeviceState == DeviceStates.Emergency & !FullReset))
{
// Reset the counter if the delay time has not been exceeded or if a full reset is not required
Counter = 0;
DeviceState = DeviceStates.Active;
}
else if (DeviceState == DeviceStates.Emergency && stopped)
{
// Reset the counter after the train has stopped
Counter = 0;
DeviceState = DeviceStates.Active;
}
break;
}
}
}
/// <summary>Is called when the plugin should perform the AI.</summary>
/// <param name="data">The AI data.</param>
/// <param name="train">The current train.</param>
/// <param name="route">The current route.</param>
internal override void PerformAI(AIData data, Train train, Route route)
{
if (DeviceState != DeviceStates.Inactive)
{
KeyChange(VirtualKeys.S, true, train);
}
}
}
}