private static void UpdateTrainPhysicsAndControls(Train Train, double TimeElapsed)
{
if (TimeElapsed == 0.0)
{
return;
}
// move cars
for (int i = 0; i < Train.Cars.Length; i++)
{
MoveCar(Train, i, Train.Cars[i].Specs.CurrentSpeed * TimeElapsed, TimeElapsed);
if (Train.State == TrainState.Disposed)
{
return;
}
}
// update station and doors
UpdateTrainStation(Train, TimeElapsed);
UpdateTrainDoors(Train, TimeElapsed);
// delayed handles
{
// power notch
if (Train.Specs.CurrentPowerNotch.DelayedChanges.Length == 0)
{
if (Train.Specs.CurrentPowerNotch.Safety < Train.Specs.CurrentPowerNotch.Actual)
{
if (Train.Specs.PowerNotchReduceSteps <= 1)
{
Train.Specs.CurrentPowerNotch.AddChange(Train, Train.Specs.CurrentPowerNotch.Actual - 1, Train.Specs.DelayPowerDown);
}
else if (Train.Specs.CurrentPowerNotch.Safety + Train.Specs.PowerNotchReduceSteps <= Train.Specs.CurrentPowerNotch.Actual | Train.Specs.CurrentPowerNotch.Safety == 0)
{
Train.Specs.CurrentPowerNotch.AddChange(Train, Train.Specs.CurrentPowerNotch.Safety, Train.Specs.DelayPowerDown);
}
}
else if (Train.Specs.CurrentPowerNotch.Safety > Train.Specs.CurrentPowerNotch.Actual)
{
Train.Specs.CurrentPowerNotch.AddChange(Train, Train.Specs.CurrentPowerNotch.Actual + 1, Train.Specs.DelayPowerUp);
}
}
else
{
int m = Train.Specs.CurrentPowerNotch.DelayedChanges.Length - 1;
if (Train.Specs.CurrentPowerNotch.Safety < Train.Specs.CurrentPowerNotch.DelayedChanges[m].Value)
{
Train.Specs.CurrentPowerNotch.AddChange(Train, Train.Specs.CurrentPowerNotch.Safety, Train.Specs.DelayPowerDown);
}
else if (Train.Specs.CurrentPowerNotch.Safety > Train.Specs.CurrentPowerNotch.DelayedChanges[m].Value)
{
Train.Specs.CurrentPowerNotch.AddChange(Train, Train.Specs.CurrentPowerNotch.Safety, Train.Specs.DelayPowerUp);
}
}
if (Train.Specs.CurrentPowerNotch.DelayedChanges.Length >= 1)
{
if (Train.Specs.CurrentPowerNotch.DelayedChanges[0].Time <= Game.SecondsSinceMidnight)
{
Train.Specs.CurrentPowerNotch.Actual = Train.Specs.CurrentPowerNotch.DelayedChanges[0].Value;
Train.Specs.CurrentPowerNotch.RemoveChanges(1);
}
}
}
{
// brake notch
int sec = Train.Specs.CurrentEmergencyBrake.Safety ? Train.Specs.MaximumBrakeNotch : Train.Specs.CurrentBrakeNotch.Safety;
if (Train.Specs.CurrentBrakeNotch.DelayedChanges.Length == 0)
{
if (sec < Train.Specs.CurrentBrakeNotch.Actual)
{
Train.Specs.CurrentBrakeNotch.AddChange(Train, Train.Specs.CurrentBrakeNotch.Actual - 1, Train.Specs.DelayBrakeDown);
}
else if (sec > Train.Specs.CurrentBrakeNotch.Actual)
{
Train.Specs.CurrentBrakeNotch.AddChange(Train, Train.Specs.CurrentBrakeNotch.Actual + 1, Train.Specs.DelayBrakeUp);
}
}
else
{
int m = Train.Specs.CurrentBrakeNotch.DelayedChanges.Length - 1;
if (sec < Train.Specs.CurrentBrakeNotch.DelayedChanges[m].Value)
{
Train.Specs.CurrentBrakeNotch.AddChange(Train, sec, Train.Specs.DelayBrakeDown);
}
else if (sec > Train.Specs.CurrentBrakeNotch.DelayedChanges[m].Value)
{
Train.Specs.CurrentBrakeNotch.AddChange(Train, sec, Train.Specs.DelayBrakeUp);
}
}
if (Train.Specs.CurrentBrakeNotch.DelayedChanges.Length >= 1)
{
if (Train.Specs.CurrentBrakeNotch.DelayedChanges[0].Time <= Game.SecondsSinceMidnight)
{
Train.Specs.CurrentBrakeNotch.Actual = Train.Specs.CurrentBrakeNotch.DelayedChanges[0].Value;
Train.Specs.CurrentBrakeNotch.RemoveChanges(1);
}
}
}
{
// air brake handle
if (Train.Specs.AirBrake.Handle.DelayedValue != AirBrakeHandleState.Invalid)
{
if (Train.Specs.AirBrake.Handle.DelayedTime <= Game.SecondsSinceMidnight)
{
Train.Specs.AirBrake.Handle.Actual = Train.Specs.AirBrake.Handle.DelayedValue;
Train.Specs.AirBrake.Handle.DelayedValue = AirBrakeHandleState.Invalid;
}
}
else
{
if (Train.Specs.AirBrake.Handle.Safety == AirBrakeHandleState.Release & Train.Specs.AirBrake.Handle.Actual != AirBrakeHandleState.Release)
{
Train.Specs.AirBrake.Handle.DelayedValue = AirBrakeHandleState.Release;
Train.Specs.AirBrake.Handle.DelayedTime = Game.SecondsSinceMidnight;
}
else if (Train.Specs.AirBrake.Handle.Safety == AirBrakeHandleState.Service & Train.Specs.AirBrake.Handle.Actual != AirBrakeHandleState.Service)
{
Train.Specs.AirBrake.Handle.DelayedValue = AirBrakeHandleState.Service;
Train.Specs.AirBrake.Handle.DelayedTime = Game.SecondsSinceMidnight;
}
else if (Train.Specs.AirBrake.Handle.Safety == AirBrakeHandleState.Lap)
{
Train.Specs.AirBrake.Handle.Actual = AirBrakeHandleState.Lap;
}
}
}
{
// emergency brake
if (Train.Specs.CurrentEmergencyBrake.Safety & !Train.Specs.CurrentEmergencyBrake.Actual)
{
double t = Game.SecondsSinceMidnight;
if (t < Train.Specs.CurrentEmergencyBrake.ApplicationTime) Train.Specs.CurrentEmergencyBrake.ApplicationTime = t;
if (Train.Specs.CurrentEmergencyBrake.ApplicationTime <= Game.SecondsSinceMidnight)
{
Train.Specs.CurrentEmergencyBrake.Actual = true;
Train.Specs.CurrentEmergencyBrake.ApplicationTime = double.MaxValue;
}
}
else if (!Train.Specs.CurrentEmergencyBrake.Safety)
{
Train.Specs.CurrentEmergencyBrake.Actual = false;
}
}
Train.Specs.CurrentHoldBrake.Actual = Train.Specs.CurrentHoldBrake.Driver;
// update speeds
UpdateSpeeds(Train, TimeElapsed);
// run sound
for (int i = 0; i < Train.Cars.Length; i++)
{
const double factor = 0.04; // 90 km/h -> m/s -> 1/x
double speed = Math.Abs(Train.Cars[i].Specs.CurrentSpeed);
if (Train.Cars[i].Derailed)
{
speed = 0.0;
}
double pitch = speed * factor;
double basegain;
if (Train.Cars[i].Specs.CurrentSpeed == 0.0)
{
if (i != 0)
{
Train.Cars[i].Sounds.RunNextReasynchronizationPosition = Train.Cars[0].FrontAxle.Follower.TrackPosition;
}
}
else if (Train.Cars[i].Sounds.RunNextReasynchronizationPosition == double.MaxValue & Train.Cars[i].Sounds.FrontAxleRunIndex >= 0)
{
double distance = Math.Abs(Train.Cars[i].FrontAxle.Follower.TrackPosition - World.CameraTrackFollower.TrackPosition);
const double minDistance = 150.0;
const double maxDistance = 750.0;
if (distance > minDistance)
{
if (Train.Cars[i].Sounds.FrontAxleRunIndex < Train.Cars[i].Sounds.Run.Length)
{
Sounds.SoundBuffer buffer = Train.Cars[i].Sounds.Run[Train.Cars[i].Sounds.FrontAxleRunIndex].Buffer;
if (buffer != null)
{
double duration = Sounds.GetDuration(buffer);
if (duration > 0.0)
{
double offset = distance > maxDistance ? 25.0 : 300.0;
Train.Cars[i].Sounds.RunNextReasynchronizationPosition = duration * Math.Ceiling((Train.Cars[0].FrontAxle.Follower.TrackPosition + offset) / duration);
}
}
}
}
}
if (Train.Cars[i].FrontAxle.Follower.TrackPosition >= Train.Cars[i].Sounds.RunNextReasynchronizationPosition)
{
Train.Cars[i].Sounds.RunNextReasynchronizationPosition = double.MaxValue;
basegain = 0.0;
}
else
{
basegain = speed < 2.77777777777778 ? 0.36 * speed : 1.0;
}
for (int j = 0; j < Train.Cars[i].Sounds.Run.Length; j++)
{
if (j == Train.Cars[i].Sounds.FrontAxleRunIndex | j == Train.Cars[i].Sounds.RearAxleRunIndex)
{
Train.Cars[i].Sounds.RunVolume[j] += 3.0 * TimeElapsed;
if (Train.Cars[i].Sounds.RunVolume[j] > 1.0) Train.Cars[i].Sounds.RunVolume[j] = 1.0;
}
else
{
Train.Cars[i].Sounds.RunVolume[j] -= 3.0 * TimeElapsed;
if (Train.Cars[i].Sounds.RunVolume[j] < 0.0) Train.Cars[i].Sounds.RunVolume[j] = 0.0;
}
double gain = basegain * Train.Cars[i].Sounds.RunVolume[j];
if (Sounds.IsPlaying(Train.Cars[i].Sounds.Run[j].Source))
{
if (pitch > 0.01 & gain > 0.001)
{
Train.Cars[i].Sounds.Run[j].Source.Pitch = pitch;
Train.Cars[i].Sounds.Run[j].Source.Volume = gain;
}
else
{
Sounds.StopSound(Train.Cars[i].Sounds.Run[j].Source);
}
}
else if (pitch > 0.02 & gain > 0.01)
{
Sounds.SoundBuffer buffer = Train.Cars[i].Sounds.Run[j].Buffer;
if (buffer != null)
{
OpenBveApi.Math.Vector3 pos = Train.Cars[i].Sounds.Run[j].Position;
Train.Cars[i].Sounds.Run[j].Source = Sounds.PlaySound(buffer, pitch, gain, pos, Train, i, true);
}
}
}
}
// motor sound
for (int i = 0; i < Train.Cars.Length; i++)
{
if (Train.Cars[i].Specs.IsMotorCar)
{
OpenBveApi.Math.Vector3 pos = Train.Cars[i].Sounds.Motor.Position;
double speed = Math.Abs(Train.Cars[i].Specs.CurrentPerceivedSpeed);
int idx = (int)Math.Round(speed * Train.Cars[i].Sounds.Motor.SpeedConversionFactor);
int odir = Train.Cars[i].Sounds.Motor.CurrentAccelerationDirection;
int ndir = Math.Sign(Train.Cars[i].Specs.CurrentAccelerationOutput);
for (int h = 0; h < 2; h++)
{
int j = h == 0 ? TrainManager.MotorSound.MotorP1 : TrainManager.MotorSound.MotorP2;
int k = h == 0 ? TrainManager.MotorSound.MotorB1 : TrainManager.MotorSound.MotorB2;
if (odir > 0 & ndir <= 0)
{
if (j < Train.Cars[i].Sounds.Motor.Tables.Length)
{
Sounds.StopSound(Train.Cars[i].Sounds.Motor.Tables[j].Source);
Train.Cars[i].Sounds.Motor.Tables[j].Source = null;
Train.Cars[i].Sounds.Motor.Tables[j].Buffer = null;
}
}
else if (odir < 0 & ndir >= 0)
{
if (k < Train.Cars[i].Sounds.Motor.Tables.Length)
{
Sounds.StopSound(Train.Cars[i].Sounds.Motor.Tables[k].Source);
Train.Cars[i].Sounds.Motor.Tables[k].Source = null;
Train.Cars[i].Sounds.Motor.Tables[k].Buffer = null;
}
}
if (ndir != 0)
{
if (ndir < 0) j = k;
if (j < Train.Cars[i].Sounds.Motor.Tables.Length)
{
int idx2 = idx;
if (idx2 >= Train.Cars[i].Sounds.Motor.Tables[j].Entries.Length)
{
idx2 = Train.Cars[i].Sounds.Motor.Tables[j].Entries.Length - 1;
}
if (idx2 >= 0)
{
Sounds.SoundBuffer obuf = Train.Cars[i].Sounds.Motor.Tables[j].Buffer;
Sounds.SoundBuffer nbuf = Train.Cars[i].Sounds.Motor.Tables[j].Entries[idx2].Buffer;
double pitch = Train.Cars[i].Sounds.Motor.Tables[j].Entries[idx2].Pitch;
double gain = Train.Cars[i].Sounds.Motor.Tables[j].Entries[idx2].Gain;
if (ndir == 1)
{
// power
double max = Train.Cars[i].Specs.AccelerationCurveMaximum;
if (max != 0.0)
{
double cur = Train.Cars[i].Specs.CurrentAccelerationOutput;
if (cur < 0.0) cur = 0.0;
gain *= Math.Pow(cur / max, 0.25);
}
}
else if (ndir == -1)
{
// brake
double max = Train.Cars[i].Specs.BrakeDecelerationAtServiceMaximumPressure;
if (max != 0.0)
{
double cur = -Train.Cars[i].Specs.CurrentAccelerationOutput;
if (cur < 0.0) cur = 0.0;
gain *= Math.Pow(cur / max, 0.25);
}
}
if (obuf != nbuf)
{
Sounds.StopSound(Train.Cars[i].Sounds.Motor.Tables[j].Source);
if (nbuf != null)
{
Train.Cars[i].Sounds.Motor.Tables[j].Source = Sounds.PlaySound(nbuf, pitch, gain, pos, Train, i, true);
Train.Cars[i].Sounds.Motor.Tables[j].Buffer = nbuf;
}
else
{
Train.Cars[i].Sounds.Motor.Tables[j].Source = null;
Train.Cars[i].Sounds.Motor.Tables[j].Buffer = null;
}
}
else if (nbuf != null)
{
if (Train.Cars[i].Sounds.Motor.Tables[j].Source != null)
{
Train.Cars[i].Sounds.Motor.Tables[j].Source.Pitch = pitch;
Train.Cars[i].Sounds.Motor.Tables[j].Source.Volume = gain;
}
}
else
{
Sounds.StopSound(Train.Cars[i].Sounds.Motor.Tables[j].Source);
Train.Cars[i].Sounds.Motor.Tables[j].Source = null;
Train.Cars[i].Sounds.Motor.Tables[j].Buffer = null;
}
}
else
{
Sounds.StopSound(Train.Cars[i].Sounds.Motor.Tables[j].Source);
Train.Cars[i].Sounds.Motor.Tables[j].Source = null;
Train.Cars[i].Sounds.Motor.Tables[j].Buffer = null;
}
}
}
}
Train.Cars[i].Sounds.Motor.CurrentAccelerationDirection = ndir;
}
}
// safety system
if (!Game.MinimalisticSimulation | Train != PlayerTrain)
{
UpdateSafetySystem(Train);
}
{
// breaker sound
bool breaker;
if (Train.Cars[Train.DriverCar].Specs.BrakeType == CarBrakeType.AutomaticAirBrake)
{
breaker = Train.Specs.CurrentReverser.Actual != 0 & Train.Specs.CurrentPowerNotch.Safety >= 1 & Train.Specs.AirBrake.Handle.Safety == AirBrakeHandleState.Release & !Train.Specs.CurrentEmergencyBrake.Safety & !Train.Specs.CurrentHoldBrake.Actual;
}
else
{
breaker = Train.Specs.CurrentReverser.Actual != 0 & Train.Specs.CurrentPowerNotch.Safety >= 1 & Train.Specs.CurrentBrakeNotch.Safety == 0 & !Train.Specs.CurrentEmergencyBrake.Safety & !Train.Specs.CurrentHoldBrake.Actual;
}
if (breaker & !Train.Cars[Train.DriverCar].Sounds.BreakerResumed)
{
// resume
if (Train.Cars[Train.DriverCar].Sounds.BreakerResume.Buffer != null)
{
Sounds.PlaySound(Train.Cars[Train.DriverCar].Sounds.BreakerResume.Buffer, 1.0, 1.0, Train.Cars[Train.DriverCar].Sounds.BreakerResume.Position, Train, Train.DriverCar, false);
}
if (Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Buffer != null)
{
Sounds.PlaySound(Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Buffer, 1.0, 1.0, Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Position, Train, Train.DriverCar, false);
}
Train.Cars[Train.DriverCar].Sounds.BreakerResumed = true;
}
else if (!breaker & Train.Cars[Train.DriverCar].Sounds.BreakerResumed)
{
// interrupt
if (Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Buffer != null)
{
Sounds.PlaySound(Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Buffer, 1.0, 1.0, Train.Cars[Train.DriverCar].Sounds.BreakerResumeOrInterrupt.Position, Train, Train.DriverCar, false);
}
Train.Cars[Train.DriverCar].Sounds.BreakerResumed = false;
}
}
// passengers
UpdateTrainPassengers(Train, TimeElapsed);
// signals
if (Train.CurrentSectionLimit == 0.0)
{
if (Train.Specs.CurrentEmergencyBrake.Driver & Train.Specs.CurrentAverageSpeed > -0.03 & Train.Specs.CurrentAverageSpeed < 0.03)
{
Train.CurrentSectionLimit = 6.94444444444444;
if (Train == PlayerTrain)
{
string s = Interface.GetInterfaceString("message_signal_proceed");
double a = (3.6 * Train.CurrentSectionLimit) * Game.SpeedConversionFactor;
s = s.Replace("[speed]", a.ToString("0", System.Globalization.CultureInfo.InvariantCulture));
s = s.Replace("[unit]", Game.UnitOfSpeed);
Game.AddMessage(s, Game.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Red, Game.SecondsSinceMidnight + 5.0);
}
}
}
// infrequent updates
Train.InternalTimerTimeElapsed += TimeElapsed;
if (Train.InternalTimerTimeElapsed > 10.0)
{
Train.InternalTimerTimeElapsed -= 10.0;
SynchronizeTrain(Train);
UpdateAtmosphericConstants(Train);
}
}