using System;
using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin
{
/// A device controlling the door operation.
internal class DoorClosingSound : Device
{
/// Whether the door closing sound is required to be played to close the doors.
private readonly bool RequireDoorClosingSound;
/// The duration of the door closing sound, in seconds.
private readonly double DoorClosingSoundDuration;
/// The timeout after which the door closing sound needs to be played again, in seconds.
private readonly double DoorClosingSoundTimeout;
/// The counter for the door closing sound.
private double DoorClosingSoundCounter;
/// Whether the AI should trigger the door closing sound.
private bool AiTriggerDoorClosingSound;
/// The index of the door closing sound.
private readonly int DoorClosingSoundIndex;
/// The current time.
private Time CurrentTime = new Time(0);
/// The time when the doors last opened.
private Time DoorOpenTime = new Time(0);
/// Whether the door closing sound is required to be played to close the doors.
/// The delay before the brakes are applied, in seconds.
/// The duration of the door closing sound, in seconds.
/// The timeout after which the door closing sound needs to be played again, in seconds.
/// The index of the door closing sound.
internal DoorClosingSound(bool requireClosingSound, double closingSoundDuration, double closingSoundTimeout, int closingSoundIndex)
{
RequireDoorClosingSound = requireClosingSound;
DoorClosingSoundDuration = closingSoundDuration;
DoorClosingSoundTimeout = closingSoundTimeout;
DoorClosingSoundIndex = closingSoundIndex;
}
/// 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, Route route, bool init, Time elapsedTime)
{
// Update current time
CurrentTime = route.CurrentTime;
if (init)
{
// Set door closing counter to value higher than maximum where doors are allowed to close
DoorClosingSoundCounter = DoorClosingSoundDuration + DoorClosingSoundTimeout;
}
// Update door closing sound counter
DoorClosingSoundCounter += elapsedTime.Seconds;
// Lock and unlock doors depending on whether the door closing sound has been played
if (RequireDoorClosingSound && train.DoorState != DoorStates.None)
{
if (DoorClosingSoundCounter > DoorClosingSoundDuration + DoorClosingSoundTimeout)
{
switch (train.DoorState)
{
case DoorStates.Both:
RequestedDoorInterlock = DoorInterlockStates.Locked;
break;
case DoorStates.Left:
RequestedDoorInterlock = DoorInterlockStates.Right;
break;
case DoorStates.Right:
RequestedDoorInterlock = DoorInterlockStates.Left;
break;
}
}
else if (DoorClosingSoundCounter > DoorClosingSoundDuration)
{
switch (train.DoorState)
{
case DoorStates.Both:
RequestedDoorInterlock = DoorInterlockStates.Unlocked;
break;
case DoorStates.Left:
RequestedDoorInterlock = DoorInterlockStates.Left;
break;
case DoorStates.Right:
RequestedDoorInterlock = DoorInterlockStates.Right;
break;
}
}
}
else
{
RequestedDoorInterlock = DoorInterlockStates.Unlocked;
}
// Check if AI needs to trigger the door closing sound
if (train.DoorState != DoorStates.None && DoorClosingSoundCounter > DoorClosingSoundDuration + DoorClosingSoundTimeout)
{
if (route.CurrentStation.Type == StationType.Normal || route.CurrentStation.Type == StationType.RequestStop)
{
// The current station is an intermediate stop
if (route.CurrentStation.DepartureTime < 0)
{
// The current station has dwell time, not a specific departure time
// Calculate departure time from the time when the doors opened
AiTriggerDoorClosingSound |= CurrentTime.Seconds >= DoorOpenTime.Seconds + (route.CurrentStation.StopTime - DoorClosingSoundDuration);
}
else
{
// Use departure time - door closing sound duration
AiTriggerDoorClosingSound |= CurrentTime.Seconds >= route.CurrentStation.DepartureTime - DoorClosingSoundDuration;
}
}
else
{
// The doors have been opened between stations
if (route.CurrentStation.StopPosition - route.CurrentStation.BackwardTolerance > train.State.Location)
{
AiTriggerDoorClosingSound = true;
}
else
{
AiTriggerDoorClosingSound = false;
}
}
}
else
{
AiTriggerDoorClosingSound = false;
}
}
/// Is called when the state of a key changes.
/// The key.
/// Whether the key is pressed or released.
/// The current train.
internal override void KeyChange(VirtualKeys key, bool pressed, Train train)
{
if (pressed)
{
switch (key)
{
case VirtualKeys.F:
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
{
// Play the door closing sound and reset timeout
DoorClosingSoundCounter = 0;
if (!SoundManager.Playing(DoorClosingSoundIndex))
{
SoundManager.Play(DoorClosingSoundIndex, 1, 1, false);
}
}
break;
}
}
}
/// Is called when the state of the doors changes.
/// The old state of the doors.
/// The new state of the doors.
internal override void DoorChange(DoorStates oldState, DoorStates newState)
{
// Set arrival time when doors open
if (oldState == DoorStates.None && newState != DoorStates.None)
{
DoorOpenTime = CurrentTime;
}
// Set door closing counter to value higher than maximum where doors are allowed to close
// This effectively locks the doors when they open
DoorClosingSoundCounter = DoorClosingSoundDuration + DoorClosingSoundTimeout;
}
/// Is called when the device should perform the AI.
/// The AI data.
/// The current train.
/// The current route.
internal override void PerformAI(AIData data, Train train, Route route)
{
if (AiTriggerDoorClosingSound)
{
KeyChange(VirtualKeys.F, true, train);
data.Response = AIResponse.Short;
KeyChange(VirtualKeys.F, false, train);
AiTriggerDoorClosingSound = false;
}
}
}
}