/// <summary>Call this method to update the train</summary>
/// <param name="TimeElapsed">The elapsed time this frame</param>
internal void Update(double TimeElapsed)
{
if (State == TrainState.Pending)
{
// pending train
bool forceIntroduction = !IsPlayerTrain && !Game.MinimalisticSimulation;
double time = 0.0;
if (!forceIntroduction)
{
for (int i = 0; i < Program.CurrentRoute.Stations.Length; i++)
{
if (Program.CurrentRoute.Stations[i].StopMode == StationStopMode.AllStop | Program.CurrentRoute.Stations[i].StopMode == StationStopMode.PlayerPass)
{
if (Program.CurrentRoute.Stations[i].ArrivalTime >= 0.0)
{
time = Program.CurrentRoute.Stations[i].ArrivalTime;
}
else if (Program.CurrentRoute.Stations[i].DepartureTime >= 0.0)
{
time = Program.CurrentRoute.Stations[i].DepartureTime - Program.CurrentRoute.Stations[i].StopTime;
}
break;
}
}
time -= TimetableDelta;
}
if (Program.CurrentRoute.SecondsSinceMidnight >= time | forceIntroduction)
{
bool introduce = true;
if (!forceIntroduction)
{
if (CurrentSectionIndex >= 0)
{
if (!Program.CurrentRoute.Sections[CurrentSectionIndex].IsFree())
{
introduce = false;
}
}
}
if (this == PlayerTrain && Loading.SimulationSetup)
{
/* Loading has finished, but we still have an AI train in the current section
* This may be caused by an iffy RunInterval value, or simply by having no sections *
*
* We must introduce the player's train as otherwise the cab and loop sounds are missing
* NOTE: In this case, the signalling cannot prevent the player from colliding with
* the AI train
*/
introduce = true;
}
if (introduce)
{
// train is introduced
State = TrainState.Available;
for (int j = 0; j < Cars.Length; j++)
{
if (Cars[j].CarSections.Length != 0)
{
if (j == this.DriverCar && IsPlayerTrain)
{
this.Cars[j].ChangeCarSection(CarSectionType.Interior);
}
else
{
/*
* HACK: Load in exterior mode first to ensure everything is cached
* before switching immediately to not visible
* https://github.com/leezer3/OpenBVE/issues/226
* Stuff like the R142A really needs to downsize the textures supplied,
* but we have no control over external factors....
*/
this.Cars[j].ChangeCarSection(CarSectionType.Exterior);
if (IsPlayerTrain)
{
this.Cars[j].ChangeCarSection(CarSectionType.NotVisible);
}
}
}
Cars[j].FrontBogie.ChangeSection(!IsPlayerTrain ? 0 : -1);
Cars[j].RearBogie.ChangeSection(!IsPlayerTrain ? 0 : -1);
Cars[j].Coupler.ChangeSection(!IsPlayerTrain ? 0 : -1);
if (Cars[j].Specs.IsMotorCar)
{
if (Cars[j].Sounds.Loop.Buffer != null)
{
Cars[j].Sounds.Loop.Source = Program.Sounds.PlaySound(Cars[j].Sounds.Loop.Buffer, 1.0, 1.0, Cars[j].Sounds.Loop.Position, Cars[j], true);
}
}
}
}
}
}
else if (State == TrainState.Available)
{
// available train
UpdatePhysicsAndControls(TimeElapsed);
if (CurrentSpeed > CurrentRouteLimit)
{
if (previousRouteLimit != CurrentRouteLimit || Interface.CurrentOptions.GameMode == GameMode.Arcade)
{
/*
* HACK: If the limit has changed, or we are in arcade mode, notify the player
* This conforms to the original behaviour, but doesn't need to raise the message from the event.
*/
Game.AddMessage(Translations.GetInterfaceString("message_route_overspeed"), MessageDependency.RouteLimit, GameMode.Normal, MessageColor.Orange, Double.PositiveInfinity, null);
}
}
previousRouteLimit = CurrentRouteLimit;
if (Interface.CurrentOptions.GameMode == GameMode.Arcade)
{
if (CurrentSectionLimit == 0.0)
{
Game.AddMessage(Translations.GetInterfaceString("message_signal_stop"), MessageDependency.PassedRedSignal, GameMode.Normal, MessageColor.Red, double.PositiveInfinity, null);
}
else if (CurrentSpeed > CurrentSectionLimit)
{
Game.AddMessage(Translations.GetInterfaceString("message_signal_overspeed"), MessageDependency.SectionLimit, GameMode.Normal, MessageColor.Orange, Double.PositiveInfinity, null);
}
}
if (AI != null)
{
AI.Trigger(TimeElapsed);
}
}
else if (State == TrainState.Bogus)
{
// bogus train
if (AI != null)
{
AI.Trigger(TimeElapsed);
}
}
//Trigger point sounds if appropriate
for (int i = 0; i < Cars.Length; i++)
{
Vector3 p = Vector3.Zero;
SoundBuffer buffer = null;
if (Cars[i].FrontAxle.PointSoundTriggered)
{
Cars[i].FrontAxle.PointSoundTriggered = false;
int bufferIndex = Cars[i].FrontAxle.RunIndex;
if (Cars[i].FrontAxle.PointSounds == null || Cars[i].FrontAxle.PointSounds.Length == 0)
{
//No point sounds defined at all
continue;
}
if (bufferIndex > Cars[i].FrontAxle.PointSounds.Length - 1 ||
Cars[i].FrontAxle.PointSounds[bufferIndex].Buffer == null)
{
//If the switch sound does not exist, return zero
//Required to handle legacy trains which don't have idx specific run sounds defined
bufferIndex = 0;
}
buffer = Cars[i].FrontAxle.PointSounds[bufferIndex].Buffer;
p = Cars[i].FrontAxle.PointSounds[bufferIndex].Position;
}
if (buffer != null)
{
double spd = Math.Abs(CurrentSpeed);
double pitch = spd / 12.5;
double gain = pitch < 0.5 ? 2.0 * pitch : 1.0;
if (pitch < 0.2 | gain < 0.2)
{
buffer = null;
}
if (buffer != null)
{
Program.Sounds.PlaySound(buffer, pitch, gain, p, Cars[i], false);
}
}
}
}